@vheins/local-memory-mcp 0.6.1 → 0.6.2

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.
@@ -82,6 +82,9 @@ function deriveLoggerName(message) {
82
82
  return "app";
83
83
  }
84
84
  function emitToStderr(level, message, context) {
85
+ if (process.env.MCP_SERVER === "true") {
86
+ return;
87
+ }
85
88
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
86
89
  if (message.startsWith("[MCP]")) {
87
90
  const icon = getMcpIcon(message);
@@ -169,19 +172,43 @@ function addLogSink(sink) {
169
172
  var LOG_LEVEL_VALUES = Object.keys(LEVELS);
170
173
 
171
174
  // src/mcp/storage/sqlite.ts
172
- import Database from "better-sqlite3";
175
+ import initSqlJs from "sql.js";
173
176
  import path2 from "path";
174
177
  import fs2 from "fs";
175
178
  import os from "os";
176
179
 
177
180
  // src/mcp/storage/migrations.ts
178
181
  var MigrationManager = class {
179
- constructor(db) {
182
+ constructor(db, saveDb) {
180
183
  this.db = db;
184
+ this.saveDb = saveDb;
181
185
  }
182
186
  db;
187
+ saveDb;
188
+ run(sql) {
189
+ this.db.run(sql);
190
+ }
191
+ exec(sql) {
192
+ this.db.exec(sql);
193
+ }
194
+ all(sql) {
195
+ const result = this.db.exec(sql);
196
+ if (result.length === 0) return [];
197
+ const { columns, values } = result[0];
198
+ return values.map((row) => {
199
+ const obj = {};
200
+ columns.forEach((col, i) => {
201
+ obj[col] = row[i];
202
+ });
203
+ return obj;
204
+ });
205
+ }
206
+ get(sql) {
207
+ const rows = this.all(sql);
208
+ return rows[0];
209
+ }
183
210
  migrate() {
184
- this.db.exec(`
211
+ this.exec(`
185
212
  CREATE TABLE IF NOT EXISTS memories (
186
213
  id TEXT PRIMARY KEY,
187
214
  repo TEXT NOT NULL,
@@ -311,35 +338,6 @@ var MigrationManager = class {
311
338
 
312
339
  CREATE INDEX IF NOT EXISTS idx_action_log_repo ON action_log(repo);
313
340
  CREATE INDEX IF NOT EXISTS idx_action_log_created_at ON action_log(created_at);
314
-
315
- -- FTS5 Virtual Table for Memories
316
- -- Note: Only using id, title, and content for search indexing
317
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
318
- id UNINDEXED,
319
- repo,
320
- type,
321
- title,
322
- content,
323
- metadata UNINDEXED,
324
- content='memories',
325
- content_rowid='id'
326
- );
327
-
328
- -- Triggers to keep FTS index in sync with base table
329
- CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
330
- INSERT INTO memories_fts(id, repo, type, title, content, metadata)
331
- VALUES (new.id, new.repo, new.type, new.title, new.content, new.metadata);
332
- END;
333
- CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
334
- INSERT INTO memories_fts(memories_fts, id, repo, type, title, content, metadata)
335
- VALUES ('delete', old.id, old.repo, old.type, old.title, old.content, old.metadata);
336
- END;
337
- CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
338
- INSERT INTO memories_fts(memories_fts, id, repo, type, title, content, metadata)
339
- VALUES ('delete', old.id, old.repo, old.type, old.title, old.content, old.metadata);
340
- INSERT INTO memories_fts(id, repo, type, title, content, metadata)
341
- VALUES (new.id, new.repo, new.type, new.title, new.content, new.metadata);
342
- END;
343
341
  `);
344
342
  const columnsToAdd = [
345
343
  { name: "title", table: "memories", definition: "ALTER TABLE memories ADD COLUMN title TEXT" },
@@ -409,37 +407,34 @@ var MigrationManager = class {
409
407
  ];
410
408
  for (const col of columnsToAdd) {
411
409
  try {
412
- const tableInfo = this.db.prepare(`PRAGMA table_info(${col.table})`).all();
410
+ const tableInfo = this.all(`PRAGMA table_info(${col.table})`);
413
411
  const existingTableColumns = tableInfo.map((c) => c.name);
414
412
  if (tableInfo.length > 0 && !existingTableColumns.includes(col.name)) {
415
- this.db.exec(col.definition);
413
+ this.exec(col.definition);
416
414
  }
417
- } catch (e) {
418
- logger.error(
419
- `Migration step failed for ${col.table}.${col.name}: ${e instanceof Error ? e.message : String(e)}`
420
- );
415
+ } catch {
421
416
  }
422
417
  }
423
418
  this.ensureMemoryTypeConstraint();
424
419
  this.ensureTaskStatusConstraintRemoved();
425
420
  this.ensureMemoryStatusConstraintRemoved();
426
- this.db.exec(`
421
+ this.exec(`
427
422
  CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status);
428
423
  CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes);
429
424
  CREATE INDEX IF NOT EXISTS idx_memories_is_global ON memories(is_global);
430
425
  `);
431
426
  try {
432
- this.db.exec("UPDATE tasks SET task_code = substr(id, 1, 8) WHERE task_code IS NULL");
433
- } catch (e) {
434
- logger.error(`Legacy backfill task_code failed: ${e instanceof Error ? e.message : String(e)}`);
427
+ this.run("UPDATE tasks SET task_code = substr(id, 1, 8) WHERE task_code IS NULL");
428
+ } catch {
435
429
  }
430
+ if (this.saveDb) this.saveDb();
436
431
  }
437
432
  ensureMemoryTypeConstraint() {
438
- const tableSql = this.db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memories'").get();
439
- if (!tableSql?.sql || !tableSql.sql.includes("CHECK (type IN")) {
433
+ const tableSql = this.get("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memories'");
434
+ if (!tableSql?.sql || !String(tableSql.sql).includes("CHECK (type IN")) {
440
435
  return;
441
436
  }
442
- this.db.exec(`
437
+ this.exec(`
443
438
  BEGIN TRANSACTION;
444
439
 
445
440
  CREATE TABLE memories__migrated (
@@ -486,11 +481,11 @@ var MigrationManager = class {
486
481
  `);
487
482
  }
488
483
  ensureTaskStatusConstraintRemoved() {
489
- const tableSql = this.db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'tasks'").get();
490
- if (!tableSql?.sql || !tableSql.sql.includes("CHECK (status IN") && !tableSql.sql.includes("DEFAULT 'pending'")) {
484
+ const tableSql = this.get("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'tasks'");
485
+ if (!tableSql?.sql || !String(tableSql.sql).includes("CHECK (status IN") && !String(tableSql.sql).includes("DEFAULT 'pending'")) {
491
486
  return;
492
487
  }
493
- this.db.exec(`
488
+ this.exec(`
494
489
  BEGIN TRANSACTION;
495
490
 
496
491
  CREATE TABLE tasks__migrated (
@@ -535,7 +530,7 @@ var MigrationManager = class {
535
530
  `);
536
531
  }
537
532
  ensureMemoryStatusConstraintRemoved() {
538
- const tableSql = this.db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memories'").get();
533
+ const tableSql = this.get("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memories'");
539
534
  if (tableSql?.sql?.includes("status TEXT NOT NULL DEFAULT 'active' CHECK")) {
540
535
  this.ensureMemoryTypeConstraint();
541
536
  }
@@ -788,13 +783,37 @@ function tokenize(text) {
788
783
 
789
784
  // src/mcp/storage/base.ts
790
785
  var BaseEntity = class {
791
- constructor(db) {
786
+ constructor(db, saveDb) {
792
787
  this.db = db;
788
+ this.saveDb = saveDb;
793
789
  }
794
790
  db;
795
- /**
796
- * Safe JSON parsing helper to avoid crashes on corrupt data
797
- */
791
+ saveDb;
792
+ run(sql, params = []) {
793
+ this.db.run(sql, params);
794
+ if (this.saveDb) this.saveDb();
795
+ return { changes: this.db.getRowsModified() };
796
+ }
797
+ exec(sql) {
798
+ this.db.exec(sql);
799
+ if (this.saveDb) this.saveDb();
800
+ }
801
+ all(sql, params = []) {
802
+ const result = this.db.exec(sql, params);
803
+ if (result.length === 0) return [];
804
+ const { columns, values } = result[0];
805
+ return values.map((row) => {
806
+ const obj = {};
807
+ columns.forEach((col, i) => {
808
+ obj[col] = row[i];
809
+ });
810
+ return obj;
811
+ });
812
+ }
813
+ get(sql, params = []) {
814
+ const rows = this.all(sql, params);
815
+ return rows[0];
816
+ }
798
817
  safeJSONParse(json, defaultValue) {
799
818
  if (!json) return defaultValue;
800
819
  try {
@@ -803,9 +822,6 @@ var BaseEntity = class {
803
822
  return defaultValue;
804
823
  }
805
824
  }
806
- /**
807
- * Mapping helper for MemoryEntry
808
- */
809
825
  rowToMemoryEntry(row) {
810
826
  const r = row;
811
827
  return {
@@ -836,9 +852,6 @@ var BaseEntity = class {
836
852
  metadata: this.safeJSONParse(r.metadata, {})
837
853
  };
838
854
  }
839
- /**
840
- * Mapping helper for Task
841
- */
842
855
  rowToTask(row) {
843
856
  const r = row;
844
857
  return {
@@ -866,9 +879,6 @@ var BaseEntity = class {
866
879
  comments_count: r.comments_count || 0
867
880
  };
868
881
  }
869
- /**
870
- * Vector math utilities (simple bag-of-words implementation)
871
- */
872
882
  computeVector(text) {
873
883
  const tokens = tokenize(text);
874
884
  const vector = {};
@@ -897,34 +907,34 @@ var BaseEntity = class {
897
907
  // src/mcp/entities/memory.ts
898
908
  var MemoryEntity = class extends BaseEntity {
899
909
  insert(entry) {
900
- const stmt = this.db.prepare(`
901
- INSERT INTO memories (
902
- id, repo, type, title, content, importance, folder, language,
903
- created_at, updated_at, hit_count, recall_count, last_used_at, expires_at,
904
- supersedes, status, is_global, tags, metadata, agent, role, model, completed_at
905
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
906
- `);
907
- stmt.run(
908
- entry.id,
909
- entry.scope.repo,
910
- entry.type,
911
- entry.title || null,
912
- entry.content,
913
- entry.importance,
914
- entry.scope.folder || null,
915
- entry.scope.language || null,
916
- entry.created_at,
917
- entry.updated_at,
918
- entry.expires_at ?? null,
919
- entry.supersedes ?? null,
920
- entry.status || "active",
921
- entry.is_global ? 1 : 0,
922
- entry.tags ? JSON.stringify(entry.tags) : null,
923
- entry.metadata ? JSON.stringify(entry.metadata) : null,
924
- entry.agent || "unknown",
925
- entry.role || "unknown",
926
- entry.model || "unknown",
927
- entry.completed_at || null
910
+ this.run(
911
+ `INSERT INTO memories (
912
+ id, repo, type, title, content, importance, folder, language,
913
+ created_at, updated_at, hit_count, recall_count, last_used_at, expires_at,
914
+ supersedes, status, is_global, tags, metadata, agent, role, model, completed_at
915
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
916
+ [
917
+ entry.id,
918
+ entry.scope.repo,
919
+ entry.type,
920
+ entry.title || null,
921
+ entry.content,
922
+ entry.importance,
923
+ entry.scope.folder || null,
924
+ entry.scope.language || null,
925
+ entry.created_at,
926
+ entry.updated_at,
927
+ entry.expires_at ?? null,
928
+ entry.supersedes ?? null,
929
+ entry.status || "active",
930
+ entry.is_global ? 1 : 0,
931
+ entry.tags ? JSON.stringify(entry.tags) : null,
932
+ entry.metadata ? JSON.stringify(entry.metadata) : null,
933
+ entry.agent || "unknown",
934
+ entry.role || "unknown",
935
+ entry.model || "unknown",
936
+ entry.completed_at || null
937
+ ]
928
938
  );
929
939
  }
930
940
  update(id, updates) {
@@ -964,23 +974,20 @@ var MemoryEntity = class extends BaseEntity {
964
974
  fields.push("updated_at = ?");
965
975
  values.push((/* @__PURE__ */ new Date()).toISOString());
966
976
  values.push(id);
967
- const stmt = this.db.prepare(`UPDATE memories SET ${fields.join(", ")} WHERE id = ?`);
968
- stmt.run(...values);
977
+ this.run(`UPDATE memories SET ${fields.join(", ")} WHERE id = ?`, values);
969
978
  }
970
979
  delete(id) {
971
- this.db.prepare("DELETE FROM memories WHERE id = ?").run(id);
980
+ this.run("DELETE FROM memories WHERE id = ?", [id]);
972
981
  }
973
982
  getById(id) {
974
- const row = this.db.prepare("SELECT * FROM memories WHERE id = ?").get(id);
983
+ const row = this.get("SELECT * FROM memories WHERE id = ?", [id]);
975
984
  return row ? this.rowToMemoryEntry(row) : null;
976
985
  }
977
986
  getByIdWithStats(id) {
978
- const row = this.db.prepare(
979
- `
980
- SELECT *, CASE WHEN hit_count > 0 THEN CAST(recall_count AS REAL) / hit_count ELSE 0 END AS recall_rate
981
- FROM memories WHERE id = ?
982
- `
983
- ).get(id);
987
+ const row = this.get(
988
+ `SELECT *, CASE WHEN hit_count > 0 THEN CAST(recall_count AS REAL) / hit_count ELSE 0 END AS recall_rate FROM memories WHERE id = ?`,
989
+ [id]
990
+ );
984
991
  if (!row) return null;
985
992
  return {
986
993
  ...this.rowToMemoryEntry(row),
@@ -999,7 +1006,7 @@ var MemoryEntity = class extends BaseEntity {
999
1006
  sql += " AND status = ?";
1000
1007
  params.push(options.status);
1001
1008
  }
1002
- const rows = this.db.prepare(sql).all(...params);
1009
+ const rows = this.all(sql, params);
1003
1010
  return rows.map((row) => this.rowToMemoryEntry(row));
1004
1011
  }
1005
1012
  getStats(repo) {
@@ -1010,7 +1017,7 @@ var MemoryEntity = class extends BaseEntity {
1010
1017
  params.push(repo);
1011
1018
  }
1012
1019
  sql += " GROUP BY type";
1013
- const rows = this.db.prepare(sql).all(...params);
1020
+ const rows = this.all(sql, params);
1014
1021
  const byType = {};
1015
1022
  let total = 0;
1016
1023
  rows.forEach((row) => {
@@ -1021,32 +1028,6 @@ var MemoryEntity = class extends BaseEntity {
1021
1028
  }
1022
1029
  searchByRepo(repo, query = "", type, limit = 5) {
1023
1030
  const now = (/* @__PURE__ */ new Date()).toISOString();
1024
- if (query && query.length >= 3) {
1025
- try {
1026
- let sql2 = `
1027
- SELECT m.*
1028
- FROM memories m
1029
- JOIN memories_fts f ON m.id = f.id
1030
- WHERE m.repo = ? AND memories_fts MATCH ? AND m.status = 'active'
1031
- AND (m.expires_at IS NULL OR m.expires_at > ?)
1032
- `;
1033
- const params2 = [repo, query, now];
1034
- if (type) {
1035
- sql2 += " AND m.type = ?";
1036
- params2.push(type);
1037
- }
1038
- sql2 += " ORDER BY rank, m.importance DESC, m.created_at DESC LIMIT ?";
1039
- params2.push(limit);
1040
- const rows2 = this.db.prepare(sql2).all(...params2);
1041
- return rows2.map((row) => this.rowToMemoryEntry(row));
1042
- } catch (e) {
1043
- logger.warn("FTS5 similarity search failed, falling back to LIKE", {
1044
- error: e instanceof Error ? e.message : String(e),
1045
- repo,
1046
- query
1047
- });
1048
- }
1049
- }
1050
1031
  let sql = "SELECT * FROM memories WHERE repo = ? AND (content LIKE ? OR title LIKE ? OR tags LIKE ?) AND status = 'active' AND (expires_at IS NULL OR expires_at > ?)";
1051
1032
  const params = [repo, `%${query}%`, `%${query}%`, `%${query}%`, now];
1052
1033
  if (type) {
@@ -1055,21 +1036,19 @@ var MemoryEntity = class extends BaseEntity {
1055
1036
  }
1056
1037
  sql += " ORDER BY importance DESC, created_at DESC LIMIT ?";
1057
1038
  params.push(limit);
1058
- const rows = this.db.prepare(sql).all(...params);
1039
+ const rows = this.all(sql, params);
1059
1040
  return rows.map((row) => this.rowToMemoryEntry(row));
1060
1041
  }
1061
1042
  bulkInsertMemories(entries) {
1062
- const insert = this.db.prepare(`
1063
- INSERT INTO memories (
1064
- id, repo, type, title, content, importance, folder, language,
1065
- created_at, updated_at, hit_count, recall_count, last_used_at, expires_at,
1066
- supersedes, status, is_global, tags, metadata, agent, role, model, completed_at
1067
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1068
- `);
1069
- const insertMany = this.db.transaction((entries2) => {
1070
- let count = 0;
1071
- for (const entry of entries2) {
1072
- insert.run(
1043
+ let count = 0;
1044
+ for (const entry of entries) {
1045
+ this.run(
1046
+ `INSERT INTO memories (
1047
+ id, repo, type, title, content, importance, folder, language,
1048
+ created_at, updated_at, hit_count, recall_count, last_used_at, expires_at,
1049
+ supersedes, status, is_global, tags, metadata, agent, role, model, completed_at
1050
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1051
+ [
1073
1052
  entry.id,
1074
1053
  entry.scope.repo,
1075
1054
  entry.type,
@@ -1090,12 +1069,11 @@ var MemoryEntity = class extends BaseEntity {
1090
1069
  entry.role || "unknown",
1091
1070
  entry.model || "unknown",
1092
1071
  entry.completed_at || null
1093
- );
1094
- count++;
1095
- }
1096
- return count;
1097
- });
1098
- return insertMany(entries);
1072
+ ]
1073
+ );
1074
+ count++;
1075
+ }
1076
+ return count;
1099
1077
  }
1100
1078
  bulkUpdateMemories(ids, updates) {
1101
1079
  if (ids.length === 0) return 0;
@@ -1119,35 +1097,28 @@ var MemoryEntity = class extends BaseEntity {
1119
1097
  if (fields.length === 0) return 0;
1120
1098
  fields.push("updated_at = ?");
1121
1099
  values.push((/* @__PURE__ */ new Date()).toISOString());
1122
- const updateMany = this.db.transaction((ids2, fields2, values2) => {
1123
- let count = 0;
1124
- const chunkSize = 500;
1125
- for (let i = 0; i < ids2.length; i += chunkSize) {
1126
- const chunk = ids2.slice(i, i + chunkSize);
1127
- const stmt = this.db.prepare(
1128
- `UPDATE memories SET ${fields2.join(", ")} WHERE id IN (${chunk.map(() => "?").join(",")})`
1129
- );
1130
- const result = stmt.run(...values2, ...chunk);
1131
- count += result.changes;
1132
- }
1133
- return count;
1134
- });
1135
- return updateMany(ids, fields, values);
1100
+ let count = 0;
1101
+ const chunkSize = 500;
1102
+ for (let i = 0; i < ids.length; i += chunkSize) {
1103
+ const chunk = ids.slice(i, i + chunkSize);
1104
+ const result = this.run(
1105
+ `UPDATE memories SET ${fields.join(", ")} WHERE id IN (${chunk.map(() => "?").join(",")})`,
1106
+ [...values, ...chunk]
1107
+ );
1108
+ count += result.changes;
1109
+ }
1110
+ return count;
1136
1111
  }
1137
1112
  bulkDeleteMemories(ids) {
1138
1113
  if (ids.length === 0) return 0;
1139
- const deleteMany = this.db.transaction((ids2) => {
1140
- let count = 0;
1141
- const chunkSize = 500;
1142
- for (let i = 0; i < ids2.length; i += chunkSize) {
1143
- const chunk = ids2.slice(i, i + chunkSize);
1144
- const stmt = this.db.prepare(`DELETE FROM memories WHERE id IN (${chunk.map(() => "?").join(",")})`);
1145
- const result = stmt.run(...chunk);
1146
- count += result.changes;
1147
- }
1148
- return count;
1149
- });
1150
- return deleteMany(ids);
1114
+ let count = 0;
1115
+ const chunkSize = 500;
1116
+ for (let i = 0; i < ids.length; i += chunkSize) {
1117
+ const chunk = ids.slice(i, i + chunkSize);
1118
+ const result = this.run(`DELETE FROM memories WHERE id IN (${chunk.map(() => "?").join(",")})`, chunk);
1119
+ count += result.changes;
1120
+ }
1121
+ return count;
1151
1122
  }
1152
1123
  getRecentMemories(repo, limit, offset = 0, includeArchived = false, excludeTypes = []) {
1153
1124
  let query = "SELECT * FROM memories WHERE repo = ?";
@@ -1161,7 +1132,7 @@ var MemoryEntity = class extends BaseEntity {
1161
1132
  }
1162
1133
  query += " ORDER BY created_at DESC LIMIT ? OFFSET ?";
1163
1134
  params.push(limit, offset);
1164
- const rows = this.db.prepare(query).all(...params);
1135
+ const rows = this.all(query, params);
1165
1136
  return rows.map((row) => this.rowToMemoryEntry(row));
1166
1137
  }
1167
1138
  getTotalCount(repo, includeArchived = false, excludeTypes = []) {
@@ -1172,25 +1143,27 @@ var MemoryEntity = class extends BaseEntity {
1172
1143
  sql += ` AND type NOT IN (${excludeTypes.map(() => "?").join(",")})`;
1173
1144
  params.push(...excludeTypes);
1174
1145
  }
1175
- const row = this.db.prepare(sql).get(...params);
1176
- return row.count;
1146
+ const row = this.get(sql, params);
1147
+ return row?.count ?? 0;
1177
1148
  }
1178
1149
  incrementHitCount(id) {
1179
- this.db.prepare("UPDATE memories SET hit_count = hit_count + 1, last_used_at = ? WHERE id = ?").run((/* @__PURE__ */ new Date()).toISOString(), id);
1150
+ this.run("UPDATE memories SET hit_count = hit_count + 1, last_used_at = ? WHERE id = ?", [
1151
+ (/* @__PURE__ */ new Date()).toISOString(),
1152
+ id
1153
+ ]);
1180
1154
  }
1181
1155
  incrementHitCounts(ids) {
1182
1156
  if (!ids || ids.length === 0) return;
1183
- const stmt = this.db.prepare("UPDATE memories SET hit_count = hit_count + 1, last_used_at = ? WHERE id = ?");
1184
1157
  const now = (/* @__PURE__ */ new Date()).toISOString();
1185
- const transaction = this.db.transaction((idsToUpdate) => {
1186
- for (const id of idsToUpdate) {
1187
- stmt.run(now, id);
1188
- }
1189
- });
1190
- transaction(ids);
1158
+ for (const id of ids) {
1159
+ this.run("UPDATE memories SET hit_count = hit_count + 1, last_used_at = ? WHERE id = ?", [now, id]);
1160
+ }
1191
1161
  }
1192
1162
  incrementRecallCount(id) {
1193
- this.db.prepare("UPDATE memories SET recall_count = recall_count + 1, last_used_at = ? WHERE id = ?").run((/* @__PURE__ */ new Date()).toISOString(), id);
1163
+ this.run("UPDATE memories SET recall_count = recall_count + 1, last_used_at = ? WHERE id = ?", [
1164
+ (/* @__PURE__ */ new Date()).toISOString(),
1165
+ id
1166
+ ]);
1194
1167
  }
1195
1168
  getVectorCandidates(repo, limit = 100) {
1196
1169
  let sql = `SELECT mv.memory_id, mv.vector FROM memory_vectors mv JOIN memories m ON mv.memory_id = m.id`;
@@ -1201,41 +1174,38 @@ var MemoryEntity = class extends BaseEntity {
1201
1174
  }
1202
1175
  sql += " LIMIT ?";
1203
1176
  params.push(limit);
1204
- return this.db.prepare(sql).all(...params);
1177
+ return this.all(sql, params);
1205
1178
  }
1206
1179
  upsertVectorEmbedding(memoryId, vector) {
1207
- this.db.prepare(
1208
- `
1209
- INSERT INTO memory_vectors (memory_id, vector, updated_at) VALUES (?, ?, ?)
1210
- ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, updated_at = excluded.updated_at
1211
- `
1212
- ).run(memoryId, JSON.stringify(vector), (/* @__PURE__ */ new Date()).toISOString());
1180
+ this.run(
1181
+ `INSERT INTO memory_vectors (memory_id, vector, updated_at) VALUES (?, ?, ?)
1182
+ ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, updated_at = excluded.updated_at`,
1183
+ [memoryId, JSON.stringify(vector), (/* @__PURE__ */ new Date()).toISOString()]
1184
+ );
1213
1185
  }
1214
1186
  getSummary(repo) {
1215
- const row = this.db.prepare("SELECT summary, updated_at FROM memory_summary WHERE repo = ?").get(repo);
1187
+ const row = this.get(
1188
+ "SELECT summary, updated_at FROM memory_summary WHERE repo = ?",
1189
+ [repo]
1190
+ );
1216
1191
  return row;
1217
1192
  }
1218
1193
  getAllMemoriesWithStats(repo) {
1219
- const rows = this.db.prepare(
1220
- `
1221
- SELECT *, CASE WHEN hit_count > 0 THEN CAST(recall_count AS REAL) / hit_count ELSE 0 END AS recall_rate
1222
- FROM memories
1223
- WHERE repo = ?
1224
- ORDER BY created_at DESC
1225
- `
1226
- ).all(repo);
1194
+ const rows = this.all(
1195
+ `SELECT *, CASE WHEN hit_count > 0 THEN CAST(recall_count AS REAL) / hit_count ELSE 0 END AS recall_rate FROM memories WHERE repo = ? ORDER BY created_at DESC`,
1196
+ [repo]
1197
+ );
1227
1198
  return rows.map((row) => ({
1228
1199
  ...this.rowToMemoryEntry(row),
1229
1200
  recall_rate: row.recall_rate || 0
1230
1201
  }));
1231
1202
  }
1232
1203
  upsertSummary(repo, summary) {
1233
- this.db.prepare(
1234
- `
1235
- INSERT INTO memory_summary (repo, summary, updated_at) VALUES (?, ?, ?)
1236
- ON CONFLICT(repo) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at
1237
- `
1238
- ).run(repo, summary, (/* @__PURE__ */ new Date()).toISOString());
1204
+ this.run(
1205
+ `INSERT INTO memory_summary (repo, summary, updated_at) VALUES (?, ?, ?)
1206
+ ON CONFLICT(repo) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at`,
1207
+ [repo, summary, (/* @__PURE__ */ new Date()).toISOString()]
1208
+ );
1239
1209
  }
1240
1210
  listMemoriesForDashboard(options) {
1241
1211
  const {
@@ -1282,9 +1252,10 @@ ORDER BY created_at DESC
1282
1252
  params.push(`%${search}%`, `%${search}%`);
1283
1253
  }
1284
1254
  const countSql = `SELECT COUNT(*) as count FROM memories WHERE ${where.join(" AND ")}`;
1285
- const total = this.db.prepare(countSql).get(...params).count;
1255
+ const totalRow = this.get(countSql, params);
1256
+ const total = totalRow?.count ?? 0;
1286
1257
  const dataSql = `SELECT *, CASE WHEN hit_count > 0 THEN CAST(recall_count AS REAL) / hit_count ELSE 0 END AS recall_rate FROM memories WHERE ${where.join(" AND ")} ORDER BY ${sortBy} ${sortOrder} LIMIT ? OFFSET ?`;
1287
- const rows = this.db.prepare(dataSql).all(...params, limit, offset);
1258
+ const rows = this.all(dataSql, [...params, limit, offset]);
1288
1259
  const items = rows.map((row) => ({
1289
1260
  ...this.rowToMemoryEntry(row),
1290
1261
  recall_rate: row.recall_rate || 0
@@ -1304,10 +1275,10 @@ ORDER BY created_at DESC
1304
1275
  let sql = `SELECT * FROM memories WHERE (${where.join(" AND ")}) AND (expires_at IS NULL OR expires_at > ?)`;
1305
1276
  if (!includeArchived) sql += " AND status = 'active'";
1306
1277
  sql += ` ORDER BY CASE WHEN repo = ? THEN 0 ELSE 1 END, importance DESC, created_at DESC LIMIT 100`;
1307
- const candidates = this.db.prepare(sql).all(...params, now.toISOString(), repo);
1278
+ const candidates = this.all(sql, [...params, now.toISOString(), repo]);
1308
1279
  if (candidates.length < 5) {
1309
1280
  const recentSql = `SELECT * FROM memories WHERE (${where.join(" OR ")}) AND status = 'active' AND (expires_at IS NULL OR expires_at > ?) ORDER BY created_at DESC LIMIT 10`;
1310
- const recent = this.db.prepare(recentSql).all(...params, now.toISOString());
1281
+ const recent = this.all(recentSql, [...params, now.toISOString()]);
1311
1282
  for (const r of recent) {
1312
1283
  if (!candidates.find((c) => c.id === r.id)) candidates.push(r);
1313
1284
  }
@@ -1338,25 +1309,21 @@ ORDER BY created_at DESC
1338
1309
  archiveExpiredMemories(force = false) {
1339
1310
  if (process.env.ENABLE_AUTO_ARCHIVE !== "true" && !force) return 0;
1340
1311
  const now = (/* @__PURE__ */ new Date()).toISOString();
1341
- const result = this.db.prepare(
1342
- `
1343
- UPDATE memories SET status = 'archived', updated_at = ?
1344
- WHERE expires_at IS NOT NULL AND expires_at <= ? AND status = 'active'
1345
- `
1346
- ).run(now, now);
1312
+ const result = this.run(
1313
+ `UPDATE memories SET status = 'archived', updated_at = ? WHERE expires_at IS NOT NULL AND expires_at <= ? AND status = 'active'`,
1314
+ [now, now]
1315
+ );
1347
1316
  return result.changes;
1348
1317
  }
1349
1318
  archiveLowScoreMemories(force = false) {
1350
1319
  if (process.env.ENABLE_AUTO_ARCHIVE !== "true" && !force) return 0;
1351
- const result = this.db.prepare(
1352
- `
1353
- UPDATE memories SET status = 'archived', updated_at = ?
1354
- WHERE status = 'active' AND (
1355
- (julianday('now') - julianday(COALESCE(last_used_at, created_at)) > 90 AND importance < 3)
1356
- OR (hit_count > 10 AND recall_count = 0)
1357
- )
1358
- `
1359
- ).run((/* @__PURE__ */ new Date()).toISOString());
1320
+ const result = this.run(
1321
+ `UPDATE memories SET status = 'archived', updated_at = ? WHERE status = 'active' AND (
1322
+ (julianday('now') - julianday(COALESCE(last_used_at, created_at)) > 90 AND importance < 3)
1323
+ OR (hit_count > 10 AND recall_count = 0)
1324
+ )`,
1325
+ [(/* @__PURE__ */ new Date()).toISOString()]
1326
+ );
1360
1327
  return result.changes;
1361
1328
  }
1362
1329
  };
@@ -1364,34 +1331,34 @@ ORDER BY created_at DESC
1364
1331
  // src/mcp/entities/task.ts
1365
1332
  var TaskEntity = class extends BaseEntity {
1366
1333
  insertTask(task) {
1367
- const stmt = this.db.prepare(`
1368
- INSERT INTO tasks (
1369
- id, repo, task_code, phase, title, description, status, priority,
1370
- agent, role, doc_path, created_at, updated_at, finished_at, canceled_at, tags, metadata, parent_id, depends_on, est_tokens, in_progress_at
1371
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1372
- `);
1373
- stmt.run(
1374
- task.id,
1375
- task.repo,
1376
- task.task_code,
1377
- task.phase || null,
1378
- task.title,
1379
- task.description || null,
1380
- task.status || "backlog",
1381
- task.priority || 3,
1382
- task.agent || "unknown",
1383
- task.role || "unknown",
1384
- task.doc_path || null,
1385
- task.created_at,
1386
- task.updated_at,
1387
- task.finished_at || null,
1388
- task.canceled_at || null,
1389
- task.tags ? JSON.stringify(task.tags) : null,
1390
- task.metadata ? JSON.stringify(task.metadata) : null,
1391
- task.parent_id || null,
1392
- task.depends_on || null,
1393
- task.est_tokens || 0,
1394
- task.in_progress_at || null
1334
+ this.run(
1335
+ `INSERT INTO tasks (
1336
+ id, repo, task_code, phase, title, description, status, priority,
1337
+ agent, role, doc_path, created_at, updated_at, finished_at, canceled_at, tags, metadata, parent_id, depends_on, est_tokens, in_progress_at
1338
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1339
+ [
1340
+ task.id,
1341
+ task.repo,
1342
+ task.task_code,
1343
+ task.phase || null,
1344
+ task.title,
1345
+ task.description || null,
1346
+ task.status || "backlog",
1347
+ task.priority || 3,
1348
+ task.agent || "unknown",
1349
+ task.role || "unknown",
1350
+ task.doc_path || null,
1351
+ task.created_at,
1352
+ task.updated_at,
1353
+ task.finished_at || null,
1354
+ task.canceled_at || null,
1355
+ task.tags ? JSON.stringify(task.tags) : null,
1356
+ task.metadata ? JSON.stringify(task.metadata) : null,
1357
+ task.parent_id || null,
1358
+ task.depends_on || null,
1359
+ task.est_tokens || 0,
1360
+ task.in_progress_at || null
1361
+ ]
1395
1362
  );
1396
1363
  }
1397
1364
  updateTask(id, updates) {
@@ -1413,43 +1380,34 @@ var TaskEntity = class extends BaseEntity {
1413
1380
  fields.push("updated_at = ?");
1414
1381
  values.push((/* @__PURE__ */ new Date()).toISOString());
1415
1382
  values.push(id);
1416
- const stmt = this.db.prepare(`UPDATE tasks SET ${fields.join(", ")} WHERE id = ?`);
1417
- stmt.run(...values);
1383
+ this.run(`UPDATE tasks SET ${fields.join(", ")} WHERE id = ?`, values);
1418
1384
  }
1419
1385
  deleteTask(id) {
1420
- this.db.prepare("DELETE FROM task_comments WHERE task_id = ?").run(id);
1421
- this.db.prepare("DELETE FROM tasks WHERE id = ?").run(id);
1386
+ this.run("DELETE FROM task_comments WHERE task_id = ?", [id]);
1387
+ this.run("DELETE FROM tasks WHERE id = ?", [id]);
1422
1388
  }
1423
1389
  getTaskById(id) {
1424
- const row = this.db.prepare(
1425
- `
1426
- SELECT t.*, d.task_code as depends_on_code
1427
- FROM tasks t
1428
- LEFT JOIN tasks d ON t.depends_on = d.id
1429
- WHERE t.id = ?
1430
- `
1431
- ).get(id);
1390
+ const row = this.get(
1391
+ `SELECT t.*, d.task_code as depends_on_code FROM tasks t LEFT JOIN tasks d ON t.depends_on = d.id WHERE t.id = ?`,
1392
+ [id]
1393
+ );
1432
1394
  return row ? { ...this.rowToTask(row), comments: this.getTaskCommentsByTaskId(id) } : null;
1433
1395
  }
1434
1396
  getTaskByCode(repo, taskCode) {
1435
- const row = this.db.prepare(
1436
- `
1437
- SELECT t.*, d.task_code as depends_on_code
1438
- FROM tasks t
1439
- LEFT JOIN tasks d ON t.depends_on = d.id
1440
- WHERE t.repo = ? AND t.task_code = ?
1441
- `
1442
- ).get(repo, taskCode);
1397
+ const row = this.get(
1398
+ `SELECT t.*, d.task_code as depends_on_code FROM tasks t LEFT JOIN tasks d ON t.depends_on = d.id WHERE t.repo = ? AND t.task_code = ?`,
1399
+ [repo, taskCode]
1400
+ );
1443
1401
  return row ? { ...this.rowToTask(row), comments: this.getTaskCommentsByTaskId(row.id) } : null;
1444
1402
  }
1445
1403
  getTasksByRepo(repo, status, limit, offset, search) {
1446
1404
  let query = `
1447
- SELECT t.*, d.task_code as depends_on_code,
1448
- (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1449
- FROM tasks t
1450
- LEFT JOIN tasks d ON t.depends_on = d.id
1451
- WHERE t.repo = ?
1452
- `;
1405
+ SELECT t.*, d.task_code as depends_on_code,
1406
+ (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1407
+ FROM tasks t
1408
+ LEFT JOIN tasks d ON t.depends_on = d.id
1409
+ WHERE t.repo = ?
1410
+ `;
1453
1411
  const params = [repo];
1454
1412
  if (status) {
1455
1413
  query += " AND t.status = ?";
@@ -1461,16 +1419,16 @@ var TaskEntity = class extends BaseEntity {
1461
1419
  params.push(searchPattern, searchPattern, searchPattern);
1462
1420
  }
1463
1421
  query += ` ORDER BY
1464
- CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1465
- CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1466
- CASE WHEN t.status = 'in_progress' THEN 0
1467
- WHEN t.status = 'pending' THEN 1
1468
- WHEN t.status = 'backlog' THEN 2
1469
- WHEN t.status = 'blocked' THEN 3
1470
- WHEN t.status = 'canceled' THEN 4
1471
- ELSE 5 END ASC,
1472
- t.priority DESC,
1473
- t.created_at ASC`;
1422
+ CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1423
+ CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1424
+ CASE WHEN t.status = 'in_progress' THEN 0
1425
+ WHEN t.status = 'pending' THEN 1
1426
+ WHEN t.status = 'backlog' THEN 2
1427
+ WHEN t.status = 'blocked' THEN 3
1428
+ WHEN t.status = 'canceled' THEN 4
1429
+ ELSE 5 END ASC,
1430
+ t.priority DESC,
1431
+ t.created_at ASC`;
1474
1432
  if (limit !== void 0) {
1475
1433
  query += " LIMIT ?";
1476
1434
  params.push(limit);
@@ -1479,40 +1437,40 @@ var TaskEntity = class extends BaseEntity {
1479
1437
  params.push(offset);
1480
1438
  }
1481
1439
  }
1482
- const rows = this.db.prepare(query).all(...params);
1440
+ const rows = this.all(query, params);
1483
1441
  return rows.map((r) => this.rowToTask(r));
1484
1442
  }
1485
1443
  listRecentTasks(limit = 50, offset = 0) {
1486
1444
  const query = `
1487
- SELECT t.*, d.task_code as depends_on_code,
1488
- (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1489
- FROM tasks t
1490
- LEFT JOIN tasks d ON t.depends_on = d.id
1491
- ORDER BY
1492
- CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1493
- CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1494
- CASE WHEN t.status = 'in_progress' THEN 0
1495
- WHEN t.status = 'pending' THEN 1
1496
- WHEN t.status = 'backlog' THEN 2
1497
- WHEN t.status = 'blocked' THEN 3
1498
- WHEN t.status = 'canceled' THEN 4
1499
- ELSE 5 END ASC,
1500
- t.priority DESC,
1501
- t.created_at ASC
1502
- LIMIT ? OFFSET ?
1503
- `;
1504
- const rows = this.db.prepare(query).all(limit, offset);
1445
+ SELECT t.*, d.task_code as depends_on_code,
1446
+ (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1447
+ FROM tasks t
1448
+ LEFT JOIN tasks d ON t.depends_on = d.id
1449
+ ORDER BY
1450
+ CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1451
+ CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1452
+ CASE WHEN t.status = 'in_progress' THEN 0
1453
+ WHEN t.status = 'pending' THEN 1
1454
+ WHEN t.status = 'backlog' THEN 2
1455
+ WHEN t.status = 'blocked' THEN 3
1456
+ WHEN t.status = 'canceled' THEN 4
1457
+ ELSE 5 END ASC,
1458
+ t.priority DESC,
1459
+ t.created_at ASC
1460
+ LIMIT ? OFFSET ?
1461
+ `;
1462
+ const rows = this.all(query, [limit, offset]);
1505
1463
  return rows.map((r) => this.rowToTask(r));
1506
1464
  }
1507
1465
  getTasksByMultipleStatuses(repo, statuses, limit, offset, search) {
1508
1466
  if (!statuses.length) return this.getTasksByRepo(repo, void 0, limit, offset, search);
1509
1467
  let query = `
1510
- SELECT t.*, d.task_code as depends_on_code,
1511
- (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1512
- FROM tasks t
1513
- LEFT JOIN tasks d ON t.depends_on = d.id
1514
- WHERE t.repo = ? AND t.status IN (${statuses.map(() => "?").join(",")})
1515
- `;
1468
+ SELECT t.*, d.task_code as depends_on_code,
1469
+ (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1470
+ FROM tasks t
1471
+ LEFT JOIN tasks d ON t.depends_on = d.id
1472
+ WHERE t.repo = ? AND t.status IN (${statuses.map(() => "?").join(",")})
1473
+ `;
1516
1474
  const params = [repo, ...statuses];
1517
1475
  if (search) {
1518
1476
  query += " AND (t.title LIKE ? OR t.description LIKE ? OR t.task_code LIKE ?)";
@@ -1520,16 +1478,16 @@ var TaskEntity = class extends BaseEntity {
1520
1478
  params.push(searchPattern, searchPattern, searchPattern);
1521
1479
  }
1522
1480
  query += ` ORDER BY
1523
- CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1524
- CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1525
- CASE WHEN t.status = 'in_progress' THEN 0
1526
- WHEN t.status = 'pending' THEN 1
1527
- WHEN t.status = 'backlog' THEN 2
1528
- WHEN t.status = 'blocked' THEN 3
1529
- WHEN t.status = 'canceled' THEN 4
1530
- ELSE 5 END ASC,
1531
- t.priority DESC,
1532
- t.created_at ASC`;
1481
+ CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END ASC,
1482
+ CASE WHEN t.status = 'completed' THEN t.updated_at ELSE NULL END DESC,
1483
+ CASE WHEN t.status = 'in_progress' THEN 0
1484
+ WHEN t.status = 'pending' THEN 1
1485
+ WHEN t.status = 'backlog' THEN 2
1486
+ WHEN t.status = 'blocked' THEN 3
1487
+ WHEN t.status = 'canceled' THEN 4
1488
+ ELSE 5 END ASC,
1489
+ t.priority DESC,
1490
+ t.created_at ASC`;
1533
1491
  if (limit !== void 0) {
1534
1492
  query += " LIMIT ?";
1535
1493
  params.push(limit);
@@ -1538,7 +1496,7 @@ var TaskEntity = class extends BaseEntity {
1538
1496
  params.push(offset);
1539
1497
  }
1540
1498
  }
1541
- const rows = this.db.prepare(query).all(...params);
1499
+ const rows = this.all(query, params);
1542
1500
  return rows.map((r) => this.rowToTask(r));
1543
1501
  }
1544
1502
  isTaskCodeDuplicate(repo, task_code, excludeId) {
@@ -1548,20 +1506,18 @@ var TaskEntity = class extends BaseEntity {
1548
1506
  query += " AND id != ?";
1549
1507
  params.push(excludeId);
1550
1508
  }
1551
- const row = this.db.prepare(query).get(...params);
1552
- return row.count > 0;
1509
+ const row = this.get(query, params);
1510
+ return (row?.count ?? 0) > 0;
1553
1511
  }
1554
1512
  bulkInsertTasks(tasks) {
1555
- const insert = this.db.prepare(`
1556
- INSERT INTO tasks (
1557
- id, repo, task_code, phase, title, description, status, priority,
1558
- agent, role, doc_path, created_at, updated_at, finished_at, canceled_at, tags, metadata, parent_id, depends_on, est_tokens, in_progress_at
1559
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1560
- `);
1561
- const insertMany = this.db.transaction((tasks2) => {
1562
- let count = 0;
1563
- for (const task of tasks2) {
1564
- insert.run(
1513
+ let count = 0;
1514
+ for (const task of tasks) {
1515
+ this.run(
1516
+ `INSERT INTO tasks (
1517
+ id, repo, task_code, phase, title, description, status, priority,
1518
+ agent, role, doc_path, created_at, updated_at, finished_at, canceled_at, tags, metadata, parent_id, depends_on, est_tokens, in_progress_at
1519
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1520
+ [
1565
1521
  task.id,
1566
1522
  task.repo,
1567
1523
  task.task_code,
@@ -1583,31 +1539,29 @@ var TaskEntity = class extends BaseEntity {
1583
1539
  task.depends_on || null,
1584
1540
  task.est_tokens || 0,
1585
1541
  task.in_progress_at || null
1586
- );
1587
- count++;
1588
- }
1589
- return count;
1590
- });
1591
- return insertMany(tasks);
1542
+ ]
1543
+ );
1544
+ count++;
1545
+ }
1546
+ return count;
1592
1547
  }
1593
1548
  insertTaskComment(comment) {
1594
- this.db.prepare(
1595
- `
1596
- INSERT INTO task_comments (
1597
- id, task_id, repo, comment, agent, role, model, previous_status, next_status, created_at
1598
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1599
- `
1600
- ).run(
1601
- comment.id,
1602
- comment.task_id,
1603
- comment.repo,
1604
- comment.comment,
1605
- comment.agent || "unknown",
1606
- comment.role || "unknown",
1607
- comment.model || "unknown",
1608
- comment.previous_status || null,
1609
- comment.next_status || null,
1610
- comment.created_at
1549
+ this.run(
1550
+ `INSERT INTO task_comments (
1551
+ id, task_id, repo, comment, agent, role, model, previous_status, next_status, created_at
1552
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1553
+ [
1554
+ comment.id,
1555
+ comment.task_id,
1556
+ comment.repo,
1557
+ comment.comment,
1558
+ comment.agent || "unknown",
1559
+ comment.role || "unknown",
1560
+ comment.model || "unknown",
1561
+ comment.previous_status || null,
1562
+ comment.next_status || null,
1563
+ comment.created_at
1564
+ ]
1611
1565
  );
1612
1566
  }
1613
1567
  updateTaskComment(id, updates) {
@@ -1622,35 +1576,29 @@ var TaskEntity = class extends BaseEntity {
1622
1576
  });
1623
1577
  if (fields.length === 0) return;
1624
1578
  values.push(id);
1625
- const stmt = this.db.prepare(`UPDATE task_comments SET ${fields.join(", ")} WHERE id = ?`);
1626
- stmt.run(...values);
1579
+ this.run(`UPDATE task_comments SET ${fields.join(", ")} WHERE id = ?`, values);
1627
1580
  }
1628
1581
  deleteTaskComment(id) {
1629
- this.db.prepare("DELETE FROM task_comments WHERE id = ?").run(id);
1582
+ this.run("DELETE FROM task_comments WHERE id = ?", [id]);
1630
1583
  }
1631
1584
  getTaskCommentById(id) {
1632
- return this.db.prepare("SELECT * FROM task_comments WHERE id = ?").get(id);
1585
+ return this.get("SELECT * FROM task_comments WHERE id = ?", [id]) ?? null;
1633
1586
  }
1634
1587
  getTaskCommentsByTaskId(taskId) {
1635
- return this.db.prepare(
1636
- `
1637
- SELECT * FROM task_comments
1638
- WHERE task_id = ?
1639
- ORDER BY created_at DESC, id DESC
1640
- `
1641
- ).all(taskId);
1588
+ return this.all(`SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at DESC, id DESC`, [
1589
+ taskId
1590
+ ]);
1642
1591
  }
1643
1592
  getAllTaskCommentsByRepo(repo) {
1644
- return this.db.prepare(
1645
- `
1646
- SELECT * FROM task_comments
1647
- WHERE repo = ?
1648
- ORDER BY created_at DESC, id DESC
1649
- `
1650
- ).all(repo);
1593
+ return this.all(`SELECT * FROM task_comments WHERE repo = ? ORDER BY created_at DESC, id DESC`, [
1594
+ repo
1595
+ ]);
1651
1596
  }
1652
1597
  getTaskStats(repo) {
1653
- const rows = this.db.prepare("SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status").all(repo);
1598
+ const rows = this.all(
1599
+ "SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status",
1600
+ [repo]
1601
+ );
1654
1602
  const stats = { total: 0, backlog: 0, todo: 0, inProgress: 0, completed: 0, blocked: 0, canceled: 0 };
1655
1603
  rows.forEach((r) => {
1656
1604
  const count = r.count;
@@ -1670,35 +1618,30 @@ var TaskEntity = class extends BaseEntity {
1670
1618
  else if (period === "weekly") dateFilter = "AND date(COALESCE(finished_at, updated_at)) >= date('now', '-7 days')";
1671
1619
  else if (period === "monthly")
1672
1620
  dateFilter = "AND date(COALESCE(finished_at, updated_at)) >= date('now', '-30 days')";
1673
- const stats = this.db.prepare(
1674
- `
1675
- SELECT
1676
- COUNT(*) as completed_count,
1677
- SUM(est_tokens) as total_tokens,
1678
- AVG(
1679
- CASE
1680
- WHEN in_progress_at IS NOT NULL AND finished_at IS NOT NULL
1681
- THEN (julianday(finished_at) - julianday(in_progress_at)) * 86400.0
1682
- ELSE NULL
1683
- END
1684
- ) as avg_duration_seconds
1685
- FROM tasks
1686
- WHERE repo = ?
1687
- AND status = 'completed'
1688
- ${dateFilter}
1689
- `
1690
- ).get(repo);
1621
+ const stats = this.get(
1622
+ `SELECT
1623
+ COUNT(*) as completed_count,
1624
+ SUM(est_tokens) as total_tokens,
1625
+ AVG(
1626
+ CASE
1627
+ WHEN in_progress_at IS NOT NULL AND finished_at IS NOT NULL
1628
+ THEN (julianday(finished_at) - julianday(in_progress_at)) * 86400.0
1629
+ ELSE NULL
1630
+ END
1631
+ ) as avg_duration_seconds
1632
+ FROM tasks
1633
+ WHERE repo = ?
1634
+ AND status = 'completed'
1635
+ ${dateFilter}`,
1636
+ [repo]
1637
+ );
1691
1638
  let addedDateFilter = "";
1692
1639
  if (period === "daily") addedDateFilter = "AND date(created_at) = date('now')";
1693
1640
  else if (period === "weekly") addedDateFilter = "AND date(created_at) >= date('now', '-7 days')";
1694
1641
  else if (period === "monthly") addedDateFilter = "AND date(created_at) >= date('now', '-30 days')";
1695
- const added = this.db.prepare(
1696
- `
1697
- SELECT COUNT(*) as count FROM tasks
1698
- WHERE repo = ?
1699
- ${addedDateFilter}
1700
- `
1701
- ).get(repo);
1642
+ const added = this.get(`SELECT COUNT(*) as count FROM tasks WHERE repo = ? ${addedDateFilter}`, [
1643
+ repo
1644
+ ]);
1702
1645
  return {
1703
1646
  completed: stats?.completed_count || 0,
1704
1647
  tokens: stats?.total_tokens || 0,
@@ -1723,33 +1666,31 @@ var TaskEntity = class extends BaseEntity {
1723
1666
  dateFilter = "1=1";
1724
1667
  }
1725
1668
  const query = `
1726
- SELECT label, SUM(created) as created, SUM(completed) as completed
1727
- FROM (
1728
- SELECT strftime(?, created_at) as label, 1 as created, 0 as completed
1729
- FROM tasks
1730
- WHERE repo = ? AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "created_at")}
1731
- UNION ALL
1732
- SELECT strftime(?, COALESCE(finished_at, updated_at)) as label, 0 as created, 1 as completed
1733
- FROM tasks
1734
- WHERE repo = ? AND status = 'completed' AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "COALESCE(finished_at, updated_at)")}
1735
- )
1736
- GROUP BY label
1737
- ORDER BY label ASC
1738
- LIMIT 100
1739
- `;
1740
- return this.db.prepare(query).all(labelFormat, repo, labelFormat, repo);
1669
+ SELECT label, SUM(created) as created, SUM(completed) as completed
1670
+ FROM (
1671
+ SELECT strftime(?, created_at) as label, 1 as created, 0 as completed
1672
+ FROM tasks
1673
+ WHERE repo = ? AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "created_at")}
1674
+ UNION ALL
1675
+ SELECT strftime(?, COALESCE(finished_at, updated_at)) as label, 0 as created, 1 as completed
1676
+ FROM tasks
1677
+ WHERE repo = ? AND status = 'completed' AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "COALESCE(finished_at, updated_at)")}
1678
+ )
1679
+ GROUP BY label
1680
+ ORDER BY label ASC
1681
+ LIMIT 100
1682
+ `;
1683
+ return this.all(query, [
1684
+ labelFormat,
1685
+ repo,
1686
+ labelFormat,
1687
+ repo
1688
+ ]);
1741
1689
  }
1742
1690
  };
1743
1691
 
1744
1692
  // src/mcp/entities/action.ts
1745
1693
  var ActionEntity = class extends BaseEntity {
1746
- constructor(db) {
1747
- super(db);
1748
- }
1749
- /**
1750
- * Log an action to the audit trail.
1751
- * Supports both object-based options (modern) and positional arguments (legacy/internal).
1752
- */
1753
1694
  logAction(action, repo, optionsOrQuery, response, memoryId, taskId, resultCount = 0) {
1754
1695
  let query = typeof optionsOrQuery === "string" ? optionsOrQuery : void 0;
1755
1696
  let finalResponse = response;
@@ -1764,39 +1705,38 @@ var ActionEntity = class extends BaseEntity {
1764
1705
  finalTaskId = optionsOrQuery.taskId || finalTaskId;
1765
1706
  finalResultCount = optionsOrQuery.resultCount !== void 0 ? optionsOrQuery.resultCount : finalResultCount;
1766
1707
  }
1767
- const stmt = this.db.prepare(`
1768
- INSERT INTO action_log (repo, action, query, response, memory_id, task_id, result_count, created_at)
1769
- VALUES (:repo, :action, :query, :response, :memory_id, :task_id, :result_count, :created_at)
1770
- `);
1771
- stmt.run({
1772
- repo: repo || "",
1773
- action: action || "unknown",
1774
- query: query || null,
1775
- response: finalResponse ? typeof finalResponse === "string" ? finalResponse : JSON.stringify(finalResponse) : null,
1776
- memory_id: finalMemoryId || null,
1777
- task_id: finalTaskId || null,
1778
- result_count: finalResultCount ?? 0,
1779
- created_at: (/* @__PURE__ */ new Date()).toISOString()
1780
- });
1708
+ this.run(
1709
+ `INSERT INTO action_log (repo, action, query, response, memory_id, task_id, result_count, created_at)
1710
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
1711
+ [
1712
+ repo || "",
1713
+ action || "unknown",
1714
+ query || null,
1715
+ finalResponse ? typeof finalResponse === "string" ? finalResponse : JSON.stringify(finalResponse) : null,
1716
+ finalMemoryId || null,
1717
+ finalTaskId || null,
1718
+ finalResultCount ?? 0,
1719
+ (/* @__PURE__ */ new Date()).toISOString()
1720
+ ]
1721
+ );
1781
1722
  }
1782
1723
  getLastActionId() {
1783
- const row = this.db.prepare("SELECT MAX(id) as id FROM action_log").get();
1724
+ const row = this.get("SELECT MAX(id) as id FROM action_log");
1784
1725
  return row?.id || 0;
1785
1726
  }
1786
1727
  getActionsAfter(id) {
1787
- return this.db.prepare(
1788
- `
1789
- SELECT a.*, m.title as memory_title, m.type as memory_type
1790
- FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1791
- WHERE a.id > ? ORDER BY a.created_at ASC
1792
- `
1793
- ).all(id);
1728
+ return this.all(
1729
+ `SELECT a.*, m.title as memory_title, m.type as memory_type
1730
+ FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1731
+ WHERE a.id > ? ORDER BY a.created_at ASC`,
1732
+ [id]
1733
+ );
1794
1734
  }
1795
1735
  getRecentActions(repo, limit = 10, offset = 0) {
1796
1736
  let query = `
1797
- SELECT a.*, m.title as memory_title, m.type as memory_type
1798
- FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1799
- `;
1737
+ SELECT a.*, m.title as memory_title, m.type as memory_type
1738
+ FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1739
+ `;
1800
1740
  const params = [];
1801
1741
  if (repo) {
1802
1742
  query += " WHERE a.repo = ?";
@@ -1804,69 +1744,81 @@ var ActionEntity = class extends BaseEntity {
1804
1744
  }
1805
1745
  query += " ORDER BY a.created_at DESC, a.id DESC LIMIT ? OFFSET ?";
1806
1746
  params.push(limit, offset);
1807
- return this.db.prepare(query).all(...params);
1747
+ return this.all(query, params);
1808
1748
  }
1809
1749
  getActionStatsByDate(repo) {
1810
- return this.db.prepare(
1811
- `
1812
- SELECT date(created_at) as date, count(*) as count
1813
- FROM action_log
1814
- WHERE repo = ? AND created_at > date('now', '-30 days')
1815
- GROUP BY date(created_at)
1816
- ORDER BY date ASC
1817
- `
1818
- ).all(repo);
1750
+ return this.all(
1751
+ `SELECT date(created_at) as date, count(*) as count
1752
+ FROM action_log
1753
+ WHERE repo = ? AND created_at > date('now', '-30 days')
1754
+ GROUP BY date(created_at)
1755
+ ORDER BY date ASC`,
1756
+ [repo]
1757
+ );
1819
1758
  }
1820
1759
  getActionDistribution(repo) {
1821
- return this.db.prepare(
1822
- `
1823
- SELECT action, count(*) as count
1824
- FROM action_log
1825
- WHERE repo = ?
1826
- GROUP BY action
1827
- `
1828
- ).all(repo);
1760
+ return this.all(
1761
+ `SELECT action, count(*) as count
1762
+ FROM action_log
1763
+ WHERE repo = ?
1764
+ GROUP BY action`,
1765
+ [repo]
1766
+ );
1829
1767
  }
1830
1768
  getActionById(id) {
1831
- return this.db.prepare(
1832
- `
1833
- SELECT a.*, m.title as memory_title, m.type as memory_type
1834
- FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1835
- WHERE a.id = ?
1836
- `
1837
- ).get(id);
1769
+ return this.get(
1770
+ `SELECT a.*, m.title as memory_title, m.type as memory_type
1771
+ FROM action_log a LEFT JOIN memories m ON a.memory_id = m.id
1772
+ WHERE a.id = ?`,
1773
+ [id]
1774
+ );
1838
1775
  }
1839
1776
  };
1840
1777
 
1841
1778
  // src/mcp/entities/system.ts
1842
1779
  var SystemEntity = class extends BaseEntity {
1843
1780
  listRepos() {
1844
- const rows = this.db.prepare("SELECT DISTINCT repo FROM memories UNION SELECT DISTINCT repo FROM tasks").all();
1781
+ const rows = this.all("SELECT DISTINCT repo FROM memories UNION SELECT DISTINCT repo FROM tasks");
1845
1782
  return rows.map((r) => r.repo);
1846
1783
  }
1847
1784
  listRepoNavigation() {
1848
1785
  const repos = this.listRepos();
1849
1786
  return repos.map((repo) => {
1850
- const memoryCount = this.db.prepare("SELECT COUNT(*) as count FROM memories WHERE repo = ?").get(repo).count;
1851
- const taskCount = this.db.prepare("SELECT COUNT(*) as count FROM tasks WHERE repo = ?").get(repo).count;
1852
- const lastActivity = this.db.prepare(
1853
- `SELECT MAX(created_at) as last FROM (SELECT created_at FROM memories WHERE repo = ? UNION ALL SELECT created_at FROM tasks WHERE repo = ? UNION ALL SELECT created_at FROM action_log WHERE repo = ?)`
1854
- ).get(repo, repo, repo).last;
1787
+ const memoryCountRow = this.get("SELECT COUNT(*) as count FROM memories WHERE repo = ?", [
1788
+ repo
1789
+ ]);
1790
+ const taskCountRow = this.get("SELECT COUNT(*) as count FROM tasks WHERE repo = ?", [repo]);
1791
+ const lastActivityRow = this.get(
1792
+ `SELECT MAX(created_at) as last FROM (SELECT created_at FROM memories WHERE repo = ? UNION ALL SELECT created_at FROM tasks WHERE repo = ? UNION ALL SELECT created_at FROM action_log WHERE repo = ?)`,
1793
+ [repo, repo, repo]
1794
+ );
1855
1795
  return {
1856
1796
  repo,
1857
- memoryCount,
1858
- taskCount,
1859
- lastActivity
1797
+ memoryCount: memoryCountRow?.count ?? 0,
1798
+ taskCount: taskCountRow?.count ?? 0,
1799
+ lastActivity: lastActivityRow?.last ?? null
1860
1800
  };
1861
1801
  });
1862
1802
  }
1863
1803
  getDashboardStats(repo) {
1864
- const memoryStats = this.db.prepare("SELECT type, COUNT(*) as count FROM memories WHERE repo = ? GROUP BY type").all(repo);
1865
- const taskStats = this.db.prepare("SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status").all(repo);
1866
- const recentMemories = this.db.prepare("SELECT * FROM memories WHERE repo = ? ORDER BY created_at DESC LIMIT 5").all(repo).map((r) => this.rowToMemoryEntry(r));
1867
- const activeTasks = this.db.prepare(
1868
- "SELECT * FROM tasks WHERE repo = ? AND status IN ('in_progress', 'pending', 'backlog') ORDER BY priority DESC, created_at ASC LIMIT 5"
1869
- ).all(repo).map((r) => this.rowToTask(r));
1804
+ const memoryStats = this.all(
1805
+ "SELECT type, COUNT(*) as count FROM memories WHERE repo = ? GROUP BY type",
1806
+ [repo]
1807
+ );
1808
+ const taskStats = this.all(
1809
+ "SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status",
1810
+ [repo]
1811
+ );
1812
+ const recentMemoriesRows = this.all(
1813
+ "SELECT * FROM memories WHERE repo = ? ORDER BY created_at DESC LIMIT 5",
1814
+ [repo]
1815
+ );
1816
+ const recentMemories = recentMemoriesRows.map((r) => this.rowToMemoryEntry(r));
1817
+ const activeTasksRows = this.all(
1818
+ "SELECT * FROM tasks WHERE repo = ? AND status IN ('in_progress', 'pending', 'backlog') ORDER BY priority DESC, created_at ASC LIMIT 5",
1819
+ [repo]
1820
+ );
1821
+ const activeTasks = activeTasksRows.map((r) => this.rowToTask(r));
1870
1822
  return {
1871
1823
  memoryStats,
1872
1824
  taskStats,
@@ -1875,23 +1827,27 @@ var SystemEntity = class extends BaseEntity {
1875
1827
  };
1876
1828
  }
1877
1829
  getGlobalStats() {
1878
- const totalMemories = this.db.prepare("SELECT COUNT(*) as count FROM memories").get().count;
1879
- const totalTasks = this.db.prepare("SELECT COUNT(*) as count FROM tasks").get().count;
1830
+ const totalMemoriesRow = this.get("SELECT COUNT(*) as count FROM memories");
1831
+ const totalTasksRow = this.get("SELECT COUNT(*) as count FROM tasks");
1880
1832
  const totalRepos = this.listRepos().length;
1881
1833
  return {
1882
- totalMemories,
1883
- totalTasks,
1834
+ totalMemories: totalMemoriesRow?.count ?? 0,
1835
+ totalTasks: totalTasksRow?.count ?? 0,
1884
1836
  totalRepos
1885
1837
  };
1886
1838
  }
1887
1839
  getRepoDetails(repo) {
1888
- const memoryCount = this.db.prepare("SELECT COUNT(*) as count FROM memories WHERE repo = ?").get(repo).count;
1889
- const taskCount = this.db.prepare("SELECT COUNT(*) as count FROM tasks WHERE repo = ?").get(repo).count;
1890
- const languages = this.db.prepare("SELECT DISTINCT language FROM memories WHERE repo = ? AND language IS NOT NULL").all(repo).map((r) => r.language);
1840
+ const memoryCountRow = this.get("SELECT COUNT(*) as count FROM memories WHERE repo = ?", [repo]);
1841
+ const taskCountRow = this.get("SELECT COUNT(*) as count FROM tasks WHERE repo = ?", [repo]);
1842
+ const languagesRows = this.all(
1843
+ "SELECT DISTINCT language FROM memories WHERE repo = ? AND language IS NOT NULL",
1844
+ [repo]
1845
+ );
1846
+ const languages = languagesRows.map((r) => r.language);
1891
1847
  return {
1892
1848
  repo,
1893
- memoryCount,
1894
- taskCount,
1849
+ memoryCount: memoryCountRow?.count ?? 0,
1850
+ taskCount: taskCountRow?.count ?? 0,
1895
1851
  languages
1896
1852
  };
1897
1853
  }
@@ -1900,16 +1856,18 @@ var SystemEntity = class extends BaseEntity {
1900
1856
  // src/mcp/entities/summary.ts
1901
1857
  var SummaryEntity = class extends BaseEntity {
1902
1858
  getSummary(repo) {
1903
- const row = this.db.prepare("SELECT summary, updated_at FROM memory_summary WHERE repo = ?").get(repo);
1859
+ const row = this.get(
1860
+ "SELECT summary, updated_at FROM memory_summary WHERE repo = ?",
1861
+ [repo]
1862
+ );
1904
1863
  return row || null;
1905
1864
  }
1906
1865
  upsertSummary(repo, summary) {
1907
- this.db.prepare(
1908
- `
1909
- INSERT INTO memory_summary (repo, summary, updated_at) VALUES (?, ?, ?)
1910
- ON CONFLICT(repo) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at
1911
- `
1912
- ).run(repo, summary, (/* @__PURE__ */ new Date()).toISOString());
1866
+ this.run(
1867
+ `INSERT INTO memory_summary (repo, summary, updated_at) VALUES (?, ?, ?)
1868
+ ON CONFLICT(repo) DO UPDATE SET summary = excluded.summary, updated_at = excluded.updated_at`,
1869
+ [repo, summary, (/* @__PURE__ */ new Date()).toISOString()]
1870
+ );
1913
1871
  }
1914
1872
  };
1915
1873
 
@@ -1926,43 +1884,80 @@ function resolveDbPath() {
1926
1884
  return standardPath;
1927
1885
  }
1928
1886
  var DB_PATH = resolveDbPath();
1929
- var SQLiteStore = class {
1887
+ var dbPathInstance = "";
1888
+ var saveDbFn = null;
1889
+ function createSaveFunction(db, dbPath) {
1890
+ return () => {
1891
+ if (dbPath && dbPath !== ":memory:") {
1892
+ const data = db.export();
1893
+ const buffer = Buffer.from(data);
1894
+ fs2.writeFileSync(dbPath, buffer);
1895
+ }
1896
+ };
1897
+ }
1898
+ var SQLiteStore = class _SQLiteStore {
1930
1899
  db;
1931
1900
  memories;
1932
1901
  tasks;
1933
1902
  actions;
1934
1903
  system;
1935
1904
  summaries;
1936
- constructor(dbPath) {
1905
+ constructor() {
1906
+ this.db = {};
1907
+ this.memories = {};
1908
+ this.tasks = {};
1909
+ this.actions = {};
1910
+ this.system = {};
1911
+ this.summaries = {};
1912
+ }
1913
+ static async create(dbPath) {
1937
1914
  const finalPath = dbPath ?? DB_PATH;
1938
- const dbDir = path2.dirname(finalPath);
1939
- if (!fs2.existsSync(dbDir)) {
1940
- fs2.mkdirSync(dbDir, { recursive: true });
1941
- }
1942
- this.db = new Database(finalPath);
1943
- this.db.pragma("journal_mode = WAL");
1944
- this.db.pragma("synchronous = NORMAL");
1945
- this.db.pragma("busy_timeout = 5000");
1946
- const migrator = new MigrationManager(this.db);
1915
+ dbPathInstance = finalPath;
1916
+ const SQL = await initSqlJs();
1917
+ let db;
1918
+ if (finalPath === ":memory:") {
1919
+ db = new SQL.Database();
1920
+ } else {
1921
+ const dbDir = path2.dirname(finalPath);
1922
+ if (!fs2.existsSync(dbDir)) {
1923
+ fs2.mkdirSync(dbDir, { recursive: true });
1924
+ }
1925
+ if (fs2.existsSync(finalPath)) {
1926
+ const fileBuffer = fs2.readFileSync(finalPath);
1927
+ db = new SQL.Database(fileBuffer);
1928
+ } else {
1929
+ db = new SQL.Database();
1930
+ }
1931
+ }
1932
+ const saveDb = createSaveFunction(db, finalPath);
1933
+ db.run("PRAGMA journal_mode = WAL");
1934
+ db.run("PRAGMA synchronous = NORMAL");
1935
+ db.run("PRAGMA busy_timeout = 5000");
1936
+ const migrator = new MigrationManager(db, saveDb);
1947
1937
  migrator.migrate();
1948
- this.memories = new MemoryEntity(this.db);
1949
- this.tasks = new TaskEntity(this.db);
1950
- this.actions = new ActionEntity(this.db);
1951
- this.system = new SystemEntity(this.db);
1952
- this.summaries = new SummaryEntity(this.db);
1953
- process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO ] SQLiteStore initialized at ${finalPath}
1938
+ const store = Object.create(_SQLiteStore.prototype);
1939
+ store.db = db;
1940
+ store.memories = new MemoryEntity(db, saveDb);
1941
+ store.tasks = new TaskEntity(db, saveDb);
1942
+ store.actions = new ActionEntity(db, saveDb);
1943
+ store.system = new SystemEntity(db, saveDb);
1944
+ store.summaries = new SummaryEntity(db, saveDb);
1945
+ if (finalPath !== ":memory:") {
1946
+ saveDb();
1947
+ }
1948
+ if (process.env.MCP_SERVER !== "true") {
1949
+ process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO ] SQLiteStore initialized at ${finalPath}
1954
1950
  `);
1951
+ }
1952
+ return store;
1955
1953
  }
1956
- /**
1957
- * Returns the current database file path.
1958
- */
1959
1954
  getDbPath() {
1960
- return this.db.name;
1955
+ return dbPathInstance;
1961
1956
  }
1962
- /**
1963
- * Closes the database connection.
1964
- */
1965
1957
  close() {
1958
+ if (saveDbFn) {
1959
+ saveDbFn();
1960
+ }
1966
1961
  this.db.close();
1967
1962
  }
1968
1963
  };