pub mod audit;
pub mod bench;
pub mod build;
// no subcommand โ€” shared trisha subprocess helpers for bench + audit
pub mod check;
pub mod deploy;
pub mod deps;
pub mod doc;
pub mod fmt;
pub mod generate;
pub mod hash;
pub mod init;
pub mod package;
pub mod prove;
pub mod registry;
pub mod run;
pub mod store;
pub mod test;
pub mod train;
pub mod tree_sitter;
pub mod trisha;
pub mod verify;
pub mod view;

use std::path::{Path, PathBuf};
use std::process;

// โ”€โ”€โ”€ Three-Register Target Resolution โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Resolved battlefield from three naming registers.
///
/// Users speak geeky (engine/network/vimputer), gamy
/// (terrain/union/state), or universal (target). All resolve
/// to the same battlefield.
pub struct BattlefieldSelection {
    /// Resolved target name (terrain or union name).
    pub target: String,
    /// Explicit state name, if provided.
    pub state: Option<String>,
}

/// Resolve a battlefield from three naming registers.
///
/// Priority: explicit register flags override `--target`.
/// Geeky (engine/network) and gamy (terrain/union) are synonyms.
/// At most one terrain-level and one union-level flag may be set
/// (enforced by clap `conflicts_with`).
pub fn resolve_battlefield(
    target: &str,
    engine: &Option<String>,
    terrain: &Option<String>,
    network: &Option<String>,
    union_flag: &Option<String>,
    vimputer: &Option<String>,
    state: &Option<String>,
) -> BattlefieldSelection {
    // Terrain-level: engine or terrain override target
    let resolved_target = engine
        .as_deref()
        .or(terrain.as_deref())
        .or(network.as_deref())
        .or(union_flag.as_deref())
        .unwrap_or(target)
        .to_string();

    // State-level: vimputer or state
    let resolved_state = vimputer.clone().or_else(|| state.clone());

    BattlefieldSelection {
        target: resolved_target,
        state: resolved_state,
    }
}

/// Resolve a battlefield without state flags (compilation commands).
pub fn resolve_battlefield_compile(
    target: &str,
    engine: &Option<String>,
    terrain: &Option<String>,
    network: &Option<String>,
    union_flag: &Option<String>,
) -> BattlefieldSelection {
    resolve_battlefield(target, engine, terrain, network, union_flag, &None, &None)
}

// โ”€โ”€โ”€ Input Resolution โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

/// Resolved input: entry file and optional project.
pub struct ResolvedInput {
    pub entry: PathBuf,
    pub project: Option<trident::project::Project>,
}

fn load_project(toml_path: &Path) -> trident::project::Project {
    match trident::project::Project::load(toml_path) {
        Ok(p) => p,
        Err(e) => {
            eprintln!("error: {}", e.message);
            process::exit(1);
        }
    }
}

/// Resolve an input path (file or project directory) to an entry file and optional project.
pub fn resolve_input(input: &Path) -> ResolvedInput {
    if input.is_dir() {
        let toml_path = input.join("trident.toml");
        if !toml_path.exists() {
            eprintln!("error: no trident.toml found in '{}'", input.display());
            process::exit(1);
        }
        let project = load_project(&toml_path);
        let entry = project.entry.clone();
        return ResolvedInput {
            entry,
            project: Some(project),
        };
    }

    if !input.extension().is_some_and(|e| e == "tri") {
        eprintln!("error: input must be a .tri file or project directory");
        process::exit(1);
    }

    let toml_path = trident::project::Project::find(input.parent().unwrap_or(Path::new(".")));
    match toml_path {
        Some(p) => {
            let project = load_project(&p);
            let entry = project.entry.clone();
            ResolvedInput {
                entry,
                project: Some(project),
            }
        }
        None => ResolvedInput {
            entry: input.to_path_buf(),
            project: None,
        },
    }
}

