Skip to main content

morph_cli/commands/
mod.rs

1mod ai;
2mod benchmark;
3mod dashboard;
4mod deps;
5mod doctor;
6mod docs;
7mod explain;
8mod graph;
9mod history;
10mod init;
11mod list;
12mod magic;
13mod plan;
14mod plugins;
15mod preset;
16mod run;
17mod scan;
18mod score;
19mod simulate;
20mod search;
21mod sessions;
22mod validate;
23mod verify;
24mod version;
25mod watch;
26mod completions;
27mod manifest;
28mod ignored;
29mod dry_run;
30
31use std::path::Path;
32
33use anyhow::{Result, bail};
34
35use crate::cli::{Cli, Command, PluginAction, PresetAction, AiAction, ScanAction};
36use crate::commands::sessions::SessionsArgs;
37
38pub fn execute(cli: Cli, project_root: &Path) -> Result<()> {
39    match cli.command {
40        Command::Version => version::execute(),
41        Command::List { path, category, tag } => list::execute(&path, category.as_deref(), tag.as_deref()),
42        Command::Search { query, path, category, maturity } => {
43            search::execute(&query, &path, category.as_deref(), maturity.as_deref())
44        }
45        Command::History { limit } => history::execute(limit, project_root),
46        Command::Init { path } => init::execute(&path),
47        Command::Dashboard { port } => dashboard::execute(port, project_root),
48        Command::Magic { path } => magic::execute(&path, project_root),
49        Command::Benchmark { path } => benchmark::execute(&path, project_root),
50        Command::ValidateRepo { path } => validate::execute(&path, project_root),
51        Command::Ai { action } => match action {
52            AiAction::Suggest { file } => ai::suggest(&file),
53        },
54        Command::Sessions => sessions::execute(project_root, &SessionsArgs::List),
55        Command::Session { id } => sessions::execute(project_root, &SessionsArgs::Show { id }),
56        Command::Plan { path, tag } => plan::execute(&path, tag.as_deref()),
57        Command::Explain { file } => explain::execute(&file),
58        Command::Scans => scan::execute_list(project_root),
59        Command::Scan { action, path, tag, verbose } => {
60            if let Some(act) = action {
61                match act {
62                    ScanAction::Show { id } => scan::execute_show(&id, project_root),
63                }
64            } else {
65                scan::execute(&path, tag.as_deref(), verbose, project_root)
66            }
67        }
68        Command::Deps { path } => deps::execute(&path),
69        Command::Score { path, format } => score::execute(&path, &format),
70        Command::Simulate { recipes, path } => simulate::execute(&recipes, &path),
71        Command::Graph { graph_type, format, path } => graph::execute(&graph_type, &format, &path),
72        Command::Preset { action } => match action {
73            PresetAction::List => preset::list(),
74            PresetAction::Run { name, path, write } => preset::run(&name, &path, write, project_root),
75        },
76        Command::Watch {
77            path,
78            recipes,
79            debounce_ms,
80        } => watch::execute(&path, &recipes, debounce_ms),
81        Command::Rollback {
82            session_id,
83            preview,
84            force,
85        } => sessions::execute(
86            project_root,
87            &SessionsArgs::Rollback {
88                session_id,
89                preview,
90                force,
91            },
92        ),
93        Command::Verify { path } => verify::execute(&path),
94        Command::Replay { session_id, write } => sessions::execute(
95            project_root,
96            &SessionsArgs::Replay {
97                session_id,
98                write,
99            },
100        ),
101        Command::Resume { checkpoint } => run::resume(&checkpoint, project_root),
102        Command::Completions { shell } => completions::execute(shell),
103        Command::Manifest { action } => manifest::execute(action, project_root),
104        Command::Ignored { path, detailed } => ignored::execute(&path, detailed),
105        Command::DryRuns => dry_run::execute_list(project_root),
106        Command::DryRun { action } => dry_run::execute_show(action, project_root),
107        Command::Run {
108            args,
109            write,
110            dry_run,
111            review,
112            verbose,
113            summary_only,
114            max_preview_lines,
115            allow_risky,
116            strict,
117            report_json,
118            report_md,
119            report_dir,
120            format,
121            prettier,
122            no_format,
123            jobs,
124            sequential,
125            autofix,
126            package,
127            profile,
128            output_style,
129            tag,
130        } => {
131            let (path, recipes) = split_run_args(args)?;
132            run::execute(
133            &recipes,
134            &path,
135            dry_run,
136            write,
137            review,
138            autofix,
139            verbose,
140            summary_only,
141            max_preview_lines,
142            allow_risky,
143            strict,
144            report_json,
145            report_md,
146            &report_dir,
147            format,
148            prettier,
149            no_format,
150            jobs,
151            sequential,
152            project_root,
153            package.as_deref(),
154            profile.as_deref(),
155            output_style.as_deref(),
156            tag.as_deref(),
157            )
158        }
159        Command::Plugins { action } => match action {
160            PluginAction::List => plugins::list::execute(project_root),
161            PluginAction::Info { name } => plugins::info::execute(&name),
162        },
163        Command::Docs => docs::execute(),
164        Command::Doctor { path } => doctor::execute(&path),
165    }
166}
167
168fn split_run_args(mut args: Vec<String>) -> Result<(std::path::PathBuf, Vec<String>)> {
169    let Some(path) = args.pop() else {
170        bail!("Usage: morph run <recipe...> <path>");
171    };
172
173    if args.is_empty() {
174        bail!("Usage: morph run <recipe...> <path>");
175    }
176
177    Ok((std::path::PathBuf::from(path), args))
178}