Nub 0.6.0 runs every package.json script body through a POSIX shell on all three platforms, makes the 24-hour install trust floor fail closed, and adds a canary release channel.
Important
Two changes affect existing projects on upgrade.
Windows script bodies now run under a POSIX shell instead of cmd.exe. A script written in cmd syntax — set NODE_ENV=production && node build.js, rd /s /q dist, %VAR% — no longer works. Rewrite it in POSIX syntax (which then works on every platform), or opt back out with script-shell=cmd in .npmrc or --script-shell cmd.
The minimumReleaseAge cooling window now fails closed. When every version satisfying a range was published less than 24 hours ago, the install errors instead of falling back to the lowest satisfying version. Set minimumReleaseAgeStrict=false in .npmrc to restore the previous fallback.
The first install after upgrading also re-links node_modules once and rebuilds native addons once, because the install caches are now keyed on the Node engine. Nothing is re-downloaded.
Script bodies run through a POSIX shell
One script body now behaves the same on macOS, Linux, and Windows — &&, pipes, $(…), ${PORT:-3000}, and globs included. macOS and Linux use the system /bin/sh. Windows has no POSIX shell, so Nub ships busybox next to its binary and uses it by default in place of cmd.exe; this adds about 700 KB to the Windows artifacts only.
Extra arguments are now escaped for the target shell and spliced onto the unescaped script body, matching how npm does it, so a multi-word argument reaches the script as a single token while the body's own expansions still run. (#559, closes #399)
The install trust floor fails closed
Nub pins both halves of the release-age floor at its own tier: a 24-hour window, and a hard failure when no version in range is old enough. The documented posture was already a hard gate; the implementation now matches it. Explicit user configuration still overrides both — the values are defaults, not policy. (#544)
Canary channel
Every code push to main now publishes a full 8-platform build under a rolling canary release and the npm canary dist-tag.
curl -fsSL https://nubjs.com/install.sh | bash -s canary # macOS, Linux
npm install -g --ignore-scripts=false @nubjs/nub@canaryA script install switches channels in place with nub upgrade --canary; nub upgrade --stable returns to the latest stable release. On a canary build, a plain nub upgrade stays on canary. (#551, #557, #558)
Interactive update picker
nub update -i replaces the pre-selected multiselect with a per-row keep-or-update table. Pressing enter with nothing selected now updates nothing rather than everything, and -i --latest folds into the same picker. Non-interactive nub update is unchanged. Minor-version rows in nub outdated moved from cyan to yellow. (#512, closes #483)
Package manager fixes
| Fix | PR |
|---|---|
| Install caches — global virtual store, side-effects cache, freshness and delta gates — are keyed on the project's Node engine, so switching Node versions no longer reuses artifacts built for another one. Dependency build scripts in a workspace member now anchor to the workspace root, matching npm and pnpm. | #530, #537, #538, #542, #548 |
nub approve-builds lists and approves dependencies installed from a local source, which install warned about but the command could not previously approve. |
#534 |
The catch-up integrity rewrite no longer re-emits a time: block the main lockfile write had already stripped. |
#531 |
Environment variables in a repo-controlled .npmrc are no longer expanded during package-manager provisioning (GHSA-3qhv-2rgh-x77r). Dependency-install authentication is unaffected. |
#370 |
| The peer pass runs in the engine's own import path, and the bun lockfile parser is covered by it. | #458 |
| The default-trust build warning drops its machine-readable fields and collapses to a single line naming the package. | #541 |
Runner and scaffold fixes
| Fix | PR |
|---|---|
nub init --name @scope/pkg preserves the scope instead of flattening it to scopepkg; malformed scoped names now error rather than silently mangling. The scaffolded .gitignore keeps .env.example. |
#515, #544 |
| The development preload resolves from the source root, closing a gap in the augmentation seam. Release builds were unaffected. | #533 |
Internal
The vendored engine gained an explicit version and provenance and split its embedder Node paths (#532). Dependency and toolchain updates now pass through a 7-day soak window (#442). Building from source requires Rust 1.95 (#553).
Commits in this release
- blog: v0.5.0 release post (
5bfca6733e) - fix(pm): key the GVS engine fingerprint off the project's Node, not the shell's (#530) (
84d0140033) - pm: tri-state interactive update picker (#512) (
58799e7523) - blog: rework the 0.5.0 init and create sections (
c6ded5d455) - fix(pm): key the side-effects cache on the Node engine, not just the platform (#537) (
f8fa6860bc) - fix(pm): record the engine in the side-effects cache marker (#538) (
67d140de24) - fix(pm): strip time: from the catch-up integrity-rewrite lockfile (#531) (
794b3bd63a) - fix(runtime): resolve the dev preload from the source root; cover the augmentation seam (#533) (
2125618456) - fix(pm): approve-builds surfaces and approves local-source deps (#534) (
a261975713) - skills(aube-bump): record the patch and build-approval fork delta (#540) (
7a6fb97128) - docs: add nub compile command page (unlisted) (
1d7dc02ccb) - Revert "docs: add nub compile command page (unlisted)" (
40a318366c) - fix(pm): fold the Node engine into the install freshness and delta gates (#542) (
0691f97988) - Trim the default trust build warning (#541) (
2c7c99937d) - pm: report linked files through the embedder events reporter, and roll back legacy lockfiles (#543) (
3830c65d75) - test(pm): pin that approve-builds runs a local-source dep's build in the same invocation (#545) (
c050655922) - scripts: run fleet builds at utility QoS with a default job cap (
6ba6d2f8a0) - skills(ad-hoc-test): warn that reused fixture package identities link stale built cells (#547) (
3ee4afd11c) - refactor(pm): document the default-trust log-collapse invariant (#546) (
fb04414e67) - fix(pm): make every remaining install cache layer engine-aware (#548) (
c5fdc55c6e) - aube: split embedder node paths, add explicit version and provenance (#532) (
57237c18dd) - fix(init): preserve scoped package names in sanitize_name (#515) (
421f6cae30) - fix(import): run the peer pass in aube's own import; cover the bun parser (#458) (
c45f2ae286) - make: clamp cargo targets to utility QoS on darwin (
0ae792acf5) - fix(pm): stop expanding env vars in a repo-controlled .npmrc (GHSA-3qhv-2rgh-x77r) (#370) (
d14224fe07) - docs: clarify agent collaboration guidance (
c3004c57ae) - site: rework start.md around an opt-in integration plan (
a4e1fa80e9) - build: 7-day soak across toolchain and deps, cold_path() hints, pinned tooling (#442) (
1efff7d445) - build: clamp every rustc to utility QoS via a machine-global cargo wrapper (
501cfa8cb0) - site: expand start.md investigation table to a class-based replacement map (
03661d7051) - test(pm): pin engine-key invariants #548 relies on (#554) (
95e1571cac) - perf(pm): restore cold_path() hints in the vendored aube hot loops (#553) (
2e27afdb3e) - site: reduce the copyable agent prompt to a two-sentence pointer (
034c618e8c) - ci: bun-style canary channel — build and publish every code push to main (#551) (
ffa1331c3f) - Polish nub init and enforce the release-age floor (#544) (
354d1199af) - fix(release): grant the canary jobs the permissions the workflow baseline denies (#558) (
f5b4c789a7) - feat(upgrade): canary channel consumers — nub upgrade --canary/--stable, installer canary arg (#557) (
050f02ff10) - feat(run): route script bodies through a real POSIX shell (bundled busybox on Windows) (#559) (
dc5b251de8)