Skip to main content

morph_cli/
cli.rs

1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4#[derive(Debug, Parser)]
5#[command(
6    name = "morph",
7    version,
8    about = "Plugin-based code transformation CLI for migrating codebases",
9    long_about = None,
10    after_help = "✨ GETTING STARTED WITH morph-cli ✨\n\n\
11                  1. Scan your project to identify files & technologies:\n\
12                     $ morph scan\n\n\
13                  2. Plan recommendations & estimate maturity/confidence:\n\
14                     $ morph plan\n\n\
15                  3. Run the interactive guided assistant wizard:\n\
16                     $ morph magic\n\n\
17                  🚀 BEGINNER-SAFE RECOMMENDATIONS:\n\n\
18                  • Migrate legacy CommonJS require calls to modern ESM imports:\n\
19                    $ morph run commonjs-to-esm . --dry-run --review\n\n\
20                  • Safely upgrade JavaScript files to TypeScript with complete confidence:\n\
21                    $ morph run js-to-ts . --dry-run --review\n\n\
22                  • Validate repository setup and environment health:\n\
23                    $ morph doctor .\n\n\
24                  👉 Need help? Visit our docs or run a preset workflow: `morph preset list`"
25)]
26pub struct Cli {
27    #[command(subcommand)]
28    pub command: Command,
29}
30
31#[derive(Debug, Subcommand)]
32pub enum Command {
33    /// Print the current morph-cli version
34    Version,
35    /// List available migration recipes
36    List {
37        #[arg(default_value = ".")]
38        path: PathBuf,
39        /// Filter recipes by category (e.g. migration, cleanup, modernization, analysis, experimental)
40        #[arg(long)]
41        category: Option<String>,
42        /// Filter recipes by tag (e.g. safe, fast, risky, typescript, react, backend, frontend)
43        #[arg(long)]
44        tag: Option<String>,
45    },
46    /// Search for recipes matching a query
47    Search {
48        /// Search query (matches name, description, category, tags)
49        query: String,
50        #[arg(default_value = ".")]
51        path: PathBuf,
52        /// Filter by category (e.g. migration, cleanup, modernization, analysis, experimental)
53        #[arg(long)]
54        category: Option<String>,
55        /// Filter by maturity (e.g. stable, beta, experimental)
56        #[arg(long)]
57        maturity: Option<String>,
58    },
59    /// Show migration history summaries
60    History {
61        /// Limit the number of sessions to display
62        #[arg(short = 'n', long, default_value_t = 10)]
63        limit: usize,
64    },
65    /// Initialize a new morph-cli.toml configuration file
66    Init {
67        #[arg(default_value = ".")]
68        path: PathBuf,
69    },
70    /// Plan recommended migration recipes for a project
71    #[command(visible_alias = "p")]
72    Plan {
73        #[arg(default_value = ".")]
74        path: PathBuf,
75        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
76        #[arg(long)]
77        tag: Option<String>,
78    },
79    /// Explain migration detection for a file
80    Explain { file: PathBuf },
81    /// Run a recipe against a target path
82    Run {
83        #[arg(required = true, num_args = 2.., value_name = "RECIPE... PATH")]
84        args: Vec<String>,
85        #[arg(long)]
86        write: bool,
87        #[arg(long)]
88        dry_run: bool,
89        #[arg(long)]
90        review: bool,
91        #[arg(long)]
92        autofix: bool,
93        #[arg(long)]
94        verbose: bool,
95        #[arg(long)]
96        summary_only: bool,
97        #[arg(long)]
98        max_preview_lines: Option<usize>,
99        #[arg(long)]
100        allow_risky: bool,
101        #[arg(long)]
102        strict: bool,
103        /// Generate JSON report
104        #[arg(long)]
105        report_json: bool,
106        /// Generate Markdown report
107        #[arg(long)]
108        report_md: bool,
109        /// Output directory for reports
110        #[arg(long, default_value = ".morph-cli/reports")]
111        report_dir: PathBuf,
112        /// Enable formatting preservation
113        #[arg(long)]
114        format: bool,
115        /// Use Prettier for formatting
116        #[arg(long)]
117        prettier: bool,
118        /// Disable formatting
119        #[arg(long)]
120        no_format: bool,
121        /// Number of parallel jobs (default: CPU count)
122        #[arg(long)]
123        jobs: Option<usize>,
124        /// Run sequentially (disable parallelism)
125        #[arg(long)]
126        sequential: bool,
127        /// Limit execution to a workspace package by package name
128        #[arg(long)]
129        package: Option<String>,
130        /// Profile name to load config overrides from
131        #[arg(long)]
132        profile: Option<String>,
133        /// Output style (minimal, default, detailed)
134        #[arg(long)]
135        output_style: Option<String>,
136        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
137        #[arg(long)]
138        tag: Option<String>,
139    },
140    /// List migration run sessions
141    Sessions,
142    /// Show a migration run session
143    Session { id: String },
144    /// Rollback files from a previous transformation session
145    Rollback {
146        session_id: String,
147        #[arg(long)]
148        preview: bool,
149        #[arg(long)]
150        force: bool,
151    },
152    /// Replay a previous transformation session with stored options
153    Replay {
154        session_id: String,
155        /// Apply changes (write to disk), overrides stored mode if true
156        #[arg(long)]
157        write: bool,
158    },
159    /// Resume migration from a saved checkpoint
160    Resume {
161        /// Checkpoint ID to resume from
162        #[arg(long)]
163        checkpoint: String,
164    },
165    /// List scan snapshots
166    Scans,
167    /// Generate shell completion scripts
168    Completions {
169        /// The shell to generate completions for
170        #[arg(value_enum)]
171        shell: clap_complete::Shell,
172    },
173    /// Scan project and detect technologies
174    #[command(visible_alias = "s")]
175    Scan {
176        #[command(subcommand)]
177        action: Option<ScanAction>,
178
179        #[arg(default_value = ".")]
180        path: PathBuf,
181        /// Filter by file tag (e.g. commonjs, esm, react, typescript, risky, generated, ignored)
182        #[arg(long)]
183        tag: Option<String>,
184        /// Show verbose skip output
185        #[arg(short = 'v', long)]
186        verbose: bool,
187    },
188    /// Analyze lightweight dependencies
189    Deps {
190        #[arg(default_value = ".")]
191        path: PathBuf,
192    },
193    /// Calculate modernization score and readiness
194    Score {
195        #[arg(default_value = ".")]
196        path: PathBuf,
197        /// Output format (text or json)
198        #[arg(long, default_value = "text")]
199        format: String,
200    },
201    /// Simulate migration impact without transforming files
202    #[command(visible_alias = "sim")]
203    Simulate {
204        /// Recipes to simulate; repeat to select multiple recipes
205        #[arg(short = 'r', long = "recipe", required = true)]
206        recipes: Vec<String>,
207
208        #[arg(default_value = ".")]
209        path: PathBuf,
210    },
211    /// Start the local dashboard backend
212    Dashboard {
213        /// Port to listen on (default: 8080)
214        #[arg(long, default_value_t = 8080)]
215        port: u16,
216    },
217    /// Start a guided migration workflow
218    Magic {
219        #[arg(default_value = ".")]
220        path: PathBuf,
221    },
222    /// Run a full validation suite on a repository (scan, detect, dry-run, verify)
223    #[command(visible_alias = "validate")]
224    ValidateRepo {
225        #[arg(default_value = ".")]
226        path: PathBuf,
227    },
228    /// Benchmark Morph execution performance on the target path
229    #[command(visible_alias = "bench")]
230    Benchmark {
231        #[arg(default_value = ".")]
232        path: PathBuf,
233    },
234    /// Generate visualization graphs (Mermaid or JSON)
235    Graph {
236        /// Type of graph to generate (pipeline, workspace, deps)
237        #[arg(long, default_value = "pipeline")]
238        graph_type: String,
239
240        /// Output format (mermaid or json)
241        #[arg(long, default_value = "mermaid")]
242        format: String,
243
244        #[arg(default_value = ".")]
245        path: PathBuf,
246    },
247    /// Manage preset workflows
248    Preset {
249        #[command(subcommand)]
250        action: PresetAction,
251    },
252    /// Verify the integrity of transformed files (syntax, imports, exports)
253    Verify {
254        #[arg(default_value = ".")]
255        path: PathBuf,
256    },
257    /// Watch for file changes and re-run migration analysis
258    Watch {
259        #[arg(default_value = ".")]
260        path: PathBuf,
261        /// Recipe to analyze; repeat to select multiple recipes
262        #[arg(long = "recipe")]
263        recipes: Vec<String>,
264        /// Debounce delay in milliseconds
265        #[arg(long, default_value_t = 500)]
266        debounce_ms: u64,
267    },
268    /// AI-powered suggestions and analysis
269    Ai {
270        #[command(subcommand)]
271        action: AiAction,
272    },
273    /// Manage and run migration manifests
274    Manifest {
275        #[command(subcommand)]
276        action: ManifestAction,
277    },
278    /// Manage plugins
279    Plugins {
280        #[command(subcommand)]
281        action: PluginAction,
282    },
283    /// View ignored and skipped files with reasons
284    Ignored {
285        #[arg(default_value = ".")]
286        path: PathBuf,
287        /// Show detailed list of all ignored files instead of a summary
288        #[arg(short, long)]
289        detailed: bool,
290    },
291    /// List all dry-run execution snapshots
292    DryRuns,
293    /// View detailed metrics of a specific dry-run execution snapshot
294    DryRun {
295        #[command(subcommand)]
296        action: DryRunAction,
297    },
298    /// Generate markdown documentation for Morph CLI components
299    Docs,
300    /// Check repository health and environment
301    Doctor {
302        #[arg(default_value = ".")]
303        path: PathBuf,
304    },
305}
306
307#[derive(Debug, Subcommand)]
308pub enum AiAction {
309    /// Suggest improvements for a specific file
310    Suggest { file: PathBuf },
311}
312
313#[derive(Debug, Subcommand)]
314pub enum PresetAction {
315    /// List all built-in presets
316    List,
317    /// Run a specific preset workflow
318    Run {
319        /// Name of the preset to run
320        name: String,
321        /// Target path (defaults to current directory)
322        #[arg(default_value = ".")]
323        path: PathBuf,
324        /// Apply changes (write to disk)
325        #[arg(long)]
326        write: bool,
327    },
328}
329
330#[derive(Debug, Subcommand)]
331pub enum PluginAction {
332    /// List all discovered plugins
333    List,
334    /// Show detailed info about a plugin
335    Info { name: String },
336}
337
338#[derive(Debug, Subcommand, Clone)]
339pub enum ManifestAction {
340    /// Create a migration manifest file
341    Create {
342        /// Path to save the manifest (e.g. morph-migration.toml)
343        #[arg(default_value = "morph-migration.toml")]
344        file: std::path::PathBuf,
345        /// Optional configuration profile to use
346        #[arg(long)]
347        profile: Option<String>,
348        /// Recipes to execute; repeat to specify multiple recipes
349        #[arg(short = 'r', long = "recipe")]
350        recipes: Vec<String>,
351        /// Target path to apply migration to (defaults to current directory)
352        #[arg(short = 't', long = "target", default_value = ".")]
353        target: std::path::PathBuf,
354        /// Apply changes (write to disk)
355        #[arg(long)]
356        write: bool,
357        /// Simulate execution without writing to disk
358        #[arg(long)]
359        dry_run: bool,
360        /// Allow recipes to execute even with potential risks
361        #[arg(long)]
362        allow_risky: bool,
363        /// Enforce strict type checking and zero warnings
364        #[arg(long)]
365        strict: bool,
366        /// Automatically fix minor lint/style issues
367        #[arg(long)]
368        autofix: bool,
369    },
370    /// Run a migration manifest file
371    Run {
372        /// Path to the manifest file (e.g. morph-migration.toml)
373        file: std::path::PathBuf,
374    },
375}
376
377#[derive(Debug, Subcommand, Clone)]
378pub enum DryRunAction {
379    /// Show a specific dry-run execution snapshot by ID
380    Show { id: String },
381}
382
383#[derive(Debug, Subcommand, Clone)]
384pub enum ScanAction {
385    /// Show a specific scan snapshot by ID
386    Show { id: String },
387}
388
389pub fn parse() -> Cli {
390    Cli::parse()
391}