fix(sling): Run bd commands from polecat worktree for proper routing
When slinging work to a polecat, run bd commands from the polecat's worktree directory instead of town root. This enables redirect-based routing to work correctly since the polecat's .beads/redirect file points to the canonical database location. Adds hookWorkDir variable to track the polecat's clone path and passes it to updateAgentHookBead for proper beads access.
This commit is contained in:
@@ -191,6 +191,7 @@ func runSling(cmd *cobra.Command, args []string) error {
|
|||||||
// Determine target agent (self or specified)
|
// Determine target agent (self or specified)
|
||||||
var targetAgent string
|
var targetAgent string
|
||||||
var targetPane string
|
var targetPane string
|
||||||
|
var hookWorkDir string // Working directory for running bd hook commands
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
@@ -250,6 +251,7 @@ func runSling(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
targetAgent = spawnInfo.AgentID()
|
targetAgent = spawnInfo.AgentID()
|
||||||
targetPane = spawnInfo.Pane
|
targetPane = spawnInfo.Pane
|
||||||
|
hookWorkDir = spawnInfo.ClonePath // Run bd commands from polecat's worktree
|
||||||
|
|
||||||
// Wake witness and refinery to monitor the new polecat
|
// Wake witness and refinery to monitor the new polecat
|
||||||
wakeRigAgents(rigName)
|
wakeRigAgents(rigName)
|
||||||
@@ -394,8 +396,20 @@ func runSling(cmd *cobra.Command, args []string) error {
|
|||||||
beadID = wispRootID
|
beadID = wispRootID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook the bead using bd update (discovery-based approach)
|
// Hook the bead using bd update
|
||||||
|
// Run from polecat's worktree if available (for redirect-based routing),
|
||||||
|
// otherwise from town root (for prefix-based routing via routes.jsonl)
|
||||||
hookCmd := exec.Command("bd", "update", beadID, "--status=hooked", "--assignee="+targetAgent)
|
hookCmd := exec.Command("bd", "update", beadID, "--status=hooked", "--assignee="+targetAgent)
|
||||||
|
if hookWorkDir != "" {
|
||||||
|
hookCmd.Dir = hookWorkDir
|
||||||
|
} else {
|
||||||
|
// Fallback to town root for non-rig targets
|
||||||
|
townRoot, err := workspace.FindFromCwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("finding town root for bead routing: %w", err)
|
||||||
|
}
|
||||||
|
hookCmd.Dir = townRoot
|
||||||
|
}
|
||||||
hookCmd.Stderr = os.Stderr
|
hookCmd.Stderr = os.Stderr
|
||||||
if err := hookCmd.Run(); err != nil {
|
if err := hookCmd.Run(); err != nil {
|
||||||
return fmt.Errorf("hooking bead: %w", err)
|
return fmt.Errorf("hooking bead: %w", err)
|
||||||
@@ -408,7 +422,7 @@ func runSling(cmd *cobra.Command, args []string) error {
|
|||||||
_ = events.LogFeed(events.TypeSling, actor, events.SlingPayload(beadID, targetAgent))
|
_ = events.LogFeed(events.TypeSling, actor, events.SlingPayload(beadID, targetAgent))
|
||||||
|
|
||||||
// Update agent bead's hook_bead field (ZFC: agents track their current work)
|
// Update agent bead's hook_bead field (ZFC: agents track their current work)
|
||||||
updateAgentHookBead(targetAgent, beadID)
|
updateAgentHookBead(targetAgent, beadID, hookWorkDir)
|
||||||
|
|
||||||
// Store args in bead description (no-tmux mode: beads as data plane)
|
// Store args in bead description (no-tmux mode: beads as data plane)
|
||||||
if slingArgs != "" {
|
if slingArgs != "" {
|
||||||
@@ -786,7 +800,13 @@ func runSlingFormula(args []string) error {
|
|||||||
fmt.Printf("%s Wisp created: %s\n", style.Bold.Render("✓"), wispResult.RootID)
|
fmt.Printf("%s Wisp created: %s\n", style.Bold.Render("✓"), wispResult.RootID)
|
||||||
|
|
||||||
// Step 3: Hook the wisp bead using bd update (discovery-based approach)
|
// Step 3: Hook the wisp bead using bd update (discovery-based approach)
|
||||||
|
// Run from town root to enable prefix-based routing via routes.jsonl
|
||||||
|
townRoot, err := workspace.FindFromCwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("finding town root for bead routing: %w", err)
|
||||||
|
}
|
||||||
hookCmd := exec.Command("bd", "update", wispResult.RootID, "--status=hooked", "--assignee="+targetAgent)
|
hookCmd := exec.Command("bd", "update", wispResult.RootID, "--status=hooked", "--assignee="+targetAgent)
|
||||||
|
hookCmd.Dir = townRoot
|
||||||
hookCmd.Stderr = os.Stderr
|
hookCmd.Stderr = os.Stderr
|
||||||
if err := hookCmd.Run(); err != nil {
|
if err := hookCmd.Run(); err != nil {
|
||||||
return fmt.Errorf("hooking wisp bead: %w", err)
|
return fmt.Errorf("hooking wisp bead: %w", err)
|
||||||
@@ -800,7 +820,8 @@ func runSlingFormula(args []string) error {
|
|||||||
_ = events.LogFeed(events.TypeSling, actor, payload)
|
_ = events.LogFeed(events.TypeSling, actor, payload)
|
||||||
|
|
||||||
// Update agent bead's hook_bead field (ZFC: agents track their current work)
|
// Update agent bead's hook_bead field (ZFC: agents track their current work)
|
||||||
updateAgentHookBead(targetAgent, wispResult.RootID)
|
// Note: formula slinging uses town root as workDir (no polecat-specific path)
|
||||||
|
updateAgentHookBead(targetAgent, wispResult.RootID, "")
|
||||||
|
|
||||||
// Store args in wisp bead if provided (no-tmux mode: beads as data plane)
|
// Store args in wisp bead if provided (no-tmux mode: beads as data plane)
|
||||||
if slingArgs != "" {
|
if slingArgs != "" {
|
||||||
@@ -838,11 +859,11 @@ func runSlingFormula(args []string) error {
|
|||||||
// updateAgentHookBead updates the agent bead's hook_bead field when work is slung.
|
// updateAgentHookBead updates the agent bead's hook_bead field when work is slung.
|
||||||
// This enables the witness to see what each agent is working on.
|
// This enables the witness to see what each agent is working on.
|
||||||
//
|
//
|
||||||
// IMPORTANT: Uses town root for routing so cross-beads references work.
|
// If workDir is provided (e.g., polecat's clone path), bd commands run from there
|
||||||
// The agent bead (e.g., gt-gastown-polecat-nux) may be in rig beads,
|
// to access the correct beads database via redirect. Otherwise falls back to town root.
|
||||||
// while the hook bead (e.g., hq-oosxt) may be in town beads.
|
// Running from the polecat's worktree is important because it has a .beads/redirect file
|
||||||
// Running from town root gives access to routes.jsonl for proper resolution.
|
// that points to the correct canonical database for redirect-based routing.
|
||||||
func updateAgentHookBead(agentID, beadID string) {
|
func updateAgentHookBead(agentID, beadID, workDir string) {
|
||||||
// Convert agent ID to agent bead ID
|
// Convert agent ID to agent bead ID
|
||||||
// Format examples (canonical: prefix-rig-role-name):
|
// Format examples (canonical: prefix-rig-role-name):
|
||||||
// greenplace/crew/max -> gt-greenplace-crew-max
|
// greenplace/crew/max -> gt-greenplace-crew-max
|
||||||
@@ -854,17 +875,21 @@ func updateAgentHookBead(agentID, beadID string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use town root for routing - this ensures cross-beads references work.
|
// Determine the directory to run bd commands from:
|
||||||
// Town beads (hq-*) and rig beads (gt-*) are resolved via routes.jsonl
|
// - If workDir is provided (polecat's clone path), use it for redirect-based routing
|
||||||
// which lives at town root.
|
// - Otherwise fall back to town root for prefix-based routing via routes.jsonl
|
||||||
|
bdWorkDir := workDir
|
||||||
|
if bdWorkDir == "" {
|
||||||
townRoot, err := workspace.FindFromCwd()
|
townRoot, err := workspace.FindFromCwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Not in a Gas Town workspace - can't update agent bead
|
// Not in a Gas Town workspace - can't update agent bead
|
||||||
fmt.Fprintf(os.Stderr, "Warning: couldn't find town root to update agent hook: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Warning: couldn't find town root to update agent hook: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
bdWorkDir = townRoot
|
||||||
|
}
|
||||||
|
|
||||||
bd := beads.New(townRoot)
|
bd := beads.New(bdWorkDir)
|
||||||
if err := bd.UpdateAgentState(agentBeadID, "running", &beadID); err != nil {
|
if err := bd.UpdateAgentState(agentBeadID, "running", &beadID); err != nil {
|
||||||
// Log warning instead of silent ignore - helps debug cross-beads issues
|
// Log warning instead of silent ignore - helps debug cross-beads issues
|
||||||
fmt.Fprintf(os.Stderr, "Warning: couldn't update agent %s hook to %s: %v\n", agentBeadID, beadID, err)
|
fmt.Fprintf(os.Stderr, "Warning: couldn't update agent %s hook to %s: %v\n", agentBeadID, beadID, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user