feat(completion): optimize ID prefix filtering and add completions to more commands

Improvements to shell completions from PR #935:

1. Add IDPrefix field to IssueFilter for efficient database-level filtering
   - Queries are now filtered at SQL level instead of fetching all issues
   - Updated sqlite, transaction, and memory stores to support IDPrefix

2. Add ValidArgsFunction to additional commands:
   - dep (add, remove, list, tree)
   - comments, comment (add)
   - delete
   - graph
   - label (add, remove, list)
   - duplicate, supersede
   - audit
   - move
   - relate, unrelate
   - refile
   - gate (show, resolve, add-waiter)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Executed-By: beads/crew/dave
Rig: beads
Role: crew
This commit is contained in:
beads/crew/dave
2026-01-06 19:05:34 -08:00
committed by Steve Yegge
parent 025cdac962
commit 5dfb838d60
16 changed files with 59 additions and 11 deletions

View File

@@ -160,6 +160,9 @@ func init() {
auditLabelCmd.Flags().StringVar(&auditLabelValue, "label", "", `Label value (e.g. "good" or "bad")`)
auditLabelCmd.Flags().StringVar(&auditLabelReason, "reason", "", "Reason for label")
// Issue ID completions
auditCmd.ValidArgsFunction = issueIDCompletion
auditCmd.AddCommand(auditRecordCmd)
auditCmd.AddCommand(auditLabelCmd)
rootCmd.AddCommand(auditCmd)

View File

@@ -218,11 +218,16 @@ func init() {
commentsCmd.AddCommand(commentsAddCmd)
commentsAddCmd.Flags().StringP("file", "f", "", "Read comment text from file")
commentsAddCmd.Flags().StringP("author", "a", "", "Add author to comment")
// Add the same flags to the alias
commentCmd.Flags().StringP("file", "f", "", "Read comment text from file")
commentCmd.Flags().StringP("author", "a", "", "Add author to comment")
// Issue ID completions
commentsCmd.ValidArgsFunction = issueIDCompletion
commentsAddCmd.ValidArgsFunction = issueIDCompletion
commentCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(commentsCmd)
rootCmd.AddCommand(commentCmd)
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
@@ -51,8 +50,10 @@ func issueIDCompletion(cmd *cobra.Command, args []string, toComplete string) ([]
defer currentStore.Close()
}
// Use SearchIssues with empty query and default filter to get all issues
filter := types.IssueFilter{}
// Use SearchIssues with IDPrefix filter to efficiently query matching issues
filter := types.IssueFilter{
IDPrefix: toComplete, // Filter at database level for better performance
}
issues, err := currentStore.SearchIssues(ctx, "", filter)
if err != nil {
// If we can't list issues, return empty completion
@@ -62,11 +63,6 @@ func issueIDCompletion(cmd *cobra.Command, args []string, toComplete string) ([]
// Build completion list
completions := make([]string, 0, len(issues))
for _, issue := range issues {
// Filter based on what's already typed
if toComplete != "" && !strings.HasPrefix(issue.ID, toComplete) {
continue
}
// Format: ID\tTitle (shown during completion)
completions = append(completions, fmt.Sprintf("%s\t%s", issue.ID, issue.Title))
}

View File

@@ -833,5 +833,6 @@ func init() {
deleteCmd.Flags().Bool("cascade", false, "Recursively delete all dependent issues")
deleteCmd.Flags().Bool("hard", false, "Permanently delete (skip tombstone, cannot be recovered via sync)")
deleteCmd.Flags().String("reason", "", "Reason for deletion (stored in tombstone for audit trail)")
deleteCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(deleteCmd)
}

View File

@@ -1167,6 +1167,12 @@ func init() {
depListCmd.Flags().String("direction", "down", "Direction: 'down' (dependencies), 'up' (dependents)")
depListCmd.Flags().StringP("type", "t", "", "Filter by dependency type (e.g., tracks, blocks, parent-child)")
// Issue ID completions for dep subcommands
depAddCmd.ValidArgsFunction = issueIDCompletion
depRemoveCmd.ValidArgsFunction = issueIDCompletion
depListCmd.ValidArgsFunction = issueIDCompletion
depTreeCmd.ValidArgsFunction = issueIDCompletion
depCmd.AddCommand(depAddCmd)
depCmd.AddCommand(depRemoveCmd)
depCmd.AddCommand(depListCmd)

View File

@@ -50,10 +50,12 @@ var (
func init() {
duplicateCmd.Flags().StringVar(&duplicateOf, "of", "", "Canonical issue ID (required)")
_ = duplicateCmd.MarkFlagRequired("of") // Only fails if flag missing (caught in tests)
duplicateCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(duplicateCmd)
supersedeCmd.Flags().StringVar(&supersededWith, "with", "", "Replacement issue ID (required)")
_ = supersedeCmd.MarkFlagRequired("with") // Only fails if flag missing (caught in tests)
supersedeCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(supersedeCmd)
}

View File

@@ -871,6 +871,11 @@ func init() {
gateCheckCmd.Flags().BoolP("escalate", "e", false, "Escalate failed/expired gates")
gateCheckCmd.Flags().IntP("limit", "l", 100, "Limit results (default 100)")
// Issue ID completions
gateShowCmd.ValidArgsFunction = issueIDCompletion
gateResolveCmd.ValidArgsFunction = issueIDCompletion
gateAddWaiterCmd.ValidArgsFunction = issueIDCompletion
// Add subcommands
gateCmd.AddCommand(gateListCmd)
gateCmd.AddCommand(gateShowCmd)

View File

@@ -117,6 +117,7 @@ Colors indicate status:
}
func init() {
graphCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(graphCmd)
}

View File

@@ -314,6 +314,11 @@ var labelListAllCmd = &cobra.Command{
},
}
func init() {
// Issue ID completions
labelAddCmd.ValidArgsFunction = issueIDCompletion
labelRemoveCmd.ValidArgsFunction = issueIDCompletion
labelListCmd.ValidArgsFunction = issueIDCompletion
labelCmd.AddCommand(labelAddCmd)
labelCmd.AddCommand(labelRemoveCmd)
labelCmd.AddCommand(labelListCmd)

View File

@@ -276,5 +276,6 @@ func init() {
moveCmd.Flags().String("to", "", "Target rig or prefix (required)")
moveCmd.Flags().Bool("keep-open", false, "Keep the source issue open (don't close it)")
moveCmd.Flags().Bool("skip-deps", false, "Skip dependency remapping")
moveCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(moveCmd)
}

View File

@@ -160,5 +160,6 @@ Examples:
func init() {
refileCmd.Flags().Bool("keep-open", false, "Keep the source issue open (don't close it)")
refileCmd.ValidArgsFunction = issueIDCompletion
rootCmd.AddCommand(refileCmd)
}

View File

@@ -41,6 +41,10 @@ Example:
}
func init() {
// Issue ID completions
relateCmd.ValidArgsFunction = issueIDCompletion
unrelateCmd.ValidArgsFunction = issueIDCompletion
// Add as subcommands of dep
depCmd.AddCommand(relateCmd)
depCmd.AddCommand(unrelateCmd)