Add shared-session MCP source debugger adapter
This commit is contained in:
@@ -279,12 +279,39 @@ Quick wins:
|
||||
|
||||
## Прочий backlog
|
||||
|
||||
- [ ] **Довести MCP C-уровня до полного безопасного контракта.** Первый
|
||||
stdio-адаптер с 16 инструментами использует общую sdbg-сессию и
|
||||
owner ID личных точек. Следующее: эксклюзивный control lease для
|
||||
DAP/MCP, heartbeat/очистка точек при аварийном выходе MCP, безопасные
|
||||
input/screenshot/console API через session server, затем доказанные
|
||||
watchpoints, запись typed values, disassemble_src и batch-загрузка
|
||||
точек. Raw `mame_mcp.py` с `-plugin mamebridge` или старым
|
||||
`mame_bridge.lua` не подключать к тому же MAME в обход общей сессии.
|
||||
Отдельно мигрировать raw `mame_mcp.py` с FastMCP SDK 1.x на MCPServer
|
||||
SDK 2.x, если этот standalone-интерфейс сохраняется; сейчас окружения
|
||||
raw и C-адаптера разделены.
|
||||
Проверять конкуренцию, ошибки и lifecycle живым DAP/MCP
|
||||
пробником; см. [sdbg-mcp.md](sdbg-mcp.md).
|
||||
- [ ] **Несколько одновременных экземпляров MAME и MCP bridge (отдельная
|
||||
задача, позже).** Проверить два изолированных процесса с разными
|
||||
дискетами/CHD/state и двумя MCP-сессиями; в протоколе явно связывать
|
||||
команду с PID/session ID, не допускать ответа от чужого процесса,
|
||||
проверить сброс/exit и одновременные команды. До успешного end-to-end
|
||||
теста параллельная работа MAME через MCP не гарантируется.
|
||||
- [ ] **Финальная полировка: оградить ввод до запуска отлаживаемой программы.**
|
||||
Проверить, можно ли не передавать в гостевой Sprinter физические
|
||||
клавиатуру/мышь, пока MAME грузит DSS и launcher вводит команду запуска:
|
||||
MAME может захватить фокус, а пользователь в это время печатает в другой
|
||||
программе. По возможности до запуска EXE сохранить фокус на прежнем
|
||||
приложении, чтобы оно продолжало получать ввод. Автоматический ввод
|
||||
команды launcher должен оставаться рабочим. При переходе к исполнению
|
||||
EXE сразу разрешить прямой ввод в MAME, в том числе для `getchar()`;
|
||||
при Stop, ошибке запуска и restart корректно сбрасывать состояние.
|
||||
Если MAME не умеет различать эти два
|
||||
источника ввода, исследовать управление фокусом/захватом окна либо
|
||||
узкий patch MAME; не блокировать ввод ценой поломки запуска.
|
||||
Проверить ручное переключение окон, сохранение ввода в другом приложении
|
||||
и ранние нажатия живым сценарием.
|
||||
- [ ] factoring parse_argv из crt0/crt0_banked в общий argv.s
|
||||
- [ ] `restore SP on EXIT` (паттерн z88dk +pps) — проверить нужность
|
||||
- [x] ~~CI: MAME с -aviwrite для screenshot-сравнения без человека~~ —
|
||||
|
||||
@@ -484,7 +484,9 @@ global/static переменной, ненулевое значение озна
|
||||
[руководство по SDBG_LOG](sdbg-log-macros.md).
|
||||
Аргументы не вычисляются кодом приложения, поэтому побочные эффекты в них
|
||||
недопустимы. Сообщение видно в MAME debugger console и VS Code Debug Console
|
||||
при подключённой source-debug сессии; без неё макрос сам ничего не печатает.
|
||||
при подключённой source-debug сессии, а MCP-клиент читает тот же журнал
|
||||
через `recent_events` ([руководство по MCP](sdbg-mcp.md)); без сессии макрос
|
||||
сам ничего не печатает.
|
||||
|
||||
## <sprinter.h> — платформа
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
Дата: 2026-09-16. План: [mame-source-debug.md](mame-source-debug.md).
|
||||
Реализованы сборка/карта, проверенный транспорт, базовая C-сессия,
|
||||
постоянный session server, DAP MVP, VS Code launch и build task. MCP C-уровня,
|
||||
постоянный session server, DAP MVP, VS Code launch/build task и первый
|
||||
stdio MCP-адаптер C-уровня. Эксклюзивное владение CPU между клиентами,
|
||||
безопасный restart и расширенная отладка ещё не готовы.
|
||||
Этапы плана не считаются завершёнными целиком по одному успешному репро.
|
||||
|
||||
@@ -118,7 +119,21 @@
|
||||
копию системного HDD и отдельные state-каталоги, показывает окно Sprinter,
|
||||
ждёт DSS, ставит только service-точку `main`, вводит `a:\\NAME.EXE`,
|
||||
проверяет сигнатуру entry и запускает session server. Закрытие DAP
|
||||
завершает только созданные им server/MAME и удаляет временный каталог.
|
||||
завершает только созданные им server/MAME, удаляет временный каталог и
|
||||
свой Unix socket (с проверкой inode, чтобы не удалить новый сеанс).
|
||||
- `sdbg_mcp.py` предоставляет 16 инструментов через официальный MCP SDK
|
||||
2.x поверх того же session server: статус, C-позиция, регистры, logical
|
||||
memory, переменные, события/логи, личные точки и команды исполнения.
|
||||
MCP-точки имеют owner ID и не могут удалить точки VS Code; при обычном
|
||||
закрытии MCP-клиента они очищаются. Живой совместный прогон проверил
|
||||
структурированные ответы, отказ на удаление чужой точки и последующее
|
||||
срабатывание точки DAP с provider `sdbg` и `osx`. Отдельный WAITKEY-прогон
|
||||
подтвердил удаление личной точки при running CPU и дальнейшее завершение
|
||||
шага после клавиши.
|
||||
Повторный запуск на том же фиксированном socket после прежнего stale-файла
|
||||
прошёл; после Stop путь удалён.
|
||||
Контракт запуска и ограничения — в
|
||||
[руководстве по MCP](sdbg-mcp.md).
|
||||
|
||||
## Использование карты
|
||||
|
||||
@@ -224,6 +239,8 @@ pyenv exec python tests/sdbg/run_vscode_dap_probe.py
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --exit-while-stopped
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --stop-while-stopped
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --term-while-stopped
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --mcp-python /tmp/sprinter-sdbg-mcp-venv/bin/python
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --waitkey --emulated-key --clear-while-running
|
||||
pyenv exec python tests/sdbg/run_vscode_dap_probe.py --waitkey --manual-key
|
||||
```
|
||||
|
||||
@@ -267,7 +284,7 @@ commit `b0c4527c2edb1ee177fd09b3c412b65b385bf35b`:
|
||||
| Ошибочная debug-сборка, 2026-09-15 | Изолированный `fault.c` вернул код 2 от make, `file:1: error 20` сохранился, Python traceback удалён; MAME не участвует |
|
||||
| Владение и generation | Второй FileBridge и чтение со stale generation отклоняются |
|
||||
|
||||
Полный host-набор: 39 тестов (38 прошли, один Unix-socket тест пропущен только
|
||||
Полный host-набор: 44 теста (43 прошли, один Unix-socket тест пропущен только
|
||||
из-за запрета `bind` в sandbox). Тот же socket path проверен живым DAP-запуском.
|
||||
После разделения репозиториев установленный VSIX в изолированном профиле
|
||||
VS Code запустил сборку SprPoP и остановился в `src/sprpop.c:264` (`main`)
|
||||
@@ -328,8 +345,9 @@ host-моста пока не готова: FileBridge использует `fcn
|
||||
|
||||
Также startup debugscript с `g` может продолжить первое реальное попадание;
|
||||
живой bridge-тест не использует такой скрипт. Повторная загрузка autoboot
|
||||
на reset защищена от дублирования callback. Старый mamebridge параллельно
|
||||
с sdbgbridge не загружать: общая арбитрирующая сессия ещё не реализована.
|
||||
на reset защищена от дублирования callback. Raw `-plugin mamebridge`
|
||||
параллельно с `sdbgbridge` не загружать: общая арбитрирующая сессия для
|
||||
двух Lua-мостов ещё не реализована.
|
||||
Два одновременно запущенных процесса MAME через MCP bridge не проверялись;
|
||||
корректная маршрутизация команд между ними не гарантируется. Это отдельная
|
||||
отложенная задача в [TODO.md](TODO.md).
|
||||
@@ -353,8 +371,12 @@ Crash reports в 19:22/19:23 относились к неподдержанно
|
||||
строит проверенное условие через I/O port. После штатных прогонов в 20:43 и
|
||||
позже новых `mame.arm-*.ips` не появилось.
|
||||
|
||||
Далее по плану: сделать MCP-адаптер, безопасный restart и расширенные
|
||||
выражения. VSIX уже упакован;
|
||||
Далее по плану: арбитраж управления CPU и lease/cleanup для MCP-точек при
|
||||
аварийном выходе клиента, затем безопасный restart и расширенные выражения.
|
||||
Низкоуровневые MAME MCP-инструменты (`src/mame_mcp.py` с новым
|
||||
`-plugin mamebridge` либо старым `mame_bridge.lua`) нельзя просто перенести: они должны
|
||||
проходить через общий session server и получить проверенный контракт для
|
||||
ввода, скриншотов, записи/watchpoints. VSIX уже упакован;
|
||||
для IDE ещё нужны Run-команда, выбор профиля
|
||||
сборки/данных и расширенная диагностика assembler/linker.
|
||||
Базовый attach уже проверяет принадлежность resident/current-bank к build,
|
||||
|
||||
@@ -534,6 +534,13 @@ console_log и загрузка набора точек. Возвращать bu
|
||||
Неподдержанное — явная ошибка. Старые низкоуровневые команды интегрируются
|
||||
в арбитраж, а не обходят его.
|
||||
|
||||
Первый stdio MCP-адаптер уже работает через общий session server и отдаёт
|
||||
16 проверенных C-инструментов. У личных MCP-точек owner ID; удаление чужой
|
||||
DAP-точки отклоняется. Совместный живой прогон подтвердил чтение состояния,
|
||||
точки и последующее срабатывание DAP-точки. Эксклюзивный control lease,
|
||||
cleanup при аварийном выходе MCP и остальные интерфейсы этого раздела ещё
|
||||
не реализованы. Настройка и точный список — [sdbg-mcp.md](sdbg-mcp.md).
|
||||
|
||||
### 8.2 DAP MVP и развитие
|
||||
|
||||
MVP: initialize, attach, configurationDone, disconnect, setBreakpoints,
|
||||
@@ -751,6 +758,17 @@ SDCC. Добавить launch/restart/stopOnMain и упаковку VSIX. До
|
||||
без side effects, после проверки размера, доступного банка, границ и image
|
||||
identity; `NULL`, закрытая страница, отсутствие NUL в лимите и неизвестный
|
||||
pointee дают явный `unavailable`/truncated, а не неверное значение.
|
||||
- Исследовать временную блокировку физического ввода в MAME до запуска
|
||||
отлаживаемого EXE: окно может получить фокус, пока пользователь вводит
|
||||
текст в другой программе. По возможности сохранить фокус и ввод за этой
|
||||
программой до запуска EXE. Автоматический ввод команды launcher в DSS
|
||||
должен работать и при блокировке. В момент запуска EXE сразу открыть
|
||||
прямой ввод, включая ожидание `getchar()`; восстановить исходное состояние
|
||||
при Stop, ошибке и restart. Если источники ввода нельзя разделить штатно,
|
||||
проверить управление фокусом или узкий patch MAME. Приёмка — живой тест
|
||||
ранних нажатий, ввода в другое приложение, переключения окон и ввода после
|
||||
запуска. Подробная задача
|
||||
сохранена в [TODO.md](TODO.md).
|
||||
|
||||
**Выход:** доказательства и ограничения каждой функции опубликованы.
|
||||
Эвристика не выдаётся за стек, anchors — за гарантированную идентичность,
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
кода печати в приложении. Сообщение попадает в Debug Console VS Code и в
|
||||
журнал debugger MAME. Отдельное окно MAME debugger видно при launch с
|
||||
`"debugger": "osx"`; режим `sdbg` оставляет окно Sprinter и журнал MAME,
|
||||
но не открывает штатное debugger-окно.
|
||||
но не открывает штатное debugger-окно. Подключённый
|
||||
[MCP-адаптер C-уровня](sdbg-mcp.md) читает те же записи `output` через
|
||||
`recent_events(after=...)`; он не ставит второй набор макросных точек.
|
||||
|
||||
## Быстрый пример
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# MCP-доступ к source debugger Sprinter
|
||||
|
||||
`toolchain/sdbg_mcp.py` подключается к уже работающей `sdbg_server.py` через
|
||||
Unix socket. Это отдельный stdio MCP-сервер для C-уровня: он использует ту же
|
||||
сессию, карту сборки и журнал, что VS Code/DAP. В репозитории MAME есть две
|
||||
Lua-реализации **другого**, raw MCP-моста: `src/mame_bridge.lua`
|
||||
(`-autoboot_script`) и более новый `-plugin mamebridge`. Оба обслуживают
|
||||
один `src/mame_mcp.py` и общий файловый протокол; plugin использует
|
||||
`register_periodic` и отвечает даже при остановленном CPU. Ни один из этих
|
||||
вариантов не должен одновременно управлять тем же MAME в обход sdbg-сессии.
|
||||
`src/mame_mcp.py` всё ещё импортирует `FastMCP` по пути SDK 1.x;
|
||||
наш адаптер использует `MCPServer` SDK 2.x. Пока raw frontend не мигрирован,
|
||||
держите для него отдельное Python-окружение. Это различие касается Python
|
||||
обвязки, а не Lua-плагина `mamebridge`.
|
||||
|
||||
Для MCP нужен Python 3.12 с официальным SDK 2.x. Он не требуется для сборки
|
||||
приложений и работы VS Code. Например, создайте отдельное окружение и
|
||||
установите `toolchain/requirements-mcp.txt`:
|
||||
|
||||
```sh
|
||||
pyenv exec python -m venv /tmp/sprinter-sdbg-mcp-venv
|
||||
/tmp/sprinter-sdbg-mcp-venv/bin/python -m pip install -r toolchain/requirements-mcp.txt
|
||||
```
|
||||
|
||||
В профиле `launch` типа `sprinter-mame` укажите фиксированный socket,
|
||||
например `"socket": "/tmp/sprinter-sdbg-hello.sock"`. После F5 дождитесь
|
||||
остановки в `main`. Путь должен быть коротким (у Unix socket есть лимит длины),
|
||||
уникальным для этого сеанса и доступным только вашему пользователю. Затем
|
||||
зарегистрируйте в MCP-клиенте stdio-сервер:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "/tmp/sprinter-sdbg-mcp-venv/bin/python",
|
||||
"args": [
|
||||
"/ABS/PATH/C-Compiler/toolchain/sdbg_mcp.py",
|
||||
"--socket", "/tmp/sprinter-sdbg-hello.sock"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Замените `/ABS/PATH/C-Compiler` абсолютным путём к toolkit. MCP-сервер при
|
||||
старте проверяет подключение; если VS Code ещё не запустил MAME или socket
|
||||
устарел, он завершается с понятной ошибкой в stderr. После Stop запустите
|
||||
MCP-сервер заново вместе с новой DAP-сессией. Альтернатива параметру
|
||||
`--socket` — переменная окружения `SDBG_SOCKET`.
|
||||
|
||||
Доступные инструменты: `session_status`, `where`, `read_registers`,
|
||||
`read_memory`, `list_variables`, `read_variable`, `recent_events`,
|
||||
`mame_console_tail`, `set_line_breakpoint`, `set_function_breakpoint`,
|
||||
`clear_breakpoint`, `clear_my_breakpoints`, `continue_execution`,
|
||||
`pause_execution`, `step_instruction`, `step_source`. Ответы SDK 2.x содержат
|
||||
`structuredContent`. `step_source` принимает `into`, `over` или `out` и
|
||||
возвращает принятие команды; итоговую остановку получите через
|
||||
`recent_events` с курсором `last`. Логи `SDBG_LOG` приходят как события
|
||||
`output`; журнал ограничен 1024 событиями и сообщает `first`/`last`/`lost`.
|
||||
|
||||
Число 16 не означает удаление возможностей более нового `-plugin mamebridge`:
|
||||
его `src/mame_mcp.py` публикует 30 raw-инструментов, ориентированных на
|
||||
машину MAME. Здесь инструменты сгруппированы по операциям C-сессии, а
|
||||
некоторые функции (C-позиция, typed global/static, журнал с generation)
|
||||
в raw MCP вообще отсутствуют. Оставшиеся группы требуют отдельного контракта:
|
||||
|
||||
| Группа raw MCP | Что требуется перед переносом в общую сессию |
|
||||
|---|---|
|
||||
| `setmem`, raw `debugger_command`, watchpoints | Проверка прав, банка, диапазона и согласование с DAP-точками; произвольная debugger-команда может нарушить состояние сессии |
|
||||
| VRAM/shares, screen pixels, screenshot | Явные адресные пространства, лимиты, формат ответа и изолированный каталог снимков |
|
||||
| Клавиатура, мышь, type/press | Один владелец ввода, корректное отпускание клавиш, ожидание running CPU и проверка прямого ввода с клавиатуры |
|
||||
| Raw disassembly | Связать адрес/банк с проверенной C-картой; не выдавать физический адрес за logical |
|
||||
|
||||
Это следующий этап, а не запрет на функции raw MCP. Нельзя просто загрузить
|
||||
`mamebridge` рядом с `sdbgbridge`: два независимых обработчика начнут менять
|
||||
CPU и точки без общего owner ID и журнала.
|
||||
|
||||
Чтение памяти принимает десятичный адрес или `0xHEX`, 1–256 байт logical
|
||||
Z80 memory, только при остановленном CPU, без side effects. Ответ содержит
|
||||
generation и страницы банков; диапазон не может пересекать границу 64 КБ.
|
||||
`read_variable` работает с проверенными global/static размером 1, 2 или 4
|
||||
байта, только когда нужный банк отображён. Локальные, стек, watchpoints,
|
||||
запись переменных и произвольные выражения пока не поддерживаются.
|
||||
|
||||
У каждой MCP-копии свой owner ID. Она может удалить только свои точки; при
|
||||
обычном закрытии stdio они очищаются. Живой тест подтвердил, что попытка
|
||||
удалить DAP-точку отвергается и точка VS Code срабатывает после выхода MCP.
|
||||
Удаление личной точки при running CPU отдельно проверено на ожидании
|
||||
`getchar()`; оно не ставит CPU на паузу и не блокирует ввод.
|
||||
Общий session server сериализует команды, но эксклюзивного владельца
|
||||
управления CPU пока нет: не посылайте `continue`/`step` одновременно из MCP
|
||||
и VS Code. При аварийном завершении MCP его точки могут остаться до конца
|
||||
сессии MAME; нужна отдельная lease/cleanup-механика. Несколько одновременно
|
||||
запущенных MAME с MCP не проверялись и не гарантируются; это отложенный тест.
|
||||
|
||||
Проверка совместной работы с DAP и реальным MAME:
|
||||
|
||||
```sh
|
||||
MAME_HOME=/path/to/MAME/runtime pyenv exec python tests/sdbg/run_vscode_dap_probe.py \
|
||||
--socket /tmp/sprinter-sdbg-mcp-probe.sock \
|
||||
--mcp-python /tmp/sprinter-sdbg-mcp-venv/bin/python
|
||||
```
|
||||
@@ -151,7 +151,8 @@ Launcher монтирует временную копию CHD как `-hard2`,
|
||||
Расширение сначала выполнит `make SRC_DEBUG=1` в `tests/hello` как задачу
|
||||
Sprinter Build. После успешной сборки должно появиться окно Sprinter;
|
||||
launcher дождётся prompt DSS, введёт
|
||||
`A:\\HELLO.EXE` и VS Code остановится в `main`.
|
||||
`A:\\HELLO.EXE` и VS Code остановится в `main`. До этой остановки
|
||||
не вводите символы в MAME: они смешаются с командой launcher в DSS.
|
||||
4. Проверьте Call Stack, scope Registers и Debug Console. После Continue
|
||||
должна сработать подтверждённая точка строки 31.
|
||||
5. На остановке проверьте F11 и F10. Курсор должен переходить только после
|
||||
@@ -168,6 +169,13 @@ launcher задаёт этому процессу `SDL_NO_SIGNAL_HANDLERS=1`, е
|
||||
не была задана вручную. Прямой `SIGTERM` и Stop проверены живыми пробниками
|
||||
на остановке в `main`; они не требуют отдельного патча MAME.
|
||||
|
||||
Для одновременного чтения C-сессии из MCP задайте в launch-профиле короткий
|
||||
фиксированный `"socket": "/tmp/sprinter-sdbg-hello.sock"` и подключите
|
||||
`toolchain/sdbg_mcp.py` после остановки в `main`. MCP использует тот же
|
||||
session server; его личные точки не заменяют точки VS Code. Порядок запуска,
|
||||
16 доступных инструментов и ограничения совместного управления описаны в
|
||||
[руководстве по MCP](sdbg-mcp.md).
|
||||
|
||||
Команда палитры `Sprinter: Build Active Project` собирает приложение по
|
||||
Makefile открытого C-файла. Задачи `Sprinter: Build ...` доступны и в
|
||||
`Tasks: Run Task`. Для launch автоматическая сборка включена по умолчанию,
|
||||
|
||||
Reference in New Issue
Block a user