//! Machine-local user preferences and project-owned presentation settings. use serde::{Deserialize, Serialize}; /// Preferred interface when a new human-facing agent terminal is opened. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum DefaultAgentTerminalInterface { /// Provider's native interactive terminal UI. NativeTui, /// IdeA's structured/custom CLI chat surface. IdeaCli, } /// Global, machine-local IdeA preferences. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct IdeaUserSettings { /// Default for newly launched human-facing agent terminals. #[serde(default)] pub default_agent_terminal_interface: Option, } /// Strict project theme colour (`#RRGGBB`). #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String", into = "String")] pub struct ThemeColor(String); impl ThemeColor { /// Validates and builds a project theme colour. pub fn new(value: impl Into) -> Result { let value = value.into(); let valid = value.len() == 7 && value.starts_with('#') && value.as_bytes()[1..].iter().all(u8::is_ascii_hexdigit); valid .then_some(Self(value)) .ok_or_else(|| "themeColor must match #RRGGBB".to_owned()) } /// Returns the validated wire representation. #[must_use] pub fn as_str(&self) -> &str { &self.0 } } impl TryFrom for ThemeColor { type Error = String; fn try_from(value: String) -> Result { Self::new(value) } } impl From for String { fn from(value: ThemeColor) -> Self { value.0 } } /// Settings owned by one project and stored below its `.ideai` directory. #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProjectSettings { /// Optional visual theme colour; absence keeps the product fallback. #[serde(default)] pub theme_color: Option, }