9734eec63c
Generated by per-group subagents covering all 52 modules across: core (18), infrastructure (10), apps (5), interfaces (3), plugins (7), testing (9) Documentation format: - AsciiDoc (.adoc) files in docs/modules/<group>/ - PlantUML (.puml) files in docs/diagrams/ - .adoc files reference diagrams via include:: directives Each doc covers: purpose, responsibilities, non-responsibilities, key types, event flow, integration points, invariants, PlantUML diagram, known issues, and open questions.
116 lines
5.4 KiB
Plaintext
116 lines
5.4 KiB
Plaintext
= app-tui
|
|
|
|
== purpose
|
|
|
|
Terminal UI built on the Tamboulib TUI framework that provides a real-time interactive dashboard for monitoring and controlling Correx sessions.
|
|
|
|
== responsibilities
|
|
|
|
* Display a live session list with status, workflow name, and background-update badges
|
|
* Show workflow definitions available on the server for starting new sessions
|
|
* Stream session lifecycle events (stage, tool, inference) in a scrollable event strip
|
|
* Display tool diffs when tool executions complete with file modifications
|
|
* Surface approval requests with tool name, tier, risk summary, and command preview
|
|
* Accept approval decisions (approve / reject) and steering notes via keyboard input
|
|
* Support session filtering by workflow name, input history navigation, and keyboard-driven UI modes
|
|
|
|
== non-responsibilities
|
|
|
|
* Does not contain any domain orchestration or event-sourcing logic
|
|
* Does not persist any state — all state is in-memory and rebuilt on reconnect
|
|
* Does not authenticate or encrypt connections
|
|
* Does not support mouse interaction
|
|
|
|
== key types
|
|
|
|
=== TuiState
|
|
* **kind**: data class
|
|
* **purpose**: Root application state. Contains `connection`, `sessions`, `input`, `provider` sub-states plus display metadata (cursor position, input buffer, history, snapshot phase flags, per-session cursors).
|
|
|
|
=== SessionsState
|
|
* **kind**: data class
|
|
* **purpose**: Holds the list of `SessionSummary` objects, filter text, session/workflow selection, and background update counter.
|
|
|
|
=== DisplayState
|
|
* **kind**: enum
|
|
* **purpose**: Tri-state enum (`IDLE`, `IN_SESSION`, `APPROVAL`) that drives which layout the TUI renders.
|
|
|
|
=== SessionSummary
|
|
* **kind**: data class
|
|
* **purpose**: Projected view of a session for display — ID, status, workflow, stage, tools, recent events, pending approval.
|
|
|
|
=== TuiWsClient
|
|
* **kind**: class
|
|
* **purpose**: Ktor WebSocket client that maintains a persistent global stream (`/stream`). Exposes cold `Flow<ServerMessage>` and `Flow<ConnectionEvent>` backed by `Channel.UNLIMITED`. Implements exponential backoff reconnection.
|
|
|
|
=== Action (sealed interface)
|
|
* **kind**: sealed interface
|
|
* **purpose**: Union of all user input and system events (navigation, input editing, approval, server messages, connection events).
|
|
|
|
=== KeyEvent (sealed class)
|
|
* **kind**: sealed class
|
|
* **purpose**: Normalized key events independent of the TUI backend (TambouiKeyEvent mapping).
|
|
|
|
=== RootReducer
|
|
* **kind**: object
|
|
* **purpose**: Top-level reducer that coordinates `SnapshotPhaseReducer` + four sub-reducers (`InputReducer`, `SessionsReducer`, `ConnectionReducer`, `ProviderReducer`). Handles cross-reducer state weaving (input history, approval dismissal, auto-enter on session start).
|
|
|
|
=== SnapshotPhaseReducer
|
|
* **kind**: object
|
|
* **purpose**: Manages the snapshot-to-live transition. Buffers event-bearing messages during snapshot replay; drains buffered events atomically when `SnapshotComplete` arrives; deduplicates live events by `sessionSequence`.
|
|
|
|
=== Effect (sealed interface)
|
|
* **kind**: sealed interface
|
|
* **purpose**: Side-effect descriptors produced by reducers — either `SendWs(ClientMessage)` or `Quit`.
|
|
|
|
=== EffectDispatcher
|
|
* **kind**: class
|
|
* **purpose**: Executes effects sequentially. Dispatches WS messages via `TuiWsClient.send()` and `Quit` via a callback that exits the TUI runner.
|
|
|
|
== event flow
|
|
|
|
*inbound:* `ServerMessage` frames from the global WebSocket stream, decoded by `TuiWsClient` and wrapped in `Action.ServerEventReceived`. Also connection lifecycle events (`Connected`, `Disconnected`, `RetryScheduled`).
|
|
|
|
*outbound:* `ClientMessage` frames sent via `Effect.SendWs` — `StartSession`, `CancelSession`, `ApprovalResponse`.
|
|
|
|
== integration points
|
|
|
|
* `:apps:server` — imports `ServerMessage`, `ClientMessage`, `ApprovalDecision`, `PauseReason`, `WorkflowDto`, `ProviderHealthDto`
|
|
* `:core:events` — imports `ApprovalRequestId`, `SessionId`
|
|
* `:core:approvals` — imports `Tier`
|
|
|
|
Tamboulib framework: `tamboui-tui`, `tamboui-widgets`, `tamboui-core`, `tamboui-jline3-backend`.
|
|
|
|
== invariants
|
|
|
|
* `ws.messages` and `ws.connection` are single-consumer cold flows — adding a second collector drops messages from one
|
|
* Effects are dispatched sequentially (dispatchAll) — order matches `RootReducer` concatenation
|
|
* `Effect.Quit` is always appended last by `RootReducer.reduce`
|
|
* Snapshot phase is entered initially and on every `Disconnected`; buffered events are drained atomically at `SnapshotComplete`
|
|
* Live event deduplication uses per-session `sessionSequence` cursor; gaps are warned and applied anyway
|
|
* The TUI creates one WS connection (`/stream`) — per-session streams are not used
|
|
|
|
== PlantUML diagram
|
|
|
|
[plantuml, app-tui, "png"]
|
|
----
|
|
include::../../diagrams/app-tui.puml[]
|
|
----
|
|
|
|
|
|
|
|
|
|
== known issues
|
|
|
|
* `StageToolManifest` arriving before `SessionStarted` is silently dropped (TODO RF-3) — the session won't exist in the list yet
|
|
* Chat submission in `IN_SESSION` is blocked (returns empty effects) — router integration is deferred to Epic 14
|
|
* `InputHistory` limit is hardcoded to 50 entries per session
|
|
* Event strip shows at most 5 events for the selected session
|
|
* Session list is capped at 7 visible entries; overflow is shown as a count but not scrollable
|
|
|
|
== open questions
|
|
|
|
* Should the TUI support per-session WebSocket streams instead of relying solely on the global stream?
|
|
* Should approval decisions support freeform steering note input that can exceed one line?
|
|
* How should workflow picker handle very large numbers of available workflows (10+)?
|