diff --git a/internal/deacon/manager.go b/internal/deacon/manager.go index d4e45aa6..ec16bbf7 100644 --- a/internal/deacon/manager.go +++ b/internal/deacon/manager.go @@ -106,9 +106,11 @@ func (m *Manager) Start(agentOverride string) error { theme := tmux.DeaconTheme() _ = t.ConfigureGasTownSession(sessionID, theme, "", "Deacon", "health-check") - // Wait for Claude to start (non-fatal) + // Wait for Claude to start - fatal if Claude fails to launch if err := t.WaitForCommand(sessionID, constants.SupportedShells, constants.ClaudeStartTimeout); err != nil { - // Non-fatal - try to continue anyway + // Kill the zombie session before returning error + _ = t.KillSessionWithProcesses(sessionID) + return fmt.Errorf("waiting for deacon to start: %w", err) } // Accept bypass permissions warning dialog if it appears. diff --git a/internal/mayor/manager.go b/internal/mayor/manager.go index eea57071..855cae31 100644 --- a/internal/mayor/manager.go +++ b/internal/mayor/manager.go @@ -114,9 +114,11 @@ func (m *Manager) Start(agentOverride string) error { theme := tmux.MayorTheme() _ = t.ConfigureGasTownSession(sessionID, theme, "", "Mayor", "coordinator") - // Wait for Claude to start (non-fatal) + // Wait for Claude to start - fatal if Claude fails to launch if err := t.WaitForCommand(sessionID, constants.SupportedShells, constants.ClaudeStartTimeout); err != nil { - // Non-fatal - try to continue anyway + // Kill the zombie session before returning error + _ = t.KillSessionWithProcesses(sessionID) + return fmt.Errorf("waiting for mayor to start: %w", err) } // Accept bypass permissions warning dialog if it appears. diff --git a/internal/refinery/manager.go b/internal/refinery/manager.go index 41d539e8..0534cab4 100644 --- a/internal/refinery/manager.go +++ b/internal/refinery/manager.go @@ -223,10 +223,12 @@ func (m *Manager) Start(foreground bool, agentOverride string) error { return fmt.Errorf("saving state: %w", err) } - // Wait for Claude to start and show its prompt (non-fatal) + // Wait for Claude to start and show its prompt - fatal if Claude fails to launch // WaitForRuntimeReady waits for the runtime to be ready if err := t.WaitForRuntimeReady(sessionID, runtimeConfig, constants.ClaudeStartTimeout); err != nil { - // Non-fatal - try to continue anyway + // Kill the zombie session before returning error + _ = t.KillSessionWithProcesses(sessionID) + return fmt.Errorf("waiting for refinery to start: %w", err) } // Accept bypass permissions warning dialog if it appears. diff --git a/internal/witness/manager.go b/internal/witness/manager.go index bd26933a..78e262a8 100644 --- a/internal/witness/manager.go +++ b/internal/witness/manager.go @@ -211,9 +211,11 @@ func (m *Manager) Start(foreground bool, agentOverride string, envOverrides []st return fmt.Errorf("saving state: %w", err) } - // Wait for Claude to start (non-fatal). + // Wait for Claude to start - fatal if Claude fails to launch if err := t.WaitForCommand(sessionID, constants.SupportedShells, constants.ClaudeStartTimeout); err != nil { - // Non-fatal - try to continue anyway + // Kill the zombie session before returning error + _ = t.KillSessionWithProcesses(sessionID) + return fmt.Errorf("waiting for witness to start: %w", err) } // Accept bypass permissions warning dialog if it appears.