Repository navigation
v1.6.0 — Audit remediation + critical vector search fix
This release is the outcome of a full five-part audit (publishing, security, code
quality, tests, documentation): 92 checklist items across 8 stages. It also fixes
a critical retrieval regression introduced after v1.5.3.
Breaking
- Node.js 22.5.0 or newer is now required. The engine is built on the built-in
node:sqlitemodule, which only exists from Node 22.5.0. Previouslyengines
was absent and the README claimed>=18.0.0, so installs on Node 18/20/21 failed
at runtime withERR_UNKNOWN_BUILTIN_MODULEinstead of at install time. ingest_document({ type: "file" })no longer reads arbitrary paths. Reads are
restricted to the current working directory and the plugin data directory. Widen
the allowlist withingestAllowedPaths, or setingestAllowAnyPath: trueto
restore the old behaviour.
Fixed
- Vector search returned zero results (critical). A
Buffer.isBuffer()guard
added afterv1.5.3discarded every stored vector, becausenode:sqlitereturns
BLOB columns asUint8Array, notBuffer. Vector and hybrid retrieval silently
degraded to BM25-only. The same bug pushed empty vectors to the cloud in
hybrid-syncand wrote empty vectors into exported snapshots. update_factin the OpenCode plugin never parsed**Title** body: its regex was
double-escaped. The title was stored verbatim as part of the body.SQLITE_BUSY("database is locked") under concurrency —PRAGMA busy_timeout
is now set to 5000 ms (it defaulted to 0).- Switching storage mode leaked the previous SQLite handle and Turso client; the
old connection is now closed before it is replaced. - A database-init failure no longer blocks reopening the local database: the
retry cooldown applies to cloud modes only. runWithRetryleaked anabortlistener on every attempt.- Optional numeric tool arguments (
offset,limit,startLine,endLine,
dimension) rejected empty strings with "Expected number"; they are now coerced. link,unlink,relink,identity,migrate_titles,enable-promptand
disable-promptwere unreachable through thememory_pluginbinary — the process
started an MCP server and blocked on stdin instead of running the command.- GPU trace reports were written to stdout, which is the MCP JSON-RPC channel.
Security
- Secrets are encrypted with PBKDF2 raised from 10,000 to 600,000 iterations
(OWASP guidance); existing files are transparently re-encrypted on first read. auth_secrets.encis written with owner-only permissions (0600).- The machine fingerprint no longer includes the volatile hostname and username,
which could permanently lock a user out of their own secrets after a rename. - SSRF filtering rewritten: IPv6 literals are unwrapped from their brackets,
IPv4-mapped forms (::ffff:127.0.0.1,::ffff:7f00:1), link-local, unique-local,
multicast and CGNAT ranges are blocked, and the resolved address is re-checked
before the request to defend against DNS rebinding — on the initial request and
on every redirect hop. - Cloud tokens are no longer taken from
argvby default: environment variables
are preferred, then a hidden stdin prompt. Passing a token as a flag now warns. - Snapshot paths are resolved with
realpath, so a symlink or junction can no
longer escape the allowlisted directories. - Snapshot and blob decompression is capped at 512 MB to prevent zip bombs.
Added
CHANGELOG.md(this file).--helpand--versionfor bothmemory_pluginandmemory-cli.- Config keys
ingestAllowedPathsandingestAllowAnyPath. mcp-server/logger.js: a central logger with levels (MEMORY_LOG_LEVEL), an
stderr sink and a swappable transport.- Two regression test suites — vector BLOB round-trip and benchmark report
labelling. The suite is now 12 files, all green.
Changed
- The six Notebook tools live in a single implementation
(mcp-server/tools/core/memory_core.js) shared by the MCP server and the
OpenCode plugin. They previously carried separate copies, so fixes reached only
one surface.opencode-plugin/index.jsshrank from 1161 to 825 lines and
memory_tools.jsfrom 516 to 124. - The OpenCode plugin uses static ESM imports instead of top-level
await import(...), and registers itsexithook once per instance rather than
on every module import. - Importing
run_benchmarks.jsno longer launches a full benchmark run; the report
renderer is exported as the pure functionbuildMarkdownReport(). npm audit: 5 advisories (1 moderate, 4 high) down to 3. The remaining
unfixable ones (xlsx,sharpvia@huggingface/transformers) are documented
in the README with their reachability.- Removed the stale nested
mcp-server/package.json, a version-drift source.
Documentation
- Corrected claims that did not match the code: the "DPAPI / OS Secret Store"
credential storage, the circuit breaker failing over to a "local database cache",
a non-existent GitHub mirror for model weights, the tool count, the TUI
diagnostics menu, and the GraphRAG language coverage. - Documented the
MEMORY_DIR→OPENCODE_CONFIG_DIR→ legacy~/.config→
%LOCALAPPDATA%resolution order, the previously undocumented config keys, and
theupdate_facttitleparameter. - Benchmark reports labelled the headline RRF/RSF rows with the grid-search winner
(k=10) while the numbers were computed with the runtime default (k=60). The
generator and every published table now state the parameters actually used. BENCHMARKS.mdtables were re-derived from the stored JSON artifacts; the
bge-m3 section had carried e5-small numbers shifted by a column.
Full changelog: v1.5.3...v1.6.0
Install: npm install -g @lotargo/memory_plugin (requires Node >= 22.5.0)