Files
gastown/internal/cmd/status.go
Steve Yegge 915594c44c Add crew rename, pristine commands and status integration
- gt crew rename: Rename crew workspace (kills session, renames dir)
- gt crew pristine: Sync crew workspaces with git pull + bd sync
- gt status: Show crew workers per rig with 👤 indicator

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 19:20:41 -08:00

197 lines
5.0 KiB
Go
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package cmd
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/config"
"github.com/steveyegge/gastown/internal/crew"
"github.com/steveyegge/gastown/internal/git"
"github.com/steveyegge/gastown/internal/rig"
"github.com/steveyegge/gastown/internal/style"
"github.com/steveyegge/gastown/internal/workspace"
)
var statusJSON bool
var statusCmd = &cobra.Command{
Use: "status",
Aliases: []string{"stat"},
Short: "Show overall town status",
Long: `Display the current status of the Gas Town workspace.
Shows town name, registered rigs, active polecats, and witness status.`,
RunE: runStatus,
}
func init() {
statusCmd.Flags().BoolVar(&statusJSON, "json", false, "Output as JSON")
rootCmd.AddCommand(statusCmd)
}
// TownStatus represents the overall status of the workspace.
type TownStatus struct {
Name string `json:"name"`
Location string `json:"location"`
Rigs []RigStatus `json:"rigs"`
Summary StatusSum `json:"summary"`
}
// RigStatus represents status of a single rig.
type RigStatus struct {
Name string `json:"name"`
Polecats []string `json:"polecats"`
PolecatCount int `json:"polecat_count"`
Crews []string `json:"crews"`
CrewCount int `json:"crew_count"`
HasWitness bool `json:"has_witness"`
HasRefinery bool `json:"has_refinery"`
}
// StatusSum provides summary counts.
type StatusSum struct {
RigCount int `json:"rig_count"`
PolecatCount int `json:"polecat_count"`
CrewCount int `json:"crew_count"`
WitnessCount int `json:"witness_count"`
RefineryCount int `json:"refinery_count"`
}
func runStatus(cmd *cobra.Command, args []string) error {
// Find town root
townRoot, err := workspace.FindFromCwdOrError()
if err != nil {
return fmt.Errorf("not in a Gas Town workspace: %w", err)
}
// Load town config
townConfigPath := filepath.Join(townRoot, "mayor", "town.json")
townConfig, err := config.LoadTownConfig(townConfigPath)
if err != nil {
// Try to continue without config
townConfig = &config.TownConfig{Name: filepath.Base(townRoot)}
}
// Load rigs config
rigsConfigPath := filepath.Join(townRoot, "mayor", "rigs.json")
rigsConfig, err := config.LoadRigsConfig(rigsConfigPath)
if err != nil {
// Empty config if file doesn't exist
rigsConfig = &config.RigsConfig{Rigs: make(map[string]config.RigEntry)}
}
// Create rig manager
g := git.NewGit(townRoot)
mgr := rig.NewManager(townRoot, rigsConfig, g)
// Discover rigs
rigs, err := mgr.DiscoverRigs()
if err != nil {
return fmt.Errorf("discovering rigs: %w", err)
}
// Build status
status := TownStatus{
Name: townConfig.Name,
Location: townRoot,
Rigs: make([]RigStatus, 0, len(rigs)),
}
for _, r := range rigs {
rs := RigStatus{
Name: r.Name,
Polecats: r.Polecats,
PolecatCount: len(r.Polecats),
HasWitness: r.HasWitness,
HasRefinery: r.HasRefinery,
}
// Count crew workers
crewGit := git.NewGit(r.Path)
crewMgr := crew.NewManager(r, crewGit)
if workers, err := crewMgr.List(); err == nil {
for _, w := range workers {
rs.Crews = append(rs.Crews, w.Name)
}
rs.CrewCount = len(workers)
}
status.Rigs = append(status.Rigs, rs)
// Update summary
status.Summary.PolecatCount += len(r.Polecats)
status.Summary.CrewCount += rs.CrewCount
if r.HasWitness {
status.Summary.WitnessCount++
}
if r.HasRefinery {
status.Summary.RefineryCount++
}
}
status.Summary.RigCount = len(rigs)
// Output
if statusJSON {
return outputStatusJSON(status)
}
return outputStatusText(status)
}
func outputStatusJSON(status TownStatus) error {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(status)
}
func outputStatusText(status TownStatus) error {
// Header
fmt.Printf("%s %s\n", style.Bold.Render(" Gas Town:"), status.Name)
fmt.Printf(" Location: %s\n\n", style.Dim.Render(status.Location))
// Summary
fmt.Printf("%s\n", style.Bold.Render("Summary"))
fmt.Printf(" Rigs: %d\n", status.Summary.RigCount)
fmt.Printf(" Polecats: %d\n", status.Summary.PolecatCount)
fmt.Printf(" Crews: %d\n", status.Summary.CrewCount)
fmt.Printf(" Witnesses: %d\n", status.Summary.WitnessCount)
fmt.Printf(" Refineries: %d\n", status.Summary.RefineryCount)
if len(status.Rigs) == 0 {
fmt.Printf("\n%s\n", style.Dim.Render("No rigs registered. Use 'gt rig add' to add one."))
return nil
}
// Rigs detail
fmt.Printf("\n%s\n", style.Bold.Render("Rigs"))
for _, r := range status.Rigs {
// Rig name with indicators
indicators := ""
if r.HasWitness {
indicators += " 👁"
}
if r.HasRefinery {
indicators += " 🏭"
}
if r.CrewCount > 0 {
indicators += " 👤"
}
fmt.Printf(" %s%s\n", style.Bold.Render(r.Name), indicators)
if len(r.Polecats) > 0 {
fmt.Printf(" Polecats: %v\n", r.Polecats)
} else {
fmt.Printf(" %s\n", style.Dim.Render("No polecats"))
}
if len(r.Crews) > 0 {
fmt.Printf(" Crews: %v\n", r.Crews)
}
}
return nil
}