claude-mem-lite 3.61.0 → 3.61.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": "3.61.0",
13
+ "version": "3.61.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.61.0",
3
+ "version": "3.61.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/cli/common.mjs CHANGED
@@ -176,6 +176,11 @@ export const KNOWN_CLI_FLAGS = new Set([
176
176
  // stay silent about (`adopt --disable/--enable`, `activity --min-importance`,
177
177
  // `save --supersedes`). Verified by running each command and checking for a warning.
178
178
  'disable', 'enable', 'min-importance', 'supersedes',
179
+ // `doctor --benchmark --prompts-limit N` — read off raw argv in cli/doctor.mjs, so
180
+ // it never appeared in a `flags.x` grep. Caught by independent review after the
181
+ // warn-on-every-unknown-flag flip turned the omission into a false warning on a
182
+ // documented, working command.
183
+ 'prompts-limit',
179
184
  ]);
180
185
 
181
186
  /** Levenshtein distance, early-exit past `max` (cheap enough for a handful of flags). */
package/mem-cli.mjs CHANGED
@@ -3194,7 +3194,7 @@ export async function run(argv) {
3194
3194
  for (const { flag, suggestion } of suggestUnknownFlags(parseArgs(cmdArgs).flags)) {
3195
3195
  process.stderr.write(suggestion
3196
3196
  ? `[mem] Unknown flag --${flag}; did you mean --${suggestion}?\n`
3197
- : `[mem] Unknown flag --${flag} — ignored (it filtered nothing). Run "claude-mem-lite help" for this command's flags.\n`);
3197
+ : `[mem] Unknown flag --${flag} — ignored, it had no effect. Run "claude-mem-lite help" for this command's flags.\n`);
3198
3198
  }
3199
3199
 
