fix(release): path-scoped npmrc + hard-fail publish (v0.14.3 retry)

v0.14.2 publish run reported "success" but @keisei/mcp-server NEVER
landed on keigit because:

1. Host-scoped `.npmrc` token (`//keigit.com/:_authToken=...`) was
   silently ignored by npm 10 — every publish errored with ENEEDAUTH.
2. The publish loop's `|| echo ":⚠️:"` swallowed the failure
   so the job exited 0 (W1+W3 finding F3).

Two fixes in one commit:

A) Path-scoped npmrc per Forgejo docs:
   `//keigit.com/api/packages/keisei/npm/:_authToken=${KEIGIT_TOKEN}`
   + `always-auth=true` for scoped registry. Also tee'd to $HOME/.npmrc
   so the publish loop's `cd packages/<pkg>` cwd doesn't lose the auth
   line. [VERIFIED: curl PUT with Bearer to /api/packages/keisei/npm/
   returns 400 "package is invalid" (auth ACCEPTED, payload bad) — auth
   format is correct]

B) Hard-fail publish loop for packages with publishConfig:
   - Iterate all packages
   - For each: read .publishConfig presence
   - If publish errors AND has publishConfig → record gated_failed=1
   - If publish errors AND no publishConfig → notice "skipped" (adapter
     without registry pin reached npm.org default, expected fail)
   - End of loop: exit 1 if any gated_failed
   - Adapters without publishConfig (gmail/grok/recall/telegram/youtube)
     correctly skip; only @keisei/mcp-server is gated, and a real
     failure now blocks the job.

Bump 0.14.2 → 0.14.3 (0.14.2 tag exists with previous failed publish).

Verification done locally:
- PAT owner Parfionovich is member of org keisei [REAL: api/v1/user
  + api/v1/users/Parfionovich/orgs]
- Bearer auth to keigit npm registry works [REAL: curl probe → 400
  "package invalid", not 401 "unauthorized"]
- Cargo workspace clean [REAL: cargo check exit 0]

After tag v0.14.3:
- npm-publish job creates .npmrc with path-scoped auth
- Publishes @keisei/mcp-server@0.14.3 to https://keigit.com/api/packages/keisei/npm/
- Adapters skip cleanly (no publishConfig, no NPM_TOKEN)
- Job exits 0 only if mcp-server actually landed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Parfii-bot 2026-05-03 23:48:07 +08:00
parent 3b8b726a1c
commit a6948770d1
3 changed files with 36 additions and 15 deletions

View file

@ -342,13 +342,21 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
set -euo pipefail
# v0.14.3 fix: path-scoped _authToken per Forgejo docs
# (https://forgejo.org/docs/latest/user/packages/npm/). The prior
# host-scoped form (`//keigit.com/:_authToken=...`) was silently
# ignored by npm 10 → ENEEDAUTH. Path-scoped exactly matches the
# @keisei:registry URL, so npm reliably resolves the token.
# Also write to $HOME/.npmrc so it's found regardless of cwd
# (the publish loop cd's into packages/<pkg>/).
{
echo "@keisei:registry=https://keigit.com/api/packages/keisei/npm/"
echo "//keigit.com/:_authToken=${KEIGIT_TOKEN}"
echo "//keigit.com/api/packages/keisei/npm/:_authToken=${KEIGIT_TOKEN}"
echo "always-auth=true"
if [ -n "${NPM_TOKEN:-}" ]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}"
fi
} > .npmrc
} | tee "$HOME/.npmrc" > .npmrc
# Sanity (no secrets in log — print only registry lines):
grep -v _authToken .npmrc
@ -367,21 +375,34 @@ jobs:
working-directory: _ts_packages
run: |
set -euo pipefail
# publishConfig.registry in each package.json decides destination.
# Currently only @keisei/mcp-server has a publishConfig — the other
# adapters skip publish (no registry pin → npm.org default → no
# token in .npmrc → publish fails → ::warning emitted, job continues).
# v0.14.3 fix (W1+W3 finding F3): hard-fail on a package WITH a
# publishConfig.registry whose publish errored. Adapters without
# publishConfig still skip gracefully (no registry pin → npm.org
# default → ENEEDAUTH → counted as "skipped" not "failed").
gated_failed=0
for pkg in packages/*/; do
if [ -f "$pkg/package.json" ]; then
name=$(node -p "require('./$pkg/package.json').name")
echo "::group::publish $name"
( cd "$pkg" && npm publish --access public ) \
|| echo "::warning::publish failed for $name (no registry pin, missing token, version conflict, or registry error — see log)"
echo "::endgroup::"
[ -f "$pkg/package.json" ] || continue
name=$(node -p "require('./$pkg/package.json').name")
has_pub=$(node -p "require('./$pkg/package.json').publishConfig ? '1' : '0'")
echo "::group::publish $name"
if ( cd "$pkg" && npm publish --access public ); then
echo "::notice::published $name"
else
if [ "$has_pub" = "1" ]; then
gated_failed=1
echo "::error::publish FAILED for $name (has publishConfig — this is a real error, see log above)"
else
echo "::notice::publish skipped for $name (no publishConfig — npm.org default reached, ENEEDAUTH expected without NPM_TOKEN)"
fi
fi
echo "::endgroup::"
done
if [ "$gated_failed" -ne 0 ]; then
echo "::error::one or more packages with publishConfig failed to publish"
exit 1
fi
- name: Cleanup .npmrc
if: always()
working-directory: _ts_packages
run: rm -f .npmrc
run: rm -f .npmrc "$HOME/.npmrc"

View file

@ -3707,7 +3707,7 @@
},
"packages/mcp-server": {
"name": "@keisei/mcp-server",
"version": "0.14.2",
"version": "0.14.3",
"license": "Apache-2.0",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",

View file

@ -1,6 +1,6 @@
{
"name": "@keisei/mcp-server",
"version": "0.14.2",
"version": "0.14.3",
"description": "MCP server exposing KeiSeiKit Rust primitives as Model Context Protocol tools — published to keigit.com (Forgejo npm registry, public DNS)",
"type": "module",
"main": "./dist/index.js",