fix(hook): enable cross-prefix bead hooking with database routing

When agents hook beads from different prefixes (e.g., rig worker hooking
hq-* bead), the status check now uses ResolveHookDir to find the correct
database for fetching the hooked bead.

Also adds fallback scanning of town-level beads for rig-level roles when
no hooked beads are found locally.

Fixes: gt-rphsv

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
furiosa
2026-01-26 12:27:18 -08:00
committed by John Ogle
parent c66dc4594c
commit afdadc77ff

View File

@@ -372,8 +372,14 @@ func runMoleculeStatus(cmd *cobra.Command, args []string) error {
// IMPORTANT: Don't use ParseAgentFieldsFromDescription - the description
// field may contain stale data, causing the wrong issue to be hooked.
if agentBead.HookBead != "" {
// Fetch the bead on the hook
hookBead, err = b.Show(agentBead.HookBead)
// Fetch the bead on the hook, using cross-prefix database routing.
// The hooked bead may be in a different database than the agent bead
// (e.g., hq-* bead hooked by a rig worker). Use ResolveHookDir to
// find the correct database directory based on the bead's prefix.
// See: https://github.com/steveyegge/gastown/issues/gt-rphsv
hookBeadDir := beads.ResolveHookDir(townRoot, agentBead.HookBead, workDir)
hookBeadDB := beads.New(hookBeadDir)
hookBead, err = hookBeadDB.Show(agentBead.HookBead)
if err != nil {
// Hook bead referenced but not found - report error but continue
hookBead = nil
@@ -438,6 +444,24 @@ func runMoleculeStatus(cmd *cobra.Command, args []string) error {
hookedBeads = scanAllRigsForHookedBeads(townRoot, target)
}
// For rig-level roles, also check town-level beads (hq-* prefix).
// Agents can hook cross-prefix beads (e.g., crew worker taking an HQ task).
// See: https://github.com/steveyegge/gastown/issues/gt-rphsv
if len(hookedBeads) == 0 && !isTownLevelRole(target) {
townBeadsDir := filepath.Join(townRoot, ".beads")
if _, statErr := os.Stat(townBeadsDir); statErr == nil {
townBeads := beads.New(townBeadsDir)
townHooked, listErr := townBeads.List(beads.ListOptions{
Status: beads.StatusHooked,
Assignee: target,
Priority: -1,
})
if listErr == nil && len(townHooked) > 0 {
hookedBeads = townHooked
}
}
}
status.HasWork = len(hookedBeads) > 0
if len(hookedBeads) > 0 {