Bump the three @opentui pins (core/keymap/solid) 0.4.0 -> 0.4.1 + lockfile. The headline upstream change is native-yoga (#1126); per the locked spec decision D11 this is NOT a memory-floor lever at typical sizes, and a fresh bench on this branch confirms it — OpenTUI capped VmHWM is within run-to-run noise across mem50/100/300 (0.4.0: 193/200/220 vs 0.4.1: 192/218/217 MB). The value is tail-session layout wins + upstream alignment, not the floor. D14 (ffiSafe re-verify): the FFI signatures ffiSafe.ts clamps (OptimizedBuffer fillRect/drawText/setCell/setCellWithAlphaBlending/drawChar + TextBufferView setViewport) are byte-identical across 0.4.0->0.4.1 (still u32, still crash on negatives under node:ffi), so the shim stays as-is and remains load-bearing. Verified live: scrolled a 300-msg transcript with syntax-highlighted code + tool cards past the viewport top (the negative-y fillRect trigger) on 0.4.1 — no ERR_INVALID_ARG_VALUE loop, clean render. Also pick up openConsoleOnError:false (public createCliRenderer option): stops core's uncaught-error handler from calling the ALLOCATING console.show(), which exit-7-masks the original error under native-handle exhaustion (the bench mem3000 postmortem). guardRendererErrorHandlers stays as belt-and-suspenders. Gate: npm run check OK (768 tests). Determinism gate green both engines. |
||
|---|---|---|
| .. | ||
| parsers | ||
| scripts | ||
| src | ||
| .gitignore | ||
| .node-version | ||
| .prettierrc | ||
| eslint.config.mjs | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
ui-opentui — native OpenTUI engine for Hermes
Solid + @opentui/core over Node FFI. Ink (ui-tui/) is the shipping default;
this is the experimental engine (draft PR #42922).
Node 26 setup (required; will not touch your other projects)
This package needs Node ≥ 26.3 (--experimental-ffi floor). Everything
else on this machine/repo can keep whatever Node it already uses — pin 26 to
this directory only:
# 1. install fnm (skip if you have it; nvm/mise work too — see below)
curl -fsSL https://fnm.vercel.app/install | bash
# add to ~/.zshrc (or bashrc): eval "$(fnm env --use-on-cd --shell zsh)"
# 2. install Node 26 SIDE BY SIDE (does NOT change your default)
fnm install 26
# 3. done — this directory has a .node-version (26.3), so `cd ui-opentui`
# auto-switches to 26 and leaving switches back. Do NOT run `fnm default 26`.
node -v # v26.x here; your old version everywhere else
No shell integration wanted (CI, scripts, one-off): fnm exec --using 26 -- node ...
or invoke the absolute binary (~/.local/share/fnm/node-versions/v26.*/installation/bin/node).
mise users: mise use node@26 in this directory. nvm users: nvm install 26,
plus an .nvmrc shim (echo 26 > .nvmrc) if you rely on auto-switching.
Gotchas
- Native modules are ABI-locked. A
node_modulesinstalled under Node 20/22 will not load under 26 (and vice versa) — runnpm ci(ornpm rebuild) after switching versions. Same applies to the tui-bench repo's node-pty (github.com/NousResearch/tui-bench). - Global npm packages don't follow between versions (per-version prefix); reinstall the few you need, or don't use globals.
- Editor terminals (Zed/VS Code) need the
fnm envline in your shell rc; the.node-versionauto-switch then covers any shell that cd's here. - Never run this package with bun — the FFI seam and the Solid/JSX build are Node-path only here.
package.jsondeclaresengines.node >= 26.3, so a wrong-Nodenpm ciwarns immediately.
Build & run
node scripts/build.mjs
HERMES_TUI_MOUSE=1 node --experimental-ffi --no-warnings dist/main.js
Gates: npm run check (typecheck + lint + tests). Memory/perf benchmarks live
in the tui-bench repo (github.com/NousResearch/tui-bench; see its README). Transcript windowing (memory architecture) is
documented in ../docs/plans/opentui-transcript-windowing.md.