1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Source: /data/home/swei/claudecode/openclaudecode/src/utils/cwd.ts
//! Working directory utilities with async context support
#![allow(dead_code)]
use std::cell::Cell;
use std::path::PathBuf;
/// Thread-local storage for cwd override
thread_local! {
static CWD_OVERRIDE: Cell<Option<String>> = const { Cell::new(None) };
}
/// Global current working directory (set during bootstrap)
static CURRENT_CWD: once_cell::sync::Lazy<std::sync::Mutex<Option<String>>> =
once_cell::sync::Lazy::new(|| std::sync::Mutex::new(None));
/// Original working directory (before any overrides)
static ORIGINAL_CWD: once_cell::sync::Lazy<std::sync::Mutex<Option<String>>> =
once_cell::sync::Lazy::new(|| {
std::sync::Mutex::new(
std::env::current_dir()
.ok()
.map(|p| p.to_string_lossy().to_string()),
)
});
/// Run a function with an overridden working directory for the current async context.
/// All calls to pwd()/get_cwd() within the function (and its async descendants) will
/// return the overridden cwd instead of the global one. This enables concurrent
/// agents to each see their own working directory without affecting each other.
pub fn run_with_cwd_override<T, F>(cwd: String, f: F) -> T
where
F: FnOnce() -> T,
{
CWD_OVERRIDE.with(|override_cell| {
let old = override_cell.replace(Some(cwd));
let result = f();
override_cell.replace(old);
result
})
}
// Note: Async version would require tokio's async context propagation.
// For now, the sync version handles most use cases. Async version can be
// added later if needed using async_executors or similar.
/// Get the current working directory
pub fn pwd() -> String {
// Try to get from thread-local override first
let override_cwd = CWD_OVERRIDE.with(|cell| {
let val = cell.replace(None);
cell.set(val.clone());
val
});
if let Some(cwd) = override_cwd {
return cwd;
}
// Fall back to global cwd state
if let Some(cwd) = get_cwd_state() {
return cwd;
}
// Fall back to current directory
std::env::current_dir()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| ".".to_string())
}
/// Get the current working directory or the original working directory if the current one is not available
pub fn get_cwd() -> String {
pwd()
}
/// Set the global current working directory (called during bootstrap)
pub fn set_cwd(cwd: PathBuf) {
if let Ok(mut guard) = CURRENT_CWD.lock() {
*guard = Some(cwd.to_string_lossy().to_string());
}
}
/// Get the global current working directory state
fn get_cwd_state() -> Option<String> {
CURRENT_CWD.lock().ok().and_then(|guard| guard.clone())
}
/// Get the original working directory
pub fn get_original_cwd() -> String {
ORIGINAL_CWD
.lock()
.ok()
.and_then(|guard| guard.clone())
.unwrap_or_else(|| {
std::env::current_dir()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| ".".to_string())
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pwd_without_override() {
let cwd = pwd();
assert!(!cwd.is_empty());
}
#[test]
fn test_run_with_cwd_override() {
let result = run_with_cwd_override("/test/dir".to_string(), || pwd());
assert_eq!(result, "/test/dir");
}
#[test]
fn test_get_original_cwd() {
let orig = get_original_cwd();
assert!(!orig.is_empty());
}
}