Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions scripts/smoke-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
# Postbuild smoke test for the compiled wizard binary.
#
# 1. Binary loads without crashing.
# 2. In production builds (WIZARD_BUILD_NODE_ENV != "ci"), --ci is rejected
# 2. Every .js chunk uses the automatic JSX runtime.
# 3. In production builds (WIZARD_BUILD_NODE_ENV != "ci"), --ci is rejected
# with the tailored "CI mode is not currently supported" error and a
# non-zero exit. Guards against a future change that re-enables --ci in
# published builds without anyone noticing.
# 3. In production builds, the experimental headless flag IS accepted (the
# 4. In production builds, the experimental headless flag IS accepted (the
# non-interactive published-build path) — it must not be rejected as an
# unknown argument. It is intentionally undocumented; this check only keeps
# the published binary from silently dropping the flag the cloud runs need.
Expand All @@ -23,7 +24,17 @@ node --input-type=module -e "import '$DIST_BIN'" 2>&1 | head -5 | grep -q 'PostH
exit 1
}

# ── 2. CI flag overrides physically absent from production builds ───────────
# ── 2. Automatic JSX runtime ────────────────────────────────────────────────
# Nothing under src/ imports React, so a classic-runtime transform emits `React.*`
# references that no module binds. A module-scope JSX value would then throw at
# import time and kill the run before the TUI draws. tsdown.config.ts pins the
# runtime; this asserts the pin still reaches the output.
if grep -q 'React\.createElement\|React\.Fragment' ./dist/*.js; then
echo 'Smoke test failed: a chunk was compiled with the classic JSX runtime' >&2
exit 1
fi

# ── 3. CI flag overrides physically absent from production builds ───────────
# The override path (src/utils/ci-flag-overrides.ts) is dead code in published
# builds and tsdown strips it; its env var name appearing in dist/*.js means
# dead-code elimination regressed and a prod surface leaked. Sourcemaps keep
Expand Down Expand Up @@ -58,7 +69,7 @@ else
done
fi

# ── 3. --ci rejected in production builds ────────────────────────────────────
# ── 4. --ci rejected in production builds ────────────────────────────────────
# build:ci sets WIZARD_BUILD_NODE_ENV=ci → --ci stays enabled → skip the check.
if [ "${WIZARD_BUILD_NODE_ENV:-production}" = "ci" ]; then
exit 0
Expand All @@ -81,7 +92,7 @@ if ! echo "$output" | grep -qi 'CI mode is not currently supported'; then
exit 1
fi

# ── 4. Experimental headless flag accepted in production builds ──────────────
# ── 5. Experimental headless flag accepted in production builds ──────────────
# The non-interactive path for published builds (cloud / CI runs). yargs must
# not reject the flag, and it must not fall through to the --ci rejection. With
# no api-key the run exits fast on "Headless mode requires --api-key" — all this
Expand Down
4 changes: 2 additions & 2 deletions src/ui/tui/screens/IntroScreenLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const WizardTitle = ({ title }: { title: string }) => (
);

/** Generic subtitle shown when a screen doesn't supply its own. */
const DEFAULT_SUBTITLE = (
const DefaultSubtitle = () => (
<>
<Text dimColor>
We'll use AI to analyze your project and complete work.
Expand Down Expand Up @@ -251,7 +251,7 @@ export const IntroScreenLayout = ({

{showSubtitle && !showingPrivacy && (
<Box flexDirection="column" alignItems="center" marginTop={1}>
{subtitle ?? DEFAULT_SUBTITLE}
{subtitle ?? <DefaultSubtitle />}
</Box>
)}

Expand Down
6 changes: 3 additions & 3 deletions src/ui/tui/screens/PostHogIntegrationIntroScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ import {
} from '@ui/tui/posthog-integration-intro';

/**
* Replaces IntroScreenLayout's DEFAULT_SUBTITLE for this screen only. The
* Replaces IntroScreenLayout's default subtitle for this screen only. The
* shared default (".env* file contents will not leave your machine") is true
* of values and false of variable names, which this screen reads and reports.
* Two lines carry the fact and name the screen that holds the detail, so the
* disclosure reaches people who never open it.
*/
const SUBTITLE = (
const Subtitle = () => (
<>
<Text dimColor>
We'll use AI to analyze your project and complete work.
Expand Down Expand Up @@ -367,7 +367,7 @@ export const PostHogIntegrationIntroScreen = ({
installDir={session.installDir}
title={title}
showSubtitle={view === 'default'}
subtitle={SUBTITLE}
subtitle={<Subtitle />}
body={body}
showDetection={showContinue}
detectionRows={detectionRows}
Expand Down
7 changes: 7 additions & 0 deletions tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ export default defineConfig({
// Keep npm dependencies external — they're installed at runtime.
skipNodeModulesBundle: true,

// Pin the automatic JSX runtime. Nothing under src/ imports React, so a
// classic-runtime transform would emit unbound `React.*` references.
// The object form is required — the `'react-jsx'` string form is ignored.
inputOptions: {
transform: { jsx: { runtime: 'automatic', importSource: 'react' } },
},

sourcemap: true,
clean: true,

Expand Down
Loading