hlx 1.2.5

Configuration language designed specifically for ml/ai/data systems
Documentation
use std::path::PathBuf;
use std::fs;
use anyhow::{Result, Context};
pub fn run_diagnostics(verbose: bool) -> Result<()> {
    println!("🏥 HELIX Doctor - System Diagnostics");
    println!("===================================");
    println!();
    let mut issues = Vec::new();
    let mut warnings = Vec::new();
    check_system_requirements(&mut issues, &mut warnings, verbose)?;
    check_hlx_installation(&mut issues, &mut warnings, verbose)?;
    check_project_structure(&mut issues, &mut warnings, verbose)?;
    check_dependencies(&mut issues, &mut warnings, verbose)?;
    check_configuration(&mut issues, &mut warnings, verbose)?;
    print_diagnostic_results(&issues, &warnings, verbose);
    if !issues.is_empty() {
        std::process::exit(1);
    }
    Ok(())
}
fn check_system_requirements(
    issues: &mut Vec<String>,
    warnings: &mut Vec<String>,
    verbose: bool,
) -> Result<()> {
    if verbose {
        println!("🔍 Checking system requirements...");
    }
    match std::process::Command::new("rustc").arg("--version").output() {
        Ok(output) => {
            if output.status.success() {
                let version = String::from_utf8_lossy(&output.stdout);
                if verbose {
                    println!("  ✅ Rust: {}", version.trim());
                }
            } else {
                issues.push("Rust compiler not found or not working".to_string());
            }
        }
        Err(_) => {
            issues.push("Rust compiler not installed".to_string());
        }
    }
    match std::process::Command::new("cargo").arg("--version").output() {
        Ok(output) => {
            if output.status.success() {
                let version = String::from_utf8_lossy(&output.stdout);
                if verbose {
                    println!("  ✅ Cargo: {}", version.trim());
                }
            } else {
                issues.push("Cargo not found or not working".to_string());
            }
        }
        Err(_) => {
            issues.push("Cargo not installed".to_string());
        }
    }
    if let Ok(mem_info) = get_memory_info() {
        if mem_info.available < 1024 * 1024 * 1024 {
            warnings
                .push(
                    format!("Low available memory: {}", format_size(mem_info.available)),
                );
        }
        if verbose {
            println!(
                "  📊 Memory: {} total, {} available", format_size(mem_info.total),
                format_size(mem_info.available)
            );
        }
    }
    if let Ok(disk_info) = get_disk_info() {
        if disk_info.available < 1024 * 1024 * 1024 * 1024 {
            warnings
                .push(format!("Low disk space: {}", format_size(disk_info.available)));
        }
        if verbose {
            println!(
                "  💾 Disk: {} total, {} available", format_size(disk_info.total),
                format_size(disk_info.available)
            );
        }
    }
    Ok(())
}
fn check_hlx_installation(
    issues: &mut Vec<String>,
    warnings: &mut Vec<String>,
    verbose: bool,
) -> Result<()> {
    if verbose {
        println!("🔍 Checking HELIX installation...");
    }
    match which::which("helix") {
        Ok(path) => {
            if verbose {
                println!("  ✅ HELIX compiler found: {}", path.display());
            }
        }
        Err(_) => {
            issues.push("HELIX compiler not found in PATH".to_string());
        }
    }
    match std::process::Command::new("helix").arg("--version").output() {
        Ok(output) => {
            if output.status.success() {
                let version = String::from_utf8_lossy(&output.stdout);
                if verbose {
                    println!("  ✅ hlx version: {}", version.trim());
                }
            } else {
                issues.push("HELIX compiler not working properly".to_string());
            }
        }
        Err(_) => {
            issues.push("HELIX compiler not accessible".to_string());
        }
    }
    let baton_dir = get_baton_directory()?;
    if !baton_dir.exists() {
        warnings
            .push(
                ".baton directory not found (will be created on first use)".to_string(),
            );
    } else if verbose {
        println!("  ✅ .baton directory: {}", baton_dir.display());
    }
    Ok(())
}
fn check_project_structure(
    issues: &mut Vec<String>,
    warnings: &mut Vec<String>,
    verbose: bool,
) -> Result<()> {
    if verbose {
        println!("🔍 Checking project structure...");
    }
    let current_dir = std::env::current_dir()
        .context("Failed to get current directory")?;
    let manifest_path = current_dir.join("project.hlx");
    if !manifest_path.exists() {
        warnings.push("No project.hlx found (not in an HELIX project)".to_string());
        return Ok(());
    }
    if verbose {
        println!("  ✅ Project manifest: {}", manifest_path.display());
    }
    let src_dir = current_dir.join("src");
    if !src_dir.exists() {
        issues.push("Source directory 'src/' not found".to_string());
    } else if verbose {
        println!("  ✅ Source directory: {}", src_dir.display());
    }
    if src_dir.exists() {
        let helix_files = find_helix_files(&src_dir)?;
        if helix_files.is_empty() {
            warnings.push("No HELIX source files found in src/".to_string());
        } else if verbose {
            println!("  ✅ Found {} HELIX files", helix_files.len());
        }
    }
    let target_dir = current_dir.join("target");
    if !target_dir.exists() {
        if verbose {
            println!("  ℹ️  Target directory not found (will be created on build)");
        }
    } else if verbose {
        println!("  ✅ Target directory: {}", target_dir.display());
    }
    Ok(())
}
fn check_dependencies(
    issues: &mut Vec<String>,
    warnings: &mut Vec<String>,
    verbose: bool,
) -> Result<()> {
    if verbose {
        println!("🔍 Checking dependencies...");
    }
    let current_dir = std::env::current_dir()
        .context("Failed to get current directory")?;
    let manifest_path = current_dir.join("project.hlx");
    if !manifest_path.exists() {
        return Ok(());
    }
    let content = fs::read_to_string(&manifest_path)
        .context("Failed to read project.hlx")?;
    if content.trim().is_empty() {
        warnings.push("Empty project.hlx file".to_string());
    }
    if content.contains("# Dependency:") || content.contains("# Dev Dependency:") {
        if verbose {
            println!("  ✅ Dependencies found in project.hlx");
        }
    } else {
        if verbose {
            println!("  ℹ️  No dependencies specified");
        }
    }
    Ok(())
}
fn check_configuration(
    issues: &mut Vec<String>,
    warnings: &mut Vec<String>,
    verbose: bool,
) -> Result<()> {
    if verbose {
        println!("🔍 Checking configuration...");
    }
    let config_path = get_global_config_path()?;
    if !config_path.exists() {
        if verbose {
            println!("  ℹ️  Global config not found (will be created on first use)");
        }
    } else if verbose {
        println!("  ✅ Global config: {}", config_path.display());
    }
    let cache_dir = get_cache_directory()?;
    if cache_dir.exists() {
        let cache_size = calculate_directory_size(&cache_dir)?;
        if verbose {
            println!(
                "  ✅ Cache directory: {} ({})", cache_dir.display(),
                format_size(cache_size)
            );
        }
        if cache_size > 1024 * 1024 * 1024 {
            warnings.push(format!("Large cache size: {}", format_size(cache_size)));
        }
    } else if verbose {
        println!("  ℹ️  Cache directory not found (will be created on first use)");
    }
    Ok(())
}
fn print_diagnostic_results(issues: &[String], warnings: &[String], verbose: bool) {
    println!();
    if issues.is_empty() && warnings.is_empty() {
        println!("✅ All checks passed! Your hlx environment is healthy.");
        return;
    }
    if !issues.is_empty() {
        println!("❌ Issues found ({}):", issues.len());
        for (i, issue) in issues.iter().enumerate() {
            println!("  {}. {}", i + 1, issue);
        }
        println!();
    }
    if !warnings.is_empty() {
        println!("⚠️  Warnings ({}):", warnings.len());
        for (i, warning) in warnings.iter().enumerate() {
            println!("  {}. {}", i + 1, warning);
        }
        println!();
    }
    if !issues.is_empty() {
        println!("💡 To fix issues:");
        println!("  1. Install missing dependencies");
        println!("  2. Run 'helix init' to create a new project");
        println!("  3. Check your system configuration");
        println!("  4. Run 'helix doctor' again to verify fixes");
    }
}
fn find_helix_files(dir: &PathBuf) -> Result<Vec<PathBuf>> {
    let mut files = Vec::new();
    find_helix_files_recursive(dir, &mut files)?;
    Ok(files)
}
fn find_helix_files_recursive(dir: &PathBuf, files: &mut Vec<PathBuf>) -> Result<()> {
    let entries = fs::read_dir(dir).context("Failed to read directory")?;
    for entry in entries {
        let entry = entry.context("Failed to read directory entry")?;
        let path = entry.path();
        if path.is_file() {
            if let Some(extension) = path.extension() {
                if extension == "hlx" {
                    files.push(path);
                }
            }
        } else if path.is_dir() {
            find_helix_files_recursive(&path, files)?;
        }
    }
    Ok(())
}
fn calculate_directory_size(dir: &PathBuf) -> Result<u64> {
    let mut total_size = 0;
    let entries = fs::read_dir(dir).context("Failed to read directory")?;
    for entry in entries {
        let entry = entry.context("Failed to read directory entry")?;
        let path = entry.path();
        if path.is_file() {
            let metadata = fs::metadata(&path).context("Failed to read file metadata")?;
            total_size += metadata.len();
        } else if path.is_dir() {
            total_size += calculate_directory_size(&path)?;
        }
    }
    Ok(total_size)
}
fn format_size(bytes: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    const THRESHOLD: u64 = 1024;
    if bytes == 0 {
        return "0 B".to_string();
    }
    let mut size = bytes as f64;
    let mut unit_index = 0;
    while size >= THRESHOLD as f64 && unit_index < UNITS.len() - 1 {
        size /= THRESHOLD as f64;
        unit_index += 1;
    }
    if unit_index == 0 {
        format!("{} {}", bytes, UNITS[unit_index])
    } else {
        format!("{:.1} {}", size, UNITS[unit_index])
    }
}
struct MemoryInfo {
    total: u64,
    available: u64,
}
struct DiskInfo {
    total: u64,
    available: u64,
}
fn get_memory_info() -> Result<MemoryInfo> {
    Ok(MemoryInfo {
        total: 8 * 1024 * 1024 * 1024,
        available: 4 * 1024 * 1024 * 1024,
    })
}
fn get_disk_info() -> Result<DiskInfo> {
    Ok(DiskInfo {
        total: 100 * 1024 * 1024 * 1024,
        available: 50 * 1024 * 1024 * 1024,
    })
}
fn get_baton_directory() -> Result<PathBuf> {
    let home_dir = dirs::home_dir()
        .ok_or_else(|| anyhow::anyhow!("Failed to get home directory"))?;
    Ok(home_dir.join(".baton"))
}
fn get_global_config_path() -> Result<PathBuf> {
    let home_dir = dirs::home_dir()
        .ok_or_else(|| anyhow::anyhow!("Failed to get home directory"))?;
    Ok(home_dir.join(".baton").join("config.toml"))
}
fn get_cache_directory() -> Result<PathBuf> {
    let home_dir = dirs::home_dir()
        .ok_or_else(|| anyhow::anyhow!("Failed to get home directory"))?;
    Ok(home_dir.join(".baton").join("cache"))
}