openmatrix 0.1.63 → 0.1.65
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/agent-runner.d.ts +1 -1
- package/dist/agents/agent-runner.js +22 -13
- package/dist/cli/commands/brainstorm.js +14 -18
- package/dist/cli/commands/complete.js +35 -2
- package/dist/cli/commands/start.js +6 -3
- package/dist/cli/commands/step.js +7 -1
- package/dist/orchestrator/executor.js +1 -1
- package/dist/orchestrator/git-commit-manager.js +12 -2
- package/dist/orchestrator/phase-executor.d.ts +3 -0
- package/dist/orchestrator/phase-executor.js +445 -349
- package/dist/orchestrator/scheduler.js +1 -1
- package/dist/storage/file-store.d.ts +9 -1
- package/dist/storage/file-store.js +24 -9
- package/dist/storage/state-manager.js +80 -2
- package/dist/types/index.d.ts +6 -0
- package/package.json +1 -1
- package/skills/auto.md +14 -2
- package/skills/meeting.md +15 -0
- package/skills/start.md +10 -1
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.AgentRunner = void 0;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
37
|
+
const fs = __importStar(require("fs/promises"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
/**
|
|
40
40
|
* AgentRunner - 使用 Subagent 执行任务
|
|
@@ -57,7 +57,7 @@ class AgentRunner {
|
|
|
57
57
|
this.approvalManager = approvalManager;
|
|
58
58
|
this.config = {
|
|
59
59
|
maxConcurrent: 3,
|
|
60
|
-
taskTimeout:
|
|
60
|
+
taskTimeout: 600000, // 10 分钟
|
|
61
61
|
...config
|
|
62
62
|
};
|
|
63
63
|
}
|
|
@@ -80,7 +80,7 @@ class AgentRunner {
|
|
|
80
80
|
*/
|
|
81
81
|
async prepareSubagentTask(task) {
|
|
82
82
|
const subagentType = this.mapAgentType(task.assignedAgent);
|
|
83
|
-
const prompt = this.buildExecutionPrompt(task);
|
|
83
|
+
const prompt = await this.buildExecutionPrompt(task);
|
|
84
84
|
const needsIsolation = this.needsIsolation(task);
|
|
85
85
|
console.log(`🤖 Preparing ${task.assignedAgent} subagent for task ${task.id}`);
|
|
86
86
|
return {
|
|
@@ -133,10 +133,10 @@ class AgentRunner {
|
|
|
133
133
|
/**
|
|
134
134
|
* 构建完整的执行提示词
|
|
135
135
|
*/
|
|
136
|
-
buildExecutionPrompt(task) {
|
|
136
|
+
async buildExecutionPrompt(task) {
|
|
137
137
|
const agentPrompt = this.buildAgentPrompt(task);
|
|
138
138
|
const phaseContext = this.buildPhaseContext(task);
|
|
139
|
-
const accumulatedContext = this.buildAccumulatedContext(task);
|
|
139
|
+
const accumulatedContext = await this.buildAccumulatedContext(task);
|
|
140
140
|
return `# 任务执行
|
|
141
141
|
|
|
142
142
|
## 任务信息
|
|
@@ -177,23 +177,32 @@ ${agentPrompt.instructions}
|
|
|
177
177
|
*
|
|
178
178
|
* 读取所有已完成任务的 context.md,为当前 Agent 提供前序 Agent 的决策和知识
|
|
179
179
|
*/
|
|
180
|
-
buildAccumulatedContext(currentTask) {
|
|
180
|
+
async buildAccumulatedContext(currentTask) {
|
|
181
181
|
const omPath = path.join(process.cwd(), '.openmatrix');
|
|
182
182
|
const tasksDir = path.join(omPath, 'tasks');
|
|
183
183
|
try {
|
|
184
|
-
|
|
184
|
+
// 异步检查目录是否存在
|
|
185
|
+
try {
|
|
186
|
+
await fs.access(tasksDir);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
185
189
|
return '';
|
|
190
|
+
}
|
|
186
191
|
const contextParts = [];
|
|
187
|
-
//
|
|
188
|
-
const taskDirs = fs.
|
|
192
|
+
// 异步读取目录
|
|
193
|
+
const taskDirs = (await fs.readdir(tasksDir)).filter(name => name.startsWith('TASK-'));
|
|
189
194
|
for (const taskId of taskDirs) {
|
|
190
195
|
const contextFile = path.join(tasksDir, taskId, 'context.md');
|
|
191
|
-
|
|
192
|
-
const content = fs.
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
try {
|
|
197
|
+
const content = await fs.readFile(contextFile, 'utf-8');
|
|
198
|
+
const trimmed = content.trim();
|
|
199
|
+
if (trimmed) {
|
|
200
|
+
contextParts.push(`### ${taskId}\n${trimmed}`);
|
|
195
201
|
}
|
|
196
202
|
}
|
|
203
|
+
catch {
|
|
204
|
+
// 文件不存在或读取失败,跳过
|
|
205
|
+
}
|
|
197
206
|
}
|
|
198
207
|
if (contextParts.length === 0)
|
|
199
208
|
return '';
|
|
@@ -389,30 +389,26 @@ function generateBrainstormQuestions(taskContent, taskTitle) {
|
|
|
389
389
|
question: '选择执行模式(控制 AI 执行过程中的审批节点)',
|
|
390
390
|
header: '执行模式',
|
|
391
391
|
options: [
|
|
392
|
-
{ label: '
|
|
392
|
+
{ label: '全自动执行 (推荐)', description: '全自动执行,无需人工审批,遇到阻塞自动 Meeting' },
|
|
393
393
|
{ label: 'confirm-key', description: '关键节点审批(计划、合并、部署)' },
|
|
394
394
|
{ label: 'confirm-all', description: '每个阶段都需人工确认' }
|
|
395
395
|
],
|
|
396
396
|
multiSelect: false,
|
|
397
397
|
why: '执行模式决定自动化程度和人工干预频率'
|
|
398
398
|
});
|
|
399
|
-
// 问题 10: E2E
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
multiSelect: false,
|
|
413
|
-
why: 'E2E 测试能验证完整用户流程,但增加执行时间'
|
|
414
|
-
});
|
|
415
|
-
}
|
|
399
|
+
// 问题 10: E2E 测试(必填)
|
|
400
|
+
// E2E 测试是必问问题,由用户在问答中选择是否启用
|
|
401
|
+
questions.push({
|
|
402
|
+
id: 'e2e_tests',
|
|
403
|
+
question: '是否启用端到端 (E2E) 测试?(适用于 Web/Mobile/GUI 项目,耗时较长)',
|
|
404
|
+
header: 'E2E 测试',
|
|
405
|
+
options: [
|
|
406
|
+
{ label: '启用 E2E 测试', description: '使用 Playwright/Cypress 等框架进行端到端测试' },
|
|
407
|
+
{ label: '不启用 (推荐)', description: '仅进行单元测试和集成测试,节省时间' }
|
|
408
|
+
],
|
|
409
|
+
multiSelect: false,
|
|
410
|
+
why: 'E2E 测试能验证完整用户流程,但增加执行时间'
|
|
411
|
+
});
|
|
416
412
|
return questions;
|
|
417
413
|
}
|
|
418
414
|
/**
|
|
@@ -38,6 +38,7 @@ exports.completeCommand = void 0;
|
|
|
38
38
|
const commander_1 = require("commander");
|
|
39
39
|
const state_manager_js_1 = require("../../storage/state-manager.js");
|
|
40
40
|
const git_commit_manager_js_1 = require("../../orchestrator/git-commit-manager.js");
|
|
41
|
+
const fs = __importStar(require("fs/promises"));
|
|
41
42
|
const path = __importStar(require("path"));
|
|
42
43
|
exports.completeCommand = new commander_1.Command('complete')
|
|
43
44
|
.description('标记任务完成并更新全局统计')
|
|
@@ -84,7 +85,13 @@ exports.completeCommand = new commander_1.Command('complete')
|
|
|
84
85
|
completed: allTasks.filter(t => t.status === 'completed').length,
|
|
85
86
|
inProgress: allTasks.filter(t => t.status === 'in_progress').length,
|
|
86
87
|
failed: allTasks.filter(t => t.status === 'failed').length,
|
|
87
|
-
pending: allTasks.filter(t => t.status === 'pending'
|
|
88
|
+
pending: allTasks.filter(t => t.status === 'pending').length,
|
|
89
|
+
scheduled: allTasks.filter(t => t.status === 'scheduled').length,
|
|
90
|
+
blocked: allTasks.filter(t => t.status === 'blocked').length,
|
|
91
|
+
waiting: allTasks.filter(t => t.status === 'waiting').length,
|
|
92
|
+
verify: allTasks.filter(t => t.status === 'verify').length,
|
|
93
|
+
accept: allTasks.filter(t => t.status === 'accept').length,
|
|
94
|
+
retry_queue: allTasks.filter(t => t.status === 'retry_queue').length
|
|
88
95
|
};
|
|
89
96
|
// 4. 更新全局状态
|
|
90
97
|
const allDone = stats.completed + stats.failed === stats.totalTasks;
|
|
@@ -94,7 +101,33 @@ exports.completeCommand = new commander_1.Command('complete')
|
|
|
94
101
|
currentPhase: allDone ? 'completed' : 'execution',
|
|
95
102
|
...(allDone ? { completedAt: now } : {})
|
|
96
103
|
});
|
|
97
|
-
// 5.
|
|
104
|
+
// 5. 写入 context.md (Agent Memory)
|
|
105
|
+
if (isSuccess) {
|
|
106
|
+
const taskDir = path.join(omPath, 'tasks', taskId);
|
|
107
|
+
const contextFile = path.join(taskDir, 'context.md');
|
|
108
|
+
try {
|
|
109
|
+
await fs.mkdir(taskDir, { recursive: true });
|
|
110
|
+
const contextContent = `## 任务:${task.id} ${task.title}
|
|
111
|
+
|
|
112
|
+
### 关键决策
|
|
113
|
+
- [待补充]
|
|
114
|
+
|
|
115
|
+
### 创建/修改的文件
|
|
116
|
+
- [待补充]
|
|
117
|
+
|
|
118
|
+
### 重要发现
|
|
119
|
+
- [待补充]
|
|
120
|
+
|
|
121
|
+
### 对后续任务的建议
|
|
122
|
+
- [待补充]
|
|
123
|
+
`;
|
|
124
|
+
await fs.writeFile(contextFile, contextContent, 'utf-8');
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// 忽略写入错误
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// 6. Git 自动提交
|
|
98
131
|
if (isSuccess) {
|
|
99
132
|
const state = await stateManager.getState();
|
|
100
133
|
const gitManager = new git_commit_manager_js_1.GitCommitManager(basePath);
|
|
@@ -106,7 +106,7 @@ exports.startCommand = new commander_1.Command('start')
|
|
|
106
106
|
// 路径 A: AI 已拆分 (--tasks-json)
|
|
107
107
|
// ============================
|
|
108
108
|
if (options.tasksJson) {
|
|
109
|
-
await handleTasksJson(options, stateManager, state, omPath);
|
|
109
|
+
await handleTasksJson(options, stateManager, state, omPath, basePath);
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
// ============================
|
|
@@ -118,13 +118,16 @@ exports.startCommand = new commander_1.Command('start')
|
|
|
118
118
|
* 处理 AI 解析的任务 (--tasks-json)
|
|
119
119
|
* AI 提供 ParsedTask 格式的结构化数据,仍由 TaskPlanner 做拆分
|
|
120
120
|
*/
|
|
121
|
-
async function handleTasksJson(options, stateManager, state, omPath) {
|
|
121
|
+
async function handleTasksJson(options, stateManager, state, omPath, basePath) {
|
|
122
122
|
let tasksInput;
|
|
123
123
|
try {
|
|
124
124
|
// 支持 @file 语法读取文件
|
|
125
125
|
let jsonStr = options.tasksJson;
|
|
126
126
|
if (jsonStr.startsWith('@')) {
|
|
127
|
-
|
|
127
|
+
const filePath = jsonStr.slice(1);
|
|
128
|
+
// 如果是相对路径,转换为绝对路径
|
|
129
|
+
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
|
|
130
|
+
jsonStr = await fs.readFile(resolvedPath, 'utf-8');
|
|
128
131
|
}
|
|
129
132
|
tasksInput = JSON.parse(jsonStr);
|
|
130
133
|
}
|
|
@@ -68,7 +68,13 @@ exports.stepCommand = new commander_1.Command('step')
|
|
|
68
68
|
completed: completed,
|
|
69
69
|
inProgress: allTasks.filter(t => t.status === 'in_progress').length,
|
|
70
70
|
failed: allTasks.filter(t => t.status === 'failed').length,
|
|
71
|
-
pending: allTasks.filter(t => t.status === 'pending').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
|
|
72
78
|
};
|
|
73
79
|
const allDone = completed + stats.failed === total;
|
|
74
80
|
await stateManager.updateState({
|
|
@@ -244,8 +244,18 @@ class GitCommitManager {
|
|
|
244
244
|
};
|
|
245
245
|
// 生成提交信息
|
|
246
246
|
const commitMessage = this.generateCommitMessage(fullInfo);
|
|
247
|
-
//
|
|
248
|
-
|
|
247
|
+
// 添加文件 - 使用 git add . 而不是 git add -A
|
|
248
|
+
// git add . 只添加当前目录及子目录的文件,不会添加上级目录的文件
|
|
249
|
+
// 同时通过 .gitignore 排除不需要的文件
|
|
250
|
+
await execAsync('git add .', { cwd: this.repoPath });
|
|
251
|
+
// 检查是否有文件被暂存(避免空提交)
|
|
252
|
+
const { stdout: staged } = await execAsync('git diff --cached --name-only', { cwd: this.repoPath });
|
|
253
|
+
if (!staged.trim()) {
|
|
254
|
+
return {
|
|
255
|
+
success: false,
|
|
256
|
+
message: 'No files to commit (all changes ignored or no changes)'
|
|
257
|
+
};
|
|
258
|
+
}
|
|
249
259
|
// 使用临时文件传递 commit message(避免 Windows 下多行消息转义问题)
|
|
250
260
|
const tmpFile = path.join(this.repoPath, '.git', 'COMMIT_MSG_TMP');
|
|
251
261
|
await fs.writeFile(tmpFile, commitMessage, 'utf-8');
|
|
@@ -192,6 +192,9 @@ export declare class PhaseExecutor {
|
|
|
192
192
|
parseBuildTestResult(output: string): BuildTestResult;
|
|
193
193
|
/**
|
|
194
194
|
* 解析质量报告
|
|
195
|
+
*
|
|
196
|
+
* 策略:优先解析 JSON 格式,失败时使用正则表达式回退
|
|
197
|
+
* 支持多种测试框架输出格式(Vitest, Jest, Mocha, Tape)
|
|
195
198
|
*/
|
|
196
199
|
parseQualityReport(output: string): QualityGateResult;
|
|
197
200
|
/**
|