pyro-mcp/examples/python_shell.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

40 lines
1.3 KiB
Python

from __future__ import annotations
import tempfile
import time
from pathlib import Path
from pyro_mcp import Pyro
def main() -> None:
pyro = Pyro()
with tempfile.TemporaryDirectory(prefix="pyro-workspace-seed-") as seed_dir:
Path(seed_dir, "note.txt").write_text("hello from shell\n", encoding="utf-8")
created = pyro.create_workspace(environment="debian:12", seed_path=seed_dir)
workspace_id = str(created["workspace_id"])
try:
opened = pyro.open_shell(workspace_id)
shell_id = str(opened["shell_id"])
pyro.write_shell(workspace_id, shell_id, input="pwd")
deadline = time.time() + 5
while True:
read = pyro.read_shell(
workspace_id,
shell_id,
cursor=0,
plain=True,
wait_for_idle_ms=300,
)
output = str(read["output"])
if "/workspace" in output or time.time() >= deadline:
print(output, end="")
break
time.sleep(0.1)
pyro.close_shell(workspace_id, shell_id)
finally:
pyro.delete_workspace(workspace_id)
if __name__ == "__main__":
main()