feat(dog): add 'gt dog done' command for dogs to mark themselves idle

Dogs can now reset their own state to idle after completing work:

  gt dog done        # Auto-detect from BD_ACTOR
  gt dog done alpha  # Explicit name

This solves the issue where dog sessions would complete work but remain in
"working" state because nothing processed the DOG_DONE mail. Now dogs can
explicitly mark themselves idle before handing off.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-22 08:34:19 -08:00
committed by John Ogle
parent 1c8d0891e1
commit ec9a07cec1

View File

@@ -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 {