memory-lucia 2.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.
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Priority Module
3
+ * Automatic message priority classification and scoring
4
+ */
5
+
6
+ class PriorityModule {
7
+ constructor(db) {
8
+ this.db = db;
9
+ this.keywords = {
10
+ critical: ['urgent', 'emergency', 'critical', 'asap', 'immediately', 'deadline', 'blocked'],
11
+ high: ['important', 'priority', 'required', 'needed', 'should', 'recommend'],
12
+ medium: ['consider', 'maybe', 'optional', 'suggestion', 'idea'],
13
+ low: ['nice to have', 'someday', 'eventually', 'wish', 'dream']
14
+ };
15
+ }
16
+
17
+ /**
18
+ * Analyze message and determine priority
19
+ * @param {string} message - Message content
20
+ * @param {object} context - Additional context
21
+ * @returns {object} Priority analysis result
22
+ */
23
+ async analyze(message, context = {}) {
24
+ const content = message.toLowerCase();
25
+ let priorityLevel = 4; // Default: Low
26
+ let importanceScore = 0;
27
+ const detectedKeywords = [];
28
+
29
+ // Check for critical keywords
30
+ for (const keyword of this.keywords.critical) {
31
+ if (content.includes(keyword)) {
32
+ priorityLevel = Math.min(priorityLevel, 1);
33
+ importanceScore += 25;
34
+ detectedKeywords.push({ word: keyword, level: 'critical' });
35
+ }
36
+ }
37
+
38
+ // Check for high priority keywords
39
+ for (const keyword of this.keywords.high) {
40
+ if (content.includes(keyword)) {
41
+ priorityLevel = Math.min(priorityLevel, 2);
42
+ importanceScore += 15;
43
+ detectedKeywords.push({ word: keyword, level: 'high' });
44
+ }
45
+ }
46
+
47
+ // Check for medium priority keywords
48
+ for (const keyword of this.keywords.medium) {
49
+ if (content.includes(keyword)) {
50
+ priorityLevel = Math.min(priorityLevel, 3);
51
+ importanceScore += 10;
52
+ detectedKeywords.push({ word: keyword, level: 'medium' });
53
+ }
54
+ }
55
+
56
+ // Context-based scoring
57
+ if (context.isMentioned) importanceScore += 10;
58
+ if (context.isReply) importanceScore += 5;
59
+ if (context.isDirectMessage) importanceScore += 10;
60
+
61
+ // Cap score at 100
62
+ importanceScore = Math.min(importanceScore, 100);
63
+
64
+ return {
65
+ priorityLevel,
66
+ importanceScore,
67
+ keywords: detectedKeywords,
68
+ contextSummary: this.generateSummary(message, detectedKeywords)
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Store priority record
74
+ */
75
+ async store(messageId, conversationId, analysis) {
76
+ const sql = `
77
+ INSERT INTO memory_priorities
78
+ (message_id, conversation_id, priority_level, importance_score, keywords, context_summary)
79
+ VALUES (?, ?, ?, ?, ?, ?)
80
+ `;
81
+
82
+ await this.db.run(sql, [
83
+ messageId,
84
+ conversationId,
85
+ analysis.priorityLevel,
86
+ analysis.importanceScore,
87
+ JSON.stringify(analysis.keywords),
88
+ analysis.contextSummary
89
+ ]);
90
+
91
+ return { success: true, messageId, priority: analysis.priorityLevel };
92
+ }
93
+
94
+ /**
95
+ * Get messages by priority level
96
+ */
97
+ async getByPriority(level, limit = 50) {
98
+ const sql = `
99
+ SELECT * FROM memory_priorities
100
+ WHERE priority_level = ?
101
+ ORDER BY importance_score DESC, created_at DESC
102
+ LIMIT ?
103
+ `;
104
+ return await this.db.all(sql, [level, limit]);
105
+ }
106
+
107
+ /**
108
+ * Get high priority messages
109
+ */
110
+ async getHighPriority(limit = 20) {
111
+ const sql = `
112
+ SELECT * FROM v_high_priority_messages
113
+ LIMIT ?
114
+ `;
115
+ return await this.db.all(sql, [limit]);
116
+ }
117
+
118
+ /**
119
+ * Search by priority range
120
+ */
121
+ async searchByPriorityRange(minLevel = 1, maxLevel = 4) {
122
+ const sql = `
123
+ SELECT * FROM memory_priorities
124
+ WHERE priority_level BETWEEN ? AND ?
125
+ ORDER BY priority_level ASC, importance_score DESC
126
+ `;
127
+ return await this.db.all(sql, [minLevel, maxLevel]);
128
+ }
129
+
130
+ /**
131
+ * Auto-cleanup low priority old records
132
+ */
133
+ async cleanupOldLowPriority(days = 30) {
134
+ const sql = `
135
+ DELETE FROM memory_priorities
136
+ WHERE priority_level = 4
137
+ AND created_at < datetime('now', '-${days} days')
138
+ `;
139
+ const result = await this.db.run(sql);
140
+ return { deleted: result.changes };
141
+ }
142
+
143
+ /**
144
+ * Generate context summary
145
+ */
146
+ generateSummary(message, keywords) {
147
+ const sentences = message.split(/[.!?]+/).filter(s => s.trim().length > 0);
148
+ const firstSentence = sentences[0]?.trim() || message.substring(0, 100);
149
+
150
+ return {
151
+ firstSentence,
152
+ keywordCount: keywords.length,
153
+ detectedWords: keywords.map(k => k.word)
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Get priority statistics
159
+ */
160
+ async getStats() {
161
+ const sql = `
162
+ SELECT
163
+ priority_level,
164
+ COUNT(*) as count,
165
+ AVG(importance_score) as avg_score
166
+ FROM memory_priorities
167
+ GROUP BY priority_level
168
+ ORDER BY priority_level
169
+ `;
170
+ return await this.db.all(sql);
171
+ }
172
+ }
173
+
174
+ module.exports = PriorityModule;
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Version Manager Module
3
+ * Handle database backups, migrations, and rollbacks
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const crypto = require('crypto');
9
+
10
+ class VersionManager {
11
+ constructor(db, backupDir = './backups') {
12
+ this.db = db;
13
+ this.backupDir = backupDir;
14
+
15
+ // Ensure backup directory exists
16
+ if (!fs.existsSync(backupDir)) {
17
+ fs.mkdirSync(backupDir, { recursive: true });
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Create database backup
23
+ */
24
+ async createBackup(description = '', type = 'full') {
25
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
26
+ const backupName = `memory-v2-${type}-${timestamp}`;
27
+ const backupPath = path.join(this.backupDir, `${backupName}.db`);
28
+
29
+ // Copy database file
30
+ const dbPath = this.db.dbPath;
31
+ await this.copyFile(dbPath, backupPath);
32
+
33
+ // Calculate checksum
34
+ const checksum = await this.calculateChecksum(backupPath);
35
+ const stats = fs.statSync(backupPath);
36
+
37
+ // Record version
38
+ const result = await this.db.run(
39
+ `INSERT INTO memory_versions
40
+ (version_name, version_type, description, backup_path, backup_size, checksum)
41
+ VALUES (?, ?, ?, ?, ?, ?)`,
42
+ [backupName, type, description, backupPath, stats.size, checksum]
43
+ );
44
+
45
+ // Record table statistics
46
+ await this.recordTableStats(result.id);
47
+
48
+ return {
49
+ success: true,
50
+ versionId: result.id,
51
+ backupPath,
52
+ size: stats.size,
53
+ checksum
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Copy file (promise wrapper)
59
+ */
60
+ copyFile(src, dest) {
61
+ return new Promise((resolve, reject) => {
62
+ fs.copyFile(src, dest, (err) => {
63
+ if (err) reject(err);
64
+ else resolve();
65
+ });
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Calculate file checksum
71
+ */
72
+ calculateChecksum(filePath) {
73
+ return new Promise((resolve, reject) => {
74
+ const hash = crypto.createHash('sha256');
75
+ const stream = fs.createReadStream(filePath);
76
+
77
+ stream.on('data', data => hash.update(data));
78
+ stream.on('end', () => resolve(hash.digest('hex')));
79
+ stream.on('error', reject);
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Record table statistics
85
+ */
86
+ async recordTableStats(versionId) {
87
+ const tables = [
88
+ 'memory_priorities',
89
+ 'memory_learning',
90
+ 'memory_learning_milestones',
91
+ 'memory_decisions',
92
+ 'memory_evolution',
93
+ 'memory_evolution_history',
94
+ 'memory_versions',
95
+ 'memory_version_stats'
96
+ ];
97
+
98
+ for (const table of tables) {
99
+ try {
100
+ const count = await this.db.get(
101
+ `SELECT COUNT(*) as count FROM ${table}`
102
+ );
103
+
104
+ await this.db.run(
105
+ `INSERT INTO memory_version_stats (version_id, table_name, record_count)
106
+ VALUES (?, ?, ?)`,
107
+ [versionId, table, count.count]
108
+ );
109
+ } catch (err) {
110
+ console.warn(`Table ${table} not found or error:`, err.message);
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * List all versions
117
+ */
118
+ async listVersions() {
119
+ const sql = `
120
+ SELECT v.*,
121
+ GROUP_CONCAT(s.table_name || ': ' || s.record_count, ', ') as table_stats
122
+ FROM memory_versions v
123
+ LEFT JOIN memory_version_stats s ON v.id = s.version_id
124
+ GROUP BY v.id
125
+ ORDER BY v.created_at DESC
126
+ `;
127
+ return await this.db.all(sql);
128
+ }
129
+
130
+ /**
131
+ * Get active version
132
+ */
133
+ async getActiveVersion() {
134
+ return await this.db.get(
135
+ `SELECT * FROM memory_versions WHERE is_active = 1`
136
+ );
137
+ }
138
+
139
+ /**
140
+ * Activate version
141
+ */
142
+ async activateVersion(versionId) {
143
+ // Deactivate current active version
144
+ await this.db.run(
145
+ `UPDATE memory_versions SET is_active = 0 WHERE is_active = 1`
146
+ );
147
+
148
+ // Activate new version
149
+ await this.db.run(
150
+ `UPDATE memory_versions
151
+ SET is_active = 1, activated_at = CURRENT_TIMESTAMP
152
+ WHERE id = ?`,
153
+ [versionId]
154
+ );
155
+
156
+ return { success: true, versionId };
157
+ }
158
+
159
+ /**
160
+ * Rollback to version
161
+ */
162
+ async rollbackToVersion(versionId) {
163
+ const version = await this.db.get(
164
+ `SELECT * FROM memory_versions WHERE id = ?`,
165
+ [versionId]
166
+ );
167
+
168
+ if (!version) {
169
+ return { success: false, error: 'Version not found' };
170
+ }
171
+
172
+ if (!fs.existsSync(version.backup_path)) {
173
+ return { success: false, error: 'Backup file not found' };
174
+ }
175
+
176
+ // Create backup before rollback
177
+ await this.createBackup(`Pre-rollback to v${versionId}`, 'pre-rollback');
178
+
179
+ // Copy backup to active database
180
+ await this.copyFile(version.backup_path, this.db.dbPath);
181
+
182
+ // Activate version
183
+ await this.activateVersion(versionId);
184
+
185
+ return {
186
+ success: true,
187
+ rolledBackTo: version.version_name,
188
+ timestamp: version.created_at
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Delete old backups
194
+ */
195
+ async cleanupOldBackups(days = 30, keepLastN = 5) {
196
+ // Get backups to delete
197
+ const oldBackups = await this.db.all(
198
+ `SELECT * FROM memory_versions
199
+ WHERE version_type = 'full'
200
+ AND created_at < datetime('now', '-${days} days')
201
+ ORDER BY created_at DESC`
202
+ );
203
+
204
+ // Keep last N backups
205
+ const toDelete = oldBackups.slice(keepLastN);
206
+ let deletedCount = 0;
207
+
208
+ for (const backup of toDelete) {
209
+ try {
210
+ if (fs.existsSync(backup.backup_path)) {
211
+ fs.unlinkSync(backup.backup_path);
212
+ }
213
+ await this.db.run(
214
+ `DELETE FROM memory_version_stats WHERE version_id = ?`,
215
+ [backup.id]
216
+ );
217
+ await this.db.run(
218
+ `DELETE FROM memory_versions WHERE id = ?`,
219
+ [backup.id]
220
+ );
221
+ deletedCount++;
222
+ } catch (err) {
223
+ console.error(`Failed to delete backup ${backup.version_name}:`, err);
224
+ }
225
+ }
226
+
227
+ return { deleted: deletedCount };
228
+ }
229
+
230
+ /**
231
+ * Get backup statistics
232
+ */
233
+ async getBackupStats() {
234
+ const stats = await this.db.get(
235
+ `SELECT
236
+ COUNT(*) as total_backups,
237
+ SUM(backup_size) as total_size,
238
+ AVG(backup_size) as avg_size,
239
+ MAX(created_at) as last_backup,
240
+ MIN(created_at) as first_backup
241
+ FROM memory_versions
242
+ WHERE version_type = 'full'`
243
+ );
244
+
245
+ return {
246
+ totalBackups: stats.total_backups || 0,
247
+ totalSize: stats.total_size || 0,
248
+ avgSize: stats.avg_size || 0,
249
+ lastBackup: stats.last_backup,
250
+ firstBackup: stats.first_backup
251
+ };
252
+ }
253
+
254
+ /**
255
+ * Verify backup integrity
256
+ */
257
+ async verifyBackup(versionId) {
258
+ const version = await this.db.get(
259
+ `SELECT * FROM memory_versions WHERE id = ?`,
260
+ [versionId]
261
+ );
262
+
263
+ if (!version) {
264
+ return { valid: false, error: 'Version not found' };
265
+ }
266
+
267
+ if (!fs.existsSync(version.backup_path)) {
268
+ return { valid: false, error: 'Backup file missing' };
269
+ }
270
+
271
+ const currentChecksum = await this.calculateChecksum(version.backup_path);
272
+
273
+ if (currentChecksum !== version.checksum) {
274
+ return {
275
+ valid: false,
276
+ error: 'Checksum mismatch',
277
+ expected: version.checksum,
278
+ actual: currentChecksum
279
+ };
280
+ }
281
+
282
+ return { valid: true, checksum: currentChecksum };
283
+ }
284
+ }
285
+
286
+ module.exports = VersionManager;
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "memory-lucia",
3
+ "version": "2.0.0",
4
+ "description": "Advanced memory system for OpenClaw agents with priority analysis, learning tracking, decision recording, and skill evolution",
5
+ "main": "api/index.js",
6
+ "scripts": {
7
+ "start": "node api/index.js",
8
+ "init": "node scripts/init-memory.js",
9
+ "test": "node tests/test.js",
10
+ "backup": "node scripts/backup.js"
11
+ },
12
+ "keywords": [
13
+ "openclaw",
14
+ "skill",
15
+ "memory",
16
+ "learning",
17
+ "decision",
18
+ "priority",
19
+ "evolution",
20
+ "sqlite"
21
+ ],
22
+ "author": "Chief of Staff",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "sqlite3": "^5.1.6"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/YOUR_USERNAME/memory-lucia.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/YOUR_USERNAME/memory-lucia/issues"
33
+ },
34
+ "homepage": "https://github.com/YOUR_USERNAME/memory-lucia#readme"
35
+ }
@@ -0,0 +1,13 @@
1
+ @echo off
2
+ echo 🚀 Publishing memory-lucia to npm...
3
+ echo.
4
+ echo This package requires 2FA authentication.
5
+ echo.
6
+ echo Please enter your 6-digit 2FA code from your Authenticator app:
7
+ set /p OTP="2FA Code: "
8
+ echo.
9
+ echo Publishing with OTP: %OTP%
10
+ npm publish --access=public --otp=%OTP%
11
+ echo.
12
+ echo ✅ Done!
13
+ pause
package/publish.bat ADDED
@@ -0,0 +1,17 @@
1
+ @echo off
2
+ echo 🚀 Publishing memory-lucia to npm...
3
+ echo.
4
+
5
+ echo Logging in to npm...
6
+ npm login --auth-type=legacy
7
+
8
+ echo.
9
+ echo Publishing package...
10
+ npm publish --access=public
11
+
12
+ echo.
13
+ echo ✅ Published!
14
+ echo.
15
+ echo Users can now install with:
16
+ echo npm install memory-lucia
17
+ pause
package/publish.sh ADDED
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+ # Memory Lucia Publish Script
3
+
4
+ echo "🚀 Publishing memory-lucia to npm..."
5
+ echo ""
6
+
7
+ # Login
8
+ echo "Logging in to npm..."
9
+ npm login --auth-type=legacy
10
+
11
+ # Publish
12
+ echo ""
13
+ echo "Publishing package..."
14
+ npm publish --access=public
15
+
16
+ echo ""
17
+ echo "✅ Published!"
18
+ echo ""
19
+ echo "Users can now install with:"
20
+ echo " npm install memory-lucia"
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Initialize Memory V2 Database
3
+ * Usage: node scripts/init-memory.js [database-path]
4
+ */
5
+
6
+ const MemoryAPI = require('../api');
7
+ const path = require('path');
8
+
9
+ const dbPath = process.argv[2] || './memory-v2.db';
10
+
11
+ console.log('🚀 Initializing Memory V2 Database...\n');
12
+
13
+ (async () => {
14
+ try {
15
+ const api = new MemoryAPI(dbPath);
16
+ await api.init();
17
+
18
+ console.log('✅ Database initialized successfully!');
19
+ console.log(`📁 Location: ${path.resolve(dbPath)}`);
20
+ console.log('\nNext steps:');
21
+ console.log(' 1. Use the API to track learning, decisions, etc.');
22
+ console.log(' 2. Run tests: npm test');
23
+ console.log(' 3. Create backups: npm run backup');
24
+
25
+ await api.close();
26
+ } catch (err) {
27
+ console.error('❌ Initialization failed:', err.message);
28
+ process.exit(1);
29
+ }
30
+ })();