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