pub mod codex;
pub mod vocab;
use std::path::PathBuf;
use crate::helpers::dirs_home;
pub const KNOWN_FAMILIES: &[&str] = &[vocab::CLAUDE_CODE, vocab::CODEX];
pub fn home_for(family: &str) -> Option<PathBuf> {
match family {
vocab::CLAUDE_CODE => Some(dirs_home().join(".claude")),
vocab::CODEX => Some(dirs_home().join(".codex")),
_ => None,
}
}
pub fn is_family_present(family: &str) -> bool {
home_for(family).is_some_and(|p| p.is_dir())
}
pub fn present_families() -> Vec<&'static str> {
KNOWN_FAMILIES
.iter()
.copied()
.filter(|f| is_family_present(f))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_families_all_resolve_to_a_home() {
for family in KNOWN_FAMILIES {
assert!(
home_for(family).is_some(),
"{family} is listed as known but has no home directory"
);
}
}
#[test]
fn unknown_family_has_no_home_and_is_absent() {
assert!(home_for("some-future-agent").is_none());
assert!(!is_family_present("some-future-agent"));
assert!(!is_family_present(""));
}
#[test]
fn homes_are_distinct_and_dotted() {
let claude = home_for(vocab::CLAUDE_CODE).unwrap();
let codex = home_for(vocab::CODEX).unwrap();
assert_ne!(claude, codex);
assert!(claude.ends_with(".claude"));
assert!(codex.ends_with(".codex"));
}
#[test]
fn present_families_is_a_subset_of_known() {
for family in present_families() {
assert!(KNOWN_FAMILIES.contains(&family));
}
}
}