feat: add Windows ARM64 support with x64-baseline CLI workaround (#2537)
* feat: add Windows ARM64 support with x64-baseline CLI workaround Windows ARM64 native opencode.exe fails with a Bun FFI/TinyCC dlopen error (anomalyco/opencode#19130). As a temporary workaround: - Bundle x64-baseline OpenCode CLI on ARM64 instead of native ARM64 (prepare-opencode-cli.mjs, env-runtime.js) - Disable OpenCode self-upgrade on ARM64 in server, VS Code, and UI (upgrade-capability.js, opencode-upgrade-runtime.ts, useUIStore.ts, OpenCodeCliSettings.tsx, search.ts, SettingsView.tsx, platform.ts) - Add ARM64 Windows cross-compile builds to release and smoke workflows (release.yml, release-desktop-smoke.yml) - Refactor Windows latest.yml to use combine-electron-manifests pattern matching macOS, since two arches now produce per-arch manifests The CI ARM64 build itself is permanent; only the x64-baseline CLI bundling and upgrade disablement are temporary and should be reverted when the upstream issue is resolved. * fix(desktop): select Windows updater by architecture --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Bohdan Triapitsyn
parent
5792a3d2e2
commit
09f0c64839
@@ -76,14 +76,11 @@ const output = {};
|
||||
|
||||
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,
|
||||
});
|
||||
if (!winX64 || !winArm64) {
|
||||
throw new Error('Both x64 and arm64 Windows update manifests are required');
|
||||
}
|
||||
output['latest.yml'] = serialize(winX64);
|
||||
output['latest-arm64.yml'] = serialize(winArm64);
|
||||
|
||||
const macX64 = await read('latest-yml-x86_64-apple-darwin', 'latest-mac.yml');
|
||||
const macArm64 = await read('latest-yml-aarch64-apple-darwin', 'latest-mac.yml');
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync, spawnSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const script = fileURLToPath(new URL('./finalize-latest-yml.mjs', import.meta.url));
|
||||
|
||||
const manifest = (architecture) => `version: 1.2.3
|
||||
files:
|
||||
- url: OpenChamber-1.2.3-win-${architecture}.exe
|
||||
sha512: ${architecture}-checksum
|
||||
size: 123
|
||||
releaseDate: '2026-07-30T00:00:00.000Z'
|
||||
`;
|
||||
|
||||
const createFixture = ({ includeArm64 = true } = {}) => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-latest-yml-'));
|
||||
const artifacts = path.join(root, 'artifacts');
|
||||
const output = path.join(root, 'output');
|
||||
fs.mkdirSync(path.join(artifacts, 'latest-yml-x86_64-pc-windows-msvc'), { recursive: true });
|
||||
fs.writeFileSync(path.join(artifacts, 'latest-yml-x86_64-pc-windows-msvc', 'latest.yml'), manifest('x64'));
|
||||
if (includeArm64) {
|
||||
fs.mkdirSync(path.join(artifacts, 'latest-yml-aarch64-pc-windows-msvc'), { recursive: true });
|
||||
fs.writeFileSync(path.join(artifacts, 'latest-yml-aarch64-pc-windows-msvc', 'latest.yml'), manifest('arm64'));
|
||||
}
|
||||
fs.mkdirSync(output);
|
||||
return { root, artifacts, output };
|
||||
};
|
||||
|
||||
const environment = ({ artifacts, output }) => ({
|
||||
...process.env,
|
||||
LATEST_YML_DIR: artifacts,
|
||||
RUNNER_TEMP: output,
|
||||
GH_REPO: 'openchamber/openchamber',
|
||||
OPENCHAMBER_VERSION: '1.2.3',
|
||||
});
|
||||
|
||||
test('writes separate x64 and ARM64 Windows update channels', (context) => {
|
||||
const fixture = createFixture();
|
||||
context.after(() => fs.rmSync(fixture.root, { recursive: true, force: true }));
|
||||
|
||||
execFileSync(process.execPath, [script], { env: environment(fixture) });
|
||||
|
||||
const x64 = fs.readFileSync(path.join(fixture.output, 'latest.yml'), 'utf8');
|
||||
const arm64 = fs.readFileSync(path.join(fixture.output, 'latest-arm64.yml'), 'utf8');
|
||||
assert.match(x64, /win-x64\.exe/);
|
||||
assert.doesNotMatch(x64, /win-arm64\.exe/);
|
||||
assert.match(arm64, /win-arm64\.exe/);
|
||||
assert.doesNotMatch(arm64, /win-x64\.exe/);
|
||||
});
|
||||
|
||||
test('fails instead of publishing an incomplete Windows channel set', (context) => {
|
||||
const fixture = createFixture({ includeArm64: false });
|
||||
context.after(() => fs.rmSync(fixture.root, { recursive: true, force: true }));
|
||||
|
||||
const result = spawnSync(process.execPath, [script], { env: environment(fixture), encoding: 'utf8' });
|
||||
|
||||
assert.notEqual(result.status, 0);
|
||||
assert.match(result.stderr, /Both x64 and arm64 Windows update manifests are required/);
|
||||
});
|
||||
@@ -47,7 +47,17 @@ const artifactForPlatform = (platform, targetArchitecture) => {
|
||||
if (arch === 'x64') return { name: 'opencode-darwin-x64-baseline.zip', binary: 'opencode' };
|
||||
}
|
||||
if (platform === 'win32') {
|
||||
if (arch === 'arm64') return { name: 'opencode-windows-arm64.zip', binary: 'opencode.exe' };
|
||||
// TEMPORARY WORKAROUND — Windows ARM64: native opencode.exe fails with a Bun
|
||||
// FFI/TinyCC dlopen error (https://github.com/anomalyco/opencode/issues/19130).
|
||||
// Bundle x64-baseline instead (runs under x64 emulation); OpenCode self-upgrade
|
||||
// is disabled elsewhere so it can't overwrite with the broken ARM64 build.
|
||||
// Remove this block and restore the original below when the upstream issue
|
||||
// is resolved.
|
||||
// --- ORIGINAL (restore when ARM64 is fixed) ---
|
||||
// if (arch === 'arm64') return { name: 'opencode-windows-arm64.zip', binary: 'opencode.exe' };
|
||||
// if (arch === 'x64') return { name: 'opencode-windows-x64-baseline.zip', binary: 'opencode.exe' };
|
||||
// --- END ORIGINAL ---
|
||||
if (arch === 'arm64') return { name: 'opencode-windows-x64-baseline.zip', binary: 'opencode.exe' };
|
||||
if (arch === 'x64') return { name: 'opencode-windows-x64-baseline.zip', binary: 'opencode.exe' };
|
||||
}
|
||||
if (platform === 'linux') {
|
||||
|
||||
Reference in New Issue
Block a user