fix: expand Ink partial clears to prevent ghost content in screenshots
Ink (React CLI framework) clears its output using repeated EL2+CUU1 sequences, one per previously-drawn line. When /clear resets Ink's internal line counter, the next frame only erases a few lines instead of the full previous output. In a real terminal the old content is in scrollback and invisible, but pyte's fixed-size screen retains it, producing ghost content (e.g. duplicated prompts) in SVG screenshots. Added AltScreen.expand_clear_sequences() which detects runs of 3+ EL2+CUU1 pairs that don't reach row 0 and extends them to erase all lines up to the top of the screen. Both DockerExecSession and TerminalSession call this before feeding data to pyte. Also made on_session_end() idempotent (contextlib.suppress KeyError) to prevent a race when close_session() and natural session exit both call it. Added docs/ink-clear-fix.md with root cause analysis, byte-level explanation, and reproduction script.
This commit is contained in:
@@ -105,6 +105,21 @@ class TestSessionManager:
|
||||
assert session_id not in manager.sessions
|
||||
assert route_key not in manager.routes
|
||||
|
||||
def test_on_session_end_idempotent(self, mock_poller, mock_path, sample_apps):
|
||||
"""Test session end cleanup is idempotent."""
|
||||
manager = SessionManager(mock_poller, mock_path, sample_apps)
|
||||
|
||||
session_id = SessionID("test-session")
|
||||
route_key = RouteKey("test-route")
|
||||
manager.sessions[session_id] = MagicMock()
|
||||
manager.routes[route_key] = session_id
|
||||
|
||||
manager.on_session_end(session_id)
|
||||
manager.on_session_end(session_id)
|
||||
|
||||
assert session_id not in manager.sessions
|
||||
assert route_key not in manager.routes
|
||||
|
||||
def test_on_session_end_nonexistent(self, mock_poller, mock_path, sample_apps):
|
||||
"""Test session end for non-existent session."""
|
||||
manager = SessionManager(mock_poller, mock_path, sample_apps)
|
||||
|
||||
Reference in New Issue
Block a user