Skip to main content

aster/blueprint/
codebase_analyzer.rs

1//! 代码库分析器
2//!
3//! 核心功能:
4//! 1. 扫描代码库目录结构
5//! 2. 检测项目类型和框架
6//! 3. 识别模块和依赖关系
7//! 4. 调用 AI 分析代码语义,理解业务逻辑
8//! 5. 生成蓝图(包含所有已有功能)
9//! 6. 生成任务树(已有功能标记为 passed)
10//!
11//! 注意:不自动批准蓝图,让用户预览后确认
12
13use chrono::Utc;
14use std::collections::HashMap;
15use std::fs;
16use std::path::{Path, PathBuf};
17use tokio::sync::mpsc;
18
19use super::blueprint_manager::BlueprintManager;
20use super::task_tree_manager::TaskTreeManager;
21use super::types::{
22    Blueprint, BlueprintSource, BlueprintStatus, BusinessProcess, ModuleType, MoscowPriority,
23    NfrCategory, NonFunctionalRequirement, ProcessStep, ProcessType, SystemModule, TaskNode,
24    TaskStatus, TaskTree,
25};
26
27// ============================================================================
28// 分析配置
29// ============================================================================
30
31/// 分析器配置
32#[derive(Debug, Clone)]
33pub struct AnalyzerConfig {
34    /// 要分析的根目录
35    pub root_dir: PathBuf,
36    /// 项目名称
37    pub project_name: Option<String>,
38    /// 项目描述
39    pub project_description: Option<String>,
40    /// 忽略的目录
41    pub ignore_dirs: Vec<String>,
42    /// 忽略的文件模式
43    pub ignore_patterns: Vec<String>,
44    /// 最大扫描深度
45    pub max_depth: usize,
46    /// 是否包含测试文件
47    pub include_tests: bool,
48    /// 分析粒度
49    pub granularity: AnalysisGranularity,
50    /// 是否使用 AI 分析语义
51    pub use_ai: bool,
52}
53
54/// 分析粒度
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum AnalysisGranularity {
57    Coarse,
58    Medium,
59    Fine,
60}
61
62impl Default for AnalyzerConfig {
63    fn default() -> Self {
64        Self {
65            root_dir: std::env::current_dir().unwrap_or_default(),
66            project_name: None,
67            project_description: None,
68            ignore_dirs: vec![
69                "node_modules".to_string(),
70                ".git".to_string(),
71                "dist".to_string(),
72                "build".to_string(),
73                "coverage".to_string(),
74                ".next".to_string(),
75                "__pycache__".to_string(),
76                "venv".to_string(),
77                "target".to_string(),
78            ],
79            ignore_patterns: vec![
80                "*.min.js".to_string(),
81                "*.map".to_string(),
82                "*.lock".to_string(),
83                "package-lock.json".to_string(),
84            ],
85            max_depth: 10,
86            include_tests: true,
87            granularity: AnalysisGranularity::Medium,
88            use_ai: true,
89        }
90    }
91}
92
93// ============================================================================
94// 代码结构信息
95// ============================================================================
96
97/// 代码库信息
98#[derive(Debug, Clone)]
99pub struct CodebaseInfo {
100    pub name: String,
101    pub description: String,
102    pub root_dir: PathBuf,
103    pub language: String,
104    pub framework: Option<String>,
105    pub modules: Vec<DetectedModule>,
106    pub dependencies: Vec<String>,
107    pub dev_dependencies: Vec<String>,
108    pub scripts: HashMap<String, String>,
109    pub structure: DirectoryNode,
110    pub stats: CodebaseStats,
111    /// AI 分析结果
112    pub ai_analysis: Option<AIAnalysisResult>,
113}
114
115/// 检测到的模块
116#[derive(Debug, Clone)]
117pub struct DetectedModule {
118    pub name: String,
119    pub path: PathBuf,
120    /// 相对于项目根目录的路径(用于蓝图约束)
121    pub root_path: String,
122    pub module_type: DetectedModuleType,
123    pub files: Vec<PathBuf>,
124    pub exports: Vec<String>,
125    pub imports: Vec<String>,
126    pub responsibilities: Vec<String>,
127    pub suggested_tasks: Vec<String>,
128    /// AI 分析的功能描述
129    pub ai_description: Option<String>,
130    /// AI 分析的核心功能列表
131    pub core_features: Option<Vec<String>>,
132    /// AI 分析的边界约束
133    pub boundary_constraints: Option<Vec<String>>,
134    /// 受保护的核心文件
135    pub protected_files: Option<Vec<String>>,
136}
137
138/// 检测到的模块类型
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum DetectedModuleType {
141    Frontend,
142    Backend,
143    Database,
144    Service,
145    Infrastructure,
146    Other,
147}
148
149impl From<DetectedModuleType> for ModuleType {
150    fn from(t: DetectedModuleType) -> Self {
151        match t {
152            DetectedModuleType::Frontend => ModuleType::Frontend,
153            DetectedModuleType::Backend => ModuleType::Backend,
154            DetectedModuleType::Database => ModuleType::Database,
155            DetectedModuleType::Service => ModuleType::Service,
156            DetectedModuleType::Infrastructure => ModuleType::Infrastructure,
157            DetectedModuleType::Other => ModuleType::Other,
158        }
159    }
160}
161
162/// 目录节点
163#[derive(Debug, Clone)]
164pub struct DirectoryNode {
165    pub name: String,
166    pub path: PathBuf,
167    pub node_type: NodeType,
168    pub children: Vec<DirectoryNode>,
169    pub extension: Option<String>,
170    pub size: Option<u64>,
171}
172
173/// 节点类型
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum NodeType {
176    Directory,
177    File,
178}
179
180/// 代码库统计
181#[derive(Debug, Clone, Default)]
182pub struct CodebaseStats {
183    pub total_files: usize,
184    pub total_dirs: usize,
185    pub total_lines: usize,
186    pub files_by_type: HashMap<String, usize>,
187    pub largest_files: Vec<(PathBuf, usize)>,
188}
189
190/// AI 分析的模块详细信息
191#[derive(Debug, Clone)]
192pub struct AIModuleAnalysis {
193    /// 模块名称
194    pub name: String,
195    /// 模块用途
196    pub purpose: String,
197    /// 职责列表
198    pub responsibilities: Vec<String>,
199    /// 依赖的其他模块
200    pub dependencies: Vec<String>,
201    /// 核心功能列表(用于生成验收测试)
202    pub core_features: Vec<String>,
203    /// 边界约束(不应修改的规则)
204    pub boundary_constraints: Vec<String>,
205    /// 受保护的核心文件(不应随意修改)
206    pub protected_files: Vec<String>,
207    /// 对外暴露的主要接口
208    pub public_interfaces: Vec<String>,
209    /// 内部实现细节(可以重构的部分)
210    pub internal_details: Vec<String>,
211}
212
213/// AI 分析结果
214#[derive(Debug, Clone)]
215pub struct AIAnalysisResult {
216    /// 项目概述
217    pub overview: String,
218    /// 架构模式
219    pub architecture_pattern: String,
220    /// 核心功能列表
221    pub core_features: Vec<String>,
222    /// 模块分析(增强版)
223    pub module_analysis: Vec<AIModuleAnalysis>,
224    /// 业务流程
225    pub business_flows: Vec<BusinessFlowInfo>,
226    /// 架构决策记录
227    pub architecture_decisions: Vec<String>,
228    /// 技术债务
229    pub technical_debts: Vec<String>,
230}
231
232/// 业务流程信息
233#[derive(Debug, Clone)]
234pub struct BusinessFlowInfo {
235    pub name: String,
236    pub description: String,
237    pub steps: Vec<String>,
238}
239
240/// 分析事件
241#[derive(Debug, Clone)]
242pub enum AnalyzerEvent {
243    Started { root_dir: PathBuf },
244    AIStarted,
245    AICompleted { analysis: AIAnalysisResult },
246    AIError { error: String },
247    CodebaseCompleted { stats: CodebaseStats },
248    BlueprintCompleted { blueprint_id: String },
249    TaskTreeCompleted { task_tree_id: String },
250    Completed,
251}
252
253// ============================================================================
254// 代码库分析器
255// ============================================================================
256
257/// 代码库分析器
258pub struct CodebaseAnalyzer {
259    config: AnalyzerConfig,
260    event_sender: Option<mpsc::Sender<AnalyzerEvent>>,
261}
262
263impl CodebaseAnalyzer {
264    /// 创建新的分析器
265    pub fn new(config: AnalyzerConfig) -> Self {
266        Self {
267            config,
268            event_sender: None,
269        }
270    }
271
272    /// 设置事件发送器
273    pub fn with_event_sender(mut self, sender: mpsc::Sender<AnalyzerEvent>) -> Self {
274        self.event_sender = Some(sender);
275        self
276    }
277
278    /// 发送事件
279    async fn emit(&self, event: AnalyzerEvent) {
280        if let Some(ref sender) = self.event_sender {
281            let _ = sender.send(event).await;
282        }
283    }
284
285    // --------------------------------------------------------------------------
286    // 一键分析并生成蓝图
287    // --------------------------------------------------------------------------
288
289    /// 一键分析代码库并生成蓝图和任务树
290    pub async fn analyze_and_generate(
291        &mut self,
292        blueprint_manager: &mut BlueprintManager,
293        task_tree_manager: &mut TaskTreeManager,
294    ) -> Result<AnalyzeResult, String> {
295        self.emit(AnalyzerEvent::Started {
296            root_dir: self.config.root_dir.clone(),
297        })
298        .await;
299
300        // 1. 基础结构分析
301        let mut codebase = self.analyze()?;
302
303        // 更新项目名称和描述
304        if let Some(ref name) = self.config.project_name {
305            codebase.name = name.clone();
306        }
307        if let Some(ref desc) = self.config.project_description {
308            codebase.description = desc.clone();
309        }
310
311        // 2. AI 语义分析(可选)
312        if self.config.use_ai {
313            self.emit(AnalyzerEvent::AIStarted).await;
314            match self.analyze_with_ai(&codebase).await {
315                Ok(analysis) => {
316                    self.emit(AnalyzerEvent::AICompleted {
317                        analysis: analysis.clone(),
318                    })
319                    .await;
320                    // 用 AI 分析结果增强模块信息
321                    self.enhance_modules_with_ai(&mut codebase, &analysis);
322                    codebase.ai_analysis = Some(analysis);
323                }
324                Err(e) => {
325                    self.emit(AnalyzerEvent::AIError { error: e }).await;
326                    // AI 分析失败不阻塞流程
327                }
328            }
329        }
330
331        self.emit(AnalyzerEvent::CodebaseCompleted {
332            stats: codebase.stats.clone(),
333        })
334        .await;
335
336        // 3. 生成蓝图
337        let blueprint = self
338            .generate_blueprint(&codebase, blueprint_manager)
339            .await?;
340        self.emit(AnalyzerEvent::BlueprintCompleted {
341            blueprint_id: blueprint.id.clone(),
342        })
343        .await;
344
345        // 4. 生成任务树(已有功能标记为 passed)
346        let task_tree = self
347            .generate_task_tree_with_passed_status(&blueprint, task_tree_manager)
348            .await?;
349        self.emit(AnalyzerEvent::TaskTreeCompleted {
350            task_tree_id: task_tree.id.clone(),
351        })
352        .await;
353
354        self.emit(AnalyzerEvent::Completed).await;
355
356        Ok(AnalyzeResult {
357            codebase,
358            blueprint,
359            task_tree,
360        })
361    }
362
363    // --------------------------------------------------------------------------
364    // 代码库分析
365    // --------------------------------------------------------------------------
366
367    /// 分析代码库结构
368    pub fn analyze(&self) -> Result<CodebaseInfo, String> {
369        let root_dir = &self.config.root_dir;
370
371        // 检测项目类型和框架
372        let (language, framework) = self.detect_project_type(root_dir)?;
373
374        // 扫描目录结构
375        let structure = self.scan_directory(root_dir, 0)?;
376
377        // 检测模块
378        let modules = self.detect_modules(root_dir, &structure);
379
380        // 读取包依赖
381        let (dependencies, dev_dependencies, scripts) = self.read_package_info(root_dir);
382
383        // 计算统计信息
384        let stats = self.calculate_stats(&structure);
385
386        // 生成项目名称和描述
387        let name = self.config.project_name.clone().unwrap_or_else(|| {
388            root_dir
389                .file_name()
390                .and_then(|n| n.to_str())
391                .unwrap_or("unknown")
392                .to_string()
393        });
394
395        let description = self.config.project_description.clone().unwrap_or_else(|| {
396            self.generate_project_description(&name, &language, framework.as_deref(), &modules)
397        });
398
399        Ok(CodebaseInfo {
400            name,
401            description,
402            root_dir: root_dir.clone(),
403            language,
404            framework,
405            modules,
406            dependencies,
407            dev_dependencies,
408            scripts,
409            structure,
410            stats,
411            ai_analysis: None,
412        })
413    }
414
415    /// 检测项目类型
416    fn detect_project_type(&self, root_dir: &Path) -> Result<(String, Option<String>), String> {
417        let entries: Vec<_> = fs::read_dir(root_dir)
418            .map_err(|e| format!("无法读取目录: {}", e))?
419            .filter_map(|e| e.ok())
420            .map(|e| e.file_name().to_string_lossy().to_string())
421            .collect();
422
423        // TypeScript/JavaScript
424        if entries.iter().any(|f| f == "package.json") {
425            let pkg_path = root_dir.join("package.json");
426            if let Ok(content) = fs::read_to_string(&pkg_path) {
427                if let Ok(pkg) = serde_json::from_str::<serde_json::Value>(&content) {
428                    let deps = pkg.get("dependencies").and_then(|d| d.as_object());
429                    let dev_deps = pkg.get("devDependencies").and_then(|d| d.as_object());
430
431                    let has_dep = |name: &str| {
432                        deps.map(|d| d.contains_key(name)).unwrap_or(false)
433                            || dev_deps.map(|d| d.contains_key(name)).unwrap_or(false)
434                    };
435
436                    let language = if entries.iter().any(|f| f == "tsconfig.json") {
437                        "TypeScript"
438                    } else {
439                        "JavaScript"
440                    };
441
442                    let framework = if has_dep("react") || has_dep("react-dom") {
443                        Some("React")
444                    } else if has_dep("vue") {
445                        Some("Vue")
446                    } else if has_dep("@angular/core") {
447                        Some("Angular")
448                    } else if has_dep("next") {
449                        Some("Next.js")
450                    } else if has_dep("express") {
451                        Some("Express")
452                    } else if has_dep("fastify") {
453                        Some("Fastify")
454                    } else if has_dep("@nestjs/core") {
455                        Some("NestJS")
456                    } else {
457                        None
458                    };
459
460                    return Ok((language.to_string(), framework.map(|s| s.to_string())));
461                }
462            }
463        }
464
465        // Rust
466        if entries.iter().any(|f| f == "Cargo.toml") {
467            return Ok(("Rust".to_string(), None));
468        }
469
470        // Python
471        if entries
472            .iter()
473            .any(|f| f == "requirements.txt" || f == "setup.py" || f == "pyproject.toml")
474        {
475            let mut framework = None;
476            let req_path = root_dir.join("requirements.txt");
477            if let Ok(content) = fs::read_to_string(&req_path) {
478                if content.contains("django") {
479                    framework = Some("Django".to_string());
480                } else if content.contains("flask") {
481                    framework = Some("Flask".to_string());
482                } else if content.contains("fastapi") {
483                    framework = Some("FastAPI".to_string());
484                }
485            }
486            return Ok(("Python".to_string(), framework));
487        }
488
489        // Go
490        if entries.iter().any(|f| f == "go.mod") {
491            return Ok(("Go".to_string(), None));
492        }
493
494        // Java
495        if entries
496            .iter()
497            .any(|f| f == "pom.xml" || f == "build.gradle")
498        {
499            return Ok(("Java".to_string(), Some("Spring".to_string())));
500        }
501
502        Ok(("Unknown".to_string(), None))
503    }
504
505    /// 扫描目录结构
506    fn scan_directory(&self, dir_path: &Path, depth: usize) -> Result<DirectoryNode, String> {
507        let name = dir_path
508            .file_name()
509            .and_then(|n| n.to_str())
510            .unwrap_or("")
511            .to_string();
512
513        // 检查深度限制
514        if depth > self.config.max_depth {
515            return Ok(DirectoryNode {
516                name,
517                path: dir_path.to_path_buf(),
518                node_type: NodeType::Directory,
519                children: vec![],
520                extension: None,
521                size: None,
522            });
523        }
524
525        // 检查是否应该忽略
526        if self.config.ignore_dirs.contains(&name) {
527            return Ok(DirectoryNode {
528                name,
529                path: dir_path.to_path_buf(),
530                node_type: NodeType::Directory,
531                children: vec![],
532                extension: None,
533                size: None,
534            });
535        }
536
537        let metadata = fs::metadata(dir_path).map_err(|e| format!("无法读取元数据: {}", e))?;
538
539        if metadata.is_file() {
540            let extension = dir_path
541                .extension()
542                .and_then(|e| e.to_str())
543                .map(|s| s.to_string());
544            return Ok(DirectoryNode {
545                name,
546                path: dir_path.to_path_buf(),
547                node_type: NodeType::File,
548                children: vec![],
549                extension,
550                size: Some(metadata.len()),
551            });
552        }
553
554        let mut children = Vec::new();
555        let entries = fs::read_dir(dir_path).map_err(|e| format!("无法读取目录: {}", e))?;
556
557        for entry in entries.filter_map(|e| e.ok()) {
558            let entry_name = entry.file_name().to_string_lossy().to_string();
559
560            // 检查是否应该忽略
561            if self.config.ignore_dirs.contains(&entry_name) {
562                continue;
563            }
564            if self.should_ignore(&entry_name) {
565                continue;
566            }
567
568            if let Ok(child) = self.scan_directory(&entry.path(), depth + 1) {
569                children.push(child);
570            }
571        }
572
573        Ok(DirectoryNode {
574            name,
575            path: dir_path.to_path_buf(),
576            node_type: NodeType::Directory,
577            children,
578            extension: None,
579            size: None,
580        })
581    }
582
583    /// 检查是否应该忽略
584    fn should_ignore(&self, name: &str) -> bool {
585        for pattern in &self.config.ignore_patterns {
586            if self.match_pattern(name, pattern) {
587                return true;
588            }
589        }
590        false
591    }
592
593    /// 简单的模式匹配
594    fn match_pattern(&self, name: &str, pattern: &str) -> bool {
595        let regex_pattern = format!("^{}$", pattern.replace("*", ".*"));
596        regex::Regex::new(&regex_pattern)
597            .map(|r| r.is_match(name))
598            .unwrap_or(false)
599    }
600
601    /// 检测模块
602    fn detect_modules(&self, root_dir: &Path, structure: &DirectoryNode) -> Vec<DetectedModule> {
603        let mut modules = Vec::new();
604        self.scan_for_modules(structure, 0, "", &mut modules, root_dir);
605
606        // 如果没有检测到模块,尝试从 src 目录递归
607        if modules.is_empty() {
608            if let Some(src_dir) = structure.children.iter().find(|c| c.name == "src") {
609                self.scan_for_modules(src_dir, 1, "src", &mut modules, root_dir);
610            }
611        }
612
613        // 如果还是没有,把 src 整体作为一个模块
614        if modules.is_empty() {
615            if let Some(src_dir) = structure.children.iter().find(|c| c.name == "src") {
616                modules.push(DetectedModule {
617                    name: "main".to_string(),
618                    path: src_dir.path.clone(),
619                    root_path: "src".to_string(),
620                    module_type: DetectedModuleType::Backend,
621                    files: self.collect_files(src_dir),
622                    exports: vec![],
623                    imports: vec![],
624                    responsibilities: vec!["主要业务逻辑".to_string()],
625                    suggested_tasks: vec!["代码重构".to_string(), "添加测试".to_string()],
626                    ai_description: None,
627                    core_features: None,
628                    boundary_constraints: None,
629                    protected_files: None,
630                });
631            }
632        }
633
634        modules
635    }
636
637    /// 递归扫描模块
638    fn scan_for_modules(
639        &self,
640        node: &DirectoryNode,
641        depth: usize,
642        parent_path: &str,
643        modules: &mut Vec<DetectedModule>,
644        root_dir: &Path,
645    ) {
646        if node.node_type != NodeType::Directory || depth > 3 {
647            return;
648        }
649
650        for child in &node.children {
651            if child.node_type != NodeType::Directory {
652                continue;
653            }
654            if self.config.ignore_dirs.contains(&child.name) {
655                continue;
656            }
657
658            // 检查是否匹配模块模式
659            let (module_type, is_leaf) = self.match_module_pattern(&child.name);
660
661            if let Some(mt) = module_type {
662                if is_leaf {
663                    // 叶子模块:直接添加
664                    if let Some(module) = self.analyze_module_deep(child, mt, parent_path, root_dir)
665                    {
666                        if !module.files.is_empty() {
667                            modules.push(module);
668                        }
669                    }
670                } else {
671                    // 非叶子模块:继续递归
672                    let new_parent = if parent_path.is_empty() {
673                        child.name.clone()
674                    } else {
675                        format!("{}/{}", parent_path, child.name)
676                    };
677                    self.scan_for_modules(child, depth + 1, &new_parent, modules, root_dir);
678                }
679            } else if depth > 0 {
680                // 如果没有匹配但有大量代码文件,也识别为模块
681                let files = self.collect_files(child);
682                let code_files: Vec<_> = files
683                    .iter()
684                    .filter(|f| {
685                        let ext = f.extension().and_then(|e| e.to_str()).unwrap_or("");
686                        matches!(ext, "ts" | "tsx" | "js" | "jsx" | "py" | "go" | "rs")
687                    })
688                    .collect();
689
690                if code_files.len() >= 5 {
691                    let inferred_type = self.infer_module_type(&child.name, &files);
692                    if let Some(module) =
693                        self.analyze_module_deep(child, inferred_type, parent_path, root_dir)
694                    {
695                        modules.push(module);
696                    }
697                }
698            }
699        }
700    }
701
702    /// 匹配模块模式
703    fn match_module_pattern(&self, name: &str) -> (Option<DetectedModuleType>, bool) {
704        let name_lower = name.to_lowercase();
705
706        // 前端模块(叶子)
707        if matches!(
708            name_lower.as_str(),
709            "client" | "frontend" | "pages" | "components" | "ui"
710        ) {
711            return (Some(DetectedModuleType::Frontend), true);
712        }
713        // 后端模块(叶子)
714        if matches!(name_lower.as_str(), "server" | "api" | "routes" | "core") {
715            return (Some(DetectedModuleType::Backend), true);
716        }
717        // 数据库模块(叶子)
718        if matches!(name_lower.as_str(), "database" | "db" | "models") {
719            return (Some(DetectedModuleType::Database), true);
720        }
721        // 服务模块(叶子)
722        if matches!(
723            name_lower.as_str(),
724            "services"
725                | "utils"
726                | "helpers"
727                | "tools"
728                | "blueprint"
729                | "parser"
730                | "hooks"
731                | "plugins"
732        ) {
733            return (Some(DetectedModuleType::Service), true);
734        }
735        // 基础设施模块(叶子)
736        if matches!(name_lower.as_str(), "config" | "infra" | "deploy") {
737            return (Some(DetectedModuleType::Infrastructure), true);
738        }
739        // 非叶子模块(需要继续递归)
740        if matches!(name_lower.as_str(), "lib" | "src" | "web") {
741            return (Some(DetectedModuleType::Backend), false);
742        }
743
744        (None, false)
745    }
746
747    /// 根据文件内容推断模块类型
748    fn infer_module_type(&self, _name: &str, files: &[PathBuf]) -> DetectedModuleType {
749        let has_react = files.iter().any(|f| {
750            let ext = f.extension().and_then(|e| e.to_str()).unwrap_or("");
751            ext == "tsx" || ext == "jsx"
752        });
753        let has_routes = files.iter().any(|f| {
754            let name = f.file_name().and_then(|n| n.to_str()).unwrap_or("");
755            name.contains("route") || name.contains("api")
756        });
757        let has_models = files.iter().any(|f| {
758            let name = f.file_name().and_then(|n| n.to_str()).unwrap_or("");
759            name.contains("model") || name.contains("schema")
760        });
761        let has_config = files.iter().any(|f| {
762            let name = f.file_name().and_then(|n| n.to_str()).unwrap_or("");
763            name.contains("config") || name.contains(".env")
764        });
765
766        if has_react {
767            DetectedModuleType::Frontend
768        } else if has_models {
769            DetectedModuleType::Database
770        } else if has_routes {
771            DetectedModuleType::Backend
772        } else if has_config {
773            DetectedModuleType::Infrastructure
774        } else {
775            DetectedModuleType::Service
776        }
777    }
778
779    /// 深度分析模块
780    fn analyze_module_deep(
781        &self,
782        node: &DirectoryNode,
783        module_type: DetectedModuleType,
784        parent_path: &str,
785        root_dir: &Path,
786    ) -> Option<DetectedModule> {
787        let files = self.collect_files(node);
788        if files.is_empty() {
789            return None;
790        }
791
792        // 生成语义化的模块名称
793        let module_name = if parent_path.is_empty() {
794            node.name.clone()
795        } else {
796            format!("{}/{}", parent_path, node.name)
797        };
798
799        // 计算相对于项目根目录的路径
800        let root_path = node
801            .path
802            .strip_prefix(root_dir)
803            .map(|p| p.to_string_lossy().to_string())
804            .unwrap_or_else(|_| node.name.clone());
805
806        // 生成职责描述
807        let responsibilities = self.infer_responsibilities(&node.name, module_type, &files);
808
809        // 生成建议任务
810        let suggested_tasks = self.generate_suggested_tasks(module_type, &files);
811
812        // 提取导出的主要符号
813        let exports = self.extract_exports_from_index(node);
814
815        // 提取依赖的其他模块
816        let imports = self.extract_imports_from_files(&files);
817
818        Some(DetectedModule {
819            name: module_name,
820            path: node.path.clone(),
821            root_path,
822            module_type,
823            files,
824            exports,
825            imports,
826            responsibilities,
827            suggested_tasks,
828            ai_description: None,
829            core_features: None,
830            boundary_constraints: None,
831            protected_files: None,
832        })
833    }
834
835    /// 收集目录下的所有文件
836    fn collect_files(&self, node: &DirectoryNode) -> Vec<PathBuf> {
837        let mut files = Vec::new();
838
839        if node.node_type == NodeType::File {
840            files.push(node.path.clone());
841        } else {
842            for child in &node.children {
843                files.extend(self.collect_files(child));
844            }
845        }
846
847        files
848    }
849
850    /// 推断模块职责
851    fn infer_responsibilities(
852        &self,
853        _name: &str,
854        module_type: DetectedModuleType,
855        files: &[PathBuf],
856    ) -> Vec<String> {
857        let mut responsibilities = Vec::new();
858
859        match module_type {
860            DetectedModuleType::Frontend => {
861                responsibilities.push("用户界面渲染".to_string());
862                responsibilities.push("用户交互处理".to_string());
863                if files.iter().any(|f| {
864                    let name = f.to_string_lossy();
865                    name.contains("state") || name.contains("store")
866                }) {
867                    responsibilities.push("状态管理".to_string());
868                }
869            }
870            DetectedModuleType::Backend => {
871                responsibilities.push("业务逻辑处理".to_string());
872                responsibilities.push("API 接口提供".to_string());
873                if files.iter().any(|f| f.to_string_lossy().contains("auth")) {
874                    responsibilities.push("认证授权".to_string());
875                }
876            }
877            DetectedModuleType::Database => {
878                responsibilities.push("数据持久化".to_string());
879                responsibilities.push("数据模型定义".to_string());
880                responsibilities.push("数据库迁移".to_string());
881            }
882            DetectedModuleType::Service => {
883                responsibilities.push("通用服务提供".to_string());
884                responsibilities.push("工具函数".to_string());
885            }
886            DetectedModuleType::Infrastructure => {
887                responsibilities.push("配置管理".to_string());
888                responsibilities.push("部署脚本".to_string());
889            }
890            DetectedModuleType::Other => {
891                responsibilities.push("其他功能".to_string());
892            }
893        }
894
895        responsibilities
896    }
897
898    /// 生成建议任务
899    fn generate_suggested_tasks(
900        &self,
901        module_type: DetectedModuleType,
902        files: &[PathBuf],
903    ) -> Vec<String> {
904        let mut tasks = vec!["代码审查和重构".to_string()];
905
906        // 检查是否有测试文件
907        let has_tests = files.iter().any(|f| {
908            let name = f.to_string_lossy();
909            name.contains(".test.") || name.contains(".spec.") || name.contains("__tests__")
910        });
911        if !has_tests {
912            tasks.push("添加单元测试".to_string());
913        }
914
915        match module_type {
916            DetectedModuleType::Frontend => {
917                tasks.push("UI/UX 优化".to_string());
918                tasks.push("性能优化".to_string());
919            }
920            DetectedModuleType::Backend => {
921                tasks.push("API 文档完善".to_string());
922                tasks.push("错误处理优化".to_string());
923            }
924            DetectedModuleType::Database => {
925                tasks.push("索引优化".to_string());
926                tasks.push("数据迁移脚本".to_string());
927            }
928            _ => {}
929        }
930
931        tasks
932    }
933
934    /// 从 index 文件提取导出的符号
935    fn extract_exports_from_index(&self, node: &DirectoryNode) -> Vec<String> {
936        let mut exports = Vec::new();
937
938        // 查找 index 文件
939        let index_file = node.children.iter().find(|c| {
940            c.node_type == NodeType::File
941                && (c.name == "index.ts"
942                    || c.name == "index.js"
943                    || c.name == "mod.rs"
944                    || c.name == "lib.rs")
945        });
946
947        if let Some(index) = index_file {
948            if let Ok(content) = fs::read_to_string(&index.path) {
949                // TypeScript/JavaScript: export const/function/class
950                let re = regex::Regex::new(
951                    r"export\s+(?:const|function|class|type|interface|enum)\s+(\w+)",
952                )
953                .ok();
954                if let Some(re) = re {
955                    for cap in re.captures_iter(&content) {
956                        if let Some(name) = cap.get(1) {
957                            exports.push(name.as_str().to_string());
958                        }
959                    }
960                }
961
962                // Rust: pub use/pub mod
963                let re_rust = regex::Regex::new(r"pub\s+(?:use|mod)\s+(\w+)").ok();
964                if let Some(re) = re_rust {
965                    for cap in re.captures_iter(&content) {
966                        if let Some(name) = cap.get(1) {
967                            exports.push(name.as_str().to_string());
968                        }
969                    }
970                }
971            }
972        }
973
974        exports.into_iter().take(20).collect()
975    }
976
977    /// 从文件中提取导入的模块
978    fn extract_imports_from_files(&self, files: &[PathBuf]) -> Vec<String> {
979        use once_cell::sync::Lazy;
980
981        static RE_TS_IMPORT: Lazy<regex::Regex> =
982            Lazy::new(|| regex::Regex::new(r#"import\s+.*from\s+['"](\.[^'"]+)['"]"#).unwrap());
983        static RE_RUST_USE: Lazy<regex::Regex> =
984            Lazy::new(|| regex::Regex::new(r"use\s+(?:crate|super)::(\w+)").unwrap());
985
986        let mut imports = std::collections::HashSet::new();
987
988        // 只检查前 10 个文件
989        for file in files.iter().take(10) {
990            let ext = file.extension().and_then(|e| e.to_str()).unwrap_or("");
991            if !matches!(ext, "ts" | "tsx" | "js" | "rs") {
992                continue;
993            }
994
995            if let Ok(content) = fs::read_to_string(file) {
996                // TypeScript/JavaScript 相对路径导入
997                for cap in RE_TS_IMPORT.captures_iter(&content) {
998                    if let Some(import_path) = cap.get(1) {
999                        let parts: Vec<&str> = import_path
1000                            .as_str()
1001                            .split('/')
1002                            .filter(|p| *p != "." && *p != "..")
1003                            .collect();
1004                        if let Some(first) = parts.first() {
1005                            imports.insert(first.to_string());
1006                        }
1007                    }
1008                }
1009
1010                // Rust use 语句
1011                for cap in RE_RUST_USE.captures_iter(&content) {
1012                    if let Some(name) = cap.get(1) {
1013                        imports.insert(name.as_str().to_string());
1014                    }
1015                }
1016            }
1017        }
1018
1019        imports.into_iter().collect()
1020    }
1021
1022    /// 读取包信息
1023    fn read_package_info(
1024        &self,
1025        root_dir: &Path,
1026    ) -> (Vec<String>, Vec<String>, HashMap<String, String>) {
1027        let pkg_path = root_dir.join("package.json");
1028
1029        if !pkg_path.exists() {
1030            // 尝试读取 Cargo.toml
1031            let cargo_path = root_dir.join("Cargo.toml");
1032            if cargo_path.exists() {
1033                if let Ok(content) = fs::read_to_string(&cargo_path) {
1034                    let mut deps = Vec::new();
1035                    let mut in_deps = false;
1036                    for line in content.lines() {
1037                        if line.starts_with("[dependencies]") {
1038                            in_deps = true;
1039                            continue;
1040                        }
1041                        if line.starts_with('[') {
1042                            in_deps = false;
1043                        }
1044                        if in_deps {
1045                            if let Some(name) = line.split('=').next() {
1046                                let name = name.trim();
1047                                if !name.is_empty() {
1048                                    deps.push(name.to_string());
1049                                }
1050                            }
1051                        }
1052                    }
1053                    return (deps, vec![], HashMap::new());
1054                }
1055            }
1056            return (vec![], vec![], HashMap::new());
1057        }
1058
1059        if let Ok(content) = fs::read_to_string(&pkg_path) {
1060            if let Ok(pkg) = serde_json::from_str::<serde_json::Value>(&content) {
1061                let deps = pkg
1062                    .get("dependencies")
1063                    .and_then(|d| d.as_object())
1064                    .map(|d| d.keys().cloned().collect())
1065                    .unwrap_or_default();
1066
1067                let dev_deps = pkg
1068                    .get("devDependencies")
1069                    .and_then(|d| d.as_object())
1070                    .map(|d| d.keys().cloned().collect())
1071                    .unwrap_or_default();
1072
1073                let scripts = pkg
1074                    .get("scripts")
1075                    .and_then(|s| s.as_object())
1076                    .map(|s| {
1077                        s.iter()
1078                            .filter_map(|(k, v)| v.as_str().map(|v| (k.clone(), v.to_string())))
1079                            .collect()
1080                    })
1081                    .unwrap_or_default();
1082
1083                return (deps, dev_deps, scripts);
1084            }
1085        }
1086
1087        (vec![], vec![], HashMap::new())
1088    }
1089
1090    /// 计算统计信息
1091    fn calculate_stats(&self, structure: &DirectoryNode) -> CodebaseStats {
1092        let mut stats = CodebaseStats::default();
1093        let mut file_sizes: Vec<(PathBuf, usize)> = Vec::new();
1094
1095        self.traverse_for_stats(structure, &mut stats, &mut file_sizes);
1096
1097        // 排序获取最大文件
1098        file_sizes.sort_by(|a, b| b.1.cmp(&a.1));
1099        stats.largest_files = file_sizes.into_iter().take(10).collect();
1100
1101        stats
1102    }
1103
1104    /// 递归遍历统计
1105    fn traverse_for_stats(
1106        &self,
1107        node: &DirectoryNode,
1108        stats: &mut CodebaseStats,
1109        file_sizes: &mut Vec<(PathBuf, usize)>,
1110    ) {
1111        match node.node_type {
1112            NodeType::File => {
1113                stats.total_files += 1;
1114                let ext = node
1115                    .extension
1116                    .clone()
1117                    .unwrap_or_else(|| "unknown".to_string());
1118                *stats.files_by_type.entry(ext).or_insert(0) += 1;
1119
1120                // 尝试计算行数
1121                if let Ok(content) = fs::read_to_string(&node.path) {
1122                    let lines = content.lines().count();
1123                    stats.total_lines += lines;
1124                    file_sizes.push((node.path.clone(), lines));
1125                }
1126            }
1127            NodeType::Directory => {
1128                stats.total_dirs += 1;
1129                for child in &node.children {
1130                    self.traverse_for_stats(child, stats, file_sizes);
1131                }
1132            }
1133        }
1134    }
1135
1136    /// 生成项目描述
1137    fn generate_project_description(
1138        &self,
1139        name: &str,
1140        language: &str,
1141        framework: Option<&str>,
1142        modules: &[DetectedModule],
1143    ) -> String {
1144        let mut parts = Vec::new();
1145
1146        parts.push(format!("{} 是一个", name));
1147
1148        if let Some(fw) = framework {
1149            parts.push(format!("基于 {} 框架的", fw));
1150        }
1151
1152        parts.push(format!("{} 项目。", language));
1153
1154        if !modules.is_empty() {
1155            parts.push(format!("包含 {} 个主要模块:", modules.len()));
1156            let module_names: Vec<_> = modules.iter().map(|m| m.name.as_str()).collect();
1157            parts.push(format!("{}。", module_names.join("、")));
1158        }
1159
1160        parts.join("")
1161    }
1162
1163    // --------------------------------------------------------------------------
1164    // AI 语义分析
1165    // --------------------------------------------------------------------------
1166
1167    /// 使用 AI 分析代码语义
1168    async fn analyze_with_ai(&self, codebase: &CodebaseInfo) -> Result<AIAnalysisResult, String> {
1169        // 构建分析上下文
1170        let _context = self.build_ai_context(codebase);
1171
1172        // 这里应该调用 AI 客户端进行分析
1173        // 由于 Rust 版本可能没有直接的 AI 客户端,返回基于规则的分析结果
1174        Ok(self.generate_rule_based_analysis(codebase))
1175    }
1176
1177    /// 构建 AI 分析上下文
1178    fn build_ai_context(&self, codebase: &CodebaseInfo) -> String {
1179        let mut lines = Vec::new();
1180
1181        lines.push(format!("# 项目: {}", codebase.name));
1182        lines.push(format!("语言: {}", codebase.language));
1183        if let Some(ref fw) = codebase.framework {
1184            lines.push(format!("框架: {}", fw));
1185        }
1186        lines.push(String::new());
1187
1188        lines.push("## 检测到的模块".to_string());
1189        for module in &codebase.modules {
1190            lines.push(format!(
1191                "- {} ({:?}): {} 文件",
1192                module.name,
1193                module.module_type,
1194                module.files.len()
1195            ));
1196        }
1197        lines.push(String::new());
1198
1199        lines.push("## 依赖".to_string());
1200        let deps: Vec<_> = codebase.dependencies.iter().take(20).collect();
1201        lines.push(format!(
1202            "主要依赖: {}",
1203            deps.iter()
1204                .map(|s| s.as_str())
1205                .collect::<Vec<_>>()
1206                .join(", ")
1207        ));
1208
1209        lines.join("\n")
1210    }
1211
1212    /// 基于规则的分析(AI 失败时的后备方案)
1213    fn generate_rule_based_analysis(&self, codebase: &CodebaseInfo) -> AIAnalysisResult {
1214        let mut core_features = Vec::new();
1215
1216        // 根据模块推断功能
1217        for module in &codebase.modules {
1218            core_features.extend(module.responsibilities.clone());
1219        }
1220
1221        // 根据依赖推断功能
1222        if codebase
1223            .dependencies
1224            .iter()
1225            .any(|d| d == "express" || d == "fastify")
1226        {
1227            core_features.push("HTTP API 服务".to_string());
1228        }
1229        if codebase
1230            .dependencies
1231            .iter()
1232            .any(|d| d == "monaster" || d == "prisma")
1233        {
1234            core_features.push("数据库操作".to_string());
1235        }
1236        if codebase
1237            .dependencies
1238            .iter()
1239            .any(|d| d == "react" || d == "vue")
1240        {
1241            core_features.push("前端界面".to_string());
1242        }
1243
1244        // 去重
1245        core_features.sort();
1246        core_features.dedup();
1247
1248        AIAnalysisResult {
1249            overview: codebase.description.clone(),
1250            architecture_pattern: self.infer_architecture_pattern(codebase),
1251            core_features,
1252            module_analysis: codebase
1253                .modules
1254                .iter()
1255                .map(|m| AIModuleAnalysis {
1256                    name: m.name.clone(),
1257                    purpose: format!("{:?} 模块", m.module_type),
1258                    responsibilities: m.responsibilities.clone(),
1259                    dependencies: m.imports.clone(),
1260                    core_features: m.responsibilities.iter().take(3).cloned().collect(),
1261                    boundary_constraints: self.infer_boundary_constraints(m.module_type),
1262                    protected_files: self.infer_protected_files(m),
1263                    public_interfaces: m.exports.clone(),
1264                    internal_details: vec![],
1265                })
1266                .collect(),
1267            business_flows: vec![],
1268            architecture_decisions: vec![],
1269            technical_debts: vec![],
1270        }
1271    }
1272
1273    /// 推断架构模式
1274    fn infer_architecture_pattern(&self, codebase: &CodebaseInfo) -> String {
1275        let module_types: Vec<_> = codebase.modules.iter().map(|m| m.module_type).collect();
1276
1277        if module_types.contains(&DetectedModuleType::Frontend)
1278            && module_types.contains(&DetectedModuleType::Backend)
1279        {
1280            return "前后端分离".to_string();
1281        }
1282        if codebase.dependencies.iter().any(|d| d == "@nestjs/core") {
1283            return "NestJS 模块化架构".to_string();
1284        }
1285        if codebase
1286            .structure
1287            .children
1288            .iter()
1289            .any(|c| c.name == "services")
1290        {
1291            return "微服务架构".to_string();
1292        }
1293        "MVC / 分层架构".to_string()
1294    }
1295
1296    /// 推断模块的边界约束
1297    fn infer_boundary_constraints(&self, module_type: DetectedModuleType) -> Vec<String> {
1298        match module_type {
1299            DetectedModuleType::Frontend => vec![
1300                "不应直接访问数据库".to_string(),
1301                "业务逻辑应通过 API 调用后端".to_string(),
1302            ],
1303            DetectedModuleType::Backend => vec![
1304                "不应包含 UI 渲染逻辑".to_string(),
1305                "数据验证应在 API 边界完成".to_string(),
1306            ],
1307            DetectedModuleType::Database => vec![
1308                "不应包含业务逻辑".to_string(),
1309                "数据模型变更需要迁移脚本".to_string(),
1310            ],
1311            DetectedModuleType::Service => {
1312                vec!["应保持无状态".to_string(), "不应依赖特定框架".to_string()]
1313            }
1314            DetectedModuleType::Infrastructure => vec![
1315                "配置不应硬编码".to_string(),
1316                "敏感信息应使用环境变量".to_string(),
1317            ],
1318            DetectedModuleType::Other => vec![],
1319        }
1320    }
1321
1322    /// 推断受保护的核心文件
1323    fn infer_protected_files(&self, module: &DetectedModule) -> Vec<String> {
1324        let mut protected = Vec::new();
1325
1326        for file in &module.files {
1327            let file_name = file.file_name().and_then(|n| n.to_str()).unwrap_or("");
1328
1329            // index 文件通常是模块入口
1330            if file_name.starts_with("index.") || file_name == "mod.rs" || file_name == "lib.rs" {
1331                protected.push(file.to_string_lossy().to_string());
1332            }
1333            // 类型定义文件
1334            if file_name == "types.ts" || file_name.ends_with(".d.ts") || file_name == "types.rs" {
1335                protected.push(file.to_string_lossy().to_string());
1336            }
1337            // 配置文件
1338            if file_name.contains("config") || file_name.contains("constants") {
1339                protected.push(file.to_string_lossy().to_string());
1340            }
1341        }
1342
1343        protected.into_iter().take(10).collect()
1344    }
1345
1346    /// 用 AI 分析结果增强模块信息
1347    fn enhance_modules_with_ai(&self, codebase: &mut CodebaseInfo, analysis: &AIAnalysisResult) {
1348        for module in &mut codebase.modules {
1349            // 尝试匹配 AI 分析的模块
1350            let ai_module = self.find_matching_ai_module(&module.name, &analysis.module_analysis);
1351
1352            if let Some(ai_mod) = ai_module {
1353                module.ai_description = Some(ai_mod.purpose.clone());
1354
1355                // 合并职责
1356                let mut responsibilities = module.responsibilities.clone();
1357                responsibilities.extend(ai_mod.responsibilities.clone());
1358                responsibilities.sort();
1359                responsibilities.dedup();
1360                module.responsibilities = responsibilities;
1361
1362                // 核心功能
1363                module.core_features = Some(if !ai_mod.core_features.is_empty() {
1364                    ai_mod.core_features.clone()
1365                } else {
1366                    module.responsibilities.iter().take(3).cloned().collect()
1367                });
1368
1369                // 边界约束
1370                module.boundary_constraints = Some(if !ai_mod.boundary_constraints.is_empty() {
1371                    ai_mod.boundary_constraints.clone()
1372                } else {
1373                    self.infer_boundary_constraints(module.module_type)
1374                });
1375
1376                // 受保护文件
1377                let mut protected = ai_mod.protected_files.clone();
1378                protected.extend(self.infer_protected_files(module));
1379                protected.sort();
1380                protected.dedup();
1381                module.protected_files = Some(protected.into_iter().take(10).collect());
1382
1383                // 合并导出信息
1384                if !ai_mod.public_interfaces.is_empty() {
1385                    let mut exports = module.exports.clone();
1386                    exports.extend(ai_mod.public_interfaces.clone());
1387                    exports.sort();
1388                    exports.dedup();
1389                    module.exports = exports;
1390                }
1391            } else {
1392                // AI 没有分析到这个模块,使用规则推断
1393                module.core_features =
1394                    Some(module.responsibilities.iter().take(3).cloned().collect());
1395                module.boundary_constraints =
1396                    Some(self.infer_boundary_constraints(module.module_type));
1397                module.protected_files = Some(self.infer_protected_files(module));
1398            }
1399        }
1400    }
1401
1402    /// 查找匹配的 AI 模块分析结果
1403    fn find_matching_ai_module<'a>(
1404        &self,
1405        module_name: &str,
1406        ai_modules: &'a [AIModuleAnalysis],
1407    ) -> Option<&'a AIModuleAnalysis> {
1408        let normalized_name = module_name.to_lowercase();
1409
1410        // 1. 尝试完全匹配
1411        if let Some(m) = ai_modules
1412            .iter()
1413            .find(|m| m.name.to_lowercase() == normalized_name)
1414        {
1415            return Some(m);
1416        }
1417
1418        // 2. 尝试部分匹配
1419        let last_part = normalized_name
1420            .rsplit('/')
1421            .next()
1422            .unwrap_or(&normalized_name);
1423        if let Some(m) = ai_modules.iter().find(|m| {
1424            let ai_last = m.name.to_lowercase();
1425            let ai_last = ai_last.rsplit('/').next().unwrap_or(&ai_last);
1426            ai_last == last_part
1427        }) {
1428            return Some(m);
1429        }
1430
1431        // 3. 尝试包含匹配
1432        ai_modules.iter().find(|m| {
1433            let ai_name = m.name.to_lowercase();
1434            ai_name.contains(last_part) || last_part.contains(&ai_name)
1435        })
1436    }
1437
1438    // --------------------------------------------------------------------------
1439    // 生成蓝图
1440    // --------------------------------------------------------------------------
1441
1442    /// 从代码库信息生成蓝图
1443    async fn generate_blueprint(
1444        &self,
1445        codebase: &CodebaseInfo,
1446        blueprint_manager: &mut BlueprintManager,
1447    ) -> Result<Blueprint, String> {
1448        // 创建蓝图
1449        let blueprint = blueprint_manager
1450            .create_blueprint(codebase.name.clone(), codebase.description.clone())
1451            .await
1452            .map_err(|e| e.to_string())?;
1453
1454        // 添加模块
1455        for module in &codebase.modules {
1456            let tech_stack = self.infer_tech_stack(codebase, module);
1457            let sys_module = SystemModule {
1458                id: uuid::Uuid::new_v4().to_string(),
1459                name: module.name.clone(),
1460                description: module
1461                    .ai_description
1462                    .clone()
1463                    .unwrap_or_else(|| format!("{} 模块 - {:?}", module.name, module.module_type)),
1464                module_type: module.module_type.into(),
1465                responsibilities: module.responsibilities.clone(),
1466                dependencies: vec![],
1467                interfaces: vec![],
1468                tech_stack: Some(tech_stack),
1469                root_path: Some(module.root_path.clone()),
1470            };
1471            blueprint_manager
1472                .add_module(&blueprint.id, sys_module)
1473                .await
1474                .map_err(|e| e.to_string())?;
1475        }
1476
1477        // 添加业务流程
1478        if let Some(ref analysis) = codebase.ai_analysis {
1479            if !analysis.business_flows.is_empty() {
1480                for flow in &analysis.business_flows {
1481                    let process = BusinessProcess {
1482                        id: uuid::Uuid::new_v4().to_string(),
1483                        name: flow.name.clone(),
1484                        description: flow.description.clone(),
1485                        process_type: ProcessType::ToBe,
1486                        steps: flow
1487                            .steps
1488                            .iter()
1489                            .enumerate()
1490                            .map(|(i, step)| ProcessStep {
1491                                id: uuid::Uuid::new_v4().to_string(),
1492                                order: i as u32 + 1,
1493                                name: step.clone(),
1494                                description: step.clone(),
1495                                actor: "系统".to_string(),
1496                                system_action: Some(step.clone()),
1497                                user_action: None,
1498                                conditions: vec![],
1499                                outcomes: vec![],
1500                            })
1501                            .collect(),
1502                        actors: vec!["系统".to_string(), "用户".to_string()],
1503                        inputs: vec![],
1504                        outputs: vec![],
1505                    };
1506                    blueprint_manager
1507                        .add_business_process(&blueprint.id, process)
1508                        .await
1509                        .map_err(|e| e.to_string())?;
1510                }
1511            }
1512        }
1513
1514        // 添加默认业务流程(如果没有 AI 分析结果)
1515        if codebase.ai_analysis.is_none()
1516            || codebase
1517                .ai_analysis
1518                .as_ref()
1519                .map(|a| a.business_flows.is_empty())
1520                .unwrap_or(true)
1521        {
1522            let default_process = BusinessProcess {
1523                id: uuid::Uuid::new_v4().to_string(),
1524                name: "开发维护流程".to_string(),
1525                description: "现有项目的开发和维护流程".to_string(),
1526                process_type: ProcessType::ToBe,
1527                steps: vec![
1528                    ProcessStep {
1529                        id: uuid::Uuid::new_v4().to_string(),
1530                        order: 1,
1531                        name: "需求分析".to_string(),
1532                        description: "分析新功能需求或 bug 修复需求".to_string(),
1533                        actor: "开发者".to_string(),
1534                        system_action: None,
1535                        user_action: Some("分析需求".to_string()),
1536                        conditions: vec![],
1537                        outcomes: vec!["需求文档".to_string()],
1538                    },
1539                    ProcessStep {
1540                        id: uuid::Uuid::new_v4().to_string(),
1541                        order: 2,
1542                        name: "编写测试".to_string(),
1543                        description: "根据需求编写测试用例".to_string(),
1544                        actor: "开发者".to_string(),
1545                        system_action: None,
1546                        user_action: Some("编写测试".to_string()),
1547                        conditions: vec!["需求文档".to_string()],
1548                        outcomes: vec!["测试用例".to_string()],
1549                    },
1550                    ProcessStep {
1551                        id: uuid::Uuid::new_v4().to_string(),
1552                        order: 3,
1553                        name: "编写代码".to_string(),
1554                        description: "实现功能或修复 bug".to_string(),
1555                        actor: "开发者".to_string(),
1556                        system_action: None,
1557                        user_action: Some("编写代码".to_string()),
1558                        conditions: vec!["测试用例".to_string()],
1559                        outcomes: vec!["代码实现".to_string()],
1560                    },
1561                ],
1562                actors: vec!["开发者".to_string()],
1563                inputs: vec![],
1564                outputs: vec![],
1565            };
1566            blueprint_manager
1567                .add_business_process(&blueprint.id, default_process)
1568                .await
1569                .map_err(|e| e.to_string())?;
1570        }
1571
1572        // 添加非功能性要求
1573        let nfr = NonFunctionalRequirement {
1574            id: uuid::Uuid::new_v4().to_string(),
1575            category: NfrCategory::Maintainability,
1576            name: "代码可维护性".to_string(),
1577            description: "保持代码清晰、有文档、有测试".to_string(),
1578            priority: MoscowPriority::Must,
1579            metric: None,
1580        };
1581        blueprint_manager
1582            .add_nfr(&blueprint.id, nfr)
1583            .await
1584            .map_err(|e| e.to_string())?;
1585
1586        // 重要:从代码逆向生成的蓝图,直接标记为 approved 状态
1587        // 重新获取蓝图以获取最新状态
1588        let mut blueprint = blueprint_manager
1589            .get_blueprint(&blueprint.id)
1590            .await
1591            .ok_or_else(|| "蓝图不存在".to_string())?;
1592        blueprint.status = BlueprintStatus::Approved;
1593        blueprint.approved_at = Some(Utc::now());
1594        blueprint.approved_by = Some("system".to_string());
1595        blueprint.source = Some(BlueprintSource::Codebase);
1596
1597        Ok(blueprint)
1598    }
1599
1600    /// 生成任务树(已有功能标记为 passed)
1601    async fn generate_task_tree_with_passed_status(
1602        &self,
1603        blueprint: &Blueprint,
1604        task_tree_manager: &mut TaskTreeManager,
1605    ) -> Result<TaskTree, String> {
1606        // 先用标准方法生成任务树
1607        let mut task_tree = task_tree_manager
1608            .generate_from_blueprint(blueprint)
1609            .await
1610            .map_err(|e| e.to_string())?;
1611
1612        // 递归标记所有任务为 passed
1613        Self::mark_all_tasks_as_passed(&mut task_tree.root);
1614
1615        // 更新统计
1616        task_tree.stats = task_tree_manager.calculate_stats(&task_tree.root);
1617        task_tree.status = super::types::TaskTreeStatus::Completed;
1618
1619        Ok(task_tree)
1620    }
1621
1622    /// 递归标记所有任务为已完成
1623    fn mark_all_tasks_as_passed(task: &mut TaskNode) {
1624        task.status = TaskStatus::Passed;
1625        task.completed_at = Some(Utc::now());
1626
1627        for child in &mut task.children {
1628            Self::mark_all_tasks_as_passed(child);
1629        }
1630    }
1631
1632    /// 推断技术栈
1633    fn infer_tech_stack(&self, codebase: &CodebaseInfo, module: &DetectedModule) -> Vec<String> {
1634        let mut stack = Vec::new();
1635
1636        stack.push(codebase.language.clone());
1637
1638        if let Some(ref fw) = codebase.framework {
1639            stack.push(fw.clone());
1640        }
1641
1642        // 根据模块类型添加常见技术
1643        match module.module_type {
1644            DetectedModuleType::Frontend => {
1645                if codebase.dependencies.iter().any(|d| d == "react") {
1646                    stack.push("React".to_string());
1647                }
1648                if codebase.dependencies.iter().any(|d| d == "vue") {
1649                    stack.push("Vue".to_string());
1650                }
1651                if codebase.dependencies.iter().any(|d| d == "tailwindcss") {
1652                    stack.push("Tailwind CSS".to_string());
1653                }
1654            }
1655            DetectedModuleType::Backend => {
1656                if codebase.dependencies.iter().any(|d| d == "express") {
1657                    stack.push("Express".to_string());
1658                }
1659                if codebase.dependencies.iter().any(|d| d == "fastify") {
1660                    stack.push("Fastify".to_string());
1661                }
1662            }
1663            DetectedModuleType::Database => {
1664                if codebase.dependencies.iter().any(|d| d == "prisma") {
1665                    stack.push("Prisma".to_string());
1666                }
1667                if codebase.dependencies.iter().any(|d| d == "monaster") {
1668                    stack.push("MongoDB".to_string());
1669                }
1670            }
1671            _ => {}
1672        }
1673
1674        stack
1675    }
1676
1677    /// 设置根目录
1678    pub fn set_root_dir(&mut self, root_dir: PathBuf) {
1679        self.config.root_dir = root_dir;
1680    }
1681}
1682
1683// ============================================================================
1684// 分析结果
1685// ============================================================================
1686
1687/// 分析结果
1688#[derive(Debug, Clone)]
1689pub struct AnalyzeResult {
1690    pub codebase: CodebaseInfo,
1691    pub blueprint: Blueprint,
1692    pub task_tree: TaskTree,
1693}
1694
1695// ============================================================================
1696// 工厂函数
1697// ============================================================================
1698
1699/// 创建代码库分析器
1700pub fn create_codebase_analyzer(config: AnalyzerConfig) -> CodebaseAnalyzer {
1701    CodebaseAnalyzer::new(config)
1702}
1703
1704/// 快捷函数:一键分析并生成蓝图
1705pub async fn quick_analyze(
1706    root_dir: PathBuf,
1707    blueprint_manager: &mut BlueprintManager,
1708    task_tree_manager: &mut TaskTreeManager,
1709) -> Result<AnalyzeResult, String> {
1710    let config = AnalyzerConfig {
1711        root_dir,
1712        ..Default::default()
1713    };
1714    let mut analyzer = CodebaseAnalyzer::new(config);
1715    analyzer
1716        .analyze_and_generate(blueprint_manager, task_tree_manager)
1717        .await
1718}