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    /// Trim oversized sessions by keeping only the most recent requests
1364    #[command(visible_alias = "t")]
1365    Trim {
1366        /// Project path (default: current directory)
1367        #[arg(long)]
1368        path: Option<String>,
1369
1370        /// Number of recent requests to keep (default: 20)
1371        #[arg(long, short, default_value = "20")]
1372        keep: usize,
1373
1374        /// Session ID to trim (default: largest session)
1375        #[arg(long, short)]
1376        session: Option<String>,
1377
1378        /// Trim all sessions over the size threshold
1379        #[arg(long, short)]
1380        all: bool,
1381
1382        /// Only trim sessions larger than this size in MB (default: 10)
1383        #[arg(long, default_value = "10")]
1384        threshold_mb: u64,
1385
1386        /// Force even if VS Code is running
1387        #[arg(long, short)]
1388        force: bool,
1389    },
1390}
1391
1392// ============================================================================
1393// Harvest Subcommands
1394// ============================================================================
1395
1396#[derive(Subcommand)]
1397pub enum HarvestCommands {
1398    /// Initialize a harvest database
1399    Init {
1400        /// Path to the database file (default: ./chat_sessions.db)
1401        #[arg(long)]
1402        path: Option<String>,
1403
1404        /// Initialize git tracking for the database
1405        #[arg(long)]
1406        git: bool,
1407    },
1408
1409    /// Scan for available providers and sessions
1410    Scan {
1411        /// Show individual sessions
1412        #[arg(long)]
1413        sessions: bool,
1414
1415        /// Scan for web-based LLM providers (ChatGPT, Claude, etc.)
1416        #[arg(long)]
1417        web: bool,
1418
1419        /// Timeout in seconds for web provider checks (default: 5)
1420        #[arg(long, default_value = "5")]
1421        timeout: u64,
1422
1423        /// Show verbose debug output for browser scanning
1424        #[arg(long, short)]
1425        verbose: bool,
1426    },
1427
1428    /// Run the harvest to collect sessions from all providers
1429    Run {
1430        /// Path to the harvest database
1431        #[arg(long)]
1432        path: Option<String>,
1433
1434        /// Only include specific providers (comma-separated: copilot,cursor,ollama)
1435        #[arg(long, value_delimiter = ',')]
1436        providers: Option<Vec<String>>,
1437
1438        /// Exclude specific providers (comma-separated)
1439        #[arg(long, value_delimiter = ',')]
1440        exclude: Option<Vec<String>>,
1441
1442        /// Only harvest sessions changed since last run
1443        #[arg(long)]
1444        incremental: bool,
1445
1446        /// Auto-commit changes to git after harvest
1447        #[arg(long)]
1448        commit: bool,
1449
1450        /// Commit message (requires --commit)
1451        #[arg(short, long)]
1452        message: Option<String>,
1453    },
1454
1455    /// Show harvest database status
1456    Status {
1457        /// Path to the harvest database
1458        #[arg(long)]
1459        path: Option<String>,
1460    },
1461
1462    /// List sessions in the harvest database
1463    List {
1464        /// Path to the harvest database
1465        #[arg(long)]
1466        path: Option<String>,
1467
1468        /// Filter by provider name
1469        #[arg(long)]
1470        provider: Option<String>,
1471
1472        /// Maximum number of sessions to show
1473        #[arg(long, default_value = "20")]
1474        limit: usize,
1475
1476        /// Search sessions by title or ID
1477        #[arg(long)]
1478        search: Option<String>,
1479    },
1480
1481    /// Export sessions from the harvest database
1482    Export {
1483        /// Output file path
1484        output: String,
1485
1486        /// Path to the harvest database
1487        #[arg(long)]
1488        path: Option<String>,
1489
1490        /// Export format: json, jsonl, md (markdown)
1491        #[arg(long, default_value = "json")]
1492        format: String,
1493
1494        /// Filter by provider name
1495        #[arg(long)]
1496        provider: Option<String>,
1497
1498        /// Export specific sessions by ID (comma-separated)
1499        #[arg(long, value_delimiter = ',')]
1500        sessions: Option<Vec<String>>,
1501    },
1502
1503    /// Import a shared chat session from a URL
1504    Share {
1505        /// Share link URL (ChatGPT, Claude, etc.)
1506        url: String,
1507
1508        /// Path to the harvest database
1509        #[arg(long)]
1510        path: Option<String>,
1511
1512        /// Custom name for the imported session
1513        #[arg(long)]
1514        name: Option<String>,
1515
1516        /// Associate with a workspace path
1517        #[arg(long)]
1518        workspace: Option<String>,
1519    },
1520
1521    /// List pending or imported share links
1522    Shares {
1523        /// Path to the harvest database
1524        #[arg(long)]
1525        path: Option<String>,
1526
1527        /// Filter by status: pending, imported, failed, expired
1528        #[arg(long)]
1529        status: Option<String>,
1530
1531        /// Maximum number of links to show
1532        #[arg(long, default_value = "20")]
1533        limit: usize,
1534    },
1535
1536    /// Create a checkpoint (version snapshot) of a session
1537    Checkpoint {
1538        /// Session ID to checkpoint
1539        session: String,
1540
1541        /// Path to the harvest database
1542        #[arg(long)]
1543        path: Option<String>,
1544
1545        /// Checkpoint description message
1546        #[arg(short, long)]
1547        message: Option<String>,
1548    },
1549
1550    /// List checkpoints for a session
1551    Checkpoints {
1552        /// Session ID to list checkpoints for
1553        session: String,
1554
1555        /// Path to the harvest database
1556        #[arg(long)]
1557        path: Option<String>,
1558    },
1559
1560    /// Revert a session to a previous checkpoint
1561    Revert {
1562        /// Session ID to revert
1563        session: String,
1564
1565        /// Checkpoint number to revert to
1566        checkpoint: i64,
1567
1568        /// Path to the harvest database
1569        #[arg(long)]
1570        path: Option<String>,
1571    },
1572
1573    /// Sync sessions between the harvest database and provider workspaces
1574    Sync {
1575        /// Path to the harvest database
1576        #[arg(long)]
1577        path: Option<String>,
1578
1579        /// Push sessions from database to provider workspaces (restore)
1580        #[arg(long)]
1581        push: bool,
1582
1583        /// Pull sessions from provider workspaces into database (backup)
1584        #[arg(long)]
1585        pull: bool,
1586
1587        /// Filter by provider name
1588        #[arg(long)]
1589        provider: Option<String>,
1590
1591        /// Filter by workspace/project path
1592        #[arg(long)]
1593        workspace: Option<String>,
1594
1595        /// Session IDs to sync (space-separated)
1596        #[arg(long, num_args = 1..)]
1597        sessions: Option<Vec<String>>,
1598
1599        /// Target format for push: auto (detect from provider), jsonl, json
1600        #[arg(long, default_value = "auto")]
1601        format: String,
1602
1603        /// Overwrite existing files without prompting
1604        #[arg(long)]
1605        force: bool,
1606
1607        /// Dry run - show what would be synced without making changes
1608        #[arg(long)]
1609        dry_run: bool,
1610    },
1611
1612    /// Rebuild the full-text search index
1613    Rebuild {
1614        /// Path to the harvest database
1615        #[arg(long)]
1616        path: Option<String>,
1617    },
1618
1619    /// Search messages across all sessions (full-text search)
1620    Search {
1621        /// Search query
1622        query: String,
1623
1624        /// Path to the harvest database
1625        #[arg(long)]
1626        path: Option<String>,
1627
1628        /// Filter by provider
1629        #[arg(long)]
1630        provider: Option<String>,
1631
1632        /// Maximum results to show
1633        #[arg(long, default_value = "20")]
1634        limit: usize,
1635    },
1636
1637    /// Git operations for the harvest database
1638    Git {
1639        #[command(subcommand)]
1640        command: HarvestGitCommands,
1641    },
1642}
1643
1644#[derive(Subcommand)]
1645pub enum HarvestGitCommands {
1646    /// Initialize git tracking for the harvest database
1647    Init {
1648        /// Path to the harvest database
1649        #[arg(long)]
1650        path: Option<String>,
1651    },
1652
1653    /// Commit changes to the harvest database
1654    Commit {
1655        /// Path to the harvest database
1656        #[arg(long)]
1657        path: Option<String>,
1658
1659        /// Commit message
1660        #[arg(short, long)]
1661        message: Option<String>,
1662    },
1663
1664    /// Show git log for the harvest database
1665    Log {
1666        /// Path to the harvest database
1667        #[arg(long)]
1668        path: Option<String>,
1669
1670        /// Number of commits to show
1671        #[arg(short = 'n', long, default_value = "10")]
1672        count: usize,
1673    },
1674
1675    /// Show changes to the harvest database
1676    Diff {
1677        /// Path to the harvest database
1678        #[arg(long)]
1679        path: Option<String>,
1680
1681        /// Compare against specific commit
1682        #[arg(long)]
1683        commit: Option<String>,
1684    },
1685
1686    /// Restore harvest database from a commit
1687    Restore {
1688        /// Commit hash to restore from
1689        commit: String,
1690
1691        /// Path to the harvest database
1692        #[arg(long)]
1693        path: Option<String>,
1694    },
1695}
1696
1697// ============================================================================
1698// Recover Subcommands
1699// ============================================================================
1700
1701#[derive(Subcommand)]
1702pub enum RecoverCommands {
1703    /// Scan for recoverable sessions from various sources
1704    Scan {
1705        /// Provider to scan: vscode, cursor, all (default: all)
1706        #[arg(long, default_value = "all")]
1707        provider: String,
1708
1709        /// Show detailed information about each session
1710        #[arg(short, long)]
1711        verbose: bool,
1712
1713        /// Include sessions older than normal retention period
1714        #[arg(long)]
1715        include_old: bool,
1716    },
1717
1718    /// Recover sessions from the recording API server
1719    Recording {
1720        /// Server URL (default: http://localhost:8787)
1721        #[arg(long, default_value = "http://localhost:8787")]
1722        server: String,
1723
1724        /// Only recover specific session ID
1725        #[arg(long)]
1726        session: Option<String>,
1727
1728        /// Output directory for recovered sessions
1729        #[arg(short, long)]
1730        output: Option<String>,
1731    },
1732
1733    /// Recover sessions from SQLite database backups
1734    Database {
1735        /// Path to the database backup file
1736        backup: String,
1737
1738        /// Extract specific session by ID
1739        #[arg(long)]
1740        session: Option<String>,
1741
1742        /// Output directory for recovered sessions
1743        #[arg(short, long)]
1744        output: Option<String>,
1745
1746        /// Output format: json, jsonl, md (default: json)
1747        #[arg(long, default_value = "json")]
1748        format: String,
1749    },
1750
1751    /// Recover sessions from incomplete/corrupted JSONL files
1752    Jsonl {
1753        /// Path to the JSONL file to repair
1754        file: String,
1755
1756        /// Output file for recovered sessions (default: same name with .recovered suffix)
1757        #[arg(short, long)]
1758        output: Option<String>,
1759
1760        /// Attempt aggressive recovery (may produce incomplete sessions)
1761        #[arg(long)]
1762        aggressive: bool,
1763    },
1764
1765    /// List sessions from VS Code's workspaceStorage that may be orphaned
1766    Orphans {
1767        /// Provider to check: vscode, cursor, all (default: all)
1768        #[arg(long, default_value = "all")]
1769        provider: String,
1770
1771        /// Show sessions not in the SQLite state database
1772        #[arg(long)]
1773        unindexed: bool,
1774
1775        /// Check if files actually exist on disk
1776        #[arg(long)]
1777        verify: bool,
1778    },
1779
1780    /// Repair corrupted session files in place
1781    Repair {
1782        /// Path to the session directory or file
1783        path: String,
1784
1785        /// Create backup before repair
1786        #[arg(long, default_value = "true")]
1787        backup: bool,
1788
1789        /// Dry run - show what would be repaired without making changes
1790        #[arg(long)]
1791        dry_run: bool,
1792    },
1793
1794    /// Show recovery status and recommendations
1795    Status {
1796        /// Provider to check: vscode, cursor, all (default: all)
1797        #[arg(long, default_value = "all")]
1798        provider: String,
1799
1800        /// Check disk space and file system health
1801        #[arg(long)]
1802        system: bool,
1803    },
1804
1805    /// Convert session files between JSON and JSONL formats
1806    Convert {
1807        /// Input file to convert (.json or .jsonl)
1808        input: String,
1809
1810        /// Output file (auto-detects format from extension, or uses --format)
1811        #[arg(short, long)]
1812        output: Option<String>,
1813
1814        /// Output format: json, jsonl (default: opposite of input)
1815        #[arg(long)]
1816        format: Option<String>,
1817
1818        /// VS Code version compatibility: legacy (< 1.109), modern (>= 1.109), both
1819        #[arg(long, default_value = "both")]
1820        compat: String,
1821    },
1822
1823    /// Extract sessions from a VS Code workspace by project path
1824    Extract {
1825        /// Project directory path (will find corresponding workspace hash)
1826        path: String,
1827
1828        /// Output directory for extracted sessions
1829        #[arg(short, long)]
1830        output: Option<String>,
1831
1832        /// Include both JSON and JSONL formats if available
1833        #[arg(long)]
1834        all_formats: bool,
1835
1836        /// Include editing session fragments (agent mode work)
1837        #[arg(long)]
1838        include_edits: bool,
1839    },
1840
1841    /// Detect and display session format and version information
1842    Detect {
1843        /// Session file to analyze (.json or .jsonl)
1844        file: String,
1845
1846        /// Show raw format detection details
1847        #[arg(long)]
1848        verbose: bool,
1849
1850        /// Output detection result as JSON
1851        #[arg(long)]
1852        json: bool,
1853    },
1854
1855    /// Upgrade session files to the current provider format (JSON to JSONL for VS Code 1.109+)
1856    Upgrade {
1857        /// Project paths to upgrade (space-separated)
1858        #[arg(required = true, num_args = 1..)]
1859        project_paths: Vec<String>,
1860
1861        /// Provider to use: vscode, cursor, auto (default: auto-detect)
1862        #[arg(long, default_value = "auto")]
1863        provider: String,
1864
1865        /// Target format: jsonl (VS Code 1.109+), json (legacy). Default: jsonl
1866        #[arg(long, default_value = "jsonl")]
1867        target_format: String,
1868
1869        /// Skip creating backup of original files
1870        #[arg(long)]
1871        no_backup: bool,
1872
1873        /// Dry run - show what would be upgraded without making changes
1874        #[arg(long)]
1875        dry_run: bool,
1876    },
1877}
1878
1879// ============================================================================
1880// API Server Subcommands
1881// ============================================================================
1882
1883#[derive(Subcommand)]
1884pub enum ApiCommands {
1885    /// Start the API server
1886    Serve {
1887        /// Host to bind to (default: 0.0.0.0 for all interfaces)
1888        #[arg(long, default_value = "0.0.0.0")]
1889        host: String,
1890
1891        /// Port to listen on (default: 8787)
1892        #[arg(short, long, default_value = "8787")]
1893        port: u16,
1894
1895        /// Path to the database file
1896        #[arg(long)]
1897        database: Option<String>,
1898    },
1899}
1900
1901// ============================================================================
1902// Agency (Agent Development Kit) Subcommands
1903// ============================================================================
1904
1905#[derive(Subcommand)]
1906pub enum AgencyCommands {
1907    /// List available agents and their roles
1908    List {
1909        /// Show detailed information
1910        #[arg(short, long)]
1911        verbose: bool,
1912    },
1913
1914    /// Show agent information
1915    Info {
1916        /// Agent name or ID
1917        name: String,
1918    },
1919
1920    /// List supported orchestration modes
1921    Modes,
1922
1923    /// Run an agent with a prompt
1924    Run {
1925        /// Agent name to run
1926        #[arg(short, long, default_value = "assistant")]
1927        agent: String,
1928
1929        /// Prompt or task for the agent
1930        prompt: String,
1931
1932        /// Model to use (e.g., gemini-2.0-flash, gpt-4o)
1933        #[arg(short, long)]
1934        model: Option<String>,
1935
1936        /// Orchestration mode (single, sequential, parallel, swarm)
1937        #[arg(long, default_value = "single")]
1938        orchestration: String,
1939
1940        /// Enable verbose output
1941        #[arg(short, long)]
1942        verbose: bool,
1943    },
1944
1945    /// Create a new agent configuration
1946    Create {
1947        /// Agent name
1948        name: String,
1949
1950        /// Agent role (coordinator, researcher, coder, reviewer, executor, writer, tester, custom)
1951        #[arg(short, long, default_value = "custom")]
1952        role: String,
1953
1954        /// System instruction for the agent
1955        #[arg(short, long)]
1956        instruction: Option<String>,
1957
1958        /// Model to use
1959        #[arg(short, long)]
1960        model: Option<String>,
1961    },
1962
1963    /// List available tools
1964    Tools,
1965
1966    /// Show swarm templates
1967    Templates,
1968}
1969
1970// ============================================================================
1971// Telemetry Subcommands
1972// ============================================================================
1973
1974#[derive(Subcommand)]
1975pub enum TelemetryCommands {
1976    /// Show telemetry status and what data is collected
1977    #[command(visible_alias = "status")]
1978    Info,
1979
1980    /// Enable anonymous usage data collection (this is the default)
1981    #[command(visible_alias = "enable")]
1982    OptIn,
1983
1984    /// Disable anonymous usage data collection
1985    #[command(visible_alias = "disable")]
1986    OptOut,
1987
1988    /// Reset telemetry ID (generates new anonymous identifier)
1989    Reset,
1990
1991    /// Record structured data for later AI analysis
1992    #[command(visible_alias = "log")]
1993    Record {
1994        /// Event category (e.g., 'workflow', 'error', 'performance', 'usage')
1995        #[arg(short, long, default_value = "custom")]
1996        category: String,
1997
1998        /// Event name or type
1999        #[arg(short, long)]
2000        event: String,
2001
2002        /// JSON data payload (or use --kv for key=value pairs)
2003        #[arg(short, long)]
2004        data: Option<String>,
2005
2006        /// Key-value pairs (can be repeated: -k foo=bar -k baz=123)
2007        #[arg(short = 'k', long = "kv", value_parser = parse_key_value)]
2008        kv: Vec<(String, String)>,
2009
2010        /// Add tags for filtering (can be repeated: -t important -t session-123)
2011        #[arg(short, long)]
2012        tags: Vec<String>,
2013
2014        /// Optional session or context ID to associate with
2015        #[arg(long)]
2016        context: Option<String>,
2017
2018        /// Print recorded event details
2019        #[arg(short, long)]
2020        verbose: bool,
2021    },
2022
2023    /// Show recorded telemetry data
2024    #[command(visible_alias = "logs")]
2025    Show {
2026        /// Filter by category
2027        #[arg(short, long)]
2028        category: Option<String>,
2029
2030        /// Filter by event name
2031        #[arg(short, long)]
2032        event: Option<String>,
2033
2034        /// Filter by tag
2035        #[arg(short, long)]
2036        tag: Option<String>,
2037
2038        /// Maximum number of records to show
2039        #[arg(short = 'n', long, default_value = "20")]
2040        limit: usize,
2041
2042        /// Output format: table, json, jsonl
2043        #[arg(short, long, default_value = "table")]
2044        format: String,
2045
2046        /// Show records after this date (YYYY-MM-DD)
2047        #[arg(long)]
2048        after: Option<String>,
2049
2050        /// Show records before this date (YYYY-MM-DD)
2051        #[arg(long)]
2052        before: Option<String>,
2053    },
2054
2055    /// Export recorded data for AI analysis
2056    Export {
2057        /// Output file path
2058        output: String,
2059
2060        /// Export format: json, jsonl, csv
2061        #[arg(short, long, default_value = "jsonl")]
2062        format: String,
2063
2064        /// Filter by category
2065        #[arg(short, long)]
2066        category: Option<String>,
2067
2068        /// Include installation metadata in export
2069        #[arg(long)]
2070        with_metadata: bool,
2071    },
2072
2073    /// Clear recorded telemetry data
2074    Clear {
2075        /// Skip confirmation prompt
2076        #[arg(short, long)]
2077        force: bool,
2078
2079        /// Only clear records older than N days
2080        #[arg(long)]
2081        older_than: Option<u32>,
2082    },
2083
2084    /// Configure remote telemetry endpoint
2085    Config {
2086        /// Set the remote endpoint URL
2087        #[arg(long)]
2088        endpoint: Option<String>,
2089
2090        /// Set the API key for authentication
2091        #[arg(long)]
2092        api_key: Option<String>,
2093
2094        /// Enable remote telemetry sending
2095        #[arg(long)]
2096        enable_remote: bool,
2097
2098        /// Disable remote telemetry sending
2099        #[arg(long)]
2100        disable_remote: bool,
2101    },
2102
2103    /// Sync telemetry records to remote server
2104    Sync {
2105        /// Maximum number of records to sync
2106        #[arg(short = 'n', long)]
2107        limit: Option<usize>,
2108
2109        /// Clear local records after successful sync
2110        #[arg(long)]
2111        clear_after: bool,
2112    },
2113
2114    /// Test connection to remote telemetry server
2115    Test,
2116}
2117
2118/// Parse key=value pairs for telemetry record command
2119fn parse_key_value(s: &str) -> std::result::Result<(String, String), String> {
2120    let pos = s
2121        .find('=')
2122        .ok_or_else(|| format!("invalid key=value pair: no '=' found in '{s}'"))?;
2123    Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
2124}
2125
2126// ============================================================================
2127// Shell Completion Enum
2128// ============================================================================
2129
2130/// Supported shells for completion generation
2131#[derive(Clone, Debug, clap::ValueEnum)]
2132pub enum CompletionShell {
2133    /// Bash shell
2134    Bash,
2135    /// Zsh shell
2136    Zsh,
2137    /// Fish shell
2138    Fish,
2139    /// PowerShell
2140    Powershell,
2141    /// Elvish shell
2142    Elvish,
2143}