mirror of https://github.com/garrytan/gstack.git
fix: exec gstack-brain-sync through bash on Windows
The #1731 fix gated the brain-sync spawns behind `shell: NEEDS_SHELL_ON_WINDOWS`, but that routes through cmd.exe, which cannot execute an extensionless bash shebang script. Every /sync-gbrain run on Windows errored with "'gstack-brain-sync' is not recognized as an internal or external command" and the stage reported "brain-sync exited 1". Invoke the script through bash explicitly on Windows (Git Bash ships with git, a hard gstack dependency); POSIX keeps the direct shebang exec. Also surface spawn errors (e.g. bash missing from PATH) in the stage summary instead of a bare exit code, and update the #1731 tripwire test to pin the new invariant: brain-sync spawns must exec bash, not rely on shell:true. Observed on Windows 11, bun 1.3.14. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a3259400a3
commit
e525385298
|
|
@ -1145,25 +1145,35 @@ function runBrainSyncPush(args: CliArgs): StageResult {
|
|||
return { name: "brain-sync", ran: false, ok: true, duration_ms: 0, summary: "skipped (gstack-brain-sync not installed)" };
|
||||
}
|
||||
|
||||
// #1731: gstack-brain-sync is a bash shebang script; Windows can't spawn it
|
||||
// without a shell, which surfaced as "brain-sync exited undefined".
|
||||
spawnSync(brainSyncPath, ["--discover-new"], {
|
||||
stdio: args.quiet ? ["ignore", "ignore", "ignore"] : ["ignore", "inherit", "inherit"],
|
||||
timeout: 60 * 1000,
|
||||
shell: NEEDS_SHELL_ON_WINDOWS,
|
||||
});
|
||||
const result = spawnSync(brainSyncPath, ["--once"], {
|
||||
stdio: args.quiet ? ["ignore", "ignore", "ignore"] : ["ignore", "inherit", "inherit"],
|
||||
timeout: 60 * 1000,
|
||||
shell: NEEDS_SHELL_ON_WINDOWS,
|
||||
});
|
||||
// #1731 gated these spawns behind `shell: NEEDS_SHELL_ON_WINDOWS`, but
|
||||
// cmd.exe cannot execute an extensionless bash shebang script either — the
|
||||
// stage errored "'gstack-brain-sync' is not recognized as an internal or
|
||||
// external command". Invoke the script through bash explicitly on Windows
|
||||
// (Git Bash ships with git, a hard gstack dependency); POSIX keeps the
|
||||
// direct shebang exec.
|
||||
const runBrainSync = (flag: string) =>
|
||||
spawnSync(
|
||||
NEEDS_SHELL_ON_WINDOWS ? "bash" : brainSyncPath,
|
||||
NEEDS_SHELL_ON_WINDOWS ? [brainSyncPath, flag] : [flag],
|
||||
{
|
||||
stdio: args.quiet ? ["ignore", "ignore", "ignore"] : ["ignore", "inherit", "inherit"],
|
||||
timeout: 60 * 1000,
|
||||
},
|
||||
);
|
||||
runBrainSync("--discover-new");
|
||||
const result = runBrainSync("--once");
|
||||
|
||||
return {
|
||||
name: "brain-sync",
|
||||
ran: true,
|
||||
ok: result.status === 0,
|
||||
duration_ms: Date.now() - t0,
|
||||
summary: result.status === 0 ? "curated artifacts pushed" : `gstack-brain-sync exited ${result.status}`,
|
||||
summary:
|
||||
result.status === 0
|
||||
? "curated artifacts pushed"
|
||||
: result.error
|
||||
? `gstack-brain-sync spawn failed (${result.error.message})`
|
||||
: `gstack-brain-sync exited ${result.status}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,12 +34,14 @@ describe("#1731 gbrain spawns carry the Windows shell flag", () => {
|
|||
});
|
||||
}
|
||||
|
||||
test("orchestrator brain-sync spawns carry the Windows shell flag", () => {
|
||||
test("orchestrator brain-sync spawns route through bash on Windows", () => {
|
||||
const src = read("bin/gstack-gbrain-sync.ts");
|
||||
const brainSyncSpawns = src.match(/spawnSync\(brainSyncPath,/g)?.length ?? 0;
|
||||
expect(brainSyncSpawns).toBe(2);
|
||||
// Both spawnSync(brainSyncPath, ...) blocks must include the shell flag.
|
||||
const withShell = src.match(/spawnSync\(brainSyncPath,[\s\S]*?shell:\s*NEEDS_SHELL_ON_WINDOWS/g)?.length ?? 0;
|
||||
expect(withShell).toBe(2);
|
||||
// cmd.exe (shell: true) cannot execute an extensionless bash shebang
|
||||
// script, so the brain-sync invocations must exec bash explicitly on
|
||||
// Windows instead of relying on the shell flag.
|
||||
expect(src).toMatch(/NEEDS_SHELL_ON_WINDOWS \? "bash" : brainSyncPath/);
|
||||
expect(src).toMatch(/NEEDS_SHELL_ON_WINDOWS \? \[brainSyncPath, flag\] : \[flag\]/);
|
||||
// And no brain-sync spawn may still route through cmd via shell:true.
|
||||
expect(src).not.toMatch(/spawnSync\(brainSyncPath,[\s\S]{0,300}?shell:\s*NEEDS_SHELL_ON_WINDOWS/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue