supercode-cli 0.4.12

supercode — a lightweight, fully-customizable AI coding agent CLI in Rust. Any model via OpenRouter; natively continues Claude Code and Codex sessions.
//! TR-10 dev/06 demo AC: an imported real Claude Code session bearing a
//! multi-KB `Write` tool_use input shows attributed `ToolInputElided`
//! savings in C7's `inspect`/`sessions show-reductions` stats.
//!
//! Follows the `reductions_cli.rs`/`reduced_resume.rs` idiom: spawn the built
//! `supercode` binary against an unreachable `--base-url` with a dummy API
//! key and a fresh, isolated `$SUPERCODE_HOME` per test. `resume --reduced`,
//! `sessions show-reductions`, and `inspect` are all offline (no network
//! activity, no API key actually used).
//!
//! No representative Claude-Code-Write fixture existed under
//! `crates/harness/tests/fixtures/` (checked: only `claude_code_session.jsonl`
//! and `codex_session.jsonl`, neither with a `Write`/large-input call), so
//! this builds one programmatically — the same "fixture built inline" idiom
//! `reductions_cli.rs::write_big_fixture` already uses for its A7 demo,
//! rather than adding a redundant static file.

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

fn bin() -> PathBuf {
    PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}

fn fresh_home(tag: &str) -> PathBuf {
    let nanos = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_nanos();
    let dir = std::env::temp_dir().join(format!(
        "supercode-tr10-cli-{tag}-{}-{nanos}",
        std::process::id()
    ));
    std::fs::create_dir_all(&dir).unwrap();
    dir
}

fn run(home: &Path, extra: &[&str]) -> Output {
    let mut args = vec!["--api-key", "x", "--base-url", "http://127.0.0.1:1"];
    args.extend_from_slice(extra);
    Command::new(bin())
        .env("SUPERCODE_HOME", home)
        .env_remove("OPENROUTER_API_KEY")
        .env_remove("OPENAI_API_KEY")
        .env_remove("ANTHROPIC_API_KEY")
        .args(&args)
        .output()
        .expect("failed to run the supercode binary")
}

fn stdout(out: &Output) -> String {
    String::from_utf8_lossy(&out.stdout).into_owned()
}
fn stderr(out: &Output) -> String {
    String::from_utf8_lossy(&out.stderr).into_owned()
}

/// A representative imported Claude Code session: a user turn asking for a
/// file to be written, an assistant turn issuing Claude's OWN native `Write`
/// tool_use (`file_path`/`content` — NOT this crate's own `write_file`/`path`
/// naming; `session.rs::push_claude_assistant` imports tool names verbatim)
/// with a 20,000-byte `content`, a SUCCESSFUL paired tool_result, and a
/// closing assistant reply — shaped like the project's own
/// `claude_code_session.jsonl` fixture envelope (`type`/`message`/`uuid`/
/// `timestamp`/`sessionId`/`cwd`/`userType`).
fn write_big_write_fixture(dir: &Path) -> (PathBuf, usize) {
    let sid = "77777777-8888-9999-aaaa-bbbbbbbbbbbb";
    let big = "y".repeat(20_000);
    let mut lines: Vec<String> = Vec::new();
    lines.push(
        serde_json::json!({
            "type": "user",
            "message": {"role": "user", "content": "please save the report to reports/out.txt"},
            "uuid": "u0", "parentUuid": null,
            "timestamp": "2026-07-07T18:38:00.000Z", "sessionId": sid,
            "cwd": "/tmp/proj", "userType": "external",
        })
        .to_string(),
    );
    lines.push(
        serde_json::json!({
            "type": "assistant",
            "message": {"role": "assistant", "content": [
                {"type": "tool_use", "id": "toolu_w1", "name": "Write",
                 "input": {"file_path": "reports/out.txt", "content": big}}
            ]},
            "uuid": "a0", "parentUuid": "u0",
            "timestamp": "2026-07-07T18:38:01.000Z", "sessionId": sid,
        })
        .to_string(),
    );
    lines.push(
        serde_json::json!({
            "type": "user",
            "message": {"role": "user", "content": [
                {"tool_use_id": "toolu_w1", "type": "tool_result",
                 "content": [{"type": "text", "text": "File created successfully."}]}
            ]},
            "uuid": "t0", "parentUuid": "a0",
            "timestamp": "2026-07-07T18:38:02.000Z", "sessionId": sid,
            "toolUseResult": {"status": "completed"},
        })
        .to_string(),
    );
    lines.push(
        serde_json::json!({
            "type": "assistant",
            "message": {"role": "assistant", "content": "Done — I saved the report."},
            "uuid": "a1", "parentUuid": "t0",
            "timestamp": "2026-07-07T18:38:03.000Z", "sessionId": sid,
        })
        .to_string(),
    );
    let path = dir.join("claude_write_session.jsonl");
    std::fs::write(&path, lines.join("\n") + "\n").unwrap();
    (path, big.len())
}

/// Mint a reduced store session from `fixture` (immediate EOF, no prompt —
/// no network activity) and return its store name, derived from the sidecar
/// path the C1 banner names (same idiom as `reductions_cli.rs`).
fn mint_reduced_session(home: &Path, fixture: &Path) -> String {
    let out = run(home, &["resume", fixture.to_str().unwrap(), "--reduced"]);
    let err = stderr(&out);
    let line = err
        .lines()
        .find(|l| l.contains("full copy:"))
        .unwrap_or_else(|| panic!("no `full copy:` line in:\n{err}"));
    let sidecar_path = line.split("full copy:").nth(1).unwrap().trim();
    Path::new(sidecar_path)
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .strip_suffix(".sidecar.jsonl")
        .unwrap()
        .to_string()
}

#[test]
fn dev06_imported_claude_write_session_shows_attributed_tool_input_savings() {
    let home = fresh_home("demo");
    let (fixture, content_len) = write_big_write_fixture(&home);
    let name = mint_reduced_session(&home, &fixture);

    // ---- `sessions show-reductions`: a `tool-input` row, byte-attributed. ----
    let show = run(&home, &["sessions", "show-reductions", &name]);
    assert!(
        show.status.success(),
        "show-reductions must exit 0: {}",
        stderr(&show)
    );
    let table = stdout(&show);
    assert!(
        table.contains("tool-input"),
        "show-reductions must list a tool-input row:\n{table}"
    );
    assert!(
        table.contains("20,000"),
        "the row must attribute the full elided payload size:\n{table}"
    );

    let json_show = run(&home, &["sessions", "show-reductions", &name, "--json"]);
    assert!(json_show.status.success());
    let log: serde_json::Value = serde_json::from_str(&stdout(&json_show)).unwrap();
    let reductions = log["reductions"].as_array().unwrap();
    assert_eq!(reductions.len(), 1, "exactly one reduction expected: {log}");
    let kind = &reductions[0]["kind"];
    assert!(
        kind.get("ToolInputElided").is_some(),
        "reduction kind must be ToolInputElided: {kind}"
    );
    assert_eq!(
        kind["ToolInputElided"]["original_bytes"].as_u64().unwrap() as usize,
        content_len,
        "original_bytes must equal the elided Write content's true length"
    );
    assert_eq!(kind["ToolInputElided"]["field"], "content");
    assert_eq!(kind["ToolInputElided"]["call_id"], "toolu_w1");

    // ---- `inspect`: aggregate savings reflect the elision (C7). ----
    let insp = run(&home, &["inspect", &name]);
    assert!(
        insp.status.success(),
        "inspect must exit 0: {}",
        stderr(&insp)
    );
    let text = stdout(&insp);
    assert!(text.contains("reduced"), "missing `reduced` row:\n{text}");
    assert!(text.contains("1 stubs"), "missing stub count of 1:\n{text}");
    assert!(
        text.contains("⊟ reduced"),
        "the Write assistant row must carry the reduced tag \
         (arguments-side stub, not `m.content`):\n{text}"
    );

    // The view must be measurably smaller than the full session — proof the
    // savings are real, not just a cosmetic stub with no attributed bytes.
    let reduced_line = text
        .lines()
        .find(|l| l.contains("reduced") && l.contains("view"))
        .unwrap_or_else(|| panic!("no reduced/view summary line:\n{text}"));
    assert!(
        reduced_line.contains('%'),
        "expected a view/full percentage: {reduced_line}"
    );
    let pct: i64 = reduced_line
        .rsplit('(')
        .next()
        .and_then(|s| s.strip_suffix("%)"))
        .and_then(|s| s.trim().parse().ok())
        .unwrap_or_else(|| panic!("could not parse pct from: {reduced_line}"));
    assert!(
        pct < 50,
        "a 20,000-byte elided Write body out of a small session must show a \
         large reduction: {reduced_line}"
    );

    std::fs::remove_dir_all(&home).ok();
}

#[test]
fn dev06_convert_of_the_same_session_leaks_nothing_and_restores_original_write() {
    let home = fresh_home("demo-convert");
    let (fixture, _content_len) = write_big_write_fixture(&home);
    let name = mint_reduced_session(&home, &fixture);

    let out_path = home.join("as-codex.jsonl");
    let conv = run(
        &home,
        &[
            "convert",
            &name,
            "--to",
            "codex",
            "-o",
            out_path.to_str().unwrap(),
        ],
    );
    assert!(
        conv.status.success(),
        "convert must succeed: {}",
        stderr(&conv)
    );
    let written = std::fs::read_to_string(&out_path).unwrap();
    assert_eq!(
        written.matches("sc-reduced").count(),
        0,
        "export must contain zero 'sc-reduced' occurrences (A11 leak guard)"
    );
    // The full original 20,000-byte write body must be present verbatim in
    // the export (A11: export always reads the sidecar, never the stub).
    assert!(
        written.contains(&"y".repeat(20_000)),
        "export must contain the ORIGINAL Write content, not the stub"
    );

    std::fs::remove_dir_all(&home).ok();
}