openmatrix 0.1.99 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agents/impl/coder-agent.js +42 -42
  2. package/dist/agents/impl/executor-agent.js +75 -75
  3. package/dist/agents/impl/planner-agent.js +63 -63
  4. package/dist/agents/impl/reviewer-agent.js +66 -66
  5. package/dist/agents/impl/tester-agent.js +56 -56
  6. package/dist/cli/commands/auto.js +20 -6
  7. package/dist/cli/commands/complete.js +1 -1
  8. package/dist/cli/commands/meeting.js +0 -1
  9. package/dist/cli/commands/report.js +45 -45
  10. package/dist/cli/commands/start.js +168 -34
  11. package/dist/cli/commands/status.js +0 -1
  12. package/dist/cli/commands/step.js +62 -35
  13. package/dist/orchestrator/ai-reviewer.d.ts +30 -2
  14. package/dist/orchestrator/ai-reviewer.js +314 -209
  15. package/dist/orchestrator/answer-mapper.d.ts +1 -0
  16. package/dist/orchestrator/answer-mapper.js +5 -2
  17. package/dist/orchestrator/approval-manager.js +14 -13
  18. package/dist/orchestrator/executor.d.ts +10 -1
  19. package/dist/orchestrator/executor.js +62 -2
  20. package/dist/orchestrator/interactive-question-generator.js +4 -3
  21. package/dist/orchestrator/meeting-manager.js +32 -31
  22. package/dist/orchestrator/phase-executor.js +9 -6
  23. package/dist/orchestrator/scheduler.d.ts +8 -6
  24. package/dist/orchestrator/scheduler.js +53 -22
  25. package/dist/orchestrator/state-machine.js +2 -2
  26. package/dist/orchestrator/task-planner.d.ts +83 -4
  27. package/dist/orchestrator/task-planner.js +702 -124
  28. package/dist/storage/state-manager.d.ts +6 -0
  29. package/dist/storage/state-manager.js +28 -0
  30. package/package.json +55 -55
  31. package/scripts/build-check.js +19 -19
  32. package/scripts/install-skills.js +57 -57
  33. package/skills/approve.md +250 -250
  34. package/skills/auto.md +298 -298
  35. package/skills/meeting.md +324 -324
  36. package/skills/om.md +112 -112
  37. package/skills/openmatrix.md +112 -112
  38. package/skills/start.md +38 -6
  39. package/dist/cli/commands/upgrade.d.ts +0 -2
  40. package/dist/cli/commands/upgrade.js +0 -329
  41. package/dist/orchestrator/task-planner.old.d.ts +0 -87
  42. package/dist/orchestrator/task-planner.old.js +0 -444
@@ -7,6 +7,7 @@ const agent_runner_js_1 = require("../agents/agent-runner.js");
7
7
  const state_machine_js_1 = require("./state-machine.js");
8
8
  const phase_executor_js_1 = require("./phase-executor.js");
9
9
  const retry_manager_js_1 = require("./retry-manager.js");
10
+ const ai_reviewer_js_1 = require("./ai-reviewer.js");
10
11
  /**
11
12
  * OrchestratorExecutor - 执行循环核心
12
13
  *
@@ -20,6 +21,7 @@ class OrchestratorExecutor {
20
21
  stateMachine;
21
22
  phaseExecutor;
22
23
  retryManager;
24
+ aiReviewer;
23
25
  config;
24
26
  taskTimers = new Map();
25
27
  constructor(stateManager, approvalManager, config) {
@@ -41,6 +43,7 @@ class OrchestratorExecutor {
41
43
  this.stateMachine = new state_machine_js_1.StateMachine();
42
44
  this.phaseExecutor = new phase_executor_js_1.PhaseExecutor(stateManager, approvalManager);
43
45
  this.retryManager = new retry_manager_js_1.RetryManager();
46
+ this.aiReviewer = new ai_reviewer_js_1.AIReviewer();
44
47
  }
45
48
  /**
46
49
  * 获取 PhaseExecutor 实例
@@ -101,7 +104,7 @@ class OrchestratorExecutor {
101
104
  }
102
105
  // 10. 准备 Subagent 任务
103
106
  const subagentTasks = await this.agentRunner.prepareSubagentTasks(executableTasks);
104
- // 8. 更新任务状态为 scheduled 并设置超时
107
+ // 11. 更新任务状态为 in_progress 并设置超时
105
108
  for (const task of executableTasks) {
106
109
  await this.scheduler.markTaskStarted(task.id);
107
110
  this.setupTaskTimeout(task.id);
@@ -251,6 +254,8 @@ class OrchestratorExecutor {
251
254
  }
252
255
  /**
253
256
  * 标记任务完成
257
+ *
258
+ * 增强:对于 reviewer 任务,自动解析 Review 报告并生成修复任务
254
259
  */
