Skip to main content

agentic_codebase/config/
loader.rs

1//! Configuration loading from file, environment, and CLI arguments.
2
3use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7use crate::AcbResult;
8
9/// Server configuration.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ServerConfig {
12    /// Path to the .acb graph file.
13    pub graph_path: String,
14    /// Transport type ("stdio" or "sse").
15    #[serde(default = "default_transport")]
16    pub transport: String,
17    /// SSE listen address (only used when transport is "sse").
18    #[serde(default = "default_sse_addr")]
19    pub sse_addr: String,
20    /// Log level.
21    #[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
48/// Load configuration from a TOML file.
49pub 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
63/// Resolve the graph file path using priority order:
64///
65/// 1. Explicit path (CLI arg)
66/// 2. `ACB_GRAPH` environment variable
67/// 3. `.acb/graph.acb` in current directory
68/// 4. `~/.agentic-codebase/graph.acb` (global default)
69pub 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}