From 7542cf759647ac40558720c15698538b97e36672 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Sun, 21 Dec 2025 23:26:54 -0800 Subject: [PATCH] Show current work (in_progress issues) in crew/polecat status bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added GetPaneWorkDir to tmux package to get pane current directory - Added getCurrentWork helper that queries beads for in_progress issues - Worker status line now shows first in_progress issue (ID: title) - Falls back to GT_ISSUE env var if set, or empty if no work in progress - Truncated to 40 chars to fit status bar Example: 👷 gt-44wh: Polecats must not create GitHu… | 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/statusline.go | 56 +++++++++++++++++++++++++++++++++----- internal/tmux/tmux.go | 9 ++++++ 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/internal/cmd/statusline.go b/internal/cmd/statusline.go index b2d107ea..82f133c1 100644 --- a/internal/cmd/statusline.go +++ b/internal/cmd/statusline.go @@ -3,9 +3,11 @@ package cmd import ( "fmt" "os" + "path/filepath" "strings" "github.com/spf13/cobra" + "github.com/steveyegge/gastown/internal/beads" "github.com/steveyegge/gastown/internal/mail" "github.com/steveyegge/gastown/internal/tmux" ) @@ -68,11 +70,11 @@ func runStatusLine(cmd *cobra.Command, args []string) error { } // Crew/Polecat status line - return runWorkerStatusLine(rigName, polecat, crew, issue) + return runWorkerStatusLine(t, statusLineSession, rigName, polecat, crew, issue) } // runWorkerStatusLine outputs status for crew or polecat sessions. -func runWorkerStatusLine(rigName, polecat, crew, issue string) error { +func runWorkerStatusLine(t *tmux.Tmux, session, rigName, polecat, crew, issue string) error { // Determine agent type and identity var icon, identity string if polecat != "" { @@ -86,15 +88,21 @@ func runWorkerStatusLine(rigName, polecat, crew, issue string) error { // Build status parts var parts []string - // Add icon prefix + // Try to get current work from beads if no issue env var + currentWork := issue + if currentWork == "" && session != "" { + currentWork = getCurrentWork(t, session, 40) + } + + // Add icon and current work if icon != "" { - if issue != "" { - parts = append(parts, fmt.Sprintf("%s %s", icon, issue)) + if currentWork != "" { + parts = append(parts, fmt.Sprintf("%s %s", icon, currentWork)) } else { parts = append(parts, icon) } - } else if issue != "" { - parts = append(parts, issue) + } else if currentWork != "" { + parts = append(parts, currentWork) } // Mail preview @@ -353,3 +361,37 @@ func getMailPreview(identity string, maxLen int) (int, string) { return len(messages), subject } + +// getCurrentWork returns a truncated title of the first in_progress issue. +// Uses the pane's working directory to find the beads. +func getCurrentWork(t *tmux.Tmux, session string, maxLen int) string { + // Get the pane's working directory + workDir, err := t.GetPaneWorkDir(session) + if err != nil || workDir == "" { + return "" + } + + // Check if there's a .beads directory + beadsDir := filepath.Join(workDir, ".beads") + if _, err := os.Stat(beadsDir); os.IsNotExist(err) { + return "" + } + + // Query beads for in_progress issues + b := beads.New(workDir) + issues, err := b.List(beads.ListOptions{ + Status: "in_progress", + Priority: -1, + }) + if err != nil || len(issues) == 0 { + return "" + } + + // Return first issue's ID and title, truncated + issue := issues[0] + display := fmt.Sprintf("%s: %s", issue.ID, issue.Title) + if len(display) > maxLen { + display = display[:maxLen-1] + "…" + } + return display +} diff --git a/internal/tmux/tmux.go b/internal/tmux/tmux.go index 8449d36b..6932111f 100644 --- a/internal/tmux/tmux.go +++ b/internal/tmux/tmux.go @@ -207,6 +207,15 @@ func (t *Tmux) GetPaneCommand(session string) (string, error) { return strings.TrimSpace(out), nil } +// GetPaneWorkDir returns the current working directory of a pane. +func (t *Tmux) GetPaneWorkDir(session string) (string, error) { + out, err := t.run("list-panes", "-t", session, "-F", "#{pane_current_path}") + 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))