1use clap::{Parser, Subcommand, ValueEnum, CommandFactory};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "tempo")]
6#[command(about = "Automatic project time tracking CLI tool")]
7#[command(version = env!("CARGO_PKG_VERSION"))]
8#[command(author = "Tempo Contributors")]
9pub struct Cli {
10 #[command(subcommand)]
11 pub command: Commands,
12
13 #[arg(long, short, help = "Path to config file")]
14 pub config: Option<PathBuf>,
15
16 #[arg(long, short, help = "Verbose output")]
17 pub verbose: bool,
18}
19
20#[derive(Subcommand)]
21pub enum Commands {
22 #[command(about = "Start the daemon")]
23 Start,
24
25 #[command(about = "Stop the daemon")]
26 Stop,
27
28 #[command(about = "Restart the daemon")]
29 Restart,
30
31 #[command(about = "Check daemon status")]
32 Status,
33
34 #[command(about = "Initialize a project for tracking")]
35 Init {
36 #[arg(help = "Project name")]
37 name: Option<String>,
38
39 #[arg(long, help = "Project path")]
40 path: Option<PathBuf>,
41
42 #[arg(long, help = "Project description")]
43 description: Option<String>,
44 },
45
46 #[command(about = "List projects")]
47 List {
48 #[arg(long, help = "Include archived projects")]
49 all: bool,
50
51 #[arg(long, help = "Filter by tag")]
52 tag: Option<String>,
53 },
54
55 #[command(about = "Generate time reports")]
56 Report {
57 #[arg(help = "Project name or ID")]
58 project: Option<String>,
59
60 #[arg(long, help = "Start date (YYYY-MM-DD)")]
61 from: Option<String>,
62
63 #[arg(long, help = "End date (YYYY-MM-DD)")]
64 to: Option<String>,
65
66 #[arg(long, help = "Export format (csv, json)")]
67 format: Option<String>,
68
69 #[arg(long, help = "Group by (day, week, month, project)")]
70 group: Option<String>,
71 },
72
73 #[command(about = "Project management")]
74 Project {
75 #[command(subcommand)]
76 action: ProjectAction,
77 },
78
79 #[command(about = "Session management")]
80 Session {
81 #[command(subcommand)]
82 action: SessionAction,
83 },
84
85 #[command(about = "Tag management")]
86 Tag {
87 #[command(subcommand)]
88 action: TagAction,
89 },
90
91 #[command(about = "Configuration management")]
92 Config {
93 #[command(subcommand)]
94 action: ConfigAction,
95 },
96
97 #[command(about = "Interactive dashboard")]
98 Dashboard,
99
100 #[command(about = "Interactive project and session viewer")]
101 Tui,
102
103 #[command(about = "Interactive timer with visual progress")]
104 Timer,
105
106 #[command(about = "Browse session history")]
107 History,
108
109 #[command(about = "Goal management")]
110 Goal {
111 #[command(subcommand)]
112 action: GoalAction,
113 },
114
115 #[command(about = "Productivity insights and analytics")]
116 Insights {
117 #[arg(long, help = "Period (daily, weekly, monthly)")]
118 period: Option<String>,
119
120 #[arg(long, help = "Project name or ID")]
121 project: Option<String>,
122 },
123
124 #[command(about = "Weekly or monthly summary")]
125 Summary {
126 #[arg(help = "Period type (week, month)")]
127 period: String,
128
129 #[arg(long, help = "Start date (YYYY-MM-DD)")]
130 from: Option<String>,
131 },
132
133 #[command(about = "Compare projects")]
134 Compare {
135 #[arg(help = "Project names or IDs (comma-separated)")]
136 projects: String,
137
138 #[arg(long, help = "Start date (YYYY-MM-DD)")]
139 from: Option<String>,
140
141 #[arg(long, help = "End date (YYYY-MM-DD)")]
142 to: Option<String>,
143 },
144
145 #[command(about = "Time estimation tracking")]
146 Estimate {
147 #[command(subcommand)]
148 action: EstimateAction,
149 },
150
151 #[command(about = "Git branch tracking")]
152 Branch {
153 #[command(subcommand)]
154 action: BranchAction,
155 },
156
157 #[command(about = "Project templates")]
158 Template {
159 #[command(subcommand)]
160 action: TemplateAction,
161 },
162
163 #[command(about = "Workspace management")]
164 Workspace {
165 #[command(subcommand)]
166 action: WorkspaceAction,
167 },
168
169 #[command(about = "Calendar integration")]
170 Calendar {
171 #[command(subcommand)]
172 action: CalendarAction,
173 },
174
175 #[command(about = "Issue tracker integration")]
176 Issue {
177 #[command(subcommand)]
178 action: IssueAction,
179 },
180
181 #[command(about = "Client reporting")]
182 Client {
183 #[command(subcommand)]
184 action: ClientAction,
185 },
186
187 #[command(about = "Generate shell completions", hide = true)]
188 Completions {
189 #[arg(help = "Shell to generate completions for")]
190 shell: Shell,
191 },
192}
193
194#[derive(Subcommand)]
195pub enum ProjectAction {
196 #[command(about = "Archive a project")]
197 Archive {
198 #[arg(help = "Project name or ID")]
199 project: String,
200 },
201
202 #[command(about = "Unarchive a project")]
203 Unarchive {
204 #[arg(help = "Project name or ID")]
205 project: String,
206 },
207
208 #[command(about = "Update project path")]
209 UpdatePath {
210 #[arg(help = "Project name or ID")]
211 project: String,
212
213 #[arg(help = "New path")]
214 path: PathBuf,
215 },
216
217 #[command(about = "Add tag to project")]
218 AddTag {
219 #[arg(help = "Project name or ID")]
220 project: String,
221
222 #[arg(help = "Tag name")]
223 tag: String,
224 },
225
226 #[command(about = "Remove tag from project")]
227 RemoveTag {
228 #[arg(help = "Project name or ID")]
229 project: String,
230
231 #[arg(help = "Tag name")]
232 tag: String,
233 },
234}
235
236#[derive(Subcommand)]
237pub enum SessionAction {
238 #[command(about = "Start tracking time for current project")]
239 Start {
240 #[arg(long, help = "Project name or path")]
241 project: Option<String>,
242
243 #[arg(long, help = "Session context")]
244 context: Option<String>,
245 },
246
247 #[command(about = "Stop current session")]
248 Stop,
249
250 #[command(about = "Pause current session")]
251 Pause,
252
253 #[command(about = "Resume paused session")]
254 Resume,
255
256 #[command(about = "Show current session")]
257 Current,
258
259 #[command(about = "List recent sessions")]
260 List {
261 #[arg(long, help = "Number of sessions to show")]
262 limit: Option<usize>,
263
264 #[arg(long, help = "Project filter")]
265 project: Option<String>,
266 },
267
268 #[command(about = "Edit a session")]
269 Edit {
270 #[arg(help = "Session ID")]
271 id: i64,
272
273 #[arg(long, help = "New start time")]
274 start: Option<String>,
275
276 #[arg(long, help = "New end time")]
277 end: Option<String>,
278
279 #[arg(long, help = "New project")]
280 project: Option<String>,
281
282 #[arg(long, help = "Edit reason")]
283 reason: Option<String>,
284 },
285
286 #[command(about = "Delete a session")]
287 Delete {
288 #[arg(help = "Session ID")]
289 id: i64,
290
291 #[arg(long, help = "Force deletion without confirmation")]
292 force: bool,
293 },
294
295 #[command(about = "Merge multiple sessions into one")]
296 Merge {
297 #[arg(help = "Session IDs to merge (comma-separated)")]
298 session_ids: String,
299
300 #[arg(long, help = "Target project for merged session")]
301 project: Option<String>,
302
303 #[arg(long, help = "Notes for the merged session")]
304 notes: Option<String>,
305 },
306
307 #[command(about = "Split a session into multiple sessions")]
308 Split {
309 #[arg(help = "Session ID to split")]
310 session_id: i64,
311
312 #[arg(help = "Split points (comma-separated times like '10:30,11:45')")]
313 split_times: String,
314
315 #[arg(long, help = "Notes for each split session (comma-separated)")]
316 notes: Option<String>,
317 },
318}
319
320#[derive(Subcommand)]
321pub enum TagAction {
322 #[command(about = "Create a new tag")]
323 Create {
324 #[arg(help = "Tag name")]
325 name: String,
326
327 #[arg(long, help = "Tag color")]
328 color: Option<String>,
329
330 #[arg(long, help = "Tag description")]
331 description: Option<String>,
332 },
333
334 #[command(about = "List all tags")]
335 List,
336
337 #[command(about = "Delete a tag")]
338 Delete {
339 #[arg(help = "Tag name")]
340 name: String,
341 },
342}
343
344#[derive(Subcommand)]
345pub enum ConfigAction {
346 #[command(about = "Show current configuration")]
347 Show,
348
349 #[command(about = "Set configuration value")]
350 Set {
351 #[arg(help = "Configuration key")]
352 key: String,
353
354 #[arg(help = "Configuration value")]
355 value: String,
356 },
357
358 #[command(about = "Get configuration value")]
359 Get {
360 #[arg(help = "Configuration key")]
361 key: String,
362 },
363
364 #[command(about = "Reset configuration to defaults")]
365 Reset,
366}
367
368#[derive(Subcommand)]
369pub enum GoalAction {
370 #[command(about = "Create a new goal")]
371 Create {
372 #[arg(help = "Goal name")]
373 name: String,
374
375 #[arg(help = "Target hours")]
376 target_hours: f64,
377
378 #[arg(long, help = "Project name or ID")]
379 project: Option<String>,
380
381 #[arg(long, help = "Goal description")]
382 description: Option<String>,
383
384 #[arg(long, help = "Start date (YYYY-MM-DD)")]
385 start_date: Option<String>,
386
387 #[arg(long, help = "End date (YYYY-MM-DD)")]
388 end_date: Option<String>,
389 },
390
391 #[command(about = "List goals")]
392 List {
393 #[arg(long, help = "Project name or ID")]
394 project: Option<String>,
395 },
396
397 #[command(about = "Update goal progress")]
398 Update {
399 #[arg(help = "Goal ID")]
400 id: i64,
401
402 #[arg(help = "Hours to add")]
403 hours: f64,
404 },
405}
406
407#[derive(Subcommand)]
408pub enum EstimateAction {
409 #[command(about = "Create a time estimate")]
410 Create {
411 #[arg(help = "Project name or ID")]
412 project: String,
413
414 #[arg(help = "Task name")]
415 task: String,
416
417 #[arg(help = "Estimated hours")]
418 hours: f64,
419
420 #[arg(long, help = "Due date (YYYY-MM-DD)")]
421 due_date: Option<String>,
422 },
423
424 #[command(about = "Record actual time")]
425 Record {
426 #[arg(help = "Estimate ID")]
427 id: i64,
428
429 #[arg(help = "Actual hours")]
430 hours: f64,
431 },
432
433 #[command(about = "List estimates")]
434 List {
435 #[arg(help = "Project name or ID")]
436 project: String,
437 },
438}
439
440#[derive(Subcommand)]
441pub enum BranchAction {
442 #[command(about = "List git branches for a project")]
443 List {
444 #[arg(help = "Project name or ID")]
445 project: String,
446 },
447
448 #[command(about = "Show branch statistics")]
449 Stats {
450 #[arg(help = "Project name or ID")]
451 project: String,
452
453 #[arg(long, help = "Branch name")]
454 branch: Option<String>,
455 },
456}
457
458#[derive(Subcommand)]
459pub enum TemplateAction {
460 #[command(about = "Create a new project template")]
461 Create {
462 #[arg(help = "Template name")]
463 name: String,
464
465 #[arg(long, help = "Template description")]
466 description: Option<String>,
467
468 #[arg(long, help = "Default tags (comma-separated)")]
469 tags: Option<String>,
470
471 #[arg(long, help = "Workspace path for template")]
472 workspace_path: Option<PathBuf>,
473 },
474
475 #[command(about = "List all templates")]
476 List,
477
478 #[command(about = "Delete a template")]
479 Delete {
480 #[arg(help = "Template name or ID")]
481 template: String,
482 },
483
484 #[command(about = "Use a template to initialize a project")]
485 Use {
486 #[arg(help = "Template name or ID")]
487 template: String,
488
489 #[arg(help = "Project name")]
490 project_name: String,
491
492 #[arg(long, help = "Project path")]
493 path: Option<PathBuf>,
494 },
495}
496
497#[derive(Subcommand)]
498pub enum WorkspaceAction {
499 #[command(about = "Create a new workspace")]
500 Create {
501 #[arg(help = "Workspace name")]
502 name: String,
503
504 #[arg(long, help = "Workspace description")]
505 description: Option<String>,
506
507 #[arg(long, help = "Workspace path")]
508 path: Option<PathBuf>,
509 },
510
511 #[command(about = "List all workspaces")]
512 List,
513
514 #[command(about = "Add project to workspace")]
515 AddProject {
516 #[arg(help = "Workspace name or ID")]
517 workspace: String,
518
519 #[arg(help = "Project name or ID")]
520 project: String,
521 },
522
523 #[command(about = "Remove project from workspace")]
524 RemoveProject {
525 #[arg(help = "Workspace name or ID")]
526 workspace: String,
527
528 #[arg(help = "Project name or ID")]
529 project: String,
530 },
531
532 #[command(about = "List projects in workspace")]
533 Projects {
534 #[arg(help = "Workspace name or ID")]
535 workspace: String,
536 },
537
538 #[command(about = "Delete a workspace")]
539 Delete {
540 #[arg(help = "Workspace name or ID")]
541 workspace: String,
542 },
543}
544
545#[derive(Subcommand)]
546pub enum CalendarAction {
547 #[command(about = "Add a calendar event")]
548 Add {
549 #[arg(help = "Event name")]
550 name: String,
551
552 #[arg(help = "Start time (YYYY-MM-DD HH:MM)")]
553 start: String,
554
555 #[arg(long, help = "End time (YYYY-MM-DD HH:MM)")]
556 end: Option<String>,
557
558 #[arg(long, help = "Event type (meeting, focus_block, deadline)")]
559 event_type: Option<String>,
560
561 #[arg(long, help = "Project name or ID")]
562 project: Option<String>,
563
564 #[arg(long, help = "Event description")]
565 description: Option<String>,
566 },
567
568 #[command(about = "List calendar events")]
569 List {
570 #[arg(long, help = "Start date (YYYY-MM-DD)")]
571 from: Option<String>,
572
573 #[arg(long, help = "End date (YYYY-MM-DD)")]
574 to: Option<String>,
575
576 #[arg(long, help = "Project name or ID")]
577 project: Option<String>,
578 },
579
580 #[command(about = "Delete a calendar event")]
581 Delete {
582 #[arg(help = "Event ID")]
583 id: i64,
584 },
585}
586
587#[derive(Subcommand)]
588pub enum IssueAction {
589 #[command(about = "Sync issues from external tracker")]
590 Sync {
591 #[arg(help = "Project name or ID")]
592 project: String,
593
594 #[arg(long, help = "Issue tracker type (jira, github, gitlab)")]
595 tracker_type: Option<String>,
596 },
597
598 #[command(about = "List issues for a project")]
599 List {
600 #[arg(help = "Project name or ID")]
601 project: String,
602
603 #[arg(long, help = "Filter by status")]
604 status: Option<String>,
605 },
606
607 #[command(about = "Link session to issue")]
608 Link {
609 #[arg(help = "Session ID")]
610 session_id: i64,
611
612 #[arg(help = "Issue ID (external ID like JIRA-123)")]
613 issue_id: String,
614 },
615}
616
617#[derive(Subcommand)]
618pub enum ClientAction {
619 #[command(about = "Generate a client report")]
620 Generate {
621 #[arg(help = "Client name")]
622 client: String,
623
624 #[arg(help = "Start date (YYYY-MM-DD)")]
625 from: String,
626
627 #[arg(help = "End date (YYYY-MM-DD)")]
628 to: String,
629
630 #[arg(long, help = "Project filter (comma-separated)")]
631 projects: Option<String>,
632
633 #[arg(long, help = "Output format (json, csv, markdown)")]
634 format: Option<String>,
635 },
636
637 #[command(about = "List all client reports")]
638 List {
639 #[arg(long, help = "Client name filter")]
640 client: Option<String>,
641 },
642
643 #[command(about = "View a specific report")]
644 View {
645 #[arg(help = "Report ID")]
646 id: i64,
647 },
648}
649
650#[derive(ValueEnum, Clone, Debug)]
651pub enum Shell {
652 Bash,
653 Zsh,
654 Fish,
655 PowerShell,
656}
657
658impl Cli {
659 pub fn generate_completions(shell: Shell) {
660 use clap_complete::{generate, shells};
661 use std::io;
662
663 let mut cmd = Self::command();
664 match shell {
665 Shell::Bash => generate(shells::Bash, &mut cmd, "tempo", &mut io::stdout()),
666 Shell::Zsh => generate(shells::Zsh, &mut cmd, "tempo", &mut io::stdout()),
667 Shell::Fish => generate(shells::Fish, &mut cmd, "tempo", &mut io::stdout()),
668 Shell::PowerShell => generate(shells::PowerShell, &mut cmd, "tempo", &mut io::stdout()),
669 }
670 }
671}