@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.1

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 (391) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +36 -2
  3. package/dist/bundling/logic-exports.d.ts +34 -0
  4. package/dist/bundling/node-builtins.d.ts +21 -0
  5. package/dist/bundling/transpiler.d.ts +7 -0
  6. package/dist/cli.js +27368 -0
  7. package/dist/client/dev-server.d.ts +59 -0
  8. package/dist/client/index.d.ts +28 -0
  9. package/dist/client/stub-services.d.ts +32 -0
  10. package/dist/client/test-session.d.ts +195 -0
  11. package/dist/client.js +16884 -0
  12. package/dist/core/asset-reference-translator.d.ts +46 -0
  13. package/dist/core/clock.d.ts +57 -0
  14. package/dist/core/faults.d.ts +65 -0
  15. package/dist/core/game-settings.d.ts +65 -0
  16. package/dist/core/history.d.ts +89 -0
  17. package/dist/core/listen-with-fallback.d.ts +30 -0
  18. package/dist/core/mutation-queue.d.ts +61 -0
  19. package/dist/core/package-scenario.d.ts +89 -0
  20. package/dist/core/participant-registry.d.ts +109 -0
  21. package/dist/core/pending-changes.d.ts +14 -0
  22. package/dist/core/protocol.d.ts +83 -0
  23. package/dist/core/scenario-drafts.d.ts +32 -0
  24. package/dist/core/session-endpoints.d.ts +108 -0
  25. package/dist/core/session-gates.d.ts +75 -0
  26. package/dist/core/session-host.d.ts +94 -0
  27. package/dist/core/session-refusals.d.ts +56 -0
  28. package/dist/core/session-rewind.d.ts +32 -0
  29. package/dist/core/session-roster.d.ts +128 -0
  30. package/dist/core/session-surfaces.d.ts +32 -0
  31. package/dist/core/session-ticks.d.ts +18 -0
  32. package/dist/core/session-timers.d.ts +84 -0
  33. package/dist/core/session-writes.d.ts +40 -0
  34. package/dist/core/session.d.ts +385 -0
  35. package/dist/core/settings-locks.d.ts +22 -0
  36. package/dist/core/team-names.d.ts +52 -0
  37. package/dist/core/team-state-store.d.ts +209 -0
  38. package/dist/core/tick-timer.d.ts +75 -0
  39. package/dist/dev/blob-links.d.ts +10 -0
  40. package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
  41. package/dist/dev/console/index.html +12 -0
  42. package/dist/dev/console-path.d.ts +19 -0
  43. package/dist/dev/lockfile.d.ts +124 -0
  44. package/dist/dev/package-watcher.d.ts +21 -0
  45. package/dist/dev/routes.d.ts +67 -0
  46. package/dist/dev/shell.d.ts +260 -0
  47. package/dist/dev/surfaces.d.ts +41 -0
  48. package/dist/dev/tools-identity.d.ts +23 -0
  49. package/dist/dev/view/batch.d.ts +172 -0
  50. package/dist/dev/view/commands.d.ts +75 -0
  51. package/dist/dev/view/route.d.ts +58 -0
  52. package/dist/dev/view/view.d.ts +78 -0
  53. package/dist/dev/view/viewer.d.ts +32 -0
  54. package/dist/discovery/config.d.ts +9 -0
  55. package/dist/discovery/manifest-paths.d.ts +21 -0
  56. package/dist/discovery/removed-fields.d.ts +90 -0
  57. package/dist/docs/api/deck.md +386 -0
  58. package/dist/docs/api/index.md +67 -0
  59. package/dist/docs/api/sdk-commands.md +286 -0
  60. package/dist/docs/api/sdk-e2e.md +433 -0
  61. package/dist/docs/api/sdk-projection.md +207 -0
  62. package/dist/docs/api/sdk-testing.md +214 -0
  63. package/dist/docs/api/sdk-tools-client.md +560 -0
  64. package/dist/docs/api/sdk-ui-testing.md +231 -0
  65. package/dist/docs/api/sdk-ui.md +1269 -0
  66. package/dist/docs/api/sdk.md +2140 -0
  67. package/dist/docs/changelog-0.x.md +1156 -0
  68. package/dist/docs/changelog.md +236 -0
  69. package/dist/docs/cli-and-dev-server.md +217 -0
  70. package/dist/docs/cli-error-codes.md +154 -0
  71. package/dist/docs/cli-reference.md +2488 -0
  72. package/dist/docs/cli-simulation-testing.md +222 -0
  73. package/dist/docs/concepts/index.md +46 -0
  74. package/dist/docs/concepts/terminology.md +322 -0
  75. package/dist/docs/environment-variables.md +102 -0
  76. package/dist/docs/getting-started.md +145 -0
  77. package/dist/docs/guides/ai-facilitation.md +220 -0
  78. package/dist/docs/guides/capabilities.md +460 -0
  79. package/dist/docs/guides/endpoints.md +335 -0
  80. package/dist/docs/guides/engine-testing.md +477 -0
  81. package/dist/docs/guides/engine.md +527 -0
  82. package/dist/docs/guides/file-handling.md +405 -0
  83. package/dist/docs/guides/games.md +176 -0
  84. package/dist/docs/guides/global-settings.md +94 -0
  85. package/dist/docs/guides/guide.md +123 -0
  86. package/dist/docs/guides/hooks.md +183 -0
  87. package/dist/docs/guides/index.md +51 -0
  88. package/dist/docs/guides/internationalization.md +288 -0
  89. package/dist/docs/guides/llm-integration.md +635 -0
  90. package/dist/docs/guides/multi-team-games.md +586 -0
  91. package/dist/docs/guides/patterns.md +391 -0
  92. package/dist/docs/guides/presentation.md +196 -0
  93. package/dist/docs/guides/production-constraints.md +130 -0
  94. package/dist/docs/guides/scenario-editor.md +143 -0
  95. package/dist/docs/guides/scenarios.md +515 -0
  96. package/dist/docs/guides/session.md +972 -0
  97. package/dist/docs/guides/settings.md +458 -0
  98. package/dist/docs/guides/setup.md +193 -0
  99. package/dist/docs/guides/speech-generation.md +233 -0
  100. package/dist/docs/guides/starter-game.md +164 -0
  101. package/dist/docs/guides/testing.md +575 -0
  102. package/dist/docs/guides/tick-controller.md +569 -0
  103. package/dist/docs/guides/type-safety.md +516 -0
  104. package/dist/docs/guides/ui.md +1389 -0
  105. package/dist/docs/guides/upgrading.md +636 -0
  106. package/dist/docs/guides/validators.md +217 -0
  107. package/dist/docs/guides/waiting-room.md +244 -0
  108. package/dist/docs/index.md +41 -0
  109. package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
  110. package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
  111. package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
  112. package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
  113. package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
  114. package/dist/docs/recipes/create-capability.md +66 -0
  115. package/dist/docs/recipes/create-endpoint.md +127 -0
  116. package/dist/docs/recipes/create-engine.md +111 -0
  117. package/dist/docs/recipes/create-game.md +70 -0
  118. package/dist/docs/recipes/create-guide.md +75 -0
  119. package/dist/docs/recipes/create-hook.md +80 -0
  120. package/dist/docs/recipes/create-presentation.md +142 -0
  121. package/dist/docs/recipes/create-scenario-editor.md +102 -0
  122. package/dist/docs/recipes/create-scenario.md +98 -0
  123. package/dist/docs/recipes/create-session-ui.md +116 -0
  124. package/dist/docs/recipes/create-settings.md +88 -0
  125. package/dist/docs/recipes/create-setup.md +115 -0
  126. package/dist/docs/recipes/create-tick-controller.md +65 -0
  127. package/dist/docs/recipes/create-user-interface.md +96 -0
  128. package/dist/docs/recipes/create-validator.md +67 -0
  129. package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
  130. package/dist/docs/recipes/declare-api-uses.md +67 -0
  131. package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
  132. package/dist/docs/recipes/distribute-package.md +80 -0
  133. package/dist/docs/recipes/e2e-testing.md +116 -0
  134. package/dist/docs/recipes/end-game-on-condition.md +154 -0
  135. package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
  136. package/dist/docs/recipes/index.md +86 -0
  137. package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
  138. package/dist/docs/recipes/negotiate-across-teams.md +164 -0
  139. package/dist/docs/recipes/observe-other-teams-state.md +119 -0
  140. package/dist/docs/recipes/publish-a-package.md +139 -0
  141. package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
  142. package/dist/docs/recipes/review-a-past-day.md +73 -0
  143. package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
  144. package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
  145. package/dist/docs/recipes/show-all-teams-participants.md +109 -0
  146. package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
  147. package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
  148. package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
  149. package/dist/docs/recipes/test-user-interface.md +95 -0
  150. package/dist/docs/recipes/test-with-engine.md +115 -0
  151. package/dist/docs/recipes/upload-and-display-files.md +148 -0
  152. package/dist/docs/recipes/use-request-play.md +65 -0
  153. package/dist/docs/recipes/use-request-tick.md +75 -0
  154. package/dist/docs/troubleshooting.md +816 -0
  155. package/dist/execution/blob-inputs.d.ts +57 -0
  156. package/dist/execution/bundle-reload.d.ts +42 -0
  157. package/dist/execution/config-resolver.d.ts +127 -0
  158. package/dist/execution/configuration-builder.d.ts +66 -0
  159. package/dist/execution/context-composition.d.ts +161 -0
  160. package/dist/execution/endpoint-actions.d.ts +9 -0
  161. package/dist/execution/endpoint-payloads.d.ts +32 -0
  162. package/dist/execution/endpoint-runner.d.ts +129 -0
  163. package/dist/execution/engine-state.d.ts +40 -0
  164. package/dist/execution/executor-callbacks.d.ts +56 -0
  165. package/dist/execution/executor.d.ts +436 -0
  166. package/dist/execution/gates.d.ts +45 -0
  167. package/dist/execution/hook-chain.d.ts +25 -0
  168. package/dist/execution/logic-calls.d.ts +190 -0
  169. package/dist/execution/logic-failure.d.ts +84 -0
  170. package/dist/execution/logic-loader.d.ts +54 -0
  171. package/dist/execution/logic-result.d.ts +76 -0
  172. package/dist/execution/tick-controller-call.d.ts +32 -0
  173. package/dist/execution/types.d.ts +48 -0
  174. package/dist/generation/ts-type.d.ts +39 -0
  175. package/dist/guide/locale.d.ts +12 -0
  176. package/dist/guide/video-registry.d.ts +42 -0
  177. package/dist/help-examples.d.ts +125 -0
  178. package/dist/host/adapter.d.ts +67 -0
  179. package/dist/host/host-channel.d.ts +222 -0
  180. package/dist/host/index.d.ts +20 -0
  181. package/dist/host/protocol.d.ts +783 -0
  182. package/dist/host/surfaces.d.ts +42 -0
  183. package/dist/host/theme.d.ts +55 -0
  184. package/dist/host.js +583 -0
  185. package/dist/prompts/index.d.ts +7 -0
  186. package/dist/prompts/schema-builder.d.ts +29 -0
  187. package/dist/prompts/types.d.ts +108 -0
  188. package/dist/prompts/validators.d.ts +32 -0
  189. package/dist/runtime/capability-scope.d.ts +6 -0
  190. package/dist/runtime/context-merge.d.ts +29 -0
  191. package/dist/runtime/context-projection.d.ts +41 -0
  192. package/dist/runtime/guarded-callbacks.d.ts +15 -0
  193. package/dist/runtime/index.d.ts +27 -0
  194. package/dist/runtime/manifest-version.d.ts +55 -0
  195. package/dist/runtime/tick-validation.d.ts +25 -0
  196. package/dist/runtime.js +346 -0
  197. package/dist/schema.json +1546 -0
  198. package/dist/server/vite-plugin.d.ts +46 -0
  199. package/dist/services/tts/client.d.ts +51 -0
  200. package/dist/services/tts/elevenlabs.d.ts +24 -0
  201. package/dist/services/tts/types.d.ts +44 -0
  202. package/dist/storage/asset-resolver.d.ts +49 -0
  203. package/dist/storage/blob-store.d.ts +41 -0
  204. package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
  205. package/dist/templates/endpoint/logic.ts.liquid +25 -0
  206. package/dist/templates/engine/init.json.liquid +7 -0
  207. package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
  208. package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
  209. package/dist/templates/engine/logic.test.ts.liquid +61 -0
  210. package/dist/templates/engine/logic.ts.liquid +32 -0
  211. package/dist/templates/engine/run.json.liquid +7 -0
  212. package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
  213. package/dist/templates/guide/02-preparation.md.liquid +18 -0
  214. package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
  215. package/dist/templates/hook/logic.test.ts.liquid +46 -0
  216. package/dist/templates/hook/logic.ts.liquid +12 -0
  217. package/dist/templates/package/CLAUDE.md.template +338 -0
  218. package/dist/templates/package/DESIGN.md.liquid +144 -0
  219. package/dist/templates/package/README.md.liquid +143 -0
  220. package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
  221. package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
  222. package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
  223. package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
  224. package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
  225. package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
  226. package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
  227. package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
  228. package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
  229. package/dist/templates/package/claude/settings.json.template +16 -0
  230. package/dist/templates/package/gitignore.template +15 -0
  231. package/dist/templates/package/global-setup.ts.template +21 -0
  232. package/dist/templates/package/globals.d.ts.template +2 -0
  233. package/dist/templates/package/oxfmtrc.json.template +14 -0
  234. package/dist/templates/package/oxlintrc.json.template +238 -0
  235. package/dist/templates/package/package.json.liquid +65 -0
  236. package/dist/templates/package/playwright.config.ts.liquid +19 -0
  237. package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
  238. package/dist/templates/package/test-setup.ts.liquid +7 -0
  239. package/dist/templates/package/tsconfig.json.liquid +15 -0
  240. package/dist/templates/package/vite.config.ts.liquid +19 -0
  241. package/dist/templates/package/vitest.config.ts.liquid +25 -0
  242. package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
  243. package/dist/templates/presentation/index.html.liquid +20 -0
  244. package/dist/templates/presentation/src/App.tsx.liquid +49 -0
  245. package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
  246. package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
  247. package/dist/templates/presentation/src/main.tsx.liquid +14 -0
  248. package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
  249. package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
  250. package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
  251. package/dist/templates/session/src/App.test.tsx.liquid +60 -0
  252. package/dist/templates/session/src/App.tsx.liquid +128 -0
  253. package/dist/templates/session/src/i18n.ts.liquid +53 -0
  254. package/dist/templates/session/src/main.tsx.liquid +48 -0
  255. package/dist/templates/session/src/theme.ts.liquid +46 -0
  256. package/dist/templates/settings-editor/index.html.liquid +12 -0
  257. package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
  258. package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
  259. package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
  260. package/dist/templates/setup/src/App.tsx.liquid +102 -0
  261. package/dist/templates/setup/src/i18n.ts.liquid +47 -0
  262. package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
  263. package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
  264. package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
  265. package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
  266. package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
  267. package/dist/templates/starter-game/engine/defaults.ts +81 -0
  268. package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
  269. package/dist/templates/starter-game/engine/logic.test.ts +221 -0
  270. package/dist/templates/starter-game/engine/logic.ts +149 -0
  271. package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
  272. package/dist/templates/starter-game/engine/types.ts +139 -0
  273. package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
  274. package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
  275. package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
  276. package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
  277. package/dist/templates/starter-game/guide/guide.test.ts +108 -0
  278. package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
  279. package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
  280. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
  281. package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
  282. package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
  283. package/dist/templates/starter-game/package.json +68 -0
  284. package/dist/templates/starter-game/playwright.config.ts +19 -0
  285. package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
  286. package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
  287. package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
  288. package/dist/templates/starter-game/session/defaults.ts +80 -0
  289. package/dist/templates/starter-game/session/index.html +12 -0
  290. package/dist/templates/starter-game/session/session.sdk.json +11 -0
  291. package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
  292. package/dist/templates/starter-game/session/src/App.tsx +309 -0
  293. package/dist/templates/starter-game/session/src/Section.tsx +37 -0
  294. package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
  295. package/dist/templates/starter-game/session/src/format.ts +8 -0
  296. package/dist/templates/starter-game/session/src/i18n.ts +51 -0
  297. package/dist/templates/starter-game/session/src/main.tsx +48 -0
  298. package/dist/templates/starter-game/session/src/theme.ts +45 -0
  299. package/dist/templates/starter-game/session/types.ts +135 -0
  300. package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
  301. package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
  302. package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
  303. package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
  304. package/dist/templates/starter-game/test-setup.ts +7 -0
  305. package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
  306. package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
  307. package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
  308. package/dist/templates/starter-game/tsconfig.json +19 -0
  309. package/dist/templates/starter-game/ui/defaults.ts +60 -0
  310. package/dist/templates/starter-game/ui/index.html +12 -0
  311. package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
  312. package/dist/templates/starter-game/ui/src/App.tsx +175 -0
  313. package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
  314. package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
  315. package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
  316. package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
  317. package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
  318. package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
  319. package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
  320. package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
  321. package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
  322. package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
  323. package/dist/templates/starter-game/ui/src/format.ts +12 -0
  324. package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
  325. package/dist/templates/starter-game/ui/src/main.tsx +48 -0
  326. package/dist/templates/starter-game/ui/src/menu.ts +18 -0
  327. package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
  328. package/dist/templates/starter-game/ui/src/theme.ts +45 -0
  329. package/dist/templates/starter-game/ui/src/writes.ts +43 -0
  330. package/dist/templates/starter-game/ui/types.ts +137 -0
  331. package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
  332. package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
  333. package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
  334. package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
  335. package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
  336. package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
  337. package/dist/templates/starter-game/vite.config.ts +19 -0
  338. package/dist/templates/starter-game/vitest.config.ts +15 -0
  339. package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
  340. package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
  341. package/dist/templates/starter-game/waiting_room/index.html +12 -0
  342. package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
  343. package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
  344. package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
  345. package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
  346. package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
  347. package/dist/templates/starter-game/waiting_room/types.ts +59 -0
  348. package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
  349. package/dist/templates/tick-controller/logic.ts.liquid +8 -0
  350. package/dist/templates/ui/index.html.liquid +12 -0
  351. package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
  352. package/dist/templates/ui/src/App.tsx.liquid +103 -0
  353. package/dist/templates/ui/src/i18n.ts.liquid +47 -0
  354. package/dist/templates/ui/src/main.tsx.liquid +48 -0
  355. package/dist/templates/ui/src/theme.ts.liquid +46 -0
  356. package/dist/templates/validator/logic.test.ts.liquid +42 -0
  357. package/dist/templates/validator/logic.ts.liquid +21 -0
  358. package/dist/templates/waiting-room/index.html.liquid +12 -0
  359. package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
  360. package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
  361. package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
  362. package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
  363. package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
  364. package/dist/templating/resource-metadata.d.ts +131 -0
  365. package/dist/types.d.ts +14 -0
  366. package/dist/utils/atomic-write.d.ts +40 -0
  367. package/dist/utils/cli-error.d.ts +64 -0
  368. package/dist/utils/document-parser-client.d.ts +20 -0
  369. package/dist/utils/env-loader.d.ts +40 -0
  370. package/dist/utils/error-codes.d.ts +335 -0
  371. package/dist/utils/errors.d.ts +19 -0
  372. package/dist/utils/global-settings.d.ts +65 -0
  373. package/dist/utils/llm-client.d.ts +34 -0
  374. package/dist/utils/logger.d.ts +36 -0
  375. package/dist/utils/output.d.ts +109 -0
  376. package/dist/utils/platform.d.ts +14 -0
  377. package/dist/utils/prompt.d.ts +36 -0
  378. package/dist/utils/real-path.d.ts +6 -0
  379. package/dist/utils/schema-properties.d.ts +35 -0
  380. package/dist/validation/ajv.d.ts +17 -0
  381. package/dist/validation/facilitator-guide-validator.d.ts +27 -0
  382. package/dist/validation/findings.d.ts +40 -0
  383. package/dist/validation/game-constraints.d.ts +10 -0
  384. package/dist/validation/game-validator.d.ts +34 -0
  385. package/dist/validation/package-validation.d.ts +41 -0
  386. package/dist/validation/package-validator.d.ts +19 -0
  387. package/dist/validation/resource-validator.d.ts +79 -0
  388. package/dist/validation/schema-defaults-validator.d.ts +29 -0
  389. package/dist/validation/schema-validation.d.ts +115 -0
  390. package/dist/validation/semver.d.ts +9 -0
  391. package/package.json +122 -3
