diff --git a/cmd/bd/list.go b/cmd/bd/list.go index 9adc4c04..3cdaaf32 100644 --- a/cmd/bd/list.go +++ b/cmd/bd/list.go @@ -315,6 +315,7 @@ var listCmd = &cobra.Command{ assignee, _ := cmd.Flags().GetString("assignee") issueType, _ := cmd.Flags().GetString("type") limit, _ := cmd.Flags().GetInt("limit") + allFlag, _ := cmd.Flags().GetBool("all") formatStr, _ := cmd.Flags().GetString("format") labels, _ := cmd.Flags().GetStringSlice("label") labelsAny, _ := cmd.Flags().GetStringSlice("label-any") @@ -404,6 +405,11 @@ var listCmd = &cobra.Command{ s := types.Status(status) filter.Status = &s } + + // Default to non-closed issues unless --all or explicit --status (GH#788) + if status == "" && !allFlag { + filter.ExcludeStatus = []types.Status{types.StatusClosed} + } // Use Changed() to properly handle P0 (priority=0) if cmd.Flags().Changed("priority") { priorityStr, _ := cmd.Flags().GetString("priority") @@ -573,7 +579,7 @@ var listCmd = &cobra.Command{ Status: status, IssueType: issueType, Assignee: assignee, - Limit: limit, + Limit: effectiveLimit, } if cmd.Flags().Changed("priority") { priorityStr, _ := cmd.Flags().GetString("priority") @@ -641,6 +647,13 @@ var listCmd = &cobra.Command{ // Parent filtering listArgs.ParentID = parentID + // Status exclusion (GH#788) + if len(filter.ExcludeStatus) > 0 { + for _, s := range filter.ExcludeStatus { + listArgs.ExcludeStatus = append(listArgs.ExcludeStatus, string(s)) + } + } + resp, err := daemonClient.List(listArgs) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) @@ -906,7 +919,7 @@ func init() { listCmd.Flags().String("id", "", "Filter by specific issue IDs (comma-separated, e.g., bd-1,bd-5,bd-10)") listCmd.Flags().IntP("limit", "n", 50, "Limit results (default 50, use 0 for unlimited)") listCmd.Flags().String("format", "", "Output format: 'digraph' (for golang.org/x/tools/cmd/digraph), 'dot' (Graphviz), or Go template") - listCmd.Flags().Bool("all", false, "Show all issues (default behavior; flag provided for CLI familiarity)") + listCmd.Flags().Bool("all", false, "Show all issues including closed (overrides default filter)") listCmd.Flags().Bool("long", false, "Show detailed multi-line output for each issue") listCmd.Flags().String("sort", "", "Sort by field: priority, created, updated, closed, status, id, title, type, assignee") listCmd.Flags().BoolP("reverse", "r", false, "Reverse sort order") diff --git a/internal/rpc/protocol.go b/internal/rpc/protocol.go index 4aa58982..78897736 100644 --- a/internal/rpc/protocol.go +++ b/internal/rpc/protocol.go @@ -208,6 +208,9 @@ type ListArgs struct { // Molecule type filtering MolType string `json:"mol_type,omitempty"` + + // Status exclusion (for default non-closed behavior, GH#788) + ExcludeStatus []string `json:"exclude_status,omitempty"` } // CountArgs represents arguments for the count operation diff --git a/internal/rpc/server_issues_epics.go b/internal/rpc/server_issues_epics.go index 08c39484..a885c00d 100644 --- a/internal/rpc/server_issues_epics.go +++ b/internal/rpc/server_issues_epics.go @@ -980,6 +980,13 @@ func (s *Server) handleList(req *Request) Response { filter.MolType = &molType } + // Status exclusion (for default non-closed behavior, GH#788) + if len(listArgs.ExcludeStatus) > 0 { + for _, s := range listArgs.ExcludeStatus { + filter.ExcludeStatus = append(filter.ExcludeStatus, types.Status(s)) + } + } + // Guard against excessive ID lists to avoid SQLite parameter limits const maxIDs = 1000 if len(filter.IDs) > maxIDs { diff --git a/internal/storage/sqlite/queries.go b/internal/storage/sqlite/queries.go index 3798f5a7..b8034f42 100644 --- a/internal/storage/sqlite/queries.go +++ b/internal/storage/sqlite/queries.go @@ -1604,6 +1604,16 @@ func (s *SQLiteStorage) SearchIssues(ctx context.Context, query string, filter t args = append(args, types.StatusTombstone) } + // Status exclusion (for default non-closed behavior, GH#788) + if len(filter.ExcludeStatus) > 0 { + placeholders := make([]string, len(filter.ExcludeStatus)) + for i, s := range filter.ExcludeStatus { + placeholders[i] = "?" + args = append(args, string(s)) + } + whereClauses = append(whereClauses, fmt.Sprintf("status NOT IN (%s)", strings.Join(placeholders, ","))) + } + if filter.Priority != nil { whereClauses = append(whereClauses, "priority = ?") args = append(args, *filter.Priority) diff --git a/internal/storage/sqlite/transaction.go b/internal/storage/sqlite/transaction.go index 627bc14b..1229c7e8 100644 --- a/internal/storage/sqlite/transaction.go +++ b/internal/storage/sqlite/transaction.go @@ -998,6 +998,16 @@ func (t *sqliteTxStorage) SearchIssues(ctx context.Context, query string, filter args = append(args, types.StatusTombstone) } + // Status exclusion (for default non-closed behavior, GH#788) + if len(filter.ExcludeStatus) > 0 { + placeholders := make([]string, len(filter.ExcludeStatus)) + for i, s := range filter.ExcludeStatus { + placeholders[i] = "?" + args = append(args, string(s)) + } + whereClauses = append(whereClauses, fmt.Sprintf("status NOT IN (%s)", strings.Join(placeholders, ","))) + } + if filter.Priority != nil { whereClauses = append(whereClauses, "priority = ?") args = append(args, *filter.Priority) diff --git a/internal/types/types.go b/internal/types/types.go index d7710b6d..75e12524 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -720,6 +720,9 @@ type IssueFilter struct { // Molecule type filtering MolType *MolType // Filter by molecule type (nil = any, swarm/patrol/work) + + // Status exclusion (for default non-closed behavior) + ExcludeStatus []Status // Exclude issues with these statuses } // SortPolicy determines how ready work is ordered