npm shims exit 0 when mirrored child signal is re-caught by the parent
What happened?
The npm JavaScript shims for codex and codex-responses-api-proxy try to mirror a native child process termination signal by calling process.kill(process.pid, childResult.signal) after the child exits due to a signal.
However, the same process still has signal forwarding handlers installed for SIGINT, SIGTERM, and SIGHUP. When the parent sends the signal to itself, its own handler catches that signal and forwards it to the already-exited child instead of letting Node terminate with signal semantics. The parent can then fall off the end of the module and exit successfully.
Reproduction
A minimal reproduction of the current signal-mirroring pattern exits with status 0 after the child exits from SIGTERM:
node --input-type=module -e 'import { spawn } from "node:child_process"; const child = spawn(process.execPath, ["-e", "setTimeout(()=>{}, 10000)"]); const forwardSignal = (signal) => { if (!child.killed) child.kill(signal); }; ["SIGINT", "SIGTERM", "SIGHUP"].forEach((sig) => process.on(sig, () => forwardSignal(sig))); child.kill("SIGTERM"); const childResult = await new Promise((resolve) => child.on("exit", (code, signal) => resolve(signal ? { type: "signal", signal } : { type: "code", exitCode: code ?? 1 }))); if (childResult.type === "signal") process.kill(process.pid, childResult.signal); else process.exit(childResult.exitCode);'; echo $?
Observed: 0
Expected behavior
If the native child exits because of SIGTERM, SIGINT, or SIGHUP, the npm shim parent should also terminate from the same signal so shell scripts and supervisors observe the correct signal/exit semantics.
Proposed fix
Store the installed signal handlers and remove them immediately before re-emitting the child's signal to the parent process. I have a local patch that applies this to both npm shims and adds a Node built-in test that creates temporary fake native binaries and asserts that the parent process exits with signal === "SIGTERM".
Local validation performed:
pnpm test:node-shims
node --check tests/node_shim_signals.test.js
node --check codex-cli/bin/codex.js
node --check codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js
pnpm dlx prettier@3.5.3 --check package.json codex-cli/bin/codex.js codex-rs/responses-api-proxy/npm/bin/codex-responses-api-proxy.js tests/node_shim_signals.test.js
git diff --check
I noticed the repository currently accepts external code PRs by invitation only, so I am filing this issue first per docs/contributing.md.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