# Releasing npm packages
This repository follows npm's 2026 security direction: no long-lived publish token. GitHub's announcement states that bypass-2FA granular tokens lose sensitive-management bypass and are planned to lose direct publishing; npm recommends Trusted Publishing (OIDC) or staged publishing instead.
Primary references:
-
-
## One-time bootstrap for a new npm package
An unpublished package has no npm Settings page, so its first public version is bootstrapped interactively:
1. Use Node.js 24.15 or newer with npm 12 or newer for the current Passkey flow. On this workstation the known-good binaries live under `~/.nvm/versions/node/v24.15.0/bin`.
2. Run `npm login --auth-type=web --registry=https://registry.npmjs.org` and complete the browser login with the npm Passkey stored in Bitwarden. npm's email-verification code is not a publishing second factor.
3. From a clean checkout, run `npm run check && npm run pack:check && npm run security:scan`, then `npm publish --workspace --access public`. Open the authentication URL printed by npm and approve the Passkey. Never paste credentials into chat or a repository file.
4. Create the Trusted Publisher directly from npm CLI (no form filling and no token):
```bash
npm trust github \
--file publish.yml \
--repo nickhelion/dsh-plugins \
--allow-publish \
--yes
```
5. Set the maximum package publishing restriction. In npm CLI, `mfa=publish` means 2FA is required and automation/bypass tokens are disallowed; Trusted Publishing OIDC remains allowed:
```bash
npm access set mfa=publish
```
6. Trigger a patch release and verify the npm provenance attestation.
7. Run `npm logout --registry=https://registry.npmjs.org` and confirm `~/.npmrc` has no npm auth token.
Repeat steps 3–5 for each new package. Each package gets one Trusted Publisher, but both may authorize the same workflow filename.
## Normal Agent release (no npm login)
1. Update and commit the target package's `CHANGELOG.md` with the intended version.
2. Ensure the repository is clean and on `main`.
3. Prepare locally:
```bash
npm run release -- dsh-qwen-token-plan-cn-responses 0.1.4
# or
npm run release -- dsh-serverchan-notify 1.0.3
```
4. Inspect the generated version commit and annotated Tag.
5. Push with the same command plus `--push`, or explicitly push `main` and the package Tag.
6. GitHub-hosted Actions exchanges its OIDC identity for a short-lived npm credential, publishes, and records provenance. No `NPM_TOKEN` exists.
7. Verify the exact npm version, provenance, GitHub workflow and clean Git status.
Only a **Tag job** may execute `npm publish`. A main-branch catalog merge merely creates the missing package Tag; that Tag then starts the same publisher used by normal releases. This prevents a release commit that changes `catalog.snapshot.json` from racing two publishers for one immutable npm version. Rerunning an already-published Tag skips the immutable publish and still verifies npm/GitHub release state.
## Reviewed Qwen catalog release
The Qwen provider has a second, narrower path for official catalog drift:
1. `catalog-sync.yml` checks public official documents daily and exits without a commit when the bundled snapshot is unchanged.
2. A real change produces one automation PR containing the generated snapshot, patch version, changelog, README pin and lockfile.
3. Review model additions/removals and reasoning semantics. Run the local `reasoning:probe` maintainer command for new or changed reasoning profiles; no provider credential is stored in GitHub.
4. Merge only after review and green validation. The snapshot-path push on `main` verifies that it came from the catalog automation PR and creates the package Tag; the Tag publishes through OIDC and creates the GitHub release.
Installed plugins never fetch official documentation. Do not bypass this review path by editing the generated snapshot directly.
## Tag prefixes
| Package | Tag |
| --- | --- |
| `dsh-qwen-token-plan-cn-responses` | `qwen-token-plan-cn-responses-vX.Y.Z` |
| `dsh-serverchan-notify` | `serverchan-notify-vX.Y.Z` |
The publish workflow refuses a Tag whose version differs from its package manifest.
## Never do this
- Do not commit `.npmrc` auth lines.
- Do not store `NPM_TOKEN` in GitHub Actions for these packages.
- Do not recreate the former Automation/GAT token wizard.
- Do not bypass failed OIDC by minting a persistent token; fix repository/workflow/package Trusted Publisher fields instead.