Problem
npm install -g @unbrained/pm-cli@<exact version> is not reproducible: the published package has no npm-shrinkwrap.json, so every install re-resolves the transitive tree from caret ranges at install time. Pinning the CLI version pins nothing below it.
On 2026-10-06 this broke every CI job that installs a pinned CLI, with no change on our side:
npm install -g @unbrained/pm-cli@2026.10.5
npm error code ETARGET
npm error notarget No matching version found for @opentelemetry/resources@2.12.0.
A few minutes later the same command failed with E404 GET .../@opentelemetry/sdk-trace/-/sdk-trace-2.12.0.tgz. The OpenTelemetry 2.12.0 release was propagating: the packuments already listed 2.12.0 (published 13:40:53Z; our failing install ran at 13:40:43Z) before the tarballs were served. The packages come in transitively through @sentry/node (pinned at 10.75.1, but its own OpenTelemetry deps use ^ ranges). Every downstream repo that pins @unbrained/pm-cli@X as a test oracle or tool failed at once: Linux, macOS and Windows jobs, required checks included.
Related: dependencies includes "@types/node": ">=22". That is an unbounded range on a type-only package, so a global install pulls whatever @types/node major is newest. Type definitions are not needed at runtime, and an open-ended >= is the least reproducible range there is.
Proposal
- Publish
npm-shrinkwrap.json with the CLI package (npm honours it for both npm i -g and npx), generated from the release lockfile that CI actually tested. A pinned CLI version then installs exactly the tree that passed the release gates. Bun's bunx/bun add -g ignore shrinkwrap, so also document --frozen-lockfile-equivalent guidance, or accept that Bun floats.
- Move
@types/node to devDependencies. If consumers of the SDK types need it, use peerDependencies + peerDependenciesMeta.optional, with a bounded range (^22 || ^24 || ^26).
- Optional: a release gate that installs the packed tarball with
--prefer-offline=false into an empty prefix, and fails if the resolved tree differs from the tested lockfile.
Acceptance
npm view @unbrained/pm-cli@<next> _hasShrinkwrap is true.
- Installing the same CLI version on two different days resolves byte-identical
node_modules (same integrity hashes).
@types/node is no longer a runtime dependency.
Problem
npm install -g @unbrained/pm-cli@<exact version>is not reproducible: the published package has nonpm-shrinkwrap.json, so every install re-resolves the transitive tree from caret ranges at install time. Pinning the CLI version pins nothing below it.On 2026-10-06 this broke every CI job that installs a pinned CLI, with no change on our side:
A few minutes later the same command failed with
E404 GET .../@opentelemetry/sdk-trace/-/sdk-trace-2.12.0.tgz. The OpenTelemetry 2.12.0 release was propagating: the packuments already listed 2.12.0 (published 13:40:53Z; our failing install ran at 13:40:43Z) before the tarballs were served. The packages come in transitively through@sentry/node(pinned at10.75.1, but its own OpenTelemetry deps use^ranges). Every downstream repo that pins@unbrained/pm-cli@Xas a test oracle or tool failed at once: Linux, macOS and Windows jobs, required checks included.Related:
dependenciesincludes"@types/node": ">=22". That is an unbounded range on a type-only package, so a global install pulls whatever@types/nodemajor is newest. Type definitions are not needed at runtime, and an open-ended>=is the least reproducible range there is.Proposal
npm-shrinkwrap.jsonwith the CLI package (npm honours it for bothnpm i -gandnpx), generated from the release lockfile that CI actually tested. A pinned CLI version then installs exactly the tree that passed the release gates. Bun'sbunx/bun add -gignore shrinkwrap, so also document--frozen-lockfile-equivalent guidance, or accept that Bun floats.@types/nodetodevDependencies. If consumers of the SDK types need it, usepeerDependencies+peerDependenciesMeta.optional, with a bounded range (^22 || ^24 || ^26).--prefer-offline=falseinto an empty prefix, and fails if the resolved tree differs from the tested lockfile.Acceptance
npm view @unbrained/pm-cli@<next> _hasShrinkwrapistrue.node_modules(same integrity hashes).@types/nodeis no longer a runtime dependency.