@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.
Files changed (295) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -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 +38 -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/reports.d.ts +4 -0
  108. package/dist/server/reports.js +40 -0
  109. package/dist/server/reports.js.map +1 -0
  110. package/dist/server/roblox-assets.d.ts +41 -0
  111. package/dist/server/roblox-assets.js +131 -0
  112. package/dist/server/roblox-assets.js.map +1 -0
  113. package/dist/server/roblox-connection.d.ts +54 -0
  114. package/dist/server/roblox-connection.js +331 -0
  115. package/dist/server/roblox-connection.js.map +1 -0
  116. package/dist/server/roblox-install.d.ts +4 -0
  117. package/dist/server/roblox-install.js +170 -0
  118. package/dist/server/roblox-install.js.map +1 -0
  119. package/dist/server/roblox-mcp.d.ts +2 -0
  120. package/dist/server/roblox-mcp.js +34 -0
  121. package/dist/server/roblox-mcp.js.map +1 -0
  122. package/dist/server/roblox-play.d.ts +23 -0
  123. package/dist/server/roblox-play.js +84 -0
  124. package/dist/server/roblox-play.js.map +1 -0
  125. package/dist/server/roblox-project-tools.d.ts +11 -0
  126. package/dist/server/roblox-project-tools.js +119 -0
  127. package/dist/server/roblox-project-tools.js.map +1 -0
  128. package/dist/server/roblox-setup.d.ts +37 -0
  129. package/dist/server/roblox-setup.js +206 -0
  130. package/dist/server/roblox-setup.js.map +1 -0
  131. package/dist/server/roblox-skills.d.ts +15 -0
  132. package/dist/server/roblox-skills.js +15 -0
  133. package/dist/server/roblox-skills.js.map +1 -0
  134. package/dist/server/roblox.d.ts +30 -0
  135. package/dist/server/roblox.js +248 -0
  136. package/dist/server/roblox.js.map +1 -0
  137. package/dist/server/routes.d.ts +11 -0
  138. package/dist/server/routes.js +223 -0
  139. package/dist/server/routes.js.map +1 -0
  140. package/dist/server/security.d.ts +4 -0
  141. package/dist/server/security.js +64 -0
  142. package/dist/server/security.js.map +1 -0
  143. package/dist/server/skills.d.ts +4 -0
  144. package/dist/server/skills.js +123 -0
  145. package/dist/server/skills.js.map +1 -0
  146. package/dist/server/store.d.ts +25 -0
  147. package/dist/server/store.js +89 -0
  148. package/dist/server/store.js.map +1 -0
  149. package/dist/server/templates/roblox-coin-run.d.ts +2 -0
  150. package/dist/server/templates/roblox-coin-run.js +326 -0
  151. package/dist/server/templates/roblox-coin-run.js.map +1 -0
  152. package/dist/server/templates/roblox-skills.json +55 -0
  153. package/dist/server/templates/yandex-sdk.d.ts +3 -0
  154. package/dist/server/templates/yandex-sdk.js +177 -0
  155. package/dist/server/templates/yandex-sdk.js.map +1 -0
  156. package/dist/server/updates.d.ts +28 -0
  157. package/dist/server/updates.js +99 -0
  158. package/dist/server/updates.js.map +1 -0
  159. package/dist/server/video-media.d.ts +47 -0
  160. package/dist/server/video-media.js +224 -0
  161. package/dist/server/video-media.js.map +1 -0
  162. package/dist/server/video-routes.d.ts +7 -0
  163. package/dist/server/video-routes.js +91 -0
  164. package/dist/server/video-routes.js.map +1 -0
  165. package/dist/server/video.d.ts +214 -0
  166. package/dist/server/video.js +301 -0
  167. package/dist/server/video.js.map +1 -0
  168. package/dist/server/web-build.d.ts +16 -0
  169. package/dist/server/web-build.js +232 -0
  170. package/dist/server/web-build.js.map +1 -0
  171. package/dist/server/workflow.d.ts +221 -0
  172. package/dist/server/workflow.js +826 -0
  173. package/dist/server/workflow.js.map +1 -0
  174. package/dist/server/yandex-config.d.ts +33 -0
  175. package/dist/server/yandex-config.js +12 -0
  176. package/dist/server/yandex-config.js.map +1 -0
  177. package/dist/server/yandex-godot.d.ts +5 -0
  178. package/dist/server/yandex-godot.js +107 -0
  179. package/dist/server/yandex-godot.js.map +1 -0
  180. package/dist/shared/aspects.d.ts +48 -0
  181. package/dist/shared/aspects.js +22 -0
  182. package/dist/shared/aspects.js.map +1 -0
  183. package/dist/shared/assistant.d.ts +7 -0
  184. package/dist/shared/assistant.js +36 -0
  185. package/dist/shared/assistant.js.map +1 -0
  186. package/dist/shared/chat.d.ts +46 -0
  187. package/dist/shared/chat.js +2 -0
  188. package/dist/shared/chat.js.map +1 -0
  189. package/dist/shared/settings.d.ts +11 -0
  190. package/dist/shared/settings.js +25 -0
  191. package/dist/shared/settings.js.map +1 -0
  192. package/dist/shared/types.d.ts +510 -0
  193. package/dist/shared/types.js +2 -0
  194. package/dist/shared/types.js.map +1 -0
  195. package/dist/web/apple-touch-icon.png +0 -0
  196. package/dist/web/assets/AgentActivity-sYJeY5Yf.js +9 -0
  197. package/dist/web/assets/ArrowRight.es-9w41WqD8.js +1 -0
  198. package/dist/web/assets/ArrowUpRight.es-BmIrpjWN.js +1 -0
  199. package/dist/web/assets/AssetMediaPreview-D2cd6oQO.js +1 -0
  200. package/dist/web/assets/AssetSelectionWizard-a43_6NO7.js +1 -0
  201. package/dist/web/assets/CaretDown.es-Cq33NYip.js +1 -0
  202. package/dist/web/assets/CheckCircle.es-D5B3hdvz.js +1 -0
  203. package/dist/web/assets/CoreAccount-D4ZC8CWv.js +1 -0
  204. package/dist/web/assets/DownloadSimple.es-DwOWFbs2.js +1 -0
  205. package/dist/web/assets/FileText.es-D83IIiOG.js +1 -0
  206. package/dist/web/assets/ImageSquare.es-DxCFt99_.js +1 -0
  207. package/dist/web/assets/KidsApp-BXWaALoK.css +1 -0
  208. package/dist/web/assets/KidsApp-D-8t3HPy.js +2 -0
  209. package/dist/web/assets/MagnifyingGlass.es-rkdOU2rH.js +1 -0
  210. package/dist/web/assets/PaperPlaneRight.es-U0twumpP.js +1 -0
  211. package/dist/web/assets/PencilSimple.es-JVHwRvGx.js +1 -0
  212. package/dist/web/assets/PlainChat-BC4K_tmj.css +1 -0
  213. package/dist/web/assets/PlainChat-CMxYwKko.js +1 -0
  214. package/dist/web/assets/Sparkle.es-CmGpvnNm.js +1 -0
  215. package/dist/web/assets/Square.es-BjNN9Ypc.js +1 -0
  216. package/dist/web/assets/UploadSimple.es-DxIuxpCC.js +1 -0
  217. package/dist/web/assets/WarningCircle.es-D63H8cL9.js +1 -0
  218. package/dist/web/assets/WorkflowJournal-Did0sRta.js +1 -0
  219. package/dist/web/assets/YandexConfigFields-DDL22Bfw.js +1 -0
  220. package/dist/web/assets/YandexGamesView-R64RSJRL.js +2 -0
  221. package/dist/web/assets/bg-build-DIalyCDw.svg +3 -0
  222. package/dist/web/assets/bg-idea-DHcE-Dhs.svg +3 -0
  223. package/dist/web/assets/bg-materials-UDVFaueI.svg +3 -0
  224. package/dist/web/assets/bg-plan-DpfwIsqJ.svg +3 -0
  225. package/dist/web/assets/bg-play-CNc1QZFK.svg +3 -0
  226. package/dist/web/assets/dist-7vx7MTaJ.js +1 -0
  227. package/dist/web/assets/index-Izzbh11U.css +1 -0
  228. package/dist/web/assets/index-sNciOZYG.js +13 -0
  229. package/dist/web/assets/jsx-runtime-CdVFa8IP.js +1 -0
  230. package/dist/web/assets/manrope-cyrillic-wght-normal-Dvxsihut.woff2 +0 -0
  231. package/dist/web/assets/manrope-greek-wght-normal-DL7QRZyv.woff2 +0 -0
  232. package/dist/web/assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2 +0 -0
  233. package/dist/web/assets/manrope-latin-wght-normal-DHIcAJRg.woff2 +0 -0
  234. package/dist/web/assets/manrope-vietnamese-wght-normal-usUDDRr7.woff2 +0 -0
  235. package/dist/web/assets/resources-DppXCagL.js +1 -0
  236. package/dist/web/assets/robot-happy-B6YvlU94.svg +24 -0
  237. package/dist/web/assets/robot-hello-CCsQgsS-.svg +24 -0
  238. package/dist/web/assets/robot-listen-Buuz9xII.svg +24 -0
  239. package/dist/web/assets/robot-sad-CRtiNVWs.svg +24 -0
  240. package/dist/web/assets/robot-think-CJ5fDBTm.svg +24 -0
  241. package/dist/web/assets/star-big-CSFDKjws.svg +22 -0
  242. package/dist/web/assets/star-empty-CC-5vioJ.svg +3 -0
  243. package/dist/web/assets/star-next-ztuDjOHU.svg +9 -0
  244. package/dist/web/assets/star-on-l_krO3aV.svg +10 -0
  245. package/dist/web/assets/ui-wHE_yBK0.js +41 -0
  246. package/dist/web/assets/umgt-logo-DAOkTN9u.png +0 -0
  247. package/dist/web/assets/unbounded-cyrillic-wght-normal-C627f1f8.woff2 +0 -0
  248. package/dist/web/assets/unbounded-latin-ext-wght-normal-D6H-S6MW.woff2 +0 -0
  249. package/dist/web/assets/unbounded-latin-wght-normal-D5afBTBx.woff2 +0 -0
  250. package/dist/web/assets/unbounded-vietnamese-wght-normal-rat7GD3o.woff2 +0 -0
  251. package/dist/web/assets/workflow-BhcU9uvG.css +1 -0
  252. package/dist/web/assets/workflow-BrIKN5ER.js +34 -0
  253. package/dist/web/favicon.ico +0 -0
  254. package/dist/web/icons/favicon-16.png +0 -0
  255. package/dist/web/icons/favicon-32.png +0 -0
  256. package/dist/web/icons/icon-192.png +0 -0
  257. package/dist/web/icons/icon-512.png +0 -0
  258. package/dist/web/icons/maskable-192.png +0 -0
  259. package/dist/web/icons/maskable-512.png +0 -0
  260. package/dist/web/index.html +28 -0
  261. package/dist/web/manifest.webmanifest +19 -0
  262. package/dist/web/sw.js +25 -0
  263. package/docs/agent-activity-ui.md +33 -0
  264. package/docs/agent-activity.md +43 -0
  265. package/docs/agent-permissions-ui.md +15 -0
  266. package/docs/api.md +145 -0
  267. package/docs/approval-journal.md +13 -0
  268. package/docs/asset-media.md +27 -0
  269. package/docs/asset-providers.md +34 -0
  270. package/docs/asset-selection.md +31 -0
  271. package/docs/automatic-approvals.md +15 -0
  272. package/docs/background-game-launch.md +17 -0
  273. package/docs/billing-validation.md +23 -0
  274. package/docs/core-isolation.md +37 -0
  275. package/docs/core.md +45 -0
  276. package/docs/generated-text-ui.md +41 -0
  277. package/docs/interactive-interview-ui.md +29 -0
  278. package/docs/interactive-interview.md +52 -0
  279. package/docs/local-codex.md +51 -0
  280. package/docs/local-meshy.md +13 -0
  281. package/docs/markdown.md +11 -0
  282. package/docs/permission-ui.md +11 -0
  283. package/docs/plan.md +47 -0
  284. package/docs/remote-core-deployment.md +47 -0
  285. package/docs/roblox.md +90 -0
  286. package/docs/validation.md +228 -0
  287. package/docs/video-reference.md +35 -0
  288. package/docs/workflow-journal-ui.md +21 -0
  289. package/docs/yandex-foundation.md +27 -0
  290. package/docs/yandex-games.md +45 -0
  291. package/package.json +95 -4
  292. package/scripts/create-roblox-demo.mjs +31 -0
  293. package/scripts/diagnose-roblox-mcp.mjs +45 -0
  294. package/scripts/open-hub-chrome.mjs +60 -0
  295. package/scripts/smoke-agent.mjs +91 -0
