Skip to content

fix: guard trend access against eager JSX evaluation (closes #5, #6) - #7

Merged
zhumengzhu merged 1 commit into
mainfrom
fix/eager-jsx-crash
Aug 7, 2026
Merged

fix: guard trend access against eager JSX evaluation (closes #5, #6)#7
zhumengzhu merged 1 commit into
mainfrom
fix/eager-jsx-crash

Conversation

@zhumengzhu

Copy link
Copy Markdown
Owner

Summary

Fixes the silent sidebar unmount reported in #5 and #6.

Root cause: npm-installed plugins live under node_modules, which opencode/opentui exclude from the babel-preset-solid transform (see opencode#39986 — the transform filter has a hardcoded node_modules exclusion since OpenTUI 0.4.2). Bun then compiles the raw TSX with its generic JSX (jsxDEV), which eagerly evaluates <Show>/<For> children before the when/guard runs. With no session data yet (fresh start / pre-sync), hasTrend is false → trend is undefinedprops.trend!.color throws TypeError → the per-slot <ErrorBoundary> silently unmounts the panel with no error surfaced (#5, #6).

Changes

  • TuiHitRow: props.trend!.colorprops.trend?.color — safe under both eager (bun generic JSX) and lazy (babel-preset-solid) evaluation
  • Hardening: same-class ! usages in cache-ttl-view.tsx (elapsed()!) and main-session-view.tsx (messages!) → optional props with runtime guards
  • tests/eager-render.test.ts: renders TuiHitRow with trend=undefined under bun's eager load path (verified to fail on the pre-fix !)
  • tests/eager-safe-jsx.test.ts: static scan for guard-variable ! derefs and optional-chain-then-bare-deref in src tsx (8 cases)
  • AGENTS.md: new Eager-safe JSX code convention
  • devDep @opentui/solid 0.3.0 → 0.4.5 (opencode 1.18.x catalog version); version bump 0.6.3 → 0.6.4

Verification

  • 345 tests pass / 0 fail
  • Reproduced locally: same source compiled under the two load paths behaves differently — node_modules path (eager) throws props.trend.color on trend=undefined; file path (lazy) does not. The fix passes both.
  • End-to-end verified on opencode 1.18.15 (npm install path): sidebar panel renders correctly after the fix.

Closes #5, #6

npm-installed plugins live under node_modules, which opencode/opentui
exclude from the babel-preset-solid transform (opencode#39986). Bun then
compiles the raw TSX with its generic JSX (jsxDEV), eagerly evaluating
<Show>/<For> children before guards run. With no session data yet,
hasTrend is false and trend is undefined, so props.trend!.color threw
TypeError and the per-slot ErrorBoundary silently unmounted the sidebar
panel (#5, #6).

- TuiHitRow: props.trend!.color -> props.trend?.color (safe under both
  eager and lazy evaluation)
- Hardening: cache-ttl-view elapsed()!, main-session-view messages! ->
  optional props with runtime guards
- tests/eager-render.test.ts: renders TuiHitRow with trend=undefined
  under bun's eager load path (verified to fail on the pre-fix !)
- tests/eager-safe-jsx.test.ts: scans src tsx for guard-variable !
  derefs and optional-chain-then-bare-deref patterns
- AGENTS.md: Eager-safe JSX convention
- devDep @opentui/solid 0.3.0 -> 0.4.5; version 0.6.3 -> 0.6.4
@zhumengzhu
zhumengzhu merged commit e7ddc15 into main Aug 7, 2026
1 check passed
@zhumengzhu
zhumengzhu deleted the fix/eager-jsx-crash branch August 8, 2026 10:28
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.

TuiHitRow renders undefined (evaluating 'props.trend.color') — sidebar slot silently unmounts via ErrorBoundary

1 participant