fix(background-agent): prevent zombie processes by aborting sessions on shutdown (#1240) (#1243)

- BackgroundManager.shutdown() now aborts all running child sessions via
  client.session.abort() before clearing state, preventing orphaned
  opencode processes when parent exits
- Add onShutdown callback to BackgroundManager constructor, used to
  trigger TmuxSessionManager.cleanup() on process exit signals
- Interactive bash session hook now aborts tracked subagent opencode
  sessions when killing tmux sessions (defense-in-depth)
- Add 4 tests verifying shutdown abort behavior and callback invocation

Closes #1240
This commit is contained in:
YeonGyu-Kim
2026-01-29 18:29:47 +09:00
committed by GitHub
parent 6d50fbe563
commit b4973954e3
4 changed files with 194 additions and 2 deletions
+6 -1
View File
@@ -6,6 +6,7 @@ import {
} from "./storage";
import { OMO_SESSION_PREFIX, buildSessionReminderMessage } from "./constants";
import type { InteractiveBashSessionState } from "./types";
import { subagentSessions } from "../../features/claude-code-session-state";
interface ToolExecuteInput {
tool: string;
@@ -146,7 +147,7 @@ function findSubcommand(tokens: string[]): string {
return ""
}
export function createInteractiveBashSessionHook(_ctx: PluginInput) {
export function createInteractiveBashSessionHook(ctx: PluginInput) {
const sessionStates = new Map<string, InteractiveBashSessionState>();
function getOrCreateState(sessionID: string): InteractiveBashSessionState {
@@ -178,6 +179,10 @@ export function createInteractiveBashSessionHook(_ctx: PluginInput) {
await proc.exited;
} catch {}
}
for (const sessionId of subagentSessions) {
ctx.client.session.abort({ path: { id: sessionId } }).catch(() => {})
}
}
const toolExecuteAfter = async (