@@ -0,0 +1,47 @@
1
+ import i18n from 'i18next';
2
+ import { initReactI18next } from 'react-i18next';
3
+
4
+ // Translation resources
5
+ const resources = {
6
+ en: {
7
+ translation: {
8
+ greeting: 'Hello, World!',
9
+ welcomeMessage: 'Welcome to your Serious Gaming User Interface.',
10
+ dataExample:
11
+ "The component below demonstrates reading and writing data to the game's shared state by using a capability.",
12
+ currentValue: 'Current value: {% raw %}{{value}}{% endraw %}',
13
+ updateButton: 'Increment Value',
14
+ },
15
+ },
16
+ it: {
17
+ translation: {
18
+ greeting: 'Ciao, mondo!',
19
+ welcomeMessage: 'Benvenuto nella tua interfaccia utente di Serious Gaming.',
20
+ dataExample:
21
+ 'Il componente sottostante dimostra come leggere e scrivere dati nello stato condiviso della simulazione utilizzando una capability.',
22
+ currentValue: 'Valore corrente: {% raw %}{{value}}{% endraw %}',
23
+ updateButton: 'Incrementa valore',
24
+ },
25
+ },
26
+ ar: {
27
+ translation: {
28
+ greeting: 'أهلاً بالعالم!',
29
+ welcomeMessage: 'مرحبًا بك في واجهة مستخدم كونشيرتو الخاصة بك.',
30
+ dataExample:
31
+ 'يوضح المكون أدناه قراءة البيانات وكتابتها إلى الحالة المشتركة للمحاكاة باستخدام إحدى الإمكانات.',
32
+ currentValue: 'القيمة الحالية: {% raw %}{{value}}{% endraw %}',
33
+ updateButton: 'زيادة القيمة',
34
+ },
35
+ },
36
+ };
37
+
38
+ i18n.use(initReactI18next).init({
39
+ resources,
40
+ lng: 'en', // default language
41
+ fallbackLng: 'en',
42
+ interpolation: {
43
+ escapeValue: false, // React already escapes
44
+ },
45
+ });
46
+
47
+ export default i18n;
@@ -0,0 +1,48 @@
1
+ import createCache from '@emotion/cache';
2
+ import { CacheProvider } from '@emotion/react';
3
+ import '@fontsource-variable/roboto-mono';
4
+ import '@fontsource-variable/work-sans';
5
+ import rtlPlugin from '@mui/stylis-plugin-rtl';
6
+ import { UserInterfaceWrapper, useUserInterfaceLocale } from '@seriousgaming/sdk/ui';
7
+
8
+ import './i18n';
9
+ import i18n from 'i18next';
10
+ import React, { StrictMode, useEffect } from 'react';
11
+ import { createRoot } from 'react-dom/client';
12
+ import { prefixer } from 'stylis';
13
+
14
+ import App from './App';
15
+
16
+ // Create RTL cache
17
+ const cacheRtl = createCache({
18
+ key: 'muirtl',
19
+ stylisPlugins: [prefixer, rtlPlugin],
20
+ });
21
+
22
+ const cacheLtr = createCache({
23
+ key: 'muiltr',
24
+ });
25
+
26
+ // Wrapper component to sync locale with i18next and setup RTL
27
+ function RootWrapper({ children }: { children: React.ReactNode }) {
28
+ const { locale } = useUserInterfaceLocale();
29
+
30
+ useEffect(() => {
31
+ const i18nextLocale = locale.split('-')[0];
32
+ i18n.changeLanguage(i18nextLocale);
33
+ }, [locale]);
34
+
35
+ const isRtl = i18n.dir(locale.split('-')[0]) === 'rtl';
36
+
37
+ return <CacheProvider value={isRtl ? cacheRtl : cacheLtr}>{children}</CacheProvider>;
38
+ }
39
+
40
+ createRoot(document.getElementById('root')!).render(
41
+ <StrictMode>
42
+ <UserInterfaceWrapper>
43
+ <RootWrapper>
44
+ <App />
45
+ </RootWrapper>
46
+ </UserInterfaceWrapper>
47
+ </StrictMode>
48
+ );
@@ -0,0 +1,46 @@
1
+ {% raw %}import { createTheme } from '@mui/material/styles';
2
+ import { useUserInterfaceTheme } from '@seriousgaming/sdk/ui';
3
+ import { useMemo } from 'react';
4
+
5
+ /**
6
+ * The host owns the palette, the game owns the typography and the component
7
+ * shapes. Reading `theme.mode` rather than the browser's preference is what
8
+ * keeps a participant's screen and the facilitator's looking like one product.
9
+ */
10
+ export const useAppTheme = () => {
11
+ const theme = useUserInterfaceTheme();
12
+
13
+ return useMemo(() => {
14
+ const colors = theme.mode === 'light' ? theme.light : theme.dark;
15
+ return createTheme({
16
+ palette: {
17
+ mode: theme.mode,
18
+ primary: { main: colors.primary, contrastText: colors.contrastText.primary },
19
+ secondary: { main: colors.secondary, contrastText: colors.contrastText.secondary },
20
+ success: { main: colors.success, contrastText: colors.contrastText.success },
21
+ error: { main: colors.error, contrastText: colors.contrastText.error },
22
+ warning: { main: colors.warning, contrastText: colors.contrastText.warning },
23
+ info: { main: colors.info, contrastText: colors.contrastText.info },
24
+ },
25
+ shape: { borderRadius: 10 },
26
+ components: {
27
+ MuiButton: { styleOverrides: { root: { textTransform: 'none' } } },
28
+ MuiTab: {
29
+ styleOverrides: { root: { textTransform: 'none', fontSize: '0.95rem' } },
30
+ },
31
+ MuiToggleButton: { styleOverrides: { root: { textTransform: 'none' } } },
32
+ MuiTableCell: {
33
+ styleOverrides: {
34
+ head: {
35
+ fontSize: '0.75rem',
36
+ fontWeight: 700,
37
+ letterSpacing: '0.07em',
38
+ textTransform: 'uppercase',
39
+ },
40
+ },
41
+ },
42
+ },
43
+ });
44
+ }, [theme]);
45
+ };
46
+ {% endraw %}
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { UpdateData } from './logic';
3
+ import type { Context, Settings } from '../types';
4
+ import type { LogicMeta } from '@seriousgaming/sdk';
5
+
6
+ // The run-wide facts the host supplies: the session locale, its random seed,
7
+ // whether this is the game being played or a walkthrough beside it, and when
8
+ // the operation started.
9
+ const meta: LogicMeta = { locale: 'en', seed: 'test-seed', runKind: 'session', now: Date.UTC(2026, 0, 1) };
10
+
11
+ // Who submitted the mutation. Swap for `{ role: 'observer', teamId: 'team-1' }`
12
+ // to cover a facilitator observing the team on the same surface.
13
+ const actor = {
14
+ role: 'participant',
15
+ participant: {
16
+ id: '1',
17
+ teamId: 'team-1',
18
+ name: 'Participant 1',
19
+ index: 0,
20
+ connected: true,
21
+ },
22
+ } as const;
23
+
24
+ describe('{{ identifier }}', () => {
25
+ describe('UpdateData', () => {
26
+ it('accepts a valid mutation', async () => {
27
+ const previous: Context = {
28
+ // TODO: Add context values based on required capabilities
29
+ } as Context;
30
+ const next: Context = {
31
+ // TODO: Add proposed next-state values
32
+ } as Context;
33
+ const settings: Settings = {
34
+ // TODO: Add values for the settings resources this reads
35
+ } as Settings;
36
+
37
+ const result = await UpdateData({ previous, next, actor, settings, meta, participants: [actor.participant] });
38
+
39
+ expect(result.ok).toBe(true);
40
+ });
41
+ });
42
+ });
@@ -0,0 +1,21 @@
1
+ import type { ValidatorFunction } from '../types';
2
+
3
+ // A validator gates what a participant does, one export per action. This one
4
+ // is `UpdateData`, the gate on a context write. Export `RequestTick` as well
5
+ // (typed `RequestTickFunction` from '../types') to gate a participant's request
6
+ // for the next tick: it receives `{ context, requestedTick, actor, settings, meta }`.
7
+ export const UpdateData: ValidatorFunction = async ({ previous, next, actor, settings }) => {
8
+ // Validators gate UI-submitted mutations before they're applied.
9
+ // Return { ok: true } to allow, { ok: false, message: '...' } to reject.
10
+ // The proposed `next` state is what would be applied if every referenced
11
+ // validator returns ok.
12
+ //
13
+ // `actor` says who submitted it: a participant, or a facilitator observing
14
+ // the team on the same surface. Both are held to this rule unless you say
15
+ // otherwise, e.g.:
16
+ //
17
+ // if (actor.role === 'observer') return { ok: true };
18
+ //
19
+ // Narrow on `actor.role` before reading `actor.participant`.
20
+ return { ok: true };
21
+ };
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{ name }}</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="./src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,57 @@
1
+ {% raw %}import { describe, it, expect, vi } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import {
4
+ UserInterfaceDataContext,
5
+ UserInterfaceOwnTeamContext,
6
+ UserInterfaceParticipantContext,
7
+ UserInterfaceParticipantsContext,
8
+ UserInterfaceThemeContext,
9
+ } from '@seriousgaming/sdk/ui';
10
+ import { createMockTheme } from '@seriousgaming/sdk/ui/testing';
11
+ import './i18n';
12
+ import App from './App';
13
+
14
+ // A waiting room UI is a player UI, so it renders under the same context
15
+ // providers. These replace the iframe communication the real app uses.
16
+ const SELF = { id: 'p1', name: 'Ada', index: 0, connected: true, teamId: 'team-1' };
17
+ const ROSTER = [
18
+ { ...SELF, connected: true },
19
+ { id: 'p2', name: 'Grace', index: 1, teamId: 'team-1', connected: false },
20
+ ];
21
+
22
+ const renderApp = (completedTicks = 0) =>
23
+ render(
24
+ <UserInterfaceThemeContext.Provider value={createMockTheme()}>
25
+ <UserInterfaceDataContext.Provider
26
+ value={{ data: {}, settings: {}, completedTicks, isRoundProcessing: false, setData: vi.fn() }}
27
+ >
28
+ <UserInterfaceOwnTeamContext.Provider
29
+ value={{ teamId: 'team-1', index: 0, name: 'Team 1' }}
30
+ >
31
+ <UserInterfaceParticipantContext.Provider value={SELF}>
32
+ <UserInterfaceParticipantsContext.Provider value={ROSTER}>
33
+ <App />
34
+ </UserInterfaceParticipantsContext.Provider>
35
+ </UserInterfaceParticipantContext.Provider>
36
+ </UserInterfaceOwnTeamContext.Provider>
37
+ </UserInterfaceDataContext.Provider>
38
+ </UserInterfaceThemeContext.Provider>
39
+ );
40
+
41
+ describe('App', () => {
42
+ it('says the session has not begun at tick 0', () => {
43
+ renderApp(0);
44
+ expect(screen.getByText(/waiting to begin/i)).toBeInTheDocument();
45
+ });
46
+
47
+ it('says the session is paused once ticks have run', () => {
48
+ renderApp(3);
49
+ expect(screen.getByText(/session paused/i)).toBeInTheDocument();
50
+ });
51
+
52
+ it('lists the team roster and marks the reader', () => {
53
+ renderApp();
54
+ expect(screen.getByText(/ada \(you\)/i)).toBeInTheDocument();
55
+ expect(screen.getByText('Grace')).toBeInTheDocument();
56
+ });
57
+ });{% endraw %}
@@ -0,0 +1,118 @@
1
+ {% raw %}import React from 'react';
2
+ import { Box, CssBaseline, ThemeProvider, Typography } from '@mui/material';
3
+ import {
4
+ useUserInterfaceOwnTeam,
5
+ useUserInterfaceData,
6
+ useUserInterfaceParticipant,
7
+ useUserInterfaceParticipants,
8
+ } from '@seriousgaming/sdk/ui';
9
+ import { useTranslation } from 'react-i18next';
10
+ import { Context, Settings } from '../types';
11
+ import { useAppTheme } from './theme';
12
+
13
+ /*
14
+ This UI requires the following dependencies:
15
+ - @mui/material
16
+ - @emotion/react
17
+ - @emotion/styled
18
+ - stylis
19
+ - @mui/stylis-plugin-rtl
20
+ - @fontsource-variable/roboto-mono
21
+ - @fontsource-variable/work-sans
22
+ - i18next
23
+ - react-i18next
24
+
25
+ Make sure to install them in your project, e.g.:
26
+ pnpm add @mui/material @emotion/react @emotion/styled stylis @mui/stylis-plugin-rtl @fontsource-variable/roboto-mono @fontsource-variable/work-sans i18next react-i18next
27
+ */
28
+
29
+ /*
30
+ A waiting room user interface is a player user interface shown in a different
31
+ place: the host mounts it instead of the game UIs while the facilitator has the
32
+ session's waiting room open, and swaps back the moment they close it. Every
33
+ player hook and callback works here exactly as it does in a game UI, so this
34
+ file uses `useUserInterfaceData` and friends rather than a waiting-room-specific
35
+ API.
36
+
37
+ Two things are worth knowing while you build one:
38
+
39
+ 1. The room can be opened at any point, not only before the session starts. Read
40
+ `completedTicks` to tell the two apart — 0 means the session has not begun,
41
+ anything higher means the facilitator has parked a session already in play.
42
+ 2. Opening the room does not stop the clock. If you want automatic ticks to
43
+ pause while players wait, read `waitingRoomOpen` in your tick controller and
44
+ return `enabled: false`.
45
+ */
46
+
47
+ function App() {
48
+ const { completedTicks } = useUserInterfaceData<Context, Settings>();
49
+ const { t } = useTranslation();
50
+ const theme = useAppTheme();
51
+ const ownTeam = useUserInterfaceOwnTeam();
52
+ const participants = useUserInterfaceParticipants();
53
+ const self = useUserInterfaceParticipant();
54
+
55
+ const roster = [...participants].sort((a, b) => a.index - b.index);
56
+
57
+ return (
58
+ <ThemeProvider theme={theme}>
59
+ <CssBaseline enableColorScheme />
60
+ <Box
61
+ sx={{
62
+ display: 'flex',
63
+ flexDirection: 'column',
64
+ alignItems: 'center',
65
+ justifyContent: 'center',
66
+ gap: 2,
67
+ minHeight: '100vh',
68
+ p: 3,
69
+ textAlign: 'center',
70
+ }}
71
+ >
72
+ <Typography variant="h4" component="h1">
73
+ {completedTicks === 0 ? t('headingBeforeStart') : t('headingPaused')}
74
+ </Typography>
75
+
76
+ <Typography variant="body1" color="text.secondary">
77
+ {ownTeam
78
+ ? t('joinedTeam', { team: ownTeam.name })
79
+ : t('waitingForFacilitator')}
80
+ </Typography>
81
+
82
+ <Box component="ul" sx={{ listStyle: 'none', p: 0, m: 0 }}>
83
+ {roster.map((participant) => (
84
+ <Box
85
+ component="li"
86
+ key={participant.id}
87
+ sx={{
88
+ display: 'flex',
89
+ alignItems: 'center',
90
+ justifyContent: 'center',
91
+ gap: 1,
92
+ }}
93
+ >
94
+ <Box
95
+ aria-hidden
96
+ sx={{
97
+ width: 8,
98
+ height: 8,
99
+ borderRadius: '50%',
100
+ bgcolor: participant.connected
101
+ ? 'success.main'
102
+ : 'text.disabled',
103
+ }}
104
+ />
105
+ <Typography variant="body2">
106
+ {participant.id === self?.id
107
+ ? t('participantSelf', { name: participant.name })
108
+ : participant.name}
109
+ </Typography>
110
+ </Box>
111
+ ))}
112
+ </Box>
113
+ </Box>
114
+ </ThemeProvider>
115
+ );
116
+ }
117
+
118
+ export default App;{% endraw %}
@@ -0,0 +1,44 @@
1
+ import i18n from 'i18next';
2
+ import { initReactI18next } from 'react-i18next';
3
+
4
+ // Translation resources
5
+ const resources = {
6
+ en: {
7
+ translation: {
8
+ headingBeforeStart: 'Waiting to begin',
9
+ headingPaused: 'Session paused',
10
+ joinedTeam: "You've joined {% raw %}{{team}}{% endraw %}. The facilitator will continue shortly.",
11
+ waitingForFacilitator: 'The facilitator will continue shortly.',
12
+ participantSelf: '{% raw %}{{name}}{% endraw %} (you)',
13
+ },
14
+ },
15
+ it: {
16
+ translation: {
17
+ headingBeforeStart: 'In attesa di iniziare',
18
+ headingPaused: 'Sessione in pausa',
19
+ joinedTeam: 'Ti sei unito a {% raw %}{{team}}{% endraw %}. Il facilitatore proseguirà a breve.',
20
+ waitingForFacilitator: 'Il facilitatore proseguirà a breve.',
21
+ participantSelf: '{% raw %}{{name}}{% endraw %} (tu)',
22
+ },
23
+ },
24
+ ar: {
25
+ translation: {
26
+ headingBeforeStart: 'في انتظار البدء',
27
+ headingPaused: 'الجلسة متوقفة مؤقتًا',
28
+ joinedTeam: 'لقد انضممت إلى {% raw %}{{team}}{% endraw %}. سيتابع الميسر قريبًا.',
29
+ waitingForFacilitator: 'سيتابع الميسر قريبًا.',
30
+ participantSelf: '{% raw %}{{name}}{% endraw %} (أنت)',
31
+ },
32
+ },
33
+ };
34
+
35
+ i18n.use(initReactI18next).init({
36
+ resources,
37
+ lng: 'en', // default language
38
+ fallbackLng: 'en',
39
+ interpolation: {
40
+ escapeValue: false, // React already escapes
41
+ },
42
+ });
43
+
44
+ export default i18n;
@@ -0,0 +1,48 @@
1
+ import createCache from '@emotion/cache';
2
+ import { CacheProvider } from '@emotion/react';
3
+ import '@fontsource-variable/roboto-mono';
4
+ import '@fontsource-variable/work-sans';
5
+ import rtlPlugin from '@mui/stylis-plugin-rtl';
6
+ import { UserInterfaceWrapper, useUserInterfaceLocale } from '@seriousgaming/sdk/ui';
7
+
8
+ import './i18n';
9
+ import i18n from 'i18next';
10
+ import React, { StrictMode, useEffect } from 'react';
11
+ import { createRoot } from 'react-dom/client';
12
+ import { prefixer } from 'stylis';
13
+
14
+ import App from './App';
15
+
16
+ // Create RTL cache
17
+ const cacheRtl = createCache({
18
+ key: 'muirtl',
19
+ stylisPlugins: [prefixer, rtlPlugin],
20
+ });
21
+
22
+ const cacheLtr = createCache({
23
+ key: 'muiltr',
24
+ });
25
+
26
+ // Wrapper component to sync locale with i18next and setup RTL
27
+ function RootWrapper({ children }: { children: React.ReactNode }) {
28
+ const { locale } = useUserInterfaceLocale();
29
+
30
+ useEffect(() => {
31
+ const i18nextLocale = locale.split('-')[0];
32
+ i18n.changeLanguage(i18nextLocale);
33
+ }, [locale]);
34
+
35
+ const isRtl = i18n.dir(locale.split('-')[0]) === 'rtl';
36
+
37
+ return <CacheProvider value={isRtl ? cacheRtl : cacheLtr}>{children}</CacheProvider>;
38
+ }
39
+
40
+ createRoot(document.getElementById('root')!).render(
41
+ <StrictMode>
42
+ <UserInterfaceWrapper>
43
+ <RootWrapper>
44
+ <App />
45
+ </RootWrapper>
46
+ </UserInterfaceWrapper>
47
+ </StrictMode>
48
+ );
@@ -0,0 +1,46 @@
1
+ {% raw %}import { createTheme } from '@mui/material/styles';
2
+ import { useUserInterfaceTheme } from '@seriousgaming/sdk/ui';
3
+ import { useMemo } from 'react';
4
+
5
+ /**
6
+ * The host owns the palette, the game owns the typography and the component
7
+ * shapes. Reading `theme.mode` rather than the browser's preference is what
8
+ * keeps a participant's screen and the facilitator's looking like one product.
9
+ */
10
+ export const useAppTheme = () => {
11
+ const theme = useUserInterfaceTheme();
12
+
13
+ return useMemo(() => {
14
+ const colors = theme.mode === 'light' ? theme.light : theme.dark;
15
+ return createTheme({
16
+ palette: {
17
+ mode: theme.mode,
18
+ primary: { main: colors.primary, contrastText: colors.contrastText.primary },
19
+ secondary: { main: colors.secondary, contrastText: colors.contrastText.secondary },
20
+ success: { main: colors.success, contrastText: colors.contrastText.success },
21
+ error: { main: colors.error, contrastText: colors.contrastText.error },
22
+ warning: { main: colors.warning, contrastText: colors.contrastText.warning },
23
+ info: { main: colors.info, contrastText: colors.contrastText.info },
24
+ },
25
+ shape: { borderRadius: 10 },
26
+ components: {
27
+ MuiButton: { styleOverrides: { root: { textTransform: 'none' } } },
28
+ MuiTab: {
29
+ styleOverrides: { root: { textTransform: 'none', fontSize: '0.95rem' } },
30
+ },
31
+ MuiToggleButton: { styleOverrides: { root: { textTransform: 'none' } } },
32
+ MuiTableCell: {
33
+ styleOverrides: {
34
+ head: {
35
+ fontSize: '0.75rem',
36
+ fontWeight: 700,
37
+ letterSpacing: '0.07em',
38
+ textTransform: 'uppercase',
39
+ },
40
+ },
41
+ },
42
+ },
43
+ });
44
+ }, [theme]);
45
+ };
46
+ {% endraw %}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Resource metadata registry — the single source of truth for how each resource
3
+ * type is laid out on disk and how it is referenced by other resources.
4
+ *
5
+ * Before #282 every `templating/<type>.ts` file hand-copied the same
6
+ * create/update/delete/find/update-references skeleton, so a bug in the shared
7
+ * idiom had to be fixed 15 times and each type's reference coverage drifted
8
+ * independently (capability delete only scanned the engine and UIs;
9
+ * scenario/facilitator-guide renames orphaned their references). The generic
10
+ * engine in `engine.ts` reads this registry so every type applies the same,
11
+ * complete rewriting.
12
+ */
13
+ /**
14
+ * How references to a resource appear inside a referrer's `definition`.
15
+ *
16
+ * - `stringArray` — `definition[path]: string[]` of identifiers. An optional
17
+ * `labelSuffix` tags the reference label ('reads' / 'writes' /
18
+ * 'crossTeamReads' for the capability fan-out).
19
+ * - `keyedMap` — `definition[path]: Record<identifier, {...}>`; the
20
+ * identifier is the key, so a rename re-keys and a delete drops the entry.
21
+ * A scenario's `settings` is one, keyed by settings identifier.
22
+ */
23
+ export type ReferenceShape = {
24
+ kind: 'stringArray';
25
+ path: string;
26
+ labelSuffix?: string;
27
+ } | {
28
+ kind: 'keyedMap';
29
+ path: string;
30
+ };
31
+ /**
32
+ * The referrer key standing for the manifest itself rather than a list of
33
+ * bundle files. A package is a game (#421), so the settings that reference
34
+ * resources by identifier sit at the manifest's top level.
35
+ */
36
+ export declare const MANIFEST_REFERRER = "__manifest__";
37
+ /** One place a resource type is referenced: which referrer files, and how. */
38
+ export interface ReferenceSite {
39
+ /**
40
+ * Manifest keys (in seriousgaming.sdk.json) of the referrer files to scan,
41
+ * or {@link MANIFEST_REFERRER} for the manifest itself.
42
+ */
43
+ referrerKeys: string[];
44
+ shape: ReferenceShape;
45
+ }
46
+ export type ResourceKind = 'logic' | 'ui' | 'composition' | 'content';
47
+ /** Every registered resource type, so a stale type name is a compile error. */
48
+ export declare const RESOURCE_TYPES: readonly ["capability", "engine", "ui", "session", "waiting_room", "presentation", "setup", "scenario_editor", "scenario", "guide", "tick_controller", "hook", "validator", "endpoint", "settings"];
49
+ export type ResourceType = (typeof RESOURCE_TYPES)[number];
50
+ /**
51
+ * Where a resource's code sits inside its own directory, and what the
52
+ * entrypoint is called.
53
+ *
54
+ * The CLI fabricates this block: `new` writes it into the bundle and `update`
55
+ * leaves it alone, so an authored value was read by nothing. It is written down
56
+ * once here because the guard on authored input has to reject exactly what the
57
+ * templater is about to write, and a second copy could disagree with it (#473).
58
+ */
59
+ export type ResourceLayout = {
60
+ logic: {
61
+ directory: string;
62
+ entrypoint: string;
63
+ };
64
+ } | {
65
+ ui: {
66
+ entrypoint: string;
67
+ };
68
+ };
69
+ /**
70
+ * Where a resource lives in its package: a fixed slot for a type a game holds
71
+ * exactly one of, which is not named because the slot is the whole of its
72
+ * address, or a directory of named resources for every other type.
73
+ */
74
+ export type ResourcePlacement = {
75
+ /** The fixed directory a singular resource lives in, e.g. `engine`. */
76
+ slot: ResourceType;
77
+ pluralDir?: undefined;
78
+ } | {
79
+ slot?: undefined;
80
+ /** Directory holding all resources of this type, e.g. `hooks`. */
81
+ pluralDir: string;
82
+ };
83
+ export type PluralResourceMeta = Extract<ResourceMeta, {
84
+ pluralDir: string;
85
+ }>;
86
+ export type ResourceMeta = ResourcePlacement & {
87
+ type: ResourceType;
88
+ /**
89
+ * The code layout the templater writes into this type's bundle. Absent for
90
+ * the types that carry neither logic nor a UI.
91
+ */
92
+ layout?: ResourceLayout;
93
+ /** Bundle filename inside each resource directory, e.g. `engine.sdk.json`. */
94
+ bundleFile: string;
95
+ /** Key under which bundle paths are listed in seriousgaming.sdk.json. */
96
+ manifestKey: string;
97
+ kind: ResourceKind;
98
+ /** Human label used in reference output when this type is a referrer. */
99
+ label: string;
100
+ /** Merge the new definition onto the existing one (capability keeps `scope`). */
101
+ mergeDefinition: boolean;
102
+ /** Definition carries a `reads: string[]` of capability identifiers. */
103
+ hasReads: boolean;
104
+ /** Definition carries a `writes: string[]` of capability identifiers. */
105
+ hasWrites: boolean;
106
+ /** Definition carries a `crossTeamReads: string[]` of capability identifiers. */
107
+ hasCrossTeamReads: boolean;
108
+ /** Definition carries an `endpoints: string[]` of endpoint refs. */
109
+ declaresEndpoints: boolean;
110
+ /** Definition carries a `settings: string[]` of settings identifiers. */
111
+ readsSettings: boolean;
112
+ /** How other resources reference this one (target perspective). */
113
+ referenceSites: ReferenceSite[];
114
+ };
115
+ export declare const RESOURCE_METADATA: readonly ResourceMeta[];
116
+ export declare const RESOURCE_METADATA_BY_MANIFEST_KEY: ReadonlyMap<string, ResourceMeta>;
117
+ /** Metadata for a resource type, or undefined for a non-resource (`package`). */
118
+ export declare function findResourceMeta(type: string): ResourceMeta | undefined;
119
+ /**
120
+ * Nothing labels this resource, so it carries no `locales`.
121
+ *
122
+ * A game holds one of each interface, so no list ever names one and the name
123
+ * was never rendered (#448). The guide is the counter-example a hand-written
124
+ * list kept getting wrong: it fills a slot too, and it is genuinely titled. So
125
+ * is the presentation, the one interface a host lists outside a session, in a
126
+ * game's library, and so labels.
127
+ */
128
+ export declare function isNamelessInterface(meta: ResourceMeta): boolean;
129
+ export declare function getResourceMeta(type: ResourceType): ResourceMeta;
130
+ /** Metadata for a type a package may hold several of, named by directory. */
131
+ export declare function getPluralResourceMeta(type: ResourceType): PluralResourceMeta;