Skip to main content

shadscan-release

Cut and publish a new @shadscan/cli version to npm, including version bump, CHANGELOG.md and site changelog entries, the full release gate suite, npm publish under the next or latest dist-tag, published-artifact verification in clean fixture projects, and post-publish checks. Use when the user asks to release, publish, ship, or cut a new shadscan or @shadscan/cli version, or to prepare a release candidate.

Source facts

Repository
TheOrcDev/shadscan
Last source activity
August 4, 2026 at 21:34
Detected SKILL.md language
English
Stars
557
Forks
14

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
shadscan-release
description
Cut and publish a new @shadscan/cli version to npm, including version bump, CHANGELOG.md and site changelog entries, the full release gate suite, npm publish under the next or latest dist-tag, published-artifact verification in clean fixture projects, and post-publish checks. Use when the user asks to release, publish, ship, or cut a new shadscan or @shadscan/cli version, or to prepare a release candidate.
# Shadscan release Ship one new `@shadscan/cli` version to npm with its changelog entries and verification. Prereleases (`0.1.0-rc.N`) publish under the npm `next` tag; stable releases publish under `latest` through the staged GitHub workflow. Before acting, read `docs/releasing.md` in full — it is the source of truth for owner prerequisites, gates, trusted publishing, and recovery. Keep this skill as the executable coordinator; never weaken or skip the runbook's gates. ## Completion contract - One release = one strictly higher, previously unpublished version. Confirm absence with `npm view @shadscan/cli versions --json` before starting. Published name/version pairs are immutable — corrections always fix forward with a new version, never a republish. - A release is complete only when: the version is live on npm under the intended dist-tag, the exact published version runs `--version` and a real audit from a clean directory, the dist-tag map is inspected and correct, and both changelog surfaces (root `CHANGELOG.md` and `changelog/<version>.md`) are committed and pushed. - Publish only from `packages/cli`. The repository root is a private Next.js app and must never be published. - npm 2FA belongs to the owner. Prepare and run the publish command for them, but never attempt to bypass, script, or wait out the 2FA prompt; hand the terminal to the owner at that step. - If any gate fails, stop and report the exact failing gate. Never publish a version whose gates did not all pass on the exact commit being published. ## Prerequisites - Clean working tree on up-to-date `main` (no uncommitted or unrelated WIP — the gates verify the tree as a whole). - Node.js version from `.node-version` and pnpm from the root `packageManager` field. - Owner is present for `npm login` / `npm whoami` and 2FA at publish time. - The target version does not exist on npm yet. ## 1. Prepare the version and changelogs 1. Bump `packages/cli/package.json` to the next unused version. 2. Update root `CHANGELOG.md`: move the `## Unreleased` content into a new `## <version> - <YYYY-MM-DD>` section with `### Added / Changed / Fixed / Security` groupings, and leave an empty `## Unreleased` behind. 3. Write the narrative site entry at `changelog/<version>.md`: - Frontmatter: `version`, `date`, `channel` (`next` for prereleases, `latest` for stable), `title`, `summary`, `highlights` (3–5 bullets). - Body: a few `##` sections telling the release as a story for users, not a commit list. Write it from the new CHANGELOG.md section. - The loader (`lib/changelog.ts`) validates the frontmatter at build time — `pnpm ci:build-site` failing on `/changelog` means the entry is malformed. 4. Verify the three versions agree: `packages/cli/package.json`, the new `CHANGELOG.md` heading, and the `changelog/<version>.md` frontmatter. 5. Sweep the product surfaces that no generator owns. `pnpm docs:check` catches the advertised version pins and rule counts, but run it now rather than discovering it at gate time: - **Advertised rule count** — both `README.md` and `packages/cli/README.md` state the rule count in prose ("N rules", "contains N deterministic checks"). A release that adds or removes a rule must update all four. Never touch the counts in `CHANGELOG.md` or `changelog/*.md`: those are historical records of what shipped then, and rewriting them is falsifying the record. - **Ruleset version** — `BUNDLED_RULESET_VERSION` in `packages/cli/src/scan.ts` must already be bumped by whatever added or changed a rule, and `docs/rules.md` regenerated with `pnpm docs:rules`. - **Hardcoded rule counts in tests** — `packages/cli/test/public-api.test.ts` and `packages/cli/scripts/smoke-package.mjs` both assert `RULE_CATALOG.length`. The smoke one fails late, after a full build and npm pack, with a message that says nothing about rule counts. 6. Commit the preparation and push. ## 2. Run every release gate From the repository root, per `docs/releasing.md`: ```bash pnpm install --frozen-lockfile pnpm check pnpm docs:check pnpm --filter ./packages/cli typecheck pnpm cli:test pnpm test:api pnpm test:web pnpm exec playwright install chromium pnpm test:e2e pnpm typecheck pnpm audit:dependencies pnpm audit:self pnpm build pnpm cli:smoke CLI_VERSION=$(node -p "require('./packages/cli/package.json').version") pnpm cli:release:check -- --tag next --git-tag "v${CLI_VERSION}" ``` For a stable release, use `--tag latest` and the matching stable Git tag. `pnpm build` also proves the new `/changelog` entry renders and the production trace verifier passes. ## 3. Publish ### Prerelease (`next`) 1. Owner authenticates: `npm login`, confirm with `npm whoami`. 2. Run `(cd packages/cli && npm publish --tag next --access public)` and let the owner complete 2FA. ### Stable (`latest`) Follow the staged flow in `docs/releasing.md`: signed `v<version>` Git tag, GitHub release, the publish workflow stages the artifact, owner inspects the staged tarball and approves on npm with 2FA. ## 4. Verify the published artifact 1. Inspect the tag map: `npm view @shadscan/cli dist-tags --json`. Confirm the new version is under the intended tag and `latest` did not move unintentionally during a prerelease. 2. Run the exact published version from a clean directory: `npx --yes @shadscan/cli@<version> --version`. 3. Run representative audits of the published version in clean temporary Next.js, Vite React, and generic React fixture projects. Run one fixture twice and confirm the two reports are identical — determinism is the product promise. 4. Verify the deployed site: - `/changelog` shows the new entry. - `/stats` reflects the release. **Nothing on this page is edited by hand** — every tile (`Latest`, `Versions`, `Downloads`, `Stars`) is pulled live from the npm registry and the GitHub API, and the page revalidates hourly (`export const revalidate = 3600`). So this is a confirmation step, not an update step: after publishing, the `Latest` tile should show the new version within the hour, and a new bar should appear in the per-version chart. If it still shows the previous version after the revalidate window, the publish did not reach the registry — investigate rather than editing the page. - `/rules` lists the new rule count; it reads `lib/generated/rule-catalog.json`, so a wrong number there means the catalog was not regenerated. - The audit badge/scoring flows still work (site examples stay pinned to `@next` or an exact version during the RC window). ## 5. Close out - Announce from `changelog/<version>.md` content only after verification passes (the summary paragraph is written to be quotable). - For a stable release only: replace `@next`-pinned examples in public docs and UI with unqualified `@shadscan/cli` commands, per the runbook. - If anything shipped broken: move the dist-tag back to the last good version, `npm deprecate` the bad version naming its replacement, and fix forward. Unpublish only for security or accidental disclosure, per policy. ## Hard-won rules - **Tag the release before publishing the next one.** Three releases published before their Git tag existed (0.8.0, 0.9.0, 0.10.0), leaving no commit to diff a shipped version against. `check-release.mjs` now fails when the previous release in `CHANGELOG.md` has no matching tag and names the command to fix it, but push the tag as part of the release rather than waiting for the next one to complain. - **Prose counts go stale silently.** The rule count in both READMEs is not owned by any generator. `pnpm docs:rules --check` now compares them against `RULE_CATALOG.length`, which is why that gate exists — do not "fix" a failure by editing the generated files. - Any new top-level file or directory in this repository must be added to `SCANNER_TRACE_EXCLUDES` in `next.config.ts`, or `pnpm build` fails in the postbuild trace verifier ("unrelated source"). This has broken the build before (CONTRIBUTING.md). - npm requires every package to keep a `latest` tag: the first publish got `latest` even with `--tag next`. During the RC window, never advertise the unqualified package name; keep every public command pinned to `@next` or an exact version. - Verify with `npx --yes @shadscan/cli@<exact-version>`, not a dist-tag — runner caches can serve a stale tag resolution minutes after publish. - pnpm 11.15+ ships a default `minimumReleaseAge` supply-chain gate: tag specs like `@next` silently resolve to the newest version OLD ENOUGH to pass the gate, while exact pins bypass it. A pnpm user reporting an ancient version days after a publish is probably hitting this gate, not a cache — check their pnpm major first. Locally it can be disabled with `minimumReleaseAge: 0` in `~/Library/Preferences/pnpm/config.yaml` (the YAML global config, not the legacy `rc` file). - The local shadscan audit binary (`node_modules/.bin/shadscan`) breaks when `packages/cli/dist` is mid-rebuild; use the published one-shot (`pnpm dlx @shadscan/cli@next --json`) for pre-commit audits during release work. - Yaml frontmatter parses unquoted dates as Date objects; the changelog loader normalizes this, but keep `date:` in `YYYY-MM-DD` form anyway. - The `ci:*` script variants skip the CLI rebuild; local release work must use the ordinary commands so lifecycle hooks rebuild the CLI and stale output cannot be verified or published.
View on GitHub