@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,23 @@
|
|
|
1
|
+
# Проверка всех реализованных списаний
|
|
2
|
+
|
|
3
|
+
19 октября 2026. Боевой UMGT и денежные платежи не используются. Стенд: реальное ядро и PostgreSQL, локальный UMGT с сохраняемым журналом, реальный Codex для двух контрольных AI-вызовов. Остальные граничные сценарии проверены в изолированных тестах с детерминированным AI-провайдером.
|
|
4
|
+
|
|
5
|
+
| Сценарий | Результат | Доказательство |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| AI по подписке | Успех: списано 19 637 токенов подписки, PAYG и рубли сохранены | Новый настоящий вызов Codex |
|
|
8
|
+
| AI без активной подписки за купленные токены | Успех: списано 18 852 PAYG-токена, рубли сохранены | Новый настоящий вызов Codex |
|
|
9
|
+
| Повтор AI requestId | Прежний результат; второй вызов Codex и новая проводка отсутствуют | Повторены оба живых запроса |
|
|
10
|
+
| Смешанное списание | При расходе 30: 10 из подписки и 20 из PAYG | Core + сохраняемый UMGT в отдельной схеме PostgreSQL |
|
|
11
|
+
| Исчерпание дневного и недельного лимитов | Без PAYG отказ до вызова провайдера; при наличии PAYG списание из PAYG | Изолированные интеграционные тесты |
|
|
12
|
+
| Месячный лимит | Отказ до вызова провайдера, расхода нет | Изолированные интеграционные тесты |
|
|
13
|
+
| Временный сбой списания | pending блокирует новые вызовы; повтор списывает один раз | Изолированные интеграционные тесты; ранее живой тест очереди |
|
|
14
|
+
| Потерянная квитанция, сбой/прерывание провайдера, неизвестный usage | Идемпотентный повтор либо сверка; оценочные токены не списываются | Автотесты ядра |
|
|
15
|
+
| Meshy 3D | Предыдущее реальное списание 5 кредитов и одна локальная проводка 1 ₽ сохранены | Проверена существующая квитанция; новой генерации нет |
|
|
16
|
+
| Денежный контракт media.image/media.audio/media.video/avatar.video | Тестовый UMGT проверяет включение сервиса и баланс, списывает деньги один раз, сохраняет LLM-токены | Только тесты контракта; адаптеры генерации этих сервисов в ядре отсутствуют |
|
|
17
|
+
| Покупка подписки, покупка токенов, пополнение рублёвого баланса | Не проверены | Это внешние checkout-страницы UMGT; имитация не доказывает реальные платежи |
|
|
18
|
+
|
|
19
|
+
Общая сверка после проверки: 8 реальных вызовов Codex, 156 083 токена. Сумма фактического usage CLI точно совпала с оплаченными AI-операциями PostgreSQL и токенами в UMGT. Все 9 оплаченных операций (8 AI + 1 Meshy) имеют ровно по одной совпадающей квитанции с теми же суммами и transaction_id. Рублёвый баланс остался 149 900 копеек. Первоначальный срок подписки восстановлен; фактически использованные тестовые токены остаются отражены в журнале.
|
|
20
|
+
|
|
21
|
+
Ядро: 44/44 теста прошли, из них 17 новых тестов с настоящим HTTP-путём Core → локальный UMGT и отдельной схемой PostgreSQL. Проверка TypeScript прошла. Изменения платёжной логики по результатам этой проверки не потребовались.
|
|
22
|
+
|
|
23
|
+
Детальные результаты живой сверки: `.artifacts/core-local/billing-result/live-proof.json`. Повторная команда `npm run test:billing:live` выполняет **ещё два реальных вызова Codex** и создаёт два новых легитимных списания на локальном тестовом счёте. Она не создаёт задач Meshy и не вызывает боевой UMGT. Полный набор без платных внешних вызовов: `TEST_DATABASE_URL=postgresql://igorgerasimov@127.0.0.1:55439/postgres npm test --prefix ../game-hub-core`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Изоляция пользователей ядра
|
|
2
|
+
|
|
3
|
+
Проверено 21 октября 2026. Каждый пользователь определяется подтверждённым `user_id` UMGT. Вход выдаёт собственную пару access/refresh; AI-сессии, запросы, операции и результаты принадлежат этому пользователю. `sessionId` или `operationId` сами по себе не дают доступа: API проверяет владельца по Bearer-токену.
|
|
4
|
+
|
|
5
|
+
Для разных людей нужны **разные аккаунты UMGT**, а на клиенте — отдельные установки Hub или отдельные папки данных. Несколько ключей одного аккаунта UMGT всё равно означают одного пользователя. Один общий ключ UMGT намеренно даёт доступ к общему аккаунту и не обеспечивает изоляцию между людьми. Общая серверная учётная запись AI-провайдера не используется как идентификатор пользователя: ядро передаёт модели только историю конкретной AI-сессии.
|
|
6
|
+
|
|
7
|
+
Один локальный Hub рассчитан на одного пользователя и хранит одно подключение к Core. Несколько вкладок с одним локальным Hub-токеном — одна локальная учётная запись. Для нескольких устройств одного пользователя создаются разные сессии входа; принадлежащие этому аккаунту AI-сессии доступны после повторного входа. Разные аккаунты не получают такого доступа.
|
|
8
|
+
|
|
9
|
+
## Что проверено
|
|
10
|
+
|
|
11
|
+
- 24 разных пользователя одновременно выполняют два шага AI: 48 вызовов и 48 отдельных проводок. У каждого своя история; общие requestId у разных людей не смешивают результаты.
|
|
12
|
+
- 24 одновременные задачи Meshy создаются и учитываются раздельно. Проверки используют имитацию провайдера, реальных генераций и расходов Meshy нет.
|
|
13
|
+
- Два экземпляра Core используют одну PostgreSQL через независимые пулы соединений. Повтор запроса на другом экземпляре возвращает только собственный результат.
|
|
14
|
+
- Чужие AI-сессии нельзя читать, продолжать, дополнять результатами инструментов или использовать для повтора запроса. Чужие операции и GLB-ссылки недоступны, отмена чужого выполняющегося запроса отклоняется.
|
|
15
|
+
- Собственные параллельные AI-запросы одного аккаунта сериализуются. Ожидающее списание или исчерпание лимита одного пользователя не блокирует другого.
|
|
16
|
+
- Refresh, logout, замена ключа, административная блокировка и отзыв действуют на нужный аккаунт. Refresh-токен нельзя использовать как access-токен; подмена владельца в JSON и обращение обычного пользователя к административному API отклоняются.
|
|
17
|
+
- Два настоящих локальных HTTP Hub с отдельными папками данных подключены к двум Core. Их агенты параллельно записали и затем прочитали свой private.txt, продолжив собственные сессии. Подстановка чужой сессии была отклонена до нового вызова модели. У каждого четыре оплаченных шага по 30 тестовых токенов; чужой локальный токен Hub не принимается.
|
|
18
|
+
- Восемь одновременных вызовов тестового моста Codex получают разные временные рабочие папки и отдельные разговоры. Проверены параметры ephemeral/ignore-user-config, отсутствие resume и удаление временных данных. В этом тесте CLI заменён имитацией, платных обращений к Codex нет.
|
|
19
|
+
|
|
20
|
+
## Исправление
|
|
21
|
+
|
|
22
|
+
Проверка 24 одновременных пользователей воспроизвела ошибки в AI и Meshy: обработчик уже удерживал соединение PostgreSQL для блокировки аккаунта, но вложенное чтение модели/результата запрашивало второе соединение. При занятых 20 слотах запросы ждали друг друга до таймаута. Чтение теперь использует уже занятое соединение. После исправления оба сценария проходят.
|
|
23
|
+
|
|
24
|
+
Это проверка изоляции и конкурентного выполнения на локальном стенде, а не измерение предельной пропускной способности целевого сервера или реального AI-провайдера.
|
|
25
|
+
|
|
26
|
+
## Воспроизведение
|
|
27
|
+
|
|
28
|
+
Нужны собранные Hub и соседний `../game-hub-core` и отдельная локальная PostgreSQL для тестов. Укажите её в TEST_DATABASE_URL; команды создают и удаляют только свои временные схемы.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
TEST_DATABASE_URL=postgresql://igorgerasimov@127.0.0.1:55440/postgres npm test --prefix ../game-hub-core
|
|
32
|
+
TEST_DATABASE_URL=postgresql://igorgerasimov@127.0.0.1:55440/postgres npm run test:core:isolation
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
На дату проверки: **56/56 тестов ядра**, проверка типов и production-сборка прошли; отдельная проверка двух Hub прошла все 5 сценариев. Внешние провайдеры и UMGT заменены тестовыми HTTP-сервисами. Старый биллинговый стенд и реальные проекты не запускались и не менялись.
|
|
36
|
+
|
|
37
|
+
Артефакты `.artifacts/multi-user-20261021/`: `before.json` (два воспроизведённых сбоя до исправления), `after.json` (итоговый прогон), `hubs-proof.json` (проверка двух Hub). Все тестовые HTTP-сервисы закрываются скриптом. Временная PostgreSQL после завершения проверки остановлена.
|
package/docs/core.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Game Hub Core и UMGT
|
|
2
|
+
|
|
3
|
+
Ядро — отдельный проект и Git-репозиторий `../game-hub-core`, который запускается на другом сервере. Hub остаётся локальным приложением. Серверные модели вызываются с ключом оператора, а игровые файлы, Godot, Roblox Studio, команды и MCP-инструменты выполняются на компьютере пользователя.
|
|
4
|
+
|
|
5
|
+
## Подключение
|
|
6
|
+
|
|
7
|
+
В Настройки → Подписка и доступ укажите HTTPS-адрес ядра без пути и API-ключ из https://game.aircoding.ai/app/. Для локальной разработки разрешён HTTP на localhost. Переменная `LM_HUB_CORE_URL` может заранее задать адрес ядра; при её наличии он имеет приоритет над введённым адресом.
|
|
8
|
+
|
|
9
|
+
Для временной проверки удалённого HTTP оператор может задать `LM_HUB_CORE_ALLOW_HTTP_ORIGIN=http://IP:PORT` при запуске Hub. Разрешается только этот точный origin; другие хосты, порты, пути и URL с секретами отклоняются. HTTP передаёт ключ и токены без TLS. Результат развёртывания и проверки Roblox описан в [отчёте](remote-core-deployment.md).
|
|
10
|
+
|
|
11
|
+
Ключ UMGT передаётся только ядру и сохраняется там зашифрованным. Браузер его не сохраняет; Hub хранит собственные токены в `core-session.json` в папке данных с правами 0600. Токены не включаются в `/settings`, `/core`, события или журналы. Выход отзывает сессию на сервере и удаляет локальный файл. Замена ключа отзывает предыдущие сессии Hub этого аккаунта.
|
|
12
|
+
|
|
13
|
+
Для каждого нового ответа используется стандартная модель, настроенная администратором ядра. Пользователь не может переопределить её. Старые идентификаторы агентов в проектах остаются совместимыми, но все они направляются в Core; старые поля CLI не определяют серверную модель.
|
|
14
|
+
|
|
15
|
+
## Доступ и расход
|
|
16
|
+
|
|
17
|
+
Активная подписка UMGT даёт дневной и недельный запас токенов. При его исчерпании используются купленные токены; они позволяют работать и без активной подписки. Периоды, срок подписки и остатки определяет UMGT, локальное приложение их не пересчитывает.
|
|
18
|
+
|
|
19
|
+
Перед каждым шагом модели ядро вызывает UMGT check, после него передаёт фактические prompt_tokens + completion_tokens в usage с `service=openrouter.game_hub`, `cost_kop=0`, `require_subscription=false`. Баланс в рублях показывается для полноты аккаунта и за AI-вызовы не списывается. Произвольного API списания по данным локального клиента нет.
|
|
20
|
+
|
|
21
|
+
Проверка не резервирует средства. Ядро сохраняет результат и расход, повторяет временно неудавшиеся списания с тем же ключом идемпотентности. До разрешения pending/rejected/unknown новые AI-вызовы аккаунта запрещены. Полученный результат остаётся в истории; инструменты после ответа AI выполняются только после подтверждённого списания. Неизвестный расход сверяет администратор по данным AI-провайдера.
|
|
22
|
+
|
|
23
|
+
Нет связи с ядром или UMGT — новые AI-вызовы не запускаются. Просмотр проектов, файлов и ручная работа с редактором остаются доступны. Изменение или удаление клиентского кода не раскрывает серверный ключ AI.
|
|
24
|
+
|
|
25
|
+
## Локальное API
|
|
26
|
+
|
|
27
|
+
Все маршруты защищены существующей локальной сессией Hub и проверкой loopback/origin:
|
|
28
|
+
|
|
29
|
+
- `GET /api/v1/core`: состояние подключения, данные UMGT; без секретов.
|
|
30
|
+
- `POST /api/v1/core/connect`: `{url,key}` — обмен ключа UMGT на собственные токены ядра.
|
|
31
|
+
- `PUT /api/v1/core/model`: устаревший маршрут возвращает 403 `model_managed_by_core`. Модель задаёт только администратор ядра; прежние локальные настройки игнорируются.
|
|
32
|
+
- `POST /api/v1/core/logout`: отзыв сессии и удаление локальных токенов.
|
|
33
|
+
- `GET /api/v1/core/operations`: последние собственные операции и ошибки учёта.
|
|
34
|
+
|
|
35
|
+
Серверный API и развёртывание описаны в отдельном репозитории Core. Контракт между Hub и Core — `/api/v1` с OpenAPI, для AI-ответов используется SSE. Каждый шаг имеет новый requestId; повторы не создают повторный расход. Ответы инструментов связаны с выданными сервером tool_call_id. Отмена передаётся серверу; при потере итогового usage операция может потребовать сверки.
|
|
36
|
+
|
|
37
|
+
## Управление
|
|
38
|
+
|
|
39
|
+
Админка ядра блокирует доступ только к Hub, отзывает его сессии, показывает данные UMGT, разрешает модели и помогает разбирать списания с аудитом. Выдача, продление и аннулирование подписок выполняются в UMGT: в предоставленной спецификации v1.2 нет административного API для этих действий. Платежи, другие продукты UMGT и локальные CLI не являются частью нового серверного AI-провайдера.
|
|
40
|
+
|
|
41
|
+
## Проверки
|
|
42
|
+
|
|
43
|
+
`tests/core-integration.test.ts` проверяет подключение, приватное хранение токенов, работу локальных инструментов, разрешения, read-only, границы файлов и блокировку отключённого AI. Тесты отдельного ядра используют собственную схему PostgreSQL и локальные имитации UMGT/AI; боевых списаний нет.
|
|
44
|
+
|
|
45
|
+
Многопользовательская изоляция, условия отдельных аккаунтов и результаты параллельной проверки описаны в [отдельном отчёте](core-isolation.md).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Generated text: frost reveal
|
|
2
|
+
|
|
3
|
+
The selected “Тающий иней” treatment is used for newly received model text. `GeneratedMarkdown.tsx` keeps semantic React Markdown content in the document throughout the effect. The lightweight `GeneratedText.tsx` context/effect module stays in the entry bundle; heavy Markdown remains in the lazy workflow bundle. New source fragments fade from a light frost (inline-compatible blurred text shadow and low opacity) to clear text in 900ms. Finished text does not move. Native headings, paragraphs, lists, tables and fenced code are rendered before the reply finishes; incomplete fenced code is already a code block. Existing URL restrictions and escaped raw HTML remain intact, with no external images loaded automatically.
|
|
4
|
+
|
|
5
|
+
## Coverage
|
|
6
|
+
|
|
7
|
+
- Live chat and saved assistant answers use the same Markdown renderer. A saved canonical answer replaces the transient response, sharing the already consumed source prefix instead of duplicating or replaying it.
|
|
8
|
+
- The plan modal shows decoded Markdown while a planning response is still arriving. The decoder accepts only the expected leading JSON `markdown` string, handles split escapes and incomplete Unicode, and never exposes the JSON wrapper. The final validated plan is authoritative. Manually saved plan versions have no generation animation.
|
|
9
|
+
- New epic/task titles, descriptions and acceptance criteria receive the treatment. A completed task’s human verification summary renders as Markdown; its checks JSON and Godot output remain plain technical text.
|
|
10
|
+
- Interview public introductions, completion summaries, question prompts, descriptions and option labels receive the treatment. Controls, numeric readouts and user answers stay unchanged. Model JSON is never displayed.
|
|
11
|
+
- Static navigation, status/action labels, user input and journal/technical output are excluded.
|
|
12
|
+
|
|
13
|
+
## Provenance and bounded work
|
|
14
|
+
|
|
15
|
+
`GeneratedTextState` belongs to one mounted application tab. It accepts selected-project events, rejects duplicate/replayed event IDs and timestamps predating the mount, and uses the active workflow kind to identify generated outputs. Snapshot history is not opted in. Reconnect snapshots also prevent older missed run events from reviving a completed run; deltas predating the current run start are rejected. Project switching clears transient text and eligibility. Each entity has consumed source offsets: paragraph reparsing, reconnect, tab revisits and canonical handoff cannot replay already claimed ranges. Unseen results expire after 2.5 seconds, so opening old sections does not animate old content. Live stream eligibility is refreshed as new chunks arrive.
|
|
16
|
+
|
|
17
|
+
Chat chunks are coalesced into one UI update per 100ms. Terminal events flush pending text immediately; stopped or failed chat retains its partial response until the next run or project change. Model streams are bounded to 250,000 characters in the transient view; the canonical stored result remains authoritative. The renderer adds at most 1,200 fragments and runs at most 32 simultaneous Web Animations. Long bursts above the limit appear directly. The entity registry is bounded to 1,500 entries; up to 128 short-lived reveal clocks preserve unfinished effects through canonical DOM replacement. There is no per-frame JavaScript glyph loop and no delayed text queue.
|
|
18
|
+
|
|
19
|
+
Reduced-motion users see clean text immediately. Hiding the document finishes active effects; new hidden-document content does not create animations or a timer backlog. Unmounting cancels active effects. Animation spans are normal inline text, without duplicate screen-reader copies or token-level live announcements. Existing agent activity announcements and Stop controls remain unchanged.
|
|
20
|
+
|
|
21
|
+
Planning may temporarily show its normal progress state until a valid `markdown` field begins. Decomposition/execution machine JSON is deliberately withheld; validated public task/epic results are then shown. Transient text is not separately persisted across a full page reload: stored messages/plans remain available and newly received chunks continue; final canonical replies restore the full authoritative content.
|
|
22
|
+
|
|
23
|
+
## Validation
|
|
24
|
+
|
|
25
|
+
Focused state/render checks cover escaped partial JSON boundaries, Markdown before completion, open code fences, safe URLs/raw HTML, range ownership and canonical handoff, terminal flush/reset, replay/project isolation, machine-JSON exclusion, burst bounds, fragment bounds and SSR. Existing Markdown and interview-render checks are included in the focused run.
|
|
26
|
+
|
|
27
|
+
`tests/e2e/frost-text.spec.ts` uses controlled provider responses with the real API/SSE/workflow/database. It exercises live formatted chat, stable settled DOM, the animation lifecycle, canonical handoff/reload, live plans, task decomposition/execution summaries, interview controls, mobile reduced motion and Stop. Any screenshots from this fixture are explicitly test-provider evidence, not a live LLM run. Root owns production browser verification and final validation reporting.
|
|
28
|
+
|
|
29
|
+
Focused validation passed: 33 tests across generated text, existing Markdown and interview UI; the comprehensive new browser fixture passed in 7.3 seconds (9.5 seconds including setup). A real readonly Codex conversation was separately verified by root: active frost spans, a heading, two list items and a code block appeared before completion. At completion mobile width390 matched document width390; active effects were zero, and reload did not animate history. That check added only chat messages to the owned QA project; plans/tasks and the concurrently running user project were unchanged.
|
|
30
|
+
|
|
31
|
+
The final entry bundle is494.02kB, with199.53kB in the lazy workflow chunk and no chunk-size warning. A test found that inline custom Markdown components remounted settled text during append; the production fix uses module-stable component identities, and the browser regression now checks DOM identity explicitly.
|
|
32
|
+
|
|
33
|
+
## Fast-token correction
|
|
34
|
+
|
|
35
|
+
The first acceptance check proved that an animation started, but used coarse, manually gated deltas. That was insufficient for a real rapid stream: the animation effect depended on the fragment end offset, so every appended tail triggered React cleanup and cancelled the reveal. In addition, ordinary non-replaced inline spans are not a dependable CSS filter surface. The corrected renderer separates source-range claims from the animation lifetime. An append updates the existing text and consumes its range without cancelling or restarting the ongoing effect. A canonical message/plan inherits the original reveal clock and finishes the remaining duration, instead of cutting it short or replaying from the beginning.
|
|
36
|
+
|
|
37
|
+
Frost now uses blurred `text-shadow`, color and opacity, which paint on ordinary inline text without forcing wide inline-block chunks or changing wrapping. Settled content returns to its inherited styles. Reduced-motion/hidden-document cleanup also clears pending reveal clocks. Animation slots are released synchronously on unmount. Fenced code inherits a safe source offset from its enclosing code block because its generated HAST text node may omit a position.
|
|
38
|
+
|
|
39
|
+
The new browser regression emits chunks every30ms and inspects the actual Web Animation object, increasing currentTime, running state and computed text shadow across multiple appends. It then checks canonical continuation, final clean text, mobile width and reload. This verifies visible rendering mechanics rather than treating a data attribute as sufficient evidence. Separate real API/SSE coverage now verifies natural start after completed interview, stale old-plan blocking and explicit fresh-plan creation. Model replies in these tests remain controlled fixtures.
|
|
40
|
+
|
|
41
|
+
Final focused verification of this correction:35 unit/render checks passed; all five selected browser scenarios passed in23.5seconds. The30ms case passed in3.6seconds, including real animation identity/progress, visible computed inline blur, canonical fenced-code continuation, clean completion,390px layout and reload. The natural-start/fresh-plan scenario passed in4.7seconds. Original controlled-provider captures are in `.artifacts/frost-chat-fix-20261008/screenshots/fixture-fast-active.png`, `fixture-fast-mobile.png` and `fixture-interview-plan.png`. Visual inspection of the active capture shows a crisp settled prefix and a genuinely blurred incoming tail. These captures do not claim an installed-model run; root owns any live Chrome acceptance and final full-suite results.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Interactive interview in chat
|
|
2
|
+
|
|
3
|
+
`InterviewRoundCard` replaces the assistant's option list with native controls when the workspace snapshot contains an interview round linked to that message. It renders the round introduction and two or three questions. Single-choice radio buttons, multi-choice checkboxes, a range slider paired with a numeric input, free text and a custom choice are available according to the server question schema. Each group uses a fieldset/legend; option labels, keyboard controls, visible focus and reduced-motion styles use native browser behavior.
|
|
4
|
+
|
|
5
|
+
One Continue button sends all answers to `POST /api/v1/projects/:id/interview/:roundId/answers`. Option IDs, not display labels, are sent. Custom text is separate; it counts as one choice for a multi-choice limit. A required range without an explicit default remains unanswered until interaction or number entry. Home/End keyboard keys can explicitly select its minimum/maximum. Local validation checks required answers, bounds, step grid, custom text and selection limits; the server remains authoritative.
|
|
6
|
+
|
|
7
|
+
Drafts are stored in browser localStorage under the project and stable round ID, so reload and temporary navigation preserve selections. Restoring a draft filters removed/unknown options and extra question IDs. Storage errors do not prevent the form from working. Failed API submission keeps the draft and shows a visible error; successful submission removes the draft, prevents duplicate sending and displays the accepted round as read-only. If submission succeeds but refresh fails, the UI explicitly says the answers were saved rather than asking the user to repeat them.
|
|
8
|
+
|
|
9
|
+
Answered or superseded rounds are compact disclosures with question/answer summaries. A completed interview is explicitly labelled «Интервью завершено». Its «Создать план» button requests a fresh draft through POST /plan and then opens the plan dialog; it does not merely show an older saved plan. The ordinary header Plan button still opens saved history without generating anything. After completion, a server-recognized explicit start message returns run.kind=planning and ChatView automatically opens the generating/reviewable plan. Neither path approves a plan or begins game development automatically. If the latest answers make a saved plan stale, Overview says «План нужно обновить», Tasks disables start/resume, and Plan disables approval while offering regeneration. Backend provenance/freshness guards remain authoritative. Failed generation retains the stale warning rather than allowing old tasks to run. The free message composer remains available; the server may supersede an open round when the user sends a conversational answer instead.
|
|
10
|
+
|
|
11
|
+
The backend supplies strict legacy rounds for recognized existing numbered A/B/C questions. The UI maps those rounds to their original assistant message and renders the same controls without modifying the transcript or inventing a new model reply. Legacy round IDs are stable, so browser drafts survive reload. No frontend parser guesses missing question semantics.
|
|
12
|
+
|
|
13
|
+
The form sits within the chat's existing scroll region. A newly opened round scrolls to its first question rather than hiding its controls at the end of a long chat. The shared current-action strip and the separate, nonshrinking Stop row remain available while the next LLM round is running. Interview JSON is suppressed by the server rather than rendered as streamed text.
|
|
14
|
+
|
|
15
|
+
## Verification scope
|
|
16
|
+
|
|
17
|
+
`tests/interview-ui.test.ts` verifies draft hydration and isolation, required slider handling, grouped payload shape, limits/grid validation, optional text, native control semantics and safe read-only rendering.
|
|
18
|
+
|
|
19
|
+
`tests/e2e/interview.spec.ts` uses an explicitly injected deterministic model with real HTTP, SSE, workflow validation and SQLite. Its first scenario exercises single/multi/range/custom controls, draft reload, mobile/reduced motion, a simulated transport error retaining the draft, real grouped submission and persisted answers, the next round with free text, completion and access to the plan. The second scenario seeds an existing legacy transcript in a disposable project, verifies native choices and persisted draft without submitting or invoking the model. Fixture screenshots are labelled `fixture-*`; they are not evidence of a live installed model's generated questions.
|
|
20
|
+
|
|
21
|
+
On 8 October 2026, the final focused browser scenarios both passed (5.6 seconds total) and nine frontend render/state checks passed. The render regression verifies that a user answer referencing the same round ID remains an ordinary chat message rather than creating a second copy of the assistant's read-only round.
|
|
22
|
+
|
|
23
|
+
Final complete validation passed: 180 tests in 20 files (23.64 seconds), all nine E2E scenarios (25.3 seconds), typecheck, production build and installed-package smoke. Root also confirmed the final real DOM contains one read-only round card with the custom user answer still rendered as ordinary text. These results validate the tested interview flows; model-chosen question content and control types still depend on the provider, and the strict legacy adapter intentionally supports recognized numbered option lists rather than arbitrary prose.
|
|
24
|
+
|
|
25
|
+
Root separately exercised the installed Codex through the real background browser UI. A newly generated round included single choice, multiple choice and a numeric range; keyboard Home/ArrowRight selected 10 and the paired numeric input matched. Custom text, selected options and the numeric value survived reload. Submitting the grouped answers produced an actual model continuation that acknowledged the custom answer, mouse/shortcut choices and value 10; the accepted round became read-only. Mobile width 390 had no horizontal overflow. Existing Snake A/B/C questions rendered as three interactive groups with a draft retained across reload; that user's existing round was inspected without submitting it. Live and fixture captures are kept separately under `.artifacts/interactive-interview-20261008/screenshots/`.
|
|
26
|
+
|
|
27
|
+
The later fast-frost/interview-to-plan regression covers a previously approved plan with old tasks, a newly completed interview, the natural command «начинай реализацию», automatic opening of a fresh unapproved plan, and explicit generation from the complete-round CTA. Existing interview controls/draft persistence scenarios continue to run unchanged apart from the new CTA label and behavior.
|
|
28
|
+
|
|
29
|
+
The updated targeted browser run passed all five frost/interview scenarios in23.5seconds, including the new natural-start/fresh-plan guard scenario in4.7seconds and both existing interview draft/control cases. The backend uses current-interview provenance; the UI displays its freshness result and never infers permission to execute from an old approved plan.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Structured interactive interview
|
|
2
|
+
|
|
3
|
+
The interview is a read-only design conversation. Codex, Claude and Kimi use the same workflow-level output protocol; no provider-specific paid inference is needed to interpret a form. Each accepted response supplies a public introduction and two or three questions, or a final summary with no questions. Completing the interview does not create or approve a plan; the existing explicit planning and approval controls remain authoritative.
|
|
4
|
+
|
|
5
|
+
`src/server/interview.ts` validates model output, validates submitted answers, converts narrow legacy transcripts and produces human-readable answer context. `Workflow.conductInterview` invokes the selected adapter with a fresh protocol-bearing prompt, saves a message and round in one project SQLite transaction, and publishes state-change events. The prompt contains the recent conversation and prior rounds/answers. Planning also receives structured rounds. IDs and status belong to the server, rather than being accepted from model output.
|
|
6
|
+
|
|
7
|
+
## Protocol and persistence
|
|
8
|
+
|
|
9
|
+
Model output is exactly `{message:string,complete:boolean,questions:InterviewQuestion[]}`. `message` is the public introduction/summary. Unknown properties, duplicate question/option IDs, invalid ranges and incomplete rounds with fewer than two or more than three questions fail validation. A completed round requires zero questions. Model JSON is buffered: interview `agent.delta` events are suppressed, while normalized activity continues. Only validated public text is stored as the assistant message. Invalid responses produce a fixed retryable error rather than showing raw protocol JSON.
|
|
10
|
+
|
|
11
|
+
Workspace `GET /api/v1/projects/:id` includes `interviewRounds` and optional latest `interviewRound`. A round has `id`, `runId`, `messageId`, `status`, `introduction`, `questions`, `createdAt`, `source`, optional `answers` and `answeredAt`. Status is `open`, `answered`, `superseded` or `complete`; source is `llm` or `legacy`. Messages may carry `interviewRoundId`. These documents live with the project and survive browser reload/server restart. `interview.updated` events carry a whole round; snapshots remain the durable source of truth.
|
|
12
|
+
|
|
13
|
+
Questions share `id`, `prompt`, `required`, optional `description` and a discriminant `type`:
|
|
14
|
+
|
|
15
|
+
| Type | Fields | Answer |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `single` | 2–8 `options: {id,label}[]`, `allowCustom` | selected ID in `value`, or `customText` |
|
|
18
|
+
| `multi` | same options, `allowCustom`, optional `maxSelections` | selected ID array plus optional `customText` |
|
|
19
|
+
| `range` | finite `min`, `max`, positive `step`, optional `defaultValue`, `unit` | number in `value` |
|
|
20
|
+
| `text` | optional `placeholder`, `maxLength` | string in `value` |
|
|
21
|
+
|
|
22
|
+
IDs use ASCII letters/digits/underscore/hyphen, at most64 characters. Numeric bounds are within ±1,000,000, ranges contain at most10,000 steps, and defaults/endpoints must lie on the step grid. Custom answers are trimmed and limited to2,000 characters. Text defaults to2,000 and can specify up to5,000 characters. Custom text counts as one multi selection. An optional omitted answer normalizes to `{questionId}`; required answers cannot be skipped. Model-supplied range defaults do not bypass server validation of submitted numbers.
|
|
23
|
+
|
|
24
|
+
## Answer submission and lifecycle
|
|
25
|
+
|
|
26
|
+
`POST /api/v1/projects/:id/interview/:roundId/answers` accepts `{answers:[{questionId,value?,customText?}]}` and returns202 `{run}`. It uses the normal local authentication/Origin policy. The project must be idle, and the round must be the latest open round. Unknown/duplicate question IDs, unknown/duplicate choices, type errors, missing required values, oversized text and invalid numeric bounds/grid return400 without closing the form. Stale/answered/superseded rounds or concurrent operations return409.
|
|
27
|
+
|
|
28
|
+
A successful submission saves normalized answers and a linked human-readable user message atomically before the next read-only interview starts. No network await exists between freshness validation and activating the next run, so duplicate submissions cannot start two operations. A cancelled or failed follow-up preserves already accepted answers; a late adapter result after cancellation cannot create another round. A new natural-language message supersedes the pending form and keeps its history. Users can continue in prose or request planning without being forced to fill obsolete controls.
|
|
29
|
+
|
|
30
|
+
Example: submit `{"answers":[{"questionId":"rules","customText":"Без стен"},{"questionId":"levels","value":3}]}`. The next model prompt receives question prompts, answer labels/custom text, and the structured round, rather than only opaque option IDs.
|
|
31
|
+
|
|
32
|
+
## Legacy compatibility and limits
|
|
33
|
+
|
|
34
|
+
For a last unanswered assistant message associated with an interview run, the snapshot can derive a stable `legacy-<messageId>` form. The conservative parser recognizes one to three numbered question headings containing a question mark and two to eight single-letter Latin/Cyrillic option lines per question. It retains the introduction and uses stable question/option IDs. GET does not rewrite project history or create migration records; the round is persisted only when submitted or superseded. Ordinary prose, ambiguous lists and trailing unrelated content remain transcript text. The same narrow parser supports old-style model responses as a compatibility fallback.
|
|
35
|
+
|
|
36
|
+
The server validates control structure and values, not the artistic quality of model questions. Arbitrary legacy prose is intentionally not guessed into controls. Interviews buffer answer content until validation, so the user sees activity while the form is generated; ordinary chat streaming is unchanged. Existing permission requests remain a separate provider mechanism.
|
|
37
|
+
|
|
38
|
+
## Verification scope
|
|
39
|
+
|
|
40
|
+
Focused backend fixtures cover all three adapter selections through the common workflow, actual Cyrillic legacy transcript shape, authenticated route behavior, validation, durable snapshot state, answer context, cancellation/late results, duplicate submission, protocol suppression and no automatic plans/tasks. These controlled adapters are not evidence of live Claude/Kimi inference. Live browser/model acceptance is recorded separately in `validation.md`.
|
|
41
|
+
|
|
42
|
+
On 8 October 2026, actual headless UI acceptance with Codex on the owned Star Counter project verified a single/multi/range round, custom and multiple selections, keyboard slider/numeric synchronization, draft reload, exact persisted answers and a following complete summary. Existing plan/task counts remained4/2. The original Snake transcript rendered three controls and restored its local draft without answer submission or server-history mutation (2 messages). Final common validation:180 tests/20 files,9 E2E, typecheck/build and installed-package checks passed. These live Codex results do not assert live structured inference with Claude/Kimi. Evidence and limitations are recorded in validation.md.
|
|
43
|
+
|
|
44
|
+
## Explicit transition to planning
|
|
45
|
+
|
|
46
|
+
After the latest round is `complete`, a whole-message request such as `начинай реализацию`, `начни разработку`, `приступай к реализации`, `создай план` or `подготовь план` starts a fresh planning run through the existing message endpoint. This works in either composer mode. The recognizer is a bounded phrase grammar with optional polite prefixes/suffixes and final punctuation; negation, questions, quoted commands and mixed prose are not treated as actions. Unrecognized prose remains a conversation, and the explicit POST `/plan` control remains available. A completion summary by itself never initiates planning.
|
|
47
|
+
|
|
48
|
+
The message response still has `{run}`, but `run.kind` is `planning`, allowing the browser to open the plan review immediately while generation runs. The new version is unapproved. No command in this path silently approves a plan or runs tasks. Planning gives the latest completed interview and subsequent user corrections precedence over conflicting old conversation/project context.
|
|
49
|
+
|
|
50
|
+
New plans carry optional `interviewRoundId` provenance. Workspace `planNeedsUpdate` reports whether the latest plan no longer corresponds to the latest interview round. For old plans without provenance, timestamps provide a conservative compatibility check; missing/unparseable timestamps require updating when an interview exists. `approve`, `execute` and resume reject stale plans with409, including when a newer planning attempt failed. Existing tasks stay in history until an explicitly approved new plan produces its task graph. An intentional manual plan save creates a new version with the current interview provenance and can then be reviewed/approved normally.
|
|
51
|
+
|
|
52
|
+
Focused regressions cover an old approved plan/task queue followed by a newer complete brief, natural-command routing, stale run/resume/approval rejection, generation failure, manual-plan revision and negative intent examples. The server does not change the live user project merely by reading the snapshot.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Локальный стенд с текущей подпиской Codex
|
|
2
|
+
|
|
3
|
+
Стенд запускает четыре локальных HTTP-сервиса и отдельную PostgreSQL. AI работает через установленный Codex CLI с текущей авторизацией ChatGPT. UMGT заменён локальной имитацией с сохраняемым балансом, лимитами и идемпотентным журналом: боевые API UMGT и платежи не используются.
|
|
4
|
+
|
|
5
|
+
## Управление
|
|
6
|
+
|
|
7
|
+
Из папки Hub:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm run dev:core
|
|
11
|
+
npm run dev:core:status
|
|
12
|
+
npm run dev:core:stop
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Для первого запуска нужны Node.js 24.13+, установленный и авторизованный Codex (`codex login status` должен показывать ChatGPT), PostgreSQL с `initdb`, `pg_ctl`, `psql`, `createdb` в PATH, установленный соседний `../game-hub-core` и собранные оба проекта. В этой среде PostgreSQL установлена через Homebrew. Docker не требуется.
|
|
16
|
+
|
|
17
|
+
Адреса по умолчанию:
|
|
18
|
+
|
|
19
|
+
| Сервис | Адрес |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| Hub | http://127.0.0.1:4317 |
|
|
22
|
+
| Ядро и админка | http://127.0.0.1:8081/admin/ |
|
|
23
|
+
| Локальный UMGT | http://127.0.0.1:8082/health |
|
|
24
|
+
| Мост Codex | http://127.0.0.1:8083/health |
|
|
25
|
+
| PostgreSQL | 127.0.0.1:55439 |
|
|
26
|
+
|
|
27
|
+
Все процессы слушают только loopback. Данные стенда, PostgreSQL, логи и секреты находятся в `.artifacts/core-local/`, которая исключена из Git. Стенд использует отдельную базу `game_hub_core_local` и отдельную папку данных Hub, не меняя реальные проекты и настройки пользователя. Авторизация Codex читается штатным CLI; файл авторизации не копируется в проекты и не передаётся браузеру. Настройки пользовательского Codex не меняются.
|
|
28
|
+
|
|
29
|
+
В `.artifacts/core-local/access.txt` после успешной проверки находятся ссылка подключения Hub и реквизиты локального администратора. Файл имеет права 0600. Приватная конфигурация сервисов — `stack.json`; не публикуйте эти файлы. После перезапуска ссылка подключения Hub может измениться.
|
|
30
|
+
|
|
31
|
+
## Проверка всего соединения
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm run test:core:live
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Это реальные вызовы модели через текущую подписку Codex. Проверка создаёт изолированный HTML5-проект в папке стенда, получает ответ через рабочий процесс Hub, создаёт и читает файл через локальные инструменты, сверяет usage Codex с операциями ядра и журналом UMGT. Далее проверяет купленные токены без подписки, отказы дневного/недельного запаса и месячного лимита до вызова модели, временную ошибку списания и автоматический повтор, ротацию токенов, блокировку/восстановление через браузер и замену ключа UMGT. Для браузерных проверок нужен установленный Chromium Playwright.
|
|
38
|
+
|
|
39
|
+
Проверка временно меняет только тестовый аккаунт локального UMGT, отзывает сессии стенда и восстанавливает подключение в конце. Не выполняйте её одновременно с собственной работой в этом стенде. В истории админки останутся ожидаемые отказы `precheck_failed`: это результат проверок лимитов, а не незавершённые списания.
|
|
40
|
+
|
|
41
|
+
Итоговый отчёт — `.artifacts/core-local/proof.json`, скриншоты — в той же папке, usage CLI без промптов — `codex-usage.jsonl`. Промежуточный контекст модели хранится стандартно в PostgreSQL ядра.
|
|
42
|
+
|
|
43
|
+
## Устройство тестового моста
|
|
44
|
+
|
|
45
|
+
Скрипт `game-hub-core/scripts/codex-bridge.mjs` предоставляет ядру локальный Chat Completions-совместимый endpoint. Он запускает `codex exec --ignore-user-config --ephemeral --json` в отдельной временной read-only папке и использует текущую штатную авторизацию. Вывод ограничен JSON Schema; команды, браузер, приложения, подагенты и генерация изображений в Codex отключены. Если CLI всё же сообщает о нативном выполнении команды или изменении файлов, мост отклоняет вызов.
|
|
46
|
+
|
|
47
|
+
Модель возвращает описания вызовов инструментов в JSON; выполняет их существующий локальный адаптер Hub с его проверками и разрешениями. Результат каждого шага переводится в серверный протокол ядра. Учёт берётся из `turn.completed.usage`: входные плюс выходные токены, включая входные из кеша и контекст самого CLI. Это отчётный расход CLI, а не оценка по длине ответа и не остаток лимита подписки ChatGPT.
|
|
48
|
+
|
|
49
|
+
Это отдельный режим локальной проверки. Основной сервер по-прежнему работает с настраиваемым AI API и серверным ключом. Мост не добавлен в production Docker-образ; для него нужен установленный на сервере CLI и авторизованный локальный аккаунт.
|
|
50
|
+
|
|
51
|
+
Официальная документация: [неинтерактивный Codex и отчёт usage](https://developers.openai.com/codex/noninteractive), [настройки инструментов](https://developers.openai.com/codex/config-reference).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Проверка Meshy через ядро
|
|
2
|
+
|
|
3
|
+
19 октября 2026: выполнена одна настоящая Text-to-3D preview-генерация Meshy 6 Lite через Hub → Core → Meshy. Создан нетекстурированный сундук, GLB 261 960 байт, 1 mesh, 4483 треугольника. Проверены заголовок GLB 2.0, границы буферов и изображение результата. Масштаб, коллизии, UV и пригодность для конкретного игрового движка отдельно не проверялись.
|
|
4
|
+
|
|
5
|
+
- Провайдер: 5 реальных кредитов, баланс 1763 → 1758; расход совпал с `consumed_credits` задачи.
|
|
6
|
+
- Локальный UMGT: 150000 → 149900 копеек. Условная тестовая цена — 1 ₽; это не тариф и не пересчёт кредитов Meshy. Боевой UMGT не вызывался, реального денежного платежа нет.
|
|
7
|
+
- Операция `784f6d9d-b674-4aec-bb02-98d8f4276eb3`: `3d.meshy`, tokens=0, cost_kop=100, paid, transaction_id=7. Доступные LLM-токены не изменились.
|
|
8
|
+
- Тестовая первая попытка списания вернула 500. Автоматическая вторая попытка завершилась успешно. Повтор того же запроса генерации и повтор `/usage` вернули прежнюю операцию и квитанцию, дополнительных списаний нет.
|
|
9
|
+
- Выключенный сервис 3D и недостаточный баланс отклонены до вызова Meshy. В автотестах дополнительно покрыты неудачная генерация, изоляция пользователей, конфликт requestId, сохранение известной задачи после восстановления и неопределённая отправка без повторного платного POST.
|
|
10
|
+
|
|
11
|
+
Результат и доказательства: `.artifacts/core-local/meshy-result/` — `chest.glb`, `thumbnail.png`, `proof.json`, `admin-operation.json`, `admin-billing.png`. Проверьте поле browserErrors в admin-operation.json. Текущий сервер: http://127.0.0.1:8081/admin/ → Операции. Ключ Meshy хранится только в игнорируемом приватном файле `.artifacts/core-local/meshy-secret.json` с правами 0600; launcher передаёт его ядру.
|
|
12
|
+
|
|
13
|
+
Воспроизводимая проверка: `npm run test:meshy:live` на запущенном локальном стенде. Если job.json уже существует, команда продолжает проверять ту же задачу. Первый запуск без job.json создаёт одну платную задачу Meshy. Скрипт ограничен локальным UMGT из stack.json; стоимость в копейках фиктивная. Не удаляйте job.json для обычного повторного запуска: это создаст новый requestId и новую платную генерацию.
|
package/docs/markdown.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Markdown in plans and conversations
|
|
2
|
+
|
|
3
|
+
`Markdown` in `src/web/workflow.tsx` renders saved plans and agent messages through `react-markdown` and `remark-gfm`. The plan editor remains a separate plain Markdown textarea; rendering does not modify saved content.
|
|
4
|
+
|
|
5
|
+
Supported formatting includes headings, emphasis, ordered and nested lists, read-only task lists, tables, blockquotes, inline code, fenced code and links. Tables and fenced blocks scroll within the content pane and can receive keyboard focus. Styling uses the existing light/dark theme tokens.
|
|
6
|
+
|
|
7
|
+
Raw HTML is escaped as text. No raw-HTML execution plugin or `dangerouslySetInnerHTML` is used. URL handling first applies the library's default sanitizer, then permits only explicit HTTP/HTTPS/mailto links and fragment references. Unsupported protocols, relative filesystem/API paths and protocol-relative URLs remain inert text. External links open with `noopener noreferrer`.
|
|
8
|
+
|
|
9
|
+
Markdown images appear as explicit links with their alternative text, so rendering model output does not automatically fetch remote images. Code is displayed as escaped text without executing snippets.
|
|
10
|
+
|
|
11
|
+
`tests/markdown.test.ts` checks semantic rendering, tables/fences, raw HTML escaping, unsafe URL handling, image behavior and incomplete streamed Markdown.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Agent requests in the workspace
|
|
2
|
+
|
|
3
|
+
The workspace reads pending requests from the existing project snapshot. A single sticky notice in `App` remains visible across sections and opens the agent conversation at the first pending request. Multiple requests are counted. Tasks, conversation feedback and the log drawer show that the agent is waiting for the user.
|
|
4
|
+
|
|
5
|
+
The chat workspace has one viewport-height boundary. Flex layout allocates the remaining space after the header, pending notice, log drawer and footer; only the message area scrolls. The notice does not require a second fixed-height calculation for the conversation.
|
|
6
|
+
|
|
7
|
+
`PermissionCard` presents an existing request's reason, command and working directory when provided. Provider strings are rendered as plain escaped text, including executable arguments and paths. Technical identifiers, the method and complete payload remain available in a closed disclosure. Unknown request shapes retain a neutral explanation and the complete technical payload rather than an invented command.
|
|
8
|
+
|
|
9
|
+
The UI does not create additional approvals or change sandbox rules. The existing allow/decline endpoint, question answers and adapter response behavior are unchanged. `tests/permission-ui.test.ts` covers the navigation action, empty and multiple pending states, concise command details, escaped provider strings, question controls and task-page waiting status.
|
|
10
|
+
|
|
11
|
+
The live audit verified a real pending Godot request after reload: the notice opened the correct card, technical details remained closed, and the desktop (1440 × 900) and mobile (390 × 844) documents matched their viewport dimensions with scroll position and header top at zero. Corresponding screenshots are `skill-permission-fixed.png` and `skill-mobile-permission.png` under `.artifacts/ui-report/screenshots/`.
|
package/docs/plan.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Game Hub — утверждённый план реализации
|
|
2
|
+
|
|
3
|
+
## Результат
|
|
4
|
+
|
|
5
|
+
Локальное приложение `lm-game-hub` открывает браузер и ведёт пользователя от идеи игры через интервью, план и утверждение к эпикам, задачам, исполнению, проверкам и сборке. Один пользователь; macOS, Windows, Linux. Первая версия: Godot, GDScript, 2D/3D, Desktop/Web. Unity и Roblox Studio — последующие адаптеры после рабочего Godot-релиза. Внешний редактор остаётся инструментом редактирования кода и сцен; Hub — IDE-подобная панель управления.
|
|
6
|
+
|
|
7
|
+
## Архитектура
|
|
8
|
+
|
|
9
|
+
TypeScript, Node.js LTS, React/Vite, Fastify, SQLite; модульный монолит. CLI `start`, `doctor`, `--port`, `--no-open`, без подкоманды запускается `start`. Дистрибутив содержит собранный UI. Сервер слушает loopback, проверяет Host/Origin и токен сессии; процессы запускаются без shell. Закрытие вкладки не останавливает работу; выход CLI завершает дочерние процессы.
|
|
10
|
+
|
|
11
|
+
Глобальная SQLite хранит реестр проектов, настройки и кеш; проектная `.lm-game-hub/` хранит планы, трекер, историю, версии и состав расширений. План экспортируется в Markdown, задачи — JSON. API `/api/v1` и SSE с восстанавливаемыми ID. Контракты: `AgentAdapter`, `EngineAdapter`, `AssetProvider`, `SkillPackManifest`.
|
|
12
|
+
|
|
13
|
+
Codex подключается через app-server stdio; Claude Code через официальный Agent SDK и установленный CLI; Kimi через ACP stdio. Используются существующие авторизации, executable/model настраиваются, диагностика проверяет версию, протокол и доступность. Единые события сообщений, инструментов, вопросов, разрешений, проверок и ошибок. Смена агента разрешена между задачами с передачей контекста. Секреты авторизации не копируются в БД.
|
|
14
|
+
|
|
15
|
+
Godot обнаруживается автоматически и по ручному пути. Шаблоны 2D/3D, открытие редактора, запуск/остановка, headless import/check, Desktop/Web export с проверкой версии, ОС и шаблонов. Web предпросмотр открывается через локальный сервер.
|
|
16
|
+
|
|
17
|
+
## Рабочий процесс
|
|
18
|
+
|
|
19
|
+
Мастер: имя, папка, движок, целевые платформы, 2D/3D, агент. Затем сохраняемое интервью небольшими порциями (жанр, цикл, управление, стиль, объём, референсы, готовность) либо прямой бриф. LLM формирует редактируемый версионированный план. Постоянная кнопка «План» открывает его в любое время. До утверждения исполнение запрещено сервером.
|
|
20
|
+
|
|
21
|
+
После утверждения отдельная сессия LLM создаёт эпики и задачи с критериями, приоритетами и зависимостями. Система проверяет DAG. Встроенный трекер продукта не зависит от br; br применяется только для разработки самого Hub согласно CLAUDE.md. Исполнитель последовательно выбирает доступные задачи, запускает проверки и закрывает только проверенные результаты. Один исполнитель изменяет проект одновременно. После трёх неудачных попыток задача блокируется с объяснением. Поддерживаются пауза после задачи, немедленная остановка, продолжение, восстановление прерванной задачи с проверкой файлов. Изменения плана создают новую версию и требуют повторного утверждения.
|
|
22
|
+
|
|
23
|
+
## Интерфейс и расширения
|
|
24
|
+
|
|
25
|
+
Использовать установленный `Leonxlnx/taste-skill`. Лёгкая современная IDE: слева проекты/разделы, в центре чат/план/задачи/каталог, внизу сворачиваемые логи. Верхняя панель содержит проект, агента, План, Запустить игру, Открыть Godot и состояние. Разделы: обзор, чат, задачи, ассеты, расширения, настройки. Русский интерфейс; светлая, тёмная, системная тема; нейтральная палитра с одним акцентом; Radix/Tailwind/Phosphor. Motion переходы 150–250 мс, клавиатура и reduced-motion. Каждая операция >1с имеет индикатор состояния. Измеряемый прогресс отражает реальные байты/задачи; LLM показывает неопределённый индикатор.
|
|
26
|
+
|
|
27
|
+
Версионированный каталог навыков содержит источники, лицензии, совместимость; выбор зависит от движка, платформ, размерности и интервью. Godot база: структура, GDScript, сцены, отладка, тесты, импорт, экспорт; дополнения: UI, движение, анимация, аудио, жанровые системы. Навыки размещаются в проекте способом выбранного агента; версии фиксируются, обновляются явно. Плагины устанавливаются по необходимости. UI различает навыки, MCP и плагины редактора и показывает причины выбора.
|
|
28
|
+
|
|
29
|
+
## Бесплатные ассеты
|
|
30
|
+
|
|
31
|
+
Poly Haven и ambientCG: поиск, метаданные, превью, скачивание через API. Kenney: проверенная подборка, ссылки и импорт архива. OpenGameArt/itch.io: внешнее открытие поиска, сохранение ссылки, ручной импорт. Категории, форматы, лицензии, избранное, коллекции проекта; карточка обозначает способ получения. Агенту доступны MCP `assets.search`, `assets.details`, `assets.download`, `assets.import` на общем с UI сервисе. Ресурсы прикрепляются к задачам. По умолчанию автопоиск использует CC0; сохраняются источник, автор, лицензия и файлы. Кеш, временная папка, лимиты размеров и проверка путей при распаковке. Ошибка одного провайдера не блокирует другие.
|
|
32
|
+
|
|
33
|
+
## Фазы и приёмка
|
|
34
|
+
|
|
35
|
+
1. CLI, сервер, хранение, оболочка.
|
|
36
|
+
2. Адаптеры Codex/Claude/Kimi и процессы.
|
|
37
|
+
3. Godot проекты и наборы расширений.
|
|
38
|
+
4. Интервью, версии, утверждение.
|
|
39
|
+
5. Трекер, декомпозиция, исполнение, восстановление.
|
|
40
|
+
6. Ассеты, импорт, инструменты агента.
|
|
41
|
+
7. Godot проверки/экспорт, анимации, доступность, упаковка.
|
|
42
|
+
|
|
43
|
+
Декомпозиция и зависимости в `docs/tasks.json` и проектном `.beads/beads.db`. При создании новых модулей поддерживать `architecture.md`; актуальную документацию зависимостей проверять через Context7. Не выполнять git add/commit.
|
|
44
|
+
|
|
45
|
+
Проверки: unit DAG/состояний/утверждения/подбора; интеграционные тесты протоколов CLI, ошибок, отмены, разрешений и reconnect; пути с пробелами/кириллицей, повреждённые архивы и конфликт файлов; E2E проект→интервью→утверждение→задачи→исполнение→ассет→запуск→сборка. CI macOS/Windows/Linux проверяет типы, сборку, тесты и Godot headless. Настоящие авторизованные CLI проверяются отдельно от протокольных фикстур. Недоступные реальные проверки документируются без утверждений о прохождении. Визуально проверить темы, клавиатуру, долгие операции и reduced-motion.
|
|
46
|
+
|
|
47
|
+
Готовность: пользователь создаёт небольшой проект, утверждает план, наблюдает настоящее исполнение задач и запускает собранную игру; результаты подтверждаются проверками и логами.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Удалённое ядро и локальная Roblox Studio
|
|
2
|
+
|
|
3
|
+
Проверено 21 октября 2026 года. Core находится на `193.164.222.8`, исходники — отдельный репозиторий `../game-hub-core`.
|
|
4
|
+
|
|
5
|
+
## Текущее состояние
|
|
6
|
+
|
|
7
|
+
| Контур | Адрес | Настройка |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Production Core | `https://umgt.aircoding.ai` | Реальный UMGT и OpenRouter, только HTTPS-домен |
|
|
10
|
+
| Demo Core | Только `127.0.0.1:8085` на сервере | Публичный вход закрыт |
|
|
11
|
+
| Локальный Hub | `http://127.0.0.1:4321` | Остановлен; новое подключение — HTTPS-домен и личный production UMGT-ключ |
|
|
12
|
+
|
|
13
|
+
Админки находятся по `/admin/`. Индивидуальные пароли, тестовый UMGT-ключ и действующая ссылка входа в Hub — в приватном `.artifacts/deploy-193-164-222-8/access.txt`. Ключ OpenRouter находится только в серверных env-файлах и не передаётся Hub или игровым скриптам. Production теперь доступен только по HTTPS-домену `umgt.aircoding.ai`. nginx отклоняет IP/чужой Host/SNI, порт 8080 не слушается. Сертификат Let’s Encrypt автоматически продлевается; COOKIE_SECURE=true.
|
|
14
|
+
|
|
15
|
+
Модель по умолчанию в обоих контурах — `deepseek/deepseek-v4.1-flash-1017`, режим `reasoningEffort=low`. Ядро не задаёт искусственный предел токенов ответа и автоматически сжимает историю при оценке заполнения от 80% фактического контекстного окна OpenRouter. Лимиты подписки по стоимости сохраняются. Сервер сохраняет finishReason, а Hub не выполняет инструменты из ответа, который провайдер остановил по длине. Полный prompt_tokens + completion_tokens остаётся учтённым, включая reasoning и cached input.
|
|
16
|
+
|
|
17
|
+
Рабочий путь: локальный Hub → HTTPS Core → HTTPS OpenRouter. Инструменты, файлы и Roblox Studio выполняются локально. SSH используется для администрирования сервера; пользователям он не нужен. SSH-туннель и локальный Codex bridge остановлены. Demo UMGT выполняется отдельной loopback-службой на сервере, поэтому demo также не зависит от ноутбука или reverse SSH. Для работы в Studio локальный Hub и Studio должны оставаться запущенными.
|
|
18
|
+
|
|
19
|
+
## Сервер
|
|
20
|
+
|
|
21
|
+
Ubuntu 26.04, Node 24.22.1, PostgreSQL 18.6, nginx. Раздельные пользователи ОС, роли и базы PostgreSQL для production и demo. Службы `game-hub-core.service`, `game-hub-core-demo.service`, `game-hub-demo-umgt.service` и nginx включены в автозапуск. Ядро и фикстура работают без root.
|
|
22
|
+
|
|
23
|
+
Выпуски устанавливаются из приватного [репозитория Core](https://github.com/darkClaw921/game-hub-core) в `/opt/game-hub-core/releases/<SHA>`, симлинк `/opt/game-hub-core/current`. Merge в `master` запускает GitHub Actions: проверки, сборку и установку через серверный runner. После readiness/version проверки оба сервиса должны возвращать SHA master по `/health/version`; при сбое установщик возвращает предыдущий код. Перед миграциями создаются закрытые резервные копии обеих баз. Инструкция — [Core deploy/README.md](https://github.com/darkClaw921/game-hub-core/blob/master/deploy/README.md). Конфигурации с секретами — `/etc/game-hub-core/prod.env`, `demo.env`, `umgt-fixture.env`, права 0600. Состояние тестового UMGT — `/var/lib/game-hub-demo/umgt.json`, права 0600. nginx принимает домен на 443 и передаёт запросы на loopback 8081 без буферизации SSE; 80 обслуживает ACME и редирект на HTTPS. Demo доступен только на loopback 8085. PostgreSQL и UMGT не имеют публичных портов.
|
|
24
|
+
|
|
25
|
+
## Проверка через OpenRouter без туннеля
|
|
26
|
+
|
|
27
|
+
В отдельном новом проекте `OpenRouter Roblox Demo` DeepSeek самостоятельно создал manifest и четыре Luau-скрипта: Main.server, SceneBuilder, WorkshopConfig и Main.client. Для свежего проекта открыто его окно Studio штатным действием Hub, после чего агент получил ограниченные этим проектом инструменты. Другие places и исходники прежнего Codex demo не менялись. Публикации не было.
|
|
28
|
+
|
|
29
|
+
Сцена CloudWorkshop: основание 70×70, четыре дерева, три ящика, арка, SpawnLocation, дорожка и пьедестал. WorkshopGuide — Model с Humanoid, семью частями и шестью Motor6D. Повторный вызов SceneBuilder не дублирует сцену. UUID проекта проверен после открытия сборки; контрольные суммы четырёх загруженных скриптов совпали с файлами на диске.
|
|
30
|
+
|
|
31
|
+
Настоящий Studio Play подтвердил здоровье игрока и NPC 100, стандартный PlayerModule и движение игрока после W на 1,2 секунды: примерно 19 studs. В Output нет ошибок созданных скриптов. После остановки подтверждён Edit и сохранение сцены. Агент выполнил реальные screen_capture в Edit и Play. Дополнительный операторский снимок Play сохранён через тот же локальный Hub HTTP bridge как `reports/scene-play.jpg`; он показывает игрока под аркой и NPC впереди.
|
|
32
|
+
|
|
33
|
+
Задача завершилась со статусом done. Подробные ожидаемые и фактические результаты — `reports/openrouter-checks.json`. Исходники и `builds/game.rbxlx` находятся в `.artifacts/deploy-193-164-222-8/projects/openrouter-roblox-demo/`.
|
|
34
|
+
|
|
35
|
+
Отдельный реальный тест модели запросил чтение локального probe-файла, получил результат инструмента и вернул его значение. Повтор requestId вернул тот же результат с replayed=true без второго списания. В конце игрового теста отсутствовали SSH-соединения с сервером и локальные слушатели Codex bridge/фикстуры/туннелей.
|
|
36
|
+
|
|
37
|
+
## Учёт и проверки
|
|
38
|
+
|
|
39
|
+
По итогам настройки и всех попыток через OpenRouter: 94 оплаченные операции, 3 491 896 токенов. Общий demo с предыдущими Codex-вызовами: 127 оплаченных операций, 127 уникальных транзакций и 5 346 286 токенов. Значение Core точно совпало с usage тестового UMGT. Три операции остановлены предварительными проверками; незавершённых, неизвестных списаний и дубликатов нет. OpenRouter использовался реально; его расходы относятся к предоставленному API-ключу. Боевой UMGT не списывался.
|
|
40
|
+
|
|
41
|
+
Проверены обе health/ready и входы в обе админки; OpenRouter настроен в обоих контурах. Авторизация реального пользователя production UMGT не проверялась без его ключа. Пройдены 60 тестов Core с PostgreSQL, 12 интеграционных тестов Hub, typecheck и production build обоих проектов. Проверки включают независимые аккаунты, биллинг, SSE, reasoning usage и запрет выполнения обрезанных tool calls.
|
|
42
|
+
|
|
43
|
+
Доказательства в приватной папке развёртывания: `openrouter-server-proof.json`, `openrouter-proof.json`, `openrouter-billing-proof.json`, `no-ssh-proof.json`, `openrouter-project-last.json`. Предыдущие `deployment-proof.json`, `server-proof.json`, `billing-proof.json` описывают историческую проверку через Codex/SSH, а не текущее подключение.
|
|
44
|
+
|
|
45
|
+
## Локальный запуск
|
|
46
|
+
|
|
47
|
+
Из корня Hub: `node .artifacts/deploy-193-164-222-8/start-local.mjs`. Скрипт требует переменную UMGT_API_KEY с реальным личным production-ключом, запускает только локальный Hub и подключается к HTTPS Core; он не запускает SSH или Codex. В ходе настройки nginx локальный Hub не запускался. Используйте актуальную ссылку из access.txt после перезапуска Hub.
|