feat(mol): add compound visualization in bd mol show (bd-iw4z)

Add visualization for compound molecules (those created by bonding protos):

- Detect compound molecules via IsCompound() check on root issue
- Display "Bonded from:" section showing constituent protos with bond types
- Show bond point when specified (attachment site within molecule)
- Format bond types as human-readable: sequential, parallel, on-failure, root
- Include is_compound and bonded_from in JSON output

Example output for compound molecules:
  🧪 Compound: proto-feature-with-tests
     ID: bd-abc123
     Steps: 5

  🔗 Bonded from:
     ├── proto-feature (sequential)
     └── proto-testing (sequential, at step-2)

Added unit tests for compound detection and bond type formatting.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beads/crew/grip
2026-01-02 13:43:07 -08:00
committed by Steve Yegge
parent 3d93166b3f
commit bb0a0ea703
2 changed files with 174 additions and 2 deletions

View File

@@ -70,14 +70,27 @@ func showMolecule(subgraph *MoleculeSubgraph) {
"issues": subgraph.Issues,
"dependencies": subgraph.Dependencies,
"variables": extractAllVariables(subgraph),
"is_compound": subgraph.Root.IsCompound(),
"bonded_from": subgraph.Root.BondedFrom,
})
return
}
fmt.Printf("\n%s Molecule: %s\n", ui.RenderAccent("🧪"), subgraph.Root.Title)
// Determine molecule type label
moleculeType := "Molecule"
if subgraph.Root.IsCompound() {
moleculeType = "Compound"
}
fmt.Printf("\n%s %s: %s\n", ui.RenderAccent("🧪"), moleculeType, subgraph.Root.Title)
fmt.Printf(" ID: %s\n", subgraph.Root.ID)
fmt.Printf(" Steps: %d\n", len(subgraph.Issues))
// Show compound bonding info if this is a compound molecule
if subgraph.Root.IsCompound() {
showCompoundBondingInfo(subgraph.Root)
}
vars := extractAllVariables(subgraph)
if len(vars) > 0 {
fmt.Printf("\n%s Variables:\n", ui.RenderWarn("📝"))
@@ -91,6 +104,52 @@ func showMolecule(subgraph *MoleculeSubgraph) {
fmt.Println()
}
// showCompoundBondingInfo displays the bonding lineage for compound molecules
func showCompoundBondingInfo(root *types.Issue) {
if !root.IsCompound() {
return
}
constituents := root.GetConstituents()
fmt.Printf("\n%s Bonded from:\n", ui.RenderAccent("🔗"))
for i, ref := range constituents {
connector := "├──"
if i == len(constituents)-1 {
connector = "└──"
}
// Format bond type for display
bondTypeDisplay := formatBondType(ref.BondType)
// Show source ID with bond type
if ref.BondPoint != "" {
fmt.Printf(" %s %s (%s, at %s)\n", connector, ref.SourceID, bondTypeDisplay, ref.BondPoint)
} else {
fmt.Printf(" %s %s (%s)\n", connector, ref.SourceID, bondTypeDisplay)
}
}
}
// formatBondType returns a human-readable bond type description
func formatBondType(bondType string) string {
switch bondType {
case types.BondTypeSequential:
return "sequential"
case types.BondTypeParallel:
return "parallel"
case types.BondTypeConditional:
return "on-failure"
case types.BondTypeRoot:
return "root"
default:
if bondType == "" {
return "default"
}
return bondType
}
}
// ParallelInfo holds parallel analysis information for a step
type ParallelInfo struct {
StepID string `json:"step_id"`
@@ -327,14 +386,27 @@ func showMoleculeWithParallel(subgraph *MoleculeSubgraph) {
"dependencies": subgraph.Dependencies,
"variables": extractAllVariables(subgraph),
"parallel": analysis,
"is_compound": subgraph.Root.IsCompound(),
"bonded_from": subgraph.Root.BondedFrom,
})
return
}
fmt.Printf("\n%s Molecule: %s\n", ui.RenderAccent("🧪"), subgraph.Root.Title)
// Determine molecule type label
moleculeType := "Molecule"
if subgraph.Root.IsCompound() {
moleculeType = "Compound"
}
fmt.Printf("\n%s %s: %s\n", ui.RenderAccent("🧪"), moleculeType, subgraph.Root.Title)
fmt.Printf(" ID: %s\n", subgraph.Root.ID)
fmt.Printf(" Steps: %d (%d ready)\n", analysis.TotalSteps, analysis.ReadySteps)
// Show compound bonding info if this is a compound molecule
if subgraph.Root.IsCompound() {
showCompoundBondingInfo(subgraph.Root)
}
// Show parallel groups summary
if len(analysis.ParallelGroups) > 0 {
fmt.Printf("\n%s Parallel Groups:\n", ui.RenderPass("⚡"))