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-14 acceptance: `supercode channels list|status` against the
//! committed Hermes and OpenClaw fixture homes, through the real binary.
//!
//! The rows are the `harness.v1.channels.list` rows verbatim, so this test
//! also pins the CLI's `--json` contract to the RPC's — and proves, on the
//! surface a human actually reads, that no credential is ever printed.

use std::path::PathBuf;
use std::process::Command;

/// The FAKE credential strings the fixture homes hold. No supercode output
/// may ever contain one.
const FIXTURE_SECRETS: &[&str] = &[
    "FAKE-TOKEN-DO-NOT-EMIT",
    "FAKE-API-SERVER-KEY-DO-NOT-EMIT",
    "FAKE-SLACK-BOT-TOKEN-DO-NOT-EMIT",
    "FAKE-SLACK-APP-TOKEN-DO-NOT-EMIT",
    "FAKE-TELEGRAM-TOKEN-DO-NOT-EMIT",
];

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

/// The harness crate's fixture homes: `<workspace>/crates/harness/tests/fixtures`.
fn fixtures() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../harness/tests/fixtures")
        .canonicalize()
        .unwrap()
}

fn command() -> Command {
    let fixtures = fixtures();
    let mut command = Command::new(bin());
    // HERMES_HOME names the home whose `config.yaml` and `state.db` supercode
    // reads; OPENCLAW_STATE_DIR names openclaw's state directory directly
    // (the same env semantics openclaw itself uses).
    command
        .env("HERMES_HOME", fixtures.join("hermes_home"))
        .env("OPENCLAW_STATE_DIR", fixtures.join("openclaw_home"));
    // Hermes enables a platform from its credential env var alone, so the
    // build box's own environment would otherwise add rows to this listing.
    for var in [
        "TELEGRAM_BOT_TOKEN",
        "DISCORD_BOT_TOKEN",
        "SLACK_BOT_TOKEN",
        "SIGNAL_HTTP_URL",
        "MATTERMOST_TOKEN",
        "MATRIX_ACCESS_TOKEN",
        "MATRIX_PASSWORD",
        "HASS_TOKEN",
        "TWILIO_ACCOUNT_SID",
        "GATEWAY_RELAY_URL",
        "API_SERVER_KEY",
    ] {
        command.env_remove(var);
    }
    command
}

fn run(args: &[&str]) -> String {
    let output = command()
        .args(args)
        .output()
        .expect("supercode binary runs");
    assert!(
        output.status.success(),
        "`{}` failed: {}",
        args.join(" "),
        String::from_utf8_lossy(&output.stderr)
    );
    let stdout = String::from_utf8(output.stdout).unwrap();
    for secret in FIXTURE_SECRETS {
        assert!(
            !stdout.contains(secret),
            "`{secret}` leaked into `supercode {}`:\n{stdout}",
            args.join(" ")
        );
    }
    stdout
}

fn row<'a>(value: &'a serde_json::Value, harness: &str, name: &str) -> &'a serde_json::Value {
    value["channels"]
        .as_array()
        .expect("channels array")
        .iter()
        .find(|row| row["harness"] == harness && row["name"] == name)
        .unwrap_or_else(|| panic!("no `{harness}` channel `{name}` in {value}"))
}

