fix: Bypass daemon for routed IDs in show command (bd-uu8p)

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 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-26 14:54:29 -08:00
parent f11ad08ad9
commit a9237741d2
2 changed files with 78 additions and 4 deletions

View File

@@ -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
}

View File

@@ -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 {