|
54 | 54 |
|
55 | 55 | - uses: actions/setup-node@v4 |
56 | 56 | with: |
57 | | - node-version: "22" |
| 57 | + node-version: "24" |
58 | 58 | registry-url: "https://registry.npmjs.org" |
59 | 59 |
|
60 | 60 | - name: Install dependencies |
|
69 | 69 | - name: Format check |
70 | 70 | run: bun run format:check |
71 | 71 |
|
72 | | - # Fail fast on bad/missing NPM_TOKEN before any side effects |
73 | | - # (version.ts writes to package.json, network calls to GH, etc.) |
74 | | - # Surfaces auth issues in ~2s instead of mid-publish. |
75 | | - - name: Verify npm auth |
76 | | - run: npm whoami --registry=https://registry.npmjs.org/ |
77 | | - env: |
78 | | - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
79 | | - |
80 | 72 | - name: Resolve version |
81 | 73 | id: version |
82 | 74 | run: bun script/version.ts |
@@ -107,11 +99,15 @@ jobs: |
107 | 99 | # recovery handler prints the exact manual recovery commands. |
108 | 100 | # ============================================================ |
109 | 101 |
|
| 102 | + # Authentication for npm publish uses OIDC trusted publishing — |
| 103 | + # no NODE_AUTH_TOKEN needed. npm CLI auto-detects the OIDC |
| 104 | + # environment when id-token: write is set and no token is present. |
| 105 | + # Configured on npmjs.com under package settings → Trusted Publishers. |
| 106 | + # Requires npm CLI v11.5.1+ and Node 22.14.0+. |
110 | 107 | - name: Publish to npm |
111 | 108 | id: publish |
112 | 109 | run: bun script/publish.ts |
113 | 110 | env: |
114 | | - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
115 | 111 | NPM_CONFIG_PROVENANCE: "true" |
116 | 112 | KILO_CHANNEL: ${{ steps.version.outputs.channel }} |
117 | 113 |
|
@@ -140,114 +136,6 @@ jobs: |
140 | 136 | echo "::warning::Could not verify $VERSION on the registry after 60s of polling. The publish step itself reported success; verification is informational only and the workflow will continue to the tag/release steps." |
141 | 137 | exit 0 |
142 | 138 |
|
143 | | - # Reconcile npm dist-tags.latest after a dev publish. On the very |
144 | | - # first publish of a new package, npm auto-assigns `latest` to |
145 | | - # whatever version was published, regardless of `--tag dev`. That |
146 | | - # leaves end users running plain `npm install <pkg>` getting a |
147 | | - # prerelease, which trips OpenClaw's prerelease guard with a |
148 | | - # confusing error. |
149 | | - # |
150 | | - # This step runs ONLY for dev-channel publishes, and ONLY when |
151 | | - # `latest` currently points at a prerelease version. It tries to |
152 | | - # repoint `latest` to the highest existing stable. If no stable |
153 | | - # exists yet (the pre-stable phase, i.e. before the first |
154 | | - # `channel=latest` release), it emits a warning and exits 0. |
155 | | - # |
156 | | - # Like the verify step above, this is INFORMATIONAL only — |
157 | | - # it never fails the workflow and never blocks tag/release. |
158 | | - - name: Reconcile latest dist-tag (dev publishes) |
159 | | - if: steps.publish.outcome == 'success' && steps.version.outputs.channel == 'dev' |
160 | | - env: |
161 | | - VERSION: ${{ steps.version.outputs.version }} |
162 | | - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
163 | | - run: | |
164 | | - set -euo pipefail |
165 | | - PKG="@kilocode/openclaw-security-advisor" |
166 | | -
|
167 | | - # Read dist-tags via the registry HTTP endpoint (faster |
168 | | - # propagation than `npm view` which has a separate cache layer |
169 | | - # and can return stale data for 30-90s after a publish). |
170 | | - # Retry up to 3x with 5s backoff in case the dist-tags entry |
171 | | - # itself hasn't propagated yet. |
172 | | - fetch_latest_dist_tag() { |
173 | | - curl -s "https://registry.npmjs.org/-/package/$PKG/dist-tags" 2>/dev/null | node -e ' |
174 | | - let s = ""; |
175 | | - process.stdin.on("data", d => s += d); |
176 | | - process.stdin.on("end", () => { |
177 | | - try { console.log(JSON.parse(s).latest || ""); } |
178 | | - catch { console.log(""); } |
179 | | - }); |
180 | | - ' || echo "" |
181 | | - } |
182 | | -
|
183 | | - LATEST="" |
184 | | - for attempt in 1 2 3; do |
185 | | - LATEST=$(fetch_latest_dist_tag) |
186 | | - if [ -n "$LATEST" ]; then |
187 | | - break |
188 | | - fi |
189 | | - if [ "$attempt" -lt 3 ]; then |
190 | | - echo " dist-tags query attempt $attempt/3 returned empty, retrying in 5s..." |
191 | | - sleep 5 |
192 | | - fi |
193 | | - done |
194 | | - echo "Current dist-tags.latest: ${LATEST:-<unset>}" |
195 | | -
|
196 | | - # If `latest` is empty or already a stable version (no `-`), |
197 | | - # there's nothing to reconcile. |
198 | | - case "$LATEST" in |
199 | | - "") |
200 | | - echo "::notice::dist-tags.latest is unset; nothing to reconcile" |
201 | | - exit 0 |
202 | | - ;; |
203 | | - *-*) |
204 | | - : # prerelease — fall through to reconciliation |
205 | | - ;; |
206 | | - *) |
207 | | - echo "::notice::dist-tags.latest is already a stable version ($LATEST); nothing to reconcile" |
208 | | - exit 0 |
209 | | - ;; |
210 | | - esac |
211 | | -
|
212 | | - # Find the highest stable version on the registry. Handles |
213 | | - # both shapes of `npm view ... versions --json`: a string for |
214 | | - # single-version packages, an array for multi-version. |
215 | | - HIGHEST_STABLE=$(npm view "$PKG" versions --json 2>/dev/null | node -e ' |
216 | | - let s = ""; |
217 | | - process.stdin.on("data", d => s += d); |
218 | | - process.stdin.on("end", () => { |
219 | | - try { |
220 | | - const data = JSON.parse(s); |
221 | | - const arr = Array.isArray(data) ? data : [data]; |
222 | | - const stable = arr.filter(x => typeof x === "string" && !x.includes("-")); |
223 | | - if (!stable.length) process.exit(42); |
224 | | - stable.sort((a, b) => a.localeCompare(b, undefined, { numeric: true })); |
225 | | - console.log(stable[stable.length - 1]); |
226 | | - } catch { |
227 | | - process.exit(43); |
228 | | - } |
229 | | - }); |
230 | | - ') || HIGHEST_STABLE="" |
231 | | -
|
232 | | - if [ -z "$HIGHEST_STABLE" ]; then |
233 | | - echo "::warning::No stable version of $PKG exists on the registry yet. npm auto-assigned dist-tags.latest to the just-published dev version ($LATEST) because --tag dev alone cannot prevent it on a first publish. Users must opt in to the dev channel explicitly: 'openclaw plugins install $PKG@dev' or 'npm install $PKG@dev'. This is expected and non-fatal until the first stable (channel=latest) release ships, at which point this step will repoint latest automatically." |
234 | | - exit 0 |
235 | | - fi |
236 | | -
|
237 | | - echo "Highest stable on registry: $HIGHEST_STABLE — repointing latest..." |
238 | | - for i in 1 2 3; do |
239 | | - if npm dist-tag add "$PKG@$HIGHEST_STABLE" latest; then |
240 | | - echo "::notice::Repointed dist-tags.latest from $LATEST to $HIGHEST_STABLE" |
241 | | - exit 0 |
242 | | - fi |
243 | | - if [ "$i" -lt 3 ]; then |
244 | | - echo " attempt $i/3 failed, retrying in 5s..." |
245 | | - sleep 5 |
246 | | - fi |
247 | | - done |
248 | | - echo "::warning::Failed to repoint dist-tags.latest to $HIGHEST_STABLE after 3 attempts. Manual fix: npm dist-tag add $PKG@$HIGHEST_STABLE latest" |
249 | | - exit 0 |
250 | | -
|
251 | 139 | - name: Configure git identity |
252 | 140 | if: steps.publish.outcome == 'success' |
253 | 141 | run: | |
|
0 commit comments