632 lines
27 KiB
Markdown
632 lines
27 KiB
Markdown
# TUI Layout Redesign — Soft Rounded + Blue Accent
|
||
|
||
This document has two halves. The **top half** describes what the user sees and experiences — the visual language, the three screens, microfeedback. The **bottom half** is the build plan — phases, files, checklists, code patterns.
|
||
|
||
---
|
||
|
||
# DESIGN SPEC
|
||
|
||
---
|
||
|
||
## 1. Visual Language
|
||
|
||
Everything shares one consistent look: a **soft rounded** dark theme with a **blue accent**.
|
||
|
||
### Surfaces
|
||
|
||
| Element | Looks like | Feels like |
|
||
|---------|------------|------------|
|
||
| Background | Deep charcoal `#14161a` | The ground — recedes |
|
||
| Panels | Slightly lighter `#181b21`, rounded borders `╭──╮` | Cards floating on the ground |
|
||
| Top bar | Darkest `#0f1115` | Anchors the screen |
|
||
| Footer bar | Same as top bar | Anchors the bottom |
|
||
| Active panel | Blue-tinted border glow | The thing you're working in |
|
||
|
||
### Light — five levels of contrast
|
||
|
||
```
|
||
#eef1f5 — bright white → headings, important values
|
||
#ced3da — light gray → body text, messages
|
||
#838b96 — muted gray → labels, metadata, timestamps
|
||
#434a55 — faint → borders, separators, placeholders
|
||
#262b33 — darkest gray → subtle panel borders
|
||
```
|
||
|
||
### Accent — blue (#4a9eff)
|
||
|
||
Used sparingly so it means something:
|
||
- **Selected item** indicator (`▶`)
|
||
- **Active panel** border highlight
|
||
- **Interactive hints** (keybind labels)
|
||
- **Brand mark** (the `x` in `correx`)
|
||
- **Inference events** in the stream
|
||
- **Prompt cursor** (`▌`)
|
||
|
||
Secondary accent is a purple-blue (`#7aa2f7`) used for lifecycle events.
|
||
|
||
---
|
||
|
||
## 2. The Three Screens
|
||
|
||
Every screen shares the same three-row grid. The middle row is a 1.7:1 horizontal split whose content changes by state. The input bar is always inside the left panel's footer.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────┐
|
||
│ status bar │ ← always visible
|
||
├─────────────────────────────────┬─────────────────────┤
|
||
│ left panel (1.7) │ right panel (1.0) │ ← changes by state
|
||
│ │ │
|
||
│ ──────────────────── │ │
|
||
│ ❯ input bar (panel footer) │ │
|
||
├─────────────────────────────────┴─────────────────────┤
|
||
│ footer bar — keybind hints · mode │ ← always visible
|
||
└──────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### IDLE — choosing what to do
|
||
|
||
Left column shows the session list (+ workflow picker if no sessions). Right column is a welcome panel.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ ● connected │ localhost:8080 │ qwen_coder_14b (local) │
|
||
├──────────────────────────┬───────────────────────────────────┤
|
||
│ sessions │ Correx Agent Harness │
|
||
│ │ │
|
||
│ ▶ [01J9CA] ACTIVE │ Connected · 3 sessions │
|
||
│ cas-segment-store │ ───────────────────── │
|
||
│ [02KF8B] COMPLETED │ Select a session from the left │
|
||
│ approval-flow │ or type a name to start a new │
|
||
│ [03LD7C] FAILED │ one. │
|
||
│ refactor-router │ │
|
||
│ │ recent: │
|
||
│ ────────────────────── │ cas-segment-store 14:02 ▸ │
|
||
│ ▌ Session name… │ approval-flow 13:45 ✔ │
|
||
│ tab filter ctrl+n new │ refactor-router 12:30 ✘ │
|
||
└──────────────────────────┴───────────────────────────────────┘
|
||
│ ⌨i message ⌨p commands ⌨a approval ⌨e events ⌨F2 skin │ Soft · blue
|
||
└──────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### IN_SESSION — interacting with an agent
|
||
|
||
Left column is the conversation (messages from user, agent, kernel). Right column is the live event stream. Status bar expands to show session name, branch, model, context meter, state badge.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ ● connected · cas-segment-store · feat/cas-segments │
|
||
│ qwen_coder_14b (local) ctx ████████░░ 64% ▸ active │
|
||
├──────────────────────────┬───────────────────────────────────┤
|
||
│ router · conversation │ event stream ◌ live │
|
||
│ │ │
|
||
│ you 14:02 │ 14:11:02 [Lifecycle] stage.enter │
|
||
│ Implement CAS storage… │ 14:11:02 [Context] pack.synth │
|
||
│ │ 14:11:03 [Inference] infer.start │
|
||
│ correx 14:02 │ 14:11:19 [Tool] fs.write │
|
||
│ Routed → planning… │ 14:11:20 [Tool] fs.write │
|
||
│ │ 14:11:24 [Domain] artifact │
|
||
│ agent 14:05 │ 14:11:31 [Tool] shell.exec │
|
||
│ Plan: each segment is… │ 14:11:48 [Inference] infer.token │
|
||
│ │ 14:12:02 [Approval] approval │
|
||
│ correx 14:11 │ raised T3 network │
|
||
│ Transition planning→impl │ │
|
||
│ │ │
|
||
│ agent 14:12 │ │
|
||
│ SegmentStore.append()… │ │
|
||
│ │ │
|
||
│ ─────────────────────── │ │
|
||
│ ▌ Ask anything… │ │
|
||
│ feat/cas-segments · chat │ │
|
||
└──────────────────────────┴───────────────────────────────────┘
|
||
│ ⌨i message ⌨p commands ⌨a approval ⌨e events ⌨Tab panels ⌨F2 skin │ Soft · blue
|
||
└────────────────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### APPROVAL — gate interrupted
|
||
|
||
The horizontal split collapses. The full main area shows the approval surface with tier badge, command preview, risk scan, steering input, and decision buttons.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────┐
|
||
│ ● connected · cas-segment-store · feat/cas-segments │
|
||
│ qwen_coder_14b (local) ctx ████████░░ 64% ⏸ awaiting│
|
||
├──────────────────────────────────────────────────────────────┤
|
||
│ ┌─ approval ────────────────────────────────────────────┐ │
|
||
│ │ T3 Approval required · external / network │ │
|
||
│ │ Resolve a new dependency over the network │ │
|
||
│ │ paused │ │
|
||
│ │ │ │
|
||
│ │ $ ./gradlew :segment-store:dependencies │ │
|
||
│ │ │ │
|
||
│ │ Adds com.github.luben:zstd-jni:1.5.6-3 for cold- │ │
|
||
│ │ segment compression. Touches Maven Central. │ │
|
||
│ │ │ │
|
||
│ │ tool shell T3 │ │
|
||
│ │ reversible no │ │
|
||
│ │ policy stages.implementation.approvals.tool=req │ │
|
||
│ │ │ │
|
||
│ │ SEMANTIC RISK SCAN │ │
|
||
│ │ ▲ Network egress to repo1.maven.org │ │
|
||
│ │ ▲ Mutates gradle.lockfile │ │
|
||
│ │ ▲ New transitive: org.lz4? (none detected) │ │
|
||
│ │ │ │
|
||
│ │ ↳ ok, but lock the version_________________ │ │
|
||
│ │ │ │
|
||
│ │ [approve a] [auto-approve A] [steer s] [reject r] │ │
|
||
│ └───────────────────────────────────────────────────────┘ │
|
||
├──────────────────────────────────────────────────────────────┤
|
||
│ ⌨a approve ⌨A auto-session ⌨s steer ⌨r reject ⌨esc later │ Soft · blue
|
||
└──────────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Footer bar — contextual keybinds
|
||
|
||
| Screen | Hints shown |
|
||
|--------|-------------|
|
||
| IDLE | `i` message · `p` commands · `a` approval · `e` events · `F2` skin |
|
||
| IN_SESSION | above + `Tab` panels · `↑↓` history · `l` back |
|
||
| APPROVAL | `a` approve · `A` auto · `s` steer · `r` reject · `esc` later |
|
||
|
||
Right-aligned mode indicator always reads `Soft · blue`.
|
||
|
||
---
|
||
|
||
## 3. Animation & Microfeedback
|
||
|
||
- **Spinner** — `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏` cycles at ~110ms. Seen next to "live" in event stream header, next to pending events, next to "paused" during approval.
|
||
- **Streaming cursor** — block `█` blinks at end of in-progress agent message. 50% opacity blink.
|
||
- **Toasts** — brief floating confirmations: "Approved", "Rejected", "Model switched". Appear near bottom center, auto-dismiss ~2.6s.
|
||
- **Panel transitions** — active panel border highlight shifts when switching focus with `Tab`.
|
||
|
||
---
|
||
|
||
# BUILD PLAN
|
||
|
||
---
|
||
|
||
## Phase 1 — Theming System
|
||
|
||
### File: NEW `components/Theme.kt`
|
||
|
||
Centralize all color and style constants into a single `object Theme` so every widget references the same palette. This eliminates the current pattern of scattered `Style.create().blue()` / `.cyan()` / `.gray()` calls.
|
||
|
||
```kotlin
|
||
object Theme {
|
||
// Surfaces
|
||
val bg: Color // xterm 233 (#14161a)
|
||
val bgDeep: Color // xterm 232 (#0f1115)
|
||
val panel: Color // xterm 234 (#181b21)
|
||
val panel2: Color // xterm 235 (#1f232b)
|
||
|
||
// Text
|
||
val fg: Color // xterm 252 (#ced3da)
|
||
val fgStrong: Color // xterm 255 (#eef1f5)
|
||
val dim: Color // xterm 243 (#838b96)
|
||
val faint: Color // xterm 238 (#434a55)
|
||
|
||
// Accent
|
||
val accent: Color // #4a9eff (blue)
|
||
val accent2: Color // #7aa2f7 (purple-blue)
|
||
|
||
// Semantic
|
||
val ok: Color // green
|
||
val warn: Color // amber
|
||
val bad: Color // red
|
||
|
||
// Border / selection
|
||
val border: Color // xterm 236 (#262b33)
|
||
val sel: Color // xterm 235+ (#21262e)
|
||
|
||
// Pre-built Style objects
|
||
val dimStyle: Style
|
||
val accentStyle: Style
|
||
val okStyle: Style
|
||
val warnStyle: Style
|
||
val badStyle: Style
|
||
val fgStrongStyle: Style
|
||
|
||
// Event category → color
|
||
fun categoryColor(category: String): Color
|
||
}
|
||
```
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Create `Theme.kt` in `components/`
|
||
- [ ] Define all Color constants (xterm or rgb depending on Mordant 2.6 API)
|
||
- [ ] Define pre-built Style objects for common patterns
|
||
- [ ] Define categoryColor() mapping (Lifecycle→accent2, Context→purple, Inference→accent, Tool→ok, Domain→amber, Approval→warn)
|
||
- [ ] Replace all hardcoded `.blue()`, `.cyan()`, `.gray()`, `.green()`, `.yellow()`, `.red()` calls across all existing components with Theme.* references
|
||
|
||
---
|
||
|
||
## Phase 2 — Layout: Three-Row Grid + Horizontal Split
|
||
|
||
### File modified: `TuiApp.kt`
|
||
|
||
**Current layout** (vertical stack for all display states):
|
||
|
||
```
|
||
StatusBar (height=1)
|
||
SessionList (height=min(count,7)+2)
|
||
[WorkflowList (height=6 if visible)]
|
||
[EventHistoryStrip (height=6 if visible)]
|
||
RouterPanel (fill)
|
||
InputBar (height=4)
|
||
```
|
||
|
||
**Target layout** — 3-row grid for all states:
|
||
|
||
```
|
||
grid rows: [status bar (length=1)] [main area (fill)] [footer bar (length=1)]
|
||
|
||
main area: horizontal split [left panel (ratio 1.7)] [right panel (ratio 1.0)]
|
||
```
|
||
|
||
Which widgets fill the panels depends on display state:
|
||
|
||
| State | Left panel (1.7) | Right panel (1.0) |
|
||
|-------|------------------|-------------------|
|
||
| IDLE | SessionList + WorkflowPicker | WelcomePanel |
|
||
| IN_SESSION | RouterPanel | EventStreamPanel |
|
||
| APPROVAL | ApprovalSurface (full width, no split) | — |
|
||
|
||
The input bar moves from being a top-level row **into the left panel's footer** (matching the reference's `Panel.footer` slot). This means each left-panel component is responsible for rendering its own footer containing the input bar.
|
||
|
||
### Layout code pattern
|
||
|
||
```kotlin
|
||
private fun renderInSessionLayout(frame: Frame, state: TuiState) {
|
||
val area = frame.area()
|
||
val vertRects = Layout.vertical()
|
||
.constraints(
|
||
Constraint.length(STATUS_HEIGHT),
|
||
Constraint.fill(), // main area
|
||
Constraint.length(FOOTER_HEIGHT),
|
||
)
|
||
.split(area)
|
||
|
||
val mainRects = Layout.horizontal()
|
||
.constraints(Constraint.ratio(1.7f), Constraint.ratio(1.0f))
|
||
.split(vertRects[1])
|
||
|
||
frame.renderWidget(statusBarWidget(state), vertRects[0])
|
||
frame.renderWidget(routerPanelWidget(state), mainRects[0]) // InputBar inside
|
||
frame.renderWidget(eventStreamPanelWidget(state), mainRects[1])
|
||
frame.renderWidget(footerBarWidget(state), vertRects[2])
|
||
}
|
||
```
|
||
|
||
### InputBar as panel footer
|
||
|
||
Each left-panel widget (RouterPanel, SessionListPanel) renders its own vertical stack:
|
||
- Top: [messages / session rows] (fill)
|
||
- Bottom: [InputBar] (fixed height)
|
||
|
||
This can be done by splitting the panel's allocated rect into two sub-rects, or combining both into a single Paragraph with a separator.
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Import `Layout.horizontal()` in `TuiApp.kt`
|
||
- [ ] IN_SESSION: 3-row grid with horizontal split (RouterPanel 1.7 + EventStreamPanel 1.0)
|
||
- [ ] IDLE: same grid but left = SessionList, right = WelcomePanel
|
||
- [ ] APPROVAL: full-width single column in main area
|
||
- [ ] Move InputBar from top-level widget to left panel footer
|
||
- [ ] Add footer bar rendering as grid row 3
|
||
|
||
---
|
||
|
||
## Phase 3 — Status Bar Polish
|
||
|
||
### File modified: `components/StatusBar.kt`
|
||
|
||
Upgrade from a simple connection+model line to the full reference `crx-top`:
|
||
|
||
```
|
||
● connected · cas-segment-store · feat/cas-segments · qwen_coder_14b (local) ctx ████████░░ 64% ▸ active
|
||
```
|
||
|
||
Segments (separated by `·`):
|
||
1. **Connection** — `●` (green) / `○` (red) + connected/disconnected
|
||
2. **Session name** — bold (shown in IN_SESSION / APPROVAL)
|
||
3. **Branch / workflow ID** — dim
|
||
4. **Model** — accent color + provider label
|
||
5. **Context meter** — bar with accent fill on faint track + percentage
|
||
6. **State badge** — pill: `▸ active` (green) or `⏸ awaiting approval` (amber)
|
||
7. **Background badge** — `+N updated` (dim yellow, shown when backgroundUpdateCount > 0)
|
||
|
||
### Context meter
|
||
|
||
Requires `contextUsed` and `contextBudget` in TuiState. Render as:
|
||
|
||
```
|
||
ctx [████████░░] 64%
|
||
```
|
||
|
||
Filled portion in accent color, empty portion in faint color.
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Add `contextUsed: Int?` and `contextBudget: Int?` to `TuiState`
|
||
- [ ] Replace current status bar spans with Theme references
|
||
- [ ] Add brand text with accented `x` (`corre` + `x`)
|
||
- [ ] Add session name + branch with `·` separators
|
||
- [ ] Add model + provider display
|
||
- [ ] Implement context meter bar (accent-fill on faint track)
|
||
- [ ] Implement state badge pill (warn for awaiting, ok for active)
|
||
- [ ] Keep background update badge, style with Theme.dim/yellow
|
||
|
||
---
|
||
|
||
## Phase 4 — Event Stream Panel
|
||
|
||
### File: NEW `components/EventStreamPanel.kt`
|
||
|
||
The right column in IN_SESSION state. Structured event list replacing the current raw-text `EventHistoryStrip`.
|
||
|
||
### Event row format
|
||
|
||
```
|
||
14:11:02 [Lifecycle] stage.enter implementation (role=coder)
|
||
14:11:19 [Tool] fs.write SegmentStore.kt (+212)
|
||
14:12:02 [Approval] approval.raised T3 · gradle network resolve ⠋[a]
|
||
```
|
||
|
||
Each row:
|
||
1. **Timestamp** — dim, fixed-width
|
||
2. **Category badge** — colored pill (see categoryColor mapping)
|
||
3. **Type** — bold/bright
|
||
4. **Detail** — normal text, truncated if long
|
||
5. **Pending indicator** — spinner + `[a]` keybind hint for pending approvals
|
||
|
||
Panel header shows:
|
||
```
|
||
event stream ◌ live
|
||
```
|
||
Or if session has pending approval:
|
||
```
|
||
event stream ⠋ paused
|
||
```
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Create `EventStreamPanel.kt` in `components/`
|
||
- [ ] Implement event row rendering with all 5 columns
|
||
- [ ] Wire categoryColor() into badge rendering
|
||
- [ ] Add pending event indicator (spinner + `[a]` hint)
|
||
- [ ] Add "live" / "paused" indicator in panel header
|
||
- [ ] Wire into TuiApp.kt as right column in IN_SESSION layout
|
||
|
||
---
|
||
|
||
## Phase 5 — Footer Keybind Bar
|
||
|
||
### File: NEW `components/FooterBar.kt`
|
||
|
||
Dedicated bottom row showing contextual keybind hints and current mode indicator. Currently these hints are embedded in InputBar row2 — they move here instead.
|
||
|
||
### Contextual hints
|
||
|
||
| State | Hints |
|
||
|-------|-------|
|
||
| IDLE | `i` message · `p` commands · `a` approval · `e` events · `F2` skin |
|
||
| IN_SESSION | above + `Tab` panels · `↑↓` history · `l` back |
|
||
| APPROVAL | `a` approve · `A` auto · `s` steer · `r` reject · `esc` later |
|
||
|
||
### Keybind chip pattern
|
||
|
||
```
|
||
i message p commands a approval
|
||
```
|
||
Key in white-on-blue (accent background, reversed), label in dim text.
|
||
|
||
### Mode indicator
|
||
|
||
Right-aligned: `Soft · blue`
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Create `FooterBar.kt` in `components/`
|
||
- [ ] Implement contextual hint logic based on display state / input mode / overlay
|
||
- [ ] Add mode indicator (right-aligned)
|
||
- [ ] Wire into TuiApp.kt as `Constraint.length(1)` in grid row 3
|
||
- [ ] Remove all key hint spans from InputBar row2 (keep only session name, chat mode)
|
||
|
||
---
|
||
|
||
## Phase 6 — Welcome Panel (IDLE Right Column)
|
||
|
||
### File: NEW `components/WelcomePanel.kt`
|
||
|
||
The right column in IDLE state. Shows contextual info when no session is active:
|
||
|
||
- Brand header (`Correx Agent Harness`) with accented `x`
|
||
- Brief contextual prompt ("select a session or type a name")
|
||
- Recent activity list (completed/active sessions with timestamps + status glyphs)
|
||
- Connection status hint if disconnected
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Create `WelcomePanel.kt` in `components/`
|
||
- [ ] Show brand header with accented `x`
|
||
- [ ] Show contextual prompt text
|
||
- [ ] Show recent sessions (if available) or empty-state message
|
||
- [ ] Use Theme colors throughout
|
||
|
||
---
|
||
|
||
## Phase 7 — Font Size 14-15
|
||
|
||
Terminal font size is emulator-controlled, not app-controlled. What we can do:
|
||
|
||
1. Review all MAX constants for readability at 14pt:
|
||
- `NAME_MAX = 15` → may need adjustment
|
||
- `DETAIL_MAX = 60` → review
|
||
- `DIFF_LINE_MAX_LENGTH = 100` → may need decrease
|
||
- `MAX_VISIBLE = 7` → may need decrease (fewer rows fit)
|
||
|
||
2. Add `Theme.fontSize: Int = 14` as documentation / scaling factor for layout constants.
|
||
|
||
3. If Mordant `Style.Builder` exposes size (needs verification), apply it.
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Add `Theme.fontSize` constant
|
||
- [ ] Review and adjust truncation/visibility constants
|
||
- [ ] Verify row estimates fit within target terminal sizes
|
||
|
||
---
|
||
|
||
## Phase 8 — Approval Surface Polish
|
||
|
||
### File modified: `components/ApprovalSurface.kt`
|
||
|
||
Already the most polished component, needs theme integration:
|
||
|
||
- Replace `Color.YELLOW` border with `Theme.warn`
|
||
- Replace hardcoded `.green()`, `.red()`, `.yellow()`, `.gray()` with Theme.*
|
||
- Tier badge → `Theme.pill()` pattern
|
||
- Risk scan section → `▲` prefix in amber (matching reference `.risk` class)
|
||
- Key hint bar → `Theme.dimStyle` with framed key labels
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Replace all hardcoded color calls with Theme references
|
||
- [ ] Replace `Color.YELLOW` border with `Theme.warn`
|
||
- [ ] Align risk section formatting with reference
|
||
|
||
---
|
||
|
||
## Phase 9 — Session List & Workflow List Polish
|
||
|
||
### Files: `SessionList.kt`, `WorkflowListPanel.kt`
|
||
|
||
Color substitution — these already use ROUNDED borders:
|
||
|
||
- `▶` prefix → `Theme.accent` (was `.blue()`)
|
||
- Names → `Theme.fgStrong` (was `.cyan()`)
|
||
- Status labels → `Theme.ok`, `Theme.warn`, `Theme.bad`
|
||
- Overflow / empty text → `Theme.dim`
|
||
- Borders → `Theme.border`
|
||
|
||
### Implementation Checklist
|
||
|
||
- [ ] Replace all hardcoded color calls with Theme references in SessionList.kt
|
||
- [ ] Replace all hardcoded color calls with Theme references in WorkflowListPanel.kt
|
||
|
||
---
|
||
|
||
# APPENDICES
|
||
|
||
---
|
||
|
||
## A. Color Reference
|
||
|
||
### Palette
|
||
|
||
| Token | Hex | ANSI | Use |
|
||
|-------|-----|------|-----|
|
||
| `bg` | `#14161a` | xterm 233 | Screen background |
|
||
| `bgDeep` | `#0f1115` | xterm 232 | Top/footer bar |
|
||
| `panel` | `#181b21` | xterm 234 | Panel surface |
|
||
| `panel2` | `#1f232b` | xterm 235 | Secondary surface |
|
||
| `fg` | `#ced3da` | xterm 252 | Body text |
|
||
| `fgStrong` | `#eef1f5` | xterm 255 | Headings, emphasis |
|
||
| `dim` | `#838b96` | xterm 243 | Muted text |
|
||
| `faint` | `#434a55` | xterm 238 | Borders, placeholders |
|
||
| `border` | `#262b33` | xterm 236 | Panel borders |
|
||
| `sel` | `#21262e` | xterm 235+ | Selection highlight |
|
||
| `accent` | `#4a9eff` | rgb(74,158,255) | Blue accent |
|
||
| `accent2` | `#7aa2f7` | rgb(122,162,247) | Purple-blue secondary |
|
||
| `ok` | `#7fd88f` | rgb(127,216,143) | Success |
|
||
| `warn` | `#e8c06a` | rgb(232,192,106) | Warning |
|
||
| `bad` | `#e87f7f` | rgb(232,127,127) | Error |
|
||
|
||
### Event category → color
|
||
|
||
| Category | Color | Hex |
|
||
|----------|-------|-----|
|
||
| Lifecycle | accent2 | `#7aa2f7` |
|
||
| Context | purple | `#c98fd9` |
|
||
| Inference | accent | `#4a9eff` |
|
||
| Tool | ok | `#7fd88f` |
|
||
| Domain | amber | `#e8b765` |
|
||
| Approval | warn | `#e8c06a` |
|
||
|
||
---
|
||
|
||
## B. Keybind Reference
|
||
|
||
| Key | Context | Action |
|
||
|-----|---------|--------|
|
||
| `↑↓` | Session list | Navigate sessions |
|
||
| `↑↓` | Input mode (IN_SESSION) | History navigation |
|
||
| `Enter` | Session list | Enter selected session |
|
||
| `Enter` | Input bar | Submit message / start session |
|
||
| `Tab` | Any | Toggle filter mode / focus panel |
|
||
| `i` | No overlay | Focus input bar |
|
||
| `p`, `/`, `:` | No overlay | Open command palette |
|
||
| `a` | No overlay | Open pending approval |
|
||
| `e` | No overlay | Open event inspector overlay |
|
||
| `c` | No overlay | Open context pack inspector |
|
||
| `g` | No overlay | Open stage graph |
|
||
| `m` | No overlay | Open model registry |
|
||
| `t` | No overlay | Open tool palette |
|
||
| `a` | Approval | Approve |
|
||
| `A` | Approval | Auto-approve session |
|
||
| `s` | Approval | Steer + approve |
|
||
| `r` | Approval | Reject |
|
||
| `ctrl+a` | Approval | Approve (alt) |
|
||
| `ctrl+r` | Approval | Reject (alt) |
|
||
| `ctrl+e` | Any | Toggle event strip |
|
||
| `ctrl+n` | IDLE | Start new session |
|
||
| `ctrl+l` | IN_SESSION | Return to session list |
|
||
| `ctrl+q` | Any | Quit |
|
||
| `ctrl+x` | Approval | Toggle diff expand |
|
||
| `F2` | Any | Cycle chrome direction |
|
||
| `F3` | Any | Cycle accent color |
|
||
| `Escape` | Overlay | Close overlay |
|
||
| `Escape` | Input focus | Blur input |
|
||
|
||
---
|
||
|
||
## C. State Changes
|
||
|
||
### TuiState additions
|
||
|
||
```kotlin
|
||
data class TuiState(
|
||
// ... existing fields ...
|
||
val contextUsed: Int? = null,
|
||
val contextBudget: Int? = null,
|
||
val eventStreamExpanded: Boolean = false,
|
||
)
|
||
```
|
||
|
||
`contextUsed` / `contextBudget` feed the context meter. Populated from `ServerMessage` snapshot data during snapshot phase.
|
||
|
||
---
|
||
|
||
## D. Implementation Order
|
||
|
||
| Phase | Files | Dependencies | Effort |
|
||
|-------|-------|-------------|--------|
|
||
| **1. Theme** | `Theme.kt` (new) | None | Medium |
|
||
| **2. Layout** | `TuiApp.kt`, left panel components | Phase 1 | Large |
|
||
| **3. Status bar** | `StatusBar.kt`, `TuiState.kt` | Phase 1 | Medium |
|
||
| **4. Event stream** | `EventStreamPanel.kt` (new) | Phase 1, Phase 2 | Medium |
|
||
| **5. Footer bar** | `FooterBar.kt` (new), `InputBar.kt` | Phase 1, Phase 2 | Small |
|
||
| **6. Welcome panel** | `WelcomePanel.kt` (new) | Phase 1, Phase 2 | Small |
|
||
| **7. Font** | `Theme.kt` (amend), constants review | Phase 1 | Small |
|
||
| **8. Approval** | `ApprovalSurface.kt` | Phase 1 | Small |
|
||
| **9. List polish** | `SessionList.kt`, `WorkflowListPanel.kt` | Phase 1 | Small |
|
||
|
||
---
|
||
|
||
## E. Constraints & Risks
|
||
|
||
1. **Mordant Color API**: `Color.rgb(r, g, b)` depends on Mordant 2.6.0. If unavailable, fall back to `Color.xterm(n)` for closest ANSI color. Verify during Phase 1.
|
||
2. **Horizontal split**: `Layout.horizontal()` is part of Tambouille 0.3.0 (currently used in build.gradle). If unavailable, simulate with two-column Paragraph or verify API existence before Phase 2.
|
||
3. **Context meter**: Requires upstream data (context used/budget) that may not be in current server protocol. May need to stub until data arrives.
|
||
4. **Interactive event clicks**: Tambouille supports widget click callbacks. Event row selection can be added if interactivity is needed.
|