use std::path::PathBuf;
use super::super::binding::AgentBinding;
const EVENT_TYPES: [&str; 9] = [
"PreToolUse",
"PostToolUse",
"UserPromptSubmit",
"Notification",
"Stop",
"SubagentStop",
"PreCompact",
"SessionStart",
"SessionEnd",
];
pub struct ClaudeCodeBinding {
pub claude_dir: PathBuf,
pub settings_path: PathBuf,
}
impl ClaudeCodeBinding {
pub fn detect() -> Option<Self> {
let claude_dir = crate::hooks::claude_code::detect()?;
let settings_path = crate::hooks::claude_code::settings_json_path(&claude_dir);
Some(Self {
claude_dir,
settings_path,
})
}
}
impl AgentBinding for ClaudeCodeBinding {
fn agent_type(&self) -> &str {
"claude-code"
}
fn settings_path(&self) -> PathBuf {
self.settings_path.clone()
}
fn hook_event_types(&self) -> &[&str] {
&EVENT_TYPES
}
fn token_env_var(&self) -> &str {
"OPENLATCH_TOKEN"
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn claude_code_agent_type() {
let b = ClaudeCodeBinding {
claude_dir: PathBuf::from("/home/test/.claude"),
settings_path: PathBuf::from("/home/test/.claude/settings.json"),
};
assert_eq!(b.agent_type(), "claude-code");
}
#[test]
fn claude_code_event_types_has_9_entries() {
let b = ClaudeCodeBinding {
claude_dir: PathBuf::from("/home/test/.claude"),
settings_path: PathBuf::from("/home/test/.claude/settings.json"),
};
assert_eq!(b.hook_event_types().len(), 9);
assert!(b.hook_event_types().contains(&"PreToolUse"));
assert!(b.hook_event_types().contains(&"SessionEnd"));
}
#[test]
fn claude_config_dir_relocates_the_settings_path() {
let _lock = crate::daemon::identity::ENV_LOCK.blocking_lock();
let env = crate::daemon::identity::test_support::EnvGuard::clear();
let dir = tempfile::tempdir().expect("temp dir");
env.set("CLAUDE_CONFIG_DIR", dir.path());
let b = ClaudeCodeBinding::detect().expect("relocated dir exists, so detect must succeed");
assert_eq!(b.claude_dir, dir.path());
assert_eq!(b.settings_path(), dir.path().join("settings.json"));
env.set("CLAUDE_CONFIG_DIR", "");
if let Some(b) = ClaudeCodeBinding::detect() {
assert_ne!(b.claude_dir, std::path::Path::new(""));
}
}
#[test]
fn claude_code_binding_is_arc_dyn_compatible() {
let b = ClaudeCodeBinding {
claude_dir: PathBuf::from("/tmp/.claude"),
settings_path: PathBuf::from("/tmp/.claude/settings.json"),
};
let _arc: Arc<dyn AgentBinding> = Arc::new(b);
}
}