claude-mem-lite 6.12.0 → 6.12.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.
@@ -9,7 +9,7 @@
9
9
  "plugins": [
10
10
  {
11
11
  "name": "claude-mem-lite",
12
- "version": "6.12.0",
12
+ "version": "6.12.1",
13
13
  "source": "./",
14
14
  "homepage": "https://github.com/sdsrss/claude-mem-lite",
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)."
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "6.12.0",
3
+ "version": "6.12.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/README.md CHANGED
@@ -165,7 +165,7 @@ is still outside it gets a message naming both sides of the mismatch instead of
165
165
 
166
166
  Plugin mode manages its own hooks/runtime. On session start it only **checks and reports** new claude-mem-lite versions; it does **not** self-overwrite plugin files in place. Update plugin-mode installs through Claude's plugin workflow.
167
167
 
168
- > **The plugin install is complete on its own** — hooks, MCP tools, and the bundled slash commands (`/mem`, `/lesson`, `/bug`, `/adopt`) all run from the plugin with no second step. The slash commands invoke the bundled CLI by an absolute path resolved from the plugin directory (`${CLAUDE_PLUGIN_ROOT}/cli.mjs <cmd>`), so they work without anything on your `PATH`. A global `claude-mem-lite` **shell** command (for running queries yourself in a terminal) is **optional** — `npm i -g claude-mem-lite` — and is a *separate* npm install: the plugin's auto-update does **not** refresh it, so re-run `npm i -g claude-mem-lite@latest` if you want that shell command kept in sync. You do **not** need it for the plugin to be fully functional.
168
+ > **The plugin install is complete on its own** — hooks, MCP tools, and the bundled slash commands (`/mem`, `/lesson`, `/bug`, `/adopt`) all run from the plugin with no second step. The slash commands invoke the bundled CLI by an absolute path resolved from the plugin directory (`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`), so they work without anything on your `PATH`. A global `claude-mem-lite` **shell** command (for running queries yourself in a terminal) is **optional** — `npm i -g claude-mem-lite` — and is a *separate* npm install: the plugin's auto-update does **not** refresh it, so re-run `npm i -g claude-mem-lite@latest` if you want that shell command kept in sync. You do **not** need it for the plugin to be fully functional.
169
169
 
170
170
  > **Auto-adopt writes into your project, on every SessionStart (v3.13+).** The plugin adds a slug-scoped **managed block** to your project's own **`<cwd>/CLAUDE.md`** — a file that is normally committed to git — plus a `<cwd>/.claude/plugin_claude_mem_lite.md` detail file. The block is a system-authority pointer that boosts Claude's proactive use of `mem_recall` / `mem_save`. Everything outside the block is preserved verbatim, and it coexists with other plugins' blocks in the same file ([details](#invited-memory-v232)). This happens on **every** SessionStart, not just the first: the sync is idempotent and re-applies the block if it is edited away, and refreshes it when the shipped template changes. It applies regardless of install path (npm, npx, `/plugin`, manual), so **no manual `/adopt` is needed**.
171
171
  >
package/README.zh-CN.md CHANGED
@@ -129,7 +129,7 @@ v5.1.0 到 v6.1.0 之间,`package.json` 声明的是 `os: ["darwin", "linux"]`
129
129
 
130
130
  插件模式会管理自己的运行时与钩子。SessionStart 时它现在只会**检查并提示**新版本,不会直接覆盖插件目录中的文件。插件模式请通过 Claude 的插件更新流程完成升级。
131
131
 
132
- > **插件安装本身即完整** —— hooks、MCP 工具、以及捆绑的 slash 命令(`/mem`、`/lesson`、`/bug`、`/adopt`)全部从插件内运行,无需第二步。slash 命令以从插件目录解析出的绝对路径调用捆绑 CLI(`${CLAUDE_PLUGIN_ROOT}/cli.mjs <cmd>`),因此不依赖 `PATH` 上的任何东西。全局 `claude-mem-lite` **shell** 命令(用于你自己在终端里跑查询)是**可选**的 —— `npm i -g claude-mem-lite` —— 且是**独立**的 npm 安装:插件的自动更新**不会**刷新它,想保持同步就重新跑 `npm i -g claude-mem-lite@latest`。插件要完整工作**并不需要**它。
132
+ > **插件安装本身即完整** —— hooks、MCP 工具、以及捆绑的 slash 命令(`/mem`、`/lesson`、`/bug`、`/adopt`)全部从插件内运行,无需第二步。slash 命令以从插件目录解析出的绝对路径调用捆绑 CLI(`node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" <cmd>`),因此不依赖 `PATH` 上的任何东西。全局 `claude-mem-lite` **shell** 命令(用于你自己在终端里跑查询)是**可选**的 —— `npm i -g claude-mem-lite` —— 且是**独立**的 npm 安装:插件的自动更新**不会**刷新它,想保持同步就重新跑 `npm i -g claude-mem-lite@latest`。插件要完整工作**并不需要**它。
133
133
 
134
134
  ### 方式二:npx(一行命令)
135
135
 
package/cli/common.mjs CHANGED
@@ -417,6 +417,21 @@ export const KNOWN_CLI_FLAGS = new Set([
417
417
  // --has?" suggestion. Locked by tests/cli-flag-allowlist.test.mjs.
418
418
  ]);
419
419
 
420
+ /**
421
+ * Flags exactly ONE subcommand reads, mapped to that command. KNOWN_CLI_FLAGS is a union, so
422
+ * without this `recent --apply` was accepted in silence while `--apply` did nothing there.
423
+ * Every other command mem-cli dispatches now reports such a flag, and the typo suggester stops
424
+ * offering it there. Install-family commands (doctor, status, …) route to install.mjs and are
425
+ * not covered. Only flags with a single reader
426
+ * belong here; tests/cli-flag-allowlist.test.mjs derives that from the sources.
427
+ */
428
+ export const COMMAND_SCOPED_FLAGS = new Map([
429
+ ['apply', 'verify-apply'],
430
+ ['digest', 'verify-apply'],
431
+ ['print-project', 'verify-apply'],
432
+ ['undo', 'verify-apply'],
433
+ ]);
434
+
420
435
  /** Levenshtein distance, early-exit past `max` (cheap enough for a handful of flags). */
421
436
  function editDistance(a, b, max = 2) {
422
437
  const m = a.length,
@@ -444,16 +459,25 @@ function editDistance(a, b, max = 2) {
444
459
  * project — a typo produced a wrong result with zero signal. Returns [{flag, suggestion}].
445
460
  * Unknown flags with NO close match are omitted: they may be a valid flag we didn't
446
461
  * catalog, so silence beats a false alarm. Warning-only by contract — never fails.
462
+ * A flag in COMMAND_SCOPED_FLAGS given to any other `cmd` is reported too, with `owner` set.
447
463
  * @param {object} flags Parsed flags from parseArgs.
448
- * @returns {Array<{flag: string, suggestion: string}>}
464
+ * @param {string} [cmd] The subcommand being run; without it scoped flags are not checked.
465
+ * @returns {Array<{flag: string, suggestion: string|null, owner?: string}>}
449
466
  */
450
- export function suggestUnknownFlags(flags) {
467
+ export function suggestUnknownFlags(flags, cmd) {
451
468
  const result = [];
452
469
  for (const key of Object.keys(flags)) {
470
+ const owner = COMMAND_SCOPED_FLAGS.get(key);
471
+ if (cmd && owner && owner !== cmd) {
472
+ result.push({ flag: key, suggestion: null, owner });
473
+ continue;
474
+ }
453
475
  if (!key || KNOWN_CLI_FLAGS.has(key)) continue;
454
476
  let best = null,
455
477
  bestDist = 3;
456
478
  for (const known of KNOWN_CLI_FLAGS) {
479
+ const knownOwner = COMMAND_SCOPED_FLAGS.get(known);
480
+ if (cmd && knownOwner && knownOwner !== cmd) continue;
457
481
  const d = editDistance(key, known);
458
482
  if (d < bestDist) {
459
483
  bestDist = d;
@@ -23,6 +23,7 @@ import {
23
23
  markUndone,
24
24
  } from '../lib/verify-apply-core.mjs';
25
25
  import { parseArgs, out, fail, rejectBareStringFlags } from './common.mjs';
26
+ import { shellWord } from '../cli-path.mjs';
26
27
 
27
28
  const USAGE =
28
29
  '[mem] Usage: claude-mem-lite verify-apply <proposals.json> [--project P] (dry run)\n' +
@@ -34,8 +35,6 @@ const BACKUP_DIR = join(DB_DIR, 'backups');
34
35
  // The commands this prints must run as printed. `claude-mem-lite` is on PATH only after an
35
36
  // optional global npm install (which may also be a different, stale code home), so name the
36
37
  // node binary and THIS cli.mjs — the one that produced the plan.
37
- /** A path as one shell word: as-is when it is plain, single-quoted otherwise. */
38
- const shellWord = (s) => (/^[\w@%+=:,./-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`);
39
38
  const SELF = process.argv[1] ? `node ${shellWord(process.argv[1])}` : 'claude-mem-lite';
40
39
 
41
40
  function readJson(path, what) {
package/cli-path.mjs CHANGED
@@ -22,4 +22,14 @@ import { join, dirname } from 'node:path';
22
22
  // module from its unused-export report entirely. Enforced by
23
23
  // tests/no-url-module-paths.test.mjs.
24
24
  export const CLI_PATH = join(dirname(fileURLToPath(import.meta.url)), 'cli.mjs');
25
- export const CLI_INVOKE = `node ${CLI_PATH}`;
25
+ /**
26
+ * A path as one shell word: as-is when it is plain, single-quoted otherwise. Conditional on
27
+ * purpose — CLI_INVOKE is LLM-visible (MCP instructions, every "Equivalent CLI" hint), so an
28
+ * ordinary install path must stay byte-identical; only a path with a space or a shell
29
+ * metacharacter gets quotes, which it needs to survive as ONE argument.
30
+ * @param {string} s
31
+ * @returns {string}
32
+ */
33
+ export const shellWord = (s) => (/^[\w@%+=:,./-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\''`)}'`);
34
+
35
+ export const CLI_INVOKE = `node ${shellWord(CLI_PATH)}`;
package/commands/adopt.md CHANGED
@@ -64,4 +64,4 @@ server builds its instructions once at boot, so the MCP-instructions trim
64
64
  (or re-attaches the mem-lite MCP server). A `/exit` + fresh session is enough.
65
65
  Same caveat applies in reverse for `/unadopt`.
66
66
 
67
- !node ${CLAUDE_PLUGIN_ROOT}/cli.mjs adopt $ARGUMENTS
67
+ !node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" adopt $ARGUMENTS
package/commands/bug.md CHANGED
@@ -49,7 +49,7 @@ goes in `--lesson` so it lands in the high-weight `lesson_learned` field.
49
49
  body in the positional content and trim `--lesson` to the core description if
50
50
  longer:
51
51
 
52
- node ${CLAUDE_PLUGIN_ROOT}/cli.mjs save "<body>" \
52
+ node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" save "<body>" \
53
53
  --type bugfix \
54
54
  --title "<first 60 chars of description>" \
55
55
  --lesson "<description, ≤500 chars>" \
@@ -42,7 +42,7 @@ field. `--lesson` is capped at 500 chars (longer values are rejected), so for a
42
42
  long lesson keep the full text in the positional content and trim `--lesson` to
43
43
  the core insight:
44
44
 
45
- node ${CLAUDE_PLUGIN_ROOT}/cli.mjs save "<full text>" \
45
+ node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" save "<full text>" \
46
46
  --type discovery \
47
47
  --title "<first 60 chars of text>" \
48
48
  --lesson "<core insight, ≤500 chars>" \
package/commands/mem.md CHANGED
@@ -23,16 +23,16 @@ Search and browse your project memory efficiently.
23
23
 
24
24
  When the user invokes `/mem`, parse their intent:
25
25
 
26
- - `/mem search <query>` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs search <query>` via Bash
27
- - `/mem recent` or `/mem recent 20` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs recent [N]` via Bash
28
- - `/mem recall <file>` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs recall <file>` via Bash
29
- - `/mem timeline <id>` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs timeline --anchor <id>` via Bash
26
+ - `/mem search <query>` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" search <query>` via Bash
27
+ - `/mem recent` or `/mem recent 20` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" recent [N]` via Bash
28
+ - `/mem recall <file>` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" recall <file>` via Bash
29
+ - `/mem timeline <id>` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" timeline --anchor <id>` via Bash
30
30
  - `/mem save <text>` → call `mem_save` MCP tool with the text as content
31
- - `/mem stats` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs stats` via Bash
32
- - `/mem get <ids>` → run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs get <ids>` via Bash
31
+ - `/mem stats` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" stats` via Bash
32
+ - `/mem get <ids>` → run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" get <ids>` via Bash
33
33
  - `/mem cleanup` → run `mem_maintain(action="scan")`, report pending purge count and stale items to user, ask for confirmation, then run `mem_maintain(action="execute", operations=["purge_stale"], confirm=true)` if confirmed. **`confirm=true` is required and is not optional politeness:** without it the call returns a dry-run PREVIEW and deletes nothing, while still succeeding — so you would report a cleanup that never happened.
34
34
  - `/mem cleanup Nd` (e.g. `60d`) → same as above but add `retain_days=N` to only purge items older than N days. **`retain_days` must be between 7 and 365**; anything outside that range is rejected by the schema, so `/mem cleanup 3d` cannot be honoured — say so rather than silently substituting the default.
35
35
  - `/mem cleanup keep Nd` (e.g. `keep 14d`) → same as above with `retain_days=N`, same 7–365 range.
36
- - `/mem <query>` (no subcommand) → treat as search, run `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs search <query>` via Bash
36
+ - `/mem <query>` (no subcommand) → treat as search, run `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" search <query>` via Bash
37
37
 
38
- Use Bash commands first. For detailed data, use `node ${CLAUDE_PLUGIN_ROOT}/cli.mjs get <id>` via Bash.
38
+ Use Bash commands first. For detailed data, use `node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" get <id>` via Bash.
@@ -43,4 +43,4 @@ Once unadopted, the conservative hook layer (SessionStart `File Lessons` /
43
43
  `Key Context`, MCP instructions `WHEN TO USE`) returns to verbose mode on the
44
44
  next session start.
45
45
 
46
- !node ${CLAUDE_PLUGIN_ROOT}/cli.mjs unadopt $ARGUMENTS
46
+ !node "${CLAUDE_PLUGIN_ROOT}/cli.mjs" unadopt $ARGUMENTS
package/install.mjs CHANGED
@@ -723,7 +723,7 @@ function registerMcpServer() {
723
723
  ok('MCP server registered: mem-lite');
724
724
  } catch (e) {
725
725
  fail('MCP registration failed: ' + e.message);
726
- warn('Try manually: claude mcp add -s user -t stdio mem-lite -- node ' + SERVER_PATH);
726
+ warn('Try manually: claude mcp add -s user -t stdio mem-lite -- node "' + SERVER_PATH + '"');
727
727
  }
728
728
  }
729
729
  }
@@ -2004,7 +2004,7 @@ async function doctor() {
2004
2004
  // misbehaving, which is the worst moment to hand out the one entry that cannot
2005
2005
  // survive a missing module. Pre-ship review of v6.7.0 caught this one left behind.
2006
2006
  dwarn(
2007
- `Hook self-heal: a recent hook fire degraded to exit-0${detail} — run \`node ${join(PROJECT_DIR, 'cli.mjs')} repair\``,
2007
+ `Hook self-heal: a recent hook fire degraded to exit-0${detail} — run \`node "${join(PROJECT_DIR, 'cli.mjs')}" repair\``,
2008
2008
  );
2009
2009
  } else {
2010
2010
  ok('Hook self-heal: no recent silent hook breakage');
@@ -2020,7 +2020,7 @@ async function doctor() {
2020
2020
  // should not pay for another round of child spawns to ask it twice.
2021
2021
  if (brokenRoots.length > 0) {
2022
2022
  fail(
2023
- `Native DB binding: unusable in ${brokenRoots.map((b) => b.label).join(', ')} — run \`node ${join(PROJECT_DIR, 'cli.mjs')} rebuild-binding\` (repairs every broken install, not just this one)`,
2023
+ `Native DB binding: unusable in ${brokenRoots.map((b) => b.label).join(', ')} — run \`node "${join(PROJECT_DIR, 'cli.mjs')}" rebuild-binding\` (repairs every broken install, not just this one)`,
2024
2024
  );
2025
2025
  issues++;
2026
2026
  } else if (breakage) {
@@ -2136,7 +2136,9 @@ async function doctor() {
2136
2136
  );
2137
2137
  for (const p of orphanPaths.slice(0, 5)) log(` missing: ${p}`);
2138
2138
  if (orphanPaths.length > 5) log(` ... +${orphanPaths.length - 5} more`);
2139
- log(` Repair: node ${join(PROJECT_DIR, 'install.mjs')} uninstall # removes the dead hook entries`);
2139
+ log(
2140
+ ` Repair: node "${join(PROJECT_DIR, 'install.mjs')}" uninstall # removes the dead hook entries`,
2141
+ );
2140
2142
  issues++;
2141
2143
  } else if (hasHooks) {
2142
2144
  ok('Orphan hooks: none (all hook targets present)');
@@ -2406,12 +2408,12 @@ async function doctor() {
2406
2408
  // already there.
2407
2409
  const noCodeInstall =
2408
2410
  !shape.managed && !shape.activePluginVersion && !hasAnyManagedCode(INSTALL_DIR, SOURCE_FILES);
2409
- const installRemedy = `node ${join(PROJECT_DIR, 'install.mjs')} install`;
2411
+ const installRemedy = `node "${join(PROJECT_DIR, 'install.mjs')}" install`;
2410
2412
  try {
2411
2413
  const skipDrift = !shape.managed && !!shape.activePluginVersion;
2412
2414
  const { checkDevDrift } = await import('./lib/doctor-drift.mjs');
2413
2415
  const r = skipDrift ? null : checkDevDrift(INSTALL_DIR, SOURCE_FILES);
2414
- const devRemedy = `re-run: node ${join(PROJECT_DIR, 'install.mjs')} install --dev`;
2416
+ const devRemedy = `re-run: node "${join(PROJECT_DIR, 'install.mjs')}" install --dev`;
2415
2417
  const nameList = (files, count) => {
2416
2418
  const suffix = count > files.length ? ` +${count - files.length} more` : '';
2417
2419
  return `${files.join(', ')}${suffix}`;
@@ -2483,7 +2485,7 @@ async function doctor() {
2483
2485
  `a damaged one. Fix: ${installRemedy}`
2484
2486
  : `Managed files: ${r.missingCount} missing (${parts.join('; ')}) — a copy install resolves ` +
2485
2487
  `imports against the install dir, so these throw at hook time. Fix: claude-mem-lite self-update ` +
2486
- `(or: node ${join(INSTALL_DIR, 'cli.mjs')} repair)`,
2488
+ `(or: node "${join(INSTALL_DIR, 'cli.mjs')}" repair)`,
2487
2489
  );
2488
2490
  }
2489
2491
  // Complete copy install: no message — drift is a dev-install concern.
@@ -2511,7 +2513,7 @@ async function doctor() {
2511
2513
  // `noCodeInstall` above: the `repair` route runs from an entry point that is itself absent.
2512
2514
  const scriptRemedy = noCodeInstall
2513
2515
  ? installRemedy
2514
- : `claude-mem-lite self-update (or: node ${join(INSTALL_DIR, 'cli.mjs')} repair)`;
2516
+ : `claude-mem-lite self-update (or: node "${join(INSTALL_DIR, 'cli.mjs')}" repair)`;
2515
2517
  if (skipScripts) {
2516
2518
  ok('Hook scripts: n/a (plugin-only install — hooks run from the plugin cache)');
2517
2519
  } else if (!h.present) {
@@ -324,7 +324,7 @@ export function probeRuntimeRoots(roots, deps = {}) {
324
324
  // "none resolvable from a parent directory" and was caught printing that
325
325
  // next to a probe error naming the parent tree it had just loaded from.
326
326
  error: `${error} — and this install owns no node_modules/better-sqlite3, so there is nothing here to rebuild`,
327
- repair: `cd ${root} && npm install --omit=dev`,
327
+ repair: `cd "${root}" && npm install --omit=dev`,
328
328
  };
329
329
  });
330
330
  }
@@ -45,7 +45,7 @@ export const NATIVE_BINDING_BROKEN_MARKER = 'native-binding-broken';
45
45
  // D#207: join(), not `new URL('../cli.mjs', …)` — that form makes knip drop the named
46
46
  // module out of its unused-export report. cli.mjs is a knip entry point so nothing was
47
47
  // lost here, but the rule is enforced for the class rather than per-file.
48
- const CLI_REBUILD_BINDING = `node ${join(dirname(fileURLToPath(import.meta.url)), '..', 'cli.mjs')} rebuild-binding`;
48
+ const CLI_REBUILD_BINDING = `node "${join(dirname(fileURLToPath(import.meta.url)), '..', 'cli.mjs')}" rebuild-binding`;
49
49
 
50
50
  // Stable-ish identity of a fault so DISTINCT failures get DISTINCT cooldown
51
51
  // windows: the same fault → same key (suppressed within the window), a different
package/mem-cli.mjs CHANGED
@@ -3692,11 +3692,13 @@ async function runDispatch(argv) {
3692
3692
  // project — a misspelled flag changed results with zero signal. Warn (stderr, non-fatal)
3693
3693
  // when a flag looks like a misspelling of a real one; stdout + exit code stay untouched,
3694
3694
  // so JSON/text consumers are unaffected. Mirrors the unknown-COMMAND suggester in cli.mjs.
3695
- for (const { flag, suggestion } of suggestUnknownFlags(parseArgs(cmdArgs).flags)) {
3695
+ for (const { flag, suggestion, owner } of suggestUnknownFlags(parseArgs(cmdArgs).flags, cmd)) {
3696
3696
  process.stderr.write(
3697
- suggestion
3698
- ? `[mem] Unknown flag --${flag}; did you mean --${suggestion}?\n`
3699
- : `[mem] Unknown flag --${flag} — ignored, it had no effect. Run "claude-mem-lite help" for this command's flags.\n`,
3697
+ owner
3698
+ ? `[mem] --${flag} is read only by ${owner}; ${cmd} does not read it.\n`
3699
+ : suggestion
3700
+ ? `[mem] Unknown flag --${flag}; did you mean --${suggestion}?\n`
3701
+ : `[mem] Unknown flag --${flag} — ignored, it had no effect. Run "claude-mem-lite help" for this command's flags.\n`,
3700
3702
  );
3701
3703
  }
3702
3704
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "6.12.0",
3
+ "version": "6.12.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "claude-mem-lite",
9
- "version": "6.12.0",
9
+ "version": "6.12.1",
10
10
  "os": [
11
11
  "darwin",
12
12
  "linux",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "6.12.0",
3
+ "version": "6.12.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",
@@ -125,7 +125,7 @@ const NB_MANUAL_CMD =
125
125
  // INSTALL_DIR (import.meta.url) so it works on a plugin-only install, where
126
126
  // bare `claude-mem-lite` is not on PATH and ~/.claude-mem-lite/ holds no source.
127
127
  // cli.mjs routes `repair` → install.mjs. (review #3)
128
- const CLI_REPAIR = `node ${join(INSTALL_DIR, 'cli.mjs')} repair`;
128
+ const CLI_REPAIR = `node "${join(INSTALL_DIR, 'cli.mjs')}" repair`;
129
129
 
130
130
  // Last-resort recovery string for users whose `cli.mjs repair` path
131
131
  // itself failed (install.mjs missing / repair errored / retry still drifting).
@@ -648,7 +648,8 @@ try {
648
648
  ORDER BY
649
649
  CASE WHEN o.lesson_learned IS NOT NULL AND o.lesson_learned != '' THEN 0 ELSE 1 END,
650
650
  ${citeFactorClause('o')} DESC,
651
- o.created_at_epoch DESC
651
+ o.created_at_epoch DESC,
652
+ o.id DESC
652
653
  LIMIT ${obsLimit}
653
654
  `,
654
655
  )
@@ -691,7 +692,8 @@ try {
691
692
  ${eventsBodyFilter}
692
693
  ORDER BY
693
694
  CASE WHEN body IS NOT NULL AND body != '' THEN 0 ELSE 1 END,
694
- created_at_epoch DESC
695
+ created_at_epoch DESC,
696
+ id DESC
695
697
  LIMIT ${eventsLimit}
696
698
  `,
697
699
  )