fix(publish): resolve catalog:/workspace:* protocols + use npm pack#73
Merged
Conversation
The publish pipeline shipped @aictrl/cli@0.3.3 with unresolved
`workspace:*` deps and @aictrl/util@1.2.16 with unresolved `catalog:`
deps, breaking plain `npm install` with EUNSUPPORTEDPROTOCOL. Both
protocols are Bun-only (also pnpm/yarn for `workspace:`); npm has no
resolver for either.
Root cause was two-part:
1. `bun pm pack` ignores in-place edits to the on-disk package.json and
re-injects workspace deps from the workspace lockfile. publish.yml's
"Strip bundled deps" step had no effect on the tarball — type,
exports, dependencies, devDependencies, peerDependencies all survived
the strip and shipped to npm verbatim.
2. publish-if-new.sh had no `catalog:` → semver step. @aictrl/util ships
`{ zod: 'catalog:' }` because the catalog protocol is invisible to
the existing strip logic (which only ran on CLI).
Fix:
- Add a catalog:/workspace: resolver to publish-if-new.sh that reads
the root package.json's workspaces.catalog and the AICTRL_VERSION env
var, substituting concrete semver into all four dep fields before
packing. Fails loud if a catalog: dep has no catalog entry, or if
workspace:* is hit without AICTRL_VERSION.
- Replace `bun pm pack` with `npm pack` so on-disk package.json edits
actually take effect in the tarball.
- Expose stripped AICTRL_VERSION (no v prefix) to subsequent workflow
steps via $GITHUB_ENV so the resolver can see it.
- Add a post-publish smoke test step that does `npm install
@aictrl/cli@$VERSION` in a scratch dir on the runner, with CDN-aware
retry. Fails the release if the published manifest is broken,
catching this entire bug class going forward.
Local verification:
- Resolver against packages/util/package.json: catalog: → 4.1.8 ✓
- Resolver against v0.3.3 packages/cli/package.json with AICTRL_VERSION=0.3.4:
all workspace:* and catalog: deps resolved to concrete semver, npm pack
produced a valid tarball.
- Fail-loud path verified: missing AICTRL_VERSION on workspace:* dep
exits with explicit error.
Closes #72
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The publish pipeline shipped `@aictrl/cli@0.3.3` with unresolved `workspace:*` deps and `@aictrl/util@1.2.16` with unresolved `catalog:` deps. Both are Bun-only protocols — plain `npm install` rejects them with `EUNSUPPORTEDPROTOCOL`. This silently broke the AI Review workflow on every PR for ~4 weeks (#72) and any downstream npm consumer.
Root cause
Two interacting bugs:
`bun pm pack` ignores in-place package.json edits. `publish.yml`'s "Strip bundled deps" step ran a `node -e ...` that deleted `pkg.dependencies`, `pkg.devDependencies`, `pkg.peerDependencies`, `pkg.exports`, and `pkg.type` before pack — but every one of those fields survived to the published tarball. Verified by extracting `aictrl-cli-0.3.3.tgz` and inspecting its `package.json`: `type`, `exports`, `dependencies` (with `workspace:*`), `devDependencies`, `peerDependencies` all present. `bun pm pack` reads workspace deps from the workspace lockfile/manifest snapshot, not from the on-disk `package.json`.
No `catalog:` resolver anywhere in the pipeline. `@aictrl/util` ships `{ zod: 'catalog:' }` because the strip-everything approach (only run on CLI) doesn't apply to packages that actually need runtime deps. The `catalog:` protocol comes from Bun's centralized version pinning; npm has no equivalent and rejects it.
Evidence:
```bash
$ npm view @aictrl/cli@0.3.3 dependencies
{ '@aictrl/plugin': 'workspace:', '@aictrl/sdk': 'workspace:', '@aictrl/util': 'workspace:*', ... }
$ npm view @aictrl/util@latest dependencies
{ zod: 'catalog:' }
$ npm install @aictrl/cli@latest
npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "workspace:": workspace:*
```
Fix
`publish-if-new.sh`
`publish.yml`
Local verification
Resolver against `packages/util/package.json`:
```
"zod": "catalog:" → "zod": "4.1.8" ✓
"typescript": "catalog:" → "typescript": "5.8.2" ✓
"@types/bun": "catalog:" → "@types/bun": "1.3.9" ✓
```
Resolver against `v0.3.3:packages/cli/package.json` with `AICTRL_VERSION=0.3.4`:
```
"@aictrl/plugin": "workspace:" → "0.3.4" ✓
"@aictrl/sdk": "workspace:" → "0.3.4" ✓
"@aictrl/util": "workspace:*" → "0.3.4" ✓
"@octokit/rest": "catalog:" → resolved from root catalog ✓
```
`npm pack` produced a valid `aictrl-cli-0.3.3.tgz`.
Fail-loud path verified: with `AICTRL_VERSION` unset on a CLI package.json that still has workspace deps, the resolver exits with `::error::dependencies[@aictrl/plugin] is workspace:* but AICTRL_VERSION env var is not set` and no tarball is produced.
End-to-end validation plan
The publish workflow only runs on `release: published` events, so this can't be exercised in CI on the PR itself. Validation steps after merge:
@aictrl/cli@0.3.3ships unresolvedworkspace:*deps →npm installfails with EUNSUPPORTEDPROTOCOL #72"` and same for `@aictrl/util@1.2.16` so existing `@latest` resolvers get a warning instead of a silent install failure.Once 0.3.4 is on npm, the `Aictrl AI Review` workflow on this repo (which does `npm install @aictrl/cli@latest`) will start passing again.
Test plan
Related
@aictrl/cli@0.3.3ships unresolvedworkspace:*deps →npm installfails with EUNSUPPORTEDPROTOCOL #72 — the parent bug@aictrl/cli@0.3.3ships unresolvedworkspace:*deps →npm installfails with EUNSUPPORTEDPROTOCOL #72Closes #72
🤖 Generated with Claude Code