@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,133 @@
|
|
|
1
|
+
# Adapt a game for walkthroughs
|
|
2
|
+
|
|
3
|
+
**Keywords:** walkthrough, runKind, meta.runKind, useRunKind, demonstrate the game, demo run, rehearse, facilitator walkthrough, show the room, spoiler, solo run, resetWalkthrough, walkthrough link
|
|
4
|
+
|
|
5
|
+
A walkthrough is a disposable second run of your game beside the session, for demonstrating it: one team, one participant, always from tick 0, and isolated from the session in both directions. It is what a facilitator puts on a projector while talking a room through the game before they play it.
|
|
6
|
+
|
|
7
|
+
Most games need no changes. Reach for this when a solo run is missing something a group has, or when a tick reaches outside for something you would rather not pay for or wait on in front of a room.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- A game with an engine (see [Create an engine](create-engine.md))
|
|
12
|
+
- The dev server running (`pnpm run sdk dev`)
|
|
13
|
+
|
|
14
|
+
## Steps
|
|
15
|
+
|
|
16
|
+
1. Open the walkthrough and see what your game looks like in it. It is at `/walkthrough`, and in the dev drawer's Surfaces tab:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pnpm run sdk dev
|
|
20
|
+
# then open http://localhost:3000/walkthrough
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The run is built the first time you open it. Nothing to create, nothing to clean up.
|
|
24
|
+
|
|
25
|
+
2. Read the run kind in logic. `meta.runKind` is `'session'` or `'walkthrough'`:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
export const Run: RunFunction<Context, Settings> = async ({ context, meta, callbacks }) => {
|
|
29
|
+
if (meta.runKind === 'walkthrough') {
|
|
30
|
+
// ...
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Hooks, endpoints and validators read it the same way, from their own `meta`.
|
|
36
|
+
|
|
37
|
+
3. Read it in a surface with `useRunKind()`:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { useRunKind } from '@seriousgaming/sdk/ui';
|
|
41
|
+
|
|
42
|
+
const runKind = useRunKind();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
It is the same value your engine reads, and neither changes for the life of the run, so a decision taken here cannot disagree with one taken in logic.
|
|
46
|
+
|
|
47
|
+
4. Fill in what a solo run genuinely lacks. A walkthrough has one team, so anything that compares teams has nobody to compare against:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
function Leaderboard() {
|
|
51
|
+
const runKind = useRunKind();
|
|
52
|
+
const data = useUserInterfaceData();
|
|
53
|
+
|
|
54
|
+
// One row is worse than no board: it teaches the room the wrong shape.
|
|
55
|
+
const rows = runKind === 'walkthrough' ? demonstrationRows : data.market.Standings;
|
|
56
|
+
|
|
57
|
+
return <Board rows={rows} />;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
5. Suppress what reaches outside. A model call is real spend, real latency, and a different answer every time, none of which you want on a projector:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const commentary =
|
|
65
|
+
meta.runKind === 'walkthrough'
|
|
66
|
+
? writtenCommentary(context)
|
|
67
|
+
: getText(await callbacks.generateText(prompt(context)));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Prefer a path your game already has. If it falls back to written text when the model is unavailable, route the walkthrough through that same fallback, so the demonstration is not a third behaviour nobody tests.
|
|
71
|
+
|
|
72
|
+
6. Offer the walkthrough from your session UI, if you have one. Gate the control on the link, so it never appears on a host that has no walkthrough to open:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
function WalkthroughControls() {
|
|
76
|
+
const walkthrough = useSessionUserInterfaceWalkthroughLink();
|
|
77
|
+
const { resetWalkthrough } = useSessionUserInterfaceCallbacks();
|
|
78
|
+
|
|
79
|
+
if (!walkthrough) return null;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<>
|
|
83
|
+
<Button href={walkthrough.url} target="_blank" rel="noreferrer">
|
|
84
|
+
Walkthrough
|
|
85
|
+
</Button>
|
|
86
|
+
<Button onClick={() => void resetWalkthrough()}>Start it again</Button>
|
|
87
|
+
</>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
7. Test both paths. `runKind` is an ordinary field on `meta`, so build the arguments with `logicArgs`, and the render helpers take it as an option:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { logicArgs } from '@seriousgaming/sdk/testing';
|
|
96
|
+
|
|
97
|
+
import { defaultContext, defaultSettings } from './defaults';
|
|
98
|
+
|
|
99
|
+
const result = await Run(
|
|
100
|
+
logicArgs.run({
|
|
101
|
+
context: defaultContext,
|
|
102
|
+
settings: defaultSettings,
|
|
103
|
+
meta: { runKind: 'walkthrough' },
|
|
104
|
+
})
|
|
105
|
+
);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
renderUserInterface(<Leaderboard />, { runKind: 'walkthrough' });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Hold one line throughout: fill in the social context a solo run lacks, and suppress spoilers and outside calls, but never change how the game plays. If the walkthrough invents a figure the game would not produce, it has gone too far.
|
|
113
|
+
|
|
114
|
+
## Verify
|
|
115
|
+
|
|
116
|
+
- `pnpm run sdk view --walkthrough` reports `"runKind": "walkthrough"`, one team, and tick 0
|
|
117
|
+
- `pnpm run sdk tick --walkthrough` advances the walkthrough and leaves `pnpm run sdk view` on the session unchanged
|
|
118
|
+
- The walkthrough never shows the waiting room, even for a game with `waitingRoom.openOnStart`
|
|
119
|
+
- `pnpm run sdk reset --walkthrough` returns it to tick 0
|
|
120
|
+
- A game that reads `runKind` nowhere behaves exactly as it did before
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
- **`meta.runKind` is always `'session'`**: you are looking at the session, not the walkthrough. In `sdk dev`, open `/walkthrough` or pass `--walkthrough`
|
|
125
|
+
- **The walkthrough asks for configuration**: it should not. It resolves settings exactly as its session does. If your game has a `setup` slot, commit the session's configuration first, then open the walkthrough
|
|
126
|
+
- **A shared-state game runs the walkthrough with one team**: that is deliberate. `teams.min` says what the game needs to be _played_, and a walkthrough is not play. Use `runKind` to fill in the teams that are not there
|
|
127
|
+
- **The walkthrough's generated content differs from the session's**: the two runs draw separate seeds, so anything derived from `meta.seed` differs between them. Rely on the shape of the screen rather than on a specific generated value when rehearsing
|
|
128
|
+
|
|
129
|
+
## Related
|
|
130
|
+
|
|
131
|
+
- [Engines guide, walkthroughs](../guides/engine.md#walkthroughs)
|
|
132
|
+
- [Building user interfaces guide, walkthroughs](../guides/ui.md#walkthroughs)
|
|
133
|
+
- [Adapt a UI for observers](adapt-ui-for-observers.md)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Adapt a UI for observers
|
|
2
|
+
|
|
3
|
+
**Keywords:** observer, observe team, viewer role, useUserInterfaceViewerRole, facilitator peek, debrief, null participant, own team, useUserInterfaceOwnTeam, which team am I
|
|
4
|
+
|
|
5
|
+
An observer is a facilitator watching one team's live game UI without joining as a team member. It is useful for seeing how a team is playing, troubleshooting, or running a debrief. Your game UI is rendered for observers as well as participants; most UIs work unchanged, and you reach for this only when you want the game UI to behave differently under observation.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A game UI (see [Create a user interface](create-user-interface.md))
|
|
10
|
+
- The dev server running (`pnpm run sdk dev`) with at least one team
|
|
11
|
+
|
|
12
|
+
## Steps
|
|
13
|
+
|
|
14
|
+
1. Read the viewer role with `useUserInterfaceViewerRole()`. It returns `'participant'` or `'observer'` and is always present:
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { useUserInterfaceViewerRole } from '@seriousgaming/sdk/ui';
|
|
18
|
+
|
|
19
|
+
const isObserver = useUserInterfaceViewerRole() === 'observer';
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. Guard reads of the participant. An observer has no caller identity, so `useUserInterfaceParticipant()` returns `null`:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { useUserInterfaceParticipant } from '@seriousgaming/sdk/ui';
|
|
26
|
+
|
|
27
|
+
const participant = useUserInterfaceParticipant(); // null when observing
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
3. Do **not** reach for the participant to find out which team you are rendering. Use `useUserInterfaceOwnTeam()`, which is populated for observers and participants alike:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { useUserInterfaceOwnTeam } from '@seriousgaming/sdk/ui';
|
|
34
|
+
|
|
35
|
+
const ownTeam = useUserInterfaceOwnTeam(); // { teamId, index, name }, not null under observation
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This is the read most often missed. `participant.teamId` is the obvious route and it silently becomes `null` when observed, so anything keyed off it (splitting a `useUserInterfaceCrossTeamData()` result into 'mine' and 'theirs', labelling a board, picking a row to highlight) breaks only in the observer view. Note that `useUserInterfaceTeams()` is the plural hook: it lists every team in the session and does not mark which is yours.
|
|
39
|
+
|
|
40
|
+
4. Adapt the game UI. Hide participant-only controls (anything keyed by participant id has no id to write under), reveal state you keep hidden during play, or present a read-only debrief view:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
function Decisions() {
|
|
44
|
+
const isObserver = useUserInterfaceViewerRole() === 'observer';
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
{isObserver && <Banner>Observing: watching this team, not playing</Banner>}
|
|
49
|
+
<PriceInput readOnly={isObserver} />
|
|
50
|
+
{!isObserver && <SubmitNoteForm />}
|
|
51
|
+
</>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
5. Open the observer view at `/team/<n>/observe`. It renders the same game UI with no participant identity and no presence.
|
|
57
|
+
|
|
58
|
+
## Verify
|
|
59
|
+
|
|
60
|
+
- The observer view shows the same live state as the participant view, and updates as the game ticks
|
|
61
|
+
- `useUserInterfaceViewerRole()` reads `'observer'` and `useUserInterfaceParticipant()` is `null` in the observer view
|
|
62
|
+
- `useUserInterfaceOwnTeam()` still returns the observed team, so anything labelled 'yours' stays correct
|
|
63
|
+
- The observer does not appear in the team roster (`useUserInterfaceParticipants()`) and no presence indicator lights up for them
|
|
64
|
+
|
|
65
|
+
## Troubleshooting
|
|
66
|
+
|
|
67
|
+
- **The UI crashes reading `participant.name` when observing**: `useUserInterfaceParticipant()` is `null` for an observer. Guard for `null` before reading its fields
|
|
68
|
+
- **Cross-team lists stop marking which team is yours when observing**: you are deriving own-team from `participant.teamId`, which is `null` under observation. Switch to `useUserInterfaceOwnTeam()`
|
|
69
|
+
- **`useUserInterfaceOwnTeam()` returns `null`**: the host is not sending an own team and there is no participant to fall back on. Against the dev server this should not happen on a game UI; on a hosted runtime that does not send the own team, an observer reads `null`
|
|
70
|
+
|
|
71
|
+
## Related
|
|
72
|
+
|
|
73
|
+
- [User interfaces guide: observers](../guides/ui.md#observers)
|
|
74
|
+
- [Observe other teams' state](observe-other-teams-state.md)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Call an endpoint from a UI
|
|
2
|
+
|
|
3
|
+
**Keywords:** call endpoint, invoke endpoint, callbacks.endpoints, UI endpoint, request response, EndpointError, endpoint failure
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- An [endpoint](create-endpoint.md) already scaffolded in the same package (or installed via another package)
|
|
8
|
+
- A user interface, session UI, setup screen, or scenario editor to call it from
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Declare the endpoint on the UI bundle. Edit the UI's bundle (`ui/ui.sdk.json`, `session/session.sdk.json`, `waiting_room/waiting_room.sdk.json`, `setup/setup.sdk.json`, or `scenario_editor/scenario_editor.sdk.json`) and add the endpoint identifier to the `endpoints` array:
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"definition": {
|
|
17
|
+
"endpoints": ["summarise"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Run `pnpm run sdk generate` (or any `new`/`update` resource command) to regenerate the UI's `types.ts`. The generator merges a typed `Endpoints` interface into the UI's `Callbacks` type.
|
|
23
|
+
|
|
24
|
+
2. Use the endpoint from the UI. Access it on the callbacks context exposed by the wrapper:
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { useUserInterfaceCallbacks } from '@seriousgaming/sdk/ui';
|
|
28
|
+
import type { Callbacks } from '../types';
|
|
29
|
+
|
|
30
|
+
function ReportButton({ reportText }: { reportText: string }) {
|
|
31
|
+
// The generated Callbacks narrows `endpoints` to the ones this UI declares
|
|
32
|
+
const { endpoints } = useUserInterfaceCallbacks() as unknown as Callbacks;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<button
|
|
36
|
+
onClick={async () => {
|
|
37
|
+
const { summary } = await endpoints['summarise']({
|
|
38
|
+
text: reportText,
|
|
39
|
+
});
|
|
40
|
+
console.log(summary);
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
Summarise
|
|
44
|
+
</button>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`request` is typed from the endpoint's `requestSchema`. The returned promise resolves with the value validated against `responseSchema`.
|
|
50
|
+
|
|
51
|
+
3. Handle errors. A failed call rejects with an `EndpointError`. Its `kind` says why, and its `applied` lists the effects that had already landed before it stopped:
|
|
52
|
+
|
|
53
|
+
| `kind` | What happened |
|
|
54
|
+
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `denied` | The UI does not list the endpoint, or the call was refused before the request was read. Nothing changed |
|
|
56
|
+
| `invalid-request` | The request does not match `requestSchema`. The handler did not run |
|
|
57
|
+
| `handler-error` | The handler threw, or ran past its time limit |
|
|
58
|
+
| `invalid-response` | The handler returned something its declaration forbids, such as a response that does not match `responseSchema` |
|
|
59
|
+
| `conflict` | A round started while the handler ran, so nothing was applied. A person may try again |
|
|
60
|
+
| `tick-failed`, or another step's own kind | One of the endpoint's actions failed once applied. `applied` lists what landed before it, and `failedStep` names it |
|
|
61
|
+
| `error` | Anything else |
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { EndpointError } from '@seriousgaming/sdk/ui';
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { summary } = await endpoints['summarise']({ text: reportText });
|
|
68
|
+
setSummary(summary);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (error instanceof EndpointError && error.applied.length > 0) {
|
|
71
|
+
// Part of the endpoint's work landed before it stopped
|
|
72
|
+
setNotice(`Some changes were saved, then: ${error.message}`);
|
|
73
|
+
} else {
|
|
74
|
+
setNotice(error instanceof Error ? error.message : String(error));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
An empty `applied` means nothing changed. A non-empty one means the session moved, so do not tell the person their action had no effect.
|
|
80
|
+
|
|
81
|
+
4. (Optional) Return binary data. If the endpoint produces audio, images, or files, it returns a `blob:<id>` reference in the JSON response. Resolve it the same way as any blob reference:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const { getAssetUrl } = useUserInterfaceCallbacks();
|
|
85
|
+
const { endpoints } = useUserInterfaceCallbacks() as unknown as Callbacks;
|
|
86
|
+
|
|
87
|
+
const { audioRef } = await endpoints['narrate']({ text });
|
|
88
|
+
const src = getAssetUrl?.(audioRef);
|
|
89
|
+
<audio src={src} controls autoPlay />
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`getAssetUrl` comes from the untyped callbacks, since the generated `Callbacks` carries `endpoints` alone.
|
|
93
|
+
|
|
94
|
+
## Verify
|
|
95
|
+
|
|
96
|
+
- TypeScript: removing the endpoint identifier from the UI's `endpoints` array makes `callbacks.endpoints['summarise']` a type error
|
|
97
|
+
- Runtime: removing the endpoint identifier from the UI's `endpoints` array makes the call reject with an `EndpointError` of kind `denied` and the message _'"ui" does not list endpoint "summarise" in its endpoints'_
|
|
98
|
+
|
|
99
|
+
## Troubleshooting
|
|
100
|
+
|
|
101
|
+
- _'"ui" does not list endpoint "X" in its endpoints'_: add the endpoint identifier to the UI's `endpoints` array, then regenerate types
|
|
102
|
+
- _'Endpoint "X" rejected the request: ...'_ (`invalid-request`): your payload does not match `requestSchema`. Compare your call against the endpoint's request schema
|
|
103
|
+
- _'Endpoint "X" returned a response its schema forbids: ...'_ (`invalid-response`): the endpoint handler is returning a value that does not match `responseSchema`. Fix the handler or widen the schema
|
|
104
|
+
- _'Endpoint "X" stopped at action 1 ("tick"): ...'_: the endpoint's write and earlier actions landed, then an action failed. `error.applied` and `error.failedStep` say which
|
|
105
|
+
|
|
106
|
+
## Related
|
|
107
|
+
|
|
108
|
+
- [Create an endpoint](create-endpoint.md)
|
|
109
|
+
- [Endpoints (concept)](../guides/endpoints.md)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Check a package from a script
|
|
2
|
+
|
|
3
|
+
Validate a package and play a few ticks from CI or an AI agent, and turn each failure into the file and line to fix.
|
|
4
|
+
|
|
5
|
+
**Keywords:** ci, agent, script, json, exit code, diagnostics, validate, automation, error code, pointer, source map
|
|
6
|
+
|
|
7
|
+
## What you'll build
|
|
8
|
+
|
|
9
|
+
A check that runs `build --validate-only` and a couple of ticks, branches on the exit code, and reads `diagnostics[]` to report each problem where it is: a JSON pointer into a bundle, or a line and column in your TypeScript.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- A package with `seriousgaming.sdk.json` in the working directory
|
|
14
|
+
- `jq`, or any language that parses JSON
|
|
15
|
+
|
|
16
|
+
## Steps
|
|
17
|
+
|
|
18
|
+
### 1. Ask for one JSON document
|
|
19
|
+
|
|
20
|
+
Pass `--json`, or set `SERIOUSGAMING_JSON=1` once for the whole job, and every command writes exactly one envelope to stdout. Run it through `pnpm run --silent` so pnpm's banner does not land on stdout before it.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
export SERIOUSGAMING_JSON=1
|
|
24
|
+
pnpm run --silent sdk build --validate-only > validate.json
|
|
25
|
+
status=$?
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Setting `SERIOUSGAMING_JSON` (or `CI`) also turns prompts off: a command that would have to ask fails with exit code 2 and `PROMPT_REQUIRED` instead of waiting.
|
|
29
|
+
|
|
30
|
+
### 2. Branch on the exit code
|
|
31
|
+
|
|
32
|
+
0 is success and 3 an invalid package; the others are in [Exit codes](../cli-reference.md#exit-codes).
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
case $status in
|
|
36
|
+
0) echo "Package is valid" ;;
|
|
37
|
+
3) echo "Package is invalid" ;;
|
|
38
|
+
*) jq -r '.error.code + ": " + .error.message' validate.json; exit $status ;;
|
|
39
|
+
esac
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Read the diagnostics
|
|
43
|
+
|
|
44
|
+
Each diagnostic names a `file` relative to the package root, and either a `pointer` (RFC 6901, into a JSON file) or a `line` and `column` (in a source file). Branch on `code`; the `message` is for people.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
jq -r '.diagnostics[]
|
|
48
|
+
| "\(.severity) \(.code) \(.file // "-")\(if .pointer then "#" + .pointer elif .line then ":\(.line):\(.column)" else "" end)\n \(.message)\(if .hint then "\n hint: " + .hint else "" end)"' validate.json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
error SETTINGS_UNKNOWN_KEY scenarios/hard/scenario.sdk.json#/definition/settings/engine/BaseDemnd
|
|
53
|
+
Overrides "BaseDemnd", which settings "engine" does not declare
|
|
54
|
+
hint: Did you mean 'BaseDemand'?
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A passing build can still have warnings. They are in the success envelope's `diagnostics`, with `"severity": "warning"`.
|
|
58
|
+
|
|
59
|
+
### 4. Play a tick and catch a logic error
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pnpm run --silent sdk tick --no-server > tick.json || jq '.diagnostics[] | select(.code == "LOGIC_ERROR")' tick.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When the engine throws, `tick` exits 4 with `error.code` `TICK_FAILED`, and the first diagnostic says where, read back through the bundle's source map, with the tick and team:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"severity": "error",
|
|
70
|
+
"code": "LOGIC_ERROR",
|
|
71
|
+
"message": "the first round has no stock",
|
|
72
|
+
"file": "engine/logic.ts",
|
|
73
|
+
"line": 13,
|
|
74
|
+
"column": 15,
|
|
75
|
+
"resource": { "type": "engine", "identifier": "engine" },
|
|
76
|
+
"tick": 1,
|
|
77
|
+
"team": { "teamId": "team-1", "index": 0 }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`--no-server` runs the session in the command's own process and leaves nothing behind, so each command starts from tick 0, and `tick` initialises the session before it plays. To play several ticks in a row, leave it off: the first command starts a background dev server, and `pnpm run sdk dev stop` stops it at the end of the job.
|
|
82
|
+
|
|
83
|
+
### 5. Do the same from Node
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { execFile } from 'node:child_process';
|
|
87
|
+
|
|
88
|
+
execFile(
|
|
89
|
+
'pnpm',
|
|
90
|
+
['run', '--silent', 'sdk', 'build', '--validate-only', '--json'],
|
|
91
|
+
(error, stdout) => {
|
|
92
|
+
const envelope = JSON.parse(stdout);
|
|
93
|
+
if (envelope.ok) return;
|
|
94
|
+
for (const diagnostic of envelope.diagnostics) {
|
|
95
|
+
const where = diagnostic.pointer ?? `${diagnostic.line}:${diagnostic.column}`;
|
|
96
|
+
console.log(`${diagnostic.code} ${diagnostic.file} ${where}: ${diagnostic.message}`);
|
|
97
|
+
}
|
|
98
|
+
process.exitCode = error?.code ?? 1;
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Verify
|
|
104
|
+
|
|
105
|
+
- Misspell a key in a scenario's `settings` and run step 1: the exit code is 3 and a `SETTINGS_UNKNOWN_KEY` diagnostic points at the key
|
|
106
|
+
- Fix it and run step 1 again: the exit code is 0
|
|
107
|
+
|
|
108
|
+
## Troubleshooting
|
|
109
|
+
|
|
110
|
+
- **`JSON.parse` fails on the first line**: pnpm printed its banner on stdout. Add `--silent` to `pnpm run`
|
|
111
|
+
- **A diagnostic has no `file`**: the check could not tie the finding to one file. Its `resource` and `message` still say what it is about
|
|
112
|
+
- **`LOGIC_ERROR` has no `line`**: the throw came from somewhere other than your bundle's own frames, such as a timeout. The `resource` says which logic it was
|
|
113
|
+
|
|
114
|
+
## Related
|
|
115
|
+
|
|
116
|
+
- [CLI reference: exit codes, JSON output and diagnostics](../cli-reference.md#exit-codes)
|
|
117
|
+
- [Publish a package to the Serious Gaming platform](publish-a-package.md)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Create a capability
|
|
2
|
+
|
|
3
|
+
Define a named slice of the game's state that the engine and screens read and write.
|
|
4
|
+
|
|
5
|
+
**Keywords:** create capability, new capability, capability variables, data structure, capability schema, variablesSchema, scope
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- A package with `seriousgaming.sdk.json` in your working directory
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Create the capability. Its identifier is its directory name, and every variable declares a `type` and a `default`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm run sdk new capability '{
|
|
17
|
+
"definition": {
|
|
18
|
+
"identifier": "pricing",
|
|
19
|
+
"variablesSchema": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"BasePrice": { "type": "number", "default": 100, "minimum": 0, "description": "Price before adjustments" },
|
|
23
|
+
"CurrentPrice": { "type": "number", "default": 100, "minimum": 0, "description": "Price after adjustments" }
|
|
24
|
+
},
|
|
25
|
+
"required": ["BasePrice", "CurrentPrice"],
|
|
26
|
+
"additionalProperties": false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This writes `capabilities/pricing/capability.sdk.json`. For nested objects, arrays, and keyed collections, see [Variable types](../guides/capabilities.md#variable-types).
|
|
33
|
+
|
|
34
|
+
2. Optional: give it a `scope` other than the default `team`, by adding `"scope"` to the `definition` above: `shared` for one value across all teams, `team-readable` for a per-team value other teams may watch, or `private` for engine bookkeeping no screen receives. See [Scope](../guides/capabilities.md#scope).
|
|
35
|
+
|
|
36
|
+
3. Declare it on each resource that uses it, in `reads` or `writes`. For the engine:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm run sdk update engine --patch '[
|
|
40
|
+
{ "op": "add", "path": "/definition/writes/-", "value": "pricing" }
|
|
41
|
+
]'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The command regenerates that resource's `types.ts`, so `context.pricing` is typed.
|
|
45
|
+
|
|
46
|
+
## Verify
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm run sdk init
|
|
50
|
+
pnpm run sdk view
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The team's context holds `pricing` with its defaults.
|
|
54
|
+
|
|
55
|
+
## Troubleshooting
|
|
56
|
+
|
|
57
|
+
| Problem | Solution |
|
|
58
|
+
| ------------------------------------ | --------------------------------------------------------------------------- |
|
|
59
|
+
| A resource cannot see the capability | Declare it in that resource's `reads` or `writes`; it receives nothing else |
|
|
60
|
+
| The build rejects a default | The default does not match the variable's `type` |
|
|
61
|
+
|
|
62
|
+
## Related
|
|
63
|
+
|
|
64
|
+
- [Capabilities guide](../guides/capabilities.md): the state model, scope, lifetime, and variable types
|
|
65
|
+
- [Create an engine](create-engine.md)
|
|
66
|
+
- [Design state for concurrent writes](design-state-for-concurrent-writes.md)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Create an endpoint
|
|
2
|
+
|
|
3
|
+
**Keywords:** create endpoint, new endpoint, server handler, callable handler, scaffold endpoint
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- A package with a valid `seriousgaming.sdk.json`
|
|
8
|
+
- A UI that will call the endpoint (or plan to add one)
|
|
9
|
+
- Optional: capabilities the endpoint will read
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Scaffold the endpoint:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm run sdk new endpoint
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Interactive mode prompts for a short identifier and the request and response properties. Alternatively pass a JSON definition:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm run sdk new endpoint '{
|
|
23
|
+
"definition": {
|
|
24
|
+
"identifier": "summarise",
|
|
25
|
+
"requestSchema": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": { "text": { "type": "string" } },
|
|
28
|
+
"required": ["text"],
|
|
29
|
+
"additionalProperties": false
|
|
30
|
+
},
|
|
31
|
+
"responseSchema": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": { "summary": { "type": "string" } },
|
|
34
|
+
"required": ["summary"],
|
|
35
|
+
"additionalProperties": false
|
|
36
|
+
},
|
|
37
|
+
"uses": ["generateText"]
|
|
38
|
+
},
|
|
39
|
+
"logic": { "directory": "logic", "entrypoint": "logic.ts" },
|
|
40
|
+
"rootDirectory": "."
|
|
41
|
+
}'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Fill in the handler at `endpoints/<identifier>/logic/logic.ts`:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { getText } from '@seriousgaming/sdk';
|
|
48
|
+
|
|
49
|
+
import type { Handler } from '../types';
|
|
50
|
+
|
|
51
|
+
export const Handle: Handler = async ({ request, callbacks, caller }) => {
|
|
52
|
+
const response = await callbacks.generateText({
|
|
53
|
+
prompt: `Summarise this text in one sentence: ${request.text}`,
|
|
54
|
+
});
|
|
55
|
+
return { summary: getText(response) };
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The signature is `({ request, context, callbacks, caller, team, meta }) => Promise<Response>`, where `team` is the team a team-scoped call runs for. A session-scoped handler has no `team`. An endpoint that declares no `writes` cannot change state: return only what fits the declared `responseSchema`.
|
|
60
|
+
|
|
61
|
+
To change state, declare the capabilities you may write and return the change alongside the response. `scope`, `writes`, and `visibility` can go straight into the `definition` you pass to `new endpoint`, which then scaffolds a handler of the writing shape:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{ "scope": "team", "writes": ["price"] }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
export const Handle: Handler = async ({ request, context }) => ({
|
|
69
|
+
response: { previous: context.price.Price, current: request.price },
|
|
70
|
+
capabilities: { price: { ...context.price, Price: request.price } },
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The generated `Handler` type switches shape when `writes` is present, so the compiler tells you which one you owe, and a writing endpoint that returns a bare value is refused at run time. Writes are held to the declaration, and are not put to the game's validators: see [Endpoints (concept)](../guides/endpoints.md#endpoints-and-validators) for why.
|
|
75
|
+
|
|
76
|
+
3. Set the scope if the endpoint is not called against a single team:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{ "scope": "session" }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`scope` defaults to `'team'`, which gives the handler that team's board and a `team` naming it: `team.teamId`, `team.index` and `team.name`. Use `team`, not `caller`, to find the team's own row in anything keyed by team: `caller` says who is calling, and a facilitator's agent or the CLI calls on a team's behalf without being on it, so its `caller.teamId` is absent. `caller.teamId` is set only for a participant or an observer, and names their own team. A session UI, a setup screen, or a scenario editor has no team of its own, so calling a team-scoped endpoint from one fails the build.
|
|
83
|
+
|
|
84
|
+
4. Declare the endpoint on every UI that should be allowed to call it:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"definition": {
|
|
89
|
+
"endpoints": ["summarise"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
UIs that don't list the endpoint cannot call it. Add the identifier to each consuming UI's `endpoints` array.
|
|
95
|
+
|
|
96
|
+
5. Use the endpoint from the UI. The generated `types.ts` makes `callbacks.endpoints` strongly typed:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const { summary } = await callbacks.endpoints['summarise']({
|
|
100
|
+
text: 'lots of text here',
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Verify
|
|
105
|
+
|
|
106
|
+
- `pnpm run sdk endpoint list` shows the endpoint with its scope and whether it writes
|
|
107
|
+
- `pnpm run sdk endpoint call <identifier> --team 1 --request '{...}'` runs it without a UI
|
|
108
|
+
- `pnpm run sdk generate` (or any `new`/`update` command) produces `endpoints/<identifier>/types.ts` with `Request`, `Response`, `Context`, and `Handler` exports (plus `Writes`, where the endpoint declares any)
|
|
109
|
+
- Calling an undeclared endpoint from a UI is a TypeScript error
|
|
110
|
+
- The dev server rejects calls when the UI did not declare the endpoint or when the request shape does not match `requestSchema`
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
- _'Endpoint X not found in configuration'_: re-run `pnpm run sdk generate`; the endpoint's bundle must sit at `endpoints/<identifier>/endpoint.sdk.json`
|
|
115
|
+
- _'Endpoint "X" rejected the request: \<path\> must have required property ...'_: the iframe sent a payload that does not match `requestSchema`. Check that the UI's call matches the declared request shape
|
|
116
|
+
- _'"ui" does not list endpoint "X" in its endpoints'_: add the endpoint identifier to the UI's `endpoints` array
|
|
117
|
+
- _'Resource "X" attempted to call callback "Y" but did not declare it in its bundle's "uses" array'_: add the `ApiUse` value to the endpoint bundle's `uses` array
|
|
118
|
+
- _'which is team-scoped, but this surface has no team of its own'_: a session UI, setup screen, or scenario editor is calling it; set `"scope": "session"` on the endpoint
|
|
119
|
+
- _'wrote X, which it does not declare in writes'_: the handler returned a capability outside its `writes`; add it, or stop returning it
|
|
120
|
+
- _'The game moved on while the endpoint was running'_: a tick committed mid-call, so the patch was computed against a board that no longer exists. Make the handler faster, or move the work into the engine
|
|
121
|
+
|
|
122
|
+
## Related
|
|
123
|
+
|
|
124
|
+
- [Make an endpoint callable from outside the game](make-an-endpoint-external.md)
|
|
125
|
+
- [Call an endpoint from a UI](call-endpoint-from-ui.md)
|
|
126
|
+
- [Declare API uses](declare-api-uses.md)
|
|
127
|
+
- [Endpoints (concept)](../guides/endpoints.md)
|