tempo_cli/cli/
types.rs

1use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
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 = "Show database pool statistics")]
146    PoolStats,
147
148    #[command(about = "Time estimation tracking")]
149    Estimate {
150        #[command(subcommand)]
151        action: EstimateAction,
152    },
153
154    #[command(about = "Git branch tracking")]
155    Branch {
156        #[command(subcommand)]
157        action: BranchAction,
158    },
159
160    #[command(about = "Project templates")]
161    Template {
162        #[command(subcommand)]
163        action: TemplateAction,
164    },
165
166    #[command(about = "Workspace management")]
167    Workspace {
168        #[command(subcommand)]
169        action: WorkspaceAction,
170    },
171
172    #[command(about = "Calendar integration")]
173    Calendar {
174        #[command(subcommand)]
175        action: CalendarAction,
176    },
177
178    #[command(about = "Issue tracker integration")]
179    Issue {
180        #[command(subcommand)]
181        action: IssueAction,
182    },
183
184    #[command(about = "Client reporting")]
185    Client {
186        #[command(subcommand)]
187        action: ClientAction,
188    },
189
190    #[command(about = "Update tempo to the latest version")]
191    Update {
192        #[arg(long, help = "Check for updates without installing")]
193        check: bool,
194
195        #[arg(long, help = "Force update even if current version is latest")]
196        force: bool,
197
198        #[arg(long, help = "Show detailed update information")]
199        verbose: bool,
200    },
201
202    #[command(about = "Generate shell completions", hide = true)]
203    Completions {
204        #[arg(help = "Shell to generate completions for")]
205        shell: Shell,
206    },
207
208    #[command(about = "Display file contents")]
209    Cat {
210        #[arg(help = "Files to display")]
211        files: Vec<PathBuf>,
212
213        #[arg(short = 'A', long, help = "Equivalent to -vET")]
214        show_all: bool,
215
216        #[arg(short = 'b', long, help = "Number nonblank output lines, overrides -n")]
217        number_nonblank: bool,
218
219        #[arg(short = 'e', help = "Equivalent to -vE")]
220        show_ends: bool,
221
222        #[arg(short = 'E', long, help = "Display $ at end of each line")]
223        show_ends_only: bool,
224
225        #[arg(short = 'n', long, help = "Number all output lines")]
226        number: bool,
227
228        #[arg(short = 's', long, help = "Suppress repeated empty output lines")]
229        squeeze_blank: bool,
230
231        #[arg(short = 't', help = "Equivalent to -vT")]
232        show_tabs: bool,
233
234        #[arg(short = 'T', long, help = "Display TAB characters as ^I")]
235        show_tabs_only: bool,
236
237        #[arg(short = 'v', long, help = "Use ^ and M- notation, except for LFD and TAB")]
238        show_nonprinting: bool,
239
240        #[arg(long, help = "Output version information and exit")]
241        version: bool,
242    },
243}
244
245#[derive(Subcommand)]
246pub enum ProjectAction {
247    #[command(about = "Archive a project")]
248    Archive {
249        #[arg(help = "Project name or ID")]
250        project: String,
251    },
252
253    #[command(about = "Unarchive a project")]
254    Unarchive {
255        #[arg(help = "Project name or ID")]
256        project: String,
257    },
258
259    #[command(about = "Update project path")]
260    UpdatePath {
261        #[arg(help = "Project name or ID")]
262        project: String,
263
264        #[arg(help = "New path")]
265        path: PathBuf,
266    },
267
268    #[command(about = "Add tag to project")]
269    AddTag {
270        #[arg(help = "Project name or ID")]
271        project: String,
272
273        #[arg(help = "Tag name")]
274        tag: String,
275    },
276
277    #[command(about = "Remove tag from project")]
278    RemoveTag {
279        #[arg(help = "Project name or ID")]
280        project: String,
281
282        #[arg(help = "Tag name")]
283        tag: String,
284    },
285}
286
287#[derive(Subcommand)]
288pub enum SessionAction {
289    #[command(about = "Start tracking time for current project")]
290    Start {
291        #[arg(long, help = "Project name or path")]
292        project: Option<String>,
293
294        #[arg(long, help = "Session context")]
295        context: Option<String>,
296    },
297
298    #[command(about = "Stop current session")]
299    Stop,
300
301    #[command(about = "Pause current session")]
302    Pause,
303
304    #[command(about = "Resume paused session")]
305    Resume,
306
307    #[command(about = "Show current session")]
308    Current,
309
310    #[command(about = "List recent sessions")]
311    List {
312        #[arg(long, help = "Number of sessions to show")]
313        limit: Option<usize>,
314
315        #[arg(long, help = "Project filter")]
316        project: Option<String>,
317    },
318
319    #[command(about = "Edit a session")]
320    Edit {
321        #[arg(help = "Session ID")]
322        id: i64,
323
324        #[arg(long, help = "New start time")]
325        start: Option<String>,
326
327        #[arg(long, help = "New end time")]
328        end: Option<String>,
329
330        #[arg(long, help = "New project")]
331        project: Option<String>,
332
333        #[arg(long, help = "Edit reason")]
334        reason: Option<String>,
335    },
336
337    #[command(about = "Delete a session")]
338    Delete {
339        #[arg(help = "Session ID")]
340        id: i64,
341
342        #[arg(long, help = "Force deletion without confirmation")]
343        force: bool,
344    },
345
346    #[command(about = "Merge multiple sessions into one")]
347    Merge {
348        #[arg(help = "Session IDs to merge (comma-separated)")]
349        session_ids: String,
350
351        #[arg(long, help = "Target project for merged session")]
352        project: Option<String>,
353
354        #[arg(long, help = "Notes for the merged session")]
355        notes: Option<String>,
356    },
357
358    #[command(about = "Split a session into multiple sessions")]
359    Split {
360        #[arg(help = "Session ID to split")]
361        session_id: i64,
362
363        #[arg(help = "Split points (comma-separated times like '10:30,11:45')")]
364        split_times: String,
365
366        #[arg(long, help = "Notes for each split session (comma-separated)")]
367        notes: Option<String>,
368    },
369}
370
371#[derive(Subcommand)]
372pub enum TagAction {
373    #[command(about = "Create a new tag")]
374    Create {
375        #[arg(help = "Tag name")]
376        name: String,
377
378        #[arg(long, help = "Tag color")]
379        color: Option<String>,
380
381        #[arg(long, help = "Tag description")]
382        description: Option<String>,
383    },
384
385    #[command(about = "List all tags")]
386    List,
387
388    #[command(about = "Delete a tag")]
389    Delete {
390        #[arg(help = "Tag name")]
391        name: String,
392    },
393}
394
395#[derive(Subcommand)]
396pub enum ConfigAction {
397    #[command(about = "Show current configuration")]
398    Show,
399
400    #[command(about = "Set configuration value")]
401    Set {
402        #[arg(help = "Configuration key")]
403        key: String,
404
405        #[arg(help = "Configuration value")]
406        value: String,
407    },
408
409    #[command(about = "Get configuration value")]
410    Get {
411        #[arg(help = "Configuration key")]
412        key: String,
413    },
414
415    #[command(about = "Reset configuration to defaults")]
416    Reset,
417}
418
419#[derive(Subcommand)]
420pub enum GoalAction {
421    #[command(about = "Create a new goal")]
422    Create {
423        #[arg(help = "Goal name")]
424        name: String,
425
426        #[arg(help = "Target hours")]
427        target_hours: f64,
428
429        #[arg(long, help = "Project name or ID")]
430        project: Option<String>,
431
432        #[arg(long, help = "Goal description")]
433        description: Option<String>,
434
435        #[arg(long, help = "Start date (YYYY-MM-DD)")]
436        start_date: Option<String>,
437
438        #[arg(long, help = "End date (YYYY-MM-DD)")]
439        end_date: Option<String>,
440    },
441
442    #[command(about = "List goals")]
443    List {
444        #[arg(long, help = "Project name or ID")]
445        project: Option<String>,
446    },
447
448    #[command(about = "Update goal progress")]
449    Update {
450        #[arg(help = "Goal ID")]
451        id: i64,
452
453        #[arg(help = "Hours to add")]
454        hours: f64,
455    },
456}
457
458#[derive(Subcommand)]
459pub enum EstimateAction {
460    #[command(about = "Create a time estimate")]
461    Create {
462        #[arg(help = "Project name or ID")]
463        project: String,
464
465        #[arg(help = "Task name")]
466        task: String,
467
468        #[arg(help = "Estimated hours")]
469        hours: f64,
470
471        #[arg(long, help = "Due date (YYYY-MM-DD)")]
472        due_date: Option<String>,
473    },
474
475    #[command(about = "Record actual time")]
476    Record {
477        #[arg(help = "Estimate ID")]
478        id: i64,
479
480        #[arg(help = "Actual hours")]
481        hours: f64,
482    },
483
484    #[command(about = "List estimates")]
485    List {
486        #[arg(help = "Project name or ID")]
487        project: String,
488    },
489}
490
491#[derive(Subcommand)]
492pub enum BranchAction {
493    #[command(about = "List git branches for a project")]
494    List {
495        #[arg(help = "Project name or ID")]
496        project: String,
497    },
498
499    #[command(about = "Show branch statistics")]
500    Stats {
501        #[arg(help = "Project name or ID")]
502        project: String,
503
504        #[arg(long, help = "Branch name")]
505        branch: Option<String>,
506    },
507}
508
509#[derive(Subcommand)]
510pub enum TemplateAction {
511    #[command(about = "Create a new project template")]
512    Create {
513        #[arg(help = "Template name")]
514        name: String,
515
516        #[arg(long, help = "Template description")]
517        description: Option<String>,
518
519        #[arg(long, help = "Default tags (comma-separated)")]
520        tags: Option<String>,
521
522        #[arg(long, help = "Workspace path for template")]
523        workspace_path: Option<PathBuf>,
524    },
525
526    #[command(about = "List all templates")]
527    List,
528
529    #[command(about = "Delete a template")]
530    Delete {
531        #[arg(help = "Template name or ID")]
532        template: String,
533    },
534
535    #[command(about = "Use a template to initialize a project")]
536    Use {
537        #[arg(help = "Template name or ID")]
538        template: String,
539
540        #[arg(help = "Project name")]
541        project_name: String,
542
543        #[arg(long, help = "Project path")]
544        path: Option<PathBuf>,
545    },
546}
547
548#[derive(Subcommand)]
549pub enum WorkspaceAction {
550    #[command(about = "Create a new workspace")]
551    Create {
552        #[arg(help = "Workspace name")]
553        name: String,
554
555        #[arg(long, help = "Workspace description")]
556        description: Option<String>,
557
558        #[arg(long, help = "Workspace path")]
559        path: Option<PathBuf>,
560    },
561
562    #[command(about = "List all workspaces")]
563    List,
564
565    #[command(about = "Add project to workspace")]
566    AddProject {
567        #[arg(help = "Workspace name or ID")]
568        workspace: String,
569
570        #[arg(help = "Project name or ID")]
571        project: String,
572    },
573
574    #[command(about = "Remove project from workspace")]
575    RemoveProject {
576        #[arg(help = "Workspace name or ID")]
577        workspace: String,
578
579        #[arg(help = "Project name or ID")]
580        project: String,
581    },
582
583    #[command(about = "List projects in workspace")]
584    Projects {
585        #[arg(help = "Workspace name or ID")]
586        workspace: String,
587    },
588
589    #[command(about = "Delete a workspace")]
590    Delete {
591        #[arg(help = "Workspace name or ID")]
592        workspace: String,
593    },
594}
595
596#[derive(Subcommand)]
597pub enum CalendarAction {
598    #[command(about = "Add a calendar event")]
599    Add {
600        #[arg(help = "Event name")]
601        name: String,
602
603        #[arg(help = "Start time (YYYY-MM-DD HH:MM)")]
604        start: String,
605
606        #[arg(long, help = "End time (YYYY-MM-DD HH:MM)")]
607        end: Option<String>,
608
609        #[arg(long, help = "Event type (meeting, focus_block, deadline)")]
610        event_type: Option<String>,
611
612        #[arg(long, help = "Project name or ID")]
613        project: Option<String>,
614
615        #[arg(long, help = "Event description")]
616        description: Option<String>,
617    },
618
619    #[command(about = "List calendar events")]
620    List {
621        #[arg(long, help = "Start date (YYYY-MM-DD)")]
622        from: Option<String>,
623
624        #[arg(long, help = "End date (YYYY-MM-DD)")]
625        to: Option<String>,
626
627        #[arg(long, help = "Project name or ID")]
628        project: Option<String>,
629    },
630
631    #[command(about = "Delete a calendar event")]
632    Delete {
633        #[arg(help = "Event ID")]
634        id: i64,
635    },
636}
637
638#[derive(Subcommand)]
639pub enum IssueAction {
640    #[command(about = "Sync issues from external tracker")]
641    Sync {
642        #[arg(help = "Project name or ID")]
643        project: String,
644
645        #[arg(long, help = "Issue tracker type (jira, github, gitlab)")]
646        tracker_type: Option<String>,
647    },
648
649    #[command(about = "List issues for a project")]
650    List {
651        #[arg(help = "Project name or ID")]
652        project: String,
653
654        #[arg(long, help = "Filter by status")]
655        status: Option<String>,
656    },
657
658    #[command(about = "Link session to issue")]
659    Link {
660        #[arg(help = "Session ID")]
661        session_id: i64,
662
663        #[arg(help = "Issue ID (external ID like JIRA-123)")]
664        issue_id: String,
665    },
666}
667
668#[derive(Subcommand)]
669pub enum ClientAction {
670    #[command(about = "Generate a client report")]
671    Generate {
672        #[arg(help = "Client name")]
673        client: String,
674
675        #[arg(help = "Start date (YYYY-MM-DD)")]
676        from: String,
677
678        #[arg(help = "End date (YYYY-MM-DD)")]
679        to: String,
680
681        #[arg(long, help = "Project filter (comma-separated)")]
682        projects: Option<String>,
683
684        #[arg(long, help = "Output format (json, csv, markdown)")]
685        format: Option<String>,
686    },
687
688    #[command(about = "List all client reports")]
689    List {
690        #[arg(long, help = "Client name filter")]
691        client: Option<String>,
692    },
693
694    #[command(about = "View a specific report")]
695    View {
696        #[arg(help = "Report ID")]
697        id: i64,
698    },
699}
700
701#[derive(ValueEnum, Clone, Debug)]
702pub enum Shell {
703    Bash,
704    Zsh,
705    Fish,
706    PowerShell,
707}
708
709impl Cli {
710    pub fn generate_completions(shell: Shell) {
711        use clap_complete::{generate, shells};
712        use std::io;
713
714        let mut cmd = Self::command();
715        match shell {
716            Shell::Bash => generate(shells::Bash, &mut cmd, "tempo", &mut io::stdout()),
717            Shell::Zsh => generate(shells::Zsh, &mut cmd, "tempo", &mut io::stdout()),
718            Shell::Fish => generate(shells::Fish, &mut cmd, "tempo", &mut io::stdout()),
719            Shell::PowerShell => generate(shells::PowerShell, &mut cmd, "tempo", &mut io::stdout()),
720        }
721    }
722}