fix(bridge): strip NODE_OPTIONS --inspect before spawning claude/gemini

claude-code and gemini-cli are both Node binaries. When the parent
gateway is launched with `NODE_OPTIONS=--inspect=127.0.0.1:9229` (for
debugging), spawn(child).env = {...process.env} propagates the flag into
the child. The child Node then tries to bind the same inspector port,
fails EADDRINUSE, and exits SILENTLY (no stdout, no stderr).

Bridge sees an empty stream and reports `claude did not return a
session_id` with an empty stderr summary — extremely opaque diagnostic
that took non-trivial digging to root-cause.

Sanitize NODE_OPTIONS before spawn: keep everything except
`--inspect*` / `--inspect-brk*` / `--debug*`. Operators that legitimately
need other NODE_OPTIONS values (e.g. `--max-old-space-size`) keep them.

Verified end-user repro on prod-t2 2026-05-31: with
`Environment=NODE_OPTIONS=--inspect=127.0.0.1:9229` in the gateway
systemd drop-in, `claude -p "hi" --output-format stream-json --verbose`
spawned from the bridge returned ZERO bytes; running the exact same
command from a shell without the env var returned the full init →
assistant → result stream in ~6s. Surfaced recruiting developer1
(Cody, contractor-claude-bridge).
This commit is contained in:
h z
2026-05-31 21:04:53 +01:00
parent 689e3da0ba
commit d381c486ab
2 changed files with 35 additions and 2 deletions

View File

@@ -156,10 +156,24 @@ export async function* dispatchToGemini(
args.push("--resume", resumeSessionId);
}
// Sanitize NODE_OPTIONS before spawning — same reason as the claude
// adapter: gemini-cli is a Node binary; inheriting a parent
// `NODE_OPTIONS=--inspect=...:9229` makes every child silently EADDRINUSE.
const childEnv: NodeJS.ProcessEnv = { ...process.env };
if (childEnv.NODE_OPTIONS) {
const filtered = childEnv.NODE_OPTIONS
.split(/\s+/)
.filter((tok) => tok && !tok.startsWith("--inspect") && !tok.startsWith("--debug"))
.join(" ")
.trim();
if (filtered) childEnv.NODE_OPTIONS = filtered;
else delete childEnv.NODE_OPTIONS;
}
const child = spawn("gemini", args, {
cwd: workspace,
stdio: ["ignore", "pipe", "pipe"],
env: { ...process.env },
env: childEnv,
});
const stderrLines: string[] = [];