memory-lucia 2.5.2 ā 2.5.4
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/README.md +2 -2
- package/SKILL.md +6 -6
- package/database/schema.sql +20 -1
- package/migrations/README.md +1 -0
- package/modules/query.js +129 -88
- package/package.json +1 -1
- package/migrations/v1-to-v2.js +0 -213
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://github.com/wen521/memory-lucia-)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Local SQLite-based memory system for OpenClaw agents. All data stored locally with no external dependencies.
|
|
8
8
|
|
|
9
9
|
## š¦ Installation
|
|
10
10
|
|
|
@@ -104,7 +104,7 @@ SQLite backend with tables:
|
|
|
104
104
|
|
|
105
105
|
## š Version
|
|
106
106
|
|
|
107
|
-
Current: 2.5.
|
|
107
|
+
Current: 2.5.4
|
|
108
108
|
|
|
109
109
|
## š License
|
|
110
110
|
|
package/SKILL.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: memory-lucia
|
|
3
|
-
version: 2.5.
|
|
3
|
+
version: 2.5.4
|
|
4
4
|
description: |
|
|
5
|
-
Memory Lucia
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
(
|
|
9
|
-
|
|
5
|
+
Memory Lucia - Local SQLite-based memory system for OpenClaw agents.
|
|
6
|
+
Features: (1) Priority analysis and tracking, (2) Learning progress with milestones,
|
|
7
|
+
(3) Decision recording with review scheduling, (4) Skill evolution monitoring,
|
|
8
|
+
(5) Local text search across all memory tables, (6) Automatic database backups.
|
|
9
|
+
All data stored locally in SQLite database. No external API calls.
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Memory V2 Skill
|
package/database/schema.sql
CHANGED
|
@@ -184,8 +184,27 @@ FROM memory_learning l
|
|
|
184
184
|
WHERE progress_status IN ('started', 'in_progress')
|
|
185
185
|
ORDER BY updated_at DESC;
|
|
186
186
|
|
|
187
|
+
-- View: Weekly Learning Report
|
|
188
|
+
CREATE VIEW IF NOT EXISTS v_weekly_learning_report AS
|
|
189
|
+
SELECT
|
|
190
|
+
learning_topic,
|
|
191
|
+
topic_category,
|
|
192
|
+
progress_status,
|
|
193
|
+
progress_percentage,
|
|
194
|
+
milestone_count,
|
|
195
|
+
completed_milestones,
|
|
196
|
+
updated_at,
|
|
197
|
+
CASE
|
|
198
|
+
WHEN progress_percentage = 100 THEN 'completed'
|
|
199
|
+
WHEN progress_percentage > 0 THEN 'in_progress'
|
|
200
|
+
ELSE 'not_started'
|
|
201
|
+
END as status_label
|
|
202
|
+
FROM memory_learning
|
|
203
|
+
WHERE updated_at >= datetime('now', '-7 days')
|
|
204
|
+
ORDER BY updated_at DESC;
|
|
205
|
+
|
|
187
206
|
-- View: High Priority Items
|
|
188
|
-
CREATE VIEW IF NOT EXISTS
|
|
207
|
+
CREATE VIEW IF NOT EXISTS v_high_priority_messages AS
|
|
189
208
|
SELECT
|
|
190
209
|
'priority' as type,
|
|
191
210
|
id,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
V2.5 uses a new schema. No migration from V1/V2 is supported. Use init-demo.js for fresh setup.
|
package/modules/query.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Memory
|
|
2
|
+
* Memory Query Module
|
|
3
3
|
*
|
|
4
4
|
* Features:
|
|
5
|
-
* - Local
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
* - Smart caching
|
|
9
|
-
* - Cost tracking
|
|
5
|
+
* - Local SQLite query with text search
|
|
6
|
+
* - Multi-table search
|
|
7
|
+
* - Result ranking
|
|
10
8
|
*
|
|
11
9
|
* @module QueryModule
|
|
12
|
-
* @version 2.5.
|
|
10
|
+
* @version 2.5.3
|
|
13
11
|
*/
|
|
14
12
|
|
|
15
13
|
const sqlite3 = require('sqlite3').verbose();
|
|
@@ -18,123 +16,166 @@ class QueryModule {
|
|
|
18
16
|
constructor(options = {}) {
|
|
19
17
|
this.dbPath = options.dbPath || './memory-v2.5.db';
|
|
20
18
|
this.db = null;
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.costStats = {
|
|
26
|
-
localQueries: 0,
|
|
27
|
-
apiFallbacks: 0,
|
|
28
|
-
totalTokens: 0
|
|
19
|
+
this.stats = {
|
|
20
|
+
totalQueries: 0,
|
|
21
|
+
resultsFound: 0
|
|
29
22
|
};
|
|
30
23
|
}
|
|
31
24
|
|
|
32
25
|
async init() {
|
|
33
26
|
this.db = new sqlite3.Database(this.dbPath);
|
|
34
|
-
console.log('ā
Query Module
|
|
27
|
+
console.log('ā
Query Module initialized');
|
|
35
28
|
return this;
|
|
36
29
|
}
|
|
37
30
|
|
|
38
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Search across all memory tables
|
|
33
|
+
* @param {string} queryText - Search text
|
|
34
|
+
* @param {Object} options - Search options
|
|
35
|
+
* @returns {Object} Search results
|
|
36
|
+
*/
|
|
37
|
+
async search(queryText, options = {}) {
|
|
39
38
|
const startTime = Date.now();
|
|
40
39
|
|
|
41
|
-
console.log(`\nš
|
|
42
|
-
|
|
43
|
-
// Try local first
|
|
44
|
-
const localResults = await this.localQuery(queryText, options);
|
|
45
|
-
if (localResults.length > 0) {
|
|
46
|
-
this.costStats.localQueries++;
|
|
47
|
-
return {
|
|
48
|
-
source: 'local',
|
|
49
|
-
results: localResults,
|
|
50
|
-
time: Date.now() - startTime,
|
|
51
|
-
cost: 0
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Fallback to API if enabled
|
|
56
|
-
if (this.useAPIFallback) {
|
|
57
|
-
this.costStats.apiFallbacks++;
|
|
58
|
-
// API call placeholder
|
|
59
|
-
return {
|
|
60
|
-
source: 'api',
|
|
61
|
-
results: [],
|
|
62
|
-
time: Date.now() - startTime,
|
|
63
|
-
cost: 'tokens'
|
|
64
|
-
};
|
|
65
|
-
}
|
|
40
|
+
console.log(`\nš Search: "${queryText}"`);
|
|
66
41
|
|
|
67
|
-
return {
|
|
68
|
-
source: 'none',
|
|
69
|
-
results: [],
|
|
70
|
-
time: Date.now() - startTime,
|
|
71
|
-
cost: 0
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async localQuery(queryText, options) {
|
|
76
|
-
const pattern = `%${queryText}%`;
|
|
77
42
|
const results = [];
|
|
78
43
|
|
|
79
|
-
//
|
|
44
|
+
// Search learning table
|
|
80
45
|
try {
|
|
81
|
-
const learning = await this.
|
|
82
|
-
results.push(...learning.map(r => ({ ...r, _source: 'learning' })));
|
|
46
|
+
const learning = await this.searchLearning(queryText);
|
|
47
|
+
results.push(...learning.map(r => ({ ...r, _source: 'learning', _score: this.calculateScore(r, queryText) })));
|
|
83
48
|
} catch (err) {
|
|
84
|
-
// Table might not exist
|
|
49
|
+
// Table might not exist
|
|
85
50
|
}
|
|
86
51
|
|
|
87
|
-
//
|
|
52
|
+
// Search priorities table
|
|
88
53
|
try {
|
|
89
|
-
const priorities = await this.
|
|
90
|
-
results.push(...priorities.map(r => ({ ...r, _source: 'priority' })));
|
|
54
|
+
const priorities = await this.searchPriorities(queryText);
|
|
55
|
+
results.push(...priorities.map(r => ({ ...r, _source: 'priority', _score: this.calculateScore(r, queryText) })));
|
|
91
56
|
} catch (err) {
|
|
92
|
-
// Table might not exist
|
|
57
|
+
// Table might not exist
|
|
93
58
|
}
|
|
94
59
|
|
|
95
|
-
//
|
|
60
|
+
// Search decisions table
|
|
96
61
|
try {
|
|
97
|
-
const decisions = await this.
|
|
98
|
-
results.push(...decisions.map(r => ({ ...r, _source: 'decision' })));
|
|
62
|
+
const decisions = await this.searchDecisions(queryText);
|
|
63
|
+
results.push(...decisions.map(r => ({ ...r, _source: 'decision', _score: this.calculateScore(r, queryText) })));
|
|
99
64
|
} catch (err) {
|
|
100
|
-
// Table might not exist
|
|
65
|
+
// Table might not exist
|
|
101
66
|
}
|
|
102
67
|
|
|
103
|
-
//
|
|
68
|
+
// Search evolution table
|
|
104
69
|
try {
|
|
105
|
-
const evolution = await this.
|
|
106
|
-
results.push(...evolution.map(r => ({ ...r, _source: 'evolution' })));
|
|
70
|
+
const evolution = await this.searchEvolution(queryText);
|
|
71
|
+
results.push(...evolution.map(r => ({ ...r, _source: 'evolution', _score: this.calculateScore(r, queryText) })));
|
|
107
72
|
} catch (err) {
|
|
108
|
-
// Table might not exist
|
|
73
|
+
// Table might not exist
|
|
109
74
|
}
|
|
110
75
|
|
|
111
|
-
|
|
76
|
+
// Sort by score and limit
|
|
77
|
+
results.sort((a, b) => b._score - a._score);
|
|
78
|
+
const limited = results.slice(0, options.limit || 10);
|
|
79
|
+
|
|
80
|
+
this.stats.totalQueries++;
|
|
81
|
+
this.stats.resultsFound += limited.length;
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
query: queryText,
|
|
85
|
+
results: limited,
|
|
86
|
+
total: results.length,
|
|
87
|
+
time: Date.now() - startTime
|
|
88
|
+
};
|
|
112
89
|
}
|
|
113
90
|
|
|
114
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Search learning table
|
|
93
|
+
*/
|
|
94
|
+
async searchLearning(queryText) {
|
|
95
|
+
const pattern = `%${queryText}%`;
|
|
115
96
|
return new Promise((resolve, reject) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
97
|
+
const sql = `SELECT * FROM memory_learning
|
|
98
|
+
WHERE learning_topic LIKE ? OR notes LIKE ?
|
|
99
|
+
LIMIT 10`;
|
|
100
|
+
this.db.all(sql, [pattern, pattern], (err, rows) => {
|
|
101
|
+
if (err) reject(err);
|
|
102
|
+
else resolve(rows || []);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Search priorities table
|
|
109
|
+
*/
|
|
110
|
+
async searchPriorities(queryText) {
|
|
111
|
+
const pattern = `%${queryText}%`;
|
|
112
|
+
return new Promise((resolve, reject) => {
|
|
113
|
+
const sql = `SELECT * FROM memory_priorities
|
|
114
|
+
WHERE context_summary LIKE ? OR keywords LIKE ?
|
|
115
|
+
LIMIT 10`;
|
|
116
|
+
this.db.all(sql, [pattern, pattern], (err, rows) => {
|
|
117
|
+
if (err) reject(err);
|
|
118
|
+
else resolve(rows || []);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Search decisions table
|
|
125
|
+
*/
|
|
126
|
+
async searchDecisions(queryText) {
|
|
127
|
+
const pattern = `%${queryText}%`;
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
const sql = `SELECT * FROM memory_decisions
|
|
130
|
+
WHERE decision_question LIKE ? OR decision_context LIKE ? OR rationale LIKE ?
|
|
131
|
+
LIMIT 10`;
|
|
132
|
+
this.db.all(sql, [pattern, pattern, pattern], (err, rows) => {
|
|
133
|
+
if (err) reject(err);
|
|
134
|
+
else resolve(rows || []);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Search evolution table
|
|
141
|
+
*/
|
|
142
|
+
async searchEvolution(queryText) {
|
|
143
|
+
const pattern = `%${queryText}%`;
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
const sql = `SELECT * FROM memory_evolution
|
|
146
|
+
WHERE skill_name LIKE ? OR skill_category LIKE ?
|
|
147
|
+
LIMIT 10`;
|
|
148
|
+
this.db.all(sql, [pattern, pattern], (err, rows) => {
|
|
149
|
+
if (err) reject(err);
|
|
150
|
+
else resolve(rows || []);
|
|
132
151
|
});
|
|
133
152
|
});
|
|
134
153
|
}
|
|
135
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Calculate relevance score
|
|
157
|
+
*/
|
|
158
|
+
calculateScore(row, queryText) {
|
|
159
|
+
const query = queryText.toLowerCase();
|
|
160
|
+
let score = 0;
|
|
161
|
+
|
|
162
|
+
// Check all text fields
|
|
163
|
+
for (const key of Object.keys(row)) {
|
|
164
|
+
if (typeof row[key] === 'string') {
|
|
165
|
+
const value = row[key].toLowerCase();
|
|
166
|
+
if (value.includes(query)) {
|
|
167
|
+
score += 1;
|
|
168
|
+
// Bonus for exact match
|
|
169
|
+
if (value === query) score += 2;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return score;
|
|
175
|
+
}
|
|
176
|
+
|
|
136
177
|
getStats() {
|
|
137
|
-
return this.
|
|
178
|
+
return this.stats;
|
|
138
179
|
}
|
|
139
180
|
|
|
140
181
|
close() {
|
|
@@ -142,4 +183,4 @@ class QueryModule {
|
|
|
142
183
|
}
|
|
143
184
|
}
|
|
144
185
|
|
|
145
|
-
module.exports = QueryModule;
|
|
186
|
+
module.exports = QueryModule;
|
package/package.json
CHANGED
package/migrations/v1-to-v2.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Memory V1 to V2 Migration Script
|
|
4
|
-
* Migrates data from old memory format to V2 schema
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const sqlite3 = require('sqlite3').verbose();
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
class MemoryMigration {
|
|
12
|
-
constructor(sourceDbPath, targetDbPath = './memory-v2.db') {
|
|
13
|
-
this.sourceDbPath = sourceDbPath;
|
|
14
|
-
this.targetDbPath = targetDbPath;
|
|
15
|
-
this.sourceDb = null;
|
|
16
|
-
this.targetDb = null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async init() {
|
|
20
|
-
// Check if source exists
|
|
21
|
-
if (!fs.existsSync(this.sourceDbPath)) {
|
|
22
|
-
throw new Error(`Source database not found: ${this.sourceDbPath}`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Open source database
|
|
26
|
-
this.sourceDb = new sqlite3.Database(this.sourceDbPath, sqlite3.OPEN_READONLY);
|
|
27
|
-
|
|
28
|
-
// Open/create target database
|
|
29
|
-
this.targetDb = new sqlite3.Database(this.targetDbPath);
|
|
30
|
-
|
|
31
|
-
console.log('ā
Connected to source and target databases');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async runSchema() {
|
|
35
|
-
const schemaPath = path.join(__dirname, '..', 'database', 'schema.sql');
|
|
36
|
-
|
|
37
|
-
if (!fs.existsSync(schemaPath)) {
|
|
38
|
-
throw new Error(`Schema file not found: ${schemaPath}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const schema = fs.readFileSync(schemaPath, 'utf8');
|
|
42
|
-
const statements = schema
|
|
43
|
-
.split(';')
|
|
44
|
-
.map(s => s.trim())
|
|
45
|
-
.filter(s => s.length > 0);
|
|
46
|
-
|
|
47
|
-
for (const statement of statements) {
|
|
48
|
-
await this.runTarget(statement);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log('ā
Target database schema initialized');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async migratePriorities() {
|
|
55
|
-
console.log('š Migrating priorities...');
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const rows = await this.allSource(
|
|
59
|
-
"SELECT * FROM memory_priorities WHERE created_at >= datetime('now', '-90 days')"
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
for (const row of rows) {
|
|
63
|
-
await this.runTarget(
|
|
64
|
-
`INSERT INTO memory_priorities
|
|
65
|
-
(msg_id, conv_id, priority_level, reasoning, category, created_at)
|
|
66
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
67
|
-
[row.msg_id, row.conv_id, row.priority_level, row.reasoning, row.category, row.created_at]
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
console.log(`ā
Migrated ${rows.length} priority records`);
|
|
72
|
-
} catch (err) {
|
|
73
|
-
console.log('ā¹ļø No priorities to migrate or table does not exist');
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async migrateLearning() {
|
|
78
|
-
console.log('š Migrating learning records...');
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const rows = await this.allSource(
|
|
82
|
-
"SELECT * FROM memory_learning WHERE status != 'abandoned'"
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
for (const row of rows) {
|
|
86
|
-
await this.runTarget(
|
|
87
|
-
`INSERT INTO memory_learning
|
|
88
|
-
(msg_id, conv_id, topic, description, status, progress, started_at, updated_at, completed_at)
|
|
89
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
90
|
-
[row.msg_id, row.conv_id, row.topic, row.description, row.status,
|
|
91
|
-
row.progress, row.started_at, row.updated_at, row.completed_at]
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
console.log(`ā
Migrated ${rows.length} learning records`);
|
|
96
|
-
} catch (err) {
|
|
97
|
-
console.log('ā¹ļø No learning records to migrate or table does not exist');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async migrateDecisions() {
|
|
102
|
-
console.log('š Migrating decisions...');
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const rows = await this.allSource(
|
|
106
|
-
"SELECT * FROM memory_decisions WHERE status IN ('pending', 'implemented')"
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
for (const row of rows) {
|
|
110
|
-
await this.runTarget(
|
|
111
|
-
`INSERT INTO memory_decisions
|
|
112
|
-
(msg_id, conv_id, summary, context, expected_outcome, actual_outcome,
|
|
113
|
-
status, review_scheduled_at, reviewed_at, created_at)
|
|
114
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
115
|
-
[row.msg_id, row.conv_id, row.summary, row.context, row.expected_outcome,
|
|
116
|
-
row.actual_outcome, row.status, row.review_scheduled_at, row.reviewed_at, row.created_at]
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.log(`ā
Migrated ${rows.length} decision records`);
|
|
121
|
-
} catch (err) {
|
|
122
|
-
console.log('ā¹ļø No decisions to migrate or table does not exist');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async migrateEvolution() {
|
|
127
|
-
console.log('š Migrating skill evolution...');
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const rows = await this.allSource(
|
|
131
|
-
"SELECT * FROM memory_evolution WHERE usage_count > 0"
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
for (const row of rows) {
|
|
135
|
-
await this.runTarget(
|
|
136
|
-
`INSERT INTO memory_evolution
|
|
137
|
-
(skill_name, category, usage_count, success_count, last_used_at, first_used_at)
|
|
138
|
-
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
139
|
-
[row.skill_name, row.category, row.usage_count, row.success_count,
|
|
140
|
-
row.last_used_at, row.first_used_at]
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
console.log(`ā
Migrated ${rows.length} skill evolution records`);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
console.log('ā¹ļø No evolution records to migrate or table does not exist');
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async runTarget(sql, params = []) {
|
|
151
|
-
return new Promise((resolve, reject) => {
|
|
152
|
-
this.targetDb.run(sql, params, function(err) {
|
|
153
|
-
if (err) reject(err);
|
|
154
|
-
else resolve({ id: this.lastID, changes: this.changes });
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async allSource(sql, params = []) {
|
|
160
|
-
return new Promise((resolve, reject) => {
|
|
161
|
-
this.sourceDb.all(sql, params, (err, rows) => {
|
|
162
|
-
if (err) reject(err);
|
|
163
|
-
else resolve(rows);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async close() {
|
|
169
|
-
if (this.sourceDb) {
|
|
170
|
-
await new Promise((resolve) => this.sourceDb.close(resolve));
|
|
171
|
-
}
|
|
172
|
-
if (this.targetDb) {
|
|
173
|
-
await new Promise((resolve) => this.targetDb.close(resolve));
|
|
174
|
-
}
|
|
175
|
-
console.log('ā
Database connections closed');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async migrate() {
|
|
179
|
-
try {
|
|
180
|
-
await this.init();
|
|
181
|
-
await this.runSchema();
|
|
182
|
-
await this.migratePriorities();
|
|
183
|
-
await this.migrateLearning();
|
|
184
|
-
await this.migrateDecisions();
|
|
185
|
-
await this.migrateEvolution();
|
|
186
|
-
|
|
187
|
-
console.log('\nš Migration completed successfully!');
|
|
188
|
-
console.log(`š New database: ${path.resolve(this.targetDbPath)}`);
|
|
189
|
-
} catch (err) {
|
|
190
|
-
console.error('\nā Migration failed:', err.message);
|
|
191
|
-
process.exit(1);
|
|
192
|
-
} finally {
|
|
193
|
-
await this.close();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// CLI usage
|
|
199
|
-
if (require.main === module) {
|
|
200
|
-
const sourceDb = process.argv[2];
|
|
201
|
-
const targetDb = process.argv[3] || './memory-v2.db';
|
|
202
|
-
|
|
203
|
-
if (!sourceDb) {
|
|
204
|
-
console.log('Usage: node migrations/v1-to-v2.js <source-v1.db> [target-v2.db]');
|
|
205
|
-
console.log('Example: node migrations/v1-to-v2.js ./memory-v1.db ./memory-v2.db');
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const migration = new MemoryMigration(sourceDb, targetDb);
|
|
210
|
-
migration.migrate();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
module.exports = MemoryMigration;
|