mirror of
https://github.com/NanmiCoder/claude-code-haha.git
synced 2026-10-10 03:43:11 +08:00
fix(native): support Windows arm64 desktop startup (#954)
Add Windows ARM64 desktop release packaging, verify architecture-specific sidecar/native files in package smoke, and give the Electron sidecar more startup time plus early diagnostics for slow Windows ARM launches. Tested: bun test electron/services/sidecarManager.test.ts Tested: bun test scripts/quality-gate/package-smoke/index.test.ts scripts/release-update-metadata.test.ts scripts/pr/release-workflow.test.ts Tested: bun run check:native Tested: bun run check:policy Not-tested: full bun run verify / coverage; this was a local issue-fix handoff, not PR-ready validation. Confidence: high Scope-risk: moderate
This commit is contained in:
@@ -13,6 +13,7 @@ on:
|
||||
- macos-arm64
|
||||
- macos-x64
|
||||
- windows-x64
|
||||
- windows-arm64
|
||||
- linux-x64
|
||||
- linux-arm64
|
||||
|
||||
@@ -31,7 +32,7 @@ jobs:
|
||||
steps:
|
||||
- id: set-matrix
|
||||
run: |
|
||||
ALL='[{"platform":"macos-latest","target_triple":"aarch64-apple-darwin","builder_args":"--mac dmg zip --arm64","label":"macOS-ARM64","artifact_name":"macos-arm64","smoke_platform":"macos"},{"platform":"macos-latest","target_triple":"x86_64-apple-darwin","builder_args":"--mac dmg zip --x64","label":"macOS-x64","artifact_name":"macos-x64","smoke_platform":"macos"},{"platform":"windows-latest","target_triple":"x86_64-pc-windows-msvc","builder_args":"--win nsis --x64","label":"Windows-x64","artifact_name":"windows-x64","smoke_platform":"windows"},{"platform":"ubuntu-22.04","target_triple":"x86_64-unknown-linux-gnu","builder_args":"--linux AppImage deb --x64","label":"Linux-x64","artifact_name":"linux-x64","smoke_platform":"linux"},{"platform":"ubuntu-22.04-arm","target_triple":"aarch64-unknown-linux-gnu","builder_args":"--linux AppImage deb --arm64","label":"Linux-ARM64","artifact_name":"linux-arm64","smoke_platform":"linux"}]'
|
||||
ALL='[{"platform":"macos-latest","target_triple":"aarch64-apple-darwin","builder_args":"--mac dmg zip --arm64","label":"macOS-ARM64","artifact_name":"macos-arm64","smoke_platform":"macos","arch":"arm64"},{"platform":"macos-latest","target_triple":"x86_64-apple-darwin","builder_args":"--mac dmg zip --x64","label":"macOS-x64","artifact_name":"macos-x64","smoke_platform":"macos","arch":"x64"},{"platform":"windows-latest","target_triple":"x86_64-pc-windows-msvc","builder_args":"--win nsis --x64","label":"Windows-x64","artifact_name":"windows-x64","smoke_platform":"windows","arch":"x64"},{"platform":"windows-latest","target_triple":"aarch64-pc-windows-msvc","builder_args":"--win nsis --arm64","label":"Windows-ARM64","artifact_name":"windows-arm64","smoke_platform":"windows","arch":"arm64"},{"platform":"ubuntu-22.04","target_triple":"x86_64-unknown-linux-gnu","builder_args":"--linux AppImage deb --x64","label":"Linux-x64","artifact_name":"linux-x64","smoke_platform":"linux","arch":"x64"},{"platform":"ubuntu-22.04-arm","target_triple":"aarch64-unknown-linux-gnu","builder_args":"--linux AppImage deb --arm64","label":"Linux-ARM64","artifact_name":"linux-arm64","smoke_platform":"linux","arch":"arm64"}]'
|
||||
SELECTED="${{ inputs.platforms }}"
|
||||
if [ "$SELECTED" = "all" ]; then
|
||||
MATRIX=$(echo "$ALL" | jq -c '{include: .}')
|
||||
@@ -40,6 +41,7 @@ jobs:
|
||||
($sel == "macos-arm64" and .label == "macOS-ARM64") or
|
||||
($sel == "macos-x64" and .label == "macOS-x64") or
|
||||
($sel == "windows-x64" and .label == "Windows-x64") or
|
||||
($sel == "windows-arm64" and .label == "Windows-ARM64") or
|
||||
($sel == "linux-x64" and .label == "Linux-x64") or
|
||||
($sel == "linux-arm64" and .label == "Linux-ARM64")
|
||||
)]}')
|
||||
@@ -113,7 +115,7 @@ jobs:
|
||||
run: node ./node_modules/electron-builder/out/cli/cli.js ${{ matrix.builder_args }} --publish never
|
||||
|
||||
- name: Verify packaged app structure
|
||||
run: bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --package-kind release --artifacts-dir desktop/build-artifacts/electron
|
||||
run: bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --arch ${{ matrix.arch }} --package-kind release --artifacts-dir desktop/build-artifacts/electron
|
||||
|
||||
- name: Collect artifacts
|
||||
id: collect
|
||||
|
||||
@@ -79,27 +79,38 @@ jobs:
|
||||
app_bundle_dir: mac-arm64
|
||||
label: macOS-ARM64
|
||||
smoke_platform: macos
|
||||
arch: arm64
|
||||
- platform: macos-latest
|
||||
target_triple: x86_64-apple-darwin
|
||||
builder_args: --mac dmg zip --x64
|
||||
app_bundle_dir: mac
|
||||
label: macOS-x64
|
||||
smoke_platform: macos
|
||||
arch: x64
|
||||
- platform: ubuntu-22.04
|
||||
target_triple: x86_64-unknown-linux-gnu
|
||||
builder_args: --linux AppImage deb --x64
|
||||
label: Linux-x64
|
||||
smoke_platform: linux
|
||||
arch: x64
|
||||
- platform: ubuntu-22.04-arm
|
||||
target_triple: aarch64-unknown-linux-gnu
|
||||
builder_args: --linux AppImage deb --arm64
|
||||
label: Linux-ARM64
|
||||
smoke_platform: linux
|
||||
arch: arm64
|
||||
- platform: windows-latest
|
||||
target_triple: x86_64-pc-windows-msvc
|
||||
builder_args: --win nsis --x64
|
||||
label: Windows-x64
|
||||
smoke_platform: windows
|
||||
arch: x64
|
||||
- platform: windows-latest
|
||||
target_triple: aarch64-pc-windows-msvc
|
||||
builder_args: --win nsis --arm64
|
||||
label: Windows-ARM64
|
||||
smoke_platform: windows
|
||||
arch: arm64
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
name: Build (${{ matrix.label }})
|
||||
@@ -361,11 +372,11 @@ jobs:
|
||||
run: node ./node_modules/electron-builder/out/cli/cli.js ${{ matrix.builder_args }} --publish never
|
||||
|
||||
- name: Verify packaged app structure
|
||||
run: bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --package-kind release --artifacts-dir desktop/build-artifacts/electron
|
||||
run: bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --arch ${{ matrix.arch }} --package-kind release --artifacts-dir desktop/build-artifacts/electron
|
||||
|
||||
- name: Verify macOS launch policy
|
||||
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && (github.event_name != 'workflow_dispatch' || inputs.notarize_macos == true)
|
||||
run: bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper
|
||||
run: bun run test:package-smoke --platform macos --arch ${{ matrix.arch }} --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper
|
||||
|
||||
- name: Warn macOS notarization skipped
|
||||
if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && github.event_name == 'workflow_dispatch' && inputs.notarize_macos == false
|
||||
@@ -421,6 +432,13 @@ jobs:
|
||||
"latest.yml"
|
||||
)
|
||||
;;
|
||||
Windows-ARM64)
|
||||
expected=(
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-arm64.exe"
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-arm64.exe.blockmap"
|
||||
"latest.yml"
|
||||
)
|
||||
;;
|
||||
*)
|
||||
echo "::error::No expected asset list for matrix label ${{ matrix.label }}"
|
||||
exit 1
|
||||
@@ -542,6 +560,8 @@ jobs:
|
||||
"Claude-Code-Haha-${APP_VERSION}-linux-arm64.deb"
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-x64.exe"
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-x64.exe.blockmap"
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-arm64.exe"
|
||||
"Claude-Code-Haha-${APP_VERSION}-win-arm64.exe.blockmap"
|
||||
)
|
||||
|
||||
missing=()
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
reserveServerPort,
|
||||
SERVER_BIND_HOST,
|
||||
SERVER_CONTROL_HOST,
|
||||
SERVER_STARTUP_TIMEOUT_MS,
|
||||
spawnSidecar,
|
||||
waitForServer,
|
||||
windowsPowerShellOverride,
|
||||
@@ -95,7 +96,7 @@ export class ElectronServerRuntime {
|
||||
try {
|
||||
const child = spawnSidecar(plan)
|
||||
this.captureLogs(child, 'claude-server', logs)
|
||||
await waitForServer(SERVER_CONTROL_HOST, port)
|
||||
await waitForServer(SERVER_CONTROL_HOST, port, SERVER_STARTUP_TIMEOUT_MS)
|
||||
writeLastServerPort(port)
|
||||
this.server = { url, child }
|
||||
this.startupError = null
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('Electron sidecar manager', () => {
|
||||
expect(resolveHostTriple('darwin', 'arm64')).toBe('aarch64-apple-darwin')
|
||||
expect(resolveHostTriple('darwin', 'x64')).toBe('x86_64-apple-darwin')
|
||||
expect(resolveHostTriple('win32', 'x64')).toBe('x86_64-pc-windows-msvc')
|
||||
expect(resolveHostTriple('win32', 'arm64')).toBe('aarch64-pc-windows-msvc')
|
||||
expect(resolveHostTriple('linux', 'arm64')).toBe('aarch64-unknown-linux-gnu')
|
||||
})
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import path from 'node:path'
|
||||
|
||||
export const SERVER_BIND_HOST = '0.0.0.0'
|
||||
export const SERVER_CONTROL_HOST = '127.0.0.1'
|
||||
export const SERVER_STARTUP_TIMEOUT_MS = 30_000
|
||||
export const SERVER_STARTUP_LOG_LIMIT = 80
|
||||
// Shared with the Tauri shell (src-tauri/src/lib.rs) so both desktop builds
|
||||
// reuse the same sticky port across restarts (issue #767).
|
||||
@@ -163,7 +164,7 @@ export function preferredServerPorts(env: NodeJS.ProcessEnv = process.env): numb
|
||||
return ports
|
||||
}
|
||||
|
||||
export async function waitForServer(host: string, port: number, timeoutMs = 10_000): Promise<void> {
|
||||
export async function waitForServer(host: string, port: number, timeoutMs = SERVER_STARTUP_TIMEOUT_MS): Promise<void> {
|
||||
const deadline = Date.now() + timeoutMs
|
||||
const healthUrl = `http://${host}:${port}/health`
|
||||
let lastError: Error | null = null
|
||||
|
||||
@@ -40,6 +40,7 @@ if (mode === 'adapters') {
|
||||
await import('../../preload.ts')
|
||||
|
||||
if (mode === 'server') {
|
||||
console.log(`[claude-sidecar] starting server mode (${process.platform}/${process.arch})`)
|
||||
const { startServer } = await import('../../src/server/index.ts')
|
||||
startServer()
|
||||
} else if (mode === 'cli') {
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('release desktop workflow', () => {
|
||||
expect(workflow).toContain(electronBuilderCli)
|
||||
}
|
||||
expect(workflow).toContain('smoke_platform')
|
||||
expect(workflow).toContain('bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --package-kind release --artifacts-dir desktop/build-artifacts/electron')
|
||||
expect(workflow).toContain('bun run test:package-smoke --platform ${{ matrix.smoke_platform }} --arch ${{ matrix.arch }} --package-kind release --artifacts-dir desktop/build-artifacts/electron')
|
||||
expect(workflow).not.toContain('tauri-apps/tauri-action@v0')
|
||||
}
|
||||
})
|
||||
@@ -116,7 +116,7 @@ describe('release desktop workflow', () => {
|
||||
expect(workflow).toContain('notarize_macos:')
|
||||
expect(workflow).toContain("description: 'Notarize macOS artifacts'")
|
||||
expect(gatekeeperStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && (github.event_name != 'workflow_dispatch' || inputs.notarize_macos == true)")
|
||||
expect(gatekeeperStep).toContain('bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper')
|
||||
expect(gatekeeperStep).toContain('bun run test:package-smoke --platform macos --arch ${{ matrix.arch }} --package-kind release --artifacts-dir desktop/build-artifacts/electron --require-macos-gatekeeper')
|
||||
expect(notarizationWarningStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed == 'true' && github.event_name == 'workflow_dispatch' && inputs.notarize_macos == false")
|
||||
expect(notarizationWarningStep).toContain('Developer ID signed but not notarized')
|
||||
expect(unsignedWarningStep).toContain("if: matrix.smoke_platform == 'macos' && needs.signing-preflight.outputs.macos_signed != 'true'")
|
||||
@@ -253,9 +253,12 @@ describe('release desktop workflow', () => {
|
||||
const buildJob = extractJob(workflow, 'build')
|
||||
|
||||
expect(buildJob).toContain('Validate matrix release asset set')
|
||||
for (const label of ['macOS-ARM64', 'macOS-x64', 'Linux-x64', 'Linux-ARM64', 'Windows-x64']) {
|
||||
for (const label of ['macOS-ARM64', 'macOS-x64', 'Linux-x64', 'Linux-ARM64', 'Windows-x64', 'Windows-ARM64']) {
|
||||
expect(buildJob).toContain(`${label})`)
|
||||
}
|
||||
expect(buildJob).toContain('target_triple: aarch64-pc-windows-msvc')
|
||||
expect(buildJob).toContain('builder_args: --win nsis --arm64')
|
||||
expect(buildJob).toContain('Claude-Code-Haha-${APP_VERSION}-win-arm64.exe')
|
||||
expect(buildJob).toContain('Upload release artifacts for final publish')
|
||||
expect(buildJob).toContain('actions/upload-artifact@v4')
|
||||
expect(buildJob).toContain('name: desktop-release-artifacts-${{ matrix.label }}')
|
||||
|
||||
@@ -44,8 +44,10 @@ describe('package smoke args', () => {
|
||||
test('requires a supported platform value', () => {
|
||||
expect(() => parsePackageSmokeArgs([])).toThrow('--platform')
|
||||
expect(() => parsePackageSmokeArgs(['--platform', 'android'])).toThrow('macos|windows|linux')
|
||||
expect(() => parsePackageSmokeArgs(['--platform', 'windows', '--arch', 'ia32'])).toThrow('x64|arm64')
|
||||
expect(() => parsePackageSmokeArgs(['--platform', 'macos', '--package-kind', 'installer'])).toThrow('auto|dir|release')
|
||||
expect(parsePackageSmokeArgs(['--platform', 'macos']).platform).toBe('macos')
|
||||
expect(parsePackageSmokeArgs(['--platform', 'windows', '--arch', 'arm64']).arch).toBe('arm64')
|
||||
expect(parsePackageSmokeArgs(['--platform', 'macos']).packageKind).toBe('auto')
|
||||
expect(parsePackageSmokeArgs(['--platform', 'macos', '--package-kind', 'dir']).packageKind).toBe('dir')
|
||||
expect(parsePackageSmokeArgs(['--platform', 'macos', '--require-macos-gatekeeper']).requireMacosGatekeeper).toBe(true)
|
||||
@@ -301,6 +303,7 @@ describe('packaged artifact inspection', () => {
|
||||
|
||||
const report = await inspectPackagedArtifacts(rootDir, {
|
||||
platform: 'windows',
|
||||
arch: 'x64',
|
||||
packageKind: 'release',
|
||||
artifactsDir: 'desktop/build-artifacts/windows-x64',
|
||||
})
|
||||
@@ -309,6 +312,56 @@ describe('packaged artifact inspection', () => {
|
||||
expect(report.artifactsDir.endsWith('desktop/build-artifacts/windows-x64')).toBe(true)
|
||||
})
|
||||
|
||||
test('passes Windows arm64 checks only when arm64 sidecar and node-pty native module are present', async () => {
|
||||
const rootDir = createRepoRoot()
|
||||
tempDirs.push(rootDir)
|
||||
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/Claude-Code-Haha-0.3.1-arm64.exe')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/Claude-Code-Haha-0.3.1-arm64.exe.blockmap')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app-update.yml')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/src-tauri/binaries/claude-sidecar-aarch64-pc-windows-msvc.exe')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/node_modules/node-pty/package.json')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/node_modules/node-pty/prebuilds/win32-arm64/pty.node')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/latest.yml', 'path: Claude-Code-Haha-0.3.1-arm64.exe\n')
|
||||
|
||||
const report = await inspectPackagedArtifacts(rootDir, {
|
||||
platform: 'windows',
|
||||
arch: 'arm64',
|
||||
packageKind: 'release',
|
||||
artifactsDir: 'desktop/build-artifacts/windows-arm64',
|
||||
})
|
||||
|
||||
expect(report.passed).toBe(true)
|
||||
expect(report.passedChecks.some((check) => check.label === 'Windows arm64 unpacked sidecar binary')).toBe(true)
|
||||
expect(report.passedChecks.some((check) => check.label === 'Windows arm64 node-pty native module')).toBe(true)
|
||||
})
|
||||
|
||||
test('fails Windows arm64 checks when the package only contains x64 native files', async () => {
|
||||
const rootDir = createRepoRoot()
|
||||
tempDirs.push(rootDir)
|
||||
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/Claude-Code-Haha-0.3.1-arm64.exe')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/Claude-Code-Haha-0.3.1-arm64.exe.blockmap')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app-update.yml')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/src-tauri/binaries/claude-sidecar-x86_64-pc-windows-msvc.exe')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/node_modules/node-pty/package.json')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/win-unpacked/resources/app.asar.unpacked/node_modules/node-pty/prebuilds/win32-x64/pty.node')
|
||||
writeFile(rootDir, 'desktop/build-artifacts/windows-arm64/latest.yml', 'path: Claude-Code-Haha-0.3.1-arm64.exe\n')
|
||||
|
||||
const report = await inspectPackagedArtifacts(rootDir, {
|
||||
platform: 'windows',
|
||||
arch: 'arm64',
|
||||
packageKind: 'release',
|
||||
artifactsDir: 'desktop/build-artifacts/windows-arm64',
|
||||
})
|
||||
|
||||
expect(report.passed).toBe(false)
|
||||
expect(report.missingChecks.some((check) => check.label === 'Windows arm64 unpacked sidecar binary')).toBe(true)
|
||||
expect(report.missingChecks.some((check) => check.label === 'Windows arm64 node-pty native module')).toBe(true)
|
||||
})
|
||||
|
||||
test('passes Windows directory-only checks for electron-builder --dir output', async () => {
|
||||
const rootDir = createRepoRoot()
|
||||
tempDirs.push(rootDir)
|
||||
|
||||
@@ -5,6 +5,7 @@ import { spawnSync } from 'node:child_process'
|
||||
import { dirname, join, relative, resolve } from 'node:path'
|
||||
|
||||
export type PackageSmokePlatform = 'macos' | 'windows' | 'linux'
|
||||
export type PackageSmokeArch = 'x64' | 'arm64'
|
||||
export type VerificationMode = 'bundle-structure' | 'static-artifact'
|
||||
export type PackageKind = 'auto' | 'dir' | 'release'
|
||||
|
||||
@@ -15,6 +16,7 @@ type CheckRecord = {
|
||||
|
||||
type InspectOptions = {
|
||||
platform: PackageSmokePlatform
|
||||
arch?: PackageSmokeArch
|
||||
artifactsDir?: string
|
||||
requireMacosGatekeeper?: boolean
|
||||
packageKind?: PackageKind
|
||||
@@ -24,6 +26,7 @@ type InspectOptions = {
|
||||
|
||||
export type PackageSmokeArgs = {
|
||||
platform: PackageSmokePlatform
|
||||
arch?: PackageSmokeArch
|
||||
artifactsDir?: string
|
||||
requireMacosGatekeeper?: boolean
|
||||
packageKind?: PackageKind
|
||||
@@ -34,6 +37,7 @@ export type PackageSmokeReport = {
|
||||
hostPlatform: string
|
||||
productName: string
|
||||
version: string
|
||||
arch?: PackageSmokeArch
|
||||
verificationMode: VerificationMode
|
||||
packageKind: PackageKind
|
||||
artifactsDir: string
|
||||
@@ -59,7 +63,7 @@ type PackageSmokeCommandResult = {
|
||||
type PackageSmokeCommandRunner = (command: string, args: string[]) => PackageSmokeCommandResult
|
||||
|
||||
function usage() {
|
||||
return 'Usage: bun run test:package-smoke --platform <macos|windows|linux> [--package-kind <auto|dir|release>] [--artifacts-dir <path>] [--require-macos-gatekeeper]'
|
||||
return 'Usage: bun run test:package-smoke --platform <macos|windows|linux> [--arch <x64|arm64>] [--package-kind <auto|dir|release>] [--artifacts-dir <path>] [--require-macos-gatekeeper]'
|
||||
}
|
||||
|
||||
function readArgValue(argv: string[], index: number, flag: string) {
|
||||
@@ -72,6 +76,7 @@ function readArgValue(argv: string[], index: number, flag: string) {
|
||||
|
||||
export function parsePackageSmokeArgs(argv: string[]): PackageSmokeArgs {
|
||||
let platform: PackageSmokePlatform | undefined
|
||||
let arch: PackageSmokeArch | undefined
|
||||
let artifactsDir: string | undefined
|
||||
let requireMacosGatekeeper = false
|
||||
let packageKind: PackageKind = 'auto'
|
||||
@@ -89,6 +94,17 @@ export function parsePackageSmokeArgs(argv: string[]): PackageSmokeArgs {
|
||||
continue
|
||||
}
|
||||
|
||||
if (arg === '--arch') {
|
||||
const value = readArgValue(argv, index, arg)
|
||||
if (value === 'x64' || value === 'arm64') {
|
||||
arch = value
|
||||
} else {
|
||||
throw new Error(`Unsupported --arch value: ${value}. Expected x64|arm64.\n${usage()}`)
|
||||
}
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if (arg === '--artifacts-dir') {
|
||||
artifactsDir = readArgValue(argv, index, arg)
|
||||
index += 1
|
||||
@@ -118,6 +134,7 @@ export function parsePackageSmokeArgs(argv: string[]): PackageSmokeArgs {
|
||||
|
||||
return {
|
||||
platform,
|
||||
arch,
|
||||
artifactsDir,
|
||||
requireMacosGatekeeper,
|
||||
packageKind,
|
||||
@@ -429,6 +446,7 @@ function addInstalledUpdateMetadataCheck(
|
||||
function createReport(
|
||||
rootDir: string,
|
||||
platform: PackageSmokePlatform,
|
||||
arch: PackageSmokeArch | undefined,
|
||||
metadata: DesktopMetadata,
|
||||
artifactsDir: string,
|
||||
verificationMode: VerificationMode,
|
||||
@@ -440,6 +458,7 @@ function createReport(
|
||||
hostPlatform,
|
||||
productName: metadata.productName,
|
||||
version: metadata.version,
|
||||
arch,
|
||||
verificationMode,
|
||||
packageKind,
|
||||
artifactsDir,
|
||||
@@ -583,6 +602,17 @@ function inspectWindowsArtifacts(rootDir: string, report: PackageSmokeReport) {
|
||||
const resourcesDir = join(unpackedDir, 'resources')
|
||||
const unpackedResourcesDir = join(resourcesDir, 'app.asar.unpacked')
|
||||
const nodePtyDir = join(unpackedResourcesDir, 'node_modules', 'node-pty')
|
||||
const sidecarDir = join(unpackedResourcesDir, 'src-tauri', 'binaries')
|
||||
const sidecarNeedle = report.arch === 'arm64'
|
||||
? '/claude-sidecar-aarch64-pc-windows-msvc.exe'
|
||||
: report.arch === 'x64'
|
||||
? '/claude-sidecar-x86_64-pc-windows-msvc.exe'
|
||||
: '/claude-sidecar-'
|
||||
const nodePtyNeedle = report.arch === 'arm64'
|
||||
? '/win32-arm64/'
|
||||
: report.arch === 'x64'
|
||||
? '/win32-x64/'
|
||||
: '/win32-'
|
||||
addPresenceCheck(report, rootDir, 'Windows app.asar', join(resourcesDir, 'app.asar'))
|
||||
addInstalledUpdateMetadataCheck(
|
||||
report,
|
||||
@@ -595,15 +625,17 @@ function inspectWindowsArtifacts(rootDir: string, report: PackageSmokeReport) {
|
||||
addMatchCheck(
|
||||
report,
|
||||
rootDir,
|
||||
'Windows unpacked sidecar binary',
|
||||
findMatches(join(unpackedResourcesDir, 'src-tauri', 'binaries'), (candidate) => normalizePath(candidate).includes('/claude-sidecar-')),
|
||||
join(unpackedResourcesDir, 'src-tauri', 'binaries'),
|
||||
report.arch ? `Windows ${report.arch} unpacked sidecar binary` : 'Windows unpacked sidecar binary',
|
||||
findMatches(sidecarDir, (candidate) => normalizePath(candidate).includes(sidecarNeedle)),
|
||||
report.arch
|
||||
? join(sidecarDir, sidecarNeedle.slice(1))
|
||||
: sidecarDir,
|
||||
)
|
||||
addMatchCheck(
|
||||
report,
|
||||
rootDir,
|
||||
'Windows node-pty native module',
|
||||
findMatches(join(nodePtyDir, 'prebuilds'), (candidate) => normalizePath(candidate).includes('/win32-') && normalizePath(candidate).endsWith('/pty.node')),
|
||||
report.arch ? `Windows ${report.arch} node-pty native module` : 'Windows node-pty native module',
|
||||
findMatches(join(nodePtyDir, 'prebuilds'), (candidate) => normalizePath(candidate).includes(nodePtyNeedle) && normalizePath(candidate).endsWith('/pty.node')),
|
||||
join(nodePtyDir, 'prebuilds'),
|
||||
)
|
||||
} else {
|
||||
@@ -728,6 +760,7 @@ export async function inspectPackagedArtifacts(rootDir: string, options: Inspect
|
||||
const report = createReport(
|
||||
resolvedRootDir,
|
||||
options.platform,
|
||||
options.arch,
|
||||
metadata,
|
||||
artifactsDir,
|
||||
verificationMode,
|
||||
@@ -753,6 +786,9 @@ function printRecord(prefix: string, record: CheckRecord) {
|
||||
|
||||
function printReport(report: PackageSmokeReport) {
|
||||
console.log(`[package-smoke] platform=${report.platform} host=${report.hostPlatform} mode=${report.verificationMode}`)
|
||||
if (report.arch) {
|
||||
console.log(`[package-smoke] arch=${report.arch}`)
|
||||
}
|
||||
console.log(`[package-smoke] packageKind=${report.packageKind}`)
|
||||
console.log(`[package-smoke] product=${report.productName} version=${report.version}`)
|
||||
console.log(`[package-smoke] artifactsDir=${report.artifactsDir}`)
|
||||
|
||||
@@ -181,6 +181,15 @@ describe('release update metadata merge', () => {
|
||||
path: Claude-Code-Haha-0.3.2-win-x64.exe
|
||||
sha512: win-checksum
|
||||
`)
|
||||
writeYaml(join(inputDir, 'latest-Windows-ARM64.yml'), `
|
||||
version: 0.3.2
|
||||
files:
|
||||
- url: Claude-Code-Haha-0.3.2-win-arm64.exe
|
||||
sha512: win-arm64-checksum
|
||||
size: 222
|
||||
path: Claude-Code-Haha-0.3.2-win-arm64.exe
|
||||
sha512: win-arm64-checksum
|
||||
`)
|
||||
|
||||
mergeUpdateMetadataArtifacts({ metadataDir: inputDir, outDir: outputDir })
|
||||
|
||||
@@ -189,7 +198,10 @@ describe('release update metadata merge', () => {
|
||||
path: string
|
||||
sha512: string
|
||||
}
|
||||
expect(windows.files.map(file => file.url)).toEqual(['Claude-Code-Haha-0.3.2-win-x64.exe'])
|
||||
expect(windows.files.map(file => file.url)).toEqual([
|
||||
'Claude-Code-Haha-0.3.2-win-x64.exe',
|
||||
'Claude-Code-Haha-0.3.2-win-arm64.exe',
|
||||
])
|
||||
expect(windows.path).toBe('Claude-Code-Haha-0.3.2-win-x64.exe')
|
||||
expect(windows.sha512).toBe('win-checksum')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user