diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a52853..bcfd636 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,43 @@ jobs: with: node-version: 22 registry-url: https://registry.npmjs.org + + - name: Sync package-lock.json if version drifted + # When the maintainer bumps the version on package.json only — for + # example via a GitHub web-UI edit — `npm ci` would refuse to run + # with `EUSAGE: npm ci can only install packages when your + # package.json and package-lock.json … are in sync`. This step + # rewrites just the lock-file's version fields (top-level + the + # `packages.""` entry) to match package.json, then auto-commits + # and pushes the result so on-disk truth on `main` stays + # consistent. Idempotent: if the lock file already matches, no + # commit is made. + run: | + set -euo pipefail + PKG_V=$(node -p "require('./package.json').version") + LOCK_V=$(node -p "require('./package-lock.json').version") + if [ "$PKG_V" = "$LOCK_V" ]; then + echo "package-lock.json already at $PKG_V — nothing to sync." + exit 0 + fi + echo "Lock-file version drift: lock=$LOCK_V, package=$PKG_V. Syncing." + # `--package-lock-only` rewrites only the lock file, doesn't + # touch node_modules or actually install anything. Cheap. + npm install --package-lock-only --ignore-scripts + # Sanity: lockfile should now report the package version. + NEW_LOCK_V=$(node -p "require('./package-lock.json').version") + if [ "$NEW_LOCK_V" != "$PKG_V" ]; then + echo "::error::lock-file still at $NEW_LOCK_V after sync attempt; expected $PKG_V"; exit 1 + fi + if git diff --quiet -- package-lock.json; then + echo "lock file unchanged after sync? bailing"; exit 1 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add package-lock.json + git commit -m "release: sync package-lock.json to ${PKG_V}" -m "[skip ci] Auto-generated by Release workflow." + git push origin "HEAD:${GITHUB_REF#refs/heads/}" + - run: npm ci - name: Ensure zip/unzip run: sudo apt-get update -qq && sudo apt-get install -y -qq zip unzip diff --git a/CLAUDE.md b/CLAUDE.md index cb2f2a2..5fd9b27 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -225,23 +225,28 @@ and publishes both the GitHub Release and the npm thin-installer Publishing manually is **wrong** now — a plain `npm publish` ships the root package (non-bundled), which breaks anyone on Node < 22.5. -The release cut itself is: +**Claude does NOT bump the version unless explicitly asked.** The maintainer +typically does it themselves — often by editing `package.json` directly via +the GitHub web UI. Don't proactively commit a version bump as part of +unrelated work, and don't propose one when summarizing a PR. -```bash -# CHANGELOG already has entries under [Unreleased] — no manual moves needed. -# Just bump the version: -npm version --no-git-tag-version # or edit package.json manually -git add package.json package-lock.json -git commit -m "release: X.Y.Z" -git push -``` +When the maintainer DOES bump the version, the only edit strictly required is +to `package.json` — the workflow's "Sync package-lock.json" step detects a +mismatch between `package.json` and `package-lock.json`, runs +`npm install --package-lock-only --ignore-scripts` to rewrite the lock file's +version fields (top-level + `packages.""`), and auto-commits + pushes the +result back to `main` with `[skip ci]`. So a GitHub-web-UI single-file edit to +`package.json` is enough to kick off a clean release. (If they edit both files +locally, that's fine too — the sync step no-ops.) -Then trigger **Actions → Release → Run workflow** (on `main`). The workflow: +Once `package.json` is at the target version on `main`, trigger +**Actions → Release → Run workflow** (on `main`). The workflow: -1. Runs `prepare-release.mjs ` → promotes `[Unreleased]` → `[X.Y.Z] - ` in `CHANGELOG.md`, appends the link reference, commits + pushes the move with `[skip ci]`. -2. Builds every platform bundle on one runner, generates `SHA256SUMS`. -3. Creates the GitHub Release with notes from the freshly-promoted `[X.Y.Z]` block. -4. Publishes the npm shim + per-platform packages. Requires the `NPM_TOKEN` repo secret. +1. Syncs `package-lock.json` to `package.json`'s version if they've drifted; commits + pushes that change. +2. Runs `prepare-release.mjs ` → promotes `[Unreleased]` → `[X.Y.Z] - ` in `CHANGELOG.md`, appends the link reference, commits + pushes the move with `[skip ci]`. +3. Builds every platform bundle on one runner, generates `SHA256SUMS`. +4. Creates the GitHub Release with notes from the freshly-promoted `[X.Y.Z]` block. +5. Publishes the npm shim + per-platform packages. Requires the `NPM_TOKEN` repo secret. **Do not run `npm publish`, `git push`, or `git tag` yourself** — these are publish actions on shared state. Write the files, hand the user the commands.