Phase 1 of the #212 OpenTUI adoption plan. Design spec: docs/superpowers/specs/2026-05-30-tui-opentui-adoption-design.md (branch feat/212-opentui-adoption-plan).
Keystone phase — unblocks typed JSX for all later phases and fixes three confirmed silent render bugs found by verifying against installed @opentui/core@0.1.87.
Root cause
OpenTUI registers lowercase tags at runtime but ships no JSX.IntrinsicElements augmentation, so Grove uses untyped React.createElement("tag" as string, …) — which hides wrong props.
Scope
- Expand
src/tui/opentui.d.ts: declare JSX.IntrinsicElements for diff, code, markdown, scrollbox, select, input, textarea, span, line-number, ascii-font, tab-select with real option props; declare/confirm SyntaxStyle, RGBA, mouse prop types, hooks useOnResize, useTimeline.
- Replace every
React.createElement("<tag>" as string, …) with typed JSX (audit artifact-preview.tsx, split-diff.tsx, detail.tsx, vfs-browser.tsx, others).
Bug fixes (silent render failures)
<code> uses language= + children → must be filetype= + content= (syntax highlighting currently does nothing).
<markdown> passes children → must be content= (renders nothing).
split-diff.tsx (via compare-view.tsx) uses oldContent/newContent/mode → <diff> takes a unified diff string + view="split" only. Share one computeUnifiedDiff util with artifact-preview.tsx.
Note (per OpenTUI gotchas): the unified diff string needs a valid @@ hunk header or <diff> won't parse it.
Acceptance
tsc --noEmit passes with zero as string intrinsic casts in src/tui.
- Artifact code/markdown/diff and compare-view render real content in a TUI smoke.
- Render tests assert code highlighting / markdown / split diff emit non-empty styled output.
Version: stays on 0.1.87. Part of #212.
Phase 1 of the #212 OpenTUI adoption plan. Design spec:
docs/superpowers/specs/2026-05-30-tui-opentui-adoption-design.md(branchfeat/212-opentui-adoption-plan).Keystone phase — unblocks typed JSX for all later phases and fixes three confirmed silent render bugs found by verifying against installed
@opentui/core@0.1.87.Root cause
OpenTUI registers lowercase tags at runtime but ships no
JSX.IntrinsicElementsaugmentation, so Grove uses untypedReact.createElement("tag" as string, …)— which hides wrong props.Scope
src/tui/opentui.d.ts: declareJSX.IntrinsicElementsfordiff,code,markdown,scrollbox,select,input,textarea,span,line-number,ascii-font,tab-selectwith real option props; declare/confirmSyntaxStyle,RGBA, mouse prop types, hooksuseOnResize,useTimeline.React.createElement("<tag>" as string, …)with typed JSX (auditartifact-preview.tsx,split-diff.tsx,detail.tsx,vfs-browser.tsx, others).Bug fixes (silent render failures)
<code>useslanguage=+ children → must befiletype=+content=(syntax highlighting currently does nothing).<markdown>passes children → must becontent=(renders nothing).split-diff.tsx(viacompare-view.tsx) usesoldContent/newContent/mode→<diff>takes a unifieddiffstring +view="split"only. Share onecomputeUnifiedDiffutil withartifact-preview.tsx.Acceptance
tsc --noEmitpasses with zeroas stringintrinsic casts insrc/tui.Version: stays on
0.1.87. Part of #212.