From b1fcb7d3e769471c6404954491e0422d494ba7ca Mon Sep 17 00:00:00 2001 From: gastown/refinery Date: Tue, 13 Jan 2026 12:00:53 -0800 Subject: [PATCH] fix(tmux): explicit process kill before session termination Merge polecat/nux-mkd083ff: Updates KillSessionWithProcesses to use cleaner inline exec.Command style and improved documentation. Prevents orphan processes that survive tmux kill-session due to SIGHUP being ignored by Claude processes. Co-Authored-By: Claude Opus 4.5 --- internal/tmux/tmux.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/internal/tmux/tmux.go b/internal/tmux/tmux.go index 67e954f5..b29c33a0 100644 --- a/internal/tmux/tmux.go +++ b/internal/tmux/tmux.go @@ -135,13 +135,16 @@ func (t *Tmux) KillSession(name string) error { } // KillSessionWithProcesses explicitly kills all processes in a session before terminating it. -// This prevents orphaned processes that can occur when Claude catches/ignores SIGHUP. -// The kill sequence is: -// 1. Get the pane's PID -// 2. Send SIGTERM to the process group (all children) -// 3. Wait 100ms for graceful exit -// 4. Send SIGKILL if processes still alive +// This prevents orphan processes that survive tmux kill-session due to SIGHUP being ignored. +// +// Process: +// 1. Get the pane's main process PID +// 2. Send SIGTERM to all child processes (pkill -TERM -P ) +// 3. Wait 100ms for graceful shutdown +// 4. Send SIGKILL to any remaining children (pkill -KILL -P ) // 5. Kill the tmux session +// +// This ensures Claude processes are properly terminated even if they ignore SIGHUP. func (t *Tmux) KillSessionWithProcesses(name string) error { // Get the pane PID pid, err := t.GetPanePID(name) @@ -151,19 +154,17 @@ func (t *Tmux) KillSessionWithProcesses(name string) error { } if pid != "" { - // Send SIGTERM to process group (all children of the pane process) - termCmd := exec.Command("pkill", "-TERM", "-P", pid) - _ = termCmd.Run() // Ignore errors - process might already be dead + // Send SIGTERM to child processes + _ = exec.Command("pkill", "-TERM", "-P", pid).Run() - // Wait for graceful termination + // Wait for graceful shutdown time.Sleep(100 * time.Millisecond) - // Send SIGKILL to any survivors - killCmd := exec.Command("pkill", "-KILL", "-P", pid) - _ = killCmd.Run() // Ignore errors - process might already be dead + // Send SIGKILL to any remaining children + _ = exec.Command("pkill", "-KILL", "-P", pid).Run() } - // Now kill the tmux session + // Kill the tmux session return t.KillSession(name) }