use std::path::PathBuf;
use std::process::{Command, Output};
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn hermes_home() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../harness/tests/fixtures/hermes_home")
}
fn run(extra: &[&str]) -> Output {
let home = std::env::temp_dir().join(format!(
"supercode-orch6-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&home).unwrap();
let output = Command::new(bin())
.env("SUPERCODE_HOME", &home)
.env("HERMES_HOME", hermes_home())
.env("NO_COLOR", "1")
.env_remove("OPENROUTER_API_KEY")
.args(extra)
.stdin(std::process::Stdio::null())
.output()
.expect("supercode binary runs");
let _ = std::fs::remove_dir_all(&home);
output
}
fn stdout(extra: &[&str]) -> String {
let output = run(extra);
assert!(
output.status.success(),
"`supercode {}` failed: {}",
extra.join(" "),
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).unwrap()
}
#[test]
fn sessions_list_shows_surface_trigger_and_profile_for_a_harness() {
let table = stdout(&["sessions", "list", "--harness", "hermes"]);
let dm = table
.lines()
.find(|line| line.contains("tg-dm-1"))
.unwrap_or_else(|| panic!("no `tg-dm-1` row in:\n{table}"));
assert!(dm.contains("telegram:dm:123456"), "{dm}");
assert!(dm.contains("channel"), "{dm}");
let fire = table
.lines()
.find(|line| line.contains("cron_job42_20260902_120000"))
.unwrap_or_else(|| panic!("no cron row in:\n{table}"));
assert!(fire.contains("cron"), "{fire}");
let coder = table
.lines()
.find(|line| line.contains("tg-coder-1"))
.unwrap_or_else(|| panic!("no `tg-coder-1` row in:\n{table}"));
assert!(coder.contains("telegram:group:-100777:55"), "{coder}");
assert!(coder.contains("coder"), "{coder}");
let acp = table
.lines()
.find(|line| line.contains("cef97234-e8e8-428a-99ab-e8fff4e7e613"))
.unwrap_or_else(|| panic!("no ACP row in:\n{table}"));
assert!(acp.contains("human"), "{acp}");
}
#[test]
fn profile_filter_selects_only_conversations_routed_through_it() {
let filtered = stdout(&[
"sessions",
"list",
"--harness",
"hermes",
"--profile",
"coder",
]);
assert!(filtered.contains("tg-coder-1"), "{filtered}");
assert!(!filtered.contains("tg-dm-1"), "{filtered}");
assert!(!filtered.contains("cron_job42"), "{filtered}");
let empty = stdout(&[
"sessions",
"list",
"--harness",
"hermes",
"--profile",
"nobody",
]);
assert!(!empty.contains("tg-coder-1"), "{empty}");
assert!(empty.contains("nobody"), "{empty}");
}
#[test]
fn harness_filter_scopes_the_listing_to_that_store() {
let other = stdout(&["sessions", "list", "--harness", "openclaw"]);
assert!(!other.contains("tg-dm-1"), "{other}");
}
#[test]
fn json_rows_carry_the_same_nouns_as_the_rpc() {
let rendered = stdout(&[
"sessions",
"list",
"--harness",
"hermes",
"--profile",
"coder",
"--json",
]);
let rows: serde_json::Value = serde_json::from_str(&rendered).unwrap();
let row = &rows[0];
assert_eq!(row["locator"]["session_id"], "tg-coder-1");
assert_eq!(row["trigger"], "channel");
assert_eq!(row["profile"], "coder");
assert_eq!(row["surface"]["platform"], "telegram");
assert_eq!(row["surface"]["thread_id"], "55");
assert_eq!(row["cross_surface"]["state"], "pending");
assert_eq!(row["cross_surface"]["platform"], "discord");
assert_eq!(row["workspace"]["kind"], "repo");
assert_eq!(row["workspace"]["value"], "/workspace/project");
}
#[test]
fn plain_sessions_list_still_lists_supercode_saved_sessions() {
let table = stdout(&["sessions", "list"]);
assert!(table.contains("no saved sessions yet"), "{table}");
assert!(!table.contains("tg-dm-1"), "{table}");
}