openmatrix 0.1.98 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/agents/impl/coder-agent.js +42 -42
  2. package/dist/agents/impl/executor-agent.js +75 -75
  3. package/dist/agents/impl/planner-agent.js +63 -63
  4. package/dist/agents/impl/reviewer-agent.js +66 -66
  5. package/dist/agents/impl/tester-agent.js +56 -56
  6. package/dist/cli/commands/report.js +45 -45
  7. package/dist/cli/commands/start.js +163 -34
  8. package/dist/cli/commands/step.js +62 -35
  9. package/dist/orchestrator/ai-reviewer.d.ts +29 -1
  10. package/dist/orchestrator/ai-reviewer.js +312 -207
  11. package/dist/orchestrator/approval-manager.js +14 -13
  12. package/dist/orchestrator/executor.d.ts +10 -1
  13. package/dist/orchestrator/executor.js +56 -2
  14. package/dist/orchestrator/meeting-manager.js +32 -31
  15. package/dist/orchestrator/phase-executor.js +7 -5
  16. package/dist/orchestrator/scheduler.d.ts +8 -6
  17. package/dist/orchestrator/scheduler.js +53 -22
  18. package/dist/orchestrator/state-machine.js +2 -2
  19. package/dist/orchestrator/task-planner.d.ts +81 -2
  20. package/dist/orchestrator/task-planner.js +683 -122
  21. package/dist/storage/state-manager.d.ts +6 -0
  22. package/dist/storage/state-manager.js +28 -0
  23. package/package.json +55 -55
  24. package/scripts/build-check.js +19 -19
  25. package/scripts/install-skills.js +57 -57
  26. package/skills/approve.md +250 -250
  27. package/skills/auto.md +298 -298
  28. package/skills/brainstorm.md +455 -495
  29. package/skills/meeting.md +324 -363
  30. package/skills/om.md +112 -112
  31. package/skills/openmatrix.md +112 -112
  32. package/skills/start.md +63 -97
  33. package/dist/cli/commands/upgrade.d.ts +0 -2
  34. package/dist/cli/commands/upgrade.js +0 -329
  35. package/dist/orchestrator/task-planner.old.d.ts +0 -87
  36. package/dist/orchestrator/task-planner.old.js +0 -444
@@ -16,7 +16,8 @@ const answer_mapper_js_1 = require("./answer-mapper.js");
16
16
  */