/// Resolve a VM target + profile to CompileOptions.
pub fn resolve_options(
    target: &str,
    profile: &str,
    project: Option<&trident::project::Project>,
) -> trident::CompileOptions {
    // Backward compat: --target debug/release โ†’ treat as profile
    let (vm_target, actual_profile) = match target {
        "debug" | "release" => {
            eprintln!(
                "warning: --target {} is deprecated; use --profile {} --target triton",
                target, target
            );
            ("triton", target)
        }
        _ => (target, profile),
    };

    // Project may override the default "triton" target
    let effective_target = match (vm_target, project) {
        ("triton", Some(proj)) if proj.target.is_some() => {
            proj.target.as_deref().expect("guarded by is_some() check")
        }
        _ => vm_target,
    };

    let target_config = if effective_target == "triton" {
        trident::target::TerrainConfig::triton()
    } else {
        match trident::target::TerrainConfig::resolve(effective_target) {
            Ok(config) => config,
            Err(e) => {
                eprintln!("error: {}", e.message);
                process::exit(1);
            }
        }
    };

    let cfg_flags = project
        .and_then(|proj| proj.targets.get(actual_profile))
        .map(|flags| flags.iter().cloned().collect())
        .unwrap_or_else(|| std::collections::BTreeSet::from([actual_profile.to_string()]));

    trident::CompileOptions {
        profile: actual_profile.to_string(),
        cfg_flags,
        target_config,
        dep_dirs: Vec::new(),
    }
}

/// Result of the shared compile โ†’ analyze โ†’ parse โ†’ verify pipeline.
pub struct PreparedArtifact {
    pub project: Option<trident::project::Project>,
    pub entry: PathBuf,
    pub tasm: String,
    pub cost: trident::cost::ProgramCost,
    pub file: trident::ast::File,
    pub name: String,
    pub version: String,
    pub resolved: trident::target::ResolvedTarget,
}

/// Shared pipeline for package and deploy.
pub fn prepare_artifact(
    input: &Path,
    target: &str,
    profile: &str,
    verify: bool,
) -> PreparedArtifact {
    let ri = resolve_input(input);
    let project = ri.project;
    let entry = ri.entry;

    let resolved = match trident::target::ResolvedTarget::resolve(target) {
        Ok(r) => r,
        Err(e) => {
            eprintln!("error: {}", e.message);
            process::exit(1);
        }
    };

    let mut options = resolve_options(&resolved.vm.name, profile, project.as_ref());
    options.target_config = resolved.vm.clone();
    if let Some(ref proj) = project {
        options.dep_dirs = load_dep_dirs(proj);
    }

    eprintln!("Compiling {}...", entry.display());
    let tasm = match trident::compile_project_with_options(&entry, &options) {
        Ok(t) => t,
        Err(_) => {
            eprintln!("error: compilation failed");
            process::exit(1);
        }
    };

    let cost = trident::analyze_costs_project(&entry, &options).unwrap_or_else(|_| {
        eprintln!("warning: cost analysis failed, using zeros");
        trident::cost::ProgramCost {
            program_name: String::new(),
            functions: Vec::new(),
            total: trident::cost::TableCost::ZERO,
            table_names: Vec::new(),
            table_short_names: Vec::new(),
            attestation_hash_rows: 0,
            padded_height: 0,
            estimated_proving_ns: 0,
            loop_bound_waste: Vec::new(),
        }
    });

    let (_, file) = load_and_parse(&entry);

    let (name, version) = match project {
        Some(ref proj) => (proj.name.clone(), proj.version.clone()),
        None => {
            let stem = entry
                .file_stem()
                .and_then(|s| s.to_str())
                .unwrap_or("program");
            (stem.to_string(), "0.1.0".to_string())
        }
    };

    if verify {
        audit_or_exit(&entry);
    }

    PreparedArtifact {
        project,
        entry,
        tasm,
        cost,
        file,
        name,
        version,
        resolved,
    }
}

fn audit_or_exit(entry: &Path) {
    eprintln!("Auditing {}...", entry.display());
    match trident::verify_project(entry) {
        Ok(report) if report.is_safe() => eprintln!("Verification: OK"),
        Ok(report) => {
            eprintln!("error: verification failed\n{}", report.format_report());
            process::exit(1);
        }
        Err(_) => {
            eprintln!("error: verification failed");
            process::exit(1);
        }
    }
}

/// Try to load and parse a .tri file, returning None on error (prints diagnostics).
pub fn try_load_and_parse(path: &Path) -> Option<(String, trident::ast::File)> {
    let source = match std::fs::read_to_string(path) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("error: cannot read '{}': {}", path.display(), e);
            return None;
        }
    };
    let filename = path.to_string_lossy().to_string();
    match trident::parse_source_silent(&source, &filename) {
        Ok(f) => Some((source, f)),
        Err(_) => {
            eprintln!("error: parse errors in '{}'", path.display());
            None
        }
    }
}

/// Load and parse a .tri file, exiting on error.
pub fn load_and_parse(path: &Path) -> (String, trident::ast::File) {
    match try_load_and_parse(path) {
        Some(result) => result,
        None => process::exit(1),
    }
}

