supaclaw 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.
package/dist/cli.js ADDED
@@ -0,0 +1,1815 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const fs_1 = require("fs");
39
+ const path_1 = require("path");
40
+ const supabase_js_1 = require("@supabase/supabase-js");
41
+ const readline_1 = require("readline");
42
+ const CONFIG_FILE = '.openclaw-memory.json';
43
+ // ============ CLI HELPERS ============
44
+ function loadConfig() {
45
+ const configPath = (0, path_1.join)(process.cwd(), CONFIG_FILE);
46
+ if (!(0, fs_1.existsSync)(configPath)) {
47
+ return null;
48
+ }
49
+ try {
50
+ return JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
51
+ }
52
+ catch (err) {
53
+ console.error(`āŒ Failed to read ${CONFIG_FILE}:`, err);
54
+ process.exit(1);
55
+ }
56
+ }
57
+ function saveConfig(config) {
58
+ const configPath = (0, path_1.join)(process.cwd(), CONFIG_FILE);
59
+ (0, fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2));
60
+ console.log(`āœ… Saved config to ${CONFIG_FILE}`);
61
+ }
62
+ async function prompt(question) {
63
+ const rl = (0, readline_1.createInterface)({
64
+ input: process.stdin,
65
+ output: process.stdout
66
+ });
67
+ return new Promise((resolve) => {
68
+ rl.question(question, (answer) => {
69
+ rl.close();
70
+ resolve(answer.trim());
71
+ });
72
+ });
73
+ }
74
+ function getSupabaseClient(config) {
75
+ return (0, supabase_js_1.createClient)(config.supabaseUrl, config.supabaseKey);
76
+ }
77
+ // ============ COMMANDS ============
78
+ async function cmdInit() {
79
+ console.log('šŸš€ OpenClaw Memory - Setup\n');
80
+ // Check if config already exists
81
+ if ((0, fs_1.existsSync)((0, path_1.join)(process.cwd(), CONFIG_FILE))) {
82
+ const overwrite = await prompt('āš ļø Config already exists. Overwrite? (y/N): ');
83
+ if (overwrite.toLowerCase() !== 'y') {
84
+ console.log('Aborted.');
85
+ return;
86
+ }
87
+ }
88
+ console.log('Enter your Supabase project details:\n');
89
+ const supabaseUrl = await prompt('Supabase URL: ');
90
+ const supabaseKey = await prompt('Supabase anon/service key: ');
91
+ const agentId = await prompt('Agent ID (e.g., "hans-assistant"): ');
92
+ if (!supabaseUrl || !supabaseKey || !agentId) {
93
+ console.error('āŒ All fields are required.');
94
+ process.exit(1);
95
+ }
96
+ // Validate URL
97
+ try {
98
+ new URL(supabaseUrl);
99
+ }
100
+ catch {
101
+ console.error('āŒ Invalid Supabase URL');
102
+ process.exit(1);
103
+ }
104
+ const config = {
105
+ supabaseUrl,
106
+ supabaseKey,
107
+ agentId
108
+ };
109
+ saveConfig(config);
110
+ console.log('\nāœ… Configuration saved!');
111
+ console.log('\nNext steps:');
112
+ console.log(' 1. Run migrations: npx openclaw-memory migrate');
113
+ console.log(' 2. Test connection: npx openclaw-memory test');
114
+ console.log(' 3. Check status: npx openclaw-memory status');
115
+ }
116
+ async function cmdMigrate() {
117
+ const config = loadConfig();
118
+ if (!config) {
119
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
120
+ process.exit(1);
121
+ }
122
+ console.log('šŸ”„ Database Migration\n');
123
+ // Read migration file
124
+ const migrationPath = (0, path_1.join)(__dirname, '../migrations/001_initial.sql');
125
+ if (!(0, fs_1.existsSync)(migrationPath)) {
126
+ console.error('āŒ Migration file not found:', migrationPath);
127
+ process.exit(1);
128
+ }
129
+ const sql = (0, fs_1.readFileSync)(migrationPath, 'utf-8');
130
+ console.log('To set up your database:\n');
131
+ console.log('1. Go to your Supabase dashboard');
132
+ console.log(` ${config.supabaseUrl.replace('/rest/v1', '')}`);
133
+ console.log('2. Navigate to: SQL Editor → New Query');
134
+ console.log('3. Copy the SQL from:');
135
+ console.log(` ${migrationPath}`);
136
+ console.log('4. Paste and run the query\n');
137
+ console.log('Or run this SQL directly:\n');
138
+ console.log('─'.repeat(60));
139
+ console.log(sql);
140
+ console.log('─'.repeat(60));
141
+ console.log('\nāœ… After running the migration, verify with:');
142
+ console.log(' npx openclaw-memory test');
143
+ console.log(' npx openclaw-memory status');
144
+ }
145
+ async function cmdTest() {
146
+ const config = loadConfig();
147
+ if (!config) {
148
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
149
+ process.exit(1);
150
+ }
151
+ console.log('šŸ”Œ Testing Supabase Connection...\n');
152
+ const supabase = getSupabaseClient(config);
153
+ try {
154
+ // Test basic connectivity
155
+ const { error: sessionsError } = await supabase
156
+ .from('sessions')
157
+ .select('id')
158
+ .limit(1);
159
+ if (sessionsError) {
160
+ if (sessionsError.code === '42P01') {
161
+ console.error('āŒ Tables not found. Run migrations first:');
162
+ console.error(' npx openclaw-memory migrate');
163
+ }
164
+ else {
165
+ console.error('āŒ Connection failed:', sessionsError.message);
166
+ }
167
+ process.exit(1);
168
+ }
169
+ console.log('āœ… Connection successful!');
170
+ console.log(` Agent ID: ${config.agentId}`);
171
+ console.log(` Database: ${config.supabaseUrl}\n`);
172
+ // Test each table
173
+ const tables = ['sessions', 'messages', 'memories', 'entities', 'tasks', 'learnings'];
174
+ let allTablesExist = true;
175
+ for (const table of tables) {
176
+ const { error } = await supabase
177
+ .from(table)
178
+ .select('id')
179
+ .limit(1);
180
+ if (error) {
181
+ console.log(`āŒ Table "${table}" not found`);
182
+ allTablesExist = false;
183
+ }
184
+ else {
185
+ console.log(`āœ… Table "${table}" accessible`);
186
+ }
187
+ }
188
+ if (!allTablesExist) {
189
+ console.log('\nāš ļø Some tables are missing. Run migrations:');
190
+ console.log(' npx openclaw-memory migrate');
191
+ process.exit(1);
192
+ }
193
+ console.log('\nšŸŽ‰ All systems operational!');
194
+ }
195
+ catch (err) {
196
+ console.error('āŒ Unexpected error:', err);
197
+ process.exit(1);
198
+ }
199
+ }
200
+ async function cmdStatus() {
201
+ const config = loadConfig();
202
+ if (!config) {
203
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
204
+ process.exit(1);
205
+ }
206
+ console.log('šŸ“Š OpenClaw Memory - Status\n');
207
+ const supabase = getSupabaseClient(config);
208
+ try {
209
+ const tables = ['sessions', 'messages', 'memories', 'entities', 'tasks', 'learnings'];
210
+ const stats = {};
211
+ for (const table of tables) {
212
+ const { count, error } = await supabase
213
+ .from(table)
214
+ .select('*', { count: 'exact', head: true })
215
+ .eq('agent_id', config.agentId);
216
+ if (error) {
217
+ if (error.code === '42P01') {
218
+ stats[table] = -1;
219
+ }
220
+ else {
221
+ console.error(`āŒ Error checking ${table}:`, error.message);
222
+ stats[table] = -1;
223
+ }
224
+ }
225
+ else {
226
+ stats[table] = count || 0;
227
+ }
228
+ }
229
+ console.log(`Agent ID: ${config.agentId}`);
230
+ console.log(`Supabase: ${config.supabaseUrl}\n`);
231
+ console.log('Database Statistics:');
232
+ for (const [table, count] of Object.entries(stats)) {
233
+ if (count === -1) {
234
+ console.log(` ${table.padEnd(12)} āš ļø not found`);
235
+ }
236
+ else {
237
+ console.log(` ${table.padEnd(12)} ${count.toString().padStart(6)} records`);
238
+ }
239
+ }
240
+ // Check for active sessions
241
+ const { data: activeSessions } = await supabase
242
+ .from('sessions')
243
+ .select('id, started_at, channel')
244
+ .eq('agent_id', config.agentId)
245
+ .is('ended_at', null)
246
+ .order('started_at', { ascending: false })
247
+ .limit(5);
248
+ if (activeSessions && activeSessions.length > 0) {
249
+ console.log(`\nšŸ’¬ Active Sessions: ${activeSessions.length}`);
250
+ activeSessions.forEach(s => {
251
+ const date = new Date(s.started_at).toLocaleString();
252
+ console.log(` - ${s.id.slice(0, 8)}... (${s.channel || 'unknown'}) started ${date}`);
253
+ });
254
+ }
255
+ else {
256
+ console.log('\nšŸ’¬ No active sessions');
257
+ }
258
+ }
259
+ catch (err) {
260
+ console.error('āŒ Failed to fetch status:', err);
261
+ process.exit(1);
262
+ }
263
+ }
264
+ async function cmdSearch(query, options) {
265
+ const config = loadConfig();
266
+ if (!config) {
267
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
268
+ process.exit(1);
269
+ }
270
+ if (!query || query.trim().length === 0) {
271
+ console.error('āŒ Search query is required');
272
+ process.exit(1);
273
+ }
274
+ const limit = options.limit || 10;
275
+ const mode = options.mode || 'keyword';
276
+ const modeEmoji = {
277
+ keyword: 'šŸ“',
278
+ semantic: '🧠',
279
+ hybrid: '⚔'
280
+ };
281
+ console.log(`${modeEmoji[mode]} Searching memories (${mode} mode): "${query}"\n`);
282
+ const supabase = getSupabaseClient(config);
283
+ try {
284
+ let data = [];
285
+ if (mode === 'keyword') {
286
+ // Traditional keyword search
287
+ const { data: results, error } = await supabase
288
+ .from('memories')
289
+ .select('*')
290
+ .eq('agent_id', config.agentId)
291
+ .or(`content.ilike.%${query}%,category.ilike.%${query}%`)
292
+ .order('importance', { ascending: false })
293
+ .limit(limit);
294
+ if (error)
295
+ throw error;
296
+ data = results || [];
297
+ }
298
+ else if (mode === 'semantic') {
299
+ // Vector similarity search (requires OpenAI API key)
300
+ const openaiKey = process.env.OPENAI_API_KEY;
301
+ if (!openaiKey) {
302
+ console.error('āŒ OPENAI_API_KEY environment variable required for semantic search');
303
+ process.exit(1);
304
+ }
305
+ const OpenAI = (await Promise.resolve().then(() => __importStar(require('openai')))).default;
306
+ const openai = new OpenAI({ apiKey: openaiKey });
307
+ const embeddingResponse = await openai.embeddings.create({
308
+ model: 'text-embedding-3-small',
309
+ input: query,
310
+ });
311
+ const queryEmbedding = embeddingResponse.data[0].embedding;
312
+ const { data: results, error } = await supabase.rpc('match_memories', {
313
+ query_embedding: queryEmbedding,
314
+ match_threshold: options.minSimilarity || 0.7,
315
+ match_count: limit,
316
+ p_agent_id: config.agentId
317
+ });
318
+ if (error)
319
+ throw error;
320
+ data = results || [];
321
+ }
322
+ else if (mode === 'hybrid') {
323
+ // Hybrid search: vector + keyword
324
+ const openaiKey = process.env.OPENAI_API_KEY;
325
+ if (!openaiKey) {
326
+ console.error('āŒ OPENAI_API_KEY environment variable required for hybrid search');
327
+ process.exit(1);
328
+ }
329
+ const OpenAI = (await Promise.resolve().then(() => __importStar(require('openai')))).default;
330
+ const openai = new OpenAI({ apiKey: openaiKey });
331
+ const embeddingResponse = await openai.embeddings.create({
332
+ model: 'text-embedding-3-small',
333
+ input: query,
334
+ });
335
+ const queryEmbedding = embeddingResponse.data[0].embedding;
336
+ const { data: results, error } = await supabase.rpc('hybrid_search_memories', {
337
+ query_embedding: queryEmbedding,
338
+ query_text: query,
339
+ vector_weight: 0.7,
340
+ keyword_weight: 0.3,
341
+ match_count: limit,
342
+ p_agent_id: config.agentId
343
+ });
344
+ if (error)
345
+ throw error;
346
+ data = results || [];
347
+ }
348
+ if (!data || data.length === 0) {
349
+ console.log('No memories found.');
350
+ return;
351
+ }
352
+ console.log(`Found ${data.length} memories:\n`);
353
+ data.forEach((mem, idx) => {
354
+ const scoreLabel = mem.similarity ? `similarity: ${mem.similarity.toFixed(3)}` :
355
+ mem.score ? `score: ${mem.score.toFixed(3)}` :
356
+ `importance: ${mem.importance}`;
357
+ console.log(`${idx + 1}. [${mem.category || 'none'}] (${scoreLabel})`);
358
+ console.log(` ${mem.content}`);
359
+ if (mem.metadata && Object.keys(mem.metadata).length > 0) {
360
+ console.log(` Metadata: ${JSON.stringify(mem.metadata)}`);
361
+ }
362
+ console.log(` Created: ${new Date(mem.created_at).toLocaleString()}\n`);
363
+ });
364
+ }
365
+ catch (err) {
366
+ console.error('āŒ Search error:', err);
367
+ process.exit(1);
368
+ }
369
+ }
370
+ async function cmdSessions(options) {
371
+ const config = loadConfig();
372
+ if (!config) {
373
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
374
+ process.exit(1);
375
+ }
376
+ console.log('šŸ“‹ Sessions\n');
377
+ const supabase = getSupabaseClient(config);
378
+ const limit = options.limit || 20;
379
+ try {
380
+ let query = supabase
381
+ .from('sessions')
382
+ .select('*')
383
+ .eq('agent_id', config.agentId);
384
+ if (options.active) {
385
+ query = query.is('ended_at', null);
386
+ }
387
+ const { data, error } = await query
388
+ .order('started_at', { ascending: false })
389
+ .limit(limit);
390
+ if (error) {
391
+ console.error('āŒ Failed to fetch sessions:', error.message);
392
+ process.exit(1);
393
+ }
394
+ if (!data || data.length === 0) {
395
+ console.log('No sessions found.');
396
+ return;
397
+ }
398
+ console.log(`Found ${data.length} sessions:\n`);
399
+ data.forEach((session, idx) => {
400
+ const started = new Date(session.started_at).toLocaleString();
401
+ const ended = session.ended_at ? new Date(session.ended_at).toLocaleString() : 'active';
402
+ const status = session.ended_at ? 'āœ“' : 'ā—';
403
+ console.log(`${status} ${session.id.slice(0, 8)}...`);
404
+ console.log(` User: ${session.user_id || 'unknown'}`);
405
+ console.log(` Channel: ${session.channel || 'unknown'}`);
406
+ console.log(` Started: ${started}`);
407
+ console.log(` Ended: ${ended}`);
408
+ if (session.summary) {
409
+ console.log(` Summary: ${session.summary.slice(0, 100)}${session.summary.length > 100 ? '...' : ''}`);
410
+ }
411
+ console.log('');
412
+ });
413
+ }
414
+ catch (err) {
415
+ console.error('āŒ Error:', err);
416
+ process.exit(1);
417
+ }
418
+ }
419
+ async function cmdExport(outputPath) {
420
+ const config = loadConfig();
421
+ if (!config) {
422
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
423
+ process.exit(1);
424
+ }
425
+ console.log('šŸ“¤ Exporting memories to markdown...\n');
426
+ const supabase = getSupabaseClient(config);
427
+ try {
428
+ // Fetch all memories
429
+ const { data, error } = await supabase
430
+ .from('memories')
431
+ .select('*')
432
+ .eq('agent_id', config.agentId)
433
+ .order('created_at', { ascending: false });
434
+ if (error) {
435
+ console.error('āŒ Export failed:', error.message);
436
+ process.exit(1);
437
+ }
438
+ if (!data || data.length === 0) {
439
+ console.log('No memories to export.');
440
+ return;
441
+ }
442
+ // Build markdown
443
+ let markdown = `# OpenClaw Memory Export\n\n`;
444
+ markdown += `**Agent:** ${config.agentId}\n`;
445
+ markdown += `**Exported:** ${new Date().toISOString()}\n`;
446
+ markdown += `**Total Memories:** ${data.length}\n\n`;
447
+ markdown += `---\n\n`;
448
+ // Group by category
449
+ const byCategory = {};
450
+ data.forEach(mem => {
451
+ const cat = mem.category || 'uncategorized';
452
+ if (!byCategory[cat])
453
+ byCategory[cat] = [];
454
+ byCategory[cat].push(mem);
455
+ });
456
+ for (const [category, memories] of Object.entries(byCategory)) {
457
+ markdown += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
458
+ memories.forEach(mem => {
459
+ markdown += `### ${new Date(mem.created_at).toISOString().split('T')[0]}\n\n`;
460
+ markdown += `**Importance:** ${mem.importance}\n\n`;
461
+ markdown += `${mem.content}\n\n`;
462
+ if (mem.metadata) {
463
+ markdown += `*Metadata:* ${JSON.stringify(mem.metadata)}\n\n`;
464
+ }
465
+ markdown += `---\n\n`;
466
+ });
467
+ }
468
+ // Write to file
469
+ const resolvedPath = outputPath || 'openclaw-memory-export.md';
470
+ (0, fs_1.writeFileSync)(resolvedPath, markdown, 'utf-8');
471
+ console.log(`āœ… Exported ${data.length} memories to: ${resolvedPath}`);
472
+ }
473
+ catch (err) {
474
+ console.error('āŒ Export error:', err);
475
+ process.exit(1);
476
+ }
477
+ }
478
+ async function cmdImport(inputPath) {
479
+ const config = loadConfig();
480
+ if (!config) {
481
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
482
+ process.exit(1);
483
+ }
484
+ console.log(`šŸ“„ Importing memories from: ${inputPath}\n`);
485
+ if (!(0, fs_1.existsSync)(inputPath)) {
486
+ console.error('āŒ File not found:', inputPath);
487
+ process.exit(1);
488
+ }
489
+ try {
490
+ const content = (0, fs_1.readFileSync)(inputPath, 'utf-8');
491
+ // Simple parser: extract lines that look like memories
492
+ // Format: "- Memory text" or "* Memory text"
493
+ const lines = content.split('\n');
494
+ const memories = [];
495
+ let currentCategory = 'imported';
496
+ lines.forEach(line => {
497
+ line = line.trim();
498
+ // Detect category headers
499
+ if (line.startsWith('## ')) {
500
+ currentCategory = line.slice(3).toLowerCase().trim();
501
+ return;
502
+ }
503
+ // Detect memory lines
504
+ if (line.startsWith('- ') || line.startsWith('* ')) {
505
+ const content = line.slice(2).trim();
506
+ if (content.length > 0) {
507
+ memories.push({
508
+ content,
509
+ category: currentCategory,
510
+ importance: 0.5 // default
511
+ });
512
+ }
513
+ }
514
+ });
515
+ if (memories.length === 0) {
516
+ console.log('āš ļø No memories found in file. Expected format:');
517
+ console.log(' ## Category Name');
518
+ console.log(' - Memory item one');
519
+ console.log(' - Memory item two');
520
+ return;
521
+ }
522
+ console.log(`Found ${memories.length} memories to import.\n`);
523
+ const supabase = getSupabaseClient(config);
524
+ let imported = 0;
525
+ for (const mem of memories) {
526
+ const { error } = await supabase
527
+ .from('memories')
528
+ .insert({
529
+ agent_id: config.agentId,
530
+ content: mem.content,
531
+ category: mem.category,
532
+ importance: mem.importance
533
+ });
534
+ if (error) {
535
+ console.error(`āŒ Failed to import: ${mem.content.slice(0, 50)}...`);
536
+ console.error(` Error: ${error.message}`);
537
+ }
538
+ else {
539
+ imported++;
540
+ }
541
+ }
542
+ console.log(`\nāœ… Successfully imported ${imported}/${memories.length} memories`);
543
+ }
544
+ catch (err) {
545
+ console.error('āŒ Import error:', err);
546
+ process.exit(1);
547
+ }
548
+ }
549
+ async function cmdDecay(options) {
550
+ const config = loadConfig();
551
+ if (!config) {
552
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
553
+ process.exit(1);
554
+ }
555
+ try {
556
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
557
+ const memory = new OpenClawMemory({
558
+ supabaseUrl: config.supabaseUrl,
559
+ supabaseKey: config.supabaseKey,
560
+ agentId: config.agentId
561
+ });
562
+ console.log(`šŸ”„ Applying importance decay to memories older than ${options.olderThanDays} days...`);
563
+ const result = await memory.decayMemoryImportance(options);
564
+ console.log(`\nāœ… Decay complete:`);
565
+ console.log(` - Updated: ${result.updated} memories`);
566
+ console.log(` - Average decay: ${(result.avgDecay * 100).toFixed(2)}%`);
567
+ }
568
+ catch (err) {
569
+ console.error('āŒ Decay error:', err);
570
+ process.exit(1);
571
+ }
572
+ }
573
+ async function cmdConsolidate(options) {
574
+ const config = loadConfig();
575
+ if (!config) {
576
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
577
+ process.exit(1);
578
+ }
579
+ try {
580
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
581
+ const memory = new OpenClawMemory({
582
+ supabaseUrl: config.supabaseUrl,
583
+ supabaseKey: config.supabaseKey,
584
+ agentId: config.agentId
585
+ });
586
+ console.log(`šŸ”„ Consolidating similar memories (threshold: ${options.similarityThreshold})...`);
587
+ const result = await memory.consolidateMemories(options);
588
+ console.log(`\nāœ… Consolidation complete:`);
589
+ console.log(` - Merged: ${result.merged} memories`);
590
+ console.log(` - Kept: ${result.kept} unique memories`);
591
+ }
592
+ catch (err) {
593
+ console.error('āŒ Consolidation error:', err);
594
+ process.exit(1);
595
+ }
596
+ }
597
+ async function cmdTag(memoryId, tags) {
598
+ const config = loadConfig();
599
+ if (!config) {
600
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
601
+ process.exit(1);
602
+ }
603
+ try {
604
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
605
+ const memory = new OpenClawMemory({
606
+ supabaseUrl: config.supabaseUrl,
607
+ supabaseKey: config.supabaseKey,
608
+ agentId: config.agentId
609
+ });
610
+ const result = await memory.tagMemory(memoryId, tags);
611
+ const allTags = result.metadata?.tags || [];
612
+ console.log(`āœ… Tagged memory ${memoryId}`);
613
+ console.log(` Tags: ${allTags.join(', ')}`);
614
+ }
615
+ catch (err) {
616
+ console.error('āŒ Tag error:', err);
617
+ process.exit(1);
618
+ }
619
+ }
620
+ async function cmdUntag(memoryId, tags) {
621
+ const config = loadConfig();
622
+ if (!config) {
623
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
624
+ process.exit(1);
625
+ }
626
+ try {
627
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
628
+ const memory = new OpenClawMemory({
629
+ supabaseUrl: config.supabaseUrl,
630
+ supabaseKey: config.supabaseKey,
631
+ agentId: config.agentId
632
+ });
633
+ const result = await memory.untagMemory(memoryId, tags);
634
+ const allTags = result.metadata?.tags || [];
635
+ console.log(`āœ… Removed tags from memory ${memoryId}`);
636
+ console.log(` Remaining tags: ${allTags.length > 0 ? allTags.join(', ') : 'none'}`);
637
+ }
638
+ catch (err) {
639
+ console.error('āŒ Untag error:', err);
640
+ process.exit(1);
641
+ }
642
+ }
643
+ async function cmdSearchTags(tags, options) {
644
+ const config = loadConfig();
645
+ if (!config) {
646
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
647
+ process.exit(1);
648
+ }
649
+ try {
650
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
651
+ const memory = new OpenClawMemory({
652
+ supabaseUrl: config.supabaseUrl,
653
+ supabaseKey: config.supabaseKey,
654
+ agentId: config.agentId
655
+ });
656
+ console.log(`šŸ” Searching for memories with tags: ${tags.join(', ')} (${options.matchAll ? 'ALL' : 'ANY'})`);
657
+ const results = await memory.searchMemoriesByTags(tags, options);
658
+ if (results.length === 0) {
659
+ console.log(' No matching memories found.');
660
+ return;
661
+ }
662
+ console.log(`\nFound ${results.length} memories:\n`);
663
+ results.forEach((mem, i) => {
664
+ const memTags = mem.metadata?.tags || [];
665
+ console.log(`${i + 1}. [${mem.category || 'uncategorized'}] ${mem.content.slice(0, 80)}...`);
666
+ console.log(` Tags: ${memTags.join(', ')}`);
667
+ console.log(` Importance: ${mem.importance}`);
668
+ console.log();
669
+ });
670
+ }
671
+ catch (err) {
672
+ console.error('āŒ Search error:', err);
673
+ process.exit(1);
674
+ }
675
+ }
676
+ async function cmdCleanup(options) {
677
+ const config = loadConfig();
678
+ if (!config) {
679
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
680
+ process.exit(1);
681
+ }
682
+ try {
683
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
684
+ const memory = new OpenClawMemory({
685
+ supabaseUrl: config.supabaseUrl,
686
+ supabaseKey: config.supabaseKey,
687
+ agentId: config.agentId
688
+ });
689
+ const actionWord = options.action === 'delete' ? 'Deleting' : 'Archiving';
690
+ console.log(`šŸ”„ ${actionWord} sessions older than ${options.olderThanDays} days...`);
691
+ const result = await memory.cleanupOldSessions(options);
692
+ const count = options.action === 'delete' ? result.deleted : result.archived;
693
+ console.log(`\nāœ… Cleanup complete: ${actionWord.toLowerCase()} ${count} sessions`);
694
+ }
695
+ catch (err) {
696
+ console.error('āŒ Cleanup error:', err);
697
+ process.exit(1);
698
+ }
699
+ }
700
+ async function cmdCleanupStats() {
701
+ const config = loadConfig();
702
+ if (!config) {
703
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
704
+ process.exit(1);
705
+ }
706
+ try {
707
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
708
+ const memory = new OpenClawMemory({
709
+ supabaseUrl: config.supabaseUrl,
710
+ supabaseKey: config.supabaseKey,
711
+ agentId: config.agentId
712
+ });
713
+ console.log('šŸ“Š Gathering cleanup statistics...\n');
714
+ const stats = await memory.getCleanupStats();
715
+ console.log('Sessions:');
716
+ console.log(` Total: ${stats.totalSessions}`);
717
+ console.log(` Archived: ${stats.archivedSessions}`);
718
+ console.log(` Old (>90 days): ${stats.oldSessions}`);
719
+ console.log();
720
+ console.log('Messages:');
721
+ console.log(` Total: ${stats.totalMessages}`);
722
+ console.log(` Orphaned: ${stats.orphanedMessages}`);
723
+ }
724
+ catch (err) {
725
+ console.error('āŒ Stats error:', err);
726
+ process.exit(1);
727
+ }
728
+ }
729
+ // ============ MAIN ============
730
+ const program = new commander_1.Command();
731
+ program
732
+ .name('openclaw-memory')
733
+ .description('Persistent memory for AI agents using Supabase')
734
+ .version('0.1.0');
735
+ program
736
+ .command('init')
737
+ .description('Initialize configuration (creates .openclaw-memory.json)')
738
+ .action(cmdInit);
739
+ program
740
+ .command('migrate')
741
+ .description('Display database migration SQL')
742
+ .action(cmdMigrate);
743
+ program
744
+ .command('test')
745
+ .description('Test Supabase connection and verify tables')
746
+ .action(cmdTest);
747
+ program
748
+ .command('status')
749
+ .description('Show database statistics and active sessions')
750
+ .action(cmdStatus);
751
+ program
752
+ .command('search <query>')
753
+ .description('Search memories using keyword, semantic, or hybrid search')
754
+ .option('-l, --limit <number>', 'Maximum results', '10')
755
+ .option('-m, --mode <type>', 'Search mode: keyword, semantic, or hybrid', 'keyword')
756
+ .option('-s, --min-similarity <number>', 'Minimum similarity score (0-1) for semantic/hybrid search', '0.7')
757
+ .action((query, options) => {
758
+ const mode = ['keyword', 'semantic', 'hybrid'].includes(options.mode) ? options.mode : 'keyword';
759
+ cmdSearch(query, {
760
+ limit: parseInt(options.limit),
761
+ mode: mode,
762
+ minSimilarity: parseFloat(options.minSimilarity)
763
+ });
764
+ });
765
+ program
766
+ .command('sessions')
767
+ .description('List recent sessions')
768
+ .option('-l, --limit <number>', 'Maximum sessions', '20')
769
+ .option('-a, --active', 'Show only active sessions')
770
+ .action((options) => {
771
+ cmdSessions({
772
+ limit: parseInt(options.limit),
773
+ active: options.active
774
+ });
775
+ });
776
+ program
777
+ .command('export [path]')
778
+ .description('Export memories to markdown file')
779
+ .action((path) => {
780
+ cmdExport(path || 'openclaw-memory-export.md');
781
+ });
782
+ program
783
+ .command('import <path>')
784
+ .description('Import memories from markdown file')
785
+ .action(cmdImport);
786
+ program
787
+ .command('decay')
788
+ .description('Apply importance decay to old memories')
789
+ .option('-d, --days <number>', 'Only decay memories older than X days', '7')
790
+ .option('-r, --rate <number>', 'Decay rate (0-1)', '0.1')
791
+ .option('--min <number>', 'Minimum importance threshold', '0.1')
792
+ .action((options) => {
793
+ cmdDecay({
794
+ olderThanDays: parseInt(options.days),
795
+ decayRate: parseFloat(options.rate),
796
+ minImportance: parseFloat(options.min)
797
+ });
798
+ });
799
+ program
800
+ .command('consolidate')
801
+ .description('Merge similar memories')
802
+ .option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.9')
803
+ .option('-c, --category <name>', 'Filter by category')
804
+ .option('-l, --limit <number>', 'Max memories to check', '100')
805
+ .action((options) => {
806
+ cmdConsolidate({
807
+ similarityThreshold: parseFloat(options.threshold),
808
+ category: options.category,
809
+ limit: parseInt(options.limit)
810
+ });
811
+ });
812
+ program
813
+ .command('tag <memoryId> <tags...>')
814
+ .description('Add tags to a memory')
815
+ .action(cmdTag);
816
+ program
817
+ .command('untag <memoryId> <tags...>')
818
+ .description('Remove tags from a memory')
819
+ .action(cmdUntag);
820
+ program
821
+ .command('search-tags <tags...>')
822
+ .description('Search memories by tags')
823
+ .option('-a, --all', 'Match ALL tags (default: match ANY)')
824
+ .option('-l, --limit <number>', 'Maximum results', '50')
825
+ .action((tags, options) => {
826
+ cmdSearchTags(tags, {
827
+ matchAll: options.all,
828
+ limit: parseInt(options.limit)
829
+ });
830
+ });
831
+ program
832
+ .command('cleanup')
833
+ .description('Archive or delete old sessions')
834
+ .option('-d, --days <number>', 'Archive sessions older than X days', '90')
835
+ .option('--delete', 'Delete instead of archive')
836
+ .option('--keep-summaries', 'Keep sessions with summaries', true)
837
+ .action((options) => {
838
+ cmdCleanup({
839
+ olderThanDays: parseInt(options.days),
840
+ action: options.delete ? 'delete' : 'archive',
841
+ keepSummaries: options.keepSummaries
842
+ });
843
+ });
844
+ program
845
+ .command('cleanup-stats')
846
+ .description('Show cleanup statistics')
847
+ .action(cmdCleanupStats);
848
+ program
849
+ .command('entities')
850
+ .description('List entities')
851
+ .option('-t, --type <type>', 'Filter by entity type')
852
+ .option('-l, --limit <number>', 'Maximum results', '50')
853
+ .action(async (options) => {
854
+ const config = loadConfig();
855
+ if (!config) {
856
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
857
+ process.exit(1);
858
+ }
859
+ try {
860
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
861
+ const memory = new OpenClawMemory({
862
+ supabaseUrl: config.supabaseUrl,
863
+ supabaseKey: config.supabaseKey,
864
+ agentId: config.agentId
865
+ });
866
+ const entities = await memory.searchEntities({
867
+ entityType: options.type,
868
+ limit: parseInt(options.limit)
869
+ });
870
+ if (entities.length === 0) {
871
+ console.log('No entities found.');
872
+ return;
873
+ }
874
+ console.log(`\nšŸ“¦ Found ${entities.length} entities:\n`);
875
+ entities.forEach((entity, i) => {
876
+ console.log(`${i + 1}. ${entity.name} [${entity.entity_type}]`);
877
+ console.log(` ID: ${entity.id}`);
878
+ if (entity.description) {
879
+ console.log(` Description: ${entity.description}`);
880
+ }
881
+ if (entity.aliases && entity.aliases.length > 0) {
882
+ console.log(` Aliases: ${entity.aliases.join(', ')}`);
883
+ }
884
+ console.log(` Mentions: ${entity.mention_count}`);
885
+ console.log(` Last seen: ${new Date(entity.last_seen_at).toLocaleString()}`);
886
+ console.log();
887
+ });
888
+ }
889
+ catch (err) {
890
+ console.error('āŒ Error:', err);
891
+ process.exit(1);
892
+ }
893
+ });
894
+ program
895
+ .command('entity-graph <entityId>')
896
+ .description('Show entity relationship graph')
897
+ .option('-d, --depth <number>', 'Maximum depth', '2')
898
+ .option('-c, --min-confidence <number>', 'Minimum confidence', '0.5')
899
+ .action(async (entityId, options) => {
900
+ const config = loadConfig();
901
+ if (!config) {
902
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
903
+ process.exit(1);
904
+ }
905
+ try {
906
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
907
+ const memory = new OpenClawMemory({
908
+ supabaseUrl: config.supabaseUrl,
909
+ supabaseKey: config.supabaseKey,
910
+ agentId: config.agentId
911
+ });
912
+ // Get direct relationships
913
+ const relationships = await memory.getEntityRelationships(entityId);
914
+ console.log(`\nšŸ•øļø Entity Relationship Graph\n`);
915
+ if (relationships.length === 0) {
916
+ console.log('No relationships found.');
917
+ return;
918
+ }
919
+ // Group by direction
920
+ const outgoing = relationships.filter(r => r.direction === 'outgoing');
921
+ const incoming = relationships.filter(r => r.direction === 'incoming');
922
+ if (outgoing.length > 0) {
923
+ console.log('Outgoing relationships:');
924
+ outgoing.forEach(r => {
925
+ console.log(` → ${r.relatedEntity.name} [${r.relationship.relationship_type}]`);
926
+ console.log(` Confidence: ${r.relationship.confidence.toFixed(2)}, Mentions: ${r.relationship.mention_count}`);
927
+ });
928
+ console.log();
929
+ }
930
+ if (incoming.length > 0) {
931
+ console.log('Incoming relationships:');
932
+ incoming.forEach(r => {
933
+ console.log(` ← ${r.relatedEntity.name} [${r.relationship.relationship_type}]`);
934
+ console.log(` Confidence: ${r.relationship.confidence.toFixed(2)}, Mentions: ${r.relationship.mention_count}`);
935
+ });
936
+ console.log();
937
+ }
938
+ // Get related entities (graph traversal)
939
+ const related = await memory.findRelatedEntities(entityId, {
940
+ maxDepth: parseInt(options.depth),
941
+ minConfidence: parseFloat(options.minConfidence)
942
+ });
943
+ if (related.length > 0) {
944
+ console.log(`Related entities (within ${options.depth} hops):`);
945
+ related.forEach(r => {
946
+ const path = r.relationshipPath.join(' → ');
947
+ console.log(` ${r.entityName} [${r.entityType}]`);
948
+ console.log(` Path: ${path}`);
949
+ console.log(` Confidence: ${r.totalConfidence.toFixed(3)}, Depth: ${r.depth}`);
950
+ });
951
+ }
952
+ }
953
+ catch (err) {
954
+ console.error('āŒ Error:', err);
955
+ process.exit(1);
956
+ }
957
+ });
958
+ program
959
+ .command('entity-stats')
960
+ .description('Show entity network statistics')
961
+ .action(async () => {
962
+ const config = loadConfig();
963
+ if (!config) {
964
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
965
+ process.exit(1);
966
+ }
967
+ try {
968
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
969
+ const memory = new OpenClawMemory({
970
+ supabaseUrl: config.supabaseUrl,
971
+ supabaseKey: config.supabaseKey,
972
+ agentId: config.agentId
973
+ });
974
+ const stats = await memory.getEntityNetworkStats();
975
+ console.log('\nšŸ“Š Entity Network Statistics\n');
976
+ console.log(`Total Entities: ${stats.totalEntities}`);
977
+ console.log(`Total Relationships: ${stats.totalRelationships}`);
978
+ console.log(`Avg Connections per Entity: ${stats.avgConnectionsPerEntity.toFixed(2)}`);
979
+ if (stats.mostConnectedEntity) {
980
+ console.log(`\nMost Connected Entity:`);
981
+ console.log(` Name: ${stats.mostConnectedEntity.name}`);
982
+ console.log(` Connections: ${stats.mostConnectedEntity.connectionCount}`);
983
+ }
984
+ }
985
+ catch (err) {
986
+ console.error('āŒ Error:', err);
987
+ process.exit(1);
988
+ }
989
+ });
990
+ program
991
+ .command('extract-entities <text>')
992
+ .description('Extract entities and relationships from text')
993
+ .option('-k, --openai-key <key>', 'OpenAI API key (or set OPENAI_API_KEY env var)')
994
+ .action(async (text, options) => {
995
+ const config = loadConfig();
996
+ if (!config) {
997
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
998
+ process.exit(1);
999
+ }
1000
+ const apiKey = options.openaiKey || process.env.OPENAI_API_KEY;
1001
+ if (!apiKey) {
1002
+ console.error('āŒ OpenAI API key required. Provide via --openai-key or OPENAI_API_KEY env var.');
1003
+ process.exit(1);
1004
+ }
1005
+ try {
1006
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1007
+ const memory = new OpenClawMemory({
1008
+ supabaseUrl: config.supabaseUrl,
1009
+ supabaseKey: config.supabaseKey,
1010
+ agentId: config.agentId,
1011
+ openaiApiKey: apiKey
1012
+ });
1013
+ console.log('🧠 Extracting entities and relationships...\n');
1014
+ const result = await memory.extractEntitiesWithRelationships(text);
1015
+ console.log(`āœ… Extracted:`);
1016
+ console.log(` Entities: ${result.entities.length}`);
1017
+ console.log(` Relationships: ${result.relationships.length}\n`);
1018
+ if (result.entities.length > 0) {
1019
+ console.log('Entities:');
1020
+ result.entities.forEach(e => {
1021
+ console.log(` - ${e.name} [${e.entity_type}]`);
1022
+ if (e.description) {
1023
+ console.log(` ${e.description}`);
1024
+ }
1025
+ });
1026
+ console.log();
1027
+ }
1028
+ if (result.relationships.length > 0) {
1029
+ console.log('Relationships:');
1030
+ result.relationships.forEach(r => {
1031
+ const source = result.entities.find(e => e.id === r.source_entity_id)?.name;
1032
+ const target = result.entities.find(e => e.id === r.target_entity_id)?.name;
1033
+ console.log(` - ${source} → ${r.relationship_type} → ${target}`);
1034
+ console.log(` Confidence: ${r.confidence.toFixed(2)}`);
1035
+ });
1036
+ }
1037
+ }
1038
+ catch (err) {
1039
+ console.error('āŒ Error:', err);
1040
+ process.exit(1);
1041
+ }
1042
+ });
1043
+ // ============ TASK DEPENDENCIES ============
1044
+ program
1045
+ .command('task-deps <taskId>')
1046
+ .description('Show task dependencies')
1047
+ .action(async (taskId) => {
1048
+ const config = loadConfig();
1049
+ if (!config) {
1050
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1051
+ process.exit(1);
1052
+ }
1053
+ try {
1054
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1055
+ const memory = new OpenClawMemory({
1056
+ supabaseUrl: config.supabaseUrl,
1057
+ supabaseKey: config.supabaseKey,
1058
+ agentId: config.agentId
1059
+ });
1060
+ const dependencies = await memory.getTaskDependencies(taskId);
1061
+ const blocked = await memory.isTaskBlocked(taskId);
1062
+ console.log(`\nšŸ“‹ Task Dependencies for ${taskId}:`);
1063
+ console.log(`Status: ${blocked ? '🚫 BLOCKED' : 'āœ… Ready'}\n`);
1064
+ if (dependencies.length === 0) {
1065
+ console.log('No dependencies');
1066
+ }
1067
+ else {
1068
+ dependencies.forEach(dep => {
1069
+ const statusIcon = dep.status === 'done' ? 'āœ…' : 'ā³';
1070
+ console.log(`${statusIcon} [${dep.status.toUpperCase()}] ${dep.title}`);
1071
+ });
1072
+ }
1073
+ }
1074
+ catch (err) {
1075
+ console.error('āŒ Error:', err);
1076
+ process.exit(1);
1077
+ }
1078
+ });
1079
+ program
1080
+ .command('task-add-dep <taskId> <dependsOnTaskId>')
1081
+ .description('Add a task dependency')
1082
+ .action(async (taskId, dependsOnTaskId) => {
1083
+ const config = loadConfig();
1084
+ if (!config) {
1085
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1086
+ process.exit(1);
1087
+ }
1088
+ try {
1089
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1090
+ const memory = new OpenClawMemory({
1091
+ supabaseUrl: config.supabaseUrl,
1092
+ supabaseKey: config.supabaseKey,
1093
+ agentId: config.agentId
1094
+ });
1095
+ await memory.addTaskDependency(taskId, dependsOnTaskId);
1096
+ console.log(`āœ… Dependency added: ${taskId} depends on ${dependsOnTaskId}`);
1097
+ }
1098
+ catch (err) {
1099
+ console.error('āŒ Error:', err);
1100
+ process.exit(1);
1101
+ }
1102
+ });
1103
+ program
1104
+ .command('task-ready')
1105
+ .description('List tasks ready to start (no blocking dependencies)')
1106
+ .option('-u, --user <userId>', 'Filter by user ID')
1107
+ .action(async (options) => {
1108
+ const config = loadConfig();
1109
+ if (!config) {
1110
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1111
+ process.exit(1);
1112
+ }
1113
+ try {
1114
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1115
+ const memory = new OpenClawMemory({
1116
+ supabaseUrl: config.supabaseUrl,
1117
+ supabaseKey: config.supabaseKey,
1118
+ agentId: config.agentId
1119
+ });
1120
+ const tasks = await memory.getReadyTasks({ userId: options.user });
1121
+ console.log(`\nāœ… Ready Tasks (${tasks.length}):\n`);
1122
+ tasks.forEach(task => {
1123
+ console.log(`[P${task.priority}] ${task.title}`);
1124
+ if (task.description) {
1125
+ console.log(` ${task.description}`);
1126
+ }
1127
+ if (task.due_at) {
1128
+ console.log(` Due: ${new Date(task.due_at).toLocaleString()}`);
1129
+ }
1130
+ console.log();
1131
+ });
1132
+ }
1133
+ catch (err) {
1134
+ console.error('āŒ Error:', err);
1135
+ process.exit(1);
1136
+ }
1137
+ });
1138
+ // ============ TASK TEMPLATES ============
1139
+ program
1140
+ .command('task-template <name>')
1141
+ .description('Create a task template')
1142
+ .option('-f, --file <path>', 'JSON file with template definition')
1143
+ .action(async (name, options) => {
1144
+ const config = loadConfig();
1145
+ if (!config) {
1146
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1147
+ process.exit(1);
1148
+ }
1149
+ if (!options.file) {
1150
+ console.error('āŒ --file required. Provide a JSON file with template definition.');
1151
+ console.log('\nExample JSON:');
1152
+ console.log(JSON.stringify({
1153
+ name: 'Example Template',
1154
+ description: 'Template description',
1155
+ tasks: [
1156
+ { title: 'Task 1', description: 'First task', priority: 5 },
1157
+ { title: 'Task 2', description: 'Depends on Task 1', priority: 3, dependencies: [0] }
1158
+ ]
1159
+ }, null, 2));
1160
+ process.exit(1);
1161
+ }
1162
+ try {
1163
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
1164
+ const templateData = JSON.parse(await fs.readFile(options.file, 'utf-8'));
1165
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1166
+ const memory = new OpenClawMemory({
1167
+ supabaseUrl: config.supabaseUrl,
1168
+ supabaseKey: config.supabaseKey,
1169
+ agentId: config.agentId
1170
+ });
1171
+ const result = await memory.createTaskTemplate(templateData);
1172
+ console.log(`āœ… Template created: ${result.id}`);
1173
+ }
1174
+ catch (err) {
1175
+ console.error('āŒ Error:', err);
1176
+ process.exit(1);
1177
+ }
1178
+ });
1179
+ program
1180
+ .command('task-templates')
1181
+ .description('List all task templates')
1182
+ .action(async () => {
1183
+ const config = loadConfig();
1184
+ if (!config) {
1185
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1186
+ process.exit(1);
1187
+ }
1188
+ try {
1189
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1190
+ const memory = new OpenClawMemory({
1191
+ supabaseUrl: config.supabaseUrl,
1192
+ supabaseKey: config.supabaseKey,
1193
+ agentId: config.agentId
1194
+ });
1195
+ const templates = await memory.getTaskTemplates();
1196
+ console.log(`\nšŸ“‹ Task Templates (${templates.length}):\n`);
1197
+ templates.forEach(t => {
1198
+ console.log(`šŸ“ ${t.name} [ID: ${t.id}]`);
1199
+ if (t.description) {
1200
+ console.log(` ${t.description}`);
1201
+ }
1202
+ console.log(` Tasks: ${t.tasks.length}`);
1203
+ console.log();
1204
+ });
1205
+ }
1206
+ catch (err) {
1207
+ console.error('āŒ Error:', err);
1208
+ process.exit(1);
1209
+ }
1210
+ });
1211
+ program
1212
+ .command('task-apply-template <templateId>')
1213
+ .description('Apply a task template (create all tasks)')
1214
+ .option('-u, --user <userId>', 'User ID for created tasks')
1215
+ .option('-s, --start <date>', 'Start date (ISO format)')
1216
+ .action(async (templateId, options) => {
1217
+ const config = loadConfig();
1218
+ if (!config) {
1219
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1220
+ process.exit(1);
1221
+ }
1222
+ try {
1223
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1224
+ const memory = new OpenClawMemory({
1225
+ supabaseUrl: config.supabaseUrl,
1226
+ supabaseKey: config.supabaseKey,
1227
+ agentId: config.agentId
1228
+ });
1229
+ const tasks = await memory.applyTaskTemplate(templateId, {
1230
+ userId: options.user,
1231
+ startDate: options.start
1232
+ });
1233
+ console.log(`āœ… Created ${tasks.length} tasks from template:`);
1234
+ tasks.forEach(t => {
1235
+ console.log(` - ${t.title} [${t.id}]`);
1236
+ });
1237
+ }
1238
+ catch (err) {
1239
+ console.error('āŒ Error:', err);
1240
+ process.exit(1);
1241
+ }
1242
+ });
1243
+ // ============ TASK REMINDERS ============
1244
+ program
1245
+ .command('task-reminders')
1246
+ .description('Show tasks needing reminders')
1247
+ .option('-u, --user <userId>', 'Filter by user ID')
1248
+ .option('-h, --hours <hours>', 'Hours ahead to check (default: 24)', '24')
1249
+ .action(async (options) => {
1250
+ const config = loadConfig();
1251
+ if (!config) {
1252
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1253
+ process.exit(1);
1254
+ }
1255
+ try {
1256
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1257
+ const memory = new OpenClawMemory({
1258
+ supabaseUrl: config.supabaseUrl,
1259
+ supabaseKey: config.supabaseKey,
1260
+ agentId: config.agentId
1261
+ });
1262
+ const tasks = await memory.getTasksNeedingReminders({
1263
+ userId: options.user,
1264
+ hoursAhead: parseInt(options.hours)
1265
+ });
1266
+ console.log(`\nā° Tasks Needing Reminders (${tasks.length}):\n`);
1267
+ tasks.forEach(task => {
1268
+ console.log(memory.formatTaskReminder(task, task.timeUntilDue));
1269
+ console.log();
1270
+ });
1271
+ }
1272
+ catch (err) {
1273
+ console.error('āŒ Error:', err);
1274
+ process.exit(1);
1275
+ }
1276
+ });
1277
+ // ============ LEARNING PATTERNS ============
1278
+ program
1279
+ .command('learning-patterns')
1280
+ .description('Detect patterns in learnings')
1281
+ .action(async () => {
1282
+ const config = loadConfig();
1283
+ if (!config) {
1284
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1285
+ process.exit(1);
1286
+ }
1287
+ try {
1288
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1289
+ const memory = new OpenClawMemory({
1290
+ supabaseUrl: config.supabaseUrl,
1291
+ supabaseKey: config.supabaseKey,
1292
+ agentId: config.agentId
1293
+ });
1294
+ const patterns = await memory.detectLearningPatterns();
1295
+ console.log('\nšŸ“Š Learning Patterns:\n');
1296
+ console.log('Common Categories:');
1297
+ patterns.commonCategories.forEach(c => {
1298
+ console.log(` - ${c.category}: ${c.count}`);
1299
+ });
1300
+ console.log('\nCommon Triggers:');
1301
+ patterns.commonTriggers.slice(0, 5).forEach(t => {
1302
+ console.log(` - "${t.pattern}": ${t.count} occurrences`);
1303
+ });
1304
+ console.log('\nRecent Trends:');
1305
+ patterns.recentTrends.forEach(t => {
1306
+ const icon = t.severity === 'critical' ? 'šŸ”“' : t.severity === 'warning' ? '🟔' : '🟢';
1307
+ console.log(` ${icon} Week ${t.week}: ${t.count} learnings`);
1308
+ });
1309
+ console.log('\nTop Applied Lessons:');
1310
+ patterns.topLessons.forEach(l => {
1311
+ console.log(` - "${l.lesson.substring(0, 60)}..." (${l.applied} times)`);
1312
+ });
1313
+ }
1314
+ catch (err) {
1315
+ console.error('āŒ Error:', err);
1316
+ process.exit(1);
1317
+ }
1318
+ });
1319
+ program
1320
+ .command('learning-recommend <context>')
1321
+ .description('Get learning recommendations for current context')
1322
+ .option('-l, --limit <number>', 'Max recommendations', '5')
1323
+ .action(async (context, options) => {
1324
+ const config = loadConfig();
1325
+ if (!config) {
1326
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1327
+ process.exit(1);
1328
+ }
1329
+ try {
1330
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1331
+ const memory = new OpenClawMemory({
1332
+ supabaseUrl: config.supabaseUrl,
1333
+ supabaseKey: config.supabaseKey,
1334
+ agentId: config.agentId
1335
+ });
1336
+ const recommendations = await memory.getLearningRecommendations(context, parseInt(options.limit));
1337
+ console.log(`\nšŸ’” Learning Recommendations for "${context}":\n`);
1338
+ recommendations.forEach(l => {
1339
+ console.log(`[${l.severity.toUpperCase()}] ${l.category}`);
1340
+ console.log(`Trigger: ${l.trigger}`);
1341
+ console.log(`Lesson: ${l.lesson}`);
1342
+ if (l.action) {
1343
+ console.log(`Action: ${l.action}`);
1344
+ }
1345
+ console.log(`Applied: ${l.applied_count} times\n`);
1346
+ });
1347
+ }
1348
+ catch (err) {
1349
+ console.error('āŒ Error:', err);
1350
+ process.exit(1);
1351
+ }
1352
+ });
1353
+ // ============ LEARNING SIMILARITY ============
1354
+ program
1355
+ .command('learning-similar <learningId>')
1356
+ .description('Find similar learnings using embeddings')
1357
+ .option('-k, --openai-key <key>', 'OpenAI API key (or set OPENAI_API_KEY env var)')
1358
+ .option('-l, --limit <number>', 'Max results', '5')
1359
+ .option('-t, --threshold <number>', 'Similarity threshold (0-1)', '0.7')
1360
+ .action(async (learningId, options) => {
1361
+ const config = loadConfig();
1362
+ if (!config) {
1363
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1364
+ process.exit(1);
1365
+ }
1366
+ const apiKey = options.openaiKey || process.env.OPENAI_API_KEY;
1367
+ if (!apiKey) {
1368
+ console.error('āŒ OpenAI API key required. Provide via --openai-key or OPENAI_API_KEY env var.');
1369
+ process.exit(1);
1370
+ }
1371
+ try {
1372
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1373
+ const memory = new OpenClawMemory({
1374
+ supabaseUrl: config.supabaseUrl,
1375
+ supabaseKey: config.supabaseKey,
1376
+ agentId: config.agentId,
1377
+ openaiApiKey: apiKey
1378
+ });
1379
+ const similar = await memory.findSimilarLearnings(learningId, {
1380
+ limit: parseInt(options.limit),
1381
+ threshold: parseFloat(options.threshold)
1382
+ });
1383
+ console.log(`\nšŸ” Similar Learnings to ${learningId}:\n`);
1384
+ similar.forEach(l => {
1385
+ console.log(`[Similarity: ${(l.similarity * 100).toFixed(1)}%] ${l.category}`);
1386
+ console.log(`Trigger: ${l.trigger}`);
1387
+ console.log(`Lesson: ${l.lesson}`);
1388
+ console.log(`ID: ${l.id}\n`);
1389
+ });
1390
+ }
1391
+ catch (err) {
1392
+ console.error('āŒ Error:', err);
1393
+ process.exit(1);
1394
+ }
1395
+ });
1396
+ // ============ LEARNING EXPORT ============
1397
+ program
1398
+ .command('learning-export')
1399
+ .description('Export learnings to markdown report')
1400
+ .option('-c, --category <category>', 'Filter by category')
1401
+ .option('-s, --severity <severity>', 'Filter by severity')
1402
+ .option('-d, --since <date>', 'Only include learnings since date (ISO format)')
1403
+ .option('-o, --output <path>', 'Output file path', 'learnings-report.md')
1404
+ .action(async (options) => {
1405
+ const config = loadConfig();
1406
+ if (!config) {
1407
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1408
+ process.exit(1);
1409
+ }
1410
+ try {
1411
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1412
+ const memory = new OpenClawMemory({
1413
+ supabaseUrl: config.supabaseUrl,
1414
+ supabaseKey: config.supabaseKey,
1415
+ agentId: config.agentId
1416
+ });
1417
+ const report = await memory.exportLearningsReport({
1418
+ category: options.category,
1419
+ severity: options.severity,
1420
+ since: options.since
1421
+ });
1422
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
1423
+ await fs.writeFile(options.output, report, 'utf-8');
1424
+ console.log(`āœ… Learning report exported to ${options.output}`);
1425
+ }
1426
+ catch (err) {
1427
+ console.error('āŒ Error:', err);
1428
+ process.exit(1);
1429
+ }
1430
+ });
1431
+ program
1432
+ .command('learning-export-json')
1433
+ .description('Export learnings to JSON')
1434
+ .option('-c, --category <category>', 'Filter by category')
1435
+ .option('-s, --severity <severity>', 'Filter by severity')
1436
+ .option('-d, --since <date>', 'Only include learnings since date (ISO format)')
1437
+ .option('-o, --output <path>', 'Output file path', 'learnings-export.json')
1438
+ .action(async (options) => {
1439
+ const config = loadConfig();
1440
+ if (!config) {
1441
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1442
+ process.exit(1);
1443
+ }
1444
+ try {
1445
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1446
+ const memory = new OpenClawMemory({
1447
+ supabaseUrl: config.supabaseUrl,
1448
+ supabaseKey: config.supabaseKey,
1449
+ agentId: config.agentId
1450
+ });
1451
+ const data = await memory.exportLearningsJSON({
1452
+ category: options.category,
1453
+ severity: options.severity,
1454
+ since: options.since
1455
+ });
1456
+ const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
1457
+ await fs.writeFile(options.output, JSON.stringify(data, null, 2), 'utf-8');
1458
+ console.log(`āœ… Learning data exported to ${options.output}`);
1459
+ }
1460
+ catch (err) {
1461
+ console.error('āŒ Error:', err);
1462
+ process.exit(1);
1463
+ }
1464
+ });
1465
+ // ============ PHASE 9: MIGRATION & IMPORT ============
1466
+ program
1467
+ .command('import-memory-md <path>')
1468
+ .description('Import MEMORY.md into memories table')
1469
+ .action(async (memoryPath) => {
1470
+ const config = loadConfig();
1471
+ if (!config) {
1472
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1473
+ process.exit(1);
1474
+ }
1475
+ try {
1476
+ console.log(`šŸ“„ Importing MEMORY.md from: ${memoryPath}\n`);
1477
+ const { parseMemoryMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1478
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1479
+ const memories = parseMemoryMd(memoryPath);
1480
+ console.log(`Found ${memories.length} memories to import\n`);
1481
+ const memory = new OpenClawMemory({
1482
+ supabaseUrl: config.supabaseUrl,
1483
+ supabaseKey: config.supabaseKey,
1484
+ agentId: config.agentId
1485
+ });
1486
+ let imported = 0;
1487
+ for (const mem of memories) {
1488
+ try {
1489
+ await memory.remember({
1490
+ content: mem.content,
1491
+ category: mem.category,
1492
+ importance: mem.importance,
1493
+ metadata: mem.metadata
1494
+ });
1495
+ imported++;
1496
+ }
1497
+ catch (err) {
1498
+ console.error(`āš ļø Failed to import: ${mem.content.substring(0, 50)}...`, err);
1499
+ }
1500
+ }
1501
+ console.log(`\nāœ… Imported ${imported}/${memories.length} memories`);
1502
+ }
1503
+ catch (err) {
1504
+ console.error('āŒ Import error:', err);
1505
+ process.exit(1);
1506
+ }
1507
+ });
1508
+ program
1509
+ .command('import-daily-logs <directory>')
1510
+ .description('Import memory/*.md daily logs into sessions table')
1511
+ .option('-u, --user-id <id>', 'User ID for sessions', 'default')
1512
+ .action(async (directory, options) => {
1513
+ const config = loadConfig();
1514
+ if (!config) {
1515
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1516
+ process.exit(1);
1517
+ }
1518
+ try {
1519
+ console.log(`šŸ“„ Importing daily logs from: ${directory}\n`);
1520
+ const { parseAllDailyLogs } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1521
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1522
+ const sessions = parseAllDailyLogs(directory, options.userId);
1523
+ console.log(`Found ${sessions.length} sessions to import\n`);
1524
+ const memory = new OpenClawMemory({
1525
+ supabaseUrl: config.supabaseUrl,
1526
+ supabaseKey: config.supabaseKey,
1527
+ agentId: config.agentId
1528
+ });
1529
+ let imported = 0;
1530
+ for (const sess of sessions) {
1531
+ try {
1532
+ const session = await memory.startSession({
1533
+ userId: sess.user_id,
1534
+ channel: sess.channel
1535
+ });
1536
+ for (const msg of sess.messages) {
1537
+ await memory.addMessage(session.id, {
1538
+ role: msg.role,
1539
+ content: msg.content
1540
+ });
1541
+ }
1542
+ if (sess.ended_at || sess.summary) {
1543
+ await memory.endSession(session.id, { summary: sess.summary });
1544
+ }
1545
+ imported++;
1546
+ }
1547
+ catch (err) {
1548
+ console.error(`āš ļø Failed to import session:`, err);
1549
+ }
1550
+ }
1551
+ console.log(`\nāœ… Imported ${imported}/${sessions.length} sessions`);
1552
+ }
1553
+ catch (err) {
1554
+ console.error('āŒ Import error:', err);
1555
+ process.exit(1);
1556
+ }
1557
+ });
1558
+ program
1559
+ .command('import-todo-md <path>')
1560
+ .description('Import TODO.md into tasks table')
1561
+ .action(async (todoPath) => {
1562
+ const config = loadConfig();
1563
+ if (!config) {
1564
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1565
+ process.exit(1);
1566
+ }
1567
+ try {
1568
+ console.log(`šŸ“„ Importing TODO.md from: ${todoPath}\n`);
1569
+ const { parseTodoMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1570
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1571
+ const tasks = parseTodoMd(todoPath);
1572
+ console.log(`Found ${tasks.length} tasks to import\n`);
1573
+ const memory = new OpenClawMemory({
1574
+ supabaseUrl: config.supabaseUrl,
1575
+ supabaseKey: config.supabaseKey,
1576
+ agentId: config.agentId
1577
+ });
1578
+ let imported = 0;
1579
+ for (const task of tasks) {
1580
+ try {
1581
+ await memory.createTask({
1582
+ title: task.title,
1583
+ description: task.description,
1584
+ priority: task.priority,
1585
+ dueAt: task.due_date,
1586
+ metadata: { ...task.metadata, originalStatus: task.status }
1587
+ });
1588
+ imported++;
1589
+ }
1590
+ catch (err) {
1591
+ console.error(`āš ļø Failed to import task: ${task.title}`, err);
1592
+ }
1593
+ }
1594
+ console.log(`\nāœ… Imported ${imported}/${tasks.length} tasks`);
1595
+ }
1596
+ catch (err) {
1597
+ console.error('āŒ Import error:', err);
1598
+ process.exit(1);
1599
+ }
1600
+ });
1601
+ program
1602
+ .command('import-learnings-md <path>')
1603
+ .description('Import LEARNINGS.md into learnings table')
1604
+ .action(async (learningsPath) => {
1605
+ const config = loadConfig();
1606
+ if (!config) {
1607
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1608
+ process.exit(1);
1609
+ }
1610
+ try {
1611
+ console.log(`šŸ“„ Importing LEARNINGS.md from: ${learningsPath}\n`);
1612
+ const { parseLearningsMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1613
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1614
+ const learnings = parseLearningsMd(learningsPath);
1615
+ console.log(`Found ${learnings.length} learnings to import\n`);
1616
+ const memory = new OpenClawMemory({
1617
+ supabaseUrl: config.supabaseUrl,
1618
+ supabaseKey: config.supabaseKey,
1619
+ agentId: config.agentId
1620
+ });
1621
+ let imported = 0;
1622
+ for (const learning of learnings) {
1623
+ try {
1624
+ // Map parsed category to valid enum value
1625
+ const validCategories = ['error', 'correction', 'improvement', 'capability_gap'];
1626
+ const category = validCategories.includes(learning.category)
1627
+ ? learning.category
1628
+ : 'improvement';
1629
+ await memory.learn({
1630
+ category,
1631
+ trigger: learning.trigger,
1632
+ lesson: learning.lesson,
1633
+ metadata: {
1634
+ originalCategory: learning.category,
1635
+ originalImportance: learning.importance
1636
+ }
1637
+ });
1638
+ imported++;
1639
+ }
1640
+ catch (err) {
1641
+ console.error(`āš ļø Failed to import learning:`, err);
1642
+ }
1643
+ }
1644
+ console.log(`\nāœ… Imported ${imported}/${learnings.length} learnings`);
1645
+ }
1646
+ catch (err) {
1647
+ console.error('āŒ Import error:', err);
1648
+ process.exit(1);
1649
+ }
1650
+ });
1651
+ program
1652
+ .command('import-all <workspace>')
1653
+ .description('Import all Clawdbot memory files from workspace (MEMORY.md, memory/, TODO.md, LEARNINGS.md)')
1654
+ .option('-u, --user-id <id>', 'User ID for sessions', 'default')
1655
+ .action(async (workspace, options) => {
1656
+ const config = loadConfig();
1657
+ if (!config) {
1658
+ console.error('āŒ No config found. Run `openclaw-memory init` first.');
1659
+ process.exit(1);
1660
+ }
1661
+ const { join } = await Promise.resolve().then(() => __importStar(require('path')));
1662
+ const { existsSync } = await Promise.resolve().then(() => __importStar(require('fs')));
1663
+ console.log(`šŸ“¦ Importing all memory files from: ${workspace}\n`);
1664
+ const memoryMdPath = join(workspace, 'MEMORY.md');
1665
+ const dailyLogsDir = join(workspace, 'memory');
1666
+ const todoMdPath = join(workspace, 'TODO.md');
1667
+ const learningsMdPath = join(workspace, 'LEARNINGS.md');
1668
+ let totalImported = 0;
1669
+ // Import MEMORY.md
1670
+ if (existsSync(memoryMdPath)) {
1671
+ try {
1672
+ console.log('šŸ“„ Importing MEMORY.md...');
1673
+ const { parseMemoryMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1674
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1675
+ const memories = parseMemoryMd(memoryMdPath);
1676
+ const memory = new OpenClawMemory({
1677
+ supabaseUrl: config.supabaseUrl,
1678
+ supabaseKey: config.supabaseKey,
1679
+ agentId: config.agentId
1680
+ });
1681
+ for (const mem of memories) {
1682
+ try {
1683
+ await memory.remember({
1684
+ content: mem.content,
1685
+ category: mem.category,
1686
+ importance: mem.importance,
1687
+ metadata: mem.metadata
1688
+ });
1689
+ totalImported++;
1690
+ }
1691
+ catch (err) {
1692
+ // Silent skip
1693
+ }
1694
+ }
1695
+ console.log(`āœ… Imported ${memories.length} memories\n`);
1696
+ }
1697
+ catch (err) {
1698
+ console.error('āš ļø Failed to import MEMORY.md:', err);
1699
+ }
1700
+ }
1701
+ // Import daily logs
1702
+ if (existsSync(dailyLogsDir)) {
1703
+ try {
1704
+ console.log('šŸ“… Importing daily logs...');
1705
+ const { parseAllDailyLogs } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1706
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1707
+ const sessions = parseAllDailyLogs(dailyLogsDir, options.userId);
1708
+ const memory = new OpenClawMemory({
1709
+ supabaseUrl: config.supabaseUrl,
1710
+ supabaseKey: config.supabaseKey,
1711
+ agentId: config.agentId
1712
+ });
1713
+ for (const sess of sessions) {
1714
+ try {
1715
+ const session = await memory.startSession({
1716
+ userId: sess.user_id,
1717
+ channel: sess.channel
1718
+ });
1719
+ for (const msg of sess.messages) {
1720
+ await memory.addMessage(session.id, {
1721
+ role: msg.role,
1722
+ content: msg.content
1723
+ });
1724
+ }
1725
+ if (sess.ended_at || sess.summary) {
1726
+ await memory.endSession(session.id, { summary: sess.summary });
1727
+ }
1728
+ totalImported++;
1729
+ }
1730
+ catch (err) {
1731
+ // Silent skip
1732
+ }
1733
+ }
1734
+ console.log(`āœ… Imported ${sessions.length} sessions\n`);
1735
+ }
1736
+ catch (err) {
1737
+ console.error('āš ļø Failed to import daily logs:', err);
1738
+ }
1739
+ }
1740
+ // Import TODO.md
1741
+ if (existsSync(todoMdPath)) {
1742
+ try {
1743
+ console.log('āœ… Importing TODO.md...');
1744
+ const { parseTodoMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1745
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1746
+ const tasks = parseTodoMd(todoMdPath);
1747
+ const memory = new OpenClawMemory({
1748
+ supabaseUrl: config.supabaseUrl,
1749
+ supabaseKey: config.supabaseKey,
1750
+ agentId: config.agentId
1751
+ });
1752
+ for (const task of tasks) {
1753
+ try {
1754
+ await memory.createTask({
1755
+ title: task.title,
1756
+ description: task.description,
1757
+ priority: task.priority,
1758
+ dueAt: task.due_date,
1759
+ metadata: { ...task.metadata, originalStatus: task.status }
1760
+ });
1761
+ totalImported++;
1762
+ }
1763
+ catch (err) {
1764
+ // Silent skip
1765
+ }
1766
+ }
1767
+ console.log(`āœ… Imported ${tasks.length} tasks\n`);
1768
+ }
1769
+ catch (err) {
1770
+ console.error('āš ļø Failed to import TODO.md:', err);
1771
+ }
1772
+ }
1773
+ // Import LEARNINGS.md
1774
+ if (existsSync(learningsMdPath)) {
1775
+ try {
1776
+ console.log('🧠 Importing LEARNINGS.md...');
1777
+ const { parseLearningsMd } = await Promise.resolve().then(() => __importStar(require('./parsers')));
1778
+ const { OpenClawMemory } = await Promise.resolve().then(() => __importStar(require('./index')));
1779
+ const learnings = parseLearningsMd(learningsMdPath);
1780
+ const memory = new OpenClawMemory({
1781
+ supabaseUrl: config.supabaseUrl,
1782
+ supabaseKey: config.supabaseKey,
1783
+ agentId: config.agentId
1784
+ });
1785
+ for (const learning of learnings) {
1786
+ try {
1787
+ // Map parsed category to valid enum value
1788
+ const validCategories = ['error', 'correction', 'improvement', 'capability_gap'];
1789
+ const category = validCategories.includes(learning.category)
1790
+ ? learning.category
1791
+ : 'improvement';
1792
+ await memory.learn({
1793
+ category,
1794
+ trigger: learning.trigger,
1795
+ lesson: learning.lesson,
1796
+ metadata: {
1797
+ originalCategory: learning.category,
1798
+ originalImportance: learning.importance
1799
+ }
1800
+ });
1801
+ totalImported++;
1802
+ }
1803
+ catch (err) {
1804
+ // Silent skip
1805
+ }
1806
+ }
1807
+ console.log(`āœ… Imported ${learnings.length} learnings\n`);
1808
+ }
1809
+ catch (err) {
1810
+ console.error('āš ļø Failed to import LEARNINGS.md:', err);
1811
+ }
1812
+ }
1813
+ console.log(`\nšŸŽ‰ Migration complete! Total items imported: ${totalImported}`);
1814
+ });
1815
+ program.parse(process.argv);