Epic: Ink-based TUI Rewrite for oclite #8307

Closed
opened 2026-02-16 18:09:39 -05:00 by yindo · 2 comments
Owner

Originally created by @randomm on GitHub (Feb 2, 2026).

Originally assigned to: @thdxr on GitHub.

Overview

Replace the current log-update based lite UI with Ink (React for terminals) to solve fundamental rendering issues with concurrent state updates.

Background

The current oclite lite implementation (17 files, ~2,500 lines) has persistent issues:

  • pausedForProse hack prevents live block updates during text streaming to avoid crashes
  • Child session mapping requires complex buffering for out-of-order events
  • State synchronization between SDK events and UI is fragile
  • log-update wasn't designed for this level of complexity

Why Ink?

  1. <Static> component — Renders completed items permanently above dynamic content (exactly what we need)
  2. React reconciler — Multiple state updates batch properly, no need for pausedForProse hacks
  3. useStdout().write() — Can output text without interfering with render cycle
  4. Battle-tested — Claude Code, Gemini CLI, Cloudflare Wrangler all use Ink

Package Versions

Package Version
ink latest stable
react latest stable (required by Ink)
ink-spinner latest stable
ink-text-input latest stable
@types/react latest stable

Scope

In Scope

  • Replace all rendering logic with Ink components
  • Maintain feature parity with current lite functionality
  • SDK event stream integration via React hooks
  • Child session status display (the feature that keeps breaking)

Out of Scope

  • Full opencode TUI feature parity (panels, scrolling, etc.)
  • Web UI
  • Desktop app

Child Issues (Implementation Order)

Phase 1: Setup

  • #11763 - Setup Ink dependencies and verify Bun compatibility (0.5 days)

Phase 2: Core Architecture

  • #11764 - Implement core App component and state management (1.5 days)
  • #11776 - Implement theming system (0.5 days)

Phase 3: Components

  • #11765 - Implement StreamingProse component with markdown (2 days)
  • #11766 - Implement ToolDisplay component (1 day)
  • #11767 - Implement TaskDisplay with child tool status (1.5 days)
  • #11768 - Implement Static component integration (1 day)
  • #11769 - Implement TextInput component (1.5 days)
  • #11770 - Implement SelectMenu component (0.5 days)
  • #11774 - Implement StatusBar component (0.5 days)

Phase 4: Integration

  • #11771 - Implement useSDKEvents hook (2.5 days) ⚠️ HIGH RISK
  • #11772 - Implement useStreaming hook (1.5 days)
  • #11773 - Implement slash command system (1 day)

Phase 5: Polish & Ship

  • #11777 - Integration testing and edge cases (3.5 days)
  • #11778 - Build configuration and optimization (1 day)
  • #11779 - Documentation: Upstream sync workflow (0.5 days)

Success Criteria

  • No crashes during prose streaming + tool updates
  • Child task status updates display correctly
  • Binary size < 15MB
  • All current working features preserved
  • Tests for critical rendering paths

Estimated Total Effort

~20 days (4 weeks of focused work)

Risk Assessment

Risk Severity Mitigation
SDK event handling complexity HIGH Same logic needed regardless of UI - React may make it cleaner
Bundle size increase Medium Tree-shaking, measure early
Bun compatibility Low Claude Code already uses Ink+Bun

Branch

feature/oclite-ink-rewrite (clean branch from dev)

Backup

Previous experimental work saved in: backup/oclite-lite-experiments-2026-02-02

