hlx 1.2.5

Configuration language designed specifically for ml/ai/data systems
Documentation
use std::path::PathBuf;
use crate::dna::compiler::{Compiler, OptimizationLevel};

pub fn run_build(args: crate::dna::cmd::build::BuildArgs) -> anyhow::Result<()> {
    let input = args.input;
    let output = args.output;
    let optimize = args.optimize;
    let compress = args.compress;
    let cache = args.cache;

    build_project(input, output, optimize, compress, cache, true)
        .map_err(|e| anyhow::anyhow!("Build failed: {}", e))
}

fn build_project(
    input: Option<PathBuf>,
    output: Option<PathBuf>,
    optimize: u8,
    compress: bool,
    cache: bool,
    verbose: bool,
) -> Result<(), Box<dyn std::error::Error>> {
    let project_dir = find_project_root()?;
    let input_file = match input {
        Some(path) => path,
        None => {
            let main_file = project_dir.join("src").join("main.hlx");
            if main_file.exists() {
                main_file
            } else {
                return Err(
                    anyhow::anyhow!(
                        "No input file specified and no src/main.hlx found.\n\
                    Specify a file with: helix build <file.hlx>"
                    )
                        .into(),
                );
            }
        }
    };
    let output_file = output
        .unwrap_or_else(|| {
            let target_dir = project_dir.join("target");
            let input_stem = input_file
                .file_stem()
                .and_then(|s| s.to_str())
                .unwrap_or("output");
            target_dir.join(format!("{}.hlxb", input_stem))
        });
    if verbose {
        println!("🔨 Building HELIX project:");
        println!("  Input: {}", input_file.display());
        println!("  Output: {}", output_file.display());
        println!("  Optimization: Level {}", optimize);
        println!("  Compression: {}", if compress { "Enabled" } else { "Disabled" });
        println!("  Cache: {}", if cache { "Enabled" } else { "Disabled" });
    }
    if let Some(parent) = output_file.parent() {
        std::fs::create_dir_all(parent)?;
    }
    let compiler = Compiler::new(OptimizationLevel::from(optimize));
    let binary = compiler.compile_file(&input_file)?;
    let serializer = crate::mds::serializer::BinarySerializer::new(compress);
    serializer.write_to_file(&binary, &output_file)?;
    println!("✅ Build completed successfully!");
    println!("  Output: {}", output_file.display());
    println!("  Size: {} bytes", binary.size());
    if verbose {
        let stats = binary.symbol_table.stats();
        println!(
            "  Strings: {} (unique: {})", stats.total_strings, stats.unique_strings
        );
        println!("  Agents: {}", stats.agents);
        println!("  Workflows: {}", stats.workflows);
    }
    Ok(())
}

fn find_project_root() -> Result<PathBuf, Box<dyn std::error::Error>> {
    let mut current = std::env::current_dir()?;
    loop {
        if current.join("hlx.toml").exists() || current.join("Cargo.toml").exists() {
            return Ok(current);
        }
        if let Some(parent) = current.parent() {
            current = parent.to_path_buf();
        } else {
            return Err("Could not find project root".into());
        }
    }
}