include!(concat!(env!("OUT_DIR"), "/bundled_agents.rs"));
use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AgentAction {
Install,
Update {
from: String,
},
Modified,
UpToDate,
}
impl AgentAction {
pub fn is_change(&self) -> bool {
!matches!(self, Self::UpToDate)
}
pub fn preselect(&self) -> bool {
matches!(self, Self::Install | Self::Update { .. })
}
pub fn label(&self, to: &str) -> String {
match self {
Self::Install => format!("install {to}"),
Self::Update { from } => format!("update {from} → {to}"),
Self::Modified => format!("{to}, edited locally - reinstall overwrites"),
Self::UpToDate => "up to date".to_string(),
}
}
}
pub fn installed_version(agents_dir: &Path, name: &str) -> Option<String> {
let manifest = std::fs::read_to_string(agents_dir.join(name).join("agent.leviath")).ok()?;
leviath_core::manifest::parse_manifest(&manifest)
.ok()
.map(|bp| bp.version)
}
fn matches_bundled(agent: &BundledAgent, agents_dir: &Path) -> bool {
let dest = agents_dir.join(agent.name);
for (rel, contents) in agent.files {
match std::fs::read_to_string(dest.join(rel)) {
Ok(on_disk) if on_disk == *contents => {}
_ => return false,
}
}
installed_file_count(&dest) == agent.files.len()
}
fn installed_file_count(dir: &Path) -> usize {
let Ok(entries) = std::fs::read_dir(dir) else {
return 0;
};
entries
.map(|entry| match entry.map(|e| e.path()) {
Ok(path) if path.is_dir() => installed_file_count(&path),
_ => 1,
})
.sum()
}
pub fn plan_agent_actions(agents_dir: &Path) -> Vec<(&'static BundledAgent, AgentAction)> {
BUNDLED_AGENTS
.iter()
.map(|agent| {
let action = match installed_version(agents_dir, agent.name) {
None => AgentAction::Install,
Some(v) if v != agent.version => AgentAction::Update { from: v },
Some(_) if matches_bundled(agent, agents_dir) => AgentAction::UpToDate,
Some(_) => AgentAction::Modified,
};
(agent, action)
})
.collect()
}
pub fn stale_install_note(
manifest_path: &Path,
blueprint: &leviath_core::Blueprint,
agents_dir: Option<&Path>,
) -> Option<String> {
let installed = agents_dir?.join(&blueprint.name);
if !manifest_path.starts_with(&installed) {
return None;
}
let bundled = BUNDLED_AGENTS.iter().find(|a| a.name == blueprint.name)?;
if bundled.version == blueprint.version {
return None;
}
Some(format!(
"note: '{}' is installed at {}, and this build ships {}. \
Run `lev setup` to update it.",
blueprint.name, blueprint.version, bundled.version
))
}
pub fn stale_install_hint(manifest_path: &Path, agents_dir: Option<&Path>) -> Option<String> {
let agents_dir = agents_dir?;
let bundled = BUNDLED_AGENTS
.iter()
.find(|a| manifest_path.starts_with(agents_dir.join(a.name)))?;
if matches_bundled(bundled, agents_dir) {
return None;
}
Some(format!(
"this is the installed copy of the bundled '{}' agent, and it differs from the one this \
build ships, so it is most likely out of date rather than broken. Run `lev setup` to \
reinstall it, or `lev add <path>` if you meant to keep your own edits.",
bundled.name
))
}
pub fn stale_install_suffix(
manifest_path: &Path,
agents_dir: Option<&Path>,
separator: &str,
) -> String {
match stale_install_hint(manifest_path, agents_dir) {
Some(hint) => format!("{separator}{hint}"),
None => String::new(),
}
}
pub fn real_agents_dir_opt() -> Option<std::path::PathBuf> {
dirs::home_dir().map(|h| crate::commands::setup::real_agents_dir(Some(&h)))
}
pub fn install_bundled(agent: &BundledAgent, agents_dir: &Path) -> anyhow::Result<()> {
let dest = agents_dir.join(agent.name);
if dest.exists() {
std::fs::remove_dir_all(&dest)?;
}
for (rel, contents) in agent.files {
let parent = match rel.rsplit_once('/') {
Some((dir, _)) => dest.join(dir),
None => dest.clone(),
};
std::fs::create_dir_all(&parent)?;
std::fs::write(dest.join(rel), contents)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_bundled_agent_has_a_name_version_and_manifest() {
assert!(
!BUNDLED_AGENTS.is_empty(),
"the binary shipped with no blueprints -- build.rs found no agents/ directory"
);
for agent in BUNDLED_AGENTS {
assert!(!agent.name.is_empty(), "a bundled agent has an empty name");
assert!(
!agent.version.is_empty(),
"bundled agent {} has an empty version",
agent.name
);
assert!(
agent.files.iter().any(|(rel, _)| *rel == "agent.leviath"),
"bundled agent {} has no agent.leviath",
agent.name
);
for (rel, contents) in agent.files {
assert!(
!rel.is_empty(),
"bundled agent {} has an empty path",
agent.name
);
assert!(
!contents.is_empty(),
"bundled agent {} has an empty file {rel}",
agent.name
);
}
}
}
#[test]
fn a_tool_script_shared_by_several_agents_is_identical_in_all_of_them() {
use std::collections::HashMap;
let mut first_seen: HashMap<&str, (&str, &str)> = HashMap::new();
for agent in BUNDLED_AGENTS {
for (rel, contents) in agent.files {
let Some(filename) = rel.strip_prefix("tools/") else {
continue;
};
match first_seen.get(filename) {
Some((other, expected)) => assert!(
expected == contents,
"tools/{filename} differs between bundled agents {other} and {} - \
a change to one copy was not applied to the others",
agent.name
),
None => {
first_seen.insert(filename, (agent.name, contents));
}
}
}
}
assert!(
!first_seen.is_empty(),
"no bundled agent ships a tools/ script - this invariant is not being tested"
);
}
#[test]
fn every_bundled_manifest_parses_and_agrees_with_its_recorded_version() {
for agent in BUNDLED_AGENTS {
let manifest = agent
.files
.iter()
.find(|(rel, _)| *rel == "agent.leviath")
.map(|(_, c)| *c)
.expect("checked above");
let parsed = leviath_core::manifest::parse_manifest(manifest);
assert!(
parsed.is_ok(),
"bundled agent {} does not parse",
agent.name
);
let blueprint = parsed.expect("asserted Ok just above");
assert_eq!(blueprint.version, agent.version);
assert_eq!(blueprint.name, agent.name);
}
}
#[test]
fn every_bundled_agent_ends_by_handing_something_back() {
for agent in BUNDLED_AGENTS {
let manifest = agent
.files
.iter()
.find(|(rel, _)| *rel == "agent.leviath")
.map(|(_, c)| *c)
.expect("checked above");
let blueprint = leviath_core::manifest::parse_manifest(manifest)
.expect("checked by every_bundled_manifest_parses");
let outputs: Vec<&leviath_core::Stage> = blueprint
.stages
.iter()
.filter(|s| s.mode == leviath_core::blueprint::StageMode::Output)
.collect();
assert!(
!outputs.is_empty(),
"bundled agent {} has no output stage, so a run of it hands back nothing",
agent.name
);
for stage in &outputs {
assert!(stage.require_output, "{} output stage", agent.name);
assert!(
stage
.available_tools
.iter()
.any(|t| t == leviath_core::blueprint::SUBMIT_OUTPUT_TOOL),
"{} output stage cannot submit",
agent.name
);
assert!(
!stage.available_tools.iter().any(|t| {
leviath_core::blueprint::MODIFYING_TOOLS
.contains(&leviath_tools::canonical_tool_name(t))
}),
"{} output stage can modify files",
agent.name
);
}
for stage in &blueprint.stages {
assert!(
!stage.allow_complete
|| stage.mode == leviath_core::blueprint::StageMode::Output,
"bundled agent {}: stage '{}' may end the run, skipping the output stage",
agent.name,
stage.name
);
}
}
}
const SETUP_PROVIDERS: &[&str] = &["anthropic", "openai", "google", "openrouter", "ollama"];
const BLUEPRINT_SCHEMA: &str = include_str!("../../../docs/schema/blueprint.schema.json");
fn schema_problems(
validator: &jsonschema::Validator,
value: &serde_json::Value,
) -> Vec<String> {
validator
.iter_errors(value)
.map(|e| format!("{}: {e}", e.instance_path()))
.collect()
}
fn toml_to_json(value: &toml::Value) -> serde_json::Value {
match value {
toml::Value::String(s) => serde_json::Value::String(s.clone()),
toml::Value::Integer(i) => serde_json::Value::from(*i),
toml::Value::Float(f) => serde_json::Value::from(*f),
toml::Value::Boolean(b) => serde_json::Value::Bool(*b),
toml::Value::Datetime(d) => serde_json::Value::String(d.to_string()),
toml::Value::Array(items) => {
serde_json::Value::Array(items.iter().map(toml_to_json).collect())
}
toml::Value::Table(table) => serde_json::Value::Object(
table
.iter()
.map(|(k, v)| (k.clone(), toml_to_json(v)))
.collect(),
),
}
}
#[test]
fn toml_converts_to_json_for_every_value_kind() {
let source = concat!(
"s = \"text\"\n",
"i = 7\n",
"f = 0.5\n",
"b = true\n",
"d = 1979-05-27T07:32:00Z\n",
"a = [1, \"two\"]\n",
"[t]\n",
"nested = 1\n"
);
let parsed: toml::Value = toml::from_str(source).expect("valid TOML");
let json = toml_to_json(&parsed);
assert_eq!(json["s"], serde_json::json!("text"));
assert_eq!(json["i"], serde_json::json!(7));
assert_eq!(json["f"], serde_json::json!(0.5));
assert_eq!(json["b"], serde_json::json!(true));
assert!(json["d"].is_string());
assert_eq!(json["a"], serde_json::json!([1, "two"]));
assert_eq!(json["t"]["nested"], serde_json::json!(1));
}
#[test]
fn every_bundled_blueprint_validates_against_the_published_schema() {
let schema: serde_json::Value =
serde_json::from_str(BLUEPRINT_SCHEMA).expect("the schema is valid JSON");
let validator = jsonschema::validator_for(&schema).expect("the schema compiles");
for agent in BUNDLED_AGENTS {
let manifest = agent
.files
.iter()
.find(|(rel, _)| *rel == "agent.leviath")
.map(|(_, c)| *c)
.expect("every bundled agent has a manifest");
let parsed: toml::Value = toml::from_str(manifest).expect("the manifest is valid TOML");
let json = toml_to_json(&parsed);
assert_eq!(
schema_problems(&validator, &json),
Vec::<String>::new(),
"{} does not match blueprint.schema.json",
agent.name
);
}
}
#[test]
fn the_blueprint_schema_accepts_every_region_kind_the_parser_names() {
let err = leviath_core::manifest::parse_manifest(
"[agent]\nname = \"a\"\n\n[context.regions]\nx = { kind = \"not-a-kind\" }\n",
)
.expect_err("an unknown region kind is a load error")
.to_string();
let listed = err
.split("valid kinds:")
.nth(1)
.expect("the error names the valid kinds")
.trim()
.trim_end_matches(')')
.split(',')
.map(str::trim)
.filter(|k| !k.is_empty())
.collect::<Vec<_>>();
assert!(
listed.len() > 5,
"the error should list every kind: {listed:?}"
);
let schema: serde_json::Value =
serde_json::from_str(BLUEPRINT_SCHEMA).expect("the schema is valid JSON");
let validator = jsonschema::validator_for(&schema).expect("the schema compiles");
for kind in listed {
let manifest = format!(
"[agent]\nname = \"a\"\n\n[context.regions]\nx = {{ kind = \"{kind}\" }}\n"
);
let parsed: toml::Value = toml::from_str(&manifest).expect("valid TOML");
assert_eq!(
schema_problems(&validator, &toml_to_json(&parsed)),
Vec::<String>::new(),
"the schema rejects region kind \"{kind}\", which the parser accepts"
);
}
}
#[test]
fn the_blueprint_schema_accepts_every_transition_condition_the_parser_names() {
let err = leviath_core::manifest::parse_manifest(
"[agent]\nname = \"a\"\n\n[stages.main.transitions.other]\ncondition = \"whenever\"\n",
)
.expect_err("an unknown condition is a load error")
.to_string();
let listed = err
.split("(valid:")
.nth(1)
.expect("the error names the valid conditions")
.trim()
.trim_end_matches(')')
.split(',')
.map(str::trim)
.filter(|c| !c.is_empty())
.collect::<Vec<_>>();
assert!(
listed.len() > 3,
"the error should list every condition: {listed:?}"
);
let schema: serde_json::Value =
serde_json::from_str(BLUEPRINT_SCHEMA).expect("the schema is valid JSON");
let validator = jsonschema::validator_for(&schema).expect("the schema compiles");
for condition in listed {
let manifest = format!(
"[agent]\nname = \"a\"\n\n[stages.main.transitions.other]\ncondition = \"{condition}\"\n"
);
let parsed: toml::Value = toml::from_str(&manifest).expect("valid TOML");
assert_eq!(
schema_problems(&validator, &toml_to_json(&parsed)),
Vec::<String>::new(),
"the schema rejects condition \"{condition}\", which the parser accepts"
);
}
}
#[test]
fn the_blueprint_schema_accepts_stage_hooks() {
let schema: serde_json::Value =
serde_json::from_str(BLUEPRINT_SCHEMA).expect("the schema is valid JSON");
let validator = jsonschema::validator_for(&schema).expect("the schema compiles");
let manifest = "[agent]\nname = \"a\"\n\n[stages.main.hooks]\n\
on_stage_enter = \"hooks/enter.rhai\"\n\
on_error = \"hooks/error.rhai\"\n";
let parsed: toml::Value = toml::from_str(manifest).expect("valid TOML");
assert_eq!(
schema_problems(&validator, &toml_to_json(&parsed)),
Vec::<String>::new(),
"the schema rejects [stages.<name>.hooks], which the parser accepts"
);
}
#[test]
fn the_blueprint_schema_rejects_what_the_parser_rejects() {
let schema: serde_json::Value =
serde_json::from_str(BLUEPRINT_SCHEMA).expect("the schema is valid JSON");
let validator = jsonschema::validator_for(&schema).expect("the schema compiles");
let rejects = |manifest: &str| {
let parsed: toml::Value = toml::from_str(manifest).expect("valid TOML");
!schema_problems(&validator, &toml_to_json(&parsed)).is_empty()
};
assert!(
rejects("[stages.main]\nmode = \"autonomous\"\n"),
"no [agent]"
);
assert!(
rejects("[agent]\nname = \"a\"\n\n[context.regions]\nx = { kind = \"nonsense\" }\n"),
"unknown region kind"
);
assert!(
rejects(
"[agent]\nname = \"a\"\n\n[stages.main.transitions.other]\ncondition = \"whenever\"\n"
),
"unknown transition condition"
);
assert!(
rejects("[agent]\nname = \"a\"\n\n[stages.main]\nmax_iteratoins = 5\n"),
"a typo'd stage key"
);
assert!(
rejects("[agent]\nname = \"a\"\n\n[tool_permissions]\nshell = \"maybe\"\n"),
"an invalid tool policy"
);
assert!(!rejects("[agent]\nname = \"a\"\n"), "a minimal manifest");
}
#[test]
fn every_bundled_stage_offers_every_provider_setup_can_configure() {
for agent in BUNDLED_AGENTS {
let manifest = agent
.files
.iter()
.find(|(rel, _)| *rel == "agent.leviath")
.map(|(_, c)| *c)
.expect("every bundled agent has a manifest");
let blueprint =
leviath_core::manifest::parse_manifest(manifest).expect("manifest parses");
for stage in &blueprint.stages {
let stage_name = &stage.name;
let listed: Vec<&str> = stage
.model
.models
.iter()
.map(|entry| entry.provider.as_str())
.collect();
for provider in SETUP_PROVIDERS {
assert!(
listed.contains(provider),
"{}/{} omits provider {}",
agent.name,
stage_name,
provider
);
}
assert_eq!(
listed.last().copied(),
Some("ollama"),
"{}/{} must list ollama last",
agent.name,
stage_name
);
}
}
}
fn lint_env_for(agent: &BundledAgent) -> crate::lint::LintEnv {
let mut known_tools: std::collections::HashSet<String> = leviath_tools::BuiltinTools::new(
leviath_tools::ToolContext::new(std::path::PathBuf::from(".")),
)
.names()
.into_iter()
.collect();
known_tools.extend(leviath_tools::BuiltinTools::subagent_tool_names());
known_tools.extend(
agent
.files
.iter()
.filter_map(|(rel, _)| rel.strip_prefix("tools/"))
.filter_map(|f| f.strip_suffix(".rhai"))
.map(str::to_string),
);
crate::lint::LintEnv {
known_tools,
known_models: crate::commands::models::closed_catalog_models(),
available_providers: None,
read_paths: None,
safe_commands_granted: None,
}
}
#[test]
fn no_bundled_agent_has_a_lint_error() {
for agent in BUNDLED_AGENTS {
let manifest = agent
.files
.iter()
.find(|(rel, _)| *rel == "agent.leviath")
.map(|(_, c)| *c)
.expect("every bundled agent has a manifest");
let parsed = leviath_core::manifest::parse_manifest(manifest);
assert!(
parsed.is_ok(),
"bundled agent {} does not parse",
agent.name
);
let blueprint = parsed.expect("asserted Ok just above");
let rendered: Vec<(bool, String)> =
crate::lint::lint_manifest(manifest, &blueprint, &lint_env_for(agent))
.iter()
.map(|f| (f.is_error(), format!("{} [{}]", f.one_line(), f.code)))
.collect();
let error_count = rendered.iter().filter(|(is_error, _)| *is_error).count();
assert_eq!(
error_count, 0,
"bundled agent {} has lint errors, among {rendered:?}",
agent.name
);
}
}
#[test]
fn the_lint_invariant_catches_a_typo_and_an_orphan_permission() {
let manifest = r#"
[agent]
name = "x"
version = "0.1.0"
description = "x"
[stages.only]
mode = "autonomous"
model = { provider = "anthropic", model = "claude-sonnet-5" }
max_iterations = 5
available_tools = ["read_file", "raed_file"]
[stages.only.tool_permissions]
write_file = "allow"
"#;
let bp = leviath_core::manifest::parse_manifest(manifest)
.expect("the fixture parses; it is the lint that should object");
let env = lint_env_for(&BundledAgent {
name: "x",
version: "0.1.0",
files: &[],
});
let codes: Vec<&str> = crate::lint::lint_manifest(manifest, &bp, &env)
.iter()
.filter(|f| f.is_error())
.map(|f| f.code)
.collect();
assert_eq!(codes, ["unknown-tool", "orphan-stage-permission"]);
}
#[test]
fn bundled_agent_names_are_unique() {
let mut names: Vec<&str> = BUNDLED_AGENTS.iter().map(|a| a.name).collect();
names.sort_unstable();
let count = names.len();
names.dedup();
assert_eq!(count, names.len(), "duplicate bundled agent names");
}
#[test]
fn installed_version_reads_a_manifest() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
assert_eq!(
installed_version(dir.path(), agent.name).as_deref(),
Some(agent.version)
);
}
#[test]
fn installed_version_is_none_when_nothing_is_installed() {
let dir = tempfile::tempdir().unwrap();
assert!(installed_version(dir.path(), "not-installed").is_none());
}
#[test]
fn installed_version_is_none_for_an_unparseable_manifest() {
let dir = tempfile::tempdir().unwrap();
std::fs::create_dir_all(dir.path().join("broken")).unwrap();
std::fs::write(
dir.path().join("broken/agent.leviath"),
"not valid toml {{{",
)
.unwrap();
assert!(installed_version(dir.path(), "broken").is_none());
}
#[test]
fn plan_offers_to_install_everything_into_an_empty_dir() {
let dir = tempfile::tempdir().unwrap();
let plan = plan_agent_actions(dir.path());
assert_eq!(plan.len(), BUNDLED_AGENTS.len());
for (agent, action) in &plan {
assert_eq!(*action, AgentAction::Install);
assert!(action.is_change());
assert_eq!(
action.label(agent.version),
format!("install {}", agent.version)
);
}
}
#[test]
fn plan_reports_up_to_date_after_installing() {
let dir = tempfile::tempdir().unwrap();
for agent in BUNDLED_AGENTS {
install_bundled(agent, dir.path()).unwrap();
}
let plan = plan_agent_actions(dir.path());
for (agent, action) in &plan {
assert_eq!(*action, AgentAction::UpToDate, "{}", agent.name);
assert!(!action.is_change());
assert_eq!(action.label(agent.version), "up to date");
}
}
#[test]
fn plan_reports_an_update_when_the_installed_version_differs() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest_path = dir.path().join(agent.name).join("agent.leviath");
let manifest = std::fs::read_to_string(&manifest_path).unwrap();
let bumped = manifest.replacen(
&format!("version = \"{}\"", agent.version),
"version = \"9.9.9\"",
1,
);
std::fs::write(&manifest_path, bumped).unwrap();
let plan = plan_agent_actions(dir.path());
let (_, action) = plan
.iter()
.find(|(a, _)| a.name == agent.name)
.expect("the bundled agent is in the plan");
assert_eq!(
*action,
AgentAction::Update {
from: "9.9.9".to_string()
}
);
assert!(action.is_change());
assert_eq!(
action.label(agent.version),
format!("update 9.9.9 → {}", agent.version)
);
}
#[test]
fn plan_reports_an_edited_install_as_modified() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest_path = dir.path().join(agent.name).join("agent.leviath");
let manifest = std::fs::read_to_string(&manifest_path).unwrap();
std::fs::write(&manifest_path, manifest + "\n# a local edit\n").unwrap();
let action = action_for(&plan_agent_actions(dir.path()), agent.name);
assert_eq!(action, AgentAction::Modified);
assert!(action.is_change());
assert!(!action.preselect());
let label = action.label(agent.version);
assert!(label.contains("edited locally"), "{label}");
}
#[test]
fn a_file_the_user_added_or_removed_counts_as_modified() {
let agent = &BUNDLED_AGENTS[0];
let added = tempfile::tempdir().unwrap();
install_bundled(agent, added.path()).unwrap();
std::fs::write(added.path().join(agent.name).join("notes.md"), "mine").unwrap();
assert_eq!(
action_for(&plan_agent_actions(added.path()), agent.name),
AgentAction::Modified
);
let multi = BUNDLED_AGENTS
.iter()
.find(|a| a.files.len() > 1)
.expect("some bundled blueprint ships more than its manifest");
let removed = tempfile::tempdir().unwrap();
install_bundled(multi, removed.path()).unwrap();
let extra = multi
.files
.iter()
.map(|(rel, _)| *rel)
.find(|rel| *rel != "agent.leviath")
.expect("a file other than the manifest");
std::fs::remove_file(removed.path().join(multi.name).join(extra)).unwrap();
assert_eq!(
action_for(&plan_agent_actions(removed.path()), multi.name),
AgentAction::Modified
);
}
#[test]
fn an_unreadable_tree_is_not_up_to_date() {
assert_eq!(installed_file_count(Path::new("/no/such/dir")), 0);
let dir = tempfile::tempdir().unwrap();
assert!(!matches_bundled(&BUNDLED_AGENTS[0], dir.path()));
}
#[test]
fn installed_file_count_walks_nested_directories() {
let dir = tempfile::tempdir().unwrap();
std::fs::create_dir_all(dir.path().join("a/b")).unwrap();
std::fs::write(dir.path().join("top.txt"), "x").unwrap();
std::fs::write(dir.path().join("a/mid.txt"), "x").unwrap();
std::fs::write(dir.path().join("a/b/leaf.txt"), "x").unwrap();
assert_eq!(installed_file_count(dir.path()), 3);
}
fn action_for(plan: &[(&'static BundledAgent, AgentAction)], name: &str) -> AgentAction {
plan.iter()
.find(|(a, _)| a.name == name)
.expect("the bundled agent is in the plan")
.1
.clone()
}
#[test]
fn an_installed_agent_that_will_not_load_is_named_as_out_of_date() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest = dir.path().join(agent.name).join("agent.leviath");
assert_eq!(stale_install_hint(&manifest, Some(dir.path())), None);
std::fs::write(&manifest, "[agent]\nname = \"x\"\nversion = \"0.0.2\"\n").unwrap();
let hint =
stale_install_hint(&manifest, Some(dir.path())).expect("a changed copy is named");
assert!(hint.contains(agent.name), "{hint}");
assert!(hint.contains("lev setup"), "{hint}");
}
#[test]
fn the_suffix_carries_the_hint_or_nothing_at_all() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest = dir.path().join(agent.name).join("agent.leviath");
assert_eq!(
stale_install_suffix(&manifest, Some(dir.path()), "\n\n"),
""
);
std::fs::write(&manifest, "[agent]\nname = \"x\"\n").unwrap();
let suffix = stale_install_suffix(&manifest, Some(dir.path()), "\n\n");
assert!(suffix.starts_with("\n\n"), "{suffix:?}");
assert!(suffix.contains(agent.name), "{suffix:?}");
assert!(
stale_install_suffix(&manifest, Some(dir.path()), ". ").starts_with(". "),
"the separator is the caller's choice"
);
}
#[test]
fn the_hint_stays_quiet_outside_the_installed_copy() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let elsewhere = dir.path().join("elsewhere").join(agent.name);
std::fs::create_dir_all(&elsewhere).unwrap();
let mine = elsewhere.join("agent.leviath");
std::fs::write(&mine, "[agent]\nname = \"mine\"\n").unwrap();
assert_eq!(stale_install_hint(&mine, Some(dir.path())), None);
let other = dir.path().join("not-a-bundled-agent");
std::fs::create_dir_all(&other).unwrap();
let manifest = other.join("agent.leviath");
std::fs::write(&manifest, "[agent]\nname = \"other\"\n").unwrap();
assert_eq!(stale_install_hint(&manifest, Some(dir.path())), None);
assert_eq!(
stale_install_hint(&dir.path().join(agent.name).join("agent.leviath"), None),
None
);
}
#[test]
fn a_stale_install_is_named_when_the_run_starts() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest = dir.path().join(agent.name).join("agent.leviath");
let mut blueprint =
leviath_core::manifest::parse_manifest(&std::fs::read_to_string(&manifest).unwrap())
.unwrap();
assert_eq!(
stale_install_note(&manifest, &blueprint, Some(dir.path())),
None
);
blueprint.version = "0.0.1".to_string();
let note = stale_install_note(&manifest, &blueprint, Some(dir.path()))
.expect("a behind install is named");
assert!(note.contains("0.0.1"), "{note}");
assert!(note.contains(agent.version), "{note}");
assert!(note.contains("lev setup"), "{note}");
}
#[test]
fn a_blueprint_that_is_not_the_installed_copy_is_left_alone() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let manifest = dir.path().join(agent.name).join("agent.leviath");
let mut blueprint =
leviath_core::manifest::parse_manifest(&std::fs::read_to_string(&manifest).unwrap())
.unwrap();
blueprint.version = "0.0.1".to_string();
let elsewhere = tempfile::tempdir().unwrap();
let copy = elsewhere.path().join(agent.name).join("agent.leviath");
assert_eq!(
stale_install_note(©, &blueprint, Some(dir.path())),
None,
"not the installed copy"
);
assert_eq!(stale_install_note(&manifest, &blueprint, None), None);
blueprint.name = "not-a-bundled-agent".to_string();
assert_eq!(
stale_install_note(
&dir.path().join("not-a-bundled-agent").join("agent.leviath"),
&blueprint,
Some(dir.path())
),
None
);
}
#[test]
fn install_writes_every_file_including_nested_ones() {
let dir = tempfile::tempdir().unwrap();
for agent in BUNDLED_AGENTS {
install_bundled(agent, dir.path()).unwrap();
for (rel, contents) in agent.files {
let written = std::fs::read_to_string(dir.path().join(agent.name).join(rel));
assert!(written.is_ok(), "{}/{rel} was not written", agent.name);
assert_eq!(written.expect("asserted Ok just above"), *contents);
}
}
assert!(
BUNDLED_AGENTS
.iter()
.any(|a| a.files.iter().any(|(rel, _)| rel.contains('/'))),
"no bundled blueprint has a nested file, so install's mkdir path is untested"
);
}
#[test]
fn install_replaces_an_existing_tree_and_drops_stale_files() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
install_bundled(agent, dir.path()).unwrap();
let stale = dir
.path()
.join(agent.name)
.join("stale-from-an-older-version");
std::fs::write(&stale, "leftover").unwrap();
install_bundled(agent, dir.path()).unwrap();
assert!(
!stale.exists(),
"a reinstall must not leave files from the previous version behind"
);
assert!(dir.path().join(agent.name).join("agent.leviath").exists());
}
#[test]
fn install_surfaces_a_directory_creation_failure() {
let dir = tempfile::tempdir().unwrap();
let blocked = dir.path().join("not-a-dir");
std::fs::write(&blocked, "").unwrap();
let result = install_bundled(&BUNDLED_AGENTS[0], &blocked);
assert!(result.is_err());
}
#[test]
fn install_surfaces_a_file_write_failure() {
let agent = BundledAgent {
name: "collides-with-its-own-directory",
version: "0.0.1",
files: &[("tools/a.rhai", "nested first"), ("tools", "then the dir")],
};
let dir = tempfile::tempdir().unwrap();
let result = install_bundled(&agent, dir.path());
assert!(result.is_err());
}
#[test]
fn install_surfaces_a_remove_failure() {
let dir = tempfile::tempdir().unwrap();
let agent = &BUNDLED_AGENTS[0];
std::fs::write(dir.path().join(agent.name), "").unwrap();
let result = install_bundled(agent, dir.path());
assert!(result.is_err());
}
}