@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,606 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JSONStore = void 0;
4
+ const logger_1 = require("../../utils/logger");
5
+ class JSONStore {
6
+ constructor(baseDir, flushIntervalMs = 50) {
7
+ this.baseDir = baseDir;
8
+ this.flushIntervalMs = flushIntervalMs;
9
+ this.eventWriters = new Map();
10
+ this.walQueue = new Map();
11
+ this.walRecovered = new Set();
12
+ // 启动时主动扫描并恢复所有 WAL
13
+ void this.recoverAllWALs();
14
+ }
15
+ // ========== 路径管理 ==========
16
+ getAgentDir(agentId) {
17
+ const path = require('path');
18
+ return path.join(this.baseDir, agentId);
19
+ }
20
+ getRuntimePath(agentId, file) {
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+ const dir = path.join(this.baseDir, agentId, 'runtime');
24
+ if (!fs.existsSync(dir)) {
25
+ fs.mkdirSync(dir, { recursive: true });
26
+ }
27
+ return path.join(dir, file);
28
+ }
29
+ getEventsPath(agentId, file) {
30
+ const fs = require('fs');
31
+ const path = require('path');
32
+ const dir = path.join(this.baseDir, agentId, 'events');
33
+ if (!fs.existsSync(dir)) {
34
+ fs.mkdirSync(dir, { recursive: true });
35
+ }
36
+ return path.join(dir, file);
37
+ }
38
+ getHistoryDir(agentId, subdir) {
39
+ const fs = require('fs');
40
+ const path = require('path');
41
+ const dir = path.join(this.baseDir, agentId, 'history', subdir);
42
+ if (!fs.existsSync(dir)) {
43
+ fs.mkdirSync(dir, { recursive: true });
44
+ }
45
+ return dir;
46
+ }
47
+ getMediaCachePath(agentId) {
48
+ return this.getRuntimePath(agentId, 'media-cache.json');
49
+ }
50
+ getSnapshotsDir(agentId) {
51
+ const fs = require('fs');
52
+ const path = require('path');
53
+ const dir = path.join(this.baseDir, agentId, 'snapshots');
54
+ if (!fs.existsSync(dir)) {
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ }
57
+ return dir;
58
+ }
59
+ getMetaPath(agentId) {
60
+ const path = require('path');
61
+ return path.join(this.baseDir, agentId, 'meta.json');
62
+ }
63
+ async writeFileSafe(filePath, data) {
64
+ const fsp = require('fs').promises;
65
+ const path = require('path');
66
+ try {
67
+ await fsp.writeFile(filePath, data, 'utf-8');
68
+ }
69
+ catch (err) {
70
+ if (err?.code !== 'ENOENT')
71
+ throw err;
72
+ await fsp.mkdir(path.dirname(filePath), { recursive: true });
73
+ await fsp.writeFile(filePath, data, 'utf-8');
74
+ }
75
+ }
76
+ async appendFileSafe(filePath, data) {
77
+ const fsp = require('fs').promises;
78
+ const path = require('path');
79
+ try {
80
+ await fsp.appendFile(filePath, data, 'utf-8');
81
+ }
82
+ catch (err) {
83
+ if (err?.code !== 'ENOENT')
84
+ throw err;
85
+ await fsp.mkdir(path.dirname(filePath), { recursive: true });
86
+ await fsp.appendFile(filePath, data, 'utf-8');
87
+ }
88
+ }
89
+ async renameSafe(tmpPath, destPath) {
90
+ const fs = require('fs');
91
+ const fsp = fs.promises;
92
+ const path = require('path');
93
+ try {
94
+ await fsp.rename(tmpPath, destPath);
95
+ }
96
+ catch (err) {
97
+ if (err?.code !== 'ENOENT')
98
+ throw err;
99
+ await fsp.mkdir(path.dirname(destPath), { recursive: true });
100
+ await fsp.rename(tmpPath, destPath);
101
+ }
102
+ }
103
+ // ========== 运行时状态管理(带 WAL) ==========
104
+ async saveMessages(agentId, messages) {
105
+ await this.saveWithWal(agentId, 'messages', messages);
106
+ }
107
+ async loadMessages(agentId) {
108
+ return await this.loadWithWal(agentId, 'messages') || [];
109
+ }
110
+ async saveToolCallRecords(agentId, records) {
111
+ await this.saveWithWal(agentId, 'tool-calls', records);
112
+ }
113
+ async loadToolCallRecords(agentId) {
114
+ return await this.loadWithWal(agentId, 'tool-calls') || [];
115
+ }
116
+ async saveTodos(agentId, snapshot) {
117
+ const path = this.getRuntimePath(agentId, 'todos.json');
118
+ await this.writeFileSafe(path, JSON.stringify(snapshot, null, 2));
119
+ }
120
+ async loadTodos(agentId) {
121
+ const fs = require('fs').promises;
122
+ try {
123
+ const data = await fs.readFile(this.getRuntimePath(agentId, 'todos.json'), 'utf-8');
124
+ return JSON.parse(data);
125
+ }
126
+ catch {
127
+ return undefined;
128
+ }
129
+ }
130
+ // ========== 统一的 WAL 读写策略 ==========
131
+ async saveWithWal(agentId, name, data) {
132
+ const fs = require('fs');
133
+ const path = this.getRuntimePath(agentId, `${name}.json`);
134
+ const walPath = this.getRuntimePath(agentId, `${name}.wal`);
135
+ // 1. Write to WAL first
136
+ const walData = JSON.stringify({ data, timestamp: Date.now() });
137
+ await this.queueWalWrite(agentId, name, async () => {
138
+ await this.writeFileSafe(walPath, walData);
139
+ });
140
+ // 2. Write to main file (atomic: tmp + rename)
141
+ const tmp = `${path}.tmp`;
142
+ const payload = JSON.stringify(data, null, 2);
143
+ await this.writeFileSafe(tmp, payload);
144
+ try {
145
+ await this.renameSafe(tmp, path);
146
+ }
147
+ catch (err) {
148
+ if (err?.code === 'ENOENT' && !fs.existsSync(tmp)) {
149
+ await this.writeFileSafe(tmp, payload);
150
+ await this.renameSafe(tmp, path);
151
+ }
152
+ else {
153
+ throw err;
154
+ }
155
+ }
156
+ // 3. Remove WAL after successful write
157
+ if (fs.existsSync(walPath)) {
158
+ await fs.promises.unlink(walPath).catch(() => undefined);
159
+ }
160
+ }
161
+ async loadWithWal(agentId, name) {
162
+ const fs = require('fs');
163
+ const path = this.getRuntimePath(agentId, `${name}.json`);
164
+ const walPath = this.getRuntimePath(agentId, `${name}.wal`);
165
+ // 1. Check and recover from WAL if exists
166
+ if (fs.existsSync(walPath)) {
167
+ try {
168
+ const walData = JSON.parse(await fs.promises.readFile(walPath, 'utf-8'));
169
+ if (walData.data !== undefined) {
170
+ // Recover from WAL
171
+ const tmp = `${path}.tmp`;
172
+ await this.writeFileSafe(tmp, JSON.stringify(walData.data, null, 2));
173
+ await this.renameSafe(tmp, path);
174
+ await fs.promises.unlink(walPath).catch(() => undefined);
175
+ }
176
+ }
177
+ catch (err) {
178
+ logger_1.logger.error(`Failed to recover ${name} from WAL:`, err);
179
+ }
180
+ }
181
+ // 2. Load from main file
182
+ try {
183
+ const data = await fs.promises.readFile(path, 'utf-8');
184
+ return JSON.parse(data);
185
+ }
186
+ catch {
187
+ return undefined;
188
+ }
189
+ }
190
+ async queueWalWrite(agentId, name, write) {
191
+ const key = `${agentId}:${name}`;
192
+ // 链式追加,确保顺序执行
193
+ const previous = this.walQueue.get(key) || Promise.resolve();
194
+ const next = previous
195
+ .then(() => write()) // 前一个成功后执行
196
+ .catch((err) => {
197
+ // 即使前一个失败,也尝试当前写入
198
+ logger_1.logger.error(`[WAL] Previous write failed for ${key}, attempting current write:`, err);
199
+ return write();
200
+ });
201
+ this.walQueue.set(key, next);
202
+ try {
203
+ await next;
204
+ }
205
+ catch (err) {
206
+ // 记录但不阻塞调用者
207
+ logger_1.logger.error(`[WAL] Write failed for ${key}:`, err);
208
+ throw err; // 重新抛出让调用者处理
209
+ }
210
+ finally {
211
+ // 清理完成的 promise(避免内存泄漏)
212
+ if (this.walQueue.get(key) === next) {
213
+ this.walQueue.delete(key);
214
+ }
215
+ }
216
+ }
217
+ // ========== WAL 主动恢复 ==========
218
+ /**
219
+ * Store 初始化时主动恢复所有 WAL 文件
220
+ */
221
+ async recoverAllWALs() {
222
+ const fs = require('fs').promises;
223
+ const path = require('path');
224
+ try {
225
+ const agentDirs = await fs.readdir(this.baseDir).catch(() => []);
226
+ for (const agentId of agentDirs) {
227
+ const agentDir = path.join(this.baseDir, agentId);
228
+ const stat = await fs.stat(agentDir).catch(() => null);
229
+ if (!stat?.isDirectory())
230
+ continue;
231
+ // 恢复运行时 WAL
232
+ await this.recoverRuntimeWAL(agentId, 'messages');
233
+ await this.recoverRuntimeWAL(agentId, 'tool-calls');
234
+ // 恢复事件 WAL
235
+ await this.recoverEventWALFile(agentId, 'progress');
236
+ await this.recoverEventWALFile(agentId, 'control');
237
+ await this.recoverEventWALFile(agentId, 'monitor');
238
+ }
239
+ if (agentDirs.length > 0) {
240
+ logger_1.logger.log(`[Store] WAL recovery completed for ${agentDirs.length} agents`);
241
+ }
242
+ }
243
+ catch (err) {
244
+ logger_1.logger.error('[Store] WAL recovery failed:', err);
245
+ }
246
+ }
247
+ /**
248
+ * 恢复运行时数据的 WAL
249
+ */
250
+ async recoverRuntimeWAL(agentId, name) {
251
+ const fs = require('fs');
252
+ const fsp = fs.promises;
253
+ const walKey = `${agentId}:${name}`;
254
+ if (this.walRecovered.has(walKey))
255
+ return;
256
+ this.walRecovered.add(walKey);
257
+ const path = this.getRuntimePath(agentId, `${name}.json`);
258
+ const walPath = this.getRuntimePath(agentId, `${name}.wal`);
259
+ if (!fs.existsSync(walPath))
260
+ return;
261
+ try {
262
+ const walData = JSON.parse(await fsp.readFile(walPath, 'utf-8'));
263
+ if (walData.data !== undefined) {
264
+ const tmp = `${path}.tmp`;
265
+ await fsp.writeFile(tmp, JSON.stringify(walData.data, null, 2), 'utf-8');
266
+ await fsp.rename(tmp, path);
267
+ await fsp.unlink(walPath);
268
+ logger_1.logger.log(`[Store] Recovered ${name} from WAL for ${agentId}`);
269
+ }
270
+ }
271
+ catch (err) {
272
+ logger_1.logger.error(`[Store] Failed to recover ${name} WAL for ${agentId}:`, err);
273
+ // 重命名损坏的 WAL 以便人工检查
274
+ await fsp.rename(walPath, `${walPath}.corrupted`).catch(() => { });
275
+ }
276
+ }
277
+ /**
278
+ * 恢复事件流的 WAL
279
+ */
280
+ async recoverEventWALFile(agentId, channel) {
281
+ const walKey = `${agentId}:${channel}`;
282
+ if (this.walRecovered.has(walKey))
283
+ return;
284
+ this.walRecovered.add(walKey);
285
+ const fs = require('fs');
286
+ const fsp = fs.promises;
287
+ const walPath = this.getEventsPath(agentId, `${channel}.wal`);
288
+ if (!fs.existsSync(walPath))
289
+ return;
290
+ try {
291
+ const data = await fsp.readFile(walPath, 'utf-8');
292
+ const lines = data.split('\n').filter(Boolean);
293
+ if (lines.length > 0) {
294
+ const payload = lines.join('\n') + '\n';
295
+ await fsp.appendFile(this.getEventsPath(agentId, `${channel}.log`), payload);
296
+ await fsp.unlink(walPath);
297
+ logger_1.logger.log(`[Store] Recovered ${lines.length} events from ${channel} WAL for ${agentId}`);
298
+ }
299
+ }
300
+ catch (err) {
301
+ logger_1.logger.error(`[Store] Failed to recover ${channel} WAL for ${agentId}:`, err);
302
+ await fsp.rename(walPath, `${walPath}.corrupted`).catch(() => { });
303
+ }
304
+ }
305
+ // ========== 事件流管理(按通道缓冲 + WAL) ==========
306
+ async appendEvent(agentId, timeline) {
307
+ const entry = JSON.stringify(timeline);
308
+ const channel = timeline.event.channel;
309
+ await this.recoverEventWal(agentId, channel);
310
+ const writers = this.getEventWriters(agentId);
311
+ const writer = writers[channel];
312
+ writer.buffer.push(entry);
313
+ await this.writeEventWal(agentId, channel, writer);
314
+ if (!writer.timer) {
315
+ writer.timer = setTimeout(() => {
316
+ void this.flushEvents(agentId, channel);
317
+ }, this.flushIntervalMs);
318
+ }
319
+ }
320
+ async *readEvents(agentId, opts) {
321
+ const channels = opts?.channel ? [opts.channel] : ['progress', 'control', 'monitor'];
322
+ for (const channel of channels) {
323
+ await this.recoverEventWal(agentId, channel);
324
+ await this.flushEvents(agentId, channel);
325
+ const fs = require('fs');
326
+ const readline = require('readline');
327
+ const path = this.getEventsPath(agentId, `${channel}.log`);
328
+ if (!fs.existsSync(path))
329
+ continue;
330
+ const stream = fs.createReadStream(path, { encoding: 'utf-8' });
331
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
332
+ for await (const line of rl) {
333
+ if (!line.trim())
334
+ continue;
335
+ try {
336
+ const event = JSON.parse(line);
337
+ if (opts?.since && event.bookmark.seq <= opts.since.seq)
338
+ continue;
339
+ yield event;
340
+ }
341
+ catch {
342
+ // skip corrupted lines
343
+ }
344
+ }
345
+ }
346
+ }
347
+ getEventWriters(agentId) {
348
+ let writers = this.eventWriters.get(agentId);
349
+ if (!writers) {
350
+ writers = {
351
+ progress: { buffer: [], flushing: [] },
352
+ control: { buffer: [], flushing: [] },
353
+ monitor: { buffer: [], flushing: [] },
354
+ };
355
+ this.eventWriters.set(agentId, writers);
356
+ }
357
+ return writers;
358
+ }
359
+ async flushEvents(agentId, channel) {
360
+ const writers = this.eventWriters.get(agentId);
361
+ if (!writers)
362
+ return;
363
+ const writer = writers[channel];
364
+ if (!writer)
365
+ return;
366
+ if (writer.timer) {
367
+ clearTimeout(writer.timer);
368
+ writer.timer = undefined;
369
+ }
370
+ if (writer.buffer.length > 0) {
371
+ writer.flushing.push(...writer.buffer);
372
+ writer.buffer = [];
373
+ }
374
+ if (writer.flushing.length === 0) {
375
+ await this.writeEventWal(agentId, channel, writer);
376
+ return;
377
+ }
378
+ const payload = writer.flushing.join('\n') + '\n';
379
+ await this.appendFileSafe(this.getEventsPath(agentId, `${channel}.log`), payload);
380
+ writer.flushing = [];
381
+ await this.writeEventWal(agentId, channel, writer);
382
+ }
383
+ async recoverEventWal(agentId, channel) {
384
+ const walKey = `${agentId}:${channel}`;
385
+ if (this.walRecovered.has(walKey))
386
+ return;
387
+ const writers = this.getEventWriters(agentId);
388
+ const writer = writers[channel];
389
+ writer.recovered = true;
390
+ this.walRecovered.add(walKey);
391
+ const fs = require('fs');
392
+ const fsp = fs.promises;
393
+ const walPath = this.getEventsPath(agentId, `${channel}.wal`);
394
+ if (!fs.existsSync(walPath))
395
+ return;
396
+ try {
397
+ const data = await fsp.readFile(walPath, 'utf-8');
398
+ const lines = data.split('\n').filter(Boolean);
399
+ if (lines.length > 0) {
400
+ const payload = lines.join('\n') + '\n';
401
+ await fsp.appendFile(this.getEventsPath(agentId, `${channel}.log`), payload);
402
+ }
403
+ await fsp.unlink(walPath);
404
+ }
405
+ catch {
406
+ // WAL corrupted, keep it for manual inspection
407
+ }
408
+ }
409
+ async writeEventWal(agentId, channel, writer) {
410
+ const fs = require('fs');
411
+ const walPath = this.getEventsPath(agentId, `${channel}.wal`);
412
+ const schedule = async () => {
413
+ const entries = [...writer.flushing, ...writer.buffer];
414
+ if (entries.length > 0) {
415
+ await this.writeFileSafe(walPath, entries.join('\n') + '\n');
416
+ }
417
+ else if (fs.existsSync(walPath)) {
418
+ await fs.promises.unlink(walPath).catch(() => undefined);
419
+ }
420
+ };
421
+ writer.walWriting = (writer.walWriting || Promise.resolve()).then(schedule, schedule);
422
+ await writer.walWriting;
423
+ }
424
+ // ========== 历史与压缩管理 ==========
425
+ async saveHistoryWindow(agentId, window) {
426
+ const path = require('path');
427
+ const dir = this.getHistoryDir(agentId, 'windows');
428
+ const filePath = path.join(dir, `${window.timestamp}.json`);
429
+ await this.writeFileSafe(filePath, JSON.stringify(window, null, 2));
430
+ }
431
+ async loadHistoryWindows(agentId) {
432
+ const fs = require('fs').promises;
433
+ const path = require('path');
434
+ try {
435
+ const dir = this.getHistoryDir(agentId, 'windows');
436
+ const files = await fs.readdir(dir);
437
+ const windows = [];
438
+ for (const file of files) {
439
+ if (file.endsWith('.json')) {
440
+ const data = await fs.readFile(path.join(dir, file), 'utf-8');
441
+ windows.push(JSON.parse(data));
442
+ }
443
+ }
444
+ return windows.sort((a, b) => a.timestamp - b.timestamp);
445
+ }
446
+ catch {
447
+ return [];
448
+ }
449
+ }
450
+ async saveCompressionRecord(agentId, record) {
451
+ const path = require('path');
452
+ const dir = this.getHistoryDir(agentId, 'compressions');
453
+ const filePath = path.join(dir, `${record.timestamp}.json`);
454
+ await this.writeFileSafe(filePath, JSON.stringify(record, null, 2));
455
+ }
456
+ async loadCompressionRecords(agentId) {
457
+ const fs = require('fs').promises;
458
+ const path = require('path');
459
+ try {
460
+ const dir = this.getHistoryDir(agentId, 'compressions');
461
+ const files = await fs.readdir(dir);
462
+ const records = [];
463
+ for (const file of files) {
464
+ if (file.endsWith('.json')) {
465
+ const data = await fs.readFile(path.join(dir, file), 'utf-8');
466
+ records.push(JSON.parse(data));
467
+ }
468
+ }
469
+ return records.sort((a, b) => a.timestamp - b.timestamp);
470
+ }
471
+ catch {
472
+ return [];
473
+ }
474
+ }
475
+ async saveRecoveredFile(agentId, file) {
476
+ const path = require('path');
477
+ const dir = this.getHistoryDir(agentId, 'recovered');
478
+ const safePath = file.path.replace(/[\/\\]/g, '_');
479
+ const filePath = path.join(dir, `${safePath}_${file.timestamp}.txt`);
480
+ const header = `# Recovered: ${file.path}\n# Timestamp: ${file.timestamp}\n# Mtime: ${file.mtime}\n\n`;
481
+ await this.writeFileSafe(filePath, header + file.content);
482
+ }
483
+ async loadRecoveredFiles(agentId) {
484
+ const fs = require('fs').promises;
485
+ const path = require('path');
486
+ try {
487
+ const dir = this.getHistoryDir(agentId, 'recovered');
488
+ const files = await fs.readdir(dir);
489
+ const recovered = [];
490
+ for (const file of files) {
491
+ const data = await fs.readFile(path.join(dir, file), 'utf-8');
492
+ const lines = data.split('\n');
493
+ const pathMatch = lines[0]?.match(/# Recovered: (.+)/);
494
+ const tsMatch = lines[1]?.match(/# Timestamp: (\d+)/);
495
+ const mtimeMatch = lines[2]?.match(/# Mtime: (\d+)/);
496
+ if (pathMatch && tsMatch && mtimeMatch) {
497
+ recovered.push({
498
+ path: pathMatch[1],
499
+ content: lines.slice(4).join('\n'),
500
+ mtime: parseInt(mtimeMatch[1]),
501
+ timestamp: parseInt(tsMatch[1]),
502
+ });
503
+ }
504
+ }
505
+ return recovered.sort((a, b) => a.timestamp - b.timestamp);
506
+ }
507
+ catch {
508
+ return [];
509
+ }
510
+ }
511
+ async saveMediaCache(agentId, records) {
512
+ const fs = require('fs').promises;
513
+ const filePath = this.getMediaCachePath(agentId);
514
+ await fs.writeFile(filePath, JSON.stringify(records, null, 2), 'utf-8');
515
+ }
516
+ async loadMediaCache(agentId) {
517
+ const fs = require('fs').promises;
518
+ const filePath = this.getMediaCachePath(agentId);
519
+ try {
520
+ const data = await fs.readFile(filePath, 'utf-8');
521
+ const parsed = JSON.parse(data);
522
+ return Array.isArray(parsed) ? parsed : [];
523
+ }
524
+ catch {
525
+ return [];
526
+ }
527
+ }
528
+ // ========== 快照管理 ==========
529
+ async saveSnapshot(agentId, snapshot) {
530
+ const path = require('path');
531
+ const dir = this.getSnapshotsDir(agentId);
532
+ const filePath = path.join(dir, `${snapshot.id}.json`);
533
+ await this.writeFileSafe(filePath, JSON.stringify(snapshot, null, 2));
534
+ }
535
+ async loadSnapshot(agentId, snapshotId) {
536
+ const fs = require('fs').promises;
537
+ const path = require('path');
538
+ try {
539
+ const dir = this.getSnapshotsDir(agentId);
540
+ const data = await fs.readFile(path.join(dir, `${snapshotId}.json`), 'utf-8');
541
+ return JSON.parse(data);
542
+ }
543
+ catch {
544
+ return undefined;
545
+ }
546
+ }
547
+ async listSnapshots(agentId) {
548
+ const fs = require('fs').promises;
549
+ const path = require('path');
550
+ try {
551
+ const dir = this.getSnapshotsDir(agentId);
552
+ const files = await fs.readdir(dir);
553
+ const snapshots = [];
554
+ for (const file of files) {
555
+ if (file.endsWith('.json')) {
556
+ const data = await fs.readFile(path.join(dir, file), 'utf-8');
557
+ snapshots.push(JSON.parse(data));
558
+ }
559
+ }
560
+ return snapshots;
561
+ }
562
+ catch {
563
+ return [];
564
+ }
565
+ }
566
+ // ========== 元数据管理 ==========
567
+ async saveInfo(agentId, info) {
568
+ await this.writeFileSafe(this.getMetaPath(agentId), JSON.stringify(info, null, 2));
569
+ }
570
+ async loadInfo(agentId) {
571
+ const fs = require('fs').promises;
572
+ try {
573
+ const data = await fs.readFile(this.getMetaPath(agentId), 'utf-8');
574
+ return JSON.parse(data);
575
+ }
576
+ catch {
577
+ return undefined;
578
+ }
579
+ }
580
+ // ========== 生命周期管理 ==========
581
+ async exists(agentId) {
582
+ const fs = require('fs').promises;
583
+ try {
584
+ await fs.access(this.getAgentDir(agentId));
585
+ return true;
586
+ }
587
+ catch {
588
+ return false;
589
+ }
590
+ }
591
+ async delete(agentId) {
592
+ const fs = require('fs').promises;
593
+ await fs.rm(this.getAgentDir(agentId), { recursive: true, force: true });
594
+ }
595
+ async list(prefix) {
596
+ const fs = require('fs').promises;
597
+ try {
598
+ const dirs = await fs.readdir(this.baseDir);
599
+ return prefix ? dirs.filter((d) => d.startsWith(prefix)) : dirs;
600
+ }
601
+ catch {
602
+ return [];
603
+ }
604
+ }
605
+ }
606
+ exports.JSONStore = JSONStore;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Store 模块 - Agent 持久化
4
+ *
5
+ * 本文件已重构为模块化结构,实际实现已拆分到 store/ 目录下:
6
+ * - store/types.ts - 接口和类型定义
7
+ * - store/json-store.ts - JSONStore 文件存储实现
8
+ * - db/sqlite/ - SQLite 数据库实现
9
+ * - db/postgres/ - PostgreSQL 数据库实现
10
+ *
11
+ * 本文件仅做向后兼容的导出
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
25
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ // 重导出所有内容以保持向后兼容
29
+ __exportStar(require("./store/index"), exports);
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BashKill = void 0;
4
+ const tool_1 = require("../tool");
5
+ const zod_1 = require("zod");
6
+ const prompt_1 = require("./prompt");
7
+ const bash_run_1 = require("../bash_run");
8
+ exports.BashKill = (0, tool_1.tool)({
9
+ name: 'bash_kill',
10
+ description: prompt_1.DESCRIPTION,
11
+ parameters: zod_1.z.object({
12
+ shell_id: zod_1.z.string().describe('Shell ID from bash_run'),
13
+ }),
14
+ async execute(args) {
15
+ const { shell_id } = args;
16
+ const proc = bash_run_1.processes.get(shell_id);
17
+ if (!proc) {
18
+ return {
19
+ ok: false,
20
+ error: `Shell not found: ${shell_id}`,
21
+ };
22
+ }
23
+ bash_run_1.processes.delete(shell_id);
24
+ return {
25
+ ok: true,
26
+ shell_id,
27
+ message: `Killed shell ${shell_id}`,
28
+ };
29
+ },
30
+ metadata: {
31
+ readonly: false,
32
+ version: '1.0',
33
+ },
34
+ });
35
+ exports.BashKill.prompt = prompt_1.PROMPT;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT = exports.DESCRIPTION = void 0;
4
+ exports.DESCRIPTION = 'Kill a background bash shell';
5
+ exports.PROMPT = `Terminate a long-running background bash session identified by shell_id.
6
+
7
+ Guidelines:
8
+ - Use this to clean up stuck processes.
9
+ - Provide the shell_id from bash_run to terminate that specific process.
10
+ - Once killed, the process cannot be restarted or accessed.
11
+
12
+ Safety/Limitations:
13
+ - Only background processes started in the current session can be killed.
14
+ - Force termination may leave incomplete work or locks.`;