chasm_cli/cli.rs
1// Copyright (c) 2024-2026 Nervosys LLC
2// SPDX-License-Identifier: Apache-2.0
3//! CLI argument definitions using clap derive macros
4
5use clap::{Parser, Subcommand};
6
7/// Chat System Manager (csm) - Manage and merge chat sessions across workspaces
8#[derive(Parser)]
9#[command(name = "csm")]
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 (TUI)
115 // ============================================================================
116 /// Run interactive tools
117 Run {
118 #[command(subcommand)]
119 command: RunCommands,
120 },
121
122 // ============================================================================
123 // Provider Commands
124 // ============================================================================
125 /// Manage LLM providers (Ollama, vLLM, Foundry, Cursor, etc.)
126 Provider {
127 #[command(subcommand)]
128 command: ProviderCommands,
129 },
130
131 // ============================================================================
132 // Detect Commands
133 // ============================================================================
134 /// Auto-detect workspace and provider information
135 Detect {
136 #[command(subcommand)]
137 command: Option<DetectCommands>,
138 },
139
140 // ============================================================================
141 // Register Commands
142 // ============================================================================
143 /// Add on-disk sessions to VS Code's database index (makes orphaned sessions visible)
144 #[command(visible_alias = "sync")]
145 Register {
146 #[command(subcommand)]
147 command: RegisterCommands,
148 },
149
150 // ============================================================================
151 // Harvest Commands
152 // ============================================================================
153 /// Harvest chat sessions from all providers into a unified database
154 Harvest {
155 #[command(subcommand)]
156 command: HarvestCommands,
157 },
158
159 // ============================================================================
160 // API Server Commands
161 // ============================================================================
162 /// Start the HTTP API server for the web frontend
163 #[command(visible_alias = "serve")]
164 Api {
165 #[command(subcommand)]
166 command: ApiCommands,
167 },
168
169 // ============================================================================
170 // Agency Commands
171 // ============================================================================
172 /// Agent Development Kit - manage agents and orchestration
173 Agency {
174 #[command(subcommand)]
175 command: AgencyCommands,
176 },
177
178 // ============================================================================
179 // Telemetry Commands
180 // ============================================================================
181 /// Manage anonymous usage data collection (opt-in by default)
182 Telemetry {
183 #[command(subcommand)]
184 command: Option<TelemetryCommands>,
185 },
186
187 // ============================================================================
188 // Easter Egg
189 // ============================================================================
190 /// Show banner
191 #[command(hide = true)]
192 Banner,
193}
194
195// ============================================================================
196// List Subcommands
197// ============================================================================
198
199#[derive(Subcommand)]
200pub enum ListCommands {
201 /// List all VS Code workspaces
202 #[command(visible_alias = "ws")]
203 Workspaces,
204
205 /// List all chat sessions
206 #[command(visible_alias = "s")]
207 Sessions {
208 /// Filter by project path
209 #[arg(long)]
210 project_path: Option<String>,
211
212 /// Show file sizes
213 #[arg(long, short = 's')]
214 size: bool,
215
216 /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
217 #[arg(long, short = 'p')]
218 provider: Option<String>,
219
220 /// Include all providers
221 #[arg(long)]
222 all_providers: bool,
223 },
224
225 /// List agent mode sessions (Copilot Edits / chatEditingSessions)
226 #[command(visible_alias = "a")]
227 Agents {
228 /// Filter by project path
229 #[arg(long)]
230 project_path: Option<String>,
231
232 /// Show file sizes
233 #[arg(long, short = 's')]
234 size: bool,
235
236 /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
237 #[arg(long, short = 'p')]
238 provider: Option<String>,
239 },
240
241 /// List sessions for a specific project path
242 Path {
243 /// Project path (default: current directory)
244 project_path: Option<String>,
245 },
246
247 /// List unregistered sessions (exist on disk but invisible to VS Code)
248 Orphaned {
249 /// Project path (default: current directory)
250 #[arg(long)]
251 path: Option<String>,
252 },
253}
254
255// ============================================================================
256// Find Subcommands
257// ============================================================================
258
259#[derive(Subcommand)]
260pub enum FindCommands {
261 /// Search workspaces by name pattern (defaults to current directory name)
262 #[command(visible_alias = "ws")]
263 Workspace {
264 /// Text pattern to match (case-insensitive, defaults to current directory name)
265 pattern: Option<String>,
266 },
267
268 /// Search sessions by title, content, or ID pattern
269 #[command(visible_alias = "s")]
270 Session {
271 /// Text pattern to match (case-insensitive, defaults to current directory name)
272 pattern: Option<String>,
273
274 /// Filter by project path or workspace name
275 #[arg(long, short = 'w')]
276 workspace: Option<String>,
277
278 /// Only search in session titles (faster, skip content search)
279 #[arg(long, short = 't')]
280 title_only: bool,
281
282 /// Include message content in search (slower)
283 #[arg(long, short = 'c')]
284 content: bool,
285
286 /// Filter sessions modified after this date (YYYY-MM-DD)
287 #[arg(long)]
288 after: Option<String>,
289
290 /// Filter sessions modified before this date (YYYY-MM-DD)
291 #[arg(long)]
292 before: Option<String>,
293
294 /// Filter by internal message timestamp date (YYYY-MM-DD)
295 #[arg(long)]
296 date: Option<String>,
297
298 /// Search across all workspaces (not just current project)
299 #[arg(long, short = 'a')]
300 all: bool,
301
302 /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
303 #[arg(long, short = 'p')]
304 provider: Option<String>,
305
306 /// Search across all providers
307 #[arg(long)]
308 all_providers: bool,
309
310 /// Limit number of results
311 #[arg(long, short = 'n', default_value = "50")]
312 limit: usize,
313 },
314
315 /// Search sessions within a specific project path
316 Path {
317 /// Search pattern (case-insensitive, defaults to current directory name)
318 pattern: Option<String>,
319
320 /// Project path (default: current directory)
321 #[arg(long)]
322 project_path: Option<String>,
323 },
324}
325
326// ============================================================================
327// Show Subcommands
328// ============================================================================
329
330#[derive(Subcommand)]
331pub enum ShowCommands {
332 /// Show workspace details
333 #[command(visible_alias = "ws")]
334 Workspace {
335 /// Workspace name or hash
336 workspace: String,
337 },
338
339 /// Show session details
340 #[command(visible_alias = "s")]
341 Session {
342 /// Session ID or filename
343 session_id: String,
344
345 /// Project path to search in
346 #[arg(long)]
347 project_path: Option<String>,
348 },
349
350 /// Show agent mode session details (Copilot Edits)
351 #[command(visible_alias = "a")]
352 Agent {
353 /// Agent session ID
354 session_id: String,
355
356 /// Project path to search in
357 #[arg(long)]
358 project_path: Option<String>,
359 },
360
361 /// Show chat history timeline for a project path
362 Path {
363 /// Path to the project (default: current directory)
364 project_path: Option<String>,
365 },
366
367 /// Show timeline of session activity with gaps visualization
368 Timeline {
369 /// Path to the project (default: current directory)
370 project_path: Option<String>,
371
372 /// Include agent mode sessions
373 #[arg(long, short = 'a')]
374 agents: bool,
375
376 /// Filter by provider (vscode, cursor, claudecode, opencode, openclaw, antigravity)
377 #[arg(long, short = 'p')]
378 provider: Option<String>,
379
380 /// Include all providers (aggregate timeline)
381 #[arg(long)]
382 all_providers: bool,
383 },
384}
385
386// ============================================================================
387// Fetch Subcommands
388// ============================================================================
389
390#[derive(Subcommand)]
391pub enum FetchCommands {
392 /// Fetch sessions from workspaces matching a pattern
393 #[command(visible_alias = "ws")]
394 Workspace {
395 /// Workspace name pattern (case-insensitive)
396 workspace_name: String,
397
398 /// Target project path (default: current directory)
399 #[arg(long)]
400 target_path: Option<String>,
401
402 /// Overwrite existing sessions
403 #[arg(long)]
404 force: bool,
405
406 /// Don't register sessions in VS Code index
407 #[arg(long)]
408 no_register: bool,
409 },
410
411 /// Fetch specific sessions by ID
412 #[command(visible_alias = "s")]
413 Session {
414 /// Session IDs to fetch (space-separated)
415 #[arg(required = true, num_args = 1..)]
416 session_ids: Vec<String>,
417
418 /// Target project path (default: current directory)
419 #[arg(long)]
420 target_path: Option<String>,
421
422 /// Overwrite existing sessions
423 #[arg(long)]
424 force: bool,
425
426 /// Don't register sessions in VS Code index
427 #[arg(long)]
428 no_register: bool,
429 },
430
431 /// Fetch chat sessions from other workspaces by project path
432 Path {
433 /// Path to the project (default: current directory)
434 project_path: Option<String>,
435
436 /// Overwrite existing sessions and skip VS Code running check
437 #[arg(long)]
438 force: bool,
439
440 /// Don't register sessions in VS Code index
441 #[arg(long)]
442 no_register: bool,
443 },
444}
445
446// ============================================================================
447// Merge Subcommands
448// ============================================================================
449
450#[derive(Subcommand)]
451pub enum MergeCommands {
452 /// Merge sessions from workspaces matching a name pattern
453 #[command(visible_alias = "ws")]
454 Workspace {
455 /// Workspace name pattern to search for (case-insensitive)
456 workspace_name: String,
457
458 /// Title for the merged session
459 #[arg(short, long)]
460 title: Option<String>,
461
462 /// Target project path to save the merged session (default: current directory)
463 #[arg(long)]
464 target_path: Option<String>,
465
466 /// Skip VS Code running check
467 #[arg(long)]
468 force: bool,
469
470 /// Don't create backup of current sessions
471 #[arg(long)]
472 no_backup: bool,
473 },
474
475 /// Merge sessions from multiple workspace name patterns
476 #[command(visible_alias = "wss")]
477 Workspaces {
478 /// Workspace name patterns to search for (space-separated, case-insensitive)
479 #[arg(required = true, num_args = 1..)]
480 workspace_names: Vec<String>,
481
482 /// Title for the merged session
483 #[arg(short, long)]
484 title: Option<String>,
485
486 /// Target project path to save the merged session (default: current directory)
487 #[arg(long)]
488 target_path: Option<String>,
489
490 /// Skip VS Code running check
491 #[arg(long)]
492 force: bool,
493
494 /// Don't create backup of current sessions
495 #[arg(long)]
496 no_backup: bool,
497 },
498
499 /// Merge specific sessions by their IDs or filenames
500 #[command(visible_alias = "s")]
501 Sessions {
502 /// Session IDs or filenames (comma-separated or space-separated)
503 #[arg(required = true, num_args = 1..)]
504 sessions: Vec<String>,
505
506 /// Title for the merged session
507 #[arg(short, long)]
508 title: Option<String>,
509
510 /// Target project path to save the merged session (default: current directory)
511 #[arg(long)]
512 target_path: Option<String>,
513
514 /// Skip VS Code running check
515 #[arg(long)]
516 force: bool,
517
518 /// Don't create backup of current sessions
519 #[arg(long)]
520 no_backup: bool,
521 },
522
523 /// Merge all sessions for a project path into one unified chat
524 Path {
525 /// Path to the project (default: current directory)
526 project_path: Option<String>,
527
528 /// Title for the merged session
529 #[arg(short, long)]
530 title: Option<String>,
531
532 /// Skip VS Code running check
533 #[arg(long)]
534 force: bool,
535
536 /// Don't create backup of current sessions
537 #[arg(long)]
538 no_backup: bool,
539 },
540
541 /// Merge sessions from an LLM provider (Ollama, Cursor, etc.)
542 Provider {
543 /// Provider name (copilot, cursor, ollama, vllm, foundry, etc.)
544 provider_name: String,
545
546 /// Title for the merged session
547 #[arg(short, long)]
548 title: Option<String>,
549
550 /// Target project path to save the merged session (default: current directory)
551 #[arg(long)]
552 target_path: Option<String>,
553
554 /// Session IDs from the provider to include (omit for all)
555 #[arg(long)]
556 sessions: Option<Vec<String>>,
557
558 /// Skip VS Code running check
559 #[arg(long)]
560 force: bool,
561
562 /// Don't create backup of current sessions
563 #[arg(long)]
564 no_backup: bool,
565 },
566
567 /// Merge sessions from multiple providers
568 #[command(name = "providers")]
569 Providers {
570 /// Provider names (space-separated: copilot cursor ollama)
571 #[arg(required = true, num_args = 1..)]
572 providers: Vec<String>,
573
574 /// Title for the merged session
575 #[arg(short, long)]
576 title: Option<String>,
577
578 /// Target project path to save the merged session (default: current directory)
579 #[arg(long)]
580 target_path: Option<String>,
581
582 /// Filter by workspace name pattern (applies to providers that support workspaces)
583 #[arg(long)]
584 workspace: Option<String>,
585
586 /// Skip VS Code running check
587 #[arg(long)]
588 force: bool,
589
590 /// Don't create backup of current sessions
591 #[arg(long)]
592 no_backup: bool,
593 },
594
595 /// Merge all sessions across all available providers
596 All {
597 /// Title for the merged session
598 #[arg(short, long)]
599 title: Option<String>,
600
601 /// Target project path to save the merged session (default: current directory)
602 #[arg(long)]
603 target_path: Option<String>,
604
605 /// Filter by workspace name pattern (applies to providers that support workspaces)
606 #[arg(long)]
607 workspace: Option<String>,
608
609 /// Skip VS Code running check
610 #[arg(long)]
611 force: bool,
612
613 /// Don't create backup of current sessions
614 #[arg(long)]
615 no_backup: bool,
616 },
617}
618
619// ============================================================================
620// Export Subcommands
621// ============================================================================
622
623#[derive(Subcommand)]
624pub enum ExportCommands {
625 /// Export sessions from a workspace by hash
626 #[command(visible_alias = "ws")]
627 Workspace {
628 /// Destination directory for exported sessions
629 destination: String,
630
631 /// Source workspace hash
632 hash: String,
633 },
634
635 /// Export specific sessions by ID
636 #[command(visible_alias = "s")]
637 Sessions {
638 /// Destination directory for exported sessions
639 destination: String,
640
641 /// Session IDs to export (space-separated)
642 #[arg(required = true, num_args = 1..)]
643 session_ids: Vec<String>,
644
645 /// Source project path
646 #[arg(long)]
647 project_path: Option<String>,
648 },
649
650 /// Export chat sessions from a project path
651 Path {
652 /// Destination directory for exported sessions
653 destination: String,
654
655 /// Source project path (default: current directory)
656 project_path: Option<String>,
657 },
658}
659
660// ============================================================================
661// Import Subcommands
662// ============================================================================
663
664#[derive(Subcommand)]
665pub enum ImportCommands {
666 /// Copy session files from external directory into a workspace
667 #[command(visible_alias = "ws")]
668 Workspace {
669 /// Source directory containing session JSON files to import
670 source: String,
671
672 /// Target workspace hash
673 hash: String,
674
675 /// Overwrite existing sessions
676 #[arg(long)]
677 force: bool,
678 },
679
680 /// Copy specific session files into a workspace
681 #[command(visible_alias = "s")]
682 Sessions {
683 /// Session files to import (space-separated paths)
684 #[arg(required = true, num_args = 1..)]
685 session_files: Vec<String>,
686
687 /// Target project path (default: current directory)
688 #[arg(long)]
689 target_path: Option<String>,
690
691 /// Overwrite existing sessions
692 #[arg(long)]
693 force: bool,
694 },
695
696 /// Copy session files from external directory into a project workspace
697 Path {
698 /// Source directory containing session JSON files to import
699 source: String,
700
701 /// Target project path (default: current directory)
702 target_path: Option<String>,
703
704 /// Overwrite existing sessions
705 #[arg(long)]
706 force: bool,
707 },
708}
709
710// ============================================================================
711// Move Subcommands
712// ============================================================================
713
714#[derive(Subcommand)]
715pub enum MoveCommands {
716 /// Move all sessions from one workspace to another
717 #[command(visible_alias = "ws")]
718 Workspace {
719 /// Source workspace hash
720 source_hash: String,
721
722 /// Target workspace hash or project path
723 target: String,
724 },
725
726 /// Move specific sessions by ID
727 #[command(visible_alias = "s")]
728 Sessions {
729 /// Session IDs to move (space-separated)
730 #[arg(required = true, num_args = 1..)]
731 session_ids: Vec<String>,
732
733 /// Target project path
734 target_path: String,
735 },
736
737 /// Move sessions from a source path to target path
738 Path {
739 /// Source project path
740 source_path: String,
741
742 /// Target project path
743 target_path: String,
744 },
745}
746
747// ============================================================================
748// Git Subcommands
749// ============================================================================
750
751#[derive(Subcommand)]
752pub enum GitCommands {
753 /// Configure git settings for chat sessions
754 Config {
755 /// Git user name
756 #[arg(long)]
757 name: Option<String>,
758
759 /// Git user email
760 #[arg(long)]
761 email: Option<String>,
762
763 /// Project path
764 #[arg(long)]
765 path: Option<String>,
766 },
767
768 /// Initialize git versioning for chat sessions
769 Init {
770 /// Project path
771 path: String,
772 },
773
774 /// Add chat sessions to git (stage and optionally commit)
775 Add {
776 /// Project path
777 path: String,
778
779 /// Also commit the changes
780 #[arg(long)]
781 commit: bool,
782
783 /// Commit message (requires --commit)
784 #[arg(short, long)]
785 message: Option<String>,
786 },
787
788 /// Show git status of chat sessions
789 Status {
790 /// Project path
791 path: String,
792 },
793
794 /// Create a git tag snapshot of chat sessions
795 Snapshot {
796 /// Project path
797 path: String,
798
799 /// Tag name (auto-generated if not provided)
800 #[arg(long)]
801 tag: Option<String>,
802
803 /// Snapshot message
804 #[arg(short, long)]
805 message: Option<String>,
806 },
807
808 /// Track chat sessions together with associated file changes
809 Track {
810 /// Project path
811 path: String,
812
813 /// Commit message describing the changes
814 #[arg(short, long)]
815 message: Option<String>,
816
817 /// Include all staged and unstaged file changes
818 #[arg(long)]
819 all: bool,
820
821 /// Include specific files in addition to chat sessions
822 #[arg(long)]
823 files: Option<Vec<String>>,
824
825 /// Create a tag for this tracked state
826 #[arg(long)]
827 tag: Option<String>,
828 },
829
830 /// Show history of chat session commits with associated file changes
831 Log {
832 /// Project path
833 path: String,
834
835 /// Number of commits to show
836 #[arg(short = 'n', long, default_value = "10")]
837 count: usize,
838
839 /// Show only commits that include chat session changes
840 #[arg(long)]
841 sessions_only: bool,
842 },
843
844 /// Diff chat sessions between commits or current state
845 Diff {
846 /// Project path
847 path: String,
848
849 /// First commit (default: HEAD)
850 #[arg(long)]
851 from: Option<String>,
852
853 /// Second commit (default: working directory)
854 #[arg(long)]
855 to: Option<String>,
856
857 /// Show associated file changes alongside chat diffs
858 #[arg(long)]
859 with_files: bool,
860 },
861
862 /// Restore chat sessions from a specific commit
863 Restore {
864 /// Project path
865 path: String,
866
867 /// Commit hash, tag, or reference to restore from
868 commit: String,
869
870 /// Also restore associated files from the same commit
871 #[arg(long)]
872 with_files: bool,
873
874 /// Create a backup before restoring
875 #[arg(long)]
876 backup: bool,
877 },
878}
879
880// ============================================================================
881// Migration Subcommands
882// ============================================================================
883
884#[derive(Subcommand)]
885pub enum MigrationCommands {
886 /// Create a migration package for moving to a new machine
887 Create {
888 /// Output directory for migration package
889 output: String,
890
891 /// Comma-separated list of project paths to include
892 #[arg(long)]
893 projects: Option<String>,
894
895 /// Include all workspaces with chat sessions
896 #[arg(long)]
897 all: bool,
898 },
899
900 /// Restore a migration package on a new machine
901 Restore {
902 /// Path to migration package directory
903 package: String,
904
905 /// Project path mapping: 'old1:new1;old2:new2'
906 #[arg(long)]
907 mapping: Option<String>,
908
909 /// Show what would be done without doing it
910 #[arg(long)]
911 dry_run: bool,
912 },
913}
914
915// ============================================================================
916// Run Subcommands
917// ============================================================================
918
919#[derive(Subcommand)]
920pub enum RunCommands {
921 /// Launch interactive TUI (Text User Interface)
922 Tui,
923}
924
925// ============================================================================
926// Provider Subcommands
927// ============================================================================
928
929#[derive(Subcommand)]
930pub enum ProviderCommands {
931 /// List all discovered LLM providers
932 List,
933
934 /// Show detailed info about a specific provider
935 Info {
936 /// Provider name (copilot, cursor, ollama, vllm, foundry, lm-studio, etc.)
937 provider: String,
938 },
939
940 /// Configure a provider
941 Config {
942 /// Provider name
943 provider: String,
944
945 /// API endpoint URL
946 #[arg(long)]
947 endpoint: Option<String>,
948
949 /// API key
950 #[arg(long)]
951 api_key: Option<String>,
952
953 /// Default model
954 #[arg(long)]
955 model: Option<String>,
956
957 /// Enable or disable the provider
958 #[arg(long)]
959 enabled: Option<bool>,
960 },
961
962 /// Import sessions from another provider
963 Import {
964 /// Source provider name
965 #[arg(long)]
966 from: String,
967
968 /// Target project path (or current directory)
969 #[arg(long)]
970 path: Option<String>,
971
972 /// Session ID to import (omit for all)
973 #[arg(long)]
974 session: Option<String>,
975 },
976
977 /// Test connection to a provider
978 Test {
979 /// Provider name
980 provider: String,
981 },
982}
983
984// ============================================================================
985// Detect Subcommands
986// ============================================================================
987
988#[derive(Subcommand)]
989pub enum DetectCommands {
990 /// Detect workspace for a path
991 Workspace {
992 /// Project path (default: current directory)
993 path: Option<String>,
994 },
995
996 /// Detect available providers
997 Providers {
998 /// Only show providers with sessions
999 #[arg(long)]
1000 with_sessions: bool,
1001 },
1002
1003 /// Detect which provider a session belongs to
1004 Session {
1005 /// Session ID or filename
1006 session_id: String,
1007
1008 /// Project path to search in
1009 #[arg(long)]
1010 path: Option<String>,
1011 },
1012
1013 /// Detect everything (workspace, providers, sessions) for a path
1014 All {
1015 /// Project path (default: current directory)
1016 path: Option<String>,
1017
1018 /// Show detailed information
1019 #[arg(long)]
1020 verbose: bool,
1021 },
1022
1023 /// Find all workspace hashes for a project path (including orphaned workspaces with sessions)
1024 Orphaned {
1025 /// Project path (default: current directory)
1026 path: Option<String>,
1027
1028 /// Automatically recover orphaned sessions by copying to active workspace
1029 #[arg(long, short)]
1030 recover: bool,
1031 },
1032}
1033
1034// ============================================================================
1035// Register Subcommands
1036// ============================================================================
1037
1038#[derive(Subcommand)]
1039pub enum RegisterCommands {
1040 /// Register all on-disk sessions into VS Code's index (fixes orphaned sessions)
1041 All {
1042 /// Project path (default: current directory)
1043 #[arg(long)]
1044 path: Option<String>,
1045
1046 /// Merge all sessions into one before registering
1047 #[arg(long, short)]
1048 merge: bool,
1049
1050 /// Force registration even if VS Code is running
1051 #[arg(long, short)]
1052 force: bool,
1053 },
1054
1055 /// Register specific sessions by ID or title into VS Code's index
1056 #[command(visible_alias = "s")]
1057 Session {
1058 /// Session IDs or filenames (without .json extension)
1059 #[arg(required_unless_present = "title")]
1060 ids: Vec<String>,
1061
1062 /// Match sessions by title instead of ID
1063 #[arg(long, short, num_args = 1.., value_delimiter = ' ')]
1064 title: Option<Vec<String>>,
1065
1066 /// Project path (default: current directory)
1067 #[arg(long)]
1068 path: Option<String>,
1069
1070 /// Force registration even if VS Code is running
1071 #[arg(long, short)]
1072 force: bool,
1073 },
1074
1075 /// Recursively walk directories to find and register orphaned sessions for all workspaces
1076 #[command(visible_alias = "r")]
1077 Recursive {
1078 /// Root path to start recursive search (default: current directory)
1079 path: Option<String>,
1080
1081 /// Maximum directory depth to recurse (default: unlimited)
1082 #[arg(long, short)]
1083 depth: Option<usize>,
1084
1085 /// Force registration even if VS Code is running
1086 #[arg(long, short)]
1087 force: bool,
1088
1089 /// Only show what would be registered without making changes
1090 #[arg(long)]
1091 dry_run: bool,
1092
1093 /// Skip directories matching these patterns (can be used multiple times)
1094 #[arg(long, short = 'x')]
1095 exclude: Vec<String>,
1096 },
1097}
1098
1099// ============================================================================
1100// Harvest Subcommands
1101// ============================================================================
1102
1103#[derive(Subcommand)]
1104pub enum HarvestCommands {
1105 /// Initialize a harvest database
1106 Init {
1107 /// Path to the database file (default: ./chat_sessions.db)
1108 #[arg(long)]
1109 path: Option<String>,
1110
1111 /// Initialize git tracking for the database
1112 #[arg(long)]
1113 git: bool,
1114 },
1115
1116 /// Scan for available providers and sessions
1117 Scan {
1118 /// Show individual sessions
1119 #[arg(long)]
1120 sessions: bool,
1121
1122 /// Scan for web-based LLM providers (ChatGPT, Claude, etc.)
1123 #[arg(long)]
1124 web: bool,
1125
1126 /// Timeout in seconds for web provider checks (default: 5)
1127 #[arg(long, default_value = "5")]
1128 timeout: u64,
1129
1130 /// Show verbose debug output for browser scanning
1131 #[arg(long, short)]
1132 verbose: bool,
1133 },
1134
1135 /// Run the harvest to collect sessions from all providers
1136 Run {
1137 /// Path to the harvest database
1138 #[arg(long)]
1139 path: Option<String>,
1140
1141 /// Only include specific providers (comma-separated: copilot,cursor,ollama)
1142 #[arg(long, value_delimiter = ',')]
1143 providers: Option<Vec<String>>,
1144
1145 /// Exclude specific providers (comma-separated)
1146 #[arg(long, value_delimiter = ',')]
1147 exclude: Option<Vec<String>>,
1148
1149 /// Only harvest sessions changed since last run
1150 #[arg(long)]
1151 incremental: bool,
1152
1153 /// Auto-commit changes to git after harvest
1154 #[arg(long)]
1155 commit: bool,
1156
1157 /// Commit message (requires --commit)
1158 #[arg(short, long)]
1159 message: Option<String>,
1160 },
1161
1162 /// Show harvest database status
1163 Status {
1164 /// Path to the harvest database
1165 #[arg(long)]
1166 path: Option<String>,
1167 },
1168
1169 /// List sessions in the harvest database
1170 List {
1171 /// Path to the harvest database
1172 #[arg(long)]
1173 path: Option<String>,
1174
1175 /// Filter by provider name
1176 #[arg(long)]
1177 provider: Option<String>,
1178
1179 /// Maximum number of sessions to show
1180 #[arg(long, default_value = "20")]
1181 limit: usize,
1182
1183 /// Search sessions by title or ID
1184 #[arg(long)]
1185 search: Option<String>,
1186 },
1187
1188 /// Export sessions from the harvest database
1189 Export {
1190 /// Output file path
1191 output: String,
1192
1193 /// Path to the harvest database
1194 #[arg(long)]
1195 path: Option<String>,
1196
1197 /// Export format: json, jsonl, md (markdown)
1198 #[arg(long, default_value = "json")]
1199 format: String,
1200
1201 /// Filter by provider name
1202 #[arg(long)]
1203 provider: Option<String>,
1204
1205 /// Export specific sessions by ID (comma-separated)
1206 #[arg(long, value_delimiter = ',')]
1207 sessions: Option<Vec<String>>,
1208 },
1209
1210 /// Import a shared chat session from a URL
1211 Share {
1212 /// Share link URL (ChatGPT, Claude, etc.)
1213 url: String,
1214
1215 /// Path to the harvest database
1216 #[arg(long)]
1217 path: Option<String>,
1218
1219 /// Custom name for the imported session
1220 #[arg(long)]
1221 name: Option<String>,
1222
1223 /// Associate with a workspace path
1224 #[arg(long)]
1225 workspace: Option<String>,
1226 },
1227
1228 /// List pending or imported share links
1229 Shares {
1230 /// Path to the harvest database
1231 #[arg(long)]
1232 path: Option<String>,
1233
1234 /// Filter by status: pending, imported, failed, expired
1235 #[arg(long)]
1236 status: Option<String>,
1237
1238 /// Maximum number of links to show
1239 #[arg(long, default_value = "20")]
1240 limit: usize,
1241 },
1242
1243 /// Create a checkpoint (version snapshot) of a session
1244 Checkpoint {
1245 /// Session ID to checkpoint
1246 session: String,
1247
1248 /// Path to the harvest database
1249 #[arg(long)]
1250 path: Option<String>,
1251
1252 /// Checkpoint description message
1253 #[arg(short, long)]
1254 message: Option<String>,
1255 },
1256
1257 /// List checkpoints for a session
1258 Checkpoints {
1259 /// Session ID to list checkpoints for
1260 session: String,
1261
1262 /// Path to the harvest database
1263 #[arg(long)]
1264 path: Option<String>,
1265 },
1266
1267 /// Restore a session to a previous checkpoint
1268 Restore {
1269 /// Session ID to restore
1270 session: String,
1271
1272 /// Checkpoint number to restore to
1273 checkpoint: i64,
1274
1275 /// Path to the harvest database
1276 #[arg(long)]
1277 path: Option<String>,
1278 },
1279
1280 /// Rebuild the full-text search index
1281 Rebuild {
1282 /// Path to the harvest database
1283 #[arg(long)]
1284 path: Option<String>,
1285 },
1286
1287 /// Search messages across all sessions (full-text search)
1288 Search {
1289 /// Search query
1290 query: String,
1291
1292 /// Path to the harvest database
1293 #[arg(long)]
1294 path: Option<String>,
1295
1296 /// Filter by provider
1297 #[arg(long)]
1298 provider: Option<String>,
1299
1300 /// Maximum results to show
1301 #[arg(long, default_value = "20")]
1302 limit: usize,
1303 },
1304
1305 /// Git operations for the harvest database
1306 Git {
1307 #[command(subcommand)]
1308 command: HarvestGitCommands,
1309 },
1310}
1311
1312#[derive(Subcommand)]
1313pub enum HarvestGitCommands {
1314 /// Initialize git tracking for the harvest database
1315 Init {
1316 /// Path to the harvest database
1317 #[arg(long)]
1318 path: Option<String>,
1319 },
1320
1321 /// Commit changes to the harvest database
1322 Commit {
1323 /// Path to the harvest database
1324 #[arg(long)]
1325 path: Option<String>,
1326
1327 /// Commit message
1328 #[arg(short, long)]
1329 message: Option<String>,
1330 },
1331
1332 /// Show git log for the harvest database
1333 Log {
1334 /// Path to the harvest database
1335 #[arg(long)]
1336 path: Option<String>,
1337
1338 /// Number of commits to show
1339 #[arg(short = 'n', long, default_value = "10")]
1340 count: usize,
1341 },
1342
1343 /// Show changes to the harvest database
1344 Diff {
1345 /// Path to the harvest database
1346 #[arg(long)]
1347 path: Option<String>,
1348
1349 /// Compare against specific commit
1350 #[arg(long)]
1351 commit: Option<String>,
1352 },
1353
1354 /// Restore harvest database from a commit
1355 Restore {
1356 /// Commit hash to restore from
1357 commit: String,
1358
1359 /// Path to the harvest database
1360 #[arg(long)]
1361 path: Option<String>,
1362 },
1363}
1364
1365// ============================================================================
1366// API Server Subcommands
1367// ============================================================================
1368
1369#[derive(Subcommand)]
1370pub enum ApiCommands {
1371 /// Start the API server
1372 Serve {
1373 /// Host to bind to (default: 0.0.0.0 for all interfaces)
1374 #[arg(long, default_value = "0.0.0.0")]
1375 host: String,
1376
1377 /// Port to listen on (default: 8787)
1378 #[arg(short, long, default_value = "8787")]
1379 port: u16,
1380
1381 /// Path to the database file
1382 #[arg(long)]
1383 database: Option<String>,
1384 },
1385}
1386
1387// ============================================================================
1388// Agency (Agent Development Kit) Subcommands
1389// ============================================================================
1390
1391#[derive(Subcommand)]
1392pub enum AgencyCommands {
1393 /// List available agents and their roles
1394 List {
1395 /// Show detailed information
1396 #[arg(short, long)]
1397 verbose: bool,
1398 },
1399
1400 /// Show agent information
1401 Info {
1402 /// Agent name or ID
1403 name: String,
1404 },
1405
1406 /// List supported orchestration modes
1407 Modes,
1408
1409 /// Run an agent with a prompt
1410 Run {
1411 /// Agent name to run
1412 #[arg(short, long, default_value = "assistant")]
1413 agent: String,
1414
1415 /// Prompt or task for the agent
1416 prompt: String,
1417
1418 /// Model to use (e.g., gemini-2.0-flash, gpt-4o)
1419 #[arg(short, long)]
1420 model: Option<String>,
1421
1422 /// Orchestration mode (single, sequential, parallel, swarm)
1423 #[arg(long, default_value = "single")]
1424 orchestration: String,
1425
1426 /// Enable verbose output
1427 #[arg(short, long)]
1428 verbose: bool,
1429 },
1430
1431 /// Create a new agent configuration
1432 Create {
1433 /// Agent name
1434 name: String,
1435
1436 /// Agent role (coordinator, researcher, coder, reviewer, executor, writer, tester, custom)
1437 #[arg(short, long, default_value = "custom")]
1438 role: String,
1439
1440 /// System instruction for the agent
1441 #[arg(short, long)]
1442 instruction: Option<String>,
1443
1444 /// Model to use
1445 #[arg(short, long)]
1446 model: Option<String>,
1447 },
1448
1449 /// List available tools
1450 Tools,
1451
1452 /// Show swarm templates
1453 Templates,
1454}
1455
1456// ============================================================================
1457// Telemetry Subcommands
1458// ============================================================================
1459
1460#[derive(Subcommand)]
1461pub enum TelemetryCommands {
1462 /// Show telemetry status and what data is collected
1463 #[command(visible_alias = "status")]
1464 Info,
1465
1466 /// Enable anonymous usage data collection (this is the default)
1467 #[command(visible_alias = "enable")]
1468 OptIn,
1469
1470 /// Disable anonymous usage data collection
1471 #[command(visible_alias = "disable")]
1472 OptOut,
1473
1474 /// Reset telemetry ID (generates new anonymous identifier)
1475 Reset,
1476
1477 /// Record structured data for later AI analysis
1478 #[command(visible_alias = "log")]
1479 Record {
1480 /// Event category (e.g., 'workflow', 'error', 'performance', 'usage')
1481 #[arg(short, long, default_value = "custom")]
1482 category: String,
1483
1484 /// Event name or type
1485 #[arg(short, long)]
1486 event: String,
1487
1488 /// JSON data payload (or use --kv for key=value pairs)
1489 #[arg(short, long)]
1490 data: Option<String>,
1491
1492 /// Key-value pairs (can be repeated: -k foo=bar -k baz=123)
1493 #[arg(short = 'k', long = "kv", value_parser = parse_key_value)]
1494 kv: Vec<(String, String)>,
1495
1496 /// Add tags for filtering (can be repeated: -t important -t session-123)
1497 #[arg(short, long)]
1498 tags: Vec<String>,
1499
1500 /// Optional session or context ID to associate with
1501 #[arg(long)]
1502 context: Option<String>,
1503
1504 /// Print recorded event details
1505 #[arg(short, long)]
1506 verbose: bool,
1507 },
1508
1509 /// Show recorded telemetry data
1510 #[command(visible_alias = "logs")]
1511 Show {
1512 /// Filter by category
1513 #[arg(short, long)]
1514 category: Option<String>,
1515
1516 /// Filter by event name
1517 #[arg(short, long)]
1518 event: Option<String>,
1519
1520 /// Filter by tag
1521 #[arg(short, long)]
1522 tag: Option<String>,
1523
1524 /// Maximum number of records to show
1525 #[arg(short = 'n', long, default_value = "20")]
1526 limit: usize,
1527
1528 /// Output format: table, json, jsonl
1529 #[arg(short, long, default_value = "table")]
1530 format: String,
1531
1532 /// Show records after this date (YYYY-MM-DD)
1533 #[arg(long)]
1534 after: Option<String>,
1535
1536 /// Show records before this date (YYYY-MM-DD)
1537 #[arg(long)]
1538 before: Option<String>,
1539 },
1540
1541 /// Export recorded data for AI analysis
1542 Export {
1543 /// Output file path
1544 output: String,
1545
1546 /// Export format: json, jsonl, csv
1547 #[arg(short, long, default_value = "jsonl")]
1548 format: String,
1549
1550 /// Filter by category
1551 #[arg(short, long)]
1552 category: Option<String>,
1553
1554 /// Include installation metadata in export
1555 #[arg(long)]
1556 with_metadata: bool,
1557 },
1558
1559 /// Clear recorded telemetry data
1560 Clear {
1561 /// Skip confirmation prompt
1562 #[arg(short, long)]
1563 force: bool,
1564
1565 /// Only clear records older than N days
1566 #[arg(long)]
1567 older_than: Option<u32>,
1568 },
1569
1570 /// Configure remote telemetry endpoint
1571 Config {
1572 /// Set the remote endpoint URL
1573 #[arg(long)]
1574 endpoint: Option<String>,
1575
1576 /// Set the API key for authentication
1577 #[arg(long)]
1578 api_key: Option<String>,
1579
1580 /// Enable remote telemetry sending
1581 #[arg(long)]
1582 enable_remote: bool,
1583
1584 /// Disable remote telemetry sending
1585 #[arg(long)]
1586 disable_remote: bool,
1587 },
1588
1589 /// Sync telemetry records to remote server
1590 Sync {
1591 /// Maximum number of records to sync
1592 #[arg(short = 'n', long)]
1593 limit: Option<usize>,
1594
1595 /// Clear local records after successful sync
1596 #[arg(long)]
1597 clear_after: bool,
1598 },
1599
1600 /// Test connection to remote telemetry server
1601 Test,
1602}
1603
1604/// Parse key=value pairs for telemetry record command
1605fn parse_key_value(s: &str) -> std::result::Result<(String, String), String> {
1606 let pos = s
1607 .find('=')
1608 .ok_or_else(|| format!("invalid key=value pair: no '=' found in '{s}'"))?;
1609 Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
1610}