- 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>
197 lines
5.0 KiB
Go
197 lines
5.0 KiB
Go
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
|
||
}
|