#!/usr/bin/env python3 """Живой MCP: долгий машинный out из tail-jump можно прервать Pause.""" from __future__ import annotations import asyncio import json import os from pathlib import Path import sys import tempfile import time from mcp import Client, StdioServerParameters ROOT = Path(__file__).resolve().parents[2] async def probe() -> None: home = Path(os.environ['MAME_HOME']).resolve() binary = Path(os.environ.get('MAME_BIN', home / 'sprinter')).resolve() package = ROOT / 'tests/hello/.sprinter-cc-hello' with tempfile.TemporaryDirectory(prefix='sprinter-out-mcp-', dir='/tmp') as temp: parameters = StdioServerParameters( command=sys.executable, args=[str(ROOT / 'toolchain/sdbg_mcp.py'), '--build', str(package), '--socket', str(Path(temp) / 'session.sock'), '--mame-home', str(home), '--mame-bin', str(binary)]) async with Client(parameters) as client: async def call(name: str, arguments: dict | None = None) -> dict: result = await client.call_tool(name, arguments or {}) if result.is_error or result.structured_content is None: raise RuntimeError(name + ': ' + repr(result.content)) return result.structured_content await call('start_session') try: deadline = time.monotonic() + 90 while time.monotonic() < deadline: status = await call('session_status') if status['phase'] == 'ready': break if status['phase'] in ('failed', 'stopped'): raise RuntimeError('Launcher: ' + repr(status)) await asyncio.sleep(.2) else: raise TimeoutError('hello не дошёл до main') entered = await call('step_instruction', {'count': 1}) code = await call('disassemble_logical', {'address': hex(entered['pc']), 'length': 12}) if 'jp (hl)' not in code['text']: raise RuntimeError('Ожидался tail-jump helper: ' + code['text']) started_at = time.monotonic() accepted = await call('step_out_instruction') response_ms = round((time.monotonic() - started_at) * 1000, 1) if not accepted['accepted'] or response_ms > 3000: raise RuntimeError('Машинный out не ответил быстро: ' + repr(accepted)) await asyncio.sleep(.3) if not (await call('session_status'))['running']: raise RuntimeError('Tail-jump out неожиданно завершился') paused = await call('pause_execution') if (await call('session_status'))['running']: raise RuntimeError('Pause не остановил долгий out') print(json.dumps({'event': 'machine_out_pause_verified', 'response_ms': response_ms, 'entered_pc': entered['pc'], 'paused_pc': paused['pc']}, ensure_ascii=False), flush=True) finally: await call('stop_session') if __name__ == '__main__': asyncio.run(probe())