use std::path::{Path, PathBuf};
pub fn patina_home() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".patina")
}
pub fn patina_cache() -> PathBuf {
patina_home().join("cache")
}
pub fn config_path() -> PathBuf {
patina_home().join("config.toml")
}
pub fn registry_path() -> PathBuf {
patina_home().join("registry.yaml")
}
pub fn adapters_dir() -> PathBuf {
patina_home().join("adapters")
}
pub mod persona {
use super::*;
pub fn events_dir() -> PathBuf {
patina_home().join("personas/default/events")
}
pub fn cache_dir() -> PathBuf {
patina_cache().join("personas/default")
}
}
pub mod repos {
use super::*;
pub fn cache_dir() -> PathBuf {
patina_cache().join("repos")
}
}
pub mod secrets {
use super::*;
use std::path::Path;
pub fn registry_path() -> PathBuf {
patina_home().join("secrets.toml")
}
pub fn vault_path() -> PathBuf {
patina_home().join("vault.age")
}
pub fn recipient_path() -> PathBuf {
patina_home().join("recipient.txt")
}
pub fn project_registry_path(root: &Path) -> PathBuf {
root.join(".patina").join("secrets.toml")
}
pub fn project_vault_path(root: &Path) -> PathBuf {
root.join(".patina").join("vault.age")
}
pub fn project_recipients_path(root: &Path) -> PathBuf {
root.join(".patina").join("recipients.txt")
}
}
pub mod serve {
use super::*;
pub fn run_dir() -> PathBuf {
patina_home().join("run")
}
pub fn socket_path() -> PathBuf {
run_dir().join("serve.sock")
}
pub fn token_path() -> PathBuf {
run_dir().join("serve.token")
}
pub fn pid_path() -> PathBuf {
run_dir().join("mother.pid")
}
}
pub mod plugin {
use super::*;
pub fn children_dir() -> PathBuf {
patina_home().join("children")
}
pub fn plugins_dir() -> PathBuf {
patina_home().join("plugins")
}
pub fn work_dir(name: &str) -> PathBuf {
plugins_dir().join(name).join("work")
}
}
pub mod mother {
use super::*;
pub fn data_dir() -> PathBuf {
patina_home().join("mother")
}
pub fn graph_db() -> PathBuf {
data_dir().join("graph.db")
}
}
pub mod models {
use super::*;
pub fn cache_dir() -> PathBuf {
patina_cache().join("models")
}
pub fn model_dir(name: &str) -> PathBuf {
cache_dir().join(name)
}
pub fn model_onnx(name: &str) -> PathBuf {
model_dir(name).join("model.onnx")
}
pub fn model_tokenizer(name: &str) -> PathBuf {
model_dir(name).join("tokenizer.json")
}
pub fn lock_path() -> PathBuf {
patina_home().join("models.lock")
}
}
pub mod project {
use super::*;
pub fn patina_dir(root: &Path) -> PathBuf {
root.join(".patina")
}
pub fn config_path(root: &Path) -> PathBuf {
root.join(".patina/config.toml")
}
pub fn local_dir(root: &Path) -> PathBuf {
root.join(".patina/local")
}
pub fn data_dir(root: &Path) -> PathBuf {
root.join(".patina/local/data")
}
pub fn db_path(root: &Path) -> PathBuf {
root.join(".patina/local/data/patina.db")
}
pub fn embeddings_dir(root: &Path) -> PathBuf {
root.join(".patina/local/data/embeddings")
}
pub fn model_projections_dir(root: &Path, model: &str) -> PathBuf {
root.join(format!(
".patina/local/data/embeddings/{}/projections",
model
))
}
pub fn recipe_path(root: &Path) -> PathBuf {
root.join(".patina/oxidize.yaml")
}
pub fn versions_path(root: &Path) -> PathBuf {
root.join(".patina/versions.json")
}
pub fn backups_dir(root: &Path) -> PathBuf {
root.join(".patina/local/backups")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_patina_home() {
let home = patina_home();
assert!(home.ends_with(".patina"));
}
#[test]
fn test_patina_cache() {
let cache = patina_cache();
assert!(cache.ends_with("cache"));
assert!(cache.starts_with(patina_home()));
}
#[test]
fn test_persona_paths() {
let events = persona::events_dir();
let cache = persona::cache_dir();
assert!(events.to_string_lossy().contains("personas/default/events"));
assert!(cache.to_string_lossy().contains("cache/personas/default"));
}
#[test]
fn test_repos_cache() {
let repos = repos::cache_dir();
assert!(repos.to_string_lossy().contains("cache/repos"));
}
#[test]
fn test_models_paths() {
let cache = models::cache_dir();
assert!(cache.to_string_lossy().contains("cache/models"));
let model_dir = models::model_dir("e5-base-v2");
assert!(model_dir
.to_string_lossy()
.contains("cache/models/e5-base-v2"));
let onnx = models::model_onnx("e5-base-v2");
assert!(onnx.to_string_lossy().ends_with("e5-base-v2/model.onnx"));
let tokenizer = models::model_tokenizer("e5-base-v2");
assert!(tokenizer
.to_string_lossy()
.ends_with("e5-base-v2/tokenizer.json"));
let lock = models::lock_path();
assert!(lock.to_string_lossy().ends_with("models.lock"));
assert!(!lock.to_string_lossy().contains("cache"));
}
#[test]
fn test_serve_paths() {
let run = serve::run_dir();
assert!(run.to_string_lossy().ends_with(".patina/run"));
let sock = serve::socket_path();
assert!(sock.to_string_lossy().ends_with("run/serve.sock"));
let token = serve::token_path();
assert!(token.to_string_lossy().ends_with("run/serve.token"));
let pid = serve::pid_path();
assert!(pid.to_string_lossy().ends_with("run/mother.pid"));
}
#[test]
fn test_project_paths() {
let root = Path::new("/tmp/test-project");
assert_eq!(
project::patina_dir(root),
PathBuf::from("/tmp/test-project/.patina")
);
assert_eq!(
project::local_dir(root),
PathBuf::from("/tmp/test-project/.patina/local")
);
assert_eq!(
project::db_path(root),
PathBuf::from("/tmp/test-project/.patina/local/data/patina.db")
);
assert_eq!(
project::model_projections_dir(root, "e5-base-v2"),
PathBuf::from("/tmp/test-project/.patina/local/data/embeddings/e5-base-v2/projections")
);
}
}