Release
Cut a new npm version of one or more publishable packages in this repo.
Context
- Repo root:
/Users/kyh/Documents/Projects/vibedgames - Publishable packages (path = where commits "count" for change detection):
vibedgames→apps/cli→ tag prefixvibedgames@@vibedgames/multiplayer→packages/multiplayer→ tag prefix@vibedgames/multiplayer@@vibedgames/gamepad→packages/gamepad→ tag prefix@vibedgames/gamepad@
- All ship
dist/built bytsc. All three keeptsBuildInfoFileat.cache/tsbuildinfo.json— NEVER insidedist/(it would ship in the tarball; vibedgames ≤0.3.0 did exactly that). Consequence:rm -rf distalone makestscsilently emit NOTHING (cache says up-to-date). Always remove bothdistand.cache. vibedgamesand@vibedgames/multiplayerhave no internal workspace consumers.@vibedgames/gamepadIS consumed in-repo by the example games viaworkspace:^, butpnpm publishrewrites that to the published version automatically — no manual downstream sync needed.- Current branch: !
git -C /Users/kyh/Documents/Projects/vibedgames rev-parse --abbrev-ref HEAD - Working tree: !
git -C /Users/kyh/Documents/Projects/vibedgames status --short
Arguments
Parse from the user message:
- Which package(s):
cli,multiplayer,gamepad, orall(bothis still accepted as an alias for cli + multiplayer). Defaultall. - Bump type:
patch,minor,major. Defaultpatch. --forceto release even if no changes since last tag (otherwise unchanged packages are skipped).
If ambiguous, ask in one short sentence before proceeding.
Process
1. Preflight
Run in parallel:
npm whoami— must bekaiyuhsu. If not, stop and tell the user tonpm login.git status --porcelain— if dirty in unrelated files, surface and ask whether to proceed.npm view <pkg> versionfor each candidate (vibedgames,@vibedgames/multiplayer,@vibedgames/gamepad) — current published.- For each candidate package, find its last release tag and check for changes:
If the log is empty andLAST=$(git tag --list '<tag-prefix>*' --sort=-v:refname | head -1) git log --oneline ${LAST:+$LAST..}HEAD -- <pkg-path>--forcewas not passed, drop that package from the release set with a note. Release whatever remains — a single changed package (e.g. only@vibedgames/gamepad) still ships. Stop only if every candidate drops (nothing to release).
2. Bump
Edit version in each remaining target's package.json. Keep semver. If the published latest is ahead of the local file (out-of-band publish), use the published version as the floor and bump from there.
3. Changelog
For each remaining target, prepend a new entry to <pkg-path>/CHANGELOG.md (create the file if missing). Source the bullets from git log --pretty='- %s' ${LAST:+$LAST..}HEAD -- <pkg-path>, dropping merge commits and the previous bump commits. Format:
# Changelog
## <new-version> — <YYYY-MM-DD>
- <commit subject>
- <commit subject>
Keep bullets terse — sacrifice grammar for concision. Drop noise like "fix typo" or pure dependency bumps unless they're the whole release. If unsure, show the proposed entry to the user before writing.
4. Install + build
pnpm installfrom repo root — defensive; deps may be unlinked after a pull.- For each target, force a clean build:
rm -rf <pkg-path>/dist <pkg-path>/.cache(both — see tsBuildInfoFile note above)pnpm --filter <pkg-name> build
- Verify
dist/exists and is non-empty.
5. Publish
For each target, from its directory:
pnpm publish --access public --no-git-checks
--access publicis required.--no-git-checksbecause we commit + tag after publish (so we don't tag a commit for a publish that failed).
6. Verify
npm view <pkg> dist-tags — confirm latest matches the new version. Registry can lag a few seconds; retry once after sleep 5 if needed before flagging.
7. Commit, tag, push
Single commit covering all bumps + changelogs:
release: <pkg>@<version>[, <pkg>@<version>]
Stage the changed package.json and CHANGELOG.md files only. Then create one annotated tag per released package pointing at that commit:
git tag -a '<pkg-name>@<version>' -m '<pkg-name>@<version>'
For @vibedgames/multiplayer this means a tag literally named @vibedgames/multiplayer@0.0.3 — git accepts @ in tag names.
Then push commit + tags together:
git push --follow-tags origin <current-branch>
If on main, this triggers the GitHub Actions deploy — fine, since releases are intentional shipping events. Mention it in the report so the user knows to check Actions.
8. Report
One short block:
Released:
vibedgames@X.Y.Z (tag: vibedgames@X.Y.Z)
@vibedgames/multiplayer@X.Y.Z (tag: @vibedgames/multiplayer@X.Y.Z)
@vibedgames/gamepad@X.Y.Z (tag: @vibedgames/gamepad@X.Y.Z)
Skipped (no changes): <pkg> (since <last-tag>)
Commit: <sha> (pushed to origin/<branch>)
Actions: triggered if pushed to main — verify deploy
If anything failed, lead with the failure and what state the registry / git remote is in (published? committed? tagged? pushed?).
Rules
- Never run
wrangler deployhere. This skill is npm-only. Worker deploys go through GitHub Actions on push to main (which this skill will trigger by pushing — that's fine for a release). - Never
--forcepush or amend prior release commits. If a publish half-succeeds (e.g. one of several packages), commit + tag + push what shipped, then handle the others separately. - If
npm publishfails withEPUBLISHCONFLICT(version already on registry), bump again rather than try to overwrite. - Tags must be created after successful publish + verify, never before. A tag without a matching registry version is worse than no tag.
- Skipping is the default for packages with no path-scoped commits since their last tag. Pass
--forceto override. - Bootstrap: if no prior tag exists for a package, treat all of its history as "the changes" — but cap the changelog bullets at the last 20 commits to keep it readable.