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