syncable_cli/config/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// Main configuration structure
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Config {
7    pub analysis: AnalysisConfig,
8    pub generation: GenerationConfig,
9    pub output: OutputConfig,
10    pub telemetry: TelemetryConfig,
11    #[serde(default)]
12    pub agent: AgentConfig,
13    /// Syncable platform authentication
14    #[serde(default)]
15    pub syncable_auth: SyncableAuth,
16}
17
18/// Analysis configuration
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct AnalysisConfig {
21    pub include_dev_dependencies: bool,
22    pub deep_analysis: bool,
23    pub ignore_patterns: Vec<String>,
24    pub max_file_size: usize,
25}
26
27/// Generation configuration
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct GenerationConfig {
30    pub dockerfile: DockerfileConfig,
31    pub compose: ComposeConfig,
32    pub terraform: TerraformConfig,
33}
34
35/// Dockerfile generation configuration
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct DockerfileConfig {
38    pub base_image_override: Option<String>,
39    pub use_multi_stage: bool,
40    pub optimize_for_size: bool,
41    pub include_health_check: bool,
42}
43
44/// Docker Compose generation configuration
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct ComposeConfig {
47    pub version: String,
48    pub include_database: bool,
49    pub include_redis: bool,
50}
51
52/// Terraform generation configuration
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct TerraformConfig {
55    pub provider: String,
56    pub include_networking: bool,
57    pub include_monitoring: bool,
58}
59
60/// Output configuration
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct OutputConfig {
63    pub format: OutputFormat,
64    pub overwrite_existing: bool,
65    pub create_backup: bool,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub enum OutputFormat {
70    Files,
71    Stdout,
72    Json,
73}
74
75// Telemetry configuration
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct TelemetryConfig {
78    pub enabled: bool,
79}
80
81/// Agent/Chat configuration
82#[derive(Debug, Clone, Serialize, Deserialize, Default)]
83pub struct AgentConfig {
84    /// OpenAI API key (legacy, use profiles instead)
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub openai_api_key: Option<String>,
87    /// Anthropic API key (legacy, use profiles instead)
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub anthropic_api_key: Option<String>,
90    /// AWS Bedrock configuration (legacy, use profiles instead)
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub bedrock: Option<BedrockConfig>,
93    /// AWS Bedrock configured flag (legacy)
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub bedrock_configured: Option<bool>,
96    /// Default provider (openai, anthropic, or bedrock)
97    #[serde(default = "default_provider")]
98    pub default_provider: String,
99    /// Default model
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub default_model: Option<String>,
102
103    // --- Global Profile support ---
104    /// Named profiles containing all provider settings
105    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
106    pub profiles: HashMap<String, Profile>,
107    /// Currently active profile name
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub active_profile: Option<String>,
110
111    // --- Legacy per-provider profiles (deprecated, kept for migration) ---
112    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
113    pub openai_profiles: HashMap<String, OpenAIProfile>,
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub openai_active_profile: Option<String>,
116    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
117    pub anthropic_profiles: HashMap<String, AnthropicProfile>,
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub anthropic_active_profile: Option<String>,
120    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
121    pub bedrock_profiles: HashMap<String, BedrockConfig>,
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub bedrock_active_profile: Option<String>,
124}
125
126/// A global profile containing settings for all providers
127#[derive(Debug, Clone, Serialize, Deserialize, Default)]
128pub struct Profile {
129    /// Description of this profile (e.g., "Work", "Personal")
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub description: Option<String>,
132    /// Default provider for this profile
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub default_provider: Option<String>,
135    /// Default model for this profile
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub default_model: Option<String>,
138    /// OpenAI settings for this profile
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub openai: Option<OpenAIProfile>,
141    /// Anthropic settings for this profile
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub anthropic: Option<AnthropicProfile>,
144    /// Bedrock settings for this profile
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub bedrock: Option<BedrockConfig>,
147}
148
149/// OpenAI profile configuration
150#[derive(Debug, Clone, Serialize, Deserialize, Default)]
151pub struct OpenAIProfile {
152    /// API key for this profile
153    pub api_key: String,
154    /// Optional description/label
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub description: Option<String>,
157    /// Preferred model for this profile
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub default_model: Option<String>,
160}
161
162/// Anthropic profile configuration
163#[derive(Debug, Clone, Serialize, Deserialize, Default)]
164pub struct AnthropicProfile {
165    /// API key for this profile
166    pub api_key: String,
167    /// Optional description/label
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub description: Option<String>,
170    /// Preferred model for this profile
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub default_model: Option<String>,
173}
174
175/// AWS Bedrock configuration
176#[derive(Debug, Clone, Serialize, Deserialize, Default)]
177pub struct BedrockConfig {
178    /// AWS region (e.g., us-east-1, us-west-2)
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub region: Option<String>,
181    /// AWS profile name from ~/.aws/credentials
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub profile: Option<String>,
184    /// AWS Access Key ID (alternative to profile)
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub access_key_id: Option<String>,
187    /// AWS Secret Access Key (alternative to profile)
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub secret_access_key: Option<String>,
190    /// AWS Bearer Token for Bedrock (used by Bedrock API Gateway)
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub bearer_token: Option<String>,
193    /// Preferred model ID
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub default_model: Option<String>,
196}
197
198/// Syncable platform authentication credentials
199#[derive(Debug, Clone, Serialize, Deserialize, Default)]
200pub struct SyncableAuth {
201    /// Access token from device authorization flow
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub access_token: Option<String>,
204    /// Refresh token for renewing access
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub refresh_token: Option<String>,
207    /// Token expiration timestamp (Unix seconds)
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub expires_at: Option<u64>,
210    /// Authenticated user's email
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub user_email: Option<String>,
213}
214
215fn default_provider() -> String {
216    "openai".to_string()
217}
218
219impl Default for Config {
220    fn default() -> Self {
221        Self {
222            analysis: AnalysisConfig {
223                include_dev_dependencies: false,
224                deep_analysis: true,
225                ignore_patterns: vec![
226                    "node_modules".to_string(),
227                    ".git".to_string(),
228                    "target".to_string(),
229                    "build".to_string(),
230                ],
231                max_file_size: 1024 * 1024, // 1MB
232            },
233            generation: GenerationConfig {
234                dockerfile: DockerfileConfig {
235                    base_image_override: None,
236                    use_multi_stage: true,
237                    optimize_for_size: true,
238                    include_health_check: true,
239                },
240                compose: ComposeConfig {
241                    version: "3.8".to_string(),
242                    include_database: false,
243                    include_redis: false,
244                },
245                terraform: TerraformConfig {
246                    provider: "docker".to_string(),
247                    include_networking: true,
248                    include_monitoring: false,
249                },
250            },
251            output: OutputConfig {
252                format: OutputFormat::Files,
253                overwrite_existing: false,
254                create_backup: true,
255            },
256            telemetry: TelemetryConfig { enabled: true },
257            agent: AgentConfig::default(),
258            syncable_auth: SyncableAuth::default(),
259        }
260    }
261}