Skip to content

fix: ngrok Windows build + close CI error-swallowing gap (v0.18.0.1)#1024

Merged
garrytan merged 5 commits intomainfrom
garrytan/fix-ngrok-windows
Apr 16, 2026
Merged

fix: ngrok Windows build + close CI error-swallowing gap (v0.18.0.1)#1024
garrytan merged 5 commits intomainfrom
garrytan/fix-ngrok-windows

Conversation

@garrytan
Copy link
Copy Markdown
Owner

Summary

Fixes a bug where ./setup on Windows (and fresh Linux installs) has been failing silently since v0.15.12 with:

Building Node-compatible server bundle...
error: cannot write multiple output files without an output directory

Root cause: @ngrok/ngrok has a native .node addon that makes Bun want to emit a separate chunk, which conflicts with --outfile. Fix: externalize it like we already do for playwright, diff, and bun:sqlite.

Then this PR keeps going. The reason the bug shipped in the first place is that package.json's build and test scripts had a shell precedence trap: the trailing || true applied to the entire && chain, so CI happily reported green while the build failed. Fixed that too.

Credit

Two community contributors independently tracked this down and proposed the identical one-line fix:

Also closes #1010 and #960.

Thanks for the sharp diagnoses. The externalize fix is exactly what both PRs proposed — I'm landing it alongside the CI-masking fixes that let this slip through in the first place.

What's in this PR

  1. browse/scripts/build-node-server.sh — externalize @ngrok/ngrok, plus a policy comment explaining when to add future externals.
  2. package.json — wrap trailing cleanup in subshells so || true only scopes to cleanup, not the whole build/test chain.
  3. browse/test/build.test.ts — new regression test. Validates server-node.mjs passes node --check and confirms @ngrok/ngrok actually stayed external (not inlined). Skips gracefully when browse/dist/ is absent.
  4. setup — Windows now verifies Node can load @ngrok/ngrok at install time (mirroring the existing Playwright check), so the failure surfaces at ./setup instead of at /pair-agent time.
  5. VERSION + CHANGELOG — v0.18.0.1.

Test plan

  • bash browse/scripts/build-node-server.sh — emits single server-node.mjs, 0.33 MB
  • node --check browse/dist/server-node.mjs — passes
  • node -e "require('@ngrok/ngrok')" — loads cleanly on darwin-arm64
  • bun test browse/test/build.test.ts — 2 pass
  • bun test — full free-tier suite passes
  • Sanity check: old cmd && rm || true exits 0 when cmd fails; new cmd && (rm || true) exits 1 (precedence fix verified)
  • Windows install verification — relying on @tomasmontbrun-hash and @scarson's verifications (both tested on Windows 11, bun 1.3.11, Node v25.2.1)

Reviews

  • /plan-ceo-review — SELECTIVE EXPANSION mode, 6 proposals, 5 accepted, 0 deferred. CLEAR.
  • /codex review (outside voice) — 3 substantive findings, all accepted into scope (same || true bug in test script, graceful-skip in test, policy comment).
  • /plan-eng-review — 1 issue (Windows setup check for ngrok), accepted. 0 critical gaps. CLEAR.

🤖 Generated with Claude Code

garrytan and others added 5 commits April 16, 2026 13:32
… Windows

@ngrok/ngrok has a native .node addon that causes `bun build --outfile` to
fail with "cannot write multiple output files without an output directory".
Externalize it alongside the existing runtime deps (playwright, diff,
bun:sqlite), matching the exact pattern used for every other dynamic import
in server.ts.

Adds a policy comment explaining when to extend the externals list so the
next native dep doesn't repeat this failure.

Two community contributors independently converged on this fix:
 - @tomasmontbrun-hash (#1019)
 - @scarson (#1013)
Also fixes issues #1010 and #960.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…st failures

Shell operator precedence trap in both the build and test scripts:

    cmd1 && cmd2 && ... && rm -f .*.bun-build || true
    bun test ... && bun run slop:diff 2>/dev/null || true

The trailing `|| true` was intended to suppress cleanup errors, but it
applies to the entire `&&` chain — so ANY failure (including the
build-node-server.sh failure that broke Windows installs since v0.15.12)
silently exits 0. CI ran the build, the build failed, and CI reported green.

Wrap the cleanup/slop-diff commands in subshells so `|| true` only scopes to
the intended step:

    ... && (rm -f .*.bun-build || true)
    bun test ... && (bun run slop:diff 2>/dev/null || true)

Verified: `bash -c 'false && echo A && rm -f X || true'` exits 0 (old,
broken), `bash -c 'false && echo A && (rm -f X || true)'` exits 1 (new,
correct).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two assertions:
1. `node --check` passes on the built `server-node.mjs` (valid ES module
   syntax). This catches regressions where the post-processing steps (perl
   regex replacements) corrupt the bundle.
2. No inlined `@ngrok/ngrok` module identifiers (ngrok_napi, platform-
   specific binding packages). Verifies the --external flag actually kept
   it external.

Skips gracefully when `browse/dist/server-node.mjs` is missing — the dist
dir is gitignored, so a fresh clone + `bun test` without a prior build is
a valid state, not a failure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the existing Playwright verification step. Since @ngrok/ngrok is
now externalized in server-node.mjs (resolved at runtime from node_modules),
confirm the platform-specific native binary (@ngrok/ngrok-win32-x64-msvc et
al.) is installed at setup time rather than surfacing the failure later
when the user runs /pair-agent.

Same fallback pattern: if `node -e "require('@ngrok/ngrok')"` fails, fall
back to `npm install --no-save @ngrok/ngrok` to pull the missing binary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes shipped in this version:
- Externalize @ngrok/ngrok so the Node server bundle builds on Windows
  (PRs #1019, #1013; issues #1010, #960)
- Shell precedence fix so build/test failures no longer exit 0 in CI
- Build validation test for server-node.mjs
- Windows setup verifies @ngrok/ngrok native binary is loadable

Credit: @tomasmontbrun-hash (#1019), @scarson (#1013).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

E2E Evals: ✅ PASS

0/0 tests passed | $0 total cost | 12 parallel runners

Suite Result Status Cost

12x ubicloud-standard-2 (Docker: pre-baked toolchain + deps) | wall clock ≈ slowest suite

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.

build-node-server.sh — "cannot write multiple output files without an output directory" on fresh install

1 participant