use clap::Args;
#[derive(Args)]
pub struct RemoveArgs {
#[arg(value_name = "NAME")]
pub name: String,
}
pub async fn execute(args: RemoveArgs) -> anyhow::Result<()> {
let installer = leviath_package::AgentInstaller::new();
remove_agent(&installer, &args.name)
}
fn remove_agent(installer: &leviath_package::AgentInstaller, name: &str) -> anyhow::Result<()> {
remove_agent_with(installer, name, &|n| installer.uninstall(n))
}
fn remove_agent_with(
installer: &leviath_package::AgentInstaller,
name: &str,
uninstall: &dyn Fn(&str) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
if installer.get_installed(name).is_none() {
anyhow::bail!(
"Agent '{}' is not installed. Use `lev list` to see installed agents.",
name
);
}
uninstall(name)?;
println!("Removed agent '{}'.", name);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn remove_args_stores_name() {
let args = RemoveArgs {
name: "my-agent".to_string(),
};
assert_eq!(args.name, "my-agent");
}
#[test]
fn remove_args_accepts_various_names() {
for name in &[
"simple",
"with-dash",
"with_underscore",
"CamelCase",
"v1.0.0",
] {
let args = RemoveArgs {
name: name.to_string(),
};
assert_eq!(args.name, *name);
}
}
fn install_test_agent(installer: &leviath_package::AgentInstaller, name: &str) {
let project_dir = tempfile::tempdir().unwrap();
std::fs::write(
project_dir.path().join("agent.leviath"),
format!(
"[agent]\nname = \"{name}\"\nversion = \"1.0.0\"\ndescription = \"test agent\"\n"
),
)
.unwrap();
let bundle = leviath_package::AgentBundler::new()
.bundle(project_dir.path())
.unwrap();
installer.install_from_bytes(name, &bundle).unwrap();
}
#[test]
fn remove_agent_not_installed_returns_error() {
let dir = tempfile::tempdir().unwrap();
let installer = leviath_package::AgentInstaller::with_install_dir(dir.path().to_path_buf());
let err = remove_agent(&installer, "nonexistent").unwrap_err();
assert!(err.to_string().contains("is not installed"));
assert!(err.to_string().contains("lev list"));
}
#[test]
fn remove_agent_installed_succeeds_and_uninstalls() {
let dir = tempfile::tempdir().unwrap();
let installer = leviath_package::AgentInstaller::with_install_dir(dir.path().to_path_buf());
install_test_agent(&installer, "my-agent");
assert!(installer.get_installed("my-agent").is_some());
remove_agent(&installer, "my-agent").unwrap();
assert!(installer.get_installed("my-agent").is_none());
}
#[tokio::test]
async fn execute_with_nonexistent_agent_returns_error() {
let args = RemoveArgs {
name: "definitely-nonexistent-agent-for-lev-remove-coverage-xyz".to_string(),
};
let err = execute(args).await.unwrap_err();
assert!(err.to_string().contains("is not installed"));
}
#[test]
fn remove_agent_uninstall_error_propagates() {
let dir = tempfile::tempdir().unwrap();
let installer = leviath_package::AgentInstaller::with_install_dir(dir.path().to_path_buf());
install_test_agent(&installer, "err-agent");
let result = remove_agent_with(&installer, "err-agent", &|_| {
Err(anyhow::anyhow!("simulated uninstall failure"))
});
assert!(result.is_err());
}
}