feat: Add gt rig boot command to start witness and refinery

Inverse of 'gt rig shutdown'. Starts rig patrol agents:
- Checks tmux sessions to avoid duplicates
- Starts witness if not running
- Starts refinery if not running
- Reports what was started vs skipped

Also adds ProcessExists util function needed by witness/refinery managers.
This commit is contained in:
Steve Yegge
2025-12-28 19:19:10 -08:00
parent cdbe5d0a1e
commit 7606bc884a
2 changed files with 117 additions and 0 deletions

View File

@@ -93,6 +93,24 @@ Examples:
RunE: runRigReset,
}
var rigBootCmd = &cobra.Command{
Use: "boot <rig>",
Short: "Start witness and refinery for a rig",
Long: `Start the witness and refinery agents for a rig.
This is the inverse of 'gt rig shutdown'. It starts:
- The witness (if not already running)
- The refinery (if not already running)
Polecats are NOT started by this command - they are spawned
on demand when work is assigned.
Examples:
gt rig boot gastown`,
Args: cobra.ExactArgs(1),
RunE: runRigBoot,
}
var rigShutdownCmd = &cobra.Command{
Use: "shutdown <rig>",
Short: "Gracefully stop all rig agents",
@@ -135,6 +153,7 @@ var (
func init() {
rootCmd.AddCommand(rigCmd)
rigCmd.AddCommand(rigAddCmd)
rigCmd.AddCommand(rigBootCmd)
rigCmd.AddCommand(rigListCmd)
rigCmd.AddCommand(rigRemoveCmd)
rigCmd.AddCommand(rigResetCmd)
@@ -533,6 +552,83 @@ func pathExists(path string) bool {
return err == nil
}
func runRigBoot(cmd *cobra.Command, args []string) error {
rigName := args[0]
// Find workspace
townRoot, err := workspace.FindFromCwdOrError()
if err != nil {
return fmt.Errorf("not in a Gas Town workspace: %w", err)
}
// Load rigs config and get rig
rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
rigsConfig, err := config.LoadRigsConfig(rigsPath)
if err != nil {
rigsConfig = &config.RigsConfig{Rigs: make(map[string]config.RigEntry)}
}
g := git.NewGit(townRoot)
rigMgr := rig.NewManager(townRoot, rigsConfig, g)
r, err := rigMgr.GetRig(rigName)
if err != nil {
return fmt.Errorf("rig '%s' not found", rigName)
}
fmt.Printf("Booting rig %s...\n", style.Bold.Render(rigName))
var started []string
var skipped []string
t := tmux.NewTmux()
// 1. Start the witness
// Check actual tmux session, not state file (may be stale)
witnessSession := fmt.Sprintf("gt-%s-witness", rigName)
witnessRunning, _ := t.HasSession(witnessSession)
if witnessRunning {
skipped = append(skipped, "witness (already running)")
} else {
fmt.Printf(" Starting witness...\n")
// Use ensureWitnessSession to create tmux session (same as gt witness start)
created, err := ensureWitnessSession(rigName, r)
if err != nil {
return fmt.Errorf("starting witness: %w", err)
}
if created {
// Update manager state to reflect running session
witMgr := witness.NewManager(r)
_ = witMgr.Start() // non-fatal: state file update
started = append(started, "witness")
}
}
// 2. Start the refinery
// Check actual tmux session, not state file (may be stale)
refinerySession := fmt.Sprintf("gt-%s-refinery", rigName)
refineryRunning, _ := t.HasSession(refinerySession)
if refineryRunning {
skipped = append(skipped, "refinery (already running)")
} else {
fmt.Printf(" Starting refinery...\n")
refMgr := refinery.NewManager(r)
if err := refMgr.Start(false); err != nil { // false = background mode
return fmt.Errorf("starting refinery: %w", err)
}
started = append(started, "refinery")
}
// Report results
if len(started) > 0 {
fmt.Printf("%s Started: %s\n", style.Success.Render("✓"), strings.Join(started, ", "))
}
if len(skipped) > 0 {
fmt.Printf("%s Skipped: %s\n", style.Dim.Render("•"), strings.Join(skipped, ", "))
}
return nil
}
func runRigShutdown(cmd *cobra.Command, args []string) error {
rigName := args[0]

View File

@@ -1,3 +1,24 @@
// Package util provides utility functions for Gas Town.
// This file was created as part of an E2E polecat workflow test.
package util
import (
"os"
"syscall"
)
// ProcessExists checks if a process with the given PID exists.
// It sends signal 0 to the process, which doesn't actually send a signal
// but does perform error checking to see if the process exists.
func ProcessExists(pid int) bool {
if pid <= 0 {
return false
}
process, err := os.FindProcess(pid)
if err != nil {
return false
}
// Signal 0 checks if process exists without sending a real signal
err = process.Signal(syscall.Signal(0))
return err == nil
}