fix: use rig-specific prefix for agent bead IDs (bd-otyh)
When spawning polecats in non-gastown rigs like beads, the agent bead ID was incorrectly using the hardcoded "gt-" prefix instead of the rig's configured prefix (e.g., "bd-" for beads). Changes: - Add GetPrefixForRig() in routes.go to look up prefix from routes.jsonl - Update agentIDToBeadID() in sling.go to use rig's prefix via the new *WithPrefix functions instead of hardcoded "gt" - Add unit tests for the new functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -130,6 +130,30 @@ func WriteRoutes(beadsDir string, routes []Route) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPrefixForRig returns the beads prefix for a given rig name.
|
||||
// The prefix is returned without the trailing hyphen (e.g., "bd" not "bd-").
|
||||
// If the rig is not found in routes, returns "gt" as the default.
|
||||
// The townRoot should be the Gas Town root directory (e.g., ~/gt).
|
||||
func GetPrefixForRig(townRoot, rigName string) string {
|
||||
beadsDir := filepath.Join(townRoot, ".beads")
|
||||
routes, err := LoadRoutes(beadsDir)
|
||||
if err != nil || routes == nil {
|
||||
return "gt" // Default prefix
|
||||
}
|
||||
|
||||
// Look for a route where the path starts with the rig name
|
||||
// Routes paths are like "gastown/mayor/rig" or "beads/mayor/rig"
|
||||
for _, r := range routes {
|
||||
parts := strings.SplitN(r.Path, "/", 2)
|
||||
if len(parts) > 0 && parts[0] == rigName {
|
||||
// Return prefix without trailing hyphen
|
||||
return strings.TrimSuffix(r.Prefix, "-")
|
||||
}
|
||||
}
|
||||
|
||||
return "gt" // Default prefix
|
||||
}
|
||||
|
||||
// FindConflictingPrefixes checks for duplicate prefixes in routes.
|
||||
// Returns a map of prefix -> list of paths that use it.
|
||||
func FindConflictingPrefixes(beadsDir string) (map[string][]string, error) {
|
||||
|
||||
86
internal/beads/routes_test.go
Normal file
86
internal/beads/routes_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package beads
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetPrefixForRig(t *testing.T) {
|
||||
// Create a temporary directory with routes.jsonl
|
||||
tmpDir := t.TempDir()
|
||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
routesContent := `{"prefix": "gt-", "path": "gastown/mayor/rig"}
|
||||
{"prefix": "bd-", "path": "beads/mayor/rig"}
|
||||
{"prefix": "hq-", "path": "."}
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(beadsDir, "routes.jsonl"), []byte(routesContent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
rig string
|
||||
expected string
|
||||
}{
|
||||
{"gastown", "gt"},
|
||||
{"beads", "bd"},
|
||||
{"unknown", "gt"}, // default
|
||||
{"", "gt"}, // empty rig -> default
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.rig, func(t *testing.T) {
|
||||
result := GetPrefixForRig(tmpDir, tc.rig)
|
||||
if result != tc.expected {
|
||||
t.Errorf("GetPrefixForRig(%q, %q) = %q, want %q", tmpDir, tc.rig, result, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPrefixForRig_NoRoutesFile(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
// No routes.jsonl file
|
||||
|
||||
result := GetPrefixForRig(tmpDir, "anything")
|
||||
if result != "gt" {
|
||||
t.Errorf("Expected default 'gt' when no routes file, got %q", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentBeadIDsWithPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func() string
|
||||
expected string
|
||||
}{
|
||||
{"PolecatBeadIDWithPrefix bd beads obsidian",
|
||||
func() string { return PolecatBeadIDWithPrefix("bd", "beads", "obsidian") },
|
||||
"bd-beads-polecat-obsidian"},
|
||||
{"PolecatBeadIDWithPrefix gt gastown Toast",
|
||||
func() string { return PolecatBeadIDWithPrefix("gt", "gastown", "Toast") },
|
||||
"gt-gastown-polecat-Toast"},
|
||||
{"WitnessBeadIDWithPrefix bd beads",
|
||||
func() string { return WitnessBeadIDWithPrefix("bd", "beads") },
|
||||
"bd-beads-witness"},
|
||||
{"RefineryBeadIDWithPrefix bd beads",
|
||||
func() string { return RefineryBeadIDWithPrefix("bd", "beads") },
|
||||
"bd-beads-refinery"},
|
||||
{"CrewBeadIDWithPrefix bd beads max",
|
||||
func() string { return CrewBeadIDWithPrefix("bd", "beads", "max") },
|
||||
"bd-beads-crew-max"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result := tc.fn()
|
||||
if result != tc.expected {
|
||||
t.Errorf("got %q, want %q", result, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/steveyegge/gastown/internal/session"
|
||||
"github.com/steveyegge/gastown/internal/style"
|
||||
"github.com/steveyegge/gastown/internal/tmux"
|
||||
"github.com/steveyegge/gastown/internal/workspace"
|
||||
)
|
||||
|
||||
var slingCmd = &cobra.Command{
|
||||
@@ -790,8 +791,9 @@ func detectActor() string {
|
||||
|
||||
// agentIDToBeadID converts an agent ID to its corresponding agent bead ID.
|
||||
// Uses canonical naming: prefix-rig-role-name
|
||||
// The prefix is looked up from routes.jsonl based on the rig name.
|
||||
func agentIDToBeadID(agentID string) string {
|
||||
// Handle simple cases
|
||||
// Handle simple cases (town-level agents always use gt- prefix)
|
||||
if agentID == "mayor" {
|
||||
return beads.MayorBeadID()
|
||||
}
|
||||
@@ -807,15 +809,21 @@ func agentIDToBeadID(agentID string) string {
|
||||
|
||||
rig := parts[0]
|
||||
|
||||
// Look up the prefix for this rig from routes.jsonl
|
||||
prefix := "gt" // default
|
||||
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
|
||||
prefix = beads.GetPrefixForRig(townRoot, rig)
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(parts) == 2 && parts[1] == "witness":
|
||||
return beads.WitnessBeadID(rig)
|
||||
return beads.WitnessBeadIDWithPrefix(prefix, rig)
|
||||
case len(parts) == 2 && parts[1] == "refinery":
|
||||
return beads.RefineryBeadID(rig)
|
||||
return beads.RefineryBeadIDWithPrefix(prefix, rig)
|
||||
case len(parts) == 3 && parts[1] == "crew":
|
||||
return beads.CrewBeadID(rig, parts[2])
|
||||
return beads.CrewBeadIDWithPrefix(prefix, rig, parts[2])
|
||||
case len(parts) == 3 && parts[1] == "polecats":
|
||||
return beads.PolecatBeadID(rig, parts[2])
|
||||
return beads.PolecatBeadIDWithPrefix(prefix, rig, parts[2])
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user