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}