Skip to main content

splice/cli/
commands.rs

1//! CLI command definitions (clap subcommand enums).
2
3use super::*;
4
5/// Available Splice commands.
6#[derive(clap::Subcommand, Debug)]
7pub enum Commands {
8    /// Delete a symbol by removing its definition.
9    #[command(display_order = 200)]
10    Delete {
11        /// Path to the source file containing the symbol.
12        #[arg(short, long)]
13        file: std::path::PathBuf,
14
15        /// Symbol name to delete.
16        #[arg(short, long)]
17        symbol: String,
18
19        /// Optional symbol kind filter.
20        #[arg(short, long)]
21        kind: Option<SymbolKind>,
22
23        /// Optional validation mode (off, os, path).
24        #[arg(long, value_name = "MODE")]
25        analyzer: Option<AnalyzerMode>,
26
27        /// Path to rust-analyzer binary (used with --analyzer path).
28        #[arg(long, value_name = "PATH")]
29        analyzer_binary: Option<std::path::PathBuf>,
30
31        /// Optional language (auto-detect from extension by default).
32        #[arg(long, value_name = "LANG")]
33        language: Option<Language>,
34
35        /// Number of context lines after the match.
36        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
37        context_after: usize,
38
39        /// Number of context lines before the match.
40        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
41        context_before: usize,
42
43        /// Number of context lines before and after the match (default: 3).
44        #[arg(short = 'C', long, value_name = "N", default_value = "3")]
45        context: usize,
46
47        /// Create a backup before deleting.
48        #[arg(long)]
49        create_backup: bool,
50
51        /// Include relationship information in output.
52        #[arg(long)]
53        relationships: bool,
54
55        /// Preview deletion without applying changes.
56        #[arg(short = 'n', long = "dry-run")]
57        dry_run: bool,
58
59        /// Number of context lines in unified diff (default: 3).
60        #[arg(short = 'U', long, value_name = "N", default_value = "3")]
61        unified: usize,
62
63        /// Optional operation ID for auditing (auto-generated UUID if not provided).
64        #[arg(long)]
65        operation_id: Option<String>,
66
67        /// Optional JSON metadata to attach to this operation.
68        #[arg(long)]
69        metadata: Option<String>,
70
71        /// Capture graph snapshot before deleting.
72        #[arg(long)]
73        snapshot_before: bool,
74
75        /// Database path for grounded symbol resolution (default: .magellan/magellan.db).
76        #[arg(short = 'd', long)]
77        db: Option<std::path::PathBuf>,
78    },
79
80    /// Apply a patch to a symbol's span.
81    #[command(display_order = 201)]
82    Patch {
83        /// Path to the source file containing the symbol.
84        #[arg(short = 'f', long, required_unless_present = "batch")]
85        file: Option<std::path::PathBuf>,
86
87        /// Symbol name to patch.
88        #[arg(short = 's', long, required_unless_present = "batch")]
89        symbol: Option<String>,
90
91        /// Optional symbol kind filter.
92        #[arg(short, long, conflicts_with = "batch")]
93        kind: Option<SymbolKind>,
94
95        /// Optional validation mode (off, os, path).
96        #[arg(long, value_name = "MODE")]
97        analyzer: Option<AnalyzerMode>,
98
99        /// Path to rust-analyzer binary (used with --analyzer path).
100        #[arg(long, value_name = "PATH")]
101        analyzer_binary: Option<std::path::PathBuf>,
102
103        /// Path to file containing replacement content.
104        #[arg(
105            short = 'w',
106            long = "with",
107            value_name = "FILE",
108            required_unless_present = "batch"
109        )]
110        with_: Option<std::path::PathBuf>,
111
112        /// Optional language (auto-detect from extension by default).
113        #[arg(long, value_name = "LANG")]
114        language: Option<Language>,
115
116        /// JSON file describing batch replacements.
117        #[arg(long, value_name = "FILE")]
118        batch: Option<std::path::PathBuf>,
119
120        /// Number of context lines after the match.
121        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
122        context_after: usize,
123
124        /// Number of context lines before the match.
125        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
126        context_before: usize,
127
128        /// Number of context lines before and after the match (default: 3).
129        #[arg(short = 'C', long, value_name = "N", default_value = "3")]
130        context_both: usize,
131
132        /// Preview changes without applying (alias: --dry-run, -n).
133        #[arg(
134            short = 'n',
135            long = "dry-run",
136            alias = "preview",
137            conflicts_with = "batch"
138        )]
139        preview: bool,
140
141        /// Number of context lines in unified diff (default: 3).
142        #[arg(short = 'U', long, value_name = "N", default_value = "3")]
143        unified: usize,
144
145        /// Create a backup before patching.
146        #[arg(long)]
147        create_backup: bool,
148
149        /// Include relationship information in output.
150        #[arg(long)]
151        relationships: bool,
152
153        /// Optional operation ID for auditing (auto-generated UUID if not provided).
154        #[arg(long)]
155        operation_id: Option<String>,
156
157        /// Optional JSON metadata to attach to this operation.
158        #[arg(long)]
159        metadata: Option<String>,
160
161        /// Path to codegraph database (required for symbol resolution).
162        #[arg(short = 'd', long, value_name = "FILE")]
163        db: Option<std::path::PathBuf>,
164
165        /// Capture graph snapshot before patching.
166        #[arg(long)]
167        snapshot_before: bool,
168
169        /// Generate DOT graph output for visualization (requires --preview)
170        #[arg(long, requires = "preview")]
171        impact_graph: bool,
172    },
173
174    /// Execute a multi-step refactoring plan.
175    Plan {
176        /// Path to the plan.json file.
177        #[arg(short, long)]
178        file: std::path::PathBuf,
179
180        /// Optional operation ID for auditing (auto-generated UUID if not provided).
181        #[arg(long)]
182        operation_id: Option<String>,
183
184        /// Optional JSON metadata to attach to this operation.
185        #[arg(long)]
186        metadata: Option<String>,
187    },
188
189    /// Undo a previous operation by restoring from a backup manifest.
190    Undo {
191        /// Path to the backup manifest file.
192        #[arg(short, long)]
193        manifest: std::path::PathBuf,
194    },
195
196    /// Apply a pattern replacement to multiple files.
197    ApplyFiles {
198        /// Glob pattern for matching files (e.g., "tests/**/*.rs" or "src/**/*.py").
199        #[arg(short, long)]
200        glob: String,
201
202        /// Text pattern to find.
203        #[arg(short, long)]
204        find: String,
205
206        /// Replacement text.
207        #[arg(short, long)]
208        replace: String,
209
210        /// Optional language (auto-detect from extension by default).
211        #[arg(long, value_name = "LANG")]
212        language: Option<Language>,
213
214        /// Number of context lines after the match.
215        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
216        context_after: usize,
217
218        /// Number of context lines before the match.
219        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
220        context_before: usize,
221
222        /// Number of context lines before and after the match (default: 3).
223        #[arg(short = 'C', long, value_name = "N", default_value = "3")]
224        context_both: usize,
225
226        /// Skip validation gates (default: false).
227        #[arg(long)]
228        no_validate: bool,
229
230        /// Create a backup before applying.
231        #[arg(long)]
232        create_backup: bool,
233
234        /// Optional operation ID for auditing (auto-generated UUID if not provided).
235        #[arg(long)]
236        operation_id: Option<String>,
237
238        /// Optional JSON metadata to attach to this operation.
239        #[arg(long)]
240        metadata: Option<String>,
241
242        /// Preview changes without applying — prints what would change and exits.
243        #[arg(short = 'n', long = "dry-run", visible_alias = "preview")]
244        dry_run: bool,
245    },
246
247    /// Query symbols by labels (uses Magellan integration).
248    #[command(display_order = 104)]
249    Query {
250        /// Path to the Magellan database.
251        #[arg(short, long)]
252        db: std::path::PathBuf,
253
254        /// Labels to query (can be specified multiple times).
255        /// Examples: rust, python, fn, struct, class, method, etc.
256        #[arg(short, long)]
257        label: Vec<String>,
258
259        /// Filter results by file path (optional).
260        /// Can be a glob pattern: "src/main.rs", "src/**/*.rs", etc.
261        #[arg(long)]
262        file: Option<String>,
263
264        /// Number of context lines after the match.
265        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
266        context_after: usize,
267
268        /// Number of context lines before the match.
269        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
270        context_before: usize,
271
272        /// Number of context lines before and after the match (default: 3).
273        #[arg(short = 'C', long, value_name = "N", default_value = "3")]
274        context_both: usize,
275
276        /// List all available labels.
277        #[arg(long)]
278        list: bool,
279
280        /// Count entities with specified label(s).
281        #[arg(long)]
282        count: bool,
283
284        /// Show source code for each result.
285        #[arg(long)]
286        show_code: bool,
287
288        /// Include relationship information in output.
289        #[arg(long)]
290        relationships: bool,
291
292        /// Expand symbol to full body.
293        #[arg(long)]
294        expand: bool,
295
296        /// Expansion level (0=none, 1=body, 2=containing block).
297        #[arg(long = "expand-level", value_name = "N", default_value = "1")]
298        expand_level: usize,
299    },
300
301    /// Get code chunks from the database (uses Magellan integration).
302    #[command(display_order = 105)]
303    Get {
304        /// Path to the Magellan database.
305        #[arg(short, long)]
306        db: std::path::PathBuf,
307
308        /// Path to the source file.
309        #[arg(short, long)]
310        file: std::path::PathBuf,
311
312        /// Start byte offset.
313        #[arg(long)]
314        start: usize,
315
316        /// End byte offset.
317        #[arg(long)]
318        end: usize,
319
320        /// Number of context lines after the match.
321        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
322        context_after: usize,
323
324        /// Number of context lines before the match.
325        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
326        context_before: usize,
327
328        /// Number of context lines before and after the match (default: 3).
329        #[arg(short = 'C', long, value_name = "N", default_value = "3")]
330        context_both: usize,
331
332        /// Include relationship information in output.
333        #[arg(long)]
334        relationships: bool,
335
336        /// Expand symbol to full body.
337        #[arg(long)]
338        expand: bool,
339
340        /// Expansion level (0=none, 1=body, 2=containing block).
341        #[arg(long = "expand-level", value_name = "N", default_value = "1")]
342        expand_level: usize,
343    },
344
345    /// Query execution log.
346    #[command(display_order = 300)]
347    Log {
348        /// Filter by operation type (patch, delete, batch, plan, apply-files, query).
349        #[arg(short, long)]
350        operation_type: Option<String>,
351
352        /// Filter by status (ok, error, partial).
353        #[arg(short, long)]
354        status: Option<String>,
355
356        /// Show operations after this date (ISO 8601 or Unix timestamp).
357        #[arg(long)]
358        after: Option<String>,
359
360        /// Show operations before this date (ISO 8601 or Unix timestamp).
361        #[arg(long)]
362        before: Option<String>,
363
364        /// Maximum number of results.
365        #[arg(short, long, default_value = "20")]
366        limit: usize,
367
368        /// Skip first N results.
369        #[arg(long, default_value = "0")]
370        offset: usize,
371
372        /// Get specific execution by ID.
373        #[arg(short, long)]
374        execution_id: Option<String>,
375
376        /// Output as JSON.
377        #[arg(short, long)]
378        json: bool,
379
380        /// Show statistics only.
381        #[arg(long)]
382        stats: bool,
383    },
384
385    /// Explain an error code with detailed documentation.
386    #[command(display_order = 400)]
387    Explain {
388        /// Error code to explain (e.g., SPL-E001, SPL-E002)
389        #[arg(short, long, value_name = "CODE")]
390        code: String,
391    },
392
393    /// Search for code patterns in files.
394    #[command(display_order = 401)]
395    Search {
396        /// Text pattern to search for.
397        #[arg(short, long)]
398        pattern: String,
399
400        /// Files or directories to search (defaults to current directory).
401        #[arg(long, value_name = "PATH", default_value = ".")]
402        path: std::path::PathBuf,
403
404        /// Optional language filter (auto-detect if not specified).
405        #[arg(long, value_name = "LANG")]
406        language: Option<Language>,
407
408        /// Glob pattern for file filtering (e.g., "src/**/*.rs", "tests/**/*.py").
409        /// If not specified, searches all supported file types in path.
410        #[arg(short = 'g', long, value_name = "GLOB")]
411        glob: Option<String>,
412
413        /// Number of context lines after the match.
414        #[arg(short = 'A', long, value_name = "N", default_value = "0")]
415        context_after: usize,
416
417        /// Number of context lines before the match.
418        #[arg(short = 'B', long, value_name = "N", default_value = "0")]
419        context_before: usize,
420
421        /// Number of context lines before and after the match (default: 2).
422        #[arg(short = 'C', long, value_name = "N", default_value = "2")]
423        context_both: usize,
424
425        /// Apply replacement to all matches (atomic with rollback on failure).
426        #[arg(long, requires = "replace")]
427        apply: bool,
428
429        /// Replacement text (required with --apply).
430        #[arg(short = 'r', long, value_name = "TEXT")]
431        replace: Option<String>,
432
433        /// Output results as JSON.
434        #[arg(long)]
435        json: bool,
436    },
437
438    /// Show database statistics (files, symbols, refs, calls, chunks)
439    ///
440    /// Use --detect-backend to check which backend format the database uses.
441    #[command(display_order = 100)]
442    Status {
443        /// Path to the Magellan database
444        #[arg(short, long)]
445        db: std::path::PathBuf,
446
447        /// Detect and report the backend format (sqlite only)
448        #[arg(long, default_value = "false")]
449        detect_backend: bool,
450    },
451
452    /// Find symbols by name, ID, or natural-language semantic query
453    #[command(display_order = 101)]
454    Find {
455        /// Path to the Magellan database
456        #[arg(short, long)]
457        db: std::path::PathBuf,
458
459        /// Symbol name to search
460        #[arg(short, long, conflicts_with = "symbol_id")]
461        name: Option<String>,
462
463        /// 16-character hex symbol ID
464        #[arg(long, conflicts_with = "name")]
465        symbol_id: Option<String>,
466
467        /// Natural-language query resolved via semantic search (HNSW embeddings)
468        #[arg(long)]
469        semantic_query: Option<String>,
470
471        /// Return all matches (default: first match only)
472        #[arg(short, long)]
473        ambiguous: bool,
474
475        /// Output format (human, json, pretty)
476        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
477        output: OutputFormat,
478    },
479
480    /// Show call relationships for a symbol
481    #[command(display_order = 102)]
482    Refs {
483        /// Path to the Magellan database
484        #[arg(short, long)]
485        db: std::path::PathBuf,
486
487        /// Symbol name
488        #[arg(short, long)]
489        name: String,
490
491        /// File path containing the symbol
492        #[arg(short, long)]
493        path: std::path::PathBuf,
494
495        /// Direction: in (callers), out (callees), both (default)
496        #[arg(long, value_enum, default_value_t = CallDirection::Both)]
497        direction: CallDirection,
498
499        /// Output format (human, json, pretty)
500        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
501        output: OutputFormat,
502
503        /// Generate DOT graph output for visualization
504        #[arg(long)]
505        impact_graph: bool,
506    },
507
508    /// List all indexed files
509    #[command(display_order = 103)]
510    Files {
511        /// Path to the Magellan database
512        #[arg(short, long)]
513        db: std::path::PathBuf,
514
515        /// Include symbol count per file
516        #[arg(long)]
517        symbols: bool,
518
519        /// Output format (human, json, pretty)
520        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
521        output: OutputFormat,
522    },
523
524    /// Export graph data in JSON, JSONL, or CSV format
525    #[command(display_order = 106)]
526    Export {
527        /// Path to the Magellan database
528        #[arg(short, long)]
529        db: std::path::PathBuf,
530
531        /// Export format (json, jsonl, csv)
532        #[arg(short, long, value_enum, default_value_t = ExportFormat::Json)]
533        format: ExportFormat,
534
535        /// Output file path (writes to stdout if not specified)
536        #[arg(long)]
537        file: Option<std::path::PathBuf>,
538    },
539
540    /// Migrate Magellan database to latest schema version
541    #[command(display_order = 107)]
542    MigrateDb {
543        /// Path to the Magellan database
544        #[arg(short, long = "db", default_value = ".magellan/magellan.db")]
545        db_path: std::path::PathBuf,
546
547        /// Create backup before migrating
548        #[arg(long, default_value = "true")]
549        backup: bool,
550
551        /// Check migration status without migrating
552        #[arg(long)]
553        dry_run: bool,
554    },
555
556    /// Rename a symbol across all files using byte-accurate references
557    #[command(display_order = 110)]
558    Rename {
559        /// Symbol ID (magellan entity ID, 32-char BLAKE3, or 16-char SHA-256)
560        #[arg(short, long, conflicts_with = "name")]
561        symbol: Option<String>,
562
563        /// Symbol name (requires --file)
564        #[arg(long, conflicts_with = "symbol")]
565        name: Option<String>,
566
567        /// File path for symbol name resolution (required with --name)
568        #[arg(short, long)]
569        file: Option<std::path::PathBuf>,
570
571        /// Optional symbol kind filter (e.g., fn, function, struct). Use when multiple symbols share the same name in one file.
572        #[arg(short, long)]
573        kind: Option<SymbolKind>,
574
575        /// New name for the symbol
576        #[arg(short, long)]
577        to: String,
578
579        /// Path to Magellan database (default: .magellan/magellan.db)
580        #[arg(short, long, default_value = ".magellan/magellan.db")]
581        db: std::path::PathBuf,
582
583        /// Preview changes without applying
584        #[arg(short = 'n', long = "dry-run")]
585        preview: bool,
586
587        /// Generate proof file (requires --dry-run)
588        #[arg(long)]
589        proof: bool,
590
591        /// Override backup directory (default: .splice/backups/)
592        #[arg(long)]
593        backup_dir: Option<std::path::PathBuf>,
594
595        /// Skip backup creation
596        #[arg(long)]
597        no_backup: bool,
598        /// Create backup before rename (default: true for safety, use --no-backup to skip)
599        #[arg(long, default_value = "true")]
600        create_backup: bool,
601
602        /// Capture graph snapshot before renaming.
603        #[arg(long)]
604        snapshot_before: bool,
605
606        /// Generate DOT graph output for visualization (requires --preview)
607        #[arg(long, requires = "preview")]
608        impact_graph: bool,
609    },
610
611    /// Show reachability analysis for a symbol (caller/callee chains)
612    #[command(display_order = 111)]
613    Reachable {
614        /// Symbol name to analyze
615        #[arg(short, long, default_value = "")]
616        symbol: String,
617
618        /// Natural-language query resolved via semantic search (HNSW embeddings)
619        #[arg(long)]
620        semantic_query: Option<String>,
621
622        /// File path containing the symbol
623        #[arg(short, long)]
624        path: std::path::PathBuf,
625
626        /// Path to Magellan database (default: .magellan/magellan.db)
627        #[arg(short, long, default_value = ".magellan/magellan.db")]
628        db: std::path::PathBuf,
629
630        /// Analysis direction: forward (callees), reverse (callers), both
631        #[arg(long, value_enum, default_value_t = ReachabilityDirection::Forward)]
632        direction: ReachabilityDirection,
633
634        /// Maximum depth to traverse (default: 10)
635        #[arg(long, default_value = "10")]
636        max_depth: usize,
637
638        /// Output format (human, json, pretty)
639        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
640        output: OutputFormat,
641
642        /// Generate DOT graph output for visualization
643        #[arg(long)]
644        impact_graph: bool,
645    },
646
647    /// Detect dead code (unreachable symbols) from entry points
648    #[command(display_order = 112)]
649    DeadCode {
650        /// Entry point symbol name (e.g., "main", "MyApp::run")
651        #[arg(short, long, default_value = "")]
652        entry: String,
653
654        /// Natural-language query resolved via semantic search (HNSW embeddings)
655        #[arg(long)]
656        semantic_query: Option<String>,
657
658        /// File path containing the entry point symbol
659        #[arg(short, long)]
660        path: std::path::PathBuf,
661
662        /// Path to Magellan database (default: .magellan/magellan.db)
663        #[arg(short, long, default_value = ".magellan/magellan.db")]
664        db: std::path::PathBuf,
665
666        /// Exclude public symbols from dead code list
667        #[arg(long)]
668        exclude_public: bool,
669
670        /// Group results by file (default: true for human output)
671        #[arg(long, default_value = "true")]
672        group_by_file: bool,
673
674        /// Output format (human, json, pretty)
675        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
676        output: OutputFormat,
677    },
678
679    /// Detect cycles in the call graph
680    #[command(display_order = 113)]
681    Cycles {
682        /// Path to Magellan database (default: .magellan/magellan.db)
683        #[arg(short, long, default_value = ".magellan/magellan.db")]
684        db: std::path::PathBuf,
685
686        /// Optional: find cycles containing this specific symbol
687        #[arg(short, long)]
688        symbol: Option<String>,
689
690        /// Optional: file path for symbol resolution (required with --symbol)
691        #[arg(short, long)]
692        path: Option<std::path::PathBuf>,
693
694        /// Maximum number of cycles to return (default: 100)
695        #[arg(short, long, default_value = "100")]
696        max_cycles: usize,
697
698        /// Show cycle members (default: true)
699        #[arg(long, default_value = "true")]
700        show_members: bool,
701
702        /// Output format (human, json, pretty)
703        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
704        output: OutputFormat,
705    },
706
707    /// Analyze condensation graph (SCCs collapsed to DAG)
708    #[command(display_order = 114)]
709    Condense {
710        /// Path to Magellan database (default: .magellan/magellan.db)
711        #[arg(short, long, default_value = ".magellan/magellan.db")]
712        db: std::path::PathBuf,
713
714        /// Show SCC members (default: true for human output)
715        #[arg(long, default_value = "true")]
716        show_members: bool,
717
718        /// Show topological levels
719        #[arg(long)]
720        show_levels: bool,
721
722        /// Output format (human, json, pretty)
723        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
724        output: OutputFormat,
725    },
726
727    /// Perform program slicing (forward/backward impact analysis)
728    #[command(display_order = 115)]
729    Slice {
730        /// Target symbol to slice from
731        #[arg(short, long, default_value = "")]
732        target: String,
733
734        /// Natural-language query resolved via semantic search (HNSW embeddings)
735        #[arg(long)]
736        semantic_query: Option<String>,
737
738        /// File path containing the target symbol
739        #[arg(short, long)]
740        path: std::path::PathBuf,
741
742        /// Path to Magellan database (default: .magellan/magellan.db)
743        #[arg(short, long, default_value = ".magellan/magellan.db")]
744        db: std::path::PathBuf,
745
746        /// Slice direction: forward (what this affects) or backward (what affects this)
747        #[arg(long, value_enum, default_value_t = SliceDirection::Forward)]
748        direction: SliceDirection,
749
750        /// Maximum depth to traverse (default: unlimited)
751        #[arg(long)]
752        max_depth: Option<usize>,
753
754        /// Output format (human, json, pretty)
755        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
756        output: OutputFormat,
757    },
758
759    /// Validate proof checksums for refactoring audit trail
760    #[command(display_order = 116)]
761    ValidateProof {
762        /// Path to the proof JSON file
763        #[arg(short, long)]
764        proof: std::path::PathBuf,
765
766        /// Output format (human, json, pretty)
767        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
768        output: OutputFormat,
769    },
770
771    /// Compare two snapshots and report differences
772    #[command(display_order = 117)]
773    Verify {
774        /// Path to the "before" snapshot file
775        #[arg(short = 'b', long)]
776        before: std::path::PathBuf,
777
778        /// Path to the "after" snapshot file
779        #[arg(short = 'a', long)]
780        after: std::path::PathBuf,
781
782        /// Show detailed symbol-by-symbol differences
783        #[arg(long)]
784        detailed: bool,
785
786        /// Output format (human, json, pretty)
787        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
788        output: OutputFormat,
789    },
790
791    /// Execute batch operations from YAML spec
792    #[command(display_order = 250)]
793    Batch {
794        /// Path to the batch specification YAML file
795        #[arg(short = 'f', long)]
796        spec: std::path::PathBuf,
797
798        /// Database path for snapshot/impact analysis (required for rollback)
799        #[arg(short = 'd', long)]
800        db: Option<std::path::PathBuf>,
801
802        /// Preview changes without applying (alias: --dry-run, -n)
803        #[arg(short = 'n', long = "dry-run")]
804        dry_run: bool,
805
806        /// Continue on error instead of stopping
807        #[arg(long = "continue-on-error")]
808        continue_on_error: bool,
809
810        /// Rollback mode: auto, never, always
811        #[arg(long, value_enum, default_value_t = CliRollbackMode::Auto)]
812        rollback: CliRollbackMode,
813
814        /// Optional validation mode (off, os, path).
815        #[arg(long, value_name = "MODE")]
816        analyzer: Option<AnalyzerMode>,
817
818        /// Path to rust-analyzer binary (used with --analyzer path).
819        #[arg(long, value_name = "PATH")]
820        analyzer_binary: Option<std::path::PathBuf>,
821    },
822
823    /// Create a new file with validation
824    #[command(display_order = 105)]
825    Create {
826        /// Path to the file to create
827        #[arg(short, long)]
828        file: std::path::PathBuf,
829
830        /// Initial file content (overrides stdin)
831        #[arg(short, long)]
832        content: Option<String>,
833
834        /// Read initial content from a file (overrides stdin and --content)
835        #[arg(long)]
836        with: Option<std::path::PathBuf>,
837
838        /// Validate only (don't write file)
839        #[arg(short = 'V', long)]
840        validate_only: bool,
841
842        /// Add module declaration to parent module
843        #[arg(short = 'm', long)]
844        with_mod: bool,
845
846        /// Workspace directory (default: current directory)
847        #[arg(short, long, default_value = ".")]
848        workspace: std::path::PathBuf,
849    },
850
851    /// Get grounded code completions using Magellan database
852    #[command(display_order = 119)]
853    Complete {
854        /// Path to the source file
855        #[arg(short, long)]
856        file: std::path::PathBuf,
857
858        /// Line number (1-based)
859        #[arg(short, long)]
860        line: usize,
861
862        /// Column number (1-based)
863        #[arg(short, long)]
864        column: usize,
865
866        /// Maximum number of suggestions
867        #[arg(short, long, default_value = "10")]
868        max_results: usize,
869
870        /// Path to Magellan database
871        #[arg(short, long, default_value = ".magellan/splice.db")]
872        db: std::path::PathBuf,
873    },
874
875    /// Manage code graph snapshots
876    #[command(display_order = 120, subcommand)]
877    Snapshots(SnapshotsCommands),
878
879    /// Edit code with text-replace and tree-sitter validation
880    #[command(display_order = 202)]
881    Edit {
882        /// Path to the source file
883        #[arg(short, long)]
884        file: std::path::PathBuf,
885
886        /// Old text to replace
887        #[arg(long)]
888        replace_old: String,
889
890        /// New text to replace with
891        #[arg(long)]
892        replace_new: String,
893
894        /// Optional language (auto-detect from extension by default)
895        #[arg(long, value_name = "LANG")]
896        language: Option<Language>,
897
898        /// Preview changes without applying
899        #[arg(short = 'n', long = "dry-run", visible_alias = "preview")]
900        preview: bool,
901
902        /// Create a backup before editing
903        #[arg(long)]
904        create_backup: bool,
905
906        /// Optional operation ID for auditing (auto-generated UUID if not provided)
907        #[arg(long)]
908        operation_id: Option<String>,
909
910        /// Optional JSON metadata to attach to this operation
911        #[arg(long)]
912        metadata: Option<String>,
913
914        /// Database path (optional, auto-discovered if not provided)
915        #[arg(long)]
916        db: Option<std::path::PathBuf>,
917
918        /// Number of context lines in unified diff (default: 3)
919        #[arg(short = 'U', long, value_name = "N", default_value = "3")]
920        unified: usize,
921    },
922
923    /// Generate grounded code scaffold from intent description
924    #[command(display_order = 203)]
925    Suggest {
926        /// Function name for scaffold
927        #[arg(short, long)]
928        fn_name: String,
929
930        /// Intent description
931        #[arg(short, long)]
932        desc: String,
933
934        /// Database path (optional, auto-discovered if not provided)
935        #[arg(long)]
936        db: Option<std::path::PathBuf>,
937
938        /// Output format (human, json, pretty)
939        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
940        output: OutputFormat,
941    },
942}
943
944/// Snapshot management subcommands.
945#[derive(clap::Subcommand, Debug, Clone)]
946pub enum SnapshotsCommands {
947    /// List all snapshots
948    List {
949        /// Filter by operation type (patch, delete, rename)
950        #[arg(short, long)]
951        operation: Option<String>,
952
953        /// Maximum number of snapshots to show
954        #[arg(short = 'n', long)]
955        limit: Option<usize>,
956
957        /// Show total disk usage
958        #[arg(long)]
959        disk_usage: bool,
960
961        /// Output format (human, json, pretty)
962        #[arg(short, long, value_enum, default_value_t = OutputFormat::Human)]
963        output: OutputFormat,
964    },
965
966    /// Delete a specific snapshot
967    Delete {
968        /// Snapshot ID (timestamp or filename)
969        #[arg(short, long)]
970        id: String,
971
972        /// Skip confirmation prompt
973        #[arg(long)]
974        force: bool,
975    },
976
977    /// Clean up old snapshots (keep N most recent)
978    Cleanup {
979        /// Number of recent snapshots to keep (default: 10)
980        #[arg(short = 'k', long, default_value = "10")]
981        keep: usize,
982
983        /// Show what would be deleted without deleting
984        #[arg(long)]
985        dry_run: bool,
986
987        /// Confirm deletion of more than 50 snapshots. Without this flag,
988        /// a bulk-delete refuses to run and asks for either `--yes` or `--dry-run`.
989        #[arg(long)]
990        yes: bool,
991    },
992}