@lotargo/memory_plugin 1.6.0 → 1.6.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ All notable changes to `@lotargo/memory_plugin` are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.6.1] - 2026-08-10
9
+
10
+ ### Fixed
11
+
12
+ - **Cryptic crash on Node.js < 22.5.0** (`No such built-in module: node:sqlite`).
13
+ ESM static imports are hoisted, so the `node:sqlite` import in `database.js`
14
+ crashed before any user code could run. Three layers of protection are now in
15
+ place:
16
+ 1. **Boot guard** (`boot.js` / `cli_boot.js`): new lightweight entry points
17
+ that check `process.versions.node` *before* loading the ESM module graph.
18
+ On incompatible versions they print a clear boxed error with upgrade
19
+ instructions (`nvm install 22` / `brew install node@22`) and exit.
20
+ 2. **`engine-strict`** (`.npmrc`): `npm install` now **fails** instead of
21
+ merely warning when `engines.node >= 22.5.0` is not satisfied.
22
+ 3. **Preinstall warning** (`preinstall.js`): a prominent `stderr` message is
23
+ printed during installation on unsupported Node versions, explaining that
24
+ the server will not start.
25
+ - Process-kill patterns in `preinstall.js` now match the new `boot.js` entry
26
+ point in addition to `index.js`, so global updates correctly terminate running
27
+ server instances.
28
+
29
+ ### Changed
30
+
31
+ - All `bin` entry points (`memory_plugin`, `memory-agent`, `memory-cli`) now
32
+ route through `boot.js` / `cli_boot.js` instead of directly to `index.js` /
33
+ `cli.js`.
34
+ - `.npmrc` is no longer git-ignored; it contains only the project-level
35
+ `engine-strict=true` setting (npm never publishes `.npmrc` to the tarball).
36
+
8
37
  ## [1.6.0] - 2026-08-10
9
38
 
