Skip to content

fix(ci): publish npm tarballs packed by bun so workspace:* resolves - #180

Merged
murrayju merged 1 commit into
mainfrom
murrayju/tnt-254-fix-published-client-protocol-dep
Jul 31, 2026
Merged

fix(ci): publish npm tarballs packed by bun so workspace:* resolves#180
murrayju merged 1 commit into
mainfrom
murrayju/tnt-254-fix-published-client-protocol-dep

Conversation

@murrayju

Copy link
Copy Markdown
Member

Fixes TNT-254

Problem

@memory.build/client@0.6.2 on npm declares its protocol dependency as a literal workspace spec:

"dependencies": { "@memory.build/protocol": "workspace:*" }

So every consumer install fails:

error: Workspace dependency "@memory.build/protocol" not found

Confirmed against the live registry (npm view @memory.build/client@latest dependencies) and reproduced locally with a tarball install.

This is a genuine runtime break, not just a metadata wart — the built dist/index.js really does import @memory.build/protocol{,/fields,/headers,/meta}.

Root cause

npm publish does not rewrite workspace:* specs when run from inside a package directory. That substitution only happens for npm-managed workspaces, and this repo installs with bun — so nothing ever rewrote it. The release workflow did cd packages/client && npm publish, shipping the raw spec.

Verified both halves of the claim by packing the same package two ways:

packer resulting dependencies consumer install
npm pack (what we shipped) "workspace:*" fails to resolve
bun pm pack "0.6.2" installs cleanly

Fix

Pack with bun pm pack (which resolves workspace protocols to the concrete version), then hand npm the finished tarball. npm still performs the upload, so OIDC trusted publishing and provenance are unaffected — verified with a --provenance dry run.

A verify gate now runs between packing and publishing, so a regression fails the release instead of reaching the immutable registry again.

  • .github/workflows/release.yml — pack both packages with bun, verify, then publish the tarballs.
  • scripts/npm/verify-tarballs.ts (new) — inspects each packed manifest, fails on any surviving workspace: / file: / link: / portal: spec in any dependency field.
  • scripts/npm/verify-tarballs.test.ts (new) — 4 unit tests over the pure check.
  • package.jsontest:unit now scans ./scripts too, so the new test actually runs in CI.

Sharp edges found while verifying

Three things that each would have broken the release on the next tag:

  1. npm publish <bare-relative-path> is read as a GitHub org/repo shorthand. It tried to git ls-remote ssh://git@github.com/npm-tarballs/....git and died. The tarball paths need a leading ./.
  2. prepublishOnly does not fire for a pre-made tarball. The workflow's explicit build steps are what produce dist/; noted in a comment so they don't get removed as redundant. Confirmed 19 dist/ files land in the tarball.
  3. bun test treats bare arguments as filters, not paths. find packages scripts ... silently dropped the new test file (109 files, new tests never ran). The find roots are now ./-prefixed — 110 files, tests confirmed running.

Testing

  • Packed real tarballs and installed them as a consumer: manifest reads "@memory.build/protocol": "0.6.2", and the full client API surface (memory, space, access, principal, group, grant, invite) loads under both bun and Node.
  • Transitive resolution: installing only the client pulls protocol from the registry correctly.
  • Verify gate rejects the old npm-packed tarball and passes the bun-packed one.
  • Parsed every file in .github/workflows/ to confirm the edited YAML is valid (this caught a : -in-step-name error that made the whole workflow unparseable).
  • ./bun run check clean: 1208 pass, 0 fail, no lint findings.

Note on 0.6.2

This repairs the pipeline; @memory.build/client@0.6.2 on npm stays broken because published versions are immutable. Consumers need a new release — until then the workaround is installing @memory.build/protocol explicitly alongside the client.

`npm publish` run from inside a package directory does not rewrite
`workspace:*` dependency specs — that substitution only happens for
npm-managed workspaces, and this repo installs with bun. The release
workflow did `cd packages/client && npm publish`, so the literal spec
shipped to the registry:

    "dependencies": { "@memory.build/protocol": "workspace:*" }

Every consumer install of @memory.build/client@0.6.2 then failed with:

    error: Workspace dependency "@memory.build/protocol" not found

This is a real runtime break, not just a metadata wart: the built
dist/index.js genuinely imports @memory.build/protocol{,/fields,
/headers,/meta}.

`bun pm pack` does resolve workspace protocols to the concrete version,
so pack with bun and hand npm the finished tarball. npm still performs
the upload, so OIDC trusted publishing and provenance are unaffected.

Also add a verify gate that fails the release if any workspace:/file:/
link:/portal: spec survives packing, so this cannot silently reach the
registry again.

Two sharp edges worth recording:

- `npm publish <bare-relative-path>` is parsed as a GitHub `org/repo`
  shorthand (it tries to `git ls-remote` it), so the tarball paths need
  a leading `./`.
- `prepublishOnly` hooks do not fire when publishing a pre-made tarball;
  the workflow's explicit build steps are what produce `dist/`.

test:unit now scans ./scripts too, so the new test actually runs in CI.
The find roots are `./`-prefixed because bun test treats bare arguments
as filters rather than paths, which silently dropped the new file.

Fixes TNT-254
@murrayju
murrayju requested a review from jgpruitt as a code owner July 31, 2026 19:42
Copilot AI review requested due to automatic review settings July 31, 2026 19:42
@murrayju
murrayju requested a review from cevian as a code owner July 31, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the release pipeline to prevent publishing npm packages whose packed manifests still contain unresolved workspace-style dependency specs (e.g. workspace:*), which caused the published @memory.build/client@0.6.2 to be uninstallable for consumers.

Changes:

  • Switch the release workflow to pack @memory.build/protocol and @memory.build/client with bun pm pack, then npm publish the resulting tarballs.
  • Add a tarball verification script + unit tests to fail the release if any workspace: / file: / link: / portal: specs survive in dependency fields.
  • Expand test:unit to include tests under ./scripts so the new verification tests run in CI.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
.github/workflows/release.yml Packs tarballs with Bun, verifies manifests, then publishes tarballs via npm to keep OIDC/provenance behavior while fixing workspace:* resolution.
scripts/npm/verify-tarballs.ts New release gate script that inspects packed tarballs’ package.json and rejects unpublishable dependency spec prefixes.
scripts/npm/verify-tarballs.test.ts Unit tests for the pure manifest-checking function.
package.json Ensures unit tests also scan ./scripts so the new test file is exercised in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +126 to +129
const manifest = await readPackedManifest(tarball);
const { name, version } = manifest as { name?: string; version?: string };
const problems = findUnpublishableSpecs(manifest);

@murrayju
murrayju merged commit d45fc45 into main Jul 31, 2026
7 checks passed
@murrayju
murrayju deleted the murrayju/tnt-254-fix-published-client-protocol-dep branch July 31, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants