Skip to content

ci: add release.yml for npm publish on v* tags; fix author field - #44

Merged
yakimoto merged 1 commit into
mainfrom
feat/release-workflow
Sep 3, 2026
Merged

ci: add release.yml for npm publish on v* tags; fix author field#44
yakimoto merged 1 commit into
mainfrom
feat/release-workflow

Conversation

@yakimoto

@yakimoto yakimoto commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

LIVE RECEIPTS

Defect (2026-09-03, code yellow P1): npx @wave-av/cli --version on a fresh install crashes on node 20 and node 22 with ReferenceError: module is not defined in ES module scope inside the sdk's chunk-VYLVDBON.mjs:73. Root cause: package.json pinned @wave-av/sdk with a caret range (^2.0.11), which npm resolved to sdk 2.1.2 — a later sdk release that ships a broken (CJS-in-ESM-context) chunk. npm view @wave-av/sdk version --@wave-av:registry=https://registry.npmjs.org confirms latest is 2.1.2; npm view @wave-av/cli versions confirms the last published cli version is 1.0.8.

Fix already merged, never published: 1.0.9 (PR #39, origin/main at 3a3db2c) pins @wave-av/sdk to an exact 2.0.14 (no caret) in package.json. It sat unpublished because this repo has no release workflow — only _checks.yml, foundation-gate.yml, issue-ops-triage.yml, public-repo-guard.yml. The only path to npmjs was a manual npm publish from a laptop, with zero build/test/smoke gate in front of it. That gap is what let 1.0.8 ship broken in the first place.

Verified locally in an isolated worktree (/tmp/cli-release, git worktree add ... origin/main, npm ci --include=dev):

  • npm run build → tsup ESM build succeeds (158.82 KB).
  • npm test → vitest: 4 test files, 11 tests, all passed.
  • npm packwave-av-cli-1.0.9.tgz (96.8 kB, 30 files).
  • Smoke-tested the packed tarball in a throwaway project on node 20.20.2 and node 22.14.0 (npm i ./wave-av-cli-1.0.9.tgz --@wave-av:registry=https://registry.npmjs.org && npx wave --version) → both print 1.0.9, and the installed node_modules/@wave-av/sdk/package.json resolves to 2.0.14 (not the broken 2.1.2).

Note for the reviewer: npm run type-check on this same tree surfaces ~35 pre-existing tsc errors (signage/slides/stream/studio/transcribe/usb/vault/voice/zoom commands referencing SDK methods that don't exist on the current SDK types, plus 3 missing types/index.js module errors). These are pre-existing on origin/main — not introduced by this PR, and not blocking tsup's transpile-only build — but they mean npm run type-check is not wired into any gate today and should probably become one in a follow-up. npm run lint fails locally with eslint: command not found (eslint isn't resolving from --include=dev install); not investigated further since it's out of scope for this PR.

WHAT CHANGED

  • .github/workflows/release.yml (new). Triggered on v* tags. Steps: checkout (SHA-pinned) → actions/setup-node node 22 (SHA-pinned) → verify the tag version matches package.json version (fails closed on mismatch) → npm ci --include=devnpm run buildnpm testnpm pack → smoke-test the packed tarball in a throwaway project (npm i <tarball> && npx wave --version, compared against package.json version) — this is the exact check 1.0.8 shipped without — then npm publish --provenance --access public. Auth: npm trusted publishing (OIDC via id-token: write) once this repo+workflow is registered as a trusted publisher on npmjs; falls back to the NPM_TOKEN repository secret otherwise (only written to the npm config if the secret is non-empty). Modeled on wave-foundation's release-spoke-chassis.yml (tag-triggered, verify+publish shape, SHA-pinned actions), adapted for a public npm target instead of GitHub Packages.
  • package.json: author corrected from "WAVE Inc. <sdk@wave.online>" to the correct legal entity "WAVE Online, LLC".

OPERATOR STEPS (to activate publishing)

  1. One-time: register wave-av/cli + .github/workflows/release.yml as a trusted publisher for @wave-av/cli in the npmjs package settings (Publishing access → Trusted Publisher → GitHub Actions), OR set the NPM_TOKEN repository secret (Settings → Secrets and variables → Actions) as the fallback path. Either is sufficient; no workflow changes needed either way.
  2. To cut a release: git tag v1.0.9 3a3db2c && git push origin v1.0.9 (or the current main tip at release time).
  3. This PR does not merge itself and carries no autonomy:auto-merge label — review and merge manually.

GATES

  • npm run build — OK (tsup ESM build, 158.82 KB)
  • npm test — OK (vitest: 4 files / 11 tests passed)
  • npm run type-check — pre-existing FAIL (~35 errors, all pre-existing on origin/main, unrelated to this change)
  • npm run lint — FAIL locally (eslint: command not found), not investigated, out of scope

🤖 Generated with Claude Code
https://claude.ai/code/session_01K9mRh8G2ugbUt2kaXvFvF6


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Cursor Bugbot is generating a summary for commit 364c726. Configure here.

Review in cubic

Summary by Sourcery

Automate gated, version-validated npm publishing for tagged CLI releases and correct the package metadata.

New Features:

  • Add a tag-triggered CI workflow that validates, builds, tests, smoke-tests, and publishes the CLI package to public npm.

Bug Fixes:

  • Prevent releases from being published when the Git tag does not match the package version.

Enhancements:

  • Correct the package author to WAVE Online, LLC.

CI:

  • Support npm trusted publishing through OIDC with an NPM_TOKEN fallback.

Deployment:

  • Automate public npm releases with provenance enabled.

Tests:

  • Verify the packed release tarball by installing it and checking the CLI version before publication.

P1 root cause (2026-09-03): published 1.0.8 crashed on every fresh install
(ReferenceError "module is not defined in ES module scope" in the sdk
chunk) because package.json pinned sdk with a caret range (^2.0.11) that
later resolved to a broken sdk release (2.1.2). 1.0.9 (already merged,
PR #39) pins sdk to an exact 2.0.14 — but nothing published it, because
this repo had no release workflow, only _checks/foundation-gate/
issue-ops-triage/public-repo-guard. A laptop npm publish was the only
path to npmjs, with no build/test/smoke gate in front of it.

Adds .github/workflows/release.yml: triggered on v* tags, verifies the
tag matches package.json version, npm ci, build, test, npm pack, smokes
the packed tarball in a throwaway project (npm i tarball && npx wave
--version, compared against package.json version) — the exact check
1.0.8 shipped without — then npm publish --provenance --access public.
Auth is npm trusted publishing (OIDC via id-token: write) when this repo
+ workflow is registered as a trusted publisher on npmjs; falls back to
the NPM_TOKEN repo secret otherwise (set only if the secret is present).
All actions are SHA-pinned, matching this repo and wave-foundations
release-spoke-chassis.yml convention.

Also fixes package.json author from "WAVE Inc. <sdk@wave.online>" to the
correct legal entity "WAVE Online, LLC".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9mRh8G2ugbUt2kaXvFvF6
@codeant-ai

codeant-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your workspace is out of credits. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 91 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 55dd8f91-9d51-48a4-819a-b7adf655ef17

📥 Commits

Reviewing files that changed from the base of the PR and between 3a3db2c and 364c726.

📒 Files selected for processing (2)
  • .github/workflows/release.yml
  • package.json

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Sep 3, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_0a537e1d-59b7-4b92-b359-8b4c97dce277)

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @yakimoto, this account has used its review budget of 2,500,000 diff characters for the last 7 days.

You can request another review in 22 hours and 38 minutes by commenting @sourcery-ai review.

@sourcery-ai

sourcery-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces a guarded, tag-based GitHub Actions release workflow for publishing the tested npm tarball with OIDC or token authentication, and corrects the package author metadata. Review the release gates, tag/version validation, tarball smoke test, npm authentication setup, and one-time trusted-publisher configuration; build and tests passed locally, while type-check and lint remain known pre-existing or unresolved issues outside this PR.

Sequence diagram for the guarded npm release workflow

sequenceDiagram
    participant Maintainer
    participant GitHubActions
    participant NpmRegistry
    participant FreshProject

    Maintainer->>GitHubActions: Push v<version> tag
    GitHubActions->>GitHubActions: Verify tag matches package.json version
    GitHubActions->>GitHubActions: npm ci --include=dev
    GitHubActions->>GitHubActions: npm run build
    GitHubActions->>GitHubActions: npm test
    GitHubActions->>GitHubActions: npm pack
    GitHubActions->>FreshProject: npm i packed tarball
    FreshProject-->>GitHubActions: npx wave --version
    alt smoke version matches package.json
        GitHubActions->>NpmRegistry: npm publish --provenance --access public
    else tag, build, test, or smoke check fails
        GitHubActions-->>Maintainer: Fail without publishing
    end
Loading

File-Level Changes

Change Details Files
Add a tag-driven npm release pipeline that validates, builds, tests, packages, smoke-tests, and publishes the exact release artifact.
  • Trigger releases on v* tags and fail when the tag does not match package.json.
  • Use SHA-pinned checkout and setup-node actions with Node 22 and constrained job permissions.
  • Install dependencies, run the build and tests, and create the npm tarball before publishing.
  • Install the packed tarball in a throwaway project and verify wave --version matches the package version.
  • Support npm trusted publishing through OIDC with an NPM_TOKEN fallback, then publish publicly with provenance.
.github/workflows/release.yml
Correct the package author metadata to the legal entity name.
  • Replace the previous company name and email with WAVE Online, LLC.
package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@macroscopeapp

macroscopeapp Bot commented Sep 3, 2026

Copy link
Copy Markdown

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR adds a tag-triggered workflow that publishes the CLI to public npm and introduces OIDC/NPM_TOKEN authentication, materially changing the production release path. The package author correction is metadata-only, but the deployment and credential scope warrants human review.

Not approved because:

  • Credit balance exhausted. Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Running ultrareview automatically — This PR adds the CI/CD release pipeline that publishes the CLI to public npm with OIDC/token auth; a bug in tag/version verification, the tarball smoke test, or the publish step could ship a broken or wrong-version package, so it warrants a deeper multi-pass review.. I'll post findings when complete.

fi

- name: Publish to npm
run: npm publish --provenance --access public

@gitar-bot gitar-bot Bot Sep 3, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Bug: npm publish --provenance conflicts with publishConfig.provenance:false

package.json has "publishConfig": { "provenance": false, ... } (package.json:54), but release.yml's final step runs npm publish --provenance --access public (.github/workflows/release.yml:102). The explicit CLI flag overrides publishConfig, so provenance attestation will be generated even though the package config says it shouldn't be — the opposite of what's declared in package.json, and it may also fail if the repo/workflow isn't OIDC-eligible for provenance (e.g. when only the NPM_TOKEN fallback path is active, --provenance requires id-token: write and a Sigstore-compatible CI, which is satisfied here, but the mismatch with publishConfig is still an inconsistency worth resolving so future edits to one don't silently diverge from the other).

Align publishConfig with the workflow's intent — remove the false override so provenance is enabled consistently, or drop --provenance from the workflow if provenance is intentionally disabled.:

"publishConfig": {
  "access": "public",
  "registry": "https://registry.npmjs.org/"
}

Was this helpful? React with 👍 / 👎

Comment on lines +90 to +99
- name: Configure npm auth (NPM_TOKEN fallback only — OIDC trusted publishing needs no config here)
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -n "$NPM_TOKEN" ]; then
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc
echo "npm auth: using NPM_TOKEN secret fallback"
else
echo "npm auth: no NPM_TOKEN secret set — relying on OIDC trusted publishing"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Quality: NPM_TOKEN fallback step is dead weight once OIDC works, but harmless if left misconfigured

The 'Configure npm auth' step (.github/workflows/release.yml:90-99) only writes the token when NPM_TOKEN is non-empty, which correctly avoids the known npm CLI issue where a stray/invalid _authToken line in .npmrc blocks OIDC trusted publishing from being attempted at all. This is safe as written, but worth a one-line comment noting that the NPM_TOKEN secret should be deleted from the repo once trusted publishing is confirmed working, so the fallback path can't accidentally become the active auth method (e.g. after an unrelated token rotation) and mask a broken OIDC registration.

Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your team has used its included automatic processing for this billing period (headroom scales with your seat count). You can still comment "Gitar review" to run one anytime, and automatic reviews resume on their own by October 1. Add seats for more headroom.
Learn more

Code Review ⚠️ Changes requested 0 resolved / 2 findings

publishConfig.provenance is set to false in package.json, but the release workflow runs npm publish --provenance, which overrides the config and generates provenance attestation anyway. Align the two by either removing --provenance from the publish command or removing provenance: false from publishConfig. Additionally, add a comment to the npm auth fallback step noting that NPM_TOKEN should be deleted from repository secrets once OIDC trusted publishing is confirmed working.

⚠️ Bug: npm publish --provenance conflicts with publishConfig.provenance:false

📄 package.json:54 📄 .github/workflows/release.yml:102

package.json has "publishConfig": { "provenance": false, ... } (package.json:54), but release.yml's final step runs npm publish --provenance --access public (.github/workflows/release.yml:102). The explicit CLI flag overrides publishConfig, so provenance attestation will be generated even though the package config says it shouldn't be — the opposite of what's declared in package.json, and it may also fail if the repo/workflow isn't OIDC-eligible for provenance (e.g. when only the NPM_TOKEN fallback path is active, --provenance requires id-token: write and a Sigstore-compatible CI, which is satisfied here, but the mismatch with publishConfig is still an inconsistency worth resolving so future edits to one don't silently diverge from the other).

Align publishConfig with the workflow's intent — remove the false override so provenance is enabled consistently, or drop --provenance from the workflow if provenance is intentionally disabled.
"publishConfig": {
  "access": "public",
  "registry": "https://registry.npmjs.org/"
}
💡 Quality: NPM_TOKEN fallback step is dead weight once OIDC works, but harmless if left misconfigured

📄 .github/workflows/release.yml:90-99

The 'Configure npm auth' step (.github/workflows/release.yml:90-99) only writes the token when NPM_TOKEN is non-empty, which correctly avoids the known npm CLI issue where a stray/invalid _authToken line in .npmrc blocks OIDC trusted publishing from being attempted at all. This is safe as written, but worth a one-line comment noting that the NPM_TOKEN secret should be deleted from the repo once trusted publishing is confirmed working, so the fallback path can't accidentally become the active auth method (e.g. after an unrelated token rotation) and mask a broken OIDC registration.

🤖 Prompt for agents
Code Review: `publishConfig.provenance` is set to `false` in `package.json`, but the release workflow runs `npm publish --provenance`, which overrides the config and generates provenance attestation anyway. Align the two by either removing `--provenance` from the publish command or removing `provenance: false` from `publishConfig`. Additionally, add a comment to the npm auth fallback step noting that `NPM_TOKEN` should be deleted from repository secrets once OIDC trusted publishing is confirmed working.

1. ⚠️ Bug: npm publish --provenance conflicts with publishConfig.provenance:false
   Files: package.json:54, .github/workflows/release.yml:102

   package.json has `"publishConfig": { "provenance": false, ... }` (package.json:54), but release.yml's final step runs `npm publish --provenance --access public` (.github/workflows/release.yml:102). The explicit CLI flag overrides publishConfig, so provenance attestation will be generated even though the package config says it shouldn't be — the opposite of what's declared in package.json, and it may also fail if the repo/workflow isn't OIDC-eligible for provenance (e.g. when only the NPM_TOKEN fallback path is active, `--provenance` requires `id-token: write` and a Sigstore-compatible CI, which is satisfied here, but the mismatch with publishConfig is still an inconsistency worth resolving so future edits to one don't silently diverge from the other).

   Fix (Align publishConfig with the workflow's intent — remove the false override so provenance is enabled consistently, or drop --provenance from the workflow if provenance is intentionally disabled.):
   "publishConfig": {
     "access": "public",
     "registry": "https://registry.npmjs.org/"
   }

2. 💡 Quality: NPM_TOKEN fallback step is dead weight once OIDC works, but harmless if left misconfigured
   Files: .github/workflows/release.yml:90-99

   The 'Configure npm auth' step (.github/workflows/release.yml:90-99) only writes the token when NPM_TOKEN is non-empty, which correctly avoids the known npm CLI issue where a stray/invalid `_authToken` line in .npmrc blocks OIDC trusted publishing from being attempted at all. This is safe as written, but worth a one-line comment noting that the NPM_TOKEN secret should be deleted from the repo once trusted publishing is confirmed working, so the fallback path can't accidentally become the active auth method (e.g. after an unrelated token rotation) and mask a broken OIDC registration.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 3, 2026

Copy link
Copy Markdown

cubic can't run this ultrareview because your workspace has reached its monthly review limit. cubic has reviewed 100,145 of the 100,000 allowed lines of code this month. Reviews resume on 4 September 2026 (in 2 days). Enable flex capacity to cover overages automatically and resume reviews now. Learn how flex capacity works.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@yakimoto
yakimoto merged commit 70e0ad8 into main Sep 3, 2026
22 checks passed
@yakimoto
yakimoto deleted the feat/release-workflow branch September 3, 2026 18:00
yakimoto added a commit that referenced this pull request Sep 4, 2026
….yml

Resolves the add/add conflict on .github/workflows/release.yml. `main` grew its
own release.yml in PR #44 after this branch was opened, so two release workflows
collided. This merge keeps EVERY gate from both sides (27 asserted, ledger in
the PR body) and fixes one gate that could never have passed.

Union structure: PR #17's 3-job gate chain (secret-scan -> verify -> publish),
with main's contributions folded in:
  - main's `npm ci --include=dev`, unconditional `npm test`, and its packed-
    tarball smoke that actually RUNS the installed binary
  - main's NPM_TOKEN classic-auth fallback (kept: without it a tag pushed before
    the npmjs Trusted Publisher registration exists fails with no recourse;
    --provenance still signs on that path since the job holds id-token: write)
  - action pins take the newer of the two sides, never a downgrade:
    checkout v6.0.3 (this branch's), setup-node v7.0.0 (main's)

Two real defects fixed, not papered over:

1. The ESM smoke could never pass. package.json sets "main" and "bin.wave" to
   the SAME file (./dist/index.js), so `import * as m from '@wave-av/cli'` does
   not import a library — it EXECUTES the CLI, which with no argv prints help
   and exits 1. Measured against a correctly built 1.0.9: exit 1. Replaced the
   import-and-count-exports assertion with import.meta.resolve (proves the entry
   resolves, without executing) plus the bin run below (proves the whole ESM
   graph loads — the "module is not defined in ES module scope" class of break
   that took 1.0.8 down). Strictly stronger than what it replaced.

2. Neither side asserted the BANNER version. @wave-av/cli@1.0.8 shipped to npm
   printing "v1.0.0" from a hardcoded string while package.json said 1.0.8, and
   the banner is a separate code path from --version (src/cli.ts printBanner(),
   suppressed in CI/agent mode). PR #17 only checked the bin file existed; that
   would have shipped the bug again. verify/e2e-smoke now asserts three-way
   parity: package.json == `wave --version` == the version the banner prints,
   clearing the CI/agent env vars so the banner actually renders.

Also made lint and type-check unconditional. They were conditional because main
carried no package.json when this branch was written; main declares both scripts
now, and a gate that downgrades itself to a ::warning when a script goes missing
is a gate that can be deleted by accident. NOTE: both currently FAIL on
origin/main for pre-existing reasons unrelated to this file (missing
src/types/index.ts; eslint referenced by the lint script but absent from
devDependencies with no eslint config). Those are source defects for the source
lane — reported in the PR body, deliberately not worked around here.

Verified locally in an isolated worktree: actionlint clean, all `uses:` pinned to
40-char SHAs, id-token: write present on the publish job, `npm test` 11/11 green,
full pack+install+run e2e-smoke green with banner parity, and a negative control
that re-injects the 1.0.8 defect and confirms the new gate rejects it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant