openmatrix 0.1.14 → 0.1.16

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/README.md CHANGED
@@ -161,15 +161,15 @@ ls ~/.claude/commands/om/
161
161
 
162
162
  ### 1️⃣ 三级质量配置 (第一个问题就让你选)
163
163
 
164
- | 级别 | TDD | 覆盖率 | Lint | 安全 | AI验收 | 适用场景 |
165
- |:----:|:---:|:------:|:----:|:----:|:------:|---------|
166
- | **strict** | ✅ | >80% | ✅ 严格 | ✅ | ✅ | 🏭 **生产代码** |
167
- | **balanced** | ❌ | >60% | ✅ | ✅ | ✅ | 📦 日常开发 |
168
- | **fast** | ❌ | >20% | ❌ | ❌ | ❌ | 🏃 快速原型 |
164
+ | 级别 | TDD | 覆盖率 | Lint | 安全 | E2E测试 | AI验收 | 适用场景 |
165
+ |:----:|:---:|:------:|:----:|:----:|:-------:|:------:|---------|
166
+ | **strict** | ✅ | >80% | ✅ 严格 | ✅ | ❓ 可选 | ✅ | 🏭 **生产代码** |
167
+ | **balanced** | ❌ | >60% | ✅ | ✅ | ❓ 可选 | ✅ | 📦 日常开发 |
168
+ | **fast** | ❌ | >20% | ❌ | ❌ | ❌ | ❌ | 🏃 快速原型 |
169
169
 
170
- > strict 可配置为 100%。默认 >80% 覆盖核心业务逻辑。
170
+ > E2E 测试耗时较长,建议根据项目需要选择。strict 可配置为 100%。默认 >80% 覆盖核心业务逻辑。
171
171
 
172
- ### 2️⃣ 六道质量门禁 (Verify 阶段)
172
+ ### 2️⃣ 七道质量门禁 (Verify 阶段)
173
173
 
174
174
  ```
175
175
  ┌─────────────────────────────────────────────────────────────┐
@@ -180,7 +180,8 @@ ls ~/.claude/commands/om/
180
180
  │ 🚪 Gate 3: 覆盖率检查 >20%/60%/80% → 可配置 │
181
181
  │ 🚪 Gate 4: Lint 检查 无 error → 可配置 │
182
182
  │ 🚪 Gate 5: 安全扫描 npm audit → 无高危漏洞 │
183
- │ 🚪 Gate 6: 验收标准 用户定义 必须全部满足
183
+ │ 🚪 Gate 6: E2E 测试 Playwright等 可选
184
+ │ 🚪 Gate 7: 验收标准 用户定义 → 必须全部满足 │
184
185
  └─────────────────────────────────────────────────────────────┘
185
186
  ```
186
187
 
@@ -378,6 +379,7 @@ Accept 阶段由 Reviewer Agent 执行:
378
379
  "build": { "success": true },
379
380
  "lint": { "errors": 0, "warnings": 3 },
380
381
  "security": { "vulnerabilities": [] },
382
+ "e2e": { "passed": 5, "failed": 0, "skipped": 0 },
381
383
  "acceptance": { "met": 5, "total": 5 }
382
384
  }
383
385
  ```
@@ -431,7 +433,8 @@ OpenMatrix 通过 Claude Code Agent 工具**原生支持所有主流编程语言
431
433
  "tdd": false,
432
434
  "minCoverage": 60,
433
435
  "strictLint": true,
434
- "securityScan": true
436
+ "securityScan": true,
437
+ "e2eTests": false
435
438
  },
436
439
  "approvalPoints": ["plan", "merge"],
437
440
  "agents": { "maxConcurrent": 3 }
@@ -452,12 +455,13 @@ cd openmatrix && npm install && npm run build && npm test
452
455
  ## Roadmap
453
456
 
454
457
  - [x] TDD 模式
455
- - [x] 6 道质量门禁
458
+ - [x] 7 道质量门禁
456
459
  - [x] Meeting 机制
457
460
  - [x] 质量报告
458
461
  - [x] AI 验收
459
462
  - [x] `/om:auto` 全自动模式
460
463
  - [x] 多语言支持 (Python/Go/Java/TypeScript 等)
464
+ - [x] E2E 测试支持 (Web/Mobile/GUI)
461
465
  - [ ] VSCode 扩展
462
466
  - [ ] CI/CD 集成
463
467
 
@@ -42,15 +42,22 @@ const task_planner_js_1 = require("../../orchestrator/task-planner.js");
42
42
  const approval_manager_js_1 = require("../../orchestrator/approval-manager.js");
43
43
  const executor_js_1 = require("../../orchestrator/executor.js");
44
44
  const gitignore_js_1 = require("../../utils/gitignore.js");
45
+ const index_js_1 = require("../../types/index.js");
45
46
  const fs = __importStar(require("fs/promises"));
46
47
  const path = __importStar(require("path"));
47
48
  exports.startCommand = new commander_1.Command('start')
48
49
  .description('启动新的任务执行周期')
49
50
  .argument('[input]', '任务文件路径或描述')
50
51
  .option('-c, --config <path>', '配置文件路径')
52
+ .option('--init-only', '仅初始化 .openmatrix 目录,不执行任务')
51
53
  .option('--skip-questions', '跳过澄清问题')
52
54
  .option('--mode <mode>', '执行模式 (confirm-all|confirm-key|auto)')
53
55
  .option('--json', '输出 JSON 格式 (供 Skill 解析)')
56
+ .option('--title <title>', '任务标题')
57
+ .option('--description <desc>', '任务描述')
58
+ .option('-q, --quality <level>', '质量级别 (strict|balanced|fast)')
59
+ .option('-t, --tech-stack <stack>', '技术栈 (逗号分隔,如 "TypeScript,Vue.js,PostgreSQL")')
60
+ .option('--docs <level>', '文档级别 (full|basic|minimal|none)')
54
61
  .action(async (input, options) => {
55
62
  const basePath = process.cwd();
56
63
  const omPath = path.join(basePath, '.openmatrix');
@@ -60,6 +67,21 @@ exports.startCommand = new commander_1.Command('start')
60
67
  await fs.mkdir(path.join(omPath, 'approvals'), { recursive: true });
61
68
  // 确保 .openmatrix 被 git 忽略
62
69
  await (0, gitignore_js_1.ensureOpenmatrixGitignore)(basePath);
70
+ // --init-only 模式:仅初始化目录后返回
71
+ if (options.initOnly) {
72
+ if (options.json) {
73
+ console.log(JSON.stringify({
74
+ status: 'initialized',
75
+ message: '.openmatrix 目录已初始化',
76
+ path: omPath
77
+ }));
78
+ }
79
+ else {
80
+ console.log('✅ .openmatrix 目录已初始化');
81
+ console.log(` 路径: ${omPath}`);
82
+ }
83
+ return;
84
+ }
63
85
  const stateManager = new state_manager_js_1.StateManager(omPath);
64
86
  await stateManager.initialize();
65
87
  const state = await stateManager.getState();
@@ -79,10 +101,18 @@ exports.startCommand = new commander_1.Command('start')
79
101
  }
80
102
  return;
81
103
  }
82
- // 获取任务内容
104
+ // 构建任务内容
83
105
  let taskContent = input;
106
+ // 如果提供了 --title 和 --description,构建任务内容
107
+ if (options.title || options.description) {
108
+ const title = options.title || '未命名任务';
109
+ const description = options.description || '';
110
+ const techStack = options.techStack ? `\n\n技术栈: ${options.techStack}` : '';
111
+ const docs = options.docs ? `\n文档要求: ${options.docs}` : '';
112
+ taskContent = `# ${title}\n\n${description}${techStack}${docs}`;
113
+ }
114
+ // 如果没有任务内容,尝试读取默认文件
84
115
  if (!taskContent) {
85
- // 尝试读取默认任务文件
86
116
  const defaultPath = path.join(basePath, 'TASK.md');
87
117
  try {
88
118
  taskContent = await fs.readFile(defaultPath, 'utf-8');
@@ -101,6 +131,7 @@ exports.startCommand = new commander_1.Command('start')
101
131
  console.log('❌ 请提供任务文件路径或描述');
102
132
  console.log(' 用法: openmatrix start <task.md>');
103
133
  console.log(' 或创建 TASK.md 文件');
134
+ console.log(' 或使用 --title 和 --description 选项');
104
135
  }
105
136
  return;
106
137
  }
@@ -158,9 +189,6 @@ exports.startCommand = new commander_1.Command('start')
158
189
  const executionMode = options.mode || 'confirm-key';
159
190
  let approvalPoints = [];
160
191
  // 根据模式设置审批点
161
- // auto 模式: 空数组,不暂停任何审批点
162
- // confirm-key 模式: 仅在关键节点暂停
163
- // confirm-all 模式: 每个阶段都暂停
164
192
  switch (executionMode) {
165
193
  case 'confirm-all':
166
194
  approvalPoints = ['plan', 'phase', 'merge', 'deploy'];
@@ -169,18 +197,27 @@ exports.startCommand = new commander_1.Command('start')
169
197
  approvalPoints = ['plan', 'merge', 'deploy'];
170
198
  break;
171
199
  case 'auto':
172
- approvalPoints = []; // 全自动模式:无任何审批点
200
+ approvalPoints = [];
173
201
  break;
174
202
  default:
175
203
  approvalPoints = ['plan', 'merge'];
176
204
  }
205
+ // 处理质量配置
206
+ let qualityConfig;
207
+ if (options.quality) {
208
+ const qualityLevel = options.quality.toLowerCase();
209
+ if (['strict', 'balanced', 'fast'].includes(qualityLevel)) {
210
+ qualityConfig = index_js_1.QUALITY_PRESETS[qualityLevel];
211
+ }
212
+ }
177
213
  // 更新状态
