fix(#3086): apply #2667 .cmd-shim gate to deps.spawn + surface errorCode in review lanes (#3142)

* fix(#3086): apply #2667 .cmd-shim gate to deps.spawn + surface errorCode in review lanes

deps.spawn used shell:false with a bare binary name — on Windows, npm-installed
CLIs (gemini, codex, etc.) are .cmd shims that CreateProcess cannot start,
producing ENOENT + empty stderr. The review path then wrote an empty err file
and emitted a generic 'failed or returned empty output' stub.

Two fixes:
1. deps.spawn: detect .cmd/.bat on win32 and mediate through cmd.exe /d /s /c
   (same gate as runWithTimeout #2667, same explicit argv array).
2. runSpawnLane: surface errorCode (ENOENT, ETIMEDOUT) in the err file so the
   stub explains WHY the lane produced nothing.

* chore(#3086): backfill changeset PR number 3142

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-07 07:43:14 -04:00
committed by GitHub
parent 7ab4556395
commit 4b66bf4560
4 changed files with 63 additions and 2 deletions

View File

@@ -664,7 +664,13 @@ function runSpawnLane(plan: SpawnPlan, deps: RunnerDeps, repoRoot: string): Lane
: plan.argv;
const out = deps.spawn(plan.binary, argv, { input, timeoutMs: plan.timeoutMs });
deps.writeFile(plan.errPath, out.stderr ?? '');
// #3086: surface spawn errors (ENOENT, ETIMEDOUT, etc.) that would otherwise
// be silently dropped — the review path read only stdout/stderr and treated
// an empty-stderr spawn failure as "the model had nothing to say".
const errContent = out.errorCode
? `${out.stderr ?? ''}\n[spawn error: ${out.errorCode}]\n`
: (out.stderr ?? '');
deps.writeFile(plan.errPath, errContent);
// `file-arg` lanes write the review themselves and their stdout is deliberately discarded (#1698).
let review =