fix: add DA1 response filtering to TerminalSession
The docker exec commands were using TerminalSession (via pty.fork), not DockerExecSession. Added the same DA1/DA2 response filtering to both session types to prevent escape sequence fragments from being displayed.
This commit is contained in:
@@ -7,6 +7,7 @@ import fcntl
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import pty
|
import pty
|
||||||
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import signal
|
import signal
|
||||||
import termios
|
import termios
|
||||||
@@ -31,6 +32,15 @@ REPLAY_BUFFER_SIZE = 256 * 1024 # 256KB
|
|||||||
DEFAULT_SCREEN_WIDTH = 132
|
DEFAULT_SCREEN_WIDTH = 132
|
||||||
DEFAULT_SCREEN_HEIGHT = 45
|
DEFAULT_SCREEN_HEIGHT = 45
|
||||||
|
|
||||||
|
# Pattern to filter out terminal device attribute responses that cause display issues
|
||||||
|
# These are responses to DA1/DA2 queries that shouldn't be displayed as text
|
||||||
|
# Matches complete responses like \x1b[?1;10;0c or \x1b[?64;1;2;...c
|
||||||
|
DA_RESPONSE_PATTERN = re.compile(rb'\x1b\[\?[\d;]+c')
|
||||||
|
|
||||||
|
# Pattern to detect partial DA responses at end of data (incomplete escape sequence)
|
||||||
|
# Matches: \x1b, \x1b[, \x1b[?, \x1b[?1, \x1b[?1;, etc.
|
||||||
|
DA_PARTIAL_PATTERN = re.compile(rb'\x1b(?:\[(?:\?[\d;]*)?)?$')
|
||||||
|
|
||||||
|
|
||||||
class TerminalSession(Session):
|
class TerminalSession(Session):
|
||||||
"""A session that manages a terminal."""
|
"""A session that manages a terminal."""
|
||||||
@@ -60,6 +70,8 @@ class TerminalSession(Session):
|
|||||||
# Change counter for reliable activity detection (monotonically increasing)
|
# Change counter for reliable activity detection (monotonically increasing)
|
||||||
self._change_counter = 0
|
self._change_counter = 0
|
||||||
self._last_snapshot_counter = 0
|
self._last_snapshot_counter = 0
|
||||||
|
# Buffer for handling escape sequences split across reads
|
||||||
|
self._escape_buffer = b""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
@@ -312,6 +324,26 @@ class TerminalSession(Session):
|
|||||||
data = await queue.get()
|
data = await queue.get()
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Prepend any buffered partial escape sequence from previous read
|
||||||
|
if self._escape_buffer:
|
||||||
|
data = self._escape_buffer + data
|
||||||
|
self._escape_buffer = b""
|
||||||
|
|
||||||
|
# Filter out complete DA1/DA2 responses (e.g., \x1b[?1;10;0c)
|
||||||
|
data = DA_RESPONSE_PATTERN.sub(b'', data)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for partial escape sequence at end that might be a DA response
|
||||||
|
# Hold it back until we get more data to see if it completes
|
||||||
|
match = DA_PARTIAL_PATTERN.search(data)
|
||||||
|
if match:
|
||||||
|
self._escape_buffer = data[match.start():]
|
||||||
|
data = data[:match.start()]
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
|
||||||
# Store in replay buffer for reconnection
|
# Store in replay buffer for reconnection
|
||||||
await self._add_to_replay_buffer(data)
|
await self._add_to_replay_buffer(data)
|
||||||
# Update pyte screen state for screenshots
|
# Update pyte screen state for screenshots
|
||||||
|
|||||||
Reference in New Issue
Block a user