@darkclaw921/umgt 0.0.0-stage → 0.1.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.
Files changed (290) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -2
  3. package/architecture.md +105 -0
  4. package/bin/lm-game-hub.js +7 -0
  5. package/dist/server/activity.d.ts +17 -0
  6. package/dist/server/activity.js +55 -0
  7. package/dist/server/activity.js.map +1 -0
  8. package/dist/server/agents/activity.d.ts +36 -0
  9. package/dist/server/agents/activity.js +117 -0
  10. package/dist/server/agents/activity.js.map +1 -0
  11. package/dist/server/agents/claude.d.ts +5 -0
  12. package/dist/server/agents/claude.js +107 -0
  13. package/dist/server/agents/claude.js.map +1 -0
  14. package/dist/server/agents/codex.d.ts +5 -0
  15. package/dist/server/agents/codex.js +128 -0
  16. package/dist/server/agents/codex.js.map +1 -0
  17. package/dist/server/agents/core-tools.d.ts +23 -0
  18. package/dist/server/agents/core-tools.js +298 -0
  19. package/dist/server/agents/core-tools.js.map +1 -0
  20. package/dist/server/agents/core.d.ts +9 -0
  21. package/dist/server/agents/core.js +106 -0
  22. package/dist/server/agents/core.js.map +1 -0
  23. package/dist/server/agents/index.d.ts +5 -0
  24. package/dist/server/agents/index.js +41 -0
  25. package/dist/server/agents/index.js.map +1 -0
  26. package/dist/server/agents/kimi.d.ts +5 -0
  27. package/dist/server/agents/kimi.js +123 -0
  28. package/dist/server/agents/kimi.js.map +1 -0
  29. package/dist/server/agents/rpc.d.ts +19 -0
  30. package/dist/server/agents/rpc.js +102 -0
  31. package/dist/server/agents/rpc.js.map +1 -0
  32. package/dist/server/agents/types.d.ts +51 -0
  33. package/dist/server/agents/types.js +7 -0
  34. package/dist/server/agents/types.js.map +1 -0
  35. package/dist/server/app.d.ts +21 -0
  36. package/dist/server/app.js +37 -0
  37. package/dist/server/app.js.map +1 -0
  38. package/dist/server/asset-catalog.d.ts +5 -0
  39. package/dist/server/asset-catalog.js +525 -0
  40. package/dist/server/asset-catalog.js.map +1 -0
  41. package/dist/server/asset-media.d.ts +16 -0
  42. package/dist/server/asset-media.js +170 -0
  43. package/dist/server/asset-media.js.map +1 -0
  44. package/dist/server/asset-selection.d.ts +71 -0
  45. package/dist/server/asset-selection.js +273 -0
  46. package/dist/server/asset-selection.js.map +1 -0
  47. package/dist/server/assets.d.ts +69 -0
  48. package/dist/server/assets.js +669 -0
  49. package/dist/server/assets.js.map +1 -0
  50. package/dist/server/browser-gateway.d.ts +82 -0
  51. package/dist/server/browser-gateway.js +285 -0
  52. package/dist/server/browser-gateway.js.map +1 -0
  53. package/dist/server/chat-computer.d.ts +13 -0
  54. package/dist/server/chat-computer.js +29 -0
  55. package/dist/server/chat-computer.js.map +1 -0
  56. package/dist/server/chat-games.d.ts +38 -0
  57. package/dist/server/chat-games.js +202 -0
  58. package/dist/server/chat-games.js.map +1 -0
  59. package/dist/server/chat.d.ts +42 -0
  60. package/dist/server/chat.js +318 -0
  61. package/dist/server/chat.js.map +1 -0
  62. package/dist/server/cli.d.ts +14 -0
  63. package/dist/server/cli.js +117 -0
  64. package/dist/server/cli.js.map +1 -0
  65. package/dist/server/core-client.d.ts +69 -0
  66. package/dist/server/core-client.js +357 -0
  67. package/dist/server/core-client.js.map +1 -0
  68. package/dist/server/directory-picker.d.ts +14 -0
  69. package/dist/server/directory-picker.js +113 -0
  70. package/dist/server/directory-picker.js.map +1 -0
  71. package/dist/server/engine.d.ts +36 -0
  72. package/dist/server/engine.js +507 -0
  73. package/dist/server/engine.js.map +1 -0
  74. package/dist/server/events.d.ts +12 -0
  75. package/dist/server/events.js +137 -0
  76. package/dist/server/events.js.map +1 -0
  77. package/dist/server/game-launch.d.ts +16 -0
  78. package/dist/server/game-launch.js +143 -0
  79. package/dist/server/game-launch.js.map +1 -0
  80. package/dist/server/html5.d.ts +9 -0
  81. package/dist/server/html5.js +107 -0
  82. package/dist/server/html5.js.map +1 -0
  83. package/dist/server/interview.d.ts +241 -0
  84. package/dist/server/interview.js +190 -0
  85. package/dist/server/interview.js.map +1 -0
  86. package/dist/server/mcp.d.ts +27 -0
  87. package/dist/server/mcp.js +91 -0
  88. package/dist/server/mcp.js.map +1 -0
  89. package/dist/server/plugins.d.ts +8 -0
  90. package/dist/server/plugins.js +144 -0
  91. package/dist/server/plugins.js.map +1 -0
  92. package/dist/server/process.d.ts +15 -0
  93. package/dist/server/process.js +89 -0
  94. package/dist/server/process.js.map +1 -0
  95. package/dist/server/publication-materials.d.ts +18 -0
  96. package/dist/server/publication-materials.js +104 -0
  97. package/dist/server/publication-materials.js.map +1 -0
  98. package/dist/server/publication-mcp.d.ts +3 -0
  99. package/dist/server/publication-mcp.js +43 -0
  100. package/dist/server/publication-mcp.js.map +1 -0
  101. package/dist/server/publication.d.ts +54 -0
  102. package/dist/server/publication.js +334 -0
  103. package/dist/server/publication.js.map +1 -0
  104. package/dist/server/push.d.ts +81 -0
  105. package/dist/server/push.js +122 -0
  106. package/dist/server/push.js.map +1 -0
  107. package/dist/server/roblox-assets.d.ts +41 -0
  108. package/dist/server/roblox-assets.js +131 -0
  109. package/dist/server/roblox-assets.js.map +1 -0
  110. package/dist/server/roblox-connection.d.ts +54 -0
  111. package/dist/server/roblox-connection.js +331 -0
  112. package/dist/server/roblox-connection.js.map +1 -0
  113. package/dist/server/roblox-install.d.ts +4 -0
  114. package/dist/server/roblox-install.js +170 -0
  115. package/dist/server/roblox-install.js.map +1 -0
  116. package/dist/server/roblox-mcp.d.ts +2 -0
  117. package/dist/server/roblox-mcp.js +34 -0
  118. package/dist/server/roblox-mcp.js.map +1 -0
  119. package/dist/server/roblox-play.d.ts +23 -0
  120. package/dist/server/roblox-play.js +84 -0
  121. package/dist/server/roblox-play.js.map +1 -0
  122. package/dist/server/roblox-project-tools.d.ts +11 -0
  123. package/dist/server/roblox-project-tools.js +119 -0
  124. package/dist/server/roblox-project-tools.js.map +1 -0
  125. package/dist/server/roblox-setup.d.ts +37 -0
  126. package/dist/server/roblox-setup.js +206 -0
  127. package/dist/server/roblox-setup.js.map +1 -0
  128. package/dist/server/roblox-skills.d.ts +15 -0
  129. package/dist/server/roblox-skills.js +15 -0
  130. package/dist/server/roblox-skills.js.map +1 -0
  131. package/dist/server/roblox.d.ts +30 -0
  132. package/dist/server/roblox.js +248 -0
  133. package/dist/server/roblox.js.map +1 -0
  134. package/dist/server/routes.d.ts +11 -0
  135. package/dist/server/routes.js +219 -0
  136. package/dist/server/routes.js.map +1 -0
  137. package/dist/server/security.d.ts +4 -0
  138. package/dist/server/security.js +64 -0
  139. package/dist/server/security.js.map +1 -0
  140. package/dist/server/skills.d.ts +4 -0
  141. package/dist/server/skills.js +123 -0
  142. package/dist/server/skills.js.map +1 -0
  143. package/dist/server/store.d.ts +25 -0
  144. package/dist/server/store.js +89 -0
  145. package/dist/server/store.js.map +1 -0
  146. package/dist/server/templates/roblox-coin-run.d.ts +2 -0
  147. package/dist/server/templates/roblox-coin-run.js +326 -0
  148. package/dist/server/templates/roblox-coin-run.js.map +1 -0
  149. package/dist/server/templates/roblox-skills.json +55 -0
  150. package/dist/server/templates/yandex-sdk.d.ts +3 -0
  151. package/dist/server/templates/yandex-sdk.js +177 -0
  152. package/dist/server/templates/yandex-sdk.js.map +1 -0
  153. package/dist/server/video-media.d.ts +47 -0
  154. package/dist/server/video-media.js +224 -0
  155. package/dist/server/video-media.js.map +1 -0
  156. package/dist/server/video-routes.d.ts +7 -0
  157. package/dist/server/video-routes.js +91 -0
  158. package/dist/server/video-routes.js.map +1 -0
  159. package/dist/server/video.d.ts +214 -0
  160. package/dist/server/video.js +301 -0
  161. package/dist/server/video.js.map +1 -0
  162. package/dist/server/web-build.d.ts +16 -0
  163. package/dist/server/web-build.js +232 -0
  164. package/dist/server/web-build.js.map +1 -0
  165. package/dist/server/workflow.d.ts +221 -0
  166. package/dist/server/workflow.js +826 -0
  167. package/dist/server/workflow.js.map +1 -0
  168. package/dist/server/yandex-config.d.ts +33 -0
  169. package/dist/server/yandex-config.js +12 -0
  170. package/dist/server/yandex-config.js.map +1 -0
  171. package/dist/server/yandex-godot.d.ts +5 -0
  172. package/dist/server/yandex-godot.js +107 -0
  173. package/dist/server/yandex-godot.js.map +1 -0
  174. package/dist/shared/aspects.d.ts +48 -0
  175. package/dist/shared/aspects.js +22 -0
  176. package/dist/shared/aspects.js.map +1 -0
  177. package/dist/shared/assistant.d.ts +7 -0
  178. package/dist/shared/assistant.js +36 -0
  179. package/dist/shared/assistant.js.map +1 -0
  180. package/dist/shared/chat.d.ts +46 -0
  181. package/dist/shared/chat.js +2 -0
  182. package/dist/shared/chat.js.map +1 -0
  183. package/dist/shared/settings.d.ts +11 -0
  184. package/dist/shared/settings.js +25 -0
  185. package/dist/shared/settings.js.map +1 -0
  186. package/dist/shared/types.d.ts +510 -0
  187. package/dist/shared/types.js +2 -0
  188. package/dist/shared/types.js.map +1 -0
  189. package/dist/web/apple-touch-icon.png +0 -0
  190. package/dist/web/assets/AgentActivity-BmfJK4y-.js +9 -0
  191. package/dist/web/assets/ArrowRight.es-rFSWI60-.js +1 -0
  192. package/dist/web/assets/ArrowUpRight.es-9AGQAwc-.js +1 -0
  193. package/dist/web/assets/AssetMediaPreview-Cqs-ltSx.js +1 -0
  194. package/dist/web/assets/AssetSelectionWizard-BB3qGs0g.js +1 -0
  195. package/dist/web/assets/CaretDown.es-BF-GEzW4.js +1 -0
  196. package/dist/web/assets/Check.es-C6V98Gx8.js +1 -0
  197. package/dist/web/assets/CheckCircle.es-CAQfdit1.js +1 -0
  198. package/dist/web/assets/CoreAccount-Dkpl4Rzw.js +1 -0
  199. package/dist/web/assets/DownloadSimple.es-CwuHLlwX.js +1 -0
  200. package/dist/web/assets/FileText.es-C7Qe_oPL.js +1 -0
  201. package/dist/web/assets/IconBase.es-Bvh5HoVq.js +1 -0
  202. package/dist/web/assets/ImageSquare.es-DXp8f5Py.js +1 -0
  203. package/dist/web/assets/KidsApp-BRwDKhZO.js +2 -0
  204. package/dist/web/assets/KidsApp-BXWaALoK.css +1 -0
  205. package/dist/web/assets/MagnifyingGlass.es-DAAoXLM5.js +1 -0
  206. package/dist/web/assets/PencilSimple.es-B8ERAsFN.js +1 -0
  207. package/dist/web/assets/PlainChat-BC4K_tmj.css +1 -0
  208. package/dist/web/assets/PlainChat-DT-l2KJ-.js +1 -0
  209. package/dist/web/assets/Plus.es-xuvXKifF.js +1 -0
  210. package/dist/web/assets/Sparkle.es-B2bpSK_D.js +1 -0
  211. package/dist/web/assets/Square.es-POdDsCpj.js +1 -0
  212. package/dist/web/assets/UploadSimple.es-DIzZ2Med.js +1 -0
  213. package/dist/web/assets/WarningCircle.es-DeosDn7W.js +1 -0
  214. package/dist/web/assets/WorkflowJournal-CnLiVdGb.js +1 -0
  215. package/dist/web/assets/YandexConfigFields-B4ZNwcRp.js +1 -0
  216. package/dist/web/assets/YandexGamesView-JIfZE9xK.js +2 -0
  217. package/dist/web/assets/bg-build-DIalyCDw.svg +3 -0
  218. package/dist/web/assets/bg-idea-DHcE-Dhs.svg +3 -0
  219. package/dist/web/assets/bg-materials-UDVFaueI.svg +3 -0
  220. package/dist/web/assets/bg-plan-DpfwIsqJ.svg +3 -0
  221. package/dist/web/assets/bg-play-CNc1QZFK.svg +3 -0
  222. package/dist/web/assets/dist-BmzcNjGQ.js +1 -0
  223. package/dist/web/assets/index-IRbQKmkO.js +13 -0
  224. package/dist/web/assets/index-aj0ikA52.css +1 -0
  225. package/dist/web/assets/manrope-cyrillic-wght-normal-Dvxsihut.woff2 +0 -0
  226. package/dist/web/assets/manrope-greek-wght-normal-DL7QRZyv.woff2 +0 -0
  227. package/dist/web/assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2 +0 -0
  228. package/dist/web/assets/manrope-latin-wght-normal-DHIcAJRg.woff2 +0 -0
  229. package/dist/web/assets/manrope-vietnamese-wght-normal-usUDDRr7.woff2 +0 -0
  230. package/dist/web/assets/resources-CT9ITJ8m.js +1 -0
  231. package/dist/web/assets/robot-happy-B6YvlU94.svg +24 -0
  232. package/dist/web/assets/robot-hello-CCsQgsS-.svg +24 -0
  233. package/dist/web/assets/robot-listen-Buuz9xII.svg +24 -0
  234. package/dist/web/assets/robot-sad-CRtiNVWs.svg +24 -0
  235. package/dist/web/assets/robot-think-CJ5fDBTm.svg +24 -0
  236. package/dist/web/assets/star-big-CSFDKjws.svg +22 -0
  237. package/dist/web/assets/star-empty-CC-5vioJ.svg +3 -0
  238. package/dist/web/assets/star-next-ztuDjOHU.svg +9 -0
  239. package/dist/web/assets/star-on-l_krO3aV.svg +10 -0
  240. package/dist/web/assets/ui-CVc6Nw0y.js +41 -0
  241. package/dist/web/assets/umgt-logo-DAOkTN9u.png +0 -0
  242. package/dist/web/assets/unbounded-cyrillic-wght-normal-C627f1f8.woff2 +0 -0
  243. package/dist/web/assets/unbounded-latin-ext-wght-normal-D6H-S6MW.woff2 +0 -0
  244. package/dist/web/assets/unbounded-latin-wght-normal-D5afBTBx.woff2 +0 -0
  245. package/dist/web/assets/unbounded-vietnamese-wght-normal-rat7GD3o.woff2 +0 -0
  246. package/dist/web/assets/workflow-BhcU9uvG.css +1 -0
  247. package/dist/web/assets/workflow-o5sZ-osd.js +34 -0
  248. package/dist/web/favicon.ico +0 -0
  249. package/dist/web/icons/favicon-16.png +0 -0
  250. package/dist/web/icons/favicon-32.png +0 -0
  251. package/dist/web/icons/icon-192.png +0 -0
  252. package/dist/web/icons/icon-512.png +0 -0
  253. package/dist/web/icons/maskable-192.png +0 -0
  254. package/dist/web/icons/maskable-512.png +0 -0
  255. package/dist/web/index.html +28 -0
  256. package/dist/web/manifest.webmanifest +19 -0
  257. package/dist/web/sw.js +25 -0
  258. package/docs/agent-activity-ui.md +33 -0
  259. package/docs/agent-activity.md +43 -0
  260. package/docs/agent-permissions-ui.md +15 -0
  261. package/docs/api.md +145 -0
  262. package/docs/approval-journal.md +13 -0
  263. package/docs/asset-media.md +27 -0
  264. package/docs/asset-providers.md +34 -0
  265. package/docs/asset-selection.md +31 -0
  266. package/docs/automatic-approvals.md +15 -0
  267. package/docs/background-game-launch.md +17 -0
  268. package/docs/billing-validation.md +23 -0
  269. package/docs/core-isolation.md +37 -0
  270. package/docs/core.md +45 -0
  271. package/docs/generated-text-ui.md +41 -0
  272. package/docs/interactive-interview-ui.md +29 -0
  273. package/docs/interactive-interview.md +52 -0
  274. package/docs/local-codex.md +51 -0
  275. package/docs/local-meshy.md +13 -0
  276. package/docs/markdown.md +11 -0
  277. package/docs/permission-ui.md +11 -0
  278. package/docs/plan.md +47 -0
  279. package/docs/remote-core-deployment.md +47 -0
  280. package/docs/roblox.md +90 -0
  281. package/docs/validation.md +228 -0
  282. package/docs/video-reference.md +35 -0
  283. package/docs/workflow-journal-ui.md +21 -0
  284. package/docs/yandex-foundation.md +27 -0
  285. package/docs/yandex-games.md +45 -0
  286. package/package.json +85 -4
  287. package/scripts/create-roblox-demo.mjs +31 -0
  288. package/scripts/diagnose-roblox-mcp.mjs +45 -0
  289. package/scripts/open-hub-chrome.mjs +60 -0
  290. package/scripts/smoke-agent.mjs +91 -0
