fix: auto-create agent bead when bd agent state called on non-existent agent

Previously, `bd agent state <agent> <state>` would fail if the agent bead
didn't exist in the database. This caused issues when `gt sling` tried to
update agent state for newly spawned polecats.

Now when the agent doesn't exist:
1. Parse role_type and rig from the agent ID (e.g., gt-gastown-polecat-nux)
2. Auto-create the agent bead with type=agent
3. Add role_type and rig labels for filtering (bd list --label=role_type:polecat)
4. Continue with the state update

This enables:
- Work history accumulation per polecat name
- Skill/success tracking over time
- `bd list --type=agent` to see all agents

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
obsidian
2026-01-02 12:26:56 -08:00
committed by Steve Yegge
parent 76359764fd
commit f37fe949e8
2 changed files with 229 additions and 21 deletions

View File

@@ -48,3 +48,95 @@ func TestFormatTimeOrNil(t *testing.T) {
t.Errorf("expected nil for nil time, got %v", result)
}
}
func TestParseAgentIDFields(t *testing.T) {
tests := []struct {
name string
agentID string
wantRoleType string
wantRig string
}{
// Town-level roles
{
name: "town-level mayor",
agentID: "gt-mayor",
wantRoleType: "mayor",
wantRig: "",
},
{
name: "town-level deacon",
agentID: "bd-deacon",
wantRoleType: "deacon",
wantRig: "",
},
// Per-rig singleton roles
{
name: "rig-level witness",
agentID: "gt-gastown-witness",
wantRoleType: "witness",
wantRig: "gastown",
},
{
name: "rig-level refinery",
agentID: "bd-beads-refinery",
wantRoleType: "refinery",
wantRig: "beads",
},
// Per-rig named roles
{
name: "named polecat",
agentID: "gt-gastown-polecat-nux",
wantRoleType: "polecat",
wantRig: "gastown",
},
{
name: "named crew",
agentID: "bd-beads-crew-dave",
wantRoleType: "crew",
wantRig: "beads",
},
{
name: "polecat with hyphenated name",
agentID: "gt-gastown-polecat-nux-123",
wantRoleType: "polecat",
wantRig: "gastown",
},
// Edge cases
{
name: "no hyphen",
agentID: "invalid",
wantRoleType: "",
wantRig: "",
},
{
name: "empty string",
agentID: "",
wantRoleType: "",
wantRig: "",
},
{
name: "unknown role",
agentID: "gt-gastown-unknown",
wantRoleType: "",
wantRig: "",
},
{
name: "prefix only",
agentID: "gt-",
wantRoleType: "",
wantRig: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotRoleType, gotRig := parseAgentIDFields(tt.agentID)
if gotRoleType != tt.wantRoleType {
t.Errorf("parseAgentIDFields(%q) roleType = %q, want %q", tt.agentID, gotRoleType, tt.wantRoleType)
}
if gotRig != tt.wantRig {
t.Errorf("parseAgentIDFields(%q) rig = %q, want %q", tt.agentID, gotRig, tt.wantRig)
}
})
}
}