openmatrix 0.1.49 → 0.1.51

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.
@@ -4,41 +4,48 @@ exports.TaskPlanner = void 0;
4
4
  /**
5
5
  * TaskPlanner - 任务拆解器
6
6
  *
7
- * 1. 按 goals 拆分为多个 coder + tester 任务对
8
- * 2. goals 为空时退化为 3 任务模式 (planner → coder → tester)
9
- * 3. 自动注入用户上下文和验收标准
7
+ * 增强版特性:
8
+ * 1. 更细粒度的任务拆分 (每个目标拆分为设计+实现+测试)
9
+ * 2. 测试任务配对 (每个开发任务自动生成对应测试任务)
10
+ * 3. 验收标准注入 (从用户回答中提取)
11
+ * 4. 用户上下文注入 (将用户回答注入任务描述)
12
+ * 5. 依赖关系分析 (自动分析任务间依赖)
13
+ * 6. 并行执行 (独立任务互不依赖)
14
+ * 7. 质量级别感知 (根据配置调整测试覆盖率)
10
15
  */
11
16
  class TaskPlanner {
17
+ userAnswers;
18
+ taskCounter = 0;
19
+ constructor(userAnswers) {
20
+ this.userAnswers = userAnswers || {};
21
+ }
12
22
  /**
13
- * Break down a parsed task into sub-tasks
23
+ * 设置用户回答
14
24
  */
15
- breakdown(parsedTask, answers) {
16
- const userContext = this.extractUserContext(answers);
17
- // 有 goals → 按 goals 拆分多任务
18
- if (parsedTask.goals.length > 0) {
19
- return this.breakdownByGoals(parsedTask, userContext, answers);
20
- }
21
- // 无 goals → 退化为 planner → coder → tester 三任务
22
- return this.breakdownFallback(parsedTask, userContext, answers);
25
+ setUserAnswers(answers) {
26
+ this.userAnswers = answers;
23
27
  }
24
28
  /**
25
- * goals 拆分: 每个 goal 一个 coder + 一个 tester
29
+ * Break down a parsed task into sub-tasks
26
30
  */
27
- breakdownByGoals(parsedTask, userContext, answers) {
31
+ breakdown(parsedTask, answers, qualityConfig, plan) {
28
32
  const breakdowns = [];
29
33
  const seenTitles = new Set();
30
- // 0. 设计阶段 (多 goal 时)
31
- if (parsedTask.goals.length > 1) {
34
+ const userContext = this.extractUserContext(answers);
35
+ // 确定测试覆盖率
36
+ const coverageTarget = this.getCoverageTarget(qualityConfig, userContext);
37
+ // 构建全局上下文块(注入到每个子任务描述中,供 agent 参考)
38
+ const globalContext = this.buildGlobalContext(parsedTask, userContext, plan);
39
+ // 0. 设计阶段任务 (根据复杂度判断)
40
+ let designTaskId;
41
+ if (this.needsDesignPhase(parsedTask)) {
42
+ designTaskId = this.generateTaskId();
32
43
  breakdowns.push({
33
- taskId: this.generateTaskId(),
44
+ taskId: designTaskId,
34
45
  title: '架构设计和任务规划',
35
46
  description: `分析需求,设计整体架构,规划实现方案
36
47
 
37
- ## 用户需求
38
- ${userContext.objective || parsedTask.title}
39
-
40
- ## 技术栈
41
- ${userContext.techStack?.join(', ') || '未指定'}
48
+ ${globalContext}
42
49
 
43
50
  ## 输出
44
51
  - 架构设计文档
@@ -57,57 +64,62 @@ ${userContext.techStack?.join(', ') || '未指定'}
57
64
  ]
58
65
  });
59
66
  }
60
- // 1. 为每个 goal 创建 coder + tester 任务对
67
+ // 1. 为每个目标创建开发+测试任务(并行,只依赖设计任务)
61
68
  const devTaskIds = [];
62
69
  for (let i = 0; i < parsedTask.goals.length; i++) {
63
70
  const goal = parsedTask.goals[i];
64
- if (seenTitles.has(goal))
71
+ // 跳过重复项
72
+ if (seenTitles.has(goal)) {
65
73
  continue;
74
+ }
66
75
  seenTitles.add(goal);
76
+ // 创建开发任务 — 所有开发任务并行,仅依赖设计任务
67
77
  const devTaskId = this.generateTaskId();
68
78
  devTaskIds.push(devTaskId);
69
- // 开发任务
79
+ const acceptanceCriteria = this.generateAcceptanceCriteria(goal, userContext);
70
80
  breakdowns.push({
71
81
  taskId: devTaskId,
72
82
  title: `实现: ${goal}`,
73
- description: this.buildTaskDescription(goal, userContext, answers),
83
+ description: this.buildTaskDescription(goal, globalContext),
74
84
  priority: this.determinePriority(i),
75
- dependencies: i === 0 && parsedTask.goals.length > 1
76
- ? [breakdowns[0].taskId]
77
- : (i > 0 ? [devTaskIds[i - 1]] : []),
85
+ // 并行: 所有开发任务只依赖设计任务(如果有),互不依赖
86
+ dependencies: designTaskId ? [designTaskId] : [],
78
87
  estimatedComplexity: this.estimateComplexity(goal),
79
88
  assignedAgent: 'coder',
80
89
  phase: 'develop',
81
- acceptanceCriteria: this.generateAcceptanceCriteria(goal, userContext)
90
+ acceptanceCriteria,
91
+ testTaskId: undefined // 稍后关联
82
92
  });
83
- // 配对的测试任务
93
+ // 为每个开发任务创建配对的测试任务
84
94
  const testTaskId = this.generateTaskId();
85
95
  breakdowns.push({
86
96
  taskId: testTaskId,
87
97
  title: `测试: ${goal}`,
88
- description: this.buildTestDescription(goal, devTaskId, userContext),
98
+ description: this.buildTestDescription(goal, devTaskId, coverageTarget, globalContext),
89
99
  priority: this.determinePriority(i),
90
- dependencies: [devTaskId],
100
+ dependencies: [devTaskId], // 测试依赖对应的开发任务
91
101
  estimatedComplexity: 'medium',
92
102
  assignedAgent: 'tester',
93
103
  phase: 'verify',
94
104
  acceptanceCriteria: [
95
- `单元测试覆盖率 >= ${userContext.testCoverage || '60%'}`,
105
+ `单元测试覆盖率 >= ${coverageTarget}%`,
96
106
  '边界情况已测试',
97
107
  '异常处理已验证',
98
108
  '所有测试通过'
99
109
  ]
100
110
  });
101
- // 关联测试任务
111
+ // 关联测试任务 ID
102
112
  breakdowns[breakdowns.length - 2].testTaskId = testTaskId;
103
113
  }
104
- // 2. 代码审查 (有开发任务时)
105
- if (devTaskIds.length > 1) {
114
+ // 2. 代码审查任务 (仅在有开发任务时创建)
115
+ if (devTaskIds.length > 0) {
106
116
  breakdowns.push({
107
117
  taskId: this.generateTaskId(),
108
118
  title: '代码审查',
109
119
  description: `对所有开发任务进行代码审查
110
120
 
121
+ ${globalContext}
122
+
111
123
  ## 审查范围
112
124
  ${devTaskIds.map(id => `- ${id}`).join('\n')}
113
125
 
@@ -117,7 +129,7 @@ ${devTaskIds.map(id => `- ${id}`).join('\n')}
117
129
  - 性能
118
130
  - 最佳实践`,
119
131
  priority: 'P1',
120
- dependencies: devTaskIds,
132
+ dependencies: devTaskIds, // 审查依赖所有开发任务完成
121
133
  estimatedComplexity: 'medium',
122
134
  assignedAgent: 'reviewer',
123
135
  phase: 'verify',
@@ -129,134 +141,135 @@ ${devTaskIds.map(id => `- ${id}`).join('\n')}
129
141
  ]
130
142
  });
131
143
  }
132
- return breakdowns;
133
- }
134
- /**
135
- * 无 goals 时的退化模式: planner → coder → tester
136
- * 把 rawContent 整体交给 planner 分析,生成 PLAN.md
137
- * coder 基于 PLAN.md 实现
138
- */
139
- breakdownFallback(parsedTask, userContext, answers) {
140
- const planTaskId = this.generateTaskId();
141
- const devTaskId = this.generateTaskId();
142
- const testTaskId = this.generateTaskId();
143
- // 组装完整上下文
144
- const contextParts = [];
145
- contextParts.push(`## 原始需求\n${parsedTask.rawContent || parsedTask.description || parsedTask.title}`);
146
- if (userContext.objective)
147
- contextParts.push(`## 核心目标\n${userContext.objective}`);
148
- if (userContext.techStack?.length)
149
- contextParts.push(`## 技术栈\n${userContext.techStack.join(', ')}`);
150
- if (parsedTask.constraints.length)
151
- contextParts.push(`## 约束\n${parsedTask.constraints.map(c => `- ${c}`).join('\n')}`);
152
- const brainstormKeys = ['brainstormAnswers', 'insights', 'designNotes'];
153
- for (const key of brainstormKeys) {
154
- if (answers[key])
155
- contextParts.push(`## ${key}\n${answers[key]}`);
156
- }
157
- const fullContext = contextParts.join('\n\n');
158
- return [
159
- {
160
- taskId: planTaskId,
161
- title: `${parsedTask.title} - 需求分析与规划`,
162
- description: `分析需求并制定实现计划。
163
-
164
- ${fullContext}
165
-
166
- ## 你的任务
167
- 1. 深入理解需求
168
- 2. 设计实现方案
169
- 3. 将需求拆解为具体步骤
170
-
171
- ## 输出: PLAN.md
172
- 在 .openmatrix/plan/ 目录创建 PLAN.md,格式:
173
-
174
- # 实现计划
175
-
176
- ## 架构设计
177
- (整体方案)
178
-
179
- ## 实现步骤
180
- ### 步骤 1: (标题)
181
- - 描述: (具体做什么)
182
- - 文件: (涉及哪些文件)
183
- - 验收: (怎么判断完成)
144
+ // 3. 集成测试任务 (如果有多个交付物)
145
+ if (parsedTask.deliverables.length > 1) {
146
+ breakdowns.push({
147
+ taskId: this.generateTaskId(),
148
+ title: '集成测试',
149
+ description: `验证所有交付物正确集成
184
150
 
185
- ### 步骤 2: (标题)
186
- ...
151
+ ${globalContext}
187
152
 
188
- ## 注意事项
189
- - (风险、约束等)`,
190
- priority: 'P0',
191
- dependencies: [],
192
- estimatedComplexity: 'high',
193
- assignedAgent: 'planner',
194
- phase: 'design',
153
+ ## 测试范围
154
+ - 模块间接口
155
+ - 端到端流程
156
+ - 数据流验证`,
157
+ priority: 'P1',
158
+ dependencies: devTaskIds,
159
+ estimatedComplexity: 'medium',
160
+ assignedAgent: 'tester',
161
+ phase: 'verify',
195
162
  acceptanceCriteria: [
196
- 'PLAN.md 已创建在 .openmatrix/plan/',
197
- '实现步骤清晰可执行',
198
- '每步有明确的文件和验收标准'
163
+ '所有模块正确集成',
164
+ '端到端流程通过',
165
+ '接口兼容性验证',
166
+ '集成测试报告完整'
199
167
  ]
200
- },
201
- {
202
- taskId: devTaskId,
203
- title: `${parsedTask.title} - 开发实现`,
204
- description: `根据 PLAN.md 实现功能。
205
-
206
- ${fullContext}
207
-
208
- ## 执行方式
209
- 1. 先读取 .openmatrix/plan/PLAN.md
210
- 2. 按照步骤逐一实现
211
- 3. 每完成一个步骤,验证对应的验收标准
212
-
213
- ## 输出
214
- - 完整的功能代码
215
- - 必要的配置文件`,
216
- priority: 'P1',
217
- dependencies: [planTaskId],
168
+ });
169
+ }
170
+ // 4. E2E 测试任务 (如果启用)
171
+ if (userContext.e2eTests) {
172
+ const e2eTaskId = this.generateTaskId();
173
+ const e2eType = userContext.e2eType || 'web';
174
+ const allTestDependencies = [...devTaskIds];
175
+ breakdowns.forEach(b => {
176
+ if (b.phase === 'verify' && b.title.startsWith('测试:')) {
177
+ allTestDependencies.push(b.taskId);
178
+ }
179
+ });
180
+ breakdowns.push({
181
+ taskId: e2eTaskId,
182
+ title: '端到端(E2E)测试',
183
+ description: this.buildE2ETestDescription(e2eType, parsedTask, userContext),
184
+ priority: 'P0',
185
+ dependencies: allTestDependencies,
218
186
  estimatedComplexity: 'high',
219
- assignedAgent: 'coder',
220
- phase: 'develop',
187
+ assignedAgent: 'tester',
188
+ phase: 'verify',
221
189
  acceptanceCriteria: [
222
- 'PLAN.md 中所有步骤已实现',
223
- '代码可编译运行',
224
- '无严重 bug'
190
+ '所有 E2E 测试用例通过',
191
+ '关键用户流程验证完成',
192
+ '跨浏览器/设备兼容性验证',
193
+ 'E2E 测试报告已生成',
194
+ '无阻塞级别的缺陷'
225
195
  ]
226
- },
227
- {
228
- taskId: testTaskId,
229
- title: `${parsedTask.title} - 验证`,
230
- description: `验证实现是否满足需求。
196
+ });
197
+ }
198
+ // 5. 文档任务 (如果需要)
199
+ if (userContext.documentationLevel && userContext.documentationLevel !== '无需文档') {
200
+ breakdowns.push({
201
+ taskId: this.generateTaskId(),
202
+ title: '文档编写',
203
+ description: `编写项目文档
231
204
 
232
- ## 原始需求
233
- ${parsedTask.rawContent || parsedTask.title}
205
+ ## 文档级别
206
+ ${userContext.documentationLevel}
234
207
 
235
- ## 验证方式
236
- 1. 读取 PLAN.md 中的验收标准
237
- 2. 逐一验证每个步骤
238
- 3. 运行测试(如有)
239
- 4. 检查代码质量`,
240
- priority: 'P1',
241
- dependencies: [devTaskId],
242
- estimatedComplexity: 'medium',
243
- assignedAgent: 'tester',
244
- phase: 'verify',
208
+ ## 文档内容
209
+ - README 更新
210
+ - API 文档
211
+ - 使用说明`,
212
+ priority: 'P2',
213
+ dependencies: devTaskIds,
214
+ estimatedComplexity: 'low',
215
+ assignedAgent: 'executor',
216
+ phase: 'accept',
245
217
  acceptanceCriteria: [
246
- '所有功能正常运行',
247
- 'PLAN.md 中验收标准全部通过',
248
- '无严重代码问题'
218
+ 'README 已更新',
219
+ 'API 文档完整',
220
+ '使用说明清晰'
249
221
  ]
250
- }
222
+ });
223
+ }
224
+ return breakdowns;
225
+ }
226
+ /**
227
+ * 判断是否需要设计阶段
228
+ *
229
+ * 条件: 多个 goal,或 goal 包含复杂关键词
230
+ */
231
+ needsDesignPhase(parsedTask) {
232
+ if (parsedTask.goals.length > 1)
233
+ return true;
234
+ // 单 goal 但包含复杂关键词
235
+ const complexKeywords = [
236
+ '系统', '架构', '模块', '集成', '完整', '平台',
237
+ '体系', '框架', '全栈', '端到端', '多个', '一系列',
238
+ 'system', 'architecture', 'framework', 'fullstack', 'integration'
251
239
  ];
240
+ const allText = `${parsedTask.title} ${parsedTask.goals.join(' ')} ${parsedTask.description}`.toLowerCase();
241
+ return complexKeywords.some(kw => allText.includes(kw.toLowerCase()));
252
242
  }
253
- // --- 工具方法 ---
243
+ /**
244
+ * 获取测试覆盖率目标
245
+ */
246
+ getCoverageTarget(qualityConfig, userContext) {
247
+ // 优先使用 qualityConfig
248
+ if (qualityConfig) {
249
+ return qualityConfig.minCoverage;
250
+ }
251
+ // 其次使用用户回答
252
+ if (userContext?.testCoverage) {
253
+ const match = userContext.testCoverage.match(/(\d+)/);
254
+ if (match)
255
+ return parseInt(match[1], 10);
256
+ }
257
+ // 默认
258
+ return 60;
259
+ }
260
+ /**
261
+ * 提取用户上下文
262
+ */
254
263
  extractUserContext(answers) {
264
+ const e2eAnswer = answers['E2E测试'] || answers['e2eTests'] || answers['e2e'];
265
+ const e2eTypeAnswer = answers['E2E类型'] || answers['e2eType'];
255
266
  return {
256
267
  objective: answers['目标'] || answers['objective'],
257
268
  techStack: this.parseArrayAnswer(answers['技术栈'] || answers['techStack']),
258
269
  testCoverage: answers['测试'] || answers['testCoverage'],
259
270
  documentationLevel: answers['文档'] || answers['documentationLevel'],
271
+ e2eTests: e2eAnswer === 'true' || e2eAnswer === '✅ 启用 E2E 测试' || e2eAnswer === '是',
272
+ e2eType: e2eTypeAnswer || 'web',
260
273
  additionalContext: answers
261
274
  };
262
275
  }
@@ -265,35 +278,58 @@ ${parsedTask.rawContent || parsedTask.title}
265
278
  return [];
266
279
  return answer.split(/[,,\n]/).map(s => s.trim()).filter(Boolean);
267
280
  }
268
- buildTaskDescription(goal, userContext, answers) {
281
+ /**
282
+ * 构建全局上下文块(注入到每个子任务描述中)
283
+ */
284
+ buildGlobalContext(parsedTask, userContext, plan) {
269
285
  const parts = [];
270
- parts.push(`## 任务目标\n${goal}\n`);
271
- if (userContext.objective)
272
- parts.push(`## 整体目标\n${userContext.objective}\n`);
273
- if (userContext.techStack?.length) {
274
- parts.push(`## 技术栈要求\n${userContext.techStack.map(t => `- ${t}`).join('\n')}\n`);
286
+ if (parsedTask.title) {
287
+ parts.push(`## 整体任务\n${parsedTask.title}`);
288
+ }
289
+ if (parsedTask.description) {
290
+ parts.push(`## 任务描述\n${parsedTask.description}`);
291
+ }
292
+ if (plan) {
293
+ parts.push(`## 执行计划\n${plan}`);
294
+ }
295
+ if (parsedTask.goals.length > 0) {
296
+ parts.push(`## 所有目标\n${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}`);
275
297
  }
276
- const relevantAnswers = Object.entries(answers).filter(([key]) => !['目标', '技术栈', '测试', '文档', 'objective', 'techStack', 'testCoverage', 'documentationLevel'].includes(key));
277
- if (relevantAnswers.length > 0) {
278
- parts.push(`## 其他要求\n${relevantAnswers.map(([k, v]) => `- ${k}: ${v}`).join('\n')}\n`);
298
+ if (parsedTask.constraints.length > 0) {
299
+ parts.push(`## 约束条件\n${parsedTask.constraints.map(c => `- ${c}`).join('\n')}`);
279
300
  }
280
- parts.push(`## 输出要求
301
+ if (parsedTask.deliverables.length > 0) {
302
+ parts.push(`## 交付物\n${parsedTask.deliverables.map(d => `- ${d}`).join('\n')}`);
303
+ }
304
+ if (userContext.techStack && userContext.techStack.length > 0) {
305
+ parts.push(`## 技术栈\n${userContext.techStack.map(t => `- ${t}`).join('\n')}`);
306
+ }
307
+ if (userContext.additionalContext) {
308
+ const relevantAnswers = Object.entries(userContext.additionalContext).filter(([key]) => !['目标', '技术栈', '测试', '文档', 'objective', 'techStack', 'testCoverage', 'documentationLevel'].includes(key));
309
+ if (relevantAnswers.length > 0) {
310
+ parts.push(`## 其他要求\n${relevantAnswers.map(([k, v]) => `- ${k}: ${v}`).join('\n')}`);
311
+ }
312
+ }
313
+ return parts.join('\n');
314
+ }
315
+ buildTaskDescription(goal, globalContext) {
316
+ return `## 当前子任务目标\n${goal}\n\n${globalContext}\n\n## 输出要求
281
317
  - 完成功能实现
282
318
  - 代码可编译
283
319
  - 遵循项目规范
284
- - 添加必要注释`);
285
- return parts.join('\n');
320
+ - 添加必要注释`;
286
321
  }
287
- buildTestDescription(goal, devTaskId, userContext) {
288
- const coverage = this.parseCoverage(userContext.testCoverage || '60%');
322
+ buildTestDescription(goal, devTaskId, coverageTarget, globalContext) {
289
323
  return `## 测试目标
290
324
  为 "${goal}" 编写测试用例
291
325
 
326
+ ${globalContext}
327
+
292
328
  ## 关联开发任务
293
329
  ${devTaskId}
294
330
 
295
331
  ## 测试要求
296
- - 单元测试覆盖率 >= ${coverage}%
332
+ - 单元测试覆盖率 >= ${coverageTarget}%
297
333
  - 测试正常流程
298
334
  - 测试边界情况
299
335
  - 测试异常处理
@@ -307,9 +343,90 @@ ${devTaskId}
307
343
  - 测试报告
308
344
  - 覆盖率报告`;
309
345
  }
310
- parseCoverage(coverageStr) {
311
- const match = coverageStr.match(/(\d+)/);
312
- return match ? parseInt(match[1], 10) : 60;
346
+ buildE2ETestDescription(e2eType, parsedTask, userContext) {
347
+ const typeConfig = this.getE2ETypeConfig(e2eType);
348
+ return `## E2E 测试目标
349
+ 执行完整的端到端测试,验证关键用户流程
350
+
351
+ ## 应用类型
352
+ ${typeConfig.description}
353
+
354
+ ## 测试框架
355
+ ${typeConfig.frameworks.map(f => `- ${f}`).join('\n')}
356
+
357
+ ## 测试范围
358
+ ${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}
359
+
360
+ ## 关键用户流程
361
+ 根据应用功能,测试以下流程:
362
+ ${this.generateUserFlows(parsedTask, e2eType)}
363
+
364
+ ## 测试环境
365
+ ${typeConfig.environments.map(e => `- ${e}`).join('\n')}
366
+
367
+ ## 测试要求
368
+ 1. **关键路径覆盖**: 所有核心用户流程必须有 E2E 测试
369
+ 2. **断言完整**: 每个测试步骤必须有明确的断言
370
+ 3. **等待策略**: 使用合理的等待机制,避免硬编码延迟
371
+ 4. **数据隔离**: 测试数据独立,不影响其他测试
372
+ 5. **清理机制**: 测试后清理创建的数据
373
+
374
+ ## 输出要求
375
+ - E2E 测试文件 (tests/e2e/*.spec.ts)
376
+ - 测试执行报告
377
+ - 截图/录像 (失败时)
378
+ - 测试覆盖率报告 (如有)
379
+
380
+ ## 运行命令
381
+ \`\`\`bash
382
+ ${typeConfig.runCommand}
383
+ \`\`\`
384
+
385
+ ## 验收标准
386
+ - [ ] 所有 E2E 测试用例通过
387
+ - [ ] 关键用户流程验证完成
388
+ - [ ] 跨浏览器/设备兼容性验证
389
+ - [ ] E2E 测试报告已生成
390
+ - [ ] 无阻塞级别的缺陷`;
391
+ }
392
+ getE2ETypeConfig(type) {
393
+ const configs = {
394
+ web: {
395
+ description: 'Web 应用 (浏览器)',
396
+ frameworks: ['Playwright (推荐)', 'Cypress', 'Selenium WebDriver', 'Puppeteer'],
397
+ environments: ['Chrome', 'Firefox', 'Safari', 'Edge', 'Mobile Viewports'],
398
+ runCommand: 'npx playwright test --reporter=html'
399
+ },
400
+ mobile: {
401
+ description: '移动应用 (iOS/Android)',
402
+ frameworks: ['Appium', 'Detox (React Native)', 'XCUITest (iOS)', 'Espresso (Android)'],
403
+ environments: ['iOS Simulator', 'Android Emulator', 'Real Devices'],
404
+ runCommand: 'npx appium --base-path /wd/hub && npm run test:e2e'
405
+ },
406
+ gui: {
407
+ description: 'GUI 桌面应用 (Electron/Native)',
408
+ frameworks: ['Playwright for Electron', 'Spectron (Electron)', 'Robot Framework', 'PyAutoGUI'],
409
+ environments: ['Windows', 'macOS', 'Linux'],
410
+ runCommand: 'npm run test:e2e'
411
+ }
412
+ };
413
+ return configs[type];
414
+ }
415
+ generateUserFlows(parsedTask, type) {
416
+ const flows = [];
417
+ const goals = parsedTask.goals;
418
+ goals.forEach((goal, i) => {
419
+ flows.push(`\n### 流程 ${i + 1}: ${goal}`);
420
+ flows.push('```gherkin');
421
+ flows.push(`Feature: ${goal}`);
422
+ flows.push('');
423
+ flows.push(' Scenario: 正常流程');
424
+ flows.push(` Given 用户已启动应用`);
425
+ flows.push(` When 用户执行 "${goal}" 操作`);
426
+ flows.push(` Then 操作成功完成`);
427
+ flows.push('```');
428
+ });
429
+ return flows.join('\n');
313
430
  }
314
431
  generateAcceptanceCriteria(goal, userContext) {
315
432
  const criteria = [
@@ -318,17 +435,19 @@ ${devTaskId}
318
435
  '代码符合项目规范',
319
436
  '必要的注释已添加'
320
437
  ];
321
- if (userContext.testCoverage)
438
+ if (userContext.testCoverage) {
322
439
  criteria.push(`测试覆盖率 >= ${userContext.testCoverage}`);
323
- if (userContext.techStack?.length)
440
+ }
441
+ if (userContext.techStack?.length) {
324
442
  criteria.push(`使用指定技术栈: ${userContext.techStack.join(', ')}`);
325
- criteria.push('无安全隐患', '边界情况已处理');
443
+ }
444
+ criteria.push('无安全隐患');
445
+ criteria.push('边界情况已处理');
326
446
  return criteria;
327
447
  }
328
448
  generateTaskId() {
329
- const timestamp = Date.now().toString(36).toUpperCase();
330
- const rand = Math.random().toString(36).slice(2, 4).toUpperCase();
331
- return `TASK-${timestamp}${rand}`;
449
+ this.taskCounter++;
450
+ return `TASK-${String(this.taskCounter).padStart(3, '0')}`;
332
451
  }
333
452
  determinePriority(goalIndex) {
334
453
  if (goalIndex === 0)
@@ -13,7 +13,6 @@ export declare class StateManager {
13
13
  timeout: number;
14
14
  dependencies: string[];
15
15
  assignedAgent: string;
16
- id?: string;
17
16
  }): Promise<Task>;
18
17
  getTask(taskId: string): Promise<Task | null>;
19
18
  updateTask(taskId: string, updates: Partial<Task>): Promise<void>;
@@ -53,7 +53,7 @@ class StateManager {
53
53
  this.stateCache = newState;
54
54
  }
55
55
  async createTask(input) {
56
- const taskId = input.id || this.generateTaskId();
56
+ const taskId = this.generateTaskId();
57
57
  const now = new Date().toISOString();
58
58
  const task = {
59
59
  id: taskId,
@@ -74,7 +74,7 @@ class StateManager {
74
74
  createdAt: now,
75
75
  updatedAt: now
76
76
  };
77
- await this.store.writeJson(`tasks/${taskId}/task.json`, task);
77
+ await this.store.writeJson(`tasks/${taskId}.json`, task);
78
78
  // Update statistics
79
79
  const state = await this.getState();
80
80
  await this.updateState({
@@ -87,7 +87,7 @@ class StateManager {
87
87
  return task;
88
88
  }
89
89
  async getTask(taskId) {
90
- return await this.store.readJson(`tasks/${taskId}/task.json`);
90
+ return await this.store.readJson(`tasks/${taskId}.json`);
91
91
  }
92
92
  async updateTask(taskId, updates) {
93
93
  const task = await this.getTask(taskId);
@@ -99,17 +99,17 @@ class StateManager {
99
99
  ...updates,
100
100
  updatedAt: new Date().toISOString()
101
101
  };
102
- await this.store.writeJson(`tasks/${taskId}/task.json`, updatedTask);
102
+ await this.store.writeJson(`tasks/${taskId}.json`, updatedTask);
103
103
  // Update statistics if status changed
104
104
  if (updates.status && updates.status !== oldStatus) {
105
105
  await this.updateTaskStatistics(oldStatus, updates.status);
106
106
  }
107
107
  }
108
108
  async listTasks() {
109
- const dirs = await this.store.listDirs('tasks');
109
+ const files = await this.store.listFiles('tasks');
110
110
  const tasks = [];
111
- for (const dir of dirs) {
112
- const task = await this.getTask(dir);
111
+ for (const file of files) {
112
+ const task = await this.store.readJson(`tasks/${file}`);
113
113
  if (task)
114
114
  tasks.push(task);
115
115
  }
@@ -144,9 +144,9 @@ class StateManager {
144
144
  return `run-${date}-${rand}`;
145
145
  }
146
146
  generateTaskId() {
147
- const timestamp = Date.now().toString(36).toUpperCase();
148
- const rand = Math.random().toString(36).slice(2, 4).toUpperCase();
149
- return `TASK-${timestamp}${rand}`;
147
+ const count = this.stateCache?.statistics.totalTasks ?? 0;
148
+ const seq = count + 1;
149
+ return `TASK-${String(seq).padStart(3, '0')}`;
150
150
  }
151
151
  // ============ Approval Methods ============
152
152
  async saveApproval(approval) {