aicx 0.6.6

Operator CLI + MCP server: canonical corpus first, optional semantic index second (Claude Code, Codex, Gemini)
Documentation
use serde_json::{Value, json};
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH};

fn unique_test_dir(name: &str) -> PathBuf {
    std::env::temp_dir().join(format!(
        "aicx-runtime-reports-{name}-{}-{}",
        std::process::id(),
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("system time before unix epoch")
            .as_nanos()
    ))
}

fn write_file(path: &Path, content: &str) {
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).expect("create parent directories");
    }
    fs::write(path, content).expect("write file");
}

fn current_profile_dir() -> PathBuf {
    let test_exe = std::env::current_exe().expect("resolve current test executable");
    test_exe
        .parent()
        .and_then(Path::parent)
        .expect("resolve cargo profile dir")
        .to_path_buf()
}

fn fallback_aicx_path() -> PathBuf {
    let mut path = current_profile_dir().join("aicx");
    if cfg!(windows) {
        path.set_extension("exe");
    }
    path
}

fn ensure_aicx_binary_exists() -> PathBuf {
    static BIN_PATH: OnceLock<PathBuf> = OnceLock::new();

    BIN_PATH
        .get_or_init(|| {
            if let Some(env_path) = std::env::var_os("CARGO_BIN_EXE_aicx").map(PathBuf::from)
                && env_path.is_file()
            {
                return env_path;
            }

            let env_path = PathBuf::from(env!("CARGO_BIN_EXE_aicx"));
            if env_path.is_file() {
                return env_path;
            }

            let fallback = fallback_aicx_path();
            if fallback.is_file() {
                return fallback;
            }

            let cargo = std::env::var_os("CARGO")
                .map(PathBuf::from)
                .unwrap_or_else(|| PathBuf::from("cargo"));
            let output = Command::new(&cargo)
                .args(["build", "--locked", "--bin", "aicx"])
                .current_dir(env!("CARGO_MANIFEST_DIR"))
                .output()
                .expect("build fallback aicx binary");

            assert!(
                output.status.success(),
                "fallback cargo build --bin aicx failed\nstatus: {}\nstdout:\n{}\nstderr:\n{}",
                output.status,
                String::from_utf8_lossy(&output.stdout),
                String::from_utf8_lossy(&output.stderr)
            );
            assert!(
                fallback.is_file(),
                "fallback cargo build succeeded but binary missing at {}",
                fallback.display()
            );

            fallback
        })
        .clone()
}

fn run_aicx(home: &Path, args: &[&str]) -> Output {
    fs::create_dir_all(home).expect("create temp HOME");
    Command::new(ensure_aicx_binary_exists())
        .args(args)
        .env("HOME", home)
        .output()
        .expect("run aicx")
}

fn assert_success(output: &Output) {
    assert!(
        output.status.success(),
        "command failed\nstatus: {}\nstdout:\n{}\nstderr:\n{}",
        output.status,
        String::from_utf8_lossy(&output.stdout),
        String::from_utf8_lossy(&output.stderr)
    );
}

#[test]
fn reports_builds_html_and_default_bundle_from_vibecrafted_artifacts() {
    let root = unique_test_dir("reports-extractor");
    let home = root.join("home");
    let artifacts_root = root.join("artifacts");
    let repo_root = artifacts_root.join("VetCoders").join("ai-contexters");
    let html_output = root.join("out").join("report-explorer.html");
    let bundle_output = root.join("out").join("report-explorer.bundle.json");

    write_file(
        &repo_root
            .join("2026_0412")
            .join("reports")
            .join("20260412_report-artifacts_codex.md"),
        "---\nagent: codex\nrun_id: wf-20260412-001\nprompt_id: report-artifacts\nstatus: completed\ncreated: 2026-04-12T20:11:06+02:00\nskill_code: vc-workflow\n---\n# Report Artifacts Dashboard\n## Findings\n- build standalone HTML\n",
    );
    write_file(
        &repo_root
            .join("2026_0412")
            .join("reports")
            .join("20260412_report-artifacts_codex.meta.json"),
        r#"{
  "status": "completed",
  "agent": "codex",
  "run_id": "wf-20260412-001",
  "prompt_id": "report-artifacts",
  "duration_s": 12.5,
  "skill_code": "impl"
}"#,
    );
    write_file(
        &repo_root
            .join("2026_0411")
            .join("marbles")
            .join("reports")
            .join("20260411_1316_marbles-ancestor_L1_codex.meta.json"),
        &json!({
            "status": "launching",
            "agent": "codex",
            "run_id": "marb-131611-001",
            "prompt_id": "marbles-ancestor_L1_20260411",
            "transcript": repo_root
                .join("2026_0411")
                .join("marbles")
                .join("reports")
                .join("20260411_1316_marbles-ancestor_L1_codex.transcript.log")
                .display()
                .to_string()
        })
        .to_string(),
    );
    write_file(
        &repo_root
            .join("2026_0411")
            .join("marbles")
            .join("reports")
            .join("20260411_1316_marbles-ancestor_L1_codex.transcript.log"),
        "[13:16:11] assistant: booting artifact scan\n",
    );

    let output = run_aicx(
        &home,
        &[
            "reports",
            "--artifacts-root",
            &artifacts_root.display().to_string(),
            "--org",
            "VetCoders",
            "--repo",
            "ai-contexters",
            "--date-from",
            "2026-04-11",
            "--date-to",
            "2026-04-12",
            "--output",
            &html_output.display().to_string(),
        ],
    );
    assert_success(&output);

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains(&html_output.display().to_string()));
    assert!(html_output.exists());
    assert!(bundle_output.exists());

    let html = fs::read_to_string(&html_output).expect("read generated html");
    assert!(html.contains("Workflow Report Explorer"));
    assert!(html.contains("Import JSON Bundle"));

    let bundle: Value =
        serde_json::from_str(&fs::read_to_string(&bundle_output).expect("read bundle"))
            .expect("parse bundle");
    assert_eq!(bundle["stats"]["total_records"].as_u64(), Some(2));
    assert_eq!(bundle["stats"]["completed_records"].as_u64(), Some(1));
    assert_eq!(bundle["stats"]["incomplete_records"].as_u64(), Some(1));
    let workflows = bundle["records"]
        .as_array()
        .expect("records array")
        .iter()
        .map(|record| {
            record["workflow"]
                .as_str()
                .expect("workflow string")
                .to_string()
        })
        .collect::<Vec<_>>();
    assert!(
        workflows
            .iter()
            .any(|workflow| workflow == "report-artifacts")
    );
    assert!(!workflows.iter().any(|workflow| workflow == "day-root"));

    let _ = fs::remove_dir_all(&root);
}