add opus

ober

779a600f908737f41904d052d1266a4dce2b51c1

diff --git a/opus-plan.md b/opus-plan.md
new file mode 100644
index 0000000..78b3df3
--- /dev/null
+++ b/opus-plan.md
@@ -0,0 +1,467 @@
+# jcode → opencode UX Parity — Plan v2
+
+**Date:** 2026-05-05
+**Goal:** Mirror the genuinely-useful UX patterns from opencode, adapted to jcode's
+Scheme + termbox2 stack. Parity by deliberate translation, not by line-by-line copy.
+**Reference:** `~/mine/opencode/packages/opencode/src/cli/cmd/tui/`
+
+---
+
+## Premise
+
+opencode has a polished TUI. Some of that polish is foundational (theme system depth,
+message visual hierarchy, ephemeral feedback). Some of it is chrome (logo, rotating
+tips, agent-colored accents). A good parity plan distinguishes between the two and
+sequences foundations before features.
+
+This plan is that pass over `qwen-plan.md`. Same goal, different sequencing, harsher
+choices about what tree-sitter-shaped things are worth building.
+
+---
+
+## What opencode does, ranked by actual UX value
+
+| Pattern | Value | Verdict |
+|---------|-------|---------|
+| Colored left borders on messages | Real (P1: messages blur in long sessions) | **Mirror** |
+| Toast notifications for ephemeral state | Real (P2: silent state changes confuse) | **Mirror** |
+| Syntax highlighting in code blocks | Real (P3: walls of green) | **Mirror, lightweight** |
+| Theme variety + custom theme JSON | Real (P4: users have strong preferences) | **Mirror** |
+| Stacked dialog system | Real for permission flows | **Mirror** |
+| Dimmed thinking display | Real with reasoning models | **Mirror** |
+| Auto dark/light detection | Real (config friction) | **Mirror** |
+| Command palette (Ctrl+K) | Real for power users | **Mirror** |
+| Leader-key chords | Real for vim users | **Mirror** |
+| ASCII logo + home screen | Aesthetic (visual identity) | **Mirror, minimal** |
+| Mouse text selection | Real (table stakes in 2026) | **Mirror** |
+| Agent-colored accent | Aesthetic | **Defer** — interacts badly with Chez parameter inheritance (see risks) |
+| Session timeline / fork UI | Niche | **Defer** — no observed demand |
+| Richer sidebar (file tree, MCP, LSP) | Real, but coupled to other work | **Defer** — fold in with each integration, not as UI exercise |
+| Plugin UI slots | Speculative | **Defer** — no plugins exist yet |
+| Client/server split | Architectural | **Out of scope** — separate decision |
+
+---
+
+## Sequencing principle: foundations before features
+
+Order matters because later items depend on earlier ones. Specifically:
+
+- **Face slots first**: every theme, toast, thinking block, and syntax token resolves
+  through the face system. Adding a slot retroactively means every theme has to gain
+  it. Front-load this.
+- **Theme JSON loader before themes**: each new theme is ~150 lines of Scheme or one
+  JSON file. Build the loader, then drop in JSON files.
+- **Stacked dialogs before command palette**: the palette renders as a dialog.
+- **Borders before logo**: borders set the visual language for messages; logo is
+  pure intro chrome that follows.
+
+`qwen-plan.md` ordered by perceived effort. This plan orders by dependency.
+
+---
+
+## Phase 1 — Foundation (≈2 weeks)
+
+Nothing user-visible blocks on these in isolation, but everything else needs them.
+
+### 1.1 Expand face system
+
+**File:** `src/jcode/ui/tui-theme.ss`
+**Effort:** ~200 LOC across all 3 existing themes
+
+Add the slots that later phases will use, applied to dark/light/gruvbox in one pass:
+
+```
+;; Toast (Phase 2.1)
+toast-error-border  toast-warning-border  toast-success-border  toast-info-border
+toast-bg            toast-title           toast-message
+
+;; Thinking (Phase 2.4)
+thinking-text       thinking-border       thinking-header
+
+;; Syntax (Phase 2.2)
+syntax-comment      syntax-keyword        syntax-function       syntax-variable
+syntax-string       syntax-number         syntax-type           syntax-operator
+syntax-punctuation
+
+;; Selection (Phase 3.5)
+selection-bg
+
+;; Leader / palette (Phase 3.2, 3.3)
+leader-indicator    leader-dim
+palette-match       palette-keybind       palette-category
+
+;; Home (Phase 3.1)
+home-logo-fg        home-logo-shadow      home-tip-text         home-tip-icon
+
+;; Borders (Phase 1.2)
+msg-border-user     msg-border-assistant  msg-border-tool       msg-border-error
+```
+
+This is mechanical and repetitive. Do it in one go, not piecemeal.
+
+### 1.2 Colored left borders on message blocks
+
+**File:** `src/jcode/ui/tui-message.ss`
+**Effort:** ~50 LOC
+
+In `render-msg-block!`: before rendering content, draw a 1-cell vertical border
+from `y` to `y + height - 1` at column `x - 1`, using `tb-change-cell!` to set
+fg/bg from the role-appropriate `msg-border-*` face. Shift content right by 2
+columns (1 border + 1 padding).
+
+This is the single highest signal-to-LOC visual change in the plan. Ship it
+early; subsequent items build on the visual language it establishes.
+
+### 1.3 opencode-compatible theme JSON loader
+
+**File:** `src/jcode/ui/tui-theme.ss` (extend), `src/jcode/core/config.ss`
+**Effort:** ~150 LOC
+
+Parse opencode's `{ "$schema", "defs", "theme" }` schema. Resolve `defs`, then
+walk `theme` slots. For slots with `{ "dark": ..., "light": ... }` variants,
+emit two jcode themes (`name-dark`, `name-light`) so users get both.
+
+Use the slot mapping table in the appendix below. Imports `(std text json)` —
+pattern is already established elsewhere in the codebase.
+
+Scan `~/.jcode/themes/*.json` and `./.jcode/themes/*.json` at startup. Register
+loaded themes alongside built-ins.
+
+### 1.4 Import 8 themes from opencode
+
+**Files:** drop into `themes/` directory (new); register at startup
+**Effort:** ~50 LOC for the registration; theme content is JSON files copied verbatim
+
+Pull these from `~/mine/opencode/.../context/theme/` — most-requested first:
+
+- dracula
+- catppuccin (becomes catppuccin-mocha + catppuccin-latte via dark/light split)
+- tokyonight (becomes tokyonight + tokyonight-day)
+- nord
+- gruvbox (already have ours, but theirs may differ — compare)
+- monokai
+
+Eight themes ≠ thirty. Eight covers ~90% of the "I want my favorite theme"
+audience without bloating the binary.
+
+---
+
+## Phase 2 — Visible UX patterns (≈3 weeks)
+
+What users will actually notice. Foundation from Phase 1 makes each of these
+small.
+
+### 2.1 Toast notifications
+
+**File:** new `src/jcode/ui/tui-toast.ss`, modified `src/jcode/ui/tui.ss`
+**Effort:** ~200 LOC
+
+```scheme
+(defstruct toast (variant title message dismiss-at))
+```
+
+State on the app: a list of active toasts. Render top-right at
+`(width - toast-width - 2, 2 + offset)` per toast, stacked downward. 3s default
+auto-dismiss. Any keypress dismisses the oldest. Variant maps to
+`toast-{error,warning,success,info}-border`.
+
+Wire to:
+- agent errors (currently silent or end up in message thread)
+- `/save` and session checkpoints
+- theme switch confirmation
+- config reload
+- tool completion when long-running (>5s)
+
+**Pitfall:** toasts run a dismiss timer on a green thread. Capture and
+re-parameterize `current-error-port` and `log-level` per
+`feedback_chez_parameter_thread_inheritance.md` or the toast thread will
+deadlock the log mutex.
+
+### 2.2 Lightweight syntax highlighting
+
+**File:** new `src/jcode/ui/tui-syntax.ss`, modified `src/jcode/ui/tui-markdown.ss`
+**Effort:** ~300 LOC
+
+Per-language tokenizers (regex-based). Languages, in priority order:
+
+1. **scheme** — we're a Scheme tool, our own code blocks should look right
+2. **bash** — agent runs lots of shell
+3. **python** — common request language
+4. **javascript / typescript** — same
+5. **json** — config files
+6. **rust, go, c** — fill out the long tail
+
+Each tokenizer is a list of `(regex face-name)` pairs scanned in order, longest
+match wins. Tokens map to `syntax-*` faces.
+
+**Why not tree-sitter:**
+- FFI to a C++ library, with parser binaries per language
+- Blocking parse calls would need `__collect_safe` declarations
+  (`feedback_ffi_collect_safe.md`)
+- Streaming code blocks during LLM output would need incremental reparsing
+- Maintenance: tree-sitter parsers change; we'd track upstream forever
+- Accuracy advantage over keyword scanning is marginal for short code blocks
+
+Approach 2 from `qwen-plan.md` was right; "Approach 1" was a footnote that should
+have been the recommendation.
+
+### 2.3 Stacked dialog system
+
+**File:** `src/jcode/ui/tui-dialog.ss`
+**Effort:** ~150 LOC modified
+
+```scheme
+(defstruct dialog-stack (dialogs backdrop?))
+```
+
+Replace single active dialog with a stack. Push opens, Escape pops. Backdrop is
+a one-pass overlay rendering `░` characters with dimmed fg over the entire
+non-dialog screen, then the top dialog at full brightness.
+
+Slight visual offset for stacked dialogs (1-2 cells down/right per layer) so
+the stack is visible.
+
+Enables: permission prompt → confirmation → result alert without losing the
+parent. Also a prerequisite for the command palette in 3.2.
+
+### 2.4 Dimmed thinking display
+
+**File:** `src/jcode/ui/tui-message.ss`, `src/jcode/ui/tui-markdown.ss`
+**Effort:** ~80 LOC
+
+Detect thinking content from provider metadata (Anthropic extended thinking,
+or `<thinking>` tags from other providers). Render the block with:
+
+- `thinking-text` face (dim + italic)
+- `thinking-border` left border (muted)
+- Header line `⚙ Thinking…` collapsed by default; expand on click/keypress
+- Show elapsed time when collapsed
+
+Faces already added in 1.1, so this is just rendering logic.
+
+---
+
+## Phase 3 — Power features (≈4 weeks)
+
+Items individual users will love but aren't universal needs.
+
+### 3.1 Home screen + ASCII logo
+
+**Files:** new `src/jcode/ui/tui-home.ss`, new `src/jcode/ui/tui-logo.ss`
+**Effort:** ~250 LOC total
+
+Half-block logo using `▀` (U+2580): fg = letter color, bg = shadow tint. One
+ASCII grid for the left half (shadow), one for the right (bold). Render with
+`tb-change-cell!` per glyph.
+
+Logo design: "jcode" in 4-row half-block typography. Small (≤40 cols wide) so
+it works on narrow terminals. Skip rendering on terminals <60 cols.
+
+Home screen layout:
+```
+         [ logo ]
+
+   ┌─────────────────────────┐
+   │ > Try a TODO…           │
+   └─────────────────────────┘
+
+   💡 Press Ctrl+B to toggle the sidebar
+```
+
+Tip rotates every 8s through ~6 messages (sidebar, /help, theme cycle, multi-line
+input, plan/build mode, scrolling).
+
+State: add `home?` to app-state. True when message list is empty. Transition
+to session view on first message submit.
+
+### 3.2 Command palette (Ctrl+K)
+
+**File:** new `src/jcode/ui/tui-command-palette.ss`, modified `src/jcode/ui/tui-keys.ss`
+**Effort:** ~300 LOC
+
+Renders as a dialog (uses the stack from 2.3). Fuzzy match across:
+
+- Slash commands (existing registry — reuse, don't duplicate)
+- Config toggles (`/sidebar`, `/theme`, `/display thinking`)
+- Session ops (`/session new|list|rename`)
+- Models, agents
+
+Categorized rendering. Keybind on right side of each entry. Recent/frecency
+ranking at top.
+
+Critical: this must be a *view* over the existing slash command registry, not
+a parallel data source. Discoverability is a UI concern, not a data concern.
+
+### 3.3 Leader-key chord system
+
+**File:** `src/jcode/ui/tui-keys.ss`
+**Effort:** ~200 LOC
+
+Default leader: Space. 2s chord window. Indicator shown in status bar during
+the window. ESC or timeout cancels.
+
+Bindings tree:
+
+```
+<leader> s n  → /session new
+<leader> s l  → /session list
+<leader> m c  → /model cycle
+<leader> a c  → /agent cycle
+<leader> t    → /theme cycle
+<leader> b    → /sidebar toggle
+<leader> k    → command palette
+<leader> ?    → leader help overlay
+```
+
+Configurable from `jcode.json`. Implementation: a key-tree walker with state.
+
+**Pitfall:** the 2s timeout runs on a green thread → parameter inheritance
+applies (same as 2.1).
+
+### 3.4 Auto dark/light detection
+
+**File:** `src/jcode/ui/tui.ss`, `src/jcode/ui/tui-theme.ss`
+**Effort:** ~80 LOC
+
+Send `\x1b]11;?\x07` at startup. Read response with a 100ms timeout. Parse
+`rgb:RRRR/GGGG/BBBB` form. Compute luminance, choose variant.
+
+Add `theme: auto` config option. Default off — opt-in only, so it doesn't
+surprise existing users.
+
+### 3.5 Mouse text selection
+
+**File:** `src/jcode/ui/tui.ss`, `src/jcode/ui/tui-ffi.ss`, `src/jcode/ui/tui-message.ss`
+**Effort:** ~250 LOC
+
+termbox2 supports mouse via `TB_INPUT_MOUSE` — we may already enable it for
+wheel scroll. Extend to capture press, drag, release events.
+
+Map screen coordinates to message-thread byte offsets (the existing rendered
+line buffer needs to retain source positions). Highlight selection range with
+`selection-bg`. Copy on Ctrl+C or right-click via OSC 52 (`\x1b]52;c;<base64>\x07`),
+which works in most modern terminals without shell-out to pbcopy/xclip.
+
+Most expensive item in this phase. Schedule last.
+
+---
+
+## Phase 4 — Deferred
+
+Listed for completeness; revisit only on real signal.
+
+- **Agent-colored accent** — every agent switch rebinds a parameter; tied to
+  the parameter-inheritance pitfall. Cute, not worth the stability cost.
+- **Session timeline / fork** — significant new UI, no observed demand.
+- **Richer sidebar panels** — should ship alongside MCP/LSP integration work,
+  not as standalone UI.
+- **Plugin UI slots** — no plugins exist; building a slot framework before
+  there's content to fill it is speculative.
+- **Client/server split** — architectural, separate decision, out of UX scope.
+- **Scroll acceleration** — minor; defer until a user complains.
+
+---
+
+## Codebase-specific risks
+
+Read before starting any item. These have all bitten before, per memory.
+
+1. **`.ss` editing**: ALWAYS use `jerboa_balanced_replace`, ALWAYS run
+   `jerboa_check_balance` after. Never touch `.ss` files with `Edit`.
+2. **Parameter inheritance**: any green thread for timers (toast dismiss,
+   leader timeout, tip rotation, theme watch) must capture
+   `current-error-port` and `log-level` and re-parameterize on the spawned
+   thread. Otherwise the TUI deadlocks the log mutex.
+   Ref: `feedback_chez_parameter_thread_inheritance.md`.
+3. **Plugin boot deps**: every new module added to the binary's import graph
+   must be listed in `build-binary.ss external-libs`. WPO inlining is not
+   enough.
+   Ref: `feedback_chez_plugin_boot_deps.md`.
+4. **Build before commit**: `make binary && ./jcode --help` must succeed
+   before any commit. The user has flagged this 3+ times.
+   Ref: `feedback_always_build_test.md`.
+5. **Forward refs**: jerbuild `.sls` output doesn't tolerate forward
+   references between top-level forms within a file. If a new module starts
+   throwing unbound-identifier errors, check definition order.
+   Ref: `feedback_build_gotchas.md`.
+
+---
+
+## Appendix — opencode → jcode slot mapping
+
+For the JSON loader (1.3). Same content as `qwen-plan.md` but condensed.
+
+```
+opencode                   → jcode face(s)
+─────────────────────────────────────────────────────────────
+primary                    → user-label, input-prompt
+secondary                  → status-mode-plan
+accent                     → spinner, tool-name, heading, status-mode-build
+error                      → error
+warning                    → status-mode-plan, toast-warning-border
+success                    → status-mode-build, toast-success-border
+info                       → tool-name, toast-info-border
+text                       → default, assistant-text, user-text
+textMuted                  → dim, tool-result, status-dim
+background                 → default (bg)
+backgroundPanel            → sidebar-bg, completion-item (bg), toast-bg
+backgroundElement          → completion-selected (bg), code-inline (bg)
+border                     → tool-border, divider, sidebar-divider, msg-border-*
+borderActive               → dialog-border, sidebar-selected (border)
+borderSubtle               → horizontal-rule, blockquote-border, thinking-border
+diffAdded/Removed/Context  → diff-added / diff-removed / diff-context
+diffHunkHeader             → diff-hunk
+markdownHeading            → heading
+markdownLink               → link
+markdownCode               → code-block, code-inline
+markdownBlockQuote         → blockquote
+markdownEmph               → italic
+markdownStrong             → bold
+markdownHorizontalRule     → horizontal-rule
+markdownListItem           → list-bullet
+syntax{Comment,Keyword,…}  → syntax-{comment,keyword,…}
+```
+
+Slots with `{ dark, light }` variants → emit a paired `<theme>-dark` / `<theme>-light`
+in jcode's theme registry, not a single theme that picks one.
+
+---
+
+## File-by-file summary
+
+**New (10 files)**
+- `themes/*.json` — 8 imported theme files
+- `src/jcode/ui/tui-toast.ss`
+- `src/jcode/ui/tui-syntax.ss`
+- `src/jcode/ui/tui-home.ss`
+- `src/jcode/ui/tui-logo.ss`
+- `src/jcode/ui/tui-command-palette.ss`
+
+**Modified**
+- `src/jcode/ui/tui-theme.ss` — face slots, JSON loader (Phase 1.1, 1.3)
+- `src/jcode/ui/tui-message.ss` — borders, thinking display (1.2, 2.4)
+- `src/jcode/ui/tui-markdown.ss` — syntax hookup, thinking blocks (2.2, 2.4)
+- `src/jcode/ui/tui-dialog.ss` — stacked dialogs (2.3)
+- `src/jcode/ui/tui-keys.ss` — leader system, palette keybind (3.2, 3.3)
+- `src/jcode/ui/tui-ffi.ss` — mouse drag events (3.5)
+- `src/jcode/ui/tui.ss` — integration glue throughout
+- `src/jcode/core/config.ss` — theme dir scan, `theme: auto`, leader bindings
+- `build-binary.ss` — register every new module under `external-libs`
+
+---
+
+## Differences from qwen-plan
+
+| | qwen-plan | this plan |
+|---|---|---|
+| Sequencing | By perceived effort | By dependency |
+| Theme expansion | Add 10 themes by hand-coding faces | Add JSON loader, drop in 8 JSON files |
+| Syntax highlighting | Tree-sitter (recommended) + keyword (footnote) | Keyword only; tree-sitter explicitly rejected |
+| Face expansion | Spread across phases as features land | Front-loaded in Phase 1 |
+| Phase 4 (architectural) | Listed with effort estimates | Marked out-of-scope for UX work |
+| Risks section | Absent | Lists the 5 jcode-specific gotchas with memory refs |
+| Agent-colored accent | Phase 3, with code sketch | Deferred — flagged as parameter-inheritance hazard |
+| Logo / home screen | Phase 1 quick win + Phase 2 home | Combined in Phase 3; not a foundation item |
+
+Same destination, but with the work ordered so each item can land cleanly without
+forcing later items to rewrite earlier ones.