From 0c791a4d40626ce92005871fbbd4fc1965c0250c Mon Sep 17 00:00:00 2001 From: max Date: Sun, 25 Jan 2026 15:56:15 -0800 Subject: [PATCH] fix(handoff): don't KillPaneProcesses on self-handoff For self-handoff, calling KillPaneProcesses kills the gt handoff process itself before it can execute RespawnPane, leaving the pane dead with no respawn. The fix is to rely on respawn-pane -k which handles killing and respawning atomically. The remote handoff path is unaffected - it correctly calls KillPaneProcesses because the caller is in a different session. Co-Authored-By: Claude Opus 4.5 --- internal/cmd/handoff.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/internal/cmd/handoff.go b/internal/cmd/handoff.go index 2313c390..c51cdcbc 100644 --- a/internal/cmd/handoff.go +++ b/internal/cmd/handoff.go @@ -211,14 +211,17 @@ func runHandoff(cmd *cobra.Command, args []string) error { style.PrintWarning("could not set remain-on-exit: %v", err) } - // Kill all processes in the pane before respawning to prevent orphan leaks - // RespawnPane's -k flag only sends SIGHUP which Claude/Node may ignore - if err := t.KillPaneProcesses(pane); err != nil { - // Non-fatal but log the warning - style.PrintWarning("could not kill pane processes: %v", err) - } + // NOTE: For self-handoff, we do NOT call KillPaneProcesses here. + // That would kill the gt handoff process itself before it can call RespawnPane, + // leaving the pane dead with no respawn. RespawnPane's -k flag handles killing + // atomically - tmux kills the old process and spawns the new one together. + // See: https://github.com/steveyegge/gastown/issues/859 (pane is dead bug) + // + // For orphan prevention, we rely on respawn-pane -k which sends SIGHUP/SIGTERM. + // If orphans still occur, the solution is to adjust the restart command to + // kill orphans at startup, not to kill ourselves before respawning. - // Use exec to respawn the pane - this kills us and restarts + // Use respawn-pane -k to atomically kill current process and start new one // Note: respawn-pane automatically resets remain-on-exit to off return t.RespawnPane(pane, restartCmd) }