Merge: keeper-mjxpe1ku - Add ensure semantics to witness/refinery start

This commit is contained in:
mayor
2026-01-02 18:54:07 -08:00
committed by Steve Yegge
2 changed files with 22 additions and 3 deletions

View File

@@ -284,7 +284,8 @@ func witnessSessionName(rigName string) string {
} }
// ensureWitnessSession creates a witness tmux session if it doesn't exist. // ensureWitnessSession creates a witness tmux session if it doesn't exist.
// Returns true if a new session was created, false if it already existed. // Returns true if a new session was created, false if it already existed (and is healthy).
// Implements 'ensure' semantics: if session exists but Claude is dead (zombie), kills and recreates.
func ensureWitnessSession(rigName string, r *rig.Rig) (bool, error) { func ensureWitnessSession(rigName string, r *rig.Rig) (bool, error) {
t := tmux.NewTmux() t := tmux.NewTmux()
sessionName := witnessSessionName(rigName) sessionName := witnessSessionName(rigName)
@@ -296,8 +297,17 @@ func ensureWitnessSession(rigName string, r *rig.Rig) (bool, error) {
} }
if running { if running {
// Session exists - check if Claude is actually running (healthy vs zombie)
if t.IsClaudeRunning(sessionName) {
// Healthy - Claude is running
return false, nil return false, nil
} }
// Zombie - tmux alive but Claude dead. Kill and recreate.
fmt.Printf("%s Detected zombie session (tmux alive, Claude dead). Recreating...\n", style.Dim.Render("⚠"))
if err := t.KillSession(sessionName); err != nil {
return false, fmt.Errorf("killing zombie session: %w", err)
}
}
// Working directory is the witness's rig clone (if it exists) or witness dir // Working directory is the witness's rig clone (if it exists) or witness dir
// This ensures gt prime detects the Witness role correctly // This ensures gt prime detects the Witness role correctly

View File

@@ -137,8 +137,17 @@ func (m *Manager) Start(foreground bool) error {
// Background mode: check if session already exists // Background mode: check if session already exists
running, _ := t.HasSession(sessionID) running, _ := t.HasSession(sessionID)
if running { if running {
// Session exists - check if Claude is actually running (healthy vs zombie)
if t.IsClaudeRunning(sessionID) {
// Healthy - Claude is running
return ErrAlreadyRunning return ErrAlreadyRunning
} }
// Zombie - tmux alive but Claude dead. Kill and recreate.
fmt.Fprintln(m.output, "⚠ Detected zombie session (tmux alive, Claude dead). Recreating...")
if err := t.KillSession(sessionID); err != nil {
return fmt.Errorf("killing zombie session: %w", err)
}
}
// Also check via PID for backwards compatibility // Also check via PID for backwards compatibility
if ref.State == StateRunning && ref.PID > 0 && util.ProcessExists(ref.PID) { if ref.State == StateRunning && ref.PID > 0 && util.ProcessExists(ref.PID) {