Skip to content

v1.2.1 ·

workspace:* on npm: the publish guard

The problem

v1.2.0 was published to npm and was completely uninstallable. Anyone running npm i -g @rasensio/aidlc got EUNSUPPORTEDPROTOCOL and nothing else.

The cause was one line of metadata. In a pnpm workspace, a package that depends on a sibling declares it as workspace:* — a spec that means "the copy in this repository" and is meaningless anywhere else. pnpm publish knows this and rewrites the spec to a concrete version on the way out. npm publish does not: it uploads workspace:* verbatim, and npm's installer has no idea what that is.

The release had run, the tag was pushed, and the tarball on the registry was broken. Nothing in the build, the tests, or the release script had any opinion about which client did the publishing.

How it could be solved

The immediate fix was obvious and boring: republish the identical code with the right client, and deprecate the broken version so nobody installs it by accident. That took minutes.

The interesting question was what to do so it could not happen twice. Three answers were available.

Write it down — a note in the release documentation saying "use pnpm publish". This is the option that feels like a fix and is not one. The failure mode was reaching for the wrong command under time pressure, and a document does not intervene at that moment.

Automate the release path so the correct command is the only one that runs. Better, and worth doing, but it only covers the path that goes through the script. A manual publish from a terminal still slips through.

Refuse to publish at all when the client is wrong. This is the one that shipped: prepublishOnly now runs a guard that inspects the publishing environment and aborts if the client would leak workspace: specifications. It fires regardless of how the publish was invoked.

How AIDLC solves it

@rasensio/aidlc@1.2.1 is byte-for-byte the same code as 1.2.0, published correctly. 1.2.0 is deprecated on the registry with a pointer to the fix.

The durable change is scripts/ensure-pnpm-publish.mjs, wired into prepublishOnly so it runs before the build and the tests on any publish attempt. A publish client that would upload an unresolved workspace: spec is rejected before a tarball exists.

There is no lifecycle instance behind this post, which is why it is hand-written rather than generated: the whole thing happened in under two hours between v1.2.0 and v1.2.1, with no ideation, no requirements, and no design phase. That is appropriate for a broken publish, and it is also the reason the trail has a gap here — there was no state to generate a post from. The lifecycle records what goes through it, and a same-day incident fix did not.