stx typecheck and stx codemod both exit immediately in any installed build, including the published tarball:
$ bun node_modules/@stacksjs/stx/dist/cli.js codemod
development.ERROR: Unhandled Rejection: ReferenceError: awaitPromise is not defined
$ bun node_modules/@stacksjs/stx/dist/cli.js typecheck
development.ERROR: Unhandled Rejection: ReferenceError: awaitPromise is not definedNeither command can do anything at all — it dies before reading a single file.
This is the published artifact, not a local build
I checked, because my node_modules/@stacksjs/stx is symlinked to a clone and a locally-built dist would have proved nothing:
$ npm pack @stacksjs/stx@0.2.170
$ tar xzf stacksjs-stx-0.2.170.tgz
$ grep -c "awaitPromise" package/dist/cli.js
2
$ grep -o ".\{80\}awaitPromise.\{80\}" package/dist/cli.js
…formatCodemodFindings:G}=await Promise.resolve().then(() => (qb(),zb)),{Glob:K}=awaitPromise.resolve(globalThis.Bun),W=…The minified identifiers differ from my local build (qb(),zb vs Vb(),Fb), so these are two independent builds that both produced the defect. Everyone who installs 0.2.170 gets it.
Root cause: await import('bun') after a comma
Both sites are the same source construct — a dynamic import of the bun builtin, which the bundler rewrites to await Promise.resolve(globalThis.Bun):
// bin/cli.ts:1795 (typecheck) and :1852 (codemod)
const { formatTypecheckDiagnostics, typecheckStxFiles } = await import('../src/typecheck')
const { Glob } = await import('bun')The two consts merge into one comma-separated let list, and the space between await and Promise is dropped on the second one, fusing them into the identifier awaitPromise:
let {…}=await Promise.resolve().then(() => (qb(),zb)), // ✅ survives
{Glob:K}=awaitPromise.resolve(globalThis.Bun) // ❌ fusedThe first await Promise in that very same statement is fine, and there are 58 correct await Promise occurrences elsewhere in the same file — so this is not a blanket minifier failure. It is specific to await Promise.resolve(<identifier>) landing after a comma in a merged declaration list.
The correlation is exact:
| count | |
|---|---|
await import('bun') in bin/cli.ts | 2 (lines 1795, 1852) |
awaitPromise in published dist/cli.js | 2 |
| commands that throw | 2 (typecheck, codemod) |
Every other command I tried (doctor, a11y, status, --help) works. dist/cli.js is the only affected file in the tarball.
Why this matters more than a two-command outage
These are the two features shipped this month, and both are unusable in every released build:
codemodis what #1843 shipped (a83305beb2) to remediate the adoption debt that issue documented — the tool written to fix "apps hand-roll what stx already exports" cannot be run by an app.typecheckis what #1889 shipped (d426fb19d7) to type-check template expressions.
Fix
Bun is a runtime global; the dynamic import buys nothing. Any of these removes the construct:
const { Glob } = globalThis.Bun // simplest
import { Glob } from 'bun' // static, top of file
const bunMod = await import('bun'); const { Glob } = bunMod // unmergedWhy nothing caught it
The test suite exercises src, so it never evaluates the emitted dist/cli.js — the defect only exists after bundling. A smoke test that shells out to the built CLI for each registered command (--help alone would have caught both, had the actions been reached) closes this class. It is the same trap as the stale-dist problem in #1891, one layer further out: there, tests read a stale artifact; here, they never read the artifact at all.
Found while trying to run stx codemod against a production app to act on #1843.