@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,143 @@
1
+ # {{ name }}
2
+
3
+ A Serious Gaming game package created with the Serious Gaming SDK.
4
+
5
+ It starts as a complete, playable simulation rather than a blank page: a
6
+ lemonade stand, run for 10 days. Each morning a team decides how many
7
+ lemonades, iced teas, and cookies to make. Whatever they make they pay for,
8
+ whatever is left at closing is poured away, and anyone who wanted something
9
+ that ran out simply leaves. The whole game is the balance between making too
10
+ much and too little.
11
+
12
+ Keep it, change the numbers, or replace the model entirely. What is worth
13
+ keeping either way is the shape around it: state keyed so two people on one team
14
+ cannot overwrite each other, a validator on the one thing they share (the
15
+ stall's capacity), every write awaited so a refusal reaches the person who made
16
+ it, and teams that each open their stall when they are ready.
17
+
18
+ If the package was created with `--empty`, none of the game is here, only the
19
+ package files: `pnpm run sdk docs view recipes/start-from-an-empty-package.md`
20
+ picks up from there.
21
+
22
+ ## Getting started
23
+
24
+ Dependencies are installed and types generated when the package is created. If
25
+ the install failed, run `pnpm install` once the cause is fixed.
26
+
27
+ ### Play it
28
+
29
+ Start the development server:
30
+
31
+ ```bash
32
+ pnpm start
33
+ ```
34
+
35
+ It opens the facilitator console at `http://localhost:3000`. Open
36
+ `http://localhost:3000/team/1/player/1` in another tab for the first
37
+ participant on team 1, then switch off **Waiting room** in the console to let
38
+ them in. Press the backtick key on any page for the dev drawer: tick, undo, and
39
+ reset controls, and the state as JSON.
40
+
41
+ Edits to logic, UIs, `*.sdk.json` bundles and `seriousgaming.sdk.json` reach
42
+ the running game without a restart. A settings change, which reaches the game
43
+ through `Init`, waits for you to re-initialise once a round has been played:
44
+ the console says so and offers a button.
45
+
46
+ ### Drive it from the CLI
47
+
48
+ ```bash
49
+ pnpm run sdk tick --patch '[{"op":"replace","path":"/plan/Make/lemonade","value":70}]'
50
+ pnpm run sdk view
51
+ ```
52
+
53
+ Session commands act on the running dev server's session. With none running,
54
+ they start one in the background; `pnpm run sdk dev status` and
55
+ `pnpm run sdk dev stop` check on it and stop it. Add `--no-server` to run a
56
+ command in-process against a fresh session instead.
57
+
58
+ ### Build your package
59
+
60
+ Validate, generate types, and bundle the game into `dist/`:
61
+
62
+ ```bash
63
+ pnpm run build
64
+ ```
65
+
66
+ ## Project structure
67
+
68
+ ```
69
+ .
70
+ ├── seriousgaming.sdk.json # The package identifier, locales, maxTicks and teams
71
+ ├── engine/ # THE engine: one day at the stall
72
+ ├── ui/ # THE participant interface: plan, open, review
73
+ ├── session/ # THE session interface: the facilitator's screen
74
+ ├── waiting_room/ # THE holding screen, shown before and between
75
+ ├── guide/ # THE facilitator guide, as markdown chapters
76
+ ├── presentation/ # THE slide deck the facilitator projects (add with `new presentation`)
77
+ ├── setup/ # THE form a facilitator fills in at session creation (`new setup`)
78
+ ├── scenario_editor/ # THE editor for authoring lasting scenarios (`new scenario_editor`)
79
+ ├── capabilities/ # The shape of the game's state
80
+ ├── settings/ # Read-only parameters, each with a default
81
+ ├── validators/ # Reject-only gates on what a surface may write
82
+ ├── hooks/ # Lifecycle handlers, outside the tick
83
+ ├── endpoints/ # Server-side functions a surface calls by name (`new endpoint`)
84
+ ├── scenarios/ # Settings overrides (an ordinary week, a heatwave)
85
+ ├── testing/ # Whole-game tests and Playwright specs
86
+ ├── dist/ # Built output (generated)
87
+ ├── package.json # Package manifest
88
+ └── tsconfig.json # TypeScript configuration
89
+ ```
90
+
91
+ ## Running the tests
92
+
93
+ ```bash
94
+ pnpm test:run # the engine's arithmetic, and every surface
95
+ pnpm test:engine # the whole game, day by day, in-process
96
+ pnpm test:e2e # the surfaces in a browser, against a dev server of its own
97
+ ```
98
+
99
+ `test:e2e` starts an isolated dev server of its own on free ports, so it runs
100
+ beside the one you are working in and leaves that session alone.
101
+
102
+ ## Adding resources
103
+
104
+ ### Create a capability
105
+
106
+ Capabilities define the data the engine and interfaces work with:
107
+
108
+ ```bash
109
+ pnpm run sdk new capability
110
+ ```
111
+
112
+ ### Change the engine or an interface
113
+
114
+ A game holds one engine, one participant interface, one session interface, and
115
+ one waiting room, and the starter game already has each. Edit their code
116
+ directly, and change their bundles with `update`:
117
+
118
+ ```bash
119
+ pnpm run sdk update engine --help
120
+ pnpm run sdk update ui --help
121
+ ```
122
+
123
+ ### The rest
124
+
125
+ `pnpm run sdk new --help` lists every resource type, including validators,
126
+ hooks, endpoints, scenarios, tick controllers, setup, and the scenario editor.
127
+
128
+ A package is a game, so there is no `new game`: the game's locales, ticks and
129
+ teams live in `seriousgaming.sdk.json` beside the package identifier, its
130
+ parameters live in `settings/`, and every resource is discovered from the
131
+ directory it sits in.
132
+
133
+ ## Learn more
134
+
135
+ ```bash
136
+ pnpm run sdk docs view getting-started.md
137
+ pnpm run sdk docs view guides/starter-game.md
138
+ pnpm run sdk docs view recipes/index.md
139
+ ```
140
+
141
+ The same documents are on disk in
142
+ `node_modules/@seriousgaming/sdk-tools/dist/docs/`, and
143
+ describe the SDK version you have installed.
@@ -0,0 +1,26 @@
1
+ ---
2
+ paths:
3
+ - '**/capabilities/**'
4
+ ---
5
+
6
+ # Workflow: Create a capability
7
+
8
+ Capabilities are the data definitions the engine and UIs read from and write to. Use the SDK CLI rather than hand-editing `capability.sdk.json`.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-capability.md
15
+ ```
16
+ 2. **Create the capability** with `pnpm run sdk new capability '{ ... }'`. `definition.identifier` is a short lowercase name (`sales`), which becomes the directory `capabilities/sales/` and the key `context.sales`. The `variablesSchema` must be a full JSON Schema 7 object (`type: 'object'` + `properties` + `required` + `additionalProperties: false`), not a properties-only object. Set `scope` (`team` by default, or `team-readable`, `shared`, `private`) if the capability is not private to each team.
17
+ 3. **Declare it** in the `reads` or `writes` of every resource that uses it (`pnpm run sdk update engine --patch '[...]'`, and so on). A resource is handed only the capabilities it declares.
18
+ 4. **Verify**: `pnpm run build` should pass without type errors. `new` and `update` regenerate types; run `pnpm run generate` yourself only after editing a bundle by hand.
19
+
20
+ ## Things that almost always go wrong
21
+
22
+ - Forgetting to add the capability to a resource's `reads` or `writes`: it is absent from that resource's `context` and generated `Context`
23
+ - Using a properties-only schema: the CLI assumes the full Draft 7 object shape everywhere
24
+ - Putting JSON in a `string`-typed field. Use `object` or `array` types so the generated types stay precise
25
+ - Using an array for something several participants add to at once: the last write wins. Key it by id instead (see `pnpm run --silent sdk docs view recipes/design-state-for-concurrent-writes.md`)
26
+ - A `default` that does not satisfy its own schema: `pnpm run sdk build --validate-only` fails it
@@ -0,0 +1,35 @@
1
+ ---
2
+ paths:
3
+ - '**/endpoints/**'
4
+ ---
5
+
6
+ # Workflow: Create an endpoint
7
+
8
+ Endpoints are named, server-side handlers that user interfaces (and, when its `visibility` is `external`, callers outside the game such as a facilitator's AI agent) invoke by identifier. The author owns the request and response schemas; the runtime validates both, builds a scoped context snapshot from the declared `reads` and `writes`, builds guarded callbacks for the declared `uses`, runs `Handle` (or `Plan` then `Respond`), and returns the response to the caller. An endpoint changes game state only if it declares `writes` or `actions`. Use the SDK CLI to scaffold it rather than hand-editing `endpoint.sdk.json`.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-endpoint.md
15
+ ```
16
+ 2. **Decide the request and response shapes.** Each is a full JSON Schema 7 object (`type: 'object'` + `properties` + `required` + `additionalProperties: false`).
17
+ 3. **Decide what it touches**: which capabilities it `reads`, which it `writes` (if any), which settings resources it reads (`settings`), which runtime callbacks it `uses` (`generateText`, `extractText`, `generateSpeech`, `writeBlob`), which session `actions` it may return (such as advancing a tick or closing the waiting room), whether its `session` argument needs each team's participants (`roster: true`), and its `scope`: `team` (the default: it acts on the calling team's board) or `session` (for a session UI, setup screen, or scenario editor, which has no team of its own).
18
+ 4. **Create the endpoint** with `pnpm run sdk new endpoint '{ ... }'`, declaring `identifier`, `requestSchema`, `responseSchema`, and whichever of `reads`, `writes`, `settings`, `uses`, `actions`, `roster`, `scope`, `visibility`, and `description` apply. An outside caller, such as an AI agent, reads `description` to decide whether to call an external endpoint, so write it for that reader. An external endpoint's `requestSchema` must be `"type": "object"` at the top (`EXTERNAL_REQUEST_NOT_OBJECT`); one taking no input declares an object with no properties.
19
+ 5. **Implement `Handle`** in `endpoints/<name>/logic/logic.ts`. It takes `{ request, context, callbacks, caller, settings, meta, session }`, plus `team` (`{ teamId, index, name }`) on a team-scoped endpoint, which is how it identifies its own team. Without `writes` or `actions` it returns the response alone; otherwise it returns `{ response, capabilities, actions }`, where `capabilities` holds only the capabilities it changed and `actions` only those it declared. To remove a key (one entry of a map), add `deletes: [['orders', 'Open', id]]` beside `capabilities`; each path must sit under a capability in `writes`. The generated `Handler` type switches shape to match, so the compiler tells you which one you owe. An endpoint whose response must describe the state its effects leave (for example the tick it just advanced) exports `Plan` and `Respond` instead of `Handle`, typed with the generated `Planner` and `Responder`: `Plan` returns the effects alone, and `Respond` receives `plan` and `outcomes` after they have landed and returns the response.
20
+ 6. **Allow the UI to call it.** Add the endpoint identifier to the `endpoints` array in the bundle of every UI that should be permitted to call it (`pnpm run sdk update ui --patch '[...]'`). Without this, the host rejects the call and TypeScript flags it. The UI then calls `callbacks.endpoints['<name>'](request)`.
21
+ 7. **Add a unit test** in the scaffolded `endpoints/<name>/logic/logic.test.ts` covering the happy path and any branch in `Handle`.
22
+ 8. **Verify**: `pnpm run sdk endpoint list` shows its scope and whether it writes; `pnpm run --silent sdk endpoint call <name> --no-server --team 1 --request '{...}'` runs it without a UI; then `pnpm run build` and `pnpm test:run`.
23
+
24
+ ## Things that almost always go wrong
25
+
26
+ - Returning a value that does not match `responseSchema`: the runtime rejects it before delivery, and the UI's call rejects with an `EndpointError` of kind `invalid-response`
27
+ - Treating a failed call as one that changed nothing: an `EndpointError` whose `applied` is non-empty means the write and earlier actions landed before a later action failed. Tell the person so, and never retry the call automatically
28
+ - Using a capability not listed in `reads` or `writes`: it is not in `context`
29
+ - Calling a callback not listed in `uses`: the runtime throws
30
+ - Forgetting to add the endpoint identifier to the UI's `endpoints` array: the host rejects every call from that UI
31
+ - Returning a capability outside `writes` in `capabilities`: the whole call fails and none of the change is applied
32
+ - Returning a bare value from an endpoint that declares `writes` or `actions`, or `{ response, capabilities }` from one that declares neither
33
+ - Calling a team-scoped endpoint from a session UI, setup screen, or scenario editor: the build fails. Set `"scope": "session"`
34
+ - Listing an endpoint with `reads`, `writes` or `actions` in the scenario editor: the build fails (`EDITOR_ENDPOINT_STATEFUL`). The editor has no session, so its endpoints read their `settings`, resolved from the scenario being edited, and nothing else
35
+ - Returning binary data inline: declare `'writeBlob'` in `uses`, call `callbacks.writeBlob(bytes, { name, mimeType })`, and return the resulting `blob:<id>` reference in the JSON response
@@ -0,0 +1,35 @@
1
+ ---
2
+ paths:
3
+ - '**/engine/**'
4
+ ---
5
+
6
+ # Workflow: Create or change the engine
7
+
8
+ The engine runs each tick. It reads from capabilities and returns the ones it writes under `capabilities`. A game holds one engine, in the `engine/` slot, so its commands take no identifier. Use the SDK CLI to change its bundle rather than hand-editing `engine.sdk.json`.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-engine.md
15
+ ```
16
+ 2. **Confirm the capabilities exist.** An engine reads and writes capabilities by their short names (`plan`, `results`). Create any that are missing first (see the create-capability workflow).
17
+ 3. **Change or create the bundle.** The starter game already has an engine, so change it with `pnpm run sdk update engine --patch '[...]'` (or a full `update engine '{ ... }'`); `new engine` refuses while `engine/` exists. In an empty package, `pnpm run sdk new engine '{ ... }'`. Declare every capability the engine reads or writes in `reads` / `writes`, and every settings resource it reads in `settings`. A tunable value belongs in a settings resource (`pnpm run sdk new settings`): a full JSON Schema 7 object, with a `default` on every property.
18
+ 4. **Implement `Init` and `Run`** in `engine/logic.ts`. Both are async, both take `{ context, settings, callbacks, meta }`, and both return `{ capabilities: Context }`. Never mutate `context`: always spread. Optionally, return `state` beside `capabilities` for memory only the engine needs between ticks (it comes back as `state`; type it with `RunFunction`'s fourth parameter), and return `complete: true` from `Run` to end the game for that team. A simulation with several steps calls them as plain functions from its one `Run`: type each as `StepFunction<Context, Settings>`, pass the context along flat, and wrap only the final one.
19
+ 5. **Check the types.** `new` and `update` regenerate `engine/types.ts`; run `pnpm run generate` yourself only after editing the bundle by hand.
20
+ 6. **Test it.** Unit tests go in `engine/logic.test.ts`, covering at least the happy path and every branch in `Run`. Whole-game behaviour across several ticks goes in `testing/engine/` and runs with `pnpm test:engine`.
21
+ 7. **Verify**: `pnpm run build`, `pnpm test:run`, `pnpm test:engine`, and `pnpm run --silent sdk tick --no-server`, which runs the logic in the restricted production runtime. A running dev server picks up the edit from its next tick, without a reset.
22
+
23
+ ## Things that almost always go wrong
24
+
25
+ - Using a capability that is not declared in `reads` / `writes`: it is absent from `context` and from the generated `Context`
26
+ - Mutating `context` directly instead of returning a fresh object via spread
27
+ - Returning the capabilities flat (`{ ...context }`) instead of under `capabilities`: the runtime fails the call
28
+ - Trying to remove a map entry by leaving it out of `capabilities`: a key you leave out keeps its value. Return its path in `deletes` beside `capabilities` instead (`deletes: [['orders', 'Open', id]]`), under a capability in `writes`
29
+ - Using a host global (`structuredClone`, `setTimeout`, `fetch`, `crypto`): production logic runs in a bare V8 isolate. `pnpm run lint` catches most of them
30
+ - Importing a Node built-in (`node:fs`, `path`, `os`, and so on), directly or through a library: the build, `dev` and `tick` refuse it with `LOGIC_NODE_BUILTIN`
31
+ - Using `Math.random()` for anything you keep: derive it from `meta.seed` with `deriveSeed` and `seededRandom`, since a tick may run more than once
32
+ - Calling `Date.now()` or `new Date()`: read `meta.now`, the instant the operation started, which every team's `Run` in one tick and a re-run of it share
33
+ - Keeping a roster in context from `participantJoin` hooks: `Init`, `Run` and the tick controller receive `participants`, the team's roster as the tick started
34
+ - Expecting an edit to replay the ticks already played: a logic edit changes the next tick only. Undo and tick again, or reset to re-run `Init`
35
+ - Using `any` in engine signatures instead of the generated `Context` and `Settings` types
@@ -0,0 +1,40 @@
1
+ ---
2
+ paths:
3
+ - '**/guide/**'
4
+ ---
5
+
6
+ # Workflow: Create a facilitator guide
7
+
8
+ Facilitator guides are content, not code: per-locale markdown chapters plus shared images, rendered natively on the facilitator's page. A game holds one guide, in the `guide/` slot, so its commands take no identifier. Scaffold it with the SDK CLI rather than hand-creating the bundle file.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-guide.md
15
+ ```
16
+ 2. **Create or change the guide.** The starter game already has one, so edit its chapters directly and change its bundle with `pnpm run sdk update guide`; `new guide` refuses while `guide/` exists. In an empty package, `pnpm run sdk new guide '{ ... }'`. Declare every locale up front: the scaffold creates a chapter skeleton per declared locale, and the per-locale `name` is the title the host renders.
17
+ 3. **Write the chapters** in `guide/content/<locale>/`. Chapters are ordered by file name (number them `01-`, `02-`, …) and file names must be identical across locales.
18
+ 4. **Validate**: `pnpm run sdk build --validate-only`. This warns on missing translations and fails on malformed video blocks or image references that do not resolve. There is nothing to wire: a `guide/` directory beside `seriousgaming.sdk.json` is served.
19
+
20
+ ## Content format
21
+
22
+ - Admonitions are container directives: `:::note`, `:::warning`, `:::tip`, plus the facilitation-specific `:::say`, `:::do`, and `:::timing`. Unknown types render as error blocks
23
+ - Headings build the table of contents (chapter H1 plus H2 to H3); end a heading with `{-}` to omit it
24
+ - Images go in the shared `assets/` directory, referenced relatively (`../../assets/diagram.png` from a chapter)
25
+ - Video embeds are fenced `video` blocks validated against a closed registry (YouTube only):
26
+ ````markdown
27
+ ```video
28
+ provider: youtube
29
+ id: dQw4w9WgXcQ
30
+ ```
31
+ ````
32
+ - Raw HTML never renders: it is escaped to visible text. Use markdown, admonitions, and video blocks only
33
+
34
+ ## Things that almost always go wrong
35
+
36
+ - Chapter file names differing between locales: the runtime matches chapters by file name, so a renamed translation is treated as missing and falls back
37
+ - Invalid YouTube ids: the id must match the 11-character format exactly; anything else renders an inert error block
38
+ - Writing HTML for layout: it will appear as escaped text. Tables, admonitions, and images cover the supported layouts
39
+ - Breaking the structure `guide/guide.test.ts` checks (in the starter game): run `pnpm test:run` after editing chapters
40
+ - A guide a new facilitator could not run the session from alone: if a step lives only in the designer's head, write it down
@@ -0,0 +1,37 @@
1
+ ---
2
+ paths:
3
+ - '**/presentation/**'
4
+ ---
5
+
6
+ # Workflow: Create or change the presentation
7
+
8
+ The presentation is the facilitator's slide deck, shown on their screen and projected to the room. A game holds one, in the `presentation/` slot, so its commands take no identifier. It is read-only: it declares `reads` and `settings`, never `writes`, `uses` or `endpoints`. It is built with `@seriousgaming/deck` (`Deck`, `Slide`, `Step`, and the building blocks `Heading`, `Text`, `Bullets`, `Table`, `Image` and `Chart`).
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-presentation.md
15
+ ```
16
+ 2. **Check the deck library is installed.** `package.json` must list `@seriousgaming/deck` at the same version as `@seriousgaming/sdk`. If it does not, add it at that version before anything else
17
+ 3. **Create or change the bundle.** In a package without one, `pnpm run sdk new presentation '{ ... }'`. Otherwise change its `reads` and `settings` with `pnpm run sdk update presentation --patch '[...]'`, then `pnpm run sdk generate`
18
+ 4. **Write the slides** in `presentation/src/`. Every element of the slides array is one slide; give each a stable `key`
19
+ 5. **Check both ways it is shown**: `/presentation` during a session and `/presentation?preview` with none, once the user has started `pnpm run sdk dev`. Then `pnpm run build`
20
+
21
+ ## Habits that keep an export faithful
22
+
23
+ A facilitator exports the deck and edits the PowerPoint, where words are editable and visuals are pictures. `pnpm run --silent sdk docs view guides/presentation.md` explains each habit; hold to them:
24
+
25
+ - **Use the building blocks** (`Heading`, `Text`, `Bullets`, `Table`) for anything a facilitator might edit
26
+ - **Render with `session === null`**, showing labelled sample figures where results would go
27
+ - **Branch on settings, not the scenario name**
28
+ - **Draw a custom animation's end state** when `useSlide().mode` is `'static'`
29
+ - **Route every word through i18n**, and keep one element per slide
30
+
31
+ ## Things that almost always go wrong
32
+
33
+ - Reading `session.data` without checking `session` first: the no-session preview breaks
34
+ - A slide that comes and goes with a setting but has no `key`: the remembered position lands on the wrong slide
35
+ - Branching on `game.scenarioName`: the deck shows the wrong slides for a facilitator's saved scenario
36
+ - A chart or diagram drawn as text the facilitator expects to edit: it exports as a picture, so put the words they will change in a `Text` or `Table` beside it
37
+ - A word written straight into a slide rather than added to `src/i18n.ts`: it stays in English whatever the session's language
@@ -0,0 +1,31 @@
1
+ ---
2
+ paths:
3
+ - '**/ui/**'
4
+ ---
5
+
6
+ # Workflow: Create or change a user interface
7
+
8
+ A user interface is a React app that reads game state and (optionally) sends decisions back via `setData`. A game holds one participant interface, in the `ui/` slot, so its commands take no identifier; `session/` and `waiting_room/` are the facilitator's screen and the holding screen, and work the same way. Use the SDK CLI to change a bundle rather than hand-editing `ui.sdk.json`.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Read the full recipe** before you start:
13
+ ```bash
14
+ pnpm run --silent sdk docs view recipes/create-user-interface.md
15
+ ```
16
+ 2. **Confirm the capabilities exist.** A UI reads (and optionally writes) capabilities by their short names. Create any that are missing first.
17
+ 3. **Change or create the bundle.** The starter game already has a `ui/`, so change it with `pnpm run sdk update ui --patch '[...]'`; `new ui` refuses while `ui/` exists. In an empty package, `pnpm run sdk new ui '{ ... }'`. Declare every capability the UI shows in `reads`, and add `writes` only for the ones it sends back via `setData`. A UI receives exactly what it declares.
18
+ 4. **Implement the components** under `ui/src/` (the entry component is `App.tsx`), with `useUserInterfaceData()` for `data`, `settings`, `setData` and `completedTicks`. Default to MUI; another library must integrate with `useUserInterfaceTheme` so dark mode and colour palettes work, and text on a theme colour uses that colour's `contrastText`. Remember a viewer's own choices with `useViewerStorage`, never `localStorage`. Put every string in `src/i18n.ts`. `pnpm run --silent sdk docs view guides/ui.md` is the reference for every hook.
19
+ 5. **Await every write.** `setData` returns a promise that rejects when the host refuses the write. Route writes through `useMutationReporter`, as the starter game's `ui/src/writes.ts` does, so the participant sees the refusal. Never retry a write automatically: on a `conflict` the host has already retried and given up, so offer `failure.retry` behind a 'Try again' button instead.
20
+ 6. **Add a test** beside the component (`App.test.tsx`), rendered with `renderUserInterface()` (or `renderSessionUserInterface<SessionData>()`, `renderSettingsEditor()`) from `@seriousgaming/sdk/ui/testing`, as the starter game's tests do. `pnpm run --silent sdk docs view guides/testing.md` has the harness.
21
+ 7. **Verify**: `pnpm run build` and `pnpm test:run`. A running dev server hot-reloads the UI. The user starts the dev server (`pnpm run sdk dev`) when they want to see it; never start it yourself.
22
+
23
+ ## Things that almost always go wrong
24
+
25
+ - Mocking the SDK contexts with `vi.mock`, or wiring a few providers by hand: the hand-wired version throws once the component uses callbacks or participants. Use `renderUserInterface()` instead, so the component renders as it does in production
26
+ - Forgetting `useUserInterfaceTheme` integration when using a non-MUI styling solution: the UI renders in the wrong colour scheme
27
+ - Writing a capability that is not declared in `writes`: `setData` for it is refused
28
+ - Calling `setData` without awaiting it: a refused write leaves the participant looking at a decision the game never received
29
+ - Expecting the engine's settings to reach the UI: a UI's `settings` holds only the settings resources the UI itself lists in `settings`, never those the engine lists, even for an engine whose capability it reads. List the settings resource in the UI's `settings` too, or write the value into context from the engine and read it via `data`
30
+ - Calling an LLM from the UI: a UI reaches external services only through an endpoint it lists in its `endpoints` array
31
+ - Using `userEvent.type` on controlled inputs in tests: the mock `setData` does not propagate, so the input value never updates between keystrokes. Use `fireEvent.change`
@@ -0,0 +1,54 @@
1
+ ---
2
+ paths:
3
+ - 'seriousgaming.sdk.json'
4
+ ---
5
+
6
+ # Workflow: Publish this package
7
+
8
+ `pnpm run sdk package publish` builds (if needed), bundles, and uploads this package to the Serious Gaming platform. Uploads are scoped to a publisher, so the command needs both an API key and a publisher slug.
9
+
10
+ ## Before you publish
11
+
12
+ You need:
13
+
14
+ - An API key (`sg_<lookupId>_<secret>`), issued from your organisation's settings page by an account with publishing access. Business Simulations grants that access; if the user's account lacks it, `publish` fails with a 403 and only they can ask for it
15
+ - The slug of the publisher you upload under
16
+ - A bumped version: the platform rejects re-uploads of a version that already exists
17
+
18
+ ## Order of operations
19
+
20
+ 1. **Configure the key and publisher once.** Either put them in `.env` in this directory (and keep `.env` git-ignored):
21
+ ```bash
22
+ SERIOUSGAMING_API_KEY=sg_your_lookup_id_your_secret
23
+ SERIOUSGAMING_PUBLISHER=your-publisher-slug
24
+ ```
25
+ Or have the user store them in the global settings file, so every project picks them up (this writes to their home directory, so leave it to them):
26
+ ```bash
27
+ pnpm run sdk config set platform.apiKey sg_your_lookup_id_your_secret
28
+ pnpm run sdk config set platform.defaultPublisher your-publisher-slug
29
+ ```
30
+ 2. **Bump the version** (the platform rejects a duplicate):
31
+ ```bash
32
+ pnpm run sdk package version patch
33
+ ```
34
+ 3. **Build and publish**:
35
+ ```bash
36
+ pnpm run sdk build
37
+ pnpm run sdk package publish
38
+ ```
39
+ The command runs `package bundle` itself when the zip is missing. On success it prints the hosted `PackageVersionResponse`.
40
+ 4. **Capture the result in CI** with `--json`. The envelope's `data` is the `PackageVersionResponse`, and a failure carries a code: `PLATFORM_UNAUTHORISED` (exit 5), `VERSION_EXISTS` or `PLATFORM_REJECTED` (exit 3):
41
+ ```bash
42
+ pnpm run --silent sdk package publish --json > publish.json
43
+ ```
44
+
45
+ ## Resolution and overrides
46
+
47
+ The publisher slug resolves from (highest priority first): `--publisher <slug>`, the `SERIOUSGAMING_PUBLISHER` env var, then `platform.defaultPublisher` in global settings. The API key and the host follow the same order: the flag (`--api-key`, `--host`), then the environment (`SERIOUSGAMING_API_KEY`, `SERIOUSGAMING_API_HOST`, from the shell or `.env`), then global settings (`platform.apiKey`, `platform.apiHost`). The default host is `https://app.businesssimulations.com`; override it with `--host` or `SERIOUSGAMING_API_HOST` for a staging target.
48
+
49
+ ## Things that almost always go wrong
50
+
51
+ - **No publisher configured.** The command fails rather than guessing. Set `SERIOUSGAMING_PUBLISHER`, pass `--publisher`, or set `platform.defaultPublisher`
52
+ - **Uploading under the wrong publisher.** The first upload binds this package to a publisher; later versions must use the same one or you get a 400 naming the registered publisher. Do not switch publishers to dodge the error
53
+ - **Version already exists (409).** Bump with `pnpm run sdk package version patch` and retry
54
+ - **Committing the API key.** Keep it in `.env` (git-ignored) or the global settings file, never in tracked source or shell history
@@ -0,0 +1,30 @@
1
+ ---
2
+ paths:
3
+ - '**/*.test.ts'
4
+ - '**/*.test.tsx'
5
+ ---
6
+
7
+ # Workflow: Test an engine or user interface
8
+
9
+ Unit and component tests live next to the source they cover: the engine's `engine/logic.test.ts` beside `engine/logic.ts`, a hook's, validator's, or endpoint's `logic/logic.test.ts` beside its `logic.ts`, and a UI's `*.test.tsx` beside its components. `pnpm test:run` runs them all. Whole-game tests live in `testing/engine/` and run with `pnpm test:engine`; Playwright specs live in `testing/e2e/` and run with `pnpm test:e2e`.
10
+
11
+ ## Order of operations
12
+
13
+ 1. **Read the full recipe** that matches what you're testing:
14
+ ```bash
15
+ pnpm run --silent sdk docs view recipes/test-user-interface.md # for UI components
16
+ pnpm run --silent sdk docs view recipes/test-with-engine.md # for whole games across several ticks
17
+ ```
18
+ 2. **For logic**, call `Init`, `Run`, a hook, an endpoint or a validator directly with arguments built by `logicArgs` from `@seriousgaming/sdk/testing` (`logicArgs.run({ context, settings: defaultSettings })`), and assert on the returned `capabilities`. For behaviour across several ticks, hooks, validators, endpoints, participants, undo or automatic ticks, use `createTestSession<Context, SharedContext>` in `testing/engine/`: it runs the session the dev server runs, in-process, with offline stubs for `generateText`, `generateSpeech` and `extractText`. The references are `pnpm run --silent sdk docs view guides/testing.md` and `guides/engine-testing.md`.
19
+ 3. **For UI components**, render with `renderUserInterface()` (or `renderSessionUserInterface()`, or `renderSettingsEditor()` for setup and the scenario editor) from `@seriousgaming/sdk/ui/testing`, which supplies every provider the host does. Never `vi.mock` the SDK contexts, and never wire the providers by hand. For a session UI, pass the generated types: `renderSessionUserInterface<SessionData>()`, with fixtures from `createMockTeamState<TeamContext>()` and `createMockSharedState<SharedContext>()`, so a shared capability left on a team fixture fails to compile.
20
+ 4. **Cover the branches.** One test per code path: the happy path plus each failure mode, each option flag, each conditional in `Run`.
21
+ 5. **Run the tests**: `pnpm test:run` and `pnpm test:engine`. `pnpm test` is watch mode, so leave it to the user. `pnpm test:e2e` starts an isolated dev server of its own on free ports (`testing/e2e/global-setup.ts`), beside any the user has running.
22
+
23
+ ## Things that almost always go wrong
24
+
25
+ - Mocking the SDK contexts with `vi.mock` instead of wrapping with the real providers: the test now exercises the mock, not the component
26
+ - Using `userEvent.type` on controlled inputs: the mock `setData` does not propagate, so subsequent keystrokes see the original value. Use `fireEvent.change`
27
+ - Asserting on internal implementation (props, state) instead of observable output (rendered text, `setData` arguments)
28
+ - Taking a green unit test as proof the logic runs in production: tests run in Node, where host globals exist. `pnpm run --silent sdk tick --no-server` runs a tick in the restricted runtime
29
+ - Casting arguments (`as never`, `{} as Callbacks`) or a session's context: `logicArgs` and the typed session make every cast unnecessary, and a cast hides the shape error the test exists to catch
30
+ - Skipping a test for a new resource: the scaffold creates the test file for a reason
@@ -0,0 +1,43 @@
1
+ ---
2
+ paths:
3
+ - 'package.json'
4
+ ---
5
+
6
+ # Workflow: Update the SDK version
7
+
8
+ The SDK ships as three npm packages: `@seriousgaming/sdk` (runtime), `@seriousgaming/sdk-tools` (CLI and dev server), and `@seriousgaming/deck` (the presentation's deck library). Update them in lockstep and read the changelog before rebuilding.
9
+
10
+ ## Order of operations
11
+
12
+ 1. **Check the installed version**:
13
+ ```bash
14
+ pnpm run --silent sdk version
15
+ ```
16
+ 2. **Read the changelog** for everything released since that version:
17
+ ```bash
18
+ pnpm run sdk docs view changelog.md
19
+ ```
20
+ Pay particular attention to any **Breaking Changes** section. If there are breaking changes, plan how to address them before bumping, and read `pnpm run sdk docs view guides/upgrading.md` too. The docs describe the installed version, so read the new changelog again after step 3.
21
+ 3. **Bump all three packages** together. The SDK and its tools are dev dependencies, so keep `-D`; the deck library is a runtime dependency of the presentation and must stay at the same version as the SDK:
22
+ ```bash
23
+ pnpm add -D @seriousgaming/sdk@latest @seriousgaming/sdk-tools@latest
24
+ pnpm add @seriousgaming/deck@latest
25
+ ```
26
+ The package also lists `@seriousgaming/sdk` under `peerDependencies`; move that range to match.
27
+ 4. **Regenerate types**: `pnpm run generate`. New schema fields, renames, or removed fields all surface through the generated `types.ts` files.
28
+ 5. **Build and address breakages**: `pnpm run build`. Work through type errors and address each Breaking Changes entry from step 2.
29
+ 6. **Run the test suites**: `pnpm test:run` and `pnpm test:engine`.
30
+ 7. **Adopt updated scaffold guidance**. New packages are scaffolded with the latest `CLAUDE.md` and `.claude/rules/`, but this package keeps whatever it was scaffolded with. The new version ships its templates inside the installed package, so both sides of the diff are on disk. Check three places and fold in anything relevant:
31
+ 1. The changelog entries between the old and new version (from step 2): anything mentioning scaffold, guidance, rules, or `CLAUDE.md` is a candidate to adopt.
32
+ 2. The shipped rules in `node_modules/@seriousgaming/sdk-tools/dist/templates/package/claude/rules/` against the local `.claude/rules/`: copy rule files that don't exist locally; for rules that do exist, diff the two and incorporate new guidance while keeping local edits.
33
+ 3. The shipped `node_modules/@seriousgaming/sdk-tools/dist/templates/package/CLAUDE.md.template` against the local `CLAUDE.md`: incorporate new advice carefully.
34
+
35
+ The templates are the source of new guidance; the local files are the source of local truth. Propose the merge as a normal reviewable change, skip anything that isn't relevant to this package, and never overwrite local content wholesale. The goal is adoption, not a reset.
36
+
37
+ ## Things that almost always go wrong
38
+
39
+ - Bumping only some of the three packages: the runtime and the CLI must agree on the schema, and the deck must match the SDK
40
+ - Skipping the changelog read: breaking changes silently corrupt resources or fail validation later
41
+ - Forgetting `pnpm run generate` after the upgrade: types stay stale and downstream code compiles against the old shape
42
+ - Leaving `package.json` scripts, `pnpm-workspace.yaml`, or the config files behind: the new version's `dist/templates/package/` holds the current copies to compare against
43
+ - Skipping the scaffold guidance check: the package quietly stays on outdated advice and never gains rules added after it was scaffolded
@@ -0,0 +1,16 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(pnpm run generate)",
5
+ "Bash(pnpm run --silent sdk build --validate-only:*)",
6
+ "Bash(pnpm run --silent sdk view:*)",
7
+ "Bash(pnpm run --silent sdk tick:*)",
8
+ "Bash(pnpm run --silent sdk init:*)",
9
+ "Bash(pnpm run --silent sdk docs view:*)",
10
+ "Bash(pnpm test:run:*)",
11
+ "Bash(pnpm test:engine:*)",
12
+ "Bash(pnpm run typecheck)",
13
+ "Bash(pnpm run lint)"
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,15 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # The dev server's local state: settings overrides, session state and uploaded files
8
+ .seriousgaming-sdk/
9
+
10
+ # Playwright results and reports
11
+ test-results/
12
+ playwright-report/
13
+
14
+ # Local environment
15
+ .env
@@ -0,0 +1,21 @@
1
+ import { dirname } from 'path';
2
+
3
+ import type { FullConfig } from '@playwright/test';
4
+ import { startDevServer } from '@seriousgaming/sdk-tools/client';
5
+
6
+ /**
7
+ * Start the dev server the browser tests run against, and stop it after them.
8
+ *
9
+ * It is the server `sdk dev --isolated --port auto` runs: on free ports, with
10
+ * no lock file, and configured from the package alone, so it starts beside
11
+ * your own dev server and every run begins from the same place. Running it in
12
+ * this process rather than spawning `sdk dev` means stopping it is a call,
13
+ * which a run cannot hang on.
14
+ */
15
+ export default async function globalSetup(config: FullConfig): Promise<() => Promise<void>> {
16
+ const server = await startDevServer({
17
+ packagePath: config.configFile ? dirname(config.configFile) : process.cwd(),
18
+ });
19
+ process.env.SERIOUSGAMING_DEV_URL = server.url;
20
+ return () => server.stop();
21
+ }
@@ -0,0 +1,2 @@
1
+ // Ambient module declarations for CSS-only packages that ship no types.
2
+ declare module '@fontsource-variable/*';
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "./node_modules/oxfmt/configuration_schema.json",
3
+ "ignorePatterns": ["**/*.sdk.json", "seriousgaming.sdk.json", "**/types.ts"],
4
+ "semi": true,
5
+ "trailingComma": "es5",
6
+ "singleQuote": true,
7
+ "printWidth": 100,
8
+ "tabWidth": 4,
9
+ "useTabs": false,
10
+ "experimentalSortImports": {
11
+ "ignoreCase": true
12
+ },
13
+ "experimentalSortPackageJson": true
14
+ }