claude-mem-lite 2.71.0 → 2.71.1

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.
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "claude-mem-lite",
13
- "version": "2.71.0",
13
+ "version": "2.71.1",
14
14
  "source": "./",
15
15
  "description": "Lightweight persistent memory system for Claude Code — FTS5 search, episode batching, error-triggered recall"
16
16
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "2.71.0",
3
+ "version": "2.71.1",
4
4
  "description": "Lightweight persistent memory system for Claude Code — FTS5 search, episode batching, error-triggered recall",
5
5
  "author": {
6
6
  "name": "sdsrss"
package/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const CLI_COMMANDS = new Set(['search', 'recent', 'recall', 'get', 'timeline', 'save', 'stats', 'context', 'browse', 'delete', 'update', 'export', 'compress', 'maintain', 'optimize', 'fts-check', 'registry', 'import', 'enrich', 'activity', 'adopt', 'unadopt', 'memdir-audit', 'defer', 'help']);
2
+ const CLI_COMMANDS = new Set(['search', 'recent', 'recall', 'get', 'timeline', 'save', 'stats', 'context', 'browse', 'delete', 'update', 'export', 'compress', 'maintain', 'optimize', 'fts-check', 'registry', 'import', 'import-jsonl', 'enrich', 'activity', 'adopt', 'unadopt', 'memdir-audit', 'defer', 'help']);
3
3
  const INSTALL_COMMANDS = new Set(['install', 'uninstall', 'status', 'doctor', 'cleanup', 'cleanup-hooks', 'self-update', 'release']);
4
4
 
5
5
  const cmd = process.argv[2];
@@ -34,12 +34,21 @@ function parseLine(line) {
34
34
  try { return JSON.parse(line); } catch { return null; }
35
35
  }
36
36
 
37
+ // Distinct mem-internal id derived from the CC session UUID. The schema
38
+ // trigger `sdk_sessions_id_mix_check_*` aborts when memory_session_id ==
39
+ // content_session_id and both look like a CC UUID (length 36 + hyphen
40
+ // pattern); writing the raw UUID into both columns would reproduce the
41
+ // v2.33.1 mix bug. The `import-` prefix makes the origin obvious in audits.
42
+ function memId(sessionId) {
43
+ return `import-${sessionId}`;
44
+ }
45
+
37
46
  function ensureSession(db, sessionId, project, ts) {
38
47
  db.prepare(`
39
48
  INSERT OR IGNORE INTO sdk_sessions
40
49
  (content_session_id, memory_session_id, project, started_at, started_at_epoch, status)
41
50
  VALUES (?, ?, ?, ?, ?, 'completed')
42
- `).run(sessionId, sessionId, project, ts, Date.parse(ts) || Date.now());
51
+ `).run(sessionId, memId(sessionId), project, ts, Date.parse(ts) || Date.now());
43
52
  }
44
53
 
45
54
  function importPrompt(db, ev, project, seenPrompts) {
@@ -109,7 +118,7 @@ function importToolPair(db, toolUse, toolResult, project) {
109
118
  (memory_session_id, project, text, type, title, subtitle, narrative, concepts, facts, files_read, files_modified, importance, created_at, created_at_epoch)
110
119
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
111
120
  `).run(
112
- sessionId, project, safe.text, type, safe.title, safe.subtitle,
121
+ memId(sessionId), project, safe.text, type, safe.title, safe.subtitle,
113
122
  safe.narrative, safe.concepts, safe.facts,
114
123
  JSON.stringify(filesRead), JSON.stringify(filesModified),
115
124
  1, ts, Date.parse(ts) || Date.now(),
@@ -171,7 +180,9 @@ export async function importJsonl(db, path, { project }) {
171
180
  const toolName = useEv.name || 'unknown';
172
181
  const titlePreview = `${toolName}: ${(useEv.input?.command || useEv.input?.file_path || '').slice(0, 80)}`;
173
182
  const ts = useEv.timestamp || new Date().toISOString();
174
- const crossKey = dedupKey([sessionId, `existing:${titlePreview}:${ts}`]);
183
+ // Match the storage convention from importToolPair (memId-prefixed) so
184
+ // the seenObs entries seeded from the DB can be matched on a re-run.
185
+ const crossKey = dedupKey([memId(sessionId), `existing:${titlePreview}:${ts}`]);
175
186
  if (seenObs.has(crossKey)) return false;
176
187
 
177
188
  return importToolPair(db, useEv, resultEv, project);
@@ -183,7 +194,31 @@ export async function importJsonl(db, path, { project }) {
183
194
  const ev = parseLine(line);
184
195
  if (!ev) { skipped++; continue; }
185
196
  if (ev.type === 'user') {
186
- if (importPrompt(db, ev, project, seenPrompts)) prompts++; else skipped++;
197
+ // Real Claude Code transcripts wrap tool_result inside a user-typed
198
+ // event's message.content array (alongside the rare text part). The
199
+ // top-level {"type":"tool_result"} shape only appears in our test
200
+ // fixtures. Consume any embedded tool_result parts here; only fall
201
+ // through to importPrompt when the event is an actual user prompt.
202
+ const content = ev?.message?.content;
203
+ let consumedAsToolResult = false;
204
+ if (Array.isArray(content)) {
205
+ for (const part of content) {
206
+ if (part?.type === 'tool_result' && part.tool_use_id) {
207
+ consumedAsToolResult = true;
208
+ const useEv = pendingToolUse.get(part.tool_use_id);
209
+ if (useEv) {
210
+ const synth = { content: part.content, tool_use_id: part.tool_use_id, timestamp: ev.timestamp };
211
+ if (tryImportToolPair(useEv, synth)) observations++;
212
+ pendingToolUse.delete(part.tool_use_id);
213
+ } else {
214
+ skipped++;
215
+ }
216
+ }
217
+ }
218
+ }
219
+ if (!consumedAsToolResult) {
220
+ if (importPrompt(db, ev, project, seenPrompts)) prompts++; else skipped++;
221
+ }
187
222
  } else if (ev.type === 'assistant' && Array.isArray(ev.message?.content)) {
188
223
  for (const part of ev.message.content) {
189
224
  if (part.type === 'tool_use') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "2.71.0",
3
+ "version": "2.71.1",
4
4
  "description": "Lightweight persistent memory system for Claude Code",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",