1use std::env;
2use std::path::{Path, PathBuf};
3
4pub fn resolve_secret_dir() -> Option<PathBuf> {
5 if let Some(dir) = env_path("CODEX_SECRET_DIR") {
6 return Some(dir);
7 }
8
9 let feature_dir = resolve_feature_dir()?;
10 if feature_dir.join("init.zsh").is_file() || feature_dir.join("codex-tools.zsh").is_file() {
11 return Some(feature_dir.join("secrets"));
12 }
13 Some(feature_dir)
14}
15
16pub fn resolve_auth_file() -> Option<PathBuf> {
17 if let Some(path) = env_path("CODEX_AUTH_FILE") {
18 return Some(path);
19 }
20
21 let home = home_dir()?;
22 let primary = home.join(".codex").join("auth.json");
23 let fallback = home.join(".codex").join("auth.json");
24
25 let mut selected = primary.clone();
26 if selected == primary && !primary.exists() && fallback.exists() {
27 selected = fallback.clone();
28 } else if selected == fallback && !fallback.exists() && primary.exists() {
29 selected = primary.clone();
30 }
31 Some(selected)
32}
33
34pub fn resolve_secret_cache_dir() -> Option<PathBuf> {
35 if let Some(path) = env_path("CODEX_SECRET_CACHE_DIR") {
36 return Some(path);
37 }
38
39 let cache_root = if let Some(path) = env_path("ZSH_CACHE_DIR") {
40 path
41 } else {
42 resolve_zdotdir()?.join("cache")
43 };
44
45 Some(cache_root.join("codex").join("secrets"))
46}
47
48pub fn resolve_feature_dir() -> Option<PathBuf> {
49 let script_dir = resolve_script_dir()?;
50 let feature_dir = script_dir.join("_features").join("codex");
51 if feature_dir.is_dir() {
52 Some(feature_dir)
53 } else {
54 None
55 }
56}
57
58pub fn resolve_script_dir() -> Option<PathBuf> {
59 if let Some(path) = env_path("ZSH_SCRIPT_DIR") {
60 return Some(path);
61 }
62 Some(resolve_zdotdir()?.join("scripts"))
63}
64
65pub fn resolve_zdotdir() -> Option<PathBuf> {
66 if let Some(path) = env_path("ZDOTDIR") {
67 return Some(path);
68 }
69
70 if let Some(preload) = env_path("_ZSH_BOOTSTRAP_PRELOAD_PATH")
71 && let Some(parent) = parent_dir(&preload, 2)
72 {
73 return Some(parent);
74 }
75
76 let home = home_dir()?;
77 Some(home.join(".config").join("zsh"))
78}
79
80fn env_path(key: &str) -> Option<PathBuf> {
81 let raw = env::var_os(key)?;
82 if raw.is_empty() {
83 return None;
84 }
85 Some(PathBuf::from(raw))
86}
87
88fn home_dir() -> Option<PathBuf> {
89 env_path("HOME")
90}
91
92fn parent_dir(path: &Path, levels: usize) -> Option<PathBuf> {
93 let mut current = path;
94 for _ in 0..levels {
95 current = current.parent()?;
96 }
97 Some(current.to_path_buf())
98}