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
@@ -282,6 +282,5 @@ exports.meetingCommand = new commander_1.Command('meeting')
282
282
  }
283
283
  catch (error) {
284
284
  console.error('❌ 处理失败:', error instanceof Error ? error.message : error);
285
- process.exit(1);
286
285
  }
287
286
  });
@@ -135,68 +135,68 @@ exports.reportCommand = new commander_1.Command('report')
135
135
  });
136
136
  function generateMarkdownReport(state, tasks, approvals, stats, efficiency, options) {
137
137
  const duration = Math.round(efficiency.totalDuration / 1000 / 60); // 转为分钟
138
- let report = `
139
- # 📊 OpenMatrix 执行报告
140
-
141
- **Run ID:** ${state.runId}
142
- **时间:** ${state.startedAt}
143
- **状态:** ${state.status}
144
-
145
- ## 统计概览
146
-
147
- | 状态 | 数量 | 占比 |
148
- |------|------|------|
149
- | ✅ 完成 | ${stats.completed} | ${stats.total > 0 ? Math.round(stats.completed / stats.total * 100) : 0}% |
150
- | ❌ 失败 | ${stats.failed} | ${stats.total > 0 ? Math.round(stats.failed / stats.total * 100) : 0}% |
151
- | 🔄 进行中 | ${stats.inProgress} | ${stats.total > 0 ? Math.round(stats.inProgress / stats.total * 100) : 0}% |
152
- | 🔴 阻塞 | ${stats.blocked} | ${stats.total > 0 ? Math.round(stats.blocked / stats.total * 100) : 0}% |
153
- | ⏳ 待处理 | ${stats.pending} | ${stats.total > 0 ? Math.round(stats.pending / stats.total * 100) : 0}% |
154
-
155
- ## 任务详情
156
-
157
- ### ✅ 已完成
138
+ let report = `
139
+ # 📊 OpenMatrix 执行报告
140
+
141
+ **Run ID:** ${state.runId}
142
+ **时间:** ${state.startedAt}
143
+ **状态:** ${state.status}
144
+
145
+ ## 统计概览
146
+
147
+ | 状态 | 数量 | 占比 |
148
+ |------|------|------|
149
+ | ✅ 完成 | ${stats.completed} | ${stats.total > 0 ? Math.round(stats.completed / stats.total * 100) : 0}% |
150
+ | ❌ 失败 | ${stats.failed} | ${stats.total > 0 ? Math.round(stats.failed / stats.total * 100) : 0}% |
151
+ | 🔄 进行中 | ${stats.inProgress} | ${stats.total > 0 ? Math.round(stats.inProgress / stats.total * 100) : 0}% |
152
+ | 🔴 阻塞 | ${stats.blocked} | ${stats.total > 0 ? Math.round(stats.blocked / stats.total * 100) : 0}% |
153
+ | ⏳ 待处理 | ${stats.pending} | ${stats.total > 0 ? Math.round(stats.pending / stats.total * 100) : 0}% |
154
+
155
+ ## 任务详情
156
+
157
+ ### ✅ 已完成
158
158
  ${tasks
159
159
  .filter(t => t.status === 'completed')
160
160
  .map(t => `- ${t.id}: ${t.title}`)
161
- .join('\n') || '_无_'}
162
-
163
- ### ❌ 失败
161
+ .join('\n') || '_无_'}
162
+
163
+ ### ❌ 失败
164
164
  ${tasks
165
165
  .filter(t => t.status === 'failed')
166
166
  .map(t => `- ${t.id}: ${t.title}\n 原因: ${t.error || '未知'}`)
167
- .join('\n') || '_无_'}
168
-
169
- ### 🔴 阻塞
167
+ .join('\n') || '_无_'}
168
+
169
+ ### 🔴 阻塞
170
170
  ${tasks
171
171
  .filter(t => t.status === 'blocked')
172
172
  .map(t => `- ${t.id}: ${t.title}\n 原因: ${t.error || '未知'}`)
173
- .join('\n') || '_无_'}
173
+ .join('\n') || '_无_'}
174
174
  `;
175
175
  // 效率分析
176
176
  if (options.efficiency) {
177
- report += `
178
- ## 🏆 效率分析
179
-
180
- | 指标 | 值 |
181
- |------|-----|
182
- | 总耗时 | ${duration} 分钟 |
183
- | Agent 调用 | ${efficiency.agentCalls} 次 |
184
- | 重试次数 | ${efficiency.retryCount} 次 |
185
- | 并行度 | ${efficiency.parallelism} / ${efficiency.targetParallelism} |
177
+ report += `
178
+ ## 🏆 效率分析
179
+
180
+ | 指标 | 值 |
181
+ |------|-----|
182
+ | 总耗时 | ${duration} 分钟 |
183
+ | Agent 调用 | ${efficiency.agentCalls} 次 |
184
+ | 重试次数 | ${efficiency.retryCount} 次 |
185
+ | 并行度 | ${efficiency.parallelism} / ${efficiency.targetParallelism} |
186
186
  `;
187
187
  }
188
188
  // 审批记录
189
- report += `
190
- ## 🔔 审批记录
191
-
192
- | ID | 类型 | 决策 | 状态 |
193
- |----|------|------|------|
189
+ report += `
190
+ ## 🔔 审批记录
191
+
192
+ | ID | 类型 | 决策 | 状态 |
193
+ |----|------|------|------|
194
194
  ${approvals.length > 0
195
195
  ? approvals.map(a => `| ${a.id} | ${a.type} | ${a.decision || '-'} | ${a.status} |`).join('\n')
196
- : '| _无_ | | | |'}
197
-
198
- ---
199
- *报告生成时间: ${new Date().toISOString()}*
196
+ : '| _无_ | | | |'}
197
+
198
+ ---
199
+ *报告生成时间: ${new Date().toISOString()}*
200
200
  `;
201
201
  return report.trim();
202
202
  }
@@ -59,6 +59,8 @@ exports.startCommand = new commander_1.Command('start')
59
59
  .option('--docs <level>', '文档级别 (full|basic|minimal|none)')
60
60
  .option('--tasks-json <json>', 'AI 已拆分的任务 JSON (跳过自动解析)')
61
61
  .option('--e2e-tests', '启用 E2E 测试')
62
+ .option('--e2e-type <type>', 'E2E 测试类型 (web|visual)')
63
+ .option('--research-context <path>', '研究上下文 JSON 路径 (来自 /om:research 的 context.json)')
62
64
  .action(async (input, options) => {
63
65
  const basePath = process.cwd();
64
66
  const omPath = path.join(basePath, '.openmatrix');
@@ -112,8 +114,91 @@ exports.startCommand = new commander_1.Command('start')
112
114
  // ============================
113
115
  // 路径 B: 自动解析 (fallback)
114
116
  // ============================
115
- await handleAutoParse(input, options, stateManager, state);
117
+ await handleAutoParse(input, options, stateManager, state, basePath, omPath);
116
118
  });
119
+ /**
120
+ * 加载研究上下文
121
+ */
122
+ async function loadResearchContext(researchContextPath, basePath, omPath) {
123
+ let contextPath = researchContextPath;
124
+ if (!contextPath) {
125
+ // 自动检测默认路径
126
+ const defaultPath = path.join(omPath, 'research', 'context.json');
127
+ try {
128
+ await fs.access(defaultPath);
129
+ contextPath = `@${defaultPath}`;
130
+ }
131
+ catch {
132
+ return { context: null, report: null };
133
+ }
134
+ }
135
+ if (!contextPath) {
136
+ return { context: null, report: null };
137
+ }
138
+ try {
139
+ // 支持 @file 语法
140
+ let jsonStr = contextPath;
141
+ if (jsonStr.startsWith('@')) {
142
+ const filePath = jsonStr.slice(1);
143
+ const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
144
+ jsonStr = await fs.readFile(resolvedPath, 'utf-8');
145
+ }
146
+ const context = JSON.parse(jsonStr);
147
+ // 读取研究报告
148
+ let report = null;
149
+ if (context.reportPath) {
150
+ const reportPath = path.isAbsolute(context.reportPath)
151
+ ? context.reportPath
152
+ : path.join(basePath, context.reportPath);
153
+ try {
154
+ report = await fs.readFile(reportPath, 'utf-8');
155
+ }
156
+ catch {
157
+ // 研究报告不存在不影响流程
158
+ }
159
+ }
160
+ return { context, report };
161
+ }
162
+ catch {
163
+ return { context: null, report: null };
164
+ }
165
+ }
166
+ /**
167
+ * 合并研究上下文到 AI 解析的输入
168
+ */
169
+ function mergeResearchContext(tasksInput, researchContext, researchReport) {
170
+ const merged = { ...tasksInput };
171
+ // goals: 研究的基础 goals + AI 补充的 goals(去重)
172
+ const baseGoals = researchContext.goals || [];
173
+ const aiGoals = tasksInput.goals || [];
174
+ const mergedGoals = [...new Set([...baseGoals, ...aiGoals])];
175
+ if (mergedGoals.length > 0) {
176
+ merged.goals = mergedGoals;
177
+ }
178
+ // constraints: 合并
179
+ const baseConstraints = researchContext.constraints || [];
180
+ const aiConstraints = tasksInput.constraints || [];
181
+ const mergedConstraints = [...new Set([...baseConstraints, ...aiConstraints])];
182
+ if (mergedConstraints.length > 0) {
183
+ merged.constraints = mergedConstraints;
184
+ }
185
+ // deliverables: 合并
186
+ const baseDeliverables = researchContext.deliverables || [];
187
+ const aiDeliverables = tasksInput.deliverables || [];
188
+ const mergedDeliverables = [...new Set([...baseDeliverables, ...aiDeliverables])];
189
+ if (mergedDeliverables.length > 0) {
190
+ merged.deliverables = mergedDeliverables;
191
+ }
192
+ // plan: 如果 AI 未提供 plan,使用研究报告内容
193
+ if (!merged.plan && researchReport) {
194
+ merged.plan = `# 领域研究: ${researchContext.domain}\n\n## 研究主题\n${researchContext.topic}\n\n${researchReport}`;
195
+ }
196
+ else if (researchReport) {
197
+ // AI 已有 plan,将研究作为附录追加
198
+ merged.plan = `${merged.plan}\n\n---\n\n# 领域研究背景: ${researchContext.domain}\n\n## 研究主题\n${researchContext.topic}\n\n${researchReport}`;
199
+ }
200
+ return merged;
201
+ }
117
202
  /**
118
203
  * 处理 AI 解析的任务 (--tasks-json)
119
204
  * AI 提供 ParsedTask 格式的结构化数据,仍由 TaskPlanner 做拆分
@@ -152,18 +237,27 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
152
237
  }
153
238
  return;
154
239
  }
240
+ // 加载并合并研究上下文
241
+ const { context: researchContext, report: researchReport } = await loadResearchContext(options.researchContext, basePath, omPath);
242
+ let resolvedInput = tasksInput;
243
+ if (researchContext) {
244
+ resolvedInput = mergeResearchContext(tasksInput, researchContext, researchReport);
245
+ if (!options.json) {
246
+ console.log(`🔬 已加载研究领域: ${researchContext.domain}`);
247
+ }
248
+ }
155
249
  // 保存 AI 生成的执行计划
156
- if (tasksInput.plan) {
157
- await fs.writeFile(path.join(omPath, 'plan.md'), tasksInput.plan, 'utf-8');
250
+ if (resolvedInput.plan) {
251
+ await fs.writeFile(path.join(omPath, 'plan.md'), resolvedInput.plan, 'utf-8');
158
252
  }
159
253
  // 构建 ParsedTask
160
254
  const parsedTask = {
161
- title: tasksInput.title,
162
- description: tasksInput.description || '',
163
- goals: tasksInput.goals,
164
- goalTypes: tasksInput.goalTypes,
165
- constraints: tasksInput.constraints || [],
166
- deliverables: tasksInput.deliverables || [],
255
+ title: resolvedInput.title || tasksInput.title,
256
+ description: resolvedInput.description || '',
257
+ goals: resolvedInput.goals,
258
+ goalTypes: resolvedInput.goalTypes,
259
+ constraints: resolvedInput.constraints || [],
260
+ deliverables: resolvedInput.deliverables || [],
167
261
  rawContent: ''
168
262
  };
169
263
  // 解析质量配置
@@ -173,15 +267,19 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
173
267
  if (tasksInput.e2eTests || options.e2eTests) {
174
268
  qualityConfig.e2eTests = true;
175
269
  }
270
+ // E2E 类型(通过 answers 传递给 TaskPlanner)
271
+ const extraAnswers = { ...(resolvedInput.answers || {}) };
272
+ if (options.e2eType) {
273
+ extraAnswers.e2eType = options.e2eType;
274
+ }
176
275
  if (!options.json) {
177
276
  console.log(`\n📋 任务: ${parsedTask.title}`);
178
277
  console.log(` 目标: ${parsedTask.goals.join(', ')}`);
179
278
  console.log('\n🔧 拆解任务...');
180
279
  }
181
280
  // 使用 TaskPlanner 拆分(保持原有拆分逻辑)
182
- const answers = tasksInput.answers || {};
183
281
  const planner = new task_planner_js_1.TaskPlanner();
184
- const subTasks = planner.breakdown(parsedTask, answers, qualityConfig, tasksInput.plan);
282
+ const subTasks = planner.breakdown(parsedTask, extraAnswers, qualityConfig, resolvedInput.plan);
185
283
  // 创建任务到状态管理器,并建立 ID 映射
186
284
  // TaskPlanner 生成的 taskId 和 StateManager 创建的 id 不同,
187
285
  // 需要映射后才能正确设置 dependencies
@@ -238,14 +336,15 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
238
336
  assignedAgent: t.assignedAgent
239
337
  })),
240
338
  taskInfo: {
241
- title: tasksInput.title,
242
- description: tasksInput.description,
243
- quality: qualityLevel
339
+ title: resolvedInput.title,
340
+ description: resolvedInput.description,
341
+ quality: qualityLevel,
342
+ domain: researchContext?.domain
244
343
  }
245
344
  }));
246
345
  }
247
346
  else {
248
- console.log(`\n📋 ${tasksInput.title} - ${subTasks.length} 个子任务:\n`);
347
+ console.log(`\n📋 ${resolvedInput.title} - ${subTasks.length} 个子任务:\n`);
249
348
  subTasks.forEach((task, i) => {
250
349
  console.log(` ${i + 1}. ${task.title} (${task.priority}, ${task.assignedAgent})`);
251
350
  });
@@ -275,14 +374,15 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
275
374
  },
276
375
  subagentTasks,
277
376
  taskInfo: {
278
- title: tasksInput.title,
279
- description: tasksInput.description,
280
- quality: qualityLevel
377
+ title: resolvedInput.title,
378
+ description: resolvedInput.description,
379
+ quality: qualityLevel,
380
+ domain: researchContext?.domain
281
381
  }
282
382
  }));
283
383
  }
284
384
  else {
285
- console.log(`\n📋 ${tasksInput.title} - ${subTasks.length} 个子任务已创建`);
385
+ console.log(`\n📋 ${resolvedInput.title} - ${subTasks.length} 个子任务已创建`);
286
386
  console.log(`🎯 执行模式:${executionMode}`);
287
387
  console.log(` 质量级别:${qualityLevel}`);
288
388
  console.log('\n🚀 等待 Skill 执行任务...');
@@ -292,7 +392,7 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
292
392
  /**
293
393
  * 处理自动解析 (fallback,无 AI 时使用)
294
394
  */
295
- async function handleAutoParse(input, options, stateManager, state) {
395
+ async function handleAutoParse(input, options, stateManager, state, basePath, omPath) {
296
396
  // 构建任务内容
297
397
  let taskContent = input;
298
398
  if (options.title || options.description) {
@@ -302,7 +402,46 @@ async function handleAutoParse(input, options, stateManager, state) {
302
402
  const docs = options.docs ? `\n文档要求: ${options.docs}` : '';
303
403
  taskContent = `# ${title}\n\n${description}${techStack}${docs}`;
304
404
  }
405
+ // 如果没有提供输入,先检测研究上下文,再检测 TASK.md
305
406
  if (!taskContent) {
407
+ // 优先检测研究上下文
408
+ const { context: researchContext, report: researchReport } = await loadResearchContext(options.researchContext, basePath, omPath);
409
+ if (researchContext) {
410
+ // 基于研究上下文构建 ParsedTask
411
+ const parsedTitle = researchContext.topic || researchContext.domain || '未命名任务';
412
+ const researchGoals = researchContext.goals || [];
413
+ if (!options.json) {
414
+ console.log(`\n🔬 检测到研究领域: ${researchContext.domain}`);
415
+ console.log(` 研究目标: ${researchGoals.length > 0 ? researchGoals.join(', ') : '待拆分'}`);
416
+ console.log('\n🔍 基于研究结果解析任务...');
417
+ }
418
+ const parsedTask = {
419
+ title: parsedTitle,
420
+ description: researchGoals.length > 0 ? researchGoals.join('\n') : '',
421
+ goals: researchGoals,
422
+ goalTypes: researchGoals.map(() => 'development'),
423
+ constraints: researchContext.constraints || [],
424
+ deliverables: researchContext.deliverables || [],
425
+ rawContent: researchReport || ''
426
+ };
427
+ if (!options.json) {
428
+ console.log(`\n📋 任务: ${parsedTask.title}`);
429
+ console.log(` 目标: ${parsedTask.goals.join(', ') || '(待 AI 补充)'}`);
430
+ console.log('\n🔧 拆解任务...');
431
+ }
432
+ let qualityConfig;
433
+ if (options.quality) {
434
+ const qualityLevel = options.quality.toLowerCase();
435
+ if (['strict', 'balanced', 'fast'].includes(qualityLevel)) {
436
+ qualityConfig = index_js_1.QUALITY_PRESETS[qualityLevel];
437
+ }
438
+ }
439
+ const planner = new task_planner_js_1.TaskPlanner();
440
+ const subTasks = planner.breakdown(parsedTask, {}, qualityConfig, researchReport || undefined);
441
+ await finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, parsedTask.title);
442
+ return;
443
+ }
444
+ // 无研究上下文,回退到 TASK.md
306
445
  const defaultPath = path.join(process.cwd(), 'TASK.md');
307
446
  try {
308
447
  taskContent = await fs.readFile(defaultPath, 'utf-8');
@@ -355,6 +494,13 @@ async function handleAutoParse(input, options, stateManager, state) {
355
494
  }
356
495
  const planner = new task_planner_js_1.TaskPlanner();
357
496
  const subTasks = planner.breakdown(parsedTask, {}, qualityConfig);
497
+ await finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, parsedTask.title);
498
+ }
499
+ /**
500
+ * 公共函数:创建任务、更新状态、处理审批、输出结果
501
+ * 被 handleTasksJson 和 handleAutoParse 共用
502
+ */
503
+ async function finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, taskTitle) {
358
504
  // 创建任务,并建立 TaskPlanner ID → StateManager ID 的映射
359
505
  const taskIdMap = new Map();
360
506
  for (const subTask of subTasks) {
@@ -401,13 +547,7 @@ async function handleAutoParse(input, options, stateManager, state) {
401
547
  approvalType: 'plan',
402
548
  message: '等待计划审批',
403
549
  tasks: subTasks.map((t, i) => ({ index: i + 1, title: t.title, priority: t.priority })),
404
- taskInfo: {
405
- title: options.title || parsedTask.title,
406
- description: options.description,
407
- quality: options.quality,
408
- techStack: options.techStack,
409
- docs: options.docs
410
- }
550
+ taskInfo: { title: taskTitle, quality: options.quality }
411
551
  }));
412
552
  }
413
553
  else {
@@ -440,13 +580,7 @@ async function handleAutoParse(input, options, stateManager, state) {
440
580
  pending: allTasks.filter(t => t.status === 'pending').length
441
581
  },
442
582
  subagentTasks,
443
- taskInfo: {
444
- title: options.title || parsedTask.title,
445
- description: options.description,
446
- quality: options.quality,
447
- techStack: options.techStack,
448
- docs: options.docs
449
- }
583
+ taskInfo: { title: taskTitle, quality: options.quality }
450
584
  }));
451
585
  }
452
586
  else {
@@ -123,7 +123,6 @@ async function showStatus(manager, reporter, options) {
123
123
  }
124
124
  catch (error) {
125
125
  console.error(chalk_1.default.red('Error:'), error);
126
- process.exit(1);
127
126
  }
128
127
  }
129
128
  /**
@@ -38,9 +38,12 @@ exports.stepCommand = void 0;
38
38
  // 循环状态持久化 - 防止上下文压缩导致循环丢失
39
39
  const commander_1 = require("commander");
40
40
  const state_manager_js_1 = require("../../storage/state-manager.js");
41
+ const scheduler_js_1 = require("../../orchestrator/scheduler.js");
42
+ const agent_runner_js_1 = require("../../agents/agent-runner.js");
43
+ const approval_manager_js_1 = require("../../orchestrator/approval-manager.js");
41
44
  const path = __importStar(require("path"));
42
45
  exports.stepCommand = new commander_1.Command('step')
43
- .description('获取下一个待执行任务(持久化循环状态)')
46
+ .description('获取下一个待执行任务(自动转换状态并准备 Subagent 配置)')
44
47
  .option('--json', '输出 JSON 格式')
45
48
  .action(async (options) => {
46
49
  const basePath = process.cwd();
@@ -53,30 +56,15 @@ exports.stepCommand = new commander_1.Command('step')
53
56
  console.log(JSON.stringify({ status: 'done', message: '所有任务已完成' }));
54
57
  return;
55
58
  }
56
- // 获取所有任务
57
- const allTasks = await stateManager.listTasks();
58
- const nextTask = allTasks.find(t => t.status === 'pending' ||
59
- t.status === 'scheduled' ||
60
- t.status === 'in_progress');
59
+ // 使用 Scheduler 获取下一个可执行任务(处理依赖、并发等)
60
+ const scheduler = new scheduler_js_1.Scheduler(stateManager, {
61
+ maxConcurrentTasks: state.config.maxConcurrentAgents || 3
62
+ });
63
+ const nextTask = await scheduler.getNextTask();
61
64
  if (!nextTask) {
62
- // 所有任务都完成了或被阻塞
63
- const completed = allTasks.filter(t => t.status === 'completed').length;
64
- const total = allTasks.length;
65
- // 自动更新统计
66
- const stats = {
67
- totalTasks: total,
68
- completed: completed,
69
- inProgress: allTasks.filter(t => t.status === 'in_progress').length,
70
- failed: allTasks.filter(t => t.status === 'failed').length,
71
- pending: allTasks.filter(t => t.status === 'pending').length,
72
- scheduled: allTasks.filter(t => t.status === 'scheduled').length,
73
- blocked: allTasks.filter(t => t.status === 'blocked').length,
74
- waiting: allTasks.filter(t => t.status === 'waiting').length,
75
- verify: allTasks.filter(t => t.status === 'verify').length,
76
- accept: allTasks.filter(t => t.status === 'accept').length,
77
- retry_queue: allTasks.filter(t => t.status === 'retry_queue').length
78
- };
79
- const allDone = completed + stats.failed === total;
65
+ // 所有任务都完成了或被阻塞 — 刷新统计后返回
66
+ const stats = await refreshStatistics(stateManager);
67
+ const allDone = stats.completed + stats.failed === stats.totalTasks;
80
68
  await stateManager.updateState({
81
69
  statistics: stats,
82
70
  status: allDone ? 'completed' : 'running',
@@ -86,30 +74,46 @@ exports.stepCommand = new commander_1.Command('step')
86
74
  status: allDone ? 'done' : 'blocked',
87
75
  statistics: stats,
88
76
  message: allDone
89
- ? `所有任务已完成 (${completed}/${total})`
90
- : `没有可执行任务 (${completed}/${total} 完成, ${stats.failed} 失败, ${stats.pending} 等待)`
77
+ ? `所有任务已完成 (${stats.completed}/${stats.totalTasks})`
78
+ : `没有可执行任务 (${stats.completed}/${stats.totalTasks} 完成, ${stats.failed} 失败, ${stats.pending} 等待)`
91
79
  }));
92
80
  return;
93
81
  }
94
- // 输出下一个任务信息
82
+ // 转换任务状态为 in_progress(通过 Scheduler)
83
+ await scheduler.markTaskStarted(nextTask.id);
84
+ // 准备 Subagent 任务配置(包含完整的 prompt)
85
+ const approvalManager = new approval_manager_js_1.ApprovalManager(stateManager);
86
+ const agentRunner = new agent_runner_js_1.AgentRunner(stateManager, approvalManager, {
87
+ maxConcurrent: state.config.maxConcurrentAgents || 3,
88
+ taskTimeout: state.config.timeout * 1000 || 120000
89
+ });
90
+ const subagentTask = await agentRunner.prepareSubagentTask(nextTask);
91
+ // 重新读取统计信息
92
+ const stats = await refreshStatistics(stateManager);
95
93
  const result = {
96
94
  status: 'next',
97
95
  task: {
98
96
  id: nextTask.id,
99
97
  title: nextTask.title,
100
98
  description: nextTask.description,
101
- status: nextTask.status,
99
+ status: 'in_progress',
102
100
  assignedAgent: nextTask.assignedAgent,
103
101
  dependencies: nextTask.dependencies,
104
102
  acceptanceCriteria: nextTask.acceptanceCriteria
105
103
  },
104
+ // 完整的 Subagent 配置(可直接用于 Agent 工具调用)
105
+ subagent: {
106
+ subagent_type: subagentTask.subagent_type,
107
+ description: subagentTask.description,
108
+ prompt: subagentTask.prompt,
109
+ isolation: subagentTask.isolation,
110
+ timeout: subagentTask.timeout
111
+ },
106
112
  statistics: {
107
- total: allTasks.length,
108
- completed: allTasks.filter(t => t.status === 'completed').length,
109
- remaining: allTasks.filter(t => t.status === 'pending' ||
110
- t.status === 'scheduled' ||
111
- t.status === 'in_progress').length,
112
- failed: allTasks.filter(t => t.status === 'failed').length
113
+ total: stats.totalTasks,
114
+ completed: stats.completed,
115
+ remaining: stats.pending + stats.inProgress + stats.scheduled + stats.verify + stats.accept,
116
+ failed: stats.failed
113
117
  }
114
118
  };
115
119
  if (options.json) {
@@ -117,6 +121,29 @@ exports.stepCommand = new commander_1.Command('step')
117
121
  }
118
122
  else {
119
123
  console.log(`📌 下一个任务: ${nextTask.id} - ${nextTask.title}`);
120
- console.log(` 进度: ${result.statistics.completed}/${result.statistics.total} 完成, ${result.statistics.remaining} 剩余`);
124
+ console.log(` 状态已转换为 in_progress`);
125
+ console.log(` Agent 类型: ${nextTask.assignedAgent}`);
126
+ console.log(` 进度: ${stats.completed}/${stats.totalTasks} 完成, ${result.statistics.remaining} 剩余`);
121
127
  }
122
128
  });
129
+ /**
130
+ * 从当前任务状态重新计算统计信息(保证准确性)
131
+ */
132
+ async function refreshStatistics(stateManager) {
133
+ const tasks = await stateManager.listTasks();
134
+ const stats = {
135
+ totalTasks: tasks.length,
136
+ completed: tasks.filter(t => t.status === 'completed').length,
137
+ inProgress: tasks.filter(t => t.status === 'in_progress').length,
138
+ failed: tasks.filter(t => t.status === 'failed').length,
139
+ pending: tasks.filter(t => t.status === 'pending').length,
140
+ scheduled: tasks.filter(t => t.status === 'scheduled').length,
141
+ blocked: tasks.filter(t => t.status === 'blocked').length,
142
+ waiting: tasks.filter(t => t.status === 'waiting').length,
143
+ verify: tasks.filter(t => t.status === 'verify').length,
144
+ accept: tasks.filter(t => t.status === 'accept').length,
145
+ retry_queue: tasks.filter(t => t.status === 'retry_queue').length
146
+ };
147
+ await stateManager.updateState({ statistics: stats });
148
+ return stats;
149
+ }
@@ -1,4 +1,4 @@
1
- import type { Task } from '../types/index.js';
1
+ import type { Task, TaskPriority, AgentType } from '../types/index.js';
2
2
  /**
3
3
  * AI Reviewer 验收报告
4
4
  */
@@ -24,6 +24,18 @@ export interface ReviewIssue {
24
24
  description: string;
25
25
  suggestion?: string;
26
26
  }
27
+ /**
28
+ * Review 修复任务配置
29
+ */
30
+ export interface ReviewFixTask {
31
+ taskId: string;
32
+ title: string;
33
+ description: string;
34
+ priority: TaskPriority;
35
+ assignedAgent: AgentType;
36
+ dependencies: string[];
37
+ timeout: number;
38
+ }
27
39
  /**
28
40
  * AIReviewer - AI 代码审查器
29
41
  *
@@ -42,9 +54,25 @@ export declare class AIReviewer {
42
54
  /**
43
55
  * 解析 AI Review 结果
44
56
  */
45
- parseReviewResult(output: string): ReviewReport;
57
+ parseReviewResult(taskId: string, output: string): ReviewReport;
46
58
  /**
47
59
  * 生成验收阶段提示词 (包含 AI Review)
48
60
  */
49
61
  buildAcceptPrompt(task: Task): string;
62
+ /**
63
+ * 根据 Review 报告生成修复任务
64
+ *
65
+ * 对每个 critical/major 问题生成独立的修复任务,
66
+ * 这些任务会被加入执行队列并自动执行。
67
+ *
68
+ * @param originalTask 被审查的原始任务
69
+ * @param report Review 报告
70
+ * @param reviewTaskId 审查任务本身的 ID(用于依赖)
71
+ * @returns 修复任务列表
72
+ */
73
+ generateFixTasks(originalTask: Task, report: ReviewReport, reviewTaskId: string): ReviewFixTask[];
74
+ /**
75
+ * 判断 Review 报告是否需要自动修复
76
+ */
77
+ needsAutoFix(report: ReviewReport): boolean;
50
78
  }