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:
@@ -93,6 +93,24 @@ Examples:
|
|||||||
RunE: runRigReset,
|
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{
|
var rigShutdownCmd = &cobra.Command{
|
||||||
Use: "shutdown <rig>",
|
Use: "shutdown <rig>",
|
||||||
Short: "Gracefully stop all rig agents",
|
Short: "Gracefully stop all rig agents",
|
||||||
@@ -135,6 +153,7 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(rigCmd)
|
rootCmd.AddCommand(rigCmd)
|
||||||
rigCmd.AddCommand(rigAddCmd)
|
rigCmd.AddCommand(rigAddCmd)
|
||||||
|
rigCmd.AddCommand(rigBootCmd)
|
||||||
rigCmd.AddCommand(rigListCmd)
|
rigCmd.AddCommand(rigListCmd)
|
||||||
rigCmd.AddCommand(rigRemoveCmd)
|
rigCmd.AddCommand(rigRemoveCmd)
|
||||||
rigCmd.AddCommand(rigResetCmd)
|
rigCmd.AddCommand(rigResetCmd)
|
||||||
@@ -533,6 +552,83 @@ func pathExists(path string) bool {
|
|||||||
return err == nil
|
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 {
|
func runRigShutdown(cmd *cobra.Command, args []string) error {
|
||||||
rigName := args[0]
|
rigName := args[0]
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,24 @@
|
|||||||
// Package util provides utility functions for Gas Town.
|
// Package util provides utility functions for Gas Town.
|
||||||
// This file was created as part of an E2E polecat workflow test.
|
// This file was created as part of an E2E polecat workflow test.
|
||||||
package util
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user