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,286 @@
1
+ /**
2
+ * Evolution Module
3
+ * Track skill proficiency and growth
4
+ */
5
+
6
+ class EvolutionModule {
7
+ constructor(db) {
8
+ this.db = db;
9
+ this.levelNames = {
10
+ 1: 'Novice',
11
+ 2: 'Beginner',
12
+ 3: 'Intermediate',
13
+ 4: 'Advanced',
14
+ 5: 'Expert',
15
+ 6: 'Master'
16
+ };
17
+
18
+ this.levelThresholds = {
19
+ 1: 0,
20
+ 2: 100,
21
+ 3: 300,
22
+ 4: 600,
23
+ 5: 1000,
24
+ 6: 1500
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Record skill usage
30
+ */
31
+ async recordUsage(skillName, skillCategory, result = 'success', metrics = {}) {
32
+ // Check if skill exists
33
+ let skill = await this.db.get(
34
+ 'SELECT * FROM memory_evolution WHERE skill_name = ?',
35
+ [skillName]
36
+ );
37
+
38
+ if (!skill) {
39
+ // Create new skill record
40
+ const result = await this.db.run(
41
+ `INSERT INTO memory_evolution (skill_name, skill_category, first_used_at)
42
+ VALUES (?, ?, CURRENT_TIMESTAMP)`,
43
+ [skillName, skillCategory]
44
+ );
45
+ skill = { id: result.id, proficiency_level: 1, experience_points: 0 };
46
+ }
47
+
48
+ // Calculate XP gain
49
+ const xpGain = this.calculateXP(result, metrics);
50
+ const newXP = skill.experience_points + xpGain;
51
+ const newLevel = this.calculateLevel(newXP);
52
+ const oldLevel = skill.proficiency_level;
53
+
54
+ // Update skill record
55
+ await this.db.run(
56
+ `UPDATE memory_evolution
57
+ SET usage_count = usage_count + 1,
58
+ ${result === 'success' ? 'success_count = success_count + 1' : 'failure_count = failure_count + 1'},
59
+ experience_points = ?,
60
+ proficiency_level = ?,
61
+ last_used_at = CURRENT_TIMESTAMP,
62
+ performance_metrics = ?
63
+ WHERE id = ?`,
64
+ [newXP, newLevel, JSON.stringify(metrics), skill.id]
65
+ );
66
+
67
+ // Record level up if applicable
68
+ if (newLevel > oldLevel) {
69
+ await this.db.run(
70
+ `INSERT INTO memory_evolution_history (skill_id, old_level, new_level, reason)
71
+ VALUES (?, ?, ?, ?)`,
72
+ [skill.id, oldLevel, newLevel, `XP reached ${newXP}`]
73
+ );
74
+ }
75
+
76
+ return {
77
+ success: true,
78
+ skillId: skill.id,
79
+ xpGained: xpGain,
80
+ totalXP: newXP,
81
+ level: newLevel,
82
+ leveledUp: newLevel > oldLevel
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Calculate XP gain
88
+ */
89
+ calculateXP(result, metrics) {
90
+ let baseXP = 10;
91
+
92
+ if (result === 'success') {
93
+ baseXP += 5;
94
+ } else if (result === 'failure') {
95
+ baseXP += 2; // Learning from failure
96
+ }
97
+
98
+ // Bonus for complexity
99
+ if (metrics.complexity) {
100
+ baseXP += metrics.complexity * 2;
101
+ }
102
+
103
+ // Bonus for time efficiency
104
+ if (metrics.timeEfficiency) {
105
+ baseXP += Math.floor(metrics.timeEfficiency / 10);
106
+ }
107
+
108
+ return baseXP;
109
+ }
110
+
111
+ /**
112
+ * Calculate level from XP
113
+ */
114
+ calculateLevel(xp) {
115
+ for (let level = 6; level >= 1; level--) {
116
+ if (xp >= this.levelThresholds[level]) {
117
+ return level;
118
+ }
119
+ }
120
+ return 1;
121
+ }
122
+
123
+ /**
124
+ * Get skill details
125
+ */
126
+ async getSkill(skillName) {
127
+ const sql = `SELECT * FROM v_skill_summary WHERE skill_name = ?`;
128
+ return await this.db.get(sql, [skillName]);
129
+ }
130
+
131
+ /**
132
+ * Get all skills
133
+ */
134
+ async getAllSkills(category = null, limit = 50) {
135
+ let sql = `SELECT * FROM v_skill_summary`;
136
+ const params = [];
137
+
138
+ if (category) {
139
+ sql += ` WHERE skill_category = ?`;
140
+ params.push(category);
141
+ }
142
+
143
+ sql += ` ORDER BY proficiency_level DESC, experience_points DESC LIMIT ?`;
144
+ params.push(limit);
145
+
146
+ return await this.db.all(sql, params);
147
+ }
148
+
149
+ /**
150
+ * Get skills by category
151
+ */
152
+ async getByCategory(category) {
153
+ const sql = `
154
+ SELECT * FROM memory_evolution
155
+ WHERE skill_category = ?
156
+ ORDER BY proficiency_level DESC, experience_points DESC
157
+ `;
158
+ return await this.db.all(sql, [category]);
159
+ }
160
+
161
+ /**
162
+ * Get skill history
163
+ */
164
+ async getSkillHistory(skillId) {
165
+ const sql = `
166
+ SELECT * FROM memory_evolution_history
167
+ WHERE skill_id = ?
168
+ ORDER BY created_at DESC
169
+ `;
170
+ return await this.db.all(sql, [skillId]);
171
+ }
172
+
173
+ /**
174
+ * Get top skills
175
+ */
176
+ async getTopSkills(limit = 10) {
177
+ const sql = `
178
+ SELECT * FROM v_skill_summary
179
+ ORDER BY proficiency_level DESC, experience_points DESC
180
+ LIMIT ?
181
+ `;
182
+ return await this.db.all(sql, [limit]);
183
+ }
184
+
185
+ /**
186
+ * Get skills needing improvement
187
+ */
188
+ async getNeedsImprovement(threshold = 50) {
189
+ const sql = `
190
+ SELECT * FROM v_skill_summary
191
+ WHERE success_rate < ?
192
+ ORDER BY success_rate ASC
193
+ `;
194
+ return await this.db.all(sql, [threshold]);
195
+ }
196
+
197
+ /**
198
+ * Get category statistics
199
+ */
200
+ async getCategoryStats() {
201
+ const sql = `
202
+ SELECT
203
+ skill_category,
204
+ COUNT(*) as skill_count,
205
+ AVG(proficiency_level) as avg_level,
206
+ SUM(experience_points) as total_xp,
207
+ AVG(CAST(success_count AS REAL) / NULLIF(usage_count, 0) * 100) as avg_success_rate
208
+ FROM memory_evolution
209
+ GROUP BY skill_category
210
+ `;
211
+ return await this.db.all(sql);
212
+ }
213
+
214
+ /**
215
+ * Generate growth report
216
+ */
217
+ async generateGrowthReport(days = 30) {
218
+ const sql = `
219
+ SELECT
220
+ skill_name,
221
+ proficiency_level,
222
+ experience_points,
223
+ usage_count,
224
+ success_count,
225
+ failure_count,
226
+ last_used_at
227
+ FROM memory_evolution
228
+ WHERE last_used_at >= datetime('now', '-${days} days')
229
+ ORDER BY experience_points DESC
230
+ `;
231
+
232
+ const recentSkills = await this.db.all(sql);
233
+ const categories = await this.getCategoryStats();
234
+
235
+ return {
236
+ period: `${days} days`,
237
+ activeSkills: recentSkills.length,
238
+ totalXP: recentSkills.reduce((sum, s) => sum + s.experience_points, 0),
239
+ avgLevel: recentSkills.length > 0
240
+ ? recentSkills.reduce((sum, s) => sum + s.proficiency_level, 0) / recentSkills.length
241
+ : 0,
242
+ topSkills: recentSkills.slice(0, 5),
243
+ categoryBreakdown: categories
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Get next milestone for skill
249
+ */
250
+ getNextMilestone(skill) {
251
+ const currentLevel = skill.proficiency_level;
252
+ const currentXP = skill.experience_points;
253
+
254
+ if (currentLevel >= 6) {
255
+ return { reachedMax: true };
256
+ }
257
+
258
+ const nextLevel = currentLevel + 1;
259
+ const xpNeeded = this.levelThresholds[nextLevel] - currentXP;
260
+
261
+ return {
262
+ currentLevel,
263
+ nextLevel,
264
+ currentXP,
265
+ xpNeeded,
266
+ levelName: this.levelNames[nextLevel]
267
+ };
268
+ }
269
+
270
+ /**
271
+ * Suggest skills to practice
272
+ */
273
+ async suggestPractice() {
274
+ // Get skills that haven't been used recently
275
+ const sql = `
276
+ SELECT * FROM memory_evolution
277
+ WHERE last_used_at IS NULL
278
+ OR last_used_at < datetime('now', '-7 days')
279
+ ORDER BY proficiency_level ASC
280
+ LIMIT 5
281
+ `;
282
+ return await this.db.all(sql);
283
+ }
284
+ }
285
+
286
+ module.exports = EvolutionModule;
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Learning Module
3
+ * Track learning intents, progress, and milestones
4
+ */
5
+
6
+ class LearningModule {
7
+ constructor(db) {
8
+ this.db = db;
9
+ this.learningPatterns = [
10
+ { pattern: /learn|study|understand|master|grasp/i, category: 'skill' },
11
+ { pattern: /read|book|article|paper|research/i, category: 'knowledge' },
12
+ { pattern: /practice|exercise|train|drill/i, category: 'practice' },
13
+ { pattern: /course|tutorial|lesson|lecture/i, category: 'course' },
14
+ { pattern: /language|english|chinese|spanish|japanese/i, category: 'language' }
15
+ ];
16
+ }
17
+
18
+ /**
19
+ * Detect learning intent in message
20
+ */
21
+ async detectIntent(message) {
22
+ const content = message.toLowerCase();
23
+ let detectedCategory = null;
24
+ let confidence = 0;
25
+
26
+ for (const { pattern, category } of this.learningPatterns) {
27
+ if (pattern.test(content)) {
28
+ detectedCategory = category;
29
+ confidence += 0.2;
30
+ }
31
+ }
32
+
33
+ // Extract topic using simple heuristics
34
+ const topic = this.extractTopic(message);
35
+
36
+ return {
37
+ isLearning: confidence > 0,
38
+ category: detectedCategory || 'general',
39
+ confidence: Math.min(confidence, 1),
40
+ topic,
41
+ suggestedResources: this.suggestResources(topic, detectedCategory)
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Extract learning topic from message
47
+ */
48
+ extractTopic(message) {
49
+ // Simple extraction - can be enhanced with NLP
50
+ const patterns = [
51
+ /learn(?:ing)?\s+(?:about\s+)?(.+?)(?:\.|,|;|$)/i,
52
+ /study(?:ing)?\s+(?:about\s+)?(.+?)(?:\.|,|;|$)/i,
53
+ /how\s+to\s+(.+?)(?:\.|,|;|$)/i,
54
+ /master(?:ing)?\s+(.+?)(?:\.|,|;|$)/i
55
+ ];
56
+
57
+ for (const pattern of patterns) {
58
+ const match = message.match(pattern);
59
+ if (match) {
60
+ return match[1].trim();
61
+ }
62
+ }
63
+
64
+ return 'general learning';
65
+ }
66
+
67
+ /**
68
+ * Create new learning record
69
+ */
70
+ async createLearning(messageId, conversationId, intent, notes = '') {
71
+ const sql = `
72
+ INSERT INTO memory_learning
73
+ (message_id, conversation_id, learning_topic, topic_category, progress_status, notes)
74
+ VALUES (?, ?, ?, ?, 'started', ?)
75
+ `;
76
+
77
+ const result = await this.db.run(sql, [
78
+ messageId,
79
+ conversationId,
80
+ intent.topic,
81
+ intent.category,
82
+ notes
83
+ ]);
84
+
85
+ return {
86
+ success: true,
87
+ learningId: result.id,
88
+ topic: intent.topic,
89
+ category: intent.category
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Update learning progress
95
+ */
96
+ async updateProgress(learningId, progressData) {
97
+ const updates = [];
98
+ const values = [];
99
+
100
+ if (progressData.percentage !== undefined) {
101
+ updates.push('progress_percentage = ?');
102
+ values.push(progressData.percentage);
103
+ }
104
+
105
+ if (progressData.status) {
106
+ updates.push('progress_status = ?');
107
+ values.push(progressData.status);
108
+ }
109
+
110
+ if (progressData.notes) {
111
+ updates.push('notes = ?');
112
+ values.push(progressData.notes);
113
+ }
114
+
115
+ if (progressData.completionDate) {
116
+ updates.push('actual_completion_date = ?');
117
+ values.push(progressData.completionDate);
118
+ }
119
+
120
+ if (updates.length === 0) return { success: false, error: 'No updates provided' };
121
+
122
+ const sql = `UPDATE memory_learning SET ${updates.join(', ')} WHERE id = ?`;
123
+ values.push(learningId);
124
+
125
+ await this.db.run(sql, values);
126
+ return { success: true, learningId };
127
+ }
128
+
129
+ /**
130
+ * Add milestone to learning
131
+ */
132
+ async addMilestone(learningId, milestone) {
133
+ const sql = `
134
+ INSERT INTO memory_learning_milestones
135
+ (learning_id, milestone_name, description, target_date)
136
+ VALUES (?, ?, ?, ?)
137
+ `;
138
+
139
+ const result = await this.db.run(sql, [
140
+ learningId,
141
+ milestone.name,
142
+ milestone.description,
143
+ milestone.targetDate
144
+ ]);
145
+
146
+ // Update milestone count
147
+ await this.db.run(
148
+ `UPDATE memory_learning SET milestone_count = milestone_count + 1 WHERE id = ?`,
149
+ [learningId]
150
+ );
151
+
152
+ return { success: true, milestoneId: result.id };
153
+ }
154
+
155
+ /**
156
+ * Complete milestone
157
+ */
158
+ async completeMilestone(milestoneId) {
159
+ const sql = `
160
+ UPDATE memory_learning_milestones
161
+ SET is_completed = 1, completed_date = CURRENT_TIMESTAMP
162
+ WHERE id = ?
163
+ `;
164
+
165
+ await this.db.run(sql, [milestoneId]);
166
+
167
+ // Get learning ID and update completed count
168
+ const milestone = await this.db.get(
169
+ 'SELECT learning_id FROM memory_learning_milestones WHERE id = ?',
170
+ [milestoneId]
171
+ );
172
+
173
+ if (milestone) {
174
+ await this.db.run(
175
+ `UPDATE memory_learning
176
+ SET completed_milestones = completed_milestones + 1
177
+ WHERE id = ?`,
178
+ [milestone.learning_id]
179
+ );
180
+ }
181
+
182
+ return { success: true };
183
+ }
184
+
185
+ /**
186
+ * Get active learning items
187
+ */
188
+ async getActiveLearning(limit = 20) {
189
+ const sql = `SELECT * FROM v_active_learning LIMIT ?`;
190
+ return await this.db.all(sql, [limit]);
191
+ }
192
+
193
+ /**
194
+ * Get learning by topic
195
+ */
196
+ async getByTopic(topic, limit = 10) {
197
+ const sql = `
198
+ SELECT * FROM memory_learning
199
+ WHERE learning_topic LIKE ?
200
+ ORDER BY created_at DESC
201
+ LIMIT ?
202
+ `;
203
+ return await this.db.all(sql, [`%${topic}%`, limit]);
204
+ }
205
+
206
+ /**
207
+ * Get learning statistics
208
+ */
209
+ async getStats() {
210
+ const sql = `
211
+ SELECT
212
+ progress_status,
213
+ COUNT(*) as count,
214
+ AVG(progress_percentage) as avg_progress
215
+ FROM memory_learning
216
+ GROUP BY progress_status
217
+ `;
218
+ return await this.db.all(sql);
219
+ }
220
+
221
+ /**
222
+ * Generate weekly report
223
+ */
224
+ async generateWeeklyReport() {
225
+ const sql = `SELECT * FROM v_weekly_learning_report LIMIT 4`;
226
+ const weeklyData = await this.db.all(sql);
227
+
228
+ const activeLearning = await this.getActiveLearning(10);
229
+
230
+ return {
231
+ weeklyTrend: weeklyData,
232
+ activeTopics: activeLearning,
233
+ summary: {
234
+ totalActive: activeLearning.length,
235
+ avgProgress: activeLearning.reduce((sum, item) => sum + item.progress_percentage, 0) / activeLearning.length || 0
236
+ }
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Suggest resources based on topic
242
+ */
243
+ suggestResources(topic, category) {
244
+ const resources = {
245
+ skill: [
246
+ { type: 'practice', name: 'Hands-on exercises' },
247
+ { type: 'project', name: 'Build a small project' }
248
+ ],
249
+ knowledge: [
250
+ { type: 'reading', name: 'Related articles' },
251
+ { type: 'video', name: 'Tutorial videos' }
252
+ ],
253
+ language: [
254
+ { type: 'app', name: 'Language learning app' },
255
+ { type: 'practice', name: 'Conversation practice' }
256
+ ],
257
+ course: [
258
+ { type: 'online', name: 'Online course platform' },
259
+ { type: 'documentation', name: 'Official documentation' }
260
+ ]
261
+ };
262
+
263
+ return resources[category] || resources.knowledge;
264
+ }
265
+ }
266
+
267
+ module.exports = LearningModule;