mirror of
https://github.com/JuliusBrussee/caveman.git
synced 2026-09-14 18:02:35 +08:00
7a03e6ffbc
pi-enable and pi-wrap could not join the Windows gate: their fixtures built PATH with `:` and wrote extensionless `#!/bin/sh` stubs, which Windows cannot execute at all. tests/harness/stub-bin.mjs gives them two stub shapes, one per way the CLI launches things — a .cmd Node shim for commands routed through portableInvocation (`pi`), and, for the Go binaries the CLI execFile's directly, a real .exe: node.exe hardlinked under the binary's name, answering from a --require preload that runs before Node resolves argv[1] as a script. A .cmd cannot serve there, since Node refuses to spawn one without a shell (CVE-2024-27980). Both fixtures also set USERPROFILE beside HOME — os.homedir() reads it on Windows, and the Pi extension directory hangs off it — and retry cleanup for handles Windows still holds. update.runtime.mjs stays out, and not for a harness reason: its committed checksum manifest carries only darwin and linux artifacts, so on win32 `update` looks up caveman-proxy_win32_amd64 and fails before downloading anything. Adding those rows needs the release signing key; the regeneration recipe is recorded at the fixture read. The macOS job also runs `go test ./engine/... ./proxy/... ./shared/...` — without it the runner touched no Go at all, so a BSD-only path, spawn or timer regression shipped green on the platform this job exists to cover. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SqmbqWDtNexzDfH5V3BMRz
77 lines
3.0 KiB
JavaScript
77 lines
3.0 KiB
JavaScript
#!/usr/bin/env node
|
|
import { mkdirSync } from "node:fs";
|
|
import { createRequire } from "node:module";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const require = createRequire(import.meta.url);
|
|
const { portableInvocation } = require(join(root, "bin", "lib", "portable-process.js"));
|
|
const goCache = join(tmpdir(), "caveman-windows-go-cache");
|
|
mkdirSync(goCache, { recursive: true });
|
|
|
|
function run(label, command, args, options = {}) {
|
|
process.stderr.write(`\n[windows-compat] ${label}\n`);
|
|
const result = spawnSync(command, args, {
|
|
cwd: root,
|
|
stdio: "inherit",
|
|
...options,
|
|
});
|
|
if (result.error) throw result.error;
|
|
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
}
|
|
|
|
function runPnpm(label, args) {
|
|
const invocation = portableInvocation("pnpm", args);
|
|
run(label, invocation.command, invocation.args);
|
|
}
|
|
|
|
runPnpm("build CLI", ["--dir", "packages/cli", "build"]);
|
|
runPnpm("build agent", ["--dir", "packages/agent", "build"]);
|
|
run("Node Windows contracts", process.execPath, [
|
|
"--test",
|
|
"--test-force-exit",
|
|
"packages/cli/tests/windows-platform.runtime.mjs",
|
|
"packages/cli/tests/portable-command.runtime.mjs",
|
|
"packages/cli/tests/delegate-windows.runtime.mjs",
|
|
// Full CLI round trips, not unit contracts: both spawn the built CLI against
|
|
// stub binaries (tests/harness/stub-bin.mjs) that are real .exe/.cmd on
|
|
// Windows, so `enable pi` and `wrap pi` are exercised end to end there.
|
|
"packages/cli/tests/pi-enable.runtime.mjs",
|
|
"packages/cli/tests/pi-wrap.runtime.mjs",
|
|
"tests/installer/binary-installer-platform.test.mjs",
|
|
"tests/installer/release-binaries.test.mjs",
|
|
"tests/installer/windows-source-install.test.mjs",
|
|
"tests/installer/portable-process.test.mjs",
|
|
"tests/installer/mcp-shrink-windows.test.mjs",
|
|
"packages/subagent-tax/tests/process-tree.test.mjs",
|
|
"packages/agent/tests/windows-process.runtime.mjs",
|
|
"packages/agent/tests/windows-shell-smoke.runtime.mjs",
|
|
]);
|
|
|
|
const baseGoEnv = {
|
|
...process.env,
|
|
CGO_ENABLED: "0",
|
|
GOOS: "windows",
|
|
GOCACHE: goCache,
|
|
GOTMPDIR: tmpdir(),
|
|
};
|
|
const hostGoArch = { x64: "amd64", arm64: "arm64" }[process.arch];
|
|
for (const arch of ["amd64", "arm64"]) {
|
|
const args = ["test", "-count=1", "-run", "^$"];
|
|
// Compiled test binaries only execute when host OS and arch both match;
|
|
// everywhere else a no-op -exec keeps this a pure compile check (a Windows
|
|
// amd64 runner cannot execute the arm64 binaries).
|
|
if (process.platform !== "win32") {
|
|
args.push("-exec", process.platform === "darwin" ? "/usr/bin/true" : "/bin/true");
|
|
} else if (arch !== hostGoArch) {
|
|
args.push("-exec", "cmd /c exit 0");
|
|
}
|
|
args.push("./...");
|
|
run(`Go Windows/${arch} compile`, "go", args, { env: { ...baseGoEnv, GOARCH: arch } });
|
|
}
|
|
|
|
process.stdout.write("windows compatibility gate passed\n");
|