diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0dbd04f8215..f21513c86a3 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -115,6 +115,8 @@ jobs: target: x86_64-apple-darwin - host: macos-latest target: aarch64-apple-darwin + - host: blacksmith-4vcpu-windows-2025 + target: aarch64-pc-windows-msvc - host: blacksmith-4vcpu-windows-2025 target: x86_64-pc-windows-msvc - host: blacksmith-4vcpu-ubuntu-2404 @@ -212,6 +214,27 @@ jobs: opencode-app-id: ${{ vars.OPENCODE_APP_ID }} opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }} + - name: Setup Windows ARM64 clang + if: runner.os == 'Windows' && matrix.settings.target == 'aarch64-pc-windows-msvc' + shell: pwsh + run: | + $vswhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer\vswhere.exe" + if (!(Test-Path $vswhere)) { throw "vswhere.exe not found at $vswhere" } + $root = & $vswhere -latest -products * -property installationPath + if (!$root) { throw "Visual Studio installation not found" } + $llvm = Join-Path $root "VC\Tools\Llvm" + $bin = @( + (Join-Path $llvm "x64\bin"), + (Join-Path $llvm "bin") + ) | Where-Object { Test-Path (Join-Path $_ "clang.exe") } | Select-Object -First 1 + if (!$bin -and (Test-Path $llvm)) { + $bin = Get-ChildItem -Path $llvm -Filter clang.exe -Recurse -File | Select-Object -First 1 | ForEach-Object { $_.DirectoryName } + } + if (!$bin) { throw "clang.exe not found under $llvm" } + $env:PATH = "$bin;$env:PATH" + Add-Content -Path $env:GITHUB_PATH -Value $bin + clang --version + - name: Build and upload artifacts uses: tauri-apps/tauri-action@390cbe447412ced1303d35abe75287949e43437a timeout-minutes: 60 @@ -254,6 +277,9 @@ jobs: - host: macos-latest target: aarch64-apple-darwin platform_flag: --mac --arm64 + - host: "blacksmith-4vcpu-windows-2025" + target: aarch64-pc-windows-msvc + platform_flag: --win --arm64 - host: "blacksmith-4vcpu-windows-2025" target: x86_64-pc-windows-msvc platform_flag: --win diff --git a/packages/desktop-electron/scripts/finalize-latest-yml.ts b/packages/desktop-electron/scripts/finalize-latest-yml.ts index 42ec23b642c..aa2ae5c96e6 100644 --- a/packages/desktop-electron/scripts/finalize-latest-yml.ts +++ b/packages/desktop-electron/scripts/finalize-latest-yml.ts @@ -78,9 +78,17 @@ async function read(subdir: string, filename: string): Promise = {} -// Windows: single arch, pass through -const win = await read("latest-yml-x86_64-pc-windows-msvc", "latest.yml") -if (win) output["latest.yml"] = serialize(win) +// Windows: merge arm64 + x64 into single file +const winX64 = await read("latest-yml-x86_64-pc-windows-msvc", "latest.yml") +const winArm64 = await read("latest-yml-aarch64-pc-windows-msvc", "latest.yml") +if (winX64 || winArm64) { + const base = winArm64 ?? winX64! + output["latest.yml"] = serialize({ + version: base.version, + files: [...(winArm64?.files ?? []), ...(winX64?.files ?? [])], + releaseDate: base.releaseDate, + }) +} // Linux x64: pass through const linuxX64 = await read("latest-yml-x86_64-unknown-linux-gnu", "latest-linux.yml") diff --git a/packages/desktop-electron/scripts/utils.ts b/packages/desktop-electron/scripts/utils.ts index 4c9af1fc7ed..1c0add87d30 100644 --- a/packages/desktop-electron/scripts/utils.ts +++ b/packages/desktop-electron/scripts/utils.ts @@ -19,6 +19,11 @@ export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; ass ocBinary: "opencode-darwin-x64-baseline", assetExt: "zip", }, + { + rustTarget: "aarch64-pc-windows-msvc", + ocBinary: "opencode-windows-arm64", + assetExt: "zip", + }, { rustTarget: "x86_64-pc-windows-msvc", ocBinary: "opencode-windows-x64-baseline", @@ -41,7 +46,7 @@ export const RUST_TARGET = Bun.env.RUST_TARGET function nativeTarget() { const { platform, arch } = process if (platform === "darwin") return arch === "arm64" ? "aarch64-apple-darwin" : "x86_64-apple-darwin" - if (platform === "win32") return "x86_64-pc-windows-msvc" + if (platform === "win32") return arch === "arm64" ? "aarch64-pc-windows-msvc" : "x86_64-pc-windows-msvc" if (platform === "linux") return arch === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu" throw new Error(`Unsupported platform: ${platform}/${arch}`) } diff --git a/packages/desktop/scripts/finalize-latest-json.ts b/packages/desktop/scripts/finalize-latest-json.ts index 5445e0640d0..a2b95d2c477 100644 --- a/packages/desktop/scripts/finalize-latest-json.ts +++ b/packages/desktop/scripts/finalize-latest-json.ts @@ -101,6 +101,7 @@ const targets = [ { key: "linux-x86_64-rpm", asset: "opencode-desktop-linux-x86_64.rpm" }, { key: "linux-aarch64-deb", asset: "opencode-desktop-linux-arm64.deb" }, { key: "linux-aarch64-rpm", asset: "opencode-desktop-linux-aarch64.rpm" }, + { key: "windows-aarch64-nsis", asset: "opencode-desktop-windows-arm64.exe" }, { key: "windows-x86_64-nsis", asset: "opencode-desktop-windows-x64.exe" }, { key: "darwin-x86_64-app", asset: "opencode-desktop-darwin-x64.app.tar.gz" }, { @@ -129,6 +130,7 @@ const alias = (key: string, source: string) => { alias("linux-x86_64", "linux-x86_64-deb") alias("linux-aarch64", "linux-aarch64-deb") +alias("windows-aarch64", "windows-aarch64-nsis") alias("windows-x86_64", "windows-x86_64-nsis") alias("darwin-x86_64", "darwin-x86_64-app") alias("darwin-aarch64", "darwin-aarch64-app") diff --git a/packages/desktop/scripts/utils.ts b/packages/desktop/scripts/utils.ts index 2629eb466c0..06ff25946ea 100644 --- a/packages/desktop/scripts/utils.ts +++ b/packages/desktop/scripts/utils.ts @@ -11,6 +11,11 @@ export const SIDECAR_BINARIES: Array<{ rustTarget: string; ocBinary: string; ass ocBinary: "opencode-darwin-x64-baseline", assetExt: "zip", }, + { + rustTarget: "aarch64-pc-windows-msvc", + ocBinary: "opencode-windows-arm64", + assetExt: "zip", + }, { rustTarget: "x86_64-pc-windows-msvc", ocBinary: "opencode-windows-x64-baseline", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index fde3ace92f1..cb915ba2639 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -35,6 +35,7 @@ "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1", "@standard-schema/spec": "1.0.0", "@tsconfig/bun": "catalog:", diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 34e80d71a08..89dba960395 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -108,6 +108,10 @@ const allTargets: { arch: "x64", avx2: false, }, + { + os: "win32", + arch: "arm64", + }, { os: "win32", arch: "x64", diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index 09fef453c9a..2914568a43c 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -100,6 +100,7 @@ export namespace Ripgrep { }, "x64-darwin": { platform: "x86_64-apple-darwin", extension: "tar.gz" }, "x64-linux": { platform: "x86_64-unknown-linux-musl", extension: "tar.gz" }, + "arm64-win32": { platform: "aarch64-pc-windows-msvc", extension: "zip" }, "x64-win32": { platform: "x86_64-pc-windows-msvc", extension: "zip" }, } as const