Skip to content

Commit 1caa3d4

Browse files
committed
🤖 fix: correctly detect signal-killed processes in isRunning()
- Check both exitCode and signalCode when determining if process is alive - Fixes terminate() always sending SIGKILL after SIGTERM, even when process already stopped (signal-killed processes have signalCode set but exitCode null) - Also gate background tools for SSH runtimes (TODO: replace duck-type check with proper capability flag once SSH implements spawnBackground)
1 parent d39f405 commit 1caa3d4

File tree

2 files changed

+10
-4
lines changed

2 files changed

+10
-4
lines changed

src/common/utils/tools/tools.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,12 @@ export async function getToolsForModel(
110110
web_fetch: wrap(createWebFetchTool(config)),
111111
};
112112

113-
// Only include background tools when manager is available
114-
// (not available in CLI/debug paths)
115-
if (config.backgroundProcessManager) {
113+
// Only include background tools when manager is available and runtime supports it
114+
// (not available in CLI/debug paths, and SSH runtimes don't support background execution yet)
115+
// TODO: Replace this duck-type check with a proper runtime.supportsBackgroundExecution capability
116+
// once SSHRuntime implements spawnBackground()
117+
const isSSHRuntime = "getConfig" in config.runtime;
118+
if (config.backgroundProcessManager && !isSSHRuntime) {
116119
runtimeTools.bash_background_read = wrap(createBashBackgroundReadTool(config));
117120
runtimeTools.bash_background_list = wrap(createBashBackgroundListTool(config));
118121
runtimeTools.bash_background_terminate = wrap(createBashBackgroundTerminateTool(config));

src/node/runtime/LocalBackgroundHandle.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ export class LocalBackgroundHandle implements BackgroundHandle {
7676
}
7777

7878
isRunning(): Promise<boolean> {
79-
return Promise.resolve(this.disposable.underlying.exitCode === null);
79+
const child = this.disposable.underlying;
80+
// Process is dead if either exitCode or signalCode is set
81+
// (signal-killed processes have signalCode set but exitCode remains null)
82+
return Promise.resolve(child.exitCode === null && child.signalCode === null);
8083
}
8184

8285
async terminate(): Promise<void> {

0 commit comments

Comments
 (0)