Files
gastown/internal/beads/beads_rig.go
JJ b1a5241430 fix(beads): align agent bead prefixes and force multi-hyphen IDs (#482)
* fix(beads): align agent bead prefixes and force multi-hyphen IDs

* fix(checkpoint): treat threshold as stale at boundary
2026-01-16 12:33:51 -08:00

121 lines
3.1 KiB
Go

// Package beads provides rig identity bead management.
package beads
import (
"encoding/json"
"fmt"
"os"
"strings"
)
// RigFields contains the fields specific to rig identity beads.
type RigFields struct {
Repo string // Git URL for the rig's repository
Prefix string // Beads prefix for this rig (e.g., "gt", "bd")
State string // Operational state: active, archived, maintenance
}
// FormatRigDescription formats the description field for a rig identity bead.
func FormatRigDescription(name string, fields *RigFields) string {
if fields == nil {
return ""
}
var lines []string
lines = append(lines, fmt.Sprintf("Rig identity bead for %s.", name))
lines = append(lines, "")
if fields.Repo != "" {
lines = append(lines, fmt.Sprintf("repo: %s", fields.Repo))
}
if fields.Prefix != "" {
lines = append(lines, fmt.Sprintf("prefix: %s", fields.Prefix))
}
if fields.State != "" {
lines = append(lines, fmt.Sprintf("state: %s", fields.State))
}
return strings.Join(lines, "\n")
}
// ParseRigFields extracts rig fields from an issue's description.
func ParseRigFields(description string) *RigFields {
fields := &RigFields{}
for _, line := range strings.Split(description, "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
colonIdx := strings.Index(line, ":")
if colonIdx == -1 {
continue
}
key := strings.TrimSpace(line[:colonIdx])
value := strings.TrimSpace(line[colonIdx+1:])
if value == "null" || value == "" {
value = ""
}
switch strings.ToLower(key) {
case "repo":
fields.Repo = value
case "prefix":
fields.Prefix = value
case "state":
fields.State = value
}
}
return fields
}
// CreateRigBead creates a rig identity bead for tracking rig metadata.
// The ID format is: <prefix>-rig-<name> (e.g., gt-rig-gastown)
// Use RigBeadID() helper to generate correct IDs.
// The created_by field is populated from BD_ACTOR env var for provenance tracking.
func (b *Beads) CreateRigBead(id, title string, fields *RigFields) (*Issue, error) {
description := FormatRigDescription(title, fields)
args := []string{"create", "--json",
"--id=" + id,
"--title=" + title,
"--description=" + description,
"--labels=gt:rig",
}
if NeedsForceForID(id) {
args = append(args, "--force")
}
// Default actor from BD_ACTOR env var for provenance tracking
if actor := os.Getenv("BD_ACTOR"); actor != "" {
args = append(args, "--actor="+actor)
}
out, err := b.run(args...)
if err != nil {
return nil, err
}
var issue Issue
if err := json.Unmarshal(out, &issue); err != nil {
return nil, fmt.Errorf("parsing bd create output: %w", err)
}
return &issue, nil
}
// RigBeadIDWithPrefix generates a rig identity bead ID using the specified prefix.
// Format: <prefix>-rig-<name> (e.g., gt-rig-gastown)
func RigBeadIDWithPrefix(prefix, name string) string {
return fmt.Sprintf("%s-rig-%s", prefix, name)
}
// RigBeadID generates a rig identity bead ID using "gt" prefix.
// For non-gastown rigs, use RigBeadIDWithPrefix with the rig's configured prefix.
func RigBeadID(name string) string {
return RigBeadIDWithPrefix("gt", name)
}