anthropics / anthropics/claude-code

Legacy Windows console (conhost): SI byte from reassertTerminalModes renders as a visible glyph in the input box; ambiguous-width glyphs corrupt partial repaints

Offen
#88,306 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:tui bug platform:windows
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

**Environment:** Claude Code 2.1.237 (native install), Windows 10 Pro 19045, cmd.exe in the legacy console host (conhost, not Windows Terminal), codepage 65001, `HKCU\Console\VirtualTerminalLevel=1`, Korean locale, CJK console font.

## Bug 1: SI (0x0F) printed as a glyph at the cursor

`reassertTerminalModes()` writes the charset reset `"\x1B(B\x0F"` (ESC(B + SI) whenever the event-loop stall monitor detects a >5s stall ("likely sleep/wake") and on stdin resume.

The Win10 inbox conhost VT parser consumes `ESC(B` but does **not** implement SI/SO (LS0/LS1). The 0x0F byte falls through and is stored as a visible cell (rendered with the legacy control-glyph, a sun/bug-like character) at the current cursor position — which, when idle, is inside the prompt input box. Each sleep/wake or throttling stall adds one more glyph; they disappear on the next input-row repaint, so users see mysterious "bug emoji" accumulating while the app is idle.

Verified empirically: writing `A \x1B(B \x0F B` to a VT-enabled Win10 conhost yields buffer cells `A, U+000F, B` and a 3-column cursor advance. Writing `A \x00 B` yields `A, B` (NUL is discarded cleanly).

**Suggested fix:** skip the SI (or the whole charset reset) when the terminal is the legacy Windows console (no `WT_SESSION`, Windows, VT enabled via console API), or replace SI with nothing on win32. DECSC/DECRC + DECSTBM in the restore path were verified fine on conhost; only SI/SO leak.

## Bug 2: East-Asian-ambiguous glyph widths desync cell-diff repaints

The renderer computes string widths with `Bun.stringWidth(s, {ambiguousIsNarrow: true})`, but legacy conhost measures each glyph against the actual console font. With a CJK console font (GulimChe and every other Korean/Japanese font), many UI symbols occupy **2 cells**: `· ← ↓ … ✔ ● ◆ ◇ ○ ✳ ⚠ ※`, and `U+FE0E` (used in `·✔︎·`) occupies 2 extra cells itself. Box-drawing chars stay 1 cell, so no single `ambiguousIsNarrow` setting can match.

Result: absolute-column partial repaints (cell diff) land N columns away from where the previous frame's text actually sits, producing mixed old/new text in status/hint lines — e.g. `(shift+tab to cycle)` displayed as `(shift+eab to cycle)`, dropped or seemingly reordered characters.

Additionally `U+23F5` (the `⏵⏵` auto/plan-mode indicator) appears to be counted emoji-wide (2) by Bun.stringWidth while conhost renders it 1 cell, desyncing that line even with a non-CJK font, and it has no glyph in most monospace fonts (tofu on legacy conhost, which does no font fallback for symbols).

**Suggested fix:** on legacy conhost, prefer full-line repaints over intra-line cell diffs (or verify real cursor advance), and/or use conservative ASCII/narrow symbols (`▸` instead of `⏵`, plain `✔` without VS15) when the legacy console is detected.

## Workarounds found

- Bug 1: byte-patch `\x1B(B\x0F` → `\x1B(B\x00` in the binary (NUL verified harmless on conhost).
- Bug 2: switch the console font to D2Coding (narrow symbol glyphs + native Hangul) — removes almost all width mismatches on ko-KR.

---
*Root-caused and verified with byte-level probes by [Claude Code](https://claude.com/claude-code) running on the affected setup.*

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Start at reassertTerminalModes and trace the restore path that writes the charset reset, then inspect the renderer's Bun.stringWidth and cell-diff repaint logic. Reproduce the byte-level probes and partial repaint behavior in legacy conhost. Done means SI no longer appears as an input glyph and affected lines repaint without width-driven desynchronization.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
bun
Bereich
cli, operating-systems
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.