openmatrix 0.1.41 → 0.1.43
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.
- package/dist/orchestrator/task-planner.d.ts +6 -82
- package/dist/orchestrator/task-planner.js +99 -514
- package/package.json +2 -1
- package/skills/brainstorm.md +429 -429
- package/skills/start.md +75 -435
|
@@ -4,581 +4,166 @@ exports.TaskPlanner = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* TaskPlanner - 任务拆解器
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 2. 测试任务配对 (每个开发任务自动生成对应测试任务)
|
|
10
|
-
* 3. 验收标准注入 (从用户回答中提取)
|
|
11
|
-
* 4. 用户上下文注入 (将用户回答注入任务描述)
|
|
12
|
-
* 5. 依赖关系分析 (自动分析任务间依赖)
|
|
7
|
+
* 始终基于整体内容拆解,不依赖 goals 提取
|
|
8
|
+
* 流程: 规划(AI输出PLAN.md) → 开发(基于PLAN.md) → 验证
|
|
13
9
|
*/
|
|
14
10
|
class TaskPlanner {
|
|
15
|
-
userAnswers;
|
|
16
|
-
constructor(userAnswers) {
|
|
17
|
-
this.userAnswers = userAnswers || {};
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 设置用户回答
|
|
21
|
-
*/
|
|
22
|
-
setUserAnswers(answers) {
|
|
23
|
-
this.userAnswers = answers;
|
|
24
|
-
}
|
|
25
11
|
/**
|
|
26
12
|
* Break down a parsed task into sub-tasks
|
|
27
13
|
*
|
|
28
|
-
*
|
|
29
|
-
* 1. 如果有明确的 goals (来自 ## 目标 section),按目标拆解
|
|
30
|
-
* 2. 如果没有 goals 但有复杂内容,创建规划任务交给 AI 拆解
|
|
31
|
-
* 3. 如果是简单任务,直接创建单个开发任务
|
|
14
|
+
* 始终基于整体内容拆解: 规划→开发→验证
|
|
32
15
|
*/
|
|
33
16
|
breakdown(parsedTask, answers) {
|
|
34
|
-
const breakdowns = [];
|
|
35
17
|
const userContext = this.extractUserContext(answers);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* 创建规划任务 (由 AI 智能拆解)
|
|
73
|
-
*/
|
|
74
|
-
createPlanningTask(parsedTask, userContext, answers) {
|
|
75
|
-
const planningTaskId = this.generateTaskId();
|
|
76
|
-
return [{
|
|
77
|
-
taskId: planningTaskId,
|
|
78
|
-
title: `${parsedTask.title} - 需求分析与架构设计`,
|
|
79
|
-
description: `# 需求分析与架构设计
|
|
18
|
+
return this.createPlanBasedTasks(parsedTask, userContext, answers);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 基于 Plan 的任务序列
|
|
22
|
+
* 规划(AI分析需求→输出PLAN.md) → 开发(基于PLAN.md实现) → 验证
|
|
23
|
+
*/
|
|
24
|
+
createPlanBasedTasks(parsedTask, userContext, answers) {
|
|
25
|
+
const planTaskId = this.generateTaskId();
|
|
26
|
+
const devTaskId = this.generateTaskId();
|
|
27
|
+
const testTaskId = this.generateTaskId();
|
|
28
|
+
// 组装完整上下文
|
|
29
|
+
const contextParts = [];
|
|
30
|
+
contextParts.push(`## 原始需求\n${parsedTask.rawContent || parsedTask.description || parsedTask.title}`);
|
|
31
|
+
if (parsedTask.goals.length)
|
|
32
|
+
contextParts.push(`## 明确目标\n${parsedTask.goals.map(g => `- ${g}`).join('\n')}`);
|
|
33
|
+
if (userContext.objective)
|
|
34
|
+
contextParts.push(`## 核心目标\n${userContext.objective}`);
|
|
35
|
+
if (userContext.techStack?.length)
|
|
36
|
+
contextParts.push(`## 技术栈\n${userContext.techStack.join(', ')}`);
|
|
37
|
+
if (parsedTask.constraints.length)
|
|
38
|
+
contextParts.push(`## 约束\n${parsedTask.constraints.map(c => `- ${c}`).join('\n')}`);
|
|
39
|
+
// brainstorm 答案
|
|
40
|
+
const brainstormKeys = ['brainstormAnswers', 'insights', 'designNotes'];
|
|
41
|
+
for (const key of brainstormKeys) {
|
|
42
|
+
if (answers[key])
|
|
43
|
+
contextParts.push(`## ${key}\n${answers[key]}`);
|
|
44
|
+
}
|
|
45
|
+
const fullContext = contextParts.join('\n\n');
|
|
46
|
+
return [
|
|
47
|
+
// 1. 规划任务
|
|
48
|
+
{
|
|
49
|
+
taskId: planTaskId,
|
|
50
|
+
title: `${parsedTask.title} - 需求分析与规划`,
|
|
51
|
+
description: `分析需求并制定实现计划。
|
|
52
|
+
|
|
53
|
+
${fullContext}
|
|
80
54
|
|
|
81
|
-
##
|
|
82
|
-
|
|
55
|
+
## 你的任务
|
|
56
|
+
1. 深入理解需求
|
|
57
|
+
2. 设计实现方案
|
|
58
|
+
3. 将需求拆解为具体步骤
|
|
83
59
|
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
${parsedTask.rawContent}
|
|
87
|
-
\`\`\`
|
|
60
|
+
## 输出: PLAN.md
|
|
61
|
+
在项目根目录创建 PLAN.md,格式如下:
|
|
88
62
|
|
|
89
|
-
|
|
90
|
-
${this.formatUserContext(userContext, answers)}
|
|
63
|
+
# 实现计划
|
|
91
64
|
|
|
92
|
-
##
|
|
93
|
-
|
|
94
|
-
1. 深入分析需求,理解核心功能
|
|
95
|
-
2. 设计系统架构
|
|
96
|
-
3. 将需求拆解为可执行的子任务
|
|
97
|
-
4. 为每个子任务定义验收标准
|
|
65
|
+
## 架构设计
|
|
66
|
+
(整体方案描述)
|
|
98
67
|
|
|
99
|
-
##
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
68
|
+
## 实现步骤
|
|
69
|
+
### 步骤 1: (标题)
|
|
70
|
+
- 描述: (具体做什么)
|
|
71
|
+
- 文件: (涉及哪些文件)
|
|
72
|
+
- 验收: (怎么判断完成)
|
|
73
|
+
|
|
74
|
+
### 步骤 2: (标题)
|
|
75
|
+
- 描述: ...
|
|
76
|
+
- 文件: ...
|
|
77
|
+
- 验收: ...
|
|
103
78
|
|
|
104
79
|
## 注意事项
|
|
105
|
-
-
|
|
106
|
-
- 任务之间要有清晰的依赖关系
|
|
107
|
-
- 考虑技术栈和约束条件`,
|
|
80
|
+
- (风险、约束等)`,
|
|
108
81
|
priority: 'P0',
|
|
109
82
|
dependencies: [],
|
|
110
83
|
estimatedComplexity: 'high',
|
|
111
84
|
assignedAgent: 'planner',
|
|
112
85
|
phase: 'design',
|
|
113
86
|
acceptanceCriteria: [
|
|
114
|
-
'
|
|
115
|
-
'
|
|
116
|
-
'
|
|
117
|
-
'依赖关系明确',
|
|
118
|
-
'技术方案可行'
|
|
119
|
-
]
|
|
120
|
-
}];
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* 创建单个开发任务
|
|
124
|
-
*/
|
|
125
|
-
createSingleTask(parsedTask, userContext, answers) {
|
|
126
|
-
const taskId = this.generateTaskId();
|
|
127
|
-
return [{
|
|
128
|
-
taskId,
|
|
129
|
-
title: parsedTask.title,
|
|
130
|
-
description: this.buildTaskDescription(parsedTask.description || parsedTask.title, userContext, answers),
|
|
131
|
-
priority: 'P1',
|
|
132
|
-
dependencies: [],
|
|
133
|
-
estimatedComplexity: 'medium',
|
|
134
|
-
assignedAgent: 'coder',
|
|
135
|
-
phase: 'develop',
|
|
136
|
-
acceptanceCriteria: [
|
|
137
|
-
'功能实现完整',
|
|
138
|
-
'代码可编译',
|
|
139
|
-
'无严重 bug',
|
|
140
|
-
'代码符合规范'
|
|
87
|
+
'PLAN.md 已创建',
|
|
88
|
+
'实现步骤清晰可执行',
|
|
89
|
+
'每步有明确的文件和验收标准'
|
|
141
90
|
]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const breakdowns = [];
|
|
149
|
-
const seenTitles = new Set();
|
|
150
|
-
const extractedContext = this.extractUserContext(answers);
|
|
151
|
-
// 0. 设计阶段任务
|
|
152
|
-
if (parsedTask.goals.length > 1) {
|
|
153
|
-
breakdowns.push({
|
|
154
|
-
taskId: this.generateTaskId(),
|
|
155
|
-
title: '架构设计和任务规划',
|
|
156
|
-
description: `分析需求,设计整体架构,规划实现方案
|
|
91
|
+
},
|
|
92
|
+
// 2. 开发任务
|
|
93
|
+
{
|
|
94
|
+
taskId: devTaskId,
|
|
95
|
+
title: `${parsedTask.title} - 开发实现`,
|
|
96
|
+
description: `根据 PLAN.md 实现功能。
|
|
157
97
|
|
|
158
|
-
|
|
159
|
-
${extractedContext.objective || '未指定'}
|
|
98
|
+
${fullContext}
|
|
160
99
|
|
|
161
|
-
##
|
|
162
|
-
|
|
100
|
+
## 执行方式
|
|
101
|
+
1. 先读取项目根目录的 PLAN.md
|
|
102
|
+
2. 按照步骤逐一实现
|
|
103
|
+
3. 每完成一个步骤,验证对应的验收标准
|
|
163
104
|
|
|
164
105
|
## 输出
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
dependencies: [],
|
|
106
|
+
- 完整的功能代码
|
|
107
|
+
- 必要的配置文件`,
|
|
108
|
+
priority: 'P1',
|
|
109
|
+
dependencies: [planTaskId],
|
|
170
110
|
estimatedComplexity: 'high',
|
|
171
|
-
assignedAgent: 'planner',
|
|
172
|
-
phase: 'design',
|
|
173
|
-
acceptanceCriteria: [
|
|
174
|
-
'架构设计文档完整',
|
|
175
|
-
'所有模块接口已定义',
|
|
176
|
-
'依赖关系明确',
|
|
177
|
-
'技术方案可行'
|
|
178
|
-
]
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
// 1. 为每个目标创建细粒度任务
|
|
182
|
-
const devTaskIds = [];
|
|
183
|
-
for (let i = 0; i < parsedTask.goals.length; i++) {
|
|
184
|
-
const goal = parsedTask.goals[i];
|
|
185
|
-
// 跳过重复项
|
|
186
|
-
if (seenTitles.has(goal)) {
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
seenTitles.add(goal);
|
|
190
|
-
// 创建开发任务
|
|
191
|
-
const devTaskId = this.generateTaskId();
|
|
192
|
-
devTaskIds.push(devTaskId);
|
|
193
|
-
const acceptanceCriteria = this.generateAcceptanceCriteria(goal, userContext);
|
|
194
|
-
breakdowns.push({
|
|
195
|
-
taskId: devTaskId,
|
|
196
|
-
title: `实现: ${goal}`,
|
|
197
|
-
description: this.buildTaskDescription(goal, userContext, answers),
|
|
198
|
-
priority: this.determinePriority(i),
|
|
199
|
-
dependencies: i === 0 && parsedTask.goals.length > 1
|
|
200
|
-
? [breakdowns[0].taskId] // 依赖设计任务
|
|
201
|
-
: (i > 0 ? [devTaskIds[i - 1]] : []), // 依赖前一个开发任务
|
|
202
|
-
estimatedComplexity: this.estimateComplexity(goal),
|
|
203
111
|
assignedAgent: 'coder',
|
|
204
112
|
phase: 'develop',
|
|
205
|
-
acceptanceCriteria,
|
|
206
|
-
testTaskId: undefined // 稍后关联
|
|
207
|
-
});
|
|
208
|
-
// 为每个开发任务创建配对的测试任务
|
|
209
|
-
const testTaskId = this.generateTaskId();
|
|
210
|
-
breakdowns.push({
|
|
211
|
-
taskId: testTaskId,
|
|
212
|
-
title: `测试: ${goal}`,
|
|
213
|
-
description: this.buildTestDescription(goal, devTaskId, userContext),
|
|
214
|
-
priority: this.determinePriority(i),
|
|
215
|
-
dependencies: [devTaskId], // 测试依赖开发任务
|
|
216
|
-
estimatedComplexity: 'medium',
|
|
217
|
-
assignedAgent: 'tester',
|
|
218
|
-
phase: 'verify',
|
|
219
|
-
acceptanceCriteria: [
|
|
220
|
-
`单元测试覆盖率 >= ${userContext.testCoverage || '60%'}`,
|
|
221
|
-
'边界情况已测试',
|
|
222
|
-
'异常处理已验证',
|
|
223
|
-
'所有测试通过'
|
|
224
|
-
]
|
|
225
|
-
});
|
|
226
|
-
// 关联测试任务 ID
|
|
227
|
-
breakdowns[breakdowns.length - 2].testTaskId = testTaskId;
|
|
228
|
-
}
|
|
229
|
-
// 2. 代码审查任务 (仅在有开发任务时创建)
|
|
230
|
-
if (devTaskIds.length > 0) {
|
|
231
|
-
breakdowns.push({
|
|
232
|
-
taskId: this.generateTaskId(),
|
|
233
|
-
title: '代码审查',
|
|
234
|
-
description: `对所有开发任务进行代码审查
|
|
235
|
-
|
|
236
|
-
## 审查范围
|
|
237
|
-
${devTaskIds.map(id => `- ${id}`).join('\n')}
|
|
238
|
-
|
|
239
|
-
## 审查要点
|
|
240
|
-
- 代码质量
|
|
241
|
-
- 安全性
|
|
242
|
-
- 性能
|
|
243
|
-
- 最佳实践`,
|
|
244
|
-
priority: 'P1',
|
|
245
|
-
dependencies: devTaskIds,
|
|
246
|
-
estimatedComplexity: 'medium',
|
|
247
|
-
assignedAgent: 'reviewer',
|
|
248
|
-
phase: 'verify',
|
|
249
113
|
acceptanceCriteria: [
|
|
250
|
-
'
|
|
251
|
-
'
|
|
252
|
-
'
|
|
253
|
-
'审查报告已生成'
|
|
114
|
+
'PLAN.md 中所有步骤已实现',
|
|
115
|
+
'代码可编译运行',
|
|
116
|
+
'无严重 bug'
|
|
254
117
|
]
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
title: '集成测试',
|
|
262
|
-
description: `验证所有交付物正确集成
|
|
118
|
+
},
|
|
119
|
+
// 3. 验证任务
|
|
120
|
+
{
|
|
121
|
+
taskId: testTaskId,
|
|
122
|
+
title: `${parsedTask.title} - 验证`,
|
|
123
|
+
description: `验证实现是否满足需求。
|
|
263
124
|
|
|
264
|
-
##
|
|
265
|
-
${parsedTask.
|
|
125
|
+
## 原始需求
|
|
126
|
+
${parsedTask.rawContent || parsedTask.title}
|
|
266
127
|
|
|
267
|
-
##
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
128
|
+
## 验证方式
|
|
129
|
+
1. 读取 PLAN.md 中的验收标准
|
|
130
|
+
2. 逐一验证每个步骤
|
|
131
|
+
3. 运行测试(如有)
|
|
132
|
+
4. 检查代码质量`,
|
|
271
133
|
priority: 'P1',
|
|
272
|
-
dependencies:
|
|
134
|
+
dependencies: [devTaskId],
|
|
273
135
|
estimatedComplexity: 'medium',
|
|
274
136
|
assignedAgent: 'tester',
|
|
275
137
|
phase: 'verify',
|
|
276
138
|
acceptanceCriteria: [
|
|
277
|
-
'
|
|
278
|
-
'
|
|
279
|
-
'
|
|
280
|
-
'集成测试报告完整'
|
|
281
|
-
]
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
// 4. E2E 测试任务 (如果启用,作为 verify 阶段的一部分)
|
|
285
|
-
if (userContext.e2eTests) {
|
|
286
|
-
const e2eTaskId = this.generateTaskId();
|
|
287
|
-
const e2eType = userContext.e2eType || 'web';
|
|
288
|
-
// E2E 测试依赖所有开发任务和单元测试任务
|
|
289
|
-
const allTestDependencies = [...devTaskIds];
|
|
290
|
-
breakdowns.forEach(b => {
|
|
291
|
-
if (b.phase === 'verify' && b.title.startsWith('测试:')) {
|
|
292
|
-
allTestDependencies.push(b.taskId);
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
breakdowns.push({
|
|
296
|
-
taskId: e2eTaskId,
|
|
297
|
-
title: '端到端(E2E)测试',
|
|
298
|
-
description: this.buildE2ETestDescription(e2eType, parsedTask, userContext),
|
|
299
|
-
priority: 'P0', // E2E 测试是关键任务
|
|
300
|
-
dependencies: allTestDependencies, // 依赖所有开发任务和单元测试
|
|
301
|
-
estimatedComplexity: 'high',
|
|
302
|
-
assignedAgent: 'tester',
|
|
303
|
-
phase: 'verify',
|
|
304
|
-
acceptanceCriteria: [
|
|
305
|
-
'所有 E2E 测试用例通过',
|
|
306
|
-
'关键用户流程验证完成',
|
|
307
|
-
'跨浏览器/设备兼容性验证',
|
|
308
|
-
'E2E 测试报告已生成',
|
|
309
|
-
'无阻塞级别的缺陷'
|
|
139
|
+
'所有功能正常运行',
|
|
140
|
+
'PLAN.md 中验收标准全部通过',
|
|
141
|
+
'无严重代码问题'
|
|
310
142
|
]
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// 5. 文档任务 (如果需要)
|
|
314
|
-
if (userContext.documentationLevel && userContext.documentationLevel !== '无需文档') {
|
|
315
|
-
breakdowns.push({
|
|
316
|
-
taskId: this.generateTaskId(),
|
|
317
|
-
title: '文档编写',
|
|
318
|
-
description: `编写项目文档
|
|
319
|
-
|
|
320
|
-
## 文档级别
|
|
321
|
-
${userContext.documentationLevel}
|
|
322
|
-
|
|
323
|
-
## 文档内容
|
|
324
|
-
- README 更新
|
|
325
|
-
- API 文档
|
|
326
|
-
- 使用说明`,
|
|
327
|
-
priority: 'P2',
|
|
328
|
-
dependencies: devTaskIds,
|
|
329
|
-
estimatedComplexity: 'low',
|
|
330
|
-
assignedAgent: 'executor',
|
|
331
|
-
phase: 'accept',
|
|
332
|
-
acceptanceCriteria: [
|
|
333
|
-
'README 已更新',
|
|
334
|
-
'API 文档完整',
|
|
335
|
-
'使用说明清晰'
|
|
336
|
-
]
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
return breakdowns;
|
|
143
|
+
}
|
|
144
|
+
];
|
|
340
145
|
}
|
|
341
146
|
/**
|
|
342
147
|
* 提取用户上下文
|
|
343
148
|
*/
|
|
344
149
|
extractUserContext(answers) {
|
|
345
|
-
const e2eAnswer = answers['E2E测试'] || answers['e2eTests'] || answers['e2e'];
|
|
346
|
-
const e2eTypeAnswer = answers['E2E类型'] || answers['e2eType'];
|
|
347
150
|
return {
|
|
348
151
|
objective: answers['目标'] || answers['objective'],
|
|
349
152
|
techStack: this.parseArrayAnswer(answers['技术栈'] || answers['techStack']),
|
|
350
153
|
testCoverage: answers['测试'] || answers['testCoverage'],
|
|
351
154
|
documentationLevel: answers['文档'] || answers['documentationLevel'],
|
|
352
|
-
e2eTests: e2eAnswer === 'true' || e2eAnswer === '✅ 启用 E2E 测试' || e2eAnswer === '是',
|
|
353
|
-
e2eType: e2eTypeAnswer || 'web',
|
|
354
155
|
additionalContext: answers
|
|
355
156
|
};
|
|
356
157
|
}
|
|
357
|
-
/**
|
|
358
|
-
* 格式化用户上下文为字符串
|
|
359
|
-
*/
|
|
360
|
-
formatUserContext(userContext, answers) {
|
|
361
|
-
const parts = [];
|
|
362
|
-
if (answers['brainstormAnswers']) {
|
|
363
|
-
parts.push('### 头脑风暴答案');
|
|
364
|
-
parts.push(answers['brainstormAnswers']);
|
|
365
|
-
}
|
|
366
|
-
if (userContext.objective) {
|
|
367
|
-
parts.push(`### 目标: ${userContext.objective}`);
|
|
368
|
-
}
|
|
369
|
-
if (userContext.techStack && userContext.techStack.length > 0) {
|
|
370
|
-
parts.push(`### 技术栈: ${userContext.techStack.join(', ')}`);
|
|
371
|
-
}
|
|
372
|
-
if (answers['insights']) {
|
|
373
|
-
parts.push(`### 洞察: ${answers['insights']}`);
|
|
374
|
-
}
|
|
375
|
-
if (answers['designNotes']) {
|
|
376
|
-
parts.push(`### 设计笔记: ${answers['designNotes']}`);
|
|
377
|
-
}
|
|
378
|
-
return parts.join('\n\n') || '无额外上下文';
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* 解析数组类型的回答
|
|
382
|
-
*/
|
|
383
158
|
parseArrayAnswer(answer) {
|
|
384
159
|
if (!answer)
|
|
385
160
|
return [];
|
|
386
|
-
// 处理逗号分隔或换行分隔的答案
|
|
387
161
|
return answer.split(/[,,\n]/).map(s => s.trim()).filter(Boolean);
|
|
388
162
|
}
|
|
389
|
-
/**
|
|
390
|
-
* 构建任务描述 (注入用户上下文)
|
|
391
|
-
*/
|
|
392
|
-
buildTaskDescription(goal, userContext, answers) {
|
|
393
|
-
const parts = [];
|
|
394
|
-
parts.push(`## 任务目标\n${goal}\n`);
|
|
395
|
-
if (userContext.objective) {
|
|
396
|
-
parts.push(`## 整体目标\n${userContext.objective}\n`);
|
|
397
|
-
}
|
|
398
|
-
if (userContext.techStack && userContext.techStack.length > 0) {
|
|
399
|
-
parts.push(`## 技术栈要求\n${userContext.techStack.map(t => `- ${t}`).join('\n')}\n`);
|
|
400
|
-
}
|
|
401
|
-
// 注入所有用户回答
|
|
402
|
-
const relevantAnswers = Object.entries(answers).filter(([key]) => !['目标', '技术栈', '测试', '文档', 'objective', 'techStack', 'testCoverage', 'documentationLevel'].includes(key));
|
|
403
|
-
if (relevantAnswers.length > 0) {
|
|
404
|
-
parts.push(`## 其他要求\n${relevantAnswers.map(([k, v]) => `- ${k}: ${v}`).join('\n')}\n`);
|
|
405
|
-
}
|
|
406
|
-
parts.push(`## 输出要求
|
|
407
|
-
- 完成功能实现
|
|
408
|
-
- 代码可编译
|
|
409
|
-
- 遵循项目规范
|
|
410
|
-
- 添加必要注释`);
|
|
411
|
-
return parts.join('\n');
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* 构建测试任务描述
|
|
415
|
-
*/
|
|
416
|
-
buildTestDescription(goal, devTaskId, userContext) {
|
|
417
|
-
const coverage = this.parseCoverage(userContext.testCoverage || '60%');
|
|
418
|
-
return `## 测试目标
|
|
419
|
-
为 "${goal}" 编写测试用例
|
|
420
|
-
|
|
421
|
-
## 关联开发任务
|
|
422
|
-
${devTaskId}
|
|
423
|
-
|
|
424
|
-
## 测试要求
|
|
425
|
-
- 单元测试覆盖率 >= ${coverage}%
|
|
426
|
-
- 测试正常流程
|
|
427
|
-
- 测试边界情况
|
|
428
|
-
- 测试异常处理
|
|
429
|
-
|
|
430
|
-
## 测试文件
|
|
431
|
-
- 创建 \`.test.ts\` 或 \`.spec.ts\` 文件
|
|
432
|
-
- 放置在与源文件相同目录或 \`tests/\` 目录
|
|
433
|
-
|
|
434
|
-
## 输出
|
|
435
|
-
- 测试文件
|
|
436
|
-
- 测试报告
|
|
437
|
-
- 覆盖率报告`;
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* 构建 E2E 测试任务描述
|
|
441
|
-
*/
|
|
442
|
-
buildE2ETestDescription(e2eType, parsedTask, userContext) {
|
|
443
|
-
const typeConfig = this.getE2ETypeConfig(e2eType);
|
|
444
|
-
return `## E2E 测试目标
|
|
445
|
-
执行完整的端到端测试,验证关键用户流程
|
|
446
|
-
|
|
447
|
-
## 应用类型
|
|
448
|
-
${typeConfig.description}
|
|
449
|
-
|
|
450
|
-
## 测试框架
|
|
451
|
-
${typeConfig.frameworks.map(f => `- ${f}`).join('\n')}
|
|
452
|
-
|
|
453
|
-
## 测试范围
|
|
454
|
-
${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}
|
|
455
|
-
|
|
456
|
-
## 关键用户流程
|
|
457
|
-
根据应用功能,测试以下流程:
|
|
458
|
-
${this.generateUserFlows(parsedTask, e2eType)}
|
|
459
|
-
|
|
460
|
-
## 测试环境
|
|
461
|
-
${typeConfig.environments.map(e => `- ${e}`).join('\n')}
|
|
462
|
-
|
|
463
|
-
## 测试要求
|
|
464
|
-
1. **关键路径覆盖**: 所有核心用户流程必须有 E2E 测试
|
|
465
|
-
2. **断言完整**: 每个测试步骤必须有明确的断言
|
|
466
|
-
3. **等待策略**: 使用合理的等待机制,避免硬编码延迟
|
|
467
|
-
4. **数据隔离**: 测试数据独立,不影响其他测试
|
|
468
|
-
5. **清理机制**: 测试后清理创建的数据
|
|
469
|
-
|
|
470
|
-
## 输出要求
|
|
471
|
-
- E2E 测试文件 (tests/e2e/*.spec.ts)
|
|
472
|
-
- 测试执行报告
|
|
473
|
-
- 截图/录像 (失败时)
|
|
474
|
-
- 测试覆盖率报告 (如有)
|
|
475
|
-
|
|
476
|
-
## 运行命令
|
|
477
|
-
\`\`\`bash
|
|
478
|
-
${typeConfig.runCommand}
|
|
479
|
-
\`\`\`
|
|
480
|
-
|
|
481
|
-
## 验收标准
|
|
482
|
-
- [ ] 所有 E2E 测试用例通过
|
|
483
|
-
- [ ] 关键用户流程验证完成
|
|
484
|
-
- [ ] 跨浏览器/设备兼容性验证
|
|
485
|
-
- [ ] E2E 测试报告已生成
|
|
486
|
-
- [ ] 无阻塞级别的缺陷`;
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* 获取 E2E 测试类型配置
|
|
490
|
-
*/
|
|
491
|
-
getE2ETypeConfig(type) {
|
|
492
|
-
const configs = {
|
|
493
|
-
web: {
|
|
494
|
-
description: 'Web 应用 (浏览器)',
|
|
495
|
-
frameworks: ['Playwright (推荐)', 'Cypress', 'Selenium WebDriver', 'Puppeteer'],
|
|
496
|
-
environments: ['Chrome', 'Firefox', 'Safari', 'Edge', 'Mobile Viewports'],
|
|
497
|
-
runCommand: 'npx playwright test --reporter=html'
|
|
498
|
-
},
|
|
499
|
-
mobile: {
|
|
500
|
-
description: '移动应用 (iOS/Android)',
|
|
501
|
-
frameworks: ['Appium', 'Detox (React Native)', 'XCUITest (iOS)', 'Espresso (Android)'],
|
|
502
|
-
environments: ['iOS Simulator', 'Android Emulator', 'Real Devices'],
|
|
503
|
-
runCommand: 'npx appium --base-path /wd/hub && npm run test:e2e'
|
|
504
|
-
},
|
|
505
|
-
gui: {
|
|
506
|
-
description: 'GUI 桌面应用 (Electron/Native)',
|
|
507
|
-
frameworks: ['Playwright for Electron', 'Spectron (Electron)', 'Robot Framework', 'PyAutoGUI'],
|
|
508
|
-
environments: ['Windows', 'macOS', 'Linux'],
|
|
509
|
-
runCommand: 'npm run test:e2e'
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
return configs[type];
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* 生成用户流程测试用例
|
|
516
|
-
*/
|
|
517
|
-
generateUserFlows(parsedTask, type) {
|
|
518
|
-
const flows = [];
|
|
519
|
-
const goals = parsedTask.goals;
|
|
520
|
-
// 根据目标生成用户流程
|
|
521
|
-
goals.forEach((goal, i) => {
|
|
522
|
-
flows.push(`\n### 流程 ${i + 1}: ${goal}`);
|
|
523
|
-
flows.push('```gherkin');
|
|
524
|
-
flows.push(`Feature: ${goal}`);
|
|
525
|
-
flows.push('');
|
|
526
|
-
flows.push(' Scenario: 正常流程');
|
|
527
|
-
flows.push(` Given 用户已启动应用`);
|
|
528
|
-
flows.push(` When 用户执行 "${goal}" 操作`);
|
|
529
|
-
flows.push(` Then 操作成功完成`);
|
|
530
|
-
flows.push('```');
|
|
531
|
-
});
|
|
532
|
-
return flows.join('\n');
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* 解析覆盖率数值
|
|
536
|
-
*/
|
|
537
|
-
parseCoverage(coverageStr) {
|
|
538
|
-
const match = coverageStr.match(/(\d+)/);
|
|
539
|
-
return match ? parseInt(match[1], 10) : 60;
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* 生成验收标准
|
|
543
|
-
*/
|
|
544
|
-
generateAcceptanceCriteria(goal, userContext) {
|
|
545
|
-
const criteria = [
|
|
546
|
-
`功能 "${goal}" 已实现`,
|
|
547
|
-
'代码可编译,无错误',
|
|
548
|
-
'代码符合项目规范',
|
|
549
|
-
'必要的注释已添加'
|
|
550
|
-
];
|
|
551
|
-
if (userContext.testCoverage) {
|
|
552
|
-
criteria.push(`测试覆盖率 >= ${userContext.testCoverage}`);
|
|
553
|
-
}
|
|
554
|
-
if (userContext.techStack?.length) {
|
|
555
|
-
criteria.push(`使用指定技术栈: ${userContext.techStack.join(', ')}`);
|
|
556
|
-
}
|
|
557
|
-
criteria.push('无安全隐患');
|
|
558
|
-
criteria.push('边界情况已处理');
|
|
559
|
-
return criteria;
|
|
560
|
-
}
|
|
561
163
|
generateTaskId() {
|
|
562
164
|
const timestamp = Date.now().toString(36).toUpperCase();
|
|
563
165
|
const rand = Math.random().toString(36).slice(2, 4).toUpperCase();
|
|
564
166
|
return `TASK-${timestamp}${rand}`;
|
|
565
167
|
}
|
|
566
|
-
determinePriority(goalIndex) {
|
|
567
|
-
// First goal is highest priority
|
|
568
|
-
if (goalIndex === 0)
|
|
569
|
-
return 'P1';
|
|
570
|
-
return 'P2';
|
|
571
|
-
}
|
|
572
|
-
estimateComplexity(goal) {
|
|
573
|
-
if (goal.includes('测试'))
|
|
574
|
-
return 'medium';
|
|
575
|
-
if (goal.includes('实现') || goal.includes('开发'))
|
|
576
|
-
return 'medium';
|
|
577
|
-
if (goal.includes('设计') || goal.includes('研究'))
|
|
578
|
-
return 'high';
|
|
579
|
-
if (goal.includes('文档') || goal.includes('说明'))
|
|
580
|
-
return 'low';
|
|
581
|
-
return 'medium';
|
|
582
|
-
}
|
|
583
168
|
}
|
|
584
169
|
exports.TaskPlanner = TaskPlanner;
|