From 296440579aef94e682ba18102483acef3bff00d4 Mon Sep 17 00:00:00 2001 From: gastown/crew/george Date: Mon, 5 Jan 2026 21:18:15 -0800 Subject: [PATCH] feat: add LED status indicators for rigs in Mayor tmux status line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace generic "3 rigs" display with per-rig LED indicators showing witness/refinery status: - 🟢 = both witness and refinery running (fully active) - 🟡 = one running (partially active) - ⚫ = neither running (inactive) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/statusline.go | 65 +++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/internal/cmd/statusline.go b/internal/cmd/statusline.go index 71c9c486..b88d05aa 100644 --- a/internal/cmd/statusline.go +++ b/internal/cmd/statusline.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "sort" "strings" "github.com/spf13/cobra" @@ -181,31 +182,71 @@ func runMayorStatusLine(t *tmux.Tmux) error { } } - // Count polecats and rigs - // Polecats: only actual polecats (not witnesses, refineries, deacon, crew) - // Rigs: only registered rigs with active sessions + // Track per-rig status for LED indicators + type rigStatus struct { + hasWitness bool + hasRefinery bool + } + rigStatuses := make(map[string]*rigStatus) + + // Initialize for all registered rigs + for rigName := range registeredRigs { + rigStatuses[rigName] = &rigStatus{} + } + + // Count polecats and track rig witness/refinery status polecatCount := 0 - rigs := make(map[string]bool) for _, s := range sessions { agent := categorizeSession(s) if agent == nil { continue } - // Count rigs from any rig-level agent, but only if registered if agent.Rig != "" && registeredRigs[agent.Rig] { - rigs[agent.Rig] = true - } - // Count only polecats for polecat count (in registered rigs) - if agent.Type == AgentPolecat && registeredRigs[agent.Rig] { - polecatCount++ + if rigStatuses[agent.Rig] == nil { + rigStatuses[agent.Rig] = &rigStatus{} + } + switch agent.Type { + case AgentWitness: + rigStatuses[agent.Rig].hasWitness = true + case AgentRefinery: + rigStatuses[agent.Rig].hasRefinery = true + case AgentPolecat: + polecatCount++ + } } } - rigCount := len(rigs) // Build status var parts []string parts = append(parts, fmt.Sprintf("%d 😺", polecatCount)) - parts = append(parts, fmt.Sprintf("%d rigs", rigCount)) + + // Build rig status display with LED indicators + // 🟢 = both witness and refinery running (fully active) + // 🟡 = one of witness/refinery running (partially active) + // ⚫ = neither running (inactive) + var rigParts []string + var rigNames []string + for rigName := range rigStatuses { + rigNames = append(rigNames, rigName) + } + sort.Strings(rigNames) + + for _, rigName := range rigNames { + status := rigStatuses[rigName] + var led string + if status.hasWitness && status.hasRefinery { + led = "🟢" // Both running - fully active + } else if status.hasWitness || status.hasRefinery { + led = "🟡" // One running - partially active + } else { + led = "⚫" // Neither running - inactive + } + rigParts = append(rigParts, led+rigName) + } + + if len(rigParts) > 0 { + parts = append(parts, strings.Join(rigParts, " ")) + } // Priority 1: Check for hooked work (town beads for mayor) hookedWork := ""