Remove all bd sync references and SQLite-specific code from gastown: **Formulas (agent priming):** - mol-polecat-work: Remove bd sync step from prepare-for-review - mol-sync-workspace: Replace sync-beads step with verify-beads (Dolt check) - mol-polecat-conflict-resolve: Remove bd sync from close-beads - mol-polecat-code-review: Remove bd sync from summarize-review and complete-and-exit - mol-polecat-review-pr: Remove bd sync from complete-and-exit - mol-convoy-cleanup: Remove bd sync from archive-convoy - mol-digest-generate: Remove bd sync from send-digest - mol-town-shutdown: Replace sync-state step with verify-state - beads-release: Replace restart-daemons with verify-install (no daemons with Dolt) **Templates (role priming):** - mayor.md.tmpl: Update session end checklist to remove bd sync steps - crew.md.tmpl: Remove bd sync references from workflow and checklist - polecat.md.tmpl: Update self-cleaning model and session close docs - spawn.md.tmpl: Remove bd sync from completion steps - nudge.md.tmpl: Remove bd sync from completion steps **Go code:** - session_manager.go: Remove syncBeads function and call - rig_dock.go: Remove bd sync calls from dock/undock - crew/manager.go: Remove runBdSync, update Pristine function - crew_maintenance.go: Remove bd sync status output - crew.go: Update pristine command help text - polecat.go: Make sync command a no-op with deprecation message - daemon/lifecycle.go: Remove bd sync from startup sequence - doctor/beads_check.go: Update fix hints and Fix to use bd import not bd sync - doctor/rig_check.go: Remove sync status check, simplify BeadsConfigValidCheck - beads/beads.go: Update primeContent to remove bd sync references With Dolt backend, beads changes are persisted immediately to the sql-server. There is no separate sync step needed. Part of epic: hq-e4eefc (SQLite removal) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
261 lines
7.3 KiB
Go
261 lines
7.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/steveyegge/gastown/internal/beads"
|
|
"github.com/steveyegge/gastown/internal/refinery"
|
|
"github.com/steveyegge/gastown/internal/style"
|
|
"github.com/steveyegge/gastown/internal/tmux"
|
|
"github.com/steveyegge/gastown/internal/witness"
|
|
)
|
|
|
|
// RigDockedLabel is the label set on rig identity beads when docked.
|
|
const RigDockedLabel = "status:docked"
|
|
|
|
var rigDockCmd = &cobra.Command{
|
|
Use: "dock <rig>",
|
|
Short: "Dock a rig (global, persistent shutdown)",
|
|
Long: `Dock a rig to persistently disable it across all clones.
|
|
|
|
Docking a rig:
|
|
- Stops the witness if running
|
|
- Stops the refinery if running
|
|
- Sets status:docked label on the rig identity bead
|
|
- Syncs via git so all clones see the docked status
|
|
|
|
This is a Level 2 (global/persistent) operation:
|
|
- Affects all clones of this rig (via git sync)
|
|
- Persists until explicitly undocked
|
|
- The daemon respects this status and won't auto-restart agents
|
|
|
|
Use 'gt rig undock' to resume normal operation.
|
|
|
|
Examples:
|
|
gt rig dock gastown
|
|
gt rig dock beads`,
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runRigDock,
|
|
}
|
|
|
|
var rigUndockCmd = &cobra.Command{
|
|
Use: "undock <rig>",
|
|
Short: "Undock a rig (remove global docked status)",
|
|
Long: `Undock a rig to remove the persistent docked status.
|
|
|
|
Undocking a rig:
|
|
- Removes the status:docked label from the rig identity bead
|
|
- Syncs via git so all clones see the undocked status
|
|
- Allows the daemon to auto-restart agents
|
|
- Does NOT automatically start agents (use 'gt rig start' for that)
|
|
|
|
Examples:
|
|
gt rig undock gastown
|
|
gt rig undock beads`,
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runRigUndock,
|
|
}
|
|
|
|
func init() {
|
|
rigCmd.AddCommand(rigDockCmd)
|
|
rigCmd.AddCommand(rigUndockCmd)
|
|
}
|
|
|
|
func runRigDock(cmd *cobra.Command, args []string) error {
|
|
rigName := args[0]
|
|
|
|
// Check we're on main branch - docking on other branches won't persist
|
|
branchCmd := exec.Command("git", "branch", "--show-current")
|
|
branchOutput, err := branchCmd.Output()
|
|
if err == nil {
|
|
currentBranch := string(branchOutput)
|
|
currentBranch = currentBranch[:len(currentBranch)-1] // trim newline
|
|
if currentBranch != "main" && currentBranch != "master" {
|
|
return fmt.Errorf("cannot dock: must be on main branch (currently on %s)\n"+
|
|
"Docking on other branches won't persist. Run: git checkout main", currentBranch)
|
|
}
|
|
}
|
|
|
|
// Get rig
|
|
_, r, err := getRig(rigName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get rig prefix for bead ID
|
|
prefix := "gt" // default
|
|
if r.Config != nil && r.Config.Prefix != "" {
|
|
prefix = r.Config.Prefix
|
|
}
|
|
|
|
// Find the rig identity bead
|
|
rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)
|
|
bd := beads.New(r.BeadsPath())
|
|
|
|
// Check if rig bead exists, create if not
|
|
rigBead, err := bd.Show(rigBeadID)
|
|
if err != nil {
|
|
// Rig identity bead doesn't exist (legacy rig) - create it
|
|
fmt.Printf(" Creating rig identity bead %s...\n", rigBeadID)
|
|
rigBead, err = bd.CreateRigBead(rigBeadID, rigName, &beads.RigFields{
|
|
Repo: r.GitURL,
|
|
Prefix: prefix,
|
|
State: "active",
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("creating rig identity bead: %w", err)
|
|
}
|
|
}
|
|
|
|
// Check if already docked
|
|
for _, label := range rigBead.Labels {
|
|
if label == RigDockedLabel {
|
|
fmt.Printf("%s Rig %s is already docked\n", style.Dim.Render("•"), rigName)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Docking rig %s...\n", style.Bold.Render(rigName))
|
|
|
|
var stoppedAgents []string
|
|
|
|
t := tmux.NewTmux()
|
|
|
|
// Stop witness if running
|
|
witnessSession := fmt.Sprintf("gt-%s-witness", rigName)
|
|
witnessRunning, _ := t.HasSession(witnessSession)
|
|
if witnessRunning {
|
|
fmt.Printf(" Stopping witness...\n")
|
|
witMgr := witness.NewManager(r)
|
|
if err := witMgr.Stop(); err != nil {
|
|
fmt.Printf(" %s Failed to stop witness: %v\n", style.Warning.Render("!"), err)
|
|
} else {
|
|
stoppedAgents = append(stoppedAgents, "Witness stopped")
|
|
}
|
|
}
|
|
|
|
// Stop refinery if running
|
|
refinerySession := fmt.Sprintf("gt-%s-refinery", rigName)
|
|
refineryRunning, _ := t.HasSession(refinerySession)
|
|
if refineryRunning {
|
|
fmt.Printf(" Stopping refinery...\n")
|
|
refMgr := refinery.NewManager(r)
|
|
if err := refMgr.Stop(); err != nil {
|
|
fmt.Printf(" %s Failed to stop refinery: %v\n", style.Warning.Render("!"), err)
|
|
} else {
|
|
stoppedAgents = append(stoppedAgents, "Refinery stopped")
|
|
}
|
|
}
|
|
|
|
// Set docked label on rig identity bead
|
|
if err := bd.Update(rigBeadID, beads.UpdateOptions{
|
|
AddLabels: []string{RigDockedLabel},
|
|
}); err != nil {
|
|
return fmt.Errorf("setting docked label: %w", err)
|
|
}
|
|
|
|
// Output
|
|
fmt.Printf("%s Rig %s docked (global)\n", style.Success.Render("✓"), rigName)
|
|
fmt.Printf(" Label added: %s\n", RigDockedLabel)
|
|
for _, msg := range stoppedAgents {
|
|
fmt.Printf(" %s\n", msg)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runRigUndock(cmd *cobra.Command, args []string) error {
|
|
rigName := args[0]
|
|
|
|
// Check we're on main branch - undocking on other branches won't persist
|
|
branchCmd := exec.Command("git", "branch", "--show-current")
|
|
branchOutput, err := branchCmd.Output()
|
|
if err == nil {
|
|
currentBranch := string(branchOutput)
|
|
currentBranch = currentBranch[:len(currentBranch)-1] // trim newline
|
|
if currentBranch != "main" && currentBranch != "master" {
|
|
return fmt.Errorf("cannot undock: must be on main branch (currently on %s)\n"+
|
|
"Undocking on other branches won't persist. Run: git checkout main", currentBranch)
|
|
}
|
|
}
|
|
|
|
// Get rig and town root
|
|
_, r, err := getRig(rigName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get rig prefix for bead ID
|
|
prefix := "gt" // default
|
|
if r.Config != nil && r.Config.Prefix != "" {
|
|
prefix = r.Config.Prefix
|
|
}
|
|
|
|
// Find the rig identity bead
|
|
rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)
|
|
bd := beads.New(r.BeadsPath())
|
|
|
|
// Check if rig bead exists, create if not
|
|
rigBead, err := bd.Show(rigBeadID)
|
|
if err != nil {
|
|
// Rig identity bead doesn't exist (legacy rig) - can't be docked
|
|
fmt.Printf("%s Rig %s has no identity bead and is not docked\n", style.Dim.Render("•"), rigName)
|
|
return nil
|
|
}
|
|
|
|
// Check if actually docked
|
|
isDocked := false
|
|
for _, label := range rigBead.Labels {
|
|
if label == RigDockedLabel {
|
|
isDocked = true
|
|
break
|
|
}
|
|
}
|
|
if !isDocked {
|
|
fmt.Printf("%s Rig %s is not docked\n", style.Dim.Render("•"), rigName)
|
|
return nil
|
|
}
|
|
|
|
// Remove docked label from rig identity bead
|
|
if err := bd.Update(rigBeadID, beads.UpdateOptions{
|
|
RemoveLabels: []string{RigDockedLabel},
|
|
}); err != nil {
|
|
return fmt.Errorf("removing docked label: %w", err)
|
|
}
|
|
|
|
fmt.Printf("%s Rig %s undocked\n", style.Success.Render("✓"), rigName)
|
|
fmt.Printf(" Label removed: %s\n", RigDockedLabel)
|
|
fmt.Printf(" Daemon can now auto-restart agents\n")
|
|
fmt.Printf(" Use '%s' to start agents immediately\n", style.Dim.Render("gt rig start "+rigName))
|
|
|
|
return nil
|
|
}
|
|
|
|
// IsRigDocked checks if a rig is docked by checking for the status:docked label
|
|
// on the rig identity bead. This function is exported for use by the daemon.
|
|
func IsRigDocked(townRoot, rigName, prefix string) bool {
|
|
// Construct the rig beads path
|
|
rigPath := townRoot + "/" + rigName
|
|
beadsPath := rigPath + "/mayor/rig"
|
|
if _, err := exec.Command("test", "-d", beadsPath).CombinedOutput(); err != nil {
|
|
beadsPath = rigPath
|
|
}
|
|
|
|
bd := beads.New(beadsPath)
|
|
rigBeadID := beads.RigBeadIDWithPrefix(prefix, rigName)
|
|
|
|
rigBead, err := bd.Show(rigBeadID)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
for _, label := range rigBead.Labels {
|
|
if label == RigDockedLabel {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|