feat(done): Add --phase-complete flag for gate-based phase handoffs

Add support for signaling phase completion when a polecat needs to wait
on a gate before continuing. The --phase-complete flag with --gate ID
allows polecats to hand off control while awaiting external conditions.

Changes:
- done.go: Add --phase-complete and --gate flags, PHASE_COMPLETE exit type
- protocol.go: Add Gate field to PolecatDonePayload
- handlers.go: Handle PHASE_COMPLETE by recycling session (keep worktree)
- beads.go: Add AddGateWaiter method for gate registration

This enables multi-phase molecule workflows with async coordination (bd-gxb4)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
furiosa
2026-01-02 16:41:39 -08:00
committed by Steve Yegge
parent 535bb8e4c2
commit f8b650cf82
4 changed files with 97 additions and 21 deletions

View File

@@ -45,10 +45,11 @@ const (
// PolecatDonePayload contains parsed data from a POLECAT_DONE message.
type PolecatDonePayload struct {
PolecatName string
Exit string // MERGED, ESCALATED, DEFERRED
Exit string // COMPLETED, ESCALATED, DEFERRED, PHASE_COMPLETE
IssueID string
MRID string
Branch string
Gate string // Gate ID when Exit is PHASE_COMPLETE
}
// HelpPayload contains parsed data from a HELP message.
@@ -101,9 +102,10 @@ func ClassifyMessage(subject string) ProtocolType {
// Subject format: POLECAT_DONE <polecat-name>
// Body format:
//
// Exit: MERGED|ESCALATED|DEFERRED
// Exit: COMPLETED|ESCALATED|DEFERRED|PHASE_COMPLETE
// Issue: <issue-id>
// MR: <mr-id>
// Gate: <gate-id>
// Branch: <branch>
func ParsePolecatDone(subject, body string) (*PolecatDonePayload, error) {
matches := PatternPolecatDone.FindStringSubmatch(subject)
@@ -124,6 +126,8 @@ func ParsePolecatDone(subject, body string) (*PolecatDonePayload, error) {
payload.IssueID = strings.TrimSpace(strings.TrimPrefix(line, "Issue:"))
} else if strings.HasPrefix(line, "MR:") {
payload.MRID = strings.TrimSpace(strings.TrimPrefix(line, "MR:"))
} else if strings.HasPrefix(line, "Gate:") {
payload.Gate = strings.TrimSpace(strings.TrimPrefix(line, "Gate:"))
} else if strings.HasPrefix(line, "Branch:") {
payload.Branch = strings.TrimSpace(strings.TrimPrefix(line, "Branch:"))
}