morph-cli 0.1.0

AST-based codebase migration and codemod tool for JavaScript and TypeScript projects.
Documentation
use std::path::Path;
use anyhow::{Result};
use inquire::{Select, MultiSelect};
use crate::core::detection::scanner::Scanner;
use crate::utils::terminal;
use crate::commands::run;

pub fn execute(path: &Path, project_root: &Path) -> Result<()> {
    println!("{}", terminal::label("morph-cli Magic ✨"));
    println!("Guided migration assistant starting...\n");

    // 1. Scan project
    let mut scanner = Scanner::new(path.to_path_buf());
    let scan_result = scanner.scan();

    if scan_result.detection.migration_opportunities.is_empty() {
        println!("{} No migration opportunities detected in this project.", terminal::info_prefix());
        return Ok(());
    }

    println!("Detected opportunities:");
    for opp in &scan_result.detection.migration_opportunities {
        println!("  {} {}", terminal::bullet(), opp.name);
        println!("    {}", opp.description);
    }
    println!();

    // 2. Suggest opportunities (allow user to select)
    let opportunities = scan_result.detection.migration_opportunities.clone();
    let opp_names: Vec<String> = opportunities.iter().map(|o| o.name.clone()).collect();

    let selected_names = MultiSelect::new("Select opportunities to migrate:", opp_names)
        .prompt()?;

    if selected_names.is_empty() {
        println!("No opportunities selected. Exiting.");
        return Ok(());
    }

    let mut selected_recipes = Vec::new();
    for name in &selected_names {
        if let Some(opp) = opportunities.iter().find(|o| &o.name == name) {
            selected_recipes.extend(opp.recipes.clone());
        }
    }

    // 3. Confirm
    let confirm = Select::new(&format!("Run {} opportunities ({} recipes) in dry-run mode?", selected_names.len(), selected_recipes.len()), vec!["Yes", "No"])
        .prompt()?;

    if confirm == "No" {
        println!("Operation cancelled.");
        return Ok(());
    }

    // 4. Run dry-run by default
    println!("\n{} Running dry-run for selected recipes...\n", terminal::info_prefix());
    
    run::execute(
        &selected_recipes,
        path,
        true, // dry_run
        false, // write
        true, // review
        true, // autofix
        false, // verbose
        true, // summary_only
        Some(10), // max_preview_lines
        false, // allow_risky
        false, // strict
        false, // report_json
        false, // report_md
        Path::new(".morph-cli/reports"),
        true, // format
        false, // prettier
        false, // no_format
        None, // jobs
        false, // sequential
        project_root,
        None, // package
        None, // profile
        None, // output_style
        None, // tag
    )?;

    println!("\n{} Magic workflow completed!", terminal::success_prefix());
    println!("You can now review the changes and run `morph run <recipes> <path> --write` to apply them.");

    Ok(())
}