ci(release): publish @workspacejson/cli from tagged releases (META-236) - #13
Merged
Conversation
Adds `.github/workflows/publish-cli.yml`, a tag-triggered publisher for `@workspacejson/cli` modelled on the flow proven in workspace-json/codex-mcp. The tag is both trigger and source of truth: `cli-v0.1.0` is read from an env var (never inlined into a shell), validated as clean semver, and asserted equal to `packages/cli/package.json` before anything reaches the registry. A tag that disagrees with the manifest fails the run instead of publishing a version nobody named. Publishing uses npm rather than pnpm for two reasons: pnpm 9 exposes no `--provenance` flag, and `pnpm publish` refuses to run on a detached tag checkout without disabling git checks wholesale. The substitution is safe only because `@workspacejson/cli` declares no `workspace:` dependencies, and verify-package-tarball.mjs asserts that against the packed manifest — so it holds by gate, not by assumption. Authority is deliberately split. `agents-audit` stays with workspace-json/agents-audit until META-243; the disjoint tag namespaces mean no one workflow can publish both. Also fixes three claims that had drifted from reality: * `.changeset/config.json` ignored `@workspacejson/cli` while `agents-audit` depended on it, which is an invalid configuration — `changeset status` failed outright. CI never ran changesets, so nothing caught it. * verify-published.mjs, release.yml and verify-package-tarball.mjs each stated that `@workspacejson/cli` is `private: true` and kept off the registry by the architecture guard. The manifest carries no `private` field, sets `publishConfig.access: public`, and the guard contains no such assertion. * verify-published.mjs verified only `agents-audit` and took its version from that package's manifest, so a CLI release would have checked the wrong package. It now takes the package as an argument. Verified: architecture guard, typecheck, 100 tests, CLI tarball verification (packs, installs into a clean project, runs `workspacejson generate`), `npm publish --dry-run`, and verify-published.mjs end to end against the published agents-audit@0.4.4.
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
Gives
@workspacejson/clia tag-triggered npm publisher, modelled on the flow proven inworkspace-json/codex-mcp. Releasing becomes:The tag is both trigger and source of truth.
cli-v0.1.0is read from an env var (never inlined into a shell), validated as clean semver, and asserted equal topackages/cli/package.jsonbefore anything reaches the registry — a tag that disagrees with the manifest fails the run rather than publishing a version nobody named.Authority stays split.
agents-auditremains published byworkspace-json/agents-audituntil META-243. The disjoint tag namespaces mean no single workflow can publish both, so this needs no authority cutover:OWNERSHIP.mdrecorded@workspacejson/cli's prior authority as "none yet", and the name is unregistered on npm.Why npm rather than pnpm for the publish step
pnpm 9 exposes no
--provenanceflag, andpnpm publishrefuses to run on a detached tag checkout without disabling git checks wholesale. The substitution is safe only because@workspacejson/clideclares noworkspace:dependencies, so there is nothing for pnpm to rewrite at pack time — andverify-package-tarball.mjsasserts that against the packed manifest. The invariant holds by gate, not by assumption.The workflow calls the existing
verify-package-tarball.mjsrather than reimplementing the reference repo's checks: ours is stronger already, installing the tarball into a clean project and runningworkspacejson generateend to end versus the reference's--help.Three claims that had drifted from reality
.changeset/config.jsonwas invalid. It ignored@workspacejson/cliwhileagents-auditdepends on it, which changesets rejects outright —pnpm changeset statusfailed before this PR. CI never ran changesets, so nothing caught it.verify-published.mjs,release.ymlandverify-package-tarball.mjseach stated that@workspacejson/cliisprivate: trueand kept off the registry by the architecture guard. The manifest carries noprivatefield, setspublishConfig.access: public,OWNERSHIP.mdsaid "public, not yet published", and the guard contains no such assertion.verify-published.mjswould have verified the wrong package. It knew onlyagents-auditand derived the version from that manifest, so acli-v*release could have gone green on a sibling. It now takes the package name as an argument, with guards against unknown names and against pinning one version across several packages.OWNERSHIP.mdis updated to match, since it is the authoritative record of publish authority and leaving it would recreate exactly this class of drift.Verification
pnpm -r typecheckpnpm -r test— 100 tests, 14 filespnpm -r buildnode packages/agents-audit-compat/dist/cli.js scan . --fail-on error— 0 errors, 0 warningsbash migration/parity-agents-audit-runtime.sh— ran in CI, passed (Compatibility parity vs frozen source, 1m3s). I had judged it not applicable, since nothingagents-auditexposes changed — the edits are release tooling (verify-published.mjsselection logic, one comment inverify-package-tarball.mjs) and its command surface, exit codes, output and exports are untouched. CI runs the harness unconditionally, so the claim is now measured rather than argued.Also run:
pnpm run check:architecture— 63 files, 3 manifests, no violationspnpm run release:verify-packs— both packages release-safepnpm changeset status— now succeedsnpm publish --dry-runfrompackages/cli— 12 files, 9.3 kB, no source or test filesnode scripts/verify-published.mjs agents-audit— end to end against the live registryNotes
Could not be tested locally:
--provenancerequires CI OIDC. Prerequisites are met (public repo,repository.urlmatches the remote,id-token: writegranted). A provenance failure occurs before upload, so the risk is a red run, not a partial publish.Before tagging: confirm
NPM_TOKENgrants publish on@workspacejson/cli. This is a new package name, so a token scoped only to existing packages will not cover the first publish — that needs broader scope or org-level publish rights.Follow-up (META-243): the same workflow shape drops in for
agents-auditon its own tag namespace, but that one needs the ordered cutover — disable the old workflow, revoke its token, then grant here. Two publishers racing on a live package is the failure mode to avoid.