vtcode-tui 0.98.2

Reusable TUI primitives and session API for VT Code-style terminal interfaces
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

pub use super::SyntaxHighlightingConfig;
use super::{
    AcpConfig, AgentConfig, AutomationConfig, ContextConfig, McpConfig, PromptCacheConfig,
    PtyConfig, SecurityConfig, ToolsConfig, UiConfig,
};

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct VTCodeConfig {
    pub agent: AgentConfig,
    pub ui: UiConfig,
    pub prompt_cache: PromptCacheConfig,
    pub mcp: McpConfig,
    pub acp: AcpConfig,
    pub automation: AutomationConfig,
    pub tools: ToolsConfig,
    pub security: SecurityConfig,
    pub context: ContextConfig,
    pub syntax_highlighting: SyntaxHighlightingConfig,
    pub pty: PtyConfig,
}

pub struct ConfigManager {
    path: PathBuf,
    config: VTCodeConfig,
}

impl ConfigManager {
    pub fn load() -> Result<Self> {
        let cwd = std::env::current_dir().context("failed to read current directory")?;
        Self::load_from_workspace(cwd)
    }

    pub fn load_from_workspace(workspace_root: impl AsRef<Path>) -> Result<Self> {
        let path = workspace_root.as_ref().join("vtcode.toml");

        let config = if path.exists() {
            let raw = std::fs::read_to_string(&path)
                .with_context(|| format!("failed to read {}", path.display()))?;
            toml::from_str::<VTCodeConfig>(&raw)
                .with_context(|| format!("failed to parse {}", path.display()))?
        } else {
            VTCodeConfig::default()
        };

        Ok(Self { path, config })
    }

    pub fn config(&self) -> &VTCodeConfig {
        &self.config
    }

    pub fn save_config(&self, config: &VTCodeConfig) -> Result<()> {
        let rendered = toml::to_string_pretty(config).context("failed to serialize config")?;
        std::fs::write(&self.path, rendered)
            .with_context(|| format!("failed to write {}", self.path.display()))
    }
}