use std::path::Path;
use anyhow::{Context, Result};
use serde_json::{json, Map, Value};
use super::Installed;
pub const SETTINGS: &str = ".agents/hooks.json";
pub const EVENT: &str = "PreToolUse";
const NAME: &str = "ralon";
const MATCHER: &str = "replace_file_content|write_to_file|create_file|edit|write";
pub fn entry() -> Value {
json!({
"enabled": true,
EVENT: [{
"matcher": MATCHER,
"hooks": [{
"type": "command",
"command": "ralon hook check",
"timeout": 15
}]
}]
})
}
pub fn install(root: &Path, dry_run: bool) -> Result<Installed> {
let path = root.join(SETTINGS);
let mut document: Value = if path.is_file() {
let text = std::fs::read_to_string(&path)
.with_context(|| format!("failed to read {}", path.display()))?;
serde_json::from_str(&text).with_context(|| {
format!(
"{} is not valid JSON, so it will not be modified",
path.display()
)
})?
} else {
Value::Object(Map::new())
};
let Some(fields) = document.as_object_mut() else {
anyhow::bail!("{} does not contain a JSON object", path.display());
};
let replaced = fields.contains_key(NAME);
fields.insert(NAME.to_string(), entry());
let rendered = format!("{}\n", serde_json::to_string_pretty(&document)?);
if dry_run {
print!("{rendered}");
} else {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)
.with_context(|| format!("failed to create {}", parent.display()))?;
}
std::fs::write(&path, rendered)
.with_context(|| format!("failed to write {}", path.display()))?;
}
Ok(Installed { path, replaced })
}