17
17
  class TaskPlanner {
18
18
  userAnswers;
19
- taskCounter = 0;
19
+ /** 静态计数器,避免多实例生成重复 ID */
20
+ static taskCounter = 0;
20
21
  constructor(userAnswers) {
21
22
  this.userAnswers = userAnswers || {};
22
23
  }
@@ -27,9 +28,481 @@ class TaskPlanner {
27
28
  this.userAnswers = answers;
28
29
  }
29
30
  /**
30
- * Break down a parsed task into sub-tasks
31
+ * 解析 plan 文本,提取模块、技术栈、数据模型等结构化信息
31
32
  */
33
+ parsePlan(planText) {
34
+ const modules = [];
35
+ const techStack = [];
36
+ // 1. 提取技术栈
37
+ const techStackMatch = planText.match(/(?:技术栈|Technology)[\s\S]*?((?:- .+\n?)+)/i);
38
+ if (techStackMatch) {
39
+ techStackMatch[1].split('\n').forEach(line => {
40
+ const trimmed = line.replace(/^- /, '').trim();
41
+ if (trimmed)
42
+ techStack.push(trimmed);
43
+ });
44
+ }
45
+ // 2. 提取模块定义
46
+ // 模式1: "N领域模块: A、B、C..." 或 "N个领域模块: A, B, C"
47
+ const moduleListMatch = planText.match(/(\d+)\s*(?:个)?领域模块\s*[::]\s*(.+)/i);
48
+ if (moduleListMatch) {
49
+ const moduleNames = moduleListMatch[2]
50
+ .split(/[,,、]/)
51
+ .map(s => s.trim().replace(/域$/, ''))
52
+ .filter(s => s.length > 0 && s.length < 30);
53
+ // 从 plan 中的 "数据模型" 部分提取表信息
54
+ // 通用方式:查找以 "- " 开头的表名/实体名列表,不在模块列表中
55
+ const moduleNamesSet = new Set(moduleNames.map(n => n.toLowerCase()));
56
+ const allTables = [];
57
+ const tableSections = planText.match(/(?:数据模型|database|tables?|schema|实体|模型)[\s\S]*?((?:[-*]\s*.+(?:\n|$))+)/gi);
58
+ if (tableSections) {
59
+ for (const section of tableSections) {
60
+ const tableLines = section.split('\n')
61
+ .map(l => l.replace(/^[-*]\s*/, '').trim())
62
+ .filter(l => l.length > 0 && l.length < 50);
63
+ for (const t of tableLines) {
64
+ // 跳过看起来像模块名的条目
65
+ const tLower = t.toLowerCase();
66
+ if (!moduleNamesSet.has(tLower) && !t.includes(':') && !t.includes('—')) {
67
+ allTables.push(t);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ for (const modName of moduleNames) {
73
+ // 通用方式:从 plan 中查找该模块相关的表(包含模块名的行附近)
74
+ const modLower = modName.toLowerCase();
75
+ const modTables = allTables.filter(t => t.toLowerCase().includes(modLower) ||
76
+ modLower.includes(t.split(/[_\s]/)[0]?.toLowerCase() || ''));
77
+ modules.push({
78
+ name: modName,
79
+ description: `${modName}模块`,
80
+ tables: modTables,
81
+ type: 'domain',
82
+ dependsOn: [],
83
+ complexity: this.estimateModuleComplexity(modName, modTables)
84
+ });
85
+ }
86
+ // 分析模块间依赖
87
+ this.analyzeModuleDependencies(modules, planText);
88
+ }
89
+ // 模式2: 架构设计部分的编号列表 "1. 用户域:描述"
90
+ if (modules.length === 0) {
91
+ const archMatch = planText.match(/架构设计[\s\S]*?((?:\d+\.\s*.+(?:\n|$))+)/i);
92
+ if (archMatch) {
93
+ const lines = archMatch[1].split('\n').filter(l => l.trim());
94
+ for (const line of lines) {
95
+ const modMatch = line.match(/\d+\.\s*(.+?)[::\s](.*)/);
96
+ if (modMatch) {
97
+ const name = modMatch[1].replace(/域$/, '').trim();
98
+ modules.push({
99
+ name,
100
+ description: modMatch[2].trim(),
101
+ tables: [],
102
+ type: 'domain',
103
+ dependsOn: [],
104
+ complexity: this.estimateModuleComplexity(name, [])
105
+ });
106
+ }
107
+ }
108
+ this.analyzeModuleDependencies(modules, planText);
109
+ }
110
+ }
111
+ return { modules, techStack, raw: planText };
112
+ }
113
+ /**
114
+ * 分析模块间依赖关系
115
+ *
116
+ * 策略:从 plan 文本中提取 AI 明确写的依赖信息,不做架构猜测。
117
+ * 如果 plan 中没有指定依赖,模块之间并行执行。
118
+ */
119
+ analyzeModuleDependencies(modules, planText) {
120
+ for (let i = 0; i < modules.length; i++) {
121
+ const mod = modules[i];
122
+ if (mod.dependsOn.length > 0)
123
+ continue; // parsePlan 中已提取的显式依赖,保留
124
+ // 从 plan 文本中查找该模块是否提到依赖其他模块
125
+ // 匹配模式:"X 依赖 Y", "X 基于 Y", "X 使用 Y", "after X", "depends on X"
126
+ const modContext = this.extractModuleContext(planText, mod.name);
127
+ if (modContext) {
128
+ for (const other of modules) {
129
+ if (other.name === mod.name)
130
+ continue;
131
+ // 如果上下文中提到其他模块且暗示依赖关系
132
+ const depPatterns = [
133
+ new RegExp(`${other.name}.*(?:依赖|基于|需要|使用|after|depends)`, 'i'),
134
+ new RegExp(`(?:依赖|基于|需要|使用|after|depends).*${other.name}`, 'i'),
135
+ ];
136
+ for (const pattern of depPatterns) {
137
+ if (pattern.test(modContext)) {
138
+ mod.dependsOn.push(other.name);
139
+ break;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ // 如果 plan 中模块是按顺序编号的,后面编号的模块依赖前面的
145
+ // 这只在模块名称是编号格式时适用(如 "1. 基础架构" → "2. 用户模块")
146
+ // 不做自动推断,保持模块间独立
147
+ }
148
+ }
149
+ /**
150
+ * 从 plan 文本中提取某个模块相关的上下文段落
151
+ */
152
+ extractModuleContext(planText, moduleName) {
153
+ const lines = planText.split('\n');
154
+ const startIdx = lines.findIndex(l => l.includes(moduleName));
155
+ if (startIdx === -1)
156
+ return null;
157
+ // 从匹配行开始,收集到下一个编号标题或空行为止
158
+ const contextLines = [];
159
+ for (let i = startIdx; i < lines.length && i < startIdx + 20; i++) {
160
+ const line = lines[i];
161
+ if (contextLines.length > 0 && line.trim() === '')
162
+ break;
163
+ if (contextLines.length > 0 && /^\d+\./.test(line.trim()))
164
+ break;
165
+ contextLines.push(line);
166
+ }
167
+ return contextLines.join('\n');
168
+ }
169
+ /**
170
+ * 预估模块复杂度 — 基于通用架构特征,不依赖具体业务领域
171
+ */
172
+ estimateModuleComplexity(name, tables) {
173
+ // 表数量是最直接的复杂度指标
174
+ if (tables.length >= 5)
175
+ return 'high';
176
+ if (tables.length >= 3)
177
+ return 'medium';
178
+ // 通用架构关键词
179
+ const highKws = ['核心', '基础', '架构', '主循环', '引擎', '框架', '平台', '系统', 'orchestrator', 'engine', 'core', 'framework'];
180
+ const mediumKws = ['管理', '服务', 'api', '接口', '控制器', '处理器', '管理器', 'manager', 'service', 'handler', 'processor', 'controller'];
181
+ const lowKws = ['工具', '脚本', '配置', '样式', '工具', 'helper', 'util', 'config', 'style', 'theme'];
182
+ const n = name.toLowerCase();
183
+ if (highKws.some(kw => n.includes(kw)))
184
+ return 'high';
185
+ if (lowKws.some(kw => n.includes(kw)))
186
+ return 'low';
187
+ if (mediumKws.some(kw => n.includes(kw)))
188
+ return 'medium';
189
+ // 默认 medium(比默认 low 更保守,避免并行执行冲突)
190
+ return 'medium';
191
+ }
32
192
  breakdown(parsedTask, answers, qualityConfig, plan) {
193
+ // 如果提供了 plan 且解析出模块信息,使用细粒度的模块级拆分
194
+ if (plan) {
195
+ const parsed = this.parsePlan(plan);
196
+ if (parsed.modules.length > 0) {
197
+ return this.breakdownByModules(parsedTask, answers, qualityConfig, parsed, plan);
198
+ }
199
+ }
200
+ // fallback: 按目标拆分的传统方式
201
+ return this.breakdownByGoals(parsedTask, answers, qualityConfig, plan);
202
+ }
203
+ /**
204
+ * 基于 plan 解析出的模块做细粒度任务拆分
205
+ */
206
+ breakdownByModules(parsedTask, answers, qualityConfig, parsedPlan, plan) {
207
+ const breakdowns = [];
208
+ const userContext = this.extractUserContext(answers);
209
+ if (qualityConfig?.e2eTests) {
210
+ userContext.e2eTests = true;
211
+ if (!userContext.e2eType) {
212
+ userContext.e2eType = 'web';
213
+ }
214
+ }
215
+ const coverageTarget = this.getCoverageTarget(qualityConfig, userContext);
216
+ const globalContext = this.buildGlobalContext(parsedTask, userContext, plan);
217
+ // 1. 为每个模块创建开发 + 测试任务对
218
+ const devTaskIds = [];
219
+ const moduleIdToTaskIds = new Map();
220
+ for (const mod of parsedPlan.modules) {
221
+ const modTaskId = this.generateTaskId();
222
+ devTaskIds.push(modTaskId);
223
+ moduleIdToTaskIds.set(mod.name, [modTaskId]);
224
+ // 构建模块描述 — 包含表名、依赖等具体信息
225
+ let modDescription = `## 模块实现: ${mod.name}\n\n${mod.description}\n\n${globalContext}`;
226
+ if (mod.tables.length > 0) {
227
+ modDescription += `\n\n## 数据模型\n需要实现以下数据库表:\n${mod.tables.map(t => `- \`${t}\``).join('\n')}`;
228
+ }
229
+ if (mod.dependsOn.length > 0) {
230
+ modDescription += `\n\n## 模块依赖\n本模块依赖以下模块: ${mod.dependsOn.join(', ')}\n请确保依赖模块的接口已定义并可调用。`;
231
+ }
232
+ modDescription += `\n\n## 输出要求\n- 完成模块实现\n- 代码可编译\n- 遵循项目规范\n- 添加必要注释`;
233
+ // 计算模块任务的实际依赖(转换为 taskId)
234
+ const modDeps = [];
235
+ for (const depName of mod.dependsOn) {
236
+ const depTaskIds = moduleIdToTaskIds.get(depName);
237
+ if (depTaskIds) {
238
+ modDeps.push(...depTaskIds);
239
+ }
240
+ }
241
+ // 同时保留 phase 级别的依赖
242
+ this.enforcePhaseDependenciesForModule(breakdowns, parsedTask, mod, modDeps);
243
+ const complexity = this.estimateModuleComplexity(mod.name, mod.tables);
244
+ breakdowns.push({
245
+ taskId: modTaskId,
246
+ title: `实现: ${mod.name}`,
247
+ description: modDescription,
248
+ priority: this.determineModulePriority(mod, parsedPlan.modules.indexOf(mod)),
249
+ dependencies: modDeps,
250
+ estimatedComplexity: complexity,
251
+ assignedAgent: 'coder',
252
+ phase: 'develop',
253
+ acceptanceCriteria: this.generateModuleAcceptanceCriteria(mod, coverageTarget, userContext),
254
+ testTaskId: undefined
255
+ });
256
+ // 配对的测试任务
257
+ const testTaskId = this.generateTaskId();
258
+ breakdowns.push({
259
+ taskId: testTaskId,
260
+ title: `测试: ${mod.name}`,
261
+ description: `## 测试目标\n为 "${mod.name}" 模块编写测试用例\n\n${globalContext}\n\n## 关联开发任务\n${modTaskId}\n\n## 测试要求\n- 单元测试覆盖率 >= ${coverageTarget}%\n- 测试正常流程\n- 测试边界情况\n- 测试异常处理\n\n## 输出\n- 测试文件\n- 测试报告\n- 覆盖率报告`,
262
+ priority: this.determineModulePriority(mod, parsedPlan.modules.indexOf(mod)),
263
+ dependencies: [modTaskId],
264
+ estimatedComplexity: 'medium',
265
+ assignedAgent: 'tester',
266
+ phase: 'verify',
267
+ acceptanceCriteria: [
268
+ `单元测试覆盖率 >= ${coverageTarget}%`,
269
+ '边界情况已测试',
270
+ '异常处理已验证',
271
+ '所有测试通过'
272
+ ]
273
+ });
274
+ breakdowns[breakdowns.length - 2].testTaskId = testTaskId;
275
+ moduleIdToTaskIds.get(mod.name).push(testTaskId);
276
+ }
277
+ // 2. 系统集成任务
278
+ let integrationTaskId;
279
+ if (devTaskIds.length > 1) {
280
+ integrationTaskId = this.generateTaskId();
281
+ breakdowns.push({
282
+ taskId: integrationTaskId,
283
+ title: '系统集成: 将所有模块组装到主入口,确保可运行',
284
+ description: `将前面所有模块连接在一起,使应用可以完整运行
285
+
286
+ ${globalContext}
287
+
288
+ ## 集成要求
289
+ - 确定项目的主入口文件并实例化所有核心模块
290
+ - 建立模块间通信和数据流
291
+ - 确保应用可以启动并正常运行
292
+
293
+ ## 已完成的模块
294
+ ${parsedPlan.modules.map(m => `- ${m.name} (${m.tables.length > 0 ? '表: ' + m.tables.join(', ') : '无数据模型'})`).join('\n')}
295
+
296
+ ## 输出
297
+ - 更新后的主入口文件
298
+ - 模块连接正确,应用可运行
299
+ - 无运行时错误`,
300
+ priority: 'P0',
301
+ dependencies: [...devTaskIds],
302
+ estimatedComplexity: 'high',
303
+ assignedAgent: 'coder',
304
+ phase: 'develop',
305
+ acceptanceCriteria: [
306
+ '主入口文件已更新',
307
+ '所有核心模块已实例化并连接',
308
+ '应用可以正常启动',
309
+ '无运行时错误',
310
+ '模块间通信正常'
311
+ ]
312
+ });
313
+ }
314
+ // 3. 代码审查任务
315
+ if (devTaskIds.length > 0) {
316
+ const reviewDeps = integrationTaskId
317
+ ? [...devTaskIds, integrationTaskId]
318
+ : [...devTaskIds];
319
+ breakdowns.push({
320
+ taskId: this.generateTaskId(),
321
+ title: '代码审查',
322
+ description: `对所有开发任务进行代码审查
323
+
324
+ ${globalContext}
325
+
326
+ ## 审查范围
327
+ ${parsedPlan.modules.map(m => `- ${m.name}: ${m.description}`).join('\n')}
328
+
329
+ ## 审查要点
330
+ - 代码质量
331
+ - 安全性
332
+ - 性能
333
+ - 最佳实践`,
334
+ priority: 'P1',
335
+ dependencies: reviewDeps,
336
+ estimatedComplexity: 'medium',
337
+ assignedAgent: 'reviewer',
338
+ phase: 'verify',
339
+ acceptanceCriteria: [
340
+ '无严重代码问题',
341
+ '无安全隐患',
342
+ '代码符合规范',
343
+ '审查报告已生成'
344
+ ]
345
+ });
346
+ }
347
+ // 4. 集成测试任务 (如果有多个交付物)
348
+ if (parsedTask.deliverables.length > 1) {
349
+ const integrationTestDeps = integrationTaskId
350
+ ? [...devTaskIds, integrationTaskId]
351
+ : [...devTaskIds];
352
+ breakdowns.push({
353
+ taskId: this.generateTaskId(),
354
+ title: '集成测试',
355
+ description: `验证所有交付物正确集成
356
+
357
+ ${globalContext}
358
+
359
+ ## 测试范围
360
+ - 模块间接口
361
+ - 端到端流程
362
+ - 数据流验证`,
363
+ priority: 'P1',
364
+ dependencies: integrationTestDeps,
365
+ estimatedComplexity: 'medium',
366
+ assignedAgent: 'tester',
367
+ phase: 'verify',
368
+ acceptanceCriteria: [
369
+ '所有模块正确集成',
370
+ '端到端流程通过',
371
+ '接口兼容性验证',
372
+ '集成测试报告完整'
373
+ ]
374
+ });
375
+ }
376
+ // 5. E2E 测试任务
377
+ if (userContext.e2eTests) {
378
+ const e2eTaskId = this.generateTaskId();
379
+ const e2eType = userContext.e2eType || 'web';
380
+ const allTestDeps = [...devTaskIds];
381
+ breakdowns.forEach(b => {
382
+ if (b.phase === 'verify' && b.title.startsWith('测试:')) {
383
+ allTestDeps.push(b.taskId);
384
+ }
385
+ });
386
+ breakdowns.push({
387
+ taskId: e2eTaskId,
388
+ title: '端到端(E2E)测试',
389
+ description: this.buildE2ETestDescription(e2eType, parsedTask, userContext),
390
+ priority: 'P0',
391
+ dependencies: allTestDeps,
392
+ estimatedComplexity: 'high',
393
+ assignedAgent: 'tester',
394
+ phase: 'verify',
395
+ acceptanceCriteria: [
396
+ '所有 E2E 测试用例通过',
397
+ '关键用户流程验证完成',
398
+ '跨浏览器/设备兼容性验证',
399
+ 'E2E 测试报告已生成',
400
+ '无阻塞级别的缺陷'
401
+ ]
402
+ });
403
+ }
404
+ // 6. 文档任务
405
+ if (userContext.documentationLevel && userContext.documentationLevel !== '无需文档') {
406
+ breakdowns.push({
407
+ taskId: this.generateTaskId(),
408
+ title: '文档编写',
409
+ description: `编写项目文档
410
+
411
+ ## 文档级别
412
+ ${userContext.documentationLevel}
413
+
414
+ ## 文档内容
415
+ - README 更新
416
+ - API 文档
417
+ - 使用说明`,
418
+ priority: 'P2',
419
+ dependencies: devTaskIds,
420
+ estimatedComplexity: 'low',
421
+ assignedAgent: 'executor',
422
+ phase: 'accept',
423
+ acceptanceCriteria: [
424
+ 'README 已更新',
425
+ 'API 文档完整',
426
+ '使用说明清晰'
427
+ ]
428
+ });
429
+ }
430
+ return breakdowns;
431
+ }
432
+ /**
433
+ * 为模块任务添加 phase 级别的跨阶段依赖
434
+ */
435
+ enforcePhaseDependenciesForModule(breakdowns, parsedTask, mod, modDeps) {
436
+ // 检测是否有顺序阶段,如果有则添加跨阶段依赖
437
+ const phaseIndices = this.detectSequentialPhases(parsedTask.goals);
438
+ if (phaseIndices.length < 2)
439
+ return;
440
+ // 找出当前模块属于哪个 phase goal
441
+ let currentPhaseIndex = -1;
442
+ for (let pi = 0; pi < phaseIndices.length; pi++) {
443
+ const goalIndex = phaseIndices[pi];
444
+ const goal = parsedTask.goals[goalIndex];
445
+ if (mod.name.toLowerCase().includes(goal.toLowerCase().slice(0, 10)) ||
446
+ goal.toLowerCase().includes(mod.name.toLowerCase().slice(0, 6))) {
447
+ currentPhaseIndex = pi;
448
+ break;
449
+ }
450
+ }
451
+ if (currentPhaseIndex <= 0)
452
+ return;
453
+ // 添加对前一阶段所有模块任务的依赖
454
+ const prevGoalIndex = phaseIndices[currentPhaseIndex - 1];
455
+ for (const b of breakdowns) {
456
+ if (b.phase === 'develop' && b.title.startsWith('实现: ')) {
457
+ // 检查这个任务是否属于前一阶段
458
+ const prevGoal = parsedTask.goals[prevGoalIndex];
459
+ if (b.description.includes(prevGoal)) {
460
+ if (!modDeps.includes(b.taskId)) {
461
+ modDeps.push(b.taskId);
462
+ }
463
+ }
464
+ }
465
+ }
466
+ }
467
+ /**
468
+ * 确定模块任务优先级
469
+ */
470
+ determineModulePriority(mod, index) {
471
+ // 基础设施模块优先级更高
472
+ if (mod.type === 'infra')
473
+ return 'P0';
474
+ // 有依赖的模块通常更核心
475
+ if (mod.dependsOn.length === 0 && index === 0)
476
+ return 'P0';
477
+ if (mod.complexity === 'high')
478
+ return 'P1';
479
+ return 'P2';
480
+ }
481
+ /**
482
+ * 为模块生成验收标准
483
+ */
484
+ generateModuleAcceptanceCriteria(mod, coverageTarget, userContext) {
485
+ const criteria = [
486
+ `模块 "${mod.name}" 功能已实现`,
487
+ '代码可编译,无错误',
488
+ '代码符合项目规范'
489
+ ];
490
+ if (mod.tables.length > 0) {
491
+ criteria.push(`数据库表 ${mod.tables.join(', ')} 已实现并可访问`);
492
+ }
493
+ criteria.push(`测试覆盖率 >= ${coverageTarget}%`);
494
+ criteria.push('必要的注释已添加');
495
+ criteria.push('无安全隐患');
496
+ criteria.push('边界情况已处理');
497
+ if (userContext.techStack?.length) {
498
+ criteria.push(`使用指定技术栈: ${userContext.techStack.join(', ')}`);
499
+ }
500
+ return criteria;
501
+ }
502
+ /**
503
+ * 按目标拆分的传统方式(fallback)
504
+ */
505
+ breakdownByGoals(parsedTask, answers, qualityConfig, plan) {
33
506
  const breakdowns = [];
34
507
  const seenTitles = new Set();
35
508
  const userContext = this.extractUserContext(answers);
@@ -53,13 +526,13 @@ class TaskPlanner {
53
526
  breakdowns.push({
54
527
  taskId: designTaskId,
55
528
  title: '架构设计和任务规划',
56
- description: `分析需求,设计整体架构,规划实现方案
57
-
58
- ${globalContext}
59
-
60
- ## 输出
61
- - 架构设计文档
62
- - 接口定义
529
+ description: `分析需求,设计整体架构,规划实现方案
530
+
531
+ ${globalContext}
532
+
533
+ ## 输出
534
+ - 架构设计文档
535
+ - 接口定义
63
536
  - 任务依赖图`,
64
537
  priority: 'P0',
65
538
  dependencies: [],
@@ -188,25 +661,25 @@ ${globalContext}
188
661
  breakdowns.push({
189
662
  taskId: integrationTaskId,
190
663
  title: '系统集成: 将所有模块组装到主入口,确保可运行',
191
- description: `将前面所有模块连接到主入口文件(main.ts/index.ts),使应用可以完整运行
192
-
193
- ${globalContext}
194
-
195
- ## 集成要求
196
- - 在主入口文件中实例化所有核心模块
197
- - 将子系统连接到主循环(Game/App/Main)
198
- - 确保模块间事件/数据流通
199
- - 确保应用可以启动并正常运行(无运行时错误)
200
-
201
- ## 已完成的模块
202
- ${devTaskIds.map(id => `- ${id}: ${breakdowns.find(b => b.taskId === id)?.title || ''}`).join('\n')}
203
-
204
- ## 输出
205
- - 更新后的主入口文件
206
- - 模块连接正确,应用可运行
207
- - 启动后无运行时错误`,
664
+ description: `将前面所有模块连接在一起,使应用可以完整运行
665
+
666
+ ${globalContext}
667
+
668
+ ## 集成要求
669
+ - 确定项目的主入口文件(如 main.ts, index.ts, App.tsx 等)
670
+ - 实例化所有核心模块并建立模块间通信
671
+ - 确保数据流和事件流通正确
672
+ - 确保应用可以启动并正常运行
673
+
674
+ ## 已完成的模块
675
+ ${devTaskIds.map(id => `- ${id}: ${breakdowns.find(b => b.taskId === id)?.title || ''}`).join('\n')}
676
+
677
+ ## 输出
678
+ - 更新后的主入口文件
679
+ - 模块连接正确,应用可运行
680
+ - 无运行时错误`,
208
681
  priority: 'P0',
209
- dependencies: devTaskIds, // 依赖所有开发任务完成
682
+ dependencies: devTaskIds,
210
683
  estimatedComplexity: 'high',
211
684
  assignedAgent: 'coder',
212
685
  phase: 'develop',
@@ -228,17 +701,17 @@ ${devTaskIds.map(id => `- ${id}: ${breakdowns.find(b => b.taskId === id)?.title
228
701
  breakdowns.push({
229
702
  taskId: this.generateTaskId(),
230
703
  title: '代码审查',
231
- description: `对所有开发任务进行代码审查
232
-
233
- ${globalContext}
234
-
235
- ## 审查范围
236
- ${devTaskIds.map(id => `- ${id}`).join('\n')}
237
-
238
- ## 审查要点
239
- - 代码质量
240
- - 安全性
241
- - 性能
704
+ description: `对所有开发任务进行代码审查
705
+
706
+ ${globalContext}
707
+
708
+ ## 审查范围
709
+ ${devTaskIds.map(id => `- ${id}`).join('\n')}
710
+
711
+ ## 审查要点
712
+ - 代码质量
713
+ - 安全性
714
+ - 性能
242
715
  - 最佳实践`,
243
716
  priority: 'P1',
244
717
  dependencies: reviewDeps,
@@ -261,13 +734,13 @@ ${devTaskIds.map(id => `- ${id}`).join('\n')}
261
734
  breakdowns.push({
262
735
  taskId: this.generateTaskId(),
263
736
  title: '集成测试',
264
- description: `验证所有交付物正确集成
265
-
266
- ${globalContext}
267
-
268
- ## 测试范围
269
- - 模块间接口
270
- - 端到端流程
737
+ description: `验证所有交付物正确集成
738
+
739
+ ${globalContext}
740
+
741
+ ## 测试范围
742
+ - 模块间接口
743
+ - 端到端流程
271
744
  - 数据流验证`,
272
745
  priority: 'P1',
273
746
  dependencies: integrationTestDeps,
@@ -315,14 +788,14 @@ ${globalContext}
315
788
  breakdowns.push({
316
789
  taskId: this.generateTaskId(),
317
790
  title: '文档编写',
318
- description: `编写项目文档
319
-
320
- ## 文档级别
321
- ${userContext.documentationLevel}
322
-
323
- ## 文档内容
324
- - README 更新
325
- - API 文档
791
+ description: `编写项目文档
792
+
793
+ ## 文档级别
794
+ ${userContext.documentationLevel}
795
+
796
+ ## 文档内容
797
+ - README 更新
798
+ - API 文档
326
799
  - 使用说明`,
327
800
  priority: 'P2',
328
801
  dependencies: devTaskIds,
@@ -336,6 +809,8 @@ ${userContext.documentationLevel}
336
809
  ]
337
810
  });
338
811
  }
812
+ // 6. 检测顺序阶段并建立跨阶段依赖(Phase 1 → Phase 2 → Phase 3 → ...)
813
+ this.enforcePhaseDependencies(breakdowns, parsedTask);
339
814
  return breakdowns;
340
815
  }
341
816
  /**
@@ -433,80 +908,80 @@ ${userContext.documentationLevel}
433
908
  return parts.join('\n');
434
909
  }
435
910
  buildTaskDescription(goal, globalContext) {
436
- return `## 当前子任务目标\n${goal}\n\n${globalContext}\n\n## 输出要求
437
- - 完成功能实现
438
- - 代码可编译
439
- - 遵循项目规范
911
+ return `## 当前子任务目标\n${goal}\n\n${globalContext}\n\n## 输出要求
912
+ - 完成功能实现
913
+ - 代码可编译
914
+ - 遵循项目规范
440
915
  - 添加必要注释`;
441
916
  }
442
917
  buildTestDescription(goal, devTaskId, coverageTarget, globalContext) {
443
- return `## 测试目标
444
- 为 "${goal}" 编写测试用例
445
-
446
- ${globalContext}
447
-
448
- ## 关联开发任务
449
- ${devTaskId}
450
-
451
- ## 测试要求
452
- - 单元测试覆盖率 >= ${coverageTarget}%
453
- - 测试正常流程
454
- - 测试边界情况
455
- - 测试异常处理
456
-
457
- ## 测试文件
458
- - 创建 \`.test.ts\` 或 \`.spec.ts\` 文件
459
- - 放置在与源文件相同目录或 \`tests/\` 目录
460
-
461
- ## 输出
462
- - 测试文件
463
- - 测试报告
918
+ return `## 测试目标
919
+ 为 "${goal}" 编写测试用例
920
+
921
+ ${globalContext}
922
+
923
+ ## 关联开发任务
924
+ ${devTaskId}
925
+
926
+ ## 测试要求
927
+ - 单元测试覆盖率 >= ${coverageTarget}%
928
+ - 测试正常流程
929
+ - 测试边界情况
930
+ - 测试异常处理
931
+
932
+ ## 测试文件
933
+ - 创建 \`.test.ts\` 或 \`.spec.ts\` 文件
934
+ - 放置在与源文件相同目录或 \`tests/\` 目录
935
+
936
+ ## 输出
937
+ - 测试文件
938
+ - 测试报告
464
939
  - 覆盖率报告`;
465
940
  }
466
941
  buildE2ETestDescription(e2eType, parsedTask, userContext) {
467
942
  const typeConfig = this.getE2ETypeConfig(e2eType);
468
- return `## E2E 测试目标
469
- 执行完整的端到端测试,验证关键用户流程
470
-
471
- ## 应用类型
472
- ${typeConfig.description}
473
-
474
- ## 测试框架
475
- ${typeConfig.frameworks.map(f => `- ${f}`).join('\n')}
476
-
477
- ## 测试范围
478
- ${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}
479
-
480
- ## 关键用户流程
481
- 根据应用功能,测试以下流程:
482
- ${this.generateUserFlows(parsedTask, e2eType)}
483
-
484
- ## 测试环境
485
- ${typeConfig.environments.map(e => `- ${e}`).join('\n')}
486
-
487
- ## 测试要求
488
- 1. **关键路径覆盖**: 所有核心用户流程必须有 E2E 测试
489
- 2. **断言完整**: 每个测试步骤必须有明确的断言
490
- 3. **等待策略**: 使用合理的等待机制,避免硬编码延迟
491
- 4. **数据隔离**: 测试数据独立,不影响其他测试
492
- 5. **清理机制**: 测试后清理创建的数据
493
-
494
- ## 输出要求
495
- - E2E 测试文件 (tests/e2e/*.spec.ts)
496
- - 测试执行报告
497
- - 截图/录像 (失败时)
498
- - 测试覆盖率报告 (如有)
499
-
500
- ## 运行命令
501
- \`\`\`bash
502
- ${typeConfig.runCommand}
503
- \`\`\`
504
-
505
- ## 验收标准
506
- - [ ] 所有 E2E 测试用例通过
507
- - [ ] 关键用户流程验证完成
508
- - [ ] 跨浏览器/设备兼容性验证
509
- - [ ] E2E 测试报告已生成
943
+ return `## E2E 测试目标
944
+ 执行完整的端到端测试,验证关键用户流程
945
+
946
+ ## 应用类型
947
+ ${typeConfig.description}
948
+
949
+ ## 测试框架
950
+ ${typeConfig.frameworks.map(f => `- ${f}`).join('\n')}
951
+
952
+ ## 测试范围
953
+ ${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}
954
+
955
+ ## 关键用户流程
956
+ 根据应用功能,测试以下流程:
957
+ ${this.generateUserFlows(parsedTask, e2eType)}
958
+
959
+ ## 测试环境
960
+ ${typeConfig.environments.map(e => `- ${e}`).join('\n')}
961
+
962
+ ## 测试要求
963
+ 1. **关键路径覆盖**: 所有核心用户流程必须有 E2E 测试
964
+ 2. **断言完整**: 每个测试步骤必须有明确的断言
965
+ 3. **等待策略**: 使用合理的等待机制,避免硬编码延迟
966
+ 4. **数据隔离**: 测试数据独立,不影响其他测试
967
+ 5. **清理机制**: 测试后清理创建的数据
968
+
969
+ ## 输出要求
970
+ - E2E 测试文件 (tests/e2e/*.spec.ts)
971
+ - 测试执行报告
972
+ - 截图/录像 (失败时)
973
+ - 测试覆盖率报告 (如有)
974
+
975
+ ## 运行命令
976
+ \`\`\`bash
977
+ ${typeConfig.runCommand}
978
+ \`\`\`
979
+
980
+ ## 验收标准
981
+ - [ ] 所有 E2E 测试用例通过
982
+ - [ ] 关键用户流程验证完成
983
+ - [ ] 跨浏览器/设备兼容性验证
984
+ - [ ] E2E 测试报告已生成
510
985
  - [ ] 无阻塞级别的缺陷`;
511
986
  }
512
987
  getE2ETypeConfig(type) {
@@ -566,8 +1041,8 @@ ${typeConfig.runCommand}
566
1041
  return criteria;
567
1042
  }
568
1043
  generateTaskId() {
569
- this.taskCounter++;
570
- return `TASK-${String(this.taskCounter).padStart(3, '0')}`;
1044
+ TaskPlanner.taskCounter++;
1045
+ return `TASK-${String(TaskPlanner.taskCounter).padStart(3, '0')}`;
571
1046
  }
572
1047
  determinePriority(goalIndex) {
573
1048
  if (goalIndex === 0)
@@ -628,5 +1103,91 @@ ${typeConfig.runCommand}
628
1103
  // 默认为开发类
629
1104
  return 'development';
630
1105
  }
1106
+ /**
1107
+ * 检测顺序阶段目标(如 "Phase 1 基础架构"、"Phase 2 AI创作核心")
1108
+ * 返回按阶段排序的索引列表
1109
+ */
1110
+ detectSequentialPhases(goals) {
1111
+ // 匹配 "Phase N" 或 "阶段 N" 或 "第 N 阶段" 等模式
1112
+ const phasePattern = /(?:phase|阶段|第\s*)(\d+)/i;
1113
+ const indexed = [];
1114
+ for (let i = 0; i < goals.length; i++) {
1115
+ const match = goals[i].match(phasePattern);
1116
+ if (match) {
1117
+ indexed.push({ index: i, phase: parseInt(match[1], 10) });
1118
+ }
1119
+ }
1120
+ // 按阶段号排序
1121
+ indexed.sort((a, b) => a.phase - b.phase);
1122
+ return indexed.map(x => x.index);
1123
+ }
1124
+ /**
1125
+ * 对顺序阶段建立跨阶段依赖
1126
+ *
1127
+ * 当 goals 包含 "Phase 1", "Phase 2", "Phase 3" 等顺序阶段时,
1128
+ * 后续阶段的所有开发任务必须依赖前一阶段的集成任务(或最后一个开发任务)。
1129
+ *
1130
+ * 这防止多个阶段同时执行导致文件冲突。
1131
+ */
1132
+ enforcePhaseDependencies(breakdowns, parsedTask) {
1133
+ const phaseIndices = this.detectSequentialPhases(parsedTask.goals);
1134
+ if (phaseIndices.length < 2)
1135
+ return; // 少于 2 个阶段,不需要建立依赖
1136
+ // 收集每个阶段的开发任务 ID 和集成任务 ID
1137
+ // 按阶段索引在 goals 中的原始位置分组
1138
+ const phaseTaskMap = new Map();
1139
+ for (let pi = 0; pi < phaseIndices.length; pi++) {
1140
+ const goalIndex = phaseIndices[pi];
1141
+ const goal = parsedTask.goals[goalIndex];
1142
+ // 找出属于这个 goal 的开发任务和集成任务
1143
+ const devTaskIds = [];
1144
+ let integrationTaskId;
1145
+ for (const b of breakdowns) {
1146
+ // 开发任务标题包含 goal 内容
1147
+ if (b.title.startsWith('实现: ') && b.description.includes(goal)) {
1148
+ devTaskIds.push(b.taskId);
1149
+ }
1150
+ // 集成任务标题包含 "系统集成"
1151
+ if (b.title.startsWith('系统集成:') && devTaskIds.length > 0) {
1152
+ // 集成任务依赖当前阶段的所有开发任务
1153
+ const currentDeps = b.dependencies;
1154
+ if (currentDeps.every(d => devTaskIds.includes(d) || !devTaskIds.includes(d))) {
1155
+ integrationTaskId = b.taskId;
1156
+ }
1157
+ }
1158
+ }
1159
+ // 如果没有集成任务,使用最后一个开发任务 ID
1160
+ phaseTaskMap.set(goalIndex, { devTaskIds, integrationTaskId });
1161
+ }
1162
+ // 建立跨阶段依赖:Phase N 的所有任务依赖 Phase N-1 的集成任务(或最后开发任务)
1163
+ for (let pi = 1; pi < phaseIndices.length; pi++) {
1164
+ const currentGoalIndex = phaseIndices[pi];
1165
+ const prevGoalIndex = phaseIndices[pi - 1];
1166
+ const prevPhase = phaseTaskMap.get(prevGoalIndex);
1167
+ if (!prevPhase || prevPhase.devTaskIds.length === 0)
1168
+ continue;
1169
+ // 前一阶段的核心依赖点(优先集成任务,其次最后开发任务)
1170
+ const prevAnchor = prevPhase.integrationTaskId || prevPhase.devTaskIds[prevPhase.devTaskIds.length - 1];
1171
+ // 找出当前阶段的所有开发任务和集成任务
1172
+ for (const b of breakdowns) {
1173
+ const isCurrentPhaseDev = b.title.startsWith('实现: ') &&
1174
+ parsedTask.goals[currentGoalIndex] &&
1175
+ b.description.includes(parsedTask.goals[currentGoalIndex]);
1176
+ const isCurrentPhaseIntegration = b.title.startsWith('系统集成:');
1177
+ // 简化判断:通过依赖关系推断——集成任务依赖当前阶段开发任务
1178
+ const isCurrentPhaseTest = b.title.startsWith('测试: ') &&
1179
+ b.dependencies.some(dep => {
1180
+ // 测试任务依赖的开发任务属于当前阶段
1181
+ const depTask = breakdowns.find(x => x.taskId === dep);
1182
+ return depTask && depTask.title.startsWith('实现: ') &&
1183
+ parsedTask.goals[currentGoalIndex] &&
1184
+ depTask.description.includes(parsedTask.goals[currentGoalIndex]);
1185
+ });
1186
+ if ((isCurrentPhaseDev || isCurrentPhaseIntegration || isCurrentPhaseTest) && !b.dependencies.includes(prevAnchor)) {
1187
+ b.dependencies.push(prevAnchor);
1188
+ }
1189
+ }
1190
+ }
1191
+ }
631
1192
  }
632
1193
  exports.TaskPlanner = TaskPlanner;