use std::path::PathBuf;
use colored::Colorize;
use trusty_mpm::core::standalone::hooks::cleanup::clean_settings_file;
fn resolve_targets(path: Option<&str>) -> anyhow::Result<Vec<PathBuf>> {
if let Some(p) = path {
let dir = PathBuf::from(p);
return Ok(vec![
dir.join(".claude").join("settings.json"),
dir.join(".claude").join("settings.local.json"),
]);
}
let home =
dirs::home_dir().ok_or_else(|| anyhow::anyhow!("could not resolve home directory"))?;
Ok(trusty_common::claude_config::discover_claude_settings(
&home,
trusty_common::claude_config::default_settings_max_depth(),
))
}
pub(crate) fn clean(path: Option<String>, force: bool) -> anyhow::Result<()> {
let targets = resolve_targets(path.as_deref())?;
let mut modified = 0usize;
for file in &targets {
match clean_settings_file(file, force) {
Ok(Some(outcome)) => {
modified += 1;
let events = outcome.removed_events.join(", ");
if let Some(backup) = &outcome.backup_path {
println!(
" {} {} — removed [{}] (backup: {})",
"✓".green(),
outcome.path.display(),
events,
backup.display()
);
} else {
println!(
" {} {} — would remove [{}]",
"~".yellow(),
outcome.path.display(),
events
);
}
}
Ok(None) => {}
Err(e) => {
eprintln!(" {} {}: {e}", "✗".red(), file.display());
}
}
}
if modified == 0 {
println!("no tm hook contamination found.");
} else if force {
println!(
"\ncleaned {} file{}.",
modified,
if modified == 1 { "" } else { "s" }
);
} else {
println!(
"\ndry run — {} file{} would be modified. Re-run with --force to apply.",
modified,
if modified == 1 { "" } else { "s" }
);
}
Ok(())
}
#[cfg(test)]
#[path = "hooks_tests.rs"]
mod tests;