openmatrix 0.2.26 → 0.2.27

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.
@@ -206,8 +206,23 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
206
206
  if (jsonStr.startsWith('@')) {
207
207
  const filePath = jsonStr.slice(1);
208
208
  // 如果是相对路径,转换为绝对路径
209
- const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
210
- jsonStr = await fs.readFile(resolvedPath, 'utf-8');
209
+ let resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(basePath, filePath);
210
+ // 特殊处理:如果文件名是 tasks-input.json 且不带路径,尝试从 runId 目录读取
211
+ if (filePath === 'tasks-input.json' || filePath.endsWith('/tasks-input.json')) {
212
+ // 先尝试从 runId 目录读取
213
+ const state = await stateManager.getState();
214
+ const runIdPath = path.join(omPath, state.runId, 'tasks-input.json');
215
+ try {
216
+ jsonStr = await fs.readFile(runIdPath, 'utf-8');
217
+ }
218
+ catch {
219
+ // 如果 runId 目录不存在,尝试原有路径
220
+ jsonStr = await fs.readFile(resolvedPath, 'utf-8');
221
+ }
222
+ }
223
+ else {
224
+ jsonStr = await fs.readFile(resolvedPath, 'utf-8');
225
+ }
211
226
  }
212
227
  tasksInput = JSON.parse(jsonStr);
213
228
  }
@@ -241,18 +256,14 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
241
256
  console.log(`🔬 已加载研究领域: ${researchContext.domain}`);
242
257
  }
243
258
  }
244
- // 读取独立的技术方案文档(plan.md)
259
+ // 读取独立的技术方案文档(从当前 runId 目录)
245
260
  let planContent;
