From 413f023512d021875649d43cf7dca651ef04d4b4 Mon Sep 17 00:00:00 2001 From: Bruno Bornsztein Date: Wed, 18 Mar 2026 10:04:15 -0500 Subject: [PATCH 1/2] Add shell tab completion for CLI commands Add `ty completion [bash|zsh|fish|powershell]` command using Cobra's built-in shell completion support. Includes dynamic completions for: - Task IDs (with status and title descriptions) - Project names (for args and --project flag) - Task statuses (for `status` command and --status flag) - Task types (for args and --type flag) - Executor names (for --executor flag) - Setting keys (for `settings set` command) Co-Authored-By: Claude Opus 4.6 (1M context) --- cmd/task/completion.go | 233 ++++++++++++++++++++++++++++++++++++ cmd/task/completion_test.go | 116 ++++++++++++++++++ cmd/task/main.go | 109 +++++++++++------ 3 files changed, 420 insertions(+), 38 deletions(-) create mode 100644 cmd/task/completion.go create mode 100644 cmd/task/completion_test.go diff --git a/cmd/task/completion.go b/cmd/task/completion.go new file mode 100644 index 00000000..934045e8 --- /dev/null +++ b/cmd/task/completion.go @@ -0,0 +1,233 @@ +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + "github.com/bborn/workflow/internal/db" +) + +// newCompletionCmd creates the completion command with subcommands for each shell. +func newCompletionCmd(rootCmd *cobra.Command) *cobra.Command { + completionCmd := &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: "Generate shell completion scripts", + Long: `Generate shell completion scripts for ty. + +To load completions: + +Bash: + $ source <(ty completion bash) + + # To load completions for each session, execute once: + # Linux: + $ ty completion bash > /etc/bash_completion.d/ty + # macOS: + $ ty completion bash > $(brew --prefix)/etc/bash_completion.d/ty + +Zsh: + # If shell completion is not already enabled in your environment, + # you will need to enable it. You can execute the following once: + $ echo "autoload -U compinit; compinit" >> ~/.zshrc + + # To load completions for each session, execute once: + $ ty completion zsh > "${fpath[1]}/_ty" + + # You will need to start a new shell for this setup to take effect. + +Fish: + $ ty completion fish | source + + # To load completions for each session, execute once: + $ ty completion fish > ~/.config/fish/completions/ty.fish + +PowerShell: + PS> ty completion powershell | Out-String | Invoke-Expression + + # To load completions for every new session, run: + PS> ty completion powershell > ty.ps1 + # and source this file from your PowerShell profile. +`, + DisableFlagsInUseLine: true, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), + Run: func(cmd *cobra.Command, args []string) { + switch args[0] { + case "bash": + rootCmd.GenBashCompletion(os.Stdout) + case "zsh": + rootCmd.GenZshCompletion(os.Stdout) + case "fish": + rootCmd.GenFishCompletion(os.Stdout, true) + case "powershell": + rootCmd.GenPowerShellCompletionWithDesc(os.Stdout) + } + }, + } + + return completionCmd +} + +// completeTaskIDs returns a completion function that suggests task IDs with their titles. +func completeTaskIDs(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return fetchTaskCompletions(toComplete) +} + +// completeTaskIDsThenStatus completes task ID for first arg, status for second. +func completeTaskIDsThenStatus(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return fetchTaskCompletions(toComplete) + } + if len(args) == 1 { + return validStatuses(), cobra.ShellCompDirectiveNoFileComp + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// completeTaskIDsThenProject completes task ID for first arg, project name for second. +func completeTaskIDsThenProject(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return fetchTaskCompletions(toComplete) + } + if len(args) == 1 { + return fetchProjectCompletions() + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// completeProjectNames returns a completion function for project names. +func completeProjectNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return fetchProjectCompletions() +} + +// completeSettingKeys returns a completion function for settings set first arg. +func completeSettingKeys(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return []string{ + "anthropic_api_key\tAPI key for ghost text autocomplete", + "autocomplete_enabled\tEnable/disable ghost text (true/false)", + "idle_suspend_timeout\tIdle timeout before suspending (e.g. 6h)", + }, cobra.ShellCompDirectiveNoFileComp + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// completeTypeNames returns a completion function for task type names. +func completeTypeNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) >= 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return fetchTypeCompletions() +} + +// completeFlagProjects provides completions for --project flag values. +func completeFlagProjects(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return fetchProjectCompletions() +} + +// completeFlagExecutors provides completions for --executor flag values. +func completeFlagExecutors(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{ + "claude\tAnthropic Claude (default)", + "codex\tOpenAI Codex", + "gemini\tGoogle Gemini", + "pi\tInflection Pi", + "opencode\tOpenCode", + "openclaw\tOpenClaw", + }, cobra.ShellCompDirectiveNoFileComp +} + +// completeFlagTypes provides completions for --type flag values. +func completeFlagTypes(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + comps, directive := fetchTypeCompletions() + if len(comps) > 0 { + return comps, directive + } + // Fallback to built-in types if DB unavailable + return []string{"code", "writing", "thinking"}, cobra.ShellCompDirectiveNoFileComp +} + +// completeFlagStatuses provides completions for --status flag values. +func completeFlagStatuses(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return validStatuses(), cobra.ShellCompDirectiveNoFileComp +} + +// fetchTaskCompletions opens the DB and returns task ID completions. +func fetchTaskCompletions(toComplete string) ([]string, cobra.ShellCompDirective) { + database, err := db.Open(db.DefaultPath()) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer database.Close() + + tasks, err := database.ListTasks(db.ListTasksOptions{IncludeClosed: true, Limit: 50}) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var completions []string + for _, t := range tasks { + desc := t.Title + if len(desc) > 40 { + desc = desc[:37] + "..." + } + completions = append(completions, fmt.Sprintf("%d\t[%s] %s", t.ID, t.Status, desc)) + } + return completions, cobra.ShellCompDirectiveNoFileComp +} + +// fetchProjectCompletions opens the DB and returns project name completions. +func fetchProjectCompletions() ([]string, cobra.ShellCompDirective) { + database, err := db.Open(db.DefaultPath()) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer database.Close() + + projects, err := database.ListProjects() + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var completions []string + for _, p := range projects { + desc := p.Name + if p.Path != "" { + desc = p.Path + } + completions = append(completions, fmt.Sprintf("%s\t%s", p.Name, desc)) + } + return completions, cobra.ShellCompDirectiveNoFileComp +} + +// fetchTypeCompletions opens the DB and returns task type completions. +func fetchTypeCompletions() ([]string, cobra.ShellCompDirective) { + database, err := db.Open(db.DefaultPath()) + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + defer database.Close() + + types, err := database.ListTaskTypes() + if err != nil { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + var completions []string + for _, t := range types { + label := t.Label + if label == "" { + label = t.Name + } + completions = append(completions, fmt.Sprintf("%s\t%s", t.Name, label)) + } + return completions, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/task/completion_test.go b/cmd/task/completion_test.go new file mode 100644 index 00000000..532dd9ef --- /dev/null +++ b/cmd/task/completion_test.go @@ -0,0 +1,116 @@ +package main + +import ( + "os" + "testing" + + "github.com/spf13/cobra" +) + +func TestNewCompletionCmd(t *testing.T) { + rootCmd := &cobra.Command{Use: "ty"} + completionCmd := newCompletionCmd(rootCmd) + + if completionCmd.Use != "completion [bash|zsh|fish|powershell]" { + t.Errorf("unexpected Use: %s", completionCmd.Use) + } + + if len(completionCmd.ValidArgs) != 4 { + t.Errorf("expected 4 valid args, got %d", len(completionCmd.ValidArgs)) + } + + expected := map[string]bool{"bash": true, "zsh": true, "fish": true, "powershell": true} + for _, arg := range completionCmd.ValidArgs { + if !expected[arg] { + t.Errorf("unexpected valid arg: %s", arg) + } + } +} + +func TestCompletionCmdOutput(t *testing.T) { + shells := []string{"bash", "zsh", "fish", "powershell"} + + for _, shell := range shells { + t.Run(shell, func(t *testing.T) { + rootCmd := &cobra.Command{Use: "ty"} + completionCmd := newCompletionCmd(rootCmd) + rootCmd.AddCommand(completionCmd) + + // Capture output + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + rootCmd.SetArgs([]string{"completion", shell}) + err := rootCmd.Execute() + + w.Close() + os.Stdout = old + + if err != nil { + t.Fatalf("completion %s failed: %v", shell, err) + } + + buf := make([]byte, 1024) + n, _ := r.Read(buf) + if n == 0 { + t.Errorf("completion %s produced no output", shell) + } + }) + } +} + +func TestCompleteTaskIDsThenStatus(t *testing.T) { + // When 1 arg already provided (task ID), should return statuses + completions, directive := completeTaskIDsThenStatus(nil, []string{"42"}, "") + if directive != cobra.ShellCompDirectiveNoFileComp { + t.Errorf("expected NoFileComp directive") + } + + statuses := validStatuses() + if len(completions) != len(statuses) { + t.Errorf("expected %d statuses, got %d", len(statuses), len(completions)) + } + + // When 2 args already provided, no more completions + completions, _ = completeTaskIDsThenStatus(nil, []string{"42", "done"}, "") + if len(completions) != 0 { + t.Errorf("expected no completions for 2+ args, got %d", len(completions)) + } +} + +func TestCompleteSettingKeys(t *testing.T) { + completions, directive := completeSettingKeys(nil, []string{}, "") + if directive != cobra.ShellCompDirectiveNoFileComp { + t.Errorf("expected NoFileComp directive") + } + if len(completions) != 3 { + t.Errorf("expected 3 setting keys, got %d", len(completions)) + } + + // After first arg, no more completions + completions, _ = completeSettingKeys(nil, []string{"anthropic_api_key"}, "") + if len(completions) != 0 { + t.Errorf("expected no completions after key, got %d", len(completions)) + } +} + +func TestCompleteFlagExecutors(t *testing.T) { + completions, directive := completeFlagExecutors(nil, nil, "") + if directive != cobra.ShellCompDirectiveNoFileComp { + t.Errorf("expected NoFileComp directive") + } + if len(completions) != 6 { + t.Errorf("expected 6 executors, got %d", len(completions)) + } +} + +func TestCompleteFlagStatuses(t *testing.T) { + completions, directive := completeFlagStatuses(nil, nil, "") + if directive != cobra.ShellCompDirectiveNoFileComp { + t.Errorf("expected NoFileComp directive") + } + if len(completions) == 0 { + t.Error("expected some status completions") + } +} diff --git a/cmd/task/main.go b/cmd/task/main.go index b94985f0..589a926e 100644 --- a/cmd/task/main.go +++ b/cmd/task/main.go @@ -401,9 +401,10 @@ Tasks will automatically reconnect to their agent sessions when viewed.`, // Delete subcommand - delete a task, kill its agent session, and remove worktree deleteCmd := &cobra.Command{ - Use: "delete ", - Short: "Delete a task, kill its agent session, and remove its worktree", - Args: cobra.ExactArgs(1), + Use: "delete ", + Short: "Delete a task, kill its agent session, and remove its worktree", + Args: cobra.ExactArgs(1), + ValidArgsFunction: completeTaskIDs, Run: func(cmd *cobra.Command, args []string) { var taskID int64 if _, err := fmt.Sscanf(args[0], "%d", &taskID); err != nil { @@ -632,6 +633,9 @@ Examples: createCmd.Flags().Bool("pinned", false, "Pin the task to the top of its column") createCmd.Flags().StringP("branch", "b", "", "Existing branch to checkout for worktree (e.g., fix/ui-overflow)") createCmd.Flags().Bool("json", false, "Output in JSON format") + createCmd.RegisterFlagCompletionFunc("project", completeFlagProjects) + createCmd.RegisterFlagCompletionFunc("type", completeFlagTypes) + createCmd.RegisterFlagCompletionFunc("executor", completeFlagExecutors) rootCmd.AddCommand(createCmd) // List subcommand - list tasks @@ -810,6 +814,9 @@ Examples: listCmd.Flags().IntP("limit", "n", 50, "Maximum number of tasks to return") listCmd.Flags().Bool("json", false, "Output in JSON format") listCmd.Flags().Bool("pr", false, "Show PR/CI status (requires network)") + listCmd.RegisterFlagCompletionFunc("status", completeFlagStatuses) + listCmd.RegisterFlagCompletionFunc("project", completeFlagProjects) + listCmd.RegisterFlagCompletionFunc("type", completeFlagTypes) rootCmd.AddCommand(listCmd) boardCmd := &cobra.Command{ @@ -922,8 +929,9 @@ Press Ctrl+C to stop.`, // Show subcommand - show task details showCmd := &cobra.Command{ - Use: "show ", - Short: "Show task details", + Use: "show ", + Short: "Show task details", + ValidArgsFunction: completeTaskIDs, Long: `Show detailed information about a task. Examples: @@ -1151,8 +1159,9 @@ Examples: // Update subcommand - update task fields updateCmd := &cobra.Command{ - Use: "update ", - Short: "Update a task", + Use: "update ", + Short: "Update a task", + ValidArgsFunction: completeTaskIDs, Long: `Update task fields. Examples: @@ -1272,12 +1281,16 @@ Examples: updateCmd.Flags().StringP("executor", "e", "", "Update task executor: claude, codex, gemini, pi, opencode, openclaw") updateCmd.Flags().String("tags", "", "Update task tags (comma-separated)") updateCmd.Flags().Bool("pinned", false, "Pin or unpin the task") + updateCmd.RegisterFlagCompletionFunc("project", completeFlagProjects) + updateCmd.RegisterFlagCompletionFunc("type", completeFlagTypes) + updateCmd.RegisterFlagCompletionFunc("executor", completeFlagExecutors) rootCmd.AddCommand(updateCmd) // Move subcommand - move a task to a different project moveCmd := &cobra.Command{ - Use: "move ", - Short: "Move a task to a different project", + Use: "move ", + Short: "Move a task to a different project", + ValidArgsFunction: completeTaskIDsThenProject, Long: `Move a task to a different project. This properly cleans up the task's worktree and agent sessions from the old project, @@ -1382,9 +1395,10 @@ Examples: // Execute subcommand - queue a task for execution executeCmd := &cobra.Command{ - Use: "execute ", - Aliases: []string{"queue", "run"}, - Short: "Queue a task for execution", + Use: "execute ", + Aliases: []string{"queue", "run"}, + Short: "Queue a task for execution", + ValidArgsFunction: completeTaskIDs, Long: `Queue a task to be executed by the daemon. Examples: @@ -1439,8 +1453,9 @@ Examples: rootCmd.AddCommand(executeCmd) statusCmd := &cobra.Command{ - Use: "status ", - Short: "Set a task's status", + Use: "status ", + Short: "Set a task's status", + ValidArgsFunction: completeTaskIDsThenStatus, Long: `Manually update a task's status. Useful for automation/orchestration when you need to move cards between columns without opening the TUI. @@ -1488,9 +1503,10 @@ Valid statuses: backlog, queued, processing, blocked, done, archived.`, rootCmd.AddCommand(statusCmd) pinCmd := &cobra.Command{ - Use: "pin ", - Short: "Pin, unpin, or toggle a task", - Args: cobra.ExactArgs(1), + Use: "pin ", + Short: "Pin, unpin, or toggle a task", + Args: cobra.ExactArgs(1), + ValidArgsFunction: completeTaskIDs, Run: func(cmd *cobra.Command, args []string) { var taskID int64 if _, err := fmt.Sscanf(args[0], "%d", &taskID); err != nil { @@ -1546,7 +1562,8 @@ Valid statuses: backlog, queued, processing, blocked, done, archived.`, // Close subcommand - mark a task as done closeCmd := &cobra.Command{ - Use: "close ", + Use: "close ", + ValidArgsFunction: completeTaskIDs, Aliases: []string{"done", "complete"}, Short: "Mark a task as done", Long: `Mark a task as completed. @@ -1603,8 +1620,9 @@ Examples: // Retry subcommand - retry a blocked/failed task retryCmd := &cobra.Command{ - Use: "retry ", - Short: "Retry a blocked or failed task", + Use: "retry ", + Short: "Retry a blocked or failed task", + ValidArgsFunction: completeTaskIDs, Long: `Retry a task that is blocked or failed, optionally with feedback. Examples: @@ -1653,8 +1671,9 @@ Examples: // Input subcommand - send input directly to a running task's executor inputCmd := &cobra.Command{ - Use: "input [message]", - Short: "Send input to a task's executor", + Use: "input [message]", + Short: "Send input to a task's executor", + ValidArgsFunction: completeTaskIDs, Long: `Send input directly to a running task's executor via tmux. This allows you to interact with a blocked or running task without going through @@ -1764,8 +1783,9 @@ Examples: // Output subcommand - capture recent output from executor pane outputCmd := &cobra.Command{ - Use: "output ", - Short: "Capture recent output from a task's executor", + Use: "output ", + Short: "Capture recent output from a task's executor", + ValidArgsFunction: completeTaskIDs, Long: `Capture recent output from a running task's executor pane. This allows you to see what the executor has outputted without attaching to the tmux pane. @@ -2038,8 +2058,9 @@ Examples: } settingsSetCmd := &cobra.Command{ - Use: "set ", - Short: "Set a setting value", + Use: "set ", + Short: "Set a setting value", + ValidArgsFunction: completeSettingKeys, Long: `Set a configuration setting. Available settings: @@ -2236,8 +2257,9 @@ Examples: // Projects show subcommand projectsShowCmd := &cobra.Command{ - Use: "show ", - Short: "Show project details", + Use: "show ", + Short: "Show project details", + ValidArgsFunction: completeProjectNames, Long: `Show detailed information about a project including its instructions. Examples: @@ -2287,8 +2309,9 @@ Examples: // Projects update subcommand projectsUpdateCmd := &cobra.Command{ - Use: "update ", - Short: "Update project settings", + Use: "update ", + Short: "Update project settings", + ValidArgsFunction: completeProjectNames, Long: `Update settings for an existing project. Examples: @@ -2342,8 +2365,9 @@ Examples: // Projects delete subcommand projectsDeleteCmd := &cobra.Command{ - Use: "delete ", - Short: "Delete a project", + Use: "delete ", + Short: "Delete a project", + ValidArgsFunction: completeProjectNames, Long: `Delete a project. The 'personal' project cannot be deleted. Note: This only removes the project from the task system. It does not @@ -2365,7 +2389,8 @@ Examples: // Block command - create a dependency between two tasks blockCmd := &cobra.Command{ - Use: "block --by ", + Use: "block --by ", + ValidArgsFunction: completeTaskIDs, Short: "Block a task until another task completes", Long: `Create a dependency where a task is blocked until another task completes. @@ -2429,7 +2454,8 @@ Use --auto-queue to automatically move the blocked task to 'queued' when unblock // Unblock command - remove a dependency unblockCmd := &cobra.Command{ - Use: "unblock --from ", + Use: "unblock --from ", + ValidArgsFunction: completeTaskIDs, Short: "Remove a blocking dependency", Long: `Remove a dependency so a task is no longer blocked by another. @@ -2471,7 +2497,8 @@ This removes the dependency where task #5 was blocked by task #3.`, // Deps command - show dependencies for a task depsCmd := &cobra.Command{ - Use: "deps ", + Use: "deps ", + ValidArgsFunction: completeTaskIDs, Short: "Show dependencies for a task", Long: `Display all dependencies for a task, showing: - Tasks that block this task (must complete before this task) @@ -2633,7 +2660,8 @@ Examples: // Types show subcommand typesShowCmd := &cobra.Command{ - Use: "show ", + Use: "show ", + ValidArgsFunction: completeTypeNames, Short: "Show details of a task type", Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { @@ -2798,7 +2826,8 @@ Examples: // Types edit subcommand typesEditCmd := &cobra.Command{ - Use: "edit ", + Use: "edit ", + ValidArgsFunction: completeTypeNames, Short: "Edit an existing task type", Long: `Edit an existing task type. Built-in types can be edited but not deleted. @@ -2899,7 +2928,8 @@ Examples: // Types delete subcommand typesDeleteCmd := &cobra.Command{ - Use: "delete ", + Use: "delete ", + ValidArgsFunction: completeTypeNames, Short: "Delete a custom task type", Long: `Delete a custom task type. Built-in types (code, writing, thinking) cannot be deleted. @@ -2959,6 +2989,9 @@ Examples: rootCmd.AddCommand(typesCmd) + // Completion command for shell tab completion + rootCmd.AddCommand(newCompletionCmd(rootCmd)) + if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, errorStyle.Render("Error: "+err.Error())) os.Exit(1) From 3181b6e4c2657d3891cd6d0a925e536a4118f436 Mon Sep 17 00:00:00 2001 From: Bruno Bornsztein Date: Sun, 22 Mar 2026 07:19:40 -0500 Subject: [PATCH 2/2] Fix lint: align struct field formatting in cobra.Command literals Co-Authored-By: Claude Opus 4.6 (1M context) --- cmd/task/main.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/task/main.go b/cmd/task/main.go index 44efa542..e57ae64f 100644 --- a/cmd/task/main.go +++ b/cmd/task/main.go @@ -1565,8 +1565,8 @@ Valid statuses: backlog, queued, processing, blocked, done, archived.`, closeCmd := &cobra.Command{ Use: "close ", ValidArgsFunction: completeTaskIDs, - Aliases: []string{"done", "complete"}, - Short: "Mark a task as done", + Aliases: []string{"done", "complete"}, + Short: "Mark a task as done", Long: `Mark a task as completed. Examples: @@ -2392,7 +2392,7 @@ Examples: blockCmd := &cobra.Command{ Use: "block --by ", ValidArgsFunction: completeTaskIDs, - Short: "Block a task until another task completes", + Short: "Block a task until another task completes", Long: `Create a dependency where a task is blocked until another task completes. Example: ty block 5 --by 3 @@ -2457,7 +2457,7 @@ Use --auto-queue to automatically move the blocked task to 'queued' when unblock unblockCmd := &cobra.Command{ Use: "unblock --from ", ValidArgsFunction: completeTaskIDs, - Short: "Remove a blocking dependency", + Short: "Remove a blocking dependency", Long: `Remove a dependency so a task is no longer blocked by another. Example: ty unblock 5 --from 3 @@ -2500,7 +2500,7 @@ This removes the dependency where task #5 was blocked by task #3.`, depsCmd := &cobra.Command{ Use: "deps ", ValidArgsFunction: completeTaskIDs, - Short: "Show dependencies for a task", + Short: "Show dependencies for a task", Long: `Display all dependencies for a task, showing: - Tasks that block this task (must complete before this task) - Tasks that this task blocks (waiting on this task)`, @@ -2663,8 +2663,8 @@ Examples: typesShowCmd := &cobra.Command{ Use: "show ", ValidArgsFunction: completeTypeNames, - Short: "Show details of a task type", - Args: cobra.ExactArgs(1), + Short: "Show details of a task type", + Args: cobra.ExactArgs(1), Run: func(cmd *cobra.Command, args []string) { name := args[0] outputJSON, _ := cmd.Flags().GetBool("json") @@ -2829,7 +2829,7 @@ Examples: typesEditCmd := &cobra.Command{ Use: "edit ", ValidArgsFunction: completeTypeNames, - Short: "Edit an existing task type", + Short: "Edit an existing task type", Long: `Edit an existing task type. Built-in types can be edited but not deleted. All flags are optional - only specified values will be updated. @@ -2931,7 +2931,7 @@ Examples: typesDeleteCmd := &cobra.Command{ Use: "delete ", ValidArgsFunction: completeTypeNames, - Short: "Delete a custom task type", + Short: "Delete a custom task type", Long: `Delete a custom task type. Built-in types (code, writing, thinking) cannot be deleted. Examples: