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