@@ -0,0 +1,137 @@
1
+ export class EventBus {
2
+ store;
3
+ listeners = new Set();
4
+ constructor(store) {
5
+ this.store = store;
6
+ }
7
+ publish(type, payload, projectId) {
8
+ const event = this.store.appendEvent(type, payload, projectId);
9
+ for (const listener of this.listeners)
10
+ listener(event);
11
+ return event;
12
+ }
13
+ history(afterId = 0, projectId) { return this.store.eventsAfter(afterId, projectId); }
14
+ subscribe(listener) {
15
+ this.listeners.add(listener);
16
+ return () => this.listeners.delete(listener);
17
+ }
18
+ }
19
+ export function registerEvents(app, events) {
20
+ app.get('/api/v1/events', (request, reply) => {
21
+ const lastId = Number(request.headers['last-event-id'] ?? request.query.after ?? 0);
22
+ if (!Number.isSafeInteger(lastId) || lastId < 0)
23
+ return reply.code(400).send({ error: 'invalid_cursor', message: 'Invalid event cursor' });
24
+ reply.hijack();
25
+ reply.raw.writeHead(200, {
26
+ 'Content-Type': 'text/event-stream; charset=utf-8', 'Cache-Control': 'no-cache, no-transform',
27
+ Connection: 'keep-alive', 'X-Accel-Buffering': 'no', 'X-Content-Type-Options': 'nosniff',
28
+ });
29
+ let closed = false;
30
+ let unsubscribe;
31
+ let heartbeat;
32
+ let cancelDrain;
33
+ let cursor = lastId;
34
+ let pumping = false;
35
+ let requested = false;
36
+ let heartbeatRequested = false;
37
+ let connected = false;
38
+ const cleanup = () => {
39
+ closed = true;
40
+ if (heartbeat)
41
+ clearInterval(heartbeat);
42
+ unsubscribe?.();
43
+ cancelDrain?.();
44
+ reply.raw.off('close', cleanup);
45
+ reply.raw.off('finish', cleanup);
46
+ reply.raw.off('error', cleanup);
47
+ };
48
+ const isOpen = () => !closed && !reply.raw.destroyed && !reply.raw.writableEnded;
49
+ const waitForDrain = () => new Promise(resolve => {
50
+ const done = (ready) => {
51
+ reply.raw.off('drain', drained);
52
+ cancelDrain = undefined;
53
+ resolve(ready);
54
+ };
55
+ const drained = () => done(isOpen());
56
+ cancelDrain = () => done(false);
57
+ reply.raw.once('drain', drained);
58
+ if (!isOpen())
59
+ done(false);
60
+ });
61
+ const write = async (chunk) => {
62
+ if (!isOpen())
63
+ return false;
64
+ // A false result still accepts the complete frame into Node's buffer.
65
+ // Stop writing until drain; a disconnected client resumes from its own ID.
66
+ return reply.raw.write(chunk) ? isOpen() : waitForDrain();
67
+ };
68
+ const replay = async () => {
69
+ if (!connected) {
70
+ connected = true;
71
+ if (!await write(': connected\n\n'))
72
+ return;
73
+ }
74
+ do {
75
+ requested = false;
76
+ if (heartbeatRequested) {
77
+ heartbeatRequested = false;
78
+ if (!await write(': heartbeat\n\n'))
79
+ return;
80
+ }
81
+ while (isOpen()) {
82
+ const page = events.history(cursor, request.query.projectId);
83
+ if (!page.length)
84
+ break;
85
+ for (const event of page) {
86
+ if (!isOpen())
87
+ return;
88
+ if (!await write(`id: ${event.id}\nevent: hub\ndata: ${JSON.stringify(event)}\n\n`))
89
+ return;
90
+ cursor = event.id;
91
+ }
92
+ // Yield even when a fast client never reaches its high-water mark.
93
+ await new Promise(resolve => setImmediate(resolve));
94
+ }
95
+ } while (requested && isOpen());
96
+ };
97
+ const wake = (withHeartbeat = false) => {
98
+ if (!isOpen()) {
99
+ cleanup();
100
+ return;
101
+ }
102
+ requested = true;
103
+ heartbeatRequested ||= withHeartbeat;
104
+ if (pumping)
105
+ return;
106
+ pumping = true;
107
+ void replay().catch(() => {
108
+ cleanup();
109
+ reply.raw.destroy();
110
+ }).finally(() => {
111
+ pumping = false;
112
+ if (!isOpen())
113
+ cleanup();
114
+ else if (requested)
115
+ wake();
116
+ });
117
+ };
118
+ reply.raw.once('close', cleanup);
119
+ reply.raw.once('finish', cleanup);
120
+ reply.raw.once('error', cleanup);
121
+ if (!isOpen()) {
122
+ cleanup();
123
+ return undefined;
124
+ }
125
+ // Subscribe before awaiting replay. Notifications only wake the durable
126
+ // cursor pump, so events arriving during drain need no in-memory queue.
127
+ unsubscribe = events.subscribe(event => {
128
+ if (!request.query.projectId || request.query.projectId === event.projectId)
129
+ wake();
130
+ });
131
+ heartbeat = setInterval(() => wake(true), 15_000);
132
+ heartbeat.unref();
133
+ wake();
134
+ return undefined;
135
+ });
136
+ }
137
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/server/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { runProcess, type ProcessOptions, type ProcessResult } from './process.js';
2
+ export interface ProcessIdentity {
3
+ pid: number;
4
+ command: string;
5
+ }
6
+ export interface BackgroundRuntime {
7
+ platform: NodeJS.Platform;
8
+ processes: () => Promise<ProcessIdentity[]>;
9
+ launch: typeof runProcess;
10
+ signal: (pid: number, signal: NodeJS.Signals) => void;
11
+ }
12
+ export declare function backgroundLaunchArgs(binary: string, projectPath: string, logPath: string): string[];
13
+ export declare function isOwnedGameProcess(item: ProcessIdentity, binary: string, logPath: string): boolean;
14
+ /** LaunchServices owns the native process; its exact nonce-tagged PID is stopped separately from open -W. */
15
+ export declare function runBackgroundGame(binary: string, projectPath: string, options?: ProcessOptions, system?: BackgroundRuntime): Promise<ProcessResult>;
16
+ export declare const developmentLaunchInstructions = "Run automated engine imports, checks and behavior tests with --headless. Visible development playtests must not activate or steal focus: on macOS launch an app bundle with /usr/bin/open -g -n -W APP.app --args ..., including --path PROJECT for Godot.app. Use the same open -g approach for native exported .app smoke tests; keep --headless for automated exported-binary checks. Never assume a --no-focus flag exists (Godot 4.7.2 does not support it), never set a permanently unfocusable game window, and never activate/raise the app or send global keyboard input for a background test. Keep the game visible and keyboard-interactive when the user selects it. On other desktops respect the window manager; do not claim guaranteed background activation without a supported mechanism. Preserve an explicitly requested editor opening.";
@@ -0,0 +1,143 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { StringDecoder } from 'node:string_decoder';
4
+ import { mkdtemp, open, realpath, rm } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { runProcess } from './process.js';
8
+ const execFileAsync = promisify(execFile);
9
+ const runtime = { platform: process.platform, launch: runProcess, signal: (pid, signal) => process.kill(pid, signal), processes: async () => {
10
+ const { stdout } = await execFileAsync('/bin/ps', ['-axo', 'pid=,args='], { maxBuffer: 8 * 1024 * 1024 });
11
+ return stdout.split('\n').flatMap(line => { const match = line.match(/^\s*(\d+)\s+(.+)$/); return match ? [{ pid: Number(match[1]), command: match[2] }] : []; });
12
+ } };
13
+ export function backgroundLaunchArgs(binary, projectPath, logPath) {
14
+ const bundle = binary.match(/^(.*\.app)\/Contents\/MacOS\/[^/]+$/)?.[1];
15
+ if (!bundle)
16
+ throw new Error('Фоновый запуск macOS требует Godot.app. Укажите исполняемый файл внутри установленного приложения Godot.');
17
+ return ['-g', '-n', '-W', '--stdout', logPath + '.stdout', '--stderr', logPath + '.stderr', bundle, '--args', '--path', projectPath, '--log-file', logPath];
18
+ }
19
+ export function isOwnedGameProcess(item, binary, logPath) {
20
+ return Number.isSafeInteger(item.pid) && item.pid > 1 && item.pid !== process.pid && item.command.startsWith(binary + ' ')
21
+ && item.command.includes(`--log-file ${logPath}`) && (item.command.endsWith(logPath) || item.command.includes(`${logPath} `));
22
+ }
23
+ /** LaunchServices owns the native process; its exact nonce-tagged PID is stopped separately from open -W. */
24
+ export async function runBackgroundGame(binary, projectPath, options = {}, system = runtime) {
25
+ options.signal?.throwIfAborted();
26
+ if (system.platform !== 'darwin')
27
+ return system.launch(binary, ['--path', projectPath], options);
28
+ const executable = await realpath(binary);
29
+ // Validate the bundle before creating private transient files or launching.
30
+ backgroundLaunchArgs(executable, projectPath, 'unused');
31
+ const directory = await mkdtemp(join(tmpdir(), 'lmgh-game-')), logPath = join(directory, 'godot.log');
32
+ const controller = new AbortController();
33
+ let output = '', owned, finished, launchError;
34
+ let stopAt = 0, terminated = false, killed = false, timedOut = false;
35
+ const start = Date.now();
36
+ const logs = ['.stdout', '.stderr'].map(suffix => ({ path: logPath + suffix, offset: 0, decoder: new StringDecoder('utf8') }));
37
+ const append = (text) => { output = (output + text).slice(-2_000_000); options.emit?.(text); };
38
+ const readLog = async (limit = 256 * 1024) => {
39
+ for (const log of logs) {
40
+ const file = await open(log.path, 'r').catch(error => { if (error.code === 'ENOENT')
41
+ return undefined; throw error; });
42
+ if (!file)
43
+ continue;
44
+ try {
45
+ const size = (await file.stat()).size;
46
+ if (size < log.offset)
47
+ log.offset = 0;
48
+ if (size - log.offset > 2_000_000) {
49
+ log.offset = size - 2_000_000;
50
+ log.decoder.end();
51
+ }
52
+ let remaining = Math.min(size - log.offset, limit);
53
+ while (remaining > 0) {
54
+ const buffer = Buffer.alloc(Math.min(remaining, 32 * 1024));
55
+ const { bytesRead } = await file.read(buffer, 0, buffer.length, log.offset);
56
+ if (!bytesRead)
57
+ break;
58
+ log.offset += bytesRead;
59
+ remaining -= bytesRead;
60
+ append(log.decoder.write(buffer.subarray(0, bytesRead)));
61
+ }
62
+ }
63
+ finally {
64
+ await file.close();
65
+ }
66
+ }
67
+ };
68
+ const stopOwned = async (signal) => {
69
+ if (!owned)
70
+ return;
71
+ const matches = (await system.processes()).filter(item => item.pid === owned && isOwnedGameProcess(item, executable, logPath));
72
+ if (matches.length === 1) {
73
+ try {
74
+ system.signal(owned, signal);
75
+ }
76
+ catch (error) {
77
+ if (error.code !== 'ESRCH')
78
+ throw error;
79
+ }
80
+ }
81
+ };
82
+ let launch;
83
+ try {
84
+ const prior = new Set((await system.processes()).map(item => item.pid));
85
+ options.signal?.throwIfAborted();
86
+ launch = system.launch('/usr/bin/open', backgroundLaunchArgs(executable, projectPath, logPath), { cwd: options.cwd, signal: controller.signal, emit: append }).then(value => { finished = value; }, error => { launchError = error; });
87
+ while (true) {
88
+ const list = await system.processes();
89
+ if (owned === undefined) {
90
+ const candidates = list.filter(item => !prior.has(item.pid) && isOwnedGameProcess(item, executable, logPath));
91
+ if (candidates.length > 1)
92
+ throw new Error('Не удалось однозначно определить процесс запущенной игры.');
93
+ owned = candidates[0]?.pid;
94
+ }
95
+ const alive = owned !== undefined && list.some(item => item.pid === owned && isOwnedGameProcess(item, executable, logPath));
96
+ await readLog();
97
+ timedOut = !!options.timeout && Date.now() - start >= options.timeout;
98
+ if (options.signal?.aborted || timedOut) {
99
+ stopAt ||= Date.now();
100
+ if (alive && !terminated) {
101
+ await stopOwned('SIGTERM');
102
+ terminated = true;
103
+ }
104
+ if (alive && !killed && Date.now() - stopAt >= 1500) {
105
+ await stopOwned('SIGKILL');
106
+ killed = true;
107
+ }
108
+ // Do not kill the launcher before discovering its separately-owned game.
109
+ if ((owned !== undefined && !alive) || Date.now() - stopAt >= 10_000)
110
+ controller.abort();
111
+ }
112
+ if (launchError)
113
+ throw launchError;
114
+ if (finished && !alive)
115
+ break;
116
+ await new Promise(resolve => setTimeout(resolve, 100));
117
+ }
118
+ await launch;
119
+ await readLog(2_000_000);
120
+ for (const log of logs)
121
+ append(log.decoder.end());
122
+ return { code: timedOut ? 124 : finished?.code ?? 1, output: output + (timedOut ? '\nProcess timed out.' : ''), cancelled: options.signal?.aborted ?? false };
123
+ }
124
+ finally {
125
+ // All signals are revalidated against executable and private nonce, never a process name alone.
126
+ await stopOwned('SIGTERM');
127
+ controller.abort();
128
+ await launch;
129
+ if (owned) {
130
+ for (let attempt = 0; attempt < 20; attempt++) {
131
+ const alive = (await system.processes()).some(item => item.pid === owned && isOwnedGameProcess(item, executable, logPath));
132
+ if (!alive)
133
+ break;
134
+ if (attempt === 10)
135
+ await stopOwned('SIGKILL');
136
+ await new Promise(resolve => setTimeout(resolve, 100));
137
+ }
138
+ }
139
+ await rm(directory, { recursive: true, force: true });
140
+ }
141
+ }
142
+ export const developmentLaunchInstructions = 'Run automated engine imports, checks and behavior tests with --headless. Visible development playtests must not activate or steal focus: on macOS launch an app bundle with /usr/bin/open -g -n -W APP.app --args ..., including --path PROJECT for Godot.app. Use the same open -g approach for native exported .app smoke tests; keep --headless for automated exported-binary checks. Never assume a --no-focus flag exists (Godot 4.7.2 does not support it), never set a permanently unfocusable game window, and never activate/raise the app or send global keyboard input for a background test. Keep the game visible and keyboard-interactive when the user selects it. On other desktops respect the window manager; do not claim guaranteed background activation without a supported mechanism. Preserve an explicitly requested editor opening.';
143
+ //# sourceMappingURL=game-launch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-launch.js","sourceRoot":"","sources":["../../src/server/game-launch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Diagnostic, Project } from '../shared/types.js';
2
+ import { type ProcessOptions } from './process.js';
3
+ export declare function detectHtml5(signal?: AbortSignal): Promise<Diagnostic>;
4
+ export declare function scaffoldHtml5(project: Project): Promise<void>;
5
+ export declare function buildHtml5(project: Project, options?: ProcessOptions): Promise<{
6
+ ok: boolean;
7
+ output: string;
8
+ directory: string;
9
+ }>;
@@ -0,0 +1,107 @@
1
+ import { mkdir, writeFile, access } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { runProcess } from './process.js';
4
+ import { isYandexProject, yandexConfig } from './yandex-config.js';
5
+ import { yandexSdkSource, yandexSdkTypes } from './templates/yandex-sdk.js';
6
+ export async function detectHtml5(signal) {
7
+ try {
8
+ const result = await runProcess(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['--version'], { signal, timeout: 6000 });
9
+ return { id: 'html5', name: 'HTML5 · TypeScript/Vite', available: result.code === 0, version: result.output.trim(), executable: process.execPath, message: result.code === 0 ? 'Node.js и npm готовы. Зависимости каждого проекта устанавливаются отдельно.' : 'Установите Node.js 24.13+ с npm.' };
10
+ }
11
+ catch {
12
+ signal?.throwIfAborted();
13
+ return { id: 'html5', name: 'HTML5 · TypeScript/Vite', available: false, message: 'Установите Node.js 24.13+ с npm.' };
14
+ }
15
+ }
16
+ export async function scaffoldHtml5(project) {
17
+ await mkdir(join(project.path, 'src/platform'), { recursive: true });
18
+ await mkdir(join(project.path, 'public/assets'), { recursive: true });
19
+ await mkdir(join(project.path, '.lm-game-hub'), { recursive: true });
20
+ const files = {
21
+ 'package.json': JSON.stringify({ name: `game-${project.id}`, version: '0.1.0', private: true, type: 'module', scripts: { dev: 'vite --host 127.0.0.1', typecheck: 'tsc --noEmit', build: 'tsc --noEmit && vite build' }, dependencies: project.dimension === '2d' ? { phaser: '3.90.0' } : { three: '0.186.1' }, devDependencies: { vite: '8.3.3', typescript: '7.0.2', ...(project.dimension === '3d' ? { '@types/three': '0.186.0' } : {}) } }, null, 2),
22
+ 'tsconfig.json': JSON.stringify({ compilerOptions: { target: 'ES2022', lib: ['ES2022', 'DOM'], module: 'ESNext', moduleResolution: 'Bundler', strict: true, skipLibCheck: true, noEmit: true, allowJs: true, checkJs: false, resolveJsonModule: true }, include: ['src'] }, null, 2),
23
+ 'vite.config.ts': `import { defineConfig } from 'vite';\nexport default defineConfig({base:'./',publicDir:'public',build:{outDir:'dist',emptyOutDir:true},server:{host:'127.0.0.1',proxy:{'/sdk.js':{target:'https://yastatic.net',changeOrigin:true,rewrite:()=>'/s3/games-static/sdk-dev/yandex-dev-adapter.js'}}}});\n`,
24
+ 'index.html': `<!doctype html><html lang="ru"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>${escapeHtml(project.name)}</title>${isYandexProject(project) ? '<script src="/sdk.js"></script>' : ''}</head><body><div id="game"></div><div id="status" role="status">Загрузка…</div><script type="module" src="/src/main.ts"></script></body></html>`,
25
+ 'src/platform/yandex.js': yandexSdkSource, 'src/platform/yandex.d.ts': yandexSdkTypes,
26
+ 'src/platform/config.json': JSON.stringify(isYandexProject(project) ? yandexConfig(project) : null, null, 2),
27
+ 'src/vite-env.d.ts': '/// <reference types="vite/client" />\n',
28
+ 'src/style.css': `*{box-sizing:border-box}html,body,#game{margin:0;width:100%;height:100%;overflow:hidden;background:#111827;touch-action:none}canvas{display:block}#status{position:fixed;bottom:16px;left:16px;color:#f3f4f6;font:15px system-ui;pointer-events:none;text-shadow:0 1px 5px #000}`,
29
+ 'src/main.ts': project.dimension === '2d' ? phaserTemplate : threeTemplate,
30
+ '.gitignore': 'node_modules/\ndist/\nbuilds/\n.lm-game-hub/tmp/\n',
31
+ 'README.md': `# ${project.name}\n\nNode.js 24.13+. Run npm install, npm run dev, npm run build. Hub installs dependencies with lifecycle scripts disabled.\n\n${isYandexProject(project) ? 'The local /sdk.js proxy uses the official Yandex development adapter. A local preview does not prove console integration or moderation acceptance. Production uses the platform-provided /sdk.js; SDK source must not be bundled.' : 'This project runs locally without Yandex services.'}\n\nAssets in public/assets are copied into the build. Keep names ASCII without spaces. Pause and mute on platform ads/focus loss. Invoke authorization, purchases and advertisements only in deliberate game UI. See installed project skills for integration details.\n`
32
+ };
33
+ for (const [path, content] of Object.entries(files))
34
+ await writeFile(join(project.path, path), content, { flag: 'wx' });
35
+ }
36
+ function escapeHtml(value) { return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;'); }
37
+ const phaserTemplate = `import Phaser from 'phaser';
38
+ import { createGamePlatform, type GamePlatform } from './platform/yandex.js';
39
+ import config from './platform/config.json';
40
+ import './style.css';
41
+ let platform:GamePlatform;
42
+ let game:Phaser.Game;
43
+ let userMuted=false;let forcedMuted=false;
44
+ const status = document.querySelector<HTMLDivElement>('#status')!;
45
+ class Play extends Phaser.Scene {
46
+ private player!:Phaser.GameObjects.Arc; private target!:Phaser.GameObjects.Arc; private cursors!:Phaser.Types.Input.Keyboard.CursorKeys; private score=0;
47
+ create(){
48
+ this.player=this.add.circle(160,220,24,0x86efac); this.target=this.add.circle(420,220,18,0xfbbf24);
49
+ this.cursors=this.input.keyboard!.createCursorKeys();
50
+ this.input.on('pointerdown',(pointer:Phaser.Input.Pointer)=>{this.player.setPosition(pointer.x,pointer.y);});
51
+ platform.ready();platform.start(); status.textContent='Стрелки или касание · Соберите золотой круг';
52
+ }
53
+ update(_time:number,delta:number){
54
+ const distance=280*Math.min(delta,50)/1000;
55
+ this.player.x+=((this.cursors.right.isDown?1:0)-(this.cursors.left.isDown?1:0))*distance;
56
+ this.player.y+=((this.cursors.down.isDown?1:0)-(this.cursors.up.isDown?1:0))*distance;
57
+ this.player.x=Phaser.Math.Clamp(this.player.x,24,this.scale.width-24);this.player.y=Phaser.Math.Clamp(this.player.y,24,this.scale.height-24);
58
+ if(Phaser.Math.Distance.Between(this.player.x,this.player.y,this.target.x,this.target.y)<42){this.score++;this.target.setPosition(Phaser.Math.Between(40,Math.max(40,this.scale.width-40)),Phaser.Math.Between(40,Math.max(40,this.scale.height-40)));status.textContent='Собрано: '+this.score;}
59
+ }
60
+ }
61
+ async function boot(){
62
+ platform=await createGamePlatform(config,{pause:paused=>{if(!game)return;if(paused)game.scene.pause('Play');else game.scene.resume('Play');},mute:muted=>{forcedMuted=muted;if(game?.sound)game.sound.mute=userMuted||forcedMuted;},warning:message=>{status.textContent=message;}});
63
+ game=new Phaser.Game({type:Phaser.AUTO,parent:'game',backgroundColor:'#111827',scale:{mode:Phaser.Scale.RESIZE,width:window.innerWidth,height:window.innerHeight},scene:[class extends Play{constructor(){super({key:'Play'});}}]});
64
+ }
65
+ void boot().catch(error=>{status.textContent=String(error);console.error(error);});
66
+ `;
67
+ const threeTemplate = `import * as THREE from 'three';
68
+ import { createGamePlatform } from './platform/yandex.js';
69
+ import config from './platform/config.json';
70
+ import './style.css';
71
+ const status=document.querySelector<HTMLDivElement>('#status')!;
72
+ async function boot(){
73
+ let paused=true;
74
+ const platform=await createGamePlatform(config,{pause:value=>{paused=value;},mute:()=>{/* Combine forced mute with user preference when adding actual audio. */},warning:message=>{status.textContent=message;}});
75
+ const scene=new THREE.Scene(); scene.background=new THREE.Color('#111827');
76
+ const camera=new THREE.PerspectiveCamera(55,innerWidth/innerHeight,0.1,100);camera.position.set(0,2,5);camera.lookAt(0,0,0);
77
+ const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);document.querySelector('#game')!.append(renderer.domElement);
78
+ scene.add(new THREE.HemisphereLight(0xffffff,0x334155,3));const light=new THREE.DirectionalLight(0xffffff,3);light.position.set(4,5,3);scene.add(light);
79
+ const cube=new THREE.Mesh(new THREE.BoxGeometry(),new THREE.MeshStandardMaterial({color:0x86efac,roughness:0.35}));scene.add(cube);
80
+ const ground=new THREE.Mesh(new THREE.PlaneGeometry(12,12),new THREE.MeshStandardMaterial({color:0x263244}));ground.rotation.x=-Math.PI/2;ground.position.y=-1;scene.add(ground);
81
+ let score=0;const raycaster=new THREE.Raycaster();const pointer=new THREE.Vector2();
82
+ renderer.domElement.addEventListener('pointerdown',event=>{if(paused)return;const rect=renderer.domElement.getBoundingClientRect();pointer.set((event.clientX-rect.left)/rect.width*2-1,-(event.clientY-rect.top)/rect.height*2+1);raycaster.setFromCamera(pointer,camera);if(raycaster.intersectObject(cube).length){score++;cube.material.color.setHSL((score*0.17)%1,0.6,0.6);status.textContent='Попаданий: '+score;}});
83
+ addEventListener('resize',()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight);});
84
+ let previous=0;renderer.setAnimationLoop(time=>{const delta=Math.min((time-previous)/1000,0.05);previous=time;if(!paused){cube.rotation.y+=delta;cube.rotation.x+=delta*0.4;}renderer.render(scene,camera);});
85
+ renderer.render(scene,camera);platform.ready();platform.start();status.textContent='Нажмите на вращающийся куб';
86
+ addEventListener('pagehide',()=>{platform.dispose();renderer.setAnimationLoop(null);renderer.dispose();cube.geometry.dispose();cube.material.dispose();ground.geometry.dispose();ground.material.dispose();},{once:true});
87
+ }
88
+ void boot().catch(error=>{status.textContent=String(error);console.error(error);});
89
+ `;
90
+ export async function buildHtml5(project, options = {}) {
91
+ const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
92
+ let output = '';
93
+ try {
94
+ await access(join(project.path, 'node_modules/.bin/vite'));
95
+ }
96
+ catch {
97
+ options.emit?.('Установка зависимостей HTML5 (npm install --ignore-scripts)…\n');
98
+ const install = await runProcess(npm, ['install', '--ignore-scripts', '--no-audit', '--no-fund'], { ...options, cwd: project.path, timeout: 300000 });
99
+ output += install.output;
100
+ if (install.code !== 0 || install.cancelled)
101
+ return { ok: false, output, directory: join(project.path, 'dist') };
102
+ }
103
+ const built = await runProcess(npm, ['run', 'build'], { ...options, cwd: project.path, timeout: 300000 });
104
+ output += built.output;
105
+ return { ok: built.code === 0 && !built.cancelled, output, directory: join(project.path, 'dist') };
106
+ }
107
+ //# sourceMappingURL=html5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html5.js","sourceRoot":"","sources":["../../src/server/html5.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAuB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE5E,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAmB;IACnD,IAAI,CAAC;QAAC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAC,CAAC,WAAW,CAAC,EAAC,EAAC,MAAM,EAAC,OAAO,EAAC,IAAI,EAAC,CAAC,CAAC;QAC1H,OAAO,EAAC,EAAE,EAAC,OAAO,EAAC,IAAI,EAAC,yBAAyB,EAAC,SAAS,EAAC,MAAM,CAAC,IAAI,KAAG,CAAC,EAAC,OAAO,EAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAC,UAAU,EAAC,OAAO,CAAC,QAAQ,EAAC,OAAO,EAAC,MAAM,CAAC,IAAI,KAAG,CAAC,CAAA,CAAC,CAAA,6EAA6E,CAAA,CAAC,CAAA,kCAAkC,EAAC,CAAC;IACjR,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,EAAE,CAAC;QAAC,OAAO,EAAC,EAAE,EAAC,OAAO,EAAC,IAAI,EAAC,yBAAyB,EAAC,SAAS,EAAC,KAAK,EAAC,OAAO,EAAC,kCAAkC,EAAC,CAAC;IAAC,CAAC;AACtJ,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe;IACjD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,cAAc,CAAC,EAAC,EAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC;IAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,eAAe,CAAC,EAAC,EAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC;IAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,cAAc,CAAC,EAAC,EAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC;IACnM,MAAM,KAAK,GAAyB;QAClC,cAAc,EAAC,IAAI,CAAC,SAAS,CAAC,EAAC,IAAI,EAAC,QAAQ,OAAO,CAAC,EAAE,EAAE,EAAC,OAAO,EAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,EAAC,GAAG,EAAC,uBAAuB,EAAC,SAAS,EAAC,cAAc,EAAC,KAAK,EAAC,4BAA4B,EAAC,EAAC,YAAY,EAAC,OAAO,CAAC,SAAS,KAAG,IAAI,CAAA,CAAC,CAAA,EAAC,MAAM,EAAC,QAAQ,EAAC,CAAA,CAAC,CAAA,EAAC,KAAK,EAAC,SAAS,EAAC,EAAC,eAAe,EAAC,EAAC,IAAI,EAAC,OAAO,EAAC,UAAU,EAAC,OAAO,EAAC,GAAG,CAAC,OAAO,CAAC,SAAS,KAAG,IAAI,CAAA,CAAC,CAAA,EAAC,cAAc,EAAC,SAAS,EAAC,CAAA,CAAC,CAAA,EAAE,CAAC,EAAC,EAAC,EAAC,IAAI,EAAC,CAAC,CAAC;QACtY,eAAe,EAAC,IAAI,CAAC,SAAS,CAAC,EAAC,eAAe,EAAC,EAAC,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,CAAC,QAAQ,EAAC,KAAK,CAAC,EAAC,MAAM,EAAC,QAAQ,EAAC,gBAAgB,EAAC,SAAS,EAAC,MAAM,EAAC,IAAI,EAAC,YAAY,EAAC,IAAI,EAAC,MAAM,EAAC,IAAI,EAAC,OAAO,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,iBAAiB,EAAC,IAAI,EAAC,EAAC,OAAO,EAAC,CAAC,KAAK,CAAC,EAAC,EAAC,IAAI,EAAC,CAAC,CAAC;QACtP,gBAAgB,EAAC,wSAAwS;QACzT,YAAY,EAAC,2JAA2J,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,eAAe,CAAC,OAAO,CAAC,CAAA,CAAC,CAAA,iCAAiC,CAAA,CAAC,CAAA,EAAE,kJAAkJ;QAC1Z,wBAAwB,EAAC,eAAe,EAAC,0BAA0B,EAAC,cAAc;QAClF,0BAA0B,EAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA,CAAC,CAAA,YAAY,CAAC,OAAO,CAAC,CAAA,CAAC,CAAA,IAAI,EAAC,IAAI,EAAC,CAAC,CAAC;QACrG,mBAAmB,EAAC,yCAAyC;QAC7D,eAAe,EAAC,kRAAkR;QAClS,aAAa,EAAC,OAAO,CAAC,SAAS,KAAG,IAAI,CAAA,CAAC,CAAA,cAAc,CAAA,CAAC,CAAA,aAAa;QACnE,YAAY,EAAC,oDAAoD;QACjE,WAAW,EAAC,KAAK,OAAO,CAAC,IAAI,kIAAkI,eAAe,CAAC,OAAO,CAAC,CAAA,CAAC,CAAA,mOAAmO,CAAA,CAAC,CAAA,oDAAoD,2QAA2Q;KAC5tB,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,IAAI,CAAC,EAAC,OAAO,EAAC,EAAC,IAAI,EAAC,IAAI,EAAC,CAAC,CAAC;AACnH,CAAC;AACD,SAAS,UAAU,CAAC,KAAY,IAAU,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAC,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,EAAC,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAC,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAC,QAAQ,CAAC,CAAC,CAAA,CAAC;AACvJ,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BtB,CAAC;AACF,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBrB,CAAC;AACF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAe,EAAC,OAAO,GAAgB,EAAE;IACxE,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAG,OAAO,CAAA,CAAC,CAAA,SAAS,CAAA,CAAC,CAAA,KAAK,CAAC;IAAC,IAAI,MAAM,GAAC,EAAE,CAAC;IACtE,IAAI,CAAC;QAAA,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,wBAAwB,CAAC,CAAC,CAAC;IAAA,CAAC;IAAC,MAAM,CAAC;QACtE,OAAO,CAAC,IAAI,EAAE,CAAC,gEAAgE,CAAC,CAAC;QACjF,MAAM,OAAO,GAAC,MAAM,UAAU,CAAC,GAAG,EAAC,CAAC,SAAS,EAAC,kBAAkB,EAAC,YAAY,EAAC,WAAW,CAAC,EAAC,EAAC,GAAG,OAAO,EAAC,GAAG,EAAC,OAAO,CAAC,IAAI,EAAC,OAAO,EAAC,MAAM,EAAC,CAAC,CAAC;QAAA,MAAM,IAAE,OAAO,CAAC,MAAM,CAAC;QAChK,IAAG,OAAO,CAAC,IAAI,KAAG,CAAC,IAAE,OAAO,CAAC,SAAS;YAAC,OAAO,EAAC,EAAE,EAAC,KAAK,EAAC,MAAM,EAAC,SAAS,EAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,MAAM,CAAC,EAAC,CAAC;IACtG,CAAC;IACD,MAAM,KAAK,GAAC,MAAM,UAAU,CAAC,GAAG,EAAC,CAAC,KAAK,EAAC,OAAO,CAAC,EAAC,EAAC,GAAG,OAAO,EAAC,GAAG,EAAC,OAAO,CAAC,IAAI,EAAC,OAAO,EAAC,MAAM,EAAC,CAAC,CAAC;IAAA,MAAM,IAAE,KAAK,CAAC,MAAM,CAAC;IACpH,OAAO,EAAC,EAAE,EAAC,KAAK,CAAC,IAAI,KAAG,CAAC,IAAE,CAAC,KAAK,CAAC,SAAS,EAAC,MAAM,EAAC,SAAS,EAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAC,MAAM,CAAC,EAAC,CAAC;AAC1F,CAAC"}