@darkclaw921/umgt 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +161 -2
- package/architecture.md +105 -0
- package/bin/lm-game-hub.js +7 -0
- package/dist/server/activity.d.ts +17 -0
- package/dist/server/activity.js +55 -0
- package/dist/server/activity.js.map +1 -0
- package/dist/server/agents/activity.d.ts +36 -0
- package/dist/server/agents/activity.js +117 -0
- package/dist/server/agents/activity.js.map +1 -0
- package/dist/server/agents/claude.d.ts +5 -0
- package/dist/server/agents/claude.js +107 -0
- package/dist/server/agents/claude.js.map +1 -0
- package/dist/server/agents/codex.d.ts +5 -0
- package/dist/server/agents/codex.js +128 -0
- package/dist/server/agents/codex.js.map +1 -0
- package/dist/server/agents/core-tools.d.ts +23 -0
- package/dist/server/agents/core-tools.js +298 -0
- package/dist/server/agents/core-tools.js.map +1 -0
- package/dist/server/agents/core.d.ts +9 -0
- package/dist/server/agents/core.js +106 -0
- package/dist/server/agents/core.js.map +1 -0
- package/dist/server/agents/index.d.ts +5 -0
- package/dist/server/agents/index.js +41 -0
- package/dist/server/agents/index.js.map +1 -0
- package/dist/server/agents/kimi.d.ts +5 -0
- package/dist/server/agents/kimi.js +123 -0
- package/dist/server/agents/kimi.js.map +1 -0
- package/dist/server/agents/rpc.d.ts +19 -0
- package/dist/server/agents/rpc.js +102 -0
- package/dist/server/agents/rpc.js.map +1 -0
- package/dist/server/agents/types.d.ts +51 -0
- package/dist/server/agents/types.js +7 -0
- package/dist/server/agents/types.js.map +1 -0
- package/dist/server/app.d.ts +21 -0
- package/dist/server/app.js +38 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/asset-catalog.d.ts +5 -0
- package/dist/server/asset-catalog.js +525 -0
- package/dist/server/asset-catalog.js.map +1 -0
- package/dist/server/asset-media.d.ts +16 -0
- package/dist/server/asset-media.js +170 -0
- package/dist/server/asset-media.js.map +1 -0
- package/dist/server/asset-selection.d.ts +71 -0
- package/dist/server/asset-selection.js +273 -0
- package/dist/server/asset-selection.js.map +1 -0
- package/dist/server/assets.d.ts +69 -0
- package/dist/server/assets.js +669 -0
- package/dist/server/assets.js.map +1 -0
- package/dist/server/browser-gateway.d.ts +82 -0
- package/dist/server/browser-gateway.js +285 -0
- package/dist/server/browser-gateway.js.map +1 -0
- package/dist/server/chat-computer.d.ts +13 -0
- package/dist/server/chat-computer.js +29 -0
- package/dist/server/chat-computer.js.map +1 -0
- package/dist/server/chat-games.d.ts +38 -0
- package/dist/server/chat-games.js +202 -0
- package/dist/server/chat-games.js.map +1 -0
- package/dist/server/chat.d.ts +42 -0
- package/dist/server/chat.js +318 -0
- package/dist/server/chat.js.map +1 -0
- package/dist/server/cli.d.ts +14 -0
- package/dist/server/cli.js +117 -0
- package/dist/server/cli.js.map +1 -0
- package/dist/server/core-client.d.ts +69 -0
- package/dist/server/core-client.js +357 -0
- package/dist/server/core-client.js.map +1 -0
- package/dist/server/directory-picker.d.ts +14 -0
- package/dist/server/directory-picker.js +113 -0
- package/dist/server/directory-picker.js.map +1 -0
- package/dist/server/engine.d.ts +36 -0
- package/dist/server/engine.js +507 -0
- package/dist/server/engine.js.map +1 -0
- package/dist/server/events.d.ts +12 -0
- package/dist/server/events.js +137 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/game-launch.d.ts +16 -0
- package/dist/server/game-launch.js +143 -0
- package/dist/server/game-launch.js.map +1 -0
- package/dist/server/html5.d.ts +9 -0
- package/dist/server/html5.js +107 -0
- package/dist/server/html5.js.map +1 -0
- package/dist/server/interview.d.ts +241 -0
- package/dist/server/interview.js +190 -0
- package/dist/server/interview.js.map +1 -0
- package/dist/server/mcp.d.ts +27 -0
- package/dist/server/mcp.js +91 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/plugins.d.ts +8 -0
- package/dist/server/plugins.js +144 -0
- package/dist/server/plugins.js.map +1 -0
- package/dist/server/process.d.ts +15 -0
- package/dist/server/process.js +89 -0
- package/dist/server/process.js.map +1 -0
- package/dist/server/publication-materials.d.ts +18 -0
- package/dist/server/publication-materials.js +104 -0
- package/dist/server/publication-materials.js.map +1 -0
- package/dist/server/publication-mcp.d.ts +3 -0
- package/dist/server/publication-mcp.js +43 -0
- package/dist/server/publication-mcp.js.map +1 -0
- package/dist/server/publication.d.ts +54 -0
- package/dist/server/publication.js +334 -0
- package/dist/server/publication.js.map +1 -0
- package/dist/server/push.d.ts +81 -0
- package/dist/server/push.js +122 -0
- package/dist/server/push.js.map +1 -0
- package/dist/server/reports.d.ts +4 -0
- package/dist/server/reports.js +40 -0
- package/dist/server/reports.js.map +1 -0
- package/dist/server/roblox-assets.d.ts +41 -0
- package/dist/server/roblox-assets.js +131 -0
- package/dist/server/roblox-assets.js.map +1 -0
- package/dist/server/roblox-connection.d.ts +54 -0
- package/dist/server/roblox-connection.js +331 -0
- package/dist/server/roblox-connection.js.map +1 -0
- package/dist/server/roblox-install.d.ts +4 -0
- package/dist/server/roblox-install.js +170 -0
- package/dist/server/roblox-install.js.map +1 -0
- package/dist/server/roblox-mcp.d.ts +2 -0
- package/dist/server/roblox-mcp.js +34 -0
- package/dist/server/roblox-mcp.js.map +1 -0
- package/dist/server/roblox-play.d.ts +23 -0
- package/dist/server/roblox-play.js +84 -0
- package/dist/server/roblox-play.js.map +1 -0
- package/dist/server/roblox-project-tools.d.ts +11 -0
- package/dist/server/roblox-project-tools.js +119 -0
- package/dist/server/roblox-project-tools.js.map +1 -0
- package/dist/server/roblox-setup.d.ts +37 -0
- package/dist/server/roblox-setup.js +206 -0
- package/dist/server/roblox-setup.js.map +1 -0
- package/dist/server/roblox-skills.d.ts +15 -0
- package/dist/server/roblox-skills.js +15 -0
- package/dist/server/roblox-skills.js.map +1 -0
- package/dist/server/roblox.d.ts +30 -0
- package/dist/server/roblox.js +248 -0
- package/dist/server/roblox.js.map +1 -0
- package/dist/server/routes.d.ts +11 -0
- package/dist/server/routes.js +223 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/security.d.ts +4 -0
- package/dist/server/security.js +64 -0
- package/dist/server/security.js.map +1 -0
- package/dist/server/skills.d.ts +4 -0
- package/dist/server/skills.js +123 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/store.d.ts +25 -0
- package/dist/server/store.js +89 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server/templates/roblox-coin-run.d.ts +2 -0
- package/dist/server/templates/roblox-coin-run.js +326 -0
- package/dist/server/templates/roblox-coin-run.js.map +1 -0
- package/dist/server/templates/roblox-skills.json +55 -0
- package/dist/server/templates/yandex-sdk.d.ts +3 -0
- package/dist/server/templates/yandex-sdk.js +177 -0
- package/dist/server/templates/yandex-sdk.js.map +1 -0
- package/dist/server/updates.d.ts +28 -0
- package/dist/server/updates.js +99 -0
- package/dist/server/updates.js.map +1 -0
- package/dist/server/video-media.d.ts +47 -0
- package/dist/server/video-media.js +224 -0
- package/dist/server/video-media.js.map +1 -0
- package/dist/server/video-routes.d.ts +7 -0
- package/dist/server/video-routes.js +91 -0
- package/dist/server/video-routes.js.map +1 -0
- package/dist/server/video.d.ts +214 -0
- package/dist/server/video.js +301 -0
- package/dist/server/video.js.map +1 -0
- package/dist/server/web-build.d.ts +16 -0
- package/dist/server/web-build.js +232 -0
- package/dist/server/web-build.js.map +1 -0
- package/dist/server/workflow.d.ts +221 -0
- package/dist/server/workflow.js +826 -0
- package/dist/server/workflow.js.map +1 -0
- package/dist/server/yandex-config.d.ts +33 -0
- package/dist/server/yandex-config.js +12 -0
- package/dist/server/yandex-config.js.map +1 -0
- package/dist/server/yandex-godot.d.ts +5 -0
- package/dist/server/yandex-godot.js +107 -0
- package/dist/server/yandex-godot.js.map +1 -0
- package/dist/shared/aspects.d.ts +48 -0
- package/dist/shared/aspects.js +22 -0
- package/dist/shared/aspects.js.map +1 -0
- package/dist/shared/assistant.d.ts +7 -0
- package/dist/shared/assistant.js +36 -0
- package/dist/shared/assistant.js.map +1 -0
- package/dist/shared/chat.d.ts +46 -0
- package/dist/shared/chat.js +2 -0
- package/dist/shared/chat.js.map +1 -0
- package/dist/shared/settings.d.ts +11 -0
- package/dist/shared/settings.js +25 -0
- package/dist/shared/settings.js.map +1 -0
- package/dist/shared/types.d.ts +510 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/assets/AgentActivity-sYJeY5Yf.js +9 -0
- package/dist/web/assets/ArrowRight.es-9w41WqD8.js +1 -0
- package/dist/web/assets/ArrowUpRight.es-BmIrpjWN.js +1 -0
- package/dist/web/assets/AssetMediaPreview-D2cd6oQO.js +1 -0
- package/dist/web/assets/AssetSelectionWizard-a43_6NO7.js +1 -0
- package/dist/web/assets/CaretDown.es-Cq33NYip.js +1 -0
- package/dist/web/assets/CheckCircle.es-D5B3hdvz.js +1 -0
- package/dist/web/assets/CoreAccount-D4ZC8CWv.js +1 -0
- package/dist/web/assets/DownloadSimple.es-DwOWFbs2.js +1 -0
- package/dist/web/assets/FileText.es-D83IIiOG.js +1 -0
- package/dist/web/assets/ImageSquare.es-DxCFt99_.js +1 -0
- package/dist/web/assets/KidsApp-BXWaALoK.css +1 -0
- package/dist/web/assets/KidsApp-D-8t3HPy.js +2 -0
- package/dist/web/assets/MagnifyingGlass.es-rkdOU2rH.js +1 -0
- package/dist/web/assets/PaperPlaneRight.es-U0twumpP.js +1 -0
- package/dist/web/assets/PencilSimple.es-JVHwRvGx.js +1 -0
- package/dist/web/assets/PlainChat-BC4K_tmj.css +1 -0
- package/dist/web/assets/PlainChat-CMxYwKko.js +1 -0
- package/dist/web/assets/Sparkle.es-CmGpvnNm.js +1 -0
- package/dist/web/assets/Square.es-BjNN9Ypc.js +1 -0
- package/dist/web/assets/UploadSimple.es-DxIuxpCC.js +1 -0
- package/dist/web/assets/WarningCircle.es-D63H8cL9.js +1 -0
- package/dist/web/assets/WorkflowJournal-Did0sRta.js +1 -0
- package/dist/web/assets/YandexConfigFields-DDL22Bfw.js +1 -0
- package/dist/web/assets/YandexGamesView-R64RSJRL.js +2 -0
- package/dist/web/assets/bg-build-DIalyCDw.svg +3 -0
- package/dist/web/assets/bg-idea-DHcE-Dhs.svg +3 -0
- package/dist/web/assets/bg-materials-UDVFaueI.svg +3 -0
- package/dist/web/assets/bg-plan-DpfwIsqJ.svg +3 -0
- package/dist/web/assets/bg-play-CNc1QZFK.svg +3 -0
- package/dist/web/assets/dist-7vx7MTaJ.js +1 -0
- package/dist/web/assets/index-Izzbh11U.css +1 -0
- package/dist/web/assets/index-sNciOZYG.js +13 -0
- package/dist/web/assets/jsx-runtime-CdVFa8IP.js +1 -0
- package/dist/web/assets/manrope-cyrillic-wght-normal-Dvxsihut.woff2 +0 -0
- package/dist/web/assets/manrope-greek-wght-normal-DL7QRZyv.woff2 +0 -0
- package/dist/web/assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2 +0 -0
- package/dist/web/assets/manrope-latin-wght-normal-DHIcAJRg.woff2 +0 -0
- package/dist/web/assets/manrope-vietnamese-wght-normal-usUDDRr7.woff2 +0 -0
- package/dist/web/assets/resources-DppXCagL.js +1 -0
- package/dist/web/assets/robot-happy-B6YvlU94.svg +24 -0
- package/dist/web/assets/robot-hello-CCsQgsS-.svg +24 -0
- package/dist/web/assets/robot-listen-Buuz9xII.svg +24 -0
- package/dist/web/assets/robot-sad-CRtiNVWs.svg +24 -0
- package/dist/web/assets/robot-think-CJ5fDBTm.svg +24 -0
- package/dist/web/assets/star-big-CSFDKjws.svg +22 -0
- package/dist/web/assets/star-empty-CC-5vioJ.svg +3 -0
- package/dist/web/assets/star-next-ztuDjOHU.svg +9 -0
- package/dist/web/assets/star-on-l_krO3aV.svg +10 -0
- package/dist/web/assets/ui-wHE_yBK0.js +41 -0
- package/dist/web/assets/umgt-logo-DAOkTN9u.png +0 -0
- package/dist/web/assets/unbounded-cyrillic-wght-normal-C627f1f8.woff2 +0 -0
- package/dist/web/assets/unbounded-latin-ext-wght-normal-D6H-S6MW.woff2 +0 -0
- package/dist/web/assets/unbounded-latin-wght-normal-D5afBTBx.woff2 +0 -0
- package/dist/web/assets/unbounded-vietnamese-wght-normal-rat7GD3o.woff2 +0 -0
- package/dist/web/assets/workflow-BhcU9uvG.css +1 -0
- package/dist/web/assets/workflow-BrIKN5ER.js +34 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/icons/favicon-16.png +0 -0
- package/dist/web/icons/favicon-32.png +0 -0
- package/dist/web/icons/icon-192.png +0 -0
- package/dist/web/icons/icon-512.png +0 -0
- package/dist/web/icons/maskable-192.png +0 -0
- package/dist/web/icons/maskable-512.png +0 -0
- package/dist/web/index.html +28 -0
- package/dist/web/manifest.webmanifest +19 -0
- package/dist/web/sw.js +25 -0
- package/docs/agent-activity-ui.md +33 -0
- package/docs/agent-activity.md +43 -0
- package/docs/agent-permissions-ui.md +15 -0
- package/docs/api.md +145 -0
- package/docs/approval-journal.md +13 -0
- package/docs/asset-media.md +27 -0
- package/docs/asset-providers.md +34 -0
- package/docs/asset-selection.md +31 -0
- package/docs/automatic-approvals.md +15 -0
- package/docs/background-game-launch.md +17 -0
- package/docs/billing-validation.md +23 -0
- package/docs/core-isolation.md +37 -0
- package/docs/core.md +45 -0
- package/docs/generated-text-ui.md +41 -0
- package/docs/interactive-interview-ui.md +29 -0
- package/docs/interactive-interview.md +52 -0
- package/docs/local-codex.md +51 -0
- package/docs/local-meshy.md +13 -0
- package/docs/markdown.md +11 -0
- package/docs/permission-ui.md +11 -0
- package/docs/plan.md +47 -0
- package/docs/remote-core-deployment.md +47 -0
- package/docs/roblox.md +90 -0
- package/docs/validation.md +228 -0
- package/docs/video-reference.md +35 -0
- package/docs/workflow-journal-ui.md +21 -0
- package/docs/yandex-foundation.md +27 -0
- package/docs/yandex-games.md +45 -0
- package/package.json +95 -4
- package/scripts/create-roblox-demo.mjs +31 -0
- package/scripts/diagnose-roblox-mcp.mjs +45 -0
- package/scripts/open-hub-chrome.mjs +60 -0
- package/scripts/smoke-agent.mjs +91 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Яндекс Игры
|
|
2
|
+
|
|
3
|
+
Яндекс Игры — платформа публикации браузерных игр. Hub поддерживает создание проектов Godot/GDScript и HTML5/TypeScript для этой платформы. HTML5 использует Phaser для 2D и Three.js для 3D; Godot использует Web-экспорт с Compatibility renderer и без потоков. Мобильное управление относится к создаваемым играм; сам Hub рассчитан на настольный интерфейс.
|
|
4
|
+
|
|
5
|
+
## Создание проекта
|
|
6
|
+
|
|
7
|
+
Выберите папку системной кнопкой, движок и платформу «Яндекс Игры». Web включается вместе с этой платформой. Настройки проекта определяют устройства, ориентацию, языки, рекламу, сохранения, авторизацию, продукты и технические имена лидербордов. Начальные настройки: компьютер и телефон, RU/EN, облачные сохранения; реклама, покупки и предложение входа выключены.
|
|
8
|
+
|
|
9
|
+
Пройдите интерактивное интервью, проверьте план и подтвердите ассеты. Задачи должны включать выбранные возможности SDK и их проверку. В проект устанавливаются собственные навыки интеграции, инструкции для выбранного движка и подготовки релиза. Источники ассетов, лицензии и исходные байты ресурсов сохраняются существующим механизмом импорта.
|
|
10
|
+
|
|
11
|
+
## SDK и сборки
|
|
12
|
+
|
|
13
|
+
SDK загружается через `/sdk.js` до `YaGames.init()`. Готовность объявляется после инициализации, загрузки состояния и отображения пригодного для игры экрана. Язык определяется через SDK. Игровые паузы, рекламные паузы и скрытая вкладка учитываются независимо; восстановление одной причины не отменяет остальные и не включает звук, выключенный игроком.
|
|
14
|
+
|
|
15
|
+
Рекламная награда выдаётся только после `onRewarded`. Для покупок требуется облачное сохранение: выдача и обработанный токен сохраняются до `consumePurchase`, а незавершённые покупки восстанавливаются без повторной выдачи. В релизе используются актуальные `ysdk.leaderboards`. Недоступность опциональной возможности или отказ игрока от входа не должны блокировать основной игровой цикл.
|
|
16
|
+
|
|
17
|
+
Архив публикации содержит корневой `index.html`, ресурсы игры и необходимые лицензии. Проверки исключают состояние Hub, секреты, исходники разработки и тестовые инструменты; распакованное содержимое ограничено текущими требованиями Яндекса. Локальные проверки и успешная сборка не являются гарантией модерации.
|
|
18
|
+
|
|
19
|
+
## Chrome и консоль
|
|
20
|
+
|
|
21
|
+
Помощник публикации использует **отдельный** [Chrome MCP](https://github.com/hangwin/mcp-chrome). Расширение ChatGPT, доступное в диалоге, не является подключением локальных агентов Hub. Установите совместимое расширение и зарегистрируйте `mcp-chrome-bridge` по инструкции разработчика, затем подключите его в настройках Hub. По умолчанию endpoint — `http://127.0.0.1:12306/mcp`; доступен только loopback endpoint.
|
|
22
|
+
|
|
23
|
+
Диагностика проверяет bridge, ответ расширения и инструменты с явным адресованием вкладки и фоновым режимом. Если версия расширения не поддерживает эти возможности, помощник показывает недоступность; локальная разработка и сборка продолжают работать.
|
|
24
|
+
|
|
25
|
+
Агент получает ограниченные инструменты для собственных вкладок консоли и одобренного превью. Доступа к истории, паролям, произвольным вкладкам и произвольным файлам нет. Для загрузки используются проверенные ID сборки и материалов, а не введённые моделью пути.
|
|
26
|
+
|
|
27
|
+
Помощник работает с черновиком, заполняет согласованные данные, загружает архив и собирает доказательства проверки. Вход, CAPTCHA и юридические действия выполняет пользователь. Пауза, остановка и возобновление сохраняют этапы; перезапуск процесса не должен создавать второй черновик автоматически. Отправка на модерацию выполняется отдельной явной кнопкой после просмотра результата и не следует из автоматического одобрения обычных инструментов.
|
|
28
|
+
|
|
29
|
+
## Различия окружений проверки
|
|
30
|
+
|
|
31
|
+
- Тестовый SDK — явно включённая инфраструктура автоматических тестов; он исключается из релиза.
|
|
32
|
+
- Официальный dev-SDK позволяет проверять локальную интеграцию; он не доказывает работу покупок или загрузку в настоящий черновик.
|
|
33
|
+
- Проверка черновика на платформе использует реальный ID приложения, авторизованную консоль и подготовленную сборку. Непроверенные этапы отмечаются отдельно.
|
|
34
|
+
|
|
35
|
+
На 9 октября 2026 года официальный `@yandex-games/sdk-dev-proxy@0.0.2` автоматически открывает браузер при `--app-id` или `--dev-mode` и не предоставляет `--no-open`. Его ручной запуск приведён в официальной документации; Hub не должен запускать этот режим незаметно с перехватом фокуса или обходить предупреждения о сертификате.
|
|
36
|
+
|
|
37
|
+
## Официальные источники
|
|
38
|
+
|
|
39
|
+
Проверены 9 октября 2026 года. Перед релизом следует сверять актуальную редакцию требований.
|
|
40
|
+
|
|
41
|
+
- [Подключение SDK](https://yandex.ru/dev/games/doc/ru/sdk/sdk-about).
|
|
42
|
+
- [Готовность и разметка геймплея](https://yandex.ru/dev/games/doc/ru/sdk/sdk-game-events).
|
|
43
|
+
- [Реклама](https://yandex.ru/dev/games/doc/ru/sdk/sdk-adv), [сохранения и авторизация](https://yandex.ru/dev/games/doc/ru/sdk/sdk-player).
|
|
44
|
+
- [Покупки](https://yandex.ru/dev/games/doc/ru/sdk/sdk-purchases), [лидерборды](https://yandex.ru/dev/games/doc/ru/sdk/sdk-leaderboard).
|
|
45
|
+
- [Требования](https://yandex.ru/dev/games/doc/ru/concepts/requirements.html), [загрузка игры](https://yandex.ru/dev/games/doc/ru/console/add-new-game), [локальная разработка](https://yandex.ru/dev/games/doc/ru/concepts/local-launch).
|
package/package.json
CHANGED
|
@@ -1,6 +1,97 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@darkclaw921/umgt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Local AI game development workspace",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24.13.0"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"umgt": "bin/lm-game-hub.js",
|
|
11
|
+
"lm-game-hub": "bin/lm-game-hub.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin",
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"architecture.md",
|
|
18
|
+
"docs/*.md",
|
|
19
|
+
"scripts/open-hub-chrome.mjs",
|
|
20
|
+
"scripts/smoke-agent.mjs",
|
|
21
|
+
"scripts/create-roblox-demo.mjs",
|
|
22
|
+
"scripts/diagnose-roblox-mcp.mjs"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "tsx watch src/server/cli.ts --no-open",
|
|
26
|
+
"dev:web": "vite --host 127.0.0.1",
|
|
27
|
+
"build": "tsc -p tsconfig.server.json && vite build",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"start": "node bin/lm-game-hub.js",
|
|
30
|
+
"open:chrome": "node scripts/open-hub-chrome.mjs",
|
|
31
|
+
"doctor": "tsx src/server/cli.ts doctor",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"test:e2e": "playwright test",
|
|
35
|
+
"prepack": "npm run build",
|
|
36
|
+
"smoke:agent": "node scripts/smoke-agent.mjs",
|
|
37
|
+
"test:package": "node scripts/check-package.mjs",
|
|
38
|
+
"demo:roblox": "node scripts/create-roblox-demo.mjs",
|
|
39
|
+
"dev:core": "node scripts/local-core-stack.mjs start",
|
|
40
|
+
"dev:core:status": "node scripts/local-core-stack.mjs status",
|
|
41
|
+
"dev:core:stop": "node scripts/local-core-stack.mjs stop",
|
|
42
|
+
"test:core:live": "node scripts/check-local-core.mjs",
|
|
43
|
+
"test:meshy:live": "node scripts/check-local-meshy.mjs",
|
|
44
|
+
"test:billing:live": "node scripts/check-local-billing.mjs",
|
|
45
|
+
"test:core:isolation": "node scripts/check-core-isolation.mjs"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.291",
|
|
49
|
+
"@fastify/multipart": "^10.1.2",
|
|
50
|
+
"@fastify/static": "^10.1.5",
|
|
51
|
+
"@fontsource-variable/manrope": "^5.3.0",
|
|
52
|
+
"@fontsource-variable/unbounded": "^5.3.0",
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
54
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
55
|
+
"@radix-ui/react-dialog": "^1.2.0",
|
|
56
|
+
"@radix-ui/react-tabs": "^1.1.22",
|
|
57
|
+
"@tailwindcss/vite": "^4.3.3",
|
|
58
|
+
"fastify": "^5.12.5",
|
|
59
|
+
"motion": "^14.0.0",
|
|
60
|
+
"react": "^19.3.0",
|
|
61
|
+
"react-dom": "^19.3.0",
|
|
62
|
+
"react-markdown": "^10.1.0",
|
|
63
|
+
"remark-gfm": "^4.0.1",
|
|
64
|
+
"sharp": "^0.35.5",
|
|
65
|
+
"tailwindcss": "^4.3.3",
|
|
66
|
+
"web-push": "^3.6.7",
|
|
67
|
+
"yauzl": "^3.4.0",
|
|
68
|
+
"zod": "^4.6.5"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@playwright/test": "^1.63.0",
|
|
72
|
+
"@types/node": "^26.6.4",
|
|
73
|
+
"@types/react": "^19.3.0",
|
|
74
|
+
"@types/react-dom": "^19.3.0",
|
|
75
|
+
"@types/web-push": "^3.6.4",
|
|
76
|
+
"@types/yauzl": "^3.4.0",
|
|
77
|
+
"@vitejs/plugin-react": "^6.1.2",
|
|
78
|
+
"tsx": "^4.23.15",
|
|
79
|
+
"typescript": "^7.0.2",
|
|
80
|
+
"vite": "^8.3.3",
|
|
81
|
+
"vitest": "^5.0.3"
|
|
82
|
+
},
|
|
83
|
+
"publishConfig": {
|
|
84
|
+
"access": "public",
|
|
85
|
+
"registry": "https://registry.npmjs.org/"
|
|
86
|
+
},
|
|
87
|
+
"umgtReleaseNotes": {
|
|
88
|
+
"title": "Репорты, переписка с командой и обновления студии",
|
|
89
|
+
"changes": [
|
|
90
|
+
"Сообщайте об ошибках и отправляйте пожелания через жучок в правом нижнем углу.",
|
|
91
|
+
"Прикрепляйте до трёх скриншотов, читайте ответы команды и дополняйте обращения прямо в студии.",
|
|
92
|
+
"В ядре появились просмотр аккаунта отправителя, переписка и статусы обращений.",
|
|
93
|
+
"API позволяет получать обращения, отвечать пользователям и автоматически закрывать репорты.",
|
|
94
|
+
"Студия сообщает о новых версиях, показывает список изменений и команду обновления."
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { resolve, join } from 'node:path';
|
|
3
|
+
import { readFile, realpath, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { createGameProject } from '../dist/server/engine.js';
|
|
6
|
+
import { createCoinRunSources, buildRoblox } from '../dist/server/roblox.js';
|
|
7
|
+
import { Store } from '../dist/server/store.js';
|
|
8
|
+
|
|
9
|
+
const {values}=parseArgs({options:{'project-dir':{type:'string',default:'examples/roblox-coin-run'},'data-dir':{type:'string',default:'.artifacts/roblox/demo-hub'},rebuild:{type:'boolean',default:false}}});
|
|
10
|
+
const projectPath=resolve(values['project-dir']),dataDir=resolve(values['data-dir']);
|
|
11
|
+
let project;
|
|
12
|
+
if(values.rebuild){
|
|
13
|
+
project=JSON.parse(await readFile(join(projectPath,'.lm-game-hub/project.json'),'utf8'));
|
|
14
|
+
if(project.engine!=='roblox')throw new Error('This is not a Roblox demo project');
|
|
15
|
+
project.path=await realpath(projectPath);
|
|
16
|
+
const result=await buildRoblox(project);if(!result.ok)throw new Error(result.output);
|
|
17
|
+
}else{
|
|
18
|
+
const timestamp=new Date().toISOString();
|
|
19
|
+
project={id:randomUUID(),name:'Coin Run',path:projectPath,engine:'roblox',dimension:'3d',platforms:['roblox'],agent:'codex',description:'Персонаж бегает, прыгает по платформам и собирает 20 монет. Checkpoint и финиш.',createdAt:timestamp,updatedAt:timestamp};
|
|
20
|
+
await createGameProject(project);
|
|
21
|
+
project.path=await realpath(project.path);
|
|
22
|
+
await createCoinRunSources(project);
|
|
23
|
+
await writeFile(join(project.path,'.lm-game-hub/project.json'),JSON.stringify(project,null,2));
|
|
24
|
+
}
|
|
25
|
+
const store=new Store(dataDir);
|
|
26
|
+
try{
|
|
27
|
+
store.put('projects',project);
|
|
28
|
+
const lock=JSON.parse(await readFile(join(project.path,'.lm-game-hub/extensions-lock.json'),'utf8'));
|
|
29
|
+
for(const pack of lock.packs)store.project(project.id).put('extensions',pack);
|
|
30
|
+
}finally{store.close();}
|
|
31
|
+
console.log(`Local Roblox demo: ${join(project.path,'builds/game.rbxlx')}\nWASD / arrows: run. Space: jump. Collect 20 coins, then reach the golden finish.\nOpen the file in Roblox Studio and press Play. Studio playtesting has not been performed by this script.\nHub: npm start -- --data-dir ${JSON.stringify(dataDir)}\nRebuild preserving source edits: npm run demo:roblox -- --rebuild`);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
4
|
+
|
|
5
|
+
// Read-only protocol probe. Does not read Hub settings, credentials, Studio
|
|
6
|
+
// content, or run Luau. Prints only tool schema shapes and connected counts.
|
|
7
|
+
const command = process.argv[2] ?? '/Applications/RobloxStudio.app/Contents/MacOS/StudioMCP';
|
|
8
|
+
const transport = new StdioClientTransport({ command, args: [], stderr: 'pipe' });
|
|
9
|
+
let denied = false;
|
|
10
|
+
transport.stderr?.on('data', chunk => {
|
|
11
|
+
if (/operation not permitted|permission denied|os error (?:1|13)/i.test(String(chunk))) denied = true;
|
|
12
|
+
});
|
|
13
|
+
const client = new Client({ name: 'lm-game-hub-readonly-diagnostic', version: '0.1.0' });
|
|
14
|
+
let changes = 0;
|
|
15
|
+
client.setNotificationHandler((await import('@modelcontextprotocol/sdk/types.js')).ToolListChangedNotificationSchema, () => { changes++; });
|
|
16
|
+
try {
|
|
17
|
+
await client.connect(transport, { timeout: 5000 });
|
|
18
|
+
for (let sample = 0; sample < 4; sample++) {
|
|
19
|
+
const tools = [];
|
|
20
|
+
let cursor;
|
|
21
|
+
do {
|
|
22
|
+
const page = await client.listTools(cursor ? { cursor } : {}, { timeout: 5000 });
|
|
23
|
+
tools.push(...page.tools); cursor = page.nextCursor;
|
|
24
|
+
if (tools.length > 300) throw new Error('Too many tools');
|
|
25
|
+
} while (cursor);
|
|
26
|
+
console.log(JSON.stringify({ sample, changes, tools: tools.map(tool => ({
|
|
27
|
+
name: tool.name, required: tool.inputSchema.required ?? [],
|
|
28
|
+
properties: Object.fromEntries(Object.entries(tool.inputSchema.properties ?? {}).map(([key, schema]) => [key, {
|
|
29
|
+
type: schema.type, ...(key === 'datamodel_type' ? { enum: schema.enum } : {}),
|
|
30
|
+
}])),
|
|
31
|
+
})) }));
|
|
32
|
+
if (tools.some(tool => tool.name === 'list_roblox_studios')) {
|
|
33
|
+
const result = await client.callTool({ name: 'list_roblox_studios', arguments: {} }, undefined, { timeout: 5000 });
|
|
34
|
+
const { parseStudios } = await import('../dist/server/roblox-connection.js');
|
|
35
|
+
console.log(JSON.stringify({ sample, connectedStudios: parseStudios(result).length, isError: result.isError === true }));
|
|
36
|
+
}
|
|
37
|
+
if (sample < 3) await delay(1500);
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
console.log(JSON.stringify({ error: denied ? 'permission_denied' : 'connection_failed' }));
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
} finally {
|
|
43
|
+
await client.close().catch(() => {});
|
|
44
|
+
await transport.close().catch(() => {});
|
|
45
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { parseArgs, promisify } from 'node:util';
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
const { values } = parseArgs({ options: {
|
|
12
|
+
log: { type: 'string' }, help: { type: 'boolean', short: 'h' },
|
|
13
|
+
} });
|
|
14
|
+
if (values.help) {
|
|
15
|
+
console.log('npm run open:chrome -- [--log <server-log>]\nOpens the running Hub in Chrome on macOS. Without --log, uses the latest .artifacts/local-stack*.log.');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (process.platform !== 'darwin') throw new Error('Этот скрипт открытия Chrome предназначен для macOS.');
|
|
19
|
+
|
|
20
|
+
let logfile = values.log && resolve(values.log);
|
|
21
|
+
if (!logfile) {
|
|
22
|
+
const directory = resolve(root, '.artifacts');
|
|
23
|
+
const names = await readdir(directory).catch(error => {
|
|
24
|
+
if (error.code === 'ENOENT') return [];
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
const logs = await Promise.all(names.filter(name => /^local-stack.*\.log$/.test(name)).map(async name => {
|
|
28
|
+
const path = resolve(directory, name);
|
|
29
|
+
return { path, modified: (await stat(path)).mtimeMs };
|
|
30
|
+
}));
|
|
31
|
+
logfile = logs.sort((a, b) => b.modified - a.modified)[0]?.path;
|
|
32
|
+
}
|
|
33
|
+
if (!logfile) throw new Error('Не найден лог сервера. Укажите --log <файл с выводом npm start>.');
|
|
34
|
+
|
|
35
|
+
const content = await readFile(logfile, 'utf8');
|
|
36
|
+
const matches = [...content.matchAll(/http:\/\/(?:127\.0\.0\.1|localhost):\d+\/#token=([a-f0-9]{64})\b/g)];
|
|
37
|
+
const match = matches.at(-1);
|
|
38
|
+
if (!match) throw new Error('В логе нет ссылки подключения Game Hub. Укажите лог текущего запуска.');
|
|
39
|
+
const url = new URL(match[0]);
|
|
40
|
+
// Use the same local origin the user opens manually. Never print the session secret.
|
|
41
|
+
url.hostname = 'localhost';
|
|
42
|
+
let response;
|
|
43
|
+
try {
|
|
44
|
+
response = await fetch(new URL('/api/v1/health', url), {
|
|
45
|
+
headers: { Authorization: `Bearer ${match[1]}` },
|
|
46
|
+
redirect: 'error', signal: AbortSignal.timeout(5000),
|
|
47
|
+
});
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error('Game Hub не отвечает. Запустите сервер и укажите его текущий лог.');
|
|
50
|
+
}
|
|
51
|
+
if (!response.ok) throw new Error('Ссылка в логе устарела или сервер не готов. Укажите лог текущего запуска.');
|
|
52
|
+
const health = await response.json();
|
|
53
|
+
if (health.status !== 'ok') throw new Error('Сервер Game Hub не готов.');
|
|
54
|
+
|
|
55
|
+
await promisify(execFile)('open', ['-g', '-a', 'Google Chrome', url.href]);
|
|
56
|
+
console.log(`Game Hub открыт в Chrome: ${url.origin}/`);
|
|
57
|
+
console.log('Подключите агента к уже открытой вкладке. Не вызывайте goto/reload: они могут снова вызвать ERR_BLOCKED_BY_CLIENT.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
main().catch(error => { console.error(error.message); process.exitCode = 1; });
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { Store } from '../dist/server/store.js';
|
|
6
|
+
import { EventBus } from '../dist/server/events.js';
|
|
7
|
+
import { Workflow } from '../dist/server/workflow.js';
|
|
8
|
+
import { createGameProject, detectGodot } from '../dist/server/engine.js';
|
|
9
|
+
import { adapters } from '../dist/server/agents/index.js';
|
|
10
|
+
|
|
11
|
+
const agent = process.argv[2] ?? 'codex';
|
|
12
|
+
if (!['codex', 'kimi', 'claude'].includes(agent)) throw new Error('Usage: node scripts/smoke-agent.mjs [codex|kimi|claude]');
|
|
13
|
+
const root = process.env.LMGH_SMOKE_ROOT ?? await mkdtemp(join(tmpdir(), 'lmgh-real-game-'));
|
|
14
|
+
if (!root.startsWith(join(tmpdir(), 'lmgh-real-game-'))) throw new Error('Smoke resume directory must be a generated temporary fixture');
|
|
15
|
+
const dataDir = join(root, 'state');
|
|
16
|
+
const store = new Store(dataDir);
|
|
17
|
+
const events = new EventBus(store);
|
|
18
|
+
const transcript = [];
|
|
19
|
+
const wrapped = Object.fromEntries(Object.entries(adapters).map(([id, adapter]) => [id, {
|
|
20
|
+
id,
|
|
21
|
+
async run(options) {
|
|
22
|
+
const result = await adapter.run(options);
|
|
23
|
+
transcript.push({ readOnly: options.readOnly, text: result.text });
|
|
24
|
+
return result;
|
|
25
|
+
},
|
|
26
|
+
}]));
|
|
27
|
+
const workflow = new Workflow({ store, events, dataDir, token: randomUUID() }, { adapters: wrapped });
|
|
28
|
+
const engine = await detectGodot();
|
|
29
|
+
if (!engine.available) { store.close(); await rm(root, { recursive: true, force: true }); throw new Error('Install Godot 4 or set GODOT_PATH before running this smoke test.'); }
|
|
30
|
+
const existing = store.list('projects')[0];
|
|
31
|
+
const project = existing ?? {
|
|
32
|
+
id: randomUUID(), name: 'Проверка счётчика', path: join(root, 'game'),
|
|
33
|
+
engine: 'godot', dimension: '2d', platforms: ['desktop'], agent,
|
|
34
|
+
description: 'Один экран с кнопкой и счётчиком.', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
const captured = [];
|
|
37
|
+
events.subscribe(event => {
|
|
38
|
+
captured.push(event);
|
|
39
|
+
if (event.type === 'run.updated') console.log(JSON.stringify({ run: event.payload.kind, status: event.payload.status, error: event.payload.error }));
|
|
40
|
+
if (event.type === 'task.updated') console.log(JSON.stringify({ task: event.payload.title, status: event.payload.status, attempts: event.payload.attempts, error: event.payload.error }));
|
|
41
|
+
if (event.type === 'permission.requested') {
|
|
42
|
+
const command = typeof event.payload.details?.command === 'string' ? event.payload.details.command : '';
|
|
43
|
+
// This optional smoke test permits only the installed headless engine.
|
|
44
|
+
// Other requests are denied and recorded rather than bypassing approvals.
|
|
45
|
+
const wrapper = command.match(/^\/bin\/(?:zsh|bash|sh)\s+-lc\s+(['"])([\s\S]*)\1$/);
|
|
46
|
+
const unquoted = (wrapper?.[2] ?? command).replace(/^["']/, '');
|
|
47
|
+
const allow = unquoted.startsWith(engine.executable) && command.includes('--headless') && !/[;|&`$\n]/.test(command);
|
|
48
|
+
console.log(JSON.stringify({ permission: event.payload.method, allow, command }));
|
|
49
|
+
workflow.answer(project.id, event.payload.id, { allow });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
let successful = false;
|
|
53
|
+
const timer = setTimeout(() => workflow.control(project.id, 'stop'), 6 * 60_000);
|
|
54
|
+
const stop = () => workflow.control(project.id, 'stop');
|
|
55
|
+
process.once('SIGINT', stop); process.once('SIGTERM', stop);
|
|
56
|
+
try {
|
|
57
|
+
if (existing) {
|
|
58
|
+
workflow.recover();
|
|
59
|
+
for (const task of workflow.snapshot(project.id).tasks) {
|
|
60
|
+
if (task.status === 'failed') workflow.retryTask(project.id, task.id);
|
|
61
|
+
else if (task.status === 'open') store.project(project.id).put('tasks', { ...task, attempts: 0 });
|
|
62
|
+
}
|
|
63
|
+
workflow.execute(project.id);
|
|
64
|
+
} else {
|
|
65
|
+
await createGameProject(project);
|
|
66
|
+
store.put('projects', project);
|
|
67
|
+
const plan = await workflow.savePlan(project.id, '# Проверочный счётчик\n\nСоздать один экран Godot 2D: Label с числом 0 и Button «Нажать». Сигнал pressed увеличивает счёт на 1. Строго один эпик и одна задача, без внешних ассетов, плагинов и экспортных сборок. Только три автоматизируемых критерия: сцена содержит Label со счётом и Button; программное испускание pressed три раза обновляет Label до 3; headless-импорт и запуск не содержат ошибок. Проверка кликов выполняется SceneTree-скриптом без ручной проверки и без GUI. Не добавлять субъективные критерии.');
|
|
68
|
+
workflow.approve(project.id, plan.id);
|
|
69
|
+
}
|
|
70
|
+
await workflow.settle(project.id);
|
|
71
|
+
const selection = workflow.snapshot(project.id).assetSelection;
|
|
72
|
+
if (selection && selection.status !== 'confirmed') {
|
|
73
|
+
if (selection.status !== 'choosing' || selection.needs.length) throw new Error('The no-external-assets smoke plan unexpectedly requires asset selection; inspect the real response.');
|
|
74
|
+
workflow.confirmSelection(project.id, selection.id, selection.revision);
|
|
75
|
+
await workflow.settle(project.id);
|
|
76
|
+
}
|
|
77
|
+
const snapshot = workflow.snapshot(project.id);
|
|
78
|
+
successful = snapshot.run?.status === 'completed' && snapshot.tasks.length > 0 && snapshot.tasks.every(task => task.status === 'done');
|
|
79
|
+
await mkdir('.artifacts/live-smoke', { recursive: true });
|
|
80
|
+
await writeFile('.artifacts/live-smoke/real-game.json', JSON.stringify({ agent, successful, run: snapshot.run, tasks: snapshot.tasks }, null, 2));
|
|
81
|
+
await writeFile(join(root, 'transcript.json'), JSON.stringify(transcript, null, 2));
|
|
82
|
+
await writeFile(join(root, 'events.json'), JSON.stringify(captured, null, 2));
|
|
83
|
+
console.log(JSON.stringify({ successful, evidenceDirectory: root }));
|
|
84
|
+
if (!successful) process.exitCode = 1;
|
|
85
|
+
} finally {
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
process.removeListener('SIGINT', stop); process.removeListener('SIGTERM', stop);
|
|
88
|
+
await workflow.close();
|
|
89
|
+
store.close();
|
|
90
|
+
if (successful && !process.env.LMGH_KEEP_SMOKE) await rm(root, { recursive: true, force: true });
|
|
91
|
+
}
|