agent_code_lib/services/
session_env.rs1use std::path::{Path, PathBuf};
11
12#[derive(Debug, Clone)]
14pub struct SessionEnvironment {
15 pub original_cwd: PathBuf,
17 pub project_root: PathBuf,
19 pub is_git_repo: bool,
21 pub git_branch: Option<String>,
23 pub platform: String,
25 pub shell: String,
27 pub is_interactive: bool,
29 pub terminal_width: u16,
31}
32
33impl SessionEnvironment {
34 pub async fn detect() -> Self {
36 let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
37
38 let project_root = detect_project_root(&cwd).await;
39 let is_git = crate::services::git::is_git_repo(&cwd).await;
40 let branch = if is_git {
41 crate::services::git::current_branch(&cwd).await
42 } else {
43 None
44 };
45
46 let terminal_width = crossterm::terminal::size().map(|(w, _)| w).unwrap_or(80);
47
48 Self {
49 original_cwd: cwd,
50 project_root,
51 is_git_repo: is_git,
52 git_branch: branch,
53 platform: std::env::consts::OS.to_string(),
54 shell: detect_shell(),
55 is_interactive: atty_check(),
56 terminal_width,
57 }
58 }
59}
60
61async fn detect_project_root(cwd: &Path) -> PathBuf {
63 if let Some(root) = crate::services::git::repo_root(cwd).await {
65 return PathBuf::from(root);
66 }
67
68 let markers = [
70 ".rc",
71 "Cargo.toml",
72 "package.json",
73 "pyproject.toml",
74 "go.mod",
75 ];
76 let mut dir = cwd.to_path_buf();
77 loop {
78 for marker in &markers {
79 if dir.join(marker).exists() {
80 return dir;
81 }
82 }
83 if !dir.pop() {
84 break;
85 }
86 }
87
88 cwd.to_path_buf()
89}
90
91fn detect_shell() -> String {
92 std::env::var("SHELL").unwrap_or_else(|_| "bash".to_string())
93}
94
95fn atty_check() -> bool {
96 #[cfg(unix)]
97 {
98 unsafe { libc::isatty(0) != 0 }
100 }
101 #[cfg(not(unix))]
102 {
103 true
104 }
105}