/// Open the codebase store, exiting on error.
pub fn open_codebase() -> trident::store::Codebase {
    match trident::store::Codebase::open() {
        Ok(cb) => cb,
        Err(e) => {
            eprintln!("error: cannot open codebase: {}", e);
            process::exit(1);
        }
    }
}

/// Create a registry client with health check, exiting on error.
pub fn registry_client(url: Option<String>) -> trident::registry::RegistryClient {
    let url = url.unwrap_or_else(trident::registry::RegistryClient::default_url);
    let client = trident::registry::RegistryClient::new(&url);
    match client.health() {
        Ok(true) => {}
        Ok(false) => {
            eprintln!("error: registry at {} is not healthy", url);
            process::exit(1);
        }
        Err(e) => {
            eprintln!("error: cannot reach registry at {}: {}", url, e);
            process::exit(1);
        }
    }
    client
}

/// Resolve a registry URL to its default if None.
pub fn registry_url(url: Option<String>) -> String {
    url.unwrap_or_else(trident::registry::RegistryClient::default_url)
}

/// Load dependency search directories from a project's lockfile (if present).
pub fn load_dep_dirs(project: &trident::project::Project) -> Vec<PathBuf> {
    let lock_path = project.root_dir.join("trident.lock");
    if !lock_path.exists() {
        return Vec::new();
    }
    match trident::manifest::load_lockfile(&lock_path) {
        Ok(lockfile) => trident::manifest::dependency_search_paths(&project.root_dir, &lockfile),
        Err(_) => Vec::new(),
    }
}

/// Find a warrior binary on PATH for the given target.
///
/// Resolution order:
/// 1. `trident-<target>` directly on PATH
/// 2. If target has a `[warrior]` config, try `trident-<warrior.name>`
/// 3. If target is an OS, try `trident-<vm>` and the VM's warrior config
pub fn find_warrior(target: &str) -> Option<PathBuf> {
    // Direct match: trident-triton, trident-neptune, trident-trisha
    let direct = format!("trident-{}", target);
    if let Ok(path) = which_on_path(&direct) {
        return Some(path);
    }

    if let Ok(resolved) = trident::target::ResolvedTarget::resolve(target) {
        // Check VM's warrior config
        if let Some(ref warrior) = resolved.vm.warrior {
            // Try prefixed name (trident-<warrior>)
            let warrior_bin = format!("trident-{}", warrior.name);
            if let Ok(path) = which_on_path(&warrior_bin) {
                return Some(path);
            }
            // Try bare warrior name (standalone binary)
            if let Ok(path) = which_on_path(&warrior.name) {
                return Some(path);
            }
        }

        // If target is an OS, also try the VM name directly
        if resolved.os.is_some() {
            let vm_warrior = format!("trident-{}", resolved.vm.name);
            if let Ok(path) = which_on_path(&vm_warrior) {
                return Some(path);
            }
        }
    }

    None
}

/// Look for an executable on PATH (simple, no `which` crate).
fn which_on_path(name: &str) -> Result<PathBuf, ()> {
    let path_var = std::env::var("PATH").unwrap_or_default();
    for dir in path_var.split(':') {
        let candidate = PathBuf::from(dir).join(name);
        if candidate.is_file() {
            return Ok(candidate);
        }
    }
    Err(())
}

/// Delegate a CLI command to a warrior binary.
///
/// Forwards `command` as the first argument, then all `extra_args`.
/// Exits with the warrior's exit code on failure.
pub fn delegate_to_warrior(warrior_bin: &Path, command: &str, extra_args: &[&str]) {
    let mut cmd = std::process::Command::new(warrior_bin);
    cmd.arg(command);
    for arg in extra_args {
        cmd.arg(arg);
    }
    match cmd.status() {
        Ok(status) => {
            if !status.success() {
                process::exit(status.code().unwrap_or(1));
            }
        }
        Err(e) => {
            eprintln!(
                "error: failed to run warrior '{}': {}",
                warrior_bin.display(),
                e
            );
            process::exit(1);
        }
    }
}

pub fn find_program_source(input: &Path) -> Option<PathBuf> {
    if input.is_file() && input.extension().is_some_and(|e| e == "tri") {
        return Some(input.to_path_buf());
    }
    if input.is_dir() {
        let main_tri = input.join("main.tri");
        if main_tri.exists() {
            return Some(main_tri);
        }
    }
    None
}

/// Truncate a hash string to a short prefix for display.
pub fn short_hash(hash: &str) -> &str {
    &hash[..hash.len().min(16)]
}

/// Resolve an input path to a list of .tri files (file or directory), exiting on error.
pub fn resolve_tri_files(input: &Path) -> Vec<PathBuf> {
    if input.is_dir() {
        collect_tri_files(input)
    } else if input.extension().is_some_and(|e| e == "tri") {
        vec![input.to_path_buf()]
    } else {
        eprintln!("error: input must be a .tri file or directory");
        process::exit(1);
    }
}

fn collect_tri_files(dir: &Path) -> Vec<PathBuf> {
    let mut result = Vec::new();
    collect_tri_files_recursive(dir, &mut result, 0);
    result.sort();
    result
}

const MAX_DIR_DEPTH: usize = 64;

fn collect_tri_files_recursive(dir: &Path, result: &mut Vec<PathBuf>, depth: usize) {
    if depth >= MAX_DIR_DEPTH {
        return;
    }

    let entries = match std::fs::read_dir(dir) {
        Ok(e) => e,
        Err(_) => return,
    };

    for entry in entries.flatten() {
        let path = entry.path();
        let name = entry.file_name();
        let name_str = name.to_string_lossy();

        // Skip hidden directories and target/
        if name_str.starts_with('.') || name_str == "target" {
            continue;
        }

        if path.is_dir() {
            collect_tri_files_recursive(&path, result, depth + 1);
        } else if path.extension().is_some_and(|e| e == "tri") {
            result.push(path);
        }
    }
}

Dimensions

trident/src/diagnostic/mod.rs
trident/src/ir/mod.rs
trident/src/deploy/mod.rs
trident/src/syntax/mod.rs
trident/src/api/mod.rs
nebu/rs/extension/mod.rs
optica/src/render/mod.rs
trident/src/config/mod.rs
trident/src/field/mod.rs
optica/src/parser/mod.rs
trident/src/neural/mod.rs
trident/src/cost/mod.rs
trident/src/typecheck/mod.rs
optica/src/server/mod.rs
trident/src/package/mod.rs
optica/src/scanner/mod.rs
optica/src/output/mod.rs
trident/src/verify/mod.rs
optica/src/graph/mod.rs
trident/src/ast/mod.rs
trident/src/lsp/mod.rs
trident/src/runtime/mod.rs
trident/src/gpu/mod.rs
optica/src/query/mod.rs
trident/src/lsp/semantic/mod.rs
trident/src/verify/equiv/mod.rs
trident/src/package/hash/mod.rs
trident/src/neural/training/mod.rs
trident/src/verify/synthesize/mod.rs
trident/src/ir/tir/mod.rs
rs/macros/src/addressed/mod.rs
trident/src/package/registry/mod.rs
rs/rsc/src/lints/mod.rs
trident/src/verify/report/mod.rs
trident/src/config/resolve/mod.rs
trident/src/verify/solve/mod.rs
rs/macros/src/registers/mod.rs
trident/src/verify/smt/mod.rs
rs/macros/src/cell/mod.rs
rs/core/src/fixed_point/mod.rs
trident/src/neural/data/mod.rs
rs/core/src/bounded/mod.rs
trident/src/lsp/util/mod.rs
trident/src/typecheck/tests/mod.rs
trident/src/neural/model/mod.rs
trident/src/cost/stack_verifier/mod.rs
trident/src/syntax/grammar/mod.rs
trident/src/package/manifest/mod.rs
trident/src/syntax/parser/mod.rs
trident/src/ir/kir/mod.rs
trident/src/neural/inference/mod.rs
trident/src/syntax/lexer/mod.rs
trident/src/cost/model/mod.rs
trident/src/ir/lir/mod.rs
trident/src/syntax/format/mod.rs
trident/src/config/scaffold/mod.rs
trident/src/verify/sym/mod.rs
trident/src/api/tests/mod.rs
trident/src/package/store/mod.rs
trident/src/ir/tree/mod.rs
trident/src/ir/kir/lower/mod.rs
trident/src/ir/lir/lower/mod.rs
trident/src/ir/tir/lower/mod.rs
trident/src/ir/tir/builder/mod.rs
trident/src/ir/tir/neural/mod.rs
trident/src/neural/data/tir_graph/mod.rs
trident/src/syntax/parser/tests/mod.rs
cw-cyber/packages/cyber-std/src/tokenfactory/mod.rs
trident/src/ir/tree/lower/mod.rs
trident/src/ir/tir/stack/mod.rs
cw-cyber/contracts/cybernet/src/tests/mod.rs
trident/src/ir/tir/optimize/mod.rs

Local Graph