Refactor burn/squash cleanup to recursive helper (gt-psj76.1)
Extract closeDescendants() helper that: - Recursively closes all descendants (not just direct children) - Logs errors instead of silent failure - Uses distinct variable names (no shadowing) - Is reused by both burn and squash This handles nested molecules from the Christmas Ornament pattern. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -337,30 +337,9 @@ func runMoleculeBurn(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
moleculeID := attachment.AttachedMolecule
|
moleculeID := attachment.AttachedMolecule
|
||||||
|
|
||||||
// Close all child step issues before detaching
|
// Recursively close all descendant step issues before detaching
|
||||||
// This prevents orphaned step issues from accumulating (gt-psj76.1)
|
// This prevents orphaned step issues from accumulating (gt-psj76.1)
|
||||||
childrenClosed := 0
|
childrenClosed := closeDescendants(b, moleculeID)
|
||||||
children, err := b.List(beads.ListOptions{
|
|
||||||
Parent: moleculeID,
|
|
||||||
Status: "all", // Include both open and in_progress
|
|
||||||
})
|
|
||||||
if err == nil && len(children) > 0 {
|
|
||||||
var idsToClose []string
|
|
||||||
for _, child := range children {
|
|
||||||
if child.Status != "closed" {
|
|
||||||
idsToClose = append(idsToClose, child.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(idsToClose) > 0 {
|
|
||||||
if err := b.Close(idsToClose...); err != nil {
|
|
||||||
// Log but don't fail - best effort cleanup
|
|
||||||
fmt.Printf("%s Warning: could not close all step issues: %v\n",
|
|
||||||
style.Dim.Render("⚠"), err)
|
|
||||||
} else {
|
|
||||||
childrenClosed = len(idsToClose)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detach the molecule with audit logging (this "burns" it by removing the attachment)
|
// Detach the molecule with audit logging (this "burns" it by removing the attachment)
|
||||||
_, err = b.DetachMoleculeWithAudit(handoff.ID, beads.DetachOptions{
|
_, err = b.DetachMoleculeWithAudit(handoff.ID, beads.DetachOptions{
|
||||||
@@ -462,30 +441,9 @@ func runMoleculeSquash(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
moleculeID := attachment.AttachedMolecule
|
moleculeID := attachment.AttachedMolecule
|
||||||
|
|
||||||
// Close all child step issues before squashing
|
// Recursively close all descendant step issues before squashing
|
||||||
// This prevents orphaned step issues from accumulating (gt-psj76.1)
|
// This prevents orphaned step issues from accumulating (gt-psj76.1)
|
||||||
childrenClosed := 0
|
childrenClosed := closeDescendants(b, moleculeID)
|
||||||
children, err := b.List(beads.ListOptions{
|
|
||||||
Parent: moleculeID,
|
|
||||||
Status: "all", // Include both open and in_progress
|
|
||||||
})
|
|
||||||
if err == nil && len(children) > 0 {
|
|
||||||
var idsToClose []string
|
|
||||||
for _, child := range children {
|
|
||||||
if child.Status != "closed" {
|
|
||||||
idsToClose = append(idsToClose, child.ID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(idsToClose) > 0 {
|
|
||||||
if err := b.Close(idsToClose...); err != nil {
|
|
||||||
// Log but don't fail - best effort cleanup
|
|
||||||
fmt.Printf("%s Warning: could not close all step issues: %v\n",
|
|
||||||
style.Dim.Render("⚠"), err)
|
|
||||||
} else {
|
|
||||||
childrenClosed = len(idsToClose)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get progress info for the digest
|
// Get progress info for the digest
|
||||||
progress, _ := getMoleculeProgressInfo(b, moleculeID)
|
progress, _ := getMoleculeProgressInfo(b, moleculeID)
|
||||||
@@ -569,3 +527,46 @@ squashed_at: %s
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closeDescendants recursively closes all descendant issues of a parent.
|
||||||
|
// Returns the count of issues closed. Logs warnings on errors but doesn't fail.
|
||||||
|
func closeDescendants(b *beads.Beads, parentID string) int {
|
||||||
|
children, err := b.List(beads.ListOptions{
|
||||||
|
Parent: parentID,
|
||||||
|
Status: "all",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s Warning: could not list children of %s: %v\n",
|
||||||
|
style.Dim.Render("⚠"), parentID, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(children) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, recursively close grandchildren
|
||||||
|
totalClosed := 0
|
||||||
|
for _, child := range children {
|
||||||
|
totalClosed += closeDescendants(b, child.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then close direct children
|
||||||
|
var idsToClose []string
|
||||||
|
for _, child := range children {
|
||||||
|
if child.Status != "closed" {
|
||||||
|
idsToClose = append(idsToClose, child.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(idsToClose) > 0 {
|
||||||
|
if closeErr := b.Close(idsToClose...); closeErr != nil {
|
||||||
|
fmt.Printf("%s Warning: could not close children of %s: %v\n",
|
||||||
|
style.Dim.Render("⚠"), parentID, closeErr)
|
||||||
|
} else {
|
||||||
|
totalClosed += len(idsToClose)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalClosed
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user