Summary
Two related issues with npm workspace support in craft's npm target when the monorepo uses workspace:* dependency specifiers (the canonical form for npm/yarn/bun workspaces):
Issue 1: npm version --workspaces fails on workspace:* deps
Craft's auto-bump (NpmTarget.bumpVersion) runs:
npm version <NEW_VERSION> --no-git-tag-version --allow-same-version --workspaces --include-workspace-root
When workspace packages declare deps on each other as "@scope/pkg": "workspace:*", this fails with:
npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "workspace:": workspace:*
and exits code 1. Craft treats this as failure and falls back to per-package npm version — which hits the same error in each subdir and fails the whole release.
The confusing part: npm does successfully bump the version field in every package.json before erroring. It only errors after the bumps land on disk, while it's validating dep URLs. So the files are in the right state — craft just can't tell from the exit code.
This is npm/cli#8845 — known and unresolved upstream. workspace: is documented as supported but npm 11.x's validator still rejects it during the version command.
Workarounds craft could pick up:
- Treat EUNSUPPORTEDPROTOCOL on
workspace: specifically as a warning rather than failure, since the bump itself already happened
- Or: edit each package.json directly via jq/awk rather than going through npm at all
- Or: detect workspace: deps and use a different bump path
Issue 2: bun.lock workspace versions remain stale after bump
Separately: when a repo uses bun.lock (Bun workspace monorepos), bun pm pack rewrites workspace:* specifiers to concrete versions at pack time. It reads those versions from bun.lock, not from the workspace package.json.
Neither npm version nor bun install updates the lockfile's workspace version entries. bun install --lockfile-only on a stale lockfile leaves the workspace version untouched — the only reliable way to refresh is rm bun.lock && bun install --lockfile-only.
Consequence: if the release pipeline publishes tarballs via bun pm pack, the published dependencies field still points at the OLD workspace version that no longer exists on the registry. Install fails with ETARGET No matching version found for @scope/pkg@OLD_VERSION.
We hit this on our first release: @loreai/opencode@0.10.0 and @loreai/pi@0.10.0 shipped with "@loreai/core": "0.9.1" deps (0.9.1 was the lockfile's recorded version), but we'd bumped to 0.10.0 and never published 0.9.1.
This one's more Bun-specific, but since craft is already workspace-aware and some monorepos use Bun, it might be worth either:
- Detecting bun.lock and refreshing workspace entries after bump
- Documenting that the bump doesn't touch bun.lock and users need their own step
Environment
- craft 2.26.0 (most recent)
- npm 11.6.2
- Node 24
- Bun 1.3.11
Our workaround (for reference)
We replaced craft's auto-bump with a preReleaseCommand script that:
- Uses
jq to rewrite the version field in each workspace package.json
- Uses
awk to rewrite the version field of workspace entries inside bun.lock
Source: https://github.com/BYK/loreai/blob/main/scripts/bump-version.sh
Suggested next step
For Issue 1 alone, the smallest craft-side fix would be: when npm version --workspaces exits non-zero, check whether the package.json files actually got bumped. If yes, log a warning about EUNSUPPORTEDPROTOCOL and proceed; if no, fail as today.
For Issue 2, a lockfile-refresh step would be nice-to-have but it's reasonable to say "use a preReleaseCommand if you're on bun".
Happy to send a PR if the approach sounds right.
Summary
Two related issues with npm workspace support in craft's npm target when the monorepo uses
workspace:*dependency specifiers (the canonical form for npm/yarn/bun workspaces):Issue 1:
npm version --workspacesfails onworkspace:*depsCraft's auto-bump (
NpmTarget.bumpVersion) runs:When workspace packages declare deps on each other as
"@scope/pkg": "workspace:*", this fails with:and exits code 1. Craft treats this as failure and falls back to per-package
npm version— which hits the same error in each subdir and fails the whole release.The confusing part: npm does successfully bump the
versionfield in every package.json before erroring. It only errors after the bumps land on disk, while it's validating dep URLs. So the files are in the right state — craft just can't tell from the exit code.This is npm/cli#8845 — known and unresolved upstream.
workspace:is documented as supported but npm 11.x's validator still rejects it during the version command.Workarounds craft could pick up:
workspace:specifically as a warning rather than failure, since the bump itself already happenedIssue 2: bun.lock workspace versions remain stale after bump
Separately: when a repo uses
bun.lock(Bun workspace monorepos),bun pm packrewritesworkspace:*specifiers to concrete versions at pack time. It reads those versions frombun.lock, not from the workspacepackage.json.Neither
npm versionnorbun installupdates the lockfile's workspace version entries.bun install --lockfile-onlyon a stale lockfile leaves the workspace version untouched — the only reliable way to refresh isrm bun.lock && bun install --lockfile-only.Consequence: if the release pipeline publishes tarballs via
bun pm pack, the publisheddependenciesfield still points at the OLD workspace version that no longer exists on the registry. Install fails withETARGET No matching version found for @scope/pkg@OLD_VERSION.We hit this on our first release:
@loreai/opencode@0.10.0and@loreai/pi@0.10.0shipped with"@loreai/core": "0.9.1"deps (0.9.1 was the lockfile's recorded version), but we'd bumped to 0.10.0 and never published 0.9.1.This one's more Bun-specific, but since craft is already workspace-aware and some monorepos use Bun, it might be worth either:
Environment
Our workaround (for reference)
We replaced craft's auto-bump with a
preReleaseCommandscript that:jqto rewrite theversionfield in each workspacepackage.jsonawkto rewrite theversionfield of workspace entries insidebun.lockSource: https://github.com/BYK/loreai/blob/main/scripts/bump-version.sh
Suggested next step
For Issue 1 alone, the smallest craft-side fix would be: when
npm version --workspacesexits non-zero, check whether the package.json files actually got bumped. If yes, log a warning aboutEUNSUPPORTEDPROTOCOLand proceed; if no, fail as today.For Issue 2, a lockfile-refresh step would be nice-to-have but it's reasonable to say "use a preReleaseCommand if you're on bun".
Happy to send a PR if the approach sounds right.