use async_trait::async_trait;
use supercode::{Agent, ChatMessage, ChatRequest, Config, Provider, Usage};
struct NeverCalled;
#[async_trait]
impl Provider for NeverCalled {
async fn complete(
&self,
_req: &ChatRequest,
_on_delta: &(dyn for<'a> Fn(&'a str) + Send + Sync),
) -> supercode::Result<(ChatMessage, Usage)> {
panic!("provider should never be called by these assembly-only tests");
}
}
fn system_prompt_of(config: Config) -> String {
let agent = Agent::with_provider(config, Box::new(NeverCalled));
agent.history()[0].content.clone().unwrap_or_default()
}
fn temp_dir(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!(
"supercode-p4b-instr-{tag}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn lock_supercode_home_env() -> std::sync::MutexGuard<'static, ()> {
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
LOCK.lock().unwrap_or_else(|e| e.into_inner())
}
#[test]
fn global_instruction_tier_is_loaded_when_project_context_is_on() {
let _guard = lock_supercode_home_env();
let global_home = temp_dir("global-home");
std::fs::write(global_home.join("AGENTS.md"), "GLOBAL MARKER TEXT").unwrap();
let cwd = temp_dir("global-cwd-empty");
std::env::set_var("SUPERCODE_HOME", &global_home);
let config = Config::builder().cwd(&cwd).project_context(true).build();
let system = system_prompt_of(config);
std::env::remove_var("SUPERCODE_HOME");
assert!(
system.contains("GLOBAL MARKER TEXT"),
"global tier must load when project_context is on: {system}"
);
let _ = std::fs::remove_dir_all(&global_home);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn global_instruction_tier_is_not_loaded_when_project_context_is_off() {
let _guard = lock_supercode_home_env();
let global_home = temp_dir("global-home-off");
std::fs::write(
global_home.join("AGENTS.md"),
"GLOBAL MARKER SHOULD NOT APPEAR",
)
.unwrap();
let cwd = temp_dir("global-cwd-off");
std::env::set_var("SUPERCODE_HOME", &global_home);
let config = Config::builder().cwd(&cwd).project_context(false).build();
let system = system_prompt_of(config);
std::env::remove_var("SUPERCODE_HOME");
assert!(
!system.contains("GLOBAL MARKER SHOULD NOT APPEAR"),
"project_context = false (the default) must be byte-identical to pre-P4b behavior"
);
let _ = std::fs::remove_dir_all(&global_home);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn cwd_tier_still_loads_project_context_unchanged_from_pre_p4b() {
let cwd = temp_dir("cwd-project-unchanged");
std::fs::write(cwd.join("CLAUDE.md"), "PROJECT MARKER TEXT").unwrap();
let config = Config::builder().cwd(&cwd).project_context(true).build();
let system = system_prompt_of(config);
assert!(system.contains("PROJECT MARKER TEXT"));
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn nearer_to_cwd_instruction_content_appears_after_the_global_tier() {
let _guard = lock_supercode_home_env();
let global_home = temp_dir("order-global");
std::fs::write(global_home.join("AGENTS.md"), "GLOBAL-ORDER-MARKER").unwrap();
let cwd = temp_dir("order-cwd");
std::fs::write(cwd.join("AGENTS.md"), "PROJECT-ORDER-MARKER").unwrap();
std::env::set_var("SUPERCODE_HOME", &global_home);
let config = Config::builder().cwd(&cwd).project_context(true).build();
let system = system_prompt_of(config);
std::env::remove_var("SUPERCODE_HOME");
let global_pos = system
.find("GLOBAL-ORDER-MARKER")
.expect("global tier present");
let project_pos = system
.find("PROJECT-ORDER-MARKER")
.expect("project tier present");
assert!(
global_pos < project_pos,
"root-first ordering: global tier must appear BEFORE the project tier (nearer-to-cwd wins by appearing later)"
);
let _ = std::fs::remove_dir_all(&global_home);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn env_context_block_appended_when_enabled() {
let cwd = temp_dir("env-ctx-on");
let config = Config::builder().cwd(&cwd).env_context(true).build();
let system = system_prompt_of(config);
assert!(system.contains("# Environment"), "{system}");
assert!(system.contains("cwd:"), "{system}");
assert!(system.contains("platform:"), "{system}");
assert!(system.contains("date:"), "{system}");
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn env_context_block_absent_by_default() {
let cwd = temp_dir("env-ctx-off");
let config = Config::builder().cwd(&cwd).build();
let system = system_prompt_of(config);
assert!(!system.contains("# Environment"), "{system}");
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn instruction_imports_inlines_the_referenced_file_content() {
let cwd = temp_dir("imports-on");
std::fs::write(cwd.join("STYLE.md"), "Use tabs, not spaces.").unwrap();
std::fs::write(
cwd.join("AGENTS.md"),
"Follow the style guide: @STYLE.md please.",
)
.unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(
system.contains("Use tabs, not spaces."),
"the imported file's content must be inlined: {system}"
);
assert!(
!system.contains("@STYLE.md"),
"the literal @STYLE.md token must have been replaced: {system}"
);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn instruction_imports_off_by_default_leaves_the_at_token_literal() {
let cwd = temp_dir("imports-off");
std::fs::write(cwd.join("STYLE.md"), "Use tabs, not spaces.").unwrap();
std::fs::write(
cwd.join("AGENTS.md"),
"Follow the style guide: @STYLE.md please.",
)
.unwrap();
let config = Config::builder().cwd(&cwd).project_context(true).build();
let system = system_prompt_of(config);
assert!(
system.contains("@STYLE.md"),
"instruction_imports defaults off: the token must stay literal: {system}"
);
assert!(!system.contains("Use tabs, not spaces."));
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn instruction_imports_reject_path_traversal_from_a_project_sourced_file() {
let cwd = temp_dir("imports-traversal");
let secret_parent = temp_dir("imports-traversal-secret-parent");
std::fs::write(secret_parent.join("SECRET.md"), "TOP SECRET CONTENT").unwrap();
let secret_name = secret_parent.file_name().unwrap().to_str().unwrap();
std::fs::write(
cwd.join("AGENTS.md"),
format!("@../{secret_name}/SECRET.md"),
)
.unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(
!system.contains("TOP SECRET CONTENT"),
"a `..`-traversing import from a PROJECT-sourced file must be rejected: {system}"
);
let _ = std::fs::remove_dir_all(&cwd);
let _ = std::fs::remove_dir_all(&secret_parent);
}
#[test]
fn instruction_imports_absolute_path_from_a_project_sourced_file_is_rejected() {
let cwd = temp_dir("imports-absolute");
let secret = temp_dir("imports-absolute-secret");
let secret_file = secret.join("SECRET.md");
std::fs::write(&secret_file, "ABSOLUTE SECRET").unwrap();
std::fs::write(cwd.join("AGENTS.md"), format!("@{}", secret_file.display())).unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(!system.contains("ABSOLUTE SECRET"), "{system}");
let _ = std::fs::remove_dir_all(&cwd);
let _ = std::fs::remove_dir_all(&secret);
}
#[cfg(unix)]
#[test]
fn instruction_imports_symlink_escaping_the_project_root_is_rejected() {
let cwd = temp_dir("imports-symlink-escape");
let secret_parent = temp_dir("imports-symlink-escape-secret-parent");
let secret_file = secret_parent.join("SECRET.md");
std::fs::write(&secret_file, "SYMLINK ESCAPE SECRET").unwrap();
std::os::unix::fs::symlink(&secret_file, cwd.join("link.md")).unwrap();
std::fs::write(cwd.join("AGENTS.md"), "@link.md").unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(
!system.contains("SYMLINK ESCAPE SECRET"),
"a symlink committed in-repo whose TARGET escapes the root must be rejected: {system}"
);
let _ = std::fs::remove_dir_all(&cwd);
let _ = std::fs::remove_dir_all(&secret_parent);
}
#[test]
fn instruction_imports_in_root_subdirectory_file_is_still_inlined() {
let cwd = temp_dir("imports-in-root-subdir");
std::fs::create_dir_all(cwd.join("sub")).unwrap();
std::fs::write(cwd.join("sub").join("real.md"), "IN ROOT SUBDIR CONTENT").unwrap();
std::fs::write(cwd.join("AGENTS.md"), "@sub/real.md").unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(
system.contains("IN ROOT SUBDIR CONTENT"),
"a genuinely in-root file must not be falsely rejected by the containment check: {system}"
);
let _ = std::fs::remove_dir_all(&cwd);
}
#[cfg(unix)]
#[test]
fn instruction_imports_symlink_pointing_within_the_project_root_is_inlined() {
let cwd = temp_dir("imports-symlink-in-root");
std::fs::write(cwd.join("real.md"), "IN ROOT SYMLINK TARGET").unwrap();
std::os::unix::fs::symlink(cwd.join("real.md"), cwd.join("link.md")).unwrap();
std::fs::write(cwd.join("AGENTS.md"), "@link.md").unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(
system.contains("IN ROOT SYMLINK TARGET"),
"an in-root symlink (target also under the project root) must still be inlined: {system}"
);
let _ = std::fs::remove_dir_all(&cwd);
}
#[cfg(unix)]
#[test]
fn instruction_imports_broken_symlink_is_rejected_without_panicking() {
let cwd = temp_dir("imports-broken-symlink");
std::os::unix::fs::symlink(cwd.join("does-not-exist.md"), cwd.join("link.md")).unwrap();
std::fs::write(cwd.join("AGENTS.md"), "@link.md").unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
assert!(system.contains("@link.md"), "{system}");
let _ = std::fs::remove_dir_all(&cwd);
}
#[cfg(unix)]
#[test]
fn instruction_imports_global_tier_symlink_stays_unrestricted() {
let _guard = lock_supercode_home_env();
let global_home = temp_dir("imports-global-symlink-home");
let outside = temp_dir("imports-global-symlink-target");
std::fs::write(outside.join("OUTSIDE.md"), "GLOBAL TRUSTED TARGET").unwrap();
std::os::unix::fs::symlink(outside.join("OUTSIDE.md"), global_home.join("link.md")).unwrap();
std::fs::write(global_home.join("AGENTS.md"), "@link.md").unwrap();
let cwd = temp_dir("imports-global-symlink-cwd");
std::env::set_var("SUPERCODE_HOME", &global_home);
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.instruction_imports(true)
.build();
let system = system_prompt_of(config);
std::env::remove_var("SUPERCODE_HOME");
assert!(
system.contains("GLOBAL TRUSTED TARGET"),
"global/user-tier imports are trusted and must stay unrestricted: {system}"
);
let _ = std::fs::remove_dir_all(&global_home);
let _ = std::fs::remove_dir_all(&outside);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn project_doc_max_bytes_caps_the_total_assembled_instruction_content() {
let cwd = temp_dir("max-bytes-on");
let huge = "x".repeat(50_000);
std::fs::write(cwd.join("CLAUDE.md"), &huge).unwrap();
let config = Config::builder()
.cwd(&cwd)
.project_context(true)
.project_doc_max_bytes(200)
.build();
let system = system_prompt_of(config);
assert!(
system.len() < huge.len(),
"assembled system prompt ({} bytes) must be far smaller than the uncapped instruction file ({} bytes)",
system.len(),
huge.len()
);
assert!(
system.contains("truncated at core.project_doc_max_bytes"),
"{system}"
);
let _ = std::fs::remove_dir_all(&cwd);
}
#[test]
fn project_doc_max_bytes_unset_leaves_instruction_content_uncapped() {
let cwd = temp_dir("max-bytes-off");
let body = "y".repeat(5_000);
std::fs::write(cwd.join("CLAUDE.md"), &body).unwrap();
let config = Config::builder().cwd(&cwd).project_context(true).build();
let system = system_prompt_of(config);
assert!(system.contains(&body), "uncapped by default");
assert!(!system.contains("truncated at core.project_doc_max_bytes"));
let _ = std::fs::remove_dir_all(&cwd);
}