mecha10-cli 0.8.0

Mecha10 CLI tool
Documentation
//! Lint command handler
//!
//! Orchestrates code linting checks.

use crate::context::CliContext;
use crate::ui::style;
use anyhow::Result;

#[derive(Debug, Clone)]
pub struct LintArgs {
    pub fix: bool,
}

/// Handle lint command
///
/// Runs code linting checks across all project code.
pub async fn handle_lint(ctx: &mut CliContext, args: &LintArgs) -> Result<()> {
    println!();
    println!("{}", style::heading("🔍 Code Linting"));
    println!("{}", style::separator(47));
    println!();

    if !ctx.is_project_initialized() {
        return Err(anyhow::anyhow!(
            "Not in a Mecha10 project directory.\n\
             Run 'mecha10 init' to create a new project."
        ));
    }

    let project = ctx.project()?;
    println!("Project: {}", project.root().display());
    println!();

    let mut all_passed = true;

    println!("Running Rust linting (clippy)...");
    let clippy_result = if args.fix {
        std::process::Command::new("cargo")
            .args(["clippy", "--fix", "--allow-dirty", "--allow-staged"])
            .current_dir(project.root())
            .status()
    } else {
        std::process::Command::new("cargo")
            .args(["clippy", "--all-targets", "--", "-D", "warnings"])
            .current_dir(project.root())
            .status()
    };

    match clippy_result {
        Ok(status) if status.success() => {
            println!("{}", style::success("✅ Rust linting passed"));
        }
        Ok(_) => {
            println!("{}", style::error("❌ Rust linting failed"));
            all_passed = false;
        }
        Err(e) => {
            println!("{}", style::warn(format!("⚠️  Could not run clippy: {}", e)));
            println!("   Install with: rustup component add clippy");
        }
    }
    println!();

    println!("Validating configs (mecha10.json + node configs)...");
    let assets_dir = if crate::config_validation::needs_environment_schema(&ctx.working_dir) {
        match ctx.assets_download().fetch_and_extract().await {
            Ok(dir) => Some(dir),
            Err(e) => {
                println!("{}", style::error("❌ Config validation failed:"));
                println!("Failed to download mecha10-assets: {:#}", e);
                return Err(anyhow::anyhow!("Linting failed"));
            }
        }
    } else {
        None
    };
    let schemas_dir = assets_dir
        .as_ref()
        .map(|dir| dir.path().join("configs/simulation/schemas"));
    match crate::config_validation::validate_config(None, schemas_dir.as_deref()) {
        Ok(target) => {
            println!(
                "{}",
                style::success(format!("✅ Config validation passed ({})", target.display()))
            );
        }
        Err(e) => {
            println!("{}", style::error("❌ Config validation failed:"));
            println!("{:#}", e);
            all_passed = false;
        }
    }
    println!();

    println!("{}", style::separator(47));
    if all_passed {
        println!("{}", style::success("✅ All linting checks passed!"));
    } else {
        println!("{}", style::error("❌ Some linting checks failed"));
        if !args.fix {
            println!();
            println!("Run with --fix to automatically fix issues:");
            println!("  mecha10 lint --fix");
        }
        return Err(anyhow::anyhow!("Linting failed"));
    }
    println!();

    Ok(())
}