@@ -2,6 +2,7 @@ name: Release Packages
22
33env :
44 NODE_VERSION : ' 25'
5+ NPM_REGISTRY_URL : https://registry.npmjs.org/
56 CLI_NATIVE_MODULE_DIRS : |
67 libraries/logger
78 libraries/md-compiler
@@ -66,13 +67,13 @@ jobs:
6667 local output_key="$2"
6768 local version
6869 local name
69- local npm_version
70+ local published_version
7071
7172 version=$(jq -r '.version' "$package_json_path")
7273 name=$(jq -r '.name' "$package_json_path")
73- npm_version =$(npm view "$name" version --registry https://registry.npmjs.org/ 2>/dev/null || echo "")
74+ published_version =$(npm view "${ name}@${version} " version --registry "$NPM_REGISTRY_URL" 2>/dev/null || echo "")
7475
75- if [[ "$version" != "$npm_version " ]]; then
76+ if [[ "$version" != "$published_version " ]]; then
7677 echo "$name@$version is not published to npm, will publish"
7778 echo "${output_key}=true" >> "$GITHUB_OUTPUT"
7879 return 0
@@ -242,6 +243,37 @@ jobs:
242243 with :
243244 node-version : ${{ env.NODE_VERSION }}
244245 registry-url : https://registry.npmjs.org/
246+ - name : Preflight npm auth
247+ shell : bash
248+ env :
249+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
250+ run : |
251+ set -euo pipefail
252+
253+ if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
254+ echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/* before rerunning release."
255+ exit 1
256+ fi
257+
258+ npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
259+ npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
260+ echo "Authenticated to npm as ${npm_user}"
261+
262+ access_json=$(npm access list packages @truenine --json 2>/dev/null || true)
263+ if [[ -z "${access_json}" || "${access_json}" == "{}" || "${access_json}" == "null" ]]; then
264+ echo "::error::Authenticated as ${npm_user}, but npm did not report package access for @truenine. Replace NPM_TOKEN with a token that has publish permission for existing @truenine/* packages."
265+ exit 1
266+ fi
267+
268+ for package_json in cli/npm/*/package.json; do
269+ package_name=$(jq -r '.name' "$package_json")
270+ package_access=$(jq -r --arg package_name "$package_name" '.[$package_name] // empty' <<<"$access_json")
271+
272+ if [[ "$package_access" != "read-write" ]]; then
273+ echo "::error::NPM_TOKEN authenticated as ${npm_user}, but ${package_name} access is '${package_access:-missing}'. Expected read-write."
274+ exit 1
275+ fi
276+ done
245277 - name : Download all platform artifacts
246278 uses : actions/download-artifact@v4
247279 with :
@@ -302,10 +334,72 @@ jobs:
302334 env :
303335 NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
304336 run : |
337+ set -euo pipefail
338+
339+ version_exists() {
340+ local package_name="$1"
341+ local package_version="$2"
342+ local published_version
343+
344+ published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
345+ [[ "$published_version" == "$package_version" ]]
346+ }
347+
348+ verify_version_exists() {
349+ local package_name="$1"
350+ local package_version="$2"
351+ local attempts=10
352+ local delay_seconds=6
353+
354+ for attempt in $(seq 1 "$attempts"); do
355+ if version_exists "$package_name" "$package_version"; then
356+ echo "Verified ${package_name}@${package_version} on npm"
357+ return 0
358+ fi
359+
360+ echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
361+ sleep "$delay_seconds"
362+ done
363+
364+ echo "::error::${package_name}@${package_version} is still missing from npm after publish."
365+ return 1
366+ }
367+
368+ publish_package() {
369+ local package_dir="$1"
370+ local package_name
371+ local package_version
372+ local publish_log
373+
374+ package_name=$(jq -r '.name' "${package_dir}package.json")
375+ package_version=$(jq -r '.version' "${package_dir}package.json")
376+
377+ if version_exists "$package_name" "$package_version"; then
378+ echo "${package_name}@${package_version} already exists on npm, skipping"
379+ return 0
380+ fi
381+
382+ publish_log=$(mktemp)
383+ if (cd "$package_dir" && pnpm publish --access public --no-git-checks) 2>&1 | tee "$publish_log"; then
384+ verify_version_exists "$package_name" "$package_version"
385+ rm -f "$publish_log"
386+ return 0
387+ fi
388+
389+ if version_exists "$package_name" "$package_version"; then
390+ echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
391+ rm -f "$publish_log"
392+ return 0
393+ fi
394+
395+ echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
396+ rm -f "$publish_log"
397+ return 1
398+ }
399+
305400 for dir in cli/npm/*/; do
306401 if [ -f "${dir}package.json" ]; then
307- echo "Publishing ${dir}..."
308- (cd "$dir" && pnpm publish --access public --no-git-checks) || echo "⚠️ Failed to publish ${dir}, may already exist"
402+ publish_package "$dir"
309403 fi
310404 done
311405
@@ -323,13 +417,83 @@ jobs:
323417 with :
324418 node-version : ${{ env.NODE_VERSION }}
325419 registry-url : https://registry.npmjs.org/
420+ - name : Preflight npm auth
421+ shell : bash
422+ env :
423+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
424+ run : |
425+ set -euo pipefail
426+
427+ if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
428+ echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/memory-sync-cli before rerunning release."
429+ exit 1
430+ fi
431+
432+ npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
433+ npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
434+ echo "Authenticated to npm as ${npm_user}"
435+
436+ access_json=$(npm access list packages @truenine --json 2>/dev/null || true)
437+ package_name=$(jq -r '.name' cli/package.json)
438+ package_access=$(jq -r --arg package_name "$package_name" '.[$package_name] // empty' <<<"${access_json:-{}}")
439+
440+ if [[ "$package_access" != "read-write" ]]; then
441+ echo "::error::NPM_TOKEN authenticated as ${npm_user}, but ${package_name} access is '${package_access:-missing}'. Expected read-write."
442+ exit 1
443+ fi
326444 - name : Build
327445 run : pnpm -F @truenine/memory-sync-cli run build
328446 - name : Publish to npm
329- working-directory : ./cli
330- run : pnpm publish --access public --no-git-checks
447+ shell : bash
331448 env :
332449 NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
450+ run : |
451+ set -euo pipefail
452+
453+ package_name=$(jq -r '.name' cli/package.json)
454+ package_version=$(jq -r '.version' cli/package.json)
455+
456+ version_exists() {
457+ local published_version
458+ published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
459+ [[ "$published_version" == "$package_version" ]]
460+ }
461+
462+ verify_version_exists() {
463+ local attempts=10
464+ local delay_seconds=6
465+
466+ for attempt in $(seq 1 "$attempts"); do
467+ if version_exists; then
468+ echo "Verified ${package_name}@${package_version} on npm"
469+ return 0
470+ fi
471+
472+ echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
473+ sleep "$delay_seconds"
474+ done
475+
476+ echo "::error::${package_name}@${package_version} is still missing from npm after publish."
477+ return 1
478+ }
479+
480+ if version_exists; then
481+ echo "${package_name}@${package_version} already exists on npm, skipping"
482+ exit 0
483+ fi
484+
485+ if (cd cli && pnpm publish --access public --no-git-checks); then
486+ verify_version_exists
487+ exit 0
488+ fi
489+
490+ if version_exists; then
491+ echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
492+ exit 0
493+ fi
494+
495+ echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
496+ exit 1
333497
334498 # 4.5. CLI 可用后,发布 MCP 包到 npm
335499 publish-mcp :
@@ -347,13 +511,83 @@ jobs:
347511 with :
348512 node-version : ${{ env.NODE_VERSION }}
349513 registry-url : https://registry.npmjs.org/
514+ - name : Preflight npm auth
515+ shell : bash
516+ env :
517+ NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
518+ run : |
519+ set -euo pipefail
520+
521+ if [[ -z "${NODE_AUTH_TOKEN:-}" ]]; then
522+ echo "::error::NPM_TOKEN is missing. Configure a publish-capable npm token for @truenine/memory-sync-mcp before rerunning release."
523+ exit 1
524+ fi
525+
526+ npm config set //registry.npmjs.org/:_authToken "${NODE_AUTH_TOKEN}"
527+ npm_user=$(npm whoami --registry "$NPM_REGISTRY_URL")
528+ echo "Authenticated to npm as ${npm_user}"
529+
530+ access_json=$(npm access list packages @truenine --json 2>/dev/null || true)
531+ package_name=$(jq -r '.name' mcp/package.json)
532+ package_access=$(jq -r --arg package_name "$package_name" '.[$package_name] // empty' <<<"${access_json:-{}}")
533+
534+ if [[ "$package_access" != "read-write" ]]; then
535+ echo "::error::NPM_TOKEN authenticated as ${npm_user}, but ${package_name} access is '${package_access:-missing}'. Expected read-write."
536+ exit 1
537+ fi
350538 - name : Build
351539 run : pnpm exec turbo run build --filter=@truenine/memory-sync-mcp
352540 - name : Publish to npm
353- working-directory : ./mcp
354- run : pnpm publish --access public --no-git-checks
541+ shell : bash
355542 env :
356543 NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
544+ run : |
545+ set -euo pipefail
546+
547+ package_name=$(jq -r '.name' mcp/package.json)
548+ package_version=$(jq -r '.version' mcp/package.json)
549+
550+ version_exists() {
551+ local published_version
552+ published_version=$(npm view "${package_name}@${package_version}" version --registry "$NPM_REGISTRY_URL" 2>/dev/null || true)
553+ [[ "$published_version" == "$package_version" ]]
554+ }
555+
556+ verify_version_exists() {
557+ local attempts=10
558+ local delay_seconds=6
559+
560+ for attempt in $(seq 1 "$attempts"); do
561+ if version_exists; then
562+ echo "Verified ${package_name}@${package_version} on npm"
563+ return 0
564+ fi
565+
566+ echo "Waiting for ${package_name}@${package_version} to appear on npm (${attempt}/${attempts})..."
567+ sleep "$delay_seconds"
568+ done
569+
570+ echo "::error::${package_name}@${package_version} is still missing from npm after publish."
571+ return 1
572+ }
573+
574+ if version_exists; then
575+ echo "${package_name}@${package_version} already exists on npm, skipping"
576+ exit 0
577+ fi
578+
579+ if (cd mcp && pnpm publish --access public --no-git-checks); then
580+ verify_version_exists
581+ exit 0
582+ fi
583+
584+ if version_exists; then
585+ echo "${package_name}@${package_version} already exists on npm after publish attempt, skipping"
586+ exit 0
587+ fi
588+
589+ echo "::error::Failed to publish ${package_name}@${package_version}. Exact version is still missing from npm."
590+ exit 1
357591
358592 # 5. 构建 CLI 独立二进制(仅 artifact,不发 Release)
359593 build-binary :
0 commit comments