name: publish
Cut a minor or major release: generate the changelog, bump, publish to npm, and create the GitHub release. Patch releases are intentionally not offered here.
This skill performs the actual publish (npm publish, git push, GitHub release) — that is the whole point of invoking it, so the general "hand the user the commands" rule does not apply inside /publish. The confirmation gate in Step 5 is the safeguard: never run a step past it without explicit approval.
Run from the repo root.
Copy this checklist and work through it in order:
- [ ] 1. Preflight: branch, sync, auth
- [ ] 2. Read base version from npm, compute candidates
- [ ] 3. Ask the user: minor or major
- [ ] 4. Generate the CHANGELOG entry from commits since the last tag
- [ ] 5. CONFIRMATION GATE — show changelog + plan, get explicit approval
- [ ] 6. Write CHANGELOG.md, bump, build
- [ ] 7. Commit + push
- [ ] 8. npm publish
- [ ] 9. scripts/release.sh (GitHub release)
- [ ] 10. Verify on the npm registry
git rev-parse --abbrev-ref HEAD # expect: main
git fetch origin
git status --porcelain # working tree should be clean
git rev-list --left-right --count origin/main...HEAD # "<behind> <ahead>"
npm whoami # npm auth (publish will fail without it)
gh auth status # gh auth (release.sh needs it)
main, stop and ask the user to confirm releasing from this branch.git pull --ff-only so the final push is a fast-forward.npm whoami or gh auth status fails, stop and tell the user to authenticate.The latest published version is the source of truth, not local package.json.
PKG=$(node -p "require('./package.json').name")
BASE=$(npm view "$PKG" version)
node -e "const [a,b]=process.argv[1].split('.').map(Number);console.log('minor ->',a+'.'+(b+1)+'.0');console.log('major ->',(a+1)+'.0.0')" "$BASE"
Note if local package.json differs from BASE (an unpublished bump) — surface it, but still base the new version on npm.
Use the AskUserQuestion tool with the two computed candidates as options (show the resulting version in each label, e.g. "minor → 0.8.0"). Set the new version from the answer.
LAST=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null)
git log --no-merges "${LAST}..HEAD" --pretty=format:'%h %s'
Read the commit subjects; for any whose user impact is unclear, inspect the diff (git show <hash> or git diff "${LAST}..HEAD" -- <path>). Then write the entry yourself following the repo's conventions in CLAUDE.md → "Writing changelog entries":
## [X.Y.Z] - YYYY-MM-DD (get the date with date +%F).### Added, ### Changed, ### Fixed, ### Removed, ### Deprecated, ### Security — omit empty sections.[X.Y.Z]: https://github.com/colbymchenry/codegraph/releases/tag/vX.Y.Z.Do not write to any file yet — draft it for review first.
Show the user, in chat:
BASE → X.Y.Z, minor/major).Then STOP. Proceed only on explicit approval ("yes" / "proceed"). If the user requests prose changes, revise the draft and re-show. Do not run any command below until approved.
## [X.Y.Z] block at the top of CHANGELOG.md (under the intro, above the previous version), and add the link reference with the other [x.y.z]: links at the bottom.Bump (also updates package-lock.json; --allow-same-version keeps re-runs safe):
npm version X.Y.Z --no-git-tag-version --allow-same-version
Build (fail fast before any push/publish):
npm run build
release.sh tags HEAD, so the bump must be committed first.
git add package.json package-lock.json CHANGELOG.md
git commit -m "release: X.Y.Z"
git push
npm publish --access public
scripts/release.sh reads the ## [X.Y.Z] block from CHANGELOG.md, tags vX.Y.Z, pushes the tag, and creates the GitHub release. It is idempotent.
./scripts/release.sh
Confirm against the registry, not the website (the website caches):
npm view "$PKG" version # must equal X.Y.Z
Report the release URL (scripts/release.sh prints it) and the published version.
Re-running is safe: npm version --allow-same-version no-ops if already bumped, git commit skips if nothing's staged (check git diff --cached --quiet), git push no-ops if up to date, and scripts/release.sh skips tag/release steps already done. Re-run from the failed step.