<# .SYNOPSIS Rebuilds the Go local-mcp binary from the repository root. .DESCRIPTION This script: 1. Detects and stops any running Go local-mcp server processes. 2. Copies root static assets into go-server\static for //go:embed. 3. Removes any previous build outputs. 4. Builds a fresh Go binary. 5. Removes the temporary go-server\static copy. 6. Moves the new binary into the repository root. 7. Restarts the Go server only if one was running before the rebuild. If go-server\static already exists, it is backed up and restored after the build so the workspace is not left dirty just from executing this script. .USAGE .\build-go-server.ps1 #> [CmdletBinding()] param() $ErrorActionPreference = "Stop" $RootDir = $PSScriptRoot $GoServerDir = Join-Path $RootDir "go-server" $RootStaticDir = Join-Path $RootDir "static" $GoStaticDir = Join-Path $GoServerDir "static" $RootBinaryPath = Join-Path $RootDir "local-mcp.exe" $BuildBinaryPath = Join-Path $GoServerDir "local-mcp.exe" $StdoutLogPath = Join-Path $GoServerDir "server.stdout.log" $StderrLogPath = Join-Path $GoServerDir "server.stderr.log" $StaticBackupDir = Join-Path ([System.IO.Path]::GetTempPath()) ("local-mcp-go-static-" + [guid]::NewGuid().ToString("N")) function Write-Step([string]$Message, [string]$Color = "Cyan") { Write-Host $Message -ForegroundColor $Color } function Get-NormalizedPath([string]$Path) { return [System.IO.Path]::GetFullPath($Path).TrimEnd('\\').ToLowerInvariant() } function Get-GoServerProcesses { $candidatePaths = @( (Get-NormalizedPath $RootBinaryPath), (Get-NormalizedPath $BuildBinaryPath) ) $processes = Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -ieq 'local-mcp.exe' -and $_.ExecutablePath -and ($candidatePaths -contains (Get-NormalizedPath $_.ExecutablePath)) } return @($processes) } function Stop-GoServerProcesses([array]$Processes) { foreach ($proc in $Processes) { Write-Step ("Stopping Go server PID {0} ({1})" -f $proc.ProcessId, $proc.ExecutablePath) "Yellow" Stop-Process -Id $proc.ProcessId -Force -ErrorAction Stop } if ($Processes.Count -gt 0) { Start-Sleep -Seconds 1 } } function Remove-BinaryIfPresent([string]$Path, [string]$Label) { if (-not (Test-Path $Path)) { return } try { Write-Step "Removing existing $Label." Remove-Item -Path $Path -Force return } catch { $lockingProcesses = Get-GoServerProcesses | Where-Object { $_.ExecutablePath -and ((Get-NormalizedPath $_.ExecutablePath) -eq (Get-NormalizedPath $Path)) } if ($lockingProcesses.Count -eq 0) { throw } $script:wasRunning = $true Write-Step "Detected locked $Label; stopping matching Go server process(es) and retrying." "Yellow" Stop-GoServerProcesses -Processes $lockingProcesses Remove-Item -Path $Path -Force } } function Start-GoServer { if (-not (Test-Path $RootBinaryPath)) { throw "Cannot restart Go server because the rebuilt binary was not found at $RootBinaryPath" } $timestamp = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [build-go-server.ps1] ---- starting rebuilt Go server ----" Add-Content -Path $StdoutLogPath -Value $timestamp Add-Content -Path $StderrLogPath -Value $timestamp $proc = Start-Process ` -FilePath $RootBinaryPath ` -WorkingDirectory $RootDir ` -RedirectStandardOutput $StdoutLogPath ` -RedirectStandardError $StderrLogPath ` -WindowStyle Hidden ` -PassThru Write-Step ("Restarted Go server with PID {0}" -f $proc.Id) "Green" } if (-not (Test-Path $GoServerDir)) { throw "Go server directory not found: $GoServerDir" } if (-not (Test-Path $RootStaticDir)) { throw "Root static directory not found: $RootStaticDir" } $runningProcesses = Get-GoServerProcesses $wasRunning = $runningProcesses.Count -gt 0 $backedUpExistingStatic = $false $buildSucceeded = $false try { if ($wasRunning) { Write-Step "Detected running Go server process(es); stopping them before rebuild." Stop-GoServerProcesses -Processes $runningProcesses } else { Write-Step "No running Go server processes found." } if (Test-Path $GoStaticDir) { Write-Step "Backing up existing go-server\\static before staging build assets." Move-Item -Path $GoStaticDir -Destination $StaticBackupDir $backedUpExistingStatic = $true } Write-Step "Copying root static assets into go-server\\static for the Go build." Copy-Item -Path $RootStaticDir -Destination $GoStaticDir -Recurse Remove-BinaryIfPresent -Path $RootBinaryPath -Label "root binary" Remove-BinaryIfPresent -Path $BuildBinaryPath -Label "Go build output" Write-Step "Building Go binary from go-server..." Push-Location $GoServerDir try { & go build -o $BuildBinaryPath . } finally { Pop-Location } if (-not (Test-Path $BuildBinaryPath)) { throw "Go build completed without producing $BuildBinaryPath" } Write-Step "Build succeeded; removing staged go-server\\static copy." Remove-Item -Path $GoStaticDir -Recurse -Force -ErrorAction SilentlyContinue Write-Step "Moving rebuilt binary into repository root." Move-Item -Path $BuildBinaryPath -Destination $RootBinaryPath -Force $buildSucceeded = $true if ($wasRunning) { Write-Step "Restarting Go server with rebuilt binary." Start-GoServer } else { Write-Step "Go server was not running before rebuild; leaving it stopped." "Green" } } finally { if (Test-Path $GoStaticDir) { Remove-Item -Path $GoStaticDir -Recurse -Force -ErrorAction SilentlyContinue } if ($backedUpExistingStatic -and (Test-Path $StaticBackupDir)) { Move-Item -Path $StaticBackupDir -Destination $GoStaticDir -Force } if ((-not $buildSucceeded) -and (Test-Path $BuildBinaryPath)) { Remove-Item -Path $BuildBinaryPath -Force -ErrorAction SilentlyContinue } } Write-Step "Go build workflow completed successfully." "Green"