From c4b942b7e95671bf719ccf10e676c0aa424f7b5c Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Wed, 17 Dec 2025 20:10:05 -0800 Subject: [PATCH] fix: gt crew at restarts Claude if it has exited MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Check pane_current_command to detect if Claude is still running - If shell is detected (bash, zsh, etc.), Claude exited - restart it - Re-prime after restart with gt prime 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/crew.go | 25 +++++++++++++++++++++++++ internal/tmux/tmux.go | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/internal/cmd/crew.go b/internal/cmd/crew.go index 01bdc1e7..e28d743a 100644 --- a/internal/cmd/crew.go +++ b/internal/cmd/crew.go @@ -463,12 +463,37 @@ func runCrewAt(cmd *cobra.Command, args []string) error { fmt.Printf("%s Created session for %s/%s\n", style.Bold.Render("✓"), r.Name, name) + } else { + // Session exists - check if Claude is still running + paneCmd, err := t.GetPaneCommand(sessionID) + if err == nil && isShellCommand(paneCmd) { + // Claude has exited, restart it + fmt.Printf("Claude exited, restarting...\n") + if err := t.SendKeys(sessionID, "claude --dangerously-skip-permissions"); err != nil { + return fmt.Errorf("restarting claude: %w", err) + } + // Prime after restart + if err := t.SendKeysDelayed(sessionID, "gt prime", 2000); err != nil { + fmt.Printf("Warning: Could not send prime command: %v\n", err) + } + } } // Attach to session using exec to properly forward TTY return attachToTmuxSession(sessionID) } +// isShellCommand checks if the command is a shell (meaning Claude has exited). +func isShellCommand(cmd string) bool { + shells := []string{"bash", "zsh", "sh", "fish", "tcsh", "ksh"} + for _, shell := range shells { + if cmd == shell { + return true + } + } + return false +} + // attachToTmuxSession attaches to a tmux session with proper TTY forwarding. func attachToTmuxSession(sessionID string) error { tmuxPath, err := exec.LookPath("tmux") diff --git a/internal/tmux/tmux.go b/internal/tmux/tmux.go index 8db4a620..4070a69a 100644 --- a/internal/tmux/tmux.go +++ b/internal/tmux/tmux.go @@ -133,6 +133,16 @@ func (t *Tmux) SendKeysDelayed(session, keys string, delayMs int) error { return t.SendKeys(session, keys) } +// GetPaneCommand returns the current command running in a pane. +// Returns "bash", "zsh", "claude", "node", etc. +func (t *Tmux) GetPaneCommand(session string) (string, error) { + out, err := t.run("list-panes", "-t", session, "-F", "#{pane_current_command}") + if err != nil { + return "", err + } + return strings.TrimSpace(out), nil +} + // CapturePane captures the visible content of a pane. func (t *Tmux) CapturePane(session string, lines int) (string, error) { return t.run("capture-pane", "-p", "-t", session, "-S", fmt.Sprintf("-%d", lines))