claude-flow 1.0.0

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/bin/claude-flow +0 -0
  4. package/bin/claude-flow-simple +0 -0
  5. package/bin/claude-flow-typecheck +0 -0
  6. package/deno.json +84 -0
  7. package/package.json +45 -0
  8. package/scripts/check-links.ts +274 -0
  9. package/scripts/check-performance-regression.ts +168 -0
  10. package/scripts/claude-sparc.sh +562 -0
  11. package/scripts/coverage-report.ts +692 -0
  12. package/scripts/demo-task-system.ts +224 -0
  13. package/scripts/install.js +72 -0
  14. package/scripts/test-batch-tasks.ts +29 -0
  15. package/scripts/test-coordination-features.ts +238 -0
  16. package/scripts/test-mcp.ts +251 -0
  17. package/scripts/test-runner.ts +571 -0
  18. package/scripts/validate-examples.ts +288 -0
  19. package/src/cli/cli-core.ts +273 -0
  20. package/src/cli/commands/agent.ts +83 -0
  21. package/src/cli/commands/config.ts +442 -0
  22. package/src/cli/commands/help.ts +765 -0
  23. package/src/cli/commands/index.ts +963 -0
  24. package/src/cli/commands/mcp.ts +191 -0
  25. package/src/cli/commands/memory.ts +74 -0
  26. package/src/cli/commands/monitor.ts +403 -0
  27. package/src/cli/commands/session.ts +595 -0
  28. package/src/cli/commands/start.ts +156 -0
  29. package/src/cli/commands/status.ts +345 -0
  30. package/src/cli/commands/task.ts +79 -0
  31. package/src/cli/commands/workflow.ts +763 -0
  32. package/src/cli/completion.ts +553 -0
  33. package/src/cli/formatter.ts +310 -0
  34. package/src/cli/index.ts +211 -0
  35. package/src/cli/main.ts +23 -0
  36. package/src/cli/repl.ts +1050 -0
  37. package/src/cli/simple-cli.js +211 -0
  38. package/src/cli/simple-cli.ts +211 -0
  39. package/src/coordination/README.md +400 -0
  40. package/src/coordination/advanced-scheduler.ts +487 -0
  41. package/src/coordination/circuit-breaker.ts +366 -0
  42. package/src/coordination/conflict-resolution.ts +490 -0
  43. package/src/coordination/dependency-graph.ts +475 -0
  44. package/src/coordination/index.ts +63 -0
  45. package/src/coordination/manager.ts +460 -0
  46. package/src/coordination/messaging.ts +290 -0
  47. package/src/coordination/metrics.ts +585 -0
  48. package/src/coordination/resources.ts +322 -0
  49. package/src/coordination/scheduler.ts +390 -0
  50. package/src/coordination/work-stealing.ts +224 -0
  51. package/src/core/config.ts +627 -0
  52. package/src/core/event-bus.ts +186 -0
  53. package/src/core/json-persistence.ts +183 -0
  54. package/src/core/logger.ts +262 -0
  55. package/src/core/orchestrator-fixed.ts +312 -0
  56. package/src/core/orchestrator.ts +1234 -0
  57. package/src/core/persistence.ts +276 -0
  58. package/src/mcp/auth.ts +438 -0
  59. package/src/mcp/claude-flow-tools.ts +1280 -0
  60. package/src/mcp/load-balancer.ts +510 -0
  61. package/src/mcp/router.ts +240 -0
  62. package/src/mcp/server.ts +548 -0
  63. package/src/mcp/session-manager.ts +418 -0
  64. package/src/mcp/tools.ts +180 -0
  65. package/src/mcp/transports/base.ts +21 -0
  66. package/src/mcp/transports/http.ts +457 -0
  67. package/src/mcp/transports/stdio.ts +254 -0
  68. package/src/memory/backends/base.ts +22 -0
  69. package/src/memory/backends/markdown.ts +283 -0
  70. package/src/memory/backends/sqlite.ts +329 -0
  71. package/src/memory/cache.ts +238 -0
  72. package/src/memory/indexer.ts +238 -0
  73. package/src/memory/manager.ts +572 -0
  74. package/src/terminal/adapters/base.ts +29 -0
  75. package/src/terminal/adapters/native.ts +504 -0
  76. package/src/terminal/adapters/vscode.ts +340 -0
  77. package/src/terminal/manager.ts +308 -0
  78. package/src/terminal/pool.ts +271 -0
  79. package/src/terminal/session.ts +250 -0
  80. package/src/terminal/vscode-bridge.ts +242 -0
  81. package/src/utils/errors.ts +231 -0
  82. package/src/utils/helpers.ts +476 -0
  83. package/src/utils/types.ts +493 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Base interface for memory backends
