feat(rig): add rig identity bead schema and creation (gt-zmznh)
- Add RigFields struct, CreateRigBead, RigBeadID helpers to beads package - Modify gt rig add to create rig identity bead after rig creation - Schema: id=<prefix>-rig-<name>, type=rig, with repo/prefix/state fields 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1780,3 +1780,113 @@ func (b *Beads) MergeSlotEnsureExists() (string, error) {
|
||||
|
||||
return status.ID, nil
|
||||
}
|
||||
|
||||
// ===== Rig Identity Beads =====
|
||||
|
||||
// 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,
|
||||
"--type=rig",
|
||||
"--title=" + title,
|
||||
"--description=" + description,
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -366,12 +366,16 @@ func runRigAdd(cmd *cobra.Command, args []string) error {
|
||||
// - Otherwise route to rig root (where initBeads creates the database)
|
||||
// The conditional routing is necessary because initBeads creates the database at
|
||||
// "<rig>/.beads", while repos with tracked beads have their database at mayor/rig/.beads.
|
||||
var beadsWorkDir string
|
||||
if newRig.Config.Prefix != "" {
|
||||
routePath := name
|
||||
mayorRigBeads := filepath.Join(townRoot, name, "mayor", "rig", ".beads")
|
||||
if _, err := os.Stat(mayorRigBeads); err == nil {
|
||||
// Source repo has .beads/ tracked - route to mayor/rig
|
||||
routePath = name + "/mayor/rig"
|
||||
beadsWorkDir = filepath.Join(townRoot, name, "mayor", "rig")
|
||||
} else {
|
||||
beadsWorkDir = filepath.Join(townRoot, name)
|
||||
}
|
||||
route := beads.Route{
|
||||
Prefix: newRig.Config.Prefix + "-",
|
||||
@@ -383,6 +387,23 @@ func runRigAdd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Create rig identity bead
|
||||
if newRig.Config.Prefix != "" && beadsWorkDir != "" {
|
||||
bd := beads.New(beadsWorkDir)
|
||||
rigBeadID := beads.RigBeadIDWithPrefix(newRig.Config.Prefix, name)
|
||||
fields := &beads.RigFields{
|
||||
Repo: gitURL,
|
||||
Prefix: newRig.Config.Prefix,
|
||||
State: "active",
|
||||
}
|
||||
if _, err := bd.CreateRigBead(rigBeadID, name, fields); err != nil {
|
||||
// Non-fatal: rig is functional without the identity bead
|
||||
fmt.Printf(" %s Could not create rig identity bead: %v\n", style.Warning.Render("!"), err)
|
||||
} else {
|
||||
fmt.Printf(" Created rig identity bead: %s\n", rigBeadID)
|
||||
}
|
||||
}
|
||||
|
||||
elapsed := time.Since(startTime)
|
||||
|
||||
// Read default branch from rig config
|
||||
|
||||
Reference in New Issue
Block a user