178
214
  await stateManager.updateState({
179
215
  status: 'running',
180
216
  currentPhase: 'execution',
181
217
  config: {
182
218
  ...state.config,
183
- approvalPoints: approvalPoints
219
+ approvalPoints: approvalPoints,
220
+ quality: qualityConfig || state.config.quality
184
221
  }
185
222
  });
186
223
  // 创建审批请求(如果有审批点)
@@ -198,7 +235,15 @@ exports.startCommand = new commander_1.Command('start')
198
235
  index: i + 1,
199
236
  title: t.title,
200
237
  priority: t.priority
201
- }))
238
+ })),
239
+ // 额外信息供 Skill 使用
240
+ taskInfo: {
241
+ title: options.title || parsedTask.title,
242
+ description: options.description,
243
+ quality: options.quality,
244
+ techStack: options.techStack,
245
+ docs: options.docs
246
+ }
202
247
  }));
203
248
  }
204
249
  else {
@@ -208,6 +253,12 @@ exports.startCommand = new commander_1.Command('start')
208
253
  });
209
254
  console.log(`\n🎯 执行模式: ${executionMode}`);
210
255
  console.log(` 审批点: ${approvalPoints.join(', ')}`);
256
+ if (options.quality) {
257
+ console.log(` 质量级别: ${options.quality}`);
258
+ }
259
+ if (options.techStack) {
260
+ console.log(` 技术栈: ${options.techStack}`);
261
+ }
211
262
  console.log(`\n⏸️ 等待计划审批`);
212
263
  console.log(` 审批ID: ${approval.id}`);
213
264
  console.log(` 使用 /om:approve ${approval.id} 审批`);
@@ -242,7 +293,15 @@ exports.startCommand = new commander_1.Command('start')
242
293
  taskId: t.taskId,
243
294
  agentType: t.agentType,
244
295
  timeout: t.timeout
245
- }))
296
+ })),
297
+ // 额外信息供 Skill 使用
298
+ taskInfo: {
299
+ title: options.title || parsedTask.title,
300
+ description: options.description,
301
+ quality: options.quality,
302
+ techStack: options.techStack,
303
+ docs: options.docs
304
+ }
246
305
  }));
247
306
  }
248
307
  else {
@@ -252,6 +311,12 @@ exports.startCommand = new commander_1.Command('start')
252
311
  });
253
312
  console.log(`\n🎯 执行模式: ${executionMode}`);
254
313
  console.log(` 审批点: ${approvalPoints.length > 0 ? approvalPoints.join(', ') : '无 (全自动)'}`);
314
+ if (options.quality) {
315
+ console.log(` 质量级别: ${options.quality}`);
316
+ }
317
+ if (options.techStack) {
318
+ console.log(` 技术栈: ${options.techStack}`);
319
+ }
255
320
  console.log('\n🚀 开始执行...');
256
321
  console.log(' 使用 /om:status 查看进度');
257
322
  }
@@ -44,6 +44,12 @@ export interface QualityGateResult {
44
44
  security: {
45
45
  vulnerabilities: number;
46
46
  };
47
+ e2e: {
48
+ passed: number;
49
+ failed: number;
50
+ skipped: number;
51
+ duration: number;
52
+ };
47
53
  acceptance: {
48
54
  met: number;
49
55
  total: number;
@@ -39,6 +39,7 @@ class PhaseExecutor {
39
39
  minCoverage: 60,
40
40
  strictLint: true,
41
41
  securityScan: true,
42
+ e2eTests: false,
42
43
  level: 'balanced'
43
44
  };
44
45
  constructor(stateManager, approvalManager) {
@@ -86,9 +87,9 @@ class PhaseExecutor {
86
87
  */
87
88
  setQualityLevel(level) {
88
89
  const presets = {
89
- fast: { tdd: false, minCoverage: 0, strictLint: false, securityScan: false, level: 'fast' },
90
- balanced: { tdd: false, minCoverage: 60, strictLint: true, securityScan: true, level: 'balanced' },
91
- strict: { tdd: true, minCoverage: 80, strictLint: true, securityScan: true, level: 'strict' }
90
+ fast: { tdd: false, minCoverage: 0, strictLint: false, securityScan: false, e2eTests: false, level: 'fast' },
91
+ balanced: { tdd: false, minCoverage: 60, strictLint: true, securityScan: true, e2eTests: false, level: 'balanced' },
92
+ strict: { tdd: true, minCoverage: 80, strictLint: true, securityScan: true, e2eTests: false, level: 'strict' }
92
93
  };
93
94
  this.qualityConfig = presets[level];
94
95
  this.minTestCoverage = this.qualityConfig.minCoverage;
@@ -376,6 +377,7 @@ ${isTDDMode ? '- [ ] 所有测试通过 (GREEN)' : ''}
376
377
  | 覆盖率 | >= ${qc.minCoverage}% | ${qc.minCoverage > 0 ? '❌ 阻止通过' : '⚠️ 仅警告'} |
377
378
  | Lint | ${qc.strictLint ? '无 error' : '无严重 error'} | ${qc.strictLint ? '❌ 阻止通过' : '⚠️ 仅警告'} |
378
379
  | 安全 | 无高危漏洞 | ${qc.securityScan ? '❌ 阻止通过' : '⏭️ 跳过'} |
380
+ | E2E | 全部通过 | ${qc.e2eTests ? '❌ 阻止通过' : '⏭️ 跳过'} |
379
381
  | 验收标准 | 全部满足 | ❌ 阻止通过 |
380
382
 
381
383
  ## 自动化验证命令
@@ -415,7 +417,21 @@ npm audit --audit-level=high || echo "Security scan skipped"
415
417
  **要求**: 无 high/critical 漏洞
416
418
  **失败后果**: ❌ VERIFY_FAILED` : '⏭️ 已禁用'}
417
419
 
418
- ### 6. 验收标准验证`);
420
+ ### 6. E2E 测试 (端到端测试)
421
+ ${qc.e2eTests ? `\`\`\`bash
422
+ # Web 应用: Playwright / Cypress
423
+ npx playwright test || npx cypress run
424
+
425
+ # 移动端: Appium / Detox
426
+ npx appium ... || npx detox test
427
+
428
+ # GUI 桌面应用: 根据项目配置
429
+ npm run test:e2e
430
+ \`\`\`
431
+ **要求**: 所有 E2E 测试通过
432
+ **失败后果**: ❌ VERIFY_FAILED` : '⏭️ 已禁用'}
433
+
434
+ ### 7. 验收标准验证`);
419
435
  // 注入验收标准
420
436
  if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
421
437
  parts.push(`
@@ -458,6 +474,13 @@ ${task.acceptanceCriteria.map((c, i) => `${i + 1}. [ ] ${c}`).join('\n')}
458
474
  "vulnerabilities": [],
459
475
  "status": "pass|fail"
460
476
  },
477
+ "e2e": {
478
+ "passed": 0,
479
+ "failed": 0,
480
+ "skipped": 0,
481
+ "duration": 0,
482
+ "status": "pass|fail|skipped"
483
+ },
461
484
  "acceptance": {
462
485
  "total": ${task.acceptanceCriteria?.length || 0},
463
486
  "met": 0,
@@ -478,6 +501,7 @@ Quality Score: [A/B/C/D/F]
478
501
  - Build: ✅ Success
479
502
  - Lint: ✅ No errors
480
503
  - Security: ✅ No vulnerabilities
504
+ ${qc.e2eTests ? '- E2E: ✅ X/X passed' : ''}
481
505
  - Acceptance: ✅ N/M criteria met
482
506
  \`\`\`
483
507
 
@@ -712,6 +736,7 @@ ACCEPT_FAILED
712
736
  build: { success: false, errors: [] },
713
737
  lint: { errors: 0, warnings: 0 },
714
738
  security: { vulnerabilities: 0 },
739
+ e2e: { passed: 0, failed: 0, skipped: 0, duration: 0 },
715
740
  acceptance: { met: 0, total: 0 }
716
741
  };
717
742
  // 解析测试结果
@@ -738,13 +763,27 @@ ACCEPT_FAILED
738
763
  const vulnMatch = output.match(/(\d+)\s*(?:vulnerabilities|vulnerable)/i);
739
764
  if (vulnMatch)
740
765
  result.security.vulnerabilities = parseInt(vulnMatch[1], 10);
766
+ // 解析 E2E 测试结果
767
+ const e2ePassedMatch = output.match(/(?:e2e|playwright|cypress|appium|detox).*?(\d+)\s*(?:passed|passing)/i);
768
+ if (e2ePassedMatch)
769
+ result.e2e.passed = parseInt(e2ePassedMatch[1], 10);
770
+ const e2eFailedMatch = output.match(/(?:e2e|playwright|cypress|appium|detox).*?(\d+)\s*(?:failed|failing)/i);
771
+ if (e2eFailedMatch)
772
+ result.e2e.failed = parseInt(e2eFailedMatch[1], 10);
773
+ const e2eSkippedMatch = output.match(/(?:e2e|playwright|cypress|appium|detox).*?(\d+)\s*skipped/i);
774
+ if (e2eSkippedMatch)
775
+ result.e2e.skipped = parseInt(e2eSkippedMatch[1], 10);
776
+ const e2eDurationMatch = output.match(/(?:e2e|playwright|cypress|appium|detox).*?(\d+)\s*(?:ms|s|min)/i);
777
+ if (e2eDurationMatch)
778
+ result.e2e.duration = parseInt(e2eDurationMatch[1], 10);
741
779
  // 判断是否通过
742
780
  const qc = this.qualityConfig;
743
781
  const testsPassed = result.tests.failed === 0;
744
782
  const coverageOk = result.tests.coverage >= qc.minCoverage;
745
783
  const lintOk = qc.strictLint ? result.lint.errors === 0 : true;
746
784
  const buildOk = result.build.success;
747
- result.passed = testsPassed && coverageOk && lintOk && buildOk;
785
+ const e2eOk = qc.e2eTests ? result.e2e.failed === 0 : true;
786
+ result.passed = testsPassed && coverageOk && lintOk && buildOk && e2eOk;
748
787
  return result;
749
788
  }
750
789
  /**
@@ -777,6 +816,13 @@ ACCEPT_FAILED
777
816
  vulnerabilities: [],
778
817
  status: gateResult.security.vulnerabilities === 0 ? 'pass' : 'fail'
779
818
  },
819
+ e2e: {
820
+ passed: gateResult.e2e.passed,
821
+ failed: gateResult.e2e.failed,
822
+ skipped: gateResult.e2e.skipped,
823
+ duration: gateResult.e2e.duration,
824
+ status: qc.e2eTests ? (gateResult.e2e.failed === 0 ? 'pass' : 'fail') : 'skipped'
825
+ },
780
826
  acceptance: {
781
827
  total: task.acceptanceCriteria?.length || 0,
782
828
  met: gateResult.acceptance.met,
@@ -17,6 +17,10 @@ export interface UserAnswers {
17
17
  testCoverage?: string;
18
18
  documentationLevel?: string;
19
19
  additionalContext?: Record<string, string>;
20
+ /** 是否启用 E2E 测试 */
21
+ e2eTests?: boolean;
22
+ /** E2E 测试类型 (web/mobile/gui) */
23
+ e2eType?: 'web' | 'mobile' | 'gui';
20
24
  }
21
25
  /**
22
26
  * TaskPlanner - 任务拆解器
@@ -57,6 +61,18 @@ export declare class TaskPlanner {
57
61
  * 构建测试任务描述
58
62
  */
59
63
  private buildTestDescription;
64
+ /**
65
+ * 构建 E2E 测试任务描述
66
+ */
67
+ private buildE2ETestDescription;
68
+ /**
69
+ * 获取 E2E 测试类型配置
70
+ */
71
+ private getE2ETypeConfig;
72
+ /**
73
+ * 生成用户流程测试用例
74
+ */
75
+ private generateUserFlows;
60
76
  /**
61
77
  * 解析覆盖率数值
62
78
  */
@@ -164,7 +164,36 @@ ${parsedTask.deliverables.map(d => `- ${d}`).join('\n')}
164
164
  ]
165
165
  });
166
166
  }
167
- // 4. 文档任务 (如果需要)
167
+ // 4. E2E 测试任务 (如果启用,作为 verify 阶段的一部分)
168
+ if (userContext.e2eTests) {
169
+ const e2eTaskId = this.generateTaskId();
170
+ const e2eType = userContext.e2eType || 'web';
171
+ // E2E 测试依赖所有开发任务和单元测试任务
172
+ const allTestDependencies = [...devTaskIds];
173
+ breakdowns.forEach(b => {
174
+ if (b.phase === 'verify' && b.title.startsWith('测试:')) {
175
+ allTestDependencies.push(b.taskId);
176
+ }
177
+ });
178
+ breakdowns.push({
179
+ taskId: e2eTaskId,
180
+ title: '端到端(E2E)测试',
181
+ description: this.buildE2ETestDescription(e2eType, parsedTask, userContext),
182
+ priority: 'P0', // E2E 测试是关键任务
183
+ dependencies: allTestDependencies, // 依赖所有开发任务和单元测试
184
+ estimatedComplexity: 'high',
185
+ assignedAgent: 'tester',
186
+ phase: 'verify',
187
+ acceptanceCriteria: [
188
+ '所有 E2E 测试用例通过',
189
+ '关键用户流程验证完成',
190
+ '跨浏览器/设备兼容性验证',
191
+ 'E2E 测试报告已生成',
192
+ '无阻塞级别的缺陷'
193
+ ]
194
+ });
195
+ }
196
+ // 5. 文档任务 (如果需要)
168
197
  if (userContext.documentationLevel && userContext.documentationLevel !== '无需文档') {
169
198
  breakdowns.push({
170
199
  taskId: this.generateTaskId(),
@@ -196,11 +225,15 @@ ${userContext.documentationLevel}
196
225
  * 提取用户上下文
197
226
  */
198
227
  extractUserContext(answers) {
228
+ const e2eAnswer = answers['E2E测试'] || answers['e2eTests'] || answers['e2e'];
229
+ const e2eTypeAnswer = answers['E2E类型'] || answers['e2eType'];
199
230
  return {
200
231
  objective: answers['目标'] || answers['objective'],
201
232
  techStack: this.parseArrayAnswer(answers['技术栈'] || answers['techStack']),
202
233
  testCoverage: answers['测试'] || answers['testCoverage'],
203
234
  documentationLevel: answers['文档'] || answers['documentationLevel'],
235
+ e2eTests: e2eAnswer === 'true' || e2eAnswer === '✅ 启用 E2E 测试' || e2eAnswer === '是',
236
+ e2eType: e2eTypeAnswer || 'web',
204
237
  additionalContext: answers
205
238
  };
206
239
  }
@@ -263,6 +296,101 @@ ${devTaskId}
263
296
  - 测试报告
264
297
  - 覆盖率报告`;
265
298
  }
299
+ /**
300
+ * 构建 E2E 测试任务描述
301
+ */
302
+ buildE2ETestDescription(e2eType, parsedTask, userContext) {
303
+ const typeConfig = this.getE2ETypeConfig(e2eType);
304
+ return `## E2E 测试目标
305
+ 执行完整的端到端测试,验证关键用户流程
306
+
307
+ ## 应用类型
308
+ ${typeConfig.description}
309
+
310
+ ## 测试框架
311
+ ${typeConfig.frameworks.map(f => `- ${f}`).join('\n')}
312
+
313
+ ## 测试范围
314
+ ${parsedTask.goals.map((g, i) => `${i + 1}. ${g}`).join('\n')}
315
+
316
+ ## 关键用户流程
317
+ 根据应用功能,测试以下流程:
318
+ ${this.generateUserFlows(parsedTask, e2eType)}
319
+
320
+ ## 测试环境
321
+ ${typeConfig.environments.map(e => `- ${e}`).join('\n')}
322
+
323
+ ## 测试要求
324
+ 1. **关键路径覆盖**: 所有核心用户流程必须有 E2E 测试
325
+ 2. **断言完整**: 每个测试步骤必须有明确的断言
326
+ 3. **等待策略**: 使用合理的等待机制,避免硬编码延迟
327
+ 4. **数据隔离**: 测试数据独立,不影响其他测试
328
+ 5. **清理机制**: 测试后清理创建的数据
329
+
330
+ ## 输出要求
331
+ - E2E 测试文件 (tests/e2e/*.spec.ts)
332
+ - 测试执行报告
333
+ - 截图/录像 (失败时)
334
+ - 测试覆盖率报告 (如有)
335
+
336
+ ## 运行命令
337
+ \`\`\`bash
338
+ ${typeConfig.runCommand}
339
+ \`\`\`
340
+
341
+ ## 验收标准
342
+ - [ ] 所有 E2E 测试用例通过
343
+ - [ ] 关键用户流程验证完成
344
+ - [ ] 跨浏览器/设备兼容性验证
345
+ - [ ] E2E 测试报告已生成
346
+ - [ ] 无阻塞级别的缺陷`;
347
+ }
348
+ /**
349
+ * 获取 E2E 测试类型配置
350
+ */
351
+ getE2ETypeConfig(type) {
352
+ const configs = {
353
+ web: {
354
+ description: 'Web 应用 (浏览器)',
355
+ frameworks: ['Playwright (推荐)', 'Cypress', 'Selenium WebDriver', 'Puppeteer'],
356
+ environments: ['Chrome', 'Firefox', 'Safari', 'Edge', 'Mobile Viewports'],
357
+ runCommand: 'npx playwright test --reporter=html'
358
+ },
359
+ mobile: {
360
+ description: '移动应用 (iOS/Android)',
361
+ frameworks: ['Appium', 'Detox (React Native)', 'XCUITest (iOS)', 'Espresso (Android)'],
362
+ environments: ['iOS Simulator', 'Android Emulator', 'Real Devices'],
363
+ runCommand: 'npx appium --base-path /wd/hub && npm run test:e2e'
364
+ },
365
+ gui: {
366
+ description: 'GUI 桌面应用 (Electron/Native)',
367
+ frameworks: ['Playwright for Electron', 'Spectron (Electron)', 'Robot Framework', 'PyAutoGUI'],
368
+ environments: ['Windows', 'macOS', 'Linux'],
369
+ runCommand: 'npm run test:e2e'
370
+ }
371
+ };
372
+ return configs[type];
373
+ }
374
+ /**
375
+ * 生成用户流程测试用例
376
+ */
377
+ generateUserFlows(parsedTask, type) {
378
+ const flows = [];
379
+ const goals = parsedTask.goals;
380
+ // 根据目标生成用户流程
381
+ goals.forEach((goal, i) => {
382
+ flows.push(`\n### 流程 ${i + 1}: ${goal}`);
383
+ flows.push('```gherkin');
384
+ flows.push(`Feature: ${goal}`);
385
+ flows.push('');
386
+ flows.push(' Scenario: 正常流程');
387
+ flows.push(` Given 用户已启动应用`);
388
+ flows.push(` When 用户执行 "${goal}" 操作`);
389
+ flows.push(` Then 操作成功完成`);
390
+ flows.push('```');
391
+ });
392
+ return flows.join('\n');
393
+ }
266
394
  /**
267
395
  * 解析覆盖率数值
268
396
  */
@@ -107,6 +107,8 @@ export interface QualityConfig {
107
107
  strictLint: boolean;
108
108
  /** 安全扫描 */
109
109
  securityScan: boolean;
110
+ /** 端到端测试 (适用于 Web 项目等需要 E2E 测试的场景) */
111
+ e2eTests: boolean;
110
112
  /** 质量级别 */
111
113
  level: 'fast' | 'balanced' | 'strict';
112
114
  }
@@ -141,6 +143,14 @@ export interface QualityReport {
141
143
  vulnerabilities: SecurityVulnerability[];
142
144
  status: 'pass' | 'fail';
143
145
  };
146
+ /** E2E 测试结果 */
147
+ e2e: {
148
+ passed: number;
149
+ failed: number;
150
+ skipped: number;
151
+ duration: number;
152
+ status: 'pass' | 'fail' | 'skipped';
153
+ };
144
154
  /** 验收标准检查 */
145
155
  acceptance: {
146
156
  total: number;
@@ -11,6 +11,7 @@ exports.QUALITY_PRESETS = {
11
11
  minCoverage: 0,
12
12
  strictLint: false,
13
13
  securityScan: false,
14
+ e2eTests: false,
14
15
  level: 'fast'
15
16
  },
16
17
  balanced: {
@@ -18,6 +19,7 @@ exports.QUALITY_PRESETS = {
18
19
  minCoverage: 60,
19
20
  strictLint: true,
20
21
  securityScan: true,
22
+ e2eTests: false,
21
23
  level: 'balanced'
22
24
  },
23
25
  strict: {
@@ -25,6 +27,7 @@ exports.QUALITY_PRESETS = {
25
27
  minCoverage: 80,
26
28
  strictLint: true,
27
29
  securityScan: true,
30
+ e2eTests: false, // 让用户选择,因为 E2E 测试耗时
28
31
  level: 'strict'
29
32
  }
30
33
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmatrix",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "AI Agent task orchestration system with Claude Code Skills integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: openmatrix
3
3
  description: "Invoke /om:start for any implementation task - adding features, fixing bugs, refactoring, creating commands, writing code, building systems. Use this when user describes work to be done, not for questions or information requests."
4
+ priority: high
5
+ always_load: true
4
6
  ---
5
7
 
6
8
  <objective>
package/skills/start.md CHANGED
@@ -19,6 +19,7 @@ description: 启动新的任务执行周期
19
19
  openmatrix start --init-only
20
20
  ```
21
21
  - 这会创建 `.openmatrix/`、`.openmatrix/tasks/`、`.openmatrix/approvals/` 目录
22
+ - 同时自动将 `.openmatrix/` 添加到 `.gitignore`
22
23
 
23
24
  2. **检查当前状态**
24
25
  - 读取 `.openmatrix/state.json`
@@ -40,7 +41,7 @@ description: 启动新的任务执行周期
40
41
 
41
42
  5. **⚠️ 交互式问答 (必须执行)**
42
43
 
43
- **重要**: 除非用户明确指定 `--skip-questions`,否则必须执行交互式问答。
44
+ **重要**: 除非用户明确指定 `--skip-questions` 或提供了 `--quality` 等选项,否则必须执行交互式问答。
44
45
 
45
46
  使用 `AskUserQuestion` 工具,逐个提出以下问题:
46
47
 
@@ -53,11 +54,11 @@ description: 启动新的任务执行周期
53
54
  options: [
54
55
  {
55
56
  label: "🚀 strict (推荐生产代码)",
56
- description: "TDD + 80%覆盖率 + 严格Lint + 安全扫描 + AI验收"
57
+ description: "TDD + 80%覆盖率 + 严格Lint + 安全扫描 + AI验收 (E2E可选)"
57
58
  },
58
59
  {
59
60
  label: "⚖️ balanced (日常开发)",
60
- description: "60%覆盖率 + Lint + 安全扫描 + AI验收"
61
+ description: "60%覆盖率 + Lint + 安全扫描 + AI验收 (E2E可选)"
61
62
  },
62
63
  {
63
64
  label: "⚡ fast (快速原型)",
@@ -69,6 +70,52 @@ description: 启动新的任务执行周期
69
70
  })
70
71
  ```
71
72
 
73
+ **⚠️ 如果用户选择 "strict" 或 "balanced",追问 E2E 测试:**
74
+ ```typescript
75
+ AskUserQuestion({
76
+ questions: [{
77
+ question: "是否需要端到端(E2E)测试?(适用于 Web、移动端、GUI 桌面应用等需要完整用户流程测试的场景,较耗时)",
78
+ header: "E2E测试",
79
+ options: [
80
+ {
81
+ label: "✅ 启用 E2E 测试",
82
+ description: "添加端到端测试,验证完整用户流程(Playwright/Cypress/Appium等)"
83
+ },
84
+ {
85
+ label: "❌ 不需要",
86
+ description: "仅运行单元测试和集成测试"
87
+ }
88
+ ],
89
+ multiSelect: false
90
+ }]
91
+ })
92
+ ```
93
+
94
+ **⚠️ 如果用户启用 E2E 测试,追问应用类型:**
95
+ ```typescript
96
+ AskUserQuestion({
97
+ questions: [{
98
+ question: "选择应用类型以确定 E2E 测试方案:",
99
+ header: "应用类型",
100
+ options: [
101
+ {
102
+ label: "🌐 Web 应用",
103
+ description: "浏览器应用 - Playwright/Cypress/Selenium"
104
+ },
105
+ {
106
+ label: "📱 移动应用",
107
+ description: "iOS/Android - Appium/Detox/XCUITest/Espresso"
108
+ },
109
+ {
110
+ label: "🖥️ GUI 桌面应用",
111
+ description: "Electron/原生桌面 - Playwright/Spectron/Robot Framework"
112
+ }
113
+ ],
114
+ multiSelect: false
115
+ }]
116
+ })
117
+ ```
118
+
72
119
  **问题 1: 任务目标**
73
120
  ```typescript
74
121
  AskUserQuestion({
@@ -389,36 +436,38 @@ $ARGUMENTS
389
436
  <notes>
390
437
  ## 质量级别详解
391
438
 
392
- | 级别 | TDD | 覆盖率 | Lint | 安全扫描 | AI验收 | 适用场景 |
393
- |------|:---:|:------:|:----:|:--------:|:------:|---------|
394
- | **strict** | ✅ | >80% | ✅ 严格 | ✅ | ✅ | 生产代码、核心功能 |
395
- | **balanced** | ❌ | >60% | ✅ | ✅ | ✅ | 日常开发 (默认) |
396
- | **fast** | ❌ | >20% | ❌ | ❌ | ❌ | 快速原型、POC |
439
+ | 级别 | TDD | 覆盖率 | Lint | 安全扫描 | E2E测试 | AI验收 | 适用场景 |
440
+ |------|:---:|:------:|:----:|:--------:|:-------:|:------:|---------|
441
+ | **strict** | ✅ | >80% | ✅ 严格 | ✅ | ❓ 可选 | ✅ | 生产代码、核心功能 |
442
+ | **balanced** | ❌ | >60% | ✅ | ✅ | ❓ 可选 | ✅ | 日常开发 (默认) |
443
+ | **fast** | ❌ | >20% | ❌ | ❌ | ❌ | ❌ | 快速原型、POC |
397
444
 
398
- > strict 可配置为 100%。80% 覆盖核心业务逻辑,100% 成本高收益低。
445
+ > E2E 测试耗时较长,即使在严格模式下也建议根据项目需要选择。strict 可配置为 100%。80% 覆盖核心业务逻辑,100% 成本高收益低。
399
446
 
400
447
  ### strict 模式 (推荐生产代码)
401
448
  ```
402
449
  🧪 TDD 阶段: 先写测试 (RED) → 测试必须失败
403
450
  ✨ 开发阶段: 再写代码 (GREEN) → 测试必须通过
404
- ✅ 验证阶段: 6道质量门禁
451
+ ✅ 验证阶段: 7道质量门禁
405
452
  ├── Gate 1: 编译检查 (必须通过)
406
453
  ├── Gate 2: 测试运行 (必须通过)
407
454
  ├── Gate 3: 覆盖率 >= 80% (必须达标)
408
455
  ├── Gate 4: Lint 无 error (必须通过)
409
456
  ├── Gate 5: 安全扫描无高危 (必须通过)
410
- └── Gate 6: 验收标准全部满足
457
+ ├── Gate 6: E2E 测试通过 (必须通过,Web项目)
458
+ └── Gate 7: 验收标准全部满足
411
459
  🎉 验收阶段: AI Reviewer 最终确认
412
460
  ```
413
461
 
414
462
  ### balanced 模式 (日常开发)
415
463
  ```
416
464
  ✨ 开发阶段: 编写代码
417
- ✅ 验证阶段: 4道质量门禁
465
+ ✅ 验证阶段: 4-5道质量门禁
418
466
  ├── Gate 1: 编译检查
419
467
  ├── Gate 2: 测试运行
420
468
  ├── Gate 3: 覆盖率 >= 60%
421
- └── Gate 4: 验收标准
469
+ ├── Gate 4: E2E 测试 (可选,Web项目)
470
+ └── Gate 5: 验收标准
422
471
  🎉 验收阶段: AI Reviewer 确认
423
472
  ```
424
473