1use std::path::PathBuf;
8
9use crate::error::RecallError;
10
11pub fn entity_root() -> Result<PathBuf, RecallError> {
17 if let Ok(p) = std::env::var("RECALL_ECHO_HOME") {
18 return Ok(PathBuf::from(p));
19 }
20 std::env::current_dir().map_err(RecallError::from)
21}
22
23pub fn memory_dir() -> Result<PathBuf, RecallError> {
25 Ok(entity_root()?.join("memory"))
26}
27
28pub fn memory_file() -> Result<PathBuf, RecallError> {
29 Ok(memory_dir()?.join("MEMORY.md"))
30}
31
32pub fn ephemeral_file() -> Result<PathBuf, RecallError> {
33 Ok(memory_dir()?.join("EPHEMERAL.md"))
34}
35
36pub fn archive_index() -> Result<PathBuf, RecallError> {
37 Ok(memory_dir()?.join("ARCHIVE.md"))
38}
39
40pub fn conversations_dir() -> Result<PathBuf, RecallError> {
41 Ok(memory_dir()?.join("conversations"))
42}
43
44pub fn config_file() -> Result<PathBuf, RecallError> {
45 Ok(memory_dir()?.join(".recall-echo.toml"))
46}
47
48pub fn claude_dir() -> Result<PathBuf, RecallError> {
54 let home = dirs::home_dir()
55 .ok_or_else(|| RecallError::Other("Could not determine home directory".into()))?;
56 Ok(home.join(".claude"))
57}
58
59#[must_use]
61pub fn expand_tilde(path: &str) -> String {
62 if let Some(rest) = path.strip_prefix("~/") {
63 if let Some(home) = dirs::home_dir() {
64 return home.join(rest).to_string_lossy().to_string();
65 }
66 }
67 path.to_string()
68}
69
70#[must_use]
73pub fn detect_claude_code() -> Option<PathBuf> {
74 let home = dirs::home_dir()?;
75 let claude = home.join(".claude");
76 if claude.exists() {
77 Some(claude)
78 } else {
79 None
80 }
81}