fix(status): Reconcile tmux session state with bead state

The gt status command now properly reconciles the tmux session
existence with the agent bead state to surface mismatches:

- If session exists AND bead says running/idle → "running"
- If session exists BUT bead says stopped/dead → "running [bead: <state>]"
- If session gone BUT bead says running/idle → "running [dead]"
- If session gone AND bead says stopped → "stopped"

This surfaces the key mismatch case where a tmux session is actually
running but the bead state incorrectly says "stopped" or "dead".

Fixes: gt-doih4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
valkyrie
2026-01-02 18:52:56 -08:00
committed by Steve Yegge
parent 92106afd6a
commit 63d5502b4b

View File

@@ -471,14 +471,40 @@ func outputStatusText(status TownStatus) error {
// renderAgentDetails renders full agent bead details
func renderAgentDetails(agent AgentRuntime, indent string, hooks []AgentHookInfo, townRoot string) {
// Line 1: Agent bead ID + status
statusStr := style.Success.Render("running")
if !agent.Running {
// Reconcile bead state with tmux session state to surface mismatches
// States: "running" (active), "idle" (waiting), "stopped", "dead", etc.
beadState := agent.State
sessionExists := agent.Running
// "idle" is a normal operational state (running but waiting for work)
// Treat it the same as "running" for reconciliation purposes
beadSaysRunning := beadState == "running" || beadState == "idle" || beadState == ""
var statusStr string
var stateInfo string
switch {
case beadSaysRunning && sessionExists:
// Normal running state - session exists and bead agrees
statusStr = style.Success.Render("running")
case beadSaysRunning && !sessionExists:
// Bead thinks running but session is gone - stale bead state
statusStr = style.Error.Render("running")
stateInfo = style.Warning.Render(" [dead]")
case !beadSaysRunning && sessionExists:
// Session exists but bead says stopped/dead - mismatch!
// This is the key case: tmux says alive, bead says dead/stopped
statusStr = style.Success.Render("running")
stateInfo = style.Warning.Render(" [bead: " + beadState + "]")
default:
// Both agree: stopped
statusStr = style.Error.Render("stopped")
}
stateInfo := ""
if agent.State != "" && agent.State != "idle" && agent.State != "running" {
stateInfo = style.Dim.Render(fmt.Sprintf(" [%s]", agent.State))
// Add agent state info if not already shown and state is interesting
// Skip "idle" and "running" as they're normal operational states
if stateInfo == "" && beadState != "" && beadState != "idle" && beadState != "running" {
stateInfo = style.Dim.Render(fmt.Sprintf(" [%s]", beadState))
}
// Build agent bead ID using canonical naming: prefix-rig-role-name