use std::path::PathBuf;
use std::process::{Command, ExitCode};
#[derive(Debug, clap::Args)]
pub struct UninstallArgs {
#[arg(long)]
pub components: Option<String>,
#[arg(long)]
pub component: Vec<String>,
#[arg(long)]
pub purge: bool,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub dry_run: bool,
#[arg(short = 'y', long)]
pub yes: bool,
}
fn uninstaller_path() -> Option<PathBuf> {
let base = match std::env::var_os("AASM_STATE_DIR") {
Some(v) => PathBuf::from(v),
None => dirs::home_dir()?.join(".aasm"),
};
Some(base.join("aasm-uninstall"))
}
pub fn dispatch(args: UninstallArgs) -> ExitCode {
let helper = match uninstaller_path() {
Some(p) if p.exists() => p,
_ => {
eprintln!(
"aasm uninstall: no local uninstaller found.\n\
If you installed via Homebrew, run: brew uninstall aasm\n\
Otherwise use the fallback:\n \
curl -fsSL https://agent-assembly.com/install.sh | sh -s -- --uninstall"
);
return ExitCode::FAILURE;
}
};
let mut cmd = Command::new("sh");
cmd.arg(&helper).arg("--uninstall");
if let Some(c) = &args.components {
cmd.arg("--components").arg(c);
}
for c in &args.component {
cmd.arg("--component").arg(c);
}
if args.all {
cmd.arg("--all");
}
if args.purge {
cmd.arg("--purge");
}
if args.dry_run {
cmd.arg("--dry-run");
}
if args.yes {
cmd.arg("--yes");
}
match cmd.status() {
Ok(s) if s.success() => ExitCode::SUCCESS,
Ok(_) => ExitCode::FAILURE,
Err(e) => {
eprintln!("aasm uninstall: failed to run {}: {e}", helper.display());
ExitCode::FAILURE
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn uninstaller_path_honors_state_dir_override() {
std::env::set_var("AASM_STATE_DIR", "/tmp/aa-state-xyz");
let p = uninstaller_path().expect("path resolves when AASM_STATE_DIR is set");
std::env::remove_var("AASM_STATE_DIR");
assert_eq!(p, PathBuf::from("/tmp/aa-state-xyz/aasm-uninstall"));
}
}