# OrchestrAD Build Script # Builds for Windows, macOS, and Linux (amd64 and arm64) # Version format: yyyy.MM.dd.HHmm param( [switch]$All, [switch]$Windows, [switch]$MacOS, [switch]$Linux, [switch]$Clean, [switch]$SkipFrontend ) $ErrorActionPreference = "Stop" # Version generation $Version = Get-Date -Format "yyyy.MM.dd.HHmm" $BuildTime = Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ" $GitCommit = git rev-parse --short HEAD 2>$null if (-not $GitCommit) { $GitCommit = "unknown" } Write-Host "Building OrchestrAD v$Version" -ForegroundColor Cyan Write-Host "Build Time: $BuildTime" Write-Host "Git Commit: $GitCommit" $ProjectRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if (-not (Test-Path "$ProjectRoot\backend")) { $ProjectRoot = Split-Path -Parent $PSScriptRoot } $BackendDir = Join-Path $ProjectRoot "backend" $FrontendDir = Join-Path $ProjectRoot "frontend" $FrontendOut = Join-Path $FrontendDir "out" $WebUIDist = Join-Path $BackendDir "internal\webui\dist" $BinariesDir = Join-Path $ProjectRoot "binaries" $ResourcesDir = Join-Path $ProjectRoot "resources" # Clean binaries directory if requested if ($Clean) { Write-Host "Cleaning binaries directory..." -ForegroundColor Yellow if (Test-Path $BinariesDir) { Remove-Item -Recurse -Force $BinariesDir } } # Build the frontend and stage it into the backend embed directory so the # produced binary ships the full UI (see docs/DesignSpecification.md ยง6.2.1). if (-not $SkipFrontend) { Write-Host "`nBuilding frontend (Next.js static export)..." -ForegroundColor Cyan Push-Location $FrontendDir try { if (-not (Test-Path (Join-Path $FrontendDir "node_modules"))) { Write-Host " Installing frontend dependencies..." -ForegroundColor Yellow npm install if ($LASTEXITCODE -ne 0) { throw "npm install failed" } } npm run build if ($LASTEXITCODE -ne 0) { throw "frontend build failed" } } finally { Pop-Location } if (-not (Test-Path $FrontendOut) -or -not (Get-ChildItem $FrontendOut -File -Recurse | Select-Object -First 1)) { throw "Frontend output directory '$FrontendOut' is missing or empty after build. Refusing to produce a binary without the UI." } Write-Host "Staging frontend assets into $WebUIDist..." -ForegroundColor Cyan if (-not (Test-Path $WebUIDist)) { New-Item -ItemType Directory -Path $WebUIDist -Force | Out-Null } Get-ChildItem -LiteralPath $WebUIDist -Force | Where-Object { $_.Name -ne ".gitignore" } | Remove-Item -Recurse -Force Copy-Item -Path (Join-Path $FrontendOut "*") -Destination $WebUIDist -Recurse -Force $uiFileCount = (Get-ChildItem $WebUIDist -Recurse -File).Count Write-Host " Staged $uiFileCount UI files" -ForegroundColor Green } else { Write-Host "`nSkipping frontend build (--SkipFrontend)." -ForegroundColor Yellow if (-not (Test-Path (Join-Path $WebUIDist "_next"))) { Write-Host " Warning: $WebUIDist does not contain a built UI; binary will ship the placeholder page." -ForegroundColor Yellow } } # Create output directories $Platforms = @( @{ OS = "windows"; Arch = "amd64"; Ext = ".exe" }, @{ OS = "windows"; Arch = "arm64"; Ext = ".exe" }, @{ OS = "darwin"; Arch = "amd64"; Ext = "" }, @{ OS = "darwin"; Arch = "arm64"; Ext = "" }, @{ OS = "linux"; Arch = "amd64"; Ext = "" }, @{ OS = "linux"; Arch = "arm64"; Ext = "" } ) # Filter platforms based on flags if (-not $All) { if ($Windows) { $Platforms = $Platforms | Where-Object { $_.OS -eq "windows" } } elseif ($MacOS) { $Platforms = $Platforms | Where-Object { $_.OS -eq "darwin" } } elseif ($Linux) { $Platforms = $Platforms | Where-Object { $_.OS -eq "linux" } } else { # Default to all platforms $All = $true } } # LDFlags for version injection $LDFlags = "-s -w -X github.com/Grace-Solutions/OrchestrAD/internal/version.Version=$Version -X github.com/Grace-Solutions/OrchestrAD/internal/version.BuildTime=$BuildTime -X github.com/Grace-Solutions/OrchestrAD/internal/version.GitCommit=$GitCommit" # Generate the Windows icon/version resource so the windows/* binaries embed the # OrchestrAD icon. goversioninfo is a pure-Go tool and runs on any host; the # arch-suffixed .syso files are only linked into their matching GOARCH build. $BuildWindows = $All -or ($Platforms | Where-Object { $_.OS -eq "windows" }) if ($BuildWindows) { Write-Host "`nGenerating Windows resource (icon + version metadata)..." -ForegroundColor Cyan $GoVersionInfo = Join-Path (Join-Path $env:USERPROFILE "go\bin") "goversioninfo.exe" if (-not (Test-Path $GoVersionInfo)) { Write-Host " Installing goversioninfo..." -ForegroundColor Yellow go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.7.0 } $vp = $Version -split '\.' Push-Location $BackendDir try { foreach ($a in @(@{arch='amd64';flags=@('-64')}, @{arch='arm64';flags=@('-64','-arm')})) { $out = "cmd\orchestrad\resource_windows_$($a.arch).syso" & $GoVersionInfo @($a.flags) ` "-ver-major=$([int]$vp[0])" "-ver-minor=$([int]$vp[1])" "-ver-patch=$([int]$vp[2])" "-ver-build=$([int]$vp[3])" ` "-product-version=$([int]$vp[0]).$([int]$vp[1]).$([int]$vp[2])" ` "-o" $out "versioninfo.json" } } finally { Pop-Location } } Push-Location $BackendDir try { foreach ($Platform in $Platforms) { $OS = $Platform.OS $Arch = $Platform.Arch $Ext = $Platform.Ext # Map darwin to macos for folder naming $FolderOS = if ($OS -eq "darwin") { "macos" } else { $OS } $OutputDir = Join-Path $BinariesDir "$FolderOS\$Arch" $OutputFile = Join-Path $OutputDir "orchestrad$Ext" # Create output directory if (-not (Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null } Write-Host "`nBuilding for $OS/$Arch..." -ForegroundColor Green # Pure-Go build (modernc.org/sqlite): CGO is disabled, so every target # cross-compiles from any host with no C toolchain. Windows binaries pick # up the icon/version resource generated into cmd/orchestrad before the # loop (resource_windows_.syso). $env:GOOS = $OS $env:GOARCH = $Arch $env:CGO_ENABLED = "0" go build -ldflags "$LDFlags" -o "$OutputFile" ./cmd/orchestrad if ($LASTEXITCODE -eq 0) { $FileSize = (Get-Item $OutputFile).Length / 1MB Write-Host " Built: $OutputFile ($([math]::Round($FileSize, 2)) MB)" -ForegroundColor Green } else { Write-Host " Failed to build for $OS/$Arch" -ForegroundColor Red } } } finally { Pop-Location Remove-Item Env:GOOS -ErrorAction SilentlyContinue Remove-Item Env:GOARCH -ErrorAction SilentlyContinue Remove-Item Env:CGO_ENABLED -ErrorAction SilentlyContinue } Write-Host "`nBuild complete!" -ForegroundColor Cyan Write-Host "Binaries are in: $BinariesDir"