fix(done,mayor): push branch before MR creation, restart runtime on attach

done.go: Push branch to origin BEFORE creating MR bead (hq-6dk53, hq-a4ksk)
- The MR bead triggers Refinery to process the branch
- If branch isnt pushed, Refinery finds nothing to merge
- The worktree gets nuked at end of gt done, losing commits forever
- This is why polecats kept submitting MRs with empty branches

mayor.go: Restart runtime with context when attaching (hq-95xfq)
- When runtime has exited, gt may at now respawns with startup beacon
- Previously, attaching to dead session left agent with no context
- Now matches gt handoff behavior: hook check, inbox check, full prime

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mayor
2026-01-13 17:53:18 -08:00
committed by Steve Yegge
parent 5882039715
commit 4ee1a4472d
2 changed files with 57 additions and 1 deletions

View File

@@ -264,6 +264,16 @@ func runDone(cmd *cobra.Command, args []string) error {
return fmt.Errorf("branch '%s' has 0 commits ahead of %s; nothing to merge\nMake and commit changes first, or use --status DEFERRED to exit without completing", branch, originDefault)
}
// CRITICAL: Push branch BEFORE creating MR bead (hq-6dk53, hq-a4ksk)
// The MR bead triggers Refinery to process this branch. If the branch
// isn't pushed yet, Refinery finds nothing to merge. The worktree gets
// nuked at the end of gt done, so the commits are lost forever.
fmt.Printf("Pushing branch to remote...\n")
if err := g.Push("origin", branch, false); err != nil {
return fmt.Errorf("pushing branch '%s' to origin: %w\nCommits exist locally but failed to push. Fix the issue and retry.", branch, err)
}
fmt.Printf("%s Branch pushed to origin\n", style.Bold.Render("✓"))
if issueID == "" {
return fmt.Errorf("cannot determine source issue from branch '%s'; use --issue to specify", branch)
}

View File

@@ -4,8 +4,11 @@ import (
"fmt"
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/config"
"github.com/steveyegge/gastown/internal/mayor"
"github.com/steveyegge/gastown/internal/session"
"github.com/steveyegge/gastown/internal/style"
"github.com/steveyegge/gastown/internal/tmux"
"github.com/steveyegge/gastown/internal/workspace"
)
@@ -142,6 +145,14 @@ func runMayorAttach(cmd *cobra.Command, args []string) error {
return err
}
townRoot, err := workspace.FindFromCwdOrError()
if err != nil {
return fmt.Errorf("finding workspace: %w", err)
}
t := tmux.NewTmux()
sessionID := mgr.SessionName()
running, err := mgr.IsRunning()
if err != nil {
return fmt.Errorf("checking session: %w", err)
@@ -152,10 +163,45 @@ func runMayorAttach(cmd *cobra.Command, args []string) error {
if err := mgr.Start(mayorAgentOverride); err != nil {
return err
}
} else {
// Session exists - check if runtime is still running (hq-95xfq)
// If runtime exited or sitting at shell, restart with proper context
agentCfg, _, err := config.ResolveAgentConfigWithOverride(townRoot, townRoot, mayorAgentOverride)
if err != nil {
return fmt.Errorf("resolving agent: %w", err)
}
if !t.IsAgentRunning(sessionID, config.ExpectedPaneCommands(agentCfg)...) {
// Runtime has exited, restart it with proper context
fmt.Println("Runtime exited, restarting with context...")
paneID, err := t.GetPaneID(sessionID)
if err != nil {
return fmt.Errorf("getting pane ID: %w", err)
}
// Build startup beacon for context (like gt handoff does)
beacon := session.FormatStartupNudge(session.StartupNudgeConfig{
Recipient: "mayor",
Sender: "human",
Topic: "attach",
})
// Build startup command with beacon
startupCmd, err := config.BuildAgentStartupCommandWithAgentOverride("mayor", "mayor", "", beacon, mayorAgentOverride)
if err != nil {
return fmt.Errorf("building startup command: %w", err)
}
if err := t.RespawnPane(paneID, startupCmd); err != nil {
return fmt.Errorf("restarting runtime: %w", err)
}
fmt.Printf("%s Mayor restarted with context\n", style.Bold.Render("✓"))
}
}
// Use shared attach helper (smart: links if inside tmux, attaches if outside)
return attachToTmuxSession(mgr.SessionName())
return attachToTmuxSession(sessionID)
}
func runMayorStatus(cmd *cobra.Command, args []string) error {