From 9b8d30107942c52bd272b702f6f8a3a80c69d09e Mon Sep 17 00:00:00 2001 From: Andrey Vasilevsky Date: Sat, 8 Aug 2026 21:32:27 -0700 Subject: [PATCH 1/3] fix(release): correct npm metadata and gate publishing on engine assets npm rewrote four `bin` paths and `repository.url` on every publish and reported the bin entries as "invalid and removed". The entries in fact survived - 0.19.0 and 0.19.1 both carry all of theirs on the registry - but the warning was indistinguishable from a real failure and cost a publish that was aborted on the assumption it had broken something. Store the forms npm normalizes to, so a clean publish is silent and any future warning means something. package-npm.sh treated a package.json/server.json version mismatch as a warning, printed into the middle of npm pack output where it scrolls past. The two files are published to two different registries under one version, and republishing that version cannot correct a disagreement between them, so this now aborts instead. The package ships no engine: every install fetches one from the release tagged with the engine's version. Publishing ahead of those assets makes a package that installs cleanly and then has nothing to run, so the assets are probed before packing rather than trusted. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_017rVbt7rENTwXkdHt3Bpgb5 --- mcp-package/package.json | 10 +++++----- scripts/package-npm.sh | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/mcp-package/package.json b/mcp-package/package.json index 5651e8a..4c2fcac 100644 --- a/mcp-package/package.json +++ b/mcp-package/package.json @@ -7,7 +7,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/codegraph-ai/CodeGraph" + "url": "git+https://github.com/codegraph-ai/CodeGraph.git" }, "keywords": [ "mcp", @@ -20,10 +20,10 @@ "copilot" ], "bin": { - "codegraph-mcp": "./bin/codegraph-mcp.js", - "codegraph-daemon": "./bin/codegraph-daemon.js", - "codegraph-mcp-install-hooks": "./bin/install-hooks.js", - "codegraph-mcp-fetch-engine": "./bin/fetch-engine-cli.js" + "codegraph-mcp": "bin/codegraph-mcp.js", + "codegraph-daemon": "bin/codegraph-daemon.js", + "codegraph-mcp-install-hooks": "bin/install-hooks.js", + "codegraph-mcp-fetch-engine": "bin/fetch-engine-cli.js" }, "files": [ "bin/", diff --git a/scripts/package-npm.sh b/scripts/package-npm.sh index f96d189..fee36fe 100755 --- a/scripts/package-npm.sh +++ b/scripts/package-npm.sh @@ -5,7 +5,6 @@ # Package the npm MCP server distribution. # Run from the repo root after all platform binaries are built. # -# Usage: # The engine is not bundled: it is fetched from the GitHub release at install # time by bin/postinstall.js. Publish the release assets first with # ./scripts/publish-release-assets.sh, or installs of this version will fail to @@ -60,9 +59,27 @@ echo "" echo "package.json version: $PKG_VERSION" echo "server.json version: $SERVER_VERSION" +# A mismatch here is fatal rather than a warning. The two files are published to +# two different registries under one version, and a warning scrolls past in the +# npm pack output - leaving npmjs.com and the MCP Registry disagreeing about what +# this release is, which cannot be corrected by republishing the same version. if [ "$PKG_VERSION" != "$SERVER_VERSION" ]; then - echo "WARNING: version mismatch between package.json and server.json" + echo "ERROR: version mismatch between package.json ($PKG_VERSION) and server.json ($SERVER_VERSION)" >&2 + exit 1 +fi + +# The npm package contains no engine; every install fetches one from the release +# tagged with this version. Publishing before those assets exist produces a +# package that installs cleanly and then has nothing to run. +ENGINE_VERSION=$(node -e "console.log(require('$PKG_DIR/bin/fetch-engine').ENGINE_VERSION)") +echo "engine version: $ENGINE_VERSION (fetched at install time)" +if ! curl -fsSL -o /dev/null \ + "https://github.com/codegraph-ai/CodeGraph/releases/download/v${ENGINE_VERSION}/codegraph-server-linux-x64.sha256"; then + echo "ERROR: no published engine assets for v${ENGINE_VERSION}" >&2 + echo " Run ./scripts/publish-release-assets.sh first, or installs will find no engine." >&2 + exit 1 fi +echo " ✓ engine assets are published for v${ENGINE_VERSION}" # Step 4: Pack echo "" From 18c36dfcd2f06cbde49b6586460c380f92eab235 Mon Sep 17 00:00:00 2001 From: Andrey Vasilevsky Date: Sat, 8 Aug 2026 22:00:54 -0700 Subject: [PATCH 2/3] no-mistakes(review): harden npm packaging version and engine-asset gates --- scripts/package-npm.sh | 77 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/scripts/package-npm.sh b/scripts/package-npm.sh index fee36fe..e52dcda 100755 --- a/scripts/package-npm.sh +++ b/scripts/package-npm.sh @@ -53,11 +53,26 @@ fi echo " ✓ package tests pass" # Step 3: Verify version consistency +# +# server.json carries the release version twice: once at the top level, and once +# inside the npm entry of `packages`, which is the field the MCP Registry +# resolves the tarball from. Nothing synchronises the three numbers - they are +# hand-edited - so all of them are compared, not just the top-level one. A +# release that bumped package.json and server.json but missed the nested version +# would register a new server entry pointing at the previous tarball, and the +# Registry would accept it because that older tarball exists and carries the +# right mcpName. PKG_VERSION=$(node -e "console.log(require('$PKG_DIR/package.json').version)") SERVER_VERSION=$(node -e "console.log(require('$PKG_DIR/server.json').version)") +SERVER_NPM_VERSION=$(node -e " + const npm = (require('$PKG_DIR/server.json').packages || []) + .find((p) => p.registryType === 'npm'); + console.log(npm ? npm.version : ''); +") echo "" -echo "package.json version: $PKG_VERSION" -echo "server.json version: $SERVER_VERSION" +echo "package.json version: $PKG_VERSION" +echo "server.json version: $SERVER_VERSION" +echo "server.json npm package: $SERVER_NPM_VERSION" # A mismatch here is fatal rather than a warning. The two files are published to # two different registries under one version, and a warning scrolls past in the @@ -67,19 +82,61 @@ if [ "$PKG_VERSION" != "$SERVER_VERSION" ]; then echo "ERROR: version mismatch between package.json ($PKG_VERSION) and server.json ($SERVER_VERSION)" >&2 exit 1 fi +if [ "$PKG_VERSION" != "$SERVER_NPM_VERSION" ]; then + echo "ERROR: version mismatch between package.json ($PKG_VERSION) and the npm entry in server.json ($SERVER_NPM_VERSION)" >&2 + echo " The MCP Registry resolves the tarball from packages[].version, so this would" >&2 + echo " publish a $PKG_VERSION server entry pointing at the $SERVER_NPM_VERSION tarball." >&2 + exit 1 +fi # The npm package contains no engine; every install fetches one from the release -# tagged with this version. Publishing before those assets exist produces a -# package that installs cleanly and then has nothing to run. +# tagged with the engine version pinned in bin/fetch-engine.js, which is +# deliberately not this package's version (see the ENGINE_VERSION comment there: +# a client-only patch release must not start asking for a tag nobody published). +# Publishing before those assets exist produces a package that installs cleanly +# and then has nothing to run. +# +# Every asset is probed, not just one. publish-release-assets.sh uploads the +# whole staging directory in a single `gh release upload`, so a network drop or +# a rate limit part-way through leaves the release with some platforms attached +# and others missing - and a one-platform probe would wave that through, giving +# users on the missing platforms exactly the empty install this gate exists to +# prevent. The list mirrors BINARIES + WINDOWS_SIDECAR there, which is the same +# set bin/fetch-engine.js resolves against. ENGINE_VERSION=$(node -e "console.log(require('$PKG_DIR/bin/fetch-engine').ENGINE_VERSION)") -echo "engine version: $ENGINE_VERSION (fetched at install time)" -if ! curl -fsSL -o /dev/null \ - "https://github.com/codegraph-ai/CodeGraph/releases/download/v${ENGINE_VERSION}/codegraph-server-linux-x64.sha256"; then - echo "ERROR: no published engine assets for v${ENGINE_VERSION}" >&2 - echo " Run ./scripts/publish-release-assets.sh first, or installs will find no engine." >&2 +ENGINE_ASSETS=( + "codegraph-server-darwin-arm64" + "codegraph-server-darwin-x64" + "codegraph-server-linux-x64" + "codegraph-server-win32-x64.exe" + "onnxruntime.dll" +) +RELEASE_BASE="https://github.com/codegraph-ai/CodeGraph/releases/download/v${ENGINE_VERSION}" + +echo "" +echo "engine version: $ENGINE_VERSION (fetched at install time)" +echo "Checking published engine assets for v${ENGINE_VERSION}..." +missing_assets=0 +for asset in "${ENGINE_ASSETS[@]}"; do + # A binary and its checksum are separate assets and the client needs both, so + # both are probed. The binaries are requested one byte at a time - presence is + # the question here, and downloading ~120 MB to answer it is not worth it. + if ! curl -fsSL -o /dev/null -r 0-0 "$RELEASE_BASE/$asset" \ + || ! curl -fsSL -o /dev/null "$RELEASE_BASE/$asset.sha256"; then + printf ' ✗ %s\n' "$asset" + missing_assets=1 + else + printf ' ✓ %s\n' "$asset" + fi +done + +if [ "$missing_assets" -ne 0 ]; then + echo "ERROR: the release v${ENGINE_VERSION} is missing engine assets (binary or .sha256)." >&2 + echo " Run ./scripts/publish-release-assets.sh --publish first, or installs on those" >&2 + echo " platforms will find no engine." >&2 exit 1 fi -echo " ✓ engine assets are published for v${ENGINE_VERSION}" +echo " ✓ every engine asset is published for v${ENGINE_VERSION}" # Step 4: Pack echo "" From e63ec0098c22f99a2cd99566a5bad60c6098af8e Mon Sep 17 00:00:00 2001 From: Andrey Vasilevsky Date: Sat, 8 Aug 2026 22:10:37 -0700 Subject: [PATCH 3/3] no-mistakes(document): clarify package-npm.sh engine-asset gate in header comment --- scripts/package-npm.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/package-npm.sh b/scripts/package-npm.sh index e52dcda..dafad3b 100755 --- a/scripts/package-npm.sh +++ b/scripts/package-npm.sh @@ -7,8 +7,9 @@ # # The engine is not bundled: it is fetched from the GitHub release at install # time by bin/postinstall.js. Publish the release assets first with -# ./scripts/publish-release-assets.sh, or installs of this version will fail to -# find an engine. +# ./scripts/publish-release-assets.sh - this script refuses to pack until every +# asset for the pinned engine version is on the release, because an install +# without them succeeds and then has nothing to run. # # Usage: # ./scripts/package-npm.sh # pack only