@modusensus/dsh-mneme 0.2.2 → 0.2.3

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/lib/index.js CHANGED
@@ -36,6 +36,11 @@ export const apply = (ctx, config) => {
36
36
  mkdirSync(memoryDir, { recursive: true });
37
37
 
38
38
  const store = createStore(join(memoryDir, "memory.db"));
39
+ // Prune reflection failure rows older than 90 days on boot (best-effort, so
40
+ // the failure table never grows unbounded).
41
+ try {
42
+ store.deleteOldFailures(new Date(Date.now() - 90 * 86400000).toISOString());
43
+ } catch { /* non-fatal */ }
39
44
  const mirror = createMirror(memoryDir);
40
45
  const service = createService({ store, mirror, config: cfg });
41
46
 
package/lib/service.js CHANGED
@@ -302,6 +302,7 @@ export function createService({ store, mirror, config, onWrite }) {
302
302
  query: ctx.query ?? null,
303
303
  expected: updated.content,
304
304
  actual: old.content,
305
+ before: { title: old.title, content: old.content, importance: old.importance },
305
306
  failure_type: "user_correction",
306
307
  memory_id: id
307
308
  });
package/lib/store.js CHANGED
@@ -42,13 +42,16 @@ CREATE TABLE IF NOT EXISTS dream_runs (
42
42
  CREATE INDEX IF NOT EXISTS idx_dream_runs_created ON dream_runs(created_at);
43
43
 
44
44
  -- failure_memories: records user corrections / reflection failures. Captures
45
- -- what a memory was ("actual") vs what the user changed it to ("expected")
45
+ -- what a memory was (actual) vs what the user changed it to (expected)
46
46
  -- so later reflection passes can mine recurring correction patterns.
47
+ -- before holds a JSON snapshot of the pre-change title/content/importance,
48
+ -- so a title-only or importance-only correction is still traceable.
47
49
  CREATE TABLE IF NOT EXISTS failure_memories (
48
50
  id TEXT PRIMARY KEY,
49
51
  query TEXT,
50
52
  expected TEXT,
51
53
  actual TEXT,
54
+ before TEXT,
52
55
  failure_type TEXT NOT NULL,
53
56
  memory_id TEXT,
54
57
  created_at TEXT NOT NULL
@@ -405,13 +408,14 @@ export function createStore(path) {
405
408
  * Like the dream audit trail this is bookkeeping: it never triggers write
406
409
  * hooks, so reflection mining of failures cannot loop back into the writer.
407
410
  */
408
- function saveFailure({ id, query, expected, actual, failure_type, memory_id }) {
411
+ function saveFailure({ id, query, expected, actual, before, failure_type, memory_id }) {
409
412
  const now = nowIso();
413
+ const beforeJson = before && typeof before === "object" ? JSON.stringify(before) : (before ?? null);
410
414
  db.prepare(
411
- `INSERT INTO failure_memories (id, query, expected, actual, failure_type, memory_id, created_at)
412
- VALUES (?, ?, ?, ?, ?, ?, ?)`
413
- ).run(id ?? randomUUID(), query ?? null, expected ?? null, actual ?? null, failure_type, memory_id ?? null, now);
414
- return { id, query, expected, actual, failure_type, memory_id, created_at: now };
415
+ `INSERT INTO failure_memories (id, query, expected, actual, before, failure_type, memory_id, created_at)
416
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
417
+ ).run(id ?? randomUUID(), query ?? null, expected ?? null, actual ?? null, beforeJson, failure_type, memory_id ?? null, now);
418
+ return { id, query, expected, actual, before: before ?? null, failure_type, memory_id, created_at: now };
415
419
  }
416
420
 
417
421
  function listFailures({ limit = 50, offset = 0, since, memory_id, failure_type } = {}) {
@@ -423,7 +427,12 @@ export function createStore(path) {
423
427
  const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
424
428
  const lim = Number.isInteger(limit) && limit > 0 ? limit : 50;
425
429
  const off = Number.isInteger(offset) && offset > 0 ? offset : 0;
426
- return db.prepare(`SELECT * FROM failure_memories ${where} ORDER BY created_at DESC, id LIMIT ? OFFSET ?`).all(...params, lim, off);
430
+ return db.prepare(`SELECT * FROM failure_memories ${where} ORDER BY created_at DESC, id LIMIT ? OFFSET ?`).all(...params, lim, off)
431
+ .map((row) => {
432
+ let before;
433
+ try { before = row.before ? JSON.parse(row.before) : null; } catch { before = null; }
434
+ return { ...row, before };
435
+ });
427
436
  }
428
437
 
429
438
  /** Delete failure rows older than `before` (ISO string). Returns count removed. */
@@ -73,7 +73,7 @@ export function createVectorIndex({ store, logger }) {
73
73
 
74
74
  /** Re-embed every row missing an embedding. Returns indexed count. */
75
75
  async rebuildIndex(embedder, { limit = 1000 } = {}) {
76
- if (!embedder || typeof embedder.embed !== "function") return { indexed: 0, skipped: 0 };
76
+ if (!embedder || typeof embedder.embedSingle !== "function") return { indexed: 0, skipped: 0 };
77
77
  const rows = store.needsEmbedding(limit);
78
78
  let indexed = 0;
79
79
  for (const row of rows) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@modusensus/dsh-mneme",
3
3
  "description": "Cross-session memory plugin for DeepSeek Harness with autoDream consolidation: SQLite store, Markdown mirrors, 6 model tools, automatic injection, session summarization, user profile/rules, custom slash commands, vector (semantic) search, and a Web GUI panel",
4
- "version": "0.2.2",
4
+ "version": "0.2.3",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",
package/src/index.js CHANGED
@@ -36,6 +36,11 @@ export const apply = (ctx, config) => {
36
36
  mkdirSync(memoryDir, { recursive: true });
37
37
 
38
38
  const store = createStore(join(memoryDir, "memory.db"));
39
+ // Prune reflection failure rows older than 90 days on boot (best-effort, so
40
+ // the failure table never grows unbounded).
41
+ try {
42
+ store.deleteOldFailures(new Date(Date.now() - 90 * 86400000).toISOString());
43
+ } catch { /* non-fatal */ }
39
44
  const mirror = createMirror(memoryDir);
40
45
  const service = createService({ store, mirror, config: cfg });
41
46
 
package/src/service.js CHANGED
@@ -302,6 +302,7 @@ export function createService({ store, mirror, config, onWrite }) {
302
302
  query: ctx.query ?? null,
303
303
  expected: updated.content,
304
304
  actual: old.content,
305
+ before: { title: old.title, content: old.content, importance: old.importance },
305
306
  failure_type: "user_correction",
306
307
  memory_id: id
307
308
  });
package/src/store.js CHANGED
@@ -42,13 +42,16 @@ CREATE TABLE IF NOT EXISTS dream_runs (
42
42
  CREATE INDEX IF NOT EXISTS idx_dream_runs_created ON dream_runs(created_at);
43
43
 
44
44
  -- failure_memories: records user corrections / reflection failures. Captures
45
- -- what a memory was ("actual") vs what the user changed it to ("expected")
45
+ -- what a memory was (actual) vs what the user changed it to (expected)
46
46
  -- so later reflection passes can mine recurring correction patterns.
47
+ -- before holds a JSON snapshot of the pre-change title/content/importance,
48
+ -- so a title-only or importance-only correction is still traceable.
47
49
  CREATE TABLE IF NOT EXISTS failure_memories (
48
50
  id TEXT PRIMARY KEY,
49
51
  query TEXT,
50
52
  expected TEXT,
51
53
  actual TEXT,
54
+ before TEXT,
52
55
  failure_type TEXT NOT NULL,
53
56
  memory_id TEXT,
54
57
  created_at TEXT NOT NULL
@@ -405,13 +408,14 @@ export function createStore(path) {
405
408
  * Like the dream audit trail this is bookkeeping: it never triggers write
406
409
  * hooks, so reflection mining of failures cannot loop back into the writer.
407
410
  */
408
- function saveFailure({ id, query, expected, actual, failure_type, memory_id }) {
411
+ function saveFailure({ id, query, expected, actual, before, failure_type, memory_id }) {
409
412
  const now = nowIso();
413
+ const beforeJson = before && typeof before === "object" ? JSON.stringify(before) : (before ?? null);
410
414
  db.prepare(
411
- `INSERT INTO failure_memories (id, query, expected, actual, failure_type, memory_id, created_at)
412
- VALUES (?, ?, ?, ?, ?, ?, ?)`
413
- ).run(id ?? randomUUID(), query ?? null, expected ?? null, actual ?? null, failure_type, memory_id ?? null, now);
414
- return { id, query, expected, actual, failure_type, memory_id, created_at: now };
415
+ `INSERT INTO failure_memories (id, query, expected, actual, before, failure_type, memory_id, created_at)
416
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
417
+ ).run(id ?? randomUUID(), query ?? null, expected ?? null, actual ?? null, beforeJson, failure_type, memory_id ?? null, now);
418
+ return { id, query, expected, actual, before: before ?? null, failure_type, memory_id, created_at: now };
415
419
  }
416
420
 
417
421
  function listFailures({ limit = 50, offset = 0, since, memory_id, failure_type } = {}) {
@@ -423,7 +427,12 @@ export function createStore(path) {
423
427
  const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
424
428
  const lim = Number.isInteger(limit) && limit > 0 ? limit : 50;
425
429
  const off = Number.isInteger(offset) && offset > 0 ? offset : 0;
426
- return db.prepare(`SELECT * FROM failure_memories ${where} ORDER BY created_at DESC, id LIMIT ? OFFSET ?`).all(...params, lim, off);
430
+ return db.prepare(`SELECT * FROM failure_memories ${where} ORDER BY created_at DESC, id LIMIT ? OFFSET ?`).all(...params, lim, off)
431
+ .map((row) => {
432
+ let before;
433
+ try { before = row.before ? JSON.parse(row.before) : null; } catch { before = null; }
434
+ return { ...row, before };
435
+ });
427
436
  }
428
437
 
429
438
  /** Delete failure rows older than `before` (ISO string). Returns count removed. */
@@ -73,7 +73,7 @@ export function createVectorIndex({ store, logger }) {
73
73
 
74
74
  /** Re-embed every row missing an embedding. Returns indexed count. */
75
75
  async rebuildIndex(embedder, { limit = 1000 } = {}) {
76
- if (!embedder || typeof embedder.embed !== "function") return { indexed: 0, skipped: 0 };
76
+ if (!embedder || typeof embedder.embedSingle !== "function") return { indexed: 0, skipped: 0 };
77
77
  const rows = store.needsEmbedding(limit);
78
78
  let indexed = 0;
79
79
  for (const row of rows) {