pub mod post_tool_use;
pub mod pre_compact;
pub mod session_start;
pub mod stop;
pub mod user_prompt;
use std::path::{Path, PathBuf};
pub fn run_silent<F>(hook_name: &str, body: F)
where
F: FnOnce() -> anyhow::Result<()>,
{
if let Err(err) = body() {
eprintln!("[spool hook {}] suppressed error: {:#}", hook_name, err);
}
}
pub fn project_runtime_dir(cwd: &Path) -> anyhow::Result<PathBuf> {
let dir = cwd.join(".spool");
if !dir.exists() {
std::fs::create_dir_all(&dir).map_err(|e| {
anyhow::anyhow!("failed to create runtime dir {}: {}", dir.display(), e)
})?;
}
Ok(dir)
}
pub fn trellis_present(cwd: &Path) -> bool {
cwd.join(".trellis").join(".developer").exists()
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn run_silent_swallows_errors() {
run_silent("unit-test", || anyhow::bail!("expected"));
}
#[test]
fn run_silent_runs_ok_branch() {
let mut hit = false;
run_silent("unit-test", || {
hit = true;
Ok(())
});
assert!(hit);
}
#[test]
fn project_runtime_dir_creates_directory() {
let temp = tempdir().unwrap();
let dir = project_runtime_dir(temp.path()).unwrap();
assert!(dir.exists());
assert!(dir.ends_with(".spool"));
}
#[test]
fn project_runtime_dir_is_idempotent() {
let temp = tempdir().unwrap();
let _ = project_runtime_dir(temp.path()).unwrap();
let _ = project_runtime_dir(temp.path()).unwrap();
assert!(temp.path().join(".spool").exists());
}
#[test]
fn trellis_present_returns_true_when_marker_exists() {
let temp = tempdir().unwrap();
let trellis = temp.path().join(".trellis");
std::fs::create_dir_all(&trellis).unwrap();
std::fs::write(trellis.join(".developer"), "name=long").unwrap();
assert!(trellis_present(temp.path()));
}
#[test]
fn trellis_present_false_when_absent() {
let temp = tempdir().unwrap();
assert!(!trellis_present(temp.path()));
}
}