@lov3kaizen/agentsea-debugger 0.5.1

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.
@@ -0,0 +1,588 @@
1
+ import 'nanoid';
2
+
3
+ // src/utils/helpers.ts
4
+ function deepClone(obj) {
5
+ if (obj === null || typeof obj !== "object") {
6
+ return obj;
7
+ }
8
+ if (Array.isArray(obj)) {
9
+ return obj.map((item) => deepClone(item));
10
+ }
11
+ if (obj instanceof Date) {
12
+ return new Date(obj.getTime());
13
+ }
14
+ if (obj instanceof Map) {
15
+ const clonedMap = /* @__PURE__ */ new Map();
16
+ obj.forEach((value, key) => {
17
+ clonedMap.set(deepClone(key), deepClone(value));
18
+ });
19
+ return clonedMap;
20
+ }
21
+ if (obj instanceof Set) {
22
+ const clonedSet = /* @__PURE__ */ new Set();
23
+ obj.forEach((value) => {
24
+ clonedSet.add(deepClone(value));
25
+ });
26
+ return clonedSet;
27
+ }
28
+ const clonedObj = {};
29
+ for (const key in obj) {
30
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
31
+ clonedObj[key] = deepClone(
32
+ obj[key]
33
+ );
34
+ }
35
+ }
36
+ return clonedObj;
37
+ }
38
+ function safeStringify(obj, indent = 0) {
39
+ const seen = /* @__PURE__ */ new WeakSet();
40
+ return JSON.stringify(
41
+ obj,
42
+ (key, value) => {
43
+ if (typeof value === "object" && value !== null) {
44
+ if (seen.has(value)) {
45
+ return "[Circular]";
46
+ }
47
+ seen.add(value);
48
+ }
49
+ if (value instanceof Error) {
50
+ return {
51
+ name: value.name,
52
+ message: value.message,
53
+ stack: value.stack
54
+ };
55
+ }
56
+ if (value instanceof Map) {
57
+ return Object.fromEntries(value);
58
+ }
59
+ if (value instanceof Set) {
60
+ return Array.from(value);
61
+ }
62
+ if (typeof value === "function") {
63
+ return `[Function: ${value.name || "anonymous"}]`;
64
+ }
65
+ if (typeof value === "bigint") {
66
+ return value.toString();
67
+ }
68
+ return value;
69
+ },
70
+ indent
71
+ );
72
+ }
73
+ function safeParse(json, defaultValue) {
74
+ try {
75
+ return JSON.parse(json);
76
+ } catch {
77
+ return defaultValue;
78
+ }
79
+ }
80
+ function estimateSize(obj) {
81
+ return safeStringify(obj).length * 2;
82
+ }
83
+
84
+ // src/storage/FileStorage.ts
85
+ var FileStorage = class {
86
+ options;
87
+ initialized = false;
88
+ constructor(options) {
89
+ this.options = {
90
+ basePath: options.basePath,
91
+ extension: options.extension ?? ".json",
92
+ compress: options.compress ?? false,
93
+ prettyPrint: options.prettyPrint ?? true,
94
+ fs: options.fs
95
+ };
96
+ }
97
+ /**
98
+ * Initialize storage (create directories)
99
+ */
100
+ async initialize() {
101
+ if (this.initialized) return;
102
+ const { fs, basePath } = this.options;
103
+ const exists = await fs.exists(basePath);
104
+ if (!exists) {
105
+ await fs.mkdir(basePath, { recursive: true });
106
+ }
107
+ const subdirs = ["recordings", "checkpoints", "metadata"];
108
+ for (const subdir of subdirs) {
109
+ const path = this.joinPath(basePath, subdir);
110
+ const subdirExists = await fs.exists(path);
111
+ if (!subdirExists) {
112
+ await fs.mkdir(path, { recursive: true });
113
+ }
114
+ }
115
+ this.initialized = true;
116
+ }
117
+ /**
118
+ * Save a recording
119
+ */
120
+ async save(recording) {
121
+ await this.initialize();
122
+ const { fs, prettyPrint } = this.options;
123
+ const filePath = this.getRecordingPath(recording.id);
124
+ const content = prettyPrint ? safeStringify(recording, 2) : safeStringify(recording);
125
+ await fs.writeFile(filePath, content);
126
+ await this.saveMetadata(recording);
127
+ for (const checkpoint of recording.checkpoints) {
128
+ await this.saveCheckpoint(checkpoint);
129
+ }
130
+ }
131
+ /**
132
+ * Load a recording
133
+ */
134
+ async load(id) {
135
+ await this.initialize();
136
+ const { fs } = this.options;
137
+ const filePath = this.getRecordingPath(id);
138
+ const exists = await fs.exists(filePath);
139
+ if (!exists) {
140
+ return void 0;
141
+ }
142
+ const content = await fs.readFile(filePath);
143
+ return safeParse(content);
144
+ }
145
+ /**
146
+ * Delete a recording
147
+ */
148
+ async delete(id) {
149
+ await this.initialize();
150
+ const { fs } = this.options;
151
+ const filePath = this.getRecordingPath(id);
152
+ const exists = await fs.exists(filePath);
153
+ if (!exists) {
154
+ return false;
155
+ }
156
+ await fs.unlink(filePath);
157
+ const metaPath = this.getMetadataPath(id);
158
+ if (await fs.exists(metaPath)) {
159
+ await fs.unlink(metaPath);
160
+ }
161
+ return true;
162
+ }
163
+ /**
164
+ * List all recordings
165
+ */
166
+ async list() {
167
+ await this.initialize();
168
+ const { fs } = this.options;
169
+ const metaDir = this.joinPath(this.options.basePath, "metadata");
170
+ const files = await fs.readdir(metaDir);
171
+ const metas = [];
172
+ for (const file of files) {
173
+ if (file.endsWith(this.options.extension)) {
174
+ const filePath = this.joinPath(metaDir, file);
175
+ const content = await fs.readFile(filePath);
176
+ const meta = safeParse(content);
177
+ if (meta) {
178
+ metas.push(meta);
179
+ }
180
+ }
181
+ }
182
+ metas.sort((a, b) => b.startedAt - a.startedAt);
183
+ return metas;
184
+ }
185
+ /**
186
+ * Query recordings
187
+ */
188
+ async query(options) {
189
+ let recordings = await this.list();
190
+ if (options.agentId) {
191
+ recordings = recordings.filter((r) => r.agentId === options.agentId);
192
+ }
193
+ if (options.status) {
194
+ recordings = recordings.filter((r) => r.status === options.status);
195
+ }
196
+ if (options.startAfter) {
197
+ recordings = recordings.filter((r) => r.startedAt > options.startAfter);
198
+ }
199
+ if (options.startBefore) {
200
+ recordings = recordings.filter((r) => r.startedAt < options.startBefore);
201
+ }
202
+ if (options.limit) {
203
+ recordings = recordings.slice(0, options.limit);
204
+ }
205
+ return recordings;
206
+ }
207
+ /**
208
+ * Save a checkpoint
209
+ */
210
+ async saveCheckpoint(checkpoint) {
211
+ await this.initialize();
212
+ const { fs, prettyPrint } = this.options;
213
+ const filePath = this.getCheckpointPath(checkpoint.id);
214
+ const content = prettyPrint ? safeStringify(checkpoint, 2) : safeStringify(checkpoint);
215
+ await fs.writeFile(filePath, content);
216
+ }
217
+ /**
218
+ * Load a checkpoint
219
+ */
220
+ async loadCheckpoint(id) {
221
+ await this.initialize();
222
+ const { fs } = this.options;
223
+ const filePath = this.getCheckpointPath(id);
224
+ const exists = await fs.exists(filePath);
225
+ if (!exists) {
226
+ return void 0;
227
+ }
228
+ const content = await fs.readFile(filePath);
229
+ return safeParse(content);
230
+ }
231
+ /**
232
+ * List checkpoints for a recording
233
+ */
234
+ async listCheckpoints(recordingId) {
235
+ await this.initialize();
236
+ const { fs } = this.options;
237
+ const cpDir = this.joinPath(this.options.basePath, "checkpoints");
238
+ const files = await fs.readdir(cpDir);
239
+ const checkpoints = [];
240
+ for (const file of files) {
241
+ if (file.endsWith(this.options.extension)) {
242
+ const filePath = this.joinPath(cpDir, file);
243
+ const content = await fs.readFile(filePath);
244
+ const cp = safeParse(content);
245
+ if (cp && cp.recordingId === recordingId) {
246
+ checkpoints.push(cp);
247
+ }
248
+ }
249
+ }
250
+ checkpoints.sort((a, b) => a.stepIndex - b.stepIndex);
251
+ return checkpoints;
252
+ }
253
+ /**
254
+ * Save metadata for quick listing
255
+ */
256
+ async saveMetadata(recording) {
257
+ const { fs, prettyPrint } = this.options;
258
+ const filePath = this.getMetadataPath(recording.id);
259
+ const meta = {
260
+ id: recording.id,
261
+ agentId: recording.agentId,
262
+ agentName: recording.agentName,
263
+ status: recording.status,
264
+ startedAt: recording.startedAt,
265
+ endedAt: recording.endedAt,
266
+ durationMs: recording.durationMs,
267
+ stepsCount: recording.steps.length,
268
+ filePath: this.getRecordingPath(recording.id)
269
+ };
270
+ const content = prettyPrint ? safeStringify(meta, 2) : safeStringify(meta);
271
+ await fs.writeFile(filePath, content);
272
+ }
273
+ /**
274
+ * Get recording file path
275
+ */
276
+ getRecordingPath(id) {
277
+ return this.joinPath(
278
+ this.options.basePath,
279
+ "recordings",
280
+ `${id}${this.options.extension}`
281
+ );
282
+ }
283
+ /**
284
+ * Get metadata file path
285
+ */
286
+ getMetadataPath(id) {
287
+ return this.joinPath(
288
+ this.options.basePath,
289
+ "metadata",
290
+ `${id}${this.options.extension}`
291
+ );
292
+ }
293
+ /**
294
+ * Get checkpoint file path
295
+ */
296
+ getCheckpointPath(id) {
297
+ return this.joinPath(
298
+ this.options.basePath,
299
+ "checkpoints",
300
+ `${id}${this.options.extension}`
301
+ );
302
+ }
303
+ /**
304
+ * Join path segments
305
+ */
306
+ joinPath(...segments) {
307
+ return segments.join("/").replace(/\/+/g, "/");
308
+ }
309
+ /**
310
+ * Get storage statistics
311
+ */
312
+ async getStats() {
313
+ await this.initialize();
314
+ const { fs } = this.options;
315
+ const recordings = await this.list();
316
+ let totalSize = 0;
317
+ for (const meta of recordings) {
318
+ const stat = await fs.stat(meta.filePath);
319
+ if (stat) {
320
+ totalSize += stat.size ?? 0;
321
+ }
322
+ }
323
+ const cpDir = this.joinPath(this.options.basePath, "checkpoints");
324
+ const cpFiles = await fs.readdir(cpDir);
325
+ return {
326
+ totalRecordings: recordings.length,
327
+ totalCheckpoints: cpFiles.length,
328
+ totalSizeBytes: totalSize
329
+ };
330
+ }
331
+ };
332
+ function createFileStorage(options) {
333
+ return new FileStorage(options);
334
+ }
335
+
336
+ // src/storage/MemoryStorage.ts
337
+ var MemoryStorage = class {
338
+ recordings = /* @__PURE__ */ new Map();
339
+ checkpoints = /* @__PURE__ */ new Map();
340
+ options;
341
+ totalSize = 0;
342
+ constructor(options) {
343
+ this.options = {
344
+ maxRecordings: options?.maxRecordings ?? 1e3,
345
+ maxSizeBytes: options?.maxSizeBytes ?? 100 * 1024 * 1024,
346
+ // 100MB
347
+ deepCopy: options?.deepCopy ?? true
348
+ };
349
+ }
350
+ /**
351
+ * Save a recording
352
+ */
353
+ save(recording) {
354
+ const size = estimateSize(recording);
355
+ if (size > this.options.maxSizeBytes) {
356
+ return Promise.reject(new Error("Recording exceeds maximum size limit"));
357
+ }
358
+ this.ensureCapacity(size);
359
+ const entry = {
360
+ recording: this.options.deepCopy ? deepClone(recording) : recording,
361
+ size,
362
+ savedAt: Date.now()
363
+ };
364
+ const existing = this.recordings.get(recording.id);
365
+ if (existing) {
366
+ this.totalSize -= existing.size;
367
+ }
368
+ this.totalSize += size;
369
+ this.recordings.set(recording.id, entry);
370
+ for (const checkpoint of recording.checkpoints) {
371
+ this.saveCheckpoint(checkpoint);
372
+ }
373
+ return Promise.resolve();
374
+ }
375
+ /**
376
+ * Load a recording
377
+ */
378
+ load(id) {
379
+ const entry = this.recordings.get(id);
380
+ if (!entry) {
381
+ return Promise.resolve(void 0);
382
+ }
383
+ return Promise.resolve(
384
+ this.options.deepCopy ? deepClone(entry.recording) : entry.recording
385
+ );
386
+ }
387
+ /**
388
+ * Delete a recording
389
+ */
390
+ delete(id) {
391
+ const entry = this.recordings.get(id);
392
+ if (!entry) {
393
+ return Promise.resolve(false);
394
+ }
395
+ this.totalSize -= entry.size;
396
+ this.recordings.delete(id);
397
+ for (const checkpoint of entry.recording.checkpoints) {
398
+ this.deleteCheckpoint(checkpoint.id);
399
+ }
400
+ return Promise.resolve(true);
401
+ }
402
+ /**
403
+ * List all recordings
404
+ */
405
+ list() {
406
+ const results = [];
407
+ for (const entry of this.recordings.values()) {
408
+ const r = entry.recording;
409
+ results.push({
410
+ id: r.id,
411
+ agentId: r.agentId,
412
+ agentName: r.agentName,
413
+ status: r.status,
414
+ startedAt: r.startedAt,
415
+ endedAt: r.endedAt,
416
+ durationMs: r.durationMs,
417
+ stepsCount: r.steps.length
418
+ });
419
+ }
420
+ results.sort((a, b) => b.startedAt - a.startedAt);
421
+ return Promise.resolve(results);
422
+ }
423
+ /**
424
+ * Query recordings
425
+ */
426
+ async query(options) {
427
+ let results = await this.list();
428
+ if (options.agentId) {
429
+ results = results.filter((r) => r.agentId === options.agentId);
430
+ }
431
+ if (options.status) {
432
+ results = results.filter((r) => r.status === options.status);
433
+ }
434
+ if (options.startAfter) {
435
+ results = results.filter((r) => r.startedAt > options.startAfter);
436
+ }
437
+ if (options.startBefore) {
438
+ results = results.filter((r) => r.startedAt < options.startBefore);
439
+ }
440
+ if (options.limit) {
441
+ results = results.slice(0, options.limit);
442
+ }
443
+ return results;
444
+ }
445
+ /**
446
+ * Save a checkpoint
447
+ */
448
+ saveCheckpoint(checkpoint) {
449
+ const size = estimateSize(checkpoint);
450
+ const entry = {
451
+ checkpoint: this.options.deepCopy ? deepClone(checkpoint) : checkpoint,
452
+ size,
453
+ savedAt: Date.now()
454
+ };
455
+ const existing = this.checkpoints.get(checkpoint.id);
456
+ if (existing) {
457
+ this.totalSize -= existing.size;
458
+ }
459
+ this.totalSize += size;
460
+ this.checkpoints.set(checkpoint.id, entry);
461
+ }
462
+ /**
463
+ * Load a checkpoint
464
+ */
465
+ loadCheckpoint(id) {
466
+ const entry = this.checkpoints.get(id);
467
+ if (!entry) {
468
+ return void 0;
469
+ }
470
+ return this.options.deepCopy ? deepClone(entry.checkpoint) : entry.checkpoint;
471
+ }
472
+ /**
473
+ * Delete a checkpoint
474
+ */
475
+ deleteCheckpoint(id) {
476
+ const entry = this.checkpoints.get(id);
477
+ if (!entry) {
478
+ return false;
479
+ }
480
+ this.totalSize -= entry.size;
481
+ this.checkpoints.delete(id);
482
+ return true;
483
+ }
484
+ /**
485
+ * List checkpoints for a recording
486
+ */
487
+ listCheckpoints(recordingId) {
488
+ const results = [];
489
+ for (const entry of this.checkpoints.values()) {
490
+ if (entry.checkpoint.recordingId === recordingId) {
491
+ results.push(
492
+ this.options.deepCopy ? deepClone(entry.checkpoint) : entry.checkpoint
493
+ );
494
+ }
495
+ }
496
+ results.sort((a, b) => a.stepIndex - b.stepIndex);
497
+ return results;
498
+ }
499
+ /**
500
+ * Ensure capacity for new data
501
+ */
502
+ ensureCapacity(requiredSize) {
503
+ while (this.recordings.size >= this.options.maxRecordings) {
504
+ this.evictOldest();
505
+ }
506
+ while (this.totalSize + requiredSize > this.options.maxSizeBytes) {
507
+ if (this.recordings.size === 0) {
508
+ break;
509
+ }
510
+ this.evictOldest();
511
+ }
512
+ }
513
+ /**
514
+ * Evict the oldest recording
515
+ */
516
+ evictOldest() {
517
+ let oldestId;
518
+ let oldestTime = Infinity;
519
+ for (const [id, entry] of this.recordings) {
520
+ if (entry.savedAt < oldestTime) {
521
+ oldestTime = entry.savedAt;
522
+ oldestId = id;
523
+ }
524
+ }
525
+ if (oldestId) {
526
+ void this.delete(oldestId);
527
+ }
528
+ }
529
+ /**
530
+ * Clear all data
531
+ */
532
+ clear() {
533
+ this.recordings.clear();
534
+ this.checkpoints.clear();
535
+ this.totalSize = 0;
536
+ }
537
+ /**
538
+ * Get storage statistics
539
+ */
540
+ getStats() {
541
+ return {
542
+ totalRecordings: this.recordings.size,
543
+ totalCheckpoints: this.checkpoints.size,
544
+ totalSizeBytes: this.totalSize,
545
+ maxRecordings: this.options.maxRecordings,
546
+ maxSizeBytes: this.options.maxSizeBytes,
547
+ utilizationPercent: this.totalSize / this.options.maxSizeBytes * 100
548
+ };
549
+ }
550
+ /**
551
+ * Export all data
552
+ */
553
+ exportAll() {
554
+ const recordings = [];
555
+ const checkpoints = [];
556
+ for (const entry of this.recordings.values()) {
557
+ recordings.push(
558
+ this.options.deepCopy ? deepClone(entry.recording) : entry.recording
559
+ );
560
+ }
561
+ for (const entry of this.checkpoints.values()) {
562
+ checkpoints.push(
563
+ this.options.deepCopy ? deepClone(entry.checkpoint) : entry.checkpoint
564
+ );
565
+ }
566
+ return { recordings, checkpoints };
567
+ }
568
+ /**
569
+ * Import data
570
+ */
571
+ importAll(data) {
572
+ for (const recording of data.recordings) {
573
+ void this.save(recording);
574
+ }
575
+ if (data.checkpoints) {
576
+ for (const checkpoint of data.checkpoints) {
577
+ this.saveCheckpoint(checkpoint);
578
+ }
579
+ }
580
+ }
581
+ };
582
+ function createMemoryStorage(options) {
583
+ return new MemoryStorage(options);
584
+ }
585
+
586
+ export { FileStorage, MemoryStorage, createFileStorage, createMemoryStorage };
587
+ //# sourceMappingURL=index.js.map
588
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/helpers.ts","../../src/storage/FileStorage.ts","../../src/storage/MemoryStorage.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Helper Utilities\n *\n * Common utility functions for the debugger.\n */\n\nimport { nanoid } from 'nanoid';\n\n/**\n * Generate a unique ID with optional prefix\n */\nexport function generateId(prefix = ''): string {\n const id = nanoid(12);\n return prefix ? `${prefix}_${id}` : id;\n}\n\n/**\n * Get current timestamp in milliseconds\n */\nexport function now(): number {\n return Date.now();\n}\n\n/**\n * Calculate duration between two timestamps\n */\nexport function duration(start: number, end: number = now()): number {\n return end - start;\n}\n\n/**\n * Deep clone an object\n */\nexport function deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => deepClone(item)) as T;\n }\n\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as T;\n }\n\n if (obj instanceof Map) {\n const clonedMap = new Map();\n obj.forEach((value, key) => {\n clonedMap.set(deepClone(key), deepClone(value));\n });\n return clonedMap as T;\n }\n\n if (obj instanceof Set) {\n const clonedSet = new Set();\n obj.forEach((value) => {\n clonedSet.add(deepClone(value));\n });\n return clonedSet as T;\n }\n\n const clonedObj = {} as T;\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n (clonedObj as Record<string, unknown>)[key] = deepClone(\n (obj as Record<string, unknown>)[key],\n );\n }\n }\n\n return clonedObj;\n}\n\n/**\n * Safely serialize an object to JSON\n */\nexport function safeStringify(obj: unknown, indent = 0): string {\n const seen = new WeakSet();\n\n return JSON.stringify(\n obj,\n (key, value) => {\n if (typeof value === 'object' && value !== null) {\n if (seen.has(value)) {\n return '[Circular]';\n }\n seen.add(value);\n }\n\n // Handle special types\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n\n if (value instanceof Set) {\n return Array.from(value);\n }\n\n if (typeof value === 'function') {\n return `[Function: ${value.name || 'anonymous'}]`;\n }\n\n if (typeof value === 'bigint') {\n return value.toString();\n }\n\n return value;\n },\n indent,\n );\n}\n\n/**\n * Safely parse JSON\n */\nexport function safeParse<T>(json: string, defaultValue?: T): T | undefined {\n try {\n return JSON.parse(json) as T;\n } catch {\n return defaultValue;\n }\n}\n\n/**\n * Format duration in human-readable format\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms}ms`;\n }\n\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n\n if (hours > 0) {\n return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\n }\n\n if (minutes > 0) {\n return `${minutes}m ${seconds % 60}s`;\n }\n\n return `${seconds}s`;\n}\n\n/**\n * Format bytes in human-readable format\n */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(2)} ${units[unitIndex]}`;\n}\n\n/**\n * Truncate string to max length\n */\nexport function truncate(\n str: string,\n maxLength: number,\n suffix = '...',\n): string {\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength - suffix.length) + suffix;\n}\n\n/**\n * Debounce a function\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(\n fn: T,\n delay: number,\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return (...args: Parameters<T>) => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n timeoutId = setTimeout(() => {\n fn(...args);\n timeoutId = null;\n }, delay);\n };\n}\n\n/**\n * Sleep for a given duration\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n maxAttempts = 3,\n baseDelayMs = 100,\n): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n if (attempt < maxAttempts - 1) {\n await sleep(baseDelayMs * Math.pow(2, attempt));\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Calculate object size in bytes (approximate)\n */\nexport function estimateSize(obj: unknown): number {\n return safeStringify(obj).length * 2; // UTF-16\n}\n","/**\n * FileStorage\n *\n * File-based storage adapter for recordings.\n */\n\nimport type {\n Recording,\n Checkpoint,\n RecordingStorageAdapter,\n} from '../types/index.js';\nimport { safeStringify, safeParse } from '../utils/helpers.js';\n\n/**\n * File system interface (for Node.js compatibility)\n */\nexport interface FileSystem {\n readFile(path: string): Promise<string>;\n writeFile(path: string, content: string): Promise<void>;\n exists(path: string): Promise<boolean>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n readdir(path: string): Promise<string[]>;\n unlink(path: string): Promise<void>;\n stat(\n path: string,\n ): Promise<{ isFile(): boolean; isDirectory(): boolean; mtime: Date }>;\n}\n\n/**\n * File storage options\n */\nexport interface FileStorageOptions {\n /** Base directory for storage */\n basePath: string;\n /** File extension */\n extension?: string;\n /** Whether to compress files */\n compress?: boolean;\n /** Whether to pretty print JSON */\n prettyPrint?: boolean;\n /** File system implementation */\n fs: FileSystem;\n}\n\n/**\n * Recording metadata for listing\n */\nexport interface RecordingMeta {\n id: string;\n agentId: string;\n agentName: string;\n status: string;\n startedAt: number;\n endedAt?: number;\n durationMs: number;\n stepsCount: number;\n filePath: string;\n fileSize?: number;\n}\n\n/**\n * FileStorage\n *\n * File-based storage for debug recordings.\n *\n * @example\n * ```typescript\n * import * as fs from 'fs/promises';\n *\n * const storage = new FileStorage({\n * basePath: './debug-recordings',\n * fs: {\n * readFile: (p) => fs.readFile(p, 'utf-8'),\n * writeFile: (p, c) => fs.writeFile(p, c, 'utf-8'),\n * exists: async (p) => fs.access(p).then(() => true).catch(() => false),\n * mkdir: (p, o) => fs.mkdir(p, o),\n * readdir: (p) => fs.readdir(p),\n * unlink: (p) => fs.unlink(p),\n * stat: (p) => fs.stat(p),\n * },\n * });\n *\n * // Save a recording\n * await storage.save(recording);\n *\n * // Load a recording\n * const loaded = await storage.load('rec_123');\n *\n * // List all recordings\n * const recordings = await storage.list();\n * ```\n */\nexport class FileStorage implements RecordingStorageAdapter {\n private options: Required<FileStorageOptions>;\n private initialized = false;\n\n constructor(options: FileStorageOptions) {\n this.options = {\n basePath: options.basePath,\n extension: options.extension ?? '.json',\n compress: options.compress ?? false,\n prettyPrint: options.prettyPrint ?? true,\n fs: options.fs,\n };\n }\n\n /**\n * Initialize storage (create directories)\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n const { fs, basePath } = this.options;\n\n // Create base directory\n const exists = await fs.exists(basePath);\n if (!exists) {\n await fs.mkdir(basePath, { recursive: true });\n }\n\n // Create subdirectories\n const subdirs = ['recordings', 'checkpoints', 'metadata'];\n for (const subdir of subdirs) {\n const path = this.joinPath(basePath, subdir);\n const subdirExists = await fs.exists(path);\n if (!subdirExists) {\n await fs.mkdir(path, { recursive: true });\n }\n }\n\n this.initialized = true;\n }\n\n /**\n * Save a recording\n */\n async save(recording: Recording): Promise<void> {\n await this.initialize();\n\n const { fs, prettyPrint } = this.options;\n const filePath = this.getRecordingPath(recording.id);\n\n const content = prettyPrint\n ? safeStringify(recording, 2)\n : safeStringify(recording);\n\n await fs.writeFile(filePath, content);\n\n // Save metadata separately for quick listing\n await this.saveMetadata(recording);\n\n // Save checkpoints separately\n for (const checkpoint of recording.checkpoints) {\n await this.saveCheckpoint(checkpoint);\n }\n }\n\n /**\n * Load a recording\n */\n async load(id: string): Promise<Recording | undefined> {\n await this.initialize();\n\n const { fs } = this.options;\n const filePath = this.getRecordingPath(id);\n\n const exists = await fs.exists(filePath);\n if (!exists) {\n return undefined;\n }\n\n const content = await fs.readFile(filePath);\n return safeParse<Recording>(content);\n }\n\n /**\n * Delete a recording\n */\n async delete(id: string): Promise<boolean> {\n await this.initialize();\n\n const { fs } = this.options;\n const filePath = this.getRecordingPath(id);\n\n const exists = await fs.exists(filePath);\n if (!exists) {\n return false;\n }\n\n await fs.unlink(filePath);\n\n // Delete metadata\n const metaPath = this.getMetadataPath(id);\n if (await fs.exists(metaPath)) {\n await fs.unlink(metaPath);\n }\n\n return true;\n }\n\n /**\n * List all recordings\n */\n async list(): Promise<RecordingMeta[]> {\n await this.initialize();\n\n const { fs } = this.options;\n const metaDir = this.joinPath(this.options.basePath, 'metadata');\n\n const files = await fs.readdir(metaDir);\n const metas: RecordingMeta[] = [];\n\n for (const file of files) {\n if (file.endsWith(this.options.extension)) {\n const filePath = this.joinPath(metaDir, file);\n const content = await fs.readFile(filePath);\n const meta = safeParse<RecordingMeta>(content);\n if (meta) {\n metas.push(meta);\n }\n }\n }\n\n // Sort by start time descending\n metas.sort((a, b) => b.startedAt - a.startedAt);\n\n return metas;\n }\n\n /**\n * Query recordings\n */\n async query(options: {\n agentId?: string;\n status?: string;\n startAfter?: number;\n startBefore?: number;\n limit?: number;\n }): Promise<RecordingMeta[]> {\n let recordings = await this.list();\n\n // Apply filters\n if (options.agentId) {\n recordings = recordings.filter((r) => r.agentId === options.agentId);\n }\n\n if (options.status) {\n recordings = recordings.filter((r) => r.status === options.status);\n }\n\n if (options.startAfter) {\n recordings = recordings.filter((r) => r.startedAt > options.startAfter!);\n }\n\n if (options.startBefore) {\n recordings = recordings.filter((r) => r.startedAt < options.startBefore!);\n }\n\n // Apply limit\n if (options.limit) {\n recordings = recordings.slice(0, options.limit);\n }\n\n return recordings;\n }\n\n /**\n * Save a checkpoint\n */\n async saveCheckpoint(checkpoint: Checkpoint): Promise<void> {\n await this.initialize();\n\n const { fs, prettyPrint } = this.options;\n const filePath = this.getCheckpointPath(checkpoint.id);\n\n const content = prettyPrint\n ? safeStringify(checkpoint, 2)\n : safeStringify(checkpoint);\n\n await fs.writeFile(filePath, content);\n }\n\n /**\n * Load a checkpoint\n */\n async loadCheckpoint(id: string): Promise<Checkpoint | undefined> {\n await this.initialize();\n\n const { fs } = this.options;\n const filePath = this.getCheckpointPath(id);\n\n const exists = await fs.exists(filePath);\n if (!exists) {\n return undefined;\n }\n\n const content = await fs.readFile(filePath);\n return safeParse<Checkpoint>(content);\n }\n\n /**\n * List checkpoints for a recording\n */\n async listCheckpoints(recordingId: string): Promise<Checkpoint[]> {\n await this.initialize();\n\n const { fs } = this.options;\n const cpDir = this.joinPath(this.options.basePath, 'checkpoints');\n\n const files = await fs.readdir(cpDir);\n const checkpoints: Checkpoint[] = [];\n\n for (const file of files) {\n if (file.endsWith(this.options.extension)) {\n const filePath = this.joinPath(cpDir, file);\n const content = await fs.readFile(filePath);\n const cp = safeParse<Checkpoint>(content);\n if (cp && cp.recordingId === recordingId) {\n checkpoints.push(cp);\n }\n }\n }\n\n // Sort by step index\n checkpoints.sort((a, b) => a.stepIndex - b.stepIndex);\n\n return checkpoints;\n }\n\n /**\n * Save metadata for quick listing\n */\n private async saveMetadata(recording: Recording): Promise<void> {\n const { fs, prettyPrint } = this.options;\n const filePath = this.getMetadataPath(recording.id);\n\n const meta: RecordingMeta = {\n id: recording.id,\n agentId: recording.agentId,\n agentName: recording.agentName,\n status: recording.status,\n startedAt: recording.startedAt,\n endedAt: recording.endedAt,\n durationMs: recording.durationMs,\n stepsCount: recording.steps.length,\n filePath: this.getRecordingPath(recording.id),\n };\n\n const content = prettyPrint ? safeStringify(meta, 2) : safeStringify(meta);\n\n await fs.writeFile(filePath, content);\n }\n\n /**\n * Get recording file path\n */\n private getRecordingPath(id: string): string {\n return this.joinPath(\n this.options.basePath,\n 'recordings',\n `${id}${this.options.extension}`,\n );\n }\n\n /**\n * Get metadata file path\n */\n private getMetadataPath(id: string): string {\n return this.joinPath(\n this.options.basePath,\n 'metadata',\n `${id}${this.options.extension}`,\n );\n }\n\n /**\n * Get checkpoint file path\n */\n private getCheckpointPath(id: string): string {\n return this.joinPath(\n this.options.basePath,\n 'checkpoints',\n `${id}${this.options.extension}`,\n );\n }\n\n /**\n * Join path segments\n */\n private joinPath(...segments: string[]): string {\n return segments.join('/').replace(/\\/+/g, '/');\n }\n\n /**\n * Get storage statistics\n */\n async getStats(): Promise<{\n totalRecordings: number;\n totalCheckpoints: number;\n totalSizeBytes: number;\n }> {\n await this.initialize();\n\n const { fs } = this.options;\n const recordings = await this.list();\n\n let totalSize = 0;\n for (const meta of recordings) {\n const stat = await fs.stat(meta.filePath);\n if (stat) {\n totalSize += (stat as { size?: number }).size ?? 0;\n }\n }\n\n const cpDir = this.joinPath(this.options.basePath, 'checkpoints');\n const cpFiles = await fs.readdir(cpDir);\n\n return {\n totalRecordings: recordings.length,\n totalCheckpoints: cpFiles.length,\n totalSizeBytes: totalSize,\n };\n }\n}\n\n/**\n * Create file storage\n */\nexport function createFileStorage(options: FileStorageOptions): FileStorage {\n return new FileStorage(options);\n}\n","/**\n * MemoryStorage\n *\n * In-memory storage adapter for recordings.\n */\n\nimport type {\n Recording,\n Checkpoint,\n RecordingStorageAdapter,\n} from '../types/index.js';\nimport { deepClone, estimateSize } from '../utils/helpers.js';\n\n/**\n * Memory storage options\n */\nexport interface MemoryStorageOptions {\n /** Maximum recordings to store */\n maxRecordings?: number;\n /** Maximum total size in bytes */\n maxSizeBytes?: number;\n /** Whether to deep clone on save/load */\n deepCopy?: boolean;\n}\n\n/**\n * Recording entry with metadata\n */\ninterface RecordingEntry {\n recording: Recording;\n size: number;\n savedAt: number;\n}\n\n/**\n * Checkpoint entry with metadata\n */\ninterface CheckpointEntry {\n checkpoint: Checkpoint;\n size: number;\n savedAt: number;\n}\n\n/**\n * MemoryStorage\n *\n * In-memory storage for debug recordings.\n * Useful for testing and development.\n *\n * @example\n * ```typescript\n * const storage = new MemoryStorage({\n * maxRecordings: 100,\n * maxSizeBytes: 50 * 1024 * 1024, // 50MB\n * });\n *\n * // Save a recording\n * await storage.save(recording);\n *\n * // Load a recording\n * const loaded = await storage.load('rec_123');\n *\n * // List all recordings\n * const recordings = await storage.list();\n * ```\n */\nexport class MemoryStorage implements RecordingStorageAdapter {\n private recordings: Map<string, RecordingEntry> = new Map();\n private checkpoints: Map<string, CheckpointEntry> = new Map();\n private options: Required<MemoryStorageOptions>;\n private totalSize = 0;\n\n constructor(options?: MemoryStorageOptions) {\n this.options = {\n maxRecordings: options?.maxRecordings ?? 1000,\n maxSizeBytes: options?.maxSizeBytes ?? 100 * 1024 * 1024, // 100MB\n deepCopy: options?.deepCopy ?? true,\n };\n }\n\n /**\n * Save a recording\n */\n save(recording: Recording): Promise<void> {\n const size = estimateSize(recording);\n\n // Check size limit\n if (size > this.options.maxSizeBytes) {\n return Promise.reject(new Error('Recording exceeds maximum size limit'));\n }\n\n // Evict old recordings if needed\n this.ensureCapacity(size);\n\n const entry: RecordingEntry = {\n recording: this.options.deepCopy ? deepClone(recording) : recording,\n size,\n savedAt: Date.now(),\n };\n\n // Update total size\n const existing = this.recordings.get(recording.id);\n if (existing) {\n this.totalSize -= existing.size;\n }\n this.totalSize += size;\n\n this.recordings.set(recording.id, entry);\n\n // Save checkpoints\n for (const checkpoint of recording.checkpoints) {\n this.saveCheckpoint(checkpoint);\n }\n\n return Promise.resolve();\n }\n\n /**\n * Load a recording\n */\n load(id: string): Promise<Recording | undefined> {\n const entry = this.recordings.get(id);\n if (!entry) {\n return Promise.resolve(undefined);\n }\n\n return Promise.resolve(\n this.options.deepCopy ? deepClone(entry.recording) : entry.recording,\n );\n }\n\n /**\n * Delete a recording\n */\n delete(id: string): Promise<boolean> {\n const entry = this.recordings.get(id);\n if (!entry) {\n return Promise.resolve(false);\n }\n\n this.totalSize -= entry.size;\n this.recordings.delete(id);\n\n // Delete associated checkpoints\n for (const checkpoint of entry.recording.checkpoints) {\n this.deleteCheckpoint(checkpoint.id);\n }\n\n return Promise.resolve(true);\n }\n\n /**\n * List all recordings\n */\n list(): Promise<\n Array<{\n id: string;\n agentId: string;\n agentName: string;\n status: string;\n startedAt: number;\n endedAt?: number;\n durationMs: number;\n stepsCount: number;\n }>\n > {\n const results: Array<{\n id: string;\n agentId: string;\n agentName: string;\n status: string;\n startedAt: number;\n endedAt?: number;\n durationMs: number;\n stepsCount: number;\n }> = [];\n\n for (const entry of this.recordings.values()) {\n const r = entry.recording;\n results.push({\n id: r.id,\n agentId: r.agentId,\n agentName: r.agentName,\n status: r.status,\n startedAt: r.startedAt,\n endedAt: r.endedAt,\n durationMs: r.durationMs,\n stepsCount: r.steps.length,\n });\n }\n\n // Sort by start time descending\n results.sort((a, b) => b.startedAt - a.startedAt);\n\n return Promise.resolve(results);\n }\n\n /**\n * Query recordings\n */\n async query(options: {\n agentId?: string;\n status?: string;\n startAfter?: number;\n startBefore?: number;\n limit?: number;\n }): Promise<\n Array<{\n id: string;\n agentId: string;\n agentName: string;\n status: string;\n startedAt: number;\n endedAt?: number;\n durationMs: number;\n stepsCount: number;\n }>\n > {\n let results = await this.list();\n\n // Apply filters\n if (options.agentId) {\n results = results.filter((r) => r.agentId === options.agentId);\n }\n\n if (options.status) {\n results = results.filter((r) => r.status === options.status);\n }\n\n if (options.startAfter) {\n results = results.filter((r) => r.startedAt > options.startAfter!);\n }\n\n if (options.startBefore) {\n results = results.filter((r) => r.startedAt < options.startBefore!);\n }\n\n // Apply limit\n if (options.limit) {\n results = results.slice(0, options.limit);\n }\n\n return results;\n }\n\n /**\n * Save a checkpoint\n */\n saveCheckpoint(checkpoint: Checkpoint): void {\n const size = estimateSize(checkpoint);\n\n const entry: CheckpointEntry = {\n checkpoint: this.options.deepCopy ? deepClone(checkpoint) : checkpoint,\n size,\n savedAt: Date.now(),\n };\n\n // Update total size\n const existing = this.checkpoints.get(checkpoint.id);\n if (existing) {\n this.totalSize -= existing.size;\n }\n this.totalSize += size;\n\n this.checkpoints.set(checkpoint.id, entry);\n }\n\n /**\n * Load a checkpoint\n */\n loadCheckpoint(id: string): Checkpoint | undefined {\n const entry = this.checkpoints.get(id);\n if (!entry) {\n return undefined;\n }\n\n return this.options.deepCopy\n ? deepClone(entry.checkpoint)\n : entry.checkpoint;\n }\n\n /**\n * Delete a checkpoint\n */\n deleteCheckpoint(id: string): boolean {\n const entry = this.checkpoints.get(id);\n if (!entry) {\n return false;\n }\n\n this.totalSize -= entry.size;\n this.checkpoints.delete(id);\n return true;\n }\n\n /**\n * List checkpoints for a recording\n */\n listCheckpoints(recordingId: string): Checkpoint[] {\n const results: Checkpoint[] = [];\n\n for (const entry of this.checkpoints.values()) {\n if (entry.checkpoint.recordingId === recordingId) {\n results.push(\n this.options.deepCopy\n ? deepClone(entry.checkpoint)\n : entry.checkpoint,\n );\n }\n }\n\n // Sort by step index\n results.sort((a, b) => a.stepIndex - b.stepIndex);\n\n return results;\n }\n\n /**\n * Ensure capacity for new data\n */\n private ensureCapacity(requiredSize: number): void {\n // Check recording count limit\n while (this.recordings.size >= this.options.maxRecordings) {\n this.evictOldest();\n }\n\n // Check size limit\n while (this.totalSize + requiredSize > this.options.maxSizeBytes) {\n if (this.recordings.size === 0) {\n break;\n }\n this.evictOldest();\n }\n }\n\n /**\n * Evict the oldest recording\n */\n private evictOldest(): void {\n let oldestId: string | undefined;\n let oldestTime = Infinity;\n\n for (const [id, entry] of this.recordings) {\n if (entry.savedAt < oldestTime) {\n oldestTime = entry.savedAt;\n oldestId = id;\n }\n }\n\n if (oldestId) {\n void this.delete(oldestId);\n }\n }\n\n /**\n * Clear all data\n */\n clear(): void {\n this.recordings.clear();\n this.checkpoints.clear();\n this.totalSize = 0;\n }\n\n /**\n * Get storage statistics\n */\n getStats(): {\n totalRecordings: number;\n totalCheckpoints: number;\n totalSizeBytes: number;\n maxRecordings: number;\n maxSizeBytes: number;\n utilizationPercent: number;\n } {\n return {\n totalRecordings: this.recordings.size,\n totalCheckpoints: this.checkpoints.size,\n totalSizeBytes: this.totalSize,\n maxRecordings: this.options.maxRecordings,\n maxSizeBytes: this.options.maxSizeBytes,\n utilizationPercent: (this.totalSize / this.options.maxSizeBytes) * 100,\n };\n }\n\n /**\n * Export all data\n */\n exportAll(): {\n recordings: Recording[];\n checkpoints: Checkpoint[];\n } {\n const recordings: Recording[] = [];\n const checkpoints: Checkpoint[] = [];\n\n for (const entry of this.recordings.values()) {\n recordings.push(\n this.options.deepCopy ? deepClone(entry.recording) : entry.recording,\n );\n }\n\n for (const entry of this.checkpoints.values()) {\n checkpoints.push(\n this.options.deepCopy ? deepClone(entry.checkpoint) : entry.checkpoint,\n );\n }\n\n return { recordings, checkpoints };\n }\n\n /**\n * Import data\n */\n importAll(data: {\n recordings: Recording[];\n checkpoints?: Checkpoint[];\n }): void {\n for (const recording of data.recordings) {\n void this.save(recording);\n }\n\n if (data.checkpoints) {\n for (const checkpoint of data.checkpoints) {\n this.saveCheckpoint(checkpoint);\n }\n }\n }\n}\n\n/**\n * Create memory storage\n */\nexport function createMemoryStorage(\n options?: MemoryStorageOptions,\n): MemoryStorage {\n return new MemoryStorage(options);\n}\n"]}