From 1907eea102c721ad17b58837b07fb9b2cf812efc Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Fri, 19 Dec 2025 00:29:57 -0800 Subject: [PATCH] fix(spawn): auto-add polecat when --create flag is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using `gt spawn rig --create` and no polecats exist (or all are busy), the command now automatically generates a Mad Max themed polecat name and creates it, rather than failing with "no available polecats". This improves agent UX by making the --create flag work intuitively. Fixes: gt-szsq 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/cmd/spawn.go | 51 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/internal/cmd/spawn.go b/internal/cmd/spawn.go index ca472b6c..dced47d4 100644 --- a/internal/cmd/spawn.go +++ b/internal/cmd/spawn.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "math/rand" "os/exec" "path/filepath" "strings" @@ -20,6 +21,13 @@ import ( "github.com/steveyegge/gastown/internal/workspace" ) +// polecatNames are Mad Max: Fury Road themed names for auto-generated polecats. +var polecatNames = []string{ + "Nux", "Toast", "Capable", "Cheedo", "Dag", "Rictus", "Slit", "Morsov", + "Ace", "Coma", "Valkyrie", "Keeper", "Vuvalini", "Organic", "Immortan", + "Corpus", "Doof", "Scabrous", "Splendid", "Fragile", +} + // Spawn command flags var ( spawnIssue string @@ -103,9 +111,16 @@ func runSpawn(cmd *cobra.Command, args []string) error { if polecatName == "" { polecatName, err = selectIdlePolecat(polecatMgr, r) if err != nil { - return fmt.Errorf("auto-select polecat: %w", err) + // If --create is set, generate a new polecat name instead of failing + if spawnCreate { + polecatName = generatePolecatName(polecatMgr) + fmt.Printf("Generated polecat name: %s\n", polecatName) + } else { + return fmt.Errorf("auto-select polecat: %w", err) + } + } else { + fmt.Printf("Auto-selected polecat: %s\n", polecatName) } - fmt.Printf("Auto-selected polecat: %s\n", polecatName) } // Check/create polecat @@ -204,6 +219,38 @@ func parseSpawnAddress(addr string) (rigName, polecatName string, err error) { return addr, "", nil } +// generatePolecatName generates a unique polecat name that doesn't conflict with existing ones. +func generatePolecatName(mgr *polecat.Manager) string { + existing, _ := mgr.List() + existingNames := make(map[string]bool) + for _, p := range existing { + existingNames[p.Name] = true + } + + // Try to find an unused name from the list + // Shuffle to avoid always picking the same name + shuffled := make([]string, len(polecatNames)) + copy(shuffled, polecatNames) + rand.Shuffle(len(shuffled), func(i, j int) { + shuffled[i], shuffled[j] = shuffled[j], shuffled[i] + }) + + for _, name := range shuffled { + if !existingNames[name] { + return name + } + } + + // All names taken, generate one with a number suffix + base := shuffled[0] + for i := 2; ; i++ { + name := fmt.Sprintf("%s%d", base, i) + if !existingNames[name] { + return name + } + } +} + // selectIdlePolecat finds an idle polecat in the rig. func selectIdlePolecat(mgr *polecat.Manager, r *rig.Rig) (string, error) { polecats, err := mgr.List()