You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for landing ink (https://github.com/vadimdemedes/ink) as a perry.compilePackages target. Surfaced in discussion #333 (TUI/CLI support) — the consensus there was that for full-screen TUIs, building a Perry-native ncurses-style framework is a lot of surface for a niche audience. ink is the modern, actively-maintained, React-based replacement for blessed / react-blessed and is what most new TS TUIs in 2025–2026 are built on (gh-copilot, claude-code, opencommit, etc.). Wiring it as a compilePackages target gives Perry users a maintained TUI library without reinventing the wheel.
End-to-end means: a user does npm install ink react, adds \"compilePackages\": [\"ink\", \"react\"] to package.json, writes a standard ink program, runs perry compile app.tsx -o app && ./app and gets an interactive TUI binary.
The unknowns split into three buckets:
React itself — Perry already ships perry-react (github.com/PerryTS/react) as a native-widget React (compiles JSX to AppKit / UIKit / Android widgets), which is not the same as ink's use case. Ink uses upstream react + react-reconciler + a custom renderer that emits ANSI to the terminal. Open question whether perry-react's React infra can be reused for ink's reconciler-as-consumer pattern, or whether DOM-style React needs to compile via compilePackages independently.
Yoga layout — ink uses yoga-layout for flexbox layout in text. Yoga is traditionally a C++ lib; current yoga-layout has both a native-binding fork and a pure-JS fork. Either path needs evaluation: link libyoga natively (cross-compile story for every Perry target) vs. compile the JS port via compilePackages.
ANSI utility deps — chalk, cli-cursor, cli-truncate, slice-ansi, string-width, strip-ansi, wrap-ansi, ansi-escapes, etc. Mostly thin string-manipulation wrappers; the gap (if any) is likely individual TS-subset features each one trips over, which is the standard compilePackages shake-out.
Acceptance
A 30-line ink program (counter component with keyboard input — increment on +, decrement on -, quit on q) compiles via perry compile, produces a single-file native binary, runs interactively, and matches ink running under node --experimental-strip-types byte-for-byte (modulo terminal cursor positioning timing).
Whatever shake-out fixes are needed in perry-codegen / perry-stdlib to make the dependency tree compile cleanly, land them under this issue's umbrella.
blessed / react-blessed — older, flakier, not the recommended path. Documenting why we picked ink over blessed is enough.
A Perry-native TUI framework written from scratch — would be a bigger lift than wiring ink and competes with a maintained library; skip unless ink turns out to be unworkable.
Tracking issue for landing
ink(https://github.com/vadimdemedes/ink) as aperry.compilePackagestarget. Surfaced in discussion #333 (TUI/CLI support) — the consensus there was that for full-screen TUIs, building a Perry-native ncurses-style framework is a lot of surface for a niche audience.inkis the modern, actively-maintained, React-based replacement forblessed/react-blessedand is what most new TS TUIs in 2025–2026 are built on (gh-copilot,claude-code,opencommit, etc.). Wiring it as acompilePackagestarget gives Perry users a maintained TUI library without reinventing the wheel.Depends on
tty.setRawMode+ raw-mode stdin +tty.isatty+process.stdout.columns/rows+ SIGWINCH. Ink can't render anything useful until at least Phase 1 + Phase 2 of TUI gap: readline + tty.setRawMode + raw-mode stdin reader #347 land.Scope
End-to-end means: a user does
npm install ink react, adds\"compilePackages\": [\"ink\", \"react\"]topackage.json, writes a standard ink program, runsperry compile app.tsx -o app && ./appand gets an interactive TUI binary.The unknowns split into three buckets:
perry-react(github.com/PerryTS/react) as a native-widget React (compiles JSX to AppKit / UIKit / Android widgets), which is not the same as ink's use case. Ink uses upstreamreact+react-reconciler+ a custom renderer that emits ANSI to the terminal. Open question whether perry-react's React infra can be reused for ink's reconciler-as-consumer pattern, or whether DOM-style React needs to compile viacompilePackagesindependently.yoga-layoutfor flexbox layout in text. Yoga is traditionally a C++ lib; currentyoga-layouthas both a native-binding fork and a pure-JS fork. Either path needs evaluation: linklibyoganatively (cross-compile story for every Perry target) vs. compile the JS port viacompilePackages.chalk,cli-cursor,cli-truncate,slice-ansi,string-width,strip-ansi,wrap-ansi,ansi-escapes, etc. Mostly thin string-manipulation wrappers; the gap (if any) is likely individual TS-subset features each one trips over, which is the standardcompilePackagesshake-out.Acceptance
+, decrement on-, quit onq) compiles viaperry compile, produces a single-file native binary, runs interactively, and matchesinkrunning undernode --experimental-strip-typesbyte-for-byte (modulo terminal cursor positioning timing).perry-codegen/perry-stdlibto make the dependency tree compile cleanly, land them under this issue's umbrella.Out of scope (separate follow-ups)
inquirer/prompts/ other prompt-style libs — those are simpler (line-buffered only) and TUI gap: readline + tty.setRawMode + raw-mode stdin reader #347's Phase 1 unblocks them directly without ink.blessed/react-blessed— older, flakier, not the recommended path. Documenting why we picked ink over blessed is enough.Discussion: #333. Primitives: #347.