3
+ */
4
+
5
+ import { MemoryEntry, MemoryQuery } from '../../utils/types.ts';
6
+
7
+ export interface IMemoryBackend {
8
+ initialize(): Promise<void>;
9
+ shutdown(): Promise<void>;
10
+ store(entry: MemoryEntry): Promise<void>;
11
+ retrieve(id: string): Promise<MemoryEntry | undefined>;
12
+ update(id: string, entry: MemoryEntry): Promise<void>;
13
+ delete(id: string): Promise<void>;
14
+ query(query: MemoryQuery): Promise<MemoryEntry[]>;
15
+ getAllEntries(): Promise<MemoryEntry[]>;
16
+ getHealthStatus(): Promise<{
17
+ healthy: boolean;
18
+ error?: string;
19
+ metrics?: Record<string, number>;
20
+ }>;
21
+ performMaintenance?(): Promise<void>;
22
+ }
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Markdown backend implementation for human-readable memory storage
3
+ */
4
+
5
+ import { IMemoryBackend } from './base.ts';
6
+ import { MemoryEntry, MemoryQuery } from '../../utils/types.ts';
7
+ import { ILogger } from '../../core/logger.ts';
8
+ import { MemoryBackendError } from '../../utils/errors.ts';
9
+ import { ensureDir } from 'https://deno.land/std@0.208.0/fs/mod.ts';
10
+
11
+ /**
12
+ * Markdown-based memory backend
13
+ */
14
+ export class MarkdownBackend implements IMemoryBackend {
15
+ private entries = new Map<string, MemoryEntry>();
16
+ private indexPath: string;
17
+
18
+ constructor(
19
+ private baseDir: string,
20
+ private logger: ILogger,
21
+ ) {
22
+ this.indexPath = `${this.baseDir}/index.json`;
23
+ }
24
+
25
+ async initialize(): Promise<void> {
26
+ this.logger.info('Initializing Markdown backend', { baseDir: this.baseDir });
27
+
28
+ try {
29
+ // Ensure directories exist
30
+ await ensureDir(this.baseDir);
31
+ await ensureDir(`${this.baseDir}/agents`);
32
+ await ensureDir(`${this.baseDir}/sessions`);
33
+
34
+ // Load index
35
+ await this.loadIndex();
36
+
37
+ this.logger.info('Markdown backend initialized');
38
+ } catch (error) {
39
+ throw new MemoryBackendError('Failed to initialize Markdown backend', { error });
40
+ }
41
+ }
42
+
43
+ async shutdown(): Promise<void> {
44
+ this.logger.info('Shutting down Markdown backend');
45
+
46
+ // Save index before shutdown
47
+ await this.saveIndex();
48
+ this.entries.clear();
49
+ }
50
+
51
+ async store(entry: MemoryEntry): Promise<void> {
52
+ try {
53
+ // Store in memory
54
+ this.entries.set(entry.id, entry);
55
+
56
+ // Write to markdown file
57
+ await this.writeEntryToFile(entry);
58
+
59
+ // Update index
60
+ await this.saveIndex();
61
+ } catch (error) {
62
+ throw new MemoryBackendError('Failed to store entry', { error });
63
+ }
64
+ }
65
+
66
+ async retrieve(id: string): Promise<MemoryEntry | undefined> {
67
+ return this.entries.get(id);
68
+ }
69
+
70
+ async update(id: string, entry: MemoryEntry): Promise<void> {
71
+ if (!this.entries.has(id)) {
72
+ throw new MemoryBackendError(`Entry not found: ${id}`);
73
+ }
74
+
75
+ await this.store(entry);
76
+ }
77
+
78
+ async delete(id: string): Promise<void> {
79
+ const entry = this.entries.get(id);
80
+ if (!entry) {
81
+ return;
82
+ }
83
+
84
+ try {
85
+ // Delete from memory
86
+ this.entries.delete(id);
87
+
88
+ // Delete file
89
+ const filePath = this.getEntryFilePath(entry);
90
+ await Deno.remove(filePath);
91
+
92
+ // Update index
93
+ await this.saveIndex();
94
+ } catch (error) {
95
+ throw new MemoryBackendError('Failed to delete entry', { error });
96
+ }
97
+ }
98
+
99
+ async query(query: MemoryQuery): Promise<MemoryEntry[]> {
100
+ let results = Array.from(this.entries.values());
101
+
102
+ // Apply filters
103
+ if (query.agentId) {
104
+ results = results.filter(e => e.agentId === query.agentId);
105
+ }
106
+
107
+ if (query.sessionId) {
108
+ results = results.filter(e => e.sessionId === query.sessionId);
109
+ }
110
+
111
+ if (query.type) {
112
+ results = results.filter(e => e.type === query.type);
113
+ }
114
+
115
+ if (query.tags && query.tags.length > 0) {
116
+ results = results.filter(e =>
117
+ query.tags!.some(tag => e.tags.includes(tag)),
118
+ );
119
+ }
120
+
121
+ if (query.startTime) {
122
+ results = results.filter(e =>
123
+ e.timestamp.getTime() >= query.startTime!.getTime(),
124
+ );
125
+ }
126
+
127
+ if (query.endTime) {
128
+ results = results.filter(e =>
129
+ e.timestamp.getTime() <= query.endTime!.getTime(),
130
+ );
131
+ }
132
+
133
+ if (query.search) {
134
+ const searchLower = query.search.toLowerCase();
135
+ results = results.filter(e =>
136
+ e.content.toLowerCase().includes(searchLower) ||
137
+ e.tags.some(tag => tag.toLowerCase().includes(searchLower)),
138
+ );
139
+ }
140
+
141
+ // Sort by timestamp (newest first)
142
+ results.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
143
+
144
+ // Apply pagination
145
+ const start = query.offset || 0;
146
+ const limit = query.limit || results.length;
147
+ results = results.slice(start, start + limit);
148
+
149
+ return results;
150
+ }
151
+
152
+ async getAllEntries(): Promise<MemoryEntry[]> {
153
+ return Array.from(this.entries.values());
154
+ }
155
+
156
+ async getHealthStatus(): Promise<{
157
+ healthy: boolean;
158
+ error?: string;
159
+ metrics?: Record<string, number>;
160
+ }> {
161
+ try {
162
+ // Check if directory is accessible
163
+ await Deno.stat(this.baseDir);
164
+
165
+ const entryCount = this.entries.size;
166
+ let totalSizeBytes = 0;
167
+
168
+ // Calculate total size
169
+ for (const entry of this.entries.values()) {
170
+ const filePath = this.getEntryFilePath(entry);
171
+ try {
172
+ const stat = await Deno.stat(filePath);
173
+ totalSizeBytes += stat.size;
174
+ } catch {
175
+ // File might not exist yet
176
+ }
177
+ }
178
+
179
+ return {
180
+ healthy: true,
181
+ metrics: {
182
+ entryCount,
183
+ totalSizeBytes,
184
+ },
185
+ };
186
+ } catch (error) {
187
+ return {
188
+ healthy: false,
189
+ error: error instanceof Error ? error.message : 'Unknown error',
190
+ };
191
+ }
192
+ }
193
+
194
+ private async loadIndex(): Promise<void> {
195
+ try {
196
+ const content = await Deno.readTextFile(this.indexPath);
197
+ const index = JSON.parse(content) as Record<string, MemoryEntry>;
198
+
199
+ // Convert and validate entries
200
+ for (const [id, entry] of Object.entries(index)) {
201
+ // Reconstruct dates
202
+ entry.timestamp = new Date(entry.timestamp);
203
+ this.entries.set(id, entry);
204
+ }
205
+
206
+ this.logger.info('Loaded memory index', { entries: this.entries.size });
207
+ } catch (error) {
208
+ if (!(error instanceof Deno.errors.NotFound)) {
209
+ this.logger.warn('Failed to load index', { error });
210
+ }
211
+ // Start with empty index if file doesn't exist
212
+ }
213
+ }
214
+
215
+ private async saveIndex(): Promise<void> {
216
+ const index: Record<string, MemoryEntry> = {};
217
+
218
+ for (const [id, entry] of this.entries) {
219
+ index[id] = entry;
220
+ }
221
+
222
+ const content = JSON.stringify(index, null, 2);
223
+ await Deno.writeTextFile(this.indexPath, content);
224
+ }
225
+
226
+ private async writeEntryToFile(entry: MemoryEntry): Promise<void> {
227
+ const filePath = this.getEntryFilePath(entry);
228
+ const dirPath = filePath.substring(0, filePath.lastIndexOf('/'));
229
+
230
+ // Ensure directory exists
231
+ await ensureDir(dirPath);
232
+
233
+ // Generate markdown content
234
+ const content = this.entryToMarkdown(entry);
235
+
236
+ // Write file
237
+ await Deno.writeTextFile(filePath, content);
238
+ }
239
+
240
+ private getEntryFilePath(entry: MemoryEntry): string {
241
+ const date = entry.timestamp.toISOString().split('T')[0];
242
+ const time = entry.timestamp.toISOString().split('T')[1].replace(/:/g, '-').split('.')[0];
243
+
244
+ return `${this.baseDir}/agents/${entry.agentId}/${date}/${time}_${entry.id}.md`;
245
+ }
246
+
247
+ private entryToMarkdown(entry: MemoryEntry): string {
248
+ const lines: string[] = [
249
+ `# Memory Entry: ${entry.id}`,
250
+ '',
251
+ `**Agent**: ${entry.agentId}`,
252
+ `**Session**: ${entry.sessionId}`,
253
+ `**Type**: ${entry.type}`,
254
+ `**Timestamp**: ${entry.timestamp.toISOString()}`,
255
+ `**Version**: ${entry.version}`,
256
+ '',
257
+ ];
258
+
259
+ if (entry.parentId) {
260
+ lines.push(`**Parent**: ${entry.parentId}`, '');
261
+ }
262
+
263
+ if (entry.tags.length > 0) {
264
+ lines.push(`**Tags**: ${entry.tags.join(', ')}`, '');
265
+ }
266
+
267
+ lines.push('## Content', '', entry.content, '');
268
+
269
+ if (Object.keys(entry.context).length > 0) {
270
+ lines.push('## Context', '', '```json');
271
+ lines.push(JSON.stringify(entry.context, null, 2));
272
+ lines.push('```', '');
273
+ }
274
+
275
+ if (entry.metadata && Object.keys(entry.metadata).length > 0) {
276
+ lines.push('## Metadata', '', '```json');
277
+ lines.push(JSON.stringify(entry.metadata, null, 2));
278
+ lines.push('```', '');
279
+ }
280
+
281
+ return lines.join('\n');
282
+ }
283
+ }
@@ -0,0 +1,329 @@
1
+ /**
2
+ * SQLite backend implementation for memory storage
3
+ */
4
+
5
+ import { IMemoryBackend } from './base.ts';
6
+ import { MemoryEntry, MemoryQuery } from '../../utils/types.ts';
7
+ import { ILogger } from '../../core/logger.ts';
8
+ import { MemoryBackendError } from '../../utils/errors.ts';
9
+
10
+ // SQLite bindings placeholder - in real implementation, use a proper SQLite library
11
+ interface Database {
12
+ execute(sql: string, params?: unknown[]): Promise<unknown[]>;
13
+ close(): Promise<void>;
14
+ }
15
+
16
+ /**
17
+ * SQLite-based memory backend
18
+ */
19
+ export class SQLiteBackend implements IMemoryBackend {
20
+ private db?: Database;
21
+
22
+ constructor(
23
+ private dbPath: string,
24
+ private logger: ILogger,
25
+ ) {}
26
+
27
+ async initialize(): Promise<void> {
28
+ this.logger.info('Initializing SQLite backend', { dbPath: this.dbPath });
29
+
30
+ try {
31
+ // In real implementation, open SQLite connection
32
+ // this.db = await openDatabase(this.dbPath);
33
+
34
+ // Create tables
35
+ await this.createTables();
36
+
37
+ // Create indexes
38
+ await this.createIndexes();
39
+
40
+ this.logger.info('SQLite backend initialized');
41
+ } catch (error) {
42
+ throw new MemoryBackendError('Failed to initialize SQLite backend', { error });
43
+ }
44
+ }
45
+
46
+ async shutdown(): Promise<void> {
47
+ this.logger.info('Shutting down SQLite backend');
48
+
49
+ if (this.db) {
50
+ await this.db.close();
51
+ delete this.db;
52
+ }
53
+ }
54
+
55
+ async store(entry: MemoryEntry): Promise<void> {
56
+ if (!this.db) {
57
+ throw new MemoryBackendError('Database not initialized');
58
+ }
59
+
60
+ const sql = `
61
+ INSERT OR REPLACE INTO memory_entries (
62
+ id, agent_id, session_id, type, content,
63
+ context, timestamp, tags, version, parent_id, metadata
64
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
65
+ `;
66
+
67
+ const params = [
68
+ entry.id,
69
+ entry.agentId,
70
+ entry.sessionId,
71
+ entry.type,
72
+ entry.content,
73
+ JSON.stringify(entry.context),
74
+ entry.timestamp.toISOString(),
75
+ JSON.stringify(entry.tags),
76
+ entry.version,
77
+ entry.parentId || null,
78
+ entry.metadata ? JSON.stringify(entry.metadata) : null,
79
+ ];
80
+
81
+ try {
82
+ await this.db.execute(sql, params);
83
+ } catch (error) {
84
+ throw new MemoryBackendError('Failed to store entry', { error });
85
+ }
86
+ }
87
+
88
+ async retrieve(id: string): Promise<MemoryEntry | undefined> {
89
+ if (!this.db) {
90
+ throw new MemoryBackendError('Database not initialized');
91
+ }
92
+
93
+ const sql = 'SELECT * FROM memory_entries WHERE id = ?';
94
+
95
+ try {
96
+ const rows = await this.db.execute(sql, [id]);
97
+
98
+ if (rows.length === 0) {
99
+ return undefined;
100
+ }
101
+
102
+ return this.rowToEntry(rows[0] as Record<string, unknown>);
103
+ } catch (error) {
104
+ throw new MemoryBackendError('Failed to retrieve entry', { error });
105
+ }
106
+ }
107
+
108
+ async update(id: string, entry: MemoryEntry): Promise<void> {
109
+ // SQLite INSERT OR REPLACE handles updates
110
+ await this.store(entry);
111
+ }
112
+
113
+ async delete(id: string): Promise<void> {
114
+ if (!this.db) {
115
+ throw new MemoryBackendError('Database not initialized');
116
+ }
117
+
118
+ const sql = 'DELETE FROM memory_entries WHERE id = ?';
119
+
120
+ try {
121
+ await this.db.execute(sql, [id]);
122
+ } catch (error) {
123
+ throw new MemoryBackendError('Failed to delete entry', { error });
124
+ }
125
+ }
126
+
127
+ async query(query: MemoryQuery): Promise<MemoryEntry[]> {
128
+ if (!this.db) {
129
+ throw new MemoryBackendError('Database not initialized');
130
+ }
131
+
132
+ const conditions: string[] = [];
133
+ const params: unknown[] = [];
134
+
135
+ if (query.agentId) {
136
+ conditions.push('agent_id = ?');
137
+ params.push(query.agentId);
138
+ }
139
+
140
+ if (query.sessionId) {
141
+ conditions.push('session_id = ?');
142
+ params.push(query.sessionId);
143
+ }
144
+
145
+ if (query.type) {
146
+ conditions.push('type = ?');
147
+ params.push(query.type);
148
+ }
149
+
150
+ if (query.startTime) {
151
+ conditions.push('timestamp >= ?');
152
+ params.push(query.startTime.toISOString());
153
+ }
154
+
155
+ if (query.endTime) {
156
+ conditions.push('timestamp <= ?');
157
+ params.push(query.endTime.toISOString());
158
+ }
159
+
160
+ if (query.search) {
161
+ conditions.push('(content LIKE ? OR tags LIKE ?)');
162
+ params.push(`%${query.search}%`, `%${query.search}%`);
163
+ }
164
+
165
+ if (query.tags && query.tags.length > 0) {
166
+ const tagConditions = query.tags.map(() => 'tags LIKE ?');
167
+ conditions.push(`(${tagConditions.join(' OR ')})`);
168
+ query.tags.forEach(tag => params.push(`%"${tag}"%`));
169
+ }
170
+
171
+ let sql = 'SELECT * FROM memory_entries';
172
+ if (conditions.length > 0) {
173
+ sql += ' WHERE ' + conditions.join(' AND ');
174
+ }
175
+
176
+ sql += ' ORDER BY timestamp DESC';
177
+
178
+ if (query.limit) {
179
+ sql += ' LIMIT ?';
180
+ params.push(query.limit);
181
+ }
182
+
183
+ if (query.offset) {
184
+ sql += ' OFFSET ?';
185
+ params.push(query.offset);
186
+ }
187
+
188
+ try {
189
+ const rows = await this.db.execute(sql, params);
190
+ return rows.map(row => this.rowToEntry(row as Record<string, unknown>));
191
+ } catch (error) {
192
+ throw new MemoryBackendError('Failed to query entries', { error });
193
+ }
194
+ }
195
+
196
+ async getAllEntries(): Promise<MemoryEntry[]> {
197
+ if (!this.db) {
198
+ throw new MemoryBackendError('Database not initialized');
199
+ }
200
+
201
+ const sql = 'SELECT * FROM memory_entries ORDER BY timestamp DESC';
202
+
203
+ try {
204
+ const rows = await this.db.execute(sql);
205
+ return rows.map(row => this.rowToEntry(row as Record<string, unknown>));
206
+ } catch (error) {
207
+ throw new MemoryBackendError('Failed to get all entries', { error });
208
+ }
209
+ }
210
+
211
+ async getHealthStatus(): Promise<{
212
+ healthy: boolean;
213
+ error?: string;
214
+ metrics?: Record<string, number>;
215
+ }> {
216
+ if (!this.db) {
217
+ return {
218
+ healthy: false,
219
+ error: 'Database not initialized',
220
+ };
221
+ }
222
+
223
+ try {
224
+ // Check database connectivity
225
+ await this.db.execute('SELECT 1');
226
+
227
+ // Get metrics
228
+ const [countResult] = await this.db.execute(
229
+ 'SELECT COUNT(*) as count FROM memory_entries',
230
+ );
231
+ const entryCount = (countResult as any).count;
232
+
233
+ const [sizeResult] = await this.db.execute(
234
+ 'SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()',
235
+ );
236
+ const dbSize = (sizeResult as any).size;
237
+
238
+ return {
239
+ healthy: true,
240
+ metrics: {
241
+ entryCount,
242
+ dbSizeBytes: dbSize,
243
+ },
244
+ };
245
+ } catch (error) {
246
+ return {
247
+ healthy: false,
248
+ error: error instanceof Error ? error.message : 'Unknown error',
249
+ };
250
+ }
251
+ }
252
+
253
+ private async createTables(): Promise<void> {
254
+ const sql = `
255
+ CREATE TABLE IF NOT EXISTS memory_entries (
256
+ id TEXT PRIMARY KEY,
257
+ agent_id TEXT NOT NULL,
258
+ session_id TEXT NOT NULL,
259
+ type TEXT NOT NULL,
260
+ content TEXT NOT NULL,
261
+ context TEXT NOT NULL,
262
+ timestamp TEXT NOT NULL,
263
+ tags TEXT NOT NULL,
264
+ version INTEGER NOT NULL,
265
+ parent_id TEXT,
266
+ metadata TEXT,
267
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
268
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
269
+ )
270
+ `;
271
+
272
+ await this.db!.execute(sql);
273
+ }
274
+
275
+ private async createIndexes(): Promise<void> {
276
+ const indexes = [
277
+ 'CREATE INDEX IF NOT EXISTS idx_agent_id ON memory_entries(agent_id)',
278
+ 'CREATE INDEX IF NOT EXISTS idx_session_id ON memory_entries(session_id)',
279
+ 'CREATE INDEX IF NOT EXISTS idx_type ON memory_entries(type)',
280
+ 'CREATE INDEX IF NOT EXISTS idx_timestamp ON memory_entries(timestamp)',
281
+ 'CREATE INDEX IF NOT EXISTS idx_parent_id ON memory_entries(parent_id)',
282
+ ];
283
+
284
+ for (const sql of indexes) {
285
+ await this.db!.execute(sql);
286
+ }
287
+ }
288
+
289
+ private rowToEntry(row: Record<string, unknown>): MemoryEntry {
290
+ const entry: MemoryEntry = {
291
+ id: row.id as string,
292
+ agentId: row.agent_id as string,
293
+ sessionId: row.session_id as string,
294
+ type: row.type as MemoryEntry['type'],
295
+ content: row.content as string,
296
+ context: JSON.parse(row.context as string),
297
+ timestamp: new Date(row.timestamp as string),
298
+ tags: JSON.parse(row.tags as string),
299
+ version: row.version as number,
300
+ };
301
+
302
+ if (row.parent_id) {
303
+ entry.parentId = row.parent_id as string;
304
+ }
305
+
306
+ if (row.metadata) {
307
+ entry.metadata = JSON.parse(row.metadata as string);
308
+ }
309
+
310
+ return entry;
311
+ }
312
+ }
313
+
314
+ // Placeholder implementation - replace with actual SQLite library
315
+ async function openDatabase(path: string): Promise<Database> {
316
+ // In real implementation, use a proper SQLite library like:
317
+ // - https://deno.land/x/sqlite
318
+ // - https://deno.land/x/sqlite3
319
+
320
+ return {
321
+ async execute(sql: string, params?: unknown[]): Promise<unknown[]> {
322
+ // Placeholder
323
+ return [];
324
+ },
325
+ async close(): Promise<void> {
326
+ // Placeholder
327
+ },
328
+ };
329
+ }