From ac0c07202420571965f71425f1cab38990e9f1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=EC=84=B1=EC=A4=80?= Date: Sun, 25 Oct 2026 18:55:17 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EB=90=9C=20npm=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98=20=EA=B2=80=EC=A6=9D=EC=9D=B4=20=EC=8B=A4=ED=8C=A8?= =?UTF-8?q?=ED=95=98=EB=8D=98=20=EB=91=90=20=EA=B0=80=EC=A7=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B3=A0=EC=B3=A4=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verify published npm install은 플랫폼 패키지를 전역 루트에서만 찾았다. npm은 전역 설치에서 launcher의 optional dependency를 전역 루트로 올리거나 launcher 밑에 중첩하거나 둘 다 할 수 있고, v0.1.0-rc.4에서는 중첩됐다. 게시된 패키지는 정상이었는데도 다섯 플랫폼이 전부 같은 줄에서 떨어졌다. 이 job은 rc.3까지 publish 실패로 skip돼서 한 번도 실행된 적이 없어 드러나지 않았다. 양쪽 배치를 모두 받아들이고, 설치가 맞는지는 뒤따르는 version/licenses 검사가 판단한다. publish의 게시 확인 루프는 12회(60초)였다. registry가 integrity와 dist-tag와 provenance를 함께 서빙하기까지 그보다 오래 걸려서, 재실행마다 패키지가 하나씩만 올라가고 나머지는 timeout 됐다. rc.4는 그래서 수동 재실행이 여섯 번 필요했다. 60회(5분)로 올린다. Co-Authored-By: Claude Opus 5 --- .github/workflows/release.yml | 37 +++++++++++++++++++++++++++++------ npm/scripts/publish.mjs | 5 ++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 164595f..5dbdb95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1046,8 +1046,22 @@ jobs: sleep 5 done global_root=$(npm root --global --prefix "$test_root/install") + # A global install keeps the launcher's optional platform dependency under the launcher + # instead of hoisting it to the global root, and npm is free to choose either layout. + # Pinning one spelling failed every platform of v0.1.0-rc.4 while the published packages + # were correct, so accept both and let the version/licenses checks below judge the install. + platform_package_root() { + for candidate in \ + "$global_root/@xgen-ai/$PLATFORM_PACKAGE" \ + "$global_root/@xgen-ai/cli/node_modules/@xgen-ai/$PLATFORM_PACKAGE"; do + if [ -f "$candidate/package.json" ]; then + printf '%s\n' "$candidate" + return 0 + fi + done + } test -f "$global_root/@xgen-ai/cli/package.json" - test -f "$global_root/@xgen-ai/$PLATFORM_PACKAGE/package.json" + test -n "$(platform_package_root)" HOME="$test_root/home" \ XGEN_STATE_HOME="$test_root/state" \ "$test_root/install/bin/xgen" --version > "$test_root/version.txt" @@ -1074,7 +1088,7 @@ jobs: --registry=https://registry.npmjs.org/ \ "@xgen-ai/cli@$version" test -f "$global_root/@xgen-ai/cli/package.json" - test -f "$global_root/@xgen-ai/$PLATFORM_PACKAGE/package.json" + test -n "$(platform_package_root)" test "$(HOME="$test_root/home" XGEN_STATE_HOME="$test_root/state" \ "$test_root/install/bin/xgen" --version)" = "xgen $version" test ! -e "$test_root/state" @@ -1084,7 +1098,7 @@ jobs: npm uninstall --global --prefix "$test_root/install" \ --ignore-scripts --no-audit --no-fund '@xgen-ai/cli' test ! -e "$global_root/@xgen-ai/cli" - test ! -e "$global_root/@xgen-ai/$PLATFORM_PACKAGE" + test -z "$(platform_package_root)" test ! -e "$test_root/install/bin/xgen" - name: Install and verify exact npm package on Windows @@ -1123,10 +1137,21 @@ jobs: } if (-not $Installed) { throw "npm install failed" } $GlobalRoot = (& npm.cmd root --global --prefix $InstallRoot | Out-String).Trim() + # npm may hoist the launcher's optional platform dependency to the global root or + # keep it under the launcher; both are a correct install, so accept either. + function Get-PlatformPackageRoot { + foreach ($Candidate in @( + (Join-Path $GlobalRoot "@xgen-ai/$env:PLATFORM_PACKAGE"), + (Join-Path $GlobalRoot "@xgen-ai/cli/node_modules/@xgen-ai/$env:PLATFORM_PACKAGE") + )) { + if (Test-Path -LiteralPath (Join-Path $Candidate "package.json")) { return $Candidate } + } + return $null + } if (-not (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/cli/package.json"))) { throw "launcher package is missing" } - if (-not (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/$env:PLATFORM_PACKAGE/package.json"))) { + if (-not (Get-PlatformPackageRoot)) { throw "platform package is missing" } $Shim = Join-Path $InstallRoot "xgen.cmd" @@ -1166,7 +1191,7 @@ jobs: } if ( -not (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/cli/package.json")) -or - -not (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/$env:PLATFORM_PACKAGE/package.json")) + -not (Get-PlatformPackageRoot) ) { throw "npm reinstall is missing an exact package" } @@ -1179,7 +1204,7 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "npm uninstall failed" } if ( (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/cli")) -or - (Test-Path -LiteralPath (Join-Path $GlobalRoot "@xgen-ai/$env:PLATFORM_PACKAGE")) + (Get-PlatformPackageRoot) ) { throw "npm uninstall left package artifacts" } diff --git a/npm/scripts/publish.mjs b/npm/scripts/publish.mjs index 2d6bf1e..85f3e5a 100644 --- a/npm/scripts/publish.mjs +++ b/npm/scripts/publish.mjs @@ -100,7 +100,10 @@ async function publishOne(report, version, distTag) { '--ignore-scripts', report.tarball, ]); - for (let attempt = 0; attempt < 12; attempt += 1) { + // The registry needs longer than a minute to serve a new version's integrity, dist-tag and + // provenance together. At twelve attempts v0.1.0-rc.4 timed out on every run: each re-run + // published one more package and then failed, so six packages took six manual re-runs. + for (let attempt = 0; attempt < 60; attempt += 1) { remote = await remoteMetadata(report.name, version); if ( remote &&