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 = "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}