feat(rig): add park/unpark commands for Level 1 rig control
Implement gt rig park <rig> and gt rig unpark <rig> commands: - park: stops witness/refinery, sets status=parked in wisp layer - unpark: clears parked status, allows daemon to restart agents This is Level 1 (local/ephemeral) control - affects only this town and disappears on wisp cleanup. Exports IsRigParked() for daemon use. (gt-vxv0u) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
149
internal/cmd/rig_park.go
Normal file
149
internal/cmd/rig_park.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/refinery"
|
||||
"github.com/steveyegge/gastown/internal/style"
|
||||
"github.com/steveyegge/gastown/internal/tmux"
|
||||
"github.com/steveyegge/gastown/internal/wisp"
|
||||
"github.com/steveyegge/gastown/internal/witness"
|
||||
)
|
||||
|
||||
// RigStatusKey is the wisp config key for rig operational status.
|
||||
const RigStatusKey = "status"
|
||||
|
||||
// RigStatusParked is the value indicating a rig is parked.
|
||||
const RigStatusParked = "parked"
|
||||
|
||||
var rigParkCmd = &cobra.Command{
|
||||
Use: "park <rig>",
|
||||
Short: "Park a rig (stops agents, daemon won't auto-restart)",
|
||||
Long: `Park a rig to temporarily disable it.
|
||||
|
||||
Parking a rig:
|
||||
- Stops the witness if running
|
||||
- Stops the refinery if running
|
||||
- Sets status=parked in the wisp layer (local/ephemeral)
|
||||
- The daemon respects this status and won't auto-restart agents
|
||||
|
||||
This is a Level 1 (local/ephemeral) operation:
|
||||
- Only affects this town
|
||||
- Disappears on wisp cleanup
|
||||
- Use 'gt rig unpark' to resume normal operation
|
||||
|
||||
Examples:
|
||||
gt rig park gastown
|
||||
gt rig park beads`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRigPark,
|
||||
}
|
||||
|
||||
var rigUnparkCmd = &cobra.Command{
|
||||
Use: "unpark <rig>",
|
||||
Short: "Unpark a rig (allow daemon to auto-restart agents)",
|
||||
Long: `Unpark a rig to resume normal operation.
|
||||
|
||||
Unparking a rig:
|
||||
- Removes the parked status from the wisp layer
|
||||
- Allows the daemon to auto-restart agents
|
||||
- Does NOT automatically start agents (use 'gt rig start' for that)
|
||||
|
||||
Examples:
|
||||
gt rig unpark gastown
|
||||
gt rig unpark beads`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRigUnpark,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rigCmd.AddCommand(rigParkCmd)
|
||||
rigCmd.AddCommand(rigUnparkCmd)
|
||||
}
|
||||
|
||||
func runRigPark(cmd *cobra.Command, args []string) error {
|
||||
rigName := args[0]
|
||||
|
||||
// Get rig and town root
|
||||
townRoot, r, err := getRig(rigName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Parking rig %s...\n", style.Bold.Render(rigName))
|
||||
|
||||
var stoppedAgents []string
|
||||
|
||||
t := tmux.NewTmux()
|
||||
|
||||
// Stop witness if running
|
||||
witnessSession := fmt.Sprintf("gt-%s-witness", rigName)
|
||||
witnessRunning, _ := t.HasSession(witnessSession)
|
||||
if witnessRunning {
|
||||
fmt.Printf(" Stopping witness...\n")
|
||||
witMgr := witness.NewManager(r)
|
||||
if err := witMgr.Stop(); err != nil {
|
||||
fmt.Printf(" %s Failed to stop witness: %v\n", style.Warning.Render("!"), err)
|
||||
} else {
|
||||
stoppedAgents = append(stoppedAgents, "Witness stopped")
|
||||
}
|
||||
}
|
||||
|
||||
// Stop refinery if running
|
||||
refinerySession := fmt.Sprintf("gt-%s-refinery", rigName)
|
||||
refineryRunning, _ := t.HasSession(refinerySession)
|
||||
if refineryRunning {
|
||||
fmt.Printf(" Stopping refinery...\n")
|
||||
refMgr := refinery.NewManager(r)
|
||||
if err := refMgr.Stop(); err != nil {
|
||||
fmt.Printf(" %s Failed to stop refinery: %v\n", style.Warning.Render("!"), err)
|
||||
} else {
|
||||
stoppedAgents = append(stoppedAgents, "Refinery stopped")
|
||||
}
|
||||
}
|
||||
|
||||
// Set parked status in wisp layer
|
||||
wispCfg := wisp.NewConfig(townRoot, rigName)
|
||||
if err := wispCfg.Set(RigStatusKey, RigStatusParked); err != nil {
|
||||
return fmt.Errorf("setting parked status: %w", err)
|
||||
}
|
||||
|
||||
// Output
|
||||
fmt.Printf("%s Rig %s parked (local only)\n", style.Success.Render("✓"), rigName)
|
||||
for _, msg := range stoppedAgents {
|
||||
fmt.Printf(" %s\n", msg)
|
||||
}
|
||||
fmt.Printf(" Daemon will not auto-restart\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runRigUnpark(cmd *cobra.Command, args []string) error {
|
||||
rigName := args[0]
|
||||
|
||||
// Get rig and town root
|
||||
townRoot, _, err := getRig(rigName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove parked status from wisp layer
|
||||
wispCfg := wisp.NewConfig(townRoot, rigName)
|
||||
if err := wispCfg.Unset(RigStatusKey); err != nil {
|
||||
return fmt.Errorf("clearing parked status: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("%s Rig %s unparked\n", style.Success.Render("✓"), rigName)
|
||||
fmt.Printf(" Daemon can now auto-restart agents\n")
|
||||
fmt.Printf(" Use '%s' to start agents immediately\n", style.Dim.Render("gt rig start "+rigName))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRigParked checks if a rig is parked in the wisp layer.
|
||||
// This function is exported for use by the daemon.
|
||||
func IsRigParked(townRoot, rigName string) bool {
|
||||
wispCfg := wisp.NewConfig(townRoot, rigName)
|
||||
return wispCfg.GetString(RigStatusKey) == RigStatusParked
|
||||
}
|
||||
Reference in New Issue
Block a user