ci: fresh-install smoke regression guard for the SDK-drift install crash
Live receipt that motivated the change
Fresh-install smoke against the published registry (npm i @wave-av/cli@latest, node 22.14.0 and node 20.20.2, .npmrc with @wave-av:registry=https://registry.npmjs.org):
$ npx --yes @wave-av/cli --version
file:///.../node_modules/@wave-av/sdk/dist/chunk-VYLVDBON.mjs:73
if (__require.main === module) {
^
ReferenceError: module is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension
and '.../node_modules/@wave-av/cli/package.json' contains "type": "module".
at file:///.../node_modules/@wave-av/sdk/dist/chunk-VYLVDBON.mjs:73:24
Node.js v22.14.0
Same crash, same file, same line on node 20.20.2. Every invocation of the published @wave-av/cli@1.0.8 dies before argv parsing.
Root cause
@wave-av/cli@1.0.8's package.json depends on @wave-av/sdk via the range ^2.0.11, which resolves to the latest matching version at install time: 2.1.2 (published 2026-08-28, months after cli 1.0.8 shipped on 2026-04-03). @wave-av/sdk@2.1.2's root dist/index.mjs imports ./chunk-VYLVDBON.mjs at line 188 — a bundling artifact that also contains the SDK's own dist/cli.js bin source (src/cli.ts, guarded by if (__require.main === module)). That guard assumes CommonJS require.main/module semantics but is loaded as ESM (.mjs), where module is not a global. Confirmed by direct inspection of unpacked tarballs for sdk 2.0.13, 2.0.14, 2.1.0-next.0, and 2.1.1 (none import chunk-VYLVDBON.mjs from the root entry) versus 2.1.2 (does). This is an @wave-av/sdk-side build defect — filed against that repo separately, not edited here.
@wave-av/cli is itself "type": "module", so it always resolves the SDK's "import" export condition — exactly the path this bug hits on every install, every version of cli that carries the unbounded ^2.0.11 range.
What changed (this repo)
Note on state: the root-cause fix for @wave-av/cli — pinning @wave-av/sdk to the last known-good published version (2.0.14, exact) instead of the ^2.0.11 range, fixing the hardcoded wave --version string, correcting wave status's wrong default host (wave.online → api.wave.online), and fixing silent-success exit codes on doctor/status/auth status — already landed on main via PR #39 (fix/cli-auth-checks, commit dd897ec) before this PR was opened. @wave-av/cli@1.0.9 (the fixed version) has not been published to npm yet; the registry's latest is still the broken 1.0.8.
This PR adds the piece that was still missing: a CI regression guard, .github/workflows/smoke-install.yml, so this exact class of bug — a real, already-published dependency drifting a fresh install into a broken combination — cannot silently reoccur. It:
- Triggers on
pull_request,pushtomain, andworkflow_dispatch. - Matrixes node
[20, 22]. - Runs
npm ci,npm run build,npm pack, then installs the packed tarball (not the linkednode_modules) into a throwaway$RUNNER_TEMP/smokeproject — the only way to catch a dependency-resolution bug, since unit tests andtype-checkrun against the already-linked tree and never see what a realnpm installresolves. - Runs
npx wave --version/wave --help, thenwave status/wave doctorwithWAVE_GATEWAY_API_KEYfrom repo secrets (env-block only, never inline in arun:string, never echoed; no-ops cleanly when the secret is absent, e.g. forked PRs). - Classifies failure narrowly: only output matching a module-resolution error pattern (
ReferenceError,Cannot find module,ERR_MODULE_NOT_FOUND,ERR_REQUIRE_ESM,is not defined in ES module scope,Cannot find package) fails the job. A normal CLI exit — includingwave statuslegitimately exiting 1 when unauthenticated — passes, since that is expected business logic, not the crash class this guard exists to catch.
Proof
Local dry-run of the exact workflow steps, against the built 1.0.9 tarball, both node versions, before pushing:
$ npm ci && npm run build && npm pack --pack-destination "$TMP"
# node 22.14.0: added 288 packages; build success (158.82 KB); wave-av-cli-1.0.9.tgz (30 files)
# node 20.20.2: identical
$ cd smoke && npm i <tarball> && npx wave --version
node22 -> 1.0.9 (exit 0)
node20 -> 1.0.9 (exit 0)
Gates in the worktree (unchanged by this PR, confirmed pre-existing and unrelated — same as documented in PR #39's own gates section):
npm run build— pass (tsup, ESM, 158.82 KB)npm test(vitest) — 4 files, 11 tests, all passnpm run type-check— 153 pre-existing TS errors (missingsrc/types/index.ts, SDK-API drift acrossstudio/vault/voice/usb/zoomcommand files) — unrelated to this change, present before and afternpm run lint—eslint: command not found(eslint is not indevDependencies) — pre-existing
LIVE RECEIPTS
npx @wave-av/cli --version(published 1.0.8, node22) → exit 1,ReferenceError: module is not defined in ES module scopeatchunk-VYLVDBON.mjs:73npx @wave-av/cli --version(published 1.0.8, node20) → exit 1, identical crash- Built 1.0.9 tarball, node22:
npx wave --version→1.0.9, exit 0 - Built 1.0.9 tarball, node20:
npx wave --version→1.0.9, exit 0 wave doctorunderdoppler run --project wave --config prdwithWAVE_API_KEY=$WAVE_GATEWAY_API_KEY(node22 and node20) → exit 0,Auth: WAVE_API_KEY env var set (wsk_live_1be...)wave statussame env (node22 and node20) → reacheshttps://api.wave.online/health,API: Healthy (~130-230ms), exit 1 (expected — no keychain login, business logic, not a crash)
Cross-repo dependency
The actual defect lives in @wave-av/sdk's published 2.1.2 build (chunk-VYLVDBON.mjs). A sibling lane owns that repo and may publish a corrected @wave-av/sdk@2.1.3+; once that lands, a follow-up here should widen the pin from the exact 2.0.14 back to a range that includes the fixed SDK release (noted already in CHANGELOG.md under [1.0.9]).
Operator steps (not run by this PR)
Publishing the already-merged 1.0.9 fix to npm is a separate operator action:
cd ~/wave-av/cli # on main, at commit dd897ec or later
npm publish
This PR does not run npm publish and does not merge anything. No autonomy:auto-merge label applied.
[!NOTE]
Low Risk
CI-only workflow with read-only repo permissions; optional live gateway checks use a secret and no-op when absent.
Overview
Adds .github/workflows/smoke-install.yml, a CI regression guard for install-time failures where a fresh npm install resolves published dependencies into a broken combination (e.g. CLI + drifting @wave-av/sdk ESM crash before argv parsing).
The job runs on PR, push to main, and workflow_dispatch, matrixing Node 20 and 22. It npm ci → build → npm pack, then installs the packed tarball into a throwaway project (not the linked monorepo node_modules) so resolution matches real users. Smoke steps run wave --version / --help, then optionally wave doctor and wave status when WAVE_GATEWAY_API_KEY is set (skipped on forks); failures are limited to module-resolution / ESM crash patterns, not normal CLI auth or HTTP exit codes.
Reviewed by Cursor Bugbot for commit 775da540e07e8cdc6ff26982ca5f5197b66814ff. Bugbot is set up for automated code reviews on this repo. Configure here.
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
Summary by Sourcery
Add CI coverage to prevent published dependency drift from reintroducing CLI installation and module-loading failures.
Enhancements:
- Add a fresh-install smoke workflow that validates the packed CLI tarball against registry-resolved dependencies on Node.js 20 and 22.
- Exercise CLI startup, help, gateway status, and diagnostics while distinguishing module-loading crashes from expected command failures.
CI:
- Run the regression guard on pull requests, pushes to main, and manual dispatches with concurrent runs cancelled per branch.
Tests:
- Verify the package through an isolated installation from its packed tarball rather than the repository's linked dependency tree.