use std::path::{Path, PathBuf};
use sha2::{Digest, Sha256};
pub fn base_dir() -> PathBuf {
if let Ok(p) = std::env::var("THEWAY_DIR") {
return PathBuf::from(p);
}
std::env::var("HOME")
.map(|home| PathBuf::from(home).join(".theway"))
.unwrap_or_else(|_| PathBuf::from(".theway"))
}
pub fn sessions_dir_for_cwd(cwd: &Path) -> PathBuf {
let hash = cwd_hash(cwd);
base_dir().join("sessions").join(hash)
}
pub fn memory_dir() -> PathBuf {
base_dir().join("memory")
}
pub fn extensions_dir() -> PathBuf {
base_dir().join("extensions")
}
pub fn extension_trust_path() -> PathBuf {
extensions_dir().join("trust.json")
}
pub fn extension_audit_path() -> PathBuf {
extensions_dir().join("audit.jsonl")
}
pub fn cwd_hash(cwd: &Path) -> String {
let mut h = Sha256::new();
h.update(cwd.to_string_lossy().as_bytes());
let digest = h.finalize();
hex::encode(&digest[..6]) }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cwd_hash_is_deterministic_and_pins_on_disk_names() {
assert_eq!(cwd_hash(Path::new("")), "e3b0c44298fc");
assert_eq!(
cwd_hash(Path::new("/tmp/project")),
cwd_hash(&PathBuf::from("/tmp/project"))
);
assert_ne!(cwd_hash(Path::new("/tmp/a")), cwd_hash(Path::new("/tmp/b")));
}
#[test]
fn path_layout_follows_theway_dir() {
unsafe { std::env::set_var("THEWAY_DIR", "/tmp/theway-contract-base") };
assert_eq!(base_dir(), PathBuf::from("/tmp/theway-contract-base"));
assert_eq!(
memory_dir(),
PathBuf::from("/tmp/theway-contract-base/memory")
);
assert_eq!(
extension_trust_path(),
PathBuf::from("/tmp/theway-contract-base/extensions/trust.json")
);
assert_eq!(
extension_audit_path(),
PathBuf::from("/tmp/theway-contract-base/extensions/audit.jsonl")
);
assert_eq!(
sessions_dir_for_cwd(Path::new("")),
PathBuf::from("/tmp/theway-contract-base/sessions/e3b0c44298fc")
);
unsafe { std::env::remove_var("THEWAY_DIR") };
}
}