pyro-mcp/tests/test_workspace_shell_output.py
Thales Maciel 21a88312b6 Add chat-friendly shell read rendering
Make workspace shell reads usable as direct chat-model input without changing the PTY or cursor model. This adds optional plain rendering and idle-window batching across CLI, SDK, and MCP while keeping raw reads backward-compatible.

Implement the rendering and wait-for-idle logic in the manager layer so the existing guest/backend shell transport stays unchanged. The new helper strips ANSI and other terminal control noise, handles carriage-return overwrite and backspace, and preserves raw cursor semantics even when plain output is requested.

Refresh the stable shell docs/examples to recommend --plain --wait-for-idle-ms 300, mark the 3.5.0 roadmap milestone done, and bump the package/catalog version to 3.5.0.

Validation: uv lock; UV_CACHE_DIR=.uv-cache make check; UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed Firecracker smoke covering shell open/write/read with ANSI plus delayed output.
2026-03-13 01:10:26 -03:00

36 lines
1.4 KiB
Python

from __future__ import annotations
from pyro_mcp.workspace_shell_output import render_plain_shell_output
def test_render_plain_shell_output_strips_ansi_osc_and_controls() -> None:
raw = "\x1b]0;title\x07\x1b[31mred\x1b[0m\t\x01done"
assert render_plain_shell_output(raw) == "red\tdone"
def test_render_plain_shell_output_handles_carriage_return_and_backspace() -> None:
raw = "hello\r\x1b[2Kbye\nabc\b\bZ"
assert render_plain_shell_output(raw) == "bye\naZ"
def test_render_plain_shell_output_preserves_trailing_newlines() -> None:
assert render_plain_shell_output("line one\n") == "line one\n"
assert render_plain_shell_output("\n") == "\n"
def test_render_plain_shell_output_handles_line_clear_modes_and_overwrite() -> None:
assert render_plain_shell_output("abcde\rab\x1b[1KZ") == " Zde"
assert render_plain_shell_output("hello\x1b[2Kx") == "x"
def test_render_plain_shell_output_handles_full_screen_clear() -> None:
assert render_plain_shell_output("one\ntwo\x1b[2Jz") == "z"
assert render_plain_shell_output("one\ntwo\x1b[3Jz") == "z"
def test_render_plain_shell_output_ignores_incomplete_and_non_csi_escape_sequences() -> None:
assert render_plain_shell_output("\x1b") == ""
assert render_plain_shell_output("\x1b[") == ""
assert render_plain_shell_output("\x1b]title\x1b\\ok") == "ok"
assert render_plain_shell_output("a\x1bOPb") == "ab"
assert render_plain_shell_output("a\x1bXb") == "ab"