feat: remove obsolete design documents for clipboard OSC52, diff view, file mention, context compaction, and add development guide

This commit is contained in:
asepharyana
2026-07-20 14:47:55 +07:00
parent 44c3dd1239
commit 66ac4dbf02
23 changed files with 775 additions and 13170 deletions
+151 -64
View File
@@ -1,79 +1,166 @@
# Frontend (TUI) Architecture
# TUI (Terminal User Interface)
## Render Pipeline
Dibangun di atas **ratatui** + **crossterm**. Kode ada di `apps/interfaces/tui/src/`.
The TUI is built with [ratatui](https://github.com/ratatui-org/ratatui) and [crossterm](https://github.com/crossterm-rs/crossterm).
## Struktur Source
```
Timer tick
main.rs: fn tui_loop()
├── controller/input.rs: handle_key() → action
├── app/runtime/actions/mod.rs: apply_action()
│ │
│ └── state mutates (AppStateRest)
── view/mod.rs: build TUI layout
├── view/chat.rs: Chat transcript
├── view/sidebar.rs: Usage dashboard
├── view/status.rs: Status bar
├── view/markdown.rs: Message renderer
├── view/workflow.rs: Hive-mind progress
└── view/theme.rs: Tokyo Night palette
apps/interfaces/tui/src/
├── run.rs # Event loop utama
├── state.rs # AppStateRest — single source of truth
├── action.rs # apply_action(): satu-satunya mutator state
├── turn.rs # Spawn agent turn di background thread
├── lib.rs # Re-export publik
├── controller/
│ ├── input.rs # Key handler → Vec<Action>
│ └── command.rs # Slash command parser
├── view/
── mod.rs # Layout + pre_render() + draw()
│ ├── chat.rs # Chat transcript panel (dengan display cache)
├── sidebar.rs # Sidebar: workflow, tasks, usage
│ ├── status.rs # Status bar satu baris
├── markdown.rs # Markdown → styled Span (pulldown-cmark)
├── workflow.rs # Workflow/hive-mind progress panel
│ ├── theme.rs # Tokyo Night color palette (const)
│ └── overlays/ # 16 overlay panel
└── model/ # Data model lokal TUI
```
## Overlay System
16 overlays managed by `app/mode/`:
| Overlay | File | Purpose |
|---------|------|---------|
| Chat input | `mod.rs` | Main input bar with autocomplete |
| Bash | `bash.rs` | Interactive shell panel |
| Editor | `editor.rs` | Built-in file editor |
| Effort | `effort.rs` | LLM effort selector |
| Help | `help.rs` | Keybindings help |
| Key Input | `key_input.rs` | Custom key binding |
| Learning | `learning.rs` | Lesson viewer |
| Loading | `loading.rs` | Spinner overlay |
| MCP | `mcp.rs` | MCP server management |
| Quit Confirm | `quit_confirm.rs` | Exit confirmation dialog |
| Rewind | `rewind.rs` | Message/history rewind |
| Settings | `settings.rs` | Settings panel |
| Todo | `todo.rs` | Task/TODO list |
| Workflow | (via view) | Workflow progress |
## Layout Structure
## Render Pipeline (Per Frame)
```
┌─────────────────────────────────────────────┐
│ Status Bar (view/status.rs)
├──────────────────────┬──────────────────────┤
│ │
│ Chat Transcript │ Sidebar │
(view/chat.rs) (view/sidebar.rs) │
│ scrollable, tokens, status, │
inline-log styleagent info │
│ │
├──────────────────────┴──────────────────────┤
│ Input Bar + Autocomplete dropdown │
│ (view/mod.rs) │
└─────────────────────────────────────────────┘
run_loop_inner() [50ms in-flight / 200ms idle]
├── drain expired toasts (1x, bukan 2x)
├── if dirty:
view::pre_render(&mut state) ← update cache (markdown, token count)
terminal.draw(|f| view::draw(f, &state))
state.dirty = false
└── poll events → apply_action → Action::Tick
```
## Input Handling
### Optimasi Performa
`controller/input.rs`:
| Masalah lama | Solusi saat ini |
|---|---|
| `count_tokens` (tiktoken) setiap frame | Cache `cached_token_count`, update hanya saat pesan baru |
| `render_markdown` ulang setiap frame | `display_lines_cache` di `AppStateRest`, rebuild saat `transcript_cache.dirty` |
| `Vec::remove(0)` untuk evict pesan lama | `VecDeque::pop_front()` — O(1) |
| `Mutex<bool>` untuk `turn_in_flight` | `Arc<AtomicBool>` — lock-free |
| Render terus meski idle | Skip `terminal.draw()` jika `dirty == false` |
| Poll 50ms konstan | Adaptif: 50ms saat in-flight, 200ms saat idle |
| `drain_expired_toasts` 2x per iterasi | Sekali saja di `run_loop_inner` |
- Normal mode: keystrokes go to the active overlay
- `@mention` triggers fuzzy autocomplete (via `nucleo-matcher`)
- Tab cycles autocomplete candidates
- `Ctrl+Y` copies selected text to clipboard (via OSC52 escape sequence)
- Arrow keys scroll chat, sidebar, and other scrollable panels
## State (AppStateRest)
`AppStateRest` di `state.rs` adalah satu-satunya sumber kebenaran TUI:
```
AppStateRest {
settings: Settings // provider, model, dll
app_config: AppConfig // endpoint, env vars
workspace_roots: Vec<PathBuf> // working directories
session_dir / session_id // path sesi aktif
memory_dir // direktori memory
session_runtime: Option<SessionRuntime> // history pesan, usage stats
transcript_cache: TranscriptCache // VecDeque<ChatMessageDisplay>
scroll: ScrollState // offset scroll pane chat
input: InputState // buffer, cursor, history, autocomplete
misc: MiscState // overlay aktif, toasts, flags
turn_events: Arc<Mutex<VecDeque<TurnEvent>>> // queue event dari agent
turn_in_flight_flag: Arc<AtomicBool> // apakah agent sedang jalan
abort_flag: Arc<AtomicBool> // sinyal abort oleh user
// Cache performa
display_lines_cache: Vec<Line<'static>> // hasil render markdown
cached_token_count: usize // token count terkini
token_count_dirty: bool // perlu hitung ulang?
last_render_width: u16 // lebar terminal saat render terakhir
dirty: bool // perlu render ulang?
quit: bool // keluar dari loop?
}
```
**Aturan mutasi:**
- Dimutasi hanya dari `action.rs::apply_action()` dan `run.rs` (untuk dirty/quit)
- Semua fungsi `view/*` bersifat read-only terhadap state
- `pre_render_chat()` boleh mutasi hanya field cache (`display_lines_cache`, `cached_token_count`, `token_count_dirty`)
## Input & Actions
`controller/input.rs::handle_key()``Vec<Action>``apply_action(&mut state, action)`
Semua mutasi state melewati satu titik: `apply_action`. Controller tidak tahu *bagaimana* state diubah, hanya *action apa* yang dihasilkan.
### Action Utama
| Action | Efek |
|--------|------|
| `SubmitInput(text)` | Push ke transcript, spawn agent turn |
| `Tick` | Drain `TurnEvent` queue, update state dari hasil agent |
| `ScrollUp/Down` | Ubah `scroll.offset` |
| `OpenOverlay(v)` | Set `misc.overlay = v` |
| `Resize(w, h)` | Invalidasi cache display, set `last_render_width` |
| `AbortTurn` | Store `true` ke `abort_flag` |
| `ForceQuit` | Set `quit = true` |
## Overlays (16 Panel)
| Overlay | File | Fungsi |
|---------|------|--------|
| `Help` | `overlays/help.rs` | Daftar shortcut keyboard |
| `Settings` | `overlays/settings.rs` | Panel pengaturan |
| `Bash` | `overlays/bash.rs` | Background shell jobs |
| `QuitConfirm` | `overlays/quit_confirm.rs` | Konfirmasi keluar |
| `KeyInput` | `overlays/key_input.rs` | Capture key binding |
| `Editor` | `overlays/editor.rs` | File editor inline |
| `Effort` | `overlays/effort.rs` | Pilih level reasoning LLM |
| `Mcp` | `overlays/mcp.rs` | Manajemen MCP server |
| `Todo` | `overlays/todo.rs` | Daftar TODO |
| `Rewind` | `overlays/rewind.rs` | Navigasi history pesan |
| `Learning` | `overlays/learning.rs` | Viewer lesson |
| `Usage` | `overlays/usage.rs` | Statistik token |
| `Loading` | `overlays/loading.rs` | Spinner generik |
| `ModelSelector` | `overlays/model_selector.rs` | Pilih model LLM |
| `ClearConfirm` | `overlays/clear_confirm.rs` | Konfirmasi clear chat |
## Layout Terminal
```
┌───────────────────────────────────────────────┐
│ │
│ Chat Transcript Sidebar (≥90) │
│ (view/chat.rs) ┌────────────┐ │
│ VecDeque messages │ Workflow │ │
│ + markdown cache ├────────────┤ │
│ scrollable │ Tasks │ │
│ ├────────────┤ │
│ │ Usage │ │
│ └────────────┘ │
├───────────────────────────────────────────────┤
Input Bar + Autocomplete dropdown │
├───────────────────────────────────────────────┤
│ ⚡zesdex READY │ ...center... │ tok · model │
└───────────────────────────────────────────────┘
```
Sidebar hanya tampil jika lebar terminal ≥ 90 kolom.
## Theme
`view/theme.rs` defines a Tokyo Night color palette as constants (`Theme::PRIMARY`, `Theme::ERROR`, `Theme::TEXT_MUTED`, etc.) rather than using a theme enum or hot-reloadable config. All view modules import and apply these constants directly.
`view/theme.rs` mendefinisikan palette **Tokyo Night** sebagai `const Color`:
`PRIMARY`, `BG`, `SURFACE`, `SURFACE_ELEVATED`, `BORDER`, `TEXT`, `TEXT_DIM`, `TEXT_MUTED`, `SUCCESS`, `WARNING`, `ERROR`, `INFO`, `HIGHLIGHT`, `CODE_BG`, dll.
## Markdown Rendering
`view/markdown.rs::render_markdown(text, width, dim)`:
- Parse dengan `pulldown-cmark`
- Hasilkan `Vec<Span<'static>>` dengan styling
- Support: heading, code block, diff block (warna +/-/@@), list, blockquote, table, inline code, link
- `dim=true` → semua span memakai `TEXT_DIM` + italic (untuk tool output)
- Hasil di-cache di `AppStateRest::display_lines_cache`