use std::path::PathBuf;
use anyhow::{anyhow, Result};
use super::host::Mode;
const PRODUCTION_SOCKET: &str = "/run/node/control.sock";
pub fn detect() -> Result<Mode> {
if let Some(monorepo) = find_monorepo_above(&std::env::current_dir().unwrap_or_default()) {
return Ok(Mode::Monorepo { path: monorepo });
}
let prod = PathBuf::from(PRODUCTION_SOCKET);
if prod.exists() {
return Ok(Mode::Remote { socket_path: prod });
}
if cfg!(target_os = "linux") && which("apt").is_some() {
return Ok(Mode::Deb);
}
if which("docker").is_some() {
return Ok(Mode::Docker);
}
Err(anyhow!(
"could not autodetect a daemon-host mode.\n\
\n\
Pick one explicitly:\n \
• --daemon /path/to/socket (existing daemon you started)\n \
• --daemon deb (Linux: apt install + systemctl, requires sudo)\n \
• --daemon docker (cross-platform: docker compose; requires Docker)\n \
• --daemon clone (in-house: gh clone econ-v1/node + cargo run)\n \
• --daemon monorepo --monorepo-path PATH (you already have a checkout)"
))
}
fn find_monorepo_above(start: &std::path::Path) -> Option<PathBuf> {
let mut current = Some(start.to_path_buf());
while let Some(dir) = current {
let cargo_toml = dir.join("Cargo.toml");
if cargo_toml.exists() {
if let Ok(contents) = std::fs::read_to_string(&cargo_toml) {
if contents.contains("\"apps/server\"") || contents.contains("apps/server") {
return Some(dir);
}
}
}
current = dir.parent().map(|p| p.to_path_buf());
}
None
}
fn which(bin: &str) -> Option<PathBuf> {
let path = std::env::var_os("PATH")?;
for dir in std::env::split_paths(&path) {
let candidate = dir.join(bin);
if candidate.is_file() {
return Some(candidate);
}
}
None
}