3200
3200
  // adopt / unadopt do pure filesystem work on ~/.claude/projects/<encoded>/memory/ —
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "3.61.0",
3
+ "version": "3.61.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "claude-mem-lite",
9
- "version": "3.61.0",
9
+ "version": "3.61.1",
10
10
  "dependencies": {
11
11
  "@modelcontextprotocol/sdk": "^1.26.0",
12
12
  "better-sqlite3": "^12.6.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "3.61.0",
3
+ "version": "3.61.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",
@@ -114,7 +114,7 @@ const OR_TOP_BM25_FLOOR = TOP_REL_FLOOR === 0
114
114
  ? 0
115
115
  : Number(process.env.CLAUDE_MEM_UPS_OR_BM25_MIN || 30);
116
116
 
117
- // ─── Corpus-size normalization of the absolute floors (v3.60.2) ─────────────
117
+ // ─── Corpus-size normalization of the absolute floors (v3.61.0) ─────────────
118
118
  //
119
119
  // Both floors above are ABSOLUTE magnitudes, but the quantity they gate is not
120
120
  // scale-free: FTS5 bm25 carries an IDF term ≈ ln(N/df), so the SAME hit scores
package/secret-scrub.mjs CHANGED
@@ -30,16 +30,45 @@ export const SECRET_PATTERNS = [
30
30
  // value is covered (the hex-only assignment pattern below misses non-hex values).
31
31
  // 1a. `=` assignment → ALWAYS scrub (config syntax, never prose):
32
32
  [/((?:\b|_)(?:password|passwd|passphrase|token|bearer|secret)\s*=\s*)(?!process\.env\.)(?!new\s)(?!\w+\()(?!(?:null|undefined|true|false|None|nil|empty|""|''|0)\b)[^\s,;'"}\]]{6,}/gi, '$1***'],
33
- // 1b. `:` separator, PASSWORD nouns always scrub. The prose lookbehind below
34
- // was originally applied to the whole noun class, which meant any credential
35
- // noun preceded by an English word escaped — so a session narrative like
36
- // "deployed to staging, the db password: hunter2correct" persisted the
37
- // password in plaintext and re-injected it into every later context block
38
- // (R5 dogfood, 2026-08-13). Unlike `token`/`bearer`/`secret`, the pinned
39
- // prose set (#8283) contains no `password|passwd|passphrase` case: writing
40
- // "<word> password: <6+ chars>" names a credential, it is not conversational
41
- // usage. Letter-glued non-keywords (`mypassword:`) still miss via `(?:\b|_)`.
42
- [/((?:\b|_)(?:password|passwd|passphrase)\s*:\s*)(?!process\.env\.)(?!new\s)(?!\w+\()(?!(?:null|undefined|true|false|None|nil|empty|""|''|0)\b)[^\s,;'"}\]]{6,}/gi, '$1***'],
33
+ // 1b. `:` separator, PASSWORD nouns. Position decides how permissive the value
34
+ // class may be, because the two positions have opposite error costs.
35
+ //
36
+ // CONFIG position (start of line, or not preceded by an English word +
37
+ // space) is unambiguous assignment syntax scrub any value, exactly as
38
+ // before. Pinned by the ` password: hunter2` indent cases.
39
+ //
40
+ // PROSE position ("<word> password: ") is where v3.61.0 first removed the
41
+ // lookbehind outright, to stop "deployed to staging, the db password:
42
+ // hunter2correct" from persisting a credential. That closed a leak by
43
+ // trading it for something worse: scrubbing runs on the WRITE path, and the
44
+ // value class matches ordinary English, so "Reset the password: instructions
45
+ // are in the onboarding doc" was stored irreversibly as "password: *** are
46
+ // in the onboarding doc" (caught by independent pre-tag review). The claim
47
+ // that "<word> password: <6+ chars>" always names a credential was simply
48
+ // false. So in prose position the VALUE must look like a credential: not a
49
+ // run of lowercase letters. A digit, any uppercase, or a symbol qualifies —
50
+ // `hunter2correct`, `S3cretValue`, `correct-horse-battery-staple` all scrub,
51
+ // while `instructions` / `rotation` / `yesterday` are left alone.
52
+ //
53
+ // "Credential-shaped" is spelled as: NOT a single run of ≤15 letters. The
54
+ // patterns carry `i`, so the letter class is case-insensitive by
55
+ // construction — deliberately, because prose capitalizes ("Reset the
56
+ // password: Instructions are in the doc" must survive, and a
57
+ // lowercase-only test would corrupt it). The length bound is what still
58
+ // catches a letters-only secret: English words in prose run short, secrets
59
+ // do not, so `aVeryLongOpaqueSecretToken` (26) scrubs while `instructions`
60
+ // (12) does not.
61
+ //
62
+ // Two known, accepted gaps: a short letters-only password in prose position
63
+ // ("the password: hunter") survives, and an English word longer than 15
64
+ // letters is over-scrubbed. Config position still catches the former; the
65
+ // latter is rare in prose and errs toward protecting a secret. A value
66
+ // indistinguishable from an English word cannot be told from one without
67
+ // corrupting prose — which is exactly the error this arm exists to undo.
68
+ // Both arms emit `***` (3 chars, under the {6,} floor), so they cannot
69
+ // double-apply.
70
+ [/((?<![A-Za-z][ \t])(?:\b|_)(?:password|passwd|passphrase)\s*:\s*)(?!process\.env\.)(?!new\s)(?!\w+\()(?!(?:null|undefined|true|false|None|nil|empty|""|''|0)\b)[^\s,;'"}\]]{6,}/gi, '$1***'],
71
+ [/((?:\b|_)(?:password|passwd|passphrase)\s*:\s*)(?!process\.env\.)(?!new\s)(?!\w+\()(?!(?:null|undefined|true|false|None|nil|empty|""|''|0)\b)(?![A-Za-z]{1,15}(?=[\s,;'"}\]]|$))[^\s,;'"}\]]{6,}/gi, '$1***'],
43
72
  // 1c. `:` separator, prose-ambiguous nouns → keep the lookbehind ("the token: alice"):
44
73
  [/((?<![A-Za-z][ \t])(?:\b|_)(?:token|bearer|secret)\s*:\s*)(?!process\.env\.)(?!new\s)(?!\w+\()(?!(?:null|undefined|true|false|None|nil|empty|""|''|0)\b)[^\s,;'"}\]]{6,}/gi, '$1***'],
45
74
  // access_token / refresh_token are the canonical OAuth2 field names — they were
package/server.mjs CHANGED
@@ -1745,7 +1745,10 @@ server.registerTool(
1745
1745
  },
1746
1746
  // verbatim: the export payload feeds `restore` — defanging it would silently
1747
1747
  // rewrite backed-up rows whose text legitimately contains these tags.
1748
- safeHandler(async (args) => runExport(db, args), { verbatim: true })
1748
+ safeHandler(
1749
+ async (args) => runExport(db, applyArgAliases(args, { from: 'date_from', to: 'date_to' })),
1750
+ { verbatim: true },
1751
+ )
1749
1752
  );
1750
1753
 
1751
1754
  // ─── Tool: mem_recall ────────────────────────────────────────────────────────
package/tool-schemas.mjs CHANGED
@@ -100,7 +100,7 @@ export const memSearchSchema = {
100
100
  or: coerceBool.optional().describe('Force OR semantics between query terms from the start (default: AND with automatic OR-fallback when AND returns 0). Aligns with CLI --or.'),
101
101
  deep: coerceBool.optional().describe('Tri-state LLM multi-query/HyDE deep search (observations-only). true=force; false=never; omit=AUTO (default ON for mem_search): a normal search that returns weak/few results auto-escalates with ONE Haiku call (query rewritten to keyword/concept/HyDE variants, RRF-fused). Set CLAUDE_MEM_AUTO_DEEP=0 to disable AUTO. Passive recall stays single-query.'),
102
102
  rerank: coerceBool.optional().describe('Opt-in: LLM-rerank the deep-search candidates for ranking precision (one extra Haiku call, ~1.4s). Requires deep=true (no effect on AUTO/normal). Reserve for hard, ranking-sensitive queries where the right memory is likely retrieved but mis-ranked — skip for routine search. Default off.'),
103
- // ── CLI-flag aliases (v3.60.2) ──────────────────────────────────────────────
103
+ // ── CLI-flag aliases (v3.61.0) ──────────────────────────────────────────────
104
104
  // A property the schema doesn't declare is STRIPPED by the validator, so a caller
105
105
  // using the CLI vocabulary (`--source` / `--from` / `--to` / `--since`) previously
106
106
  // got the UNFILTERED answer with nothing marking the filter as dropped — a wider
@@ -274,6 +274,11 @@ export const memExportSchema = {
274
274
  format: z.enum(['json', 'jsonl']).optional().describe('Output format (default: json)'),
275
275
  date_from: z.string().optional().describe('Start date (ISO 8601 or YYYY-MM-DD)'),
276
276
  date_to: z.string().optional().describe('End date (ISO 8601 or YYYY-MM-DD)'),
277
+ // CLI-flag aliases — `export` reads flags.from / flags.to (mem-cli.mjs). Same
278
+ // silent-drop defect the search/recent aliases fix, and the widest blast radius of
279
+ // the three: an ignored bound exports the whole DB instead of a date slice.
280
+ from: z.string().optional().describe('Alias for `date_from` (CLI `export --from`)'),
281
+ to: z.string().optional().describe('Alias for `date_to` (CLI `export --to`)'),
277
282
  include_compressed: coerceBool.optional().describe('Include compressed observations (default: false)'),
278
283
  limit: coerceInt.pipe(z.number().int().min(1).max(1000)).optional().describe('Max observations to export (default: 200, max: 1000)'),
279
284
  };