feat: add CLI core commands (status, prime, init)
- status: Show town status with rig/polecat/witness counts (--json supported) - prime: Output role context based on current directory - init: Initialize a git repo as a Gas Town rig Closes gt-u1j.10 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
141
internal/cmd/init.go
Normal file
141
internal/cmd/init.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/steveyegge/gastown/internal/git"
|
||||||
|
"github.com/steveyegge/gastown/internal/rig"
|
||||||
|
"github.com/steveyegge/gastown/internal/style"
|
||||||
|
)
|
||||||
|
|
||||||
|
var initForce bool
|
||||||
|
|
||||||
|
var initCmd = &cobra.Command{
|
||||||
|
Use: "init",
|
||||||
|
Short: "Initialize current directory as a Gas Town rig",
|
||||||
|
Long: `Initialize the current directory for use as a Gas Town rig.
|
||||||
|
|
||||||
|
This creates the standard agent directories (polecats/, witness/, refinery/,
|
||||||
|
mayor/) and updates .git/info/exclude to ignore them.
|
||||||
|
|
||||||
|
The current directory must be a git repository. Use --force to reinitialize
|
||||||
|
an existing rig structure.`,
|
||||||
|
RunE: runInit,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initCmd.Flags().BoolVarP(&initForce, "force", "f", false, "Reinitialize existing structure")
|
||||||
|
rootCmd.AddCommand(initCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runInit(cmd *cobra.Command, args []string) error {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting current directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a git repository
|
||||||
|
g := git.NewGit(cwd)
|
||||||
|
if _, err := g.CurrentBranch(); err != nil {
|
||||||
|
return fmt.Errorf("not a git repository (run 'git init' first)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already initialized
|
||||||
|
polecatsDir := filepath.Join(cwd, "polecats")
|
||||||
|
if _, err := os.Stat(polecatsDir); err == nil && !initForce {
|
||||||
|
return fmt.Errorf("rig already initialized (use --force to reinitialize)")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s Initializing Gas Town rig in %s\n\n",
|
||||||
|
style.Bold.Render("⚙️"), style.Dim.Render(cwd))
|
||||||
|
|
||||||
|
// Create agent directories
|
||||||
|
created := 0
|
||||||
|
for _, dir := range rig.AgentDirs {
|
||||||
|
dirPath := filepath.Join(cwd, dir)
|
||||||
|
if err := os.MkdirAll(dirPath, 0755); err != nil {
|
||||||
|
return fmt.Errorf("creating %s: %w", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create .gitkeep to ensure directory is tracked if needed
|
||||||
|
gitkeep := filepath.Join(dirPath, ".gitkeep")
|
||||||
|
if _, err := os.Stat(gitkeep); os.IsNotExist(err) {
|
||||||
|
os.WriteFile(gitkeep, []byte(""), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf(" ✓ Created %s/\n", dir)
|
||||||
|
created++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update .git/info/exclude
|
||||||
|
if err := updateGitExclude(cwd); err != nil {
|
||||||
|
fmt.Printf(" %s Could not update .git/info/exclude: %v\n",
|
||||||
|
style.Dim.Render("⚠"), err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" ✓ Updated .git/info/exclude\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n%s Rig initialized with %d directories.\n",
|
||||||
|
style.Bold.Render("✓"), created)
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Next steps:")
|
||||||
|
fmt.Printf(" 1. Add this rig to a town: %s\n",
|
||||||
|
style.Dim.Render("gt rig add <name> <git-url>"))
|
||||||
|
fmt.Printf(" 2. Create a polecat: %s\n",
|
||||||
|
style.Dim.Render("gt polecat add <name>"))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateGitExclude(repoPath string) error {
|
||||||
|
excludePath := filepath.Join(repoPath, ".git", "info", "exclude")
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
excludeDir := filepath.Dir(excludePath)
|
||||||
|
if err := os.MkdirAll(excludeDir, 0755); err != nil {
|
||||||
|
return fmt.Errorf("creating .git/info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read existing content
|
||||||
|
content, err := os.ReadFile(excludePath)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already has Gas Town section
|
||||||
|
contentStr := string(content)
|
||||||
|
if len(content) > 0 && contains(contentStr, "Gas Town") {
|
||||||
|
return nil // Already configured
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append agent dirs
|
||||||
|
additions := "\n# Gas Town agent directories\n"
|
||||||
|
for _, dir := range rig.AgentDirs {
|
||||||
|
// Get first component (e.g., "polecats" from "polecats")
|
||||||
|
// or "refinery" from "refinery/rig"
|
||||||
|
base := filepath.Dir(dir)
|
||||||
|
if base == "." {
|
||||||
|
base = dir
|
||||||
|
}
|
||||||
|
additions += base + "/\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write back
|
||||||
|
return os.WriteFile(excludePath, append(content, []byte(additions)...), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(s, substr string) bool {
|
||||||
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsHelper(s, substr string) bool {
|
||||||
|
for i := 0; i <= len(s)-len(substr); i++ {
|
||||||
|
if s[i:i+len(substr)] == substr {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
229
internal/cmd/prime.go
Normal file
229
internal/cmd/prime.go
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/steveyegge/gastown/internal/style"
|
||||||
|
"github.com/steveyegge/gastown/internal/workspace"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Role represents a detected agent role.
|
||||||
|
type Role string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleMayor Role = "mayor"
|
||||||
|
RoleWitness Role = "witness"
|
||||||
|
RoleRefinery Role = "refinery"
|
||||||
|
RolePolecat Role = "polecat"
|
||||||
|
RoleUnknown Role = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
var primeCmd = &cobra.Command{
|
||||||
|
Use: "prime",
|
||||||
|
Short: "Output role context for current directory",
|
||||||
|
Long: `Detect the agent role from the current directory and output context.
|
||||||
|
|
||||||
|
Role detection:
|
||||||
|
- Town root or mayor/rig/ → Mayor context
|
||||||
|
- <rig>/witness/rig/ → Witness context
|
||||||
|
- <rig>/refinery/rig/ → Refinery context
|
||||||
|
- <rig>/polecats/<name>/ → Polecat context
|
||||||
|
|
||||||
|
This command is typically used in shell prompts or agent initialization.`,
|
||||||
|
RunE: runPrime,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(primeCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleContext contains information about the detected role.
|
||||||
|
type RoleContext struct {
|
||||||
|
Role Role `json:"role"`
|
||||||
|
Rig string `json:"rig,omitempty"`
|
||||||
|
Polecat string `json:"polecat,omitempty"`
|
||||||
|
TownRoot string `json:"town_root"`
|
||||||
|
WorkDir string `json:"work_dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPrime(cmd *cobra.Command, args []string) error {
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting current directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find town root
|
||||||
|
townRoot, err := workspace.FindFromCwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("finding workspace: %w", err)
|
||||||
|
}
|
||||||
|
if townRoot == "" {
|
||||||
|
return fmt.Errorf("not in a Gas Town workspace")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect role
|
||||||
|
ctx := detectRole(cwd, townRoot)
|
||||||
|
|
||||||
|
// Output context
|
||||||
|
return outputPrimeContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectRole(cwd, townRoot string) RoleContext {
|
||||||
|
ctx := RoleContext{
|
||||||
|
Role: RoleUnknown,
|
||||||
|
TownRoot: townRoot,
|
||||||
|
WorkDir: cwd,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get relative path from town root
|
||||||
|
relPath, err := filepath.Rel(townRoot, cwd)
|
||||||
|
if err != nil {
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize and split path
|
||||||
|
relPath = filepath.ToSlash(relPath)
|
||||||
|
parts := strings.Split(relPath, "/")
|
||||||
|
|
||||||
|
// Check for mayor role
|
||||||
|
// At town root, or in mayor/ or mayor/rig/
|
||||||
|
if relPath == "." || relPath == "" {
|
||||||
|
ctx.Role = RoleMayor
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
if len(parts) >= 1 && parts[0] == "mayor" {
|
||||||
|
ctx.Role = RoleMayor
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, first part should be a rig name
|
||||||
|
if len(parts) < 1 {
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
rigName := parts[0]
|
||||||
|
ctx.Rig = rigName
|
||||||
|
|
||||||
|
// Check for witness: <rig>/witness/rig/
|
||||||
|
if len(parts) >= 2 && parts[1] == "witness" {
|
||||||
|
ctx.Role = RoleWitness
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for refinery: <rig>/refinery/rig/
|
||||||
|
if len(parts) >= 2 && parts[1] == "refinery" {
|
||||||
|
ctx.Role = RoleRefinery
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for polecat: <rig>/polecats/<name>/
|
||||||
|
if len(parts) >= 3 && parts[1] == "polecats" {
|
||||||
|
ctx.Role = RolePolecat
|
||||||
|
ctx.Polecat = parts[2]
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: could be rig root - treat as unknown
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputPrimeContext(ctx RoleContext) error {
|
||||||
|
switch ctx.Role {
|
||||||
|
case RoleMayor:
|
||||||
|
outputMayorContext(ctx)
|
||||||
|
case RoleWitness:
|
||||||
|
outputWitnessContext(ctx)
|
||||||
|
case RoleRefinery:
|
||||||
|
outputRefineryContext(ctx)
|
||||||
|
case RolePolecat:
|
||||||
|
outputPolecatContext(ctx)
|
||||||
|
default:
|
||||||
|
outputUnknownContext(ctx)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputMayorContext(ctx RoleContext) {
|
||||||
|
fmt.Printf("%s\n\n", style.Bold.Render("# Mayor Context"))
|
||||||
|
fmt.Println("You are the **Mayor** - the global coordinator of Gas Town.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("## Responsibilities")
|
||||||
|
fmt.Println("- Coordinate work across all rigs")
|
||||||
|
fmt.Println("- Delegate to Refineries, not directly to polecats")
|
||||||
|
fmt.Println("- Monitor overall system health")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("## Key Commands")
|
||||||
|
fmt.Println("- `gt status` - Show overall town status")
|
||||||
|
fmt.Println("- `gt rigs` - List all rigs")
|
||||||
|
fmt.Println("- `bd ready` - Issues ready to work")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("Town root: %s\n", style.Dim.Render(ctx.TownRoot))
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputWitnessContext(ctx RoleContext) {
|
||||||
|
fmt.Printf("%s\n\n", style.Bold.Render("# Witness Context"))
|
||||||
|
fmt.Printf("You are the **Witness** for rig: %s\n\n", style.Bold.Render(ctx.Rig))
|
||||||
|
fmt.Println("## Responsibilities")
|
||||||
|
fmt.Println("- Monitor polecat health via heartbeat")
|
||||||
|
fmt.Println("- Spawn ephemeral agents for stuck polecats")
|
||||||
|
fmt.Println("- Report rig status to Mayor")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("## Key Commands")
|
||||||
|
fmt.Println("- `gt witness status` - Show witness status")
|
||||||
|
fmt.Println("- `gt polecats` - List polecats in this rig")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("Rig: %s\n", style.Dim.Render(ctx.Rig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputRefineryContext(ctx RoleContext) {
|
||||||
|
fmt.Printf("%s\n\n", style.Bold.Render("# Refinery Context"))
|
||||||
|
fmt.Printf("You are the **Refinery** for rig: %s\n\n", style.Bold.Render(ctx.Rig))
|
||||||
|
fmt.Println("## Responsibilities")
|
||||||
|
fmt.Println("- Process the merge queue for this rig")
|
||||||
|
fmt.Println("- Merge polecat work to integration branch")
|
||||||
|
fmt.Println("- Resolve merge conflicts")
|
||||||
|
fmt.Println("- Land completed swarms to main")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("## Key Commands")
|
||||||
|
fmt.Println("- `gt merge queue` - Show pending merges")
|
||||||
|
fmt.Println("- `gt merge next` - Process next merge")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("Rig: %s\n", style.Dim.Render(ctx.Rig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputPolecatContext(ctx RoleContext) {
|
||||||
|
fmt.Printf("%s\n\n", style.Bold.Render("# Polecat Context"))
|
||||||
|
fmt.Printf("You are polecat **%s** in rig: %s\n\n",
|
||||||
|
style.Bold.Render(ctx.Polecat), style.Bold.Render(ctx.Rig))
|
||||||
|
fmt.Println("## Responsibilities")
|
||||||
|
fmt.Println("- Work on assigned issues")
|
||||||
|
fmt.Println("- Commit work to your branch")
|
||||||
|
fmt.Println("- Signal completion for merge queue")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("## Key Commands")
|
||||||
|
fmt.Println("- `bd show <issue>` - View your assigned issue")
|
||||||
|
fmt.Println("- `bd close <issue>` - Mark issue complete")
|
||||||
|
fmt.Println("- `gt done` - Signal work ready for merge")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("Polecat: %s | Rig: %s\n",
|
||||||
|
style.Dim.Render(ctx.Polecat), style.Dim.Render(ctx.Rig))
|
||||||
|
}
|
||||||
|
|
||||||
|
func outputUnknownContext(ctx RoleContext) {
|
||||||
|
fmt.Printf("%s\n\n", style.Bold.Render("# Gas Town Context"))
|
||||||
|
fmt.Println("Could not determine specific role from current directory.")
|
||||||
|
fmt.Println()
|
||||||
|
if ctx.Rig != "" {
|
||||||
|
fmt.Printf("You appear to be in rig: %s\n\n", style.Bold.Render(ctx.Rig))
|
||||||
|
}
|
||||||
|
fmt.Println("Navigate to a specific agent directory:")
|
||||||
|
fmt.Println("- `<rig>/polecats/<name>/` - Polecat role")
|
||||||
|
fmt.Println("- `<rig>/witness/rig/` - Witness role")
|
||||||
|
fmt.Println("- `<rig>/refinery/rig/` - Refinery role")
|
||||||
|
fmt.Println("- Town root or `mayor/` - Mayor role")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("Town root: %s\n", style.Dim.Render(ctx.TownRoot))
|
||||||
|
}
|
||||||
171
internal/cmd/status.go
Normal file
171
internal/cmd/status.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
|
"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",
|
||||||
|
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"`
|
||||||
|
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"`
|
||||||
|
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, "config", "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, "config", "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,
|
||||||
|
}
|
||||||
|
status.Rigs = append(status.Rigs, rs)
|
||||||
|
|
||||||
|
// Update summary
|
||||||
|
status.Summary.PolecatCount += len(r.Polecats)
|
||||||
|
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(" 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 += " 🏭"
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user