255
260
  async completeTask(taskId, result) {
256
261
  const task = await this.stateManager.getTask(taskId);
@@ -297,12 +302,53 @@ class OrchestratorExecutor {
297
302
  }
298
303
  else if (currentPhase === 'accept') {
299
304
  await this.scheduler.markTaskCompleted(taskId);
305
+ // Review 任务完成:自动解析报告并生成修复任务
306
+ if (task.assignedAgent === 'reviewer' && result.output) {
307
+ return await this.processReviewResult(taskId, result.output);
308
+ }
300
309
  }
301
310
  }
302
311
  else {
303
312
  this.clearTaskTimeout(taskId);
304
313
  await this.scheduler.markTaskFailed(taskId, result.error || 'Unknown error');
305
314
  }
315
+ return {};
316
+ }
317
+ /**
318
+ * 处理 Review 结果:解析报告,如有 critical/major 问题则自动创建修复任务
319
+ */
320
+ async processReviewResult(taskId, output) {
321
+ const report = this.aiReviewer.parseReviewResult(taskId, output);
322
+ const task = await this.stateManager.getTask(taskId);
323
+ if (!task)
324
+ return {};
325
+ // 保存 Review 报告到 artifacts
326
+ await this.stateManager.savePhaseResult(taskId, 'review', {
327
+ report,
328
+ taskId,
329
+ reviewedAt: report.reviewedAt
330
+ });
331
+ if (!this.aiReviewer.needsAutoFix(report)) {
332
+ console.log(`✅ Review 通过: ${taskId} — 无 critical/major 问题`);
333
+ return {};
334
+ }
335
+ // 生成修复任务
336
+ const fixTasks = this.aiReviewer.generateFixTasks(task, report, taskId);
337
+ const createdIds = [];
338
+ for (const fixTask of fixTasks) {
339
+ // 将生成的 taskId 转换为 StateManager 的 ID 格式
340
+ const created = await this.stateManager.createTask({
341
+ title: fixTask.title,
342
+ description: fixTask.description,
343
+ priority: fixTask.priority,
344
+ timeout: fixTask.timeout,
345
+ dependencies: fixTask.dependencies,
346
+ assignedAgent: fixTask.assignedAgent
347
+ });
348
+ createdIds.push(created.id);
349
+ }
350
+ console.log(`🔧 Review 发现 ${report.issues.length} 个问题,已创建 ${createdIds.length} 个修复任务`);
351
+ return { createdFixTasks: createdIds };
306
352
  }
307
353
  /**
308
354
  * 获取当前阶段
@@ -370,13 +416,27 @@ class OrchestratorExecutor {
370
416
  */
