Skip to main content

chasm/
cli.rs

1// Copyright (c) 2024-2026 Nervosys LLC
2// SPDX-License-Identifier: AGPL-3.0-only
3//! CLI argument definitions using clap derive macros
4
5use clap::{Parser, Subcommand};
6
7/// CHAt System Manager (chasm) - Manage and merge chat sessions across workspaces
8#[derive(Parser)]
9#[command(name = "chasm")]
10#[command(author = "Nervosys")]
11#[command(version)]
12#[command(about = "Manage and merge chat sessions across workspaces", long_about = None)]
13pub struct Cli {
14    #[command(subcommand)]
15    pub command: Commands,
16}
17
18#[derive(Subcommand)]
19pub enum Commands {
20    // ============================================================================
21    // List Commands
22    // ============================================================================
23    /// List workspaces, sessions, or paths
24    #[command(visible_alias = "ls")]
25    List {
26        #[command(subcommand)]
27        command: Option<ListCommands>,
28    },
29
30    // ============================================================================
31    // Find Commands
32    // ============================================================================
33    /// Search workspaces or sessions by text pattern (title, content, ID)
34    Find {
35        #[command(subcommand)]
36        command: Option<FindCommands>,
37    },
38
39    // ============================================================================
40    // Show Commands
41    // ============================================================================
42    /// Show workspaces, sessions, or paths
43    #[command(visible_alias = "info")]
44    Show {
45        #[command(subcommand)]
46        command: Option<ShowCommands>,
47    },
48
49    // ============================================================================
50    // Fetch Commands
51    // ============================================================================
52    /// Fetch chat sessions from workspaces, sessions, or paths
53    Fetch {
54        #[command(subcommand)]
55        command: Option<FetchCommands>,
56    },
57
58    // ============================================================================
59    // Merge Commands
60    // ============================================================================
61    /// Merge chat sessions from workspaces, sessions, or paths
62    Merge {
63        #[command(subcommand)]
64        command: Option<MergeCommands>,
65    },
66
67    // ============================================================================
68    // Export Commands
69    // ============================================================================
70    /// Export chat sessions from workspaces, sessions, or paths
71    Export {
72        #[command(subcommand)]
73        command: Option<ExportCommands>,
74    },
75
76    // ============================================================================
77    // Import Commands
78    // ============================================================================
79    /// Import session files from external directories into a workspace
80    Import {
81        #[command(subcommand)]
82        command: Option<ImportCommands>,
83    },
84
85    // ============================================================================
86    // Move Commands
87    // ============================================================================
88    /// Move chat sessions between workspaces
89    #[command(visible_alias = "mv")]
90    Move {
91        #[command(subcommand)]
92        command: Option<MoveCommands>,
93    },
94
95    // ============================================================================
96    // Git Integration Commands
97    // ============================================================================
98    /// Git integration for chat session versioning
99    Git {
100        #[command(subcommand)]
101        command: GitCommands,
102    },
103
104    // ============================================================================
105    // Migration Commands
106    // ============================================================================
107    /// Migration commands for moving chat sessions between machines
108    Migration {
109        #[command(subcommand)]
110        command: MigrationCommands,
111    },
112
113    // ============================================================================
114    // Run Commands (Agent Launcher + TUI)
115    // ============================================================================
116    /// Launch an AI coding agent with auto-save, or run interactive tools
117    ///
118    /// Supported agents: claude, open, claw, cursor, codex, droid, gemini
119    Run {
120        #[command(subcommand)]
121        command: RunCommands,
122    },
123
124    // ============================================================================
125    // Watch Command (File-System Monitor)
126    // ============================================================================
127    /// Watch agent session directories for changes and auto-harvest
128    ///
129    /// Monitors session storage paths for new or modified files.
130    /// Default: watches all known agent directories.
131    #[command(visible_alias = "w")]
132    Watch {
133        /// Watch a specific agent's session directory (e.g., claude, gemini)
134        #[arg(short, long)]
135        agent: Option<String>,
136
137        /// Watch a custom path instead of agent directories
138        #[arg(short, long)]
139        path: Option<String>,
140
141        /// Debounce interval in seconds before harvesting (default: 3)
142        #[arg(short, long, default_value = "3")]
143        debounce: u64,
144
145        /// Detect changes without harvesting (dry-run)
146        #[arg(long)]
147        no_harvest: bool,
148
149        /// Show detailed file change events
150        #[arg(short, long)]
151        verbose: bool,
152    },
153
154    // ============================================================================
155    // Provider Commands
156    // ============================================================================
157    /// Manage LLM providers (Ollama, vLLM, Foundry, Cursor, etc.)
158    Provider {
159        #[command(subcommand)]
160        command: ProviderCommands,
161    },
162
163    // ============================================================================
164    // Detect Commands
165    // ============================================================================
166    /// Auto-detect workspace and provider information
167    Detect {
168        #[command(subcommand)]
169        command: Option<DetectCommands>,
170    },
171
172    // ============================================================================
173    // Register Commands
174    // ============================================================================
175    /// Add on-disk sessions to VS Code's database index (makes orphaned sessions visible)
176    Register {
177        #[command(subcommand)]
178        command: RegisterCommands,
179    },
180
181    // ============================================================================
182    // Sync Commands (shortcut to harvest sync)
183    // ============================================================================
184    /// Sync sessions between the harvest database and provider workspaces
185    Sync {
186        /// Path to the harvest database
187        #[arg(long)]
188        path: Option<String>,
189
190        /// Push sessions from database to provider workspaces (restore)
191        #[arg(long)]
192        push: bool,
193
194        /// Pull sessions from provider workspaces into database (backup)
195        #[arg(long)]
196        pull: bool,
197
198        /// Filter by provider name
199        #[arg(long)]
200        provider: Option<String>,
201
202        /// Filter by workspace/project path
203        #[arg(long)]
204        workspace: Option<String>,
205
206        /// Session IDs to sync (space-separated)
207        #[arg(long, num_args = 1..)]
208        sessions: Option<Vec<String>>,
209
210        /// Target format for push: auto (detect from provider), jsonl, json
211        #[arg(long, default_value = "auto")]
212        format: String,
213
214        /// Overwrite existing files without prompting
215        #[arg(long)]
216        force: bool,
217
218        /// Dry run - show what would be synced without making changes
219        #[arg(long)]
220        dry_run: bool,
221    },
222
223    // ============================================================================
224    // Harvest Commands
225    // ============================================================================
226    /// Harvest chat sessions from all providers into a unified database
227    Harvest {
228        #[command(subcommand)]
229        command: HarvestCommands,
230    },
231
232    // ============================================================================
233    // Recover Commands
234    // ============================================================================
235    /// Recover lost chat sessions from backups, recording state, or corrupted files
236    #[command(visible_alias = "restore")]
237    Recover {
238        #[command(subcommand)]
239        command: RecoverCommands,
240    },
241
242    // ============================================================================
243    // API Server Commands
244    // ============================================================================
245    /// Start the HTTP API server for the web frontend
246    #[command(visible_alias = "serve")]
247    Api {
248        #[command(subcommand)]
249        command: ApiCommands,
250    },
251
252    // ============================================================================
253    // Agency Commands
254    // ============================================================================
255    /// Agent Development Kit - manage agents and orchestration
256    Agency {
257        #[command(subcommand)]
258        command: AgencyCommands,
259    },
260
261    // ============================================================================
262    // Telemetry Commands
263    // ============================================================================
264    /// Manage anonymous usage data collection (opt-in by default)
265    Telemetry {
266        #[command(subcommand)]
267        command: Option<TelemetryCommands>,
268    },
269
270    // ============================================================================
271    // Completions Command
272    // ============================================================================
273    /// Generate shell completions for bash, zsh, fish, or PowerShell
274    Completions {
275        /// Shell to generate completions for
276        #[arg(value_enum)]
277        shell: CompletionShell,
278    },
279
280    // ============================================================================
281    // Doctor Command
282    // ============================================================================
283    /// Check system environment, providers, and configuration health
284    #[command(visible_alias = "check")]
285    Doctor {
286        /// Run all checks including network connectivity
287        #[arg(long)]
288        full: bool,
289
290        /// Output format: text, json
291        #[arg(long, default_value = "text")]
292        format: String,
293
294        /// Attempt to fix detected issues automatically
295        #[arg(long)]
296        fix: bool,
297    },
298
299    // ============================================================================
300    // Easter Egg
301    // ============================================================================
302    /// Show banner
303    #[command(hide = true)]
304    Banner,
305}
306
307// ============================================================================
308// List Subcommands
309// ============================================================================
310
311#[derive(Subcommand)]
312pub enum ListCommands {
313    /// List all VS Code workspaces
314    #[command(visible_alias = "ws")]
315    Workspaces,
316
317    /// List all chat sessions
318    #[command(visible_alias = "s")]
319    Sessions {
320        /// Filter by project path
321        #[arg(long)]
322        project_path: Option<String>,
323
324        /// Show file sizes
325        #[arg(long, short = 's')]
326        size: bool,
327
328        /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
329        #[arg(long, short = 'p')]
330        provider: Option<String>,
331
332        /// Include all providers
333        #[arg(long)]
334        all_providers: bool,
335    },
336
337    /// List available AI coding agents and their installation status
338    #[command(visible_alias = "a")]
339    Agents,
340
341    /// List agent mode sessions (Copilot Edits / chatEditingSessions)
342    #[command(visible_alias = "e")]
343    Edits {
344        /// Filter by project path
345        #[arg(long)]
346        project_path: Option<String>,
347
348        /// Show file sizes
349        #[arg(long, short = 's')]
350        size: bool,
351
352        /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
353        #[arg(long, short = 'p')]
354        provider: Option<String>,
355    },
356
357    /// List sessions for a specific project path
358    Path {
359        /// Project path (default: current directory)
360        project_path: Option<String>,
361    },
362
363    /// List unregistered sessions (exist on disk but invisible to VS Code)
364    Orphaned {
365        /// Project path (default: current directory)
366        #[arg(long)]
367        path: Option<String>,
368    },
369}
370
371// ============================================================================
372// Find Subcommands
373// ============================================================================
374
375#[derive(Subcommand)]
376pub enum FindCommands {
377    /// Search workspaces by name pattern (defaults to current directory name)
378    #[command(visible_alias = "ws")]
379    Workspace {
380        /// Text pattern to match (case-insensitive, defaults to current directory name)
381        pattern: Option<String>,
382    },
383
384    /// Search sessions by title, content, or ID pattern
385    #[command(visible_alias = "s")]
386    Session {
387        /// Text pattern to match (case-insensitive, defaults to current directory name)
388        pattern: Option<String>,
389
390        /// Filter by project path or workspace name
391        #[arg(long, short = 'w')]
392        workspace: Option<String>,
393
394        /// Only search in session titles (faster, skip content search)
395        #[arg(long, short = 't')]
396        title_only: bool,
397
398        /// Include message content in search (slower)
399        #[arg(long, short = 'c')]
400        content: bool,
401
402        /// Filter sessions modified after this date (YYYY-MM-DD)
403        #[arg(long)]
404        after: Option<String>,
405
406        /// Filter sessions modified before this date (YYYY-MM-DD)
407        #[arg(long)]
408        before: Option<String>,
409
410        /// Filter by internal message timestamp date (YYYY-MM-DD)
411        #[arg(long)]
412        date: Option<String>,
413
414        /// Search across all workspaces (not just current project)
415        #[arg(long, short = 'a')]
416        all: bool,
417
418        /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
419        #[arg(long, short = 'p')]
420        provider: Option<String>,
421
422        /// Search across all providers
423        #[arg(long)]
424        all_providers: bool,
425
426        /// Limit number of results
427        #[arg(long, short = 'n', default_value = "50")]
428        limit: usize,
429    },
430
431    /// Search sessions within a specific project path
432    Path {
433        /// Search pattern (case-insensitive, defaults to current directory name)
434        pattern: Option<String>,
435
436        /// Project path (default: current directory)
437        #[arg(long)]
438        project_path: Option<String>,
439    },
440}
441
442// ============================================================================
443// Show Subcommands
444// ============================================================================
445
446#[derive(Subcommand)]
447pub enum ShowCommands {
448    /// Show workspace details
449    #[command(visible_alias = "ws")]
450    Workspace {
451        /// Workspace name or hash
452        workspace: String,
453    },
454
455    /// Show session details
456    #[command(visible_alias = "s")]
457    Session {
458        /// Session ID or filename
459        session_id: String,
460
461        /// Project path to search in
462        #[arg(long)]
463        project_path: Option<String>,
464    },
465
466    /// Show agent mode session details (Copilot Edits)
467    #[command(visible_alias = "a")]
468    Agent {
469        /// Agent session ID
470        session_id: String,
471
472        /// Project path to search in
473        #[arg(long)]
474        project_path: Option<String>,
475    },
476
477    /// Show the VS Code session index (state.vscdb) for a workspace
478    #[command(visible_alias = "idx")]
479    Index {
480        /// Project path (default: current directory)
481        #[arg(long)]
482        path: Option<String>,
483
484        /// Show indexes for all workspaces that have chat sessions
485        #[arg(long, short)]
486        all: bool,
487    },
488
489    /// Show chat history timeline for a project path
490    Path {
491        /// Path to the project (default: current directory)
492        project_path: Option<String>,
493    },
494
495    /// Show timeline of session activity with gaps visualization
496    Timeline {
497        /// Path to the project (default: current directory)
498        project_path: Option<String>,
499
500        /// Include agent mode sessions
501        #[arg(long, short = 'a')]
502        agents: bool,
503
504        /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
505        #[arg(long, short = 'p')]
506        provider: Option<String>,
507
508        /// Include all providers (aggregate timeline)
509        #[arg(long)]
510        all_providers: bool,
511    },
512}
513
514// ============================================================================
515// Fetch Subcommands
516// ============================================================================
517
518#[derive(Subcommand)]
519pub enum FetchCommands {
520    /// Fetch sessions from workspaces matching a pattern
521    #[command(visible_alias = "ws")]
522    Workspace {
523        /// Workspace name pattern (case-insensitive)
524        workspace_name: String,
525
526        /// Target project path (default: current directory)
527        #[arg(long)]
528        target_path: Option<String>,
529
530        /// Overwrite existing sessions
531        #[arg(long)]
532        force: bool,
533
534        /// Don't register sessions in VS Code index
535        #[arg(long)]
536        no_register: bool,
537    },
538
539    /// Fetch specific sessions by ID
540    #[command(visible_alias = "s")]
541    Session {
542        /// Session IDs to fetch (space-separated)
543        #[arg(required = true, num_args = 1..)]
544        session_ids: Vec<String>,
545
546        /// Target project path (default: current directory)
547        #[arg(long)]
548        target_path: Option<String>,
549
550        /// Overwrite existing sessions
551        #[arg(long)]
552        force: bool,
553
554        /// Don't register sessions in VS Code index
555        #[arg(long)]
556        no_register: bool,
557    },
558
559    /// Fetch chat sessions from other workspaces by project path
560    Path {
561        /// Path to the project (default: current directory)
562        project_path: Option<String>,
563
564        /// Overwrite existing sessions and skip VS Code running check
565        #[arg(long)]
566        force: bool,
567
568        /// Don't register sessions in VS Code index
569        #[arg(long)]
570        no_register: bool,
571    },
572}
573
574// ============================================================================
575// Merge Subcommands
576// ============================================================================
577
578#[derive(Subcommand)]
579pub enum MergeCommands {
580    /// Merge sessions from workspaces matching a name pattern
581    #[command(visible_alias = "ws")]
582    Workspace {
583        /// Workspace name pattern to search for (case-insensitive)
584        workspace_name: String,
585
586        /// Title for the merged session
587        #[arg(short, long)]
588        title: Option<String>,
589
590        /// Target project path to save the merged session (default: current directory)
591        #[arg(long)]
592        target_path: Option<String>,
593
594        /// Skip VS Code running check
595        #[arg(long)]
596        force: bool,
597
598        /// Don't create backup of current sessions
599        #[arg(long)]
600        no_backup: bool,
601    },
602
603    /// Merge sessions from multiple workspace name patterns
604    #[command(visible_alias = "wss")]
605    Workspaces {
606        /// Workspace name patterns to search for (space-separated, case-insensitive)
607        #[arg(required = true, num_args = 1..)]
608        workspace_names: Vec<String>,
609
610        /// Title for the merged session
611        #[arg(short, long)]
612        title: Option<String>,
613
614        /// Target project path to save the merged session (default: current directory)
615        #[arg(long)]
616        target_path: Option<String>,
617
618        /// Skip VS Code running check
619        #[arg(long)]
620        force: bool,
621
622        /// Don't create backup of current sessions
623        #[arg(long)]
624        no_backup: bool,
625    },
626
627    /// Merge specific sessions by their IDs or filenames
628    #[command(visible_alias = "s")]
629    Sessions {
630        /// Session IDs or filenames (comma-separated or space-separated)
631        #[arg(required = true, num_args = 1..)]
632        sessions: Vec<String>,
633
634        /// Title for the merged session
635        #[arg(short, long)]
636        title: Option<String>,
637
638        /// Target project path to save the merged session (default: current directory)
639        #[arg(long)]
640        target_path: Option<String>,
641
642        /// Skip VS Code running check
643        #[arg(long)]
644        force: bool,
645
646        /// Don't create backup of current sessions
647        #[arg(long)]
648        no_backup: bool,
649    },
650
651    /// Merge all sessions for a project path into one unified chat
652    Path {
653        /// Path to the project (default: current directory)
654        project_path: Option<String>,
655
656        /// Title for the merged session
657        #[arg(short, long)]
658        title: Option<String>,
659
660        /// Skip VS Code running check
661        #[arg(long)]
662        force: bool,
663
664        /// Don't create backup of current sessions
665        #[arg(long)]
666        no_backup: bool,
667    },
668
669    /// Merge sessions from an LLM provider (Ollama, Cursor, etc.)
670    Provider {
671        /// Provider name (copilot, cursor, ollama, vllm, foundry, etc.)
672        provider_name: String,
673
674        /// Title for the merged session
675        #[arg(short, long)]
676        title: Option<String>,
677
678        /// Target project path to save the merged session (default: current directory)
679        #[arg(long)]
680        target_path: Option<String>,
681
682        /// Session IDs from the provider to include (omit for all)
683        #[arg(long)]
684        sessions: Option<Vec<String>>,
685
686        /// Skip VS Code running check
687        #[arg(long)]
688        force: bool,
689
690        /// Don't create backup of current sessions
691        #[arg(long)]
692        no_backup: bool,
693    },
694
695    /// Merge sessions from multiple providers
696    #[command(name = "providers")]
697    Providers {
698        /// Provider names (space-separated: copilot cursor ollama)
699        #[arg(required = true, num_args = 1..)]
700        providers: Vec<String>,
701
702        /// Title for the merged session
703        #[arg(short, long)]
704        title: Option<String>,
705
706        /// Target project path to save the merged session (default: current directory)
707        #[arg(long)]
708        target_path: Option<String>,
709
710        /// Filter by workspace name pattern (applies to providers that support workspaces)
711        #[arg(long)]
712        workspace: Option<String>,
713
714        /// Skip VS Code running check
715        #[arg(long)]
716        force: bool,
717
718        /// Don't create backup of current sessions
719        #[arg(long)]
720        no_backup: bool,
721    },
722
723    /// Merge all sessions across all available providers
724    All {
725        /// Title for the merged session
726        #[arg(short, long)]
727        title: Option<String>,
728
729        /// Target project path to save the merged session (default: current directory)
730        #[arg(long)]
731        target_path: Option<String>,
732
733        /// Filter by workspace name pattern (applies to providers that support workspaces)
734        #[arg(long)]
735        workspace: Option<String>,
736
737        /// Skip VS Code running check
738        #[arg(long)]
739        force: bool,
740
741        /// Don't create backup of current sessions
742        #[arg(long)]
743        no_backup: bool,
744    },
745}
746
747// ============================================================================
748// Export Subcommands
749// ============================================================================
750
751#[derive(Subcommand)]
752pub enum ExportCommands {
753    /// Export sessions from a workspace by hash
754    #[command(visible_alias = "ws")]
755    Workspace {
756        /// Destination directory for exported sessions
757        destination: String,
758
759        /// Source workspace hash
760        hash: String,
761    },
762
763    /// Export specific sessions by ID
764    #[command(visible_alias = "s")]
765    Sessions {
766        /// Destination directory for exported sessions
767        destination: String,
768
769        /// Session IDs to export (space-separated)
770        #[arg(required = true, num_args = 1..)]
771        session_ids: Vec<String>,
772
773        /// Source project path
774        #[arg(long)]
775        project_path: Option<String>,
776    },
777
778    /// Export chat sessions from a project path
779    Path {
780        /// Destination directory for exported sessions
781        destination: String,
782
783        /// Source project path (default: current directory)
784        project_path: Option<String>,
785    },
786
787    /// Export chat sessions from multiple project paths (batch operation)
788    Batch {
789        /// Base destination directory (subdirectories created per project)
790        destination: String,
791
792        /// Project paths to export (space-separated)
793        #[arg(required = true, num_args = 1..)]
794        project_paths: Vec<String>,
795    },
796}
797
798// ============================================================================
799// Import Subcommands
800// ============================================================================
801
802#[derive(Subcommand)]
803pub enum ImportCommands {
804    /// Copy session files from external directory into a workspace
805    #[command(visible_alias = "ws")]
806    Workspace {
807        /// Source directory containing session JSON files to import
808        source: String,
809
810        /// Target workspace hash
811        hash: String,
812
813        /// Overwrite existing sessions
814        #[arg(long)]
815        force: bool,
816    },
817
818    /// Copy specific session files into a workspace
819    #[command(visible_alias = "s")]
820    Sessions {
821        /// Session files to import (space-separated paths)
822        #[arg(required = true, num_args = 1..)]
823        session_files: Vec<String>,
824
825        /// Target project path (default: current directory)
826        #[arg(long)]
827        target_path: Option<String>,
828
829        /// Overwrite existing sessions
830        #[arg(long)]
831        force: bool,
832    },
833
834    /// Copy session files from external directory into a project workspace
835    Path {
836        /// Source directory containing session JSON files to import
837        source: String,
838
839        /// Target project path (default: current directory)
840        target_path: Option<String>,
841
842        /// Overwrite existing sessions
843        #[arg(long)]
844        force: bool,
845    },
846}
847
848// ============================================================================
849// Move Subcommands
850// ============================================================================
851
852#[derive(Subcommand)]
853pub enum MoveCommands {
854    /// Move all sessions from one workspace to another
855    #[command(visible_alias = "ws")]
856    Workspace {
857        /// Source workspace hash
858        source_hash: String,
859
860        /// Target workspace hash or project path
861        target: String,
862    },
863
864    /// Move specific sessions by ID
865    #[command(visible_alias = "s")]
866    Sessions {
867        /// Session IDs to move (space-separated)
868        #[arg(required = true, num_args = 1..)]
869        session_ids: Vec<String>,
870
871        /// Target project path
872        target_path: String,
873    },
874
875    /// Move sessions from a source path to target path
876    Path {
877        /// Source project path
878        source_path: String,
879
880        /// Target project path
881        target_path: String,
882    },
883}
884
885// ============================================================================
886// Git Subcommands
887// ============================================================================
888
889#[derive(Subcommand)]
890pub enum GitCommands {
891    /// Configure git settings for chat sessions
892    Config {
893        /// Git user name
894        #[arg(long)]
895        name: Option<String>,
896
897        /// Git user email
898        #[arg(long)]
899        email: Option<String>,
900
901        /// Project path
902        #[arg(long)]
903        path: Option<String>,
904    },
905
906    /// Initialize git versioning for chat sessions
907    Init {
908        /// Project path
909        path: String,
910    },
911
912    /// Add chat sessions to git (stage and optionally commit)
913    Add {
914        /// Project path
915        path: String,
916
917        /// Also commit the changes
918        #[arg(long)]
919        commit: bool,
920
921        /// Commit message (requires --commit)
922        #[arg(short, long)]
923        message: Option<String>,
924    },
925
926    /// Show git status of chat sessions
927    Status {
928        /// Project path
929        path: String,
930    },
931
932    /// Create a git tag snapshot of chat sessions
933    Snapshot {
934        /// Project path
935        path: String,
936
937        /// Tag name (auto-generated if not provided)
938        #[arg(long)]
939        tag: Option<String>,
940
941        /// Snapshot message
942        #[arg(short, long)]
943        message: Option<String>,
944    },
945
946    /// Track chat sessions together with associated file changes
947    Track {
948        /// Project path
949        path: String,
950
951        /// Commit message describing the changes
952        #[arg(short, long)]
953        message: Option<String>,
954
955        /// Include all staged and unstaged file changes
956        #[arg(long)]
957        all: bool,
958
959        /// Include specific files in addition to chat sessions
960        #[arg(long)]
961        files: Option<Vec<String>>,
962
963        /// Create a tag for this tracked state
964        #[arg(long)]
965        tag: Option<String>,
966    },
967
968    /// Show history of chat session commits with associated file changes
969    Log {
970        /// Project path
971        path: String,
972
973        /// Number of commits to show
974        #[arg(short = 'n', long, default_value = "10")]
975        count: usize,
976
977        /// Show only commits that include chat session changes
978        #[arg(long)]
979        sessions_only: bool,
980    },
981
982    /// Diff chat sessions between commits or current state
983    Diff {
984        /// Project path
985        path: String,
986
987        /// First commit (default: HEAD)
988        #[arg(long)]
989        from: Option<String>,
990
991        /// Second commit (default: working directory)
992        #[arg(long)]
993        to: Option<String>,
994
995        /// Show associated file changes alongside chat diffs
996        #[arg(long)]
997        with_files: bool,
998    },
999
1000    /// Restore chat sessions from a specific commit
1001    Restore {
1002        /// Project path
1003        path: String,
1004
1005        /// Commit hash, tag, or reference to restore from
1006        commit: String,
1007
1008        /// Also restore associated files from the same commit
1009        #[arg(long)]
1010        with_files: bool,
1011
1012        /// Create a backup before restoring
1013        #[arg(long)]
1014        backup: bool,
1015    },
1016}
1017
1018// ============================================================================
1019// Migration Subcommands
1020// ============================================================================
1021
1022#[derive(Subcommand)]
1023pub enum MigrationCommands {
1024    /// Create a migration package for moving to a new machine
1025    Create {
1026        /// Output directory for migration package
1027        output: String,
1028
1029        /// Comma-separated list of project paths to include
1030        #[arg(long)]
1031        projects: Option<String>,
1032
1033        /// Include all workspaces with chat sessions
1034        #[arg(long)]
1035        all: bool,
1036    },
1037
1038    /// Restore a migration package on a new machine
1039    Restore {
1040        /// Path to migration package directory
1041        package: String,
1042
1043        /// Project path mapping: 'old1:new1;old2:new2'
1044        #[arg(long)]
1045        mapping: Option<String>,
1046
1047        /// Show what would be done without doing it
1048        #[arg(long)]
1049        dry_run: bool,
1050    },
1051}
1052
1053// ============================================================================
1054// Run Subcommands
1055// ============================================================================
1056
1057#[derive(Subcommand)]
1058pub enum RunCommands {
1059    /// Launch interactive TUI (Text User Interface)
1060    Tui,
1061
1062    /// Launch Claude Code with auto-save
1063    #[command(visible_aliases = ["claude-code", "claudecode"])]
1064    Claude {
1065        /// Extra arguments to pass to the agent
1066        #[arg(last = true)]
1067        args: Vec<String>,
1068        /// Disable auto-save
1069        #[arg(long)]
1070        no_save: bool,
1071        /// Verbose output
1072        #[arg(short, long)]
1073        verbose: bool,
1074    },
1075
1076    /// Launch OpenCode with auto-save
1077    #[command(visible_aliases = ["opencode", "open-code"])]
1078    Open {
1079        #[arg(last = true)]
1080        args: Vec<String>,
1081        #[arg(long)]
1082        no_save: bool,
1083        #[arg(short, long)]
1084        verbose: bool,
1085    },
1086
1087    /// Launch OpenClaw (ClawdBot) with auto-save
1088    #[command(visible_aliases = ["openclaw", "clawdbot"])]
1089    Claw {
1090        #[arg(last = true)]
1091        args: Vec<String>,
1092        #[arg(long)]
1093        no_save: bool,
1094        #[arg(short, long)]
1095        verbose: bool,
1096    },
1097
1098    /// Launch Cursor CLI with auto-save
1099    Cursor {
1100        #[arg(last = true)]
1101        args: Vec<String>,
1102        #[arg(long)]
1103        no_save: bool,
1104        #[arg(short, long)]
1105        verbose: bool,
1106    },
1107
1108    /// Launch Codex CLI (OpenAI) with auto-save
1109    #[command(visible_aliases = ["codex-cli", "codexcli"])]
1110    Codex {
1111        #[arg(last = true)]
1112        args: Vec<String>,
1113        #[arg(long)]
1114        no_save: bool,
1115        #[arg(short, long)]
1116        verbose: bool,
1117    },
1118
1119    /// Launch Droid CLI (Factory) with auto-save
1120    #[command(visible_aliases = ["droid-cli", "droidcli", "factory"])]
1121    Droid {
1122        #[arg(last = true)]
1123        args: Vec<String>,
1124        #[arg(long)]
1125        no_save: bool,
1126        #[arg(short, long)]
1127        verbose: bool,
1128    },
1129
1130    /// Launch Gemini CLI (Google) with auto-save
1131    #[command(visible_aliases = ["gemini-cli", "geminicli"])]
1132    Gemini {
1133        #[arg(last = true)]
1134        args: Vec<String>,
1135        #[arg(long)]
1136        no_save: bool,
1137        #[arg(short, long)]
1138        verbose: bool,
1139    },
1140}
1141
1142// ============================================================================
1143// Provider Subcommands
1144// ============================================================================
1145
1146#[derive(Subcommand)]
1147pub enum ProviderCommands {
1148    /// List all discovered LLM providers
1149    List,
1150
1151    /// Show detailed info about a specific provider
1152    Info {
1153        /// Provider name (copilot, cursor, ollama, vllm, foundry, lm-studio, etc.)
1154        provider: String,
1155    },
1156
1157    /// Configure a provider
1158    Config {
1159        /// Provider name
1160        provider: String,
1161
1162        /// API endpoint URL
1163        #[arg(long)]
1164        endpoint: Option<String>,
1165
1166        /// API key
1167        #[arg(long)]
1168        api_key: Option<String>,
1169
1170        /// Default model
1171        #[arg(long)]
1172        model: Option<String>,
1173
1174        /// Enable or disable the provider
1175        #[arg(long)]
1176        enabled: Option<bool>,
1177    },
1178
1179    /// Import sessions from another provider
1180    Import {
1181        /// Source provider name
1182        #[arg(long)]
1183        from: String,
1184
1185        /// Target project path (or current directory)
1186        #[arg(long)]
1187        path: Option<String>,
1188
1189        /// Session ID to import (omit for all)
1190        #[arg(long)]
1191        session: Option<String>,
1192    },
1193
1194    /// Test connection to a provider
1195    Test {
1196        /// Provider name
1197        provider: String,
1198    },
1199}
1200
1201// ============================================================================
1202// Detect Subcommands
1203// ============================================================================
1204
1205#[derive(Subcommand)]
1206pub enum DetectCommands {
1207    /// Detect workspace for a path
1208    Workspace {
1209        /// Project path (default: current directory)
1210        path: Option<String>,
1211    },
1212
1213    /// Detect available providers
1214    Providers {
1215        /// Only show providers with sessions
1216        #[arg(long)]
1217        with_sessions: bool,
1218    },
1219
1220    /// Detect which provider a session belongs to
1221    Session {
1222        /// Session ID or filename
1223        session_id: String,
1224
1225        /// Project path to search in
1226        #[arg(long)]
1227        path: Option<String>,
1228    },
1229
1230    /// Detect everything (workspace, providers, sessions) for a path
1231    All {
1232        /// Project path (default: current directory)
1233        path: Option<String>,
1234
1235        /// Show detailed information
1236        #[arg(long)]
1237        verbose: bool,
1238    },
1239
1240    /// Find all workspace hashes for a project path (including orphaned workspaces with sessions)
1241    Orphaned {
1242        /// Project path (default: current directory)
1243        path: Option<String>,
1244
1245        /// Automatically recover orphaned sessions by copying to active workspace
1246        #[arg(long, short)]
1247        recover: bool,
1248    },
1249}
1250
1251// ============================================================================
1252// Register Subcommands
1253// ============================================================================
1254
1255#[derive(Subcommand)]
1256pub enum RegisterCommands {
1257    /// Register all on-disk sessions into VS Code's index (fixes orphaned sessions)
1258    All {
1259        /// Project path (default: current directory)
1260        #[arg(long)]
1261        path: Option<String>,
1262
1263        /// Merge all sessions into one before registering
1264        #[arg(long, short)]
1265        merge: bool,
1266
1267        /// Force registration even if VS Code is running
1268        #[arg(long, short)]
1269        force: bool,
1270
1271        /// Close VS Code before registering (ensures index is not overwritten by cache)
1272        #[arg(long)]
1273        close_vscode: bool,
1274
1275        /// Reopen VS Code after registering (implies --close-vscode)
1276        #[arg(long)]
1277        reopen: bool,
1278    },
1279
1280    /// Register specific sessions by ID or title into VS Code's index
1281    #[command(visible_alias = "s")]
1282    Session {
1283        /// Session IDs or filenames (without .json extension)
1284        #[arg(required_unless_present = "title")]
1285        ids: Vec<String>,
1286
1287        /// Match sessions by title instead of ID
1288        #[arg(long, short, num_args = 1.., value_delimiter = ' ')]
1289        title: Option<Vec<String>>,
1290
1291        /// Project path (default: current directory)
1292        #[arg(long)]
1293        path: Option<String>,
1294
1295        /// Force registration even if VS Code is running
1296        #[arg(long, short)]
1297        force: bool,
1298    },
1299
1300    /// Recursively walk directories to find and register orphaned sessions for all workspaces
1301    #[command(visible_alias = "r")]
1302    Recursive {
1303        /// Root path to start recursive search (default: current directory)
1304        path: Option<String>,
1305
1306        /// Maximum directory depth to recurse (default: unlimited)
1307        #[arg(long, short)]
1308        depth: Option<usize>,
1309
1310        /// Force registration even if VS Code is running
1311        #[arg(long, short)]
1312        force: bool,
1313
1314        /// Only show what would be registered without making changes
1315        #[arg(long)]
1316        dry_run: bool,
1317
1318        /// Skip directories matching these patterns (can be used multiple times)
1319        #[arg(long, short = 'x')]
1320        exclude: Vec<String>,
1321    },
1322
1323    /// Repair sessions: compact large JSONL files and rebuild the index with correct metadata
1324    #[command(visible_alias = "fix")]
1325    Repair {
1326        /// Project path (default: current directory)
1327        #[arg(long)]
1328        path: Option<String>,
1329
1330        /// Repair all workspaces that have chat sessions
1331        #[arg(long, short)]
1332        all: bool,
1333
1334        /// Recursively scan a directory tree for workspaces and repair all discovered sessions
1335        #[arg(long, short)]
1336        recursive: bool,
1337
1338        /// Maximum directory depth when using --recursive (default: unlimited)
1339        #[arg(long, short)]
1340        depth: Option<usize>,
1341
1342        /// Skip directories matching these patterns when using --recursive
1343        #[arg(long, short = 'x')]
1344        exclude: Vec<String>,
1345
1346        /// Only show what would be repaired without making changes
1347        #[arg(long)]
1348        dry_run: bool,
1349
1350        /// Force even if VS Code is running
1351        #[arg(long, short)]
1352        force: bool,
1353
1354        /// Close VS Code before repairing (ensures index is not overwritten)
1355        #[arg(long)]
1356        close_vscode: bool,
1357
1358        /// Reopen VS Code after repairing (implies --close-vscode)
1359        #[arg(long)]
1360        reopen: bool,
1361    },
1362}
1363
1364// ============================================================================
1365// Harvest Subcommands
1366// ============================================================================
1367
1368#[derive(Subcommand)]
1369pub enum HarvestCommands {
1370    /// Initialize a harvest database
1371    Init {
1372        /// Path to the database file (default: ./chat_sessions.db)
1373        #[arg(long)]
1374        path: Option<String>,
1375
1376        /// Initialize git tracking for the database
1377        #[arg(long)]
1378        git: bool,
1379    },
1380
1381    /// Scan for available providers and sessions
1382    Scan {
1383        /// Show individual sessions
1384        #[arg(long)]
1385        sessions: bool,
1386
1387        /// Scan for web-based LLM providers (ChatGPT, Claude, etc.)
1388        #[arg(long)]
1389        web: bool,
1390
1391        /// Timeout in seconds for web provider checks (default: 5)
1392        #[arg(long, default_value = "5")]
1393        timeout: u64,
1394
1395        /// Show verbose debug output for browser scanning
1396        #[arg(long, short)]
1397        verbose: bool,
1398    },
1399
1400    /// Run the harvest to collect sessions from all providers
1401    Run {
1402        /// Path to the harvest database
1403        #[arg(long)]
1404        path: Option<String>,
1405
1406        /// Only include specific providers (comma-separated: copilot,cursor,ollama)
1407        #[arg(long, value_delimiter = ',')]
1408        providers: Option<Vec<String>>,
1409
1410        /// Exclude specific providers (comma-separated)
1411        #[arg(long, value_delimiter = ',')]
1412        exclude: Option<Vec<String>>,
1413
1414        /// Only harvest sessions changed since last run
1415        #[arg(long)]
1416        incremental: bool,
1417
1418        /// Auto-commit changes to git after harvest
1419        #[arg(long)]
1420        commit: bool,
1421
1422        /// Commit message (requires --commit)
1423        #[arg(short, long)]
1424        message: Option<String>,
1425    },
1426
1427    /// Show harvest database status
1428    Status {
1429        /// Path to the harvest database
1430        #[arg(long)]
1431        path: Option<String>,
1432    },
1433
1434    /// List sessions in the harvest database
1435    List {
1436        /// Path to the harvest database
1437        #[arg(long)]
1438        path: Option<String>,
1439
1440        /// Filter by provider name
1441        #[arg(long)]
1442        provider: Option<String>,
1443
1444        /// Maximum number of sessions to show
1445        #[arg(long, default_value = "20")]
1446        limit: usize,
1447
1448        /// Search sessions by title or ID
1449        #[arg(long)]
1450        search: Option<String>,
1451    },
1452
1453    /// Export sessions from the harvest database
1454    Export {
1455        /// Output file path
1456        output: String,
1457
1458        /// Path to the harvest database
1459        #[arg(long)]
1460        path: Option<String>,
1461
1462        /// Export format: json, jsonl, md (markdown)
1463        #[arg(long, default_value = "json")]
1464        format: String,
1465
1466        /// Filter by provider name
1467        #[arg(long)]
1468        provider: Option<String>,
1469
1470        /// Export specific sessions by ID (comma-separated)
1471        #[arg(long, value_delimiter = ',')]
1472        sessions: Option<Vec<String>>,
1473    },
1474
1475    /// Import a shared chat session from a URL
1476    Share {
1477        /// Share link URL (ChatGPT, Claude, etc.)
1478        url: String,
1479
1480        /// Path to the harvest database
1481        #[arg(long)]
1482        path: Option<String>,
1483
1484        /// Custom name for the imported session
1485        #[arg(long)]
1486        name: Option<String>,
1487
1488        /// Associate with a workspace path
1489        #[arg(long)]
1490        workspace: Option<String>,
1491    },
1492
1493    /// List pending or imported share links
1494    Shares {
1495        /// Path to the harvest database
1496        #[arg(long)]
1497        path: Option<String>,
1498
1499        /// Filter by status: pending, imported, failed, expired
1500        #[arg(long)]
1501        status: Option<String>,
1502
1503        /// Maximum number of links to show
1504        #[arg(long, default_value = "20")]
1505        limit: usize,
1506    },
1507
1508    /// Create a checkpoint (version snapshot) of a session
1509    Checkpoint {
1510        /// Session ID to checkpoint
1511        session: String,
1512
1513        /// Path to the harvest database
1514        #[arg(long)]
1515        path: Option<String>,
1516
1517        /// Checkpoint description message
1518        #[arg(short, long)]
1519        message: Option<String>,
1520    },
1521
1522    /// List checkpoints for a session
1523    Checkpoints {
1524        /// Session ID to list checkpoints for
1525        session: String,
1526
1527        /// Path to the harvest database
1528        #[arg(long)]
1529        path: Option<String>,
1530    },
1531
1532    /// Revert a session to a previous checkpoint
1533    Revert {
1534        /// Session ID to revert
1535        session: String,
1536
1537        /// Checkpoint number to revert to
1538        checkpoint: i64,
1539
1540        /// Path to the harvest database
1541        #[arg(long)]
1542        path: Option<String>,
1543    },
1544
1545    /// Sync sessions between the harvest database and provider workspaces
1546    Sync {
1547        /// Path to the harvest database
1548        #[arg(long)]
1549        path: Option<String>,
1550
1551        /// Push sessions from database to provider workspaces (restore)
1552        #[arg(long)]
1553        push: bool,
1554
1555        /// Pull sessions from provider workspaces into database (backup)
1556        #[arg(long)]
1557        pull: bool,
1558
1559        /// Filter by provider name
1560        #[arg(long)]
1561        provider: Option<String>,
1562
1563        /// Filter by workspace/project path
1564        #[arg(long)]
1565        workspace: Option<String>,
1566
1567        /// Session IDs to sync (space-separated)
1568        #[arg(long, num_args = 1..)]
1569        sessions: Option<Vec<String>>,
1570
1571        /// Target format for push: auto (detect from provider), jsonl, json
1572        #[arg(long, default_value = "auto")]
1573        format: String,
1574
1575        /// Overwrite existing files without prompting
1576        #[arg(long)]
1577        force: bool,
1578
1579        /// Dry run - show what would be synced without making changes
1580        #[arg(long)]
1581        dry_run: bool,
1582    },
1583
1584    /// Rebuild the full-text search index
1585    Rebuild {
1586        /// Path to the harvest database
1587        #[arg(long)]
1588        path: Option<String>,
1589    },
1590
1591    /// Search messages across all sessions (full-text search)
1592    Search {
1593        /// Search query
1594        query: String,
1595
1596        /// Path to the harvest database
1597        #[arg(long)]
1598        path: Option<String>,
1599
1600        /// Filter by provider
1601        #[arg(long)]
1602        provider: Option<String>,
1603
1604        /// Maximum results to show
1605        #[arg(long, default_value = "20")]
1606        limit: usize,
1607    },
1608
1609    /// Git operations for the harvest database
1610    Git {
1611        #[command(subcommand)]
1612        command: HarvestGitCommands,
1613    },
1614}
1615
1616#[derive(Subcommand)]
1617pub enum HarvestGitCommands {
1618    /// Initialize git tracking for the harvest database
1619    Init {
1620        /// Path to the harvest database
1621        #[arg(long)]
1622        path: Option<String>,
1623    },
1624
1625    /// Commit changes to the harvest database
1626    Commit {
1627        /// Path to the harvest database
1628        #[arg(long)]
1629        path: Option<String>,
1630
1631        /// Commit message
1632        #[arg(short, long)]
1633        message: Option<String>,
1634    },
1635
1636    /// Show git log for the harvest database
1637    Log {
1638        /// Path to the harvest database
1639        #[arg(long)]
1640        path: Option<String>,
1641
1642        /// Number of commits to show
1643        #[arg(short = 'n', long, default_value = "10")]
1644        count: usize,
1645    },
1646
1647    /// Show changes to the harvest database
1648    Diff {
1649        /// Path to the harvest database
1650        #[arg(long)]
1651        path: Option<String>,
1652
1653        /// Compare against specific commit
1654        #[arg(long)]
1655        commit: Option<String>,
1656    },
1657
1658    /// Restore harvest database from a commit
1659    Restore {
1660        /// Commit hash to restore from
1661        commit: String,
1662
1663        /// Path to the harvest database
1664        #[arg(long)]
1665        path: Option<String>,
1666    },
1667}
1668
1669// ============================================================================
1670// Recover Subcommands
1671// ============================================================================
1672
1673#[derive(Subcommand)]
1674pub enum RecoverCommands {
1675    /// Scan for recoverable sessions from various sources
1676    Scan {
1677        /// Provider to scan: vscode, cursor, all (default: all)
1678        #[arg(long, default_value = "all")]
1679        provider: String,
1680
1681        /// Show detailed information about each session
1682        #[arg(short, long)]
1683        verbose: bool,
1684
1685        /// Include sessions older than normal retention period
1686        #[arg(long)]
1687        include_old: bool,
1688    },
1689
1690    /// Recover sessions from the recording API server
1691    Recording {
1692        /// Server URL (default: http://localhost:8787)
1693        #[arg(long, default_value = "http://localhost:8787")]
1694        server: String,
1695
1696        /// Only recover specific session ID
1697        #[arg(long)]
1698        session: Option<String>,
1699
1700        /// Output directory for recovered sessions
1701        #[arg(short, long)]
1702        output: Option<String>,
1703    },
1704
1705    /// Recover sessions from SQLite database backups
1706    Database {
1707        /// Path to the database backup file
1708        backup: String,
1709
1710        /// Extract specific session by ID
1711        #[arg(long)]
1712        session: Option<String>,
1713
1714        /// Output directory for recovered sessions
1715        #[arg(short, long)]
1716        output: Option<String>,
1717
1718        /// Output format: json, jsonl, md (default: json)
1719        #[arg(long, default_value = "json")]
1720        format: String,
1721    },
1722
1723    /// Recover sessions from incomplete/corrupted JSONL files
1724    Jsonl {
1725        /// Path to the JSONL file to repair
1726        file: String,
1727
1728        /// Output file for recovered sessions (default: same name with .recovered suffix)
1729        #[arg(short, long)]
1730        output: Option<String>,
1731
1732        /// Attempt aggressive recovery (may produce incomplete sessions)
1733        #[arg(long)]
1734        aggressive: bool,
1735    },
1736
1737    /// List sessions from VS Code's workspaceStorage that may be orphaned
1738    Orphans {
1739        /// Provider to check: vscode, cursor, all (default: all)
1740        #[arg(long, default_value = "all")]
1741        provider: String,
1742
1743        /// Show sessions not in the SQLite state database
1744        #[arg(long)]
1745        unindexed: bool,
1746
1747        /// Check if files actually exist on disk
1748        #[arg(long)]
1749        verify: bool,
1750    },
1751
1752    /// Repair corrupted session files in place
1753    Repair {
1754        /// Path to the session directory or file
1755        path: String,
1756
1757        /// Create backup before repair
1758        #[arg(long, default_value = "true")]
1759        backup: bool,
1760
1761        /// Dry run - show what would be repaired without making changes
1762        #[arg(long)]
1763        dry_run: bool,
1764    },
1765
1766    /// Show recovery status and recommendations
1767    Status {
1768        /// Provider to check: vscode, cursor, all (default: all)
1769        #[arg(long, default_value = "all")]
1770        provider: String,
1771
1772        /// Check disk space and file system health
1773        #[arg(long)]
1774        system: bool,
1775    },
1776
1777    /// Convert session files between JSON and JSONL formats
1778    Convert {
1779        /// Input file to convert (.json or .jsonl)
1780        input: String,
1781
1782        /// Output file (auto-detects format from extension, or uses --format)
1783        #[arg(short, long)]
1784        output: Option<String>,
1785
1786        /// Output format: json, jsonl (default: opposite of input)
1787        #[arg(long)]
1788        format: Option<String>,
1789
1790        /// VS Code version compatibility: legacy (< 1.109), modern (>= 1.109), both
1791        #[arg(long, default_value = "both")]
1792        compat: String,
1793    },
1794
1795    /// Extract sessions from a VS Code workspace by project path
1796    Extract {
1797        /// Project directory path (will find corresponding workspace hash)
1798        path: String,
1799
1800        /// Output directory for extracted sessions
1801        #[arg(short, long)]
1802        output: Option<String>,
1803
1804        /// Include both JSON and JSONL formats if available
1805        #[arg(long)]
1806        all_formats: bool,
1807
1808        /// Include editing session fragments (agent mode work)
1809        #[arg(long)]
1810        include_edits: bool,
1811    },
1812
1813    /// Detect and display session format and version information
1814    Detect {
1815        /// Session file to analyze (.json or .jsonl)
1816        file: String,
1817
1818        /// Show raw format detection details
1819        #[arg(long)]
1820        verbose: bool,
1821
1822        /// Output detection result as JSON
1823        #[arg(long)]
1824        json: bool,
1825    },
1826
1827    /// Upgrade session files to the current provider format (JSON to JSONL for VS Code 1.109+)
1828    Upgrade {
1829        /// Project paths to upgrade (space-separated)
1830        #[arg(required = true, num_args = 1..)]
1831        project_paths: Vec<String>,
1832
1833        /// Provider to use: vscode, cursor, auto (default: auto-detect)
1834        #[arg(long, default_value = "auto")]
1835        provider: String,
1836
1837        /// Target format: jsonl (VS Code 1.109+), json (legacy). Default: jsonl
1838        #[arg(long, default_value = "jsonl")]
1839        target_format: String,
1840
1841        /// Skip creating backup of original files
1842        #[arg(long)]
1843        no_backup: bool,
1844
1845        /// Dry run - show what would be upgraded without making changes
1846        #[arg(long)]
1847        dry_run: bool,
1848    },
1849}
1850
1851// ============================================================================
1852// API Server Subcommands
1853// ============================================================================
1854
1855#[derive(Subcommand)]
1856pub enum ApiCommands {
1857    /// Start the API server
1858    Serve {
1859        /// Host to bind to (default: 0.0.0.0 for all interfaces)
1860        #[arg(long, default_value = "0.0.0.0")]
1861        host: String,
1862
1863        /// Port to listen on (default: 8787)
1864        #[arg(short, long, default_value = "8787")]
1865        port: u16,
1866
1867        /// Path to the database file
1868        #[arg(long)]
1869        database: Option<String>,
1870    },
1871}
1872
1873// ============================================================================
1874// Agency (Agent Development Kit) Subcommands
1875// ============================================================================
1876
1877#[derive(Subcommand)]
1878pub enum AgencyCommands {
1879    /// List available agents and their roles
1880    List {
1881        /// Show detailed information
1882        #[arg(short, long)]
1883        verbose: bool,
1884    },
1885
1886    /// Show agent information
1887    Info {
1888        /// Agent name or ID
1889        name: String,
1890    },
1891
1892    /// List supported orchestration modes
1893    Modes,
1894
1895    /// Run an agent with a prompt
1896    Run {
1897        /// Agent name to run
1898        #[arg(short, long, default_value = "assistant")]
1899        agent: String,
1900
1901        /// Prompt or task for the agent
1902        prompt: String,
1903
1904        /// Model to use (e.g., gemini-2.0-flash, gpt-4o)
1905        #[arg(short, long)]
1906        model: Option<String>,
1907
1908        /// Orchestration mode (single, sequential, parallel, swarm)
1909        #[arg(long, default_value = "single")]
1910        orchestration: String,
1911
1912        /// Enable verbose output
1913        #[arg(short, long)]
1914        verbose: bool,
1915    },
1916
1917    /// Create a new agent configuration
1918    Create {
1919        /// Agent name
1920        name: String,
1921
1922        /// Agent role (coordinator, researcher, coder, reviewer, executor, writer, tester, custom)
1923        #[arg(short, long, default_value = "custom")]
1924        role: String,
1925
1926        /// System instruction for the agent
1927        #[arg(short, long)]
1928        instruction: Option<String>,
1929
1930        /// Model to use
1931        #[arg(short, long)]
1932        model: Option<String>,
1933    },
1934
1935    /// List available tools
1936    Tools,
1937
1938    /// Show swarm templates
1939    Templates,
1940}
1941
1942// ============================================================================
1943// Telemetry Subcommands
1944// ============================================================================
1945
1946#[derive(Subcommand)]
1947pub enum TelemetryCommands {
1948    /// Show telemetry status and what data is collected
1949    #[command(visible_alias = "status")]
1950    Info,
1951
1952    /// Enable anonymous usage data collection (this is the default)
1953    #[command(visible_alias = "enable")]
1954    OptIn,
1955
1956    /// Disable anonymous usage data collection
1957    #[command(visible_alias = "disable")]
1958    OptOut,
1959
1960    /// Reset telemetry ID (generates new anonymous identifier)
1961    Reset,
1962
1963    /// Record structured data for later AI analysis
1964    #[command(visible_alias = "log")]
1965    Record {
1966        /// Event category (e.g., 'workflow', 'error', 'performance', 'usage')
1967        #[arg(short, long, default_value = "custom")]
1968        category: String,
1969
1970        /// Event name or type
1971        #[arg(short, long)]
1972        event: String,
1973
1974        /// JSON data payload (or use --kv for key=value pairs)
1975        #[arg(short, long)]
1976        data: Option<String>,
1977
1978        /// Key-value pairs (can be repeated: -k foo=bar -k baz=123)
1979        #[arg(short = 'k', long = "kv", value_parser = parse_key_value)]
1980        kv: Vec<(String, String)>,
1981
1982        /// Add tags for filtering (can be repeated: -t important -t session-123)
1983        #[arg(short, long)]
1984        tags: Vec<String>,
1985
1986        /// Optional session or context ID to associate with
1987        #[arg(long)]
1988        context: Option<String>,
1989
1990        /// Print recorded event details
1991        #[arg(short, long)]
1992        verbose: bool,
1993    },
1994
1995    /// Show recorded telemetry data
1996    #[command(visible_alias = "logs")]
1997    Show {
1998        /// Filter by category
1999        #[arg(short, long)]
2000        category: Option<String>,
2001
2002        /// Filter by event name
2003        #[arg(short, long)]
2004        event: Option<String>,
2005
2006        /// Filter by tag
2007        #[arg(short, long)]
2008        tag: Option<String>,
2009
2010        /// Maximum number of records to show
2011        #[arg(short = 'n', long, default_value = "20")]
2012        limit: usize,
2013
2014        /// Output format: table, json, jsonl
2015        #[arg(short, long, default_value = "table")]
2016        format: String,
2017
2018        /// Show records after this date (YYYY-MM-DD)
2019        #[arg(long)]
2020        after: Option<String>,
2021
2022        /// Show records before this date (YYYY-MM-DD)
2023        #[arg(long)]
2024        before: Option<String>,
2025    },
2026
2027    /// Export recorded data for AI analysis
2028    Export {
2029        /// Output file path
2030        output: String,
2031
2032        /// Export format: json, jsonl, csv
2033        #[arg(short, long, default_value = "jsonl")]
2034        format: String,
2035
2036        /// Filter by category
2037        #[arg(short, long)]
2038        category: Option<String>,
2039
2040        /// Include installation metadata in export
2041        #[arg(long)]
2042        with_metadata: bool,
2043    },
2044
2045    /// Clear recorded telemetry data
2046    Clear {
2047        /// Skip confirmation prompt
2048        #[arg(short, long)]
2049        force: bool,
2050
2051        /// Only clear records older than N days
2052        #[arg(long)]
2053        older_than: Option<u32>,
2054    },
2055
2056    /// Configure remote telemetry endpoint
2057    Config {
2058        /// Set the remote endpoint URL
2059        #[arg(long)]
2060        endpoint: Option<String>,
2061
2062        /// Set the API key for authentication
2063        #[arg(long)]
2064        api_key: Option<String>,
2065
2066        /// Enable remote telemetry sending
2067        #[arg(long)]
2068        enable_remote: bool,
2069
2070        /// Disable remote telemetry sending
2071        #[arg(long)]
2072        disable_remote: bool,
2073    },
2074
2075    /// Sync telemetry records to remote server
2076    Sync {
2077        /// Maximum number of records to sync
2078        #[arg(short = 'n', long)]
2079        limit: Option<usize>,
2080
2081        /// Clear local records after successful sync
2082        #[arg(long)]
2083        clear_after: bool,
2084    },
2085
2086    /// Test connection to remote telemetry server
2087    Test,
2088}
2089
2090/// Parse key=value pairs for telemetry record command
2091fn parse_key_value(s: &str) -> std::result::Result<(String, String), String> {
2092    let pos = s
2093        .find('=')
2094        .ok_or_else(|| format!("invalid key=value pair: no '=' found in '{s}'"))?;
2095    Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
2096}
2097
2098// ============================================================================
2099// Shell Completion Enum
2100// ============================================================================
2101
2102/// Supported shells for completion generation
2103#[derive(Clone, Debug, clap::ValueEnum)]
2104pub enum CompletionShell {
2105    /// Bash shell
2106    Bash,
2107    /// Zsh shell
2108    Zsh,
2109    /// Fish shell
2110    Fish,
2111    /// PowerShell
2112    Powershell,
2113    /// Elvish shell
2114    Elvish,
2115}