Skip to main content

aster/blueprint/
task_tree_manager.rs

1//! 任务树管理器
2//!
3//!
4//! 负责:
5//! 1. 从蓝图生成任务树
6//! 2. 任务树的 CRUD 操作
7//! 3. 任务状态管理
8//! 4. 检查点(时光倒流)管理
9//! 5. 任务树统计
10
11use anyhow::{anyhow, Result};
12use chrono::Utc;
13use std::collections::HashMap;
14use std::path::PathBuf;
15use std::sync::Arc;
16use tokio::sync::RwLock;
17use uuid::Uuid;
18
19use super::types::*;
20
21// ============================================================================
22// 任务树管理器
23// ============================================================================
24
25/// 任务树管理器
26#[allow(dead_code)]
27pub struct TaskTreeManager {
28    /// 任务树存储
29    task_trees: Arc<RwLock<HashMap<String, TaskTree>>>,
30    /// 当前任务树 ID
31    current_tree_id: Arc<RwLock<Option<String>>>,
32    /// 当前蓝图引用
33    current_blueprint: Arc<RwLock<Option<Blueprint>>>,
34    /// 存储目录
35    storage_dir: PathBuf,
36}
37
38impl TaskTreeManager {
39    /// 创建新的任务树管理器
40    pub fn new(storage_dir: PathBuf) -> Self {
41        Self {
42            task_trees: Arc::new(RwLock::new(HashMap::new())),
43            current_tree_id: Arc::new(RwLock::new(None)),
44            current_blueprint: Arc::new(RwLock::new(None)),
45            storage_dir,
46        }
47    }
48
49    /// 从默认目录创建
50    pub fn with_default_dir() -> Self {
51        let storage_dir = dirs::home_dir()
52            .unwrap_or_else(|| PathBuf::from("."))
53            .join(".aster")
54            .join("task-trees");
55        Self::new(storage_dir)
56    }
57
58    /// 设置当前蓝图
59    pub async fn set_current_blueprint(&self, blueprint: Blueprint) {
60        *self.current_blueprint.write().await = Some(blueprint);
61    }
62
63    /// 获取当前蓝图
64    pub async fn get_current_blueprint(&self) -> Option<Blueprint> {
65        self.current_blueprint.read().await.clone()
66    }
67
68    // ------------------------------------------------------------------------
69    // 从蓝图生成任务树
70    // ------------------------------------------------------------------------
71
72    /// 从蓝图生成任务树
73    pub async fn generate_from_blueprint(&self, blueprint: &Blueprint) -> Result<TaskTree> {
74        // 保存蓝图引用
75        *self.current_blueprint.write().await = Some(blueprint.clone());
76
77        // 创建根任务节点
78        let mut root_task = self.create_root_task(blueprint);
79
80        // 为每个系统模块创建任务分支
81        for module in &blueprint.modules {
82            let module_task = self.create_module_task(module, &root_task.id, 1);
83            root_task.children.push(module_task);
84        }
85
86        // 处理模块间的依赖关系
87        self.resolve_dependencies(&mut root_task, &blueprint.modules);
88
89        // 创建任务树
90        let mut task_tree = TaskTree::new(blueprint.id.clone(), root_task);
91        task_tree.stats = self.calculate_stats(&task_tree.root);
92
93        // 保存
94        let tree_id = task_tree.id.clone();
95        self.task_trees
96            .write()
97            .await
98            .insert(tree_id.clone(), task_tree.clone());
99        *self.current_tree_id.write().await = Some(tree_id);
100
101        Ok(task_tree)
102    }
103
104    /// 创建根任务
105    fn create_root_task(&self, blueprint: &Blueprint) -> TaskNode {
106        let mut task = TaskNode::new(
107            format!("项目:{}", blueprint.name),
108            blueprint.description.clone(),
109            0,
110        );
111        task.priority = 100;
112        task
113    }
114
115    /// 为系统模块创建任务分支
116    fn create_module_task(&self, module: &SystemModule, parent_id: &str, depth: u32) -> TaskNode {
117        let mut module_task = TaskNode::new(
118            format!("模块:{}", module.name),
119            module.description.clone(),
120            depth,
121        );
122        module_task.parent_id = Some(parent_id.to_string());
123        module_task.blueprint_module_id = Some(module.id.clone());
124        module_task.priority = self.calculate_module_priority(module);
125        module_task.metadata = Some(serde_json::json!({
126            "moduleType": format!("{:?}", module.module_type),
127            "techStack": module.tech_stack,
128        }));
129
130        // 为每个职责创建子任务
131        for (i, responsibility) in module.responsibilities.iter().enumerate() {
132            let resp_task =
133                self.create_responsibility_task(responsibility, &module_task.id, depth + 1, i);
134            module_task.children.push(resp_task);
135        }
136
137        // 为每个接口创建子任务
138        for iface in &module.interfaces {
139            let iface_task = self.create_interface_task(iface, &module_task.id, depth + 1);
140            module_task.children.push(iface_task);
141        }
142
143        module_task
144    }
145
146    /// 为职责创建任务
147    fn create_responsibility_task(
148        &self,
149        responsibility: &str,
150        parent_id: &str,
151        depth: u32,
152        index: usize,
153    ) -> TaskNode {
154        let mut task = TaskNode::new(
155            format!("功能:{}", responsibility),
156            responsibility.to_string(),
157            depth,
158        );
159        task.parent_id = Some(parent_id.to_string());
160        task.priority = 50 - index as i32;
161
162        // 为每个功能创建更细粒度的子任务
163        let subtasks = self.decompose_responsibility(responsibility, &task.id, depth + 1);
164        task.children = subtasks;
165
166        task
167    }
168
169    /// 分解职责为更细粒度的任务
170    fn decompose_responsibility(
171        &self,
172        responsibility: &str,
173        parent_id: &str,
174        depth: u32,
175    ) -> Vec<TaskNode> {
176        let subtask_templates = [
177            ("设计", format!("设计 {} 的实现方案", responsibility)),
178            ("测试用例", format!("编写 {} 的测试用例", responsibility)),
179            ("实现", format!("实现 {}", responsibility)),
180            ("集成测试", format!("{} 的集成测试", responsibility)),
181        ];
182
183        subtask_templates
184            .iter()
185            .enumerate()
186            .map(|(i, (name, desc))| {
187                let short_resp = if responsibility.len() > 20 {
188                    // Find safe UTF-8 boundary for truncation
189                    let truncate_at = responsibility
190                        .char_indices()
191                        .take_while(|(idx, _)| *idx < 20)
192                        .last()
193                        .map(|(idx, c)| idx + c.len_utf8())
194                        .unwrap_or(0);
195                    format!(
196                        "{}...",
197                        responsibility.get(..truncate_at).unwrap_or(responsibility)
198                    )
199                } else {
200                    responsibility.to_string()
201                };
202
203                let mut task =
204                    TaskNode::new(format!("{}:{}", name, short_resp), desc.clone(), depth);
205                task.parent_id = Some(parent_id.to_string());
206                task.priority = 40 - (i as i32 * 10);
207                task
208            })
209            .collect()
210    }
211
212    /// 为接口创建任务
213    fn create_interface_task(
214        &self,
215        iface: &ModuleInterface,
216        parent_id: &str,
217        depth: u32,
218    ) -> TaskNode {
219        let mut task = TaskNode::new(
220            format!("接口:{}", iface.name),
221            format!("{:?} 接口 - {}", iface.interface_type, iface.description),
222            depth,
223        );
224        task.parent_id = Some(parent_id.to_string());
225        task.priority = 30;
226        task.metadata = Some(serde_json::json!({
227            "interfaceType": format!("{:?}", iface.interface_type),
228        }));
229        task
230    }
231
232    /// 计算模块优先级
233    fn calculate_module_priority(&self, module: &SystemModule) -> i32 {
234        let type_priority = match module.module_type {
235            ModuleType::Infrastructure => 90,
236            ModuleType::Database => 85,
237            ModuleType::Backend => 80,
238            ModuleType::Service => 70,
239            ModuleType::Frontend => 60,
240            ModuleType::Other => 50,
241        };
242
243        // 依赖越少优先级越高
244        let dep_penalty = module.dependencies.len() as i32 * 5;
245        type_priority - dep_penalty
246    }
247
248    /// 解析模块间依赖关系
249    fn resolve_dependencies(&self, root_task: &mut TaskNode, modules: &[SystemModule]) {
250        // 创建模块 ID 到任务 ID 的映射
251        let module_to_task: HashMap<String, String> = root_task
252            .children
253            .iter()
254            .filter_map(|child| {
255                child
256                    .blueprint_module_id
257                    .as_ref()
258                    .map(|mid| (mid.clone(), child.id.clone()))
259            })
260            .collect();
261
262        // 更新任务依赖
263        for child in &mut root_task.children {
264            if let Some(module_id) = &child.blueprint_module_id {
265                if let Some(module) = modules.iter().find(|m| &m.id == module_id) {
266                    for dep_module_id in &module.dependencies {
267                        if let Some(dep_task_id) = module_to_task.get(dep_module_id) {
268                            child.dependencies.push(dep_task_id.clone());
269                        }
270                    }
271                }
272            }
273        }
274    }
275
276    // ------------------------------------------------------------------------
277    // 任务状态管理
278    // ------------------------------------------------------------------------
279
280    /// 更新任务状态
281    pub async fn update_task_status(
282        &self,
283        tree_id: &str,
284        task_id: &str,
285        status: TaskStatus,
286    ) -> Result<TaskNode> {
287        let mut trees = self.task_trees.write().await;
288        let tree = trees
289            .get_mut(tree_id)
290            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
291
292        let task = Self::find_task_mut(&mut tree.root, task_id)
293            .ok_or_else(|| anyhow!("Task {} not found", task_id))?;
294
295        let _previous_status = task.status;
296        task.status = status;
297
298        // 更新时间戳
299        match status {
300            TaskStatus::Coding | TaskStatus::TestWriting => {
301                if task.started_at.is_none() {
302                    task.started_at = Some(Utc::now());
303                }
304            }
305            TaskStatus::Passed | TaskStatus::Approved => {
306                task.completed_at = Some(Utc::now());
307            }
308            _ => {}
309        }
310
311        let task_clone = task.clone();
312
313        // 更新统计
314        tree.stats = self.calculate_stats(&tree.root);
315
316        // 向上传播状态
317        Self::propagate_status(&mut tree.root);
318
319        Ok(task_clone)
320    }
321
322    /// 在树中查找任务(可变引用)
323    fn find_task_mut<'a>(node: &'a mut TaskNode, task_id: &str) -> Option<&'a mut TaskNode> {
324        if node.id == task_id {
325            return Some(node);
326        }
327
328        for child in &mut node.children {
329            if let Some(found) = Self::find_task_mut(child, task_id) {
330                return Some(found);
331            }
332        }
333
334        None
335    }
336
337    /// 在树中查找任务
338    pub fn find_task<'a>(node: &'a TaskNode, task_id: &str) -> Option<&'a TaskNode> {
339        if node.id == task_id {
340            return Some(node);
341        }
342
343        for child in &node.children {
344            if let Some(found) = Self::find_task(child, task_id) {
345                return Some(found);
346            }
347        }
348
349        None
350    }
351
352    /// 向上传播状态
353    fn propagate_status(node: &mut TaskNode) {
354        if node.children.is_empty() {
355            return;
356        }
357
358        // 先递归处理子节点
359        for child in &mut node.children {
360            Self::propagate_status(child);
361        }
362
363        // 统计子任务状态
364        let all_passed = node
365            .children
366            .iter()
367            .all(|c| c.status == TaskStatus::Passed || c.status == TaskStatus::Approved);
368        let any_failed = node
369            .children
370            .iter()
371            .any(|c| c.status == TaskStatus::TestFailed || c.status == TaskStatus::Rejected);
372        let any_running = node.children.iter().any(|c| {
373            matches!(
374                c.status,
375                TaskStatus::Coding | TaskStatus::Testing | TaskStatus::TestWriting
376            )
377        });
378
379        // 更新父节点状态
380        if all_passed && node.status != TaskStatus::Approved {
381            node.status = TaskStatus::Passed;
382            node.completed_at = Some(Utc::now());
383        } else if any_failed && node.status != TaskStatus::TestFailed {
384            node.status = TaskStatus::TestFailed;
385        } else if any_running && node.status == TaskStatus::Pending {
386            node.status = TaskStatus::Coding;
387            if node.started_at.is_none() {
388                node.started_at = Some(Utc::now());
389            }
390        }
391    }
392
393    /// 检查任务是否可以开始
394    pub async fn can_start_task(&self, tree_id: &str, task_id: &str) -> (bool, Vec<String>) {
395        let trees = self.task_trees.read().await;
396        let tree = match trees.get(tree_id) {
397            Some(t) => t,
398            None => return (false, vec!["任务树不存在".to_string()]),
399        };
400
401        let task = match Self::find_task(&tree.root, task_id) {
402            Some(t) => t,
403            None => return (false, vec!["任务不存在".to_string()]),
404        };
405
406        if task.status != TaskStatus::Pending && task.status != TaskStatus::Blocked {
407            return (
408                false,
409                vec![format!("任务状态为 {:?},不能开始", task.status)],
410            );
411        }
412
413        let mut blockers = Vec::new();
414
415        // 检查依赖
416        for dep_id in &task.dependencies {
417            if let Some(dep_task) = Self::find_task(&tree.root, dep_id) {
418                if dep_task.status != TaskStatus::Passed && dep_task.status != TaskStatus::Approved
419                {
420                    blockers.push(format!(
421                        "依赖任务 \"{}\" 尚未完成 ({:?})",
422                        dep_task.name, dep_task.status
423                    ));
424                }
425            }
426        }
427
428        (blockers.is_empty(), blockers)
429    }
430
431    /// 获取可执行的任务列表
432    pub async fn get_executable_tasks(&self, tree_id: &str) -> Vec<TaskNode> {
433        let trees = self.task_trees.read().await;
434        let tree = match trees.get(tree_id) {
435            Some(t) => t,
436            None => return Vec::new(),
437        };
438
439        let mut executable = Vec::new();
440        self.collect_executable_tasks(&tree.root, &mut executable, tree_id, &trees);
441
442        // 按优先级排序
443        executable.sort_by(|a, b| b.priority.cmp(&a.priority));
444        executable
445    }
446
447    fn collect_executable_tasks(
448        &self,
449        node: &TaskNode,
450        result: &mut Vec<TaskNode>,
451        tree_id: &str,
452        trees: &HashMap<String, TaskTree>,
453    ) {
454        if node.status == TaskStatus::Pending || node.status == TaskStatus::Blocked {
455            // 简化检查:只检查依赖是否完成
456            let can_start = node.dependencies.iter().all(|dep_id| {
457                if let Some(tree) = trees.get(tree_id) {
458                    if let Some(dep_task) = Self::find_task(&tree.root, dep_id) {
459                        return dep_task.status == TaskStatus::Passed
460                            || dep_task.status == TaskStatus::Approved;
461                    }
462                }
463                false
464            }) || node.dependencies.is_empty();
465
466            if can_start {
467                result.push(node.clone());
468            }
469        }
470
471        for child in &node.children {
472            self.collect_executable_tasks(child, result, tree_id, trees);
473        }
474    }
475
476    // ------------------------------------------------------------------------
477    // 检查点管理
478    // ------------------------------------------------------------------------
479
480    /// 创建任务检查点
481    pub async fn create_task_checkpoint(
482        &self,
483        tree_id: &str,
484        task_id: &str,
485        name: String,
486        description: Option<String>,
487    ) -> Result<Checkpoint> {
488        let mut trees = self.task_trees.write().await;
489        let tree = trees
490            .get_mut(tree_id)
491            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
492
493        let task = Self::find_task_mut(&mut tree.root, task_id)
494            .ok_or_else(|| anyhow!("Task {} not found", task_id))?;
495
496        // 收集代码快照
497        let code_snapshot: Vec<CodeSnapshot> = task
498            .code_artifacts
499            .iter()
500            .filter_map(|artifact| {
501                if let (Some(path), Some(content)) = (&artifact.file_path, &artifact.content) {
502                    Some(CodeSnapshot {
503                        file_path: path.clone(),
504                        content: content.clone(),
505                        hash: Self::hash_content(content),
506                    })
507                } else {
508                    None
509                }
510            })
511            .collect();
512
513        let checkpoint = Checkpoint {
514            id: Uuid::new_v4().to_string(),
515            task_id: task_id.to_string(),
516            timestamp: Utc::now(),
517            name,
518            description,
519            task_status: task.status,
520            test_result: task.test_spec.as_ref().and_then(|s| s.last_result.clone()),
521            code_snapshot,
522            can_restore: true,
523            metadata: None,
524        };
525
526        task.checkpoints.push(checkpoint.clone());
527
528        Ok(checkpoint)
529    }
530
531    /// 创建全局检查点
532    pub async fn create_global_checkpoint(
533        &self,
534        tree_id: &str,
535        name: String,
536        description: Option<String>,
537    ) -> Result<GlobalCheckpoint> {
538        let mut trees = self.task_trees.write().await;
539        let tree = trees
540            .get_mut(tree_id)
541            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
542
543        // 序列化整棵树
544        let tree_snapshot = serde_json::to_string(&tree.root)?;
545
546        // 收集所有文件变更
547        let mut file_changes = Vec::new();
548        Self::collect_file_changes(&tree.root, &mut file_changes);
549
550        let checkpoint = GlobalCheckpoint {
551            id: Uuid::new_v4().to_string(),
552            tree_id: tree_id.to_string(),
553            timestamp: Utc::now(),
554            name,
555            description,
556            tree_snapshot,
557            file_changes,
558            can_restore: true,
559        };
560
561        tree.global_checkpoints.push(checkpoint.clone());
562
563        Ok(checkpoint)
564    }
565
566    fn collect_file_changes(node: &TaskNode, changes: &mut Vec<FileChange>) {
567        for artifact in &node.code_artifacts {
568            if let Some(path) = &artifact.file_path {
569                if artifact.artifact_type == ArtifactType::File {
570                    changes.push(FileChange {
571                        file_path: path.clone(),
572                        change_type: FileChangeType::Create,
573                        previous_content: None,
574                        new_content: artifact.content.clone(),
575                    });
576                }
577            }
578        }
579
580        for child in &node.children {
581            Self::collect_file_changes(child, changes);
582        }
583    }
584
585    fn hash_content(content: &str) -> String {
586        use std::collections::hash_map::DefaultHasher;
587        use std::hash::{Hash, Hasher};
588
589        let mut hasher = DefaultHasher::new();
590        content.hash(&mut hasher);
591        format!("{:x}", hasher.finish())
592    }
593
594    /// 回滚到任务检查点
595    pub async fn rollback_to_checkpoint(
596        &self,
597        tree_id: &str,
598        task_id: &str,
599        checkpoint_id: &str,
600    ) -> Result<TaskNode> {
601        let mut trees = self.task_trees.write().await;
602        let tree = trees
603            .get_mut(tree_id)
604            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
605
606        // 先找到任务并完成所有修改,然后克隆结果
607        let task_clone = {
608            let task = Self::find_task_mut(&mut tree.root, task_id)
609                .ok_or_else(|| anyhow!("Task {} not found", task_id))?;
610
611            let checkpoint = task
612                .checkpoints
613                .iter()
614                .find(|c| c.id == checkpoint_id)
615                .ok_or_else(|| anyhow!("Checkpoint {} not found", checkpoint_id))?
616                .clone();
617
618            if !checkpoint.can_restore {
619                return Err(anyhow!("Checkpoint {} cannot be restored", checkpoint_id));
620            }
621
622            // 恢复任务状态
623            task.status = checkpoint.task_status;
624
625            // 恢复测试结果
626            if let Some(ref mut test_spec) = task.test_spec {
627                test_spec.last_result = checkpoint.test_result.clone();
628            }
629
630            // 恢复代码(标记为待恢复的代码产出物)
631            for snapshot in &checkpoint.code_snapshot {
632                task.code_artifacts.push(CodeArtifact {
633                    id: Uuid::new_v4().to_string(),
634                    artifact_type: ArtifactType::File,
635                    file_path: Some(snapshot.file_path.clone()),
636                    content: Some(snapshot.content.clone()),
637                    command: None,
638                    created_at: Utc::now(),
639                    checkpoint_id: Some(checkpoint.id.clone()),
640                });
641            }
642
643            // 删除此检查点之后的所有检查点
644            let checkpoint_index = task
645                .checkpoints
646                .iter()
647                .position(|c| c.id == checkpoint_id)
648                .unwrap_or(0);
649            task.checkpoints.truncate(checkpoint_index + 1);
650
651            task.clone()
652        };
653
654        // 更新统计(此时 task 的可变借用已结束)
655        tree.stats = self.calculate_stats(&tree.root);
656
657        Ok(task_clone)
658    }
659
660    /// 回滚到全局检查点
661    pub async fn rollback_to_global_checkpoint(
662        &self,
663        tree_id: &str,
664        checkpoint_id: &str,
665    ) -> Result<TaskTree> {
666        let mut trees = self.task_trees.write().await;
667        let tree = trees
668            .get_mut(tree_id)
669            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
670
671        let checkpoint = tree
672            .global_checkpoints
673            .iter()
674            .find(|c| c.id == checkpoint_id)
675            .ok_or_else(|| anyhow!("Global checkpoint {} not found", checkpoint_id))?
676            .clone();
677
678        if !checkpoint.can_restore {
679            return Err(anyhow!(
680                "Global checkpoint {} cannot be restored",
681                checkpoint_id
682            ));
683        }
684
685        // 恢复整棵树
686        let restored_root: TaskNode = serde_json::from_str(&checkpoint.tree_snapshot)?;
687        tree.root = restored_root;
688
689        // 删除此检查点之后的所有检查点
690        let checkpoint_index = tree
691            .global_checkpoints
692            .iter()
693            .position(|c| c.id == checkpoint_id)
694            .unwrap_or(0);
695        tree.global_checkpoints.truncate(checkpoint_index + 1);
696
697        // 更新统计
698        tree.stats = self.calculate_stats(&tree.root);
699
700        Ok(tree.clone())
701    }
702
703    // ------------------------------------------------------------------------
704    // 动态任务细化
705    // ------------------------------------------------------------------------
706
707    /// 动态添加子任务
708    pub async fn add_sub_task(
709        &self,
710        tree_id: &str,
711        parent_task_id: &str,
712        name: String,
713        description: String,
714        priority: i32,
715    ) -> Result<TaskNode> {
716        let mut trees = self.task_trees.write().await;
717        let tree = trees
718            .get_mut(tree_id)
719            .ok_or_else(|| anyhow!("Task tree {} not found", tree_id))?;
720
721        let parent_task = Self::find_task_mut(&mut tree.root, parent_task_id)
722            .ok_or_else(|| anyhow!("Parent task {} not found", parent_task_id))?;
723
724        let mut new_task = TaskNode::new(name, description, parent_task.depth + 1);
725        new_task.parent_id = Some(parent_task_id.to_string());
726        new_task.priority = priority;
727
728        let task_clone = new_task.clone();
729        parent_task.children.push(new_task);
730
731        // 更新统计
732        tree.stats = self.calculate_stats(&tree.root);
733
734        Ok(task_clone)
735    }
736
737    // ------------------------------------------------------------------------
738    // 统计
739    // ------------------------------------------------------------------------
740
741    /// 计算任务树统计
742    pub fn calculate_stats(&self, root: &TaskNode) -> TaskTreeStats {
743        let mut stats = TaskTreeStats::default();
744        let mut total_depth = 0u64;
745
746        fn traverse(node: &TaskNode, stats: &mut TaskTreeStats, total_depth: &mut u64) {
747            stats.total_tasks += 1;
748            *total_depth += node.depth as u64;
749
750            if node.depth > stats.max_depth {
751                stats.max_depth = node.depth;
752            }
753
754            match node.status {
755                TaskStatus::Pending => stats.pending_tasks += 1,
756                TaskStatus::Blocked => stats.blocked_tasks += 1,
757                TaskStatus::Coding | TaskStatus::Testing | TaskStatus::TestWriting => {
758                    stats.running_tasks += 1
759                }
760                TaskStatus::Passed | TaskStatus::Approved => stats.passed_tasks += 1,
761                TaskStatus::TestFailed | TaskStatus::Rejected => stats.failed_tasks += 1,
762                _ => {}
763            }
764
765            if node.test_spec.is_some() {
766                stats.total_tests += 1;
767                if let Some(ref spec) = node.test_spec {
768                    if let Some(ref result) = spec.last_result {
769                        if result.passed {
770                            stats.passed_tests += 1;
771                        } else {
772                            stats.failed_tests += 1;
773                        }
774                    }
775                }
776            }
777
778            for child in &node.children {
779                traverse(child, stats, total_depth);
780            }
781        }
782
783        traverse(root, &mut stats, &mut total_depth);
784
785        stats.avg_depth = if stats.total_tasks > 0 {
786            total_depth as f64 / stats.total_tasks as f64
787        } else {
788            0.0
789        };
790
791        stats.progress_percentage = if stats.total_tasks > 0 {
792            ((stats.passed_tasks + stats.failed_tasks) as f64 / stats.total_tasks as f64) * 100.0
793        } else {
794            0.0
795        };
796
797        stats
798    }
799
800    // ------------------------------------------------------------------------
801    // 查询
802    // ------------------------------------------------------------------------
803
804    /// 获取任务树
805    pub async fn get_task_tree(&self, id: &str) -> Option<TaskTree> {
806        let trees = self.task_trees.read().await;
807        trees.get(id).cloned()
808    }
809
810    /// 获取当前任务树
811    pub async fn get_current_task_tree(&self) -> Option<TaskTree> {
812        let current_id = self.current_tree_id.read().await;
813        if let Some(id) = current_id.as_ref() {
814            return self.get_task_tree(id).await;
815        }
816        None
817    }
818
819    /// 获取任务路径(从根到目标任务的路径)
820    pub async fn get_task_path(&self, tree_id: &str, task_id: &str) -> Vec<TaskNode> {
821        let trees = self.task_trees.read().await;
822        let tree = match trees.get(tree_id) {
823            Some(t) => t,
824            None => return Vec::new(),
825        };
826
827        let mut path = Vec::new();
828        Self::find_task_path(&tree.root, task_id, &mut path);
829        path
830    }
831
832    fn find_task_path(node: &TaskNode, task_id: &str, path: &mut Vec<TaskNode>) -> bool {
833        path.push(node.clone());
834
835        if node.id == task_id {
836            return true;
837        }
838
839        for child in &node.children {
840            if Self::find_task_path(child, task_id, path) {
841                return true;
842            }
843        }
844
845        path.pop();
846        false
847    }
848
849    /// 获取所有叶子任务
850    pub async fn get_leaf_tasks(&self, tree_id: &str) -> Vec<TaskNode> {
851        let trees = self.task_trees.read().await;
852        let tree = match trees.get(tree_id) {
853            Some(t) => t,
854            None => return Vec::new(),
855        };
856
857        let mut leaves = Vec::new();
858        Self::collect_leaf_tasks(&tree.root, &mut leaves);
859        leaves
860    }
861
862    fn collect_leaf_tasks(node: &TaskNode, result: &mut Vec<TaskNode>) {
863        if node.children.is_empty() {
864            result.push(node.clone());
865        } else {
866            for child in &node.children {
867                Self::collect_leaf_tasks(child, result);
868            }
869        }
870    }
871}
872
873impl Default for TaskTreeManager {
874    fn default() -> Self {
875        Self::with_default_dir()
876    }
877}
878
879#[cfg(test)]
880mod tests {
881    use super::*;
882
883    #[tokio::test]
884    async fn test_generate_from_blueprint() {
885        let manager = TaskTreeManager::default();
886
887        let mut blueprint = Blueprint::new("测试项目".to_string(), "测试描述".to_string());
888
889        blueprint.modules.push(SystemModule {
890            id: Uuid::new_v4().to_string(),
891            name: "后端模块".to_string(),
892            description: "后端服务".to_string(),
893            module_type: ModuleType::Backend,
894            responsibilities: vec!["用户认证".to_string(), "数据存储".to_string()],
895            dependencies: Vec::new(),
896            interfaces: Vec::new(),
897            tech_stack: Some(vec!["Rust".to_string()]),
898            root_path: Some("src/backend".to_string()),
899        });
900
901        let tree = manager.generate_from_blueprint(&blueprint).await.unwrap();
902
903        assert_eq!(tree.blueprint_id, blueprint.id);
904        assert!(!tree.root.children.is_empty());
905        assert!(tree.stats.total_tasks > 0);
906    }
907
908    #[tokio::test]
909    async fn test_task_status_update() {
910        let manager = TaskTreeManager::default();
911
912        let blueprint = Blueprint::new("测试".to_string(), "描述".to_string());
913        let tree = manager.generate_from_blueprint(&blueprint).await.unwrap();
914
915        // 获取第一个叶子任务
916        let leaves = manager.get_leaf_tasks(&tree.id).await;
917        if let Some(leaf) = leaves.first() {
918            let updated = manager
919                .update_task_status(&tree.id, &leaf.id, TaskStatus::Coding)
920                .await
921                .unwrap();
922
923            assert_eq!(updated.status, TaskStatus::Coding);
924            assert!(updated.started_at.is_some());
925        }
926    }
927}