@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.2
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.
- package/LICENSE +93 -0
- package/README.md +38 -2
- package/dist/bundling/logic-exports.d.ts +34 -0
- package/dist/bundling/node-builtins.d.ts +21 -0
- package/dist/bundling/transpiler.d.ts +7 -0
- package/dist/cli.js +27404 -0
- package/dist/client/dev-server.d.ts +59 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/stub-services.d.ts +32 -0
- package/dist/client/test-session.d.ts +195 -0
- package/dist/client.js +16920 -0
- package/dist/core/asset-reference-translator.d.ts +46 -0
- package/dist/core/clock.d.ts +57 -0
- package/dist/core/faults.d.ts +65 -0
- package/dist/core/game-settings.d.ts +65 -0
- package/dist/core/history.d.ts +89 -0
- package/dist/core/listen-with-fallback.d.ts +30 -0
- package/dist/core/mutation-queue.d.ts +61 -0
- package/dist/core/package-scenario.d.ts +89 -0
- package/dist/core/participant-registry.d.ts +109 -0
- package/dist/core/pending-changes.d.ts +14 -0
- package/dist/core/protocol.d.ts +83 -0
- package/dist/core/scenario-drafts.d.ts +32 -0
- package/dist/core/session-endpoints.d.ts +108 -0
- package/dist/core/session-gates.d.ts +75 -0
- package/dist/core/session-host.d.ts +94 -0
- package/dist/core/session-refusals.d.ts +56 -0
- package/dist/core/session-rewind.d.ts +32 -0
- package/dist/core/session-roster.d.ts +128 -0
- package/dist/core/session-surfaces.d.ts +32 -0
- package/dist/core/session-ticks.d.ts +18 -0
- package/dist/core/session-timers.d.ts +84 -0
- package/dist/core/session-writes.d.ts +40 -0
- package/dist/core/session.d.ts +385 -0
- package/dist/core/settings-locks.d.ts +22 -0
- package/dist/core/team-names.d.ts +52 -0
- package/dist/core/team-state-store.d.ts +218 -0
- package/dist/core/tick-timer.d.ts +75 -0
- package/dist/dev/blob-links.d.ts +10 -0
- package/dist/dev/console/assets/index-DgFglsnA.js +204 -0
- package/dist/dev/console/index.html +12 -0
- package/dist/dev/console-path.d.ts +19 -0
- package/dist/dev/lockfile.d.ts +124 -0
- package/dist/dev/package-watcher.d.ts +21 -0
- package/dist/dev/routes.d.ts +67 -0
- package/dist/dev/shell.d.ts +260 -0
- package/dist/dev/surfaces.d.ts +41 -0
- package/dist/dev/tools-identity.d.ts +23 -0
- package/dist/dev/view/batch.d.ts +172 -0
- package/dist/dev/view/commands.d.ts +75 -0
- package/dist/dev/view/route.d.ts +58 -0
- package/dist/dev/view/view.d.ts +78 -0
- package/dist/dev/view/viewer.d.ts +32 -0
- package/dist/discovery/config.d.ts +9 -0
- package/dist/discovery/manifest-paths.d.ts +21 -0
- package/dist/discovery/removed-fields.d.ts +90 -0
- package/dist/docs/api/deck.md +386 -0
- package/dist/docs/api/index.md +67 -0
- package/dist/docs/api/sdk-commands.md +286 -0
- package/dist/docs/api/sdk-e2e.md +433 -0
- package/dist/docs/api/sdk-projection.md +207 -0
- package/dist/docs/api/sdk-testing.md +214 -0
- package/dist/docs/api/sdk-tools-client.md +560 -0
- package/dist/docs/api/sdk-ui-testing.md +231 -0
- package/dist/docs/api/sdk-ui.md +1269 -0
- package/dist/docs/api/sdk.md +2140 -0
- package/dist/docs/changelog-0.x.md +1156 -0
- package/dist/docs/changelog.md +241 -0
- package/dist/docs/cli-and-dev-server.md +217 -0
- package/dist/docs/cli-error-codes.md +156 -0
- package/dist/docs/cli-reference.md +2489 -0
- package/dist/docs/cli-simulation-testing.md +222 -0
- package/dist/docs/concepts/index.md +46 -0
- package/dist/docs/concepts/terminology.md +322 -0
- package/dist/docs/environment-variables.md +102 -0
- package/dist/docs/getting-started.md +145 -0
- package/dist/docs/guides/ai-facilitation.md +220 -0
- package/dist/docs/guides/capabilities.md +460 -0
- package/dist/docs/guides/endpoints.md +335 -0
- package/dist/docs/guides/engine-testing.md +477 -0
- package/dist/docs/guides/engine.md +527 -0
- package/dist/docs/guides/file-handling.md +405 -0
- package/dist/docs/guides/games.md +176 -0
- package/dist/docs/guides/global-settings.md +94 -0
- package/dist/docs/guides/guide.md +123 -0
- package/dist/docs/guides/hooks.md +183 -0
- package/dist/docs/guides/index.md +51 -0
- package/dist/docs/guides/internationalization.md +288 -0
- package/dist/docs/guides/llm-integration.md +635 -0
- package/dist/docs/guides/multi-team-games.md +586 -0
- package/dist/docs/guides/patterns.md +391 -0
- package/dist/docs/guides/presentation.md +196 -0
- package/dist/docs/guides/production-constraints.md +130 -0
- package/dist/docs/guides/scenario-editor.md +143 -0
- package/dist/docs/guides/scenarios.md +515 -0
- package/dist/docs/guides/session.md +972 -0
- package/dist/docs/guides/settings.md +458 -0
- package/dist/docs/guides/setup.md +193 -0
- package/dist/docs/guides/speech-generation.md +233 -0
- package/dist/docs/guides/starter-game.md +164 -0
- package/dist/docs/guides/testing.md +577 -0
- package/dist/docs/guides/tick-controller.md +569 -0
- package/dist/docs/guides/type-safety.md +516 -0
- package/dist/docs/guides/ui.md +1389 -0
- package/dist/docs/guides/upgrading.md +636 -0
- package/dist/docs/guides/validators.md +217 -0
- package/dist/docs/guides/waiting-room.md +244 -0
- package/dist/docs/index.md +41 -0
- package/dist/docs/recipes/act-on-the-session-from-an-endpoint.md +95 -0
- package/dist/docs/recipes/adapt-a-game-for-walkthroughs.md +133 -0
- package/dist/docs/recipes/adapt-ui-for-observers.md +74 -0
- package/dist/docs/recipes/call-endpoint-from-ui.md +109 -0
- package/dist/docs/recipes/check-a-package-from-a-script.md +117 -0
- package/dist/docs/recipes/create-capability.md +66 -0
- package/dist/docs/recipes/create-endpoint.md +127 -0
- package/dist/docs/recipes/create-engine.md +111 -0
- package/dist/docs/recipes/create-game.md +70 -0
- package/dist/docs/recipes/create-guide.md +75 -0
- package/dist/docs/recipes/create-hook.md +80 -0
- package/dist/docs/recipes/create-presentation.md +142 -0
- package/dist/docs/recipes/create-scenario-editor.md +102 -0
- package/dist/docs/recipes/create-scenario.md +98 -0
- package/dist/docs/recipes/create-session-ui.md +116 -0
- package/dist/docs/recipes/create-settings.md +88 -0
- package/dist/docs/recipes/create-setup.md +115 -0
- package/dist/docs/recipes/create-tick-controller.md +65 -0
- package/dist/docs/recipes/create-user-interface.md +96 -0
- package/dist/docs/recipes/create-validator.md +67 -0
- package/dist/docs/recipes/create-waiting-room-ui.md +109 -0
- package/dist/docs/recipes/declare-api-uses.md +67 -0
- package/dist/docs/recipes/design-state-for-concurrent-writes.md +96 -0
- package/dist/docs/recipes/distribute-package.md +80 -0
- package/dist/docs/recipes/e2e-testing.md +116 -0
- package/dist/docs/recipes/end-game-on-condition.md +154 -0
- package/dist/docs/recipes/fix-duplicate-packages.md +101 -0
- package/dist/docs/recipes/index.md +86 -0
- package/dist/docs/recipes/make-an-endpoint-external.md +101 -0
- package/dist/docs/recipes/negotiate-across-teams.md +164 -0
- package/dist/docs/recipes/observe-other-teams-state.md +119 -0
- package/dist/docs/recipes/publish-a-package.md +139 -0
- package/dist/docs/recipes/remember-a-viewers-choice.md +55 -0
- package/dist/docs/recipes/review-a-past-day.md +73 -0
- package/dist/docs/recipes/share-assets-across-scenarios.md +120 -0
- package/dist/docs/recipes/share-logic-between-engine-and-ui.md +130 -0
- package/dist/docs/recipes/show-all-teams-participants.md +109 -0
- package/dist/docs/recipes/start-from-an-empty-package.md +169 -0
- package/dist/docs/recipes/take-a-file-in-an-endpoint.md +82 -0
- package/dist/docs/recipes/test-a-multi-role-game.md +51 -0
- package/dist/docs/recipes/test-user-interface.md +95 -0
- package/dist/docs/recipes/test-with-engine.md +115 -0
- package/dist/docs/recipes/upload-and-display-files.md +148 -0
- package/dist/docs/recipes/use-request-play.md +65 -0
- package/dist/docs/recipes/use-request-tick.md +75 -0
- package/dist/docs/troubleshooting.md +816 -0
- package/dist/execution/blob-inputs.d.ts +57 -0
- package/dist/execution/bundle-reload.d.ts +42 -0
- package/dist/execution/config-resolver.d.ts +127 -0
- package/dist/execution/configuration-builder.d.ts +66 -0
- package/dist/execution/context-composition.d.ts +161 -0
- package/dist/execution/endpoint-actions.d.ts +9 -0
- package/dist/execution/endpoint-payloads.d.ts +32 -0
- package/dist/execution/endpoint-runner.d.ts +129 -0
- package/dist/execution/engine-state.d.ts +40 -0
- package/dist/execution/executor-callbacks.d.ts +56 -0
- package/dist/execution/executor.d.ts +436 -0
- package/dist/execution/gates.d.ts +45 -0
- package/dist/execution/hook-chain.d.ts +25 -0
- package/dist/execution/logic-calls.d.ts +190 -0
- package/dist/execution/logic-failure.d.ts +84 -0
- package/dist/execution/logic-loader.d.ts +54 -0
- package/dist/execution/logic-result.d.ts +76 -0
- package/dist/execution/tick-controller-call.d.ts +32 -0
- package/dist/execution/types.d.ts +48 -0
- package/dist/generation/ts-type.d.ts +39 -0
- package/dist/guide/locale.d.ts +12 -0
- package/dist/guide/video-registry.d.ts +42 -0
- package/dist/help-examples.d.ts +125 -0
- package/dist/host/adapter.d.ts +67 -0
- package/dist/host/host-channel.d.ts +222 -0
- package/dist/host/index.d.ts +20 -0
- package/dist/host/protocol.d.ts +783 -0
- package/dist/host/surfaces.d.ts +42 -0
- package/dist/host/theme.d.ts +55 -0
- package/dist/host.js +583 -0
- package/dist/prompts/index.d.ts +7 -0
- package/dist/prompts/schema-builder.d.ts +29 -0
- package/dist/prompts/types.d.ts +108 -0
- package/dist/prompts/validators.d.ts +32 -0
- package/dist/runtime/capability-scope.d.ts +6 -0
- package/dist/runtime/context-merge.d.ts +29 -0
- package/dist/runtime/context-projection.d.ts +41 -0
- package/dist/runtime/guarded-callbacks.d.ts +15 -0
- package/dist/runtime/index.d.ts +27 -0
- package/dist/runtime/manifest-version.d.ts +55 -0
- package/dist/runtime/tick-validation.d.ts +25 -0
- package/dist/runtime.js +346 -0
- package/dist/schema.json +1546 -0
- package/dist/server/vite-plugin.d.ts +46 -0
- package/dist/services/tts/client.d.ts +51 -0
- package/dist/services/tts/elevenlabs.d.ts +24 -0
- package/dist/services/tts/types.d.ts +44 -0
- package/dist/storage/asset-resolver.d.ts +49 -0
- package/dist/storage/blob-store.d.ts +41 -0
- package/dist/templates/endpoint/logic.test.ts.liquid +61 -0
- package/dist/templates/endpoint/logic.ts.liquid +25 -0
- package/dist/templates/engine/init.json.liquid +7 -0
- package/dist/templates/engine/logic-aggregate.test.ts.liquid +90 -0
- package/dist/templates/engine/logic-aggregate.ts.liquid +46 -0
- package/dist/templates/engine/logic.test.ts.liquid +61 -0
- package/dist/templates/engine/logic.ts.liquid +32 -0
- package/dist/templates/engine/run.json.liquid +7 -0
- package/dist/templates/guide/01-at-a-glance.md.liquid +19 -0
- package/dist/templates/guide/02-preparation.md.liquid +18 -0
- package/dist/templates/guide/03-running-the-session.md.liquid +37 -0
- package/dist/templates/hook/logic.test.ts.liquid +46 -0
- package/dist/templates/hook/logic.ts.liquid +12 -0
- package/dist/templates/package/CLAUDE.md.template +338 -0
- package/dist/templates/package/DESIGN.md.liquid +144 -0
- package/dist/templates/package/README.md.liquid +143 -0
- package/dist/templates/package/claude/rules/workflow-create-capability.md +26 -0
- package/dist/templates/package/claude/rules/workflow-create-endpoint.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-engine.md +35 -0
- package/dist/templates/package/claude/rules/workflow-create-guide.md +40 -0
- package/dist/templates/package/claude/rules/workflow-create-presentation.md +37 -0
- package/dist/templates/package/claude/rules/workflow-create-user-interface.md +31 -0
- package/dist/templates/package/claude/rules/workflow-publish-package.md +54 -0
- package/dist/templates/package/claude/rules/workflow-test-engine-or-ui.md +30 -0
- package/dist/templates/package/claude/rules/workflow-update-sdk-version.md +43 -0
- package/dist/templates/package/claude/settings.json.template +16 -0
- package/dist/templates/package/gitignore.template +15 -0
- package/dist/templates/package/global-setup.ts.template +21 -0
- package/dist/templates/package/globals.d.ts.template +2 -0
- package/dist/templates/package/oxfmtrc.json.template +14 -0
- package/dist/templates/package/oxlintrc.json.template +238 -0
- package/dist/templates/package/package.json.liquid +65 -0
- package/dist/templates/package/playwright.config.ts.liquid +19 -0
- package/dist/templates/package/pnpm-workspace.yaml.template +27 -0
- package/dist/templates/package/test-setup.ts.liquid +7 -0
- package/dist/templates/package/tsconfig.json.liquid +15 -0
- package/dist/templates/package/vite.config.ts.liquid +19 -0
- package/dist/templates/package/vitest.config.ts.liquid +25 -0
- package/dist/templates/package/vitest.engine.config.ts.liquid +12 -0
- package/dist/templates/presentation/index.html.liquid +20 -0
- package/dist/templates/presentation/src/App.tsx.liquid +49 -0
- package/dist/templates/presentation/src/Slides.tsx.liquid +81 -0
- package/dist/templates/presentation/src/i18n.ts.liquid +54 -0
- package/dist/templates/presentation/src/main.tsx.liquid +14 -0
- package/dist/templates/scenario_editor/src/App.test.tsx.liquid +30 -0
- package/dist/templates/scenario_editor/src/App.tsx.liquid +95 -0
- package/dist/templates/scenario_editor/src/i18n.ts.liquid +44 -0
- package/dist/templates/session/src/App.test.tsx.liquid +60 -0
- package/dist/templates/session/src/App.tsx.liquid +128 -0
- package/dist/templates/session/src/i18n.ts.liquid +53 -0
- package/dist/templates/session/src/main.tsx.liquid +48 -0
- package/dist/templates/session/src/theme.ts.liquid +46 -0
- package/dist/templates/settings-editor/index.html.liquid +12 -0
- package/dist/templates/settings-editor/src/main.tsx.liquid +48 -0
- package/dist/templates/settings-editor/src/theme.ts.liquid +24 -0
- package/dist/templates/setup/src/App.test.tsx.liquid +39 -0
- package/dist/templates/setup/src/App.tsx.liquid +102 -0
- package/dist/templates/setup/src/i18n.ts.liquid +47 -0
- package/dist/templates/starter-game/capabilities/briefing/capability.sdk.json +18 -0
- package/dist/templates/starter-game/capabilities/plan/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/results/capability.sdk.json +61 -0
- package/dist/templates/starter-game/capabilities/roles/capability.sdk.json +17 -0
- package/dist/templates/starter-game/capabilities/weather/capability.sdk.json +23 -0
- package/dist/templates/starter-game/engine/defaults.ts +81 -0
- package/dist/templates/starter-game/engine/engine.sdk.json +12 -0
- package/dist/templates/starter-game/engine/logic.test.ts +221 -0
- package/dist/templates/starter-game/engine/logic.ts +149 -0
- package/dist/templates/starter-game/engine/test-helpers.ts +74 -0
- package/dist/templates/starter-game/engine/types.ts +139 -0
- package/dist/templates/starter-game/guide/content/en/01-at-a-glance.md +51 -0
- package/dist/templates/starter-game/guide/content/en/02-preparation.md +35 -0
- package/dist/templates/starter-game/guide/content/en/03-running-the-day.md +58 -0
- package/dist/templates/starter-game/guide/guide.sdk.json +10 -0
- package/dist/templates/starter-game/guide/guide.test.ts +108 -0
- package/dist/templates/starter-game/hooks/assignproducts/defaults.ts +37 -0
- package/dist/templates/starter-game/hooks/assignproducts/hook.sdk.json +13 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.test.ts +77 -0
- package/dist/templates/starter-game/hooks/assignproducts/logic/logic.ts +47 -0
- package/dist/templates/starter-game/hooks/assignproducts/types.ts +55 -0
- package/dist/templates/starter-game/package.json +68 -0
- package/dist/templates/starter-game/playwright.config.ts +19 -0
- package/dist/templates/starter-game/scenarios/heatwave/scenario.sdk.json +20 -0
- package/dist/templates/starter-game/scenarios/ordinary_week/scenario.sdk.json +12 -0
- package/dist/templates/starter-game/seriousgaming.sdk.json +23 -0
- package/dist/templates/starter-game/session/defaults.ts +80 -0
- package/dist/templates/starter-game/session/index.html +12 -0
- package/dist/templates/starter-game/session/session.sdk.json +11 -0
- package/dist/templates/starter-game/session/src/App.test.tsx +307 -0
- package/dist/templates/starter-game/session/src/App.tsx +309 -0
- package/dist/templates/starter-game/session/src/Section.tsx +37 -0
- package/dist/templates/starter-game/session/src/TeamDoor.tsx +96 -0
- package/dist/templates/starter-game/session/src/format.ts +8 -0
- package/dist/templates/starter-game/session/src/i18n.ts +51 -0
- package/dist/templates/starter-game/session/src/main.tsx +48 -0
- package/dist/templates/starter-game/session/src/theme.ts +45 -0
- package/dist/templates/starter-game/session/types.ts +135 -0
- package/dist/templates/starter-game/settings/engine/settings.sdk.json +50 -0
- package/dist/templates/starter-game/settings/menu/settings.sdk.json +78 -0
- package/dist/templates/starter-game/settings/session/settings.sdk.json +23 -0
- package/dist/templates/starter-game/settings/ui/settings.sdk.json +25 -0
- package/dist/templates/starter-game/test-setup.ts +7 -0
- package/dist/templates/starter-game/testing/e2e/game.spec.ts +139 -0
- package/dist/templates/starter-game/testing/e2e/global-setup.ts +21 -0
- package/dist/templates/starter-game/testing/engine/game.engine.test.ts +171 -0
- package/dist/templates/starter-game/tsconfig.json +19 -0
- package/dist/templates/starter-game/ui/defaults.ts +60 -0
- package/dist/templates/starter-game/ui/index.html +12 -0
- package/dist/templates/starter-game/ui/src/App.test.tsx +138 -0
- package/dist/templates/starter-game/ui/src/App.tsx +175 -0
- package/dist/templates/starter-game/ui/src/DayBar.test.tsx +78 -0
- package/dist/templates/starter-game/ui/src/DayBar.tsx +72 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.test.tsx +74 -0
- package/dist/templates/starter-game/ui/src/HistoryPanel.tsx +120 -0
- package/dist/templates/starter-game/ui/src/MakeRow.tsx +129 -0
- package/dist/templates/starter-game/ui/src/Section.tsx +37 -0
- package/dist/templates/starter-game/ui/src/ThemeToggle.tsx +49 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.test.tsx +179 -0
- package/dist/templates/starter-game/ui/src/TodayPanel.tsx +92 -0
- package/dist/templates/starter-game/ui/src/YesterdayPanel.tsx +142 -0
- package/dist/templates/starter-game/ui/src/format.ts +12 -0
- package/dist/templates/starter-game/ui/src/i18n.ts +95 -0
- package/dist/templates/starter-game/ui/src/main.tsx +48 -0
- package/dist/templates/starter-game/ui/src/menu.ts +18 -0
- package/dist/templates/starter-game/ui/src/test-helpers.ts +58 -0
- package/dist/templates/starter-game/ui/src/theme.ts +45 -0
- package/dist/templates/starter-game/ui/src/writes.ts +43 -0
- package/dist/templates/starter-game/ui/types.ts +137 -0
- package/dist/templates/starter-game/ui/ui.sdk.json +11 -0
- package/dist/templates/starter-game/validators/capacity/defaults.ts +37 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.test.ts +96 -0
- package/dist/templates/starter-game/validators/capacity/logic/logic.ts +45 -0
- package/dist/templates/starter-game/validators/capacity/types.ts +55 -0
- package/dist/templates/starter-game/validators/capacity/validator.sdk.json +11 -0
- package/dist/templates/starter-game/vite.config.ts +19 -0
- package/dist/templates/starter-game/vitest.config.ts +15 -0
- package/dist/templates/starter-game/vitest.engine.config.ts +19 -0
- package/dist/templates/starter-game/waiting_room/defaults.ts +40 -0
- package/dist/templates/starter-game/waiting_room/index.html +12 -0
- package/dist/templates/starter-game/waiting_room/src/App.test.tsx +102 -0
- package/dist/templates/starter-game/waiting_room/src/App.tsx +194 -0
- package/dist/templates/starter-game/waiting_room/src/i18n.ts +33 -0
- package/dist/templates/starter-game/waiting_room/src/main.tsx +48 -0
- package/dist/templates/starter-game/waiting_room/src/theme.ts +45 -0
- package/dist/templates/starter-game/waiting_room/types.ts +59 -0
- package/dist/templates/starter-game/waiting_room/waiting_room.sdk.json +10 -0
- package/dist/templates/tick-controller/logic.ts.liquid +8 -0
- package/dist/templates/ui/index.html.liquid +12 -0
- package/dist/templates/ui/src/App.test.tsx.liquid +41 -0
- package/dist/templates/ui/src/App.tsx.liquid +103 -0
- package/dist/templates/ui/src/i18n.ts.liquid +47 -0
- package/dist/templates/ui/src/main.tsx.liquid +48 -0
- package/dist/templates/ui/src/theme.ts.liquid +46 -0
- package/dist/templates/validator/logic.test.ts.liquid +42 -0
- package/dist/templates/validator/logic.ts.liquid +21 -0
- package/dist/templates/waiting-room/index.html.liquid +12 -0
- package/dist/templates/waiting-room/src/App.test.tsx.liquid +57 -0
- package/dist/templates/waiting-room/src/App.tsx.liquid +118 -0
- package/dist/templates/waiting-room/src/i18n.ts.liquid +44 -0
- package/dist/templates/waiting-room/src/main.tsx.liquid +48 -0
- package/dist/templates/waiting-room/src/theme.ts.liquid +46 -0
- package/dist/templating/resource-metadata.d.ts +131 -0
- package/dist/types.d.ts +14 -0
- package/dist/utils/atomic-write.d.ts +40 -0
- package/dist/utils/cli-error.d.ts +64 -0
- package/dist/utils/document-parser-client.d.ts +20 -0
- package/dist/utils/env-loader.d.ts +40 -0
- package/dist/utils/error-codes.d.ts +339 -0
- package/dist/utils/errors.d.ts +19 -0
- package/dist/utils/global-settings.d.ts +65 -0
- package/dist/utils/llm-client.d.ts +34 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/output.d.ts +109 -0
- package/dist/utils/platform.d.ts +14 -0
- package/dist/utils/prompt.d.ts +36 -0
- package/dist/utils/real-path.d.ts +6 -0
- package/dist/utils/schema-properties.d.ts +35 -0
- package/dist/validation/ajv.d.ts +17 -0
- package/dist/validation/facilitator-guide-validator.d.ts +27 -0
- package/dist/validation/findings.d.ts +40 -0
- package/dist/validation/game-constraints.d.ts +10 -0
- package/dist/validation/game-validator.d.ts +34 -0
- package/dist/validation/package-validation.d.ts +41 -0
- package/dist/validation/package-validator.d.ts +19 -0
- package/dist/validation/resource-validator.d.ts +79 -0
- package/dist/validation/schema-defaults-validator.d.ts +29 -0
- package/dist/validation/schema-validation.d.ts +115 -0
- package/dist/validation/semver.d.ts +9 -0
- package/package.json +123 -3
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { SDKUserInterface, SDKScenarioEditor, SDKSetup, SDKSessionUserInterface, SDKWaitingRoomUserInterface, SDKPresentation } from '@seriousgaming/sdk';
|
|
2
|
+
import type { Plugin } from 'vite';
|
|
3
|
+
export interface SeriousGamingUiPluginSurfaces {
|
|
4
|
+
userInterfaces: SDKUserInterface[];
|
|
5
|
+
setups: SDKSetup[];
|
|
6
|
+
scenarioEditors: SDKScenarioEditor[];
|
|
7
|
+
sessionUserInterfaces: SDKSessionUserInterface[];
|
|
8
|
+
waitingRoomUserInterfaces: SDKWaitingRoomUserInterface[];
|
|
9
|
+
/** Optional so a caller predating the slot need not name it. */
|
|
10
|
+
presentations?: SDKPresentation[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The surfaces to route, as a fixed set or as a function the plugin calls on
|
|
14
|
+
* each request. A dev server passes the function, so a surface added while it
|
|
15
|
+
* runs is routed without a restart (#640).
|
|
16
|
+
*/
|
|
17
|
+
export type SeriousGamingUiPluginOptions = {
|
|
18
|
+
workingDir: string;
|
|
19
|
+
} & (SeriousGamingUiPluginSurfaces | {
|
|
20
|
+
surfaces: () => SeriousGamingUiPluginSurfaces;
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Rewrite a document's relative asset references to root-relative ones.
|
|
24
|
+
*
|
|
25
|
+
* A surface's HTML is authored beside its sources (`src="./src/main.tsx"`) and
|
|
26
|
+
* served from under a prefix, so the browser resolves that against the prefixed
|
|
27
|
+
* document URL while Vite's module graph knows the same file by its
|
|
28
|
+
* root-relative path. The module was then fetched under both, evaluated twice,
|
|
29
|
+
* and every surface called `createRoot` on the same container twice.
|
|
30
|
+
*
|
|
31
|
+
* Rewriting here makes the document name the module the way Vite names it, so
|
|
32
|
+
* there is one identity and one evaluation.
|
|
33
|
+
*/
|
|
34
|
+
export declare function toRootRelative(html: string, documentDirectory: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Module id of the dev-only recovery guard injected into every served surface.
|
|
37
|
+
*
|
|
38
|
+
* Virtual, so it needs no file on disk and no route of its own: Vite resolves
|
|
39
|
+
* it through the plugin and serves it under `/@id/`, which means it goes
|
|
40
|
+
* through the transform pipeline and gets an `import.meta.hot` like any other
|
|
41
|
+
* module.
|
|
42
|
+
*/
|
|
43
|
+
export declare const RECOVERY_MODULE_ID = "virtual:seriousgaming-surface-recovery";
|
|
44
|
+
/** How the injected tag names it. Vite spells a leading NUL `__x00__` in a URL. */
|
|
45
|
+
export declare const RECOVERY_MODULE_URL = "/@id/__x00__virtual:seriousgaming-surface-recovery";
|
|
46
|
+
export declare function seriousgamingUiPlugin(options: SeriousGamingUiPluginOptions): Plugin;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTS Client - dispatcher that wraps the configured TtsProvider.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the provider adapter, the tier-to-model mapping, the preset-to-voice
|
|
5
|
+
* mapping, clamps `speed` to the provider's supported range, and surfaces a
|
|
6
|
+
* single `generateSpeech` entry point to the rest of the runtime.
|
|
7
|
+
*
|
|
8
|
+
* v1 ships with the ElevenLabs adapter only; additional providers (OpenAI,
|
|
9
|
+
* Google, Azure, Polly) will land behind a future `TTS_PROVIDER` env var.
|
|
10
|
+
* Adding them is a non-breaking change for game code.
|
|
11
|
+
*/
|
|
12
|
+
import type { GenerateSpeechRequest, GenerateSpeechResponse } from '@seriousgaming/sdk';
|
|
13
|
+
import type { TtsProvider } from './types';
|
|
14
|
+
export declare class TtsClientError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
export interface TtsClientConfig {
|
|
18
|
+
/** ElevenLabs API key. When omitted, the client throws on first call. */
|
|
19
|
+
elevenLabsApiKey?: string;
|
|
20
|
+
/** Tier-to-model mapping. Missing tiers fall back toward `quick`. */
|
|
21
|
+
quickModel?: string;
|
|
22
|
+
standardModel?: string;
|
|
23
|
+
expertModel?: string;
|
|
24
|
+
/** Preset-to-voice mapping. Missing presets fall back to `neutral`, then provider default. */
|
|
25
|
+
voicePresets?: {
|
|
26
|
+
neutral?: string;
|
|
27
|
+
narrator?: string;
|
|
28
|
+
announcer?: string;
|
|
29
|
+
executive?: string;
|
|
30
|
+
coach?: string;
|
|
31
|
+
[preset: string]: string | undefined;
|
|
32
|
+
};
|
|
33
|
+
/** Optional custom provider — used only by tests. */
|
|
34
|
+
provider?: TtsProvider;
|
|
35
|
+
}
|
|
36
|
+
export declare class TtsClient {
|
|
37
|
+
private readonly provider;
|
|
38
|
+
private readonly quickModel;
|
|
39
|
+
private readonly standardModel?;
|
|
40
|
+
private readonly expertModel?;
|
|
41
|
+
private readonly voicePresets;
|
|
42
|
+
constructor(config: TtsClientConfig);
|
|
43
|
+
/** Whether the client is configured to make TTS calls. */
|
|
44
|
+
isConfigured(): boolean;
|
|
45
|
+
generateSpeech(requestOrText: GenerateSpeechRequest | string): Promise<GenerateSpeechResponse & {
|
|
46
|
+
audio: Uint8Array;
|
|
47
|
+
}>;
|
|
48
|
+
private resolveModel;
|
|
49
|
+
private resolveVoice;
|
|
50
|
+
private buildConfigurationError;
|
|
51
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ElevenLabs adapter for the TTS dispatcher. v1 of `generateSpeech` ships
|
|
3
|
+
* with this provider only; OpenAI, Google, Azure and Polly adapters will
|
|
4
|
+
* follow behind a future `TTS_PROVIDER` env var.
|
|
5
|
+
*/
|
|
6
|
+
import type { NormalisedTtsRequest, TtsProvider, TtsSynthesisResult } from './types';
|
|
7
|
+
export declare const ELEVENLABS_DEFAULT_MODELS: {
|
|
8
|
+
readonly quick: "eleven_flash_v2_5";
|
|
9
|
+
readonly standard: "eleven_turbo_v2_5";
|
|
10
|
+
readonly expert: "eleven_multilingual_v2";
|
|
11
|
+
};
|
|
12
|
+
export interface ElevenLabsAdapterConfig {
|
|
13
|
+
apiKey: string;
|
|
14
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
15
|
+
}
|
|
16
|
+
export declare class ElevenLabsAdapter implements TtsProvider {
|
|
17
|
+
readonly name = "elevenlabs";
|
|
18
|
+
private readonly apiKey;
|
|
19
|
+
private readonly fetchImpl;
|
|
20
|
+
constructor(config: ElevenLabsAdapterConfig);
|
|
21
|
+
defaultVoice(): string;
|
|
22
|
+
clampSpeed(speed: number): number;
|
|
23
|
+
synthesize(request: NormalisedTtsRequest): Promise<TtsSynthesisResult>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-agnostic text-to-speech contract used by the TTS dispatcher.
|
|
3
|
+
*
|
|
4
|
+
* Adapters (`elevenlabs.ts`, future `openai.ts`, etc.) implement
|
|
5
|
+
* {@link TtsProvider}. The dispatcher resolves the configured adapter, maps
|
|
6
|
+
* tier → model and preset → provider voice, clamps `speed` to the supported
|
|
7
|
+
* range, and calls `synthesize` with a normalised request.
|
|
8
|
+
*/
|
|
9
|
+
import type { GenerateSpeechFormat, LLMTier } from '@seriousgaming/sdk';
|
|
10
|
+
export interface NormalisedTtsRequest {
|
|
11
|
+
/** Plain-text utterance. */
|
|
12
|
+
text: string;
|
|
13
|
+
/** Provider-specific voice ID resolved from the preset. */
|
|
14
|
+
voice: string;
|
|
15
|
+
/** Provider-specific model ID resolved from the tier. */
|
|
16
|
+
model: string;
|
|
17
|
+
/** Output audio container. */
|
|
18
|
+
format: GenerateSpeechFormat;
|
|
19
|
+
/** Optional BCP-47 hint passed through to the provider. */
|
|
20
|
+
languageHint?: string;
|
|
21
|
+
/** Speed multiplier already clamped to the provider's supported range. */
|
|
22
|
+
speed?: number;
|
|
23
|
+
/** Tier that selected the model — useful for adapters that branch behaviour. */
|
|
24
|
+
tier: LLMTier;
|
|
25
|
+
}
|
|
26
|
+
export interface TtsSynthesisResult {
|
|
27
|
+
audio: Uint8Array;
|
|
28
|
+
mimeType: string;
|
|
29
|
+
durationMs?: number;
|
|
30
|
+
charactersBilled?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface TtsProvider {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/**
|
|
35
|
+
* Synthesise audio for `request`. Throws when the provider cannot service
|
|
36
|
+
* the call (missing config, transport error, etc.); the dispatcher converts
|
|
37
|
+
* the error into a callback-level failure for game code.
|
|
38
|
+
*/
|
|
39
|
+
synthesize(request: NormalisedTtsRequest): Promise<TtsSynthesisResult>;
|
|
40
|
+
/** Provider-default voice ID, used when no preset (including `neutral`) is configured. */
|
|
41
|
+
defaultVoice(): string;
|
|
42
|
+
/** Clamp `speed` to the provider's supported range. */
|
|
43
|
+
clampSpeed(speed: number): number;
|
|
44
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve an asset reference under the unified URI scheme.
|
|
3
|
+
*
|
|
4
|
+
* `asset:<path>` — package-bundled file, resolved against the active
|
|
5
|
+
* scenario's `assets/` directory.
|
|
6
|
+
* `shared:<path>` — package-level file, resolved against the package's
|
|
7
|
+
* top-level `shared-assets/` directory. Resolvable even
|
|
8
|
+
* when no scenario is active.
|
|
9
|
+
* `blob:<id>` — runtime-uploaded file, resolved against the dev
|
|
10
|
+
* server's blob store.
|
|
11
|
+
*
|
|
12
|
+
* The dispatch lives here so every engine-side and endpoint-side caller
|
|
13
|
+
* (`readAsset`, `extractText`) shares a single implementation.
|
|
14
|
+
*/
|
|
15
|
+
export interface ResolvedAsset {
|
|
16
|
+
data: Buffer;
|
|
17
|
+
mimeType: string;
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns true when `value` is a string starting with one of the known
|
|
22
|
+
* asset URI scheme prefixes.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isAssetReference(value: unknown): value is string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve an `asset:` reference to a file under the scenario's `assets/`
|
|
27
|
+
* directory. The path is normalised and validated against directory traversal.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveAsset(scenarioRootDirectory: string, path: string): Promise<ResolvedAsset>;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve a `shared:` reference to a file under the package's top-level
|
|
32
|
+
* `shared-assets/` directory. Unlike `asset:`, shared assets are package-level
|
|
33
|
+
* and resolvable with no active scenario. The path is normalised and validated
|
|
34
|
+
* against directory traversal relative to the `shared-assets/` root.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSharedAsset(packagePath: string, path: string): Promise<ResolvedAsset>;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve an `asset:<path>`, `shared:<path>`, or `blob:<id>` reference and
|
|
39
|
+
* return the underlying bytes, MIME type, and display name.
|
|
40
|
+
* `scenarioRootDirectory` is required for `asset:` references; pass `null` if
|
|
41
|
+
* no scenario is active and the resolver should throw on `asset:` references.
|
|
42
|
+
* `shared:` references are package-level and resolve regardless of the active
|
|
43
|
+
* scenario.
|
|
44
|
+
*
|
|
45
|
+
* Relative `scenarioRootDirectory` values resolve against `packagePath`
|
|
46
|
+
* (rather than the process CWD) so callers don't need to absolutize the
|
|
47
|
+
* scenario root before passing it in.
|
|
48
|
+
*/
|
|
49
|
+
export declare function readAssetByReference(packagePath: string, scenarioRootDirectory: string | null, reference: string): Promise<ResolvedAsset>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blob storage for game assets uploaded during configuration or play.
|
|
3
|
+
*
|
|
4
|
+
* Blobs are stored as pairs of files under .seriousgaming-sdk/blobs/:
|
|
5
|
+
* <uuid>.bin — raw binary data
|
|
6
|
+
* <uuid>.meta.json — { name, mimeType, retention }
|
|
7
|
+
*
|
|
8
|
+
* Retention (§16.2) is a deletion-lifecycle bucket, not an access dimension:
|
|
9
|
+
* "settings" — survives a session reset; cleared on a re-initialise
|
|
10
|
+
* "game" — cleared on a session reset or a re-initialise
|
|
11
|
+
*/
|
|
12
|
+
export type BlobRetention = 'settings' | 'game';
|
|
13
|
+
export interface BlobMeta {
|
|
14
|
+
name: string;
|
|
15
|
+
mimeType: string;
|
|
16
|
+
retention: BlobRetention;
|
|
17
|
+
}
|
|
18
|
+
export interface BlobData extends BlobMeta {
|
|
19
|
+
data: Buffer;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Keep a package's blobs in `dir` rather than in the package, until the
|
|
23
|
+
* returned function is called. For an isolated dev server, which must neither
|
|
24
|
+
* read the developer's uploads nor leave its own beside them (#640).
|
|
25
|
+
*/
|
|
26
|
+
export declare function redirectBlobs(packagePath: string, dir: string): () => void;
|
|
27
|
+
/**
|
|
28
|
+
* Store a blob on disk. Returns the generated blob ID.
|
|
29
|
+
* Throws if data exceeds the 20 MB limit.
|
|
30
|
+
*/
|
|
31
|
+
export declare function storeBlob(packagePath: string, data: Buffer, name: string, mimeType: string, retention: BlobRetention): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Read a blob from disk by ID.
|
|
34
|
+
* Throws if the blob does not exist.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readBlob(packagePath: string, id: string): Promise<BlobData>;
|
|
37
|
+
/**
|
|
38
|
+
* Delete every blob held under one of `retentions` (§16.2). A deleted blob is
|
|
39
|
+
* read as an unknown one: {@link readBlob} throws, and the asset route 404s.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deleteBlobs(packagePath: string, retentions: readonly BlobRetention[]): Promise<void>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { Handle } from './logic';
|
|
3
|
+
import type { Request, Response, Context, Callbacks } from '../types';
|
|
4
|
+
import type { EndpointCaller, EndpointSession, {% unless sessionScoped %}TeamInfo, {% endunless %}LogicMeta } from '@seriousgaming/sdk';
|
|
5
|
+
|
|
6
|
+
// The run-wide facts the host supplies: the session locale, its random seed,
|
|
7
|
+
// whether this is the game being played or a walkthrough beside it, and when
|
|
8
|
+
// the operation started.
|
|
9
|
+
const meta: LogicMeta = { locale: 'en', seed: 'test-seed', runKind: 'session', now: Date.UTC(2026, 0, 1) };
|
|
10
|
+
// Where the session stands when the call is made: the ticks it has completed,
|
|
11
|
+
// whether the waiting room is open, and every team's standing.
|
|
12
|
+
const session: EndpointSession = {
|
|
13
|
+
mode: 'independent',
|
|
14
|
+
completedTicks: 1,
|
|
15
|
+
maxTicks: null,
|
|
16
|
+
waitingRoomOpen: false,
|
|
17
|
+
complete: false,
|
|
18
|
+
teams: [],
|
|
19
|
+
};
|
|
20
|
+
const callbacks = {} as Callbacks;
|
|
21
|
+
const caller: EndpointCaller = {
|
|
22
|
+
sessionId: 'test-session',
|
|
23
|
+
// A participant's own team; a facilitator's or external call carries none.
|
|
24
|
+
teamId: 'team-1',
|
|
25
|
+
role: 'participant',
|
|
26
|
+
userInterfaceIdentifier: '{{ identifier }}',
|
|
27
|
+
};
|
|
28
|
+
{% unless sessionScoped %}// The team the call runs for, which the runtime always supplies on team scope.
|
|
29
|
+
const team: TeamInfo = { teamId: 'team-1', index: 0, name: 'Team 1' };
|
|
30
|
+
{% endunless %}
|
|
31
|
+
describe('{{ identifier }}', () => {
|
|
32
|
+
describe('Handle', () => {
|
|
33
|
+
it('returns a valid response', async () => {
|
|
34
|
+
const request: Request = {
|
|
35
|
+
// TODO: populate request fields from requestSchema
|
|
36
|
+
} as Request;
|
|
37
|
+
const context: Context = {
|
|
38
|
+
// TODO: populate context based on declared reads
|
|
39
|
+
} as Context;
|
|
40
|
+
|
|
41
|
+
// The settings resources this endpoint lists in `settings`, keyed by
|
|
42
|
+
// identifier. Empty until it lists some.
|
|
43
|
+
const settings = {} as Parameters<typeof Handle>[0]['settings'];
|
|
44
|
+
|
|
45
|
+
const result = await Handle({
|
|
46
|
+
request,
|
|
47
|
+
context,
|
|
48
|
+
settings,
|
|
49
|
+
callbacks,
|
|
50
|
+
caller,
|
|
51
|
+
{% unless sessionScoped %} team,
|
|
52
|
+
{% endunless %} meta,
|
|
53
|
+
participants: [],
|
|
54
|
+
session,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// TODO: assert result matches responseSchema
|
|
58
|
+
expect(result).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Handler } from '../types';
|
|
2
|
+
|
|
3
|
+
export const Handle: Handler = async ({ request, context, callbacks, caller }) => {
|
|
4
|
+
// The runtime validates `request` against the requestSchema before this
|
|
5
|
+
// runs, and the response against the responseSchema before it reaches the
|
|
6
|
+
// caller.
|
|
7
|
+
{%- if writes %}
|
|
8
|
+
// This endpoint declares `writes`, so it returns the response and the
|
|
9
|
+
// capabilities it changed. Only those in `writes` may appear in
|
|
10
|
+
// `capabilities`.
|
|
11
|
+
return {
|
|
12
|
+
response: {
|
|
13
|
+
// TODO: build the response shape declared in responseSchema
|
|
14
|
+
},
|
|
15
|
+
capabilities: {
|
|
16
|
+
// TODO: the capabilities this call changes
|
|
17
|
+
},
|
|
18
|
+
} as Awaited<ReturnType<Handler>>;
|
|
19
|
+
{%- else %}
|
|
20
|
+
// It declares no `writes`, so it cannot change the game: return the response.
|
|
21
|
+
return {
|
|
22
|
+
// TODO: build the response shape declared in responseSchema
|
|
23
|
+
} as Awaited<ReturnType<Handler>>;
|
|
24
|
+
{%- endif %}
|
|
25
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import type { Participant, TeamRunMeta } from '@seriousgaming/sdk';
|
|
3
|
+
import { defaultSettings, defaultContext, defaultSharedContext, defaultTeamContext } from './defaults';
|
|
4
|
+
import { Init, InitAggregate, RunAggregate } from './logic';
|
|
5
|
+
import type { Context, Settings, Callbacks, TeamContext } from './types';
|
|
6
|
+
|
|
7
|
+
// `teamId` and `index` name the team whose context a per-team call receives,
|
|
8
|
+
// `seed` is the session's random seed (a fixed one here keeps an assertion on
|
|
9
|
+
// derived randomness stable), `runKind` says whether this is the game being
|
|
10
|
+
// played or a walkthrough beside it, and `now` is when the operation started
|
|
11
|
+
// (fixed here, as `seed` is, so a test asserting on it is stable). All of them come from the runtime in a
|
|
12
|
+
// real session, so a test has to state them.
|
|
13
|
+
const meta: TeamRunMeta = {
|
|
14
|
+
tick: 0,
|
|
15
|
+
locale: 'en',
|
|
16
|
+
teamId: 'team-1',
|
|
17
|
+
index: 0,
|
|
18
|
+
seed: 'test-seed',
|
|
19
|
+
runKind: 'session',
|
|
20
|
+
now: Date.UTC(2026, 0, 1),
|
|
21
|
+
};
|
|
22
|
+
// The participants on the team, taken when the operation started. Empty here;
|
|
23
|
+
// add records to test logic that reads the roster.
|
|
24
|
+
const participants: Participant[] = [];
|
|
25
|
+
const callbacks = {} as Callbacks;
|
|
26
|
+
|
|
27
|
+
// `defaultContext` and `defaultSettings` are generated beside the types, from
|
|
28
|
+
// the very schemas they satisfy: the values a session opens with. Spread
|
|
29
|
+
// them and name only what the case is about, and a capability added later
|
|
30
|
+
// arrives here already populated rather than breaking every fixture. An
|
|
31
|
+
// aggregate function receives them split: the shared store once, and each
|
|
32
|
+
// team's own capabilities, so its fixtures use `defaultSharedContext` and
|
|
33
|
+
// `defaultTeamContext`.
|
|
34
|
+
const shared = { context: { ...defaultSharedContext } };
|
|
35
|
+
|
|
36
|
+
describe('{{ identifier }}', () => {
|
|
37
|
+
describe('Init', () => {
|
|
38
|
+
it('should initialize each team context', async () => {
|
|
39
|
+
// TODO: override the capabilities this case is about
|
|
40
|
+
const context: Context = { ...defaultContext };
|
|
41
|
+
// TODO: override the settings this case is about
|
|
42
|
+
const settings: Settings = { ...defaultSettings };
|
|
43
|
+
|
|
44
|
+
const { capabilities } = await Init({ context, settings, meta, participants, callbacks });
|
|
45
|
+
|
|
46
|
+
// TODO: Add assertions for initialized values
|
|
47
|
+
expect(capabilities).toBeDefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('InitAggregate', () => {
|
|
52
|
+
it('should seed shared state across all teams', async () => {
|
|
53
|
+
const teams = [
|
|
54
|
+
{
|
|
55
|
+
teamId: 'team-1',
|
|
56
|
+
index: 0,
|
|
57
|
+
// TODO: override the capabilities this case is about
|
|
58
|
+
context: { ...defaultTeamContext } satisfies TeamContext,
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
// TODO: override the settings this case is about
|
|
62
|
+
const settings: Settings = { ...defaultSettings };
|
|
63
|
+
|
|
64
|
+
const result = await InitAggregate({ shared, teams, settings, meta, participants, callbacks });
|
|
65
|
+
|
|
66
|
+
// TODO: Add assertions for shared and per-team values
|
|
67
|
+
expect(result.teams).toHaveLength(teams.length);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('RunAggregate', () => {
|
|
72
|
+
it('should update shared state on each tick', async () => {
|
|
73
|
+
const teams = [
|
|
74
|
+
{
|
|
75
|
+
teamId: 'team-1',
|
|
76
|
+
index: 0,
|
|
77
|
+
// TODO: override the capabilities this case is about
|
|
78
|
+
context: { ...defaultTeamContext } satisfies TeamContext,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
// TODO: override the settings this case is about
|
|
82
|
+
const settings: Settings = { ...defaultSettings };
|
|
83
|
+
|
|
84
|
+
const result = await RunAggregate({ shared, teams, settings, meta, participants, callbacks });
|
|
85
|
+
|
|
86
|
+
// TODO: Add assertions for shared and per-team values
|
|
87
|
+
expect(result.teams).toHaveLength(teams.length);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { InitializationFunction, InitAggregateFunction, RunAggregateFunction } from '@seriousgaming/sdk';
|
|
2
|
+
import type { Context, Settings, Callbacks, SharedContext, TeamContext } from './types';
|
|
3
|
+
|
|
4
|
+
export const Init: InitializationFunction<Context, Settings, Callbacks> = async ({ context, settings, callbacks }) => {
|
|
5
|
+
// Initialise each team's context here. Return the capabilities it writes
|
|
6
|
+
// under `capabilities`: a patch, merged into the team's context. `Init` is
|
|
7
|
+
// optional: delete it and every team starts from the capabilities' defaults.
|
|
8
|
+
return {
|
|
9
|
+
capabilities: {
|
|
10
|
+
...context
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const InitAggregate: InitAggregateFunction<TeamContext, SharedContext, Settings, Callbacks> = async ({ shared, teams, settings, callbacks }) => {
|
|
16
|
+
// Seed shared state from all teams' initial contexts here.
|
|
17
|
+
// `shared.context` is the session's shared store, once; each team's
|
|
18
|
+
// `context` holds only its own capabilities. Write shared capabilities under
|
|
19
|
+
// `shared.capabilities`, and each team's under its `teams` entry, in the
|
|
20
|
+
// same order as the input. A shared capability in a `teams` entry fails.
|
|
21
|
+
return {
|
|
22
|
+
shared: { capabilities: {} },
|
|
23
|
+
teams: teams.map((team) => ({
|
|
24
|
+
capabilities: {
|
|
25
|
+
...team.context
|
|
26
|
+
}
|
|
27
|
+
}))
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const RunAggregate: RunAggregateFunction<TeamContext, SharedContext, Settings, Callbacks> = async ({ shared, teams, settings, callbacks }) => {
|
|
32
|
+
// Run once across all teams each tick, reading the shared store from
|
|
33
|
+
// `shared.context` rather than from any one team
|
|
34
|
+
// Callbacks are narrowed by the engine's `uses` array. To call generateText
|
|
35
|
+
// or extractText, declare them in engine.sdk.json's `uses` field — the
|
|
36
|
+
// runtime throws on any callback that isn't declared. A declared one is
|
|
37
|
+
// always present, so call it directly, without `?.`.
|
|
38
|
+
return {
|
|
39
|
+
shared: { capabilities: {} },
|
|
40
|
+
teams: teams.map((team) => ({
|
|
41
|
+
capabilities: {
|
|
42
|
+
...team.context
|
|
43
|
+
}
|
|
44
|
+
}))
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Participant, TeamRunMeta } from '@seriousgaming/sdk';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { defaultSettings, defaultContext } from './defaults';
|
|
5
|
+
import { Init, Run } from './logic';
|
|
6
|
+
import type { Context, Settings, Callbacks } from './types';
|
|
7
|
+
|
|
8
|
+
// `teamId` and `index` name the team whose context a per-team call receives,
|
|
9
|
+
// `seed` is the session's random seed (a fixed one here keeps an assertion on
|
|
10
|
+
// derived randomness stable), `runKind` says whether this is the game being
|
|
11
|
+
// played or a walkthrough beside it, and `now` is when the operation started
|
|
12
|
+
// (fixed here, as `seed` is, so a test asserting on it is stable). All of them come from the runtime in a
|
|
13
|
+
// real session, so a test has to state them.
|
|
14
|
+
const meta: TeamRunMeta = {
|
|
15
|
+
tick: 0,
|
|
16
|
+
locale: 'en',
|
|
17
|
+
teamId: 'team-1',
|
|
18
|
+
index: 0,
|
|
19
|
+
seed: 'test-seed',
|
|
20
|
+
runKind: 'session',
|
|
21
|
+
now: Date.UTC(2026, 0, 1),
|
|
22
|
+
};
|
|
23
|
+
// The participants on the team, taken when the operation started. Empty here;
|
|
24
|
+
// add records to test logic that reads the roster.
|
|
25
|
+
const participants: Participant[] = [];
|
|
26
|
+
const callbacks = {} as Callbacks;
|
|
27
|
+
|
|
28
|
+
// `defaultContext` and `defaultSettings` are generated beside the types, from
|
|
29
|
+
// the very schemas they satisfy: the values a session opens with. Spread
|
|
30
|
+
// them and name only what the case is about, and a capability added later
|
|
31
|
+
// arrives here already populated rather than breaking every fixture.
|
|
32
|
+
|
|
33
|
+
describe('{{ identifier }}', () => {
|
|
34
|
+
describe('Init', () => {
|
|
35
|
+
it('should initialize context variables', async () => {
|
|
36
|
+
// TODO: override the capabilities this case is about
|
|
37
|
+
const context: Context = { ...defaultContext };
|
|
38
|
+
// TODO: override the settings this case is about
|
|
39
|
+
const settings: Settings = { ...defaultSettings };
|
|
40
|
+
|
|
41
|
+
const { capabilities } = await Init({ context, settings, meta, participants, callbacks });
|
|
42
|
+
|
|
43
|
+
// TODO: Add assertions for initialized values
|
|
44
|
+
expect(capabilities).toBeDefined();
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('Run', () => {
|
|
49
|
+
it('should update context on each tick', async () => {
|
|
50
|
+
// TODO: override the capabilities this case is about
|
|
51
|
+
const context: Context = { ...defaultContext };
|
|
52
|
+
// TODO: override the settings this case is about
|
|
53
|
+
const settings: Settings = { ...defaultSettings };
|
|
54
|
+
|
|
55
|
+
const { capabilities } = await Run({ context, settings, meta, participants, callbacks });
|
|
56
|
+
|
|
57
|
+
// TODO: Add assertions for updated values
|
|
58
|
+
expect(capabilities).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { InitializationFunction, RunFunction } from '@seriousgaming/sdk';
|
|
2
|
+
import type { Context, Settings, Callbacks } from './types';
|
|
3
|
+
|
|
4
|
+
export const Init: InitializationFunction<Context, Settings, Callbacks> = async ({ context, settings, callbacks }) => {
|
|
5
|
+
// Initialise your engine here. Return the capabilities it writes under
|
|
6
|
+
// `capabilities`: a patch, merged into the team's context. `Init` is
|
|
7
|
+
// optional: delete it and every team starts from the capabilities' defaults.
|
|
8
|
+
//
|
|
9
|
+
// Memory only the engine needs between ticks can go under `state` beside
|
|
10
|
+
// `capabilities` instead of in a capability: no surface ever sees it, and
|
|
11
|
+
// undo rewinds it. Type it with the fourth parameter, for example
|
|
12
|
+
// `RunFunction<Context, Settings, Callbacks, EngineState>`, and `Run` receives
|
|
13
|
+
// it back as `state`.
|
|
14
|
+
return {
|
|
15
|
+
capabilities: {
|
|
16
|
+
...context
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Run: RunFunction<Context, Settings, Callbacks> = async ({ context, settings, callbacks }) => {
|
|
22
|
+
// Run your engine logic here
|
|
23
|
+
// Callbacks are narrowed by the engine's `uses` array. To call generateText
|
|
24
|
+
// or extractText, declare them in engine.sdk.json's `uses` field — the
|
|
25
|
+
// runtime throws on any callback that isn't declared. A declared one is
|
|
26
|
+
// always present, so call it directly, without `?.`.
|
|
27
|
+
return {
|
|
28
|
+
capabilities: {
|
|
29
|
+
...context
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# {{ name }} at a glance
|
|
2
|
+
|
|
3
|
+
A one-page summary a facilitator can keep next to the laptop. Replace the placeholders with the real shape of your session.
|
|
4
|
+
|
|
5
|
+
:::timing
|
|
6
|
+
Total session length: about 90 minutes.
|
|
7
|
+
:::
|
|
8
|
+
|
|
9
|
+
| Phase | Duration | Facilitator focus |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Briefing | 15 minutes | Introduce the simulation and form teams |
|
|
12
|
+
| Play | 60 minutes | Run ticks and coach teams between decisions |
|
|
13
|
+
| Debrief | 15 minutes | Connect outcomes to the learning objectives |
|
|
14
|
+
|
|
15
|
+
## Materials
|
|
16
|
+
|
|
17
|
+
- One laptop or tablet per team
|
|
18
|
+
- A room layout that lets teams talk without overhearing each other
|
|
19
|
+
- This guide, printed or on a second screen
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Preparing for the session
|
|
2
|
+
|
|
3
|
+
Everything to do before participants arrive.
|
|
4
|
+
|
|
5
|
+
## Before the day
|
|
6
|
+
|
|
7
|
+
- Read this guide end to end
|
|
8
|
+
- Run the simulation once yourself so the decisions feel familiar
|
|
9
|
+
- Decide team composition and prepare name cards if needed
|
|
10
|
+
|
|
11
|
+
## On the day
|
|
12
|
+
|
|
13
|
+
- Start the session and confirm every team device can reach it
|
|
14
|
+
- Check the room layout gives each team space to confer
|
|
15
|
+
|
|
16
|
+
:::note
|
|
17
|
+
A facilitator new to this simulation should be able to run the session from this guide alone. If a step relies on knowledge that is only in your head, write it down here.
|
|
18
|
+
:::
|