@@ -0,0 +1,170 @@
1
+ import { cp, lstat, mkdir, mkdtemp, rename, rm, open } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { spawn } from 'node:child_process';
5
+ import { detectRoblox } from './roblox.js';
6
+ import { runProcess } from './process.js';
7
+ const downloadHosts = new Set(['setup.rbxcdn.com', 'setup-ak.rbxcdn.com', 'setup-cfly.rbxcdn.com', 'clientsettingscdn.roblox.com']);
8
+ export async function officialDownload(url, signal) {
9
+ for (let redirects = 0; redirects < 5; redirects++) {
10
+ const target = new URL(url);
11
+ if (target.protocol !== 'https:' || !downloadHosts.has(target.hostname) || target.username || target.password || target.port)
12
+ throw new Error('Недопустимый адрес установщика Roblox');
13
+ let response;
14
+ try {
15
+ response = await fetch(target, { redirect: 'manual', signal });
16
+ }
17
+ catch (error) {
18
+ signal.throwIfAborted();
19
+ const code = error.cause?.code;
20
+ throw new Error(`Не удалось загрузить Roblox Studio с официального CDN${code ? ` (${code})` : ''}. Проверьте доступ к сети и повторите настройку.`);
21
+ }
22
+ if ([301, 302, 303, 307, 308].includes(response.status)) {
23
+ const location = response.headers.get('location');
24
+ await response.body?.cancel();
25
+ if (!location)
26
+ throw new Error('Roblox CDN вернул перенаправление без адреса');
27
+ url = new URL(location, target).href;
28
+ continue;
29
+ }
30
+ if (!response.ok) {
31
+ await response.body?.cancel();
32
+ throw new Error(`Roblox CDN: HTTP ${response.status}`);
33
+ }
34
+ return response;
35
+ }
36
+ throw new Error('Слишком много перенаправлений Roblox CDN');
37
+ }
38
+ async function downloadFile(url, filename, signal, progress) {
39
+ const response = await officialDownload(url, signal);
40
+ const file = await open(filename, 'wx', 0o600);
41
+ let bytes = 0, reported = 0;
42
+ try {
43
+ if (!response.body)
44
+ throw new Error('Пустой ответ установщика');
45
+ for await (const chunk of response.body) {
46
+ signal.throwIfAborted();
47
+ bytes += chunk.byteLength;
48
+ if (bytes > 600 * 1024 * 1024)
49
+ throw new Error('Установщик превышает допустимый размер');
50
+ await file.writeFile(Buffer.from(chunk));
51
+ if (bytes - reported > 10 * 1024 * 1024) {
52
+ reported = bytes;
53
+ progress(`Загрузка Roblox Studio: ${Math.round(bytes / 1024 / 1024)} МБ`);
54
+ }
55
+ }
56
+ if (!bytes)
57
+ throw new Error('Пустой установщик');
58
+ }
59
+ finally {
60
+ await file.close();
61
+ }
62
+ }
63
+ const pending = new Map();
64
+ /** No sudo, Homebrew, unsigned binaries, preference edits, cookies or CLI permission changes. */
65
+ export async function ensureRobloxInstalled(configured, dataDir, signal, progress = () => { }) {
66
+ const existing = await detectRoblox(configured, signal);
67
+ if (existing.available)
68
+ return existing;
69
+ if (configured?.trim())
70
+ throw new Error('Указанный путь Studio не найден. Очистите его для автоматической установки.');
71
+ if (!['darwin', 'win32'].includes(process.platform))
72
+ throw new Error('Roblox Studio поддерживает macOS и Windows. На Linux доступна только локальная сборка.');
73
+ const key = process.platform;
74
+ const current = pending.get(key);
75
+ if (current) {
76
+ await current;
77
+ signal.throwIfAborted();
78
+ return detectRoblox(undefined, signal);
79
+ }
80
+ const work = install(dataDir, signal, progress);
81
+ pending.set(key, work);
82
+ try {
83
+ return await work;
84
+ }
85
+ finally {
86
+ pending.delete(key);
87
+ }
88
+ }
89
+ async function install(dataDir, outerSignal, progress) {
90
+ const signal = AbortSignal.any([outerSignal, AbortSignal.timeout(300_000)]);
91
+ const directory = join(dataDir, 'roblox-install');
92
+ await mkdir(directory, { recursive: true });
93
+ const staging = await mkdtemp(join(directory, 'download-'));
94
+ try {
95
+ if (process.platform === 'darwin') {
96
+ progress('Определяем последнюю версию Roblox Studio');
97
+ const response = await officialDownload('https://clientsettingscdn.roblox.com/v1/client-version/MacStudio', signal);
98
+ const version = await response.json();
99
+ if (!/^version-[a-f0-9]{16}$/i.test(version.clientVersionUpload ?? ''))
100
+ throw new Error('Roblox вернул неизвестный формат версии Studio');
101
+ const archive = join(staging, 'studio.zip'), unpacked = join(staging, 'unpacked');
102
+ progress('Загружаем Roblox Studio с официального CDN');
103
+ await downloadFile(`https://setup.rbxcdn.com/mac/${process.arch === 'arm64' ? 'arm64/' : ''}${version.clientVersionUpload}-RobloxStudioApp.zip`, archive, signal, progress);
104
+ const extracted = await runProcess('/usr/bin/ditto', ['-x', '-k', archive, unpacked], { signal, timeout: 120_000 });
105
+ if (extracted.code !== 0)
106
+ throw new Error(`Не удалось распаковать Studio: ${extracted.output}`);
107
+ const bundle = join(unpacked, 'RobloxStudio.app');
108
+ progress('Проверяем подпись Roblox Studio');
109
+ const signed = await runProcess('/usr/bin/codesign', ['--verify', '--deep', '--strict', bundle], { signal, timeout: 30_000 });
110
+ const identity = await runProcess('/usr/bin/codesign', ['-d', '--verbose=2', bundle], { signal, timeout: 15_000 });
111
+ if (signed.code !== 0 || identity.code !== 0 || !identity.output.includes('TeamIdentifier=2CFABCH843'))
112
+ throw new Error('Не удалось подтвердить подпись разработчика Roblox');
113
+ const applications = join(homedir(), 'Applications'), destination = join(applications, 'RobloxStudio.app');
114
+ await mkdir(applications, { recursive: true });
115
+ // Never replace an installed editor or delete somebody else's bundle.
116
+ if (await lstat(destination).then(() => true).catch(() => false))
117
+ throw new Error('RobloxStudio.app уже существует в ~/Applications; автоматическая замена отключена');
118
+ try {
119
+ await rename(bundle, destination);
120
+ }
121
+ catch (error) {
122
+ if (error.code !== 'EXDEV')
123
+ throw error;
124
+ const localStaging = await mkdtemp(join(applications, '.lmgh-studio-'));
125
+ try {
126
+ const copied = join(localStaging, 'RobloxStudio.app');
127
+ await cp(bundle, copied, { recursive: true, errorOnExist: true, force: false, verbatimSymlinks: true });
128
+ const verified = await runProcess('/usr/bin/codesign', ['--verify', '--deep', '--strict', copied], { signal, timeout: 30_000 });
129
+ if (verified.code !== 0)
130
+ throw new Error('Подпись Studio не прошла проверку после копирования');
131
+ signal.throwIfAborted();
132
+ await rename(copied, destination);
133
+ }
134
+ finally {
135
+ await rm(localStaging, { recursive: true, force: true });
136
+ }
137
+ }
138
+ progress('Roblox Studio установлена в ~/Applications');
139
+ return detectRoblox(undefined, signal);
140
+ }
141
+ progress('Загружаем официальный установщик Roblox Studio');
142
+ const installer = join(staging, 'RobloxStudioLauncherBeta.exe');
143
+ await downloadFile('https://setup.rbxcdn.com/RobloxStudioLauncherBeta.exe', installer, signal, progress);
144
+ // Check Authenticode before running the official bootstrapper. The path is an
145
+ // environment value rather than interpolated PowerShell source.
146
+ const verification = await new Promise((resolve, reject) => {
147
+ const child = spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', "$s=Get-AuthenticodeSignature -LiteralPath $env:LMGH_ROBLOX_INSTALLER; if($s.Status -eq 'Valid' -and $s.SignerCertificate.Subject -match 'O=ROBLOX Corporation(,|$)'){exit 0};exit 1"], { env: { ...process.env, LMGH_ROBLOX_INSTALLER: installer }, stdio: 'ignore', windowsHide: true, signal });
148
+ child.once('error', reject);
149
+ child.once('close', code => resolve(code ?? 1));
150
+ });
151
+ if (verification !== 0)
152
+ throw new Error('Не удалось подтвердить подпись установщика Roblox');
153
+ progress('Устанавливаем Studio. Завершите системное подтверждение, если оно появится');
154
+ const installed = await runProcess(installer, [], { signal, timeout: 180_000 });
155
+ if (installed.code !== 0)
156
+ throw new Error('Установщик Studio не завершился: завершите системный диалог и повторите настройку');
157
+ for (let attempt = 0; attempt < 20; attempt++) {
158
+ const studio = await detectRoblox(undefined, signal);
159
+ if (studio.available)
160
+ return studio;
161
+ signal.throwIfAborted();
162
+ await new Promise((resolve, reject) => { const abort = () => { clearTimeout(timer); reject(signal.reason); }; const timer = setTimeout(() => { signal.removeEventListener('abort', abort); resolve(); }, 1500); signal.addEventListener('abort', abort, { once: true }); });
163
+ }
164
+ throw new Error('Завершите установку в открытом системном окне и повторите настройку');
165
+ }
166
+ finally {
167
+ await rm(staging, { recursive: true, force: true });
168
+ }
169
+ }
170
+ //# sourceMappingURL=roblox-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roblox-install.js","sourceRoot":"","sources":["../../src/server/roblox-install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Agent subprocess uses the Hub-owned Studio connection; no global config edits. */
2
+ export declare function serveRobloxMcp(): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
+ import { fileURLToPath } from 'node:url';
5
+ /** Agent subprocess uses the Hub-owned Studio connection; no global config edits. */
6
+ export async function serveRobloxMcp() {
7
+ const url = new URL(process.env.LM_HUB_ROBLOX_URL ?? '');
8
+ if (url.protocol !== 'http:' || url.hostname !== '127.0.0.1' || !/^\/api\/v1\/projects\/[^/]+\/roblox\/mcp$/.test(url.pathname) || url.search || url.hash)
9
+ throw new Error('Invalid project Studio endpoint');
10
+ const token = process.env.LM_HUB_ROBLOX_TOKEN;
11
+ if (!token)
12
+ throw new Error('Missing Studio capability');
13
+ const call = async (body) => {
14
+ const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify(body), redirect: 'error', signal: AbortSignal.timeout(120_000) });
15
+ const data = await response.json();
16
+ if (!response.ok)
17
+ throw new Error(data.message ?? 'Studio request failed');
18
+ return data;
19
+ };
20
+ const server = new Server({ name: 'lm-game-hub-roblox', version: '0.1.0' }, { capabilities: { tools: {} } });
21
+ server.setRequestHandler(ListToolsRequestSchema, async () => await call({ action: 'list' }));
22
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
23
+ try {
24
+ return await call({ action: 'call', name: request.params.name, arguments: request.params.arguments ?? {} });
25
+ }
26
+ catch (error) {
27
+ return { isError: true, content: [{ type: 'text', text: error instanceof Error ? error.message : String(error) }] };
28
+ }
29
+ });
30
+ await server.connect(new StdioServerTransport());
31
+ }
32
+ if (process.argv[1] === fileURLToPath(import.meta.url))
33
+ await serveRobloxMcp();
34
+ //# sourceMappingURL=roblox-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roblox-mcp.js","sourceRoot":"","sources":["../../src/server/roblox-mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { HubContext } from './app.js';
2
+ import type { HubSettings, RobloxPlayStatus } from '../shared/types.js';
3
+ import type { StudioConnection } from './roblox-connection.js';
4
+ /** Play commands share the project-scoped connection, never reopen a place. */
5
+ export declare class RobloxPlay {
6
+ private hub;
7
+ private connection;
8
+ private settings;
9
+ private states;
10
+ private pending;
11
+ private reads;
12
+ private controller;
13
+ constructor(hub: HubContext, connection: StudioConnection, settings: () => HubSettings);
14
+ private current;
15
+ private update;
16
+ private read;
17
+ state(id: string): Promise<RobloxPlayStatus>;
18
+ assertIdle(id: string): void;
19
+ run(id: string, signal?: AbortSignal): Promise<RobloxPlayStatus>;
20
+ stop(id: string): Promise<RobloxPlayStatus>;
21
+ private command;
22
+ close(): Promise<void>;
23
+ }
@@ -0,0 +1,84 @@
1
+ /** Play commands share the project-scoped connection, never reopen a place. */
2
+ export class RobloxPlay {
3
+ hub;
4
+ connection;
5
+ settings;
6
+ states = new Map();
7
+ pending = new Map();
8
+ reads = new Map();
9
+ controller = new AbortController();
10
+ constructor(hub, connection, settings) {
11
+ this.hub = hub;
12
+ this.connection = connection;
13
+ this.settings = settings;
14
+ }
15
+ current(id) { return this.states.get(id) ?? { projectId: id, status: 'unknown', checkedAt: new Date().toISOString() }; }
16
+ update(id, patch) {
17
+ const previous = this.current(id), state = { ...previous, ...patch, checkedAt: new Date().toISOString() };
18
+ this.states.set(id, state);
19
+ if (previous.status !== state.status || previous.error !== state.error || previous.studioId !== state.studioId)
20
+ this.hub.events.publish('engine.state', state, id);
21
+ return state;
22
+ }
23
+ async read(id) {
24
+ try {
25
+ await this.connection.connect(this.settings(), this.controller.signal);
26
+ const state = await this.connection.playing(id, undefined, this.controller.signal);
27
+ return this.update(id, { status: state.playing ? 'playing' : 'stopped', studioId: state.studioId, error: undefined });
28
+ }
29
+ catch (error) {
30
+ return this.update(id, { status: 'failed', error: error instanceof Error ? error.message : String(error) });
31
+ }
32
+ }
33
+ async state(id) {
34
+ if (this.pending.has(id))
35
+ return this.current(id);
36
+ const current = this.reads.get(id);
37
+ if (current)
38
+ return current;
39
+ const read = this.read(id);
40
+ this.reads.set(id, read);
41
+ try {
42
+ return await read;
43
+ }
44
+ finally {
45
+ if (this.reads.get(id) === read)
46
+ this.reads.delete(id);
47
+ }
48
+ }
49
+ assertIdle(id) { if (this.pending.has(id))
50
+ throw Object.assign(new Error('Команда Play ещё выполняется'), { statusCode: 409 }); }
51
+ run(id, signal) {
52
+ this.assertIdle(id);
53
+ return this.command(id, true, signal);
54
+ }
55
+ stop(id) {
56
+ // Do not abort a dispatched start: it may still enter Play inside Studio.
57
+ // Queue Stop after its confirmation (or failure), then confirm Edit.
58
+ const prior = this.pending.get(id);
59
+ return this.command(id, false, undefined, prior);
60
+ }
61
+ command(id, playing, signal, prior) {
62
+ const job = (async () => {
63
+ await prior?.catch(() => { });
64
+ await this.reads.get(id);
65
+ this.update(id, { status: playing ? 'starting' : 'stopping', error: undefined });
66
+ const combined = signal ? AbortSignal.any([signal, this.controller.signal]) : this.controller.signal;
67
+ try {
68
+ await this.connection.connect(this.settings(), combined);
69
+ const state = await this.connection.setPlaying(id, playing, combined);
70
+ return this.update(id, { status: state.playing ? 'playing' : 'stopped', studioId: state.studioId, error: undefined });
71
+ }
72
+ catch (error) {
73
+ this.update(id, { status: 'failed', error: error instanceof Error ? error.message : String(error) });
74
+ throw error;
75
+ }
76
+ })();
77
+ this.pending.set(id, job);
78
+ void job.finally(() => { if (this.pending.get(id) === job)
79
+ this.pending.delete(id); }).catch(() => { });
80
+ return job;
81
+ }
82
+ async close() { this.controller.abort(); await Promise.allSettled([...this.pending.values(), ...this.reads.values()]); }
83
+ }
84
+ //# sourceMappingURL=roblox-play.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roblox-play.js","sourceRoot":"","sources":["../../src/server/roblox-play.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { Project } from '../shared/types.js';
3
+ import type { HubContext } from './app.js';
4
+ import type { StudioConnection } from './roblox-connection.js';
5
+ import { openRoblox } from './roblox.js';
6
+ export declare const robloxProjectTools: Tool[];
7
+ export declare function resolveOpenedBuild(hub: HubContext, connection: StudioConnection, project: Project, signal?: AbortSignal): Promise<void>;
8
+ export declare function openedBuildTarget(hub: HubContext, connection: StudioConnection, project: Project, signal?: AbortSignal): Promise<import("./roblox-connection.js").StudioInstance>;
9
+ export declare function callRobloxProjectTool(hub: HubContext, connection: StudioConnection, project: Project, name: string, signal: AbortSignal, options?: {
10
+ open?: typeof openRoblox;
11
+ }): Promise<CallToolResult>;
@@ -0,0 +1,119 @@
1
+ import { z } from 'zod';
2
+ import { mkdir, writeFile, lstat, realpath } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { StudioConnectionError } from './roblox-connection.js';
5
+ import { buildRoblox, openRoblox } from './roblox.js';
6
+ import { robloxResult } from './roblox-assets.js';
7
+ export const robloxProjectTools = [
8
+ { name: 'hub_build', description: 'Build this project from its current filesystem sources into builds/game.rbxlx. Reports packaging only; does not prove gameplay.', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
9
+ { name: 'hub_open_build', description: 'Build and ask the installed Roblox Studio to open or focus this project’s generated builds/game.rbxlx, after checking ownership and requiring Edit mode. Revalidates the project marker. Opening is not a reload or gameplay guarantee: verify loaded source and asset properties against the build before Play. Does not publish or close other places.', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
10
+ { name: 'hub_sync_scripts', description: 'Build and copy current filesystem Luau sources into the verified project place in Edit mode. Preserves prior Studio sources in .lm-game-hub/studio-backups. Creates missing script folders. Does not publish, change the project marker, or start Play. Use before testing changed scripts.', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
11
+ ];
12
+ const result = (value) => ({ content: [{ type: 'text', text: JSON.stringify(value) }] });
13
+ function literal(value) { let equals = ''; while (value.includes(']' + equals + ']'))
14
+ equals += '='; return 'string.sub([' + equals + '[!' + value + ']' + equals + '],2)'; }
15
+ export async function resolveOpenedBuild(hub, connection, project, signal) {
16
+ let request = hub.store.get('roblox-open-requests', project.id);
17
+ if (!request && !hub.store.get('roblox-targets', project.id)) {
18
+ // Recover an opening from an earlier Hub version, including late registration.
19
+ const row = hub.store.db.prepare("SELECT payload FROM events WHERE project_id=? AND type='roblox.opened' ORDER BY id DESC LIMIT 1").get(project.id);
20
+ const opened = row ? JSON.parse(String(row.payload)) : undefined;
21
+ if (opened?.openingRequested === true && typeof opened.studioId === 'string' && typeof opened.path === 'string')
22
+ request = { id: project.id, path: opened.path, before: [opened.studioId] };
23
+ }
24
+ if (!request || request.resolved)
25
+ return;
26
+ if (request.path !== join(await realpath(project.path), 'builds/game.rbxlx'))
27
+ throw new Error('Opening does not belong to this project build');
28
+ const candidates = (await connection.instances(signal)).filter(studio => !request.before.includes(studio.id));
29
+ if (!candidates.length)
30
+ return;
31
+ const scripts = [];
32
+ const build = await buildRoblox(project, { signal, onScript: s => scripts.push(s) });
33
+ if (!build.ok)
34
+ throw new Error(build.output);
35
+ const specs = scripts.map(s => `{path=${literal(s.path)},source=${literal(s.source)},segments={${s.path.split('.').slice(1).map(literal).join(',')}}}`).join(',');
36
+ const code = `local output={};for _,spec in {${specs}} do local s=game;for _,name in spec.segments do s=s and s:FindFirstChild(name) end;table.insert(output,{path=spec.path,className=s and s.ClassName or '',matches=s~=nil and s:IsA('LuaSourceContainer') and s.Source==spec.source}) end;return game:GetService('HttpService'):JSONEncode(output)`;
37
+ const matching = [];
38
+ for (const candidate of candidates) {
39
+ if (!await connection.owns(candidate.id, project.id, signal))
40
+ continue;
41
+ const sources = z.array(z.object({ path: z.string(), className: z.string(), matches: z.boolean() })).parse(robloxResult(await connection.raw('execute_luau', { studio_id: candidate.id, datamodel_type: 'Edit', code }, signal)));
42
+ if (sources.length === scripts.length && scripts.every(s => sources.some(value => value.path === s.path && value.className === s.className && value.matches)))
43
+ matching.push(candidate.id);
44
+ }
45
+ if (matching.length !== 1)
46
+ throw new StudioConnectionError('target_ambiguous', 'Открытая сборка не выбрана: требуется одна новая сцена с UUID проекта и точными исходниками сборки');
47
+ hub.store.put('roblox-targets', { id: project.id, studioId: matching[0], path: request.path });
48
+ hub.store.put('roblox-open-requests', { ...request, resolved: true });
49
+ hub.events.publish('roblox.target-selected', { studioId: matching[0], path: request.path, sourceVerified: true }, project.id);
50
+ }
51
+ export async function openedBuildTarget(hub, connection, project, signal) {
52
+ try {
53
+ return await connection.target(project.id, signal);
54
+ }
55
+ catch (error) {
56
+ if (!(error instanceof StudioConnectionError) || error.reason !== 'target_ambiguous')
57
+ throw error;
58
+ await resolveOpenedBuild(hub, connection, project, signal);
59
+ return connection.target(project.id, signal);
60
+ }
61
+ }
62
+ export async function callRobloxProjectTool(hub, connection, project, name, signal, options = {}) {
63
+ if (name === 'hub_open_build') {
64
+ if ((await connection.playing(project.id, undefined, signal)).playing)
65
+ throw Object.assign(new Error('Остановите Play перед открытием сборки'), { statusCode: 409 });
66
+ const before = await connection.instances(signal);
67
+ hub.store.put('roblox-open-requests', { id: project.id, path: join(await realpath(project.path), 'builds/game.rbxlx'), before: before.map(s => s.id) });
68
+ const opened = await (options.open ?? openRoblox)(project, hub.store.get('settings', 'settings')?.robloxStudioPath, { signal, emit: text => hub.events.publish('log', { text }, project.id) });
69
+ if (!opened.ok)
70
+ return { ...result(opened), isError: true };
71
+ await resolveOpenedBuild(hub, connection, project, signal);
72
+ const target = await openedBuildTarget(hub, connection, project, signal);
73
+ const value = { ...opened, studioId: target.id, openingRequested: true, gameplayVerified: false, reloadVerified: false };
74
+ hub.events.publish('roblox.opened', value, project.id);
75
+ return result(value);
76
+ }
77
+ const scripts = [];
78
+ const build = await buildRoblox(project, { signal, onScript: script => scripts.push(script), emit: text => hub.events.publish('log', { text }, project.id) });
79
+ if (!build.ok)
80
+ return { ...result(build), isError: true };
81
+ if (name === 'hub_build')
82
+ return result(build);
83
+ if (name !== 'hub_sync_scripts')
84
+ throw new Error('Unknown Hub project tool');
85
+ if ((await connection.playing(project.id, undefined, signal)).playing)
86
+ throw Object.assign(new Error('Остановите Play перед синхронизацией исходников'), { statusCode: 409 });
87
+ const saved = [];
88
+ const synced = [];
89
+ for (const script of scripts) {
90
+ signal.throwIfAborted();
91
+ const parts = script.path.split('.');
92
+ if (parts[0] !== 'game' || parts.some(part => !part || !/^[-\p{L}\p{N}_ ]+$/u.test(part)))
93
+ throw new Error('Script path cannot be represented safely by Studio MCP: ' + script.path);
94
+ const segments = parts.slice(1);
95
+ const code = `local segments=${'{' + segments.map(literal).join(',') + '}'};local current=game;for i=1,#segments-1 do local next=current:FindFirstChild(segments[i]);if not next then next=Instance.new('Folder');next.Name=segments[i];next.Parent=current end;current=next end;local s=current:FindFirstChild(segments[#segments]);if s then assert(s.ClassName==${literal(script.className)},'Script path is occupied by another class') end;return game:GetService('HttpService'):JSONEncode({exists=s~=nil,source=s and s.Source or ''})`;
96
+ const read = z.object({ exists: z.boolean(), source: z.string() }).parse(robloxResult(await connection.call(project.id, 'execute_luau', { datamodel_type: 'Edit', code }, signal)));
97
+ if (read.source === script.source)
98
+ continue;
99
+ saved.push({ path: script.path, exists: read.exists, source: read.source });
100
+ // Persist the prior source before dispatching any change.
101
+ const directory = join(project.path, '.lm-game-hub', 'studio-backups');
102
+ for (const path of [join(project.path, '.lm-game-hub'), directory]) {
103
+ const info = await lstat(path).catch(error => { if (error.code !== 'ENOENT')
104
+ throw error; return undefined; });
105
+ if (info?.isSymbolicLink())
106
+ throw new Error('Studio backup directory must not be a symlink');
107
+ }
108
+ await mkdir(directory, { recursive: true });
109
+ await writeFile(join(directory, `sync-${Date.now()}-${synced.length}.json`), JSON.stringify(saved, null, 2), { flag: 'wx' });
110
+ const edited = await connection.call(project.id, 'multi_edit', { datamodel_type: 'Edit', file_path: script.path, ...(!read.exists ? { className: script.className } : {}), edits: [{ old_string: read.source, new_string: script.source }] }, signal);
111
+ if (edited.isError)
112
+ throw new Error(edited.content.filter(b => b.type === 'text').map(b => b.text).join('\n'));
113
+ synced.push(script.path);
114
+ }
115
+ const value = { ok: true, path: build.path, scripts: scripts.length, synced, output: 'Filesystem Luau synchronized with verified Studio project; Play not started.' };
116
+ hub.events.publish('roblox.synced', value, project.id);
117
+ return result(value);
118
+ }
119
+ //# sourceMappingURL=roblox-project-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roblox-project-tools.js","sourceRoot":"","sources":["../../src/server/roblox-project-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { HubContext } from './app.js';
3
+ import type { HubSettings, Project, RobloxSetupStatus } from '../shared/types.js';
4
+ import type { AgentMcpServer } from './agents/types.js';
5
+ import { StudioConnection } from './roblox-connection.js';
6
+ import { RobloxPlay } from './roblox-play.js';
7
+ export declare class RobloxSetup {
8
+ private hub;
9
+ private settings;
10
+ private jobs;
11
+ readonly connection: StudioConnection;
12
+ readonly play: RobloxPlay;
13
+ private closed;
14
+ constructor(hub: HubContext, settings: () => HubSettings);
15
+ status(project: Project): RobloxSetupStatus;
16
+ assertIdle(id: string): void;
17
+ settle(id: string): Promise<void>;
18
+ cancel(project: Project): RobloxSetupStatus;
19
+ private update;
20
+ start(project: Project): RobloxSetupStatus;
21
+ private failure;
22
+ private prepare;
23
+ private ready;
24
+ check(project: Project, signal?: AbortSignal): Promise<RobloxSetupStatus>;
25
+ agentConfig(project: Project, signal?: AbortSignal): Promise<{
26
+ server?: AgentMcpServer;
27
+ message: string;
28
+ }>;
29
+ close(): Promise<void>;
30
+ }
31
+ export declare function registerRobloxSetup(app: FastifyInstance, hub: HubContext, settings: () => HubSettings, projectById: (id: string) => Project, assertIdle: (id: string) => void, executionSignal: (id: string) => AbortSignal | undefined): {
32
+ setup: RobloxSetup;
33
+ config: (p: Project, signal?: AbortSignal) => Promise<{
34
+ server?: AgentMcpServer;
35
+ message: string;
36
+ }>;
37
+ };