claude-mem-lite 2.53.0 → 2.53.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.53.0",
13
+ "version": "2.53.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.53.0",
3
+ "version": "2.53.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/install.mjs CHANGED
@@ -524,14 +524,19 @@ async function install() {
524
524
  try {
525
525
  const cacheBase = join(homedir(), '.claude', 'plugins', 'cache', MARKETPLACE_KEY, 'claude-mem-lite');
526
526
  if (existsSync(cacheBase)) {
527
- const srcLaunch = join(PROJECT_DIR, 'scripts', 'launch.mjs');
527
+ const launchSyncFiles = ['launch.mjs', 'launch-preflight.mjs'];
528
528
  let clearedHooks = 0;
529
529
  for (const ver of readdirSync(cacheBase)) {
530
530
  const verDir = join(cacheBase, ver);
531
531
 
532
- // Sync launch.mjs
532
+ // Sync launch.mjs + its preflight companion (issue #15)
533
533
  if (existsSync(join(verDir, 'scripts'))) {
534
- try { copyFileSync(srcLaunch, join(verDir, 'scripts', 'launch.mjs')); } catch {}
534
+ for (const f of launchSyncFiles) {
535
+ const src = join(PROJECT_DIR, 'scripts', f);
536
+ if (existsSync(src)) {
537
+ try { copyFileSync(src, join(verDir, 'scripts', f)); } catch { /* keep going */ }
538
+ }
539
+ }
535
540
  }
536
541
 
537
542
  // Clear cached hooks.json (runtime reads here, not marketplace source)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "2.53.0",
3
+ "version": "2.53.1",
4
4
  "description": "Lightweight persistent memory system for Claude Code",
5
5
  "type": "module",
6
6
  "engines": {
@@ -98,6 +98,7 @@
98
98
  "commands/bug.md",
99
99
  "hooks/hooks.json",
100
100
  "scripts/launch.mjs",
101
+ "scripts/launch-preflight.mjs",
101
102
  "scripts/setup.sh",
102
103
  "scripts/post-tool-use.sh",
103
104
  "scripts/user-prompt-search.js",
@@ -0,0 +1,79 @@
1
+ // launch-preflight.mjs — Detect incomplete installs at MCP server launch.
2
+ //
3
+ // Why: issue #15 — published v2.53.0 npm tarball contains all files, but some
4
+ // users end up with a partial install (server.mjs present, search-engine.mjs
5
+ // missing) and the resulting ERR_MODULE_NOT_FOUND has no actionable message.
6
+ // We can't fix every cause (mirror lag / interrupted download / npm cache
7
+ // corruption / permission) on the user side, but we can detect the broken
8
+ // state and either fall back to ~/.claude-mem-lite/ (which hook-update.mjs
9
+ // keeps healthy) or print a clear repair command instead of a Node stack.
10
+ //
11
+ // Pure module — no I/O at import time, all deps injected. Tested in isolation;
12
+ // scripts/launch.mjs wires it to the actual filesystem + stderr.
13
+
14
+ import { existsSync, readFileSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+
17
+ // Match relative `.mjs` imports — covers all four ESM forms:
18
+ // from './x.mjs' (static named/default/namespace)
19
+ // import './x.mjs' (side-effect static)
20
+ // await import('./x.mjs') (dynamic)
21
+ // import('./x.mjs') without await (dynamic)
22
+ // Skips 'node:*' / package imports / non-mjs paths.
23
+ const FROM_RE = /\bfrom\s+['"](\.\/[^'"]+\.mjs)['"]/g;
24
+ const IMPORT_RE = /\bimport\s*\(?\s*['"](\.\/[^'"]+\.mjs)['"]/g;
25
+
26
+ export function detectMissingImports(installRoot) {
27
+ const serverPath = join(installRoot, 'server.mjs');
28
+ if (!existsSync(serverPath)) return ['server.mjs'];
29
+
30
+ let src;
31
+ try {
32
+ src = readFileSync(serverPath, 'utf8');
33
+ } catch {
34
+ return ['server.mjs'];
35
+ }
36
+
37
+ const missing = new Set();
38
+ for (const re of [FROM_RE, IMPORT_RE]) {
39
+ re.lastIndex = 0;
40
+ for (const m of src.matchAll(re)) {
41
+ const rel = m[1].replace(/^\.\//, '');
42
+ if (!existsSync(join(installRoot, rel))) missing.add(rel);
43
+ }
44
+ }
45
+ return [...missing];
46
+ }
47
+
48
+ export function resolveLaunchEntry({ primaryRoot, fallbackRoot, warn = () => {} }) {
49
+ const primaryMissing = detectMissingImports(primaryRoot);
50
+ if (primaryMissing.length === 0) {
51
+ return { path: join(primaryRoot, 'server.mjs'), source: 'primary' };
52
+ }
53
+
54
+ if (fallbackRoot && fallbackRoot !== primaryRoot) {
55
+ const fallbackMissing = detectMissingImports(fallbackRoot);
56
+ if (fallbackMissing.length === 0) {
57
+ warn(
58
+ `[claude-mem-lite] Primary install incomplete at ${primaryRoot} ` +
59
+ `(missing: ${primaryMissing.join(', ')}). Falling back to ${fallbackRoot}.`,
60
+ );
61
+ return {
62
+ path: join(fallbackRoot, 'server.mjs'),
63
+ source: 'fallback',
64
+ missingFromPrimary: primaryMissing,
65
+ };
66
+ }
67
+ }
68
+
69
+ const repairCmd = 'npm install -g claude-mem-lite@latest --force';
70
+ const err = new Error(
71
+ `[claude-mem-lite] Install incomplete at ${primaryRoot}\n` +
72
+ `[claude-mem-lite] Missing: ${primaryMissing.join(', ')}\n` +
73
+ `[claude-mem-lite] Repair: ${repairCmd}\n` +
74
+ `[claude-mem-lite] Or via Claude Code: /plugin uninstall claude-mem-lite && /plugin install claude-mem-lite@sdsrss`,
75
+ );
76
+ err.code = 'INSTALL_INCOMPLETE';
77
+ err.missing = primaryMissing;
78
+ throw err;
79
+ }
@@ -45,12 +45,31 @@ try {
45
45
  // Dev mode: prefer ~/.claude-mem-lite/server.mjs (symlinked to source) over
46
46
  // CLAUDE_PLUGIN_ROOT (potentially stale plugin cache). This ensures the MCP
47
47
  // server always runs the latest code when installed with `install --dev`.
48
- const devServer = join(homedir(), '.claude-mem-lite', 'server.mjs');
48
+ const dataDir = join(homedir(), '.claude-mem-lite');
49
+ const devServer = join(dataDir, 'server.mjs');
49
50
  let useDevServer = false;
50
51
  try { useDevServer = existsSync(devServer) && lstatSync(devServer).isSymbolicLink(); } catch {}
51
52
 
52
53
  if (useDevServer) {
53
54
  await import(pathToFileURL(devServer).href);
54
55
  } else {
55
- await import(new URL('../server.mjs', import.meta.url).href);
56
+ // Preflight: detect incomplete primary install (issue #15) — if relative
57
+ // imports referenced by server.mjs are missing on disk, fall back to the
58
+ // hook-update.mjs-maintained ~/.claude-mem-lite/ copy when healthy, or exit
59
+ // with a clear repair command instead of a Node ERR_MODULE_NOT_FOUND stack.
60
+ const { resolveLaunchEntry } = await import('./launch-preflight.mjs');
61
+ try {
62
+ const entry = resolveLaunchEntry({
63
+ primaryRoot: ROOT,
64
+ fallbackRoot: dataDir,
65
+ warn: (msg) => process.stderr.write(msg + '\n'),
66
+ });
67
+ await import(pathToFileURL(entry.path).href);
68
+ } catch (e) {
69
+ if (e.code === 'INSTALL_INCOMPLETE') {
70
+ process.stderr.write(e.message + '\n');
71
+ process.exit(1);
72
+ }
73
+ throw e;
74
+ }
56
75
  }