1use std::env;
2use std::path::{Path, PathBuf};
3
4use directories::ProjectDirs;
5
6const APP_QUALIFIER: &str = "com";
7const APP_ORG: &str = "codei";
8const APP_NAME: &str = "codei";
9
10pub fn user_config_dir() -> PathBuf {
12 ProjectDirs::from(APP_QUALIFIER, APP_ORG, APP_NAME)
13 .map(|dirs| dirs.config_dir().to_path_buf())
14 .unwrap_or_else(|| PathBuf::from(".config/codei"))
15}
16
17pub fn user_log_dir() -> PathBuf {
19 ProjectDirs::from(APP_QUALIFIER, APP_ORG, APP_NAME)
20 .map(|dirs| dirs.data_local_dir().join("logs"))
21 .unwrap_or_else(|| PathBuf::from(".local/share/codei/logs"))
22}
23
24pub fn debug_log_path() -> PathBuf {
26 user_log_dir().join("debug.log")
27}
28
29pub fn user_config_path() -> PathBuf {
31 user_config_dir().join("config.toml")
32}
33
34pub fn project_config_path(project_root: &Path) -> PathBuf {
36 project_root.join(".codei").join("config.toml")
37}
38
39pub fn discover_project_root(start: &Path) -> Option<PathBuf> {
41 let start = start.canonicalize().ok()?;
42 let mut current = start;
43
44 loop {
45 if is_project_root(¤t) {
46 return Some(current);
47 }
48 if !current.pop() {
49 break;
50 }
51 }
52
53 None
54}
55
56fn is_project_root(path: &Path) -> bool {
57 path.join(".git").exists() || path.join(".codei").is_dir() || path.join("AGENTS.md").is_file()
58}
59
60pub fn expand_tilde(path: &str) -> PathBuf {
62 if let Some(rest) = path.strip_prefix("~/") {
63 if let Ok(home) = env::var("HOME") {
64 return PathBuf::from(home).join(rest);
65 }
66 }
67 PathBuf::from(path)
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn expand_tilde_uses_home() {
76 if let Ok(home) = env::var("HOME") {
77 assert_eq!(
78 expand_tilde("~/sessions"),
79 PathBuf::from(home).join("sessions")
80 );
81 }
82 }
83}