openmatrix 0.2.21 → 0.2.23

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.
@@ -128,6 +128,10 @@ export declare class AgentRunner {
128
128
  * 获取运行中的 Agent 数量
129
129
  */
130
130
  getRunningCount(): number;
131
+ /**
132
+ * 标记任务完成,释放 runningAgents 槽位
133
+ */
134
+ markTaskCompleted(taskId: string): void;
131
135
  /**
132
136
  * 检查是否可以启动新 Agent
133
137
  */
@@ -820,6 +820,12 @@ describe('MyFunction', () => {
820
820
  getRunningCount() {
821
821
  return this.runningAgents.size;
822
822
  }
823
+ /**
824
+ * 标记任务完成,释放 runningAgents 槽位
825
+ */
826
+ markTaskCompleted(taskId) {
827
+ this.runningAgents.delete(taskId);
828
+ }
823
829
  /**
824
830
  * 检查是否可以启动新 Agent
825
831
  */
@@ -46,12 +46,14 @@ export declare class OrchestratorExecutor {
46
46
  private aiReviewer;
47
47
  private meetingManager;
48
48
  private config;
49
+ private _configReady;
49
50
  private taskTimers;
50
51
  constructor(stateManager: StateManager, approvalManager: ApprovalManager, config?: Partial<ExecutorConfig>);
51
52
  /**
52
53
  * 获取 PhaseExecutor 实例
53
54
  */
54
55
  getPhaseExecutor(): PhaseExecutor;
56
+ private loadConfigFromState;
55
57
  /**
56
58
  * 执行一步 - 返回待执行的 Subagent 任务
57
59
  *
@@ -65,10 +67,6 @@ export declare class OrchestratorExecutor {
65
67
  * 仅在失败/异常时才暂停
66
68
  */
67
69
  private checkApprovals;
68
- /**
69
- * 检查是否所有任务完成
70
- */
71
- private checkAllCompleted;
72
70
  /**
73
71
  * 获取统计信息
74
72
  */
@@ -26,25 +26,19 @@ class OrchestratorExecutor {
26
26
  aiReviewer;
27
27
  meetingManager;
28
28
  config;
29
+ _configReady;
29
30
  taskTimers = new Map();
30
31
  constructor(stateManager, approvalManager, config) {
31
32
  this.stateManager = stateManager;
32
33
  this.approvalManager = approvalManager;
33
34
  this.meetingManager = new meeting_manager_js_1.MeetingManager(stateManager, approvalManager);
34
- // 从 state.config 读取 taskTimeout,如果未定义则使用默认值
35
- const stateConfig = stateManager.getState().then(s => s.config).catch(() => null);
36
35
  const defaultTaskTimeout = 600000; // 10 分钟(毫秒)
37
36
  this.config = {
38
37
  maxConcurrent: 3,
39
38
  taskTimeout: defaultTaskTimeout,
40
39
  ...config
41
40
  };
42
- // 异步获取配置并更新 taskTimeout
43
- stateConfig.then(cfg => {
44
- if (cfg?.taskTimeout) {
45
- this.config.taskTimeout = cfg.taskTimeout;
46
- }
47
- });
41
+ this._configReady = this.loadConfigFromState(stateManager);
48
42
  this.scheduler = new scheduler_js_1.Scheduler(stateManager, {
49
43
  maxConcurrentTasks: this.config.maxConcurrent,
50
44
  taskTimeout: this.config.taskTimeout
@@ -64,12 +58,24 @@ class OrchestratorExecutor {
64
58
  getPhaseExecutor() {
65
59
  return this.phaseExecutor;
66
60
  }
61
+ async loadConfigFromState(stateManager) {
62
+ try {
63
+ const state = await stateManager.getState();
64
+ if (state.config?.taskTimeout) {
65
+ this.config.taskTimeout = state.config.taskTimeout;
66
+ }
67
+ }
68
+ catch {
69
+ // use default config
70
+ }
71
+ }
67
72
  /**
68
73
  * 执行一步 - 返回待执行的 Subagent 任务
69
74
  *
70
75
  * Skills 调用此方法获取任务,然后使用 Agent 工具执行
71
76
  */
72
77
  async step() {
78
+ await this._configReady;
73
79
  const state = await this.stateManager.getState();
74
80
  // 1. 检查是否需要审批
75
81
  const pendingApprovals = await this.checkApprovals(state);
@@ -163,14 +169,6 @@ class OrchestratorExecutor {
163
169
  return state.config.approvalPoints.includes(approvalPoint);
164
170
  });
165
171
  }
166
- /**
167
- * 检查是否所有任务完成
168
- */
169
- checkAllCompleted(tasks) {
170
- if (tasks.length === 0)
171
- return true;
172
- return tasks.every(task => task.status === 'completed');
173
- }
174
172
  /**
175
173
  * 获取统计信息
176
174
  */
@@ -327,6 +325,7 @@ class OrchestratorExecutor {
327
325
  }
328
326
  else if (currentPhase === 'accept') {
329
327
  await this.scheduler.markTaskCompleted(taskId);
328
+ this.agentRunner.markTaskCompleted(taskId);
330
329
  // Review 任务完成:自动解析报告并生成修复任务
331
330
  if (task.assignedAgent === 'reviewer' && result.output) {
332
331
  return await this.processReviewResult(taskId, result.output);
@@ -335,6 +334,7 @@ class OrchestratorExecutor {
335
334
  }
336
335
  else {
337
336
  this.clearTaskTimeout(taskId);
337
+ this.agentRunner.markTaskCompleted(taskId);
338
338
  await this.scheduler.markTaskFailed(taskId, result.error || 'Unknown error');
339
339
  }
340
340
  return {};
@@ -525,6 +525,7 @@ class OrchestratorExecutor {
525
525
  console.error(`⏰ 任务超时: ${taskId} (${timeoutSeconds}s)`);
526
526
  logger_js_1.logger.task.timeout(taskId, timeoutSeconds);
527
527
  this.taskTimers.delete(taskId);
528
+ this.agentRunner.markTaskCompleted(taskId);
528
529
  await this.scheduler.markTaskFailed(taskId, `Task timed out after ${timeoutSeconds}s`);
529
530
  }, this.config.taskTimeout);
530
531
  this.taskTimers.set(taskId, timer);
@@ -874,13 +874,20 @@ ACCEPT_FAILED
874
874
  async processPhaseResult(task, phase, result) {
875
875
  const now = new Date().toISOString();
876
876
  if (result.success) {
877
+ // 计算阶段耗时
878
+ const phaseKey = phase;
879
+ const phaseData = task.phases?.[phaseKey];
880
+ const startedAt = phaseData?.startedAt;
881
+ const duration = startedAt
882
+ ? Math.round((new Date(now).getTime() - new Date(startedAt).getTime()) / 1000)
883
+ : 0;
877
884
  // 更新阶段状态
878
885
  const updates = {
879
886
  phases: {
880
887
  ...task.phases,
881
888
  [phase]: {
882
889
  status: 'completed',
883
- duration: 0,
890
+ duration,
884
891
  completedAt: now
885
892
  }
886
893
  }
@@ -262,14 +262,17 @@ class Scheduler {
262
262
  this.cycleCacheKey = hash;
263
263
  this.lastCycleCheck = now;
264
264
  // 标记阻塞任务
265
+ const blockedIds = new Set();
265
266
  for (const cycle of cycles) {
266
267
  for (const taskId of cycle) {
268
+ if (blockedIds.has(taskId))
269
+ continue;
267
270
  const task = tasks.find(t => t.id === taskId);
268
271
  if (task && (task.status === 'pending' || task.status === 'retry_queue')) {
269
- await this.stateManager.updateTask(taskId, {
270
- status: 'blocked',
272
+ await this.transitionTask(taskId, 'block', {
271
273
  error: `循环依赖检测: ${cycle.join(' → ')}`
272
274
  });
275
+ blockedIds.add(taskId);
273
276
  }
274
277
  }
275
278
  }
@@ -3,16 +3,19 @@ import type { Task, TaskStatus } from '../types/index.js';
3
3
  * 任务状态转换规则
4
4
  *
5
5
  * pending → scheduled → in_progress → verify → accept → completed
6
- * │ │ │
7
- * │ ▼ ▼ ▼
8
- * blocked failed failed
9
- * │ │ │ │
10
- * └────────┘
11
- * waiting
12
- * │ │
13
- * └────────────┴──────────► retry_queue
6
+ * │ │ │
7
+ * ├──────► blocked ◄──────┘ ▼ ▼
8
+ * failed ◄─ failed
9
+ *
10
+ * waiting
11
+ * retry_queue
12
+ * │ │ │ │
13
+ * └────────────┴───────────────────┘ └──► blocked
14
+ *
15
+ * retry_queue → in_progress (直接重试)
16
+ * scheduled/blocked/waiting → failed
14
17
  */
15
- export type TransitionEvent = 'schedule' | 'start' | 'develop_done' | 'verify_done' | 'accept_done' | 'need_verify' | 'need_accept' | 'block' | 'unblock' | 'wait' | 'resume' | 'fail' | 'retry' | 'cancel';
18
+ export type TransitionEvent = 'schedule' | 'start' | 'develop_done' | 'verify_done' | 'accept_done' | 'block' | 'wait' | 'resume' | 'fail' | 'retry' | 'cancel';
16
19
  export interface TransitionResult {
17
20
  success: boolean;
18
21
  fromStatus: TaskStatus;
@@ -9,6 +9,12 @@ const TRANSITIONS = [
9
9
  { from: 'scheduled', to: 'in_progress', event: 'start' },
10
10
  // pending → in_progress (跳过 scheduled,直接开始)
11
11
  { from: 'pending', to: 'in_progress', event: 'start' },
12
+ // retry_queue → in_progress (重试后直接开始)
13
+ { from: 'retry_queue', to: 'in_progress', event: 'start' },
14
+ // pending → blocked (循环依赖检测)
15
+ { from: 'pending', to: 'blocked', event: 'block' },
16
+ // retry_queue → blocked (循环依赖检测)
17
+ { from: 'retry_queue', to: 'blocked', event: 'block' },
12
18
  // in_progress → verify
13
19
  { from: 'in_progress', to: 'verify', event: 'develop_done' },
14
20
  // verify → accept
@@ -25,6 +31,9 @@ const TRANSITIONS = [
25
31
  { from: 'in_progress', to: 'failed', event: 'fail' },
26
32
  { from: 'verify', to: 'failed', event: 'fail' },
27
33
  { from: 'accept', to: 'failed', event: 'fail' },
34
+ { from: 'scheduled', to: 'failed', event: 'fail' },
35
+ { from: 'blocked', to: 'failed', event: 'fail' },
36
+ { from: 'waiting', to: 'failed', event: 'fail' },
28
37
  // failed → retry_queue
29
38
  { from: 'failed', to: 'retry_queue', event: 'retry' },
30
39
  // retry_queue → pending (安全上限 100,由 executor 层控制具体 maxRetries)
@@ -110,10 +119,7 @@ class StateMachine {
110
119
  'develop_done': '开发完成',
111
120
  'verify_done': '验证完成',
112
121
  'accept_done': '验收完成',
113
- 'need_verify': '需要验证',
114
- 'need_accept': '需要验收',
115
122
  'block': '阻塞任务',
116
- 'unblock': '解除阻塞',
117
123
  'wait': '等待外部',
118
124
  'resume': '恢复执行',
119
125
  'fail': '标记失败',
@@ -1368,7 +1368,7 @@ ${typeConfig.runCommand}
1368
1368
  if (b.title.startsWith('系统集成:') && devTaskIds.length > 0) {
1369
1369
  // 集成任务依赖当前阶段的所有开发任务
1370
1370
  const currentDeps = b.dependencies;
1371
- if (currentDeps.every(d => devTaskIds.includes(d) || !devTaskIds.includes(d))) {
1371
+ if (currentDeps.length === 0 || currentDeps.some(d => devTaskIds.includes(d))) {
1372
1372
  integrationTaskId = b.taskId;
1373
1373
  }
1374
1374
  }
@@ -292,19 +292,13 @@ class StateManager {
292
292
  // 从文件重新读取最新状态(不用缓存,避免 stale)
293
293
  const state = await this.store.readJson('state.json') ?? await this.getState();
294
294
  const stats = { ...state.statistics };
295
- // 扩展统计字段(如果不存在则初始化)
296
- if (!('scheduled' in stats))
297
- stats.scheduled = 0;
298
- if (!('blocked' in stats))
299
- stats.blocked = 0;
300
- if (!('waiting' in stats))
301
- stats.waiting = 0;
302
- if (!('verify' in stats))
303
- stats.verify = 0;
304
- if (!('accept' in stats))
305
- stats.accept = 0;
306
- if (!('retry_queue' in stats))
307
- stats.retry_queue = 0;
295
+ // 确保扩展统计字段已初始化
296
+ stats.scheduled ??= 0;
297
+ stats.blocked ??= 0;
298
+ stats.waiting ??= 0;
299
+ stats.verify ??= 0;
300
+ stats.accept ??= 0;
301
+ stats.retry_queue ??= 0;
308
302
  // Decrement old status count
309
303
  if (oldStatus === 'pending')
310
304
  stats.pending--;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmatrix",
3
- "version": "0.2.21",
3
+ "version": "0.2.23",
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",
@@ -41,18 +41,18 @@
41
41
  "url": "https://github.com/bigfish1913/openmatrix/issues"
42
42
  },
43
43
  "dependencies": {
44
- "@types/node": "^22.0.0",
45
44
  "chalk": "^5.6.2",
46
45
  "chokidar": "^5.0.0",
47
46
  "commander": "^14.0.3",
48
- "typescript": "^5.3.3",
49
47
  "winston": "^3.19.0"
50
48
  },
51
49
  "devDependencies": {
50
+ "@types/node": "^22.0.0",
52
51
  "@typescript-eslint/eslint-plugin": "^8.58.1",
53
52
  "@typescript-eslint/parser": "^8.58.1",
54
53
  "@vitest/coverage-v8": "^1.6.1",
55
54
  "eslint": "^10.2.0",
55
+ "typescript": "^5.3.3",
56
56
  "vitest": "^1.6.0"
57
57
  },
58
58
  "engines": {
package/skills/deploy.md CHANGED
@@ -91,6 +91,80 @@ cat requirements.txt pyproject.toml 2>/dev/null
91
91
 
92
92
  ---
93
93
 
94
+ ## Step 2.1: 检测并优化依赖源
95
+
96
+ 检测项目使用的包管理器和镜像源,如果是国外慢源则建议替换为国内镜像:
97
+
98
+ ```bash
99
+ # npm/yarn/pnpm 源
100
+ npm config get registry 2>/dev/null
101
+ cat .npmrc 2>/dev/null
102
+ cat .yarnrc 2>/dev/null
103
+ cat .yarnrc.yml 2>/dev/null
104
+
105
+ # pip 源
106
+ cat pip.conf 2>/dev/null
107
+ pip config get global.index-url 2>/dev/null
108
+
109
+ # Docker 镜像源
110
+ cat /etc/docker/daemon.json 2>/dev/null
111
+ cat ~/.docker/daemon.json 2>/dev/null
112
+
113
+ # Go 代理
114
+ go env GOPROXY 2>/dev/null
115
+
116
+ # Rust 源
117
+ cat ~/.cargo/config.toml 2>/dev/null
118
+
119
+ # Gradle/Maven 源
120
+ cat build.gradle 2>/dev/null | grep -i "repositories" -A 5
121
+ cat pom.xml 2>/dev/null | grep -i "mirror" -A 5
122
+ ```
123
+
124
+ **AI 分析源速度,如果检测到国外源,建议替换:**
125
+
126
+ | 包管理器 | 国外源 | 国内镜像 |
127
+ |---------|--------|---------|
128
+ | npm/yarn/pnpm | registry.npmjs.org | https://registry.npmmirror.com |
129
+ | pip | pypi.org | https://pypi.tuna.tsinghua.edu.cn/simple |
130
+ | Docker | docker.io | mirror.ccs.tencentyun.com |
131
+ | Go | proxy.golang.org | https://goproxy.cn,direct |
132
+ | Rust/Cargo | crates.io | https://rsproxy.cn/crates.io-index |
133
+ | Gradle/Maven | repo.maven.apache.org | https://maven.aliyun.com/repository/public |
134
+
135
+ **如果检测到慢源,输出建议并询问:**
136
+
137
+ ```
138
+ AskUserQuestion:
139
+ header: "镜像源"
140
+ question: "检测到 npm 使用官方源(registry.npmjs.org),国内访问较慢。是否切换到国内镜像?"
141
+
142
+ options:
143
+ - label: "切换到淘宝镜像 (推荐)"
144
+ description: "npmmirror.com,国内速度快,同步延迟 < 10 分钟"
145
+ - label: "保持不变"
146
+ description: "当前源可用,不需要切换"
147
+ - label: "使用其他镜像"
148
+ description: "指定自定义镜像地址"
149
+ ```
150
+
151
+ **用户确认后执行切换:**
152
+ ```bash
153
+ # npm
154
+ npm config set registry https://registry.npmmirror.com
155
+
156
+ # pip
157
+ pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
158
+
159
+ # Go
160
+ go env -w GOPROXY=https://goproxy.cn,direct
161
+
162
+ # Dockerfile 中的 apt 源(如果有)
163
+ # AI 读取 Dockerfile,将 archive.ubuntu.com 替换为 mirrors.aliyun.com
164
+ ```
165
+
166
+ ---
167
+
94
168
  ## Step 3: 检测系统环境
95
169
 
96
170
  ```bash
@@ -181,6 +255,40 @@ AskUserQuestion:
181
255
 
182
256
  ---
183
257
 
258
+ ## Step 6.1: 生成部署任务清单
259
+
260
+ 根据前面的分析和用户选择,将所有部署步骤写入 TodoWrite,逐条执行:
261
+
262
+ **示例(Docker 本地部署 + 源优化 + 脚本生成):**
263
+
264
+ ```typescript
265
+ TodoWrite({
266
+ todos: [
267
+ { content: "切换 npm 源到淘宝镜像", activeForm: "正在切换 npm 镜像源", status: "pending" },
268
+ { content: "构建 Docker 镜像", activeForm: "正在构建 Docker 镜像", status: "pending" },
269
+ { content: "启动容器", activeForm: "正在启动容器", status: "pending" },
270
+ { content: "验证部署:容器状态", activeForm: "正在检查容器状态", status: "pending" },
271
+ { content: "验证部署:端口监听", activeForm: "正在检查端口", status: "pending" },
272
+ { content: "验证部署:HTTP 连通", activeForm: "正在验证 HTTP 连通性", status: "pending" },
273
+ { content: "生成 Taskfile.yml 一键脚本", activeForm: "正在生成一键脚本", status: "pending" },
274
+ { content: "保存部署配置", activeForm: "正在保存部署配置", status: "pending" }
275
+ ]
276
+ })
277
+ ```
278
+
279
+ **任务清单根据实际情况动态生成:**
280
+ - 需要切换源 → 加入源切换任务
281
+ - 需要生成 Dockerfile → 加入生成任务
282
+ - 多服务 → 每个服务一条任务
283
+ - 选择生成脚本 → 加入脚本生成任务
284
+
285
+ **执行规则:**
286
+ - 每次只执行一条,完成后立即标记 completed
287
+ - 失败时停止,输出错误信息
288
+ - 用户可以看到整体进度
289
+
290
+ ---
291
+
184
292
  ## Step 7: 执行部署
185
293
 
186
294
  根据用户选择,AI 执行对应命令: