use std::path::{Path, PathBuf};
use std::time::Instant;
use crate::cli::{OutputFormat, UninstallArgs};
use crate::error::CliError;
use crate::output::{Action, FileEntry, Report};
pub fn run(args: &UninstallArgs, output: &OutputFormat) -> Result<(), CliError> {
let start = Instant::now();
let target = resolve_target(&args.path)?;
let opencode_dir = target.join(".opencode");
let manifest = if args.force {
crate::manifest::load(&opencode_dir)
.unwrap_or_else(|_| crate::manifest::Manifest::new("unknown"))
} else {
crate::manifest::load(&opencode_dir)?
};
let plugin_version = manifest.plugin_version.clone();
let mut report = Report::new("uninstall", &plugin_version);
for file in &manifest.files {
if args.keep_state && file.path == "ralph-loop.local.md" {
continue;
}
if args.keep_node_modules && file.path.starts_with("node_modules") {
continue;
}
let dest = opencode_dir.join(&file.path);
let action = if dest.exists() {
if !args.dry_run {
std::fs::remove_file(&dest)
.map_err(|e| CliError::io(dest.to_string_lossy().into_owned(), e))?;
}
Action::Removed
} else {
Action::Missing
};
report.files.push(FileEntry {
path: file.path.clone(),
action,
sha256: file.sha256.clone(),
expected_sha256: None,
size_bytes: file.size_bytes,
});
}
if !args.dry_run {
crate::manifest::remove(&opencode_dir)?;
}
report.duration_ms = start.elapsed().as_millis() as u64;
report.finalize();
emit_report(&report, output);
Ok(())
}
fn resolve_target(path: &Path) -> Result<PathBuf, CliError> {
let resolved = if path.is_absolute() {
path.to_path_buf()
} else {
std::env::current_dir()
.map_err(|e| CliError::io("current directory", e))?
.join(path)
};
if !resolved.exists() {
return Err(CliError::Io {
path: resolved.to_string_lossy().to_string(),
source: std::io::Error::new(std::io::ErrorKind::NotFound, "directory does not exist"),
});
}
Ok(resolved)
}
fn emit_report(report: &Report, format: &OutputFormat) {
match format {
OutputFormat::Text => crate::output::text::print_report(report),
OutputFormat::Json => crate::output::json::print_report(report),
OutputFormat::Ndjson => crate::output::ndjson::print_report(report),
OutputFormat::Quiet => {}
}
}