Skip to content

chore(release): v4.2.4#45

Merged
kevintseng merged 12 commits into
mainfrom
chore/release-v4.2.4
May 12, 2026
Merged

chore(release): v4.2.4#45
kevintseng merged 12 commits into
mainfrom
chore/release-v4.2.4

Conversation

@kevintseng
Copy link
Copy Markdown
Contributor

@kevintseng kevintseng commented May 12, 2026

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" because dist/ was gitignored and the MCP server was re-installed via npx on every start. Plugin marketplace installs now work without npm/npx/build-tools:

  • Compiled dist/ (~1.7 MB) and dashboard/dist/index.html (~380 KB) are now tracked in git so the plugin is runnable on clone.
  • .mcp.json points at the plugin cache's local launcher.js, which already self-heals a missing better-sqlite3 binding via in-process rebuild.

Highlights

  • LLM client recovers from malformed provider responses instead of silently returning empty strings (failover chain engages on parse drift)
  • memesh doctor flags drifted README localisations (10 locale files)
  • memesh kg backfill-relations skips already-considered orphans on re-runs (new --reset-idempotency flag to opt out)
  • HTTP requests over the 1 MB body cap return structured 413 JSON instead of Express's default HTML error page
  • Lint becomes a hard CI gate (zero new warnings allowed)
  • Dashboard launcher no longer invokes a shell on Windows (CodeQL)

Commits

Type Subject
feat(llm-client) validate response shape so failover engages on parse drift
feat(doctor) add README locale-parity check
feat(kg) persistent idempotency cache for backfill-relations
feat(http) return structured 413 JSON on body-limit overflow
docs(api) document 1MB request body limit and 413 response shape
chore(ci) hard-gate lint at zero warnings
chore(release) bump v4.2.4
fix(test) route fetch mock by hostname not substring (CodeQL #97)
fix(cli) launch dashboard browser without invoking a shell (CodeQL #89/#96)
fix(plugin) self-contain plugin install with tracked dist/ and local launcher

Full release notes in CHANGELOG.md.

Test plan

  • npm run lint — 0 warnings (hard gate)
  • npm run typecheck — 0 errors
  • npm test -- --run — 1034/1034 passing
  • npm run build — green, dashboard built, manifest regenerated
  • memesh doctor — PASS_WITH_CONCERNS (only hook-activity WARN, expected on dev install)
  • Version coherence across 6 anchors confirmed via scripts/check-version-coherence.mjs
  • CodeQL alerts #89, #96, #97 — fixes pushed, expecting re-scan to close them
  • Plugin marketplace install path — .mcp.json now uses local launcher; verified dist/mcp/launcher.js is present in tracked files

Notes

  • Repo size +~2.1 MB from tracking dist/ and dashboard/dist/. Contributors who touch src/ or dashboard/src/ must run npm run build before committing.
  • No breaking changes; all changes additive, behaviour-improving, or install-reliability.
  • No new runtime dependencies.
  • proposeBackfillCandidates internal return shape changed (no external consumers; CLI + tests updated in same commit).

…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.
@github-actions
Copy link
Copy Markdown

Multi-Model Synthesis

Both Claude and Codex reviews above are independent. The most
valuable signals are the issues only ONE model raised
— those
are the blind spots single-model review misses.

Reviewer responsibility: read both, surface non-overlapping
findings, decide which need fixing before merge.

Comment thread tests/core/llm-client.test.ts Fixed
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.
@github-actions
Copy link
Copy Markdown

Multi-Model Synthesis

Both Claude and Codex reviews above are independent. The most
valuable signals are the issues only ONE model raised
— those
are the blind spots single-model review misses.

Reviewer responsibility: read both, surface non-overlapping
findings, decide which need fixing before merge.

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.
@github-actions
Copy link
Copy Markdown

Multi-Model Synthesis

Both Claude and Codex reviews above are independent. The most
valuable signals are the issues only ONE model raised
— those
are the blind spots single-model review misses.

Reviewer responsibility: read both, surface non-overlapping
findings, decide which need fixing before merge.

- 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.
@github-actions
Copy link
Copy Markdown

Multi-Model Synthesis

Both Claude and Codex reviews above are independent. The most
valuable signals are the issues only ONE model raised
— those
are the blind spots single-model review misses.

Reviewer responsibility: read both, surface non-overlapping
findings, decide which need fixing before merge.

…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.
@github-actions
Copy link
Copy Markdown

Multi-Model Synthesis

Both Claude and Codex reviews above are independent. The most
valuable signals are the issues only ONE model raised
— those
are the blind spots single-model review misses.

Reviewer responsibility: read both, surface non-overlapping
findings, decide which need fixing before merge.

@kevintseng kevintseng merged commit 5248ec7 into main May 12, 2026
14 of 15 checks passed
@kevintseng kevintseng deleted the chore/release-v4.2.4 branch May 12, 2026 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants