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