Upgrade NPM Packages
A malicious npm release is usually found and pulled from the registry within days. The project therefore waits before taking any newly published package version.
- Dependabot waits three days, through
cooldown: default-days: 3in.github/dependabot.yml. - Upgrades made by hand bypass Dependabot. Run them through the
upgrade-npm-packagesagent skill or its script, which wait ten days.
Agent skill
The upgrade-npm-packages skill in .agents/skills/ runs the script,
explains every change, runs the project's build and tests, and pins back
any upgrade that breaks them. Ask a coding agent to upgrade the npm
packages of a project to use it. Coding Agents
explains how skills are organised.
Usage
The script needs Node.js 24 or later, npm 7 or later and yarn 1. It has no npm dependencies of its own. To run it without an agent:
The script takes the path to one package.json and performs these steps:
- Computes the cutoff date, ten days before now.
- For every entry in
dependencies,devDependenciesandoptionalDependencies, picks the newest stable, non-deprecated version published on or before the cutoff that stays within the range the spec already allows. The range prefix (^,~or none) is kept. - Writes the new versions into the
package.json. - Deletes the
yarn.lockbeside it and generates a fresh one.
The range follows npm's meaning of the prefix, and an exact version is
treated like ^:
| Spec | Stays below |
|---|---|
^6.0.3 or 6.0.3 |
7.0.0 |
^0.18.9 |
0.19.0 |
~30.4.2 |
30.5.0 |
The output lists every changed package as upgrade or DOWNGRADE, and
every package left alone as skip, with the reason. A line starting with
newer names a version outside the range, such as a new major release,
which the script does not apply. Take such a version by editing the
package.json and running the script again.
Packages published from this repository
Packages in the @into-cps-association/ scope, such as
@into-cps-association/dt-automation, are built and published from this
repository, so the cooldown does not apply to them. The script keeps their
versions as written in the package.json, even when the release is only
days old. Their provenance is tracked separately; see the issue on npm
provenance attestations.
How the new lockfile honours the cooldown
Yarn 1 has no setting to hold back recently published versions, and a
fresh yarn install resolves every transitive dependency to its newest
version. The script therefore builds the lockfile in an empty temporary
directory, away from any existing node_modules:
npm install --package-lock-only --before=<cutoff>resolves the whole dependency tree, transitive dependencies included, as it stood at the cutoff. The exempt@into-cps-association/packages are left out of this step.- A second
npm install --package-lock-only, without--before, adds the exempt packages. It keeps every version the first step locked. Any package this step adds is printed asno cooldown: <name>@<version>for review. yarn_lock_from_npm.jsconverts thepackage-lock.jsoninto ayarn.lockholding exactly the versions npm chose.yarn install --frozen-lockfilechecks that yarn accepts the lockfile without resolving anything itself. The lockfile is then copied beside thepackage.json.
yarn import is not used. It reads an existing node_modules in
preference to the package-lock.json, and it re-resolves some entries
from the live registry, which lets recent versions back in.
Run yarn install afterwards to install the new versions.
Review the result
The script applies the cooldown mechanically. Review the diff before committing it.
- Downgrades. A version newer than the cutoff is replaced by the newest older version.
- Newer versions outside the range. Review each
newerline. A major release can break the build; for example, TypeScript 7 does not work withts-jest, so the client stays on TypeScript 6. - Deliberate pins. A
~range keeps a package on its minor release. For example,jestinservers/libstays on~30.4.2; seeservers/lib/DEVELOPER.md. - Skipped entries. Ranges such as
>=1.0.0,file:andnpm:aliases, prerelease versions and packages missing from the registry are left unchanged.
Then run the build and test commands for the project; see PROJECT.md.
Linting and tests
The Lint and Test Node Scripts job in
.github/workflows/lint-scripts.yml checks the skill's scripts/
directory with eslint and prettier, runs its unit tests, and checks every
skill's Claude Code stub. The linters are installed only in
CI, at exact versions and without a package.json. To run the same checks
locally: