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
Telemetry instrumentation (#56) — new ExRatatui.Telemetry module emits :telemetry events across the runtime so apps can plug in logging, metrics, or OpenTelemetry tracing without forking the server. Five span events (:start / :stop / :exception) wrap the costly stages: [:ex_ratatui, :runtime, :init] around mount/1, [:ex_ratatui, :runtime, :event] around terminal-input handle_event/2, [:ex_ratatui, :runtime, :update] around info-message handle_info/2 (subscriptions, async results, user messages), [:ex_ratatui, :render, :frame] around the build+draw cycle (adds :widget_count to stop metadata), and [:ex_ratatui, :transport, :connect] around local/SSH/distributed handshakes. Four single events fire for point-in-time facts: [:ex_ratatui, :session, :lifecycle, :open] when a session-backed runtime adopts a session (carries :width / :height), [:ex_ratatui, :session, :lifecycle, :close] when it releases the session (carries :reason; fires exactly once per session even when the transport's own teardown defensively closes the same ref afterwards), [:ex_ratatui, :render, :dropped] on draw errors (with a TODO placeholder for future frame-skip backpressure), and [:ex_ratatui, :transport, :disconnect] on server teardown. Every event carries :mod and :transport in its metadata. ExRatatui.Telemetry.span/3 is a thin helper that prefixes events with :ex_ratatui and forwards start metadata to stop; execute/3 does the same for single events and auto-adds :system_time. attach_default_logger/1 / detach_default_logger/0 ship a handler that logs every event at a configurable level. New Telemetry guide walks through the full event catalogue, a Telemetry.Metrics example, and an opentelemetry_telemetry wiring snippet. Added {:telemetry, "~> 1.0"} as an explicit dependency and to extra_applications so the handler registry is available on every node (including peers in distributed tests)
Transport behaviour — new ExRatatui.Transport module documents the protocol between the runtime server and the processes that carry I/O for a running ExRatatui.App. Declares the server_transport, writer_fn, and to_server typespecs, plus one optional child_spec/1 callback and a public start_server/1 entrypoint for custom transports to boot the runtime without depending on internal modules. ExRatatui.SSH, ExRatatui.SSH.Daemon, and ExRatatui.Distributed.Listener all adopt the behaviour. New ExRatatui.Transport.ByteStream helper packages the byte-pump pattern (forward_input/3, forward_resize/4) so any byte-oriented transport — SSH today, Kino/Livebook next, a custom TCP bridge — can plug in without reimplementing event dispatch or Resize absorption. ExRatatui.SSH now delegates to ByteStream instead of hand-rolling the loop. New Custom Transports guide walks through the contract and a working TCP example covering separation of acceptor and per-connection worker (so the listener survives across disconnects and serves concurrent clients), the alt-screen enter/leave sequences, runtime-server monitoring, and the raw-mode client requirement (stty raw -echo; nc …; stty sane) that plain TCP needs since it has no equivalent of SSH's PTY negotiation
Property-based test pass over the recently-added surface — five new files under test/ex_ratatui/property/ covering the modules introduced by the telemetry + transport-behaviour work, plus older surface that previously lacked sweeping coverage. session_input_property_test.exs proves ExRatatui.Session.feed_input/2's byte stitchability (splitting any byte stream at any boundary, including byte-by-byte, yields the same event sequence) along with shape invariants for printable bytes, bare ESC, and arrow keys. byte_stream_property_test.exs covers ExRatatui.Transport.ByteStream.forward_input/3's contract: no %Event.Resize{} ever leaks as a regular event, every parsed event is delivered in order, and forward_resize/4 always emits an :ex_ratatui_resize notification. bridge_property_test.exs covers Bridge.encode_commands!/1's list-level contract — length / order preservation, {map, map} shape, rect coordinate passthrough, and ArgumentError on malformed entries — across structurally simple widgets (Paragraph, Block, Clear, Gauge, Throbber). text_encode_property_test.exs covers Text.Encode.to_wire_text!/to_wire_line! line/span count and content preservation, alignment serialization, and per-line agreement between the two encoders. normalize_property_test.exs covers Subscription.normalize/1 and Command.normalize/1 idempotence, leaf-count preservation across nested batches, order preservation, and refusal of garbage shapes. The exhaustive per-widget validation property suite (one shape generator per widget × known-malformed shapes raising ArgumentError, ~22 widgets) is intentionally deferred — the structural invariants above are uniform across widgets, so the next pass is a per-widget effort rather than a generic one
Changed
Internal :ssh transport tag renamed to :session — the Server's internal transport tag always described "generic byte-stream session"; SSH just happened to be the first user. The new name makes room for other byte-stream transports (Kino, custom TCP) to share the same runtime without impersonating SSH. User-facing routing shorthand is untouched: {MyApp, transport: :ssh} still routes to SSH.Daemon. Affected surfaces: Runtime.snapshot/1.transport now returns :session for byte-stream sessions (was :ssh); telemetry metadata %{transport: _} on [:runtime, :init], [:transport, :connect], etc. is now :session on byte-stream events; mount(opts)[:transport] is now :session for SSH apps (was :ssh). If your app branches on opts[:transport] to detect SSH specifically, switch to a different signal (you control the {MyApp, transport: :ssh} line in your own supervision tree)