use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
use supercode::{ChatMessage, SessionStore};
fn bin() -> &'static str {
env!("CARGO_BIN_EXE_supercode")
}
fn temp_home(label: &str) -> PathBuf {
let nonce = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let home = std::env::temp_dir().join(format!(
"supercode-resume-id-cli-{label}-{}-{nonce}",
std::process::id()
));
fs::create_dir_all(&home).unwrap();
home
}
fn write_claude(path: &Path, id: &str, malformed_tail: bool) {
fs::create_dir_all(path.parent().unwrap()).unwrap();
let mut text = format!(
"{{\"type\":\"user\",\"sessionId\":{},\"cwd\":\"/tmp\",\"message\":{{\"role\":\"user\",\"content\":\"hi\"}}}}\n",
serde_json::to_string(id).unwrap()
);
if malformed_tail {
text.push_str("{truncated\n");
}
fs::write(path, text).unwrap();
}
fn write_codex(path: &Path, id: &str) {
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(
path,
format!(
"{{\"timestamp\":\"2026-01-01T00:00:00Z\",\"type\":\"session_meta\",\"payload\":{{\"id\":{},\"cwd\":\"/tmp\"}}}}\n",
serde_json::to_string(id).unwrap()
),
)
.unwrap();
}
fn run(home: &Path, input: &str) -> std::process::Output {
Command::new(bin())
.env("HOME", home)
.env("SUPERCODE_HOME", home.join("supercode-home"))
.env_remove("CLAUDE_CONFIG_DIR")
.env_remove("CODEX_HOME")
.env_remove("PI_CODING_AGENT_SESSION_DIR")
.env_remove("PI_CODING_AGENT_DIR")
.env_remove("OPENCODE_DB")
.env_remove("XDG_DATA_HOME")
.env_remove("GROK_HOME")
.env_remove("OPENROUTER_API_KEY")
.args(["--quiet", "resume", input])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("run supercode")
}
fn run_dry(home: &Path, input: &str) -> std::process::Output {
run_dry_with(home, input, &[])
}
fn run_dry_with(home: &Path, input: &str, extra: &[&str]) -> std::process::Output {
let mut args = vec![
"--quiet",
"--model",
"z-ai/glm-5.2",
"--reduced",
"resume",
input,
"--dry-run",
];
args.extend_from_slice(extra);
Command::new(bin())
.env("HOME", home)
.env("SUPERCODE_HOME", home.join("supercode-home"))
.env_remove("OPENROUTER_API_KEY")
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("run supercode dry resume")
}
#[test]
fn dry_run_loads_named_and_full_path_supercode_store_sessions() {
let home = temp_home("supercode-store");
let store = SessionStore::open(home.join("supercode-home/sessions")).unwrap();
let name = "chosen-store-session";
let messages = [
ChatMessage::system("stored system"),
ChatMessage::user("stored request"),
ChatMessage::assistant("stored response"),
];
let jsonl = messages
.iter()
.map(|message| serde_json::to_string(message).unwrap())
.collect::<Vec<_>>()
.join("\n");
store.save(name, "chosen", &jsonl).unwrap();
for input in [
name.to_string(),
store.session_path(name).unwrap().display().to_string(),
] {
let output = run_dry(&home, &input);
assert!(
output.status.success(),
"input={input}; stderr={}",
String::from_utf8_lossy(&output.stderr)
);
let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(report["source"], "Native");
assert_eq!(report["replay_message_count"], messages.len());
assert_eq!(report["provider_request_sent"], false);
assert_eq!(report["store_written"], false);
}
fs::remove_dir_all(home).ok();
}
#[test]
fn named_resume_honors_the_configured_session_directory() {
let home = temp_home("configured-supercode-store");
let redirected = home.join("redirected-sessions");
let config_home = home.join("supercode-home");
fs::create_dir_all(&config_home).unwrap();
fs::write(
config_home.join("config.toml"),
format!(
"[core.session]\ndir = {}\n",
serde_json::to_string(redirected.to_str().unwrap()).unwrap()
),
)
.unwrap();
let store = SessionStore::open(&redirected).unwrap();
let name = "redirected-session";
let message = ChatMessage::user("loaded from configured store");
store
.save(
name,
"redirected",
&serde_json::to_string(&message).unwrap(),
)
.unwrap();
let output = run_dry(&home, name);
assert!(
output.status.success(),
"{}",
String::from_utf8_lossy(&output.stderr)
);
let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(report["replay_message_count"], 1);
assert!(!config_home.join("sessions").exists());
fs::remove_dir_all(home).ok();
}
#[test]
fn ambiguous_native_id_requires_harness_disambiguation() {
let home = temp_home("collision");
write_claude(
&home.join(".claude/projects/project/shared.jsonl"),
"shared-id",
false,
);
write_codex(
&home.join(".codex/sessions/2026/07/shared.jsonl"),
"shared-id",
);
let output = run(&home, "shared-id");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("ambiguous across harnesses"), "{stderr}");
assert!(stderr.contains("--harness"), "{stderr}");
assert!(stderr.contains("claude-code"), "{stderr}");
assert!(stderr.contains("codex"), "{stderr}");
fs::remove_dir_all(home).ok();
}
#[test]
fn existing_path_wins_over_the_same_catalog_id() {
let home = temp_home("path-precedence");
let explicit = home.join("explicit.jsonl");
write_claude(&explicit, "explicit-source", true);
write_codex(
&home.join(".codex/sessions/2026/07/path-id.jsonl"),
explicit.to_str().unwrap(),
);
let output = run(&home, explicit.to_str().unwrap());
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("refusing to continue"), "{stderr}");
assert!(stderr.contains("no provider call was made"), "{stderr}");
assert!(!stderr.contains("no discovered"), "{stderr}");
fs::remove_dir_all(home).ok();
}
#[test]
fn dry_run_restores_claude_context_and_runtime_without_key_or_writes() {
let home = temp_home("dry-run");
let project = home.join("fleet");
fs::create_dir_all(project.join(".claude/agents")).unwrap();
fs::create_dir_all(home.join(".claude")).unwrap();
fs::write(home.join(".claude/CLAUDE.md"), "GLOBAL RULE").unwrap();
fs::write(
project.join(".claude/agents/pilot-tick.md"),
"---\nname: pilot-tick\ntools: Bash, Read\nmodel: sonnet\n---\nPilot.\n",
)
.unwrap();
let transcript = home.join("session.jsonl");
fs::write(
&transcript,
format!(
"{{\"type\":\"permission-mode\",\"permissionMode\":\"bypassPermissions\"}}\n\
{{\"type\":\"user\",\"sessionId\":\"dry-session\",\"cwd\":{},\"message\":{{\"role\":\"user\",\"content\":\"continue\"}}}}\n\
{{\"type\":\"queue-operation\",\"operation\":\"enqueue\",\"content\":\"queued follow-up\"}}\n",
serde_json::to_string(project.to_str().unwrap()).unwrap()
),
)
.unwrap();
let output = run_dry(&home, transcript.to_str().unwrap());
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(report["target_model"], "z-ai/glm-5.2");
assert_eq!(report["target_context_limit"], 1_048_576);
assert_eq!(report["provider_request_sent"], false);
assert_eq!(report["store_written"], false);
assert_eq!(report["runtime_activation"], "paused");
assert_eq!(report["runtime_would_activate"], true);
assert_eq!(report["runtime"]["execution_state"], "paused");
assert_eq!(report["runtime"]["queue"]["unmatched_evidence_count"], 1);
assert_eq!(report["runtime"]["queue"]["reconstructable"], true);
assert_eq!(report["runtime"]["queue"]["will_replay"], true);
assert_eq!(report["reduction"]["reversible"], true);
let baseline_input = report["reduction"]["baseline_input_tokens"]
.as_u64()
.unwrap();
let full_messages = report["reduction"]["full_message_tokens"].as_u64().unwrap();
assert!(baseline_input >= full_messages);
assert_eq!(report["reduction"]["target_applied"], false);
assert_eq!(report["reduction"]["target_input_tokens"], baseline_input);
assert_eq!(report["reduction"]["target_met"], true);
assert_eq!(
report["runtime"]["posture"]["permission_mode"],
"bypassPermissions"
);
assert_eq!(report["custom_agents"][0]["name"], "pilot-tick");
assert_eq!(
report["custom_agents"][0]["resolved_model"],
"anthropic/claude-sonnet-4-6"
);
assert_eq!(report["claude_global_instructions_loaded"], true);
fs::remove_dir_all(home).ok();
}
#[test]
fn dry_run_reports_explicit_paused_opt_out() {
let home = temp_home("dry-run-paused");
let transcript = home.join("session.jsonl");
fs::write(
&transcript,
"{\"type\":\"user\",\"sessionId\":\"dry-paused-session\",\"cwd\":\"/tmp\",\"message\":{\"role\":\"user\",\"content\":\"hi\"}}\n\
{\"type\":\"queue-operation\",\"operation\":\"enqueue\",\"content\":\"stay paused\"}\n",
)
.unwrap();
let output = run_dry_with(&home, transcript.to_str().unwrap(), &["--paused"]);
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let report: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(report["runtime_activation"], "paused");
assert_eq!(report["runtime_would_activate"], false);
assert_eq!(report["source_log_modified"], false);
assert_eq!(report["store_written"], false);
assert_eq!(report["provider_request_sent"], false);
assert_eq!(report["runtime"]["queue"]["unmatched_evidence_count"], 1);
assert_eq!(report["runtime"]["queue"]["reconstructable"], true);
assert_eq!(report["runtime"]["queue"]["will_replay"], false);
fs::remove_dir_all(home).ok();
}