diff --git a/cmd/bd/create.go b/cmd/bd/create.go index eb72d1ca..7dcb23c9 100644 --- a/cmd/bd/create.go +++ b/cmd/bd/create.go @@ -128,6 +128,16 @@ var createCmd = &cobra.Command{ deps, _ := cmd.Flags().GetStringSlice("deps") forceCreate, _ := cmd.Flags().GetBool("force") repoOverride, _ := cmd.Flags().GetString("repo") + + // Get estimate if provided + var estimatedMinutes *int + if cmd.Flags().Changed("estimate") { + est, _ := cmd.Flags().GetInt("estimate") + if est < 0 { + FatalError("estimate must be a non-negative number of minutes") + } + estimatedMinutes = &est + } // Use global jsonOutput set by PersistentPreRun // Determine target repository using routing logic @@ -227,6 +237,7 @@ var createCmd = &cobra.Command{ AcceptanceCriteria: acceptance, Assignee: assignee, ExternalRef: externalRef, + EstimatedMinutes: estimatedMinutes, Labels: labels, Dependencies: deps, } @@ -264,6 +275,7 @@ var createCmd = &cobra.Command{ IssueType: types.IssueType(issueType), Assignee: assignee, ExternalRef: externalRefPtr, + EstimatedMinutes: estimatedMinutes, } ctx := rootCtx @@ -402,6 +414,7 @@ func init() { createCmd.Flags().StringSlice("deps", []string{}, "Dependencies in format 'type:id' or 'id' (e.g., 'discovered-from:bd-20,blocks:bd-15' or 'bd-20')") createCmd.Flags().Bool("force", false, "Force creation even if prefix doesn't match database prefix") createCmd.Flags().String("repo", "", "Target repository for issue (overrides auto-routing)") + createCmd.Flags().IntP("estimate", "e", 0, "Time estimate in minutes (e.g., 60 for 1 hour)") // Note: --json flag is defined as a persistent flag in main.go, not here rootCmd.AddCommand(createCmd) } diff --git a/cmd/bd/show.go b/cmd/bd/show.go index 975c7771..ca7fd925 100644 --- a/cmd/bd/show.go +++ b/cmd/bd/show.go @@ -506,6 +506,14 @@ var updateCmd = &cobra.Command{ externalRef, _ := cmd.Flags().GetString("external-ref") updates["external_ref"] = externalRef } + if cmd.Flags().Changed("estimate") { + estimate, _ := cmd.Flags().GetInt("estimate") + if estimate < 0 { + fmt.Fprintf(os.Stderr, "Error: estimate must be a non-negative number of minutes\n") + os.Exit(1) + } + updates["estimated_minutes"] = estimate + } if cmd.Flags().Changed("add-label") { addLabels, _ := cmd.Flags().GetStringSlice("add-label") updates["add_labels"] = addLabels @@ -583,9 +591,12 @@ var updateCmd = &cobra.Command{ if acceptanceCriteria, ok := updates["acceptance_criteria"].(string); ok { updateArgs.AcceptanceCriteria = &acceptanceCriteria } - if externalRef, ok := updates["external_ref"].(string); ok { // NEW: Map external_ref + if externalRef, ok := updates["external_ref"].(string); ok { updateArgs.ExternalRef = &externalRef } + if estimate, ok := updates["estimated_minutes"].(int); ok { + updateArgs.EstimatedMinutes = &estimate + } if addLabels, ok := updates["add_labels"].([]string); ok { updateArgs.AddLabels = addLabels } @@ -1012,6 +1023,7 @@ func init() { updateCmd.Flags().String("notes", "", "Additional notes") updateCmd.Flags().String("acceptance-criteria", "", "DEPRECATED: use --acceptance") _ = updateCmd.Flags().MarkHidden("acceptance-criteria") + updateCmd.Flags().IntP("estimate", "e", 0, "Time estimate in minutes (e.g., 60 for 1 hour)") updateCmd.Flags().StringSlice("add-label", nil, "Add labels (repeatable)") updateCmd.Flags().StringSlice("remove-label", nil, "Remove labels (repeatable)") updateCmd.Flags().StringSlice("set-labels", nil, "Set labels, replacing all existing (repeatable)") diff --git a/internal/rpc/protocol.go b/internal/rpc/protocol.go index c410fd2f..9f16bd35 100644 --- a/internal/rpc/protocol.go +++ b/internal/rpc/protocol.go @@ -68,6 +68,7 @@ type CreateArgs struct { AcceptanceCriteria string `json:"acceptance_criteria,omitempty"` Assignee string `json:"assignee,omitempty"` ExternalRef string `json:"external_ref,omitempty"` // Link to external issue trackers + EstimatedMinutes *int `json:"estimated_minutes,omitempty"` // Time estimate in minutes Labels []string `json:"labels,omitempty"` Dependencies []string `json:"dependencies,omitempty"` } @@ -84,6 +85,7 @@ type UpdateArgs struct { Notes *string `json:"notes,omitempty"` Assignee *string `json:"assignee,omitempty"` ExternalRef *string `json:"external_ref,omitempty"` // Link to external issue trackers + EstimatedMinutes *int `json:"estimated_minutes,omitempty"` // Time estimate in minutes AddLabels []string `json:"add_labels,omitempty"` RemoveLabels []string `json:"remove_labels,omitempty"` SetLabels []string `json:"set_labels,omitempty"` diff --git a/internal/rpc/server_issues_epics.go b/internal/rpc/server_issues_epics.go index 86abf278..c9441563 100644 --- a/internal/rpc/server_issues_epics.go +++ b/internal/rpc/server_issues_epics.go @@ -70,6 +70,9 @@ func updatesFromArgs(a UpdateArgs) map[string]interface{} { if a.ExternalRef != nil { u["external_ref"] = *a.ExternalRef } + if a.EstimatedMinutes != nil { + u["estimated_minutes"] = *a.EstimatedMinutes + } return u } @@ -142,6 +145,7 @@ func (s *Server) handleCreate(req *Request) Response { AcceptanceCriteria: strValue(acceptance), Assignee: strValue(assignee), ExternalRef: externalRef, + EstimatedMinutes: createArgs.EstimatedMinutes, Status: types.StatusOpen, }