From a60066df822df818bd0950afb0a9917a42b75bc8 Mon Sep 17 00:00:00 2001 From: Felix Berlakovich Date: Tue, 13 Jan 2026 11:12:43 +0100 Subject: [PATCH 1/2] fix: forward signals to child process in binary launcher --- scripts/claude_version_utils.cjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/claude_version_utils.cjs b/scripts/claude_version_utils.cjs index 2184917a..1a6b6380 100644 --- a/scripts/claude_version_utils.cjs +++ b/scripts/claude_version_utils.cjs @@ -497,6 +497,18 @@ function runClaudeCli(cliPath) { stdio: 'inherit', env: process.env }); + + // Forward signals to child process so it gets killed when parent is killed + // This prevents orphaned Claude processes when switching between local/remote modes + const forwardSignal = (signal) => { + if (child.pid && !child.killed) { + child.kill(signal); + } + }; + process.on('SIGTERM', () => forwardSignal('SIGTERM')); + process.on('SIGINT', () => forwardSignal('SIGINT')); + process.on('SIGHUP', () => forwardSignal('SIGHUP')); + child.on('exit', (code) => { process.exit(code || 0); }); From c7a1f6e2236566001c689f414de992c15f995e87 Mon Sep 17 00:00:00 2001 From: Felix Berlakovich Date: Mon, 19 Jan 2026 10:02:10 +0100 Subject: [PATCH 2/2] Add signal forwarding to claudeLocal.ts --- src/claude/claudeLocal.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/claude/claudeLocal.ts b/src/claude/claudeLocal.ts index d4f7ac0b..1ef8b971 100644 --- a/src/claude/claudeLocal.ts +++ b/src/claude/claudeLocal.ts @@ -232,6 +232,28 @@ export async function claudeLocal(opts: { env, }); + // Forward signals to child process to prevent orphaned processes + // Note: signal: opts.abort handles programmatic abort (mode switching), + // but direct OS signals (e.g., kill, Ctrl+C) need explicit forwarding + const forwardSignal = (signal: NodeJS.Signals) => { + if (child.pid && !child.killed) { + child.kill(signal); + } + }; + const onSigterm = () => forwardSignal('SIGTERM'); + const onSigint = () => forwardSignal('SIGINT'); + const onSighup = () => forwardSignal('SIGHUP'); + process.on('SIGTERM', onSigterm); + process.on('SIGINT', onSigint); + process.on('SIGHUP', onSighup); + + // Cleanup signal handlers when child exits to avoid leaks + child.on('exit', () => { + process.off('SIGTERM', onSigterm); + process.off('SIGINT', onSigint); + process.off('SIGHUP', onSighup); + }); + // Listen to the custom fd (fd 3) for thinking state tracking if (child.stdio[3]) { const rl = createInterface({