mod ai;
mod benchmark;
mod dashboard;
mod deps;
mod doctor;
mod docs;
mod explain;
mod graph;
mod history;
mod init;
mod list;
mod magic;
mod plan;
mod plugins;
mod preset;
mod run;
mod scan;
mod score;
mod simulate;
mod search;
mod sessions;
mod validate;
mod verify;
mod version;
mod watch;
mod completions;
mod manifest;
mod ignored;
mod dry_run;
use std::path::Path;
use anyhow::{Result, bail};
use crate::cli::{Cli, Command, PluginAction, PresetAction, AiAction, ScanAction};
use crate::commands::sessions::SessionsArgs;
pub fn execute(cli: Cli, project_root: &Path) -> Result<()> {
match cli.command {
Command::Version => version::execute(),
Command::List { path, category, tag } => list::execute(&path, category.as_deref(), tag.as_deref()),
Command::Search { query, path, category, maturity } => {
search::execute(&query, &path, category.as_deref(), maturity.as_deref())
}
Command::History { limit } => history::execute(limit, project_root),
Command::Init { path } => init::execute(&path),
Command::Dashboard { port } => dashboard::execute(port, project_root),
Command::Magic { path } => magic::execute(&path, project_root),
Command::Benchmark { path } => benchmark::execute(&path, project_root),
Command::ValidateRepo { path } => validate::execute(&path, project_root),
Command::Ai { action } => match action {
AiAction::Suggest { file } => ai::suggest(&file),
},
Command::Sessions => sessions::execute(project_root, &SessionsArgs::List),
Command::Session { id } => sessions::execute(project_root, &SessionsArgs::Show { id }),
Command::Plan { path, tag } => plan::execute(&path, tag.as_deref()),
Command::Explain { file } => explain::execute(&file),
Command::Scans => scan::execute_list(project_root),
Command::Scan { action, path, tag, verbose } => {
if let Some(act) = action {
match act {
ScanAction::Show { id } => scan::execute_show(&id, project_root),
}
} else {
scan::execute(&path, tag.as_deref(), verbose, project_root)
}
}
Command::Deps { path } => deps::execute(&path),
Command::Score { path, format } => score::execute(&path, &format),
Command::Simulate { recipes, path } => simulate::execute(&recipes, &path),
Command::Graph { graph_type, format, path } => graph::execute(&graph_type, &format, &path),
Command::Preset { action } => match action {
PresetAction::List => preset::list(),
PresetAction::Run { name, path, write } => preset::run(&name, &path, write, project_root),
},
Command::Watch {
path,
recipes,
debounce_ms,
} => watch::execute(&path, &recipes, debounce_ms),
Command::Rollback {
session_id,
preview,
force,
} => sessions::execute(
project_root,
&SessionsArgs::Rollback {
session_id,
preview,
force,
},
),
Command::Verify { path } => verify::execute(&path),
Command::Replay { session_id, write } => sessions::execute(
project_root,
&SessionsArgs::Replay {
session_id,
write,
},
),
Command::Resume { checkpoint } => run::resume(&checkpoint, project_root),
Command::Completions { shell } => completions::execute(shell),
Command::Manifest { action } => manifest::execute(action, project_root),
Command::Ignored { path, detailed } => ignored::execute(&path, detailed),
Command::DryRuns => dry_run::execute_list(project_root),
Command::DryRun { action } => dry_run::execute_show(action, project_root),
Command::Run {
args,
write,
dry_run,
review,
verbose,
summary_only,
max_preview_lines,
allow_risky,
strict,
report_json,
report_md,
report_dir,
format,
prettier,
no_format,
jobs,
sequential,
autofix,
package,
profile,
output_style,
tag,
} => {
let (path, recipes) = split_run_args(args)?;
run::execute(
&recipes,
&path,
dry_run,
write,
review,
autofix,
verbose,
summary_only,
max_preview_lines,
allow_risky,
strict,
report_json,
report_md,
&report_dir,
format,
prettier,
no_format,
jobs,
sequential,
project_root,
package.as_deref(),
profile.as_deref(),
output_style.as_deref(),
tag.as_deref(),
)
}
Command::Plugins { action } => match action {
PluginAction::List => plugins::list::execute(project_root),
PluginAction::Info { name } => plugins::info::execute(&name),
},
Command::Docs => docs::execute(),
Command::Doctor { path } => doctor::execute(&path),
}
}
fn split_run_args(mut args: Vec<String>) -> Result<(std::path::PathBuf, Vec<String>)> {
let Some(path) = args.pop() else {
bail!("Usage: morph run <recipe...> <path>");
};
if args.is_empty() {
bail!("Usage: morph run <recipe...> <path>");
}
Ok((std::path::PathBuf::from(path), args))
}