claude-mem-lite 3.9.0 → 3.9.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/hook.mjs +5 -1
- package/lib/citation-tracker.mjs +26 -14
- package/mem-cli.mjs +4 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "claude-mem-lite",
|
|
13
|
-
"version": "3.9.
|
|
13
|
+
"version": "3.9.1",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark)."
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.1",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "sdsrss"
|
package/hook.mjs
CHANGED
|
@@ -553,7 +553,11 @@ async function handleStop() {
|
|
|
553
553
|
// Union closed by extractAllInjected — one integration point so the
|
|
554
554
|
// contract test in tests/citation-tracker-userprompt.test.mjs covers it.
|
|
555
555
|
try {
|
|
556
|
-
|
|
556
|
+
// mainOnly: the injected denominator must use the same thread
|
|
557
|
+
// filter as citedMain (the numerator, below) — an obs injected only
|
|
558
|
+
// inside a subagent (sidechain) would otherwise enter the denominator
|
|
559
|
+
// but never the numerator and streak-demote despite being used there.
|
|
560
|
+
const injected = extractAllInjected(transcriptPath, { mainOnly: true });
|
|
557
561
|
// P5 ①: cite-back signals — observations whose warned file the agent
|
|
558
562
|
// edited this session. Union into injected so they're resolved (they
|
|
559
563
|
// were injected via pre-tool-recall) and, below, into cited so the
|
package/lib/citation-tracker.mjs
CHANGED
|
@@ -182,8 +182,15 @@ function normalizeHookCommand(command) {
|
|
|
182
182
|
*
|
|
183
183
|
* @param {string|null|undefined} transcriptPath
|
|
184
184
|
* @param {(ctx: {command: string, text: string}) => void} fn
|
|
185
|
+
* @param {object} [opts]
|
|
186
|
+
* @param {boolean} [opts.mainOnly=false] If true, skip attachments on sidechain
|
|
187
|
+
* (subagent) transcript records. Mirrors extractCitationsFromTranscript's
|
|
188
|
+
* mainOnly so the citation-decay injected DENOMINATOR uses the same thread
|
|
189
|
+
* filter as the cited NUMERATOR — an obs injected only inside a subagent must
|
|
190
|
+
* not enter the denominator, else it streak-demotes despite being used there.
|
|
185
191
|
*/
|
|
186
|
-
function eachHookAttachment(transcriptPath, fn) {
|
|
192
|
+
function eachHookAttachment(transcriptPath, fn, opts = {}) {
|
|
193
|
+
const { mainOnly = false } = opts;
|
|
187
194
|
if (!transcriptPath || !existsSync(transcriptPath)) return;
|
|
188
195
|
let raw;
|
|
189
196
|
try { raw = readFileSync(transcriptPath, 'utf8'); } catch { return; }
|
|
@@ -192,6 +199,7 @@ function eachHookAttachment(transcriptPath, fn) {
|
|
|
192
199
|
let entry;
|
|
193
200
|
try { entry = JSON.parse(line); } catch { continue; }
|
|
194
201
|
if (entry.type !== 'attachment') continue;
|
|
202
|
+
if (mainOnly && entry.isSidechain === true) continue;
|
|
195
203
|
const att = entry.attachment;
|
|
196
204
|
if (!att || att.type !== 'hook_success') continue;
|
|
197
205
|
const stdout = att.stdout || '';
|
|
@@ -217,14 +225,14 @@ function eachHookAttachment(transcriptPath, fn) {
|
|
|
217
225
|
* @param {string|null|undefined} transcriptPath
|
|
218
226
|
* @returns {Set<number>} unique injected IDs (empty set on missing path/file)
|
|
219
227
|
*/
|
|
220
|
-
export function extractInjectedFromPreToolUse(transcriptPath) {
|
|
228
|
+
export function extractInjectedFromPreToolUse(transcriptPath, opts = {}) {
|
|
221
229
|
const ids = new Set();
|
|
222
230
|
eachHookAttachment(transcriptPath, ({ command, text }) => {
|
|
223
231
|
if (!command.includes('pre-tool-recall')) return;
|
|
224
232
|
INJECTED_RE.lastIndex = 0;
|
|
225
233
|
let m;
|
|
226
234
|
while ((m = INJECTED_RE.exec(text))) addObsId(ids, m[1]);
|
|
227
|
-
});
|
|
235
|
+
}, opts);
|
|
228
236
|
return ids;
|
|
229
237
|
}
|
|
230
238
|
|
|
@@ -251,7 +259,7 @@ const UPS_COMMAND_SUFFIX = 'hook.mjs user-prompt';
|
|
|
251
259
|
* @param {string|null|undefined} transcriptPath
|
|
252
260
|
* @returns {Set<number>}
|
|
253
261
|
*/
|
|
254
|
-
export function extractInjectedFromUserPromptSubmit(transcriptPath) {
|
|
262
|
+
export function extractInjectedFromUserPromptSubmit(transcriptPath, opts = {}) {
|
|
255
263
|
const ids = new Set();
|
|
256
264
|
eachHookAttachment(transcriptPath, ({ command, text }) => {
|
|
257
265
|
if (!command.includes(UPS_COMMAND_SUFFIX)) return;
|
|
@@ -265,7 +273,7 @@ export function extractInjectedFromUserPromptSubmit(transcriptPath) {
|
|
|
265
273
|
if (matches.length === 0) continue;
|
|
266
274
|
addObsId(ids, matches[matches.length - 1][1]);
|
|
267
275
|
}
|
|
268
|
-
});
|
|
276
|
+
}, opts);
|
|
269
277
|
return ids;
|
|
270
278
|
}
|
|
271
279
|
|
|
@@ -280,7 +288,7 @@ export function extractInjectedFromUserPromptSubmit(transcriptPath) {
|
|
|
280
288
|
* @param {string|null|undefined} transcriptPath
|
|
281
289
|
* @returns {Set<number>}
|
|
282
290
|
*/
|
|
283
|
-
export function extractInjectedFromErrorRecall(transcriptPath) {
|
|
291
|
+
export function extractInjectedFromErrorRecall(transcriptPath, opts = {}) {
|
|
284
292
|
const ids = new Set();
|
|
285
293
|
eachHookAttachment(transcriptPath, ({ command, text }) => {
|
|
286
294
|
if (!command.includes('post-tool-use')) return;
|
|
@@ -290,7 +298,7 @@ export function extractInjectedFromErrorRecall(transcriptPath) {
|
|
|
290
298
|
INJECTED_RE.lastIndex = 0;
|
|
291
299
|
let m;
|
|
292
300
|
while ((m = INJECTED_RE.exec(text))) addObsId(ids, m[1]);
|
|
293
|
-
});
|
|
301
|
+
}, opts);
|
|
294
302
|
return ids;
|
|
295
303
|
}
|
|
296
304
|
|
|
@@ -311,7 +319,7 @@ const FYI_LINE_ID_RE = /^#(\d{1,7})\s/;
|
|
|
311
319
|
* @param {string|null|undefined} transcriptPath
|
|
312
320
|
* @returns {Set<number>}
|
|
313
321
|
*/
|
|
314
|
-
export function extractInjectedFromFyi(transcriptPath) {
|
|
322
|
+
export function extractInjectedFromFyi(transcriptPath, opts = {}) {
|
|
315
323
|
const ids = new Set();
|
|
316
324
|
eachHookAttachment(transcriptPath, ({ command, text }) => {
|
|
317
325
|
if (!command.includes('user-prompt-search')) return;
|
|
@@ -320,7 +328,7 @@ export function extractInjectedFromFyi(transcriptPath) {
|
|
|
320
328
|
const m = FYI_LINE_ID_RE.exec(fyiLine);
|
|
321
329
|
if (m) addObsId(ids, m[1]);
|
|
322
330
|
}
|
|
323
|
-
});
|
|
331
|
+
}, opts);
|
|
324
332
|
return ids;
|
|
325
333
|
}
|
|
326
334
|
|
|
@@ -330,14 +338,18 @@ export function extractInjectedFromFyi(transcriptPath) {
|
|
|
330
338
|
* user-prompt-search FYI block. Single integration point the Stop handler calls.
|
|
331
339
|
*
|
|
332
340
|
* @param {string|null|undefined} transcriptPath
|
|
341
|
+
* @param {object} [opts]
|
|
342
|
+
* @param {boolean} [opts.mainOnly=false] Skip sidechain-injected IDs. The
|
|
343
|
+
* citation-decay caller passes true so the injected denominator matches the
|
|
344
|
+
* mainOnly cited numerator; the P4 access-bump caller omits it (broader).
|
|
333
345
|
* @returns {Set<number>}
|
|
334
346
|
*/
|
|
335
|
-
export function extractAllInjected(transcriptPath) {
|
|
347
|
+
export function extractAllInjected(transcriptPath, opts = {}) {
|
|
336
348
|
return new Set([
|
|
337
|
-
...extractInjectedFromPreToolUse(transcriptPath),
|
|
338
|
-
...extractInjectedFromUserPromptSubmit(transcriptPath),
|
|
339
|
-
...extractInjectedFromErrorRecall(transcriptPath),
|
|
340
|
-
...extractInjectedFromFyi(transcriptPath),
|
|
349
|
+
...extractInjectedFromPreToolUse(transcriptPath, opts),
|
|
350
|
+
...extractInjectedFromUserPromptSubmit(transcriptPath, opts),
|
|
351
|
+
...extractInjectedFromErrorRecall(transcriptPath, opts),
|
|
352
|
+
...extractInjectedFromFyi(transcriptPath, opts),
|
|
341
353
|
]);
|
|
342
354
|
}
|
|
343
355
|
|
package/mem-cli.mjs
CHANGED
|
@@ -1405,8 +1405,11 @@ function cmdUpdate(db, args) {
|
|
|
1405
1405
|
`Prompts and sessions are append-only.`);
|
|
1406
1406
|
return;
|
|
1407
1407
|
}
|
|
1408
|
+
// Strict parseIdToken gate (aligned with cmdDelete): a bare parseInt fallback
|
|
1409
|
+
// truncated "3.9" → 3 and silently UPDATE'd the WRONG row #3 (no preview, no
|
|
1410
|
+
// --confirm). Require an exact obs-id token; non-matching input → usage error.
|
|
1408
1411
|
const parsed = raw ? parseIdToken(raw) : null;
|
|
1409
|
-
const id = parsed && parsed.source === null ? parsed.id :
|
|
1412
|
+
const id = parsed && parsed.source === null ? parsed.id : NaN;
|
|
1410
1413
|
if (!id || isNaN(id)) {
|
|
1411
1414
|
fail('[mem] Usage: claude-mem-lite update <id> [--title T] [--type T] [--importance N] [--lesson T] [--narrative T] [--concepts T]');
|
|
1412
1415
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.1",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@10.9.2",
|