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