claude-mem-lite 2.84.0 → 2.84.2

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.84.0",
13
+ "version": "2.84.2",
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.84.0",
3
+ "version": "2.84.2",
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/README.md CHANGED
@@ -498,6 +498,24 @@ Checks Node.js version, dependencies, server/hook files, database integrity, FTS
498
498
 
499
499
  Shows MCP registration, hook configuration, plugin disabled state, and database stats (observation/session counts).
500
500
 
501
+ ### Recovery (stuck install / hook errors)
502
+
503
+ If you see `ERR_MODULE_NOT_FOUND` on PreToolUse:Read/Edit/Skill hooks, or `claude-mem-lite` commands crash with import errors, you're likely hit by a partial auto-update — the updater copied new scripts but missed a sibling `lib/*` file, breaking the hook chain (and the next auto-update that would have healed it).
504
+
505
+ **v2.84.0+** ships a `repair` subcommand that re-syncs from the latest GitHub release:
506
+
507
+ ```bash
508
+ claude-mem-lite repair
509
+ ```
510
+
511
+ **If `repair` itself fails** (the bin is older than v2.84.0, or the bin is also broken), run this one-liner — it pulls a fresh tarball into a temp dir and runs *that* tarball's `install.mjs`, bypassing every file on your disk:
512
+
513
+ ```bash
514
+ T=$(mktemp -d) && curl -sL https://api.github.com/repos/sdsrss/claude-mem-lite/tarball | tar xz -C "$T" --strip-components=1 && node "$T/install.mjs" install
515
+ ```
516
+
517
+ After it finishes, `~/.claude-mem-lite/` is back in sync with the latest release and `claude-mem-lite repair` is available for next time.
518
+
501
519
  ## Uninstall
502
520
 
503
521
  ```bash
package/README.zh-CN.md CHANGED
@@ -460,6 +460,24 @@ npx claude-mem-lite doctor # 诊断问题
460
460
 
461
461
  显示 MCP 注册状态、钩子配置、插件禁用状态和数据库统计(观察/会话数量)。
462
462
 
463
+ ### 故障恢复(安装卡死 / hook 报错)
464
+
465
+ 如果你看到 PreToolUse:Read/Edit/Skill hook 报 `ERR_MODULE_NOT_FOUND`,或者 `claude-mem-lite` 命令本身因为 import 错误崩溃,多半是被部分自动更新坑了——更新器复制了新脚本但漏了配套的 `lib/*` 文件,hook 链就此断掉(连下一次本可自愈的自动更新也跑不了)。
466
+
467
+ **v2.84.0+** 提供 `repair` 子命令,从 GitHub 最新 release 重新同步:
468
+
469
+ ```bash
470
+ claude-mem-lite repair
471
+ ```
472
+
473
+ **如果 `repair` 自己也跑不起来**(bin 比 v2.84.0 旧,或 bin 也坏了),用这条单行命令——它把最新 tarball 拉到临时目录、跑 *那份* tarball 里的 `install.mjs`,完全不依赖你磁盘上的任何文件:
474
+
475
+ ```bash
476
+ T=$(mktemp -d) && curl -sL https://api.github.com/repos/sdsrss/claude-mem-lite/tarball | tar xz -C "$T" --strip-components=1 && node "$T/install.mjs" install
477
+ ```
478
+
479
+ 跑完之后,`~/.claude-mem-lite/` 就和最新 release 对齐,`claude-mem-lite repair` 下次再遇到类似问题也能直接用了。
480
+
463
481
  ## 卸载
464
482
 
465
483
  ```bash
package/install.mjs CHANGED
@@ -5,7 +5,8 @@ import { execSync, execFileSync } from 'child_process';
5
5
  import { readFileSync, writeFileSync, existsSync, rmSync, mkdirSync, copyFileSync, cpSync, renameSync, symlinkSync, unlinkSync, readdirSync, statSync, lstatSync } from 'fs';
6
6
  import { join, resolve, dirname, isAbsolute } from 'path';
7
7
  import { homedir, tmpdir } from 'os';
8
- import { fileURLToPath } from 'url';
8
+ import { fileURLToPath, pathToFileURL } from 'url';
9
+ import { createRequire } from 'node:module';
9
10
 
10
11
  const PROJECT_DIR = resolve(import.meta.dirname ?? dirname(fileURLToPath(import.meta.url)));
11
12
  const SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
@@ -186,9 +187,19 @@ function registerVirtualResources(rdb) {
186
187
  );
187
188
  count += changes;
188
189
 
189
- // Backfill FTS5 fields for existing resources
190
+ // Backfill FTS5 fields for existing resources.
191
+ // ?N numbered placeholders REQUIRE object-form binding in better-sqlite3 —
192
+ // positional .run(v1, v2, …) always throws "Too many parameter values"
193
+ // regardless of arg count. Pre-fix this swallow-warned on every install
194
+ // (masked by install.mjs:785 import failure before the v2.84.2 path fix).
190
195
  if (changes === 0) {
191
- updateFts.run(meta.keywords || '', meta.tech_stack || '', meta.use_cases || '', type, name);
196
+ updateFts.run({
197
+ 1: meta.keywords || '',
198
+ 2: meta.tech_stack || '',
199
+ 3: meta.use_cases || '',
200
+ 4: type,
201
+ 5: name,
202
+ });
192
203
  }
193
204
  }
194
205
 
@@ -285,6 +296,16 @@ function isDevInstall() {
285
296
  async function install() {
286
297
  console.log('\nclaude-mem-lite installer\n');
287
298
 
299
+ // Resolve dynamic imports against the installed copy at INSTALL_DIR rather
300
+ // than install.mjs's own directory. Lets install.mjs run correctly from a
301
+ // /tmp staging dir (repair flow, `curl … | tar xz | node install.mjs install`)
302
+ // where PROJECT_DIR has no node_modules but INSTALL_DIR does — step 2 below
303
+ // ran `npm install --cwd INSTALL_DIR`. Pre-fix, steps 6/7 fired
304
+ // "Cannot find package 'better-sqlite3' imported from /tmp/…/registry.mjs"
305
+ // and silently skipped registry-DB seeding + DB health check on every repair.
306
+ const importFromInstall = (rel) => import(pathToFileURL(join(INSTALL_DIR, rel)).href);
307
+ const requireFromInstall = createRequire(pathToFileURL(join(INSTALL_DIR, 'package.json')).href);
308
+
288
309
  // 1. Install source files to ~/.claude-mem-lite/
289
310
  const IS_DEV = flags.has('--dev');
290
311
 
@@ -782,7 +803,7 @@ async function install() {
782
803
  (deadRepos.size > 0 ? `, ${deadRepos.size} dead removed` : ''));
783
804
 
784
805
  // 6b. Init registry DB and record preinstalled entries
785
- const { ensureRegistryDb } = await import('./registry.mjs');
806
+ const { ensureRegistryDb } = await importFromInstall('registry.mjs');
786
807
  const regDbPath = join(DATA_DIR, 'resource-registry.db');
787
808
  const rdb = ensureRegistryDb(regDbPath);
788
809
 
@@ -830,7 +851,7 @@ async function install() {
830
851
 
831
852
  // 6d. Scan and index resources (fallback-only, Haiku indexing deferred to first run)
832
853
  log(' Scanning resources...');
833
- const { scanAllResources, diffResources } = await import('./registry-scanner.mjs');
854
+ const { scanAllResources, diffResources } = await importFromInstall('registry-scanner.mjs');
834
855
  const scanned = scanAllResources({ dataDir: DATA_DIR });
835
856
 
836
857
  // Attach star counts and repo URLs
@@ -846,7 +867,7 @@ async function install() {
846
867
  if (toIndex.length > 0) {
847
868
  // Use fallback indexing at install time (no Haiku calls)
848
869
  // Full Haiku indexing happens on first SessionStart
849
- const { upsertResource } = await import('./registry.mjs');
870
+ const { upsertResource } = await importFromInstall('registry.mjs');
850
871
  for (const res of toIndex) {
851
872
  try {
852
873
  const metaKey = `${res.type}:${res.name}`;
@@ -892,7 +913,7 @@ async function install() {
892
913
  // 7. Verify database
893
914
  if (existsSync(DB_PATH)) {
894
915
  try {
895
- const Database = (await import('better-sqlite3')).default;
916
+ const Database = requireFromInstall('better-sqlite3');
896
917
  const db = new Database(DB_PATH, { readonly: true });
897
918
  const count = db.prepare('SELECT COUNT(*) as c FROM observations').get();
898
919
  db.close();
@@ -914,7 +935,7 @@ async function install() {
914
935
  const remote = execFileSync('git', ['-C', PROJECT_DIR, 'config', '--get', 'remote.origin.url'], { encoding: 'utf8', stdio: 'pipe' }).trim();
915
936
  const isDogfood = /github\.com[:/]sdsrss\/claude-mem-lite(\.git)?$/i.test(remote);
916
937
  if (isDogfood) {
917
- const { cmdAdopt } = await import('./adopt-cli.mjs');
938
+ const { cmdAdopt } = await importFromInstall('adopt-cli.mjs');
918
939
  cmdAdopt([]);
919
940
  ok('Invited-memory: auto-adopt for claude-mem-lite dogfood repo');
920
941
  }
@@ -1795,6 +1816,11 @@ async function repair() {
1795
1816
  ok('Repair complete — broken install resynced from latest release');
1796
1817
  } catch (e) {
1797
1818
  fail(`Repair failed: ${e.message}`);
1819
+ console.log('');
1820
+ console.log(' Manual fallback — run this in any shell:');
1821
+ console.log('');
1822
+ console.log(' T=$(mktemp -d) && curl -sL https://api.github.com/repos/sdsrss/claude-mem-lite/tarball | tar xz -C "$T" --strip-components=1 && node "$T/install.mjs" install');
1823
+ console.log('');
1798
1824
  process.exit(1);
1799
1825
  } finally {
1800
1826
  try { rmSync(stagingDir, { recursive: true, force: true }); } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "2.84.0",
3
+ "version": "2.84.2",
4
4
  "description": "Lightweight persistent memory system for Claude Code",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",
@@ -32,6 +32,13 @@ const RUNTIME_DIR = process.env.CLAUDE_MEM_DIR
32
32
  const HEAL_MARKER = join(RUNTIME_DIR, 'hook-launcher-lastheal');
33
33
  const HEAL_COOLDOWN_MS = 6 * 60 * 60 * 1000;
34
34
 
35
+ // Last-resort recovery string for users whose `claude-mem-lite repair` path
36
+ // itself failed (install.mjs missing / repair errored / retry still drifting).
37
+ // Duplicated in install.mjs::repair() catch; both are reachable when local
38
+ // scripts are broken, so neither can import a shared constant.
39
+ const TARBALL_FALLBACK =
40
+ 'T=$(mktemp -d) && curl -sL https://api.github.com/repos/sdsrss/claude-mem-lite/tarball | tar xz -C "$T" --strip-components=1 && node "$T/install.mjs" install';
41
+
35
42
  const [, , entryArg, ...rest] = process.argv;
36
43
  if (!entryArg) {
37
44
  process.stderr.write('[claude-mem-lite] hook-launcher: missing entry argument\n');
@@ -74,7 +81,9 @@ function recordHealAttempt() {
74
81
  async function attemptHeal(reason) {
75
82
  if (recentHealAttempt()) {
76
83
  process.stderr.write(
77
- `[claude-mem-lite] Self-heal skipped (last attempt < 6h ago). Manual recovery: claude-mem-lite repair\n`,
84
+ `[claude-mem-lite] Self-heal skipped (last attempt < 6h ago).\n` +
85
+ `[claude-mem-lite] Manual recovery: claude-mem-lite repair\n` +
86
+ `[claude-mem-lite] If that fails, run: ${TARBALL_FALLBACK}\n`,
78
87
  );
79
88
  return false;
80
89
  }
@@ -82,7 +91,10 @@ async function attemptHeal(reason) {
82
91
  process.stderr.write(`[claude-mem-lite] Detected broken install (${reason}) — running self-heal\n`);
83
92
  const installer = join(INSTALL_DIR, 'install.mjs');
84
93
  if (!existsSync(installer)) {
85
- process.stderr.write(`[claude-mem-lite] install.mjs missing at ${installer} — cannot self-heal\n`);
94
+ process.stderr.write(
95
+ `[claude-mem-lite] install.mjs missing at ${installer} — cannot self-heal\n` +
96
+ `[claude-mem-lite] Manual recovery: ${TARBALL_FALLBACK}\n`,
97
+ );
86
98
  return false;
87
99
  }
88
100
  const result = spawnSync(process.execPath, [installer, 'repair'], {
@@ -102,7 +114,10 @@ try {
102
114
  try {
103
115
  await runEntry({ bustCache: true });
104
116
  } catch (retryErr) {
105
- process.stderr.write(`[claude-mem-lite] Hook still failing after self-heal: ${retryErr.message}\n`);
117
+ process.stderr.write(
118
+ `[claude-mem-lite] Hook still failing after self-heal: ${retryErr.message}\n` +
119
+ `[claude-mem-lite] Manual recovery: ${TARBALL_FALLBACK}\n`,
120
+ );
106
121
  process.exit(1);
107
122
  }
108
123
  }