fix: repair fresh-install breakage and silent-success exit codes

Merged
YA
2mo ago
+5726-10

P0: fresh installs of @wave-av/cli were broken; several safety commands lied about success

Reproduction (live probe, confirmed against 1.0.8 as published)

$ npm i @wave-av/cli          # resolves @wave-av/sdk via ^2.0.11 -> 2.1.2 (2026-08-28)
$ wave --version
node_modules/@wave-av/sdk/dist/chunk-VYLVDBON.mjs:73
if (__require.main === module) {
                       ^
ReferenceError: module is not defined in ES module scope

Root cause lives in @wave-av/sdk (separate PR: wave-av/sdk#111) — a CJS-only
require.main === module entry guard got bundled into a shared ESM chunk, so it
throws for any ESM importer of the package. This CLI is itself
"type": "module", so it always takes the SDK's "import" export condition —
exactly the path the bug hits. Every single wave invocation died before argv
parsing even started.

Related defects fixed in the same pass (all reproduced live before fixing):

  • @wave-av/sdk and @wave-av/cli both declare a bin named wave — which one
    wins in node_modules/.bin is install-order luck. (Resolved on the SDK side by
    renaming its bin to wave-sdk; see wave-av/sdk#111.)
  • wave --version printed a hardcoded "1.0.0", not the real published version.
  • wave doctor, wave status, wave auth status all exited 0 unconditionally,
    even with a failing check or while completely unauthenticated.
  • wave status health-checked https://wave.online (the marketing site) at
    /api/health — verified live: 404. The correct target,
    https://api.wave.online/health, verified live: 200
    ({"ok":true,"service":"wave-gateway","version":"dev"}).

Fixes in this PR

  1. Unbreak fresh installs today, independent of the SDK PR's publish timing.
    Pinned @wave-av/sdk to 2.0.14 (exact, last known-good published version)
    instead of the ^2.0.11 range that resolves the broken 2.1.x line.
    @wave-av/sdk@2.1.3 (the real fix) is not yet published to npm as of this
    PR — verified via npm view @wave-av/sdk versions against the public registry.
    Once it is published, bump this pin to ^2.1.3 in a follow-up so installs pick
    up the fixed SDK build going forward instead of staying pinned indefinitely.
  2. wave --version now reads the version from package.json at runtime via
    node:module's createRequire (works identically from src/cli.ts in dev and
    the bundled dist/index.js, since both sit one directory below the package
    root).
  3. wave doctor / wave status / wave auth status now set
    process.exitCode = 1 when a check fails or the caller is unauthenticated.
    wave whoami already exited 1 correctly ("keep the good copy" per the brief)
    — unchanged in behavior, just hardened with an explicit return after each
    process.exit(1) so a future refactor (or a test harness that mocks
    process.exit) can't accidentally fall through to the authenticated code path.
  4. wave status now health-checks https://api.wave.online/health (not
    https://wave.online/api/health). Also fixed the identical wrong-default-host
    bug in wave auth login's device-authorization flow and wave whoami's
    /api/v1/me call, both of which fell back to the marketing site when no
    project-specific baseUrl was configured. No separate "apex"/marketing check
    was added — there wasn't one before this fix either; the single check now just
    targets the correct host.

Tests (this PR adds the CLI's first test suite — 0 tests existed before)

  • src/cli.test.ts — --version resolves from package.json, not a hardcoded
    string.
  • src/commands/doctor/index.test.ts — exits non-zero on a failing check, exits
    clean (no exitCode set) when everything passes.
  • src/commands/status/index.test.ts — hits https://api.wave.online/health
    (not the marketing host); exits non-zero when unauthenticated; exits non-zero
    when the API is unreachable even if authenticated; stays exit-0 on the healthy
    path.
  • src/commands/auth/index.test.ts — auth status exits non-zero unauthenticated
    (previously always 0); whoami calls the API host, not the marketing site, and
    exits 1 immediately without an API call when no key is stored.

Verified all 8 behavior-changing assertions fail against pre-fix origin/main
(ran the identical test files in a detached-HEAD worktree at the pre-fix commit,
with the fixed SDK tarball installed so only the CLI-side behavior is under
test) and pass against this branch. The 3 "stays healthy" assertions correctly
pass in both states — those aren't regressions, just confirming the happy path
was never broken.

Gates

  • npm run build (tsup) — succeeds.
  • npx vitest run — 11 passed.
  • npm run type-check — pre-existing breakage, unrelated to this change: 148
    TS errors on origin/main before this PR, from a missing src/types/index.ts
    (this repo's source was recovered from published sourcemaps — see PR #24/#18
    history) plus drift between command code and the installed SDK's actual API
    shape. Diffed the full error list before/after this PR: identical count,
    identical error codes, zero errors in any file this PR touches.
    Not fixing
    the pre-existing 148 here — that's a much larger, separate undertaking
    (recreating types/index.ts and reconciling ~15 command files against the
    current SDK surface).
  • npm run lint — pre-existing breakage, unrelated: eslint isn't even
    listed in devDependencies (sh: eslint: command not found), confirmed on a
    pristine origin/main checkout before this PR touched anything.

Fresh-install proof (paste of actual commands + exit codes)

$ npm install   # picks up the @wave-av/sdk@2.0.14 pin from the public registry
$ npm run build
$ HOME=/tmp/fake-home node dist/index.js --version
1.0.9
exit: 0
$ HOME=/tmp/fake-home node dist/index.js doctor
  ...
  ✗ Auth: No API key found
  1 issue(s) need attention.
exit: 1
$ HOME=/tmp/fake-home node dist/index.js status
  ...
  API:      Healthy (162ms)      # <- really hit api.wave.online/health, not wave.online
exit: 1                          # <- unauthenticated, correctly non-zero
$ HOME=/tmp/fake-home node dist/index.js whoami
Not authenticated. Run `wave auth login` first.
exit: 1
$ HOME=/tmp/fake-home node dist/index.js auth status
exit: 1

Release note

Publishing @wave-av/cli@1.0.9 to npm is a separate, manual operator step.
This PR does not run npm publish. Publish order is now less coupled to
wave-av/sdk#111's publish timing than originally planned, since this release pins
to the already-published, working 2.0.14 rather than depending on the
not-yet-published 2.1.3.

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

🤖 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]
Medium Risk
Touches install-time SDK resolution, default API hosts for auth/status, and exit-code semantics that automation may depend on—mostly fixes but behavior changes for failing/unauthenticated runs.

Overview
Release @wave-av/cli@1.0.9 addresses a P0 where fresh npm i pulled a broken @wave-av/sdk (2.1.x ESM crash) by pinning the SDK to 2.0.14 and adding a lockfile; version is bumped in package.json.

wave --version no longer hardcodes 1.0.0 — it loads the real version from package.json via createRequire, including the banner and Commander -v.

Diagnostics and auth commands now signal failure to scripts: wave doctor, wave status, and wave auth status set process.exitCode = 1 when checks fail or the user is unauthenticated; wave whoami keeps process.exit(1) but adds explicit return after exit so execution cannot fall through.

Default API base URL is corrected from the marketing site to https://api.wave.online for wave status (/health), wave auth login, and wave whoami when no project baseUrl is set.

Adds Vitest coverage (e.g. src/cli.test.ts and command tests per PR description) and a detailed CHANGELOG entry for 1.0.9.

Reviewed by Cursor Bugbot for commit dd897ec519fa60ed6e220bba5cdaa5a66ce58e2d. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by Sourcery

Repair fresh-install compatibility and make CLI health and authentication commands accurately report failures.

Bug Fixes:

  • Restore fresh CLI installs by pinning the SDK to a known-good published version.
  • Report the installed CLI version dynamically instead of using a hardcoded value.
  • Return failing exit codes for unsuccessful doctor, status, and authentication checks.
  • Route default authentication, identity, and health requests to the API host and correct health endpoint.

Build:

  • Add the package lockfile and update the CLI package version to 1.0.9.

Documentation:

  • Document the release fixes and manual npm publishing requirement in the changelog.

Tests:

  • Add regression coverage for version reporting, command exit codes, authentication behavior, and API health-host selection.