diff --git a/internal/cmd/dog.go b/internal/cmd/dog.go index 71459d9c..33435e30 100644 --- a/internal/cmd/dog.go +++ b/internal/cmd/dog.go @@ -182,6 +182,22 @@ Examples: RunE: runDogDispatch, } +var dogDoneCmd = &cobra.Command{ + Use: "done [name]", + Short: "Mark a dog as idle (work complete)", + Long: `Mark a dog as idle after completing its work. + +Dogs call this command after finishing plugin execution to reset their state +to idle, allowing them to receive new work dispatches. + +If no name is provided, attempts to detect the current dog from BD_ACTOR. + +Examples: + gt dog done alpha # Explicit dog name + gt dog done # Auto-detect from BD_ACTOR (e.g., "deacon/dogs/alpha")`, + RunE: runDogDone, +} + func init() { // List flags dogListCmd.Flags().BoolVar(&dogListJSON, "json", false, "Output as JSON") @@ -212,6 +228,7 @@ func init() { dogCmd.AddCommand(dogCallCmd) dogCmd.AddCommand(dogStatusCmd) dogCmd.AddCommand(dogDispatchCmd) + dogCmd.AddCommand(dogDoneCmd) rootCmd.AddCommand(dogCmd) } @@ -500,6 +517,34 @@ func runDogStatus(cmd *cobra.Command, args []string) error { return showPackStatus(mgr) } +func runDogDone(cmd *cobra.Command, args []string) error { + mgr, err := getDogManager() + if err != nil { + return err + } + + var name string + if len(args) > 0 { + name = args[0] + } else { + // Try to detect from BD_ACTOR (e.g., "deacon/dogs/alpha") + actor := os.Getenv("BD_ACTOR") + if actor != "" && strings.HasPrefix(actor, "deacon/dogs/") { + name = strings.TrimPrefix(actor, "deacon/dogs/") + } + if name == "" { + return fmt.Errorf("no dog name provided and could not detect from BD_ACTOR") + } + } + + if err := mgr.ClearWork(name); err != nil { + return fmt.Errorf("marking dog %s as done: %w", name, err) + } + + fmt.Printf("✓ %s marked as idle (ready for new work)\n", name) + return nil +} + func showDogStatus(mgr *dog.Manager, name string) error { d, err := mgr.Get(name) if err != nil {