use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::AcbResult;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
pub graph_path: String,
#[serde(default = "default_transport")]
pub transport: String,
#[serde(default = "default_sse_addr")]
pub sse_addr: String,
#[serde(default = "default_log_level")]
pub log_level: String,
}
fn default_transport() -> String {
"stdio".to_string()
}
fn default_sse_addr() -> String {
"127.0.0.1:3000".to_string()
}
fn default_log_level() -> String {
"warn".to_string()
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
graph_path: resolve_default_graph_path(),
transport: default_transport(),
sse_addr: default_sse_addr(),
log_level: default_log_level(),
}
}
}
pub fn load_config(path: &str) -> AcbResult<ServerConfig> {
let content = std::fs::read_to_string(path).map_err(|e| {
crate::AcbError::Io(std::io::Error::other(format!(
"Failed to read config file {path}: {e}"
)))
})?;
toml::from_str(&content).map_err(|e| {
crate::AcbError::Io(std::io::Error::other(format!(
"Failed to parse config: {e}"
)))
})
}
pub fn resolve_graph_path(explicit: Option<&str>) -> String {
if let Some(path) = explicit {
return path.to_string();
}
if let Ok(env_path) = std::env::var("ACB_GRAPH") {
return env_path;
}
let cwd_graph = PathBuf::from(".acb/graph.acb");
if cwd_graph.exists() {
return cwd_graph.display().to_string();
}
resolve_default_graph_path()
}
fn resolve_default_graph_path() -> String {
let home = std::env::var("HOME")
.or_else(|_| std::env::var("USERPROFILE"))
.unwrap_or_else(|_| ".".to_string());
format!("{home}/.agentic-codebase/graph.acb")
}