refactor(tui): migrate renderer from Mosaic to tamboui
Replaces the Mosaic 0.18 string-frame renderer with tamboui 0.2.1-SNAPSHOT to unlock a cell buffer, widget catalog, and real layout engine. Domain core (state/reducer/ws/input) is unchanged; only the renderer and the key mapper are rewritten. Fixes a latent Mosaic-mapper bug where q/n/c/a/r/s// were swallowed inside input modes by making the new mapper mode-aware.
This commit is contained in:
@@ -51,11 +51,7 @@
|
||||
- **NOT YET WIRED** into `TuiApp.kt` — that is Task 2.3. The old `applyAction`/`applyServerMessage` paths still run.
|
||||
- Decisions deviating from plan: dropped unused `selectedSessionId` param on `InputReducer.reduce`; dropped unused `clock` param on `ConnectionReducer.reduce`. Old `StateReducer.kt` left in place alongside new `ServerMessageReducer.kt` (no callers of `ServerMessageReducer` yet).
|
||||
|
||||
---
|
||||
|
||||
## Pending — resume here
|
||||
|
||||
### Task 2.3 — EffectDispatcher + wire RootReducer into TuiApp 🚧 NEXT
|
||||
### Task 2.3 — EffectDispatcher + wire RootReducer into TuiApp ✅
|
||||
- Create `reducer/EffectDispatcher.kt`.
|
||||
- Rewrite `ws/TuiWsClient.kt`: expose `messages: SharedFlow<ServerMessage>` and `connection: SharedFlow<ConnectionEvent>`; remove suspend-callback constructor params. Add `sealed interface ConnectionEvent { Connected, Disconnected, RetryScheduled(attempt, nextRetryAtMs) }`.
|
||||
- In `TuiApp`: single `dispatch(action)` → `RootReducer.reduce` → `Snapshot.withMutableSnapshot { state = next }` → trySend each `Effect` to a `Channel<Effect>`.
|
||||
@@ -63,20 +59,32 @@
|
||||
- Delete old `applyAction`/`applyServerMessage` (and `StateReducer.kt` if unused after the cut).
|
||||
- Smoke-test: `n` → workflow id prompt → submit → session starts; approval flow; steering note.
|
||||
|
||||
### Task 3.1 — `Panel` composable + `TerminalSize`
|
||||
### Task 3.1 — `Panel` composable + `TerminalSize` ✅
|
||||
- Create `components/Panel.kt` (`@Composable fun Panel(title: String?, content: @Composable () -> Unit)`).
|
||||
- Create `components/TerminalSize.kt` (data class + `staticCompositionLocalOf { TerminalSize(80, 24) }`).
|
||||
- Do not wire yet.
|
||||
|
||||
### Task 3.2 — Migrate components to `Panel`
|
||||
### Task 3.2 — Migrate components to `Panel` ✅
|
||||
- Wrap each section in `TuiApp` with `Panel(title=…) { … }`.
|
||||
- Drop every `BOX_WIDTH` constant and hand-padding from `StatusBar`, `SessionList`, `ActiveSession`, `ApprovalPanel`, `InputBar`.
|
||||
- `grep -r "BOX_WIDTH" apps/tui` must return nothing.
|
||||
|
||||
### Task 3.3 — Responsive terminal width
|
||||
### Task 3.3 — Responsive terminal width ✅
|
||||
- Add `readTerminalSize()` (stty fallback, default 80×24) in `TerminalSize.kt`.
|
||||
- 500ms polling loop in `TuiApp.runTuiApp`; wrap content in `CompositionLocalProvider(LocalTerminalSize provides …)`.
|
||||
|
||||
### Task 4.2 — Session filter via `InputMode.Filter` ✅
|
||||
- `/` enters Filter mode (already wired in resolver). On `SubmitInput` mode=Filter, copy text into `sessions.filter`. On `CancelInput` mode=Filter, clear filter.
|
||||
- `SessionList` renders only sessions whose `workflowId` contains `filter` (case-insensitive).
|
||||
|
||||
### Task 4.3 — Reconnect feedback ✅
|
||||
- In `TuiWsClient.connect`, before backoff `delay`, emit `ConnectionEvent.RetryScheduled(attempt = ++count, nextRetryAtMs = clock() + delayMs)`.
|
||||
- `ConnectionReducer.RetryScheduled` already handles state; `Connected` resets attempt to 0.
|
||||
- `StatusBar` formats `nextRetryAtMs - clock()` as countdown.
|
||||
|
||||
---
|
||||
|
||||
## Pending — resume here
|
||||
### Task 4.1 — Scrollable session output log
|
||||
- Extend `SessionsState`: `eventLog: Map<SessionId, ArrayDeque<LogEntry>>`, `scrollOffsetById: Map<SessionId, Int>`.
|
||||
- New `LogEntry(timestampMs, kind, text)`.
|
||||
@@ -84,15 +92,6 @@
|
||||
- Rename `ActiveSession.kt` → `SessionOutputLog.kt`; render last N entries with scroll offset.
|
||||
- Add `Action.ScrollLogUp/Down`; introduce `FocusState { SessionList, OutputLog }`, Tab toggles. Map `NavUp/NavDown` to scroll when focus is on log.
|
||||
|
||||
### Task 4.2 — Session filter via `InputMode.Filter`
|
||||
- `/` enters Filter mode (already wired in resolver). On `SubmitInput` mode=Filter, copy text into `sessions.filter`. On `CancelInput` mode=Filter, clear filter.
|
||||
- `SessionList` renders only sessions whose `workflowId` contains `filter` (case-insensitive).
|
||||
|
||||
### Task 4.3 — Reconnect feedback
|
||||
- In `TuiWsClient.connect`, before backoff `delay`, emit `ConnectionEvent.RetryScheduled(attempt = ++count, nextRetryAtMs = clock() + delayMs)`.
|
||||
- `ConnectionReducer.RetryScheduled` already handles state; `Connected` resets attempt to 0.
|
||||
- `StatusBar` formats `nextRetryAtMs - clock()` as countdown.
|
||||
|
||||
### Task 5.1 — Coverage gate
|
||||
- Add kover verify rule to `apps/tui/build.gradle`: minBound 70 on `com.correx.apps.tui.reducer.*` + `com.correx.apps.tui.input.*`. Confirm syntax against current kover version.
|
||||
|
||||
@@ -104,8 +103,8 @@
|
||||
|
||||
## Sequencing
|
||||
```
|
||||
[done] 1.1 → 1.2 → 1.3 → 1.4 → 2.1 → 2.2
|
||||
[next] 2.3 → 3.1 → 3.2 → 3.3 → {4.1, 4.2, 4.3} → 5.1 → 5.2
|
||||
[done] 1.1 → 1.2 → 1.3 → 1.4 → 2.1 → 2.2 → 2.3 → 3.1 → 3.2 → 3.3 → {4.2, 4.3}
|
||||
[next] 4.1 → 5.1 → 5.2
|
||||
```
|
||||
|
||||
## Renderer evaluation — Mosaic is the floor
|
||||
|
||||
Reference in New Issue
Block a user