chore(release): v4.2.4#45
Conversation
…e drift Previously a malformed 2xx body (missing field, renamed key, HTML error page returned as JSON) was silently extracted as an empty string and the cross-provider failover chain treated that as success. A broken upstream could block the chain from advancing. Add LLMResponseParseError, classified as 'parse' so the chain continues on the next provider. Shape validators read each provider's response with type guards instead of unchecked casts; an unexpected shape throws and surfaces in telemetry. An intentionally empty string is still treated as a successful call (matches prior caller contract).
Compare H2 heading count across README.md and each of the 10 locale README files. Tolerance of ±1 absorbs routine translation collapse; drift of 2+ raises WARN, a missing locale raises WARN, and a missing README.md skips silently so packaged installs without bundled docs don't false-fail. Fenced code blocks are skipped when counting headings, so example markdown inside triple backticks doesn't inflate the count. Also corrects the F15 corrupt-database test fixture to use MEMESH_DB_PATH env override (matching every sibling F15 test) instead of an unsupported option that silently fell through to the real default path.
Re-running 'memesh kg backfill-relations' no longer re-tokenises and re-scores orphans that were already considered in a prior run. The cache lives in memesh_metadata under key kg_backfill_processed_v1. CLI gets --reset-idempotency to clear the cache (useful after schema changes or when reconsidering every orphan). The reset honours dry-run correctly (was previously a silent no-op on that path). orphansSkippedIdempotent now reflects this run only, not cumulative cache size, so the summary line is accurate. proposeBackfillCandidates returns a richer result so the orphan IDs considered this run and skipped this run are surfaced explicitly; this removes a duplicate orphan query previously needed to mark no-candidate orphans as processed.
Oversize requests previously got Express's default HTML error page,
inconsistent with the JSON-shaped errors every other handler emits.
Error middleware now converts PayloadTooLargeError into:
{ success: false, code: PAYLOAD_TOO_LARGE, limit: "1mb", hint: ... }
The handler is a named function declaration so the 4-arg signature
Express uses to identify error middleware survives any downstream
code transformation that might rewrite parameter arity.
Adds a "Request body limits" section under HTTP REST API explaining the 1 MB cap, the structured 413 response shape, and pointing users at the CLI (memesh export / import) for bulk operations that exceed it — the CLI reads/writes files directly and is not subject to the per-request cap.
'npm run lint' now carries --max-warnings 0 directly, and CI runs it as a hard step before typecheck (lint is faster, so fail-fast cuts CI minutes on bad PRs). Pre-condition met since the lint cleanup that closed all warnings; this commit promotes the bar to a guarantee. New eslint-disable comments require explicit justification. Drops the duplicate 'lint:strict' script (now identical to 'lint').
Release notes in CHANGELOG.md. Version aligned across: - package.json - .claude-plugin/plugin.json - .claude-plugin/marketplace.json - CHANGELOG.md [4.2.4] header - docs/ARCHITECTURE.md - docs/api/API_REFERENCE.md dist/skills-manifest.json regenerated via 'npm run build' so 'memesh doctor' integrity check passes for fresh installs.
Multi-Model SynthesisBoth Claude and Codex reviews above are independent. The most Reviewer responsibility: read both, surface non-overlapping |
CodeQL flagged a substring URL match in the parse-error test as incomplete URL sanitization. The test controls its own URLs so it's not exploitable in practice, but the pattern is a real anti-pattern elsewhere — fix the test to use a strict hostname match so it demonstrates the safe form.
Multi-Model SynthesisBoth Claude and Codex reviews above are independent. The most Reviewer responsibility: read both, surface non-overlapping |
CodeQL flagged src/cli/view.ts for two related issues: - js/shell-command-injection-from-environment - js/indirect-command-line-injection The Windows path used cmd.exe /c start, which re-parses the path argument through cmd's shell parser. MEMESH_DIR can feed into the path, so this remains an attack surface despite the existing character allow-list. Drop the cmd.exe route. On Windows, dispatch via rundll32 + url.dll's FileProtocolHandler — the documented way to launch the default protocol handler without routing the path through a shell. macOS open and Linux xdg-open already accept the path as a direct argv element.
… launcher
The Claude Code plugin marketplace installs do not run npm scripts
(security model), so plugin cache directories arrived with:
- dist/ empty except skills-manifest.json (no compiled JS)
- node_modules/better-sqlite3 binding missing
- node_modules/.bin/memesh-mcp absent
The previous .mcp.json worked around this by running
'npx -y -p @pcircle/memesh memesh-mcp' — re-installing the package
from npm each time the MCP server started. That depends on npm
reachability, build tools on the user's machine, and a clean npx
cache; any one of those failing left users with a -32000
"failed to reconnect" error and a broken plugin install.
Move to a self-contained plugin layout:
- Track compiled dist/ in git so a plugin clone is runnable without
a build step. Adds ~1.7 MB to the repo. Contributors who touch
src/ must run 'npm run build' before committing.
- dashboard/dist/index.html (~380 KB Preact build) tracked for the
same reason — 'memesh serve' works on a fresh plugin install.
- .mcp.json points at the plugin cache's local launcher.js. The
launcher already has self-healing better-sqlite3 binding rebuild
(shipped in v4.2.2), so a missing native binding still recovers
automatically without depending on npx or npm registry access.
Multi-Model SynthesisBoth Claude and Codex reviews above are independent. The most Reviewer responsibility: read both, surface non-overlapping |
- README.md: clarify that the MCP server runs from the plugin's bundled compiled output (no npx lookup needed). The previous "npx-based launch pattern" text described the old behaviour that broke plugin marketplace installs. Same correction applied to the 5 locale READMEs that carried the same passage (es, ja, ko, zh-CN, zh-TW). The remaining 5 locales (de, fr, pt, th, vi) did not include that paragraph and need no change. - docs/api/API_REFERENCE.md: add --reset-idempotency flag to the memesh kg backfill-relations options table; add an "Idempotency" note explaining the persistent cache behaviour.
Multi-Model SynthesisBoth Claude and Codex reviews above are independent. The most Reviewer responsibility: read both, surface non-overlapping |
…json The manifest committed in the previous build was hashed against the stale .mcp.json size (132 bytes, before the npx → local-launcher edit). Without this refresh, `memesh doctor` would have reported 'Skills + hooks integrity FAIL' on every fresh plugin install. Re-run of `npm run build` produces the same JSON shape and entries — only the .mcp.json hash + bytes field and the generated_at timestamp change.
Multi-Model SynthesisBoth Claude and Codex reviews above are independent. The most Reviewer responsibility: read both, surface non-overlapping |
Summary
v4.2.4 — six reliability/DX improvements plus a critical plugin install fix and a security cleanup.
Plugin install fix (this is the headline)
Claude Code's plugin marketplace does not execute npm scripts on install (security model), so the previous setup left users with
-32000 "failed to reconnect to plugin:memesh"becausedist/was gitignored and the MCP server was re-installed vianpxon every start. Plugin marketplace installs now work without npm/npx/build-tools:dist/(~1.7 MB) anddashboard/dist/index.html(~380 KB) are now tracked in git so the plugin is runnable on clone..mcp.jsonpoints at the plugin cache's locallauncher.js, which already self-heals a missing better-sqlite3 binding via in-process rebuild.Highlights
memesh doctorflags drifted README localisations (10 locale files)memesh kg backfill-relationsskips already-considered orphans on re-runs (new--reset-idempotencyflag to opt out)Commits
Full release notes in
CHANGELOG.md.Test plan
npm run lint— 0 warnings (hard gate)npm run typecheck— 0 errorsnpm test -- --run— 1034/1034 passingnpm run build— green, dashboard built, manifest regeneratedmemesh doctor— PASS_WITH_CONCERNS (only hook-activity WARN, expected on dev install)scripts/check-version-coherence.mjs.mcp.jsonnow uses local launcher; verifieddist/mcp/launcher.jsis present in tracked filesNotes
dist/anddashboard/dist/. Contributors who touchsrc/ordashboard/src/must runnpm run buildbefore committing.proposeBackfillCandidatesinternal return shape changed (no external consumers; CLI + tests updated in same commit).