mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
fix: prevent iTerm2 terminal response sequences from leaking into REPL input (#172)
The earlyInput capture's escape sequence detection was too simplistic — it only checked if the byte after ESC fell in 0x40-0x7E range, treating it as a terminator. This caused DCS sequences (e.g. XTVERSION `\x1bP>|iTerm2 3.6.4\x1b\\`) and CSI parameter sequences (e.g. DA1 `\x1b[?64;...c`) to partially leak into the input buffer as `>|iTerm2 3.6.4?64;1;2;4;6;17;18;21;22c`. Fix by handling each escape sequence type per ECMA-48: - CSI (`ESC [`): skip parameter + intermediate bytes, then final byte - DCS/OSC/SOS/PM (`ESC P/]/X/^`): scan to BEL or ST terminator - Other: keep single-byte skip Closes #171 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,17 +102,43 @@ function processChunk(str: string): void {
|
||||
}
|
||||
|
||||
// Skip escape sequences (arrow keys, function keys, focus events, etc.)
|
||||
// All escape sequences start with ESC (0x1B) and end with a byte in 0x40-0x7E
|
||||
// All escape sequences start with ESC (0x1B).
|
||||
if (code === 27) {
|
||||
i++ // Skip the ESC character
|
||||
// Skip until the terminating byte (@ to ~) or end of string
|
||||
while (
|
||||
i < str.length &&
|
||||
!(str.charCodeAt(i) >= 64 && str.charCodeAt(i) <= 126)
|
||||
) {
|
||||
i++
|
||||
if (i >= str.length) continue
|
||||
|
||||
const next = str.charCodeAt(i)!
|
||||
|
||||
// CSI sequences: ESC [ ... <final_byte 0x40-0x7E>
|
||||
// e.g. \x1b[?64;1;2;4;6;17;18;21;22c (DA1 response)
|
||||
if (next === 0x5b /* [ */) {
|
||||
i++ // skip '['
|
||||
// Skip parameter bytes (0x30-0x3F) and intermediate bytes (0x20-0x2F)
|
||||
while (i < str.length && str.charCodeAt(i)! >= 0x20 && str.charCodeAt(i)! <= 0x3f) {
|
||||
i++
|
||||
}
|
||||
// Skip the final byte (0x40-0x7E)
|
||||
if (i < str.length && str.charCodeAt(i)! >= 0x40 && str.charCodeAt(i)! <= 0x7e) i++
|
||||
continue
|
||||
}
|
||||
if (i < str.length) i++ // Skip the terminating byte
|
||||
|
||||
// String sequences: DCS (P), OSC (]), SOS (X), PM (^)
|
||||
// These end with BEL (0x07) or ST (ESC \)
|
||||
if (next === 0x50 /* P */ || next === 0x5d /* ] */ || next === 0x58 /* X */ || next === 0x5e /* ^ */) {
|
||||
i++ // skip the introducer
|
||||
while (i < str.length) {
|
||||
if (str.charCodeAt(i) === 0x07) { i++; break } // BEL terminates
|
||||
if (str.charCodeAt(i) === 0x1b && i + 1 < str.length && str.charCodeAt(i + 1)! === 0x5c) {
|
||||
i += 2; break // ESC \ (ST) terminates
|
||||
}
|
||||
i++
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// SS2 (N), SS3 (O) — 2-byte sequences, just skip both
|
||||
// Other simple escape sequences: ESC <byte 0x40-0x7E> — just skip the one byte
|
||||
if (i < str.length) i++
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user