fix(tmux): use KillSessionWithProcesses to prevent zombie bash processes

When Claude sessions were terminated using KillSession(), bash subprocesses
spawned by Claude's Bash tool could survive because they ignore SIGHUP.
This caused zombie processes to accumulate over time.

Changed all critical session termination paths to use KillSessionWithProcesses()
which explicitly kills all descendant processes before terminating the session.

Fixes: gt-ew3tk

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
slit
2026-01-20 20:37:34 -08:00
committed by beads/crew/emma
parent 78ca8bd5bf
commit 9caf5302d4
18 changed files with 66 additions and 39 deletions

View File

@@ -470,8 +470,9 @@ func (m *Manager) Start(name string, opts StartOptions) error {
}
if running {
if opts.KillExisting {
// Restart mode - kill existing session
if err := t.KillSession(sessionID); err != nil {
// Restart mode - kill existing session.
// Use KillSessionWithProcesses to ensure all descendant processes are killed.
if err := t.KillSessionWithProcesses(sessionID); err != nil {
return fmt.Errorf("killing existing session: %w", err)
}
} else {
@@ -479,8 +480,9 @@ func (m *Manager) Start(name string, opts StartOptions) error {
if t.IsClaudeRunning(sessionID) {
return fmt.Errorf("%w: %s", ErrSessionRunning, sessionID)
}
// Zombie session - kill and recreate
if err := t.KillSession(sessionID); err != nil {
// Zombie session - kill and recreate.
// Use KillSessionWithProcesses to ensure all descendant processes are killed.
if err := t.KillSessionWithProcesses(sessionID); err != nil {
return fmt.Errorf("killing zombie session: %w", err)
}
}
@@ -573,8 +575,10 @@ func (m *Manager) Stop(name string) error {
return ErrSessionNotFound
}
// Kill the session
if err := t.KillSession(sessionID); err != nil {
// Kill the session.
// Use KillSessionWithProcesses to ensure all descendant processes are killed.
// This prevents orphan bash processes from Claude's Bash tool surviving session termination.
if err := t.KillSessionWithProcesses(sessionID); err != nil {
return fmt.Errorf("killing session: %w", err)
}