anomalyco / anomalyco/opencode

[Bug]: TUI streaming Markdown renders item 2 over item 1 nested bullet points (cursor offset)

Open
#48,714 2 comments 0 reactions 1 assignee View on GitHub

@simonklee is already working on this.

Since Sep 12, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

While the assistant is streaming a Markdown response containing a numbered list with nested bullet items, the TUI encounters a 1-row cursor offset error. Item 2. is stamped directly on top of the sub-bullet of item 1., overwriting its first 19 characters and completely swallowing the preceding bullet point.

Crucial Observation:
Selecting and copying the corrupted text with the mouse yields 100% complete, intact, and correct text. The raw record in ~/.local/share/opencode/opencode.db (part table) is also completely undamaged. This proves the underlying AST and message buffer are intact—the bug is strictly an ANSI cursor repositioning / line-height calculation error in OpenTUI's differential streaming renderer.


Steps to Reproduce
  1. Start OpenCode in interactive TUI mode (tested in both standard and --mini mode):
    opencode
    
  2. Send the following prompt (which forces the model to stream the exact Markdown structure):
    Repeat the following Markdown text verbatim without codeblocks or extra text:
    
    1. **Hardware-Optimierungen:**
        * **MLX Engine:** Massive Performance-Verbesserungen für Apple Silicon (Macs).
        * **GGUF-Unterstützung:** Bessere Kompatibilität und schnellere Ausführung von GGUF-Modellen über `llama.cpp`.
    2. **Neue Funktionen:**
        * **Thinking-Modus:** Die Fähigkeit, internen Denkprozessen (Reasoning) bei Modellen zu folgen bzw. diese zu steuern.
        * **Streaming für Tool-Calls:** Verbessertes Streaming von Antworten auch dann, wenn das Modell Werkzeuge (Tools) nutzt.
    3. **Modell-Vielfalt & Integration:**
        * Schnelleres Hinzufügen neuer High-End-Modelle (wie Nemotron, Gemmaerweiterungen).
        * Bessere Unterstützung für Multimodalität (Bild- und Textverarbeitung in einem Flow).
    4. **Stabilität:**
        * Speichermanagement zur Vermeidung von Abstürzen beim Laden sehr großer Modelle auf lokaler Hardware.
    
  3. Watch the live terminal streaming output.

Expected Behavior

All 4 numbered sections should render with their respective sub-bullets cleanly indented below them:

1. Hardware-Optimierungen:
   - MLX Engine: Massive Performance-Verbesserungen...
   - GGUF-Unterstützung: Bessere Kompatibilität...
2. Neue Funktionen:
   - Thinking-Modus: ...
   ...

Actual Behavior (Visual Screenshot)
Image

Anatomy of the visual corruption:

  1. Under 1. Hardware-Optimierungen:, OpenCode draws a card divider line ────────────────────────.
  2. The first sub-bullet (MLX Engine) is swallowed in the blank row.
  3. The heading 2. Neue Funktionen: (19 characters) is stamped directly over the first 19 characters of the second sub-bullet (* GGUF-Unterstüt), leaving only the tail zung: Bessere Kompatibilität und schnellere Ausführung von GGUF-Modellen über llama.cpp. trailing in white/green.
  4. Once OpenCode enters ordered list mode, items 2., 3., and 4. no longer draw horizontal divider lines, and their respective sub-bullets render properly with -.

Technical Investigation & Root Cause Notes
  1. State Transition Glitch:
    At token 1. **...**:, the streaming lexer does not yet know an ordered list is following and renders it as a card/section header with an underlying horizontal separator rule (───).
  2. Cursor Offset Miscalculation:
    When token 2. **...**: arrives, the streaming engine recognizes the ordered list context and issues an ANSI cursorUp sequence to re-anchor the layout. However, the calculation does not account for the extra line consumed by the horizontal separator.
  3. Overdraw:
    The cursor lands exactly on the line where sub-bullet 2 was just written. It prints 2. Neue Funktionen: at (X=0, Y) without clearing the line, producing the spliced text.
  4. Clipboard vs. Screen:
    Selecting the corrupted region with the mouse and copying to clipboard outputs the complete, untruncated text, confirming that the internal DOM/component tree is completely correct and only the terminal cursor coordinates were miscalculated.

Environment Details
  • OpenCode Version: 1.18.30 (opencode-ai)
  • OS: Linux (x86_64, Kernel 6.x)
  • Terminal: GNOME Terminal (xterm-256color, COLORTERM=truecolor)
  • Terminal Resolution: Tested on 382 columns × 92 rows
  • Provider: Ollama (via local streaming proxy)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.