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
Reducer runtime for ExRatatui.App via use ExRatatui.App, runtime: :reducer. Reducer apps implement init/1, render/2, and update/2, receive terminal input as {:event, event}, mailbox messages as {:info, msg}, and can declare subscriptions with subscriptions/1
ExRatatui.Command — reducer side-effect helpers for immediate messages, delayed messages, async work, and batched command execution
ExRatatui.Subscription — reducer timer/subscription helpers for interval and one-shot self-messages reconciled by stable id
ExRatatui.Runtime — runtime inspection helpers exposing snapshots, trace events, and trace enable/disable controls for supervised TUI processes
ExRatatui.Runtime.inject_event/2 — deterministic synthetic event injection for supervised apps under test_mode
Example: examples/reducer_counter_app.exs — simple reducer-driven counter showing update/2 and subscriptions/1
Changed
ExRatatui.App now supports two runtime styles: the existing callback runtime and the new reducer runtime selected with runtime: :reducer
The internal server now supports reducer runtime options for commands, render suppression, trace state, runtime snapshots, async command tracking, and subscription reconciliation
Render-command encoding moved into ExRatatui.Bridge, making ExRatatui.draw/2 and ExRatatui.Session.draw/2 share one validation and encoding path
Native render-command decoding was refactored into reusable helpers in native/ex_ratatui/src/decode.rs and shared between local terminal rendering and session rendering
Fixed
New subscriptions now store their timer reference correctly instead of keeping the {timer_ref, token} tuple in the timer_ref field, which broke timer cancellation/rearming paths in the reducer runtime
Async command mappers are now wrapped the same way as async functions, so mapper exceptions/exits return structured error tuples and active_async_commands bookkeeping is always decremented
The mount/1 callback contract now includes the supported {:ok, state, callback_opts} form, which keeps reducer-style startup shims aligned with Dialyzer and the runtime's actual behavior
Invalid reducer/runtime payloads and malformed render commands now fail earlier with clearer Elixir-side or Rust-side validation errors
Parallel cold compile crash — the NIF bridge no longer loads its NIF via @on_load during dependency compilation. Precompiled/source artifacts are still prepared at compile time, but the NIF now loads lazily on first use, which stops isolated compiler VMs from crashing under parallel cold compiles on this host
test_mode input flake — local supervised apps and distributed attach clients no longer poll the real terminal while running headless tests, which removes ambient crossterm events from async test runs and stops spurious renders like the render?: false reducer flake
SSH auto_host_key bootstrap — host-key generation now recreates the parent <priv_dir>/ssh/ directory immediately before writing the key, so first boot succeeds even if the app's priv tree was absent or cleaned between runs
Docs
README now documents the reducer runtime, reducer example app, command/subscription helpers, and runtime inspection API
README and ExRatatui.App docs now call out that mount/1 may return runtime opts and that WidgetList.scroll_offset is row-based with partial clipping semantics
Expanded public moduledocs for ExRatatui.App, ExRatatui.Command, ExRatatui.Subscription, and ExRatatui.Runtime
HexDocs module grouping now includes reducer-runtime modules
README now notes that the native library loads lazily on first use
Tests
Added reducer runtime coverage for commands, subscriptions, tracing, render suppression, async failure handling, and invalid runtime return values
Added coverage for public Command, Subscription, Runtime, App, and shared bridge validation paths