param( [Parameter(Mandatory = $true)][string]$ProjectRoot, [switch]$QuickAppOnly, [switch]$Clean ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $ProjectRoot = (Resolve-Path -LiteralPath $ProjectRoot).Path $toolBin = Join-Path $PSScriptRoot 'temp\glyphix-v0.7.2-windows-x64\bin' $gx = Join-Path $toolBin 'gx.exe' if (-not (Test-Path -LiteralPath $gx)) { throw "Glyphix toolchain not found: $gx" } $manifestPath = Join-Path $ProjectRoot 'src\manifest.json' $manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json if ($manifest.package -cnotmatch '^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$') { throw 'Invalid Glyphix package name' } $quickAppTargets = @('generic-watch-466x466-quickapp', 'generic-watch-390x450-quickapp') $targets = if ($QuickAppOnly) { $quickAppTargets } else { @('generic-watch-466x466', 'generic-watch-390x450', 'generic-watch-466x466-quickapp', 'generic-watch-390x450-quickapp') } $originalPath = $env:Path Push-Location $ProjectRoot try { $env:Path = "$toolBin;$originalPath" $availableDevices = @(& $gx list device) if ($LASTEXITCODE -ne 0) { throw 'Unable to read Glyphix device profiles' } foreach ($device in $targets) { if ($availableDevices -cnotcontains $device) { throw "Missing Glyphix device profile: $device" } } if ($Clean) { & $gx clean if ($LASTEXITCODE -ne 0) { throw 'Glyphix clean failed' } } foreach ($device in $targets) { $arguments = @('build', '-d', $device) if (-not $device.Contains('quickapp')) { $arguments += '-e' } $output = @(& $gx @arguments 2>&1 | ForEach-Object { $_.ToString() }) $output | ForEach-Object { Write-Host $_ } if ($LASTEXITCODE -ne 0 -or ($output -join "`n") -match '(?im)^\s*(?:error|fatal):\s') { throw "Glyphix build failed for $device" } } foreach ($device in $quickAppTargets) { $deliveryRoot = Join-Path $ProjectRoot ".glyphix-work\dist\$device\$($manifest.package)" foreach ($fileName in @('bundle.pkg', 'manifest.json', 'icon.png')) { $artifact = Join-Path $deliveryRoot $fileName if (-not (Test-Path -LiteralPath $artifact -PathType Leaf) -or (Get-Item -LiteralPath $artifact).Length -eq 0) { throw "Missing or empty QuickApp artifact: $artifact" } } $packedManifest = Get-Content -LiteralPath (Join-Path $deliveryRoot 'manifest.json') -Raw | ConvertFrom-Json if ($packedManifest.package -cne $manifest.package -or $packedManifest.versionName -cne $manifest.versionName -or $packedManifest.versionCode -ne $manifest.versionCode) { throw "QuickApp package/version mismatch: $device" } $icon = [IO.File]::ReadAllBytes((Join-Path $deliveryRoot 'icon.png')) if ($icon.Length -lt 8 -or [Convert]::ToHexString($icon[0..7]) -cne '89504E470D0A1A0A') { throw "Invalid QuickApp PNG icon: $device" } foreach ($fileName in @('bundle.pkg', 'manifest.json', 'icon.png')) { $artifact = Join-Path $deliveryRoot $fileName [pscustomobject]@{ Package = $manifest.package Device = $device File = $fileName Bytes = (Get-Item -LiteralPath $artifact).Length SHA256 = (Get-FileHash -LiteralPath $artifact -Algorithm SHA256).Hash } } } } finally { Pop-Location $env:Path = $originalPath }