#[test]
fn channels_list_json_carries_both_harnesses_in_one_row_shape() {
    let stdout = run(&["channels", "list", "--json"]);
    let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
    assert_eq!(value["schema"], "supercode.channels.v1");

    // Hermes: `platforms.<platform>` blocks. `sessions` is the discovery
    // count for that surface platform, not a config field.
    let telegram = row(&value, "hermes", "telegram");
    assert_eq!(telegram["kind"], "telegram");
    assert_eq!(telegram["enabled"], true);
    assert_eq!(telegram["configured"], true);
    assert_eq!(telegram["sessions"], 2);
    let api = row(&value, "hermes", "api_server");
    assert_eq!(api["configured"], true);
    assert_eq!(api["sessions"], 0);
    assert_eq!(row(&value, "hermes", "webhook")["enabled"], false);

    // OpenClaw: one row per account under `channels.<name>.accounts`.
    let linked = row(&value, "openclaw", "slack/T0FIXTURE");
    assert_eq!(linked["kind"], "slack");
    assert_eq!(linked["account"], "T0FIXTURE");
    assert_eq!(linked["configured"], true);
    let unlinked = row(&value, "openclaw", "slack/T1FIXTURE");
    assert_eq!(unlinked["enabled"], false);
    assert_eq!(unlinked["configured"], false);
    assert_eq!(
        row(&value, "openclaw", "telegram")["account"],
        "hermes-fixture-bot"
    );

    // Nothing claims a connection state from a config file.
    for row in value["channels"].as_array().unwrap() {
        assert_eq!(row["status"], "unknown", "{row}");
    }
}

#[test]
fn channels_list_filters_by_harness_and_prints_a_table() {
    let stdout = run(&["channels", "list", "--harness", "openclaw"]);
    let header = stdout.lines().next().unwrap();
    for column in [
        "HARNESS", "NAME", "KIND", "ACCOUNT", "ENABLED", "STATUS", "SESSIONS",
    ] {
        assert!(header.contains(column), "missing `{column}` in `{header}`");
    }
    assert!(stdout.contains("slack/T0FIXTURE"), "{stdout}");
    assert!(stdout.contains("T1FIXTURE"), "{stdout}");
    assert!(
        !stdout.contains("hermes "),
        "harness filter leaked: {stdout}"
    );
}

#[test]
fn channels_status_reads_one_row() {
    let stdout = run(&[
        "channels",
        "status",
        "--harness",
        "hermes",
        "api_server",
        "--json",
    ]);
    let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
    assert_eq!(value["schema"], "supercode.channels.v1");
    assert_eq!(value["channel"]["name"], "api_server");
    assert_eq!(value["channel"]["kind"], "api_server");
    assert_eq!(value["channel"]["configured"], true);
    assert_eq!(value["channel"]["status"], "unknown");

    // The human form names the same facts without the credential that
    // decided `configured`.
    let human = run(&["channels", "status", "--harness", "hermes", "api_server"]);
    assert!(human.contains("configured: yes"), "{human}");
    assert!(human.contains("status:     unknown"), "{human}");
}

/// Hermes enables a platform from the environment alone, so an env-only
/// install is listed — by the var's PRESENCE. The value never appears.
#[test]
fn an_env_only_hermes_platform_is_listed_without_its_value() {
    let output = command()
        .env("SIGNAL_HTTP_URL", "http://127.0.0.1:65535/env-only-probe")
        .args(["channels", "list", "--harness", "hermes", "--json"])
        .output()
        .unwrap();
    assert!(output.status.success());
    let stdout = String::from_utf8(output.stdout).unwrap();
    let value: serde_json::Value = serde_json::from_str(&stdout).unwrap();
    let signal = row(&value, "hermes", "signal");
    assert_eq!(signal["enabled"], true);
    assert_eq!(signal["configured"], true);
    assert!(
        !stdout.contains("env-only-probe"),
        "the env var's VALUE was emitted: {stdout}"
    );
}

/// A verb a harness lacks fails, never a silent empty table. Claude Code has
/// channels, but declares them over the MCP protocol rather than in a file.
#[test]
fn unsupported_harness_is_refused() {
    for harness in ["claude-code", "codex"] {
        let output = command()
            .args(["channels", "list", "--harness", harness])
            .output()
            .unwrap();
        assert!(!output.status.success(), "{harness} must be refused");
        let stderr = String::from_utf8_lossy(&output.stderr);
        assert!(
            stderr.contains("has no channel concept"),
            "unexpected refusal for {harness}: {stderr}"
        );
    }
}