openmatrix 0.1.63 → 0.1.64
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/agents/agent-runner.js +19 -10
- package/dist/cli/commands/brainstorm.js +14 -18
- package/dist/cli/commands/complete.js +35 -2
- package/dist/cli/commands/start.js +6 -3
- package/dist/cli/commands/step.js +7 -1
- package/dist/orchestrator/executor.js +1 -1
- package/dist/orchestrator/git-commit-manager.js +12 -2
- package/dist/orchestrator/phase-executor.d.ts +3 -0
- package/dist/orchestrator/phase-executor.js +445 -349
- package/dist/orchestrator/scheduler.js +1 -1
- package/dist/storage/file-store.d.ts +9 -1
- package/dist/storage/file-store.js +24 -9
- package/dist/storage/state-manager.js +58 -1
- package/dist/types/index.d.ts +6 -0
- package/package.json +1 -1
- package/skills/auto.md +14 -2
- package/skills/meeting.md +15 -0
- package/skills/start.md +10 -1
|
@@ -202,62 +202,62 @@ class PhaseExecutor {
|
|
|
202
202
|
*/
|
|
203
203
|
buildTDDPrompt(task) {
|
|
204
204
|
const parts = [];
|
|
205
|
-
parts.push(`# TDD 阶段 - 先写测试 (Test-First)
|
|
206
|
-
|
|
207
|
-
## 任务信息
|
|
208
|
-
- ID: ${task.id}
|
|
209
|
-
- 标题: ${task.title}
|
|
210
|
-
- 描述: ${task.description}
|
|
211
|
-
|
|
212
|
-
## TDD 目标
|
|
213
|
-
在编写实现代码之前,先编写测试用例。这确保:
|
|
214
|
-
1. 你理解需求
|
|
215
|
-
2. 代码可测试
|
|
216
|
-
3. 有明确的成功标准
|
|
217
|
-
|
|
218
|
-
## 验收标准 → 测试用例
|
|
219
|
-
${task.acceptanceCriteria?.map((c, i) => `${i + 1}. ${c}`).join('\n') || '根据任务描述生成测试用例'}
|
|
220
|
-
|
|
221
|
-
## 测试要求
|
|
222
|
-
1. **覆盖正常流程** - 主要功能路径
|
|
223
|
-
2. **覆盖边界情况** - 空值、极值、特殊字符
|
|
224
|
-
3. **覆盖异常处理** - 错误输入、网络失败
|
|
225
|
-
4. **AAA 模式** - Arrange, Act, Assert
|
|
226
|
-
|
|
227
|
-
## 测试框架
|
|
228
|
-
根据项目选择:
|
|
229
|
-
- TypeScript/JavaScript: Vitest, Jest
|
|
230
|
-
- Python: pytest
|
|
205
|
+
parts.push(`# TDD 阶段 - 先写测试 (Test-First)
|
|
206
|
+
|
|
207
|
+
## 任务信息
|
|
208
|
+
- ID: ${task.id}
|
|
209
|
+
- 标题: ${task.title}
|
|
210
|
+
- 描述: ${task.description}
|
|
211
|
+
|
|
212
|
+
## TDD 目标
|
|
213
|
+
在编写实现代码之前,先编写测试用例。这确保:
|
|
214
|
+
1. 你理解需求
|
|
215
|
+
2. 代码可测试
|
|
216
|
+
3. 有明确的成功标准
|
|
217
|
+
|
|
218
|
+
## 验收标准 → 测试用例
|
|
219
|
+
${task.acceptanceCriteria?.map((c, i) => `${i + 1}. ${c}`).join('\n') || '根据任务描述生成测试用例'}
|
|
220
|
+
|
|
221
|
+
## 测试要求
|
|
222
|
+
1. **覆盖正常流程** - 主要功能路径
|
|
223
|
+
2. **覆盖边界情况** - 空值、极值、特殊字符
|
|
224
|
+
3. **覆盖异常处理** - 错误输入、网络失败
|
|
225
|
+
4. **AAA 模式** - Arrange, Act, Assert
|
|
226
|
+
|
|
227
|
+
## 测试框架
|
|
228
|
+
根据项目选择:
|
|
229
|
+
- TypeScript/JavaScript: Vitest, Jest
|
|
230
|
+
- Python: pytest
|
|
231
231
|
- Go: testing package`);
|
|
232
232
|
// Auto 模式提示 - 不要停下来询问用户
|
|
233
233
|
if (this.isAutoMode) {
|
|
234
|
-
parts.push(`
|
|
235
|
-
|
|
236
|
-
## ⚠️ 全自动执行模式
|
|
237
|
-
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
238
|
-
- **不要停下来询问用户确认** - 直接创建测试文件
|
|
239
|
-
- **不要输出"继续..."或等待用户回复** - 完成后直接返回结果
|
|
240
|
-
- **不要询问"是否需要..."** - 根据验收标准自动生成测试
|
|
241
|
-
- 测试应该失败 (RED 阶段),这是正确的
|
|
234
|
+
parts.push(`
|
|
235
|
+
|
|
236
|
+
## ⚠️ 全自动执行模式
|
|
237
|
+
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
238
|
+
- **不要停下来询问用户确认** - 直接创建测试文件
|
|
239
|
+
- **不要输出"继续..."或等待用户回复** - 完成后直接返回结果
|
|
240
|
+
- **不要询问"是否需要..."** - 根据验收标准自动生成测试
|
|
241
|
+
- 测试应该失败 (RED 阶段),这是正确的
|
|
242
242
|
- 完成后直接输出结果,不要等待任何确认`);
|
|
243
243
|
}
|
|
244
|
-
parts.push(`
|
|
245
|
-
|
|
246
|
-
## 输出
|
|
247
|
-
1. 创建测试文件 (\`.test.ts\` 或 \`.spec.ts\`)
|
|
248
|
-
2. 测试应该**失败** (因为还没实现)
|
|
249
|
-
3. 输出测试文件路径
|
|
250
|
-
|
|
251
|
-
## 验证
|
|
252
|
-
运行 \`npm test\` 确认测试失败 (这是正确的!)
|
|
253
|
-
|
|
254
|
-
## 输出格式
|
|
255
|
-
\`\`\`
|
|
256
|
-
TDD_TESTS_CREATED
|
|
257
|
-
测试文件: [路径]
|
|
258
|
-
测试用例数: [数量]
|
|
259
|
-
预期: 全部失败 (RED 阶段)
|
|
260
|
-
\`\`\`
|
|
244
|
+
parts.push(`
|
|
245
|
+
|
|
246
|
+
## 输出
|
|
247
|
+
1. 创建测试文件 (\`.test.ts\` 或 \`.spec.ts\`)
|
|
248
|
+
2. 测试应该**失败** (因为还没实现)
|
|
249
|
+
3. 输出测试文件路径
|
|
250
|
+
|
|
251
|
+
## 验证
|
|
252
|
+
运行 \`npm test\` 确认测试失败 (这是正确的!)
|
|
253
|
+
|
|
254
|
+
## 输出格式
|
|
255
|
+
\`\`\`
|
|
256
|
+
TDD_TESTS_CREATED
|
|
257
|
+
测试文件: [路径]
|
|
258
|
+
测试用例数: [数量]
|
|
259
|
+
预期: 全部失败 (RED 阶段)
|
|
260
|
+
\`\`\`
|
|
261
261
|
`);
|
|
262
262
|
return parts.join('\n');
|
|
263
263
|
}
|
|
@@ -299,86 +299,86 @@ TDD_TESTS_CREATED
|
|
|
299
299
|
buildDevelopPrompt(task) {
|
|
300
300
|
const parts = [];
|
|
301
301
|
const isTDDMode = this.qualityConfig.tdd;
|
|
302
|
-
parts.push(`# 开发阶段 (Develop Phase)${isTDDMode ? ' - TDD GREEN 阶段' : ''}
|
|
303
|
-
|
|
304
|
-
## 任务信息
|
|
305
|
-
- ID: ${task.id}
|
|
306
|
-
- 标题: ${task.title}
|
|
307
|
-
- 描述: ${task.description}
|
|
308
|
-
- 优先级: ${task.priority}
|
|
302
|
+
parts.push(`# 开发阶段 (Develop Phase)${isTDDMode ? ' - TDD GREEN 阶段' : ''}
|
|
303
|
+
|
|
304
|
+
## 任务信息
|
|
305
|
+
- ID: ${task.id}
|
|
306
|
+
- 标题: ${task.title}
|
|
307
|
+
- 描述: ${task.description}
|
|
308
|
+
- 优先级: ${task.priority}
|
|
309
309
|
- 质量级别: ${this.qualityConfig.level}`);
|
|
310
310
|
// Auto 模式提示 - 不要停下来询问用户
|
|
311
311
|
if (this.isAutoMode) {
|
|
312
|
-
parts.push(`
|
|
313
|
-
|
|
314
|
-
## ⚠️ 全自动执行模式
|
|
315
|
-
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
316
|
-
- **不要停下来询问用户确认** - 直接执行所有操作
|
|
317
|
-
- **不要输出"继续..."或等待用户回复** - 完成任务后直接返回结果
|
|
318
|
-
- **不要询问"是否需要..."** - 自动做出合理决策
|
|
319
|
-
- 如果遇到阻塞问题,记录到 Meeting 并继续执行其他任务
|
|
312
|
+
parts.push(`
|
|
313
|
+
|
|
314
|
+
## ⚠️ 全自动执行模式
|
|
315
|
+
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
316
|
+
- **不要停下来询问用户确认** - 直接执行所有操作
|
|
317
|
+
- **不要输出"继续..."或等待用户回复** - 完成任务后直接返回结果
|
|
318
|
+
- **不要询问"是否需要..."** - 自动做出合理决策
|
|
319
|
+
- 如果遇到阻塞问题,记录到 Meeting 并继续执行其他任务
|
|
320
320
|
- 完成后直接输出结果,不要等待任何确认`);
|
|
321
321
|
}
|
|
322
322
|
// TDD 模式提示
|
|
323
323
|
if (isTDDMode) {
|
|
324
|
-
parts.push(`
|
|
325
|
-
## ⚠️ TDD 模式
|
|
326
|
-
你已经在上一步编写了测试。现在需要:
|
|
327
|
-
1. 编写最小代码使测试通过
|
|
328
|
-
2. 不要过度设计
|
|
324
|
+
parts.push(`
|
|
325
|
+
## ⚠️ TDD 模式
|
|
326
|
+
你已经在上一步编写了测试。现在需要:
|
|
327
|
+
1. 编写最小代码使测试通过
|
|
328
|
+
2. 不要过度设计
|
|
329
329
|
3. 测试通过即可 (GREEN 阶段)`);
|
|
330
330
|
}
|
|
331
331
|
// 注入用户上下文
|
|
332
332
|
if (this.userContext.objective) {
|
|
333
|
-
parts.push(`
|
|
334
|
-
## 整体目标
|
|
333
|
+
parts.push(`
|
|
334
|
+
## 整体目标
|
|
335
335
|
${this.userContext.objective}`);
|
|
336
336
|
}
|
|
337
337
|
if (this.userContext.techStack && this.userContext.techStack.length > 0) {
|
|
338
|
-
parts.push(`
|
|
339
|
-
## 技术栈要求
|
|
338
|
+
parts.push(`
|
|
339
|
+
## 技术栈要求
|
|
340
340
|
${this.userContext.techStack.map(t => `- ${t}`).join('\n')}`);
|
|
341
341
|
}
|
|
342
342
|
// 注入验收标准
|
|
343
343
|
if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
|
|
344
|
-
parts.push(`
|
|
345
|
-
## 验收标准 (必须全部满足)
|
|
344
|
+
parts.push(`
|
|
345
|
+
## 验收标准 (必须全部满足)
|
|
346
346
|
${task.acceptanceCriteria.map((c, i) => `${i + 1}. [ ] ${c}`).join('\n')}`);
|
|
347
347
|
}
|
|
348
|
-
parts.push(`
|
|
349
|
-
## 开发要求
|
|
350
|
-
1. 根据任务描述编写代码
|
|
351
|
-
2. 遵循项目代码规范
|
|
352
|
-
3. 编写必要的注释
|
|
353
|
-
4. 处理边界情况和错误
|
|
354
|
-
5. 确保代码可编译
|
|
355
|
-
|
|
356
|
-
## 编码规范 (SOLID + Clean Code)
|
|
357
|
-
- **S**ingle Responsibility: 每个函数只做一件事
|
|
358
|
-
- **O**pen/Closed: 对扩展开放,对修改关闭
|
|
359
|
-
- **L**iskov Substitution: 子类可替换父类
|
|
360
|
-
- **I**nterface Segregation: 接口要小而专注
|
|
361
|
-
- **D**ependency Inversion: 依赖抽象而非具体
|
|
362
|
-
|
|
363
|
-
## 代码质量标准
|
|
364
|
-
- 函数长度: < 30 行
|
|
365
|
-
- 参数数量: < 4 个
|
|
366
|
-
- 嵌套深度: < 3 层
|
|
367
|
-
- 圈复杂度: < 10
|
|
368
|
-
|
|
369
|
-
## 输出要求
|
|
370
|
-
完成后,在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建:
|
|
371
|
-
- \`result.md\` - 实现说明
|
|
372
|
-
- \`changes.txt\` - 变更文件列表
|
|
373
|
-
|
|
374
|
-
## 完成检查清单
|
|
375
|
-
- [ ] 代码可编译
|
|
376
|
-
- [ ] 边界情况已处理
|
|
377
|
-
- [ ] 错误处理完善
|
|
378
|
-
- [ ] 无安全隐患
|
|
379
|
-
- [ ] 代码风格一致
|
|
380
|
-
- [ ] 验收标准全部满足
|
|
381
|
-
${isTDDMode ? '- [ ] 所有测试通过 (GREEN)' : ''}
|
|
348
|
+
parts.push(`
|
|
349
|
+
## 开发要求
|
|
350
|
+
1. 根据任务描述编写代码
|
|
351
|
+
2. 遵循项目代码规范
|
|
352
|
+
3. 编写必要的注释
|
|
353
|
+
4. 处理边界情况和错误
|
|
354
|
+
5. 确保代码可编译
|
|
355
|
+
|
|
356
|
+
## 编码规范 (SOLID + Clean Code)
|
|
357
|
+
- **S**ingle Responsibility: 每个函数只做一件事
|
|
358
|
+
- **O**pen/Closed: 对扩展开放,对修改关闭
|
|
359
|
+
- **L**iskov Substitution: 子类可替换父类
|
|
360
|
+
- **I**nterface Segregation: 接口要小而专注
|
|
361
|
+
- **D**ependency Inversion: 依赖抽象而非具体
|
|
362
|
+
|
|
363
|
+
## 代码质量标准
|
|
364
|
+
- 函数长度: < 30 行
|
|
365
|
+
- 参数数量: < 4 个
|
|
366
|
+
- 嵌套深度: < 3 层
|
|
367
|
+
- 圈复杂度: < 10
|
|
368
|
+
|
|
369
|
+
## 输出要求
|
|
370
|
+
完成后,在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建:
|
|
371
|
+
- \`result.md\` - 实现说明
|
|
372
|
+
- \`changes.txt\` - 变更文件列表
|
|
373
|
+
|
|
374
|
+
## 完成检查清单
|
|
375
|
+
- [ ] 代码可编译
|
|
376
|
+
- [ ] 边界情况已处理
|
|
377
|
+
- [ ] 错误处理完善
|
|
378
|
+
- [ ] 无安全隐患
|
|
379
|
+
- [ ] 代码风格一致
|
|
380
|
+
- [ ] 验收标准全部满足
|
|
381
|
+
${isTDDMode ? '- [ ] 所有测试通过 (GREEN)' : ''}
|
|
382
382
|
`);
|
|
383
383
|
return parts.join('\n');
|
|
384
384
|
}
|
|
@@ -388,189 +388,208 @@ ${isTDDMode ? '- [ ] 所有测试通过 (GREEN)' : ''}
|
|
|
388
388
|
buildVerifyPrompt(task) {
|
|
389
389
|
const parts = [];
|
|
390
390
|
const qc = this.qualityConfig;
|
|
391
|
-
parts.push(`# 验证阶段 (Verify Phase) - 严格质量门禁
|
|
392
|
-
|
|
393
|
-
## 任务信息
|
|
394
|
-
- ID: ${task.id}
|
|
395
|
-
- 标题: ${task.title}
|
|
396
|
-
- 质量级别: ${qc.level}
|
|
397
|
-
|
|
398
|
-
## 🚨 质量门禁 (Quality Gates)
|
|
399
|
-
|
|
400
|
-
| 检查项 | 要求 | 失败后果 |
|
|
401
|
-
|--------|------|----------|
|
|
402
|
-
| 编译 | 无错误 | ❌ 阻止通过 |
|
|
403
|
-
| 测试 | 全部通过 | ❌ 阻止通过 |
|
|
404
|
-
| 覆盖率 | >= ${qc.minCoverage}% | ${qc.minCoverage > 0 ? '❌ 阻止通过' : '⚠️ 仅警告'} |
|
|
405
|
-
| Lint | ${qc.strictLint ? '无 error' : '无严重 error'} | ${qc.strictLint ? '❌ 阻止通过' : '⚠️ 仅警告'} |
|
|
406
|
-
| 安全 | 无高危漏洞 | ${qc.securityScan ? '❌ 阻止通过' : '⏭️ 跳过'} |
|
|
407
|
-
| E2E | 全部通过 | ${qc.e2eTests ? '❌ 阻止通过' : '⏭️ 跳过'} |
|
|
391
|
+
parts.push(`# 验证阶段 (Verify Phase) - 严格质量门禁
|
|
392
|
+
|
|
393
|
+
## 任务信息
|
|
394
|
+
- ID: ${task.id}
|
|
395
|
+
- 标题: ${task.title}
|
|
396
|
+
- 质量级别: ${qc.level}
|
|
397
|
+
|
|
398
|
+
## 🚨 质量门禁 (Quality Gates)
|
|
399
|
+
|
|
400
|
+
| 检查项 | 要求 | 失败后果 |
|
|
401
|
+
|--------|------|----------|
|
|
402
|
+
| 编译 | 无错误 | ❌ 阻止通过 |
|
|
403
|
+
| 测试 | 全部通过 | ❌ 阻止通过 |
|
|
404
|
+
| 覆盖率 | >= ${qc.minCoverage}% | ${qc.minCoverage > 0 ? '❌ 阻止通过' : '⚠️ 仅警告'} |
|
|
405
|
+
| Lint | ${qc.strictLint ? '无 error' : '无严重 error'} | ${qc.strictLint ? '❌ 阻止通过' : '⚠️ 仅警告'} |
|
|
406
|
+
| 安全 | 无高危漏洞 | ${qc.securityScan ? '❌ 阻止通过' : '⏭️ 跳过'} |
|
|
407
|
+
| E2E | 全部通过 | ${qc.e2eTests ? '❌ 阻止通过' : '⏭️ 跳过'} |
|
|
408
408
|
| 验收标准 | 全部满足 | ❌ 阻止通过 |`);
|
|
409
409
|
// Auto 模式提示 - 不要停下来询问用户
|
|
410
410
|
if (this.isAutoMode) {
|
|
411
|
-
parts.push(`
|
|
412
|
-
|
|
413
|
-
## ⚠️ 全自动执行模式
|
|
414
|
-
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
415
|
-
- **不要停下来询问用户确认** - 直接执行所有验证命令
|
|
416
|
-
- **不要输出"继续..."或等待用户回复** - 完成验证后直接返回结果
|
|
417
|
-
- **不要询问"是否需要..."** - 根据质量门禁配置自动执行
|
|
418
|
-
- 如果质量门禁失败,记录失败原因并返回结果
|
|
411
|
+
parts.push(`
|
|
412
|
+
|
|
413
|
+
## ⚠️ 全自动执行模式
|
|
414
|
+
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
415
|
+
- **不要停下来询问用户确认** - 直接执行所有验证命令
|
|
416
|
+
- **不要输出"继续..."或等待用户回复** - 完成验证后直接返回结果
|
|
417
|
+
- **不要询问"是否需要..."** - 根据质量门禁配置自动执行
|
|
418
|
+
- 如果质量门禁失败,记录失败原因并返回结果
|
|
419
419
|
- 完成后直接输出结果,不要等待任何确认`);
|
|
420
420
|
}
|
|
421
|
-
parts.push(`
|
|
422
|
-
|
|
423
|
-
## 自动化验证命令
|
|
424
|
-
|
|
425
|
-
### 1. 编译检查 (必须通过)
|
|
426
|
-
\`\`\`bash
|
|
427
|
-
npm run build
|
|
428
|
-
\`\`\`
|
|
429
|
-
**预期**: 无编译错误
|
|
430
|
-
**失败后果**: ❌ VERIFY_FAILED
|
|
431
|
-
|
|
432
|
-
### 2. 测试运行 (必须通过)
|
|
433
|
-
\`\`\`bash
|
|
434
|
-
npm test
|
|
435
|
-
\`\`\`
|
|
436
|
-
**预期**: 所有测试通过
|
|
437
|
-
**失败后果**: ❌ VERIFY_FAILED
|
|
438
|
-
|
|
439
|
-
### 3. 覆盖率检查
|
|
440
|
-
\`\`\`bash
|
|
441
|
-
npm test -- --coverage 2>/dev/null || npm run test:coverage 2>/dev/null || echo "Coverage check skipped"
|
|
442
|
-
\`\`\`
|
|
443
|
-
**最低覆盖率**: ${qc.minCoverage}%
|
|
444
|
-
**失败后果**: ${qc.minCoverage > 0 ? '❌ VERIFY_FAILED' : '⚠️ 警告'}
|
|
445
|
-
|
|
446
|
-
### 4. Lint 检查
|
|
447
|
-
\`\`\`bash
|
|
448
|
-
# 先检查是否有 lint 脚本
|
|
449
|
-
npm run lint 2>&1 || echo "EXIT_CODE: $?"
|
|
450
|
-
\`\`\`
|
|
451
|
-
**重要**: 如果 lint 命令返回非零退出码且有 errors,必须报告为 VERIFY_FAILED。
|
|
452
|
-
如果项目没有 lint 脚本(显示 "missing script"),标记为 ⏭️ Skipped。
|
|
453
|
-
**要求**: ${qc.strictLint ? '无 error' : '无严重 error'}
|
|
454
|
-
**失败后果**: ${qc.strictLint ? '❌ VERIFY_FAILED' : '⚠️ 警告'}
|
|
455
|
-
|
|
456
|
-
### 5. 安全扫描
|
|
457
|
-
${qc.securityScan ? `\`\`\`bash
|
|
458
|
-
npm audit --audit-level=high || echo "Security scan skipped"
|
|
459
|
-
\`\`\`
|
|
460
|
-
**要求**: 无 high/critical 漏洞
|
|
461
|
-
**失败后果**: ❌ VERIFY_FAILED` : '⏭️ 已禁用'}
|
|
462
|
-
|
|
463
|
-
### 6. E2E 测试 (端到端测试)
|
|
464
|
-
${qc.e2eTests ? `\`\`\`bash
|
|
465
|
-
#
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
#
|
|
469
|
-
npx
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
421
|
+
parts.push(`
|
|
422
|
+
|
|
423
|
+
## 自动化验证命令
|
|
424
|
+
|
|
425
|
+
### 1. 编译检查 (必须通过)
|
|
426
|
+
\`\`\`bash
|
|
427
|
+
npm run build
|
|
428
|
+
\`\`\`
|
|
429
|
+
**预期**: 无编译错误
|
|
430
|
+
**失败后果**: ❌ VERIFY_FAILED
|
|
431
|
+
|
|
432
|
+
### 2. 测试运行 (必须通过)
|
|
433
|
+
\`\`\`bash
|
|
434
|
+
npm test
|
|
435
|
+
\`\`\`
|
|
436
|
+
**预期**: 所有测试通过
|
|
437
|
+
**失败后果**: ❌ VERIFY_FAILED
|
|
438
|
+
|
|
439
|
+
### 3. 覆盖率检查
|
|
440
|
+
\`\`\`bash
|
|
441
|
+
npm test -- --coverage 2>/dev/null || npm run test:coverage 2>/dev/null || echo "Coverage check skipped"
|
|
442
|
+
\`\`\`
|
|
443
|
+
**最低覆盖率**: ${qc.minCoverage}%
|
|
444
|
+
**失败后果**: ${qc.minCoverage > 0 ? '❌ VERIFY_FAILED' : '⚠️ 警告'}
|
|
445
|
+
|
|
446
|
+
### 4. Lint 检查
|
|
447
|
+
\`\`\`bash
|
|
448
|
+
# 先检查是否有 lint 脚本
|
|
449
|
+
npm run lint 2>&1 || echo "EXIT_CODE: $?"
|
|
450
|
+
\`\`\`
|
|
451
|
+
**重要**: 如果 lint 命令返回非零退出码且有 errors,必须报告为 VERIFY_FAILED。
|
|
452
|
+
如果项目没有 lint 脚本(显示 "missing script"),标记为 ⏭️ Skipped。
|
|
453
|
+
**要求**: ${qc.strictLint ? '无 error' : '无严重 error'}
|
|
454
|
+
**失败后果**: ${qc.strictLint ? '❌ VERIFY_FAILED' : '⚠️ 警告'}
|
|
455
|
+
|
|
456
|
+
### 5. 安全扫描
|
|
457
|
+
${qc.securityScan ? `\`\`\`bash
|
|
458
|
+
npm audit --audit-level=high || echo "Security scan skipped"
|
|
459
|
+
\`\`\`
|
|
460
|
+
**要求**: 无 high/critical 漏洞
|
|
461
|
+
**失败后果**: ❌ VERIFY_FAILED` : '⏭️ 已禁用'}
|
|
462
|
+
|
|
463
|
+
### 6. E2E 测试 (端到端测试)
|
|
464
|
+
${qc.e2eTests ? `\`\`\`bash
|
|
465
|
+
# 首先检查 E2E 测试工具是否可用
|
|
466
|
+
# 不要直接运行测试 - 先检查工具是否存在
|
|
467
|
+
|
|
468
|
+
# 检查 Playwright
|
|
469
|
+
if command -v npx &> /dev/null && npx playwright --version 2>/dev/null; then
|
|
470
|
+
echo "✅ Playwright available"
|
|
471
|
+
npx playwright test
|
|
472
|
+
elif command -v npx &> /dev/null && npx cypress --version 2>/dev/null; then
|
|
473
|
+
echo "✅ Cypress available"
|
|
474
|
+
npx cypress run
|
|
475
|
+
# 检查移动端工具
|
|
476
|
+
elif command -v appium &> /dev/null; then
|
|
477
|
+
echo "✅ Appium available"
|
|
478
|
+
npx appium ...
|
|
479
|
+
elif command -v detox &> /dev/null; then
|
|
480
|
+
echo "✅ Detox available"
|
|
481
|
+
npx detox test
|
|
482
|
+
# 检查项目自定义脚本
|
|
483
|
+
elif npm run | grep -q "test:e2e"; then
|
|
484
|
+
echo "✅ Using project e2e script"
|
|
485
|
+
npm run test:e2e
|
|
486
|
+
else
|
|
487
|
+
echo "⚠️ No E2E test tool found - skipping E2E tests"
|
|
488
|
+
echo "Install Playwright: npm install -D @playwright/test"
|
|
489
|
+
echo "Or Cypress: npm install -D cypress"
|
|
490
|
+
exit 0
|
|
491
|
+
fi
|
|
492
|
+
\`\`\`
|
|
493
|
+
**要求**: 所有 E2E 测试通过(如果工具可用)
|
|
494
|
+
**失败后果**: ❌ VERIFY_FAILED (工具可用但未通过) / ⏭️ Skipped (工具不可用)` : '⏭️ 已禁用'}
|
|
495
|
+
|
|
477
496
|
### 7. 验收标准验证`);
|
|
478
497
|
// 注入验收标准
|
|
479
498
|
if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
|
|
480
|
-
parts.push(`
|
|
481
|
-
逐项检查以下标准:
|
|
482
|
-
${task.acceptanceCriteria.map((c, i) => `${i + 1}. [ ] ${c}`).join('\n')}
|
|
499
|
+
parts.push(`
|
|
500
|
+
逐项检查以下标准:
|
|
501
|
+
${task.acceptanceCriteria.map((c, i) => `${i + 1}. [ ] ${c}`).join('\n')}
|
|
483
502
|
**失败后果**: ❌ VERIFY_FAILED`);
|
|
484
503
|
}
|
|
485
504
|
else {
|
|
486
|
-
parts.push(`
|
|
505
|
+
parts.push(`
|
|
487
506
|
⏭️ 无验收标准定义`);
|
|
488
507
|
}
|
|
489
|
-
parts.push(`
|
|
490
|
-
|
|
491
|
-
## 📊 质量报告格式
|
|
492
|
-
|
|
493
|
-
在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建 \`quality-report.json\`:
|
|
494
|
-
|
|
495
|
-
\`\`\`json
|
|
496
|
-
{
|
|
497
|
-
"taskId": "${task.id}",
|
|
498
|
-
"timestamp": "[ISO时间]",
|
|
499
|
-
"tests": {
|
|
500
|
-
"passed": 0,
|
|
501
|
-
"failed": 0,
|
|
502
|
-
"skipped": 0,
|
|
503
|
-
"coverage": 0,
|
|
504
|
-
"status": "pass|fail"
|
|
505
|
-
},
|
|
506
|
-
"build": {
|
|
507
|
-
"success": true,
|
|
508
|
-
"errors": [],
|
|
509
|
-
"status": "pass|fail"
|
|
510
|
-
},
|
|
511
|
-
"lint": {
|
|
512
|
-
"errors": 0,
|
|
513
|
-
"warnings": 0,
|
|
514
|
-
"status": "pass|fail|warning"
|
|
515
|
-
},
|
|
516
|
-
"security": {
|
|
517
|
-
"vulnerabilities": [],
|
|
518
|
-
"status": "pass|fail"
|
|
519
|
-
},
|
|
520
|
-
"e2e": {
|
|
521
|
-
"passed": 0,
|
|
522
|
-
"failed": 0,
|
|
523
|
-
"skipped": 0,
|
|
524
|
-
"duration": 0,
|
|
525
|
-
"status": "pass|fail|skipped"
|
|
526
|
-
},
|
|
527
|
-
"acceptance": {
|
|
528
|
-
"total": ${task.acceptanceCriteria?.length || 0},
|
|
529
|
-
"met": 0,
|
|
530
|
-
"details": [],
|
|
531
|
-
"status": "pass|fail"
|
|
532
|
-
},
|
|
533
|
-
"overall": "pass|fail|warning"
|
|
534
|
-
}
|
|
535
|
-
\`\`\`
|
|
536
|
-
|
|
537
|
-
## 最终输出
|
|
538
|
-
|
|
539
|
-
✅ **所有门禁通过**:
|
|
540
|
-
\`\`\`
|
|
541
|
-
VERIFY_PASSED
|
|
542
|
-
Quality Score: [A/B/C/D/F]
|
|
543
|
-
- Tests: ✅ X/X passed, Y% coverage
|
|
544
|
-
- Build: ✅ Success
|
|
545
|
-
- Lint: ✅ No errors
|
|
546
|
-
- Security: ✅ No vulnerabilities
|
|
547
|
-
${qc.e2eTests ? '- E2E: ✅ X/X passed' : ''}
|
|
548
|
-
- Acceptance: ✅ N/M criteria met
|
|
549
|
-
\`\`\`
|
|
550
|
-
|
|
551
|
-
❌ **门禁失败**:
|
|
552
|
-
\`\`\`
|
|
553
|
-
VERIFY_FAILED
|
|
554
|
-
Failed Gates:
|
|
555
|
-
1. [检查项]: [失败原因]
|
|
556
|
-
2. [检查项]: [失败原因]
|
|
557
|
-
|
|
558
|
-
Fix Required:
|
|
559
|
-
1. [修复建议]
|
|
560
|
-
2. [修复建议]
|
|
561
|
-
\`\`\`
|
|
562
|
-
|
|
563
|
-
## ⚠️ 重要提示
|
|
564
|
-
- **不要跳过任何检查**
|
|
565
|
-
- **不要伪造通过结果**
|
|
566
|
-
- 如果项目没有某个脚本,标记为 "⏭️ Skipped" 而非 "❌ Failed"
|
|
567
|
-
- 所有检查结果必须基于实际命令输出
|
|
568
|
-
|
|
569
|
-
## 🔧 配置检查 (可选但推荐)
|
|
570
|
-
检查以下常见配置问题:
|
|
571
|
-
- **Vitest 配置**: 如果存在 \`e2e/\` 目录,确保 \`vite.config.ts\` 的 \`test.exclude\` 包含 \`e2e\`
|
|
572
|
-
- **测试框架冲突**: 确保 Vitest 不运行 Playwright/Cypress 测试文件
|
|
573
|
-
- 如果发现配置问题,记录到报告中但不要阻止通过
|
|
508
|
+
parts.push(`
|
|
509
|
+
|
|
510
|
+
## 📊 质量报告格式
|
|
511
|
+
|
|
512
|
+
在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建 \`quality-report.json\`:
|
|
513
|
+
|
|
514
|
+
\`\`\`json
|
|
515
|
+
{
|
|
516
|
+
"taskId": "${task.id}",
|
|
517
|
+
"timestamp": "[ISO时间]",
|
|
518
|
+
"tests": {
|
|
519
|
+
"passed": 0,
|
|
520
|
+
"failed": 0,
|
|
521
|
+
"skipped": 0,
|
|
522
|
+
"coverage": 0,
|
|
523
|
+
"status": "pass|fail"
|
|
524
|
+
},
|
|
525
|
+
"build": {
|
|
526
|
+
"success": true,
|
|
527
|
+
"errors": [],
|
|
528
|
+
"status": "pass|fail"
|
|
529
|
+
},
|
|
530
|
+
"lint": {
|
|
531
|
+
"errors": 0,
|
|
532
|
+
"warnings": 0,
|
|
533
|
+
"status": "pass|fail|warning"
|
|
534
|
+
},
|
|
535
|
+
"security": {
|
|
536
|
+
"vulnerabilities": [],
|
|
537
|
+
"status": "pass|fail"
|
|
538
|
+
},
|
|
539
|
+
"e2e": {
|
|
540
|
+
"passed": 0,
|
|
541
|
+
"failed": 0,
|
|
542
|
+
"skipped": 0,
|
|
543
|
+
"duration": 0,
|
|
544
|
+
"status": "pass|fail|skipped"
|
|
545
|
+
},
|
|
546
|
+
"acceptance": {
|
|
547
|
+
"total": ${task.acceptanceCriteria?.length || 0},
|
|
548
|
+
"met": 0,
|
|
549
|
+
"details": [],
|
|
550
|
+
"status": "pass|fail"
|
|
551
|
+
},
|
|
552
|
+
"overall": "pass|fail|warning"
|
|
553
|
+
}
|
|
554
|
+
\`\`\`
|
|
555
|
+
|
|
556
|
+
## 最终输出
|
|
557
|
+
|
|
558
|
+
✅ **所有门禁通过**:
|
|
559
|
+
\`\`\`
|
|
560
|
+
VERIFY_PASSED
|
|
561
|
+
Quality Score: [A/B/C/D/F]
|
|
562
|
+
- Tests: ✅ X/X passed, Y% coverage
|
|
563
|
+
- Build: ✅ Success
|
|
564
|
+
- Lint: ✅ No errors
|
|
565
|
+
- Security: ✅ No vulnerabilities
|
|
566
|
+
${qc.e2eTests ? '- E2E: ✅ X/X passed' : ''}
|
|
567
|
+
- Acceptance: ✅ N/M criteria met
|
|
568
|
+
\`\`\`
|
|
569
|
+
|
|
570
|
+
❌ **门禁失败**:
|
|
571
|
+
\`\`\`
|
|
572
|
+
VERIFY_FAILED
|
|
573
|
+
Failed Gates:
|
|
574
|
+
1. [检查项]: [失败原因]
|
|
575
|
+
2. [检查项]: [失败原因]
|
|
576
|
+
|
|
577
|
+
Fix Required:
|
|
578
|
+
1. [修复建议]
|
|
579
|
+
2. [修复建议]
|
|
580
|
+
\`\`\`
|
|
581
|
+
|
|
582
|
+
## ⚠️ 重要提示
|
|
583
|
+
- **不要跳过任何检查**
|
|
584
|
+
- **不要伪造通过结果**
|
|
585
|
+
- 如果项目没有某个脚本,标记为 "⏭️ Skipped" 而非 "❌ Failed"
|
|
586
|
+
- 所有检查结果必须基于实际命令输出
|
|
587
|
+
|
|
588
|
+
## 🔧 配置检查 (可选但推荐)
|
|
589
|
+
检查以下常见配置问题:
|
|
590
|
+
- **Vitest 配置**: 如果存在 \`e2e/\` 目录,确保 \`vite.config.ts\` 的 \`test.exclude\` 包含 \`e2e\`
|
|
591
|
+
- **测试框架冲突**: 确保 Vitest 不运行 Playwright/Cypress 测试文件
|
|
592
|
+
- 如果发现配置问题,记录到报告中但不要阻止通过
|
|
574
593
|
`);
|
|
575
594
|
return parts.join('\n');
|
|
576
595
|
}
|
|
@@ -579,76 +598,76 @@ Fix Required:
|
|
|
579
598
|
*/
|
|
580
599
|
buildAcceptPrompt(task) {
|
|
581
600
|
const parts = [];
|
|
582
|
-
parts.push(`# 验收阶段 (Accept Phase)
|
|
583
|
-
|
|
584
|
-
## 任务信息
|
|
585
|
-
- ID: ${task.id}
|
|
586
|
-
- 标题: ${task.title}
|
|
601
|
+
parts.push(`# 验收阶段 (Accept Phase)
|
|
602
|
+
|
|
603
|
+
## 任务信息
|
|
604
|
+
- ID: ${task.id}
|
|
605
|
+
- 标题: ${task.title}
|
|
587
606
|
- 描述: ${task.description}`);
|
|
588
607
|
// Auto 模式提示 - 不要停下来询问用户
|
|
589
608
|
if (this.isAutoMode) {
|
|
590
|
-
parts.push(`
|
|
591
|
-
|
|
592
|
-
## ⚠️ 全自动执行模式
|
|
593
|
-
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
594
|
-
- **不要停下来询问用户确认** - 直接执行所有验收检查
|
|
595
|
-
- **不要输出"继续..."或等待用户回复** - 完成验收后直接返回结果
|
|
596
|
-
- **不要询问"是否通过..."** - 根据验收标准自动判断
|
|
597
|
-
- 如果验收标准全部满足,直接输出 ACCEPT_PASSED
|
|
609
|
+
parts.push(`
|
|
610
|
+
|
|
611
|
+
## ⚠️ 全自动执行模式
|
|
612
|
+
**重要**: 此任务在全自动模式下执行,必须遵守以下规则:
|
|
613
|
+
- **不要停下来询问用户确认** - 直接执行所有验收检查
|
|
614
|
+
- **不要输出"继续..."或等待用户回复** - 完成验收后直接返回结果
|
|
615
|
+
- **不要询问"是否通过..."** - 根据验收标准自动判断
|
|
616
|
+
- 如果验收标准全部满足,直接输出 ACCEPT_PASSED
|
|
598
617
|
- 完成后直接输出结果,不要等待任何确认`);
|
|
599
618
|
}
|
|
600
619
|
// 注入验收标准
|
|
601
620
|
if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
|
|
602
|
-
parts.push(`
|
|
603
|
-
|
|
604
|
-
## 验收标准 (必须全部满足)
|
|
621
|
+
parts.push(`
|
|
622
|
+
|
|
623
|
+
## 验收标准 (必须全部满足)
|
|
605
624
|
${task.acceptanceCriteria.map((c, i) => `${i + 1}. [ ] ${c}`).join('\n')}`);
|
|
606
625
|
}
|
|
607
|
-
parts.push(`
|
|
608
|
-
## 验收检查清单
|
|
609
|
-
- [ ] 功能演示/验证
|
|
610
|
-
- [ ] 测试报告 (verify-report.md 已生成)
|
|
611
|
-
- [ ] 代码审查通过
|
|
612
|
-
- [ ] 文档已更新 (如需要)
|
|
613
|
-
- [ ] 所有验收标准已满足
|
|
614
|
-
|
|
615
|
-
## 验收流程
|
|
616
|
-
|
|
617
|
-
### 1. 检查验证阶段结果
|
|
618
|
-
读取 \`.openmatrix/tasks/${task.id}/artifacts/verify-report.md\`
|
|
619
|
-
确认所有检查项已通过
|
|
620
|
-
|
|
621
|
-
### 2. 验证验收标准
|
|
622
|
-
逐项检查验收标准是否满足
|
|
623
|
-
|
|
624
|
-
### 3. 最终确认
|
|
625
|
-
- 确认代码可以合并
|
|
626
|
-
- 确认无遗留问题
|
|
627
|
-
|
|
628
|
-
## 输出要求
|
|
629
|
-
在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建:
|
|
630
|
-
- \`accept-report.md\` - 验收报告
|
|
631
|
-
|
|
632
|
-
## 结果格式
|
|
633
|
-
如果验收通过,输出:
|
|
634
|
-
\`\`\`
|
|
635
|
-
ACCEPT_PASSED
|
|
636
|
-
\`\`\`
|
|
637
|
-
|
|
638
|
-
如果需要修改,输出:
|
|
639
|
-
\`\`\`
|
|
640
|
-
ACCEPT_NEEDS_MODIFICATION
|
|
641
|
-
修改建议:
|
|
642
|
-
1. [建议]
|
|
643
|
-
2. [建议]
|
|
644
|
-
\`\`\`
|
|
645
|
-
|
|
646
|
-
如果验收失败,输出:
|
|
647
|
-
\`\`\`
|
|
648
|
-
ACCEPT_FAILED
|
|
649
|
-
失败原因:
|
|
650
|
-
1. [原因]
|
|
651
|
-
\`\`\`
|
|
626
|
+
parts.push(`
|
|
627
|
+
## 验收检查清单
|
|
628
|
+
- [ ] 功能演示/验证
|
|
629
|
+
- [ ] 测试报告 (verify-report.md 已生成)
|
|
630
|
+
- [ ] 代码审查通过
|
|
631
|
+
- [ ] 文档已更新 (如需要)
|
|
632
|
+
- [ ] 所有验收标准已满足
|
|
633
|
+
|
|
634
|
+
## 验收流程
|
|
635
|
+
|
|
636
|
+
### 1. 检查验证阶段结果
|
|
637
|
+
读取 \`.openmatrix/tasks/${task.id}/artifacts/verify-report.md\`
|
|
638
|
+
确认所有检查项已通过
|
|
639
|
+
|
|
640
|
+
### 2. 验证验收标准
|
|
641
|
+
逐项检查验收标准是否满足
|
|
642
|
+
|
|
643
|
+
### 3. 最终确认
|
|
644
|
+
- 确认代码可以合并
|
|
645
|
+
- 确认无遗留问题
|
|
646
|
+
|
|
647
|
+
## 输出要求
|
|
648
|
+
在 \`.openmatrix/tasks/${task.id}/artifacts/\` 目录下创建:
|
|
649
|
+
- \`accept-report.md\` - 验收报告
|
|
650
|
+
|
|
651
|
+
## 结果格式
|
|
652
|
+
如果验收通过,输出:
|
|
653
|
+
\`\`\`
|
|
654
|
+
ACCEPT_PASSED
|
|
655
|
+
\`\`\`
|
|
656
|
+
|
|
657
|
+
如果需要修改,输出:
|
|
658
|
+
\`\`\`
|
|
659
|
+
ACCEPT_NEEDS_MODIFICATION
|
|
660
|
+
修改建议:
|
|
661
|
+
1. [建议]
|
|
662
|
+
2. [建议]
|
|
663
|
+
\`\`\`
|
|
664
|
+
|
|
665
|
+
如果验收失败,输出:
|
|
666
|
+
\`\`\`
|
|
667
|
+
ACCEPT_FAILED
|
|
668
|
+
失败原因:
|
|
669
|
+
1. [原因]
|
|
670
|
+
\`\`\`
|
|
652
671
|
`);
|
|
653
672
|
return parts.join('\n');
|
|
654
673
|
}
|
|
@@ -805,6 +824,9 @@ ACCEPT_FAILED
|
|
|
805
824
|
}
|
|
806
825
|
/**
|
|
807
826
|
* 解析质量报告
|
|
827
|
+
*
|
|
828
|
+
* 策略:优先解析 JSON 格式,失败时使用正则表达式回退
|
|
829
|
+
* 支持多种测试框架输出格式(Vitest, Jest, Mocha, Tape)
|
|
808
830
|
*/
|
|
809
831
|
parseQualityReport(output) {
|
|
810
832
|
const result = {
|
|
@@ -816,13 +838,87 @@ ACCEPT_FAILED
|
|
|
816
838
|
e2e: { passed: 0, failed: 0, skipped: 0, duration: 0 },
|
|
817
839
|
acceptance: { met: 0, total: 0 }
|
|
818
840
|
};
|
|
819
|
-
//
|
|
820
|
-
const
|
|
821
|
-
if (
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
841
|
+
// 策略 1: 尝试解析 JSON 格式(质量门禁首选)
|
|
842
|
+
const jsonMatch = output.match(/```(?:json)?\s*\{[\s\S]*?"tests":\s*\{[\s\S]*?\}[\s\S]*?\}\s*```/);
|
|
843
|
+
if (jsonMatch) {
|
|
844
|
+
try {
|
|
845
|
+
const jsonStr = jsonMatch[0].replace(/```(?:json)?/g, '').replace(/```/g, '').trim();
|
|
846
|
+
const jsonReport = JSON.parse(jsonStr);
|
|
847
|
+
// 解析 tests
|
|
848
|
+
if (jsonReport.tests) {
|
|
849
|
+
result.tests.passed = jsonReport.tests.passed ?? 0;
|
|
850
|
+
result.tests.failed = jsonReport.tests.failed ?? 0;
|
|
851
|
+
result.tests.coverage = jsonReport.tests.coverage ?? 0;
|
|
852
|
+
}
|
|
853
|
+
// 解析 build
|
|
854
|
+
if (jsonReport.build) {
|
|
855
|
+
result.build.success = jsonReport.build.success ?? false;
|
|
856
|
+
result.build.errors = jsonReport.build.errors ?? [];
|
|
857
|
+
}
|
|
858
|
+
// 解析 lint
|
|
859
|
+
if (jsonReport.lint) {
|
|
860
|
+
result.lint.errors = jsonReport.lint.errors ?? 0;
|
|
861
|
+
result.lint.warnings = jsonReport.lint.warnings ?? 0;
|
|
862
|
+
}
|
|
863
|
+
// 解析 security
|
|
864
|
+
if (jsonReport.security) {
|
|
865
|
+
result.security.vulnerabilities = jsonReport.security.vulnerabilities?.length ?? 0;
|
|
866
|
+
}
|
|
867
|
+
// 解析 e2e
|
|
868
|
+
if (jsonReport.e2e) {
|
|
869
|
+
result.e2e.passed = jsonReport.e2e.passed ?? 0;
|
|
870
|
+
result.e2e.failed = jsonReport.e2e.failed ?? 0;
|
|
871
|
+
result.e2e.skipped = jsonReport.e2e.skipped ?? 0;
|
|
872
|
+
result.e2e.duration = jsonReport.e2e.duration ?? 0;
|
|
873
|
+
}
|
|
874
|
+
// 解析 acceptance
|
|
875
|
+
if (jsonReport.acceptance) {
|
|
876
|
+
result.acceptance.total = jsonReport.acceptance.total ?? 0;
|
|
877
|
+
result.acceptance.met = jsonReport.acceptance.met ?? 0;
|
|
878
|
+
}
|
|
879
|
+
// 判断是否通过
|
|
880
|
+
const qc = this.qualityConfig;
|
|
881
|
+
const testsPassed = result.tests.failed === 0;
|
|
882
|
+
const coverageOk = result.tests.coverage >= qc.minCoverage;
|
|
883
|
+
const lintOk = qc.strictLint ? result.lint.errors === 0 : true;
|
|
884
|
+
const buildOk = result.build.success;
|
|
885
|
+
const e2eOk = qc.e2eTests ? result.e2e.failed === 0 : true;
|
|
886
|
+
result.passed = testsPassed && coverageOk && lintOk && buildOk && e2eOk;
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
catch (e) {
|
|
890
|
+
console.debug('JSON report parse failed, falling back to regex:', e);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
// 策略 2: 正则表达式回退 - 支持多种测试框架输出格式
|
|
894
|
+
// Vitest: "✓ 10 tests | 10 passed"
|
|
895
|
+
// Jest: "Tests: 10 passed, 10 total"
|
|
896
|
+
// Mocha: "10 passing"
|
|
897
|
+
// Tape: "# tests 10\n# ok\n# pass 10"
|
|
898
|
+
const testPatterns = [
|
|
899
|
+
/✓\s*(\d+)\s*tests.*?\|\s*(\d+)\s*passed/i, // Vitest
|
|
900
|
+
/Tests?:\s*(\d+)\s*passed/i, // Jest
|
|
901
|
+
/(\d+)\s*(?:passed|passing)/i, // Mocha/Tape
|
|
902
|
+
];
|
|
903
|
+
for (const pattern of testPatterns) {
|
|
904
|
+
const match = output.match(pattern);
|
|
905
|
+
if (match) {
|
|
906
|
+
result.tests.passed = parseInt(match[1], 10);
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
const failPatterns = [
|
|
911
|
+
/✗\s*(\d+)\s*tests/i, // Vitest
|
|
912
|
+
/Tests?:\s*(\d+)\s*failed/i, // Jest
|
|
913
|
+
/(\d+)\s*(?:failed|failing)/i, // Mocha/Tape
|
|
914
|
+
];
|
|
915
|
+
for (const pattern of failPatterns) {
|
|
916
|
+
const match = output.match(pattern);
|
|
917
|
+
if (match) {
|
|
918
|
+
result.tests.failed = parseInt(match[1], 10);
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
826
922
|
const coverageMatch = output.match(/(?:coverage|covered).*?(\d+)%/i);
|
|
827
923
|
if (coverageMatch)
|
|
828
924
|
result.tests.coverage = parseInt(coverageMatch[1], 10);
|