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.
package/api/index.js ADDED
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Memory V2.0 Unified API
3
+ * Single entry point for all memory operations
4
+ */
5
+
6
+ const PriorityModule = require('../modules/priority');
7
+ const LearningModule = require('../modules/learning');
8
+ const DecisionModule = require('../modules/decision');
9
+ const EvolutionModule = require('../modules/evolution');
10
+ const VersionManager = require('../modules/version');
11
+ const MemoryDatabase = require('../database/init');
12
+
13
+ class MemoryAPI {
14
+ constructor(dbPath = './memory-v2.db') {
15
+ this.dbPath = dbPath;
16
+ this.db = new MemoryDatabase(dbPath);
17
+ this.modules = {};
18
+ }
19
+
20
+ /**
21
+ * Initialize API and all modules
22
+ */
23
+ async init() {
24
+ await this.db.init();
25
+ await this.db.runSchema();
26
+
27
+ // Initialize modules
28
+ this.modules = {
29
+ priority: new PriorityModule(this.db),
30
+ learning: new LearningModule(this.db),
31
+ decision: new DecisionModule(this.db),
32
+ evolution: new EvolutionModule(this.db),
33
+ version: new VersionManager(this.db)
34
+ };
35
+
36
+ console.log('✅ Memory V2.0 API initialized');
37
+ return this;
38
+ }
39
+
40
+ // =========================================
41
+ // PRIORITY API
42
+ // =========================================
43
+
44
+ async analyzePriority(message, context = {}) {
45
+ return await this.modules.priority.analyze(message, context);
46
+ }
47
+
48
+ async storePriority(messageId, conversationId, analysis) {
49
+ return await this.modules.priority.store(messageId, conversationId, analysis);
50
+ }
51
+
52
+ async getHighPriority(limit = 20) {
53
+ return await this.modules.priority.getHighPriority(limit);
54
+ }
55
+
56
+ // =========================================
57
+ // LEARNING API
58
+ // =========================================
59
+
60
+ async detectLearningIntent(message) {
61
+ return await this.modules.learning.detectIntent(message);
62
+ }
63
+
64
+ async startLearning(messageId, conversationId, message) {
65
+ const intent = await this.detectLearningIntent(message);
66
+ if (!intent.isLearning) {
67
+ return { success: false, error: 'No learning intent detected' };
68
+ }
69
+ return await this.modules.learning.createLearning(messageId, conversationId, intent, message);
70
+ }
71
+
72
+ async updateLearningProgress(learningId, progressData) {
73
+ return await this.modules.learning.updateProgress(learningId, progressData);
74
+ }
75
+
76
+ async addMilestone(learningId, milestone) {
77
+ return await this.modules.learning.addMilestone(learningId, milestone);
78
+ }
79
+
80
+ async getActiveLearning(limit = 20) {
81
+ return await this.modules.learning.getActiveLearning(limit);
82
+ }
83
+
84
+ async getWeeklyLearningReport() {
85
+ return await this.modules.learning.generateWeeklyReport();
86
+ }
87
+
88
+ // =========================================
89
+ // DECISION API
90
+ // =========================================
91
+
92
+ async recordDecision(messageId, conversationId, decisionData) {
93
+ return await this.modules.decision.createDecision(messageId, conversationId, decisionData);
94
+ }
95
+
96
+ async updateDecisionOutcome(decisionId, outcomeData) {
97
+ return await this.modules.decision.updateOutcome(decisionId, outcomeData);
98
+ }
99
+
100
+ async getPendingDecisions(limit = 20) {
101
+ return await this.modules.decision.getPendingDecisions(limit);
102
+ }
103
+
104
+ async getDueReviews(days = 7) {
105
+ return await this.modules.decision.getDueReviews(days);
106
+ }
107
+
108
+ async getDecisionStats() {
109
+ return await this.modules.decision.getStats();
110
+ }
111
+
112
+ async analyzeDecisionPatterns() {
113
+ return await this.modules.decision.analyzePatterns();
114
+ }
115
+
116
+ // =========================================
117
+ // EVOLUTION API
118
+ // =========================================
119
+
120
+ async recordSkillUsage(skillName, category, result = 'success', metrics = {}) {
121
+ return await this.modules.evolution.recordUsage(skillName, category, result, metrics);
122
+ }
123
+
124
+ async getSkill(skillName) {
125
+ return await this.modules.evolution.getSkill(skillName);
126
+ }
127
+
128
+ async getTopSkills(limit = 10) {
129
+ return await this.modules.evolution.getTopSkills(limit);
130
+ }
131
+
132
+ async getSkillGrowthReport(days = 30) {
133
+ return await this.modules.evolution.generateGrowthReport(days);
134
+ }
135
+
136
+ async suggestSkillsToPractice() {
137
+ return await this.modules.evolution.suggestPractice();
138
+ }
139
+
140
+ // =========================================
141
+ // VERSION API
142
+ // =========================================
143
+
144
+ async createBackup(description = '') {
145
+ return await this.modules.version.createBackup(description, 'full');
146
+ }
147
+
148
+ async listVersions() {
149
+ return await this.modules.version.listVersions();
150
+ }
151
+
152
+ async rollbackToVersion(versionId) {
153
+ return await this.modules.version.rollbackToVersion(versionId);
154
+ }
155
+
156
+ async getBackupStats() {
157
+ return await this.modules.version.getBackupStats();
158
+ }
159
+
160
+ // =========================================
161
+ // UNIFIED QUERY API
162
+ // =========================================
163
+
164
+ /**
165
+ * Search across all memory modules
166
+ */
167
+ async search(query, options = {}) {
168
+ const results = {
169
+ query,
170
+ timestamp: new Date().toISOString(),
171
+ modules: {}
172
+ };
173
+
174
+ // Search priorities
175
+ if (options.modules?.includes('priority') || !options.modules) {
176
+ results.modules.priority = await this.modules.priority.searchByPriorityRange();
177
+ }
178
+
179
+ // Search learning
180
+ if (options.modules?.includes('learning') || !options.modules) {
181
+ results.modules.learning = await this.modules.learning.getByTopic(query);
182
+ }
183
+
184
+ // Search decisions
185
+ if (options.modules?.includes('decision') || !options.modules) {
186
+ results.modules.decisions = await this.modules.decision.getSimilarDecisions(query);
187
+ }
188
+
189
+ return results;
190
+ }
191
+
192
+ /**
193
+ * Get comprehensive dashboard data
194
+ */
195
+ async getDashboard() {
196
+ return {
197
+ priority: {
198
+ high: await this.modules.priority.getHighPriority(5),
199
+ stats: await this.modules.priority.getStats()
200
+ },
201
+ learning: {
202
+ active: await this.modules.learning.getActiveLearning(5),
203
+ weekly: await this.modules.learning.generateWeeklyReport()
204
+ },
205
+ decisions: {
206
+ pending: await this.modules.decision.getPendingDecisions(5),
207
+ dueReviews: await this.modules.decision.getDueReviews(7)
208
+ },
209
+ evolution: {
210
+ top: await this.modules.evolution.getTopSkills(5),
211
+ needsPractice: await this.modules.evolution.suggestPractice()
212
+ },
213
+ version: {
214
+ stats: await this.modules.version.getBackupStats()
215
+ }
216
+ };
217
+ }
218
+
219
+ /**
220
+ * Health check
221
+ */
222
+ async health() {
223
+ return await this.db.healthCheck();
224
+ }
225
+
226
+ /**
227
+ * Close database connection
228
+ */
229
+ async close() {
230
+ await this.db.close();
231
+ }
232
+ }
233
+
234
+ // CLI usage
235
+ if (require.main === module) {
236
+ const api = new MemoryAPI();
237
+
238
+ (async () => {
239
+ try {
240
+ await api.init();
241
+
242
+ // Example usage
243
+ console.log('\n📊 Dashboard:');
244
+ const dashboard = await api.getDashboard();
245
+ console.log(JSON.stringify(dashboard, null, 2));
246
+
247
+ await api.close();
248
+ } catch (err) {
249
+ console.error('❌ Error:', err);
250
+ process.exit(1);
251
+ }
252
+ })();
253
+ }
254
+
255
+ module.exports = MemoryAPI;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Memory V2.0 Database Initialization
3
+ * Extends Lossless Claw with personal modules
4
+ */
5
+
6
+ const sqlite3 = require('sqlite3').verbose();
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ class MemoryDatabase {
11
+ constructor(dbPath = './memory-v2.db') {
12
+ this.dbPath = dbPath;
13
+ this.db = null;
14
+ }
15
+
16
+ async init() {
17
+ return new Promise((resolve, reject) => {
18
+ this.db = new sqlite3.Database(this.dbPath, (err) => {
19
+ if (err) {
20
+ console.error('Error opening database:', err);
21
+ reject(err);
22
+ } else {
23
+ console.log('✅ Connected to Memory V2.0 database');
24
+ resolve();
25
+ }
26
+ });
27
+ });
28
+ }
29
+
30
+ async runSchema() {
31
+ const schemaPath = path.join(__dirname, 'schema.sql');
32
+ const schema = fs.readFileSync(schemaPath, 'utf8');
33
+
34
+ // Split schema into individual statements
35
+ const statements = schema
36
+ .split(';')
37
+ .map(s => s.trim())
38
+ .filter(s => s.length > 0);
39
+
40
+ for (const statement of statements) {
41
+ await this.run(statement);
42
+ }
43
+
44
+ console.log('✅ Database schema initialized');
45
+ }
46
+
47
+ async run(sql, params = []) {
48
+ return new Promise((resolve, reject) => {
49
+ this.db.run(sql, params, function(err) {
50
+ if (err) {
51
+ console.error('SQL Error:', err);
52
+ reject(err);
53
+ } else {
54
+ resolve({ id: this.lastID, changes: this.changes });
55
+ }
56
+ });
57
+ });
58
+ }
59
+
60
+ async get(sql, params = []) {
61
+ return new Promise((resolve, reject) => {
62
+ this.db.get(sql, params, (err, row) => {
63
+ if (err) {
64
+ reject(err);
65
+ } else {
66
+ resolve(row);
67
+ }
68
+ });
69
+ });
70
+ }
71
+
72
+ async all(sql, params = []) {
73
+ return new Promise((resolve, reject) => {
74
+ this.db.all(sql, params, (err, rows) => {
75
+ if (err) {
76
+ reject(err);
77
+ } else {
78
+ resolve(rows);
79
+ }
80
+ });
81
+ });
82
+ }
83
+
84
+ async close() {
85
+ return new Promise((resolve, reject) => {
86
+ this.db.close((err) => {
87
+ if (err) {
88
+ reject(err);
89
+ } else {
90
+ console.log('✅ Database connection closed');
91
+ resolve();
92
+ }
93
+ });
94
+ });
95
+ }
96
+
97
+ // Health check
98
+ async healthCheck() {
99
+ try {
100
+ const tables = await this.all(
101
+ "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'memory_%'"
102
+ );
103
+ return {
104
+ status: 'healthy',
105
+ tables: tables.map(t => t.name),
106
+ timestamp: new Date().toISOString()
107
+ };
108
+ } catch (err) {
109
+ return {
110
+ status: 'unhealthy',
111
+ error: err.message,
112
+ timestamp: new Date().toISOString()
113
+ };
114
+ }
115
+ }
116
+ }
117
+
118
+ // CLI usage
119
+ if (require.main === module) {
120
+ const db = new MemoryDatabase();
121
+
122
+ (async () => {
123
+ try {
124
+ await db.init();
125
+ await db.runSchema();
126
+ const health = await db.healthCheck();
127
+ console.log('\n📊 Database Health:', health);
128
+ await db.close();
129
+ console.log('\n🎉 Memory V2.0 database initialized successfully!');
130
+ } catch (err) {
131
+ console.error('❌ Initialization failed:', err);
132
+ process.exit(1);
133
+ }
134
+ })();
135
+ }
136
+
137
+ module.exports = MemoryDatabase;
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Decision Module
3
+ * Track decisions, outcomes, and reviews
4
+ */
5
+
6
+ class DecisionModule {
7
+ constructor(db) {
8
+ this.db = db;
9
+ this.decisionTypes = ['framework', 'vendor', 'migration', 'publish', 'spend', 'other'];
10
+
11
+ // Keywords for automatic decision type detection
12
+ this.typeKeywords = {
13
+ framework: ['framework', 'library', 'architecture', 'stack', 'technology'],
14
+ vendor: ['vendor', 'provider', 'service', 'platform', 'tool'],
15
+ migration: ['migrate', 'upgrade', 'update', 'move', 'transfer', 'switch'],
16
+ publish: ['publish', 'release', 'deploy', 'launch', 'ship'],
17
+ spend: ['budget', 'cost', 'price', 'purchase', 'buy', 'invest', 'spend'],
18
+ other: ['decide', 'choice', 'option', 'select', 'pick']
19
+ };
20
+ }
21
+
22
+ /**
23
+ * Detect decision type from message
24
+ */
25
+ detectType(message) {
26
+ const content = message.toLowerCase();
27
+ const scores = {};
28
+
29
+ for (const [type, keywords] of Object.entries(this.typeKeywords)) {
30
+ scores[type] = 0;
31
+ for (const keyword of keywords) {
32
+ if (content.includes(keyword)) {
33
+ scores[type] += 1;
34
+ }
35
+ }
36
+ }
37
+
38
+ // Find highest score
39
+ let detectedType = 'other';
40
+ let maxScore = 0;
41
+
42
+ for (const [type, score] of Object.entries(scores)) {
43
+ if (score > maxScore) {
44
+ maxScore = score;
45
+ detectedType = type;
46
+ }
47
+ }
48
+
49
+ return {
50
+ type: detectedType,
51
+ confidence: maxScore > 0 ? Math.min(maxScore / 3, 1) : 0,
52
+ scores
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Extract decision question
58
+ */
59
+ extractQuestion(message) {
60
+ // Look for question patterns
61
+ const patterns = [
62
+ /(?:should|need to|want to|decide|choose)\s+(.+?)(?:\?|\.|$)/i,
63
+ /which\s+(.+?)(?:\?|\.|$)/i,
64
+ /what\s+(.+?)(?:\?|\.|$)/i,
65
+ /how\s+(.+?)(?:\?|\.|$)/i
66
+ ];
67
+
68
+ for (const pattern of patterns) {
69
+ const match = message.match(pattern);
70
+ if (match) {
71
+ return match[1].trim();
72
+ }
73
+ }
74
+
75
+ // Fallback: first sentence
76
+ const sentences = message.split(/[.!?]+/);
77
+ return sentences[0]?.trim() || message.substring(0, 100);
78
+ }
79
+
80
+ /**
81
+ * Create new decision record
82
+ */
83
+ async createDecision(messageId, conversationId, decisionData) {
84
+ const sql = `
85
+ INSERT INTO memory_decisions
86
+ (message_id, conversation_id, decision_type, decision_question,
87
+ decision_context, options_considered, chosen_option, rationale,
88
+ confidence_level, expected_outcome, review_date)
89
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
90
+ `;
91
+
92
+ // Auto-detect type if not provided
93
+ const typeDetection = decisionData.type
94
+ ? { type: decisionData.type, confidence: 1 }
95
+ : this.detectType(decisionData.question || decisionData.context);
96
+
97
+ // Calculate review date (default: 30 days)
98
+ const reviewDate = new Date();
99
+ reviewDate.setDate(reviewDate.getDate() + (decisionData.reviewDays || 30));
100
+
101
+ const result = await this.db.run(sql, [
102
+ messageId,
103
+ conversationId,
104
+ typeDetection.type,
105
+ decisionData.question || this.extractQuestion(decisionData.context),
106
+ decisionData.context,
107
+ JSON.stringify(decisionData.options || []),
108
+ decisionData.chosenOption,
109
+ decisionData.rationale,
110
+ decisionData.confidence || 3,
111
+ decisionData.expectedOutcome,
112
+ reviewDate.toISOString()
113
+ ]);
114
+
115
+ return {
116
+ success: true,
117
+ decisionId: result.id,
118
+ type: typeDetection.type,
119
+ reviewDate: reviewDate.toISOString()
120
+ };
121
+ }
122
+
123
+ /**
124
+ * Update decision outcome
125
+ */
126
+ async updateOutcome(decisionId, outcomeData) {
127
+ const sql = `
128
+ UPDATE memory_decisions
129
+ SET outcome_status = ?, actual_outcome = ?, updated_at = CURRENT_TIMESTAMP
130
+ WHERE id = ?
131
+ `;
132
+
133
+ await this.db.run(sql, [
134
+ outcomeData.status,
135
+ outcomeData.description,
136
+ decisionId
137
+ ]);
138
+
139
+ return { success: true, decisionId };
140
+ }
141
+
142
+ /**
143
+ * Schedule review
144
+ */
145
+ async scheduleReview(decisionId, reviewDate) {
146
+ const sql = `
147
+ UPDATE memory_decisions
148
+ SET review_date = ?, updated_at = CURRENT_TIMESTAMP
149
+ WHERE id = ?
150
+ `;
151
+
152
+ await this.db.run(sql, [reviewDate, decisionId]);
153
+ return { success: true };
154
+ }
155
+
156
+ /**
157
+ * Complete review
158
+ */
159
+ async completeReview(decisionId, reviewData) {
160
+ const sql = `
161
+ UPDATE memory_decisions
162
+ SET reviewed_at = CURRENT_TIMESTAMP, review_notes = ?, updated_at = CURRENT_TIMESTAMP
163
+ WHERE id = ?
164
+ `;
165
+
166
+ await this.db.run(sql, [reviewData.notes, decisionId]);
167
+ return { success: true };
168
+ }
169
+
170
+ /**
171
+ * Get pending decisions
172
+ */
173
+ async getPendingDecisions(limit = 20) {
174
+ const sql = `SELECT * FROM v_pending_decisions LIMIT ?`;
175
+ return await this.db.all(sql, [limit]);
176
+ }
177
+
178
+ /**
179
+ * Get decisions by type
180
+ */
181
+ async getByType(type, limit = 20) {
182
+ const sql = `
183
+ SELECT * FROM memory_decisions
184
+ WHERE decision_type = ?
185
+ ORDER BY created_at DESC
186
+ LIMIT ?
187
+ `;
188
+ return await this.db.all(sql, [type, limit]);
189
+ }
190
+
191
+ /**
192
+ * Get decisions needing review
193
+ */
194
+ async getDueReviews(days = 7) {
195
+ const sql = `
196
+ SELECT * FROM memory_decisions
197
+ WHERE outcome_status = 'pending'
198
+ AND review_date <= datetime('now', '+${days} days')
199
+ AND reviewed_at IS NULL
200
+ ORDER BY review_date ASC
201
+ `;
202
+ return await this.db.all(sql);
203
+ }
204
+
205
+ /**
206
+ * Get decision statistics
207
+ */
208
+ async getStats() {
209
+ const sql = `
210
+ SELECT
211
+ decision_type,
212
+ outcome_status,
213
+ COUNT(*) as count
214
+ FROM memory_decisions
215
+ GROUP BY decision_type, outcome_status
216
+ `;
217
+ return await this.db.all(sql);
218
+ }
219
+
220
+ /**
221
+ * Analyze decision patterns
222
+ */
223
+ async analyzePatterns() {
224
+ const sql = `
225
+ SELECT
226
+ decision_type,
227
+ AVG(confidence_level) as avg_confidence,
228
+ COUNT(CASE WHEN outcome_status = 'successful' THEN 1 END) as success_count,
229
+ COUNT(CASE WHEN outcome_status = 'failed' THEN 1 END) as failure_count,
230
+ COUNT(*) as total
231
+ FROM memory_decisions
232
+ WHERE outcome_status != 'pending'
233
+ GROUP BY decision_type
234
+ `;
235
+
236
+ const patterns = await this.db.all(sql);
237
+
238
+ return patterns.map(p => ({
239
+ ...p,
240
+ success_rate: p.total > 0 ? (p.success_count / p.total * 100).toFixed(2) : 0
241
+ }));
242
+ }
243
+
244
+ /**
245
+ * Get similar past decisions
246
+ */
247
+ async getSimilarDecisions(question, limit = 5) {
248
+ const keywords = question.toLowerCase().split(/\s+/).filter(w => w.length > 3);
249
+
250
+ if (keywords.length === 0) return [];
251
+
252
+ const conditions = keywords.map(() => 'decision_question LIKE ?').join(' OR ');
253
+ const sql = `
254
+ SELECT * FROM memory_decisions
255
+ WHERE ${conditions}
256
+ ORDER BY created_at DESC
257
+ LIMIT ?
258
+ `;
259
+
260
+ const params = keywords.map(k => `%${k}%`);
261
+ params.push(limit);
262
+
263
+ return await this.db.all(sql, params);
264
+ }
265
+ }
266
+
267
+ module.exports = DecisionModule;