371
417
  async processRetries(failedTasks) {
372
418
  let retried = 0;
419
+ let limit;
420
+ try {
421
+ const state = await this.stateManager.getState();
422
+ limit = state.config.maxRetries;
423
+ }
424
+ catch {
425
+ limit = 3;
426
+ }
373
427
  for (const task of failedTasks) {
428
+ const currentRetryCount = task.retryCount || 0;
429
+ // 先检查是否还有重试次数,再决定是否加入队列
430
+ if (currentRetryCount >= limit) {
431
+ console.log(`⚠️ 任务 ${task.id} 已达到最大重试次数 (${limit}),跳过重试`);
432
+ continue;
433
+ }
374
434
  this.retryManager.addToQueue(task.id, task.error || 'Unknown error');
375
435
  if (this.retryManager.shouldRetry(task.id)) {
376
436
  // 将任务从 failed 转为 retry_queue 再转为 pending
377
437
  await this.stateManager.updateTask(task.id, {
378
438
  status: 'retry_queue',
379
- retryCount: (task.retryCount || 0) + 1
439
+ retryCount: currentRetryCount + 1
380
440
  });
381
441
  await this.stateManager.updateTask(task.id, {
382
442
  status: 'pending'
@@ -313,14 +313,15 @@ class InteractiveQuestionGenerator {
313
313
  // 7. E2E 测试
314
314
  questions.push({
315
315
  id: 'e2e_tests',
316
- question: '是否启用端到端 (E2E) 测试?(适用于 Web/Mobile/GUI 项目,耗时较长)',
316
+ question: '是否需要端到端 (E2E) 测试?(适用于 Web/Mobile/GUI 项目,耗时较长)',
317
317
  type: 'single',
318
318
  required: false,
319
319
  category: 'quality',
320
320
  priority: 7,
321
321
  options: [
322
- { key: 'true', label: '启用 E2E 测试', description: '使用 Playwright/Cypress 等框架进行端到端测试' },
323
- { key: 'false', label: '不启用 (推荐)', description: '仅进行单元测试和集成测试,节省时间' }
322
+ { key: 'functional', label: '功能测试 (推荐)', description: '验证业务流程正确性,无需浏览器可视化,速度快' },
323
+ { key: 'visual', label: '视觉验证', description: '需要浏览器可视化验证,可检查页面样式和布局' },
324
+ { key: 'false', label: '不需要', description: '仅进行单元测试和集成测试,节省时间' }
324
325
  ]
325
326
  });
326
327
  // 8. 风险评估
@@ -42,24 +42,24 @@ class MeetingManager {
42
42
  type: 'meeting',
43
43
  taskId,
44
44
  title: meeting.title,
45
- description: `
46
- ## 阻塞问题描述
47
-
48
- **任务**: ${taskId}
49
- **原因**: ${blockingReason}
50
-
51
- ## 影响范围
52
-
53
- ${impactScope.map(item => `- ${item}`).join('\n')}
54
-
55
- ## 需要的行动
56
-
57
- 请选择以下操作之一:
58
-
59
- 1. **提供信息** - 提供解决阻塞所需的信息
60
- 2. **跳过任务** - 标记任务为可选,跳过继续执行
61
- 3. **修改方案** - 调整任务方案或参数
62
- 4. **取消执行** - 停止整个执行流程
45
+ description: `
46
+ ## 阻塞问题描述
47
+
48
+ **任务**: ${taskId}
49
+ **原因**: ${blockingReason}
50
+
51
+ ## 影响范围
52
+
53
+ ${impactScope.map(item => `- ${item}`).join('\n')}
54
+
55
+ ## 需要的行动
56
+
57
+ 请选择以下操作之一:
58
+
59
+ 1. **提供信息** - 提供解决阻塞所需的信息
60
+ 2. **跳过任务** - 标记任务为可选,跳过继续执行
61
+ 3. **修改方案** - 调整任务方案或参数
62
+ 4. **取消执行** - 停止整个执行流程
63
63
  `,
64
64
  content: JSON.stringify({ meetingId, blockingReason, impactScope })
65
65
  });
@@ -87,17 +87,17 @@ ${impactScope.map(item => `- ${item}`).join('\n')}
87
87
  type: 'meeting',
88
88
  taskId,
89
89
  title: meeting.title,
90
- description: `
91
- ## 决策点
92
-
93
- **任务**: ${taskId}
94
- **问题**: ${decision}
95
-
96
- ## 可选方案
97
-
98
- ${options.map((opt, i) => `${i + 1}. ${opt}`).join('\n')}
99
-
100
- 请在审批时提供您的选择。
90
+ description: `
91
+ ## 决策点
92
+
93
+ **任务**: ${taskId}
94
+ **问题**: ${decision}
95
+
96
+ ## 可选方案
97
+
98
+ ${options.map((opt, i) => `${i + 1}. ${opt}`).join('\n')}
99
+
100
+ 请在审批时提供您的选择。
101
101
  `,
102
102
  content: JSON.stringify({ meetingId, decision, options })
103
103
  });
@@ -136,9 +136,10 @@ ${options.map((opt, i) => `${i + 1}. ${opt}`).join('\n')}
136
136
  await this.stateManager.saveMeeting(updatedMeeting);
137
137
  // 更新关联任务状态
138
138
  if (meeting.type === 'blocking') {
139
- // 将任务从 waiting 恢复到 pending
139
+ // 将阻塞任务恢复到 pending,让调度器重新调度
140
+ // 阻塞任务可能是 waiting 或 blocked 状态
140
141
  const task = await this.stateManager.getTask(meeting.taskId);
141
- if (task && task.status === 'waiting') {
142
+ if (task && (task.status === 'waiting' || task.status === 'blocked')) {
142
143
  await this.stateManager.updateTask(meeting.taskId, {
143
144
  status: 'pending',
144
145
  error: undefined
@@ -535,7 +535,7 @@ try {
535
535
  }
536
536
  } catch(e) {
537
537
  console.error('❌ Import failed:', e.message);
538
- process.exit(1);
538
+ process.exitCode = 1;
539
539
  }
540
540
  "
541
541
  \`\`\`
@@ -740,7 +740,7 @@ for (const mod of modules) {
740
740
  }
741
741
  if (failed.length > 0) {
742
742
  console.error('Failed imports:', failed.join(', '));
743
- process.exit(1);
743
+ process.exitCode = 1;
744
744
  }
745
745
  console.log('All module imports passed');
746
746
  "
@@ -955,7 +955,7 @@ ACCEPT_FAILED
955
955
  parseQualityReport(output) {
956
956
  const result = {
957
957
  passed: false,
958
- tests: { passed: 0, failed: 0, coverage: 0 },
958
+ tests: { passed: 0, failed: 0, coverage: -1 }, // -1 = coverage not measured
959
959
  build: { success: false, errors: [] },
960
960
  lint: { errors: 0, warnings: 0 },
961
961
  security: { vulnerabilities: 0 },
@@ -972,7 +972,8 @@ ACCEPT_FAILED
972
972
  if (jsonReport.tests) {
973
973
  result.tests.passed = jsonReport.tests.passed ?? 0;
974
974
  result.tests.failed = jsonReport.tests.failed ?? 0;
975
- result.tests.coverage = jsonReport.tests.coverage ?? 0;
975
+ // -1 表示未测量覆盖率
976
+ result.tests.coverage = jsonReport.tests.coverage ?? -1;
976
977
  }
977
978
  // 解析 build
978
979
  if (jsonReport.build) {
@@ -1003,7 +1004,8 @@ ACCEPT_FAILED
1003
1004
  // 判断是否通过
1004
1005
  const qc = this.qualityConfig;
1005
1006
  const testsPassed = result.tests.failed === 0;
1006
- const coverageOk = result.tests.coverage >= qc.minCoverage;
1007
+ // 覆盖率 -1 表示未测量(无覆盖率输出),跳过检查
1008
+ const coverageOk = result.tests.coverage < 0 || result.tests.coverage >= qc.minCoverage;
1007
1009
  const lintOk = qc.strictLint ? result.lint.errors === 0 : true;
1008
1010
  const buildOk = result.build.success;
1009
1011
  const e2eOk = qc.e2eTests ? result.e2e.failed === 0 : true;
@@ -1095,7 +1097,8 @@ ACCEPT_FAILED
1095
1097
  // 判断是否通过
1096
1098
  const qc = this.qualityConfig;
1097
1099
  const testsPassed = result.tests.failed === 0;
1098
- const coverageOk = result.tests.coverage >= qc.minCoverage;
1100
+ // 覆盖率 -1 表示未测量(regex 回退路径下未匹配到覆盖率时保持 -1)
1101
+ const coverageOk = result.tests.coverage < 0 || result.tests.coverage >= qc.minCoverage;
1099
1102
  const lintOk = qc.strictLint ? result.lint.errors === 0 : true;
1100
1103
  const buildOk = result.build.success;
1101
1104
  const e2eOk = qc.e2eTests ? result.e2e.failed === 0 : true;
@@ -14,8 +14,11 @@ export declare class Scheduler {
14
14
  private stateManager;
15
15
  private stateMachine;
16
16
  private config;
17
- private runningTasks;
18
17
  constructor(stateManager: StateManager, config?: Partial<SchedulerConfig>);
18
+ /**
19
+ * 获取当前正在执行的任务数(从持久化状态读取,非内存缓存)
20
+ */
21
+ private getRunningCount;
19
22
  /**
20
23
  * 获取下一个可执行的任务
21
24
  */
@@ -33,7 +36,7 @@ export declare class Scheduler {
33
36
  */
34
37
  private transitionTask;
35
38
  /**
36
- * 标记任务开始执行
39
+ * 标记任务开始执行(阶段感知,不重置已完成的 phase)
37
40
  */
38
41
  markTaskStarted(taskId: string): Promise<void>;
39
42
  /**
@@ -66,11 +69,10 @@ export declare class Scheduler {
66
69
  */
67
70
  private handleCircularDependencies;
68
71
  /**
69
- * 获取调度状态
72
+ * 获取调度状态(从持久化状态读取)
70
73
  */
71
- getStatus(): {
74
+ getStatus(): Promise<{
72
75
  running: number;
73
76
  maxConcurrent: number;
74
- runningTaskIds: string[];
75
- };
77
+ }>;
76
78
  }
@@ -6,7 +6,6 @@ class Scheduler {
6
6
  stateManager;
7
7
  stateMachine;
8
8
  config;
9
- runningTasks = new Set();
10
9
  constructor(stateManager, config) {
11
10
  this.stateManager = stateManager;
12
11
  this.stateMachine = new state_machine_js_1.StateMachine();
@@ -16,6 +15,13 @@ class Scheduler {
16
15
  ...config
17
16
  };
18
17
  }
18
+ /**
19
+ * 获取当前正在执行的任务数(从持久化状态读取,非内存缓存)
20
+ */
21
+ async getRunningCount() {
22
+ const tasks = await this.stateManager.listTasks();
23
+ return tasks.filter(t => t.status === 'in_progress' || t.status === 'scheduled').length;
24
+ }
19
25
  /**
20
26
  * 获取下一个可执行的任务
21
27
  */
@@ -24,7 +30,12 @@ class Scheduler {
24
30
  // 检测并处理循环依赖
25
31
  await this.handleCircularDependencies(tasks);
26
32
  // 筛选可执行任务
27
- const executable = tasks.filter(task => this.canExecute(task, tasks));
33
+ const executable = [];
34
+ for (const task of tasks) {
35
+ if (await this.canExecute(task, tasks)) {
36
+ executable.push(task);
37
+ }
38
+ }
28
39
  if (executable.length === 0) {
29
40
  return null;
30
41
  }
@@ -35,13 +46,14 @@ class Scheduler {
35
46
  /**
36
47
  * 检查任务是否可执行
37
48
  */
38
- canExecute(task, allTasks) {
49
+ async canExecute(task, allTasks) {
39
50
  // 1. 状态必须是 pending 或 retry_queue
40
51
  if (task.status !== 'pending' && task.status !== 'retry_queue') {
41
52
  return false;
42
53
  }
43
- // 2. 检查并发限制
44
- if (this.runningTasks.size >= this.config.maxConcurrentTasks) {
54
+ // 2. 检查并发限制(从持久化状态读取)
55
+ const runningCount = await this.getRunningCount();
56
+ if (runningCount >= this.config.maxConcurrentTasks) {
45
57
  return false;
46
58
  }
47
59
  // 3. 检查依赖是否完成
@@ -84,23 +96,39 @@ class Scheduler {
84
96
  });
85
97
  }
86
98
  /**
87
- * 标记任务开始执行
99
+ * 标记任务开始执行(阶段感知,不重置已完成的 phase)
88
100
  */
89
101
  async markTaskStarted(taskId) {
90
- this.runningTasks.add(taskId);
91
- await this.transitionTask(taskId, 'start', {
92
- phases: {
93
- develop: { status: 'in_progress', duration: null, startedAt: new Date().toISOString() },
94
- verify: { status: 'pending', duration: null },
95
- accept: { status: 'pending', duration: null }
102
+ const task = await this.stateManager.getTask(taskId);
103
+ if (!task)
104
+ throw new Error(`Task ${taskId} not found`);
105
+ const now = new Date().toISOString();
106
+ // 根据任务当前状态决定设置哪个 phase in_progress
107
+ let phases = { ...task.phases };
108
+ if (task.status === 'pending' || task.status === 'retry_queue') {
109
+ // 首次开始:设置 develop 为 in_progress
110
+ phases.develop = { status: 'in_progress', duration: null, startedAt: now };
111
+ if (phases.verify.status === 'pending') {
112
+ phases.verify = { status: 'pending', duration: null };
96
113
  }
97
- });
114
+ if (phases.accept.status === 'pending') {
115
+ phases.accept = { status: 'pending', duration: null };
116
+ }
117
+ }
118
+ else if (task.status === 'verify') {
119
+ // develop 已完成,开始 verify 阶段
120
+ phases.verify = { status: 'in_progress', duration: null, startedAt: now };
121
+ }
122
+ else if (task.status === 'accept') {
123
+ // develop + verify 已完成,开始 accept 阶段
124
+ phases.accept = { status: 'in_progress', duration: null, startedAt: now };
125
+ }
126
+ await this.transitionTask(taskId, 'start', { phases });
98
127
  }
99
128
  /**
100
129
  * 标记任务完成
101
130
  */
102
131
  async markTaskCompleted(taskId) {
103
- this.runningTasks.delete(taskId);
104
132
  const task = await this.stateManager.getTask(taskId);
105
133
  if (task) {
106
134
  await this.transitionTask(taskId, 'accept_done', {
@@ -115,7 +143,6 @@ class Scheduler {
115
143
  * 标记任务失败
116
144
  */
117
145
  async markTaskFailed(taskId, error) {
118
- this.runningTasks.delete(taskId);
119
146
  const task = await this.stateManager.getTask(taskId);
120
147
  const retryCount = task?.retryCount || 0;
121
148
  await this.transitionTask(taskId, 'fail', {
@@ -133,7 +160,6 @@ class Scheduler {
133
160
  * 标记任务阻塞(需要 Meeting)
134
161
  */
135
162
  async markTaskBlocked(taskId, reason) {
136
- this.runningTasks.delete(taskId);
137
163
  await this.transitionTask(taskId, 'block', {
138
164
  error: reason
139
165
  });
@@ -146,7 +172,12 @@ class Scheduler {
146
172
  // 检测并处理循环依赖
147
173
  await this.handleCircularDependencies(tasks);
148
174
  // 筛选可执行任务
149
- const executable = tasks.filter(task => this.canExecute(task, tasks));
175
+ const executable = [];
176
+ for (const task of tasks) {
177
+ if (await this.canExecute(task, tasks)) {
178
+ executable.push(task);
179
+ }
180
+ }
150
181
  // 按优先级排序(高优先级优先)
151
182
  executable.sort((a, b) => this.getPriorityWeight(b.priority) - this.getPriorityWeight(a.priority));
152
183
  // 限制并发数
@@ -208,13 +239,13 @@ class Scheduler {
208
239
  }
209
240
  }
210
241
  /**
211
- * 获取调度状态
242
+ * 获取调度状态(从持久化状态读取)
212
243
  */
213
- getStatus() {
244
+ async getStatus() {
245
+ const running = await this.getRunningCount();
214
246
  return {
215
- running: this.runningTasks.size,
216
- maxConcurrent: this.config.maxConcurrentTasks,
217
- runningTaskIds: Array.from(this.runningTasks)
247
+ running,
248
+ maxConcurrent: this.config.maxConcurrentTasks
218
249
  };
219
250
  }
220
251
  }
@@ -27,8 +27,8 @@ const TRANSITIONS = [
27
27
  { from: 'accept', to: 'failed', event: 'fail' },
28
28
  // failed → retry_queue
29
29
  { from: 'failed', to: 'retry_queue', event: 'retry' },
30
- // retry_queue → pending
31
- { from: 'retry_queue', to: 'pending', event: 'retry' },
30
+ // retry_queue → pending (安全上限 100,由 executor 层控制具体 maxRetries)
31
+ { from: 'retry_queue', to: 'pending', event: 'retry', condition: (task) => (task.retryCount || 0) < 100 },
32
32
  // any → pending (cancel and restart)
33
33
  { from: 'scheduled', to: 'pending', event: 'cancel' },
34
34
  { from: 'blocked', to: 'pending', event: 'cancel' },
@@ -1,4 +1,32 @@
1
1
  import type { ParsedTask, QualityConfig } from '../types/index.js';
2
+ /**
3
+ * 从 plan 中解析出的结构化模块信息
4
+ */
5
+ export interface PlanModule {
6
+ /** 模块名称,如 "用户域" */
7
+ name: string;
8
+ /** 模块描述 */
9
+ description: string;
10
+ /** 关联的表,如 ["users", "user_profiles"] */
11
+ tables: string[];
12
+ /** 模块类型 */
13
+ type: 'domain' | 'feature' | 'infra' | 'system';
14
+ /** 依赖的其他模块名称 */
15
+ dependsOn: string[];
16
+ /** 预估复杂度 */
17
+ complexity: 'low' | 'medium' | 'high';
18
+ }
19
+ /**
20
+ * 从 plan 中解析出的结构化信息
21
+ */
22
+ export interface ParsedPlan {
23
+ /** 核心模块列表 */
24
+ modules: PlanModule[];
25
+ /** 技术栈摘要 */
26
+ techStack: string[];
27
+ /** 原始 plan 文本 */
28
+ raw: string;
29
+ }
2
30
  export interface TaskBreakdown {
3
31
  taskId: string;
4
32
  title: string;
@@ -19,8 +47,8 @@ export interface UserAnswers {
19
47
  additionalContext?: Record<string, string | string[]>;
20
48
  /** 是否启用 E2E 测试 */
21
49
  e2eTests?: boolean;
22
- /** E2E 测试类型 (web/mobile/gui) */
23
- e2eType?: 'web' | 'mobile' | 'gui';
50
+ /** E2E 测试类型 (web/mobile/gui/visual) */
51
+ e2eType?: 'web' | 'mobile' | 'gui' | 'visual';
24
52
  /** 质量级别 */
25
53
  qualityLevel?: 'fast' | 'balanced' | 'strict';
26
54
  }
@@ -38,16 +66,53 @@ export interface UserAnswers {
38
66
  */
39
67
  export declare class TaskPlanner {
40
68
  private userAnswers;
41
- private taskCounter;
69
+ /** 静态计数器,避免多实例生成重复 ID */
70
+ private static taskCounter;
42
71
  constructor(userAnswers?: UserAnswers);
43
72
  /**
44
73
  * 设置用户回答
45
74
  */
46
75
  setUserAnswers(answers: UserAnswers): void;
47
76
  /**
48
- * Break down a parsed task into sub-tasks
77
+ * 解析 plan 文本,提取模块、技术栈、数据模型等结构化信息
49
78
  */
79
+ parsePlan(planText: string): ParsedPlan;
80
+ /**
81
+ * 分析模块间依赖关系
82
+ *
83
+ * 策略:从 plan 文本中提取 AI 明确写的依赖信息,不做架构猜测。
84
+ * 如果 plan 中没有指定依赖,模块之间并行执行。
85
+ */
86
+ private analyzeModuleDependencies;
87
+ /**
88
+ * 从 plan 文本中提取某个模块相关的上下文段落
89
+ */
90
+ private extractModuleContext;
91
+ /**
92
+ * 预估模块复杂度 — 基于通用架构特征,不依赖具体业务领域
93
+ */
94
+ private estimateModuleComplexity;
50
95
  breakdown(parsedTask: ParsedTask, answers: Record<string, string>, qualityConfig?: QualityConfig, plan?: string): TaskBreakdown[];
96
+ /**
97
+ * 基于 plan 解析出的模块做细粒度任务拆分
98
+ */
99
+ private breakdownByModules;
100
+ /**
101
+ * 为模块任务添加 phase 级别的跨阶段依赖
102
+ */
103
+ private enforcePhaseDependenciesForModule;
104
+ /**
105
+ * 确定模块任务优先级
106
+ */
107
+ private determineModulePriority;
108
+ /**
109
+ * 为模块生成验收标准
110
+ */
111
+ private generateModuleAcceptanceCriteria;
112
+ /**
113
+ * 按目标拆分的传统方式(fallback)
114
+ */
115
+ private breakdownByGoals;
51
116
  /**
52
117
  * 判断是否需要设计阶段
53
118
  *
@@ -84,4 +149,18 @@ export declare class TaskPlanner {
84
149
  * - other: 其他类型(配置、优化、部署等) → 单个任务
85
150
  */
86
151
  private classifyGoal;
152
+ /**
153
+ * 检测顺序阶段目标(如 "Phase 1 基础架构"、"Phase 2 AI创作核心")
154
+ * 返回按阶段排序的索引列表
155
+ */
156
+ private detectSequentialPhases;
157
+ /**
158
+ * 对顺序阶段建立跨阶段依赖
159
+ *
160
+ * 当 goals 包含 "Phase 1", "Phase 2", "Phase 3" 等顺序阶段时,
161
+ * 后续阶段的所有开发任务必须依赖前一阶段的集成任务(或最后一个开发任务)。
162
+ *
163
+ * 这防止多个阶段同时执行导致文件冲突。
164
+ */
165
+ private enforcePhaseDependencies;
87
166
  }