feat(bd): add --children flag to bd show command (#1069)

Adds a --children flag to the bd show command that displays only the
children of the specified issue. This is useful for quickly viewing
child steps of an epic without the full issue details.

The flag supports:
- Default mode: shows children with full dependency line formatting
- --short mode: shows compact one-liner per child
- --json mode: outputs children in JSON format

Fixes gt-lzf3.5

Co-authored-by: toast <julianknutsen@users.noreply.github>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Julian Knutsen
2026-01-13 19:41:28 +00:00
committed by GitHub
parent f27fed9577
commit a2bf15ee48

View File

@@ -24,6 +24,7 @@ var showCmd = &cobra.Command{
showThread, _ := cmd.Flags().GetBool("thread")
shortMode, _ := cmd.Flags().GetBool("short")
showRefs, _ := cmd.Flags().GetBool("refs")
showChildren, _ := cmd.Flags().GetBool("children")
ctx := rootCtx
// Check database freshness before reading
@@ -83,6 +84,12 @@ var showCmd = &cobra.Command{
return
}
// Handle --children flag: show only children of this issue
if showChildren {
showIssueChildren(ctx, args, resolvedIDs, routedArgs, jsonOutput, shortMode)
return
}
// If daemon is running, use RPC (but fall back to direct mode for routed IDs)
if daemonClient != nil {
allDetails := []interface{}{}
@@ -898,6 +905,125 @@ func getRefTypeEmoji(depType types.DependencyType) string {
}
}
// showIssueChildren displays only the children of the specified issue(s)
func showIssueChildren(ctx context.Context, args []string, resolvedIDs []string, routedArgs []string, jsonOut bool, shortMode bool) {
// Collect all children for all issues
allChildren := make(map[string][]*types.IssueWithDependencyMetadata)
// Process each issue to get its children
processIssue := func(issueID string, issueStore storage.Storage) error {
sqliteStore, ok := issueStore.(*sqlite.SQLiteStorage)
if !ok {
// Fallback: try to get dependents without metadata
dependents, err := issueStore.GetDependents(ctx, issueID)
if err != nil {
return err
}
// Filter for parent-child relationships (can't filter without metadata)
for _, dep := range dependents {
allChildren[issueID] = append(allChildren[issueID], &types.IssueWithDependencyMetadata{Issue: *dep})
}
return nil
}
// Get all dependents with metadata so we can filter for children
refs, err := sqliteStore.GetDependentsWithMetadata(ctx, issueID)
if err != nil {
return err
}
// Filter for only parent-child relationships
for _, ref := range refs {
if ref.DependencyType == types.DepParentChild {
allChildren[issueID] = append(allChildren[issueID], ref)
}
}
return nil
}
// Handle routed IDs via direct mode
for _, id := range routedArgs {
result, err := resolveAndGetIssueWithRouting(ctx, store, id)
if err != nil {
fmt.Fprintf(os.Stderr, "Error resolving %s: %v\n", id, err)
continue
}
if result == nil || result.Issue == nil {
if result != nil {
result.Close()
}
fmt.Fprintf(os.Stderr, "Issue %s not found\n", id)
continue
}
if err := processIssue(result.ResolvedID, result.Store); err != nil {
fmt.Fprintf(os.Stderr, "Error getting children for %s: %v\n", id, err)
}
result.Close()
}
// Handle resolved IDs (daemon mode)
if daemonClient != nil {
for _, id := range resolvedIDs {
// Need to open direct connection for GetDependentsWithMetadata
dbStore, err := sqlite.New(ctx, dbPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error opening database: %v\n", err)
continue
}
if err := processIssue(id, dbStore); err != nil {
fmt.Fprintf(os.Stderr, "Error getting children for %s: %v\n", id, err)
}
_ = dbStore.Close()
}
} else {
// Direct mode - process each arg
for _, id := range args {
if containsStr(routedArgs, id) {
continue // Already processed above
}
result, err := resolveAndGetIssueWithRouting(ctx, store, id)
if err != nil {
fmt.Fprintf(os.Stderr, "Error resolving %s: %v\n", id, err)
continue
}
if result == nil || result.Issue == nil {
if result != nil {
result.Close()
}
fmt.Fprintf(os.Stderr, "Issue %s not found\n", id)
continue
}
if err := processIssue(result.ResolvedID, result.Store); err != nil {
fmt.Fprintf(os.Stderr, "Error getting children for %s: %v\n", id, err)
}
result.Close()
}
}
// Output results
if jsonOut {
outputJSON(allChildren)
return
}
// Display children
for issueID, children := range allChildren {
if len(children) == 0 {
fmt.Printf("%s: No children found\n", ui.RenderAccent(issueID))
continue
}
fmt.Printf("%s Children of %s (%d):\n", ui.RenderAccent("↳"), issueID, len(children))
for _, child := range children {
if shortMode {
fmt.Printf(" %s\n", formatShortIssue(&child.Issue))
} else {
fmt.Println(formatDependencyLine("↳", child))
}
}
fmt.Println()
}
}
// containsStr checks if a string slice contains a value
func containsStr(slice []string, val string) bool {
for _, s := range slice {
@@ -912,6 +1038,7 @@ func init() {
showCmd.Flags().Bool("thread", false, "Show full conversation thread (for messages)")
showCmd.Flags().Bool("short", false, "Show compact one-line output per issue")
showCmd.Flags().Bool("refs", false, "Show issues that reference this issue (reverse lookup)")
showCmd.Flags().Bool("children", false, "Show only the children of this issue")
showCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(showCmd)
}