feat(rig): support parking multiple rigs in single call
- gt rig park now accepts variadic args (fixes #375) - gt rig unpark updated for consistency - Errors collected and reported at end Also fixes test self-interruption bug where sling tests sent real tmux nudges containing "Work slung: gt-wisp-xyz", causing agents running tests to interrupt themselves. Added GT_TEST_NO_NUDGE env var to skip nudge during tests. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,9 +18,9 @@ const RigStatusKey = "status"
|
|||||||
const RigStatusParked = "parked"
|
const RigStatusParked = "parked"
|
||||||
|
|
||||||
var rigParkCmd = &cobra.Command{
|
var rigParkCmd = &cobra.Command{
|
||||||
Use: "park <rig>",
|
Use: "park <rig>...",
|
||||||
Short: "Park a rig (stops agents, daemon won't auto-restart)",
|
Short: "Park one or more rigs (stops agents, daemon won't auto-restart)",
|
||||||
Long: `Park a rig to temporarily disable it.
|
Long: `Park rigs to temporarily disable them.
|
||||||
|
|
||||||
Parking a rig:
|
Parking a rig:
|
||||||
- Stops the witness if running
|
- Stops the witness if running
|
||||||
@@ -35,15 +35,15 @@ This is a Level 1 (local/ephemeral) operation:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
gt rig park gastown
|
gt rig park gastown
|
||||||
gt rig park beads`,
|
gt rig park beads gastown mayor`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
RunE: runRigPark,
|
RunE: runRigPark,
|
||||||
}
|
}
|
||||||
|
|
||||||
var rigUnparkCmd = &cobra.Command{
|
var rigUnparkCmd = &cobra.Command{
|
||||||
Use: "unpark <rig>",
|
Use: "unpark <rig>...",
|
||||||
Short: "Unpark a rig (allow daemon to auto-restart agents)",
|
Short: "Unpark one or more rigs (allow daemon to auto-restart agents)",
|
||||||
Long: `Unpark a rig to resume normal operation.
|
Long: `Unpark rigs to resume normal operation.
|
||||||
|
|
||||||
Unparking a rig:
|
Unparking a rig:
|
||||||
- Removes the parked status from the wisp layer
|
- Removes the parked status from the wisp layer
|
||||||
@@ -52,8 +52,8 @@ Unparking a rig:
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
gt rig unpark gastown
|
gt rig unpark gastown
|
||||||
gt rig unpark beads`,
|
gt rig unpark beads gastown mayor`,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
RunE: runRigUnpark,
|
RunE: runRigUnpark,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,8 +63,25 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runRigPark(cmd *cobra.Command, args []string) error {
|
func runRigPark(cmd *cobra.Command, args []string) error {
|
||||||
rigName := args[0]
|
var errs []error
|
||||||
|
|
||||||
|
for _, rigName := range args {
|
||||||
|
if err := parkOneRig(rigName); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("%s: %w", rigName, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err := range errs {
|
||||||
|
fmt.Printf("%s %v\n", style.Error.Render("✗"), err)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("failed to park %d rig(s)", len(errs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parkOneRig(rigName string) error {
|
||||||
// Get rig and town root
|
// Get rig and town root
|
||||||
townRoot, r, err := getRig(rigName)
|
townRoot, r, err := getRig(rigName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -120,8 +137,25 @@ func runRigPark(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runRigUnpark(cmd *cobra.Command, args []string) error {
|
func runRigUnpark(cmd *cobra.Command, args []string) error {
|
||||||
rigName := args[0]
|
var errs []error
|
||||||
|
|
||||||
|
for _, rigName := range args {
|
||||||
|
if err := unparkOneRig(rigName); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("%s: %w", rigName, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err := range errs {
|
||||||
|
fmt.Printf("%s %v\n", style.Error.Render("✗"), err)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("failed to unpark %d rig(s)", len(errs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unparkOneRig(rigName string) error {
|
||||||
// Get rig and town root
|
// Get rig and town root
|
||||||
townRoot, _, err := getRig(rigName)
|
townRoot, _, err := getRig(rigName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -175,6 +175,11 @@ func injectStartPrompt(pane, beadID, subject, args string) error {
|
|||||||
return fmt.Errorf("no target pane")
|
return fmt.Errorf("no target pane")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip nudge during tests to prevent agent self-interruption
|
||||||
|
if os.Getenv("GT_TEST_NO_NUDGE") != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Build the prompt to inject
|
// Build the prompt to inject
|
||||||
var prompt string
|
var prompt string
|
||||||
if args != "" {
|
if args != "" {
|
||||||
|
|||||||
@@ -292,6 +292,9 @@ exit 0
|
|||||||
slingVars = nil
|
slingVars = nil
|
||||||
slingOnTarget = "gt-abc123"
|
slingOnTarget = "gt-abc123"
|
||||||
|
|
||||||
|
// Prevent real tmux nudge from firing during tests (causes agent self-interruption)
|
||||||
|
t.Setenv("GT_TEST_NO_NUDGE", "1")
|
||||||
|
|
||||||
if err := runSling(nil, []string{"mol-review"}); err != nil {
|
if err := runSling(nil, []string{"mol-review"}); err != nil {
|
||||||
t.Fatalf("runSling: %v", err)
|
t.Fatalf("runSling: %v", err)
|
||||||
}
|
}
|
||||||
@@ -452,6 +455,9 @@ exit 0
|
|||||||
slingVars = nil
|
slingVars = nil
|
||||||
slingOnTarget = "gt-abc123"
|
slingOnTarget = "gt-abc123"
|
||||||
|
|
||||||
|
// Prevent real tmux nudge from firing during tests (causes agent self-interruption)
|
||||||
|
t.Setenv("GT_TEST_NO_NUDGE", "1")
|
||||||
|
|
||||||
if err := runSling(nil, []string{"mol-review"}); err != nil {
|
if err := runSling(nil, []string{"mol-review"}); err != nil {
|
||||||
t.Fatalf("runSling: %v", err)
|
t.Fatalf("runSling: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user