246
- const planPath = path.join(omPath, 'plan.md');
247
- try {
248
- planContent = await fs.readFile(planPath, 'utf-8');
249
- if (!options.json) {
250
- console.log(`📄 已加载技术方案: plan.md`);
251
- }
252
- }
253
- catch {
254
- // plan.md 不存在时继续(可能由 AI 后续生成或无 plan)
261
+ planContent = await stateManager.getPlan();
262
+ if (planContent && !options.json) {
263
+ console.log(`📄 已加载技术方案: plan.md`);
255
264
  }
265
+ // 转换为 string | undefined(供 TaskPlanner 使用)
266
+ const planContentForPlanner = planContent || undefined;
256
267
  // 构建 ParsedTask
257
268
  const parsedTask = {
258
269
  title: resolvedInput.title || tasksInput.title,
@@ -285,7 +296,7 @@ async function handleTasksJson(options, stateManager, state, omPath, basePath) {
285
296
  }
286
297
  // 使用 TaskPlanner 拆分(保持原有拆分逻辑)
287
298
  const planner = new task_planner_js_1.TaskPlanner();
288
- const subTasks = planner.breakdown(parsedTask, extraAnswers, qualityConfig, planContent);
299
+ const subTasks = planner.breakdown(parsedTask, extraAnswers, qualityConfig, planContentForPlanner);
289
300
  // 创建任务到状态管理器,并建立 ID 映射
290
301
  // TaskPlanner 生成的 taskId 和 StateManager 创建的 id 不同,
291
302
  // 需要映射后才能正确设置 dependencies
@@ -70,7 +70,19 @@ async function showStatus(manager, reporter, options) {
70
70
  const state = await manager.getState();
71
71
  const tasks = await manager.listTasks();
72
72
  if (options.json) {
73
- console.log(JSON.stringify({ state, tasks }, null, 2));
73
+ // 添加文件状态字段
74
+ const hasPlan = await manager.hasPlan();
75
+ const hasTasksInput = await manager.hasTasksInput();
76
+ const hasResearchContext = await manager.hasResearchContext();
77
+ console.log(JSON.stringify({
78
+ state,
79
+ tasks,
80
+ files: {
81
+ hasPlan,
82
+ hasTasksInput,
83
+ hasResearchContext
84
+ }
85
+ }, null, 2));
74
86
  return;
75
87
  }
76
88
  // Header
@@ -62,6 +62,114 @@ export declare class StateManager {
62
62
  updateApproval(approval: Approval): Promise<void>;
63
63
  getApprovalsByStatus(status: ApprovalStatus): Promise<Approval[]>;
64
64
  getAllApprovals(): Promise<Approval[]>;
65
+ /**
66
+ * 保存技术方案文档 (plan.md)
67
+ * 路径: .openmatrix/{runId}/plan.md
68
+ */
69
+ savePlan(content: string): Promise<void>;
70
+ /**
71
+ * 读取技术方案文档
72
+ * @returns plan.md 内容,不存在返回 null
73
+ */
74
+ getPlan(): Promise<string | null>;
75
+ /**
76
+ * 检查 plan.md 是否存在
77
+ */
78
+ hasPlan(): Promise<boolean>;
79
+ /**
80
+ * 保存任务输入元数据
81
+ * 路径: .openmatrix/{runId}/tasks-input.json
82
+ */
83
+ saveTasksInput(data: {
84
+ title: string;
85
+ description?: string;
86
+ goals: string[];
87
+ goalTypes?: string[];
88
+ goalComplexity?: ('low' | 'medium' | 'high')[];
89
+ constraints?: string[];
90
+ deliverables?: string[];
91
+ answers?: Record<string, string>;
92
+ }): Promise<void>;
93
+ /**
94
+ * 读取任务输入元数据
95
+ * @returns tasks-input.json 数据,不存在返回 null
96
+ */
97
+ getTasksInput(): Promise<{
98
+ title: string;
99
+ description?: string;
100
+ goals: string[];
101
+ goalTypes?: string[];
102
+ goalComplexity?: ('low' | 'medium' | 'high')[];
103
+ constraints?: string[];
104
+ deliverables?: string[];
105
+ answers?: Record<string, string>;
106
+ } | null>;
107
+ /**
108
+ * 检查 tasks-input.json 是否存在
109
+ */
110
+ hasTasksInput(): Promise<boolean>;
111
+ /**
112
+ * 保存研究会话
113
+ * 路径: .openmatrix/{runId}/research/session.json
114
+ */
115
+ saveResearchSession(session: Record<string, unknown>): Promise<void>;
116
+ /**
117
+ * 读取研究会话
118
+ */
119
+ getResearchSession(): Promise<Record<string, unknown> | null>;
120
+ /**
121
+ * 保存研究报告
122
+ */
123
+ saveResearchReport(content: string): Promise<void>;
124
+ /**
125
+ * 读取研究报告
126
+ */
127
+ getResearchReport(): Promise<string | null>;
128
+ /**
129
+ * 保存研究上下文 (供 start 使用)
130
+ */
131
+ saveResearchContext(context: {
132
+ topic: string;
133
+ domain: string;
134
+ goals?: string[];
135
+ constraints?: string[];
136
+ deliverables?: string[];
137
+ reportPath?: string;
138
+ knowledgePath?: string;
139
+ }): Promise<void>;
140
+ /**
141
+ * 读取研究上下文
142
+ */
143
+ getResearchContext(): Promise<{
144
+ topic: string;
145
+ domain: string;
146
+ goals?: string[];
147
+ constraints?: string[];
148
+ deliverables?: string[];
149
+ reportPath?: string;
150
+ knowledgePath?: string;
151
+ } | null>;
152
+ /**
153
+ * 检查研究上下文是否存在
154
+ */
155
+ hasResearchContext(): Promise<boolean>;
156
+ /**
157
+ * 保存知识条目
158
+ */
159
+ saveKnowledgeFinding(index: number, content: string): Promise<void>;
160
+ /**
161
+ * 保存头脑风暴会话
162
+ */
163
+ saveBrainstormSession(session: Record<string, unknown>): Promise<void>;
164
+ /**
165
+ * 读取头脑风暴会话
166
+ */
167
+ getBrainstormSession(): Promise<Record<string, unknown> | null>;
168
+ /**
169
+ * 迁移旧版本文件到 runId 目录
170
+ * 只在首次检测到旧文件时执行
171
+ */
172
+ migrateFromLegacy(): Promise<void>;
65
173
  saveMeeting(meeting: Meeting): Promise<void>;
66
174
  getMeeting(meetingId: string): Promise<Meeting | null>;
67
175
  getMeetingsByStatus(status: MeetingStatus): Promise<Meeting[]>;
@@ -110,6 +110,8 @@ class StateManager {
110
110
  retry_queue: existing.statistics?.retry_queue ?? 0
111
111
  };
112
112
  this.stateCache = existing;
113
+ // 迁移旧版本文件到 runId 目录
114
+ await this.migrateFromLegacy();
113
115
  return;
114
116
  }
115
117
  }
@@ -151,12 +153,17 @@ class StateManager {
151
153
  if (oldRunId) {
152
154
  await this.rootStore.removeDir(oldRunId);
153
155
  }
154
- // 兼容旧版本的目录
156
+ // 兼容旧版本的目录和文件(根目录)
155
157
  await this.rootStore.removeDir('tasks');
156
158
  await this.rootStore.removeDir('approvals');
157
159
  await this.rootStore.removeDir('meetings');
158
160
  await this.rootStore.removeDir('runs');
161
+ await this.rootStore.removeDir('research');
162
+ await this.rootStore.removeDir('brainstorm');
159
163
  await this.rootStore.removeFile('context.md');
164
+ await this.rootStore.removeFile('plan.md');
165
+ await this.rootStore.removeFile('tasks-input.json');
166
+ await this.rootStore.removeFile('state.json');
160
167
  // 创建新运行
161
168
  const runId = this.generateRunId();
162
169
  this.store = new file_store_js_1.FileStore((0, path_1.join)(this.basePath, runId));
@@ -443,6 +450,167 @@ class StateManager {
443
450
  }
444
451
  return approvals.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
445
452
  }
453
+ // ============ Plan Methods ============
454
+ /**
455
+ * 保存技术方案文档 (plan.md)
456
+ * 路径: .openmatrix/{runId}/plan.md
457
+ */
458
+ async savePlan(content) {
459
+ await this.store.writeMarkdown('plan.md', content);
460
+ }
461
+ /**
462
+ * 读取技术方案文档
463
+ * @returns plan.md 内容,不存在返回 null
464
+ */
465
+ async getPlan() {
466
+ return await this.store.readMarkdown('plan.md');
467
+ }
468
+ /**
469
+ * 检查 plan.md 是否存在
470
+ */
471
+ async hasPlan() {
472
+ return await this.store.exists('plan.md');
473
+ }
474
+ // ============ TasksInput Methods ============
475
+ /**
476
+ * 保存任务输入元数据
477
+ * 路径: .openmatrix/{runId}/tasks-input.json
478
+ */
479
+ async saveTasksInput(data) {
480
+ await this.store.writeJson('tasks-input.json', data);
481
+ }
482
+ /**
483
+ * 读取任务输入元数据
484
+ * @returns tasks-input.json 数据,不存在返回 null
485
+ */
486
+ async getTasksInput() {
487
+ return await this.store.readJson('tasks-input.json');
488
+ }
489
+ /**
490
+ * 检查 tasks-input.json 是否存在
491
+ */
492
+ async hasTasksInput() {
493
+ return await this.store.exists('tasks-input.json');
494
+ }
495
+ // ============ Research Methods ============
496
+ /**
497
+ * 保存研究会话
498
+ * 路径: .openmatrix/{runId}/research/session.json
499
+ */
500
+ async saveResearchSession(session) {
501
+ await this.store.ensureDir('research');
502
+ await this.store.writeJson('research/session.json', session);
503
+ }
504
+ /**
505
+ * 读取研究会话
506
+ */
507
+ async getResearchSession() {
508
+ return await this.store.readJson('research/session.json');
509
+ }
510
+ /**
511
+ * 保存研究报告
512
+ */
513
+ async saveResearchReport(content) {
514
+ await this.store.ensureDir('research');
515
+ await this.store.writeMarkdown('research/RESEARCH.md', content);
516
+ }
517
+ /**
518
+ * 读取研究报告
519
+ */
520
+ async getResearchReport() {
521
+ return await this.store.readMarkdown('research/RESEARCH.md');
522
+ }
523
+ /**
524
+ * 保存研究上下文 (供 start 使用)
525
+ */
526
+ async saveResearchContext(context) {
527
+ await this.store.ensureDir('research');
528
+ await this.store.writeJson('research/context.json', context);
529
+ }
530
+ /**
531
+ * 读取研究上下文
532
+ */
533
+ async getResearchContext() {
534
+ return await this.store.readJson('research/context.json');
535
+ }
536
+ /**
537
+ * 检查研究上下文是否存在
538
+ */
539
+ async hasResearchContext() {
540
+ return await this.store.exists('research/context.json');
541
+ }
542
+ /**
543
+ * 保存知识条目
544
+ */
545
+ async saveKnowledgeFinding(index, content) {
546
+ await this.store.ensureDir('research/knowledge');
547
+ await this.store.writeMarkdown(`research/knowledge/finding-${index}.md`, content);
548
+ }
549
+ // ============ Brainstorm Methods ============
550
+ /**
551
+ * 保存头脑风暴会话
552
+ */
553
+ async saveBrainstormSession(session) {
554
+ await this.store.ensureDir('brainstorm');
555
+ await this.store.writeJson('brainstorm/session.json', session);
556
+ }
557
+ /**
558
+ * 读取头脑风暴会话
559
+ */
560
+ async getBrainstormSession() {
561
+ return await this.store.readJson('brainstorm/session.json');
562
+ }
563
+ // ============ Legacy Migration Methods ============
564
+ /**
565
+ * 迁移旧版本文件到 runId 目录
566
+ * 只在首次检测到旧文件时执行
567
+ */
568
+ async migrateFromLegacy() {
569
+ // Check if migration already done
570
+ if (await this.store.exists('plan.md')) {
571
+ return; // Already migrated
572
+ }
573
+ // Move plan.md from root to runId
574
+ const rootPlan = await this.rootStore.readMarkdown('plan.md');
575
+ if (rootPlan) {
576
+ await this.store.writeMarkdown('plan.md', rootPlan);
577
+ await this.rootStore.removeFile('plan.md');
578
+ }
579
+ // Move tasks-input.json from root to runId
580
+ const rootTasksInput = await this.rootStore.readJson('tasks-input.json');
581
+ if (rootTasksInput) {
582
+ await this.store.writeJson('tasks-input.json', rootTasksInput);
583
+ await this.rootStore.removeFile('tasks-input.json');
584
+ }
585
+ // Move research directory from root to runId
586
+ const rootResearchSession = await this.rootStore.readJson('research/session.json');
587
+ if (rootResearchSession) {
588
+ await this.store.ensureDir('research/knowledge');
589
+ // Copy session.json
590
+ if (rootResearchSession) {
591
+ await this.store.writeJson('research/session.json', rootResearchSession);
592
+ }
593
+ // Copy context.json
594
+ const rootContext = await this.rootStore.readJson('research/context.json');
595
+ if (rootContext) {
596
+ await this.store.writeJson('research/context.json', rootContext);
597
+ }
598
+ // Copy RESEARCH.md
599
+ const rootReport = await this.rootStore.readMarkdown('research/RESEARCH.md');
600
+ if (rootReport) {
601
+ await this.store.writeMarkdown('research/RESEARCH.md', rootReport);
602
+ }
603
+ // Remove old directory
604
+ await this.rootStore.removeDir('research');
605
+ }
606
+ // Move brainstorm directory from root to runId
607
+ const rootBrainstormSession = await this.rootStore.readJson('brainstorm/session.json');
608
+ if (rootBrainstormSession) {
609
+ await this.store.ensureDir('brainstorm');
610
+ await this.store.writeJson('brainstorm/session.json', rootBrainstormSession);
611
+ await this.rootStore.removeDir('brainstorm');
612
+ }
613
+ }
446
614
  // ============ Meeting Methods ============
447
615
  async saveMeeting(meeting) {
448
616
  await this.store.writeJson(`meetings/${meeting.id}.json`, meeting);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmatrix",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "AI Agent task orchestration system with Claude Code Skills integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/skills/approve.md CHANGED
@@ -35,7 +35,7 @@ description: "Use when handling pending approvals including plan review, merge c
35
35
  </INTENT-JUDGMENT>
36
36
 
37
37
  <NO-OTHER-SKILLS>
38
- 执行此技能时,不得调用 superpowers、gsd 或其他任务编排相关的技能。OpenMatrix 独立运行,不依赖外部任务编排系统。
38
+ skill 与其他任务编排技能功能重叠,请勿同时使用。
39
39
  </NO-OTHER-SKILLS>
40
40
 
41
41
  <objective>
package/skills/auto.md CHANGED
@@ -37,14 +37,9 @@ description: "Use when the user wants fully automated task execution with zero m
37
37
  </INTENT-JUDGMENT>
38
38
 
39
39
  <NO-OTHER-SKILLS>
40
- **绝对禁止**调用以下任何技能或工具:
41
- - gsd-executor、gsd:* 等 GSD 相关技能
42
- - superpowers:* 等 superpowers 相关技能
43
- - 任何其他任务编排相关的 Agent 或工具
40
+ 本 skill 与其他任务编排技能功能重叠,请勿同时使用。
44
41
 
45
- **Step 5 只能使用 Agent 工具** — 直接调用 Agent,不通过任何中间层。
46
-
47
- 违规调用将导致执行失败。
42
+ **Step 5 使用 Agent 工具执行子任务。**
48
43
 
49
44
  **相关技能**: `/om:brainstorm` (需求探索) | `/om:plan` (方案生成) | `/om:start` (交互式执行) | `/om:status` (状态查看) | `/om:report` (报告)
50
45
  </NO-OTHER-SKILLS>
@@ -80,6 +75,22 @@ Step 5: 逐个执行 subagentTasks(调用 Agent 工具) ← 只
80
75
  **执行时不要请求用户确认任何操作。**
81
76
  </BYPASS-MODE>
82
77
 
78
+ <RED-FLAGS>
79
+ ## 红旗警告 - 停止并检查
80
+
81
+ 这些想法意味着你在找借口:
82
+
83
+ | 想法 | 真相 |
84
+ |-----|------|
85
+ | "全自动不需要检查" | 全自动更需要状态持久化 |
86
+ | "跳过 CLI 调用更快" | CLI 是唯一正确的入口 |
87
+ | "我不需要验证状态" | 上下文压缩会丢失状态 |
88
+ | "直接用 Bash 写代码" | 业务代码必须通过 Agent |
89
+ | "忘记任务顺序没关系" | 用 `openmatrix step` 重新获取 |
90
+ | "这个歧义不重要" | 所有歧义都写入 Meeting |
91
+
92
+ </RED-FLAGS>
93
+
83
94
  <objective>
84
95
  全自动执行任务。读取已有的 plan.md + tasks-input.json,通过 CLI 拆分任务,然后通过 Agent 逐个执行。无交互、无审批、无中断。
85
96
 
@@ -101,11 +112,21 @@ openmatrix start --init-only
101
112
 
102
113
  ### Step 2: 验证前置条件
103
114
 
104
- **检查 plan.md 和 tasks-input.json 是否已存在:**
115
+ **先获取当前 runId:**
116
+ ```bash
117
+ cat .openmatrix/current.json 2>/dev/null || echo '{"runId":"run-default"}'
118
+ ```
105
119
 
120
+ **检查 plan.md 和 tasks-input.json 是否已存在(使用 runId):**
121
+
122
+ ```bash
123
+ cat .openmatrix/${runId}/tasks-input.json 2>/dev/null || echo "NOT_FOUND"
124
+ cat .openmatrix/${runId}/plan.md 2>/dev/null || echo "NOT_FOUND"
125
+ ```
126
+
127
+ **或通过 CLI 检查(推荐):**
106
128
  ```bash
107
- cat .openmatrix/tasks-input.json 2>/dev/null || echo "NOT_FOUND"
108
- cat .openmatrix/plan.md 2>/dev/null || echo "NOT_FOUND"
129
+ openmatrix status --json | jq '.files'
109
130
  ```
110
131
 
111
132
  | 情况 | 处理方式 |
@@ -119,15 +140,17 @@ cat .openmatrix/plan.md 2>/dev/null || echo "NOT_FOUND"
119
140
 
120
141
  ### Step 3: 调用 CLI 创建任务 ⚠️ 不可跳过
121
142
 
143
+ **CLI 自动从当前 runId 目录读取 tasks-input.json 和 plan.md。**
144
+
122
145
  **这是最关键的步骤。必须执行以下命令,不能跳过:**
123
146
 
124
147
  ```bash
125
- openmatrix start --tasks-json @.openmatrix/tasks-input.json --quality <质量等级> --mode auto --json
148
+ openmatrix start --tasks-json @tasks-input.json --quality <质量等级> --mode auto --json
126
149
  ```
127
150
 
128
151
  如果启用了 E2E 测试,加上 `--e2e-tests`:
129
152
  ```bash
130
- openmatrix start --tasks-json @.openmatrix/tasks-input.json --quality strict --mode auto --e2e-tests --json
153
+ openmatrix start --tasks-json @tasks-input.json --quality strict --mode auto --e2e-tests --json
131
154
  ```
132
155
 
133
156
  此命令会:
@@ -346,8 +369,10 @@ auto 和 start 在同一位置,区别在于:
346
369
  - **auto**: 零交互,不询问任何问题,无审批节点,质量通过 --quality 指定
347
370
 
348
371
  前置条件(同 start):
349
- - `.openmatrix/plan.md` — 技术方案(由 /om:plan 生成)
350
- - `.openmatrix/tasks-input.json` — 结构化元数据(由 /om:plan 生成)
372
+ - `.openmatrix/{runId}/plan.md` — 技术方案(由 /om:plan 生成)
373
+ - `.openmatrix/{runId}/tasks-input.json` — 结构化元数据(由 /om:plan 生成)
374
+
375
+ CLI 自动通过 `current.json` 定位当前 runId。
351
376
 
352
377
  如果前置条件不满足,自动调用 /om:plan 生成。
353
378
 
@@ -36,11 +36,7 @@ description: "Use when the user wants to explore requirements, design alternativ
36
36
  </INTENT-JUDGMENT>
37
37
 
38
38
  <NO-OTHER-SKILLS>
39
- **绝对禁止**调用以下技能(OpenMatrix 完全替代它们):
40
- - ❌ superpowers:brainstorming → 你已经在 om:brainstorm 中了
41
- - ❌ superpowers:* → 全部被 OpenMatrix 替代
42
- - ❌ gsd:* → 全部被 OpenMatrix 替代
43
- - ❌ 任何其他任务编排相关的技能
39
+ skill 与其他任务编排技能功能重叠,请勿同时使用。
44
40
 
45
41
  **相关技能**: `/om:research` (领域调研) | `/om:plan` (方案生成) | `/om:start` (任务执行) | `/om:auto` (全自动)
46
42
  </NO-OTHER-SKILLS>
package/skills/check.md CHANGED
@@ -4,7 +4,7 @@ description: 自动检测项目可改进点并提供升级建议,用户确认
4
4
  ---
5
5
 
6
6
  <NO-OTHER-SKILLS>
7
- 执行此技能时,不得调用 superpowers、gsd 或其他任务编排相关的技能。OpenMatrix 独立运行,不依赖外部任务编排系统。
7
+ skill 与其他任务编排技能功能重叠,请勿同时使用。
8
8
  </NO-OTHER-SKILLS>
9
9
 
10
10
  <objective>