cargo-mate 1.7.6

Rust development companion that enhances cargo with intelligent workflows, state management, performance optimization, and comprehensive project monitoring.
Documentation
use anyhow::{Result, Context};
use colored::*;
use chrono;
use std::fs;
use std::path::PathBuf;
use dirs;
use crate::captain::license;
use crate::captain::wtf;
use crate::captain::version;
use crate::display;
use crate::captain::captain_log;
pub fn run_cargo_with_wrapper(args: &[&str]) -> Result<()> {
    if !args.is_empty() {
        let license_manager = crate::captain::license::LicenseManager::new();
        if let Err(e) = license_manager?.enforce_license(&format!("cargo-{}", args[0])) {
            eprintln!("❌ License enforcement failed: {}", e);
            crate::captain::wtf::display_api_failure_art();
            std::process::exit(1);
        }
    }
    if let Err(e) = version::pre_operation_hook(None) {
        eprintln!("⚠️  Version auto-increment failed: {}", e);
    }
    display::run_cargo_with_display(args);
    if let Ok(mut log) = captain_log::CaptainLog::new() {
        let build_result = captain_log::BuildResult {
            success: true,
            error_count: 0,
            warning_count: 0,
            duration_seconds: 0.0,
        };
        if let Err(e) = log
            .log_command(&format!("cargo {}", args.join(" ")), build_result)
        {
            eprintln!("⚠️  Captain's Log recording failed: {}", e);
        }
        println!("\n📝 {}", "Captain's Log: Session recorded".dimmed());
    }
    if let Err(e) = version::post_operation_hook(None, true) {
        eprintln!("⚠️  Version post-operation hook failed: {}", e);
    }
    Ok(())
}
pub fn run_tracked_command(command: &str, session_id: &str) -> Result<()> {
    use std::process::Command;
    use std::io::{BufRead, BufReader};
    let parts: Vec<&str> = command.split_whitespace().collect();
    if parts.is_empty() {
        return Err(anyhow::anyhow!("Empty command"));
    }
    let mut log = captain_log::CaptainLog::new()?;
    let parser = captain_log::CargoOutputParser::new();
    let mut cmd = Command::new(parts[0]);
    cmd.args(&parts[1..]);
    if parts[0] == "cargo" {
        cmd.arg("--message-format=json");
    }
    let start_time = std::time::Instant::now();
    let mut child = cmd
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()?;
    if let Some(stdout) = child.stdout.take() {
        let reader = BufReader::new(stdout);
        for line in reader.lines() {
            let line = line?;
            println!("{}", line);
            if let Some(msg) = parser.parse_message(&line)? {
                if let Some(diagnostic) = msg.message {
                    let entry = parser
                        .create_log_entry_from_diagnostic(&diagnostic, session_id);
                    log.log(&entry.message, entry.tags)?;
                }
            }
        }
    }
    if let Some(stderr) = child.stderr.take() {
        let reader = BufReader::new(stderr);
        for line in reader.lines() {
            let line = line?;
            eprintln!("{}", line);
            if let Some(msg) = parser.parse_message(&line)? {
                if let Some(diagnostic) = msg.message {
                    let entry = parser
                        .create_log_entry_from_diagnostic(&diagnostic, session_id);
                    log.log(&entry.message, entry.tags)?;
                }
            }
        }
    }
    let status = child.wait()?;
    let duration = start_time.elapsed();
    let build_result = captain_log::BuildResult {
        success: status.success(),
        error_count: 0,
        warning_count: 0,
        duration_seconds: duration.as_secs_f64(),
    };
    log.log_command(command, build_result)?;
    println!("\n🔍 Analysis:");
    let entries = log.get_recent(1000);
    let entries_owned: Vec<captain_log::LogEntry> = entries
        .into_iter()
        .cloned()
        .collect();
    let detector = captain_log::PatternDetector::new(entries_owned);
    let recurring = detector.find_recurring_errors();
    if !recurring.is_empty() {
        println!("\n⚠️  Recurring Issues:");
        for (error_key, count, _) in recurring.into_iter().take(5) {
            println!("   {} ({})", error_key.cyan(), count);
        }
    }
    let regressions = detector.detect_build_time_regression();
    if !regressions.is_empty() {
        println!("\n📈 Build Time Regressions:");
        for (command, old_time, new_time) in regressions {
            println!(
                "   {}: {:.2}s → {:.2}s ({:.1}%)", command.cyan(), old_time, new_time,
                ((new_time - old_time) / old_time) * 100.0
            );
        }
    }
    Ok(())
}
pub fn get_recent_errors(count: usize) -> Result<Vec<String>> {
    let home_dir = dirs::home_dir()
        .ok_or_else(|| anyhow::anyhow!("Could not find home directory"))?;
    let shipwreck = home_dir.join(".shipwreck");
    let error_file = shipwreck.join("errors").join("latest.txt");
    if error_file.exists() {
        let content = std::fs::read_to_string(&error_file)?;
        let errors: Vec<String> = content
            .lines()
            .filter(|line| !line.trim().is_empty())
            .take(count)
            .map(|s| s.to_string())
            .collect();
        if errors.is_empty() {
            Ok(vec!["No recent errors found in the error logs.".to_string()])
        } else {
            Ok(errors)
        }
    } else {
        Ok(
            vec![
                "No error log file found. Try running some cargo commands first."
                .to_string()
            ],
        )
    }
}
pub fn show_loading_messages() {
    let messages = [
        "⚓ Hoisting the sails... preparing to set sail for knowledge!",
        "🌊 Riding the waves... surfing through the digital ocean!",
        "🧭 Checking the compass... navigating to the answer!",
        "🚢 Batten down the hatches... stormy seas of computation ahead!",
        "🦜 Arr, matey! Consulting the ancient tomes of wisdom!",
        "⚡ Charging the canons... ready to fire the knowledge salvo!",
        "🧜‍♀️ Singing sea shanties... luring the answers from the deep!",
        "🗺️ Reading the treasure map... X marks the spot of knowledge!",
        "🦈 Dodging digital sharks... swimming towards the answer!",
        "🌟 Aligning the stars... consulting the celestial database!",
    ];
    let mut index = 0;
    let start_time = std::time::Instant::now();
    while start_time.elapsed().as_secs() < 30 {
        println!("{}", messages[index]);
        std::thread::sleep(std::time::Duration::from_secs(3));
        index = (index + 1) % messages.len();
    }
}
pub fn parse_bool(s: &str) -> Result<bool, std::num::ParseIntError> {
    match s.to_lowercase().as_str() {
        "true" | "1" | "yes" | "on" => Ok(true),
        "false" | "0" | "no" | "off" => Ok(false),
        _ => Ok(s.parse::<u8>()? != 0),
    }
}
pub fn is_cm_command(cmd: &str) -> bool {
    matches!(
        cmd, "anchor" | "journey" | "log" | "tide" | "map" | "mutiny" | "config" |
        "version" | "view" | "optimize" | "test" | "history" | "init" | "install" |
        "activate" | "register" | "idea" | "wtf" | "checklist" | "add" | "done" | "clear"
        | "show" | "list" | "user" | "debug" | "help" | "--help" | "-h" | "tool" |
        "tools" | "strip" | "scat"
    )
}
pub fn handle_license_check(command: &str) -> Result<()> {
    let license_manager = crate::captain::license::LicenseManager::new();
    license_manager?.enforce_license(command)
}
pub fn check_command_license(command: &str) -> Result<()> {
    let license_manager = crate::captain::license::LicenseManager::new();
    match license_manager?.enforce_license(command) {
        Ok(_) => Ok(()),
        Err(e) => Err(e),
    }
}