fix(tmux): kill pane processes before all RespawnPane calls to prevent orphans
## Problem Claude processes were accumulating as orphans, with 100+ processes piling up daily. Every `gt handoff` (used dozens of times/hour by crew) left orphaned processes because `tmux respawn-pane -k` only sends SIGHUP, which Node/Claude ignores. ## Root Cause Previous fixes (1043f00d,f89ac47f,2feefd17,1b036aad) were laser-focused on specific symptoms (shutdown, setsid, done.go, molecule_step.go) but never did a comprehensive audit of ALL RespawnPane call sites. handoff.go was never fixed despite being the main source of orphans. ## Solution Added KillPaneProcesses() call before every RespawnPane() in: - handoff.go (self handoff and remote handoff) - mayor.go (mayor restart) - crew_at.go (new session and restart) KillPaneProcesses explicitly kills all descendant processes with SIGTERM/SIGKILL before respawning, preventing orphans regardless of SIGHUP handling. molecule_step.go already had this fix from commit1b036aad. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -209,6 +209,12 @@ func runCrewAt(cmd *cobra.Command, args []string) error {
|
||||
if runtimeConfig.Session != nil && runtimeConfig.Session.ConfigDirEnv != "" && claudeConfigDir != "" {
|
||||
startupCmd = config.PrependEnv(startupCmd, map[string]string{runtimeConfig.Session.ConfigDirEnv: claudeConfigDir})
|
||||
}
|
||||
// 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(paneID); err != nil {
|
||||
// Non-fatal but log the warning
|
||||
style.PrintWarning("could not kill pane processes: %v", err)
|
||||
}
|
||||
if err := t.RespawnPane(paneID, startupCmd); err != nil {
|
||||
return fmt.Errorf("starting runtime: %w", err)
|
||||
}
|
||||
@@ -252,6 +258,12 @@ func runCrewAt(cmd *cobra.Command, args []string) error {
|
||||
if runtimeConfig.Session != nil && runtimeConfig.Session.ConfigDirEnv != "" && claudeConfigDir != "" {
|
||||
startupCmd = config.PrependEnv(startupCmd, map[string]string{runtimeConfig.Session.ConfigDirEnv: claudeConfigDir})
|
||||
}
|
||||
// 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(paneID); err != nil {
|
||||
// Non-fatal but log the warning
|
||||
style.PrintWarning("could not kill pane processes: %v", err)
|
||||
}
|
||||
if err := t.RespawnPane(paneID, startupCmd); err != nil {
|
||||
return fmt.Errorf("restarting runtime: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user