supercode-cli 0.4.19

supercode — a lightweight, fully-customizable AI coding agent CLI in Rust. Any model via OpenRouter; natively continues Claude Code and Codex sessions.
//! ORCH-7 CLI acceptance: `supercode jobs list|get` over the committed
//! fixtures.
//!
//! The harness homes are pointed at `crates/harness/tests/fixtures` through the
//! same environment variables a real install uses (`CLAUDE_CONFIG_DIR`,
//! `HERMES_HOME`, `OPENCLAW_STATE_DIR`), so the spawned binary reads exactly
//! the paths the loader reads on a machine — nothing is injected past the
//! product's own door. Every invocation is offline and read-only.

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

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

fn fixtures() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../harness/tests/fixtures")
}

fn run(args: &[&str]) -> Output {
    let fixtures = fixtures();
    Command::new(bin())
        .env("CLAUDE_CONFIG_DIR", fixtures.join("claude_jobs_home"))
        .env("HERMES_HOME", fixtures.join("hermes_home"))
        .env("OPENCLAW_STATE_DIR", fixtures.join("openclaw_home"))
        .args(args)
        .output()
        .expect("supercode binary runs")
}

fn json_of(output: &Output) -> serde_json::Value {
    assert!(
        output.status.success(),
        "command failed: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    serde_json::from_slice(&output.stdout).expect("stdout is the RPC result verbatim")
}

#[test]
fn jobs_list_json_returns_the_rpc_rows_for_all_three_stores() {
    let result = json_of(&run(&["jobs", "list", "--json"]));
    let ids: Vec<&str> = result["jobs"]
        .as_array()
        .unwrap()
        .iter()
        .map(|job| job["id"].as_str().unwrap())
        .collect();
    assert_eq!(
        ids,
        vec![
            "release-watch",
            "toolu_wake_recheck",
            "digest-15m",
            "nightly-audit",
            "coder-standup",
            "ops-once-boot",
            // OpenClaw's PINNED store is `cron_jobs` in the shared state DB;
            // the legacy `cron/jobs.json` beside it is read second, so an
            // un-migrated install still answers. Four rows, two stores.
            "85ad7832-896f-42be-af31-3e1ed2fbdc4b",
            "8bb7d938-ca46-4a6d-90eb-c92331155566",
            "cron_standup",
            "cron_reindex",
        ],
        "{result}"
    );
    // The rows are the RPC's, verbatim: every documented column is present.
    let standup = result["jobs"]
        .as_array()
        .unwrap()
        .iter()
        .find(|job| job["id"] == "cron_standup")
        .unwrap();
    assert_eq!(standup["harness"], "openclaw");
    assert_eq!(standup["scope"], "install");
    assert_eq!(standup["session_target"], "isolated");
    // ORCH-13: the mode word and the channel it announces on are separate.
    assert_eq!(standup["deliver"]["mode"], "announce");
    assert_eq!(standup["deliver"]["target"], "slack");
    assert_eq!(standup["deliver"]["chat_id"], "C0429ABCD");
    assert_eq!(standup["schedule"]["display"], "30 8 * * 1-5");
    assert!(result["sources"].as_array().unwrap().len() >= 4, "{result}");
}

#[test]
fn jobs_list_table_carries_the_eight_declared_columns() {
    let output = run(&["jobs", "list", "--harness", "hermes"]);
    assert!(output.status.success());
    let text = String::from_utf8_lossy(&output.stdout);
    let header = text.lines().next().unwrap();
    for column in [
        "HARNESS",
        "ID",
        "SCOPE",
        "SCHEDULE",
        "PAYLOAD",
        "NEXT_RUN",
        "DELIVERY",
        "LAST_STATUS",
    ] {
        assert!(header.contains(column), "header `{header}` lacks {column}");
    }
    assert!(text.contains("digest-15m"), "{text}");
    assert!(text.contains("every 15 min"), "{text}");
    // ORCH-13: the delivery cell names where the job's output goes — the
    // `deliver` word and the chat (with its thread) it is addressed to.
    assert!(text.contains("origin \u{2192} -100777:55"), "{text}");
    assert!(
        !text.contains("cron_standup"),
        "--harness must filter: {text}"
    );
}

#[test]
fn jobs_get_json_carries_the_row_and_the_native_record() {
    let result = json_of(&run(&[
        "jobs",
        "get",
        "--harness",
        "openclaw",
        "cron_standup",
        "--json",
    ]));
    assert_eq!(result["job"]["id"], "cron_standup");
    assert_eq!(result["job"]["payload"]["kind"], "prompt");
    // The native record survives beside the uniform row.
    assert_eq!(result["source"]["name"], "standup");
    assert_eq!(result["source"]["delivery"]["channel"], "slack");
}

#[test]
fn a_harness_without_scheduled_jobs_fails_instead_of_listing_nothing() {
    let output = run(&["jobs", "list", "--harness", "codex", "--json"]);
    assert!(
        !output.status.success(),
        "codex has no scheduled-job concept; an empty list would be a silent no-op"
    );
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(stderr.contains("has no scheduled jobs"), "{stderr}");
}