agentic_codebase/config/
loader.rs1use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7use crate::AcbResult;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ServerConfig {
12 pub graph_path: String,
14 #[serde(default = "default_transport")]
16 pub transport: String,
17 #[serde(default = "default_sse_addr")]
19 pub sse_addr: String,
20 #[serde(default = "default_log_level")]
22 pub log_level: String,
23}
24
25fn default_transport() -> String {
26 "stdio".to_string()
27}
28
29fn default_sse_addr() -> String {
30 "127.0.0.1:3000".to_string()
31}
32
33fn default_log_level() -> String {
34 "warn".to_string()
35}
36
37impl Default for ServerConfig {
38 fn default() -> Self {
39 Self {
40 graph_path: resolve_default_graph_path(),
41 transport: default_transport(),
42 sse_addr: default_sse_addr(),
43 log_level: default_log_level(),
44 }
45 }
46}
47
48pub fn load_config(path: &str) -> AcbResult<ServerConfig> {
50 let content = std::fs::read_to_string(path).map_err(|e| {
51 crate::AcbError::Io(std::io::Error::other(format!(
52 "Failed to read config file {path}: {e}"
53 )))
54 })?;
55
56 toml::from_str(&content).map_err(|e| {
57 crate::AcbError::Io(std::io::Error::other(format!(
58 "Failed to parse config: {e}"
59 )))
60 })
61}
62
63pub fn resolve_graph_path(explicit: Option<&str>) -> String {
70 if let Some(path) = explicit {
71 return path.to_string();
72 }
73
74 if let Ok(env_path) = std::env::var("ACB_GRAPH") {
75 return env_path;
76 }
77
78 let cwd_graph = PathBuf::from(".acb/graph.acb");
79 if cwd_graph.exists() {
80 return cwd_graph.display().to_string();
81 }
82
83 resolve_default_graph_path()
84}
85
86fn resolve_default_graph_path() -> String {
87 let home = std::env::var("HOME")
88 .or_else(|_| std::env::var("USERPROFILE"))
89 .unwrap_or_else(|_| ".".to_string());
90
91 format!("{home}/.agentic-codebase/graph.acb")
92}