From a9237741d2a1ac22f47a41afdfff0ac82f687971 Mon Sep 17 00:00:00 2001 From: Steve Yegge Date: Fri, 26 Dec 2025 14:54:29 -0800 Subject: [PATCH] fix: Bypass daemon for routed IDs in show command (bd-uu8p) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an ID needs routing to a different beads directory, the daemon cannot resolve it. Now we check needsRouting() before daemon resolution and handle routed IDs via direct mode with routing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cmd/bd/routed.go | 17 +++++++++++++ cmd/bd/show.go | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/cmd/bd/routed.go b/cmd/bd/routed.go index 26c0791b..ee1dd31c 100644 --- a/cmd/bd/routed.go +++ b/cmd/bd/routed.go @@ -164,3 +164,20 @@ func getRoutedStoreForID(ctx context.Context, id string) (*routing.RoutedStorage beadsDir := filepath.Dir(dbPath) return routing.GetRoutedStorageForID(ctx, id, beadsDir) } + +// needsRouting checks if an ID would be routed to a different beads directory. +// This is used to decide whether to bypass the daemon for cross-repo lookups. +func needsRouting(id string) bool { + if dbPath == "" { + return false + } + + beadsDir := filepath.Dir(dbPath) + targetDir, routed, err := routing.ResolveBeadsDirForID(context.Background(), id, beadsDir) + if err != nil || !routed { + return false + } + + // Check if the routed directory is different from the current one + return targetDir != beadsDir +} diff --git a/cmd/bd/show.go b/cmd/bd/show.go index b23a8a61..a9b50ff8 100644 --- a/cmd/bd/show.go +++ b/cmd/bd/show.go @@ -39,9 +39,15 @@ var showCmd = &cobra.Command{ // Resolve partial IDs first (daemon mode only - direct mode uses routed resolution) var resolvedIDs []string + var routedArgs []string // IDs that need cross-repo routing (bypass daemon) if daemonClient != nil { - // In daemon mode, resolve via RPC + // In daemon mode, resolve via RPC - but check routing first for _, id := range args { + // Check if this ID needs routing to a different beads directory + if needsRouting(id) { + routedArgs = append(routedArgs, id) + continue + } resolveArgs := &rpc.ResolveIDArgs{ID: id} resp, err := daemonClient.ResolveID(resolveArgs) if err != nil { @@ -74,10 +80,60 @@ var showCmd = &cobra.Command{ } } - // If daemon is running, use RPC + // If daemon is running, use RPC (but fall back to direct mode for routed IDs) if daemonClient != nil { allDetails := []interface{}{} - for idx, id := range resolvedIDs { + displayIdx := 0 + + // First, handle routed IDs via direct mode + for _, id := range routedArgs { + result, err := resolveAndGetIssueWithRouting(ctx, store, id) + if result != nil { + defer result.Close() + } + if err != nil { + fmt.Fprintf(os.Stderr, "Error fetching %s: %v\n", id, err) + continue + } + if result == nil || result.Issue == nil { + fmt.Fprintf(os.Stderr, "Issue %s not found\n", id) + continue + } + issue := result.Issue + issueStore := result.Store + if jsonOutput { + // Get labels and deps for JSON output + type IssueDetails struct { + *types.Issue + Labels []string `json:"labels,omitempty"` + Dependencies []*types.IssueWithDependencyMetadata `json:"dependencies,omitempty"` + Dependents []*types.IssueWithDependencyMetadata `json:"dependents,omitempty"` + } + details := &IssueDetails{Issue: issue} + details.Labels, _ = issueStore.GetLabels(ctx, issue.ID) + if sqliteStore, ok := issueStore.(*sqlite.SQLiteStorage); ok { + details.Dependencies, _ = sqliteStore.GetDependenciesWithMetadata(ctx, issue.ID) + details.Dependents, _ = sqliteStore.GetDependentsWithMetadata(ctx, issue.ID) + } + allDetails = append(allDetails, details) + } else { + if displayIdx > 0 { + fmt.Println("\n" + strings.Repeat("─", 60)) + } + fmt.Printf("\n%s: %s\n", ui.RenderAccent(issue.ID), issue.Title) + fmt.Printf("Status: %s\n", issue.Status) + fmt.Printf("Priority: P%d\n", issue.Priority) + fmt.Printf("Type: %s\n", issue.IssueType) + if issue.Description != "" { + fmt.Printf("\nDescription:\n%s\n", issue.Description) + } + fmt.Println() + displayIdx++ + } + } + + // Then, handle local IDs via daemon + for _, id := range resolvedIDs { showArgs := &rpc.ShowArgs{ID: id} resp, err := daemonClient.Show(showArgs) if err != nil { @@ -102,9 +158,10 @@ var showCmd = &cobra.Command{ fmt.Fprintf(os.Stderr, "Issue %s not found\n", id) continue } - if idx > 0 { + if displayIdx > 0 { fmt.Println("\n" + strings.Repeat("─", 60)) } + displayIdx++ // Parse response and use existing formatting code type IssueDetails struct {