Add MQ summary to gt status output (gt-tvwnz)

Shows merge queue status under the Refinery section:
- pending: Open MRs ready to merge (no blockers)
- in-flight: MRs currently being processed
- blocked: MRs waiting on dependencies

Output appears as: MQ: 4 pending, 1 in-flight

Also adds MQ summary to JSON output in RigStatus.mq field.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-30 01:50:29 -08:00
parent 1d4b27cf06
commit 04f0e46619

View File

@@ -83,6 +83,14 @@ type RigStatus struct {
HasRefinery bool `json:"has_refinery"`
Hooks []AgentHookInfo `json:"hooks,omitempty"`
Agents []AgentRuntime `json:"agents,omitempty"` // Runtime state of all agents in rig
MQ *MQSummary `json:"mq,omitempty"` // Merge queue summary
}
// MQSummary represents the merge queue status for a rig.
type MQSummary struct {
Pending int `json:"pending"` // Open MRs ready to merge (no blockers)
InFlight int `json:"in_flight"` // MRs currently being processed
Blocked int `json:"blocked"` // MRs waiting on dependencies
}
// AgentHookInfo represents an agent's hook (pinned work) status.
@@ -202,6 +210,9 @@ func runStatus(cmd *cobra.Command, args []string) error {
// Discover runtime state for all agents in this rig
rs.Agents = discoverRigAgents(t, r, rs.Crews, agentBeads, mailRouter)
// Get MQ summary if rig has a refinery
rs.MQ = getMQSummary(r)
status.Rigs = append(status.Rigs, rs)
// Update summary
@@ -312,6 +323,22 @@ func outputStatusText(status TownStatus) error {
for _, agent := range refineries {
renderAgentDetails(agent, " ", r.Hooks)
}
// MQ summary (shown under refinery)
if r.MQ != nil {
mqParts := []string{}
if r.MQ.Pending > 0 {
mqParts = append(mqParts, fmt.Sprintf("%d pending", r.MQ.Pending))
}
if r.MQ.InFlight > 0 {
mqParts = append(mqParts, style.Warning.Render(fmt.Sprintf("%d in-flight", r.MQ.InFlight)))
}
if r.MQ.Blocked > 0 {
mqParts = append(mqParts, style.Dim.Render(fmt.Sprintf("%d blocked", r.MQ.Blocked)))
}
if len(mqParts) > 0 {
fmt.Printf(" MQ: %s\n", strings.Join(mqParts, ", "))
}
}
fmt.Println()
}
@@ -675,6 +702,57 @@ func discoverRigAgents(t *tmux.Tmux, r *rig.Rig, crews []string, agentBeads *bea
return agents
}
// getMQSummary queries beads for merge-request issues and returns a summary.
// Returns nil if the rig has no refinery or no MQ issues.
func getMQSummary(r *rig.Rig) *MQSummary {
if !r.HasRefinery {
return nil
}
// Create beads instance for the rig
b := beads.New(r.BeadsPath())
// Query for all open merge-request type issues
opts := beads.ListOptions{
Type: "merge-request",
Status: "open",
Priority: -1, // No priority filter
}
openMRs, err := b.List(opts)
if err != nil {
return nil
}
// Query for in-progress merge-requests
opts.Status = "in_progress"
inProgressMRs, err := b.List(opts)
if err != nil {
return nil
}
// Count pending (open with no blockers) vs blocked
pending := 0
blocked := 0
for _, mr := range openMRs {
if len(mr.BlockedBy) > 0 || mr.BlockedByCount > 0 {
blocked++
} else {
pending++
}
}
// Only return summary if there's something to show
if pending == 0 && len(inProgressMRs) == 0 && blocked == 0 {
return nil
}
return &MQSummary{
Pending: pending,
InFlight: len(inProgressMRs),
Blocked: blocked,
}
}
// getAgentHook retrieves hook status for a specific agent.
func getAgentHook(b *beads.Beads, role, agentAddress, roleType string) AgentHookInfo {
hook := AgentHookInfo{