Skip to main content

track/cli/
mod.rs

1//! Command-line interface definitions for the track CLI.
2//!
3//! This module defines the CLI structure using `clap`, including all commands,
4//! subcommands, and their arguments. The actual command handling logic is in the
5//! [`handler`] module.
6
7pub mod handler;
8pub mod handlers;
9
10use clap::{Parser, Subcommand, ValueEnum};
11
12/// Types of completion data that can be output
13#[derive(Debug, Clone, ValueEnum)]
14pub enum CompletionType {
15    /// Task IDs and names for 'track switch'
16    Tasks,
17    /// TODO IDs and content for current task
18    Todos,
19    /// Link IDs and URLs for current task
20    Links,
21    /// Repository IDs and paths for current task
22    Repos,
23}
24
25/// Main CLI structure for the track application.
26#[derive(Parser)]
27#[command(name = "track")]
28#[command(about = "WorkTracker CLI - Manage your development tasks and context", long_about = None)]
29pub struct Cli {
30    #[command(subcommand)]
31    pub command: Commands,
32}
33
34#[derive(Subcommand)]
35pub enum Commands {
36    /// Create a new task and switch to it
37    New {
38        /// Task name
39        name: String,
40
41        /// Task description
42        #[arg(short, long)]
43        description: Option<String>,
44
45        /// Ticket ID (e.g., PROJ-123, owner/repo/456)
46        #[arg(short, long)]
47        ticket: Option<String>,
48
49        /// Ticket URL
50        #[arg(long)]
51        ticket_url: Option<String>,
52
53        /// Template task reference (ID, ticket, or alias) to copy TODOs from
54        #[arg(long)]
55        template: Option<String>,
56    },
57
58    /// List tasks
59    List {
60        /// Include archived tasks
61        #[arg(short, long)]
62        all: bool,
63    },
64
65    /// Switch to a different task
66    Switch {
67        /// Task ID or ticket reference (e.g., 1 or t:PROJ-123)
68        task_ref: String,
69    },
70
71    /// Show detailed information about the current task
72    Status {
73        /// Task ID or ticket reference (e.g., 1 or t:PROJ-123)
74        id: Option<String>,
75
76        /// Output in JSON format
77        #[arg(short, long)]
78        json: bool,
79
80        /// Show all scraps
81        #[arg(short, long)]
82        all: bool,
83    },
84
85    /// View or set task description
86    Desc {
87        /// Description text (if omitted, displays current description)
88        description: Option<String>,
89
90        /// Target task ID (defaults to current task)
91        #[arg(short, long)]
92        task: Option<i64>,
93    },
94
95    /// Link a ticket to a task
96    Ticket {
97        /// Ticket ID
98        ticket_id: String,
99
100        /// Ticket URL
101        url: String,
102
103        /// Target task ID (defaults to current task)
104        #[arg(long)]
105        task: Option<i64>,
106    },
107
108    /// Archive a task
109    Archive {
110        /// Task ID or ticket reference (defaults to current task)
111        task_ref: Option<String>,
112
113        /// Skip jj-task and dirty-workspace checks
114        #[arg(short, long)]
115        force: bool,
116    },
117
118    /// TODO management
119    #[command(subcommand)]
120    Todo(TodoCommands),
121
122    /// Link management
123    #[command(subcommand)]
124    Link(LinkCommands),
125
126    /// Scrap (work notes) management
127    #[command(subcommand)]
128    Scrap(ScrapCommands),
129
130    /// Sync repositories and setup task branches
131    Sync {
132        /// JJ mode only: run legacy bookmark/per-TODO workspace sync (deprecated)
133        #[arg(long)]
134        legacy: bool,
135    },
136
137    /// Migrate data between workflow models
138    #[command(subcommand)]
139    Migrate(MigrateCommands),
140
141    /// Repository management
142    #[command(subcommand)]
143    Repo(RepoCommands),
144
145    /// Task alias management
146    #[command(subcommand)]
147    Alias(AliasCommands),
148
149    /// Show help optimized for LLM agents
150    LlmHelp,
151
152    /// Generate shell completion script
153    Completion {
154        /// Shell to generate completions for
155        #[arg(value_enum)]
156        shell: clap_complete::Shell,
157
158        /// Generate dynamic completion script (with real-time data)
159        #[arg(short, long)]
160        dynamic: bool,
161    },
162
163    /// Output completion candidates (hidden, for shell completion scripts)
164    #[command(hide = true)]
165    #[command(name = "_complete")]
166    Complete {
167        /// Type of completion data to output
168        #[arg(value_enum)]
169        completion_type: CompletionType,
170    },
171
172    /// Configuration management
173    #[command(subcommand)]
174    Config(ConfigCommands),
175
176    /// Start web-based user interface
177    Webui {
178        /// Port to listen on
179        #[arg(short, long, default_value = "3000")]
180        port: u16,
181
182        /// Open browser automatically
183        #[arg(short, long)]
184        open: bool,
185    },
186}
187
188#[derive(Subcommand)]
189pub enum MigrateCommands {
190    /// Clear legacy per-TODO worktree flags (switch to jj-task)
191    LegacyWorktrees {
192        /// Task ID or ticket reference (defaults to all tasks)
193        task_ref: Option<String>,
194
195        /// Show what would change without writing
196        #[arg(long)]
197        dry_run: bool,
198
199        /// Remove legacy workspaces even when jj reports uncommitted changes
200        #[arg(short, long)]
201        force: bool,
202    },
203}
204
205#[derive(Subcommand)]
206pub enum TodoCommands {
207    /// Add a new TODO
208    Add {
209        /// TODO content
210        text: String,
211
212        /// [DEPRECATED] Legacy per-TODO worktree — use jj-task per task instead
213        #[arg(short, long, hide = true)]
214        worktree: bool,
215
216        /// Research/planning TODO that does not need a jj-task or git worktree
217        #[arg(long, conflicts_with = "worktree")]
218        no_workspace: bool,
219    },
220
221    /// List TODOs
222    List,
223
224    /// Update TODO status
225    Update {
226        /// TODO ID
227        id: i64,
228
229        /// New status (done or cancelled; reopen to pending is not allowed)
230        status: String,
231    },
232
233    /// Complete a TODO (merges worktree if exists)
234    Done {
235        /// TODO ID
236        id: i64,
237    },
238
239    /// Create or show worktrees for a TODO in the current repo
240    Workspace {
241        /// TODO ID
242        id: i64,
243
244        /// Recreate worktrees from the latest bookmark
245        #[arg(long)]
246        recreate: bool,
247
248        /// Force recreation even if uncommitted changes exist
249        #[arg(short, long)]
250        force: bool,
251
252        /// Operate on all registered repos for the task
253        #[arg(long)]
254        all: bool,
255    },
256
257    /// Delete a TODO
258    Delete {
259        /// TODO ID
260        id: i64,
261
262        /// Skip confirmation prompt
263        #[arg(short, long)]
264        force: bool,
265    },
266
267    /// Move a TODO to the front (make it the next todo to work on)
268    Next {
269        /// TODO ID
270        id: i64,
271    },
272}
273
274#[derive(Subcommand)]
275pub enum LinkCommands {
276    /// Add a new link
277    Add {
278        /// URL
279        url: String,
280
281        /// Link title (defaults to URL)
282        title: Option<String>,
283    },
284
285    /// List links
286    List,
287
288    /// Delete a link
289    Delete {
290        /// Link index (1-based)
291        index: usize,
292    },
293}
294
295#[derive(Subcommand)]
296pub enum ScrapCommands {
297    /// Add a new scrap (work note)
298    Add {
299        /// Scrap content
300        content: String,
301    },
302
303    /// List scraps
304    List,
305}
306
307#[derive(Subcommand)]
308pub enum RepoCommands {
309    /// Add a repository to the current task
310    Add {
311        /// Repository path (defaults to current directory)
312        path: Option<String>,
313
314        /// Base branch to use (defaults to current branch)
315        #[arg(short, long)]
316        base: Option<String>,
317    },
318
319    /// List repositories
320    List,
321
322    /// Remove a repository
323    Remove {
324        /// Repository ID
325        id: i64,
326    },
327}
328
329#[derive(Subcommand)]
330pub enum AliasCommands {
331    /// Set an alias for the current task
332    Set {
333        /// Alias name
334        alias: String,
335
336        /// Target task ID (defaults to current task)
337        #[arg(short, long)]
338        task: Option<i64>,
339
340        /// Force overwrite if alias already exists on another task
341        #[arg(short, long)]
342        force: bool,
343    },
344
345    /// Remove the alias from the current task
346    Remove {
347        /// Target task ID (defaults to current task)
348        #[arg(short, long)]
349        task: Option<i64>,
350    },
351}
352
353#[derive(Subcommand)]
354pub enum ConfigCommands {
355    /// Set a configuration value (e.g. vcs-mode jj|git)
356    Set {
357        /// Configuration key (e.g. vcs-mode)
358        key: String,
359
360        /// Configuration value
361        value: String,
362    },
363
364    /// Set Google Calendar ID for today task
365    SetCalendar {
366        /// Google Calendar ID
367        calendar_id: String,
368    },
369
370    /// Show current configuration
371    Show,
372}