fix(publish): make the npm release idempotent and verify it installs - #5633
Conversation
Every publish run since 0.7.0-rc.24 failed, so npm has stopped at rc.23 while the repo is at rc.40, and the "latest" dist-tag still points at rc.11 — the version a plain `npm i @nodetool-ai/cli` installs. rc.11 predates the validate, debug, node and harness commands, so the published CLI is missing half its surface. Nothing in CI noticed for five months. The immediate cause is an unauthorized npm token (404 on PUT for a package that exists), which is fixed outside this repo. These changes stop the same failure from being silent and unrecoverable: - scripts/publish-packages.mjs replaces `npm publish --workspaces`, which aborts on the first failing package. protocol is first in the workspace list, so one 404 there meant the other 58 packages were never attempted. The script tries every package, treats an already-published version as success, and exits non-zero at the end — so a re-run after a partial publish finishes the job instead of dying on EPUBLISHCONFLICT. - A smoke job installs the just-published CLI from the registry and asserts it reports the released version and lists its commands. `nodetool validate --help` is not usable as that check: commander's --help short-circuits before unknown-command handling, so it prints top-level help and exits 0 even on rc.11, where the command does not exist. - nodetool --version read a hardcoded "0.1.0" that never moved across any 0.7.0-rc release. It now comes from package.json. - Nightly tags match the workflow's "v*" trigger and would publish to npm daily; excluded. - engines widened from ">=22.0.0 <23.0.0" to ">=22.0.0" so the CLI installs on Node 23+ without --force. - vectorstore ships sql/, which its own error message tells users to run. - blender-nodes and reliability-harness listed README.md in files[] without having one.
|
Two checks went red on 1.
That file does not exist on this PR's branch point; it arrived on Identical counts and identical assertion to the CI run, so the base branch is red here on its own. This PR touches no file under The test asserts the inspector captions an unreadable easing ( 2. The build never reached a Dockerfile step — it could not resolve the syntax frontend image — and the smoke container was never created ( Generated by Claude Code |
georgi
left a comment
There was a problem hiding this comment.
Reviewed the full diff. The idempotency logic is sound:
classifyPublishResultcorrectly distinguishesEPUBLISHCONFLICT(skip) from genuine auth/network errors (fail) by inspecting output after checkingstatus === 0.alreadyPublishedpre-check vianpm viewavoids unnecessary publish attempts.- Post-publish smoke job installs from the public registry and asserts version string and key commands.
--provenanceand--ignore-scriptspreserved. Nightly tag exclusion correct.- CLI version now reads from
package.jsonviacreateRequireinstead of hardcoded"0.1.0". - Engine field widened to
>=22.0.0is reasonable. - Unit tests cover all
classifyPublishResultbranches.
No issues found. Ready to merge once CI is green.
Generated by Claude Code
What changed
npm i @nodetool-ai/cliinstalls 0.7.0-rc.11 — the version thelatestdist-tag still points at. The registry stops at rc.23 while this repo is at rc.40, because every publish run since rc.24 failed; the last three died on404 Not Found - PUT .../@nodetool-ai%2fprotocol, an unauthorized npm token. rc.11 predates thevalidate,debug,nodeandharnesscommands, so what users get is missing half the CLI, and 35 of the 59 public packages (including 9 direct CLI dependencies) have never been published at all. Nothing in CI noticed for five months. Fixing the token is outside this repo; this diff stops the same failure from being silent and unrecoverable.scripts/publish-packages.mjsreplacesnpm publish --workspaces, which aborts on the first failing package —protocolis first in the workspace list, so one 404 there meant the other 58 were never attempted, and any package that did publish then returnedEPUBLISHCONFLICTand killed the retry. The new script attempts every package, counts an already-published version as success, and exits non-zero at the end, so re-running after a partial publish finishes the job. Asmokejob then installs the just-published CLI from the registry and asserts it reports the released version and lists its commands. Alongside that:nodetool --versionno longer returns a hardcoded0.1.0; nightly tags no longer match thev*publish trigger;enginesis widened to>=22.0.0so the CLI installs on Node 23+ without--force;vectorstoreships thesql/migration its own error message tells users to run; andblender-nodesandreliability-harnessget theREADME.mdthey already declared infiles[].Verification
npm run test:affected— 1 failure, load-induced, not from this diff.blender-nodes tests/settings.test.tshitTest timed out in 5000mswhile 44 vitest workers ran concurrently (that run's import phase took 229s). In isolation it passes in 3.86s, and the full package suite is green:npm run typecheck— web and electron pass; the mobile leg fails with 36 errors, caused by the stalelatestdist-tag this PR is about (mechanism below). Not introduced by this diff — confirmed identical on cleanorigin/mainin a separate worktree, same exit code and same 36 errors:packages/cli/src/nodetool.ts;git diff origin/main -- packages/protocol/src packages/app-runtime/srcis empty.npm run lint—LINT_EXIT=0npm run dev:nodetool -- harness gate --base origin/main—GATE_EXIT=0,Gate: 15/15 selfchecks passed(it selects the newrepo-scriptssuite)npm run build:packages—BUILD_EXIT=0, 62/62 tasksnpm run check:lockfile,check:deps,check:circular,check:agents-docs— all passBehavior verified against a real CLI rather than assumed:
Why the mobile typecheck fails, and why it is this bug
mobile/is not a workspace, sonpm cithere resolves@nodetool-ai/protocol: "*"from the registry, not from source."*"resolves to thelatestdist-tag, andlatestis rc.11 — stale since April because publishing has been broken:mobile/tsconfig.jsonmaps@nodetool-ai/app-runtime(and two deep protocol paths) to local source, but not bare@nodetool-ai/protocol. So mobile compiles current-sourceapp-runtimeagainst five-month-oldprotocoltypes. The 36 errors are that skew:mobile/package-lock.jsonpins rc.11 as well, so CI'scd mobile && npm cireproduces it. Fixing it properly means pinning mobile's protocol dependency or adding apathsentry for the bare specifier — a mobile-build change, deliberately out of scope here — but it resolves itself for new installs oncelatestpoints at a current release.Agent capabilities
No capability added, and no capability's declared contract changed.
New checks
return "skipped"toreturn "failed"inclassifyPublishResult:Tests 5 passed (5).nodetool validate --help, is not a usable check: commander's--helpshort-circuits before unknown-command handling, so on rc.11 — which has novalidatecommand — it prints top-level help and exits 0. Replaced with a check that the command is listed, which correctly rejects rc.11 and accepts the current build:Notes for the reviewer
Two things this diff deliberately does not fix:
latestdist-tag stays at rc.11 until someone moves it. Prereleases only move therctag, so even a green publish leavesnpm i @nodetool-ai/clion rc.11 — and, as above, leaves mobile compiling against rc.11 types. That needsnpm dist-tag addper package, or a stable (non-prerelease) release.prepare-publish.mjs --dry-runafter the realprepare-publish.mjs, so every"*"dep is already rewritten and it always reports "No workspace*dependencies found to resolve." Same class of bug as the rest of this PR; left alone to keep the diff scoped — happy to fix it here if preferred.Unblocking the release still needs the npm side: a token authorized for the
@nodetool-aiscope, or Trusted Publishing (OIDC) for this repo, which the workflow already hasid-token: writefor.🤖 Generated with Claude Code
https://claude.ai/code/session_01HWxheb5NMNMeUDgeQwykjk