use std::path::Path;
use std::sync::OnceLock;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Frontend {
Cli,
Acp {
fs_delegated: bool,
shell_delegated: bool,
},
Headless,
}
impl Frontend {
fn fs_delegated(self) -> bool {
matches!(
self,
Self::Acp {
fs_delegated: true,
..
}
)
}
fn describe(self) -> String {
match self {
Self::Cli => "CLI".to_owned(),
Self::Acp {
fs_delegated,
shell_delegated,
} => format!(
"ACP (fs: {}, shell: {})",
delegation(fs_delegated),
delegation(shell_delegated),
),
Self::Headless => "headless".to_owned(),
}
}
}
fn delegation(delegated: bool) -> &'static str {
if delegated { "delegated" } else { "local" }
}
pub struct RunningContext<'a> {
pub frontend: Frontend,
pub cwd: &'a Path,
}
impl<'a> RunningContext<'a> {
pub fn new(frontend: Frontend, cwd: &'a Path) -> Self {
Self { frontend, cwd }
}
pub fn render(&self) -> String {
let mut lines = Vec::with_capacity(6);
lines.push(format!("- platform: {}", platform_line()));
lines.push(format!("- defect version: {}", env!("CARGO_PKG_VERSION")));
lines.push(format!("- frontend: {}", self.frontend.describe()));
lines.push(format!("- cwd: {}", self.cwd.display()));
lines.push(format!("- shell: {}", shell_line()));
if self.frontend.fs_delegated() {
lines.push(
"- note: the filesystem is delegated and only supports text reads; \
do not use read_file on image or other binary files (it will fail)"
.to_owned(),
);
}
lines.join("\n")
}
}
fn platform_line() -> &'static str {
static PLATFORM: OnceLock<String> = OnceLock::new();
PLATFORM.get_or_init(|| {
let info = os_info::get();
format!(
"{} / {} ({} {})",
std::env::consts::OS,
std::env::consts::ARCH,
info.os_type(),
info.version(),
)
})
}
fn shell_line() -> &'static str {
static SHELL: OnceLock<String> = OnceLock::new();
SHELL.get_or_init(|| std::env::var("SHELL").unwrap_or_else(|_| "unknown".to_owned()))
}
#[cfg(test)]
mod tests;