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