Bring the coder-lite TUI to inventoried parity with the TypeScript and Rust coder UIs #117

Closed AtlantisPleb opened this 1d ago 4 comments

Coder-lite is the coder UI users get (#105 consolidated onto it), and it is deliberately thin: crates/coder-lite owns the frame, palette, spinner, system prompt, and session loop, taking openagents-cli as the runtime library. The thinness is right for the runtime seam and currently wrong for the terminal experience: the TypeScript coder UI (packages/openagents-cli/src/coder-ui.ts, ~1,700 lines, plus coder-markdown.ts, coder-plain.ts) and the vendored grok-build engine carry TUI capabilities coder-lite has not absorbed.

This is the first improvement target of the autoimprovement loop (docs/coder/autoimprove.md): make the coder-lite TUI the best terminal surface we have shipped, by porting what earns its place from the Rust and TypeScript versions.

Scope

First, an inventory (best practice V3: parity claims quantify). Enumerate the TUI feature set of the TypeScript coder UI and the vendored grok-build markdown engine, mark each feature ported / deliberately dropped / to-port, and commit the inventory under docs/coder/. Candidates known now:

  • Composer: multi-line editing, prompt history recall, kill/yank, paste handling.
  • Keybindings: the TypeScript binding table (packages/input-bindings where applicable) versus coder-lite's current set.
  • Rendering: streaming markdown is already ported (src/markdown, from grok-build); diff rendering, tool-call collapse/expand, and transcript scrollback are not confirmed.
  • Fleet/delegation display: live child-agent rows during /delegate fan-out.
  • Status: usage bar exists (7ad52a0c8d); thread id, lane, and model surface.

Then port in dependency order, smallest first, one landing per feature group.

Guardrails

  • The runtime boundary stays where Cargo.toml draws it: tools, refusal patterns, composer semantics, lanes, catalog, metering stay in openagents-cli; coder-lite owns presentation and the session loop.
  • Every ported feature lands with a PTY-harness assertion (prerequisite issue) — no TUI feature is done on headless evidence again.
  • Where TypeScript and Rust disagree, the inventory records which behavior wins and why, so the other implementation can be retired knowingly.

Acceptance

  • The committed inventory with per-feature disposition.
  • Each to-port feature either landed with its PTY assertion or re-dispositioned with a reason.
  • pnpm run check green per landing.
  1. AtlantisPleb opened this issue 1d ago
  2. A AtlantisPleb Author 1d ago

    Inventory landed — (3a3f31e8af)

    The first half of this issue is done. The porting half stays open, blocked on #116.

    Counts: 79 feature rows across three implementations. 32 ported · 10 dropped (each with its reason) · 31 to-port · 2 flagged as boundary violations as scoped · 4 recorded as undetermined rather than guessed.

    There are three coder UIs, not two

    coder-lite (3,976 app lines + 24,127 vendored markdown), oa coder in openagents-cli (5,176 TUI-stack lines), and coder-ui.ts (3,862). All three are live. §5 records which behaviour wins per subsystem so the losers can be retired knowingly.

    Five premises in the issue did not survive contact (§2)

    1. The composer arrow points the other way. The TypeScript composer is one flat string (coder-ui.ts:485) with no cursor index variable anywhere in the file. Verified absent: keyboard newline insertion, cursor movement, word-wise editing, ctrl+w/k/y/a/e, forward delete, prompt history of any kind, and Tab completion of any kind. coder-lite has all of it — 22 chords in composer/keys.rs, a 500-entry persisted history, path/command/@-mention completion. Multi-line editing, history recall, and kill are ported, not owed.
    2. "Fixed-row template with fleet/composer/spacer constants" describes coder-ui.ts, not tui.rs. Those constants are at coder-ui.ts:107-176. tui.rs:273-280 is a ratatui Layout with a composer that grows 1..8 rows.
    3. coder-lite is not missing scrollback. scroll_override/scroll_max/effective_scroll/scroll_by at tui.rs:170-390, PageUp/PageDown and Up/Down wired at interactive.rs:457-472.
    4. packages/input-bindings has zero runtime consumers (1,125 lines) and is DOM-shaped — KeyboardEvent.code, mouse buttons, wheel deltas — written for the Autopilot Desktop app deleted on 2026-08-04. Not a source for a terminal binding table.
    5. --offline does not exist in coder-lite. Its parser (main.rs:105-150) takes exactly --help, --version, --dev, --lane, --reasoning. #116 names --offline in its minimum assertions. This blocks #116, so it is item 1 of the ordered list.

    Streaming markdown: 99.8% ported

    20,663 upstream xai-grok-markdown/src lines → 20,699 vendored, 8 of 23 files byte-identical, 596 tests carried. Only three semantic edits exist; everything else is a crate::crate::markdown:: rewrite. Dropped with reasons: mermaid SVG raster (2,170 lines, needs a graphics protocol), benches/fuzz/playgrounds (1,515 lines), footnotes (absent upstream too).

    Top five to-port, in order

    # Item Size Note
    1 --offline on coder-lite S Unblocks #116; the stand-in reply source belongs in openagents-cli (cli.rs:814-832 already has the text)
    2 Live fleet rows during /delegate fan-out M Highest product value, and cheap — see below
    3 Bracketed paste + placeholders + image paste M Today a multi-line paste submits at the first newline: Event::Paste is dropped at interactive.rs:166 and EnableBracketedPaste appears nowhere in crates/
    4 /run under a pseudoterminal L openagents-cli/src/pty.rs is 753 complete lines with 20 tests; this is pane plumbing, not an emulator port
    5 Status bar: model, lane, repo, branch, reasoning, state, elapsed, hints M Five facts the frame already holds are rendered nowhere. ui.reasoning is assigned at interactive.rs:73 and read by nothing at all

    On #2: the machinery already exists and oa delegate already renders from it. ChildEvent (delegate.rs:83-97) and DelegationSupervisor::dispatch_streaming (delegate.rs:387) are both there. coder-lite sees nothing only because fanout_for_tool calls the blocking dispatch() at delegate.rs:1604 and returns one string at the end. Today a 3-way fan-out is one tool box that stays empty until every child finishes.

    Boundary violations flagged rather than scheduled (§7)

    • /goal — a goal store with token budgets is spending policy. The store belongs in openagents-cli; coder-lite renders the row.
    • Image paste — the placeholder token is presentation; MIME sniffing, base64, and the multimodal content-part shape are runtime.

    Two near misses recorded with them (--offline's reply source, /skills' catalog), plus the reasoning for why fleet rows are not a violation: the test is direction. Logic moving into coder-lite is the violation; a fact moving out to be drawn is the boundary working.

    Written against the post-0.0.2 shape — one shipped artifact answering two fronts — which makes the boundary a module seam held by review rather than a binary seam held by a linker. §0 says which parts came from the pre-release tree.

    Recorded as undetermined (§8), not guessed

    Whether coder-lite orphans child processes on exit (settle before the fleet display ships); whether a thread id is reachable by the frame; whether a turn can be cancelled at all (execute_turn is spawned detached with no handle at interactive.rs:517); and whether oa coder's frame has any user after 0.0.2.

    Not closing this — the porting half is outstanding. Each to-port entry in §6 names the PTY assertion that would prove it, so the port can be executed straight from the document once #116 lands.

  3. A AtlantisPleb Author 1d ago

    Correction to the heading above — my shell ate the filename in the first line. The inventory is at:

    docs/coder/2026-08-26-coder-lite-tui-inventory.md, landed in 3a3f31e8af.

    Everything else in that comment is intact.

  4. A AtlantisPleb Author 1d ago

    Claiming this from forge main at b166ba0480. I will reconcile the parity inventory against the current native TUI, implement or explicitly disposition every remaining gap, add PTY coverage for behavior we retain, run the completion gate, and close the issue when the acceptance criteria are met.

  5. A AtlantisPleb Author 1d ago

    Completed on forge main in dd75e29dc6 (WAL receipt 326, link 697fe060a4f538b7eda03105c2f38dbfbf2dce49fec22308818ee9788d342120). The inventory now reconciles all 36 historical to-port rows plus the separately scheduled --offline item: 11 capabilities are retained with current implementation and test evidence, and 26 obsolete, duplicative, or contract-free ports are explicitly dropped with reasons. Removed the unreachable CoderUi.reasoning, CoderUi.running, and test-only Role::Reasoning presentation states. Verification: cargo test -p openagents-cli --test coder_rebase_contract (7 passed), cargo test -p openagents-cli --test coder_interactive_pty (17 passed), focused native Coder tests (652 passed), and the full pnpm run check gate. The full gate passed 115 TypeScript projects, the Rust workspace including 922 CLI unit tests, 2,427 Vite files / 20,775 tests, and 177 Node tests (one platform skip).

  6. closed this as completed 1d ago
Sign in with GitHub to comment on this issue.