10
39
  This release is the outcome of a full five-part audit (publishing, security, code
@@ -105,4 +134,5 @@ a critical retrieval regression introduced after `v1.5.3`.
105
134
  - `BENCHMARKS.md` tables were re-derived from the stored JSON artifacts; the
106
135
  bge-m3 section had carried e5-small numbers shifted by a column.
107
136
 
137
+ [1.6.1]: https://github.com/Lotargo/memory_pugin/releases/tag/v1.6.1
108
138
  [1.6.0]: https://github.com/Lotargo/memory_pugin/releases/tag/v1.6.0
package/README.md CHANGED
@@ -334,18 +334,41 @@ The engine is configured through `<memory-dir>/config.json` (created with defaul
334
334
 
335
335
  ## Testing & Benchmarking
336
336
 
337
- To run the automated test suite and benchmarks locally:
337
+ To run the automated test suite and benchmarks locally, from the repository root:
338
338
 
339
339
  ```bash
340
- cd mcp-server
341
-
342
- # Run unit and integration tests
340
+ # Unit + integration + cloud suites (12 files) — fast and fully offline
343
341
  npm test
344
342
 
345
- # Run search quality & ingestion benchmarks
343
+ # End-to-end smoke test with REAL ONNX embeddings — run before a release
344
+ npm run smoke
345
+
346
+ # Search quality & ingestion benchmarks
346
347
  npm run benchmark
347
348
  ```
348
349
 
350
+ ### Two testing modes, and why both exist
351
+
352
+ `npm test` runs every suite with `generateEmbeddings: false`. That keeps it fast
353
+ and offline (no model download, no network), but it means the **dense-vector half
354
+ of the engine is never exercised** — retrieval falls back to BM25-only.
355
+
356
+ `npm run smoke` covers exactly that blind spot: it ingests a document with real
357
+ ONNX vectors and asserts that hybrid retrieval returns a non-zero cosine
358
+ similarity, plus that a Russian query still reaches an English document
359
+ (something BM25 cannot do). It also walks the full user journey — remember →
360
+ recall → ingest → query → link → update → get → forget — and checks the ingest
361
+ path guard.
362
+
363
+ This split is not academic: a regression in `v1.5.3+` disabled vector search
364
+ entirely (`node:sqlite` returns BLOBs as `Uint8Array`, and a `Buffer.isBuffer()`
365
+ guard discarded every stored vector) while all offline suites stayed green. The
366
+ smoke test exists so that class of failure cannot ship unnoticed again.
367
+
368
+ The smoke test reuses the model weights already cached in your data directory, so
369
+ it does not re-download them. Point `MEMORY_MODEL_CACHE` at a cache directory to
370
+ override the lookup; without any cache the weights are fetched once.
371
+
349
372
  For complete methodology details and search quality evaluation metrics, see [`docs/BENCHMARKS.md`](./docs/BENCHMARKS.md).
350
373
 
351
374
  ### Empirical Search Quality Results
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ── Boot Guard ──────────────────────────────────────────────────────────────
4
+ // This file is the true entry point for both `memory_plugin` and `memory-agent`
5
+ // binaries. Its sole purpose is to verify the Node.js version BEFORE the ESM
6
+ // module graph is evaluated — because `mcp-server/index.js` transitively
7
+ // imports `node:sqlite` (a built-in available only from Node 22.5.0), and ESM
8
+ // static imports are hoisted, so a version check inside that file would never
9
+ // execute.
10
+ //
11
+ // By keeping this file free of any `node:sqlite` dependency we can print a
12
+ // clear, actionable error message instead of the cryptic
13
+ // "No such built-in module: node:sqlite"
14
+ // that users on Node 18/20/21 would otherwise see.
15
+ // ─────────────────────────────────────────────────────────────────────────────
16
+
17
+ const MIN_MAJOR = 22;
18
+ const MIN_MINOR = 5;
19
+
20
+ const [major, minor] = process.versions.node.split(".").map(Number);
21
+
22
+ if (major < MIN_MAJOR || (major === MIN_MAJOR && minor < MIN_MINOR)) {
23
+ process.stderr.write(
24
+ `\n` +
25
+ ` ╔══════════════════════════════════════════════════════════════════╗\n` +
26
+ ` ║ @lotargo/memory_plugin requires Node.js >= 22.5.0 ║\n` +
27
+ ` ║ ║\n` +
28
+ ` ║ Detected: Node.js ${process.versions.node.padEnd(44)}║\n` +
29
+ ` ║ ║\n` +
30
+ ` ║ The built-in node:sqlite module used by this plugin was ║\n` +
31
+ ` ║ introduced in Node.js 22.5.0. Please upgrade your ║\n` +
32
+ ` ║ Node.js installation: ║\n` +
33
+ ` ║ ║\n` +
34
+ ` ║ nvm install 22 # or: brew install node@22 ║\n` +
35
+ ` ║ ║\n` +
36
+ ` ╚══════════════════════════════════════════════════════════════════╝\n` +
37
+ `\n`
38
+ );
39
+ process.exit(1);
40
+ }
41
+
42
+ // Version is OK — hand off to the real entry point.
43
+ import("./index.js");
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ── CLI Boot Guard ──────────────────────────────────────────────────────────
4
+ // Same version check as boot.js — see that file for the rationale.
5
+ // ─────────────────────────────────────────────────────────────────────────────
6
+
7
+ const MIN_MAJOR = 22;
8
+ const MIN_MINOR = 5;
9
+
10
+ const [major, minor] = process.versions.node.split(".").map(Number);
11
+
12
+ if (major < MIN_MAJOR || (major === MIN_MAJOR && minor < MIN_MINOR)) {
13
+ process.stderr.write(
14
+ `\n` +
15
+ ` ╔══════════════════════════════════════════════════════════════════╗\n` +
16
+ ` ║ @lotargo/memory_plugin requires Node.js >= 22.5.0 ║\n` +
17
+ ` ║ ║\n` +
18
+ ` ║ Detected: Node.js ${process.versions.node.padEnd(44)}║\n` +
19
+ ` ║ ║\n` +
20
+ ` ║ The built-in node:sqlite module used by this plugin was ║\n` +
21
+ ` ║ introduced in Node.js 22.5.0. Please upgrade your ║\n` +
22
+ ` ║ Node.js installation: ║\n` +
23
+ ` ║ ║\n` +
24
+ ` ║ nvm install 22 # or: brew install node@22 ║\n` +
25
+ ` ║ ║\n` +
26
+ ` ╚══════════════════════════════════════════════════════════════════╝\n` +
27
+ `\n`
28
+ );
29
+ process.exit(1);
30
+ }
31
+
32
+ // Version is OK — hand off to the real CLI.
33
+ import("./cli.js").then(m => {
34
+ if (process.argv[1] && process.argv[1].includes("cli_boot.js")) {
35
+ m.runCli().catch((err) => console.error("CLI error:", err));
36
+ }
37
+ });
@@ -5,6 +5,27 @@ if (process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.DEBIAN_F
5
5
  process.exit(0);
6
6
  }
7
7
 
8
+ // ── Node version warning ────────────────────────────────────────────────────
9
+ // engines.node >= 22.5.0 is set in package.json but npm only warns by default.
10
+ // Print a loud, actionable message so the user notices before the server crashes.
11
+ {
12
+ const [major, minor] = process.versions.node.split(".").map(Number);
13
+ if (major < 22 || (major === 22 && minor < 5)) {
14
+ console.error(
15
+ `\n` +
16
+ ` ⚠️ @lotargo/memory_plugin requires Node.js >= 22.5.0\n` +
17
+ ` Detected: Node.js ${process.versions.node}\n` +
18
+ `\n` +
19
+ ` The built-in node:sqlite module used by this plugin was\n` +
20
+ ` introduced in Node.js 22.5.0. The server WILL NOT START\n` +
21
+ ` on your current version.\n` +
22
+ `\n` +
23
+ ` Please upgrade: nvm install 22 (or: brew install node@22)\n`
24
+ );
25
+ }
26
+ }
27
+
28
+
8
29
  // Only run graceful process termination during explicit global npm updates
9
30
  if (process.env.npm_config_global === "true" || process.env.MEMORY_PREINSTALL_FORCE === "true") {
10
31
  try {
@@ -13,7 +34,7 @@ if (process.env.npm_config_global === "true" || process.env.MEMORY_PREINSTALL_FO
13
34
 
14
35
  if (process.platform === "win32") {
15
36
  try {
16
- const psCmd = `Get-CimInstance Win32_Process | Where-Object { ($_.CommandLine -like '*mcp-server/index.js*' -or $_.CommandLine -like '*mcp-server\\\\index.js*') -and $_.CommandLine -notlike '*install*' -and $_.ProcessId -ne ${currentPid} -and $_.ProcessId -ne ${ppid} } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }`;
37
+ const psCmd = `Get-CimInstance Win32_Process | Where-Object { ($_.CommandLine -like '*mcp-server/boot.js*' -or $_.CommandLine -like '*mcp-server\\\\boot.js*' -or $_.CommandLine -like '*mcp-server/index.js*' -or $_.CommandLine -like '*mcp-server\\\\index.js*') -and $_.CommandLine -notlike '*install*' -and $_.ProcessId -ne ${currentPid} -and $_.ProcessId -ne ${ppid} } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }`;
17
38
  execSync(`powershell -NoProfile -NonInteractive -Command "${psCmd}"`, { stdio: "ignore" });
18
39
  } catch {}
19
40
  } else {
@@ -30,7 +51,7 @@ if (process.env.npm_config_global === "true" || process.env.MEMORY_PREINSTALL_FO
30
51
 
31
52
  if (!pid || pid === currentPid || pid === ppid || parentPid === currentPid) continue;
32
53
 
33
- const isServer = cmd.includes("mcp-server/index.js") || cmd.includes("mcp-server/index.js");
54
+ const isServer = cmd.includes("mcp-server/boot.js") || cmd.includes("mcp-server/index.js");
34
55
  const isInstaller = /npm|npx|yarn|pnpm|preinstall|install/i.test(cmd);
35
56
 
36
57
  if (isServer && !isInstaller) {
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@lotargo/memory_plugin",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "100% local hybrid RAG memory for AI coding agents (OpenCode, Claude Code, Codex, Antigravity). MCP server + plugin: persistent user facts, document ingestion, vector + SQLite FTS5 retrieval across sessions.",
5
5
  "type": "module",
6
6
  "main": "opencode-plugin/index.js",
7
7
  "scripts": {
8
8
  "preinstall": "node mcp-server/preinstall.js || true",
9
9
  "test": "node tests/run_all.js",
10
+ "smoke": "node tests/smoke/e2e_real_embeddings.test.js",
10
11
  "benchmark": "node mcp-server/benchmarks/run_benchmarks.js"
11
12
  },
12
13
  "bin": {
13
- "memory_plugin": "mcp-server/index.js",
14
- "memory-agent": "mcp-server/index.js",
15
- "memory-cli": "mcp-server/cli.js"
14
+ "memory_plugin": "mcp-server/boot.js",
15
+ "memory-agent": "mcp-server/boot.js",
16
+ "memory-cli": "mcp-server/cli_boot.js"
16
17
  },
17
18
  "files": [
18
19
  "CHANGELOG.md",
@@ -28,6 +29,8 @@
28
29
  "mcp-server/security",
29
30
  "mcp-server/storage",
30
31
  "mcp-server/tools",
32
+ "mcp-server/boot.js",
33
+ "mcp-server/cli_boot.js",
31
34
  "mcp-server/cli.js",
32
35
  "mcp-server/index.js",
33
36
  "mcp-server/fact_format.js",