diff --git a/internal/cmd/statusline.go b/internal/cmd/statusline.go index 2edf1be8..00253eea 100644 --- a/internal/cmd/statusline.go +++ b/internal/cmd/statusline.go @@ -6,6 +6,7 @@ import ( "path/filepath" "sort" "strings" + "time" "github.com/spf13/cobra" "github.com/steveyegge/gastown/internal/beads" @@ -14,6 +15,37 @@ import ( "github.com/steveyegge/gastown/internal/tmux" "github.com/steveyegge/gastown/internal/workspace" ) +// statusLineCacheTTL is how long cached status output remains valid. +const statusLineCacheTTL = 10 * time.Second + +// statusLineCachePath returns the cache file path for a session. +func statusLineCachePath(session string) string { + return filepath.Join(os.TempDir(), fmt.Sprintf("gt-status-%s", session)) +} + +// getStatusLineCache returns cached status if fresh, empty string otherwise. +func getStatusLineCache(session string) string { + path := statusLineCachePath(session) + info, err := os.Stat(path) + if err != nil { + return "" + } + if time.Since(info.ModTime()) > statusLineCacheTTL { + return "" + } + data, err := os.ReadFile(path) + if err != nil { + return "" + } + return string(data) +} + +// setStatusLineCache writes status to cache file. +func setStatusLineCache(session, status string) { + path := statusLineCachePath(session) + _ = os.WriteFile(path, []byte(status), 0644) +} + var ( statusLineSession string @@ -34,6 +66,19 @@ func init() { func runStatusLine(cmd *cobra.Command, args []string) error { t := tmux.NewTmux() + // Optimization: skip expensive beads queries for detached sessions + if statusLineSession != "" { + if !t.IsSessionAttached(statusLineSession) { + fmt.Print("○ |") + return nil + } + // Check cache for attached sessions too + if cached := getStatusLineCache(statusLineSession); cached != "" { + fmt.Print(cached) + return nil + } + } + // Get session environment var rigName, polecat, crew, issue, role string @@ -150,7 +195,11 @@ func runWorkerStatusLine(t *tmux.Tmux, session, rigName, polecat, crew, issue st // Output if len(parts) > 0 { - fmt.Print(strings.Join(parts, " | ") + " |") + output := strings.Join(parts, " | ") + " |" + if statusLineSession != "" { + setStatusLineCache(statusLineSession, output) + } + fmt.Print(output) } return nil @@ -389,7 +438,11 @@ func runMayorStatusLine(t *tmux.Tmux) error { } } - fmt.Print(strings.Join(parts, " | ") + " |") + output := strings.Join(parts, " | ") + " |" + if statusLineSession != "" { + setStatusLineCache(statusLineSession, output) + } + fmt.Print(output) return nil } @@ -458,7 +511,11 @@ func runDeaconStatusLine(t *tmux.Tmux) error { } } - fmt.Print(strings.Join(parts, " | ") + " |") + output := strings.Join(parts, " | ") + " |" + if statusLineSession != "" { + setStatusLineCache(statusLineSession, output) + } + fmt.Print(output) return nil } @@ -526,7 +583,11 @@ func runWitnessStatusLine(t *tmux.Tmux, rigName string) error { } } - fmt.Print(strings.Join(parts, " | ") + " |") + output := strings.Join(parts, " | ") + " |" + if statusLineSession != "" { + setStatusLineCache(statusLineSession, output) + } + fmt.Print(output) return nil } @@ -617,7 +678,11 @@ func runRefineryStatusLine(t *tmux.Tmux, rigName string) error { } } - fmt.Print(strings.Join(parts, " | ") + " |") + output := strings.Join(parts, " | ") + " |" + if statusLineSession != "" { + setStatusLineCache(statusLineSession, output) + } + fmt.Print(output) return nil }