openmatrix 0.1.99 → 0.2.1
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/impl/coder-agent.js +42 -42
- package/dist/agents/impl/executor-agent.js +75 -75
- package/dist/agents/impl/planner-agent.js +63 -63
- package/dist/agents/impl/reviewer-agent.js +66 -66
- package/dist/agents/impl/tester-agent.js +56 -56
- package/dist/cli/commands/report.js +45 -45
- package/dist/cli/commands/start.js +163 -34
- package/dist/cli/commands/step.js +62 -35
- package/dist/orchestrator/ai-reviewer.d.ts +29 -1
- package/dist/orchestrator/ai-reviewer.js +312 -207
- package/dist/orchestrator/approval-manager.js +14 -13
- package/dist/orchestrator/executor.d.ts +10 -1
- package/dist/orchestrator/executor.js +56 -2
- package/dist/orchestrator/meeting-manager.js +32 -31
- package/dist/orchestrator/phase-executor.js +7 -5
- package/dist/orchestrator/scheduler.d.ts +8 -6
- package/dist/orchestrator/scheduler.js +53 -22
- package/dist/orchestrator/state-machine.js +2 -2
- package/dist/orchestrator/task-planner.d.ts +81 -2
- package/dist/orchestrator/task-planner.js +683 -122
- package/dist/storage/state-manager.d.ts +6 -0
- package/dist/storage/state-manager.js +28 -0
- package/package.json +55 -55
- package/scripts/build-check.js +19 -19
- package/scripts/install-skills.js +57 -57
- package/skills/approve.md +250 -250
- package/skills/auto.md +298 -298
- package/skills/meeting.md +324 -324
- package/skills/om.md +112 -112
- package/skills/openmatrix.md +112 -112
- package/skills/start.md +24 -1
- package/dist/cli/commands/upgrade.d.ts +0 -2
- package/dist/cli/commands/upgrade.js +0 -329
- package/dist/orchestrator/task-planner.old.d.ts +0 -87
- package/dist/orchestrator/task-planner.old.js +0 -444
|
@@ -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,7 @@ 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('--research-context <path>', '研究上下文 JSON 路径 (来自 /om:research 的 context.json)')
|
|
62
63
|
.action(async (input, options) => {
|
|
63
64
|
const basePath = process.cwd();
|
|
64
65
|
const omPath = path.join(basePath, '.openmatrix');
|
|
@@ -112,8 +113,91 @@ exports.startCommand = new commander_1.Command('start')
|
|
|
112
113
|
// ============================
|
|
113
114
|
// 路径 B: 自动解析 (fallback)
|
|
114
115
|
// ============================
|
|
115
|
-
await handleAutoParse(input, options, stateManager, state);
|
|
116
|
+
await handleAutoParse(input, options, stateManager, state, basePath, omPath);
|
|
116
117
|
});
|
|
118
|
+
/**
|
|
119
|
+
* 加载研究上下文
|
|
120
|
+
*/
|
|
121
|
+
async function loadResearchContext(researchContextPath, basePath, omPath) {
|
|
122
|
+
let contextPath = researchContextPath;
|
|
123
|
+
if (!contextPath) {
|
|
124
|
+
// 自动检测默认路径
|
|
125
|
+
const defaultPath = path.join(omPath, 'research', 'context.json');
|
|
126
|
+
try {
|
|
127
|
+
await fs.access(defaultPath);
|
|
128
|
+
contextPath = `@${defaultPath}`;
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return { context: null, report: null };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!contextPath) {
|
|
135
|
+
return { context: null, report: null };
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
// 支持 @file 语法
|
|
139
|
+
let jsonStr = contextPath;
|
|
140
|
+
if (jsonStr.startsWith('@')) {
|
|
141
|
+
const filePath = jsonStr.slice(1);
|
|
142
|
+
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
|
|
143
|
+
jsonStr = await fs.readFile(resolvedPath, 'utf-8');
|
|
144
|
+
}
|
|
145
|
+
const context = JSON.parse(jsonStr);
|
|
146
|
+
// 读取研究报告
|
|
147
|
+
let report = null;
|
|
148
|
+
if (context.reportPath) {
|
|
149
|
+
const reportPath = path.isAbsolute(context.reportPath)
|
|
150
|
+
? context.reportPath
|
|
151
|
+
: path.join(basePath, context.reportPath);
|
|
152
|
+
try {
|
|
153
|
+
report = await fs.readFile(reportPath, 'utf-8');
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// 研究报告不存在不影响流程
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { context, report };
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return { context: null, report: null };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 合并研究上下文到 AI 解析的输入
|
|
167
|
+
*/
|
|
168
|
+
function mergeResearchContext(tasksInput, researchContext, researchReport) {
|
|
169
|
+
const merged = { ...tasksInput };
|
|
170
|
+
// goals: 研究的基础 goals + AI 补充的 goals(去重)
|
|
171
|
+
const baseGoals = researchContext.goals || [];
|
|
172
|
+
const aiGoals = tasksInput.goals || [];
|
|
173
|
+
const mergedGoals = [...new Set([...baseGoals, ...aiGoals])];
|
|
174
|
+
if (mergedGoals.length > 0) {
|
|
175
|
+
merged.goals = mergedGoals;
|
|
176
|
+
}
|
|
177
|
+
// constraints: 合并
|
|
178
|
+
const baseConstraints = researchContext.constraints || [];
|
|
179
|
+
const aiConstraints = tasksInput.constraints || [];
|
|
180
|
+
const mergedConstraints = [...new Set([...baseConstraints, ...aiConstraints])];
|
|
181
|
+
if (mergedConstraints.length > 0) {
|
|
182
|
+
merged.constraints = mergedConstraints;
|
|
183
|
+
}
|
|
184
|
+
// deliverables: 合并
|
|
185
|
+
const baseDeliverables = researchContext.deliverables || [];
|
|
186
|
+
const aiDeliverables = tasksInput.deliverables || [];
|
|
187
|
+
const mergedDeliverables = [...new Set([...baseDeliverables, ...aiDeliverables])];
|
|
188
|
+
if (mergedDeliverables.length > 0) {
|
|
189
|
+
merged.deliverables = mergedDeliverables;
|
|
190
|
+
}
|
|
191
|
+
// plan: 如果 AI 未提供 plan,使用研究报告内容
|
|
192
|
+
if (!merged.plan && researchReport) {
|
|
193
|
+
merged.plan = `# 领域研究: ${researchContext.domain}\n\n## 研究主题\n${researchContext.topic}\n\n${researchReport}`;
|
|
194
|
+
}
|
|
195
|
+
else if (researchReport) {
|
|
196
|
+
// AI 已有 plan,将研究作为附录追加
|
|
197
|
+
merged.plan = `${merged.plan}\n\n---\n\n# 领域研究背景: ${researchContext.domain}\n\n## 研究主题\n${researchContext.topic}\n\n${researchReport}`;
|
|
198
|
+
}
|
|
199
|
+
return merged;
|
|
200
|
+
}
|
|
117
201
|
/**
|
|
118
202
|
* 处理 AI 解析的任务 (--tasks-json)
|
|
119
203
|
* AI 提供 ParsedTask 格式的结构化数据,仍由 TaskPlanner 做拆分
|
|
@@ -152,18 +236,27 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
|
152
236
|
}
|
|
153
237
|
return;
|
|
154
238
|
}
|
|
239
|
+
// 加载并合并研究上下文
|
|
240
|
+
const { context: researchContext, report: researchReport } = await loadResearchContext(options.researchContext, basePath, omPath);
|
|
241
|
+
let resolvedInput = tasksInput;
|
|
242
|
+
if (researchContext) {
|
|
243
|
+
resolvedInput = mergeResearchContext(tasksInput, researchContext, researchReport);
|
|
244
|
+
if (!options.json) {
|
|
245
|
+
console.log(`🔬 已加载研究领域: ${researchContext.domain}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
155
248
|
// 保存 AI 生成的执行计划
|
|
156
|
-
if (
|
|
157
|
-
await fs.writeFile(path.join(omPath, 'plan.md'),
|
|
249
|
+
if (resolvedInput.plan) {
|
|
250
|
+
await fs.writeFile(path.join(omPath, 'plan.md'), resolvedInput.plan, 'utf-8');
|
|
158
251
|
}
|
|
159
252
|
// 构建 ParsedTask
|
|
160
253
|
const parsedTask = {
|
|
161
|
-
title: tasksInput.title,
|
|
162
|
-
description:
|
|
163
|
-
goals:
|
|
164
|
-
goalTypes:
|
|
165
|
-
constraints:
|
|
166
|
-
deliverables:
|
|
254
|
+
title: resolvedInput.title || tasksInput.title,
|
|
255
|
+
description: resolvedInput.description || '',
|
|
256
|
+
goals: resolvedInput.goals,
|
|
257
|
+
goalTypes: resolvedInput.goalTypes,
|
|
258
|
+
constraints: resolvedInput.constraints || [],
|
|
259
|
+
deliverables: resolvedInput.deliverables || [],
|
|
167
260
|
rawContent: ''
|
|
168
261
|
};
|
|
169
262
|
// 解析质量配置
|
|
@@ -179,9 +272,9 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
|
179
272
|
console.log('\n🔧 拆解任务...');
|
|
180
273
|
}
|
|
181
274
|
// 使用 TaskPlanner 拆分(保持原有拆分逻辑)
|
|
182
|
-
const answers =
|
|
275
|
+
const answers = resolvedInput.answers || {};
|
|
183
276
|
const planner = new task_planner_js_1.TaskPlanner();
|
|
184
|
-
const subTasks = planner.breakdown(parsedTask, answers, qualityConfig,
|
|
277
|
+
const subTasks = planner.breakdown(parsedTask, answers, qualityConfig, resolvedInput.plan);
|
|
185
278
|
// 创建任务到状态管理器,并建立 ID 映射
|
|
186
279
|
// TaskPlanner 生成的 taskId 和 StateManager 创建的 id 不同,
|
|
187
280
|
// 需要映射后才能正确设置 dependencies
|
|
@@ -238,14 +331,15 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
|
238
331
|
assignedAgent: t.assignedAgent
|
|
239
332
|
})),
|
|
240
333
|
taskInfo: {
|
|
241
|
-
title:
|
|
242
|
-
description:
|
|
243
|
-
quality: qualityLevel
|
|
334
|
+
title: resolvedInput.title,
|
|
335
|
+
description: resolvedInput.description,
|
|
336
|
+
quality: qualityLevel,
|
|
337
|
+
domain: researchContext?.domain
|
|
244
338
|
}
|
|
245
339
|
}));
|
|
246
340
|
}
|
|
247
341
|
else {
|
|
248
|
-
console.log(`\n📋 ${
|
|
342
|
+
console.log(`\n📋 ${resolvedInput.title} - ${subTasks.length} 个子任务:\n`);
|
|
249
343
|
subTasks.forEach((task, i) => {
|
|
250
344
|
console.log(` ${i + 1}. ${task.title} (${task.priority}, ${task.assignedAgent})`);
|
|
251
345
|
});
|
|
@@ -275,14 +369,15 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
|
275
369
|
},
|
|
276
370
|
subagentTasks,
|
|
277
371
|
taskInfo: {
|
|
278
|
-
title:
|
|
279
|
-
description:
|
|
280
|
-
quality: qualityLevel
|
|
372
|
+
title: resolvedInput.title,
|
|
373
|
+
description: resolvedInput.description,
|
|
374
|
+
quality: qualityLevel,
|
|
375
|
+
domain: researchContext?.domain
|
|
281
376
|
}
|
|
282
377
|
}));
|
|
283
378
|
}
|
|
284
379
|
else {
|
|
285
|
-
console.log(`\n📋 ${
|
|
380
|
+
console.log(`\n📋 ${resolvedInput.title} - ${subTasks.length} 个子任务已创建`);
|
|
286
381
|
console.log(`🎯 执行模式:${executionMode}`);
|
|
287
382
|
console.log(` 质量级别:${qualityLevel}`);
|
|
288
383
|
console.log('\n🚀 等待 Skill 执行任务...');
|
|
@@ -292,7 +387,7 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
|
292
387
|
/**
|
|
293
388
|
* 处理自动解析 (fallback,无 AI 时使用)
|
|
294
389
|
*/
|
|
295
|
-
async function handleAutoParse(input, options, stateManager, state) {
|
|
390
|
+
async function handleAutoParse(input, options, stateManager, state, basePath, omPath) {
|
|
296
391
|
// 构建任务内容
|
|
297
392
|
let taskContent = input;
|
|
298
393
|
if (options.title || options.description) {
|
|
@@ -302,7 +397,46 @@ async function handleAutoParse(input, options, stateManager, state) {
|
|
|
302
397
|
const docs = options.docs ? `\n文档要求: ${options.docs}` : '';
|
|
303
398
|
taskContent = `# ${title}\n\n${description}${techStack}${docs}`;
|
|
304
399
|
}
|
|
400
|
+
// 如果没有提供输入,先检测研究上下文,再检测 TASK.md
|
|
305
401
|
if (!taskContent) {
|
|
402
|
+
// 优先检测研究上下文
|
|
403
|
+
const { context: researchContext, report: researchReport } = await loadResearchContext(options.researchContext, basePath, omPath);
|
|
404
|
+
if (researchContext) {
|
|
405
|
+
// 基于研究上下文构建 ParsedTask
|
|
406
|
+
const parsedTitle = researchContext.topic || researchContext.domain || '未命名任务';
|
|
407
|
+
const researchGoals = researchContext.goals || [];
|
|
408
|
+
if (!options.json) {
|
|
409
|
+
console.log(`\n🔬 检测到研究领域: ${researchContext.domain}`);
|
|
410
|
+
console.log(` 研究目标: ${researchGoals.length > 0 ? researchGoals.join(', ') : '待拆分'}`);
|
|
411
|
+
console.log('\n🔍 基于研究结果解析任务...');
|
|
412
|
+
}
|
|
413
|
+
const parsedTask = {
|
|
414
|
+
title: parsedTitle,
|
|
415
|
+
description: researchGoals.length > 0 ? researchGoals.join('\n') : '',
|
|
416
|
+
goals: researchGoals,
|
|
417
|
+
goalTypes: researchGoals.map(() => 'development'),
|
|
418
|
+
constraints: researchContext.constraints || [],
|
|
419
|
+
deliverables: researchContext.deliverables || [],
|
|
420
|
+
rawContent: researchReport || ''
|
|
421
|
+
};
|
|
422
|
+
if (!options.json) {
|
|
423
|
+
console.log(`\n📋 任务: ${parsedTask.title}`);
|
|
424
|
+
console.log(` 目标: ${parsedTask.goals.join(', ') || '(待 AI 补充)'}`);
|
|
425
|
+
console.log('\n🔧 拆解任务...');
|
|
426
|
+
}
|
|
427
|
+
let qualityConfig;
|
|
428
|
+
if (options.quality) {
|
|
429
|
+
const qualityLevel = options.quality.toLowerCase();
|
|
430
|
+
if (['strict', 'balanced', 'fast'].includes(qualityLevel)) {
|
|
431
|
+
qualityConfig = index_js_1.QUALITY_PRESETS[qualityLevel];
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const planner = new task_planner_js_1.TaskPlanner();
|
|
435
|
+
const subTasks = planner.breakdown(parsedTask, {}, qualityConfig, researchReport || undefined);
|
|
436
|
+
await finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, parsedTask.title);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
// 无研究上下文,回退到 TASK.md
|
|
306
440
|
const defaultPath = path.join(process.cwd(), 'TASK.md');
|
|
307
441
|
try {
|
|
308
442
|
taskContent = await fs.readFile(defaultPath, 'utf-8');
|
|
@@ -355,6 +489,13 @@ async function handleAutoParse(input, options, stateManager, state) {
|
|
|
355
489
|
}
|
|
356
490
|
const planner = new task_planner_js_1.TaskPlanner();
|
|
357
491
|
const subTasks = planner.breakdown(parsedTask, {}, qualityConfig);
|
|
492
|
+
await finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, parsedTask.title);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* 公共函数:创建任务、更新状态、处理审批、输出结果
|
|
496
|
+
* 被 handleTasksJson 和 handleAutoParse 共用
|
|
497
|
+
*/
|
|
498
|
+
async function finalizeAndOutput(subTasks, options, stateManager, state, qualityConfig, taskTitle) {
|
|
358
499
|
// 创建任务,并建立 TaskPlanner ID → StateManager ID 的映射
|
|
359
500
|
const taskIdMap = new Map();
|
|
360
501
|
for (const subTask of subTasks) {
|
|
@@ -401,13 +542,7 @@ async function handleAutoParse(input, options, stateManager, state) {
|
|
|
401
542
|
approvalType: 'plan',
|
|
402
543
|
message: '等待计划审批',
|
|
403
544
|
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
|
-
}
|
|
545
|
+
taskInfo: { title: taskTitle, quality: options.quality }
|
|
411
546
|
}));
|
|
412
547
|
}
|
|
413
548
|
else {
|
|
@@ -440,13 +575,7 @@ async function handleAutoParse(input, options, stateManager, state) {
|
|
|
440
575
|
pending: allTasks.filter(t => t.status === 'pending').length
|
|
441
576
|
},
|
|
442
577
|
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
|
-
}
|
|
578
|
+
taskInfo: { title: taskTitle, quality: options.quality }
|
|
450
579
|
}));
|
|
451
580
|
}
|
|
452
581
|
else {
|
|
@@ -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
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
64
|
-
const
|
|
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}/${
|
|
90
|
-
: `没有可执行任务 (${completed}/${
|
|
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:
|
|
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:
|
|
108
|
-
completed:
|
|
109
|
-
remaining:
|
|
110
|
-
|
|
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(`
|
|
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
|
*
|
|
@@ -47,4 +59,20 @@ export declare class AIReviewer {
|
|
|
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
|
}
|