//! kei-refactor-engine — binary entry. //! //! Usage: //! kei-refactor-engine --input conflicts.json --plan-only > plan.md //! kei-refactor-engine --input conflicts.json --apply-to-branch deep-sleep/2026-04-22 \ //! --plan-out plan.md --patch-out changes.patch use anyhow::Result; use clap::Parser; use kei_refactor_engine::input::{read_conflicts, read_from_stdin}; use kei_refactor_engine::plan::Plan; use kei_refactor_engine::{patch, render}; use std::path::PathBuf; use std::process::ExitCode; #[derive(Parser, Debug)] #[command(name = "kei-refactor-engine", about = "Deep-sleep refactor-plan generator.")] struct Cli { /// Input JSON file (output of kei-conflict-scan). Use `-` for stdin. #[arg(long)] input: Option, /// Plan-only mode (default). Prints markdown to stdout if no --plan-out. #[arg(long, default_value_t = true)] plan_only: bool, /// Apply mode — also write a patch file; takes the branch name. #[arg(long)] apply_to_branch: Option, /// Optional explicit path for the markdown plan. #[arg(long)] plan_out: Option, /// Optional explicit path for the patch file. #[arg(long)] patch_out: Option, } fn load(cli: &Cli) -> Result> { match cli.input.as_deref() { None => read_from_stdin(), Some(p) if p.to_string_lossy() == "-" => read_from_stdin(), Some(p) => read_conflicts(p), } } fn write_plan(plan: &Plan, branch: Option<&str>, out: Option<&PathBuf>) -> Result<()> { let md = render::render(plan, branch); match out { Some(p) => std::fs::write(p, md)?, None => print!("{}", md), } Ok(()) } fn maybe_write_patch( plan: &Plan, branch: &str, out: Option<&PathBuf>, ) -> Result { let default = PathBuf::from("deep-sleep.patch"); let target = out.unwrap_or(&default); patch::write_patch(plan, branch, target) } fn run(cli: &Cli) -> Result { let conflicts = load(cli)?; let plan = Plan::from_conflicts(&conflicts); let branch = cli.apply_to_branch.as_deref(); write_plan(&plan, branch, cli.plan_out.as_ref())?; if let Some(br) = branch { let applied = maybe_write_patch(&plan, br, cli.patch_out.as_ref())?; eprintln!( "kei-refactor-engine: wrote patch with {} auto-apply item(s); {} human-decision item(s) excluded.", applied, plan.manual_items().len(), ); } Ok(ExitCode::SUCCESS) } fn main() -> ExitCode { let cli = Cli::parse(); match run(&cli) { Ok(c) => c, Err(e) => { eprintln!("kei-refactor-engine: {e}"); ExitCode::from(1) } } }