claude-mem-lite 3.70.0 → 3.70.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.70.0",
13
+ "version": "3.70.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.70.0",
3
+ "version": "3.70.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"
@@ -116,7 +116,7 @@ export function listPluginCacheVersions(opts = {}) {
116
116
  * twice would double every failure message for a single fault.
117
117
  *
118
118
  * @param {{home?: string, projectDir?: string, installDir?: string, marketplace?: string, plugin?: string, pluginRoot?: string}} opts
119
- * @returns {{managed: boolean, pluginVersions: Array<{version: string, root: string}>, activePluginVersion: {version: string, root: string}|null, runtimeRoots: Array<{label: string, root: string, depsMissing?: boolean}>}}
119
+ * @returns {{managed: boolean, pluginVersions: Array<{version: string, root: string}>, activePluginVersion: {version: string, root: string}|null, runtimeRoots: Array<{label: string, root: string, ownDeps: boolean}>}}
120
120
  */
121
121
  export function detectInstallShape({
122
122
  home = homedir(), projectDir, installDir, marketplace, plugin,
@@ -137,31 +137,43 @@ export function detectInstallShape({
137
137
  || null;
138
138
 
139
139
  const runtimeRoots = [];
140
- const byBinding = new Map();
140
+ const byKey = new Map();
141
141
  const add = (label, root, { certified = false } = {}) => {
142
142
  if (!root) return;
143
143
  const bs3 = join(root, 'node_modules', 'better-sqlite3');
144
- if (!existsSync(bs3)) {
145
- // A dir that merely lacks deps is not a runtime root — but one this function
146
- // just CERTIFIED as a code home is. Its hooks and MCP server load from it and
147
- // throw ERR_MODULE_NOT_FOUND on every fire, and that error is not in
148
- // NATIVE_BINDING_PATTERNS, so nothing else records it either. Dropping it
149
- // turned a pre-v3.70 exit 1 into exit 0 (pre-tag review, SHOULD-FIX 1).
150
- if (certified && existsSync(root)) runtimeRoots.push({ label, root, depsMissing: true });
151
- return;
144
+ const ownDeps = existsSync(bs3);
145
+ // A dir that merely lacks deps is not a runtime root — but one this function
146
+ // just CERTIFIED as a code home is, because that is where hooks and the MCP
147
+ // server load from. Dropping it turned a pre-v3.70 exit 1 into exit 0.
148
+ //
149
+ // It is added as a probe TARGET, not pre-judged broken. v3.70.0 pre-judged it,
150
+ // which over-corrected into a false red: Node resolves a specifier up the
151
+ // directory tree, so a code home nested under an ancestor that owns a working
152
+ // better-sqlite3 loads perfectly well. Measured on that build — ground-truth
153
+ // probe {ok:true} against a verdict of "absent, every hook throws". Owning the
154
+ // tree is not the question; being able to LOAD is, and only a probe answers it.
155
+ if (!ownDeps && !(certified && existsSync(root))) return;
156
+
157
+ // Dedup on the binding's realpath when there is one (scripts/setup.sh symlinks a
158
+ // plugin cache's node_modules at the managed dir's, so two homes routinely share
159
+ // one tree and one probe answers for both). With no own tree there is no binding
160
+ // path to key on, so key on the root itself.
161
+ let key = root;
162
+ if (ownDeps) {
163
+ key = bs3;
164
+ try { key = realpathSync(bs3); } catch { /* unresolvable → key on the literal path */ }
165
+ } else {
166
+ try { key = realpathSync(root); } catch { /* ditto */ }
152
167
  }
153
- let key = bs3;
154
- try { key = realpathSync(bs3); } catch { /* unresolvable → dedupe on the literal path */ }
155
- const existing = byBinding.get(key);
168
+ const existing = byKey.get(key);
156
169
  if (existing) {
157
- // Same tree reached through a second home. One probe still answers for
158
- // both, but the label has to say so otherwise a plugin user reading
159
- // "managed install is broken" has no way to know their plugin shares it.
170
+ // The label has to name both homes otherwise a plugin user reading
171
+ // "managed install is broken" has no way to know their plugin shares that tree.
160
172
  existing.label += `, ${label}`;
161
173
  return;
162
174
  }
163
- const entry = { label, root };
164
- byBinding.set(key, entry);
175
+ const entry = { label, root, ownDeps };
176
+ byKey.set(key, entry);
165
177
  runtimeRoots.push(entry);
166
178
  };
167
179
 
@@ -192,27 +204,31 @@ function resolvesSame(a, b) {
192
204
  */
193
205
  export function probeRuntimeRoots(roots, deps = {}) {
194
206
  const probe = deps.probe || ((root) => probeBindingInFreshProcess(root));
195
- return roots.map(({ label, root, depsMissing }) => {
196
- // Nothing to dlopen: the tree is absent, not stale. Say so and prescribe an
197
- // install `npm rebuild` on a missing package exits 0 and heals nothing.
198
- if (depsMissing) {
199
- return {
207
+ return roots.map(({ label, root, ownDeps = true }) => {
208
+ // EVERY root is probed, including one with no tree of its own: the probe uses
209
+ // Node's real resolution chain, so it is the only thing that knows whether an
210
+ // ancestor node_modules is carrying this install. Pre-judging an unowned tree
211
+ // broken is what made v3.70.0 report "absent — every hook throws" about a root
212
+ // that loaded fine.
213
+ const r = probe(root);
214
+ if (r.ok) return { label, root, ok: true };
215
+ // The repair depends on WHICH failure it is. `npm rebuild` on a package that is
216
+ // not installed exits 0 and heals nothing, so an unowned tree that also cannot
217
+ // resolve from an ancestor needs an install; a present-but-unloadable tree needs
218
+ // the rebuild.
219
+ const error = String(r.error || 'unknown').split('\n')[0];
220
+ return ownDeps
221
+ ? { label, root, ok: false, error, repair: `cd ${root} && ${NATIVE_BINDING_REBUILD_CMD}` }
222
+ : {
200
223
  label,
201
224
  root,
202
225
  ok: false,
203
- error: 'node_modules/better-sqlite3 is absent every hook and the MCP server '
204
- + 'that load this install throw ERR_MODULE_NOT_FOUND',
226
+ // Say only what is known. The probe may have reached an ANCESTOR
227
+ // node_modules and failed there — an earlier draft of this line asserted
228
+ // "none resolvable from a parent directory" and was caught printing that
229
+ // next to a probe error naming the parent tree it had just loaded from.
230
+ error: `${error} — and this install owns no node_modules/better-sqlite3, so there is nothing here to rebuild`,
205
231
  repair: `cd ${root} && npm install --omit=dev`,
206
232
  };
207
- }
208
- const r = probe(root);
209
- if (r.ok) return { label, root, ok: true };
210
- return {
211
- label,
212
- root,
213
- ok: false,
214
- error: String(r.error || 'unknown').split('\n')[0],
215
- repair: `cd ${root} && ${NATIVE_BINDING_REBUILD_CMD}`,
216
- };
217
233
  });
218
234
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "3.70.0",
3
+ "version": "3.70.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "claude-mem-lite",
9
- "version": "3.70.0",
9
+ "version": "3.70.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.70.0",
3
+ "version": "3.70.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",