feat(done): Add --exit flag for session self-termination (gt-lynar)
Add --exit flag to `gt done` that terminates the Claude session immediately after submitting the MR to the merge queue. This prevents polecats from sitting idle (and wasting money) while waiting for the Witness to kill them. Changes: - Rename existing --exit flag to --status (for exit type) - Add new --exit boolean flag for session self-termination - Update docs and help text to reflect new flag names Usage: gt done --exit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -225,7 +225,7 @@ EOF
|
|||||||
gt escalate --type decision --issue $ISSUE "Caching approach needs decision"
|
gt escalate --type decision --issue $ISSUE "Caching approach needs decision"
|
||||||
|
|
||||||
# 3. Exit cleanly
|
# 3. Exit cleanly
|
||||||
gt done --exit ESCALATED
|
gt done --status ESCALATED
|
||||||
```
|
```
|
||||||
|
|
||||||
## Mayor Startup Check
|
## Mayor Startup Check
|
||||||
|
|||||||
@@ -24,24 +24,27 @@ This is a convenience command for polecats that:
|
|||||||
1. Submits the current branch to the merge queue
|
1. Submits the current branch to the merge queue
|
||||||
2. Auto-detects issue ID from branch name
|
2. Auto-detects issue ID from branch name
|
||||||
3. Notifies the Witness with the exit outcome
|
3. Notifies the Witness with the exit outcome
|
||||||
|
4. Optionally exits the Claude session (--exit flag)
|
||||||
|
|
||||||
Exit types:
|
Exit statuses:
|
||||||
COMPLETED - Work done, MR submitted (default)
|
COMPLETED - Work done, MR submitted (default)
|
||||||
ESCALATED - Hit blocker, needs human intervention
|
ESCALATED - Hit blocker, needs human intervention
|
||||||
DEFERRED - Work paused, issue still open
|
DEFERRED - Work paused, issue still open
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
gt done # Submit branch, notify COMPLETED
|
gt done # Submit branch, notify COMPLETED
|
||||||
gt done --issue gt-abc # Explicit issue ID
|
gt done --exit # Submit and exit Claude session
|
||||||
gt done --exit ESCALATED # Signal blocker, skip MR
|
gt done --issue gt-abc # Explicit issue ID
|
||||||
gt done --exit DEFERRED # Pause work, skip MR`,
|
gt done --status ESCALATED # Signal blocker, skip MR
|
||||||
|
gt done --status DEFERRED # Pause work, skip MR`,
|
||||||
RunE: runDone,
|
RunE: runDone,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
doneIssue string
|
doneIssue string
|
||||||
donePriority int
|
donePriority int
|
||||||
doneExit string
|
doneStatus string
|
||||||
|
doneExit bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// Valid exit types for gt done
|
// Valid exit types for gt done
|
||||||
@@ -54,16 +57,17 @@ const (
|
|||||||
func init() {
|
func init() {
|
||||||
doneCmd.Flags().StringVar(&doneIssue, "issue", "", "Source issue ID (default: parse from branch name)")
|
doneCmd.Flags().StringVar(&doneIssue, "issue", "", "Source issue ID (default: parse from branch name)")
|
||||||
doneCmd.Flags().IntVarP(&donePriority, "priority", "p", -1, "Override priority (0-4, default: inherit from issue)")
|
doneCmd.Flags().IntVarP(&donePriority, "priority", "p", -1, "Override priority (0-4, default: inherit from issue)")
|
||||||
doneCmd.Flags().StringVar(&doneExit, "exit", ExitCompleted, "Exit type: COMPLETED, ESCALATED, or DEFERRED")
|
doneCmd.Flags().StringVar(&doneStatus, "status", ExitCompleted, "Exit status: COMPLETED, ESCALATED, or DEFERRED")
|
||||||
|
doneCmd.Flags().BoolVar(&doneExit, "exit", false, "Exit Claude session after MR submission (self-terminate)")
|
||||||
|
|
||||||
rootCmd.AddCommand(doneCmd)
|
rootCmd.AddCommand(doneCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDone(cmd *cobra.Command, args []string) error {
|
func runDone(cmd *cobra.Command, args []string) error {
|
||||||
// Validate exit type
|
// Validate exit status
|
||||||
exitType := strings.ToUpper(doneExit)
|
exitType := strings.ToUpper(doneStatus)
|
||||||
if exitType != ExitCompleted && exitType != ExitEscalated && exitType != ExitDeferred {
|
if exitType != ExitCompleted && exitType != ExitEscalated && exitType != ExitDeferred {
|
||||||
return fmt.Errorf("invalid exit type '%s': must be COMPLETED, ESCALATED, or DEFERRED", doneExit)
|
return fmt.Errorf("invalid exit status '%s': must be COMPLETED, ESCALATED, or DEFERRED", doneStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find workspace
|
// Find workspace
|
||||||
@@ -277,6 +281,15 @@ func runDone(cmd *cobra.Command, args []string) error {
|
|||||||
// Update agent bead state (ZFC: self-report completion)
|
// Update agent bead state (ZFC: self-report completion)
|
||||||
updateAgentStateOnDone(cwd, townRoot, exitType, issueID)
|
updateAgentStateOnDone(cwd, townRoot, exitType, issueID)
|
||||||
|
|
||||||
|
// Handle session self-termination if requested
|
||||||
|
if doneExit {
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s Session self-terminating (--exit flag)\n", style.Bold.Render("→"))
|
||||||
|
fmt.Printf(" Witness will handle worktree cleanup.\n")
|
||||||
|
fmt.Printf(" Goodbye!\n")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ var handoffCmd = &cobra.Command{
|
|||||||
This is the canonical way to end any agent session. It handles all roles:
|
This is the canonical way to end any agent session. It handles all roles:
|
||||||
|
|
||||||
- Mayor, Crew, Witness, Refinery, Deacon: Respawns with fresh Claude instance
|
- Mayor, Crew, Witness, Refinery, Deacon: Respawns with fresh Claude instance
|
||||||
- Polecats: Calls 'gt done --exit DEFERRED' (Witness handles lifecycle)
|
- Polecats: Calls 'gt done --status DEFERRED' (Witness handles lifecycle)
|
||||||
|
|
||||||
When run without arguments, hands off the current session.
|
When run without arguments, hands off the current session.
|
||||||
When given a bead ID (gt-xxx, hq-xxx), hooks that work first, then restarts.
|
When given a bead ID (gt-xxx, hq-xxx), hooks that work first, then restarts.
|
||||||
|
|||||||
Reference in New Issue
Block a user