Skip to main content

tracevault_cli/
config.rs

1use serde::{Deserialize, Serialize};
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, Serialize, Deserialize)]
5pub struct TracevaultConfig {
6    pub agent: String,
7    pub server_url: Option<String>,
8    pub api_key: Option<String>,
9    pub org_slug: Option<String>,
10    pub repo_id: Option<String>,
11}
12
13impl Default for TracevaultConfig {
14    fn default() -> Self {
15        Self {
16            agent: "claude-code".to_string(),
17            server_url: None,
18            api_key: None,
19            org_slug: None,
20            repo_id: None,
21        }
22    }
23}
24
25impl TracevaultConfig {
26    pub fn config_dir(project_root: &Path) -> PathBuf {
27        project_root.join(".tracevault")
28    }
29
30    pub fn config_path(project_root: &Path) -> PathBuf {
31        Self::config_dir(project_root).join("config.toml")
32    }
33
34    pub fn to_toml(&self) -> String {
35        let mut out = format!("# TraceVault configuration\nagent = \"{}\"\n", self.agent);
36        if let Some(url) = &self.server_url {
37            out.push_str(&format!("server_url = \"{url}\"\n"));
38        }
39        if let Some(slug) = &self.org_slug {
40            out.push_str(&format!("org_slug = \"{slug}\"\n"));
41        }
42        if let Some(rid) = &self.repo_id {
43            out.push_str(&format!("repo_id = \"{rid}\"\n"));
44        }
45        out
46    }
47
48    /// Parse config from the TOML file using simple line-based parsing
49    /// (consistent with the existing resolve_credentials approach).
50    pub fn load(project_root: &Path) -> Option<Self> {
51        let path = Self::config_path(project_root);
52        let content = std::fs::read_to_string(path).ok()?;
53
54        let parse_field = |key: &str| -> Option<String> {
55            content
56                .lines()
57                .find(|l| l.starts_with(key))
58                .and_then(|l| l.split('=').nth(1))
59                .map(|s| s.trim().trim_matches('"').to_string())
60        };
61
62        Some(Self {
63            agent: parse_field("agent").unwrap_or_else(|| "claude-code".to_string()),
64            server_url: parse_field("server_url"),
65            api_key: parse_field("api_key"),
66            org_slug: parse_field("org_slug"),
67            repo_id: parse_field("repo_id"),
68        })
69    }
70}