@shareai-lab/kode-sdk 2.7.1 → 2.7.2

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.
Files changed (97) hide show
  1. package/dist/core/agent/breakpoint-manager.js +36 -0
  2. package/dist/core/agent/message-queue.js +57 -0
  3. package/dist/core/agent/permission-manager.js +32 -0
  4. package/dist/core/agent/todo-manager.js +91 -0
  5. package/dist/core/agent/tool-runner.js +45 -0
  6. package/dist/core/agent.js +2035 -0
  7. package/dist/core/config.js +2 -0
  8. package/dist/core/context-manager.js +241 -0
  9. package/dist/core/errors.js +49 -0
  10. package/dist/core/events.js +329 -0
  11. package/dist/core/file-pool.d.ts +2 -0
  12. package/dist/core/file-pool.js +125 -0
  13. package/dist/core/hooks.js +71 -0
  14. package/dist/core/permission-modes.js +61 -0
  15. package/dist/core/pool.js +301 -0
  16. package/dist/core/room.js +57 -0
  17. package/dist/core/scheduler.js +58 -0
  18. package/dist/core/skills/index.js +20 -0
  19. package/dist/core/skills/management-manager.js +557 -0
  20. package/dist/core/skills/manager.js +243 -0
  21. package/dist/core/skills/operation-queue.js +113 -0
  22. package/dist/core/skills/sandbox-file-manager.js +183 -0
  23. package/dist/core/skills/types.js +9 -0
  24. package/dist/core/skills/xml-generator.js +70 -0
  25. package/dist/core/template.js +35 -0
  26. package/dist/core/time-bridge.js +100 -0
  27. package/dist/core/todo.js +89 -0
  28. package/dist/core/types.js +3 -0
  29. package/dist/index.js +148 -60461
  30. package/dist/infra/db/postgres/postgres-store.js +1073 -0
  31. package/dist/infra/db/sqlite/sqlite-store.js +800 -0
  32. package/dist/infra/e2b/e2b-fs.js +128 -0
  33. package/dist/infra/e2b/e2b-sandbox.js +156 -0
  34. package/dist/infra/e2b/e2b-template.js +105 -0
  35. package/dist/infra/e2b/index.js +9 -0
  36. package/dist/infra/e2b/types.js +2 -0
  37. package/dist/infra/provider.js +67 -0
  38. package/dist/infra/providers/anthropic.js +308 -0
  39. package/dist/infra/providers/core/errors.js +353 -0
  40. package/dist/infra/providers/core/fork.js +418 -0
  41. package/dist/infra/providers/core/index.js +76 -0
  42. package/dist/infra/providers/core/logger.js +191 -0
  43. package/dist/infra/providers/core/retry.js +189 -0
  44. package/dist/infra/providers/core/usage.js +376 -0
  45. package/dist/infra/providers/gemini.js +493 -0
  46. package/dist/infra/providers/index.js +83 -0
  47. package/dist/infra/providers/openai.js +662 -0
  48. package/dist/infra/providers/types.js +20 -0
  49. package/dist/infra/providers/utils.js +400 -0
  50. package/dist/infra/sandbox-factory.js +30 -0
  51. package/dist/infra/sandbox.js +243 -0
  52. package/dist/infra/store/factory.js +80 -0
  53. package/dist/infra/store/index.js +26 -0
  54. package/dist/infra/store/json-store.js +606 -0
  55. package/dist/infra/store/types.js +2 -0
  56. package/dist/infra/store.js +29 -0
  57. package/dist/tools/bash_kill/index.js +35 -0
  58. package/dist/tools/bash_kill/prompt.js +14 -0
  59. package/dist/tools/bash_logs/index.js +40 -0
  60. package/dist/tools/bash_logs/prompt.js +14 -0
  61. package/dist/tools/bash_run/index.js +61 -0
  62. package/dist/tools/bash_run/prompt.js +18 -0
  63. package/dist/tools/builtin.js +26 -0
  64. package/dist/tools/define.js +214 -0
  65. package/dist/tools/fs_edit/index.js +62 -0
  66. package/dist/tools/fs_edit/prompt.js +15 -0
  67. package/dist/tools/fs_glob/index.js +40 -0
  68. package/dist/tools/fs_glob/prompt.js +15 -0
  69. package/dist/tools/fs_grep/index.js +66 -0
  70. package/dist/tools/fs_grep/prompt.js +16 -0
  71. package/dist/tools/fs_multi_edit/index.js +106 -0
  72. package/dist/tools/fs_multi_edit/prompt.js +16 -0
  73. package/dist/tools/fs_read/index.js +40 -0
  74. package/dist/tools/fs_read/prompt.js +16 -0
  75. package/dist/tools/fs_write/index.js +40 -0
  76. package/dist/tools/fs_write/prompt.js +15 -0
  77. package/dist/tools/index.js +61 -0
  78. package/dist/tools/mcp.js +185 -0
  79. package/dist/tools/registry.js +26 -0
  80. package/dist/tools/scripts.js +205 -0
  81. package/dist/tools/skills.js +115 -0
  82. package/dist/tools/task_run/index.js +58 -0
  83. package/dist/tools/task_run/prompt.js +25 -0
  84. package/dist/tools/todo_read/index.js +29 -0
  85. package/dist/tools/todo_read/prompt.js +18 -0
  86. package/dist/tools/todo_write/index.js +42 -0
  87. package/dist/tools/todo_write/prompt.js +23 -0
  88. package/dist/tools/tool.js +211 -0
  89. package/dist/tools/toolkit.js +98 -0
  90. package/dist/tools/type-inference.js +207 -0
  91. package/dist/utils/agent-id.js +28 -0
  92. package/dist/utils/logger.js +44 -0
  93. package/dist/utils/session-id.js +64 -0
  94. package/package.json +7 -38
  95. package/dist/index.js.map +0 -7
  96. package/dist/index.mjs +0 -60385
  97. package/dist/index.mjs.map +0 -7
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FilePool = void 0;
4
+ const logger_1 = require("../utils/logger");
5
+ class FilePool {
6
+ constructor(sandbox, opts) {
7
+ this.sandbox = sandbox;
8
+ this.records = new Map();
9
+ this.watchers = new Map();
10
+ this.watchPending = new Map(); // per-path 锁,防止并发创建 watcher
11
+ this.watchEnabled = opts?.watch ?? true;
12
+ this.onChange = opts?.onChange;
13
+ }
14
+ async getMtime(path) {
15
+ try {
16
+ const stat = await this.sandbox.fs.stat(path);
17
+ return stat.mtimeMs;
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ }
23
+ async recordRead(path) {
24
+ const resolved = this.sandbox.fs.resolve(path);
25
+ const record = this.records.get(resolved) || { path: resolved };
26
+ record.lastRead = Date.now();
27
+ record.lastReadMtime = await this.getMtime(resolved);
28
+ record.lastKnownMtime = record.lastReadMtime;
29
+ this.records.set(resolved, record);
30
+ await this.ensureWatch(resolved);
31
+ }
32
+ async recordEdit(path) {
33
+ const resolved = this.sandbox.fs.resolve(path);
34
+ const record = this.records.get(resolved) || { path: resolved };
35
+ record.lastEdit = Date.now();
36
+ record.lastKnownMtime = await this.getMtime(resolved);
37
+ this.records.set(resolved, record);
38
+ await this.ensureWatch(resolved);
39
+ }
40
+ async validateWrite(path) {
41
+ const resolved = this.sandbox.fs.resolve(path);
42
+ const record = this.records.get(resolved);
43
+ const currentMtime = await this.getMtime(resolved);
44
+ if (!record) {
45
+ return { isFresh: true, currentMtime };
46
+ }
47
+ const isFresh = record.lastRead !== undefined &&
48
+ (currentMtime === undefined || record.lastReadMtime === undefined || currentMtime === record.lastReadMtime);
49
+ return {
50
+ isFresh,
51
+ lastRead: record.lastRead,
52
+ lastEdit: record.lastEdit,
53
+ currentMtime,
54
+ };
55
+ }
56
+ async checkFreshness(path) {
57
+ const resolved = this.sandbox.fs.resolve(path);
58
+ const record = this.records.get(resolved);
59
+ const currentMtime = await this.getMtime(resolved);
60
+ if (!record) {
61
+ return { isFresh: false, currentMtime };
62
+ }
63
+ const isFresh = record.lastRead !== undefined &&
64
+ (currentMtime === undefined || record.lastKnownMtime === undefined || currentMtime === record.lastKnownMtime);
65
+ return {
66
+ isFresh,
67
+ lastRead: record.lastRead,
68
+ lastEdit: record.lastEdit,
69
+ currentMtime,
70
+ };
71
+ }
72
+ getTrackedFiles() {
73
+ return Array.from(this.records.keys());
74
+ }
75
+ async ensureWatch(path) {
76
+ if (!this.watchEnabled)
77
+ return;
78
+ if (!this.sandbox.watchFiles)
79
+ return;
80
+ if (this.watchers.has(path))
81
+ return;
82
+ // 检查是否有正在进行的 watch 操作(per-path 锁)
83
+ const pending = this.watchPending.get(path);
84
+ if (pending) {
85
+ await pending; // 等待已有操作完成
86
+ return;
87
+ }
88
+ // 创建 watch 操作并存储 Promise
89
+ const watchPromise = this.doWatch(path);
90
+ this.watchPending.set(path, watchPromise);
91
+ try {
92
+ await watchPromise;
93
+ }
94
+ finally {
95
+ this.watchPending.delete(path);
96
+ }
97
+ }
98
+ async doWatch(path) {
99
+ // 再次检查(可能在等待期间已被设置)
100
+ if (this.watchers.has(path))
101
+ return;
102
+ if (!this.sandbox.watchFiles)
103
+ return;
104
+ try {
105
+ const id = await this.sandbox.watchFiles([path], (event) => {
106
+ const record = this.records.get(path);
107
+ if (record) {
108
+ record.lastKnownMtime = event.mtimeMs;
109
+ }
110
+ this.onChange?.({ path, mtime: event.mtimeMs });
111
+ });
112
+ this.watchers.set(path, id);
113
+ }
114
+ catch (err) {
115
+ // 记录 watch 失败,但不中断流程
116
+ logger_1.logger.warn(`[FilePool] Failed to watch file: ${path}`, err);
117
+ }
118
+ }
119
+ getAccessedFiles() {
120
+ return Array.from(this.records.values())
121
+ .filter((r) => r.lastKnownMtime !== undefined)
122
+ .map((r) => ({ path: r.path, mtime: r.lastKnownMtime }));
123
+ }
124
+ }
125
+ exports.FilePool = FilePool;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HookManager = void 0;
4
+ class HookManager {
5
+ constructor() {
6
+ this.hooks = [];
7
+ }
8
+ register(hooks, origin = 'agent') {
9
+ this.hooks.push({ hooks, origin });
10
+ }
11
+ getRegistered() {
12
+ return this.hooks.map(({ hooks, origin }) => ({
13
+ origin,
14
+ names: [
15
+ hooks.preToolUse && 'preToolUse',
16
+ hooks.postToolUse && 'postToolUse',
17
+ hooks.preModel && 'preModel',
18
+ hooks.postModel && 'postModel',
19
+ ].filter(Boolean),
20
+ }));
21
+ }
22
+ async runPreToolUse(call, ctx) {
23
+ for (const { hooks } of this.hooks) {
24
+ if (hooks.preToolUse) {
25
+ const result = await hooks.preToolUse(call, ctx);
26
+ if (result)
27
+ return result;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ async runPostToolUse(outcome, ctx) {
33
+ let current = outcome;
34
+ for (const { hooks } of this.hooks) {
35
+ if (hooks.postToolUse) {
36
+ const result = await hooks.postToolUse(current, ctx);
37
+ if (result && typeof result === 'object') {
38
+ if ('replace' in result) {
39
+ current = result.replace;
40
+ }
41
+ else if ('update' in result) {
42
+ current = { ...current, ...result.update };
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return current;
48
+ }
49
+ async runPreModel(request) {
50
+ for (const { hooks } of this.hooks) {
51
+ if (hooks.preModel) {
52
+ await hooks.preModel(request);
53
+ }
54
+ }
55
+ }
56
+ async runPostModel(response) {
57
+ for (const { hooks } of this.hooks) {
58
+ if (hooks.postModel) {
59
+ await hooks.postModel(response);
60
+ }
61
+ }
62
+ }
63
+ async runMessagesChanged(snapshot) {
64
+ for (const { hooks } of this.hooks) {
65
+ if (hooks.messagesChanged) {
66
+ await hooks.messagesChanged(snapshot);
67
+ }
68
+ }
69
+ }
70
+ }
71
+ exports.HookManager = HookManager;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.permissionModes = exports.PermissionModeRegistry = void 0;
4
+ class PermissionModeRegistry {
5
+ constructor() {
6
+ this.handlers = new Map();
7
+ this.customModes = new Set();
8
+ }
9
+ register(mode, handler, isBuiltIn = false) {
10
+ this.handlers.set(mode, handler);
11
+ if (!isBuiltIn) {
12
+ this.customModes.add(mode);
13
+ }
14
+ }
15
+ get(mode) {
16
+ return this.handlers.get(mode);
17
+ }
18
+ list() {
19
+ return Array.from(this.handlers.keys());
20
+ }
21
+ /**
22
+ * 序列化权限模式配置
23
+ * 仅序列化自定义模式的名称,内置模式在 Resume 时自动恢复
24
+ */
25
+ serialize() {
26
+ return Array.from(this.handlers.keys()).map(name => ({
27
+ name,
28
+ builtIn: !this.customModes.has(name)
29
+ }));
30
+ }
31
+ /**
32
+ * 验证序列化的权限模式是否可恢复
33
+ * 返回缺失的自定义模式列表
34
+ */
35
+ validateRestore(serialized) {
36
+ const missing = [];
37
+ for (const mode of serialized) {
38
+ if (!mode.builtIn && !this.handlers.has(mode.name)) {
39
+ missing.push(mode.name);
40
+ }
41
+ }
42
+ return missing;
43
+ }
44
+ }
45
+ exports.PermissionModeRegistry = PermissionModeRegistry;
46
+ exports.permissionModes = new PermissionModeRegistry();
47
+ const MUTATING_ACCESS = new Set(['write', 'execute', 'manage', 'mutate']);
48
+ // 内置模式
49
+ exports.permissionModes.register('auto', () => 'allow', true);
50
+ exports.permissionModes.register('approval', () => 'ask', true);
51
+ exports.permissionModes.register('readonly', (ctx) => {
52
+ const metadata = ctx.descriptor?.metadata || {};
53
+ if (metadata.mutates === true)
54
+ return 'deny';
55
+ if (metadata.mutates === false)
56
+ return 'allow';
57
+ const access = typeof metadata.access === 'string' ? metadata.access.toLowerCase() : undefined;
58
+ if (access && MUTATING_ACCESS.has(access))
59
+ return 'deny';
60
+ return 'ask';
61
+ }, true);
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentPool = void 0;
4
+ const agent_1 = require("./agent");
5
+ const logger_1 = require("../utils/logger");
6
+ class AgentPool {
7
+ constructor(opts) {
8
+ this.agents = new Map();
9
+ this.deps = opts.dependencies;
10
+ this.maxAgents = opts.maxAgents || 50;
11
+ }
12
+ async create(agentId, config) {
13
+ if (this.agents.has(agentId)) {
14
+ throw new Error(`Agent already exists: ${agentId}`);
15
+ }
16
+ if (this.agents.size >= this.maxAgents) {
17
+ throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
18
+ }
19
+ const agent = await agent_1.Agent.create({ ...config, agentId }, this.deps);
20
+ this.agents.set(agentId, agent);
21
+ return agent;
22
+ }
23
+ get(agentId) {
24
+ return this.agents.get(agentId);
25
+ }
26
+ list(opts) {
27
+ const ids = Array.from(this.agents.keys());
28
+ return opts?.prefix ? ids.filter((id) => id.startsWith(opts.prefix)) : ids;
29
+ }
30
+ async status(agentId) {
31
+ const agent = this.agents.get(agentId);
32
+ return agent ? await agent.status() : undefined;
33
+ }
34
+ async fork(agentId, snapshotSel) {
35
+ const agent = this.agents.get(agentId);
36
+ if (!agent) {
37
+ throw new Error(`Agent not found: ${agentId}`);
38
+ }
39
+ return agent.fork(snapshotSel);
40
+ }
41
+ async resume(agentId, config, opts) {
42
+ // 1. Check if already in pool
43
+ if (this.agents.has(agentId)) {
44
+ return this.agents.get(agentId);
45
+ }
46
+ // 2. Check pool capacity
47
+ if (this.agents.size >= this.maxAgents) {
48
+ throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
49
+ }
50
+ // 3. Verify session exists
51
+ const exists = await this.deps.store.exists(agentId);
52
+ if (!exists) {
53
+ throw new Error(`Agent not found in store: ${agentId}`);
54
+ }
55
+ // 4. Use Agent.resume() to restore
56
+ const agent = await agent_1.Agent.resume(agentId, { ...config, agentId }, this.deps, opts);
57
+ // 5. Add to pool
58
+ this.agents.set(agentId, agent);
59
+ return agent;
60
+ }
61
+ async resumeAll(configFactory, opts) {
62
+ const agentIds = await this.deps.store.list();
63
+ const resumed = [];
64
+ for (const agentId of agentIds) {
65
+ if (this.agents.size >= this.maxAgents)
66
+ break;
67
+ if (this.agents.has(agentId))
68
+ continue;
69
+ try {
70
+ const config = configFactory(agentId);
71
+ const agent = await this.resume(agentId, config, opts);
72
+ resumed.push(agent);
73
+ }
74
+ catch (error) {
75
+ logger_1.logger.error(`Failed to resume ${agentId}:`, error);
76
+ }
77
+ }
78
+ return resumed;
79
+ }
80
+ async delete(agentId) {
81
+ this.agents.delete(agentId);
82
+ await this.deps.store.delete(agentId);
83
+ }
84
+ size() {
85
+ return this.agents.size;
86
+ }
87
+ /**
88
+ * Gracefully shutdown all agents in the pool
89
+ * 1. Stop accepting new operations
90
+ * 2. Wait for running agents to complete current step
91
+ * 3. Persist all agent states
92
+ * 4. Optionally save running agents list for recovery
93
+ */
94
+ async gracefulShutdown(opts) {
95
+ const startTime = Date.now();
96
+ const timeout = opts?.timeout ?? 30000;
97
+ const saveRunningList = opts?.saveRunningList ?? true;
98
+ const forceInterrupt = opts?.forceInterrupt ?? true;
99
+ const result = {
100
+ completed: [],
101
+ interrupted: [],
102
+ failed: [],
103
+ durationMs: 0,
104
+ };
105
+ const agentIds = Array.from(this.agents.keys());
106
+ logger_1.logger.info(`[AgentPool] Starting graceful shutdown for ${agentIds.length} agents`);
107
+ // Group agents by state
108
+ const workingAgents = [];
109
+ const readyAgents = [];
110
+ for (const [id, agent] of this.agents) {
111
+ const status = await agent.status();
112
+ if (status.state === 'WORKING') {
113
+ workingAgents.push({ id, agent });
114
+ }
115
+ else {
116
+ readyAgents.push({ id, agent });
117
+ }
118
+ }
119
+ // 1. Persist ready agents immediately
120
+ for (const { id, agent } of readyAgents) {
121
+ try {
122
+ await this.persistAgentState(agent);
123
+ result.completed.push(id);
124
+ }
125
+ catch (error) {
126
+ logger_1.logger.error(`[AgentPool] Failed to persist agent ${id}:`, error);
127
+ result.failed.push(id);
128
+ }
129
+ }
130
+ // 2. Wait for working agents with timeout
131
+ if (workingAgents.length > 0) {
132
+ logger_1.logger.info(`[AgentPool] Waiting for ${workingAgents.length} working agents...`);
133
+ const waitPromises = workingAgents.map(async ({ id, agent }) => {
134
+ try {
135
+ const completed = await this.waitForAgentReady(agent, timeout);
136
+ if (completed) {
137
+ await this.persistAgentState(agent);
138
+ return { id, status: 'completed' };
139
+ }
140
+ else if (forceInterrupt) {
141
+ await agent.interrupt({ note: 'Graceful shutdown timeout' });
142
+ await this.persistAgentState(agent);
143
+ return { id, status: 'interrupted' };
144
+ }
145
+ else {
146
+ return { id, status: 'interrupted' };
147
+ }
148
+ }
149
+ catch (error) {
150
+ logger_1.logger.error(`[AgentPool] Error during shutdown for agent ${id}:`, error);
151
+ return { id, status: 'failed' };
152
+ }
153
+ });
154
+ const results = await Promise.all(waitPromises);
155
+ for (const { id, status } of results) {
156
+ if (status === 'completed') {
157
+ result.completed.push(id);
158
+ }
159
+ else if (status === 'interrupted') {
160
+ result.interrupted.push(id);
161
+ }
162
+ else {
163
+ result.failed.push(id);
164
+ }
165
+ }
166
+ }
167
+ // 3. Save running agents list for recovery
168
+ if (saveRunningList) {
169
+ try {
170
+ await this.saveRunningAgentsList(agentIds);
171
+ logger_1.logger.info(`[AgentPool] Saved running agents list: ${agentIds.length} agents`);
172
+ }
173
+ catch (error) {
174
+ logger_1.logger.error(`[AgentPool] Failed to save running agents list:`, error);
175
+ }
176
+ }
177
+ result.durationMs = Date.now() - startTime;
178
+ logger_1.logger.info(`[AgentPool] Graceful shutdown completed in ${result.durationMs}ms`, {
179
+ completed: result.completed.length,
180
+ interrupted: result.interrupted.length,
181
+ failed: result.failed.length,
182
+ });
183
+ return result;
184
+ }
185
+ /**
186
+ * Resume agents from a previous graceful shutdown
187
+ * Reads the running agents list and resumes each agent
188
+ */
189
+ async resumeFromShutdown(configFactory, opts) {
190
+ const runningList = await this.loadRunningAgentsList();
191
+ if (!runningList || runningList.length === 0) {
192
+ logger_1.logger.info('[AgentPool] No running agents list found, nothing to resume');
193
+ return [];
194
+ }
195
+ logger_1.logger.info(`[AgentPool] Resuming ${runningList.length} agents from shutdown`);
196
+ const resumed = [];
197
+ for (const agentId of runningList) {
198
+ if (this.agents.size >= this.maxAgents) {
199
+ logger_1.logger.warn(`[AgentPool] Pool is full, cannot resume more agents`);
200
+ break;
201
+ }
202
+ try {
203
+ const config = configFactory(agentId);
204
+ const agent = await this.resume(agentId, config, {
205
+ autoRun: opts?.autoRun ?? false,
206
+ strategy: opts?.strategy ?? 'crash',
207
+ });
208
+ resumed.push(agent);
209
+ }
210
+ catch (error) {
211
+ logger_1.logger.error(`[AgentPool] Failed to resume agent ${agentId}:`, error);
212
+ }
213
+ }
214
+ // Clear the running agents list after successful resume
215
+ await this.clearRunningAgentsList();
216
+ logger_1.logger.info(`[AgentPool] Resumed ${resumed.length}/${runningList.length} agents`);
217
+ return resumed;
218
+ }
219
+ /**
220
+ * Register signal handlers for graceful shutdown
221
+ * Call this in your server setup code
222
+ */
223
+ registerShutdownHandlers(configFactory, opts) {
224
+ const handler = async (signal) => {
225
+ logger_1.logger.info(`[AgentPool] Received ${signal}, initiating graceful shutdown...`);
226
+ try {
227
+ const result = await this.gracefulShutdown(opts);
228
+ logger_1.logger.info(`[AgentPool] Shutdown complete:`, result);
229
+ process.exit(0);
230
+ }
231
+ catch (error) {
232
+ logger_1.logger.error(`[AgentPool] Shutdown failed:`, error);
233
+ process.exit(1);
234
+ }
235
+ };
236
+ process.on('SIGTERM', () => handler('SIGTERM'));
237
+ process.on('SIGINT', () => handler('SIGINT'));
238
+ logger_1.logger.info('[AgentPool] Shutdown handlers registered for SIGTERM and SIGINT');
239
+ }
240
+ // ========== Private Helper Methods ==========
241
+ async waitForAgentReady(agent, timeout) {
242
+ const startTime = Date.now();
243
+ const pollInterval = 100; // ms
244
+ while (Date.now() - startTime < timeout) {
245
+ const status = await agent.status();
246
+ if (status.state !== 'WORKING') {
247
+ return true;
248
+ }
249
+ await this.sleep(pollInterval);
250
+ }
251
+ return false;
252
+ }
253
+ async persistAgentState(agent) {
254
+ // Agent's internal persist methods are private, so we rely on the fact that
255
+ // state is automatically persisted during normal operation.
256
+ // This is a no-op placeholder for potential future explicit persist calls.
257
+ // The agent's state is already persisted via WAL mechanism.
258
+ }
259
+ async saveRunningAgentsList(agentIds) {
260
+ const meta = {
261
+ agentIds,
262
+ shutdownAt: new Date().toISOString(),
263
+ version: '1.0.0',
264
+ };
265
+ // Use the store's saveInfo to persist to a special key
266
+ // We use a well-known agent ID prefix for pool metadata
267
+ const poolMetaId = '__pool_meta__';
268
+ await this.deps.store.saveInfo(poolMetaId, {
269
+ agentId: poolMetaId,
270
+ templateId: '__pool_meta__',
271
+ createdAt: new Date().toISOString(),
272
+ runningAgents: meta,
273
+ });
274
+ }
275
+ async loadRunningAgentsList() {
276
+ const poolMetaId = '__pool_meta__';
277
+ try {
278
+ const info = await this.deps.store.loadInfo(poolMetaId);
279
+ if (info && info.runningAgents) {
280
+ return info.runningAgents.agentIds;
281
+ }
282
+ }
283
+ catch {
284
+ // Ignore errors, return null
285
+ }
286
+ return null;
287
+ }
288
+ async clearRunningAgentsList() {
289
+ const poolMetaId = '__pool_meta__';
290
+ try {
291
+ await this.deps.store.delete(poolMetaId);
292
+ }
293
+ catch {
294
+ // Ignore errors
295
+ }
296
+ }
297
+ sleep(ms) {
298
+ return new Promise((resolve) => setTimeout(resolve, ms));
299
+ }
300
+ }
301
+ exports.AgentPool = AgentPool;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Room = void 0;
4
+ class Room {
5
+ constructor(pool) {
6
+ this.pool = pool;
7
+ this.members = new Map();
8
+ }
9
+ join(name, agentId) {
10
+ if (this.members.has(name)) {
11
+ throw new Error(`Member already exists: ${name}`);
12
+ }
13
+ this.members.set(name, agentId);
14
+ }
15
+ leave(name) {
16
+ this.members.delete(name);
17
+ }
18
+ async say(from, text) {
19
+ const mentions = this.extractMentions(text);
20
+ if (mentions.length > 0) {
21
+ // Directed message
22
+ for (const mention of mentions) {
23
+ const agentId = this.members.get(mention);
24
+ if (agentId) {
25
+ const agent = this.pool.get(agentId);
26
+ if (agent) {
27
+ await agent.complete(`[from:${from}] ${text}`);
28
+ }
29
+ }
30
+ }
31
+ }
32
+ else {
33
+ // Broadcast to all except sender
34
+ for (const [name, agentId] of this.members) {
35
+ if (name !== from) {
36
+ const agent = this.pool.get(agentId);
37
+ if (agent) {
38
+ await agent.complete(`[from:${from}] ${text}`);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ getMembers() {
45
+ return Array.from(this.members.entries()).map(([name, agentId]) => ({ name, agentId }));
46
+ }
47
+ extractMentions(text) {
48
+ const regex = /@(\w+)/g;
49
+ const mentions = [];
50
+ let match;
51
+ while ((match = regex.exec(text)) !== null) {
52
+ mentions.push(match[1]);
53
+ }
54
+ return mentions;
55
+ }
56
+ }
57
+ exports.Room = Room;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Scheduler = void 0;
4
+ class Scheduler {
5
+ constructor(opts) {
6
+ this.stepTasks = new Map();
7
+ this.listeners = new Set();
8
+ this.queued = Promise.resolve();
9
+ this.onTrigger = opts?.onTrigger;
10
+ }
11
+ everySteps(every, callback) {
12
+ if (!Number.isFinite(every) || every <= 0) {
13
+ throw new Error('everySteps: interval must be positive');
14
+ }
15
+ const id = this.generateId('steps');
16
+ this.stepTasks.set(id, {
17
+ id,
18
+ every,
19
+ callback,
20
+ lastTriggered: 0,
21
+ });
22
+ return id;
23
+ }
24
+ onStep(callback) {
25
+ this.listeners.add(callback);
26
+ return () => this.listeners.delete(callback);
27
+ }
28
+ enqueue(callback) {
29
+ this.queued = this.queued.then(() => Promise.resolve(callback())).catch(() => undefined);
30
+ }
31
+ notifyStep(stepCount) {
32
+ for (const listener of this.listeners) {
33
+ void Promise.resolve(listener({ stepCount }));
34
+ }
35
+ for (const task of this.stepTasks.values()) {
36
+ const shouldTrigger = stepCount - task.lastTriggered >= task.every;
37
+ if (!shouldTrigger)
38
+ continue;
39
+ task.lastTriggered = stepCount;
40
+ void Promise.resolve(task.callback({ stepCount }));
41
+ this.onTrigger?.({ taskId: task.id, spec: `steps:${task.every}`, kind: 'steps' });
42
+ }
43
+ }
44
+ cancel(taskId) {
45
+ this.stepTasks.delete(taskId);
46
+ }
47
+ clear() {
48
+ this.stepTasks.clear();
49
+ this.listeners.clear();
50
+ }
51
+ notifyExternalTrigger(info) {
52
+ this.onTrigger?.(info);
53
+ }
54
+ generateId(prefix) {
55
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
56
+ }
57
+ }
58
+ exports.Scheduler = Scheduler;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Skills 模块导出
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SandboxFileManager = exports.OperationStatus = exports.OperationType = exports.OperationQueue = exports.SkillsManagementManager = exports.generateSkillsMetadataXml = exports.SkillsManager = void 0;
7
+ // 路径2: Agent使用(现有模块)
8
+ var manager_1 = require("./manager");
9
+ Object.defineProperty(exports, "SkillsManager", { enumerable: true, get: function () { return manager_1.SkillsManager; } });
10
+ var xml_generator_1 = require("./xml-generator");
11
+ Object.defineProperty(exports, "generateSkillsMetadataXml", { enumerable: true, get: function () { return xml_generator_1.generateSkillsMetadataXml; } });
12
+ // 路径1: 技能管理(新增模块)
13
+ var management_manager_1 = require("./management-manager");
14
+ Object.defineProperty(exports, "SkillsManagementManager", { enumerable: true, get: function () { return management_manager_1.SkillsManagementManager; } });
15
+ var operation_queue_1 = require("./operation-queue");
16
+ Object.defineProperty(exports, "OperationQueue", { enumerable: true, get: function () { return operation_queue_1.OperationQueue; } });
17
+ Object.defineProperty(exports, "OperationType", { enumerable: true, get: function () { return operation_queue_1.OperationType; } });
18
+ Object.defineProperty(exports, "OperationStatus", { enumerable: true, get: function () { return operation_queue_1.OperationStatus; } });
19
+ var sandbox_file_manager_1 = require("./sandbox-file-manager");
20
+ Object.defineProperty(exports, "SandboxFileManager", { enumerable: true, get: function () { return sandbox_file_manager_1.SandboxFileManager; } });