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    /// Compact the database by stripping session_json blobs (data preserved in messages_v2)
1613    #[command(visible_alias = "gc")]
1614    Compact {
1615        /// Path to the harvest database
1616        #[arg(long)]
1617        path: Option<String>,
1618
1619        /// Show what would be compacted without making changes
1620        #[arg(long)]
1621        dry_run: bool,
1622    },
1623
1624    /// Rebuild the full-text search index
1625    Rebuild {
1626        /// Path to the harvest database
1627        #[arg(long)]
1628        path: Option<String>,
1629    },
1630
1631    /// Search messages across all sessions (full-text search)
1632    Search {
1633        /// Search query
1634        query: String,
1635
1636        /// Path to the harvest database
1637        #[arg(long)]
1638        path: Option<String>,
1639
1640        /// Filter by provider
1641        #[arg(long)]
1642        provider: Option<String>,
1643
1644        /// Maximum results to show
1645        #[arg(long, default_value = "20")]
1646        limit: usize,
1647    },
1648
1649    /// Git operations for the harvest database
1650    Git {
1651        #[command(subcommand)]
1652        command: HarvestGitCommands,
1653    },
1654}
1655
1656#[derive(Subcommand)]
1657pub enum HarvestGitCommands {
1658    /// Initialize git tracking for the harvest database
1659    Init {
1660        /// Path to the harvest database
1661        #[arg(long)]
1662        path: Option<String>,
1663    },
1664
1665    /// Commit changes to the harvest database
1666    Commit {
1667        /// Path to the harvest database
1668        #[arg(long)]
1669        path: Option<String>,
1670
1671        /// Commit message
1672        #[arg(short, long)]
1673        message: Option<String>,
1674    },
1675
1676    /// Show git log for the harvest database
1677    Log {
1678        /// Path to the harvest database
1679        #[arg(long)]
1680        path: Option<String>,
1681
1682        /// Number of commits to show
1683        #[arg(short = 'n', long, default_value = "10")]
1684        count: usize,
1685    },
1686
1687    /// Show changes to the harvest database
1688    Diff {
1689        /// Path to the harvest database
1690        #[arg(long)]
1691        path: Option<String>,
1692
1693        /// Compare against specific commit
1694        #[arg(long)]
1695        commit: Option<String>,
1696    },
1697
1698    /// Restore harvest database from a commit
1699    Restore {
1700        /// Commit hash to restore from
1701        commit: String,
1702
1703        /// Path to the harvest database
1704        #[arg(long)]
1705        path: Option<String>,
1706    },
1707}
1708
1709// ============================================================================
1710// Recover Subcommands
1711// ============================================================================
1712
1713#[derive(Subcommand)]
1714pub enum RecoverCommands {
1715    /// Scan for recoverable sessions from various sources
1716    Scan {
1717        /// Provider to scan: vscode, cursor, all (default: all)
1718        #[arg(long, default_value = "all")]
1719        provider: String,
1720
1721        /// Show detailed information about each session
1722        #[arg(short, long)]
1723        verbose: bool,
1724
1725        /// Include sessions older than normal retention period
1726        #[arg(long)]
1727        include_old: bool,
1728    },
1729
1730    /// Recover sessions from the recording API server
1731    Recording {
1732        /// Server URL (default: http://localhost:8787)
1733        #[arg(long, default_value = "http://localhost:8787")]
1734        server: String,
1735
1736        /// Only recover specific session ID
1737        #[arg(long)]
1738        session: Option<String>,
1739
1740        /// Output directory for recovered sessions
1741        #[arg(short, long)]
1742        output: Option<String>,
1743    },
1744
1745    /// Recover sessions from SQLite database backups
1746    Database {
1747        /// Path to the database backup file
1748        backup: String,
1749
1750        /// Extract specific session by ID
1751        #[arg(long)]
1752        session: Option<String>,
1753
1754        /// Output directory for recovered sessions
1755        #[arg(short, long)]
1756        output: Option<String>,
1757
1758        /// Output format: json, jsonl, md (default: json)
1759        #[arg(long, default_value = "json")]
1760        format: String,
1761    },
1762
1763    /// Recover sessions from incomplete/corrupted JSONL files
1764    Jsonl {
1765        /// Path to the JSONL file to repair
1766        file: String,
1767
1768        /// Output file for recovered sessions (default: same name with .recovered suffix)
1769        #[arg(short, long)]
1770        output: Option<String>,
1771
1772        /// Attempt aggressive recovery (may produce incomplete sessions)
1773        #[arg(long)]
1774        aggressive: bool,
1775    },
1776
1777    /// List sessions from VS Code's workspaceStorage that may be orphaned
1778    Orphans {
1779        /// Provider to check: vscode, cursor, all (default: all)
1780        #[arg(long, default_value = "all")]
1781        provider: String,
1782
1783        /// Show sessions not in the SQLite state database
1784        #[arg(long)]
1785        unindexed: bool,
1786
1787        /// Check if files actually exist on disk
1788        #[arg(long)]
1789        verify: bool,
1790    },
1791
1792    /// Repair corrupted session files in place
1793    Repair {
1794        /// Path to the session directory or file
1795        path: String,
1796
1797        /// Create backup before repair
1798        #[arg(long, default_value = "true")]
1799        backup: bool,
1800
1801        /// Dry run - show what would be repaired without making changes
1802        #[arg(long)]
1803        dry_run: bool,
1804    },
1805
1806    /// Show recovery status and recommendations
1807    Status {
1808        /// Provider to check: vscode, cursor, all (default: all)
1809        #[arg(long, default_value = "all")]
1810        provider: String,
1811
1812        /// Check disk space and file system health
1813        #[arg(long)]
1814        system: bool,
1815    },
1816
1817    /// Convert session files between JSON and JSONL formats
1818    Convert {
1819        /// Input file to convert (.json or .jsonl)
1820        input: String,
1821
1822        /// Output file (auto-detects format from extension, or uses --format)
1823        #[arg(short, long)]
1824        output: Option<String>,
1825
1826        /// Output format: json, jsonl (default: opposite of input)
1827        #[arg(long)]
1828        format: Option<String>,
1829
1830        /// VS Code version compatibility: legacy (< 1.109), modern (>= 1.109), both
1831        #[arg(long, default_value = "both")]
1832        compat: String,
1833    },
1834
1835    /// Extract sessions from a VS Code workspace by project path
1836    Extract {
1837        /// Project directory path (will find corresponding workspace hash)
1838        path: String,
1839
1840        /// Output directory for extracted sessions
1841        #[arg(short, long)]
1842        output: Option<String>,
1843
1844        /// Include both JSON and JSONL formats if available
1845        #[arg(long)]
1846        all_formats: bool,
1847
1848        /// Include editing session fragments (agent mode work)
1849        #[arg(long)]
1850        include_edits: bool,
1851    },
1852
1853    /// Detect and display session format and version information
1854    Detect {
1855        /// Session file to analyze (.json or .jsonl)
1856        file: String,
1857
1858        /// Show raw format detection details
1859        #[arg(long)]
1860        verbose: bool,
1861
1862        /// Output detection result as JSON
1863        #[arg(long)]
1864        json: bool,
1865    },
1866
1867    /// Upgrade session files to the current provider format (JSON to JSONL for VS Code 1.109+)
1868    Upgrade {
1869        /// Project paths to upgrade (space-separated)
1870        #[arg(required = true, num_args = 1..)]
1871        project_paths: Vec<String>,
1872
1873        /// Provider to use: vscode, cursor, auto (default: auto-detect)
1874        #[arg(long, default_value = "auto")]
1875        provider: String,
1876
1877        /// Target format: jsonl (VS Code 1.109+), json (legacy). Default: jsonl
1878        #[arg(long, default_value = "jsonl")]
1879        target_format: String,
1880
1881        /// Skip creating backup of original files
1882        #[arg(long)]
1883        no_backup: bool,
1884
1885        /// Dry run - show what would be upgraded without making changes
1886        #[arg(long)]
1887        dry_run: bool,
1888    },
1889}
1890
1891// ============================================================================
1892// API Server Subcommands
1893// ============================================================================
1894
1895#[derive(Subcommand)]
1896pub enum ApiCommands {
1897    /// Start the API server
1898    Serve {
1899        /// Host to bind to (default: 0.0.0.0 for all interfaces)
1900        #[arg(long, default_value = "0.0.0.0")]
1901        host: String,
1902
1903        /// Port to listen on (default: 8787)
1904        #[arg(short, long, default_value = "8787")]
1905        port: u16,
1906
1907        /// Path to the database file
1908        #[arg(long)]
1909        database: Option<String>,
1910    },
1911}
1912
1913// ============================================================================
1914// Agency (Agent Development Kit) Subcommands
1915// ============================================================================
1916
1917#[derive(Subcommand)]
1918pub enum AgencyCommands {
1919    /// List available agents and their roles
1920    List {
1921        /// Show detailed information
1922        #[arg(short, long)]
1923        verbose: bool,
1924    },
1925
1926    /// Show agent information
1927    Info {
1928        /// Agent name or ID
1929        name: String,
1930    },
1931
1932    /// List supported orchestration modes
1933    Modes,
1934
1935    /// Run an agent with a prompt
1936    Run {
1937        /// Agent name to run
1938        #[arg(short, long, default_value = "assistant")]
1939        agent: String,
1940
1941        /// Prompt or task for the agent
1942        prompt: String,
1943
1944        /// Model to use (e.g., gemini-2.0-flash, gpt-4o)
1945        #[arg(short, long)]
1946        model: Option<String>,
1947
1948        /// Orchestration mode (single, sequential, parallel, swarm)
1949        #[arg(long, default_value = "single")]
1950        orchestration: String,
1951
1952        /// Enable verbose output
1953        #[arg(short, long)]
1954        verbose: bool,
1955    },
1956
1957    /// Create a new agent configuration
1958    Create {
1959        /// Agent name
1960        name: String,
1961
1962        /// Agent role (coordinator, researcher, coder, reviewer, executor, writer, tester, custom)
1963        #[arg(short, long, default_value = "custom")]
1964        role: String,
1965
1966        /// System instruction for the agent
1967        #[arg(short, long)]
1968        instruction: Option<String>,
1969
1970        /// Model to use
1971        #[arg(short, long)]
1972        model: Option<String>,
1973    },
1974
1975    /// List available tools
1976    Tools,
1977
1978    /// Show swarm templates
1979    Templates,
1980}
1981
1982// ============================================================================
1983// Telemetry Subcommands
1984// ============================================================================
1985
1986#[derive(Subcommand)]
1987pub enum TelemetryCommands {
1988    /// Show telemetry status and what data is collected
1989    #[command(visible_alias = "status")]
1990    Info,
1991
1992    /// Enable anonymous usage data collection (this is the default)
1993    #[command(visible_alias = "enable")]
1994    OptIn,
1995
1996    /// Disable anonymous usage data collection
1997    #[command(visible_alias = "disable")]
1998    OptOut,
1999
2000    /// Reset telemetry ID (generates new anonymous identifier)
2001    Reset,
2002
2003    /// Record structured data for later AI analysis
2004    #[command(visible_alias = "log")]
2005    Record {
2006        /// Event category (e.g., 'workflow', 'error', 'performance', 'usage')
2007        #[arg(short, long, default_value = "custom")]
2008        category: String,
2009
2010        /// Event name or type
2011        #[arg(short, long)]
2012        event: String,
2013
2014        /// JSON data payload (or use --kv for key=value pairs)
2015        #[arg(short, long)]
2016        data: Option<String>,
2017
2018        /// Key-value pairs (can be repeated: -k foo=bar -k baz=123)
2019        #[arg(short = 'k', long = "kv", value_parser = parse_key_value)]
2020        kv: Vec<(String, String)>,
2021
2022        /// Add tags for filtering (can be repeated: -t important -t session-123)
2023        #[arg(short, long)]
2024        tags: Vec<String>,
2025
2026        /// Optional session or context ID to associate with
2027        #[arg(long)]
2028        context: Option<String>,
2029
2030        /// Print recorded event details
2031        #[arg(short, long)]
2032        verbose: bool,
2033    },
2034
2035    /// Show recorded telemetry data
2036    #[command(visible_alias = "logs")]
2037    Show {
2038        /// Filter by category
2039        #[arg(short, long)]
2040        category: Option<String>,
2041
2042        /// Filter by event name
2043        #[arg(short, long)]
2044        event: Option<String>,
2045
2046        /// Filter by tag
2047        #[arg(short, long)]
2048        tag: Option<String>,
2049
2050        /// Maximum number of records to show
2051        #[arg(short = 'n', long, default_value = "20")]
2052        limit: usize,
2053
2054        /// Output format: table, json, jsonl
2055        #[arg(short, long, default_value = "table")]
2056        format: String,
2057
2058        /// Show records after this date (YYYY-MM-DD)
2059        #[arg(long)]
2060        after: Option<String>,
2061
2062        /// Show records before this date (YYYY-MM-DD)
2063        #[arg(long)]
2064        before: Option<String>,
2065    },
2066
2067    /// Export recorded data for AI analysis
2068    Export {
2069        /// Output file path
2070        output: String,
2071
2072        /// Export format: json, jsonl, csv
2073        #[arg(short, long, default_value = "jsonl")]
2074        format: String,
2075
2076        /// Filter by category
2077        #[arg(short, long)]
2078        category: Option<String>,
2079
2080        /// Include installation metadata in export
2081        #[arg(long)]
2082        with_metadata: bool,
2083    },
2084
2085    /// Clear recorded telemetry data
2086    Clear {
2087        /// Skip confirmation prompt
2088        #[arg(short, long)]
2089        force: bool,
2090
2091        /// Only clear records older than N days
2092        #[arg(long)]
2093        older_than: Option<u32>,
2094    },
2095
2096    /// Configure remote telemetry endpoint
2097    Config {
2098        /// Set the remote endpoint URL
2099        #[arg(long)]
2100        endpoint: Option<String>,
2101
2102        /// Set the API key for authentication
2103        #[arg(long)]
2104        api_key: Option<String>,
2105
2106        /// Enable remote telemetry sending
2107        #[arg(long)]
2108        enable_remote: bool,
2109
2110        /// Disable remote telemetry sending
2111        #[arg(long)]
2112        disable_remote: bool,
2113    },
2114
2115    /// Sync telemetry records to remote server
2116    Sync {
2117        /// Maximum number of records to sync
2118        #[arg(short = 'n', long)]
2119        limit: Option<usize>,
2120
2121        /// Clear local records after successful sync
2122        #[arg(long)]
2123        clear_after: bool,
2124    },
2125
2126    /// Test connection to remote telemetry server
2127    Test,
2128}
2129
2130/// Parse key=value pairs for telemetry record command
2131fn parse_key_value(s: &str) -> std::result::Result<(String, String), String> {
2132    let pos = s
2133        .find('=')
2134        .ok_or_else(|| format!("invalid key=value pair: no '=' found in '{s}'"))?;
2135    Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
2136}
2137
2138// ============================================================================
2139// Shell Completion Enum
2140// ============================================================================
2141
2142/// Supported shells for completion generation
2143#[derive(Clone, Debug, clap::ValueEnum)]
2144pub enum CompletionShell {
2145    /// Bash shell
2146    Bash,
2147    /// Zsh shell
2148    Zsh,
2149    /// Fish shell
2150    Fish,
2151    /// PowerShell
2152    Powershell,
2153    /// Elvish shell
2154    Elvish,
2155}