Merge pull request 'fix(bridge): strip NODE_OPTIONS --inspect before spawning claude/gemini' (#5) from fix/strip-inspect-from-spawn-env into main

This commit was merged in pull request #5.
This commit is contained in:
h z
2026-05-31 20:04:54 +00:00
2 changed files with 35 additions and 2 deletions

View File

@@ -158,10 +158,29 @@ export async function* dispatchToClaude(
// detached:true puts claude in its own process group. Claude's Bash tool // detached:true puts claude in its own process group. Claude's Bash tool
// occasionally leaks shells/ssh that keep claude alive past end-of-turn; when // occasionally leaks shells/ssh that keep claude alive past end-of-turn; when
// that happens we SIGKILL the whole group rather than wait forever. // that happens we SIGKILL the whole group rather than wait forever.
// Sanitize NODE_OPTIONS before spawning. Claude Code is a Node CLI; if
// the parent gateway runs with `NODE_OPTIONS=--inspect=...:9229`, every
// child Node process — including claude — tries to bind the same inspector
// port, fails (EADDRINUSE), and exits SILENTLY (no stdout, no stderr).
// Bridge then sees an empty stream and reports `claude did not return a
// session_id` with no useful diagnostic. Strip any --inspect* /
// --inspect-brk* / --debug* flag from NODE_OPTIONS; keep everything else
// (e.g. --max-old-space-size) in case operators depend on it.
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("claude", args, { const child = spawn("claude", args, {
cwd: workspace, cwd: workspace,
stdio: ["ignore", "pipe", "pipe"], stdio: ["ignore", "pipe", "pipe"],
env: { ...process.env }, env: childEnv,
detached: true, detached: true,
}); });

View File

@@ -156,10 +156,24 @@ export async function* dispatchToGemini(
args.push("--resume", resumeSessionId); 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, { const child = spawn("gemini", args, {
cwd: workspace, cwd: workspace,
stdio: ["ignore", "pipe", "pipe"], stdio: ["ignore", "pipe", "pipe"],
env: { ...process.env }, env: childEnv,
}); });
const stderrLines: string[] = []; const stderrLines: string[] = [];