tempo_cli/cli/
types.rs

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 = "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
209#[derive(Subcommand)]
210pub enum ProjectAction {
211    #[command(about = "Archive a project")]
212    Archive {
213        #[arg(help = "Project name or ID")]
214        project: String,
215    },
216    
217    #[command(about = "Unarchive a project")]
218    Unarchive {
219        #[arg(help = "Project name or ID")]
220        project: String,
221    },
222    
223    #[command(about = "Update project path")]
224    UpdatePath {
225        #[arg(help = "Project name or ID")]
226        project: String,
227        
228        #[arg(help = "New path")]
229        path: PathBuf,
230    },
231    
232    #[command(about = "Add tag to project")]
233    AddTag {
234        #[arg(help = "Project name or ID")]
235        project: String,
236        
237        #[arg(help = "Tag name")]
238        tag: String,
239    },
240    
241    #[command(about = "Remove tag from project")]
242    RemoveTag {
243        #[arg(help = "Project name or ID")]
244        project: String,
245        
246        #[arg(help = "Tag name")]
247        tag: String,
248    },
249}
250
251#[derive(Subcommand)]
252pub enum SessionAction {
253    #[command(about = "Start tracking time for current project")]
254    Start {
255        #[arg(long, help = "Project name or path")]
256        project: Option<String>,
257        
258        #[arg(long, help = "Session context")]
259        context: Option<String>,
260    },
261    
262    #[command(about = "Stop current session")]
263    Stop,
264    
265    #[command(about = "Pause current session")]
266    Pause,
267    
268    #[command(about = "Resume paused session")]
269    Resume,
270    
271    #[command(about = "Show current session")]
272    Current,
273    
274    #[command(about = "List recent sessions")]
275    List {
276        #[arg(long, help = "Number of sessions to show")]
277        limit: Option<usize>,
278        
279        #[arg(long, help = "Project filter")]
280        project: Option<String>,
281    },
282    
283    #[command(about = "Edit a session")]
284    Edit {
285        #[arg(help = "Session ID")]
286        id: i64,
287        
288        #[arg(long, help = "New start time")]
289        start: Option<String>,
290        
291        #[arg(long, help = "New end time")]
292        end: Option<String>,
293        
294        #[arg(long, help = "New project")]
295        project: Option<String>,
296        
297        #[arg(long, help = "Edit reason")]
298        reason: Option<String>,
299    },
300    
301    #[command(about = "Delete a session")]
302    Delete {
303        #[arg(help = "Session ID")]
304        id: i64,
305        
306        #[arg(long, help = "Force deletion without confirmation")]
307        force: bool,
308    },
309    
310    #[command(about = "Merge multiple sessions into one")]
311    Merge {
312        #[arg(help = "Session IDs to merge (comma-separated)")]
313        session_ids: String,
314        
315        #[arg(long, help = "Target project for merged session")]
316        project: Option<String>,
317        
318        #[arg(long, help = "Notes for the merged session")]
319        notes: Option<String>,
320    },
321    
322    #[command(about = "Split a session into multiple sessions")]
323    Split {
324        #[arg(help = "Session ID to split")]
325        session_id: i64,
326        
327        #[arg(help = "Split points (comma-separated times like '10:30,11:45')")]
328        split_times: String,
329        
330        #[arg(long, help = "Notes for each split session (comma-separated)")]
331        notes: Option<String>,
332    },
333}
334
335#[derive(Subcommand)]
336pub enum TagAction {
337    #[command(about = "Create a new tag")]
338    Create {
339        #[arg(help = "Tag name")]
340        name: String,
341        
342        #[arg(long, help = "Tag color")]
343        color: Option<String>,
344        
345        #[arg(long, help = "Tag description")]
346        description: Option<String>,
347    },
348    
349    #[command(about = "List all tags")]
350    List,
351    
352    #[command(about = "Delete a tag")]
353    Delete {
354        #[arg(help = "Tag name")]
355        name: String,
356    },
357}
358
359#[derive(Subcommand)]
360pub enum ConfigAction {
361    #[command(about = "Show current configuration")]
362    Show,
363    
364    #[command(about = "Set configuration value")]
365    Set {
366        #[arg(help = "Configuration key")]
367        key: String,
368        
369        #[arg(help = "Configuration value")]
370        value: String,
371    },
372    
373    #[command(about = "Get configuration value")]
374    Get {
375        #[arg(help = "Configuration key")]
376        key: String,
377    },
378    
379    #[command(about = "Reset configuration to defaults")]
380    Reset,
381}
382
383#[derive(Subcommand)]
384pub enum GoalAction {
385    #[command(about = "Create a new goal")]
386    Create {
387        #[arg(help = "Goal name")]
388        name: String,
389        
390        #[arg(help = "Target hours")]
391        target_hours: f64,
392        
393        #[arg(long, help = "Project name or ID")]
394        project: Option<String>,
395        
396        #[arg(long, help = "Goal description")]
397        description: Option<String>,
398        
399        #[arg(long, help = "Start date (YYYY-MM-DD)")]
400        start_date: Option<String>,
401        
402        #[arg(long, help = "End date (YYYY-MM-DD)")]
403        end_date: Option<String>,
404    },
405    
406    #[command(about = "List goals")]
407    List {
408        #[arg(long, help = "Project name or ID")]
409        project: Option<String>,
410    },
411    
412    #[command(about = "Update goal progress")]
413    Update {
414        #[arg(help = "Goal ID")]
415        id: i64,
416        
417        #[arg(help = "Hours to add")]
418        hours: f64,
419    },
420}
421
422#[derive(Subcommand)]
423pub enum EstimateAction {
424    #[command(about = "Create a time estimate")]
425    Create {
426        #[arg(help = "Project name or ID")]
427        project: String,
428        
429        #[arg(help = "Task name")]
430        task: String,
431        
432        #[arg(help = "Estimated hours")]
433        hours: f64,
434        
435        #[arg(long, help = "Due date (YYYY-MM-DD)")]
436        due_date: Option<String>,
437    },
438    
439    #[command(about = "Record actual time")]
440    Record {
441        #[arg(help = "Estimate ID")]
442        id: i64,
443        
444        #[arg(help = "Actual hours")]
445        hours: f64,
446    },
447    
448    #[command(about = "List estimates")]
449    List {
450        #[arg(help = "Project name or ID")]
451        project: String,
452    },
453}
454
455#[derive(Subcommand)]
456pub enum BranchAction {
457    #[command(about = "List git branches for a project")]
458    List {
459        #[arg(help = "Project name or ID")]
460        project: String,
461    },
462    
463    #[command(about = "Show branch statistics")]
464    Stats {
465        #[arg(help = "Project name or ID")]
466        project: String,
467        
468        #[arg(long, help = "Branch name")]
469        branch: Option<String>,
470    },
471}
472
473#[derive(Subcommand)]
474pub enum TemplateAction {
475    #[command(about = "Create a new project template")]
476    Create {
477        #[arg(help = "Template name")]
478        name: String,
479        
480        #[arg(long, help = "Template description")]
481        description: Option<String>,
482        
483        #[arg(long, help = "Default tags (comma-separated)")]
484        tags: Option<String>,
485        
486        #[arg(long, help = "Workspace path for template")]
487        workspace_path: Option<PathBuf>,
488    },
489    
490    #[command(about = "List all templates")]
491    List,
492    
493    #[command(about = "Delete a template")]
494    Delete {
495        #[arg(help = "Template name or ID")]
496        template: String,
497    },
498    
499    #[command(about = "Use a template to initialize a project")]
500    Use {
501        #[arg(help = "Template name or ID")]
502        template: String,
503        
504        #[arg(help = "Project name")]
505        project_name: String,
506        
507        #[arg(long, help = "Project path")]
508        path: Option<PathBuf>,
509    },
510}
511
512#[derive(Subcommand)]
513pub enum WorkspaceAction {
514    #[command(about = "Create a new workspace")]
515    Create {
516        #[arg(help = "Workspace name")]
517        name: String,
518        
519        #[arg(long, help = "Workspace description")]
520        description: Option<String>,
521        
522        #[arg(long, help = "Workspace path")]
523        path: Option<PathBuf>,
524    },
525    
526    #[command(about = "List all workspaces")]
527    List,
528    
529    #[command(about = "Add project to workspace")]
530    AddProject {
531        #[arg(help = "Workspace name or ID")]
532        workspace: String,
533        
534        #[arg(help = "Project name or ID")]
535        project: String,
536    },
537    
538    #[command(about = "Remove project from workspace")]
539    RemoveProject {
540        #[arg(help = "Workspace name or ID")]
541        workspace: String,
542        
543        #[arg(help = "Project name or ID")]
544        project: String,
545    },
546    
547    #[command(about = "List projects in workspace")]
548    Projects {
549        #[arg(help = "Workspace name or ID")]
550        workspace: String,
551    },
552    
553    #[command(about = "Delete a workspace")]
554    Delete {
555        #[arg(help = "Workspace name or ID")]
556        workspace: String,
557    },
558}
559
560#[derive(Subcommand)]
561pub enum CalendarAction {
562    #[command(about = "Add a calendar event")]
563    Add {
564        #[arg(help = "Event name")]
565        name: String,
566        
567        #[arg(help = "Start time (YYYY-MM-DD HH:MM)")]
568        start: String,
569        
570        #[arg(long, help = "End time (YYYY-MM-DD HH:MM)")]
571        end: Option<String>,
572        
573        #[arg(long, help = "Event type (meeting, focus_block, deadline)")]
574        event_type: Option<String>,
575        
576        #[arg(long, help = "Project name or ID")]
577        project: Option<String>,
578        
579        #[arg(long, help = "Event description")]
580        description: Option<String>,
581    },
582    
583    #[command(about = "List calendar events")]
584    List {
585        #[arg(long, help = "Start date (YYYY-MM-DD)")]
586        from: Option<String>,
587        
588        #[arg(long, help = "End date (YYYY-MM-DD)")]
589        to: Option<String>,
590        
591        #[arg(long, help = "Project name or ID")]
592        project: Option<String>,
593    },
594    
595    #[command(about = "Delete a calendar event")]
596    Delete {
597        #[arg(help = "Event ID")]
598        id: i64,
599    },
600}
601
602#[derive(Subcommand)]
603pub enum IssueAction {
604    #[command(about = "Sync issues from external tracker")]
605    Sync {
606        #[arg(help = "Project name or ID")]
607        project: String,
608        
609        #[arg(long, help = "Issue tracker type (jira, github, gitlab)")]
610        tracker_type: Option<String>,
611    },
612    
613    #[command(about = "List issues for a project")]
614    List {
615        #[arg(help = "Project name or ID")]
616        project: String,
617        
618        #[arg(long, help = "Filter by status")]
619        status: Option<String>,
620    },
621    
622    #[command(about = "Link session to issue")]
623    Link {
624        #[arg(help = "Session ID")]
625        session_id: i64,
626        
627        #[arg(help = "Issue ID (external ID like JIRA-123)")]
628        issue_id: String,
629    },
630}
631
632#[derive(Subcommand)]
633pub enum ClientAction {
634    #[command(about = "Generate a client report")]
635    Generate {
636        #[arg(help = "Client name")]
637        client: String,
638        
639        #[arg(help = "Start date (YYYY-MM-DD)")]
640        from: String,
641        
642        #[arg(help = "End date (YYYY-MM-DD)")]
643        to: String,
644        
645        #[arg(long, help = "Project filter (comma-separated)")]
646        projects: Option<String>,
647        
648        #[arg(long, help = "Output format (json, csv, markdown)")]
649        format: Option<String>,
650    },
651    
652    #[command(about = "List all client reports")]
653    List {
654        #[arg(long, help = "Client name filter")]
655        client: Option<String>,
656    },
657    
658    #[command(about = "View a specific report")]
659    View {
660        #[arg(help = "Report ID")]
661        id: i64,
662    },
663}
664
665#[derive(ValueEnum, Clone, Debug)]
666pub enum Shell {
667    Bash,
668    Zsh,
669    Fish,
670    PowerShell,
671}
672
673impl Cli {
674    pub fn generate_completions(shell: Shell) {
675        use clap_complete::{generate, shells};
676        use std::io;
677
678        let mut cmd = Self::command();
679        match shell {
680            Shell::Bash => generate(shells::Bash, &mut cmd, "tempo", &mut io::stdout()),
681            Shell::Zsh => generate(shells::Zsh, &mut cmd, "tempo", &mut io::stdout()),
682            Shell::Fish => generate(shells::Fish, &mut cmd, "tempo", &mut io::stdout()),
683            Shell::PowerShell => generate(shells::PowerShell, &mut cmd, "tempo", &mut io::stdout()),
684        }
685    }
686}