@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,46 @@
1
+ /**
2
+ * Translator for blob references in a configuration tree.
3
+ *
4
+ * `blob:*` → `asset:*`: read runtime blob bytes and materialise them as a
5
+ * file under the package scenario assets directory. Used when saving a
6
+ * runtime configuration as a package scenario bundle (issue #101).
7
+ *
8
+ * The walker is shape-agnostic: it traverses any nested record / array
9
+ * structure and replaces string values that match a known reference prefix.
10
+ * Other primitives pass through unchanged.
11
+ */
12
+ /**
13
+ * Translate a single reference string. Returns the new reference, or the
14
+ * original string when the reference does not apply.
15
+ */
16
+ export type ReferenceTranslator = (reference: string) => Promise<string>;
17
+ /**
18
+ * Build the blob-to-asset translator used by the author-time save flow. Reads
19
+ * each `blob:*` reference from the dev server's blob store, writes the bytes
20
+ * as a file under the target scenario's assets directory, and returns the
21
+ * resulting `asset:<relative-path>` reference.
22
+ *
23
+ * `asset:*` references are returned unchanged when
24
+ * `copyExistingAssets === false` (default). When true, the bytes are read
25
+ * from the source scenario root and re-materialised under the target assets
26
+ * directory — used for save-as-new flows that need a fully self-contained
27
+ * copy of a different scenario's assets.
28
+ *
29
+ * Materialised files are written under `<assetsSubdirectory>/` (default
30
+ * `shared`) inside the target assets directory, matching the layout that
31
+ * `createScenarioFiles` scaffolds for hand-authored scenarios.
32
+ */
33
+ export declare function createBlobToAssetTranslator(opts: {
34
+ packagePath: string;
35
+ sourceScenarioRootDirectory: string | null;
36
+ targetAssetsDirectory: string;
37
+ assetsSubdirectory?: string;
38
+ copyExistingAssets?: boolean;
39
+ }): ReferenceTranslator;
40
+ /**
41
+ * Walk a configuration tree and translate every asset-reference string in
42
+ * place using the supplied translator. Returns a new value; the input is not
43
+ * mutated. Strings that are not asset references (per `isAssetReference`) are
44
+ * passed through unchanged.
45
+ */
46
+ export declare function translateAssetReferences<T>(value: T, translate: ReferenceTranslator): Promise<T>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Time, as a port.
3
+ *
4
+ * Every timing decision the runtime makes reads the clock through this
5
+ * interface: the automatic tick schedule (§11.2), the 30-second floor and
6
+ * 7-day ceiling on the effective cadence (§11.8), the per-tick execution bound
7
+ * (§11.10), and pause and resume.
8
+ *
9
+ * The point is testability. A 7-day ceiling asserted against the real clock is
10
+ * either untestable or a test that lies by shortening the bound it claims to
11
+ * check; against {@link FakeClock} it is exact and takes microseconds. It is
12
+ * also the difference between a suite that is slow and flaky on a loaded
13
+ * machine and one that is neither, which is most of why the current
14
+ * `tick-timer.ts` needs 566 lines to express a small amount of behaviour.
15
+ */
16
+ /** Cancels a scheduled callback. Idempotent. */
17
+ export interface Cancellable {
18
+ cancel(): void;
19
+ }
20
+ export interface Clock {
21
+ /** Milliseconds since the epoch. */
22
+ now(): number;
23
+ /** Run `fn` after at least `ms`. */
24
+ schedule(fn: () => void, ms: number): Cancellable;
25
+ }
26
+ /** The real clock. The only implementation that reaches a host timer. */
27
+ export declare const systemClock: Clock;
28
+ /**
29
+ * A clock a test drives by hand.
30
+ *
31
+ * Time only moves when {@link advance} or {@link set} is called, so a test
32
+ * states the passage of time it means rather than waiting for it.
33
+ */
34
+ export declare class FakeClock implements Clock {
35
+ private current;
36
+ private nextId;
37
+ private scheduled;
38
+ constructor(startAt?: number);
39
+ now(): number;
40
+ schedule(fn: () => void, ms: number): Cancellable;
41
+ /** How many callbacks are waiting. */
42
+ get pending(): number;
43
+ /** When the soonest waiting callback is due, or null when none is. */
44
+ get nextDueAt(): number | null;
45
+ /**
46
+ * Move time forward by `ms`, running everything that comes due.
47
+ *
48
+ * Callbacks run in due order, and time is set to each one's due instant
49
+ * before it runs, so a callback that reschedules measures from when it
50
+ * actually fired rather than from the end of the whole advance.
51
+ */
52
+ advance(ms: number): void;
53
+ /** Move time to `timestamp`, running everything that comes due. */
54
+ set(timestamp: number): void;
55
+ /** Drop every scheduled callback without running any. */
56
+ clear(): void;
57
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Deliberately reproducing the failures this runtime cannot otherwise produce.
3
+ *
4
+ * §9.7 names two conformant serialisation strategies. This runtime uses the
5
+ * first, full serialisation, and the platform uses the second, optimistic
6
+ * concurrency. Both are correct, and §12.5.1 spells out what follows: *'a
7
+ * runtime that fully serialises writes against ticks will never emit
8
+ * `conflict`'*.
9
+ *
10
+ * So an author's UI will never receive a `conflict` outcome in development and
11
+ * will in production. The retry path they were told to write is the one path
12
+ * development structurally cannot exercise, and the same is true of a hook chain
13
+ * throwing (§14.5), an LLM call failing (§17), and a write denied after a
14
+ * participant move (§13.2).
15
+ *
16
+ * Arming a fault is the design rule of the redesign applied to failures: every
17
+ * runtime state is reachable by an explicit control, and none only by
18
+ * re-enacting the circumstances that produce it. Faults are armed by name, fire
19
+ * once, and are reproducible, so an agent can verify a game's error handling
20
+ * without having to manufacture a race.
21
+ */
22
+ import type { ArmedFault, FaultKind } from '@seriousgaming/sdk/projection';
23
+ export type { ArmedFault, FaultKind };
24
+ export declare const FAULT_KINDS: readonly FaultKind[];
25
+ export declare function isFaultKind(value: unknown): value is FaultKind;
26
+ /**
27
+ * The armed faults for one session.
28
+ *
29
+ * Deliberately not random. A fault fires a stated number of times and is then
30
+ * spent, so the same sequence of operations produces the same failures, which
31
+ * is what makes a failure reproducible enough to fix.
32
+ */
33
+ export declare class FaultInjector {
34
+ private armed;
35
+ /**
36
+ * Arm a fault to fire the next `times` occasions it is consulted.
37
+ *
38
+ * Arming a kind that is already armed replaces it rather than adding to it:
39
+ * an operator who clicks twice means 'do it', not 'do it twice'.
40
+ */
41
+ arm(kind: FaultKind, options?: {
42
+ times?: number;
43
+ reason?: string;
44
+ }): ArmedFault;
45
+ /** Disarm one kind. Returns true when something was armed. */
46
+ disarm(kind: FaultKind): boolean;
47
+ /** Disarm everything. */
48
+ disarmAll(): void;
49
+ /** What is armed, for the state projection. */
50
+ list(): ArmedFault[];
51
+ /** Whether `kind` would fire, without consuming it. */
52
+ isArmed(kind: FaultKind): boolean;
53
+ /**
54
+ * Consume one occasion of `kind`, reporting whether it fires.
55
+ *
56
+ * Call this at the point the real failure would occur, so an armed fault
57
+ * exercises the same code path the genuine one would.
58
+ */
59
+ shouldFire(kind: FaultKind): boolean;
60
+ /**
61
+ * {@link shouldFire}, returning the fault that fired, so the failure it
62
+ * stands in for can carry the operator's `reason`.
63
+ */
64
+ fire(kind: FaultKind): ArmedFault | undefined;
65
+ }
@@ -0,0 +1,65 @@
1
+ import type { GameSettingConstraint, GameSettings, GameSettingsConstraints, PackageManifest, SDKSettings } from '@seriousgaming/sdk';
2
+ /**
3
+ * The game-level settings: the built-in settings resource every game has.
4
+ *
5
+ * The number of rounds, the team bounds and names, and whether the waiting
6
+ * room opens with the session used to be a closed set of manifest fields a
7
+ * scenario could vary and a session could not. They are an ordinary settings
8
+ * resource now, under the reserved identifier `game`: the SDK owns its schema,
9
+ * the manifest's values are its defaults, and a scenario or a session
10
+ * overrides it by identifier, through the one resolver every setting goes
11
+ * through (SPECIFICATION.md §6.10, §8.2). A new game-level setting is a new
12
+ * property of that schema, and needs nothing else.
13
+ *
14
+ * `teams.mode` is deliberately not in it: §5.2 fixes the interaction mode at
15
+ * authoring time, because a game that needs both topologies ships as two.
16
+ */
17
+ export declare const GAME_SETTINGS = "game";
18
+ type DeepRequired<T> = T extends readonly unknown[] ? T : T extends object ? {
19
+ [K in keyof T]-?: DeepRequired<T[K]>;
20
+ } : T;
21
+ /** The `game` settings as they resolve: every property present. */
22
+ export type ResolvedGameSettings = DeepRequired<GameSettings>;
23
+ /** The manifest fields whose values are the `game` settings' defaults. */
24
+ export type GameSettingsSource = Pick<PackageManifest, 'maxTicks' | 'teams' | 'waitingRoom' | 'gameSettingsConstraints'>;
25
+ /** The game's own values for its `game` settings, from its manifest. */
26
+ export declare function gameSettingsDefaults(manifest: GameSettingsSource): ResolvedGameSettings;
27
+ /**
28
+ * The built-in `game` settings resource for a game: the SDK's schema with the
29
+ * game's values as its defaults, at every level, so a resolved value is
30
+ * complete however little of it an override names, and with the game's
31
+ * `gameSettingsConstraints` merged in, so a runtime sees one ordinary schema.
32
+ */
33
+ export declare function gameSettingsResource(manifest: GameSettingsSource): SDKSettings;
34
+ /** The constraint on each `game` setting a game narrows, by dotted path. */
35
+ export declare function gameSettingConstraints(constraints: GameSettingsConstraints | undefined): Map<string, GameSettingConstraint>;
36
+ /**
37
+ * Whether a game is single-team (§5.3): its `game` settings fix `teams.max`
38
+ * at 1, the default 1 and the value read-only. A maximum of 1 that a scenario
39
+ * or session could raise is no more single-team than an omitted one.
40
+ */
41
+ export declare function teamsMaxOf(schema: unknown): {
42
+ max: number | null;
43
+ locked: boolean;
44
+ };
45
+ /**
46
+ * The `game` settings out of a resolution. A resolution always carries them,
47
+ * since every package has the resource; the neutral values stand in only for
48
+ * a configuration built by hand, as some tests build one.
49
+ */
50
+ export declare function gameSettingsOf(resolved: Record<string, Record<string, unknown>>): ResolvedGameSettings;
51
+ /**
52
+ * The game's own values for its `game` settings, as the package declares them:
53
+ * the defaults of its built-in resource. What a build checks scenarios
54
+ * against, having no session.
55
+ */
56
+ export declare function declaredGameSettings(schema: unknown): ResolvedGameSettings;
57
+ /**
58
+ * Why a session-layer override of the `game` settings is refused, or null
59
+ * when it is not. `waitingRoom.openOnStart` seeds the waiting-room flag as
60
+ * the session is created, before any setup step runs, so a session-layer
61
+ * value would be read by nothing; refusing it says so where an inert override
62
+ * would read as applied (§6.14.4, §8.2).
63
+ */
64
+ export declare function gameOverrideRefusal(overrides: unknown): string | null;
65
+ export {};
@@ -0,0 +1,89 @@
1
+ /**
2
+ * HistoryManager - the closed rounds of one team, or of one session.
3
+ *
4
+ * A snapshot is the board as it stood **when a tick was submitted**, captured
5
+ * before that tick's engine run consumed it. Snapshot `k` is therefore the
6
+ * close of round `k + 1`: it carries tick `k`'s outcomes and everything the
7
+ * team then did with them. Written post-`Run`, it would carry the outcomes and
8
+ * none of the decisions, and any value the next tick cleared would never be
9
+ * observable in any snapshot at all.
10
+ *
11
+ * The head is never in here. A team at tick `N` has snapshots 0 to `N - 1` and
12
+ * holds round `N + 1`'s board in live state, which is where every surface reads
13
+ * it from. So history holds exactly the reviewable rounds, and the tick a
14
+ * snapshot is labelled with is its position in the array.
15
+ */
16
+ export interface ContextSnapshot {
17
+ tick: number;
18
+ context: Record<string, unknown>;
19
+ /** All team contexts when running in multi-team mode */
20
+ teamContexts?: Record<string, unknown>[];
21
+ /**
22
+ * Stable team index for each entry of `teamContexts`. Indexes survive
23
+ * removals (positions shift, indexes do not), so snapshots written after
24
+ * a removal can have gaps. Absent in snapshots from older SDK versions,
25
+ * where the index is the array position.
26
+ */
27
+ teamIndexes?: number[];
28
+ recordedAt: number;
29
+ }
30
+ export declare class HistoryManager {
31
+ private snapshots;
32
+ /**
33
+ * Position of the newest snapshot, or -1 when there is none. Equal to the
34
+ * owner's tick minus one, because a tick writes the round it closed.
35
+ *
36
+ * Undo walks it down without truncating, so the entries above it are ticks
37
+ * that have been rewound: still present, so a later push can reuse the
38
+ * array, and reviewable by nobody.
39
+ */
40
+ private currentIndex;
41
+ /**
42
+ * Where this team started, before any round. Not a snapshot: the post-`Init`
43
+ * board closed no round, and putting it in the array would give tick 0 two
44
+ * meanings. A per-team reset is the only reader.
45
+ */
46
+ private initial;
47
+ /**
48
+ * Record the round a tick closed. `tick` is the tick being left behind
49
+ * (`next - 1`), so the entry lands at its own position in the array.
50
+ */
51
+ push(context: Record<string, unknown>, tick: number, teamContexts?: Record<string, unknown>[], teamIndexes?: number[]): void;
52
+ /**
53
+ * Step back one tick, returning the board to restore.
54
+ *
55
+ * The newest snapshot is the one to go back to, not the one before it: it
56
+ * holds the round that the tick being undone consumed, so restoring it
57
+ * leaves the team where it was the moment somebody pressed tick, decisions
58
+ * and all. Undo is for a tick triggered by accident, and a team that has to
59
+ * re-enter a round it already entered has not had anything undone.
60
+ */
61
+ undo(): ContextSnapshot | null;
62
+ /** Drop every snapshot. The initial board is not one, and survives. */
63
+ clear(): void;
64
+ /** Remember where this team started, for a per-team reset to return to. */
65
+ setInitial(context: Record<string, unknown>): void;
66
+ /** Where this team started, or null before it has been initialised. */
67
+ getInitial(): Record<string, unknown> | null;
68
+ /**
69
+ * Position of the newest snapshot, which is also its tick. -1 when empty.
70
+ */
71
+ getCursor(): number;
72
+ /**
73
+ * The snapshot for `tick` if that tick is reviewable, else null.
74
+ *
75
+ * Reviewable means recorded and not since rewound, which the cursor answers
76
+ * on its own: everything at or below it is a closed round, everything above
77
+ * it is a tick an undo took back. The head needs no special case, because a
78
+ * team at tick `N` has no snapshot `N` to exclude.
79
+ */
80
+ reviewable(tick: number): ContextSnapshot | null;
81
+ /**
82
+ * Every snapshot, in record order. Returns a fresh array so callers cannot
83
+ * push into or splice the manager's internal history; the snapshot objects
84
+ * themselves are shared and must be treated as read-only.
85
+ */
86
+ getAllSnapshots(): ContextSnapshot[];
87
+ /** Whether there is a round to step back into. */
88
+ canUndo(): boolean;
89
+ }
@@ -0,0 +1,30 @@
1
+ import type { Server } from 'http';
2
+ export interface ListenWithPortFallbackOptions {
3
+ /** The address to bind. Every interface when absent. */
4
+ host?: string;
5
+ maxAttempts?: number;
6
+ onPortInUse?: (port: number) => void;
7
+ }
8
+ /**
9
+ * Bind `server` to the first free port at or above `startPort`, stepping up one
10
+ * port at a time when a port is already in use. Resolves with the port actually
11
+ * bound.
12
+ *
13
+ * Each attempt settles fully before the next begins and its `error`/`listening`
14
+ * listeners are detached the moment it settles. This keeps the search linear and
15
+ * leaves no residual `error` listener on the server: attaching a persistent
16
+ * `.on('error')` per attempt (as an earlier version did) meant every `EADDRINUSE`
17
+ * re-fired every accumulated handler, fanning retries out exponentially and
18
+ * pegging a CPU under port contention.
19
+ */
20
+ export declare function listenWithPortFallback(server: Server, startPort: number, options?: ListenWithPortFallbackOptions): Promise<number>;
21
+ /**
22
+ * The first free port at or above `startPort`, found by binding and letting go.
23
+ *
24
+ * For a port something else will bind — Vite's hot-reload socket, which opens
25
+ * its own listener rather than sharing the HTTP server's. There is a race
26
+ * between letting go and the real listener binding, and it is the right trade:
27
+ * the alternative is handing Vite a port that is already taken, which is not a
28
+ * race but a certainty whenever a second dev server is running.
29
+ */
30
+ export declare function findFreePort(startPort: number, maxAttempts?: number): Promise<number>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * §9.7 strategy 1, in one place.
3
+ *
4
+ * The specification names two conformant ways to keep a session's committed
5
+ * state equivalent to a single total order of its mutating operations, and
6
+ * assigns the first to this runtime by name: *'Run mutating operations one at a
7
+ * time through a single queue … This is the model the SDK dev server
8
+ * implements.'*
9
+ *
10
+ * Holding that as one object, rather than as a lock here and a debounce there,
11
+ * is what makes the guarantee checkable. Three rules, and nothing else:
12
+ *
13
+ * 1. **Mutations run one at a time, in submission order.** A tick is therefore
14
+ * atomic for free: nothing else runs while it does.
15
+ * 2. **Reads never enter the queue.** §9.7 makes that a MUST, so this object
16
+ * has no read path at all — a caller that wants current state reads it.
17
+ * 3. **An automatic tick that fires while anything is in flight is dropped,
18
+ * not queued** (§11.1). Queueing it would let a slow tick accumulate a
19
+ * backlog of ticks nobody asked for.
20
+ */
21
+ /** What {@link MutationQueue.submitIfIdle} returns when it declines to run. */
22
+ export declare const DROPPED: unique symbol;
23
+ export type Dropped = typeof DROPPED;
24
+ export declare class MutationQueue {
25
+ /**
26
+ * The tail of the chain. Every submission appends to it, which is what
27
+ * imposes the total order.
28
+ */
29
+ private tail;
30
+ /** Submitted but not yet settled, the running one included. */
31
+ private inFlight;
32
+ /** True while any mutation is queued or running. */
33
+ get busy(): boolean;
34
+ /** How many mutations are queued or running. */
35
+ get depth(): number;
36
+ /**
37
+ * Run `work` after everything already submitted, and report its result.
38
+ *
39
+ * A rejection settles the caller's promise and nothing else: the chain
40
+ * continues, because one failed operation must not wedge the session for
41
+ * every operation after it.
42
+ */
43
+ submit<T>(work: () => Promise<T>): Promise<T>;
44
+ /**
45
+ * Run `work` only if nothing is in flight; otherwise decline (§11.1).
46
+ *
47
+ * For timer-driven ticks, which are the one mutation the runtime issues on
48
+ * its own behalf. A participant's write is queued because they asked for it
49
+ * and are waiting; a tick the clock fired while the previous one is still
50
+ * running is simply late, and running it afterwards would advance the game
51
+ * twice for one interval.
52
+ */
53
+ submitIfIdle<T>(work: () => Promise<T>): Promise<T | Dropped>;
54
+ /**
55
+ * Resolve once everything currently queued has settled.
56
+ *
57
+ * For shutdown and for tests. Not a lock: work submitted after this is
58
+ * called is not waited for.
59
+ */
60
+ drain(): Promise<void>;
61
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Author-time scenario persistence for the dev server (issue #101).
3
+ *
4
+ * Takes a snapshot of the resolved settings in force, translates any
5
+ * `blob:*` references into materialised files under the target scenario's
6
+ * `assets/` directory, and writes the resulting scenario bundle to disk.
7
+ *
8
+ * One function, two flows:
9
+ * - an overwrite re-saves a scenario in place, replacing its settings (and
10
+ * its name, when one is given) and keeping every other field on disk
11
+ * - a new scenario writes a fresh `scenarios/<id>/` bundle, a copy of its
12
+ * source's definition when it has one. Nothing registers it: the
13
+ * directory is the declaration (#431)
14
+ *
15
+ * Reference translation is delegated to `asset-reference-translator.ts` so
16
+ * the inverse direction (asset→blob) used by `selectScenario` and the
17
+ * runtime `customScenarios` fork operation stays a sibling, not a copy.
18
+ */
19
+ import type { SessionSettingsOverrides } from '../execution/configuration-builder';
20
+ export interface SavePackageScenarioBaseOptions {
21
+ packagePath: string;
22
+ settings: SessionSettingsOverrides;
23
+ activeScenarioRootDirectory: string | null;
24
+ }
25
+ export interface CreatePackageScenarioOptions extends SavePackageScenarioBaseOptions {
26
+ identifier: string;
27
+ /**
28
+ * The scenario's name. A new scenario carries it in every locale it has;
29
+ * an overwrite replaces it in `nameLocale` alone, and keeps the name on
30
+ * disk when none is given. A new scenario with no name is named by its
31
+ * identifier.
32
+ */
33
+ name?: string;
34
+ /** The locale an overwrite's `name` replaces. Defaults to `en`. */
35
+ nameLocale?: string;
36
+ /**
37
+ * The scenario a new one is a copy of, by identifier. The copy carries
38
+ * everything the source declares on disk apart from its settings, which
39
+ * are the save's, and `default`, which a copy is given only when asked.
40
+ */
41
+ source?: string;
42
+ default?: boolean;
43
+ /**
44
+ * Carried from the scenario the save started out from (§6.7). A copy that
45
+ * loses the flag is a scenario built for one audience that ships to every
46
+ * one of them in the next release, and nothing downstream can tell that it
47
+ * ever was restricted. Clearing it is an edit the author makes on purpose.
48
+ */
49
+ restricted?: boolean;
50
+ /**
51
+ * If true and the scenario already exists on disk, overwrite the bundle
52
+ * (preserving the existing `rootDirectory`) instead of throwing
53
+ * `identifier-exists`. Used by the modal flow when the author has
54
+ * explicitly confirmed they want to replace the existing bundle.
55
+ */
56
+ overwrite?: boolean;
57
+ }
58
+ export interface PackageScenarioResult {
59
+ identifier: string;
60
+ /** Path to the scenario bundle file, absolute. */
61
+ scenarioFilePath: string;
62
+ }
63
+ /**
64
+ * Reasons for a save attempt to be rejected without writing anything.
65
+ */
66
+ export type PackageScenarioErrorCode = 'invalid-identifier' | 'identifier-exists' | 'scenario-not-found' | 'game-not-found' | 'package-manifest-missing' | 'no-game-loaded';
67
+ export declare class PackageScenarioError extends Error {
68
+ readonly code: PackageScenarioErrorCode;
69
+ constructor(code: PackageScenarioErrorCode, message: string);
70
+ }
71
+ /**
72
+ * Persist the live settings into a brand-new package scenario. Writes
73
+ * the bundle file, materialises any `blob:*` references as assets under
74
+ * `scenarios/<id>/assets/shared/`, and patches the game and package
75
+ * manifests so the new scenario is picked up on the next dev-server
76
+ * reload.
77
+ */
78
+ export declare function createPackageScenario(opts: CreatePackageScenarioOptions): Promise<PackageScenarioResult>;
79
+ /**
80
+ * Remove a scenario from the package on disk.
81
+ *
82
+ * Author-time, like saving one: it deletes a directory in the author's own
83
+ * source tree. A production runtime removes a facilitator's scenario from its
84
+ * own store and never touches a package.
85
+ */
86
+ export declare function deletePackageScenario(packagePath: string, identifier: string): Promise<void>;
87
+ /** Every scenario bundle on disk, in directory-name order. */
88
+ /** The scenarios a package holds on disk, by identifier. */
89
+ export declare function packageScenarioIdentifiers(packagePath: string): string[];
@@ -0,0 +1,109 @@
1
+ /**
2
+ * ParticipantRegistry — who is on which team.
3
+ *
4
+ * Scoped per team: each team has its own counter and its own set of
5
+ * participants. A participant is identified by a stable id assigned at
6
+ * creation (`team.counter + 1`), which never changes for the life of the
7
+ * session. Identity is addressed explicitly in the URL — `/team/2/player/1` is
8
+ * the first participant of the second team — so there is no per-browser
9
+ * cookie and nothing to resolve server-side.
10
+ *
11
+ * The registry tracks connection state but deliberately does not auto-evict
12
+ * disconnected participants — facilitators often want to see 'who was here'
13
+ * during a session. Use `clearOffline(teamId)` to remove disconnected entries.
14
+ *
15
+ * Nothing here is persisted. The session is the process (design decision 3),
16
+ * so a restarted server is a new session with a new roster.
17
+ *
18
+ * Events:
19
+ * - `change`: emitted with the affected `teamId` after every mutation
20
+ * (including connect/disconnect), so subscribers (e.g. WebSocket handlers)
21
+ * can broadcast updated lists.
22
+ * - `rosterChange`: emitted with the affected `teamId` after a *structural*
23
+ * mutation (create / rename / remove) — not on connect/disconnect.
24
+ * - `participantJoin`: emitted with the newly created `ParticipantRecord`
25
+ * when a participant is created. Drives the `participantJoin` hook signal
26
+ * (§14).
27
+ */
28
+ import { EventEmitter } from 'events';
29
+ export interface ParticipantRecord {
30
+ id: string;
31
+ teamId: string;
32
+ index: number;
33
+ name: string;
34
+ connected: boolean;
35
+ }
36
+ export declare class ParticipantRegistry extends EventEmitter {
37
+ private teams;
38
+ /**
39
+ * Session-wide participant id counter. Ids are unique across the whole
40
+ * session rather than within a team, so a participant keeps its id across a
41
+ * move and the host can resolve which team holds an id.
42
+ */
43
+ private idCounter;
44
+ private getTeam;
45
+ /**
46
+ * Create a new participant on a team. When `name` is omitted, an
47
+ * auto-name (`Participant N`) is chosen, bumping N to avoid colliding with
48
+ * an existing (possibly renamed) participant. New participants start
49
+ * disconnected; call `markConnected` once a live channel is established.
50
+ */
51
+ create(teamId: string, name?: string): ParticipantRecord;
52
+ private autoName;
53
+ /**
54
+ * Rename a participant. A blank name is ignored (the previous name stands).
55
+ * Returns the updated record, or `undefined` if the participant is unknown.
56
+ */
57
+ rename(teamId: string, id: string, name: string): ParticipantRecord | undefined;
58
+ /**
59
+ * Reassign a participant to another team.
60
+ *
61
+ * The record keeps its `id` but takes a fresh index within the destination,
62
+ * because index is join order *within a team* and the destination has its
63
+ * own sequence. Returns the moved record, or `undefined` when the
64
+ * participant is unknown or already on the destination team.
65
+ *
66
+ * Emits no participant signal of its own: a move is not a join, and the
67
+ * caller drives the two-phase `participantMove` hook dispatch because only
68
+ * it can persist the departure context before the arrival runs.
69
+ */
70
+ move(fromTeamId: string, id: string, toTeamId: string): ParticipantRecord | undefined;
71
+ /**
72
+ * Remove a participant. Returns true if one was removed. Does not re-seed a
73
+ * default — the caller decides whether an emptied team needs one, so it can
74
+ * also drive the resulting hook dispatch and persistence.
75
+ */
76
+ remove(teamId: string, id: string): boolean;
77
+ /** Look up a participant by id. Never creates one; returns undefined on a miss. */
78
+ getById(teamId: string, id: string): ParticipantRecord | undefined;
79
+ /**
80
+ * The team's default participant — the lowest-index record — or undefined
81
+ * when the team has no participants. Drives the bare `/play/:n` route.
82
+ */
83
+ getDefault(teamId: string): ParticipantRecord | undefined;
84
+ /**
85
+ * Return the team's default participant, creating a seed participant first
86
+ * if the team is empty so a team is never at zero. Used at session start,
87
+ * when a team is added, and to resolve the bare `/play/:n` route.
88
+ */
89
+ ensureDefault(teamId: string): ParticipantRecord;
90
+ markConnected(teamId: string, id: string): void;
91
+ markDisconnected(teamId: string, id: string): void;
92
+ list(teamId: string): ParticipantRecord[];
93
+ /**
94
+ * Drop a team's participants entirely. Used when a team is removed at
95
+ * runtime; the remaining teams keep their ids, so no re-keying happens.
96
+ */
97
+ removeTeam(teamId: string): void;
98
+ /**
99
+ * Drop every team and participant — a full clean slate. Used by the
100
+ * dev server's 'reload everything' action; teams re-seed their default on
101
+ * the next play.
102
+ */
103
+ clear(): void;
104
+ /**
105
+ * Remove all disconnected participants from a team. The counter is not
106
+ * reset, so future participants still get fresh indices.
107
+ */
108
+ clearOffline(teamId: string): void;
109
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Edits on disk a running session has not applied, said the same way wherever
3
+ * they are said: the console's banner, the dev server's log, and the CLI.
4
+ */
5
+ import type { PendingChanges } from '@seriousgaming/sdk/projection';
6
+ export type { PendingChanges };
7
+ export declare const NO_PENDING_CHANGES: PendingChanges;
8
+ export declare function hasPendingChanges(pending: PendingChanges | undefined): boolean;
9
+ /** The banner's headline: settings first, since they are the common case. */
10
+ export declare function pendingHeadline(pending: PendingChanges): string;
11
+ /** What is waiting, as one sentence naming each part. */
12
+ export declare function describePendingChanges(pending: PendingChanges): string;
13
+ /** Where to go from here. */
14
+ export declare const PENDING_CHANGES_HINT: string;