supercode-cli 0.4.6

supercode — a lightweight, fully-customizable AI coding agent CLI in Rust. Any model via OpenRouter; natively continues Claude Code and Codex sessions.
use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

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

fn core_fixture(name: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("../harness/tests/fixtures")
        .join(name)
}

fn fresh_dir(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-watch-cli-{tag}-{}-{nanos}",
        std::process::id()
    ));
    std::fs::create_dir_all(&dir).unwrap();
    dir
}

#[test]
fn watch_prints_one_clean_initial_ndjson_event_for_every_supported_harness() {
    let cases = [
        ("claude_code_session.jsonl", "claude_code"),
        ("codex_session.jsonl", "codex"),
        ("pi_session_live_corpus.jsonl", "pi"),
        ("opencode_fixture/opencode.db", "opencode"),
    ];
    for (fixture, source) in cases {
        let output = Command::new(bin())
            .arg("watch")
            .arg(core_fixture(fixture))
            .args(["--max-events", "1", "--poll-ms", "10"])
            .stdin(Stdio::null())
            .output()
            .unwrap();
        assert!(
            output.status.success(),
            "{}\nstdout: {}\nstderr: {}",
            fixture,
            String::from_utf8_lossy(&output.stdout),
            String::from_utf8_lossy(&output.stderr)
        );
        assert!(output.stderr.is_empty(), "{fixture}");
        let line = String::from_utf8(output.stdout).unwrap();
        assert_eq!(line.lines().count(), 1, "{fixture}");
        let event: serde_json::Value = serde_json::from_str(&line).unwrap();
        assert_eq!(event["type"], "session_snapshot", "{fixture}");
        assert_eq!(event["sequence"], 1, "{fixture}");
        assert_eq!(event["session"]["source"], source, "{fixture}");
    }
}

#[test]
fn a_running_watch_process_observes_a_concurrent_append() {
    let dir = fresh_dir("live");
    let path = dir.join("session.jsonl");
    std::fs::write(
        &path,
        concat!(
            r#"{"type":"user","message":{"role":"user","content":"one"},"uuid":"u1","parentUuid":null,"sessionId":"s1"}"#,
            "\n"
        ),
    )
    .unwrap();

    let mut child = Command::new(bin())
        .arg("watch")
        .arg(&path)
        .args(["--max-events", "2", "--poll-ms", "10"])
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .unwrap();
    let stdout = child.stdout.take().unwrap();
    let mut lines = BufReader::new(stdout).lines();

    let initial: serde_json::Value = serde_json::from_str(&lines.next().unwrap().unwrap()).unwrap();
    assert_eq!(initial["type"], "session_snapshot");
    assert_eq!(initial["sequence"], 1);

    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(&path)
        .unwrap();
    file.write_all(
        concat!(
            r#"{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"two"}]},"uuid":"a1","parentUuid":"u1","sessionId":"s1"}"#,
            "\n"
        )
        .as_bytes(),
    )
    .unwrap();
    file.flush().unwrap();

    let appended: serde_json::Value =
        serde_json::from_str(&lines.next().unwrap().unwrap()).unwrap();
    assert_eq!(appended["type"], "messages_appended");
    assert_eq!(appended["sequence"], 2);
    assert_eq!(appended["messages"][0]["content"], "two");

    let status = child.wait().unwrap();
    assert!(status.success());
    std::fs::remove_dir_all(dir).ok();
}