openmatrix 0.1.55 → 0.1.57
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 +24 -0
- package/dist/agents/impl/researcher-agent.d.ts +10 -1
- package/dist/agents/impl/researcher-agent.js +163 -41
- package/dist/cli/commands/brainstorm.js +47 -3
- package/dist/cli/commands/complete.js +55 -48
- package/dist/cli/commands/research.d.ts +2 -0
- package/dist/cli/commands/research.js +270 -0
- package/dist/cli/commands/start.js +5 -1
- package/dist/cli/commands/step.js +61 -47
- package/dist/cli/index.js +6 -0
- package/dist/orchestrator/phase-executor.js +14 -0
- package/dist/storage/state-manager.d.ts +16 -0
- package/dist/storage/state-manager.js +58 -6
- package/dist/types/index.d.ts +37 -1
- package/package.json +1 -1
- package/skills/auto.md +22 -15
- package/skills/brainstorm.md +86 -20
- package/skills/om.md +47 -101
- package/skills/openmatrix.md +97 -190
- package/skills/research.md +258 -0
- package/skills/start.md +52 -22
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.researchCommand = void 0;
|
|
37
|
+
// src/cli/commands/research.ts
|
|
38
|
+
const commander_1 = require("commander");
|
|
39
|
+
const gitignore_js_1 = require("../../utils/gitignore.js");
|
|
40
|
+
const fs = __importStar(require("fs/promises"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
/**
|
|
43
|
+
* 生成并行研究 Agent 配置
|
|
44
|
+
*/
|
|
45
|
+
function generateAgents(topic, domain, aspects) {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
role: 'domain_researcher',
|
|
49
|
+
focus: `搜索 ${domain} 领域的核心概念、行业标准、最佳实践。关键词: ${aspects.slice(0, 4).join(', ')}`,
|
|
50
|
+
status: 'pending'
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
role: 'tech_explorer',
|
|
54
|
+
focus: `搜索 ${domain} 的主流技术方案、开源项目、技术栈选择、架构模式`,
|
|
55
|
+
status: 'pending'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
role: 'scenario_analyst',
|
|
59
|
+
focus: `结合用户具体需求 "${topic}",分析实际应用场景、常见挑战、经验教训`,
|
|
60
|
+
status: 'pending'
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
exports.researchCommand = new commander_1.Command('research')
|
|
65
|
+
.description('领域调研和问题探索 - 为后续任务提供知识基础')
|
|
66
|
+
.argument('[topic]', '研究主题')
|
|
67
|
+
.option('--json', '输出 JSON 格式 (供 Skill 解析)')
|
|
68
|
+
.option('--confirm', '确认进入深度研究 (从 Skill 传入)')
|
|
69
|
+
.option('--complete', '标记研究完成,生成报告和任务上下文')
|
|
70
|
+
.option('--results <json>', '研究结果 JSON (从 Skill 传入)')
|
|
71
|
+
.action(async (topic, options) => {
|
|
72
|
+
const basePath = process.cwd();
|
|
73
|
+
const omPath = path.join(basePath, '.openmatrix');
|
|
74
|
+
const researchPath = path.join(omPath, 'research');
|
|
75
|
+
const knowledgePath = path.join(researchPath, 'knowledge');
|
|
76
|
+
// 确保目录存在
|
|
77
|
+
await fs.mkdir(omPath, { recursive: true });
|
|
78
|
+
await fs.mkdir(researchPath, { recursive: true });
|
|
79
|
+
await fs.mkdir(knowledgePath, { recursive: true });
|
|
80
|
+
// 确保 .openmatrix 被 git 忽略
|
|
81
|
+
await (0, gitignore_js_1.ensureOpenmatrixGitignore)(basePath);
|
|
82
|
+
const sessionPath = path.join(researchPath, 'session.json');
|
|
83
|
+
// ========== --complete 模式: 研究完成,汇总结果 ==========
|
|
84
|
+
if (options.complete) {
|
|
85
|
+
try {
|
|
86
|
+
const sessionData = await fs.readFile(sessionPath, 'utf-8');
|
|
87
|
+
const session = JSON.parse(sessionData);
|
|
88
|
+
// 如果传入了结果,合并
|
|
89
|
+
if (options.results) {
|
|
90
|
+
try {
|
|
91
|
+
const results = JSON.parse(options.results);
|
|
92
|
+
if (results.agents)
|
|
93
|
+
session.agents = results.agents;
|
|
94
|
+
if (results.report)
|
|
95
|
+
session.report = results.report;
|
|
96
|
+
if (results.knowledge)
|
|
97
|
+
session.knowledge = [...session.knowledge, ...results.knowledge];
|
|
98
|
+
if (results.context)
|
|
99
|
+
session.context = results.context;
|
|
100
|
+
if (results.domainQuestions)
|
|
101
|
+
session.domainQuestions = results.domainQuestions;
|
|
102
|
+
if (results.answers)
|
|
103
|
+
session.answers = { ...session.answers, ...results.answers };
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// 忽略解析错误
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
session.status = 'completed';
|
|
110
|
+
session.completedAt = new Date().toISOString();
|
|
111
|
+
await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
|
|
112
|
+
// 写入研究报告
|
|
113
|
+
if (session.report) {
|
|
114
|
+
await fs.writeFile(path.join(researchPath, 'RESEARCH.md'), session.report, 'utf-8');
|
|
115
|
+
}
|
|
116
|
+
// 写入知识条目
|
|
117
|
+
for (let i = 0; i < session.knowledge.length; i++) {
|
|
118
|
+
await fs.writeFile(path.join(knowledgePath, `finding-${i + 1}.md`), session.knowledge[i], 'utf-8');
|
|
119
|
+
}
|
|
120
|
+
// 写入任务上下文 (供 start 使用)
|
|
121
|
+
const taskContext = session.context || { goals: [], constraints: [], deliverables: [] };
|
|
122
|
+
await fs.writeFile(path.join(researchPath, 'context.json'), JSON.stringify({
|
|
123
|
+
topic: session.topic,
|
|
124
|
+
domain: session.domain,
|
|
125
|
+
...taskContext,
|
|
126
|
+
reportPath: '.openmatrix/research/RESEARCH.md',
|
|
127
|
+
knowledgePath: '.openmatrix/research/knowledge/'
|
|
128
|
+
}, null, 2), 'utf-8');
|
|
129
|
+
if (options.json) {
|
|
130
|
+
console.log(JSON.stringify({
|
|
131
|
+
status: 'completed',
|
|
132
|
+
message: '研究完成',
|
|
133
|
+
topic: session.topic,
|
|
134
|
+
domain: session.domain,
|
|
135
|
+
report: session.report,
|
|
136
|
+
knowledge: session.knowledge,
|
|
137
|
+
context: taskContext,
|
|
138
|
+
reportPath: '.openmatrix/research/RESEARCH.md',
|
|
139
|
+
hint: '研究结果已保存,可以使用 /om:start 开始执行任务'
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log('研究完成!');
|
|
144
|
+
console.log(` 主题: ${session.topic}`);
|
|
145
|
+
console.log(` 领域: ${session.domain}`);
|
|
146
|
+
console.log(` 知识条目: ${session.knowledge.length} 个`);
|
|
147
|
+
console.log('\n使用 /om:start 基于研究结果开始任务');
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
if (options.json) {
|
|
153
|
+
console.log(JSON.stringify({ status: 'error', message: '没有进行中的研究会话' }));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
console.log('没有进行中的研究会话');
|
|
157
|
+
console.log(' 使用 openmatrix research <topic> 开始新的研究');
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// ========== --confirm 模式: 用户确认后进入深度研究 ==========
|
|
163
|
+
if (options.confirm) {
|
|
164
|
+
try {
|
|
165
|
+
const sessionData = await fs.readFile(sessionPath, 'utf-8');
|
|
166
|
+
const session = JSON.parse(sessionData);
|
|
167
|
+
if (session.status !== 'preview') {
|
|
168
|
+
if (options.json) {
|
|
169
|
+
console.log(JSON.stringify({ status: 'error', message: `当前状态为 ${session.status},无法确认` }));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.log(`当前状态为 ${session.status},无法确认`);
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// 生成研究 Agent
|
|
177
|
+
const agents = generateAgents(session.topic, session.domain, session.aspects);
|
|
178
|
+
session.status = 'researching';
|
|
179
|
+
session.agents = agents;
|
|
180
|
+
await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
|
|
181
|
+
if (options.json) {
|
|
182
|
+
console.log(JSON.stringify({
|
|
183
|
+
status: 'researching',
|
|
184
|
+
message: '开始深度研究',
|
|
185
|
+
topic: session.topic,
|
|
186
|
+
domain: session.domain,
|
|
187
|
+
aspects: session.aspects,
|
|
188
|
+
agents: agents.map(a => ({ role: a.role, focus: a.focus, status: a.status })),
|
|
189
|
+
hint: '使用 Agent 工具并行执行研究'
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
console.log('\n开始深度研究...\n');
|
|
194
|
+
console.log(` 主题: ${session.topic}`);
|
|
195
|
+
console.log(` 领域: ${session.domain}`);
|
|
196
|
+
console.log('\n研究 Agent:');
|
|
197
|
+
agents.forEach((a, i) => {
|
|
198
|
+
console.log(` ${i + 1}. [${a.role}] ${a.focus}`);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
if (options.json) {
|
|
205
|
+
console.log(JSON.stringify({ status: 'error', message: '没有待确认的研究会话' }));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.log('没有待确认的研究会话');
|
|
209
|
+
}
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// ========== 初始模式: 创建会话,等待 AI 分析 ==========
|
|
214
|
+
let researchTopic = topic;
|
|
215
|
+
if (!researchTopic) {
|
|
216
|
+
const defaultPath = path.join(basePath, 'RESEARCH.md');
|
|
217
|
+
try {
|
|
218
|
+
const content = await fs.readFile(defaultPath, 'utf-8');
|
|
219
|
+
const lines = content.split('\n');
|
|
220
|
+
for (const line of lines) {
|
|
221
|
+
const match = line.match(/^#\s+(.+)$/);
|
|
222
|
+
if (match) {
|
|
223
|
+
researchTopic = match[1].trim();
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!researchTopic)
|
|
228
|
+
researchTopic = content.slice(0, 100).trim();
|
|
229
|
+
if (!options.json)
|
|
230
|
+
console.log(`读取研究文件: ${defaultPath}`);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
if (options.json) {
|
|
234
|
+
console.log(JSON.stringify({ status: 'error', message: '请提供研究主题' }));
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
console.log('请提供研究主题');
|
|
238
|
+
console.log(' 用法: openmatrix research <topic>');
|
|
239
|
+
console.log(' 或创建 RESEARCH.md 文件');
|
|
240
|
+
}
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// 创建初始会话 - 领域信息由 Agent 分析后更新
|
|
245
|
+
const session = {
|
|
246
|
+
status: 'initialized',
|
|
247
|
+
topic: researchTopic,
|
|
248
|
+
domain: '',
|
|
249
|
+
aspects: [],
|
|
250
|
+
estimatedQuestions: 0,
|
|
251
|
+
agents: [],
|
|
252
|
+
domainQuestions: [],
|
|
253
|
+
answers: {},
|
|
254
|
+
knowledge: [],
|
|
255
|
+
createdAt: new Date().toISOString()
|
|
256
|
+
};
|
|
257
|
+
await fs.writeFile(sessionPath, JSON.stringify(session, null, 2));
|
|
258
|
+
if (options.json) {
|
|
259
|
+
console.log(JSON.stringify({
|
|
260
|
+
status: 'initialized',
|
|
261
|
+
message: '研究会话已创建,需要 AI 分析领域',
|
|
262
|
+
topic: researchTopic,
|
|
263
|
+
hint: '请使用 Agent 分析主题,识别领域和调研方向,然后更新会话并展示给用户确认'
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
console.log(`\n研究主题: ${researchTopic}`);
|
|
268
|
+
console.log('使用 /om:research 技能启动 AI 分析');
|
|
269
|
+
}
|
|
270
|
+
});
|
|
@@ -164,7 +164,11 @@ async function handleTasksJson(options, stateManager, state, omPath) {
|
|
|
164
164
|
};
|
|
165
165
|
// 解析质量配置
|
|
166
166
|
const qualityLevel = tasksInput.quality || options.quality || 'balanced';
|
|
167
|
-
const qualityConfig = index_js_1.QUALITY_PRESETS[qualityLevel.toLowerCase()] || index_js_1.QUALITY_PRESETS.balanced;
|
|
167
|
+
const qualityConfig = { ...(index_js_1.QUALITY_PRESETS[qualityLevel.toLowerCase()] || index_js_1.QUALITY_PRESETS.balanced) };
|
|
168
|
+
// E2E 测试覆盖(用户在 Skill 问答中选择启用)
|
|
169
|
+
if (tasksInput.e2eTests) {
|
|
170
|
+
qualityConfig.e2eTests = true;
|
|
171
|
+
}
|
|
168
172
|
if (!options.json) {
|
|
169
173
|
console.log(`\n📋 任务: ${parsedTask.title}`);
|
|
170
174
|
console.log(` 目标: ${parsedTask.goals.join(', ')}`);
|
|
@@ -35,68 +35,82 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.stepCommand = void 0;
|
|
37
37
|
// src/cli/commands/step.ts
|
|
38
|
+
// 循环状态持久化 - 防止上下文压缩导致循环丢失
|
|
38
39
|
const commander_1 = require("commander");
|
|
39
40
|
const state_manager_js_1 = require("../../storage/state-manager.js");
|
|
40
|
-
const approval_manager_js_1 = require("../../orchestrator/approval-manager.js");
|
|
41
|
-
const executor_js_1 = require("../../orchestrator/executor.js");
|
|
42
41
|
const path = __importStar(require("path"));
|
|
43
42
|
exports.stepCommand = new commander_1.Command('step')
|
|
44
|
-
.description('
|
|
45
|
-
.option('--json', 'JSON
|
|
43
|
+
.description('获取下一个待执行任务(持久化循环状态)')
|
|
44
|
+
.option('--json', '输出 JSON 格式')
|
|
46
45
|
.action(async (options) => {
|
|
47
46
|
const basePath = process.cwd();
|
|
48
47
|
const omPath = path.join(basePath, '.openmatrix');
|
|
49
48
|
const stateManager = new state_manager_js_1.StateManager(omPath);
|
|
50
49
|
await stateManager.initialize();
|
|
51
50
|
const state = await stateManager.getState();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
status: 'error',
|
|
56
|
-
message: '没有正在执行的任务',
|
|
57
|
-
currentState: state.status
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
console.log('⚠️ 没有正在执行的任务');
|
|
62
|
-
console.log(` 当前状态: ${state.status}`);
|
|
63
|
-
}
|
|
51
|
+
// 检查是否已完成
|
|
52
|
+
if (state.status === 'completed') {
|
|
53
|
+
console.log(JSON.stringify({ status: 'done', message: '所有任务已完成' }));
|
|
64
54
|
return;
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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');
|
|
61
|
+
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
|
+
};
|
|
73
|
+
const allDone = completed + stats.failed === total;
|
|
74
|
+
await stateManager.updateState({
|
|
75
|
+
statistics: stats,
|
|
76
|
+
status: allDone ? 'completed' : 'running',
|
|
77
|
+
currentPhase: allDone ? 'completed' : 'execution'
|
|
78
|
+
});
|
|
77
79
|
console.log(JSON.stringify({
|
|
78
|
-
status:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
description: t.description,
|
|
84
|
-
prompt: t.prompt,
|
|
85
|
-
isolation: t.isolation,
|
|
86
|
-
taskId: t.taskId,
|
|
87
|
-
agentType: t.agentType,
|
|
88
|
-
timeout: t.timeout
|
|
89
|
-
}))
|
|
80
|
+
status: allDone ? 'done' : 'blocked',
|
|
81
|
+
statistics: stats,
|
|
82
|
+
message: allDone
|
|
83
|
+
? `所有任务已完成 (${completed}/${total})`
|
|
84
|
+
: `没有可执行任务 (${completed}/${total} 完成, ${stats.failed} 失败, ${stats.pending} 等待)`
|
|
90
85
|
}));
|
|
86
|
+
return;
|
|
91
87
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
// 输出下一个任务信息
|
|
89
|
+
const result = {
|
|
90
|
+
status: 'next',
|
|
91
|
+
task: {
|
|
92
|
+
id: nextTask.id,
|
|
93
|
+
title: nextTask.title,
|
|
94
|
+
description: nextTask.description,
|
|
95
|
+
status: nextTask.status,
|
|
96
|
+
assignedAgent: nextTask.assignedAgent,
|
|
97
|
+
dependencies: nextTask.dependencies,
|
|
98
|
+
acceptanceCriteria: nextTask.acceptanceCriteria
|
|
99
|
+
},
|
|
100
|
+
statistics: {
|
|
101
|
+
total: allTasks.length,
|
|
102
|
+
completed: allTasks.filter(t => t.status === 'completed').length,
|
|
103
|
+
remaining: allTasks.filter(t => t.status === 'pending' ||
|
|
104
|
+
t.status === 'scheduled' ||
|
|
105
|
+
t.status === 'in_progress').length,
|
|
106
|
+
failed: allTasks.filter(t => t.status === 'failed').length
|
|
100
107
|
}
|
|
108
|
+
};
|
|
109
|
+
if (options.json) {
|
|
110
|
+
console.log(JSON.stringify(result, null, 2));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.log(`📌 下一个任务: ${nextTask.id} - ${nextTask.title}`);
|
|
114
|
+
console.log(` 进度: ${result.statistics.completed}/${result.statistics.total} 完成, ${result.statistics.remaining} 剩余`);
|
|
101
115
|
}
|
|
102
116
|
});
|
package/dist/cli/index.js
CHANGED
|
@@ -15,6 +15,9 @@ const check_js_1 = require("./commands/check.js");
|
|
|
15
15
|
const check_gitignore_js_1 = require("./commands/check-gitignore.js");
|
|
16
16
|
const analyze_js_1 = require("./commands/analyze.js");
|
|
17
17
|
const brainstorm_js_1 = require("./commands/brainstorm.js");
|
|
18
|
+
const research_js_1 = require("./commands/research.js");
|
|
19
|
+
const complete_js_1 = require("./commands/complete.js");
|
|
20
|
+
const step_js_1 = require("./commands/step.js");
|
|
18
21
|
const program = new commander_1.Command();
|
|
19
22
|
program
|
|
20
23
|
.name('openmatrix')
|
|
@@ -29,10 +32,13 @@ program.addCommand(retry_js_1.retryCommand);
|
|
|
29
32
|
program.addCommand(report_js_1.reportCommand);
|
|
30
33
|
program.addCommand(meeting_js_1.meetingCommand);
|
|
31
34
|
program.addCommand(auto_js_1.autoCommand);
|
|
35
|
+
program.addCommand(complete_js_1.completeCommand);
|
|
36
|
+
program.addCommand(step_js_1.stepCommand);
|
|
32
37
|
program.addCommand(install_skills_js_1.installSkillsCommand);
|
|
33
38
|
program.addCommand(check_js_1.checkCommand);
|
|
34
39
|
program.addCommand(check_gitignore_js_1.checkGitignoreCommand);
|
|
35
40
|
program.addCommand(analyze_js_1.analyzeCommand);
|
|
36
41
|
program.addCommand(brainstorm_js_1.brainstormCommand);
|
|
42
|
+
program.addCommand(research_js_1.researchCommand);
|
|
37
43
|
// 默认帮助
|
|
38
44
|
program.parse();
|
|
@@ -702,6 +702,13 @@ ACCEPT_FAILED
|
|
|
702
702
|
updates.status = 'completed';
|
|
703
703
|
}
|
|
704
704
|
await this.stateManager.updateTask(task.id, updates);
|
|
705
|
+
// 持久化 Phase 结果到磁盘
|
|
706
|
+
await this.stateManager.savePhaseResult(task.id, phase, {
|
|
707
|
+
success: true,
|
|
708
|
+
output: result.output,
|
|
709
|
+
phaseStatus: 'completed',
|
|
710
|
+
completedAt: now
|
|
711
|
+
});
|
|
705
712
|
// 自动提交代码
|
|
706
713
|
if (this.runId) {
|
|
707
714
|
try {
|
|
@@ -740,6 +747,13 @@ ACCEPT_FAILED
|
|
|
740
747
|
status: 'failed',
|
|
741
748
|
error: result.error || `${phase} phase failed`
|
|
742
749
|
});
|
|
750
|
+
// 持久化失败结果
|
|
751
|
+
await this.stateManager.savePhaseResult(task.id, phase, {
|
|
752
|
+
success: false,
|
|
753
|
+
error: result.error || `${phase} phase failed`,
|
|
754
|
+
phaseStatus: 'failed',
|
|
755
|
+
failedAt: now
|
|
756
|
+
});
|
|
743
757
|
return {
|
|
744
758
|
phase,
|
|
745
759
|
success: false,
|
|
@@ -17,6 +17,22 @@ export declare class StateManager {
|
|
|
17
17
|
getTask(taskId: string): Promise<Task | null>;
|
|
18
18
|
updateTask(taskId: string, updates: Partial<Task>): Promise<void>;
|
|
19
19
|
listTasks(): Promise<Task[]>;
|
|
20
|
+
/**
|
|
21
|
+
* 保存 Phase 结果到任务子目录
|
|
22
|
+
*/
|
|
23
|
+
savePhaseResult(taskId: string, phase: string, result: Record<string, unknown>): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* 读取 Phase 结果
|
|
26
|
+
*/
|
|
27
|
+
getPhaseResult(taskId: string, phase: string): Promise<Record<string, unknown> | null>;
|
|
28
|
+
/**
|
|
29
|
+
* 保存 Agent 上下文到 context.md
|
|
30
|
+
*/
|
|
31
|
+
saveTaskContext(taskId: string, content: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* 读取 Agent 上下文
|
|
34
|
+
*/
|
|
35
|
+
getTaskContext(taskId: string): Promise<string | null>;
|
|
20
36
|
private updateTaskStatistics;
|
|
21
37
|
private generateRunId;
|
|
22
38
|
private generateTaskId;
|
|
@@ -74,7 +74,9 @@ class StateManager {
|
|
|
74
74
|
createdAt: now,
|
|
75
75
|
updatedAt: now
|
|
76
76
|
};
|
|
77
|
-
await this.store.writeJson(`tasks/${taskId}.json`, task);
|
|
77
|
+
await this.store.writeJson(`tasks/${taskId}/task.json`, task);
|
|
78
|
+
// Create artifacts subdirectory
|
|
79
|
+
await this.store.ensureDir(`tasks/${taskId}/artifacts`);
|
|
78
80
|
// Update statistics
|
|
79
81
|
const state = await this.getState();
|
|
80
82
|
await this.updateState({
|
|
@@ -87,7 +89,12 @@ class StateManager {
|
|
|
87
89
|
return task;
|
|
88
90
|
}
|
|
89
91
|
async getTask(taskId) {
|
|
90
|
-
|
|
92
|
+
// Try subdirectory structure first, fall back to flat file
|
|
93
|
+
let task = await this.store.readJson(`tasks/${taskId}/task.json`);
|
|
94
|
+
if (!task) {
|
|
95
|
+
task = await this.store.readJson(`tasks/${taskId}.json`);
|
|
96
|
+
}
|
|
97
|
+
return task;
|
|
91
98
|
}
|
|
92
99
|
async updateTask(taskId, updates) {
|
|
93
100
|
const task = await this.getTask(taskId);
|
|
@@ -99,22 +106,67 @@ class StateManager {
|
|
|
99
106
|
...updates,
|
|
100
107
|
updatedAt: new Date().toISOString()
|
|
101
108
|
};
|
|
102
|
-
|
|
109
|
+
// Always write to subdirectory structure
|
|
110
|
+
await this.store.writeJson(`tasks/${taskId}/task.json`, updatedTask);
|
|
103
111
|
// Update statistics if status changed
|
|
104
112
|
if (updates.status && updates.status !== oldStatus) {
|
|
105
113
|
await this.updateTaskStatistics(oldStatus, updates.status);
|
|
106
114
|
}
|
|
107
115
|
}
|
|
108
116
|
async listTasks() {
|
|
109
|
-
const files = await this.store.listFiles('tasks');
|
|
110
117
|
const tasks = [];
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
// Read from subdirectory structure: tasks/TASK-XXX/task.json
|
|
119
|
+
const dirs = await this.store.listDirs('tasks');
|
|
120
|
+
for (const dir of dirs) {
|
|
121
|
+
const task = await this.store.readJson(`tasks/${dir}/task.json`);
|
|
113
122
|
if (task)
|
|
114
123
|
tasks.push(task);
|
|
115
124
|
}
|
|
125
|
+
// Also check flat files (backward compat)
|
|
126
|
+
const files = await this.store.listFiles('tasks');
|
|
127
|
+
for (const file of files) {
|
|
128
|
+
if (!file.endsWith('.json'))
|
|
129
|
+
continue;
|
|
130
|
+
const task = await this.store.readJson(`tasks/${file}`);
|
|
131
|
+
if (task) {
|
|
132
|
+
// Avoid duplicate if already found in subdirectory
|
|
133
|
+
if (!tasks.some(t => t.id === task.id)) {
|
|
134
|
+
tasks.push(task);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
116
138
|
return tasks.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
117
139
|
}
|
|
140
|
+
// ============ Task Artifact Methods ============
|
|
141
|
+
/**
|
|
142
|
+
* 保存 Phase 结果到任务子目录
|
|
143
|
+
*/
|
|
144
|
+
async savePhaseResult(taskId, phase, result) {
|
|
145
|
+
await this.store.writeJson(`tasks/${taskId}/${phase}.json`, {
|
|
146
|
+
taskId,
|
|
147
|
+
phase,
|
|
148
|
+
timestamp: new Date().toISOString(),
|
|
149
|
+
...result
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 读取 Phase 结果
|
|
154
|
+
*/
|
|
155
|
+
async getPhaseResult(taskId, phase) {
|
|
156
|
+
return await this.store.readJson(`tasks/${taskId}/${phase}.json`);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 保存 Agent 上下文到 context.md
|
|
160
|
+
*/
|
|
161
|
+
async saveTaskContext(taskId, content) {
|
|
162
|
+
await this.store.writeMarkdown(`tasks/${taskId}/context.md`, content);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 读取 Agent 上下文
|
|
166
|
+
*/
|
|
167
|
+
async getTaskContext(taskId) {
|
|
168
|
+
return await this.store.readMarkdown(`tasks/${taskId}/context.md`);
|
|
169
|
+
}
|
|
118
170
|
async updateTaskStatistics(oldStatus, newStatus) {
|
|
119
171
|
const state = await this.getState();
|
|
120
172
|
const stats = { ...state.statistics };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type TaskStatus = 'pending' | 'scheduled' | 'in_progress' | 'blocked' | 'waiting' | 'verify' | 'accept' | 'completed' | 'failed' | 'retry_queue';
|
|
2
2
|
export type TaskPriority = 'P0' | 'P1' | 'P2' | 'P3';
|
|
3
|
+
export type ResearchMode = 'domain' | 'tech' | 'problem';
|
|
3
4
|
export interface TaskPhase {
|
|
4
5
|
status: TaskStatus;
|
|
5
6
|
duration: number | null;
|
|
@@ -75,7 +76,7 @@ export interface GlobalState {
|
|
|
75
76
|
version: string;
|
|
76
77
|
runId: string;
|
|
77
78
|
status: RunStatus;
|
|
78
|
-
currentPhase: 'planning' | 'execution' | 'verification' | 'acceptance';
|
|
79
|
+
currentPhase: 'planning' | 'execution' | 'verification' | 'acceptance' | 'completed';
|
|
79
80
|
startedAt: string;
|
|
80
81
|
config: AppConfig;
|
|
81
82
|
statistics: {
|
|
@@ -201,3 +202,38 @@ export interface ParsedTask {
|
|
|
201
202
|
deliverables: string[];
|
|
202
203
|
rawContent: string;
|
|
203
204
|
}
|
|
205
|
+
export interface ResearchAgentConfig {
|
|
206
|
+
role: string;
|
|
207
|
+
focus: string;
|
|
208
|
+
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
209
|
+
result?: string;
|
|
210
|
+
}
|
|
211
|
+
export interface ResearchQuestion {
|
|
212
|
+
id: string;
|
|
213
|
+
question: string;
|
|
214
|
+
header: string;
|
|
215
|
+
options: Array<{
|
|
216
|
+
label: string;
|
|
217
|
+
description: string;
|
|
218
|
+
}>;
|
|
219
|
+
multiSelect: boolean;
|
|
220
|
+
}
|
|
221
|
+
export interface ResearchSession {
|
|
222
|
+
status: 'initialized' | 'preview' | 'researching' | 'questioning' | 'completed';
|
|
223
|
+
topic: string;
|
|
224
|
+
domain: string;
|
|
225
|
+
aspects: string[];
|
|
226
|
+
estimatedQuestions: number;
|
|
227
|
+
agents: ResearchAgentConfig[];
|
|
228
|
+
domainQuestions: ResearchQuestion[];
|
|
229
|
+
answers: Record<string, string | string[]>;
|
|
230
|
+
report?: string;
|
|
231
|
+
knowledge: string[];
|
|
232
|
+
context?: {
|
|
233
|
+
goals: string[];
|
|
234
|
+
constraints: string[];
|
|
235
|
+
deliverables: string[];
|
|
236
|
+
};
|
|
237
|
+
createdAt: string;
|
|
238
|
+
completedAt?: string;
|
|
239
|
+
}
|