1use super::agents_md_parser::AgentsMdParser;
6use super::config_manager::{ConfigManager, ConfigSource};
7use serde_json::Value;
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, Default)]
12pub struct ConfigDisplayOptions {
13 pub show_secrets: bool,
15 pub show_sources: bool,
17 pub show_backups: bool,
19 pub format: ConfigFormat,
21}
22
23#[derive(Debug, Clone, Copy, Default)]
25pub enum ConfigFormat {
26 #[default]
27 Json,
28 Yaml,
29 Table,
30}
31
32pub struct ConfigCommand<'a> {
34 config_manager: &'a ConfigManager,
35}
36
37impl<'a> ConfigCommand<'a> {
38 pub fn new(config_manager: &'a ConfigManager) -> Self {
40 Self { config_manager }
41 }
42
43 pub fn display(&self, options: ConfigDisplayOptions) -> String {
45 let mut output = String::new();
46
47 output.push_str(&"=".repeat(60));
49 output.push_str("\nAster Configuration\n");
50 output.push_str(&"=".repeat(60));
51 output.push_str("\n\n");
52
53 let config = if options.show_secrets {
55 serde_json::to_string_pretty(&self.config_manager.get_all()).unwrap_or_default()
56 } else {
57 self.config_manager.export(true)
58 };
59
60 output.push_str("**当前配置:**\n");
61 output.push_str("```json\n");
62 output.push_str(&config);
63 output.push_str("\n```\n\n");
64
65 if options.show_sources {
67 output.push_str(&self.display_sources());
68 }
69
70 if options.show_backups {
72 output.push_str(&self.display_backups());
73 }
74
75 output.push_str(&self.display_agents_md());
77
78 output.push('\n');
79 output.push_str(&"=".repeat(60));
80 output.push('\n');
81
82 output
83 }
84
85 fn display_sources(&self) -> String {
87 let mut output = String::from("**配置来源:**\n\n");
88
89 let sources = self.config_manager.get_config_source_info();
90
91 output.push_str("| 优先级 | 来源 | 路径 | 状态 |\n");
92 output.push_str("|--------|------|------|------|\n");
93
94 for info in sources {
95 let status = if info.exists { "OK" } else { "未找到" };
96 let path = info
97 .path
98 .as_ref()
99 .map(|p| p.display().to_string())
100 .unwrap_or_else(|| "N/A".to_string());
101
102 output.push_str(&format!(
103 "| {} | {:?} | {} | {} |\n",
104 info.priority, info.source, path, status
105 ));
106 }
107
108 output.push_str("\n**配置项来源:**\n\n");
109 output.push_str("| 配置键 | 值 | 来源 |\n");
110 output.push_str("|--------|-----|------|\n");
111
112 let config = self.config_manager.get_all();
113 let sources = self.config_manager.get_all_config_sources();
114
115 let important_keys = [
116 "api_key",
117 "model",
118 "max_tokens",
119 "api_provider",
120 "theme",
121 "enable_telemetry",
122 ];
123
124 for key in important_keys {
125 if let Some(value) = config.get(key) {
126 let formatted_value = self.format_value(value);
127 let source = sources.get(key).copied().unwrap_or(ConfigSource::Default);
128 output.push_str(&format!(
129 "| {} | {} | {:?} |\n",
130 key, formatted_value, source
131 ));
132 }
133 }
134
135 output.push('\n');
136 output
137 }
138
139 fn format_value(&self, value: &Value) -> String {
141 match value {
142 Value::Null => "null".to_string(),
143 Value::Bool(b) => b.to_string(),
144 Value::Number(n) => n.to_string(),
145 Value::String(s) => {
146 if s.len() > 30 {
147 format!("{}...", s.get(..27).unwrap_or(s))
148 } else {
149 s.clone()
150 }
151 }
152 Value::Array(_) | Value::Object(_) => {
153 let json = serde_json::to_string(value).unwrap_or_default();
154 if json.len() > 30 {
155 format!("{}...", json.get(..27).unwrap_or(&json))
156 } else {
157 json
158 }
159 }
160 }
161 }
162
163 fn display_backups(&self) -> String {
165 let mut output = String::from("**可用备份:**\n\n");
166
167 let user_backups = self.config_manager.list_backups("user");
168 let project_backups = self.config_manager.list_backups("project");
169 let local_backups = self.config_manager.list_backups("local");
170
171 output.push_str(&format!("用户配置备份: {}\n", user_backups.len()));
172 if let Some(latest) = user_backups.first() {
173 output.push_str(&format!(" 最新: {}\n", latest));
174 }
175
176 output.push_str(&format!("项目配置备份: {}\n", project_backups.len()));
177 if let Some(latest) = project_backups.first() {
178 output.push_str(&format!(" 最新: {}\n", latest));
179 }
180
181 output.push_str(&format!("本地配置备份: {}\n", local_backups.len()));
182 if let Some(latest) = local_backups.first() {
183 output.push_str(&format!(" 最新: {}\n", latest));
184 }
185
186 output.push('\n');
187 output
188 }
189
190 fn display_agents_md(&self) -> String {
192 let parser = AgentsMdParser::default();
193 let info = parser.parse();
194
195 let mut output = String::from("**AGENTS.md 状态:**\n\n");
196
197 if info.exists {
198 let stats = parser.get_stats();
199 let validation = parser.validate();
200
201 output.push_str(&format!("路径: {}\n", info.path.display()));
202 output.push_str("状态: 已找到 ✓\n");
203
204 if let Some(modified) = info.last_modified {
205 if let Ok(duration) = modified.elapsed() {
206 output.push_str(&format!("最后修改: {}秒前\n", duration.as_secs()));
207 }
208 }
209
210 if let Some(stats) = stats {
211 output.push_str(&format!(
212 "大小: {} 字节 ({} 行, {} 字符)\n",
213 stats.size, stats.lines, stats.chars
214 ));
215 }
216
217 if !validation.warnings.is_empty() {
218 output.push_str("\n警告:\n");
219 for warning in validation.warnings {
220 output.push_str(&format!(" - {}\n", warning));
221 }
222 }
223 } else {
224 output.push_str(&format!("路径: {}\n", info.path.display()));
225 output.push_str("状态: 未找到 ✗\n");
226 output.push_str("\n提示: 创建 AGENTS.md 文件为 AI Agent 提供项目指导。\n");
227 }
228
229 output.push('\n');
230 output
231 }
232
233 pub fn get(&self, key: &str) -> String {
235 match self.config_manager.get_with_source::<Value>(key) {
236 Some((value, source, path)) => {
237 let path_info = path.map(|p| format!(" ({:?})", p)).unwrap_or_default();
238 format!(
239 "{} = {} (来源: {:?}{})",
240 key,
241 serde_json::to_string_pretty(&value).unwrap_or_default(),
242 source,
243 path_info
244 )
245 }
246 None => format!("{} = 未设置", key),
247 }
248 }
249
250 pub fn set(&self, key: &str, value: Value, target: &str) -> String {
252 let mut config = HashMap::new();
253 config.insert(key.to_string(), value.clone());
254
255 let result = match target {
256 "local" => self.config_manager.save_local(&config),
257 "project" => self.config_manager.save_project(&config),
258 _ => self.config_manager.save(Some(&config)),
259 };
260
261 match result {
262 Ok(_) => format!("已设置 {} = {:?} 到 {} 配置", key, value, target),
263 Err(e) => format!("设置失败: {}", e),
264 }
265 }
266
267 pub fn list_backups(&self, config_type: &str) -> String {
269 let backups = self.config_manager.list_backups(config_type);
270
271 if backups.is_empty() {
272 return format!("未找到 {} 配置的备份", config_type);
273 }
274
275 let mut output = format!("{} 配置的备份:\n\n", config_type);
276 for (index, backup) in backups.iter().enumerate() {
277 output.push_str(&format!("{}. {}\n", index + 1, backup));
278 }
279 output
280 }
281
282 pub fn restore(
284 &self,
285 backup_filename: &str,
286 config_type: &str,
287 manager: &mut ConfigManager,
288 ) -> String {
289 match manager.restore_from_backup(backup_filename, config_type) {
290 Ok(_) => format!("已从 {} 恢复 {} 配置", backup_filename, config_type),
291 Err(e) => format!("恢复失败: {}", e),
292 }
293 }
294
295 pub fn reset(&self, manager: &mut ConfigManager) -> String {
297 manager.reset();
298 "配置已重置为默认值".to_string()
299 }
300
301 pub fn export_config(&self, mask_secrets: bool) -> String {
303 self.config_manager.export(mask_secrets)
304 }
305
306 pub fn import_config(&self, config_json: &str, manager: &mut ConfigManager) -> String {
308 match manager.import(config_json) {
309 Ok(_) => "配置导入成功".to_string(),
310 Err(e) => format!("导入失败: {}", e),
311 }
312 }
313
314 pub fn help(&self) -> String {
316 r#"
317Aster 配置命令
318
319用法:
320 /config - 显示当前配置
321 /config get <key> - 获取特定配置值
322 /config set <key> <value> - 设置配置值
323 /config backups [type] - 列出可用备份 (user/project/local)
324 /config restore <file> - 从备份恢复配置
325 /config reset - 重置为默认配置
326 /config export - 导出配置(敏感信息已掩码)
327 /config import <json> - 从 JSON 导入配置
328 /config help - 显示此帮助信息
329
330示例:
331 /config get model
332 /config set theme dark
333 /config backups user
334 /config restore settings.2024-01-01T12-00-00.yaml
335
336配置来源(优先级从低到高):
337 0. default - 内置默认值
338 1. userSettings - 用户全局配置 (~/.aster/settings.yaml)
339 2. projectSettings - 项目配置 (./.aster/settings.yaml)
340 3. localSettings - 本地配置 (./.aster/settings.local.yaml)
341 4. envSettings - 环境变量 (ASTER_*)
342 5. flagSettings - 命令行标志 (--settings)
343 6. policySettings - 企业策略 (~/.aster/managed_settings.yaml)
344"#
345 .to_string()
346 }
347}
348
349pub fn create_config_command(config_manager: &ConfigManager) -> ConfigCommand<'_> {
351 ConfigCommand::new(config_manager)
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn test_config_command_help() {
360 let manager = ConfigManager::default();
361 let cmd = ConfigCommand::new(&manager);
362 let help = cmd.help();
363 assert!(help.contains("/config"));
364 assert!(help.contains("配置来源"));
365 }
366
367 #[test]
368 fn test_config_command_get() {
369 let manager = ConfigManager::default();
370 let cmd = ConfigCommand::new(&manager);
371 let result = cmd.get("model");
372 assert!(result.contains("model"));
373 }
374
375 #[test]
376 fn test_config_command_display() {
377 let manager = ConfigManager::default();
378 let cmd = ConfigCommand::new(&manager);
379 let output = cmd.display(ConfigDisplayOptions::default());
380 assert!(output.contains("Aster Configuration"));
381 }
382
383 #[test]
384 fn test_format_value() {
385 let manager = ConfigManager::default();
386 let cmd = ConfigCommand::new(&manager);
387
388 assert_eq!(cmd.format_value(&Value::Bool(true)), "true");
389 assert_eq!(cmd.format_value(&Value::Number(42.into())), "42");
390 assert_eq!(cmd.format_value(&Value::String("test".to_string())), "test");
391 }
392}