Originally created by @randomm on GitHub (Feb 2, 2026). Originally assigned to: @thdxr on GitHub. ## Overview Replace the current log-update based lite UI with Ink (React for terminals) to solve fundamental rendering issues with concurrent state updates. ## Background The current oclite lite implementation (17 files, ~2,500 lines) has persistent issues: - `pausedForProse` hack prevents live block updates during text streaming to avoid crashes - Child session mapping requires complex buffering for out-of-order events - State synchronization between SDK events and UI is fragile - log-update wasn't designed for this level of complexity ## Why Ink? 1. **`<Static>` component** — Renders completed items permanently above dynamic content (exactly what we need) 2. **React reconciler** — Multiple state updates batch properly, no need for pausedForProse hacks 3. **`useStdout().write()`** — Can output text without interfering with render cycle 4. **Battle-tested** — Claude Code, Gemini CLI, Cloudflare Wrangler all use Ink ## Package Versions | Package | Version | |---------|---------| | `ink` | latest stable | | `react` | latest stable (required by Ink) | | `ink-spinner` | latest stable | | `ink-text-input` | latest stable | | `@types/react` | latest stable | ## Scope ### In Scope - Replace all rendering logic with Ink components - Maintain feature parity with current lite functionality - SDK event stream integration via React hooks - Child session status display (the feature that keeps breaking) ### Out of Scope - Full opencode TUI feature parity (panels, scrolling, etc.) - Web UI - Desktop app ## Child Issues (Implementation Order) ### Phase 1: Setup - [ ] #11763 - Setup Ink dependencies and verify Bun compatibility (0.5 days) ### Phase 2: Core Architecture - [ ] #11764 - Implement core App component and state management (1.5 days) - [ ] #11776 - Implement theming system (0.5 days) ### Phase 3: Components - [ ] #11765 - Implement StreamingProse component with markdown (2 days) - [ ] #11766 - Implement ToolDisplay component (1 day) - [ ] #11767 - Implement TaskDisplay with child tool status (1.5 days) - [ ] #11768 - Implement Static component integration (1 day) - [ ] #11769 - Implement TextInput component (1.5 days) - [ ] #11770 - Implement SelectMenu component (0.5 days) - [ ] #11774 - Implement StatusBar component (0.5 days) ### Phase 4: Integration - [ ] #11771 - Implement useSDKEvents hook (2.5 days) ⚠️ HIGH RISK - [ ] #11772 - Implement useStreaming hook (1.5 days) - [ ] #11773 - Implement slash command system (1 day) ### Phase 5: Polish & Ship - [ ] #11777 - Integration testing and edge cases (3.5 days) - [ ] #11778 - Build configuration and optimization (1 day) - [ ] #11779 - Documentation: Upstream sync workflow (0.5 days) ## Success Criteria - [ ] No crashes during prose streaming + tool updates - [ ] Child task status updates display correctly - [ ] Binary size < 15MB - [ ] All current working features preserved - [ ] Tests for critical rendering paths ## Estimated Total Effort ~20 days (4 weeks of focused work) ## Risk Assessment | Risk | Severity | Mitigation | |------|----------|------------| | SDK event handling complexity | HIGH | Same logic needed regardless of UI - React may make it cleaner | | Bundle size increase | Medium | Tree-shaking, measure early | | Bun compatibility | Low | Claude Code already uses Ink+Bun | ## Branch `feature/oclite-ink-rewrite` (clean branch from dev) ## Backup Previous experimental work saved in: `backup/oclite-lite-experiments-2026-02-02`
yindo added the opentui label 2026-02-16 18:09:39 -05:00
yindo closed this issue 2026-02-16 18:09:39 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Feb 2, 2026):

Related Issues Found

This epic addresses multiple interconnected rendering and state management issues across the codebase. Here are the most critical related issues that the Ink-based TUI rewrite should resolve:

Critical Rendering Issues

  • #3905: Message history randomly flickers/disappears
  • #4905: Screen flickering/vibrating on diff views, causes PTY host crash
  • #3719: Navigating away from active session causes flicker when returning
  • #3776: Screen becomes completely blank
  • #3614: Error corrupts TUI

Child Session Display Issues (Major problem mentioned in epic)

  • #3338: Can't read subagent session
  • #2390: Switching to child session doesn't route messages correctly
  • #6447: /session/status always empty
  • #6573: Sessions hang indefinitely when Task tool spawns subagents

Performance Issues (Solved by Ink batching)

  • #811: Text rendering extremely slow, high CPU usage even when idle
  • #6172: High CPU usage during LLM streaming due to O(n) text buffer rendering
  • #3746: Long prompt history stalls the app
  • #3526: session-child-cycle becomes extremely slow with many sessions

TUI Stability Issues

  • #3798: OpenTUI causes crashes and heavy memory usage
  • #5561: TextNodeRenderable only accepts strings error
  • #3831: New TUI breaks running agents with @agent_name
  • #4077: TUI upgrade causes image paste issues

Streaming Issues (Related to pausedForProse hack)

  • #5838: Conversation streaming cuts off near the end
  • #3124: Pauses in OpenCode execution

These issues collectively demonstrate the limitations of the current log-update based approach and validate the need for the Ink-based rewrite.

@github-actions[bot] commented on GitHub (Feb 2, 2026): ## Related Issues Found This epic addresses multiple interconnected rendering and state management issues across the codebase. Here are the most critical related issues that the Ink-based TUI rewrite should resolve: ### Critical Rendering Issues - #3905: Message history randomly flickers/disappears - #4905: Screen flickering/vibrating on diff views, causes PTY host crash - #3719: Navigating away from active session causes flicker when returning - #3776: Screen becomes completely blank - #3614: Error corrupts TUI ### Child Session Display Issues (Major problem mentioned in epic) - #3338: Can't read subagent session - #2390: Switching to child session doesn't route messages correctly - #6447: /session/status always empty - #6573: Sessions hang indefinitely when Task tool spawns subagents ### Performance Issues (Solved by Ink batching) - #811: Text rendering extremely slow, high CPU usage even when idle - #6172: High CPU usage during LLM streaming due to O(n) text buffer rendering - #3746: Long prompt history stalls the app - #3526: session-child-cycle becomes extremely slow with many sessions ### TUI Stability Issues - #3798: OpenTUI causes crashes and heavy memory usage - #5561: TextNodeRenderable only accepts strings error - #3831: New TUI breaks running agents with @agent_name - #4077: TUI upgrade causes image paste issues ### Streaming Issues (Related to pausedForProse hack) - #5838: Conversation streaming cuts off near the end - #3124: Pauses in OpenCode execution These issues collectively demonstrate the limitations of the current log-update based approach and validate the need for the Ink-based rewrite.
Author
Owner

@randomm commented on GitHub (Feb 3, 2026):

Reopening epic - Phase 1 & 2 merged, proceeding with Phase 3.

@randomm commented on GitHub (Feb 3, 2026): Reopening epic - Phase 1 & 2 merged, proceeding with Phase 3.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8307