@seriousgaming/sdk-tools 0.0.0-stage → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +93 -0
- package/README.md +36 -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 +27368 -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 +16884 -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 +209 -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 +236 -0
- package/dist/docs/cli-and-dev-server.md +217 -0
- package/dist/docs/cli-error-codes.md +154 -0
- package/dist/docs/cli-reference.md +2488 -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 +575 -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 +335 -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 +122 -3
|
@@ -0,0 +1,2488 @@
|
|
|
1
|
+
<!-- Generated by `pnpm docs:generate` from `sdk-tools/cli/program.ts`, the resource registry and `sdk-tools/docs-partials/cli-reference/`. Edit those, not this file. -->
|
|
2
|
+
|
|
3
|
+
# CLI reference
|
|
4
|
+
|
|
5
|
+
Every `seriousgaming-sdk` command and flag, in one place. For a worked session that strings these commands together, see [Drive a game from the CLI](./cli-simulation-testing.md).
|
|
6
|
+
|
|
7
|
+
## Command structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
pnpm run sdk [options] <command> [arguments]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Global options
|
|
14
|
+
|
|
15
|
+
The program's own options, which work with every command:
|
|
16
|
+
|
|
17
|
+
| Option | Default | Description |
|
|
18
|
+
| --------------- | ------- | ----------------------- |
|
|
19
|
+
| `-v, --verbose` | | Enable verbose logging. |
|
|
20
|
+
|
|
21
|
+
Every command also takes `-j, --json` (see [JSON output](#json-output)). `-j, --json` and `-w, --working-dir` may come before the command as well as after it, so `sdk --json -w ./game view` is `sdk view --json -w ./game`.
|
|
22
|
+
|
|
23
|
+
### Verbose mode
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm run sdk --verbose <command>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`-v, --verbose` works on every command. It is a flag only: no configuration file or environment variable turns it on.
|
|
30
|
+
|
|
31
|
+
By default the CLI prints as little as it can, which suits scripts, CI, and agents that parse its output:
|
|
32
|
+
|
|
33
|
+
- Errors and warnings always appear
|
|
34
|
+
- Validation reports problems only, not the checks that passed
|
|
35
|
+
- Progress from Vite and the TypeScript compiler is suppressed
|
|
36
|
+
- Type generation and configuration loading run silently
|
|
37
|
+
- The final summary (`✓ Build complete!`) always appears
|
|
38
|
+
|
|
39
|
+
With `--verbose` you also see:
|
|
40
|
+
|
|
41
|
+
- Each configuration file as it loads
|
|
42
|
+
- The validation result for every resource, including the ones that passed
|
|
43
|
+
- Type generation for each resource
|
|
44
|
+
- Each build step, with Vite and TypeScript output
|
|
45
|
+
- Asset copying and file generation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm run sdk build --verbose
|
|
49
|
+
pnpm run sdk generate --verbose
|
|
50
|
+
pnpm run sdk resolve --verbose
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
A verbose build looks like this:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
Step 1: Loading configuration...
|
|
57
|
+
Loaded: capabilities/counter/capability.sdk.json
|
|
58
|
+
Loaded: settings/engine/settings.sdk.json
|
|
59
|
+
Loaded: engine/engine.sdk.json
|
|
60
|
+
Loaded: ui/ui.sdk.json
|
|
61
|
+
...
|
|
62
|
+
Found 1 capabilities, an engine, 1 user interfaces, 0 settings editors, 0 tick controllers, 0 hooks, and 0 validators
|
|
63
|
+
|
|
64
|
+
Step 2: Validating...
|
|
65
|
+
...
|
|
66
|
+
package "com.e2e" is valid
|
|
67
|
+
capability "counter" is valid
|
|
68
|
+
engine "engine" is valid
|
|
69
|
+
ui "ui" is valid
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
Step 3: Generating types...
|
|
73
|
+
Generating types for module engine
|
|
74
|
+
Generating types for engine...
|
|
75
|
+
Generated /path/to/engine/types.ts
|
|
76
|
+
Generated /path/to/engine/defaults.ts
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
✓ Build complete!
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
What each kind of output looks like, and when it appears:
|
|
83
|
+
|
|
84
|
+
| Output | Default | `--verbose` | Example |
|
|
85
|
+
| ------------------------------------ | ------- | ----------- | ---------------------------------------------------------------------------------- |
|
|
86
|
+
| Errors | Shown | Shown | `Engine "engine" reads capability "invalid" which is not found in configuration` |
|
|
87
|
+
| Warnings | Shown | Shown | `⚠️ Engine "engine" declares a read of capability "forecast", but no engine, ...` |
|
|
88
|
+
| Progress and debug detail | Hidden | Shown | `Loaded: capabilities/price/capability.sdk.json` |
|
|
89
|
+
| Per-resource success lines | Hidden | Shown | `game "com.e2e.game" is valid` |
|
|
90
|
+
| Vite, TypeScript, and process output | Hidden | Shown | `✓ 1176 modules transformed.` |
|
|
91
|
+
|
|
92
|
+
To diagnose a failing build, rerun it verbose and keep the log:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pnpm run build --verbose 2>&1 | tee build.log
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Exit codes
|
|
99
|
+
|
|
100
|
+
Every command exits with one of six codes, and the code says what kind of failure it was. Scripts, CI and agents branch on it; the message is for people and may change.
|
|
101
|
+
|
|
102
|
+
| Code | Meaning | Examples |
|
|
103
|
+
| ---- | ------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
104
|
+
| 0 | Success | |
|
|
105
|
+
| 1 | Unexpected internal error | A bug in the CLI. Please report it |
|
|
106
|
+
| 2 | Usage error | An unknown flag, a bad argument, missing input, a prompt needed with no terminal to ask on |
|
|
107
|
+
| 3 | Invalid package | A schema or validation failure, a missing `seriousgaming.sdk.json`, a logic file that will not bundle |
|
|
108
|
+
| 4 | Refused by the game | A denied command, a validator rejection, a conflict, a failed tick, a superseded write, a failed endpoint |
|
|
109
|
+
| 5 | Environment | No session running, a port in use, a dev server already running, the platform unreachable or unauthorised |
|
|
110
|
+
|
|
111
|
+
Each failure also carries a stable error code in `UPPER_SNAKE` case, such as `MANIFEST_NOT_FOUND`, `REFUSED_VALIDATION` or `NO_SESSION`. The codes are the contract, and each belongs to one exit code. Every code, with its exit code and when it is reported, is listed in [CLI error codes](./cli-error-codes.md). The catalogue is also exported from `cli/utils/error-codes.ts` in `@seriousgaming/sdk-tools`.
|
|
112
|
+
|
|
113
|
+
A session refusal maps one-to-one onto the outcome kinds a UI sees when one of its writes is refused ([`MutationOutcome`](./api/sdk-ui.md#mutationoutcome)): `REFUSED_DENIED`, `REFUSED_VALIDATION`, `REFUSED_CONFLICT`, `REFUSED_SUPERSEDED` and `TICK_FAILED`. A failed endpoint call reports `INVALID_REQUEST`, `HANDLER_ERROR` or `INVALID_RESPONSE`, or the refusal it shares with any other write. All of these exit 4.
|
|
114
|
+
|
|
115
|
+
Without `--json`, a failure prints `Error: <message>` on stderr, followed by `Hint: <what to do>` when there is one.
|
|
116
|
+
|
|
117
|
+
## JSON output
|
|
118
|
+
|
|
119
|
+
Pass `-j, --json` to any command, or set `SERIOUSGAMING_JSON=1` in the environment, and the command writes exactly one JSON document to stdout, whether it succeeds or fails. Progress, logs and notices go to stderr. Every document is indented with two spaces.
|
|
120
|
+
|
|
121
|
+
On success:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"ok": true,
|
|
126
|
+
"command": "tick",
|
|
127
|
+
"data": {
|
|
128
|
+
"gameId": "com.example.factory.game",
|
|
129
|
+
"completedTicks": 1,
|
|
130
|
+
"complete": false,
|
|
131
|
+
"context": {}
|
|
132
|
+
},
|
|
133
|
+
"diagnostics": [],
|
|
134
|
+
"warnings": []
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
On failure:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"ok": false,
|
|
143
|
+
"command": "build",
|
|
144
|
+
"error": {
|
|
145
|
+
"code": "PACKAGE_INVALID",
|
|
146
|
+
"message": "Validation failed: 1 of 6 resources have errors.",
|
|
147
|
+
"hint": "Fix the errors listed and run the command again."
|
|
148
|
+
},
|
|
149
|
+
"diagnostics": [
|
|
150
|
+
{
|
|
151
|
+
"severity": "error",
|
|
152
|
+
"code": "SETTINGS_UNKNOWN_KEY",
|
|
153
|
+
"message": "Overrides \"BaseDemnd\", which settings \"engine\" does not declare",
|
|
154
|
+
"file": "scenarios/hard/scenario.sdk.json",
|
|
155
|
+
"pointer": "/definition/settings/engine/BaseDemnd",
|
|
156
|
+
"resource": { "type": "scenario", "identifier": "hard" },
|
|
157
|
+
"hint": "Did you mean 'BaseDemand'?"
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"warnings": []
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- `ok` says which of the two it is, as the UI protocol's `mutation:response` does
|
|
165
|
+
- `command` is the full command path: `tick`, `new engine`, `timer`, `package publish`
|
|
166
|
+
- `data` is the command's result: the session report for session commands, the change list for `new`, `update` and `delete`, the validation summary for `build --validate-only`. A command with nothing to report has `"data": null`
|
|
167
|
+
- `error.code` is the stable code; `error.hint` says what to do; `error.details` carries structured detail where a failure has it, such as the outcome of a refused write (with a validator's `rejections`) or a failed endpoint call (with the steps it `applied`)
|
|
168
|
+
- `diagnostics` lists findings about the package, errors and warnings both: on failure what failed it, on success the warnings a passing `build` found. See [Diagnostics](#diagnostics)
|
|
169
|
+
- `warnings` lists notices the command printed on the way that point at no file
|
|
170
|
+
|
|
171
|
+
Session commands (`init`, `tick`, `view`, `patch` and the rest) print their result as JSON even without the flag: the bare report, not the envelope.
|
|
172
|
+
|
|
173
|
+
### Diagnostics
|
|
174
|
+
|
|
175
|
+
A diagnostic is one finding, located as precisely as the check that made it can say. Read `file` and `pointer` (or `line` and `column`) to go straight to the problem; branch on `code`, never on `message`.
|
|
176
|
+
|
|
177
|
+
| Field | Always | What it holds |
|
|
178
|
+
| ---------- | ------ | --------------------------------------------------------------------------------------------------------------- |
|
|
179
|
+
| `severity` | Yes | `error`, which fails the command, or `warning`, which does not |
|
|
180
|
+
| `code` | Yes | A stable code from the list below |
|
|
181
|
+
| `message` | Yes | What is wrong, for a person. Not part of the contract |
|
|
182
|
+
| `file` | No | The file it is about, relative to the package root, with forward slashes. A directory ends in `/` |
|
|
183
|
+
| `pointer` | No | Where in `file`, when `file` is JSON: an RFC 6901 pointer such as `/definition/reads/0`. `""` is the whole file |
|
|
184
|
+
| `line` | No | Where in `file`, when `file` is source code: 1-based |
|
|
185
|
+
| `column` | No | 1-based, with `line` |
|
|
186
|
+
| `resource` | No | The resource it is about: `{ "type": "scenario", "identifier": "hard" }` |
|
|
187
|
+
| `hint` | No | What to do about it, such as `Did you mean 'BaseDemand'?` or what replaced a removed field |
|
|
188
|
+
| `tick` | No | For `LOGIC_ERROR`: the tick the logic threw in |
|
|
189
|
+
| `team` | No | For `LOGIC_ERROR`: the team whose logic threw, `{ "teamId": "team-1", "index": 0 }` |
|
|
190
|
+
|
|
191
|
+
When game logic throws during a session command (`init`, `tick`, `endpoint call` and the rest), the command fails with the code for what it was doing (`TICK_FAILED` for a tick, `HANDLER_ERROR` for an endpoint, `SESSION_ERROR` otherwise, all exit 4), and the first diagnostic is `LOGIC_ERROR`, located in your TypeScript through the bundle's source map:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"severity": "error",
|
|
196
|
+
"code": "LOGIC_ERROR",
|
|
197
|
+
"message": "the second round has no stock",
|
|
198
|
+
"file": "engine/logic.ts",
|
|
199
|
+
"line": 13,
|
|
200
|
+
"column": 15,
|
|
201
|
+
"resource": { "type": "engine", "identifier": "engine" },
|
|
202
|
+
"tick": 2,
|
|
203
|
+
"team": { "teamId": "team-1", "index": 0 }
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
A failure that is the environment's rather than the game's keeps its own code even when it surfaces through logic: a call to `generateText` with no platform API key configured fails the tick or endpoint call with `LLM_NOT_CONFIGURED` (exit 5), and its hint says how to configure one.
|
|
208
|
+
|
|
209
|
+
Without `--json`, each diagnostic that names a file is printed under the error as `<code> at <location>`: `LOGIC_ERROR at engine/logic.ts:13:15 (tick 2, team 1)`, or `SETTINGS_UNKNOWN_KEY at scenarios/hard/scenario.sdk.json#/definition/settings/engine/BaseDemnd`.
|
|
210
|
+
|
|
211
|
+
#### Diagnostic codes
|
|
212
|
+
|
|
213
|
+
| Code | When |
|
|
214
|
+
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
215
|
+
| `PACKAGE_INVALID` | The package fails validation. The diagnostics say where. As a diagnostic code, a finding no finer code describes yet. |
|
|
216
|
+
| `SCHEMA_INVALID` | A bundle or the manifest does not match the SDK's schema. The diagnostic's pointer names the value. |
|
|
217
|
+
| `JSON_INVALID` | A bundle file is not valid JSON. |
|
|
218
|
+
| `BUNDLE_MISSING` | A resource directory holds no bundle file. |
|
|
219
|
+
| `REMOVED_FIELD` | A bundle or the manifest carries a field the SDK no longer reads. The hint says what replaced it. |
|
|
220
|
+
| `LAYOUT_OUTDATED` | A directory or bundle file sits where an earlier version of the SDK kept it. The hint says where it goes now. |
|
|
221
|
+
| `FEATURE_UNSUPPORTED` | The manifest's `requires` names an optional feature this version of the SDK does not support. |
|
|
222
|
+
| `REFERENCE_UNKNOWN` | A `reads`, `writes`, `settings`, `configures` or `endpoints` entry names something the package does not declare. |
|
|
223
|
+
| `SETTINGS_UNKNOWN` | A scenario overrides a settings resource the package does not declare. |
|
|
224
|
+
| `SETTINGS_UNKNOWN_KEY` | A scenario overrides a key that its settings resource does not declare. |
|
|
225
|
+
| `SETTINGS_INVALID` | A scenario's override does not match its settings resource's schema. |
|
|
226
|
+
| `SETTINGS_RESERVED` | A settings resource is named `game`, which is reserved for the built-in game settings. |
|
|
227
|
+
| `SETTINGS_LOCKED` | A scenario overrides a setting the game locks with `readOnly`, in its settings schema or its `gameSettingsConstraints`. |
|
|
228
|
+
| `GAME_CONSTRAINT_INVALID` | A `gameSettingsConstraints` entry widens the SDK schema for the `game` settings rather than narrowing it. |
|
|
229
|
+
| `GAME_CONSTRAINT_VIOLATED` | The game's own value for a `game` setting breaks its `gameSettingsConstraints`. |
|
|
230
|
+
| `LOGIC_EXPORT_MISSING` | A logic file is missing, or does not export the functions its resource needs. |
|
|
231
|
+
| `LOGIC_NODE_BUILTIN` | Game logic imports a Node built-in, which is absent in production: logic runs on the JavaScript language alone. |
|
|
232
|
+
| `LOGIC_BUNDLE_FAILED` | A logic file does not bundle: a syntax error, or an import that does not resolve. |
|
|
233
|
+
| `READ_NEVER_WRITTEN` | A warning: a resource reads a capability nothing in the package writes, so it only ever holds its defaults. |
|
|
234
|
+
| `NO_TERMINATION` | A warning: the game declares neither `maxTicks` nor a tick controller, so only its engine can end it. |
|
|
235
|
+
| `EDITOR_ENDPOINT_STATEFUL` | The scenario editor lists an endpoint that declares `reads`, `writes` or `actions`, which need a session the editor does not have. |
|
|
236
|
+
| `EXTERNAL_REQUEST_NOT_OBJECT` | An external endpoint's `requestSchema` does not declare `"type": "object"` at the top, which a caller outside the game needs to pass named arguments. |
|
|
237
|
+
| `ENDPOINT_UNREQUESTED` | A warning: an internal endpoint no user interface lists in its `endpoints`. |
|
|
238
|
+
| `LOGIC_ERROR` | Game logic (an engine, hook, endpoint, validator or tick controller) threw. A diagnostic, not an error code: it sits in `diagnostics` under the command's TICK_FAILED, SESSION_ERROR or HANDLER_ERROR, with the file, line and column it threw at. |
|
|
239
|
+
|
|
240
|
+
### Non-interactive use
|
|
241
|
+
|
|
242
|
+
The CLI prompts only when stdin and stdout are both terminals, JSON output is off and `CI` is unset. Anywhere else, a command that would need to ask fails with exit code 2 and `PROMPT_REQUIRED`, naming the question and how to pass the answer instead: as an argument, with `--file`, or on stdin. Input piped on stdin is read to the end, however long it takes.
|
|
243
|
+
|
|
244
|
+
`delete` asks for confirmation, and so does an interactive `update` before it writes. Pass `-y, --yes` to answer it.
|
|
245
|
+
|
|
246
|
+
`new package` fails with exit code 5 and `INSTALL_FAILED` when `pnpm install` fails in the new package. The files are written; run `pnpm install` in the package to finish.
|
|
247
|
+
|
|
248
|
+
### Parsing JSON through pnpm
|
|
249
|
+
|
|
250
|
+
The catch is `pnpm run`, not the CLI. Before version 12, pnpm prints a banner to stdout ahead of your command:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
> com.example.game@0.0.1 sdk /path/to/package
|
|
254
|
+
> seriousgaming-sdk view
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
That banner is not JSON, so `JSON.parse(stdout)` throws and `jq` stops at the first line. pnpm 12 sends it to stderr instead, but a script cannot count on which pnpm runs it, and the CLI cannot suppress the banner from inside. Add `--silent` to `pnpm run` whenever you parse the output:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Pipe straight into jq
|
|
261
|
+
pnpm run --silent sdk view | jq '.completedTicks'
|
|
262
|
+
|
|
263
|
+
# The envelope from a command that takes --json
|
|
264
|
+
pnpm run --silent sdk configure -f config.json --json | jq '.data.restarted'
|
|
265
|
+
|
|
266
|
+
# Branch on the code, not the message
|
|
267
|
+
pnpm run --silent sdk tick --json | jq -r 'if .ok then "ticked" else .error.code end'
|
|
268
|
+
|
|
269
|
+
# Redirect to a file other tools will parse
|
|
270
|
+
pnpm run --silent sdk package bundle --json > bundle.json
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The same flag belongs in any command a Node script runs:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const { stdout } = await execAsync('pnpm run --silent sdk view');
|
|
277
|
+
const state = JSON.parse(stdout);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Calling the CLI binary directly, rather than through a `pnpm run` script, prints no banner, so `--silent` is unnecessary there.
|
|
281
|
+
|
|
282
|
+
## Resource commands
|
|
283
|
+
|
|
284
|
+
### Creating resources
|
|
285
|
+
|
|
286
|
+
#### Create a capability
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
pnpm run sdk new capability [definition] [options]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Create a new capability.
|
|
293
|
+
|
|
294
|
+
| Option | Default | Description |
|
|
295
|
+
| -------------------------- | --------------------- | -------------------------------------------------------------------------------- |
|
|
296
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the capability in. |
|
|
297
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the capability definition. |
|
|
298
|
+
| `--scope <scope>` | | Cross-team visibility: 'team' (default), 'team-readable', 'shared' or 'private'. |
|
|
299
|
+
|
|
300
|
+
Example:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
pnpm run sdk new capability '{
|
|
304
|
+
"definition": {
|
|
305
|
+
"identifier": "inventory",
|
|
306
|
+
"variablesSchema": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"properties": {
|
|
309
|
+
"Stock": { "type": "number", "default": 100 }
|
|
310
|
+
},
|
|
311
|
+
"required": ["Stock"],
|
|
312
|
+
"additionalProperties": false
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}'
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The optional `definition.scope` field sets the capability's cross-team visibility, and is written to the created `capability.sdk.json`:
|
|
319
|
+
|
|
320
|
+
- `'team'` (the default): private to each team
|
|
321
|
+
- `'team-readable'`: each team writes its own copy, but user interfaces on other teams may observe every team's value live in shared-state games
|
|
322
|
+
- `'shared'`: one value for all teams
|
|
323
|
+
- `'private'`: per team like `'team'`, but never delivered to any user interface, so a UI that reads or writes it fails the build
|
|
324
|
+
|
|
325
|
+
For invocations that do not pass JSON, the `--scope` flag sets any of the four:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
pnpm run sdk new capability --scope shared
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Create settings
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
pnpm run sdk new settings [definition] [options]
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Create a new settings resource.
|
|
338
|
+
|
|
339
|
+
| Option | Default | Description |
|
|
340
|
+
| -------------------------- | --------------------- | ---------------------------------------------------------------- |
|
|
341
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the settings resource in. |
|
|
342
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the settings resource definition. |
|
|
343
|
+
|
|
344
|
+
Example:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
pnpm run sdk new settings '{
|
|
348
|
+
"definition": {
|
|
349
|
+
"identifier": "demand",
|
|
350
|
+
"settingsSchema": {
|
|
351
|
+
"type": "object",
|
|
352
|
+
"properties": {
|
|
353
|
+
"BaseDemand": {
|
|
354
|
+
"type": "number",
|
|
355
|
+
"description": "Base demand per tick",
|
|
356
|
+
"default": 100,
|
|
357
|
+
"minimum": 0
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
"additionalProperties": false
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}'
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Creates `settings/<identifier>/settings.sdk.json`: named, read-only parameters that any resource reads by listing its identifier in `settings`. `definition.identifier` names the directory and is stripped from the bundle that is written, so on disk the directory is the name. A package may hold any number, so `update` and `delete` take the identifier.
|
|
367
|
+
|
|
368
|
+
**Every property declares a `default`.** It is the value the game plays with unless a scenario or the session overrides it, so the command refuses a property without one, and a `settingsSchema` with a top-level `required`. With no JSON, the command prompts for the name and each property interactively.
|
|
369
|
+
|
|
370
|
+
The identifier `game` is reserved for the built-in game settings, whose values the manifest sets (see [The game settings](./guides/settings.md#the-game-settings)), so `new settings` refuses it with `SETTINGS_RESERVED`.
|
|
371
|
+
|
|
372
|
+
A settings resource does nothing until something reads it: add its identifier to the `settings` array of each resource that needs it, to the `configures` of the `setup` or `scenario_editor` slot to make it editable, and under a scenario's `settings` to override it. See the [settings guide](./guides/settings.md) and [Create settings](./recipes/create-settings.md).
|
|
373
|
+
|
|
374
|
+
#### Create the engine
|
|
375
|
+
|
|
376
|
+
```text
|
|
377
|
+
pnpm run sdk new engine [definition] [options]
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Create a new engine.
|
|
381
|
+
|
|
382
|
+
| Option | Default | Description |
|
|
383
|
+
| -------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
384
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the engine in. |
|
|
385
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the engine definition. |
|
|
386
|
+
| `--aggregate` | | Scaffold logic exporting InitAggregate and RunAggregate, for an engine that runs once across all teams. |
|
|
387
|
+
|
|
388
|
+
Example:
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
pnpm run sdk new engine '{
|
|
392
|
+
"definition": {
|
|
393
|
+
"writes": ["inventory"],
|
|
394
|
+
"uses": ["generateText"],
|
|
395
|
+
"settings": ["demand"]
|
|
396
|
+
},
|
|
397
|
+
"logic": {
|
|
398
|
+
"directory": ".",
|
|
399
|
+
"entrypoint": "logic.ts"
|
|
400
|
+
},
|
|
401
|
+
"rootDirectory": "."
|
|
402
|
+
}'
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
The optional `definition.uses` field lists the runtime callbacks the engine may invoke: `'generateText'`, `'extractText'`, `'generateSpeech'`, and `'writeBlob'`. It defaults to `[]`. Each one listed is present on the engine's generated `Callbacks`, so logic calls it without a `?.` check, and a call to an undeclared callback throws `UndeclaredApiUseError` at runtime. `new hook`, `new tick_controller`, and `new endpoint` accept the same field, as do the matching `update` commands.
|
|
406
|
+
|
|
407
|
+
User interfaces have no `uses` field. `new ui`, `new session`, `new waiting_room`, `new presentation`, `new setup`, and `new scenario_editor` refuse one, and so does `pnpm run sdk build`: a user interface reaches an external service through an endpoint instead. See [Declare API uses](./recipes/declare-api-uses.md).
|
|
408
|
+
|
|
409
|
+
The optional `definition.settings` field lists the settings resources the engine reads, by identifier, exactly as `reads` lists capabilities. Its logic receives exactly those as `settings`, keyed by identifier (`settings.demand.BaseDemand`), and an identifier the package does not declare fails the build. The UIs, the tick controller, hooks, validators, and endpoints accept the same field, as do the matching `update` commands. With no JSON, `new` offers the settings resources already on disk to choose from.
|
|
410
|
+
|
|
411
|
+
The optional `--aggregate` flag scaffolds an engine that runs once across all teams rather than per team: its logic exports `Init`, `InitAggregate`, and `RunAggregate` instead of `Init` and `Run`. `Init` is optional in either shape: an engine without one starts from its capabilities' defaults, but the scaffold writes one to fill in. Those exports are what make the engine aggregate, so nothing is written into `engine.sdk.json`, and an authored `definition.aggregate` is rejected. See the [multi-team games guide](./guides/multi-team-games.md).
|
|
412
|
+
|
|
413
|
+
#### Create the game UI
|
|
414
|
+
|
|
415
|
+
```text
|
|
416
|
+
pnpm run sdk new ui [definition] [options]
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Create a new user interface.
|
|
420
|
+
|
|
421
|
+
| Option | Default | Description |
|
|
422
|
+
| -------------------------- | --------------------- | ------------------------------------------------------------- |
|
|
423
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the user interface in. |
|
|
424
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the user interface definition. |
|
|
425
|
+
|
|
426
|
+
Example:
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
pnpm run sdk new ui '{
|
|
430
|
+
"definition": {
|
|
431
|
+
"reads": ["revenue"],
|
|
432
|
+
"writes": ["price"],
|
|
433
|
+
"settings": ["display"]
|
|
434
|
+
},
|
|
435
|
+
"rootDirectory": ".",
|
|
436
|
+
"ui": {
|
|
437
|
+
"entrypoint": "index.html"
|
|
438
|
+
}
|
|
439
|
+
}'
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
`definition.reads` and `definition.writes` are arrays of capability identifiers, and a UI's `data` carries exactly the union of the two. `definition.settings` lists the settings resources it reads, which arrive as `settings` on `useUserInterfaceData()`, keyed by identifier. A value participants must not see, such as an answer key, belongs in a settings resource the UI does not list.
|
|
443
|
+
|
|
444
|
+
The optional `definition.crossTeamReads` narrows `reads` to the capabilities for which every team's value arrives, live. Each entry must also appear in `reads` and must name a capability with `scope: 'team-readable'`, in a shared-state game. Only `new ui` and `new waiting_room` accept it, and both write it straight into the created bundle. See [Observe other teams' state](./recipes/observe-other-teams-state.md).
|
|
445
|
+
|
|
446
|
+
#### Create a scenario
|
|
447
|
+
|
|
448
|
+
```text
|
|
449
|
+
pnpm run sdk new scenario [definition] [options]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Create a new scenario.
|
|
453
|
+
|
|
454
|
+
| Option | Default | Description |
|
|
455
|
+
| -------------------------- | --------------------- | ------------------------------------------------------- |
|
|
456
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the scenario in. |
|
|
457
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the scenario definition. |
|
|
458
|
+
|
|
459
|
+
Example:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
pnpm run sdk new scenario '{
|
|
463
|
+
"definition": {
|
|
464
|
+
"identifier": "ai_influence",
|
|
465
|
+
"locales": {
|
|
466
|
+
"en": {
|
|
467
|
+
"name": "AI Influence",
|
|
468
|
+
"description": "AI-driven market disruption"
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
"settings": {
|
|
472
|
+
"demand": { "BaseDemand": 50 }
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
"rootDirectory": "."
|
|
476
|
+
}'
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Creates `scenarios/<identifier>/scenario.sdk.json` and `scenarios/<identifier>/assets/shared/`. The directory is the declaration: nothing registers it. `settings` is keyed by settings identifier, and each entry is a partial override of that settings resource's defaults.
|
|
480
|
+
|
|
481
|
+
#### Create the facilitator guide
|
|
482
|
+
|
|
483
|
+
```text
|
|
484
|
+
pnpm run sdk new guide [definition] [options]
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Create a new facilitator guide.
|
|
488
|
+
|
|
489
|
+
| Option | Default | Description |
|
|
490
|
+
| -------------------------- | --------------------- | ---------------------------------------------------------------- |
|
|
491
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the facilitator guide in. |
|
|
492
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the facilitator guide definition. |
|
|
493
|
+
|
|
494
|
+
Example:
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
pnpm run sdk new guide '{
|
|
498
|
+
"definition": {
|
|
499
|
+
"locales": {
|
|
500
|
+
"en": { "name": "Facilitator guide" },
|
|
501
|
+
"de": { "name": "Moderationsleitfaden" }
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
"rootDirectory": "."
|
|
505
|
+
}'
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Creates `guide/guide.sdk.json`, an `assets/` directory, and a recommended chapter skeleton under `content/<locale>/` for every declared locale. The per-locale `name` is the guide's title. See [Facilitator guides](./guides/guide.md).
|
|
509
|
+
|
|
510
|
+
#### Create the session UI
|
|
511
|
+
|
|
512
|
+
```text
|
|
513
|
+
pnpm run sdk new session [definition] [options]
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Create a new session user interface.
|
|
517
|
+
|
|
518
|
+
| Option | Default | Description |
|
|
519
|
+
| -------------------------- | --------------------- | --------------------------------------------------------------------- |
|
|
520
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the session user interface in. |
|
|
521
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the session user interface definition. |
|
|
522
|
+
|
|
523
|
+
Example:
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
pnpm run sdk new session '{
|
|
527
|
+
"definition": {
|
|
528
|
+
"reads": ["price", "workers"],
|
|
529
|
+
"writes": ["price", "workers"]
|
|
530
|
+
},
|
|
531
|
+
"rootDirectory": ".",
|
|
532
|
+
"ui": {
|
|
533
|
+
"entrypoint": "index.html"
|
|
534
|
+
}
|
|
535
|
+
}'
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
The session UI gives the facilitator cross-team, session-level control. See the [session UIs guide](./guides/session.md).
|
|
539
|
+
|
|
540
|
+
#### Create the waiting room UI
|
|
541
|
+
|
|
542
|
+
```text
|
|
543
|
+
pnpm run sdk new waiting_room [definition] [options]
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
Create a new waiting room user interface.
|
|
547
|
+
|
|
548
|
+
| Option | Default | Description |
|
|
549
|
+
| -------------------------- | --------------------- | -------------------------------------------------------------------------- |
|
|
550
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the waiting room user interface in. |
|
|
551
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the waiting room user interface definition. |
|
|
552
|
+
|
|
553
|
+
Example:
|
|
554
|
+
|
|
555
|
+
```bash
|
|
556
|
+
pnpm run sdk new waiting_room '{
|
|
557
|
+
"definition": {
|
|
558
|
+
"reads": ["briefing"]
|
|
559
|
+
},
|
|
560
|
+
"rootDirectory": ".",
|
|
561
|
+
"ui": {
|
|
562
|
+
"entrypoint": "index.html"
|
|
563
|
+
}
|
|
564
|
+
}'
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
The holding screen participants see instead of the game UIs while the facilitator has the session's waiting room open. It is a game UI in a different display context: the same `reads`, `writes`, `endpoints`, hooks, and callbacks are available, and it renders under `UserInterfaceWrapper`. It lives at the `waiting_room/` slot, so nothing references it.
|
|
568
|
+
|
|
569
|
+
The manifest's `waitingRoom` block carries one setting, `openOnStart`, so `"openOnStart": true` there makes every session begin with the room open. See the [waiting room UIs guide](./guides/waiting-room.md).
|
|
570
|
+
|
|
571
|
+
#### Create the presentation
|
|
572
|
+
|
|
573
|
+
```text
|
|
574
|
+
pnpm run sdk new presentation [definition] [options]
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Create a new presentation.
|
|
578
|
+
|
|
579
|
+
| Option | Default | Description |
|
|
580
|
+
| -------------------------- | --------------------- | ----------------------------------------------------------- |
|
|
581
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the presentation in. |
|
|
582
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the presentation definition. |
|
|
583
|
+
|
|
584
|
+
Example:
|
|
585
|
+
|
|
586
|
+
```bash
|
|
587
|
+
pnpm run sdk new presentation '{
|
|
588
|
+
"definition": {
|
|
589
|
+
"reads": ["results"],
|
|
590
|
+
"settings": ["engine"]
|
|
591
|
+
},
|
|
592
|
+
"rootDirectory": ".",
|
|
593
|
+
"ui": {
|
|
594
|
+
"entrypoint": "index.html"
|
|
595
|
+
}
|
|
596
|
+
}'
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
The facilitator's slide deck. It reads every team's state through `reads` and its settings through `settings`, and accepts no `writes`, `uses` or `endpoints`. It renders under `PresentationWrapper`, with or without a session, and the starter deck it scaffolds is built with `@seriousgaming/deck`, which the package must list at the SDK's version. It lives at the `presentation/` slot, so nothing references it. See the [presentations guide](./guides/presentation.md).
|
|
600
|
+
|
|
601
|
+
#### Create the setup screen
|
|
602
|
+
|
|
603
|
+
```text
|
|
604
|
+
pnpm run sdk new setup [definition] [options]
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Create a new setup user interface.
|
|
608
|
+
|
|
609
|
+
| Option | Default | Description |
|
|
610
|
+
| -------------------------- | --------------------- | ------------------------------------------------------------------- |
|
|
611
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the setup user interface in. |
|
|
612
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the setup user interface definition. |
|
|
613
|
+
|
|
614
|
+
Example:
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
pnpm run sdk new setup '{
|
|
618
|
+
"definition": {
|
|
619
|
+
"configures": ["demand"]
|
|
620
|
+
},
|
|
621
|
+
"rootDirectory": ".",
|
|
622
|
+
"ui": {
|
|
623
|
+
"entrypoint": "index.html"
|
|
624
|
+
}
|
|
625
|
+
}'
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
The short form a facilitator fills in at session creation. `configures` lists the settings resources it edits, by identifier, and what it writes lands in that session's overrides only. A game with a setup screen opens at its configuration step and waits for Play. It renders under `SettingsEditorWrapper` and may send `requestPlay`. It lives at the `setup/` slot, so nothing references it. See the [setup guide](./guides/setup.md).
|
|
629
|
+
|
|
630
|
+
#### Create the scenario editor
|
|
631
|
+
|
|
632
|
+
```text
|
|
633
|
+
pnpm run sdk new scenario_editor [definition] [options]
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Create a new scenario editor.
|
|
637
|
+
|
|
638
|
+
| Option | Default | Description |
|
|
639
|
+
| -------------------------- | --------------------- | -------------------------------------------------------------- |
|
|
640
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the scenario editor in. |
|
|
641
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the scenario editor definition. |
|
|
642
|
+
|
|
643
|
+
Example:
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
pnpm run sdk new scenario_editor '{
|
|
647
|
+
"definition": {
|
|
648
|
+
"configures": ["demand"]
|
|
649
|
+
},
|
|
650
|
+
"rootDirectory": ".",
|
|
651
|
+
"ui": {
|
|
652
|
+
"entrypoint": "index.html"
|
|
653
|
+
}
|
|
654
|
+
}'
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
The screen for authoring lasting scenarios, at any time and with no session. `configures` lists the settings resources it edits, by identifier. It renders under `SettingsEditorWrapper`, the host offers save-as-scenario from it (never from setup), and the host ignores `requestPlay` from it. It lives at the `scenario_editor/` slot, so nothing references it. It is optional: `customScenarios.supported` is what switches custom scenarios on. See the [scenario editor guide](./guides/scenario-editor.md).
|
|
658
|
+
|
|
659
|
+
#### Create the tick controller
|
|
660
|
+
|
|
661
|
+
```text
|
|
662
|
+
pnpm run sdk new tick_controller [definition] [options]
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Create a new tick controller.
|
|
666
|
+
|
|
667
|
+
| Option | Default | Description |
|
|
668
|
+
| -------------------------- | --------------------- | -------------------------------------------------------------- |
|
|
669
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the tick controller in. |
|
|
670
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the tick controller definition. |
|
|
671
|
+
|
|
672
|
+
Minimal example:
|
|
673
|
+
|
|
674
|
+
```bash
|
|
675
|
+
pnpm run sdk new tick_controller '{
|
|
676
|
+
"definition": {},
|
|
677
|
+
"logic": {
|
|
678
|
+
"directory": ".",
|
|
679
|
+
"entrypoint": "logic.ts"
|
|
680
|
+
},
|
|
681
|
+
"rootDirectory": "."
|
|
682
|
+
}'
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
With capability reads and settings:
|
|
686
|
+
|
|
687
|
+
```bash
|
|
688
|
+
pnpm run sdk new tick_controller '{
|
|
689
|
+
"definition": {
|
|
690
|
+
"reads": ["progress"],
|
|
691
|
+
"settings": ["timing"]
|
|
692
|
+
},
|
|
693
|
+
"logic": {
|
|
694
|
+
"directory": ".",
|
|
695
|
+
"entrypoint": "logic.ts"
|
|
696
|
+
},
|
|
697
|
+
"rootDirectory": "."
|
|
698
|
+
}'
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
#### Create a hook
|
|
702
|
+
|
|
703
|
+
```text
|
|
704
|
+
pnpm run sdk new hook [definition] [options]
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
Create a new hook.
|
|
708
|
+
|
|
709
|
+
| Option | Default | Description |
|
|
710
|
+
| -------------------------- | --------------------- | --------------------------------------------------- |
|
|
711
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the hook in. |
|
|
712
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the hook definition. |
|
|
713
|
+
|
|
714
|
+
A hook is a single-signal handler that fires on an out-of-tick lifecycle event. The available signals are `participantJoin` and `participantMove`. See the [hooks guide](./guides/hooks.md).
|
|
715
|
+
|
|
716
|
+
Minimal example:
|
|
717
|
+
|
|
718
|
+
```bash
|
|
719
|
+
pnpm run sdk new hook '{
|
|
720
|
+
"definition": {
|
|
721
|
+
"identifier": "assignroles",
|
|
722
|
+
"signal": "participantJoin"
|
|
723
|
+
},
|
|
724
|
+
"logic": {
|
|
725
|
+
"directory": "logic",
|
|
726
|
+
"entrypoint": "logic.ts"
|
|
727
|
+
},
|
|
728
|
+
"rootDirectory": "."
|
|
729
|
+
}'
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
With capability writes and settings:
|
|
733
|
+
|
|
734
|
+
```bash
|
|
735
|
+
pnpm run sdk new hook '{
|
|
736
|
+
"definition": {
|
|
737
|
+
"identifier": "assignroles",
|
|
738
|
+
"signal": "participantJoin",
|
|
739
|
+
"writes": ["roles"],
|
|
740
|
+
"settings": ["roles"]
|
|
741
|
+
},
|
|
742
|
+
"logic": {
|
|
743
|
+
"directory": "logic",
|
|
744
|
+
"entrypoint": "logic.ts"
|
|
745
|
+
},
|
|
746
|
+
"rootDirectory": "."
|
|
747
|
+
}'
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
#### Create a validator
|
|
751
|
+
|
|
752
|
+
```text
|
|
753
|
+
pnpm run sdk new validator [definition] [options]
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
Create a new validator.
|
|
757
|
+
|
|
758
|
+
| Option | Default | Description |
|
|
759
|
+
| -------------------------- | --------------------- | -------------------------------------------------------- |
|
|
760
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the validator in. |
|
|
761
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the validator definition. |
|
|
762
|
+
|
|
763
|
+
A validator is a standalone, read-only check that gates UI-submitted state mutations before they are applied. It can only reject, and never modifies state. See the [validators guide](./guides/validators.md).
|
|
764
|
+
|
|
765
|
+
Minimal example:
|
|
766
|
+
|
|
767
|
+
```bash
|
|
768
|
+
pnpm run sdk new validator '{
|
|
769
|
+
"definition": {
|
|
770
|
+
"identifier": "decisionlimit"
|
|
771
|
+
},
|
|
772
|
+
"logic": {
|
|
773
|
+
"directory": "logic",
|
|
774
|
+
"entrypoint": "logic.ts"
|
|
775
|
+
},
|
|
776
|
+
"rootDirectory": "."
|
|
777
|
+
}'
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
With capability reads and settings:
|
|
781
|
+
|
|
782
|
+
```bash
|
|
783
|
+
pnpm run sdk new validator '{
|
|
784
|
+
"definition": {
|
|
785
|
+
"identifier": "decisionlimit",
|
|
786
|
+
"reads": ["decisions"],
|
|
787
|
+
"settings": ["limits"]
|
|
788
|
+
},
|
|
789
|
+
"logic": {
|
|
790
|
+
"directory": "logic",
|
|
791
|
+
"entrypoint": "logic.ts"
|
|
792
|
+
},
|
|
793
|
+
"rootDirectory": "."
|
|
794
|
+
}'
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
#### Create an endpoint
|
|
798
|
+
|
|
799
|
+
```text
|
|
800
|
+
pnpm run sdk new endpoint [definition] [options]
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
Create a new endpoint.
|
|
804
|
+
|
|
805
|
+
| Option | Default | Description |
|
|
806
|
+
| -------------------------- | --------------------- | ------------------------------------------------------- |
|
|
807
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the endpoint in. |
|
|
808
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the endpoint definition. |
|
|
809
|
+
|
|
810
|
+
Scaffolds `endpoints/<identifier>/endpoint.sdk.json` and `endpoints/<identifier>/logic/logic.ts`, and regenerates types.
|
|
811
|
+
|
|
812
|
+
```bash
|
|
813
|
+
pnpm run sdk new endpoint # interactive
|
|
814
|
+
pnpm run sdk new endpoint '<json definition>' # from JSON argument
|
|
815
|
+
pnpm run sdk new endpoint --file endpoint.json # from JSON file
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
Example:
|
|
819
|
+
|
|
820
|
+
```bash
|
|
821
|
+
pnpm run sdk new endpoint '{
|
|
822
|
+
"definition": {
|
|
823
|
+
"identifier": "summarise",
|
|
824
|
+
"requestSchema": {
|
|
825
|
+
"type": "object",
|
|
826
|
+
"properties": { "text": { "type": "string" } },
|
|
827
|
+
"required": ["text"],
|
|
828
|
+
"additionalProperties": false
|
|
829
|
+
},
|
|
830
|
+
"responseSchema": {
|
|
831
|
+
"type": "object",
|
|
832
|
+
"properties": { "summary": { "type": "string" } },
|
|
833
|
+
"required": ["summary"],
|
|
834
|
+
"additionalProperties": false
|
|
835
|
+
},
|
|
836
|
+
"uses": ["generateText"],
|
|
837
|
+
"settings": ["summaries"]
|
|
838
|
+
},
|
|
839
|
+
"logic": {
|
|
840
|
+
"directory": "logic",
|
|
841
|
+
"entrypoint": "logic.ts"
|
|
842
|
+
},
|
|
843
|
+
"rootDirectory": "."
|
|
844
|
+
}'
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
An endpoint's `Handle` receives the settings resources it lists in `settings` as `settings`, keyed by identifier, as every other logic function does.
|
|
848
|
+
|
|
849
|
+
Declare the endpoint on every UI that may call it by adding the identifier to the UI bundle's `endpoints` array:
|
|
850
|
+
|
|
851
|
+
```json
|
|
852
|
+
{
|
|
853
|
+
"definition": {
|
|
854
|
+
"endpoints": ["summarise"]
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
### Notes on resource creation
|
|
860
|
+
|
|
861
|
+
**The `rootDirectory` field.** Most `new` commands require `rootDirectory` in the root object, not inside `definition`, and it is usually `"."`. `new capability` and `new settings` are the exceptions: their bundles carry `definition` alone, and a `rootDirectory` is rejected.
|
|
862
|
+
|
|
863
|
+
- **Engine and tick controller**: `{ "definition": {...}, "logic": {...}, "rootDirectory": "." }`
|
|
864
|
+
- **User interfaces, including setup and the scenario editor**: `{ "definition": {...}, "rootDirectory": ".", "ui": { "entrypoint": "index.html" } }`
|
|
865
|
+
|
|
866
|
+
**Identifiers.** For the nine slot kinds (`engine`, `ui`, `session`, `waiting_room`, `presentation`, `setup`, `scenario_editor`, `tick_controller`, and `guide`) any authored identifier is ignored, since the slot names the resource. For the plural kinds (`capability`, `settings`, `endpoint`, `hook`, `validator`, and `scenario`) `definition.identifier` is required: it names the directory to create, and is stripped from the bundle that is written.
|
|
867
|
+
|
|
868
|
+
**Nothing to wire.** A package declares whatever sits under the conventional directories, and a game uses whatever its package declares, so the directory `new` creates is the whole of the wiring.
|
|
869
|
+
|
|
870
|
+
### Updating resources
|
|
871
|
+
|
|
872
|
+
Every resource type has an `update` command, and so does the package:
|
|
873
|
+
|
|
874
|
+
| Command | What it does | Options |
|
|
875
|
+
| ------------------------------------------------------- | ------------------------------------- | --------------------------------------------- |
|
|
876
|
+
| `update package [definition] [options]` | Update a package. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
877
|
+
| `update capability <identifier> [definition] [options]` | Update a capability. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
878
|
+
| `update settings <identifier> [definition] [options]` | Update a settings resource. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
879
|
+
| `update engine [definition] [options]` | Update an engine. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
880
|
+
| `update ui [definition] [options]` | Update a user interface. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
881
|
+
| `update setup [definition] [options]` | Update a setup user interface. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
882
|
+
| `update scenario_editor [definition] [options]` | Update a scenario editor. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
883
|
+
| `update tick_controller [definition] [options]` | Update a tick controller. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
884
|
+
| `update session [definition] [options]` | Update a session user interface. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
885
|
+
| `update waiting_room [definition] [options]` | Update a waiting room user interface. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
886
|
+
| `update presentation [definition] [options]` | Update a presentation. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
887
|
+
| `update scenario <identifier> [definition] [options]` | Update a scenario. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
888
|
+
| `update guide [definition] [options]` | Update a facilitator guide. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
889
|
+
| `update hook <identifier> [definition] [options]` | Update a hook. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
890
|
+
| `update validator <identifier> [definition] [options]` | Update a validator. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
891
|
+
| `update endpoint <identifier> [definition] [options]` | Update an endpoint. | `--working-dir`, `--file`, `--patch`, `--yes` |
|
|
892
|
+
|
|
893
|
+
Their options, as `update capability` takes them (the table above shows which commands take each):
|
|
894
|
+
|
|
895
|
+
| Option | Default | Description |
|
|
896
|
+
| -------------------------- | --------------------- | ---------------------------------------------------------- |
|
|
897
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory containing the package. |
|
|
898
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the update definition. |
|
|
899
|
+
| `-p, --patch [PATCH]` | | JSON Patch (RFC 6902) array for partial updates. |
|
|
900
|
+
| `-y, --yes` | | Answer yes to the confirmation an interactive update asks. |
|
|
901
|
+
|
|
902
|
+
#### Full replacement
|
|
903
|
+
|
|
904
|
+
Replace a resource's whole definition:
|
|
905
|
+
|
|
906
|
+
```bash
|
|
907
|
+
pnpm run sdk update <type> <identifier> '<JSON>'
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
The nine slot kinds take the slot as their identifier, so `update` and `delete` take no identifier for them:
|
|
911
|
+
|
|
912
|
+
```bash
|
|
913
|
+
pnpm run sdk update engine '<JSON>'
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
Examples:
|
|
917
|
+
|
|
918
|
+
```bash
|
|
919
|
+
pnpm run sdk update capability inventory '{...}'
|
|
920
|
+
pnpm run sdk update settings demand '{...}'
|
|
921
|
+
pnpm run sdk update engine '{...}'
|
|
922
|
+
pnpm run sdk update session '{...}'
|
|
923
|
+
pnpm run sdk update waiting_room '{...}'
|
|
924
|
+
pnpm run sdk update presentation '{...}'
|
|
925
|
+
pnpm run sdk update setup '{...}'
|
|
926
|
+
pnpm run sdk update scenario_editor '{...}'
|
|
927
|
+
pnpm run sdk update tick_controller '{...}'
|
|
928
|
+
pnpm run sdk update hook assignroles '{...}'
|
|
929
|
+
pnpm run sdk update validator decisionlimit '{...}'
|
|
930
|
+
pnpm run sdk update scenario ai_influence '{...}'
|
|
931
|
+
pnpm run sdk update guide '{...}'
|
|
932
|
+
pnpm run sdk update endpoint report '{...}'
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
#### Partial update with JSON Patch
|
|
936
|
+
|
|
937
|
+
Change part of a resource with an [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902):
|
|
938
|
+
|
|
939
|
+
```bash
|
|
940
|
+
pnpm run sdk update <type> <identifier> --patch '<JSON-PATCH-ARRAY>'
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
The CLI loads the existing `.sdk.json` file, applies the patch, validates the result, and writes it back. The supported operations are `add`, `remove`, `replace`, `move`, `copy`, and `test`.
|
|
944
|
+
|
|
945
|
+
```bash
|
|
946
|
+
# Add a write to an engine
|
|
947
|
+
pnpm run sdk update engine --patch '[
|
|
948
|
+
{"op": "add", "path": "/definition/writes/-", "value": "forecast"}
|
|
949
|
+
]'
|
|
950
|
+
|
|
951
|
+
# Change the default value of a capability variable
|
|
952
|
+
pnpm run sdk update capability inventory --patch '[
|
|
953
|
+
{"op": "replace", "path": "/definition/variablesSchema/properties/Stock/default", "value": 200}
|
|
954
|
+
]'
|
|
955
|
+
|
|
956
|
+
# Change the default of a setting
|
|
957
|
+
pnpm run sdk update settings demand --patch '[
|
|
958
|
+
{"op": "replace", "path": "/definition/settingsSchema/properties/BaseDemand/default", "value": 150}
|
|
959
|
+
]'
|
|
960
|
+
|
|
961
|
+
# Remove a read from an engine (by index)
|
|
962
|
+
pnpm run sdk update engine --patch '[
|
|
963
|
+
{"op": "remove", "path": "/definition/reads/1"}
|
|
964
|
+
]'
|
|
965
|
+
|
|
966
|
+
# Update the tick count. A package is a game, so update package takes
|
|
967
|
+
# no identifier, and its patch paths start at the manifest rather than a bundle
|
|
968
|
+
pnpm run sdk update package --patch '[
|
|
969
|
+
{"op": "replace", "path": "/maxTicks", "value": 20}
|
|
970
|
+
]'
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
**Renaming settings.** A full replacement of settings whose `definition.identifier` differs from the one named on the command line renames them, and re-keys every reference: each resource's `settings`, the `configures` of the setup and scenario editor slots, and each scenario's `settings`. The interactive `update settings` offers the same rename, and a new, changed, or removed property in the same pass. Every property must still declare a `default`:
|
|
974
|
+
|
|
975
|
+
```bash
|
|
976
|
+
pnpm run sdk update settings demand '{
|
|
977
|
+
"definition": {
|
|
978
|
+
"identifier": "demand",
|
|
979
|
+
"settingsSchema": {
|
|
980
|
+
"type": "object",
|
|
981
|
+
"properties": {
|
|
982
|
+
"BaseDemand": {
|
|
983
|
+
"type": "number",
|
|
984
|
+
"description": "Base demand per tick",
|
|
985
|
+
"default": 150,
|
|
986
|
+
"minimum": 0
|
|
987
|
+
},
|
|
988
|
+
"Elasticity": {
|
|
989
|
+
"type": "number",
|
|
990
|
+
"description": "How strongly demand responds to price",
|
|
991
|
+
"default": 1.2
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
"additionalProperties": false
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}'
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
**Patch target.** Paths address the whole `.sdk.json` file as it sits on disk: `/definition/writes/-` for an engine's writes array, or `/logic/entrypoint` for the logic file path. `update package` patches `seriousgaming.sdk.json` itself, so its paths start at the top level.
|
|
1001
|
+
|
|
1002
|
+
**Missing parent paths.** RFC 6902 `add` creates only the final path segment, so every parent must already exist. Resource templates may omit empty arrays (an engine created with `reads: []` may have no `reads` key on disk). To add to a field that may not exist, create it first:
|
|
1003
|
+
|
|
1004
|
+
```bash
|
|
1005
|
+
# Two-op approach: create the array, then append
|
|
1006
|
+
pnpm run sdk update engine --patch '[
|
|
1007
|
+
{"op": "add", "path": "/definition/reads", "value": []},
|
|
1008
|
+
{"op": "add", "path": "/definition/reads/-", "value": "x"}
|
|
1009
|
+
]'
|
|
1010
|
+
|
|
1011
|
+
# Or set the whole array in one operation
|
|
1012
|
+
pnpm run sdk update engine --patch '[
|
|
1013
|
+
{"op": "add", "path": "/definition/reads", "value": ["x"]}
|
|
1014
|
+
]'
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
**Input modes.** When `--patch` is present, it takes priority over a positional JSON argument and stdin. `--file` supplies a full definition rather than a patch array, so a patch passed that way fails validation.
|
|
1018
|
+
|
|
1019
|
+
#### Update the package
|
|
1020
|
+
|
|
1021
|
+
```bash
|
|
1022
|
+
pnpm run sdk update package '<JSON>'
|
|
1023
|
+
pnpm run sdk update package --patch '<JSON Patch>'
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
A package is a game, so this one command replaces or patches `seriousgaming.sdk.json`, which carries the package identifier and the game's own fields (locales, `maxTicks`, `teams`, and so on). There is no `new game` and no `delete game`. The game's own identifier is the package identifier with `.game` appended, and it uses whatever the package declares. The command never touches `package.json`, which owns the npm name, description and version.
|
|
1027
|
+
|
|
1028
|
+
A full replacement replaces the whole manifest, so any setting the JSON omits (`customScenarios` and `scenarioFormat` included) is dropped. The manifest has no `configuration` block: a game's values are its settings resources' defaults, so change those with `update settings`, and the build refuses a manifest that still carries one. Restate every setting you want to keep, or use `--patch` to change one path at a time.
|
|
1029
|
+
|
|
1030
|
+
```bash
|
|
1031
|
+
pnpm run sdk update package '{
|
|
1032
|
+
"identifier": "com.example.mygame",
|
|
1033
|
+
"supportedLocales": ["en"],
|
|
1034
|
+
"locales": { "en": { "name": "My Game" } },
|
|
1035
|
+
"maxTicks": 10,
|
|
1036
|
+
"teams": { "mode": "shared-state", "min": 2 }
|
|
1037
|
+
}'
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
`maxTicks` is optional when something else ends the game: the engine returning `complete: true` from `Run`, or a tick controller returning `complete: true`. A game with neither `maxTicks` nor a tick controller still builds, with a warning, because only the engine can end it and the build cannot see whether it ever does. See [Goal-based games](./guides/games.md#goal-based-games).
|
|
1041
|
+
|
|
1042
|
+
### Deleting resources
|
|
1043
|
+
|
|
1044
|
+
| Command | What it does | Options |
|
|
1045
|
+
| ------------------------------------------ | ------------------------------------- | ------------------------ |
|
|
1046
|
+
| `delete capability <identifier> [options]` | Delete a capability. | `--working-dir`, `--yes` |
|
|
1047
|
+
| `delete settings <identifier> [options]` | Delete a settings resource. | `--working-dir`, `--yes` |
|
|
1048
|
+
| `delete engine [options]` | Delete an engine. | `--working-dir`, `--yes` |
|
|
1049
|
+
| `delete ui [options]` | Delete a user interface. | `--working-dir`, `--yes` |
|
|
1050
|
+
| `delete setup [options]` | Delete a setup user interface. | `--working-dir`, `--yes` |
|
|
1051
|
+
| `delete scenario_editor [options]` | Delete a scenario editor. | `--working-dir`, `--yes` |
|
|
1052
|
+
| `delete tick_controller [options]` | Delete a tick controller. | `--working-dir`, `--yes` |
|
|
1053
|
+
| `delete session [options]` | Delete a session user interface. | `--working-dir`, `--yes` |
|
|
1054
|
+
| `delete waiting_room [options]` | Delete a waiting room user interface. | `--working-dir`, `--yes` |
|
|
1055
|
+
| `delete presentation [options]` | Delete a presentation. | `--working-dir`, `--yes` |
|
|
1056
|
+
| `delete scenario <identifier> [options]` | Delete a scenario. | `--working-dir`, `--yes` |
|
|
1057
|
+
| `delete guide [options]` | Delete a facilitator guide. | `--working-dir`, `--yes` |
|
|
1058
|
+
| `delete hook <identifier> [options]` | Delete a hook. | `--working-dir`, `--yes` |
|
|
1059
|
+
| `delete validator <identifier> [options]` | Delete a validator. | `--working-dir`, `--yes` |
|
|
1060
|
+
| `delete endpoint <identifier> [options]` | Delete an endpoint. | `--working-dir`, `--yes` |
|
|
1061
|
+
|
|
1062
|
+
Their options, as `delete capability` takes them:
|
|
1063
|
+
|
|
1064
|
+
| Option | Default | Description |
|
|
1065
|
+
| -------------------------- | --------------------- | ---------------------------------------------------------- |
|
|
1066
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory containing the package. |
|
|
1067
|
+
| `-y, --yes` | | Answer yes to the confirmation, so it runs without asking. |
|
|
1068
|
+
|
|
1069
|
+
A slot resource takes no identifier, since the slot is its identifier:
|
|
1070
|
+
|
|
1071
|
+
```bash
|
|
1072
|
+
pnpm run sdk delete <type> <identifier>
|
|
1073
|
+
pnpm run sdk delete <slot-type>
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
Examples:
|
|
1077
|
+
|
|
1078
|
+
```bash
|
|
1079
|
+
pnpm run sdk delete capability inventory
|
|
1080
|
+
pnpm run sdk delete settings demand
|
|
1081
|
+
pnpm run sdk delete engine
|
|
1082
|
+
pnpm run sdk delete session
|
|
1083
|
+
pnpm run sdk delete waiting_room
|
|
1084
|
+
pnpm run sdk delete presentation
|
|
1085
|
+
pnpm run sdk delete setup
|
|
1086
|
+
pnpm run sdk delete scenario_editor
|
|
1087
|
+
pnpm run sdk delete tick_controller
|
|
1088
|
+
pnpm run sdk delete hook assignroles
|
|
1089
|
+
pnpm run sdk delete validator decisionlimit
|
|
1090
|
+
pnpm run sdk delete endpoint summarise
|
|
1091
|
+
pnpm run sdk delete scenario ai_influence
|
|
1092
|
+
pnpm run sdk delete guide
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
Each `delete` asks for confirmation first. Pass `-y, --yes` to answer it, as a script, CI or an agent must: without a terminal to ask on, a `delete` without `--yes` fails with `PROMPT_REQUIRED` (exit 2) rather than waiting.
|
|
1096
|
+
|
|
1097
|
+
`delete settings` removes the settings directory and every reference to it: from each resource's `settings`, the `configures` of the setup and scenario editor slots, and each scenario's `settings`. It lists those references before asking you to confirm.
|
|
1098
|
+
|
|
1099
|
+
### JSON output
|
|
1100
|
+
|
|
1101
|
+
With `--json`, the `data` of `new`, `update`, and `delete` lists what changed, the same shape for every resource type. Paths are relative to the package root, with forward slashes:
|
|
1102
|
+
|
|
1103
|
+
```bash
|
|
1104
|
+
pnpm run --silent sdk update settings demand -- \
|
|
1105
|
+
--patch '[{"op":"replace","path":"/definition/settingsSchema/properties/BaseDemand/default","value":150}]' \
|
|
1106
|
+
--json
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
```json
|
|
1110
|
+
{
|
|
1111
|
+
"ok": true,
|
|
1112
|
+
"command": "update settings",
|
|
1113
|
+
"data": {
|
|
1114
|
+
"resourceType": "settings",
|
|
1115
|
+
"identifier": "demand",
|
|
1116
|
+
"filesCreated": [],
|
|
1117
|
+
"filesUpdated": ["settings/demand/settings.sdk.json"],
|
|
1118
|
+
"filesDeleted": [],
|
|
1119
|
+
"referencesUpdated": [],
|
|
1120
|
+
"referencesRemoved": [],
|
|
1121
|
+
"directoriesRenamed": []
|
|
1122
|
+
},
|
|
1123
|
+
"warnings": []
|
|
1124
|
+
}
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
A failure is the failure envelope, with a code and exit code 2 for a resource that does not exist:
|
|
1128
|
+
|
|
1129
|
+
```json
|
|
1130
|
+
{
|
|
1131
|
+
"ok": false,
|
|
1132
|
+
"command": "update capability",
|
|
1133
|
+
"error": { "code": "RESOURCE_NOT_FOUND", "message": "Capability \"missing\" not found" },
|
|
1134
|
+
"diagnostics": [],
|
|
1135
|
+
"warnings": []
|
|
1136
|
+
}
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
Prompts cannot produce JSON, so under `--json`:
|
|
1140
|
+
|
|
1141
|
+
- `new` and `update` need a JSON definition (as an argument, via `--file`, or on stdin) or a `--patch`, since without one they would fall through to interactive prompts and fail with `PROMPT_REQUIRED`
|
|
1142
|
+
- `delete` needs `--yes`, which answers the confirmation prompt
|
|
1143
|
+
|
|
1144
|
+
### Supplying JSON
|
|
1145
|
+
|
|
1146
|
+
- **Inline**: wrap the JSON in single quotes and use double quotes inside, as every example on this page does
|
|
1147
|
+
- **From a file**: `--file definition.json`, or redirect it on stdin with `pnpm run sdk new capability < definition.json`
|
|
1148
|
+
|
|
1149
|
+
### Identifier naming
|
|
1150
|
+
|
|
1151
|
+
A package is named globally, so it keeps a reverse-DNS identifier. A resource is named by its directory inside the package, so it is a single short name:
|
|
1152
|
+
|
|
1153
|
+
```
|
|
1154
|
+
✅ com.mycompany.retailgame package
|
|
1155
|
+
✅ inventory resource
|
|
1156
|
+
❌ com.mycompany.game.inventory resource, not a short name
|
|
1157
|
+
❌ Inventory resource, not lowercase
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
A resource name is lowercase letters, digits, and underscores, starting with a letter. Its game's identifier is the package identifier with `.game` appended.
|
|
1161
|
+
|
|
1162
|
+
## Session commands
|
|
1163
|
+
|
|
1164
|
+
These commands play the game. None takes a game identifier: a package is a game, so there is nothing to name.
|
|
1165
|
+
|
|
1166
|
+
### Where the session lives
|
|
1167
|
+
|
|
1168
|
+
The dev server owns the session in memory and is the only thing that runs your game's logic. A session command reaches it rather than keeping a copy of its own: `sdk tick` advances the session a browser is watching, and a tick taken in the browser is what the next `sdk view` reports.
|
|
1169
|
+
|
|
1170
|
+
`.seriousgaming-sdk/session.json` is how a command finds it: a lock file, written once at startup and removed at shutdown, carrying the server's pid, port and instance id, the machine it runs on, the version and install path of the tools that started it, and whether a command started it in the background. Session state itself is never written to disk. Set `SERIOUSGAMING_DEV_STATE_DIR` to keep the lock outside the package, one entry per package, for example in a container whose project directory is restored from a snapshot.
|
|
1171
|
+
|
|
1172
|
+
With no server running, a session command starts one in the background, says so on stderr, and carries on. That server outlives the command, and `SERIOUSGAMING_DEV_PORT` tells it where to start looking for a port.
|
|
1173
|
+
|
|
1174
|
+
Set `SERIOUSGAMING_DEV_URL` to send every session command to a server by its address instead of the one the lock names, such as one started with [`sdk dev --isolated`](#run-a-second-server-beside-your-own). A server that does not answer there fails the command with `DEV_SERVER_UNREACHABLE` (exit 5), and nothing is started in its place.
|
|
1175
|
+
|
|
1176
|
+
**A stale lock.** A lock no longer names a running server when its process is gone, its pid is the process reading it, it was written on another machine, or its port refuses the connection or answers as another server. Such a lock is removed and the command carries on as if there were none, so `sdk dev` starts rather than reporting itself as already running.
|
|
1177
|
+
|
|
1178
|
+
**A server from other tools.** A server outlives the tools that started it, so after an SDK upgrade, a rebuild of a linked checkout or a switch of branch, it may be running code your CLI no longer is. A command compares the lock's tools version and install path with its own:
|
|
1179
|
+
|
|
1180
|
+
- A server a command started in the background is stopped and a fresh one started, with a `SESSION_RESTARTED` warning. Its session does not carry over
|
|
1181
|
+
- A server you started with `sdk dev` in a terminal is never stopped for you. The command fails with `SESSION_STALE` (exit 5) and a hint to run `sdk dev stop`
|
|
1182
|
+
|
|
1183
|
+
**What the server could not apply.** Whatever the dev server could not apply live is recorded, not only logged, and every session command repeats it on stderr and in the envelope's `warnings`, so it reaches you even from a background server nobody is watching:
|
|
1184
|
+
|
|
1185
|
+
| Code | Meaning |
|
|
1186
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
1187
|
+
| `SETTINGS_STALE` | An edit is pending until `sdk init` (see [What reloads](#what-reloads)) |
|
|
1188
|
+
| `RELOAD_FAILED` | The last edited bundle did not load, so the previous one is still in use. Cleared by an edit that loads |
|
|
1189
|
+
| `CAPABILITY_SEEDED` | A capability was added with its schema defaults and `Init` has not run for it. Cleared by `sdk init` |
|
|
1190
|
+
|
|
1191
|
+
`GET /api/session` reports the same list as `warnings`, with the pending edits as `pending`.
|
|
1192
|
+
|
|
1193
|
+
**What `sdk build` would refuse.** The dev server runs the checks `sdk build --validate-only` runs, when it starts and after every edit. A package that fails them still runs, so an edit that spans several files can be finished with the session in view, but not silently: each error is printed on the server's stderr, shown in a banner on the console, and added to the list above under its own diagnostic code (`REFERENCE_UNKNOWN`, `LOGIC_EXPORT_MISSING` and so on, see [CLI error codes](cli-error-codes.md)) with `build: true`. It is cleared by the edit that fixes it. Run `sdk build --validate-only` for the full report, warnings included.
|
|
1194
|
+
|
|
1195
|
+
A game with a `setup` slot starts at its configuration step (see [Building a setup screen](./guides/setup.md)). A session a command starts for itself has no configuration page anybody is looking at, so the command presses Play for you. One you started with `sdk dev`, or sent back with `sdk reconfigure`, waits there: a tick or a context write is refused until somebody presses Play in the console or runs [`sdk play`](#undo-reset-and-reconfigure).
|
|
1196
|
+
|
|
1197
|
+
Every session command also takes:
|
|
1198
|
+
|
|
1199
|
+
- `-w, --working-dir [PATH]`: the package directory (default: the current directory)
|
|
1200
|
+
- `--no-server`: run in this process instead of starting a dev server. Each such command is a fresh session starting at tick 0, with nothing left behind, so a multi-tick run needs a server, or [`createTestSession`](./guides/engine-testing.md)
|
|
1201
|
+
|
|
1202
|
+
See [The CLI and the dev server](./cli-and-dev-server.md) for how the two fit together.
|
|
1203
|
+
|
|
1204
|
+
### Configure the game
|
|
1205
|
+
|
|
1206
|
+
```text
|
|
1207
|
+
pnpm run sdk configure [settings] [options]
|
|
1208
|
+
```
|
|
1209
|
+
|
|
1210
|
+
Override the game's settings for this session, keyed by settings identifier.
|
|
1211
|
+
|
|
1212
|
+
| Option | Default | Description |
|
|
1213
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
1214
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1215
|
+
| `-f, --file [PATH]` | | Read the settings from a file. |
|
|
1216
|
+
|
|
1217
|
+
```bash
|
|
1218
|
+
pnpm run sdk configure '<JSON>'
|
|
1219
|
+
pnpm run sdk configure -f config.json
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
Sets settings values for CLI and dev server sessions, keyed by settings identifier: the directory name under `settings/`. For an engine whose settings resource is `settings/engine/`:
|
|
1223
|
+
|
|
1224
|
+
```json
|
|
1225
|
+
{
|
|
1226
|
+
"engine": { "BaseDemand": 200, "CostPerUnit": 2 }
|
|
1227
|
+
}
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
The number of rounds and the team bounds are the built-in `game` settings, set the same way: `{ "game": { "maxTicks": 6 } }` plays six ticks. `game.waitingRoom.openOnStart` is refused, because it takes effect before setup (see [The game settings](./guides/settings.md#the-game-settings)).
|
|
1231
|
+
|
|
1232
|
+
The values are validated against each settings resource's `settingsSchema` and written to `.seriousgaming-sdk/configuration.json`, which holds the session overrides. A partial object is fine: keys you omit keep their scenario's value, or their default. An identifier that names no settings resource in the package is an error.
|
|
1233
|
+
|
|
1234
|
+
Settings are resolved when a session starts (see [Settings](./guides/settings.md#overriding-settings)), so a running session is started again on the new values, at tick 0, keeping its team count, scenario and locale. A session waiting at its configuration step is started, because saving a configuration is what that step's Play is for. With no session running, the next one starts on it.
|
|
1235
|
+
|
|
1236
|
+
With `--json`, the envelope's `data` is `{ "message": "...", "restarted": true|false }`, with the resolved `settings` when a session was restarted.
|
|
1237
|
+
|
|
1238
|
+
**Output:** `✓ Settings saved, and the running session restarted on them at tick 0.` With no session running, `✓ Settings saved. The next session starts on them.`
|
|
1239
|
+
|
|
1240
|
+
**Errors:** every validation failure is reported together, each labelled by its settings identifier and followed by the JSON Pointer to the offending field:
|
|
1241
|
+
|
|
1242
|
+
```
|
|
1243
|
+
Error: Settings validation failed:
|
|
1244
|
+
Settings "engine": /BaseDemand must be number
|
|
1245
|
+
Unknown settings "pricing": expected one of engine, ui
|
|
1246
|
+
```
|
|
1247
|
+
|
|
1248
|
+
`.seriousgaming-sdk/configuration.json` is authored content, so a value in it that no schema declares any more is an error rather than something to overwrite. Correct the file, or delete it to start again from the schema defaults.
|
|
1249
|
+
|
|
1250
|
+
### Start or rebuild a session
|
|
1251
|
+
|
|
1252
|
+
```text
|
|
1253
|
+
pnpm run sdk init [options]
|
|
1254
|
+
```
|
|
1255
|
+
|
|
1256
|
+
Start the session, or put a running one back at tick 0.
|
|
1257
|
+
|
|
1258
|
+
| Option | Default | Description |
|
|
1259
|
+
| -------------------------- | --------------------- | -------------------------------------------------------------------------------------------- |
|
|
1260
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1261
|
+
| `--teams [NUMBER]` | | Number of teams to simulate (enables multi-team mode). |
|
|
1262
|
+
| `--participants [COUNT]` | | Participants to seed each team with, zero or more, or one per team as 3,0,2 (defaults to 1). |
|
|
1263
|
+
| `--scenario [ID]` | | Scenario identifier to activate (uses default scenario if omitted). |
|
|
1264
|
+
| `--locale [LOCALE]` | | Session locale to run the game in (defaults to en). |
|
|
1265
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1266
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1267
|
+
|
|
1268
|
+
Starts the session, or rebuilds a running one from the package. Any session command starts a session when none is running, so a fresh package needs no `init` at all. Reach for it to rebuild an existing session with a different team count, scenario, or locale, or after editing settings.
|
|
1269
|
+
|
|
1270
|
+
`init` resolves all three afresh, so omitting `--scenario` goes back to the package's default. That is the difference from `reset`, which returns the session to tick 0 with the scenario, team count, and locale it already has.
|
|
1271
|
+
|
|
1272
|
+
In more detail:
|
|
1273
|
+
|
|
1274
|
+
- `--teams`: a whole number, one or more; anything else is a usage error (exit 2). Each team has its own context. See [Multi-team games](./guides/multi-team-games.md)
|
|
1275
|
+
- `--participants`: zero is allowed, for testing a team before anybody has joined it. Without it, each team gets one, or the game's `perTeam.minParticipants`. The count is kept for later `init` runs until you pass a different `--teams`, which drops a per-team list
|
|
1276
|
+
- `--scenario`: the scenario's settings overrides sit between the settings defaults and the session overrides (see [Overriding settings](./guides/settings.md#overriding-settings)). If omitted and the game has a default scenario, the default is used. A scenario the package does not hold is `RESOURCE_NOT_FOUND` (exit 2). See [Scenarios](./guides/scenarios.md)
|
|
1277
|
+
- `--walkthrough`: see [Walkthrough runs](#walkthrough-runs)
|
|
1278
|
+
|
|
1279
|
+
**Output:** JSON with the initial context and tick data, and `scenario`, the scenario the session started on (`null` when it has none). `maxTicks` is omitted for goal-based games whose `game` settings set no `maxTicks`. `sharedContext` is included when the game has shared capabilities, and `teamContexts` when it has several teams.
|
|
1280
|
+
|
|
1281
|
+
```json
|
|
1282
|
+
{
|
|
1283
|
+
"gameId": "com.example.factory.game",
|
|
1284
|
+
"completedTicks": 0,
|
|
1285
|
+
"maxTicks": 10,
|
|
1286
|
+
"complete": false,
|
|
1287
|
+
"context": {
|
|
1288
|
+
"workers": { "WorkerCount": 5 },
|
|
1289
|
+
"production": { "Production": 250 },
|
|
1290
|
+
"sales": { "Sales": 0 }
|
|
1291
|
+
},
|
|
1292
|
+
"scenario": "standard"
|
|
1293
|
+
}
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
**Examples:**
|
|
1297
|
+
|
|
1298
|
+
```bash
|
|
1299
|
+
# Single-team (default)
|
|
1300
|
+
pnpm run sdk init
|
|
1301
|
+
|
|
1302
|
+
# Multi-team with 3 teams
|
|
1303
|
+
pnpm run sdk init --teams 3
|
|
1304
|
+
|
|
1305
|
+
# Three teams: two participants, nobody, and one
|
|
1306
|
+
pnpm run sdk init --teams 3 --participants 2,0,1
|
|
1307
|
+
|
|
1308
|
+
# With a specific scenario
|
|
1309
|
+
pnpm run sdk init --scenario hard_mode
|
|
1310
|
+
```
|
|
1311
|
+
|
|
1312
|
+
### Advance a tick
|
|
1313
|
+
|
|
1314
|
+
```text
|
|
1315
|
+
pnpm run sdk tick [options]
|
|
1316
|
+
```
|
|
1317
|
+
|
|
1318
|
+
Execute the next tick, initializing the game first if it has not been run yet.
|
|
1319
|
+
|
|
1320
|
+
| Option | Default | Description |
|
|
1321
|
+
| -------------------------- | --------------------- | --------------------------------------------------------------------------------------------- |
|
|
1322
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1323
|
+
| `-p, --patch [JSON]` | | RFC 6902 JSON Patch to apply to context before tick. |
|
|
1324
|
+
| `--team [NUMBER]` | | Team to apply --patch to (multi-team games only, 1-based). |
|
|
1325
|
+
| `--teams [NUMBER]` | | Number of teams to simulate (first run only). |
|
|
1326
|
+
| `--participants [COUNT]` | | Participants to seed each team with, zero or more, or one per team as 3,0,2 (first run only). |
|
|
1327
|
+
| `--scenario [ID]` | | Scenario identifier to activate (first run only). |
|
|
1328
|
+
| `--locale [LOCALE]` | | Change the session locale for this tick onwards. |
|
|
1329
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1330
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1331
|
+
|
|
1332
|
+
Executes one tick, optionally applying decisions first. Against a running `sdk dev` this advances that session, and the person watching the browser sees it immediately. With nothing running it starts a session and then ticks.
|
|
1333
|
+
|
|
1334
|
+
How teams advance depends on the game's `teams.mode`:
|
|
1335
|
+
|
|
1336
|
+
- **Shared-state**: every team advances together, with or without `--team`
|
|
1337
|
+
- **Independent** (the default when `mode` is omitted): with no `--team`, each team advances by one from its own tick, carrying the teams that can move past one that is complete or at its limit. `--team N` advances that team alone
|
|
1338
|
+
|
|
1339
|
+
See [Play modes](./guides/multi-team-games.md#play-modes).
|
|
1340
|
+
|
|
1341
|
+
In more detail:
|
|
1342
|
+
|
|
1343
|
+
- `--patch`: paths start at the capability (`/price/Price`)
|
|
1344
|
+
- `--team N`: the stable team id `team-N` to tick, and the team the `--patch` applies to. Required with `--patch` in a multi-team game, and refused in a one-team game
|
|
1345
|
+
- `--teams`, `--participants` and `--scenario` apply to the first run, when the tick starts the session. `--locale` changes the session locale from this tick onwards
|
|
1346
|
+
- `--walkthrough`: see [Walkthrough runs](#walkthrough-runs)
|
|
1347
|
+
|
|
1348
|
+
**Output:** JSON with the updated context for this tick. It includes `complete: true` when a tick controller has signalled that the game is finished. If the game is already complete, the command exits non-zero with the refusal.
|
|
1349
|
+
|
|
1350
|
+
**Examples:**
|
|
1351
|
+
|
|
1352
|
+
```bash
|
|
1353
|
+
# Execute next tick with no changes
|
|
1354
|
+
pnpm run sdk tick
|
|
1355
|
+
|
|
1356
|
+
# Apply decisions before ticking
|
|
1357
|
+
pnpm run sdk tick \
|
|
1358
|
+
-- --patch '[{"op":"replace","path":"/price/Price","value":3}]'
|
|
1359
|
+
|
|
1360
|
+
# Multiple decisions
|
|
1361
|
+
pnpm run sdk tick \
|
|
1362
|
+
-- --patch '[
|
|
1363
|
+
{"op":"replace","path":"/price/Price","value":5},
|
|
1364
|
+
{"op":"replace","path":"/workers/WorkerCount","value":8}
|
|
1365
|
+
]'
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
### Update the context
|
|
1369
|
+
|
|
1370
|
+
```text
|
|
1371
|
+
pnpm run sdk patch <patch> [options]
|
|
1372
|
+
```
|
|
1373
|
+
|
|
1374
|
+
Apply an RFC 6902 JSON Patch to the game context without ticking forward.
|
|
1375
|
+
|
|
1376
|
+
| Option | Default | Description |
|
|
1377
|
+
| -------------------------- | --------------------- | ------------------------------------------------------- |
|
|
1378
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1379
|
+
| `--team [NUMBER]` | | Team to patch (required for multi-team games, 1-based). |
|
|
1380
|
+
| `--shared` | | Patch the shared store rather than a team. |
|
|
1381
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1382
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1383
|
+
|
|
1384
|
+
Applies an RFC 6902 JSON Patch to the game context without advancing the tick. With no session running, it starts one first, so it patches tick 0 of a fresh session.
|
|
1385
|
+
|
|
1386
|
+
| Command | Effect | Use it for |
|
|
1387
|
+
| -------------- | ------------------------------------------------------------ | --------------------------------------------------- |
|
|
1388
|
+
| `patch` | Modifies the context, stays at the current tick | Adjusting state without running the engine |
|
|
1389
|
+
| `tick --patch` | Modifies the context, then executes the engine for next tick | Simulating decisions that should drive engine logic |
|
|
1390
|
+
|
|
1391
|
+
In more detail:
|
|
1392
|
+
|
|
1393
|
+
- `<patch>`: required, in the same format as `tick --patch`
|
|
1394
|
+
- `--team N`: the stable team id `team-N` to patch. Required in a multi-team game, unless you pass `--shared`
|
|
1395
|
+
- `--shared`: patches the shared store (see [shared capabilities](./guides/multi-team-games.md#shared-capabilities)), as a session UI's shared write does. Paths start at a shared capability (`/market/AveragePrice`), and every team sees the change. A `remove` is refused, because a shared write merges into the store. Use this for a shared capability in a multi-team game, where a team-addressed patch to one is refused
|
|
1396
|
+
|
|
1397
|
+
**Output:** JSON with the updated context at the current tick.
|
|
1398
|
+
|
|
1399
|
+
**Errors:** a failed operation exits non-zero and leaves the session unchanged. `Path does not exist` means a path does not match the context's structure, and `Array index out of range` means an index is past the end of an array. Other failures are reported as `Patch failed: <reason>`.
|
|
1400
|
+
|
|
1401
|
+
**Examples:**
|
|
1402
|
+
|
|
1403
|
+
```bash
|
|
1404
|
+
# Update a single context value
|
|
1405
|
+
pnpm run sdk patch '[{"op":"replace","path":"/price/Price","value":3}]'
|
|
1406
|
+
|
|
1407
|
+
# Update multiple values
|
|
1408
|
+
pnpm run sdk patch '[
|
|
1409
|
+
{"op":"replace","path":"/price/Price","value":5},
|
|
1410
|
+
{"op":"replace","path":"/workers/WorkerCount","value":8}
|
|
1411
|
+
]'
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
### View the state
|
|
1415
|
+
|
|
1416
|
+
```text
|
|
1417
|
+
pnpm run sdk view [options]
|
|
1418
|
+
```
|
|
1419
|
+
|
|
1420
|
+
View the current game state.
|
|
1421
|
+
|
|
1422
|
+
| Option | Default | Description |
|
|
1423
|
+
| -------------------------- | --------------------- | ----------------------------------------------------------------- |
|
|
1424
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1425
|
+
| `--team [NUMBER]` | | Show a specific team (multi-team games only, 1-based). |
|
|
1426
|
+
| `--full` | | Print the whole state projection rather than the reading summary. |
|
|
1427
|
+
| `--tick [NUMBER]` | | Print a past committed tick rather than the current one. |
|
|
1428
|
+
| `--to [NUMBER]` | | With --tick, print every tick from --tick to this one. |
|
|
1429
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1430
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1431
|
+
|
|
1432
|
+
Prints the current game state without changing it, or the state at a past tick.
|
|
1433
|
+
|
|
1434
|
+
In more detail:
|
|
1435
|
+
|
|
1436
|
+
- `--team N`: show only the team with the stable id `team-N`. Omit to show all teams
|
|
1437
|
+
- `--full`: the whole state projection is the session, every team's context and roster, the shared store, the resolved `settings`, the timer, and any armed faults. It is the same document the dev server serves at `GET /api/state` and the console renders from
|
|
1438
|
+
- `--tick N`: the state as it was at committed tick N, from the session's own snapshots. Returns `{ "entries": [...] }`, one per team per tick, each with `tick`, `teamId`, `index`, `name`, `context`, `recordedAt` and `complete`. The current tick is not in the past, so use `view` on its own for that
|
|
1439
|
+
- `--to M`: M is clamped to the last committed tick, so `--tick 0 --to 99` reads everything there is
|
|
1440
|
+
|
|
1441
|
+
**Output:** JSON with the latest tick data, the context, and each team's roster. In a multi-team game without `--team`, it returns `{ "teams": [...] }`. Every team carries `participants`, each with its `id`, `name`, `index`, and `connected`, so the plain view already answers who is in the room.
|
|
1442
|
+
|
|
1443
|
+
**Examples:**
|
|
1444
|
+
|
|
1445
|
+
```bash
|
|
1446
|
+
pnpm run sdk view
|
|
1447
|
+
|
|
1448
|
+
# The whole state projection, which is what an agent reads
|
|
1449
|
+
pnpm run sdk view --full
|
|
1450
|
+
|
|
1451
|
+
# What rounds 1 to 3 left behind, for team 2
|
|
1452
|
+
pnpm run sdk view --tick 1 --to 3 --team 2
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
### Undo, reset, and reconfigure
|
|
1456
|
+
|
|
1457
|
+
```text
|
|
1458
|
+
pnpm run sdk undo [options]
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
Undo the last committed tick.
|
|
1462
|
+
|
|
1463
|
+
| Option | Default | Description |
|
|
1464
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1465
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1466
|
+
| `--team [NUMBER]` | | Team to undo (multi-team games only, 1-based). |
|
|
1467
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1468
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1469
|
+
|
|
1470
|
+
```text
|
|
1471
|
+
pnpm run sdk reset [options]
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
Return the session to tick 0.
|
|
1475
|
+
|
|
1476
|
+
| Option | Default | Description |
|
|
1477
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1478
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1479
|
+
| `--team [NUMBER]` | | Team to reset (multi-team games only, 1-based). |
|
|
1480
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1481
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1482
|
+
|
|
1483
|
+
```text
|
|
1484
|
+
pnpm run sdk reconfigure [options]
|
|
1485
|
+
```
|
|
1486
|
+
|
|
1487
|
+
Return the session to its configuration step, and to tick 0.
|
|
1488
|
+
|
|
1489
|
+
| Option | Default | Description |
|
|
1490
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1491
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1492
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1493
|
+
|
|
1494
|
+
```text
|
|
1495
|
+
pnpm run sdk play [options]
|
|
1496
|
+
```
|
|
1497
|
+
|
|
1498
|
+
Leave the configuration step and start the session: the console's Play.
|
|
1499
|
+
|
|
1500
|
+
| Option | Default | Description |
|
|
1501
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1502
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1503
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1504
|
+
|
|
1505
|
+
```bash
|
|
1506
|
+
pnpm run sdk undo [--team N] # undo the last committed tick
|
|
1507
|
+
pnpm run sdk reset [--team N] # back to tick 0
|
|
1508
|
+
pnpm run sdk reconfigure # back to the configuration step, and tick 0
|
|
1509
|
+
pnpm run sdk play # leave the configuration step, as Play does
|
|
1510
|
+
```
|
|
1511
|
+
|
|
1512
|
+
`reset` keeps the scenario, team count, and locale the session already has; use `init` to resolve them afresh. `undo` and `reset` also take `--walkthrough`. `reset --walkthrough` starts the walkthrough again from the session's current scenario, locale and configuration, as the console's reset does. See [Walkthrough runs](#walkthrough-runs).
|
|
1513
|
+
|
|
1514
|
+
`reconfigure` is for a game with a `setup` slot, and is refused for one without. It resets as well, because settings are fixed when play starts: a change that did not restart the session would reach nothing.
|
|
1515
|
+
|
|
1516
|
+
`play` starts a session waiting at its configuration step on the configuration it has, and prints the tick report with the resolved `settings` and `started: true`. On a session already playing it changes nothing and reports `started: false`. To set values and start in one go, use [`configure`](#configure-the-game).
|
|
1517
|
+
|
|
1518
|
+
### Teams
|
|
1519
|
+
|
|
1520
|
+
`<team>` is 1-based, as it reads in a URL.
|
|
1521
|
+
|
|
1522
|
+
```text
|
|
1523
|
+
pnpm run sdk team add [name] [options]
|
|
1524
|
+
```
|
|
1525
|
+
|
|
1526
|
+
Add a team to the running session.
|
|
1527
|
+
|
|
1528
|
+
| Option | Default | Description |
|
|
1529
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1530
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1531
|
+
| `--participants [COUNT]` | | Participants to seed the new team with, zero or more. |
|
|
1532
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1533
|
+
|
|
1534
|
+
```text
|
|
1535
|
+
pnpm run sdk team remove <team> [options]
|
|
1536
|
+
```
|
|
1537
|
+
|
|
1538
|
+
Remove an empty team (1-based, independent mode only).
|
|
1539
|
+
|
|
1540
|
+
| Option | Default | Description |
|
|
1541
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1542
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1543
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1544
|
+
|
|
1545
|
+
```text
|
|
1546
|
+
pnpm run sdk team rename <team> <name> [options]
|
|
1547
|
+
```
|
|
1548
|
+
|
|
1549
|
+
Rename a team (1-based).
|
|
1550
|
+
|
|
1551
|
+
| Option | Default | Description |
|
|
1552
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1553
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1554
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1555
|
+
|
|
1556
|
+
`team remove` deletes an empty team from an independent-mode session, as a session UI's `deleteTeam` does. It is refused in a shared-state session, for a team that still has participants (move them out with `participant move` first, connected or not), and for the last team. Every team starts with one placeholder participant unless you pass `--participants 0` to `team add` or `init`, so move that one too. The removed team's index is left as a gap and no other team is renumbered; the next `team add` takes the gap back as a new team with the default name. Undo never restores a removed team.
|
|
1557
|
+
|
|
1558
|
+
### Participants
|
|
1559
|
+
|
|
1560
|
+
```text
|
|
1561
|
+
pnpm run sdk participant add [name] [options]
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
Add a participant to a team.
|
|
1565
|
+
|
|
1566
|
+
| Option | Default | Description |
|
|
1567
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1568
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1569
|
+
| `--team [NUMBER]` | | Team to add them to (1-based, defaults to 1). |
|
|
1570
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1571
|
+
|
|
1572
|
+
```text
|
|
1573
|
+
pnpm run sdk participant rename <participantId> <name> [options]
|
|
1574
|
+
```
|
|
1575
|
+
|
|
1576
|
+
Rename a participant.
|
|
1577
|
+
|
|
1578
|
+
| Option | Default | Description |
|
|
1579
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1580
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1581
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1582
|
+
|
|
1583
|
+
```text
|
|
1584
|
+
pnpm run sdk participant move <participantId> <team> [options]
|
|
1585
|
+
```
|
|
1586
|
+
|
|
1587
|
+
Move a participant to another team (1-based).
|
|
1588
|
+
|
|
1589
|
+
| Option | Default | Description |
|
|
1590
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1591
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1592
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1593
|
+
|
|
1594
|
+
`participant add` defaults to team 1 when `--team` is omitted.
|
|
1595
|
+
|
|
1596
|
+
### Waiting room, scenario, and locale
|
|
1597
|
+
|
|
1598
|
+
```text
|
|
1599
|
+
pnpm run sdk waiting-room <action> [options]
|
|
1600
|
+
```
|
|
1601
|
+
|
|
1602
|
+
Open or close the session waiting room.
|
|
1603
|
+
|
|
1604
|
+
| Option | Default | Description |
|
|
1605
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1606
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1607
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1608
|
+
|
|
1609
|
+
`<action>` is `open` or `close`.
|
|
1610
|
+
|
|
1611
|
+
```text
|
|
1612
|
+
pnpm run sdk scenario [identifier] [options]
|
|
1613
|
+
```
|
|
1614
|
+
|
|
1615
|
+
Activate a scenario, or `none` to run on the settings defaults.
|
|
1616
|
+
|
|
1617
|
+
| Option | Default | Description |
|
|
1618
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1619
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1620
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1621
|
+
|
|
1622
|
+
```text
|
|
1623
|
+
pnpm run sdk locale <code> [options]
|
|
1624
|
+
```
|
|
1625
|
+
|
|
1626
|
+
Change the session locale.
|
|
1627
|
+
|
|
1628
|
+
| Option | Default | Description |
|
|
1629
|
+
| -------------------------- | --------------------- | ----------------------------------------------------- |
|
|
1630
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1631
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1632
|
+
|
|
1633
|
+
### The tick timer
|
|
1634
|
+
|
|
1635
|
+
For a game with a [tick controller](./guides/tick-controller.md). Each command prints the timer afterwards: one `timer` for the session, or one per team in an independent multi-team game, where every team has its own. Each is the timer's `TimerState` (`enabled`, `paused`, `nextTickAt`, `intervalMs`, `pausedAt`, `pausedMs`, `extendedMs`, `scheduleStartedAt`, durations in milliseconds) plus `nextTickIn`, the whole seconds left, for a person reading it.
|
|
1636
|
+
|
|
1637
|
+
```text
|
|
1638
|
+
pnpm run sdk timer [action] [seconds] [options]
|
|
1639
|
+
```
|
|
1640
|
+
|
|
1641
|
+
Pause, resume or extend the automatic tick timer, or report it when no action is given. `extend <seconds>` moves the scheduled tick only, and a negative value brings it forward.
|
|
1642
|
+
|
|
1643
|
+
| Option | Default | Description |
|
|
1644
|
+
| -------------------------- | --------------------- | ------------------------------------------------------------------------- |
|
|
1645
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1646
|
+
| `--team [NUMBER]` | | Team whose timer to address (independent multi-team games only, 1-based). |
|
|
1647
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1648
|
+
|
|
1649
|
+
```bash
|
|
1650
|
+
pnpm run sdk timer # report it
|
|
1651
|
+
pnpm run sdk timer pause [-- --team N]
|
|
1652
|
+
pnpm run sdk timer resume [-- --team N]
|
|
1653
|
+
pnpm run sdk timer extend <seconds> [-- --team N]
|
|
1654
|
+
```
|
|
1655
|
+
|
|
1656
|
+
**Moving time.** On a dev server started with `--fake-clock`, time stands still until you move it:
|
|
1657
|
+
|
|
1658
|
+
```text
|
|
1659
|
+
pnpm run sdk clock advance <seconds> [options]
|
|
1660
|
+
```
|
|
1661
|
+
|
|
1662
|
+
Move the clock forward, running every automatic tick that comes due.
|
|
1663
|
+
|
|
1664
|
+
| Option | Default | Description |
|
|
1665
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
1666
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1667
|
+
|
|
1668
|
+
It runs every automatic tick that falls due on the way, so three minutes on a one-minute timer is three ticks, and prints `advancedBy`, `ticksRun`, the timer and the tick report. It is refused on the real clock, and backwards. See [Testing without waiting](./guides/tick-controller.md#testing-without-waiting).
|
|
1669
|
+
|
|
1670
|
+
`extend` takes seconds, moves the currently scheduled tick only, and a negative number brings it forward. The interval the controller returns for later ticks is untouched. It is refused while the timer is paused, because there is no scheduled tick to move. Leaving out `--team` addresses every team, and `--team` is refused where every team shares one timer.
|
|
1671
|
+
|
|
1672
|
+
### Fault injection
|
|
1673
|
+
|
|
1674
|
+
The dev server serialises every write against every tick, so it never produces the `conflict` outcome a production runtime produces most, which is the 'Try again' path your UI was told to offer. Arming a fault makes that path reachable, deliberately and reproducibly.
|
|
1675
|
+
|
|
1676
|
+
```text
|
|
1677
|
+
pnpm run sdk fault [kind] [options]
|
|
1678
|
+
```
|
|
1679
|
+
|
|
1680
|
+
Arm a failure the dev server cannot otherwise produce, so the path a UI was told to handle is reachable in development: conflict, denied, llm-failure, hook-throw, endpoint-timeout, tick-failure.
|
|
1681
|
+
|
|
1682
|
+
| Option | Default | Description |
|
|
1683
|
+
| -------------------------- | --------------------- | --------------------------------------------------------- |
|
|
1684
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1685
|
+
| `--times [NUMBER]` | | Fire this many times before disarming (defaults to once). |
|
|
1686
|
+
| `--reason [TEXT]` | | Message to carry on the resulting outcome. |
|
|
1687
|
+
| `--disarm` | | Disarm the fault instead of arming it. |
|
|
1688
|
+
| `--no-server` | | Run in this process instead of starting a dev server. |
|
|
1689
|
+
|
|
1690
|
+
```bash
|
|
1691
|
+
pnpm run sdk fault conflict --reason 'testing the Try again path'
|
|
1692
|
+
pnpm run sdk fault llm-failure --times 3
|
|
1693
|
+
pnpm run sdk fault conflict --disarm
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
Available faults: `conflict`, `denied`, `llm-failure`, `hook-throw`, `endpoint-timeout`, and `tick-failure`. Each fires once unless `--times` says otherwise, and `--disarm` puts it away. A `--reason` becomes the message on the refusal, failed tick, or failed endpoint call the fault produces, so you can check how your UI shows it; on `hook-throw` it is added to the failure the console reports.
|
|
1697
|
+
|
|
1698
|
+
`llm-failure` fails the next call your logic makes to a platform service (`generateText`, `extractText`, or `generateSpeech`) as a platform failure would, with `--reason` in the error. Each failed call uses up one of its `--times`, so `--times 3` fails the next three calls, whichever resources make them. Logic that does not catch the error fails its tick, hook, or endpoint call, exactly as it would in production.
|
|
1699
|
+
|
|
1700
|
+
### Walkthrough runs
|
|
1701
|
+
|
|
1702
|
+
A walkthrough is a disposable second run of the same game beside the session, for demonstrating it: one team, one participant, always from tick 0, and isolated from the session in both directions, so driving it moves nothing you were about to play. It inherits the session's configuration, scenario, and locale, respects the tick limit its session resolves, and never shows the waiting room.
|
|
1703
|
+
|
|
1704
|
+
`--walkthrough` points `init`, `tick`, `view`, `patch`, `undo`, `reset`, and `endpoint call` at it instead of the session.
|
|
1705
|
+
|
|
1706
|
+
```bash
|
|
1707
|
+
pnpm run sdk view --walkthrough # where the walkthrough is
|
|
1708
|
+
pnpm run sdk tick --walkthrough # advance it, leaving the session alone
|
|
1709
|
+
pnpm run sdk reset --walkthrough # back to tick 0
|
|
1710
|
+
```
|
|
1711
|
+
|
|
1712
|
+
The run is built the first time something asks for it, so there is nothing to create. In `sdk dev` it is also a surface, at `/walkthrough`, listed in the drawer's Surfaces tab.
|
|
1713
|
+
|
|
1714
|
+
Your logic reads `meta.runKind` and your surfaces read `useRunKind()` to tell the two apart. See [Engines](./guides/engine.md#walkthroughs) and [User interfaces](./guides/ui.md#walkthroughs).
|
|
1715
|
+
|
|
1716
|
+
### Upload a blob
|
|
1717
|
+
|
|
1718
|
+
```text
|
|
1719
|
+
pnpm run sdk blob upload <file> [options]
|
|
1720
|
+
```
|
|
1721
|
+
|
|
1722
|
+
Upload a file as a blob and print its blob ID.
|
|
1723
|
+
|
|
1724
|
+
| Option | Default | Description |
|
|
1725
|
+
| -------------------------- | --------------------- | --------------------------------------------------------- |
|
|
1726
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1727
|
+
| `--settings` | | Store with settings retention (survives a session reset). |
|
|
1728
|
+
|
|
1729
|
+
Uploads a file and associates it with the game session. It returns the `blob:`-prefixed asset reference that you can patch into the game context for the engine and user interfaces to use (see [Asset references](./guides/file-handling.md#asset-references)).
|
|
1730
|
+
|
|
1731
|
+
`--settings` stores the blob with `'settings'` retention, as a setup or scenario editor upload is, which survives a session reset. Without it the blob has `'game'` retention, cleared on reset.
|
|
1732
|
+
|
|
1733
|
+
**Output (default):**
|
|
1734
|
+
|
|
1735
|
+
```
|
|
1736
|
+
Uploaded blob: blob:a3f7c2d1-84b0-4e12-9f1a-0c7e8a3b1d5e
|
|
1737
|
+
File: market-research.pdf
|
|
1738
|
+
Type: application/pdf
|
|
1739
|
+
Retention: game
|
|
1740
|
+
```
|
|
1741
|
+
|
|
1742
|
+
**Output (`--json`):** the [envelope](#json-output), whose `data` is:
|
|
1743
|
+
|
|
1744
|
+
```json
|
|
1745
|
+
{
|
|
1746
|
+
"reference": "blob:a3f7c2d1-84b0-4e12-9f1a-0c7e8a3b1d5e",
|
|
1747
|
+
"name": "market-research.pdf",
|
|
1748
|
+
"mimeType": "application/pdf",
|
|
1749
|
+
"retention": "game"
|
|
1750
|
+
}
|
|
1751
|
+
```
|
|
1752
|
+
|
|
1753
|
+
Upload and patch into the context:
|
|
1754
|
+
|
|
1755
|
+
```bash
|
|
1756
|
+
REFERENCE=$(pnpm run --silent sdk blob upload ./market-research.pdf --json | jq -r '.data.reference')
|
|
1757
|
+
pnpm run sdk patch \
|
|
1758
|
+
"[{\"op\":\"replace\",\"path\":\"/upload/DocumentRef\",\"value\":\"$REFERENCE\"}]"
|
|
1759
|
+
```
|
|
1760
|
+
|
|
1761
|
+
A blob with settings retention, which survives a session reset:
|
|
1762
|
+
|
|
1763
|
+
```bash
|
|
1764
|
+
pnpm run sdk blob upload ./scenario-brief.pdf --settings
|
|
1765
|
+
```
|
|
1766
|
+
|
|
1767
|
+
See [File handling](./guides/file-handling.md) for the full reference.
|
|
1768
|
+
|
|
1769
|
+
### Call an endpoint
|
|
1770
|
+
|
|
1771
|
+
```text
|
|
1772
|
+
pnpm run sdk endpoint call <identifier> [options]
|
|
1773
|
+
```
|
|
1774
|
+
|
|
1775
|
+
Invoke an endpoint against the running session and print its response.
|
|
1776
|
+
|
|
1777
|
+
| Option | Default | Description |
|
|
1778
|
+
| ------------------------------ | --------------------- | ------------------------------------------------------------------------- |
|
|
1779
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1780
|
+
| `-r, --request [JSON]` | | The request payload, as JSON. |
|
|
1781
|
+
| `-f, --file [PATH]` | | Read the request payload from a file. |
|
|
1782
|
+
| `-t, --team [INDEX]` | | The team a team-scoped endpoint acts on (one-based). |
|
|
1783
|
+
| `--external` | | Call as a caller outside the game, which reaches only external endpoints. |
|
|
1784
|
+
| `--principal [KIND:ID[:NAME]]` | | With --external, who the call stands in for, e.g. agent:claude-7:Claude. |
|
|
1785
|
+
| `--attach [FIELD=PATH]` | | Send a local file as a file field, inline as a data: URI (repeatable). |
|
|
1786
|
+
| `--save-blobs [DIR]` | | Save every file the response names into DIR. |
|
|
1787
|
+
| `--no-server` | | Run in this process rather than against a dev server. |
|
|
1788
|
+
| `--walkthrough` | | Drive the walkthrough run rather than the session. |
|
|
1789
|
+
|
|
1790
|
+
Invokes one of the package's endpoints against the running session and prints its response as JSON.
|
|
1791
|
+
|
|
1792
|
+
It exercises an endpoint without its real caller. An external endpoint is reached in production by a caller outside the game, such as a facilitator's AI agent, and a user interface endpoint by a screen you may not have built yet: both are slow and unrepeatable ways to find out that a request schema is wrong.
|
|
1793
|
+
|
|
1794
|
+
In more detail:
|
|
1795
|
+
|
|
1796
|
+
- `--external`: an internal endpoint is refused, and the handler sees `caller.role` as `'external'` with no `userInterfaceIdentifier`
|
|
1797
|
+
- `--principal`: who the call stands in for, as a platform would say after authenticating its caller. The handler sees it as `caller.principal`, and the audit records it
|
|
1798
|
+
- `--attach`: a file field is one whose schema carries `blob`. A dotted field reaches into nested objects
|
|
1799
|
+
- `--save-blobs`: each `blob:` reference in the response is saved into `DIR` under its stored name
|
|
1800
|
+
- `--json`: the [envelope](#json-output) carries the response as `data`, or the failure (see below)
|
|
1801
|
+
|
|
1802
|
+
The request may also arrive on stdin, so a payload built by another command can be piped straight in.
|
|
1803
|
+
|
|
1804
|
+
A failed call exits non-zero and prints its kind, its message, and the effects that had already landed before it stopped:
|
|
1805
|
+
|
|
1806
|
+
```
|
|
1807
|
+
Error: Endpoint "startround" failed (tick-failed): Endpoint "startround" stopped at action 1 ("tick"): The game is complete. Its write, action 0 ("tick") had already been applied
|
|
1808
|
+
Applied before the failure: its write, action 0 ("tick")
|
|
1809
|
+
Failed at: action 1 ("tick")
|
|
1810
|
+
```
|
|
1811
|
+
|
|
1812
|
+
A failed call exits 4. With `--json`, the failure envelope's code names the kind, and its `error.details` carries the failure itself:
|
|
1813
|
+
|
|
1814
|
+
```json
|
|
1815
|
+
{
|
|
1816
|
+
"ok": false,
|
|
1817
|
+
"command": "endpoint call",
|
|
1818
|
+
"error": {
|
|
1819
|
+
"code": "INVALID_REQUEST",
|
|
1820
|
+
"message": "Endpoint \"setprice\" failed (invalid-request): ...\nNothing was applied.",
|
|
1821
|
+
"details": {
|
|
1822
|
+
"outcome": {
|
|
1823
|
+
"kind": "invalid-request",
|
|
1824
|
+
"message": "Endpoint \"setprice\" rejected the request: /price must be <= 50"
|
|
1825
|
+
},
|
|
1826
|
+
"applied": []
|
|
1827
|
+
}
|
|
1828
|
+
},
|
|
1829
|
+
"diagnostics": [],
|
|
1830
|
+
"warnings": []
|
|
1831
|
+
}
|
|
1832
|
+
```
|
|
1833
|
+
|
|
1834
|
+
The code is `INVALID_REQUEST`, `HANDLER_ERROR` or `INVALID_RESPONSE` for the three failures only an endpoint has, and the refusal's own code (`REFUSED_DENIED`, `TICK_FAILED` and so on) for the rest. `outcome.kind` is one of `denied`, `invalid-request`, `handler-error`, `invalid-response`, `conflict`, a failed step's own kind such as `tick-failed`, or `error`. `applied` lists the steps that committed, and `failedStep` names the one that failed. See [Endpoints](./guides/endpoints.md#when-a-call-fails).
|
|
1835
|
+
|
|
1836
|
+
Against a dev server, an `--external` call also prints each returned `blob:` reference with the URL an outside caller would fetch it from. That goes to stderr, so stdout stays the response alone for a script to parse.
|
|
1837
|
+
|
|
1838
|
+
A file sent the way a script without an upload route of its own would, and the export an endpoint returns saved beside it:
|
|
1839
|
+
|
|
1840
|
+
```bash
|
|
1841
|
+
pnpm run sdk endpoint call attachresearch --external --team 1 --attach document=./research.pdf
|
|
1842
|
+
pnpm run sdk endpoint call export --external --save-blobs ./exports
|
|
1843
|
+
```
|
|
1844
|
+
|
|
1845
|
+
To send a file the other way, upload it first with `sdk blob upload` and put the `blob:` reference it prints in the request.
|
|
1846
|
+
|
|
1847
|
+
A team-scoped endpoint that changes state:
|
|
1848
|
+
|
|
1849
|
+
```bash
|
|
1850
|
+
pnpm run sdk endpoint call setprice --team 1 --request '{"price": 3.53}'
|
|
1851
|
+
```
|
|
1852
|
+
|
|
1853
|
+
```json
|
|
1854
|
+
{
|
|
1855
|
+
"previous": 5,
|
|
1856
|
+
"current": 3.53
|
|
1857
|
+
}
|
|
1858
|
+
```
|
|
1859
|
+
|
|
1860
|
+
A session-scoped endpoint takes no `--team`, because there is no team for the value to mean anything against. An endpoint that declares `writes` applies its change to the board as part of the call, so `sdk view` afterwards shows it.
|
|
1861
|
+
|
|
1862
|
+
### List the endpoints
|
|
1863
|
+
|
|
1864
|
+
```text
|
|
1865
|
+
pnpm run sdk endpoint list [options]
|
|
1866
|
+
```
|
|
1867
|
+
|
|
1868
|
+
List the package's endpoints and what each one may do.
|
|
1869
|
+
|
|
1870
|
+
| Option | Default | Description |
|
|
1871
|
+
| -------------------------- | --------------------- | ------------------------------------------------------ |
|
|
1872
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1873
|
+
| `--external` | | Only the endpoints a caller outside the game may call. |
|
|
1874
|
+
|
|
1875
|
+
Prints every endpoint the package declares, with its scope, whether it writes, whether a caller outside the game may call it, and its description. It reads the manifest, so it answers without starting a session.
|
|
1876
|
+
|
|
1877
|
+
With `--json`, the [envelope](#json-output)'s `data` lists the endpoints, including each one's request and response schemas.
|
|
1878
|
+
|
|
1879
|
+
An endpoint that declares `actions` is marked `acts` and lists them, and one that answers in two phases (`Plan` and `Respond`) is marked `responds after`. `--json` carries both as `actions` and `responds`.
|
|
1880
|
+
|
|
1881
|
+
**Output (default):**
|
|
1882
|
+
|
|
1883
|
+
```
|
|
1884
|
+
setprice (team, writes, external)
|
|
1885
|
+
Set the unit price
|
|
1886
|
+
Sets a team's unit price, in pounds per unit. Use this when a facilitator asks
|
|
1887
|
+
to change what a team charges.
|
|
1888
|
+
writes: price
|
|
1889
|
+
```
|
|
1890
|
+
|
|
1891
|
+
The description column is the reason to run it. On an external endpoint, the description is what an outside caller, a model most of all, reads to decide whether to call it. Reading yours side by side is when you notice that three of them say much the same thing, which means a wrong call every session and is the one thing here that no test catches.
|
|
1892
|
+
|
|
1893
|
+
### Audit endpoint calls
|
|
1894
|
+
|
|
1895
|
+
```text
|
|
1896
|
+
pnpm run sdk endpoint audit [options]
|
|
1897
|
+
```
|
|
1898
|
+
|
|
1899
|
+
List every endpoint call that changed the running session, and who made it.
|
|
1900
|
+
|
|
1901
|
+
| Option | Default | Description |
|
|
1902
|
+
| -------------------------- | --------------------- | ------------------------------------------------- |
|
|
1903
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1904
|
+
| `--walkthrough` | | Read the walkthrough run rather than the session. |
|
|
1905
|
+
|
|
1906
|
+
Lists every endpoint call that changed the running session, oldest first: which endpoint, the team it ran for, who called it (with the principal of an external call), what it wrote, and the actions it carried out. A call that stopped partway says where. The dev server holds the log, so this needs one running; a `--no-server` session is new and has nothing to show.
|
|
1907
|
+
|
|
1908
|
+
With `--json`, the [envelope](#json-output)'s `data` is the entries.
|
|
1909
|
+
|
|
1910
|
+
**Output (default):**
|
|
1911
|
+
|
|
1912
|
+
```
|
|
1913
|
+
2026-09-30T14:02:11.000Z startround by external agent:claude-7 (Claude)
|
|
1914
|
+
wrote noticeboard; did setWaitingRoom, tick
|
|
1915
|
+
```
|
|
1916
|
+
|
|
1917
|
+
### Team addressing errors
|
|
1918
|
+
|
|
1919
|
+
| Error | Cause |
|
|
1920
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
1921
|
+
| `--team can only be used with multi-team games` | `--team` passed, but the session has one team |
|
|
1922
|
+
| `--team <number> is required for multi-team games` | `patch` in a multi-team game without `--team` |
|
|
1923
|
+
| `--team is required when using --patch with a multi-team game` | `tick --patch` in a multi-team game without `--team` |
|
|
1924
|
+
| `There is no team N in this session. Teams: 1, 2, 3` | The team number is out of range, or the team has been removed |
|
|
1925
|
+
|
|
1926
|
+
## Development server
|
|
1927
|
+
|
|
1928
|
+
### Start the dev server
|
|
1929
|
+
|
|
1930
|
+
Run the game with live reloading:
|
|
1931
|
+
|
|
1932
|
+
```text
|
|
1933
|
+
pnpm run sdk dev [options]
|
|
1934
|
+
```
|
|
1935
|
+
|
|
1936
|
+
Start the Serious Gaming development server with hot reload.
|
|
1937
|
+
|
|
1938
|
+
| Option | Default | Description |
|
|
1939
|
+
| --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1940
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
1941
|
+
| `-p, --port [PORT]` | `3000` | Port to run the dev server on, or auto for any free port (can also be set via SERIOUSGAMING_DEV_PORT env var or .env file). |
|
|
1942
|
+
| `--vite-port [VITE_PORT]` | | Port to run the Vite dev server on (defaults to PORT + 1). |
|
|
1943
|
+
| `--asset-port [ASSET_PORT]` | | Port game UI bundles and their assets are served from, which is a separate origin from the console (defaults to the next free port after the Vite port). |
|
|
1944
|
+
| `--no-open` | | Do not automatically open browser. |
|
|
1945
|
+
| `--api-key [KEY]` | | Serious Gaming platform API key for LLM calls (can also be set via SERIOUSGAMING_API_KEY env var or .env file). |
|
|
1946
|
+
| `--host [URL]` | | Serious Gaming platform origin for LLM calls (can also be set via SERIOUSGAMING_API_HOST env var or .env file). |
|
|
1947
|
+
| `--lan` | | Listen on every network interface, so phones and tablets on the same network can connect (localhost only by default). |
|
|
1948
|
+
| `--teams [NUMBER]` | | Number of teams to simulate (each accessible at `/team/<n>);` omit to use the game's teams.min. |
|
|
1949
|
+
| `--participants [COUNT]` | | Participants to seed each team with, zero or more, or one per team as 3,0,2 (defaults to 1). |
|
|
1950
|
+
| `--scenario [ID]` | | Scenario identifier to activate (uses default scenario if omitted). |
|
|
1951
|
+
| `--fake-clock` | | Run on a clock that moves only when `sdk clock advance` moves it, to test automatic ticks without waiting. |
|
|
1952
|
+
| `--reinit-on-change` | | Restart the game at tick 0 whenever an edit applies only at initialisation (a setting, a manifest field such as teams, a capability removed or rescoped), rather than recording it as pending once play is under way. |
|
|
1953
|
+
| `--isolated` | | Run beside any dev server already running for this package, for tests and recordings: no lock file (CLI commands reach it through SERIOUSGAMING_DEV_URL), configuration from the package alone, and uploads in a temporary directory. |
|
|
1954
|
+
|
|
1955
|
+
In more detail:
|
|
1956
|
+
|
|
1957
|
+
- `--port`: where to start looking for a port. The default is `SERIOUSGAMING_DEV_PORT` when set, otherwise 3000. The server steps up to the first free port from there and prints the one it lands on. `auto` takes any free port the system offers
|
|
1958
|
+
- `--asset-port`: a separate origin from the console, as production's asset host is, so a UI cannot reach the console's API
|
|
1959
|
+
- `--lan`: to test on a phone or tablet (see below). Without it, only this machine can reach the server
|
|
1960
|
+
- `--api-key` and `--host`: default to `SERIOUSGAMING_API_KEY` and `SERIOUSGAMING_API_HOST`, from the environment or `.env`. The host defaults to `https://app.businesssimulations.com`
|
|
1961
|
+
- `--teams` and `--scenario`: see below
|
|
1962
|
+
- `--participants`: zero is allowed. Without it, each team gets one, or the game's `perTeam.minParticipants`
|
|
1963
|
+
- `--fake-clock`: moved with [`sdk clock advance`](#the-tick-timer)
|
|
1964
|
+
- `--reinit-on-change`: however far play has gone, rather than holding the edit as pending (see [What reloads](#what-reloads)). The console shows a short 'Settings changed, game restarted' notice each time. The hosted builder starts the dev server this way
|
|
1965
|
+
- `--isolated`: for a test run or a recording (see below)
|
|
1966
|
+
|
|
1967
|
+
A package holds one session, so a second `sdk dev` for the same package is refused whatever port it asks for, and names the one already running. Stop that one with `sdk dev stop` to move it elsewhere, or start the second with `--isolated`.
|
|
1968
|
+
|
|
1969
|
+
The server prints the console's address and the address game surfaces are served from. With `-j, --json`, the envelope it writes when it stops carries `url`, `assetUrl`, `port`, `assetPort` and `isolated`.
|
|
1970
|
+
|
|
1971
|
+
### Run a second server beside your own
|
|
1972
|
+
|
|
1973
|
+
```bash
|
|
1974
|
+
pnpm run sdk dev --isolated --port auto --no-open
|
|
1975
|
+
# ✓ Dev server running at http://localhost:53712
|
|
1976
|
+
# Game surfaces are served from http://localhost:53714
|
|
1977
|
+
|
|
1978
|
+
SERIOUSGAMING_DEV_URL=http://localhost:53712 pnpm run sdk tick
|
|
1979
|
+
```
|
|
1980
|
+
|
|
1981
|
+
`--isolated` starts a server that touches nothing of the one you are working in, so an end-to-end run, a walkthrough recording or a clip capture does not need yours stopped:
|
|
1982
|
+
|
|
1983
|
+
- **No lock file.** It neither reads nor writes `.seriousgaming-sdk/session.json`, so it starts whatever is running, and a CLI command reaches it only through `SERIOUSGAMING_DEV_URL`
|
|
1984
|
+
- **Configuration from the package alone.** It neither reads nor writes `.seriousgaming-sdk/configuration.json`, so what you last ran `sdk configure` with does not leak into a test
|
|
1985
|
+
- **Temporary uploads.** Blobs go to a temporary directory, removed when the server stops
|
|
1986
|
+
|
|
1987
|
+
Pair it with `--port auto` so it never collides with yours. To start one from a test runner without spawning the CLI, use [`startDevServer`](./guides/testing.md#a-dev-server-for-browser-tests).
|
|
1988
|
+
|
|
1989
|
+
**Several teams.** Start with N teams, each at its own URL:
|
|
1990
|
+
|
|
1991
|
+
```bash
|
|
1992
|
+
pnpm run sdk dev --teams 3
|
|
1993
|
+
# Team 1, first player: http://localhost:3000/team/1/player/1
|
|
1994
|
+
# Team 2, first player: http://localhost:3000/team/2/player/1
|
|
1995
|
+
# Team 3, first player: http://localhost:3000/team/3/player/1
|
|
1996
|
+
# The console, which shows the session UI: http://localhost:3000/
|
|
1997
|
+
# A link to hand out, which asks who you are: http://localhost:3000/team/1/join
|
|
1998
|
+
```
|
|
1999
|
+
|
|
2000
|
+
The setup screen, for a game with a `setup` slot, is at `/setup`: the console opens there while the session is at its configuration step. The scenario editor is at `/scenario-editor`, opened on one scenario from the dev drawer's **Scenario** tab.
|
|
2001
|
+
|
|
2002
|
+
Without `--teams`, the dev server starts with `teams.min` teams when the game sets it above one. A `--teams` count below `teams.min` or above `teams.max` is refused rather than adjusted. Once the session is running, teams can be added up to `teams.max` and removed down to one. See [Multi-team games](./guides/multi-team-games.md).
|
|
2003
|
+
|
|
2004
|
+
Every surface has its own URL, and `?bare` drops the dev chrome from any of them. [Surfaces and their URLs](./cli-and-dev-server.md#surfaces-and-their-urls) lists them all.
|
|
2005
|
+
|
|
2006
|
+
**On a phone or tablet.** The dev server listens on `localhost` only, so nobody else on a shared network, such as an office, an event or a café, can reach it. To open a surface on another device, start it with `--lan`:
|
|
2007
|
+
|
|
2008
|
+
```bash
|
|
2009
|
+
pnpm run sdk dev --lan
|
|
2010
|
+
# ⚠ Listening on your network (--lan). Anyone on the same network can open this
|
|
2011
|
+
# session, use its API and read your package files. Use it only on a network you trust.
|
|
2012
|
+
# On another device, open:
|
|
2013
|
+
# http://192.168.1.157:3000
|
|
2014
|
+
```
|
|
2015
|
+
|
|
2016
|
+
Every port the server opens, the console's, the asset origin's and Vite's hot-reload socket, then listens on every interface. Add the surface's path to the printed address, for example `http://192.168.1.157:3000/team/1/player/1`. The device must be on the same network, and a firewall on this machine may still need to allow the ports.
|
|
2017
|
+
|
|
2018
|
+
**A scenario.** Start with a scenario's settings overrides and assets:
|
|
2019
|
+
|
|
2020
|
+
```bash
|
|
2021
|
+
pnpm run sdk dev --scenario hard_mode
|
|
2022
|
+
```
|
|
2023
|
+
|
|
2024
|
+
Without `--scenario`, the game's default scenario is used if it has one. Scenario assets are served at `/api/scenario/assets/*`. See [Scenarios](./guides/scenarios.md).
|
|
2025
|
+
|
|
2026
|
+
### Manage the background server
|
|
2027
|
+
|
|
2028
|
+
```text
|
|
2029
|
+
pnpm run sdk dev status [options]
|
|
2030
|
+
```
|
|
2031
|
+
|
|
2032
|
+
Report whether a dev server is running for this package, and where.
|
|
2033
|
+
|
|
2034
|
+
| Option | Default | Description |
|
|
2035
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
2036
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2037
|
+
|
|
2038
|
+
```text
|
|
2039
|
+
pnpm run sdk dev stop [options]
|
|
2040
|
+
```
|
|
2041
|
+
|
|
2042
|
+
Stop the dev server running for this package.
|
|
2043
|
+
|
|
2044
|
+
| Option | Default | Description |
|
|
2045
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
2046
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2047
|
+
|
|
2048
|
+
`dev status` and `dev stop` report through the [envelope](#json-output) with `-j, --json`, like every command.
|
|
2049
|
+
|
|
2050
|
+
### Dev server features
|
|
2051
|
+
|
|
2052
|
+
- **Hot reloading**: edit logic, bundles, the manifest or UIs and see the change without a restart (see [What reloads](#what-reloads))
|
|
2053
|
+
- **The dev drawer**: press the backtick key on any surface for the session, the scenario, the surface list, the state projection, armed faults, and errors (see [The dev drawer](./cli-and-dev-server.md#the-dev-drawer))
|
|
2054
|
+
- **One command set**: everything the drawer does, the CLI does, because both send the same commands
|
|
2055
|
+
- **Direct addressing**: every surface has a URL, and `?bare` removes the dev chrome
|
|
2056
|
+
- **Fault injection**: arm an outcome the dev server cannot otherwise produce, so the path your UI handles is reachable
|
|
2057
|
+
- **Several teams**: run N teams at once with `--teams N`, or from `teams.min`
|
|
2058
|
+
|
|
2059
|
+
### What reloads
|
|
2060
|
+
|
|
2061
|
+
Every edit falls into one of three buckets. Knowing which saves guessing at why an edit appears to do nothing.
|
|
2062
|
+
|
|
2063
|
+
**Live: applied straight away, keeping the session where it is.**
|
|
2064
|
+
|
|
2065
|
+
| You edit | What happens |
|
|
2066
|
+
| ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2067
|
+
| A user interface (`ui/src/**`) | Vite hot-replaces the UI |
|
|
2068
|
+
| Resource logic (`engine/logic.ts`, `tick_controller/logic.ts`, or `logic.ts` in `hooks/`, `validators/`, `endpoints/`) | The next run uses the new code. Ticks already played are not re-run |
|
|
2069
|
+
| A resource bundle (`*.sdk.json`) | The session uses it from the next operation. A bundle that does not load is reported and the last good one stays in use |
|
|
2070
|
+
| A new surface, such as a `waiting_room/` or `presentation/` slot | Served at its URL as soon as its bundle is saved |
|
|
2071
|
+
| A new capability, or one a resource starts to read or write | Every team's board gets it with its schema defaults. `Init` has not run for it, and the dev server says so: run `sdk init` to start from `Init` |
|
|
2072
|
+
| `locales` or `supportedLocales` in `seriousgaming.sdk.json` | The session uses them from the next operation |
|
|
2073
|
+
| Scenario or facilitator-guide markdown, or an asset file | The new content is served on the next request |
|
|
2074
|
+
| A colocated test (`*.test.ts`, `*.spec.ts`) | Nothing. Tests are not part of a logic bundle |
|
|
2075
|
+
|
|
2076
|
+
**Pending until `sdk init`: applied when the session next initialises.** These reach the game through `Init` or session creation, so applying them mid-session would give a state no real session can reach, such as a setting `Init` used keeping its old effect while the next tick reads the new value.
|
|
2077
|
+
|
|
2078
|
+
- A settings resource's values, including a default or a scenario's override
|
|
2079
|
+
- `maxTicks`, `teams` and `waitingRoom.openOnStart` in `seriousgaming.sdk.json`, which are the game's own values for the built-in `game` settings, and `teams.mode` and `identifier`
|
|
2080
|
+
- Adding or removing the `setup` slot, which decides whether there is a configuration step
|
|
2081
|
+
- Removing a capability, or changing its `scope`
|
|
2082
|
+
|
|
2083
|
+
What happens to a pending change depends on whether anything has been played:
|
|
2084
|
+
|
|
2085
|
+
- **At tick 0**, nothing has been played, so the session re-initialises on its own and applies it
|
|
2086
|
+
- **Once a tick has been played**, the session keeps running on what it started with and records the change. The console shows 'Settings changed: re-initialise to apply' with a **Re-initialise** button. `sdk tick`, `sdk undo`, a context patch, a writing endpoint call and resuming the tick timer are refused with `SETTINGS_STALE` (exit 4) until you re-initialise, with a hint to run `sdk init`. `sdk view` still answers, with `stale` in its data naming what changed and a warning on stderr. Reads, roster and team changes, and the waiting room are unaffected
|
|
2087
|
+
- **Under `sdk dev --reinit-on-change`**, the session always re-initialises, however far play has gone
|
|
2088
|
+
|
|
2089
|
+
Re-initialising from the console's button keeps the team count, the scenario and the locale, and returns play to tick 0. So does a session-wide reset. `sdk init` rebuilds the session from the package and takes `--teams`, `--scenario` and `--locale` as usual. Editing the file back to what the session started with clears the pending change.
|
|
2090
|
+
|
|
2091
|
+
**Needs a restart.** Only an upgrade of the SDK tools themselves. A command notices one (see [A server from other tools](#where-the-session-lives)): it replaces a server it started in the background, and otherwise asks you to stop yours with `sdk dev stop` and start it again.
|
|
2092
|
+
|
|
2093
|
+
A UI that throws while it first loads cannot be hot-replaced, because there is no mounted component left to replace. The dev server reloads its frame on the next edit to any file it uses instead, so fixing the mistake is all it takes, though anything typed into the surface is lost with the reload.
|
|
2094
|
+
|
|
2095
|
+
The dev server watches the package directory and nothing outside it, so logic code in a linked workspace dependency is not watched: an edit there reaches the next run once a source file in the package changes. A UI is different, because its files are Vite's to watch, and Vite follows a linked dependency a UI imports and hot-replaces it like an edit under `ui/src/`. A logic edit changes the next run, not the ticks already played or the context `Init` built: undo and tick again to see a change applied from the same starting point, or reset to run the new `Init`.
|
|
2096
|
+
|
|
2097
|
+
## Project commands
|
|
2098
|
+
|
|
2099
|
+
### Create a package
|
|
2100
|
+
|
|
2101
|
+
```text
|
|
2102
|
+
pnpm run sdk new package [definition] [options]
|
|
2103
|
+
```
|
|
2104
|
+
|
|
2105
|
+
Create a new package.
|
|
2106
|
+
|
|
2107
|
+
| Option | Default | Description |
|
|
2108
|
+
| -------------------------- | --------------------- | -------------------------------------------------------- |
|
|
2109
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to create the package in. |
|
|
2110
|
+
| `-f, --file [PATH]` | | Path to a JSON file containing the package definition. |
|
|
2111
|
+
| `--empty` | | Skip the starter game: package files and CLAUDE.md only. |
|
|
2112
|
+
| `--skip-install` | | Skip running pnpm install after creating the package. |
|
|
2113
|
+
|
|
2114
|
+
```bash
|
|
2115
|
+
pnpm dlx @seriousgaming/sdk-tools new package
|
|
2116
|
+
```
|
|
2117
|
+
|
|
2118
|
+
Scaffolds the package structure and `seriousgaming.sdk.json`. It runs interactively by default, and also accepts a JSON definition as an argument, via `--file`, or on stdin. The `pnpm run sdk` script exists only once a package has been scaffolded, so this first command goes through `pnpm dlx`.
|
|
2119
|
+
|
|
2120
|
+
What it writes is a complete, playable game, not an empty shell: an engine, a game UI, a session UI, a waiting room UI, a validator, a `participantJoin` hook, a facilitator guide, five capabilities, four settings resources, two scenarios, and tests at every level. It is the game the SDK's own test suites play, copied out verbatim apart from the game's name. See [A tour of the starter game](./guides/starter-game.md) for what it is and why.
|
|
2121
|
+
|
|
2122
|
+
`--empty` writes the package files and the agent guidance (`CLAUDE.md`, `.claude/`) alone: no game resources or tests.
|
|
2123
|
+
|
|
2124
|
+
### Resolve configuration
|
|
2125
|
+
|
|
2126
|
+
```text
|
|
2127
|
+
pnpm run sdk resolve [options]
|
|
2128
|
+
```
|
|
2129
|
+
|
|
2130
|
+
Resolve the package to its built manifest and print it to stdout.
|
|
2131
|
+
|
|
2132
|
+
| Option | Default | Description |
|
|
2133
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
2134
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2135
|
+
|
|
2136
|
+
Prints the complete resolved package: every resource it declares, settings resources included.
|
|
2137
|
+
|
|
2138
|
+
### Generate types
|
|
2139
|
+
|
|
2140
|
+
```text
|
|
2141
|
+
pnpm run sdk generate [options]
|
|
2142
|
+
```
|
|
2143
|
+
|
|
2144
|
+
Generate code from capabilities and the engine.
|
|
2145
|
+
|
|
2146
|
+
| Option | Default | Description |
|
|
2147
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
2148
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2149
|
+
|
|
2150
|
+
Regenerates the typed `types.ts` beside each resource that has logic or a user interface, from the capabilities and bundles the package declares. `new`, `update`, and `build` already run it, so reach for it after editing a `*.sdk.json` file by hand.
|
|
2151
|
+
|
|
2152
|
+
### Lint
|
|
2153
|
+
|
|
2154
|
+
```bash
|
|
2155
|
+
pnpm run lint
|
|
2156
|
+
pnpm run lint:fix
|
|
2157
|
+
```
|
|
2158
|
+
|
|
2159
|
+
`lint` checks code for style and quality issues, and `lint:fix` fixes what it can. Use the `lint:fix` script rather than `pnpm run lint -- --fix`: pnpm passes the `--` through, so `oxlint` reads `--fix` as a path and lints nothing.
|
|
2160
|
+
|
|
2161
|
+
## Build and publish commands
|
|
2162
|
+
|
|
2163
|
+
### Build the game
|
|
2164
|
+
|
|
2165
|
+
```bash
|
|
2166
|
+
pnpm run build
|
|
2167
|
+
```
|
|
2168
|
+
|
|
2169
|
+
```text
|
|
2170
|
+
pnpm run sdk build [options]
|
|
2171
|
+
```
|
|
2172
|
+
|
|
2173
|
+
Build your Serious Gaming package, or just its engine.
|
|
2174
|
+
|
|
2175
|
+
| Option | Default | Description |
|
|
2176
|
+
| -------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
2177
|
+
| `-c, --config [PATH]` | `seriousgaming.sdk.json` | The Serious Gaming SDK config file to load. |
|
|
2178
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2179
|
+
| `-b, --build-dir [PATH]` | `dist/` | The directory to write build artefacts to. |
|
|
2180
|
+
| `--validate-only` | | Run validation checks without building (checks logic files, capability references, game composition). |
|
|
2181
|
+
|
|
2182
|
+
Run in the package directory. Validates the package, generates types, and builds the engine and UIs for deployment. A top-level `shared-assets/` directory (if present) is copied verbatim into the build root as `dist/shared-assets/`, so `shared:<path>` references resolve against the built package. See [Share assets across scenarios](./recipes/share-assets-across-scenarios.md).
|
|
2183
|
+
|
|
2184
|
+
`--validate-only` is described below. With `--json`, the [envelope](#json-output)'s `data` under `--validate-only` is the validation summary (`success`, `resources`, `summary`); a failure is `PACKAGE_INVALID` (exit 3) with a diagnostic per finding. `--verbose`, the [global option](#global-options), shows detailed build progress.
|
|
2185
|
+
|
|
2186
|
+
### Validate the package
|
|
2187
|
+
|
|
2188
|
+
```bash
|
|
2189
|
+
# Human-readable validation output
|
|
2190
|
+
pnpm run sdk build --validate-only
|
|
2191
|
+
|
|
2192
|
+
# Structured JSON output for automation
|
|
2193
|
+
pnpm run sdk build --validate-only --json
|
|
2194
|
+
```
|
|
2195
|
+
|
|
2196
|
+
Runs every validation check without building:
|
|
2197
|
+
|
|
2198
|
+
- Engine logic files exist and export `Init` and `Run`
|
|
2199
|
+
- UI entrypoint files exist
|
|
2200
|
+
- Capability references resolve correctly
|
|
2201
|
+
- Game composition (settings and locales)
|
|
2202
|
+
- Every `settings` entry names a settings resource the package declares, and so does the `configures` of the setup and scenario editor slots
|
|
2203
|
+
- Every settings property declares a `default`, and no `settingsSchema` declares a top-level `required`
|
|
2204
|
+
- No bundle carries a `configurationSchema`, and the manifest carries no `configuration` block
|
|
2205
|
+
- Scenario settings overrides against each settings resource's `settingsSchema` (see [Scenario settings](#scenario-settings))
|
|
2206
|
+
- Every schema `default` satisfies the subschema that declares it (see [Schema defaults](#schema-defaults))
|
|
2207
|
+
|
|
2208
|
+
It also warns, without failing, when a resource reads a capability that **nothing in the package writes**. Such a read can only ever see the capability's schema defaults, so it is usually a leftover from a deleted writer, or a set of constants that belongs in a [settings resource](./guides/settings.md) instead. The check is package-wide, so a capability written anywhere is never flagged.
|
|
2209
|
+
|
|
2210
|
+
#### Scenario settings
|
|
2211
|
+
|
|
2212
|
+
A scenario's `settings` block is keyed by settings identifier, and each entry is checked against that settings resource's `settingsSchema`. An entry naming a settings resource the package does not declare fails too. This is the check the dev server and the production runtime make when a scenario is activated, brought forward to build time.
|
|
2213
|
+
|
|
2214
|
+
Overrides are **partial**: a scenario that sets only the keys it cares about is fine, and omitted keys fall through to their defaults. What fails the build is a key the schema does not declare (usually a misspelling), or a declared key whose value violates the schema.
|
|
2215
|
+
|
|
2216
|
+
```json
|
|
2217
|
+
"settings": {
|
|
2218
|
+
"engine": {
|
|
2219
|
+
"BaseDemand": 15000,
|
|
2220
|
+
"DemandPriceModifer": 300
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
```
|
|
2224
|
+
|
|
2225
|
+
`DemandPriceModifer` is a typo, so the build fails and names it, rather than the scenario failing at session start.
|
|
2226
|
+
|
|
2227
|
+
#### Schema defaults
|
|
2228
|
+
|
|
2229
|
+
A `default` must be a valid instance of the subschema that declares it. Defaults seed the initial context (`variablesSchema`) and the resolved settings (`settingsSchema`), so one that violates its own schema puts invalid state into the game before any logic runs. Validation covers `variablesSchema`, `settingsSchema`, and an endpoint's `requestSchema` and `responseSchema`, at any depth.
|
|
2230
|
+
|
|
2231
|
+
The common trap is an object default that carries a field the subschema does not declare:
|
|
2232
|
+
|
|
2233
|
+
```json
|
|
2234
|
+
"Company": {
|
|
2235
|
+
"type": "object",
|
|
2236
|
+
"properties": { "Name": { "type": "string" } },
|
|
2237
|
+
"required": ["Name"],
|
|
2238
|
+
"additionalProperties": false,
|
|
2239
|
+
"default": { "Name": "Acme", "Tagline": "We deliver" }
|
|
2240
|
+
}
|
|
2241
|
+
```
|
|
2242
|
+
|
|
2243
|
+
`Tagline` is not declared and `additionalProperties` is `false`, so the default can never validate. Either declare `Tagline` or drop it from the default.
|
|
2244
|
+
|
|
2245
|
+
Also flagged: a default of the wrong type, one outside a declared `enum`, `minimum`, `maximum`, or `pattern`, and one that omits a field its own object marks `required`. A default is used **whole** when its key is absent, not merged with anything, so a partial object default seeds an incomplete value.
|
|
2246
|
+
|
|
2247
|
+
> A value that is only legitimate before your logic first writes the capability still has to be in the schema. If a status starts as `'Unknown'` and your engine later sets it to one of four ratings, `'Unknown'` belongs in the `enum` too, otherwise the generated union misrepresents what the capability holds at tick 0.
|
|
2248
|
+
|
|
2249
|
+
### Build the engine on its own
|
|
2250
|
+
|
|
2251
|
+
```text
|
|
2252
|
+
pnpm run sdk build engine [options]
|
|
2253
|
+
```
|
|
2254
|
+
|
|
2255
|
+
Build the engine and output to stdout.
|
|
2256
|
+
|
|
2257
|
+
| Option | Default | Description |
|
|
2258
|
+
| -------------------------- | ------------------------ | ------------------------------------------- |
|
|
2259
|
+
| `-c, --config [PATH]` | `seriousgaming.sdk.json` | The Serious Gaming SDK config file to load. |
|
|
2260
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2261
|
+
|
|
2262
|
+
Transpiles the engine's TypeScript logic and writes the bundled JavaScript to stdout, without producing a `dist/`. Useful for inspecting what the engine actually runs, or for piping into another tool.
|
|
2263
|
+
|
|
2264
|
+
It takes no argument: a game holds one engine, in the `engine` slot. The command fails when the slot is empty.
|
|
2265
|
+
|
|
2266
|
+
**Example:**
|
|
2267
|
+
|
|
2268
|
+
```bash
|
|
2269
|
+
CODE=$(pnpm run --silent sdk build engine)
|
|
2270
|
+
```
|
|
2271
|
+
|
|
2272
|
+
### Package a built game for distribution
|
|
2273
|
+
|
|
2274
|
+
```text
|
|
2275
|
+
pnpm run sdk package bundle [options]
|
|
2276
|
+
```
|
|
2277
|
+
|
|
2278
|
+
Package the built `dist/` directory into a distributable zip archive.
|
|
2279
|
+
|
|
2280
|
+
| Option | Default | Description |
|
|
2281
|
+
| -------------------------- | --------------------- | ----------------------------------------- |
|
|
2282
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2283
|
+
| `-b, --build-dir [PATH]` | `dist/` | The directory containing build artefacts. |
|
|
2284
|
+
| `-o, --output-file [PATH]` | | Where to write the zip archive. |
|
|
2285
|
+
|
|
2286
|
+
Wraps the contents of a built `dist/` directory into a single zip archive for uploading to a production runtime. Run it after `pnpm run sdk build`; it does not build.
|
|
2287
|
+
|
|
2288
|
+
The archive root mirrors the build layout, with `seriousgaming.json` at the top and any `shared-assets/` directory included once at the root. See [Distribute a built package](./recipes/distribute-package.md) for a CI recipe.
|
|
2289
|
+
|
|
2290
|
+
`--output-file` defaults to `<build-dir>/<identifier>-<version>.zip`. With `--json`, the [envelope](#json-output)'s `data` is `outputFile`, `size`, `fileCount`, `identifier` and `version`.
|
|
2291
|
+
|
|
2292
|
+
**Example:**
|
|
2293
|
+
|
|
2294
|
+
```bash
|
|
2295
|
+
pnpm run sdk build
|
|
2296
|
+
pnpm run sdk package bundle
|
|
2297
|
+
# → dist/coffeeshop-1.2.0.zip
|
|
2298
|
+
|
|
2299
|
+
pnpm run --silent sdk package bundle --json > bundle.json
|
|
2300
|
+
```
|
|
2301
|
+
|
|
2302
|
+
### Set the package version
|
|
2303
|
+
|
|
2304
|
+
```text
|
|
2305
|
+
pnpm run sdk package version <value> [options]
|
|
2306
|
+
```
|
|
2307
|
+
|
|
2308
|
+
Set the package version in package.json, which owns it.
|
|
2309
|
+
|
|
2310
|
+
| Option | Default | Description |
|
|
2311
|
+
| -------------------------- | --------------------- | ------------------------------------ |
|
|
2312
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2313
|
+
|
|
2314
|
+
Sets the package's version in `package.json`, which owns it. The manifest carries no version; the build reads it from here and writes it into the built artefact. Useful in CI to bump the version before `package bundle`, since production runtimes typically reject a re-upload of the same identifier and version.
|
|
2315
|
+
|
|
2316
|
+
`<value>` is either a literal semver string (such as `1.2.3` or `1.2.3-rc.1`) or one of the bump keywords `patch`, `minor`, `major`, and `prerelease`. The new version is validated against the same pattern `schema.json` enforces on `PackageDefinition.version`. The command does not run `git tag` or `git commit`; leave tagging to CI.
|
|
2317
|
+
|
|
2318
|
+
**Bump keywords:**
|
|
2319
|
+
|
|
2320
|
+
- `patch`: `1.2.3` becomes `1.2.4`
|
|
2321
|
+
- `minor`: `1.2.3` becomes `1.3.0`
|
|
2322
|
+
- `major`: `1.2.3` becomes `2.0.0` (drops any existing pre-release)
|
|
2323
|
+
- `prerelease`: on a stable version, bumps patch and appends `-0` (`1.2.3` becomes `1.2.4-0`); on an existing pre-release, increments a trailing numeric identifier (`1.2.3-rc.1` becomes `1.2.3-rc.2`) or appends `.0` when the trailing identifier is alphanumeric (`1.2.3-rc` becomes `1.2.3-rc.0`)
|
|
2324
|
+
|
|
2325
|
+
With `--json`, the [envelope](#json-output)'s `data` is `previous`, `next` and `files`.
|
|
2326
|
+
|
|
2327
|
+
**Example:**
|
|
2328
|
+
|
|
2329
|
+
```bash
|
|
2330
|
+
pnpm run sdk package version 1.4.2
|
|
2331
|
+
pnpm run sdk package version patch
|
|
2332
|
+
pnpm run --silent sdk package version prerelease --json > version.json
|
|
2333
|
+
```
|
|
2334
|
+
|
|
2335
|
+
### Publish a package to the Serious Gaming platform
|
|
2336
|
+
|
|
2337
|
+
```text
|
|
2338
|
+
pnpm run sdk package publish [zip] [options]
|
|
2339
|
+
```
|
|
2340
|
+
|
|
2341
|
+
Upload a built and bundled package to the Serious Gaming platform.
|
|
2342
|
+
|
|
2343
|
+
| Option | Default | Description |
|
|
2344
|
+
| -------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2345
|
+
| `-w, --working-dir [PATH]` | the current directory | The working directory to execute in. |
|
|
2346
|
+
| `-b, --build-dir [PATH]` | `dist/` | The directory containing build artefacts. |
|
|
2347
|
+
| `--host [URL]` | | Origin to upload to, e.g. https://app.businesssimulations.com (defaults to SERIOUSGAMING_API_HOST env var or https://app.businesssimulations.com). The CLI appends `/api/v0/admin/publishers/<slug>/packages` itself. |
|
|
2348
|
+
| `--api-key [KEY]` | | API key (defaults to SERIOUSGAMING_API_KEY env var or .env file). |
|
|
2349
|
+
| `--publisher [SLUG]` | | Publisher slug to upload under (defaults to SERIOUSGAMING_PUBLISHER env var or platform.defaultPublisher in global settings). |
|
|
2350
|
+
| `--no-auto-bundle` | | Fail rather than re-bundle when the zip is missing. |
|
|
2351
|
+
|
|
2352
|
+
Uploads a built and bundled package zip to the Serious Gaming platform through the `/api/v0/admin/publishers/<slug>/packages` endpoint. It reads the identifier from `seriousgaming.sdk.json` and the version from `package.json`, locates `<build-dir>/<identifier>-<version>.zip`, and POSTs it as `multipart/form-data` with field `body` and an `Authorization: Bearer <key>` header. The key must come from an account with publishing access, which Business Simulations grants.
|
|
2353
|
+
|
|
2354
|
+
When the bundle is missing, the command runs `package bundle` first. Pass `--no-auto-bundle` to fail instead, or an explicit `[zip]` argument to upload that file without re-bundling.
|
|
2355
|
+
|
|
2356
|
+
**Publisher.** The upload is scoped to a publisher, resolved from (highest priority first) the `--publisher` flag, the `SERIOUSGAMING_PUBLISHER` environment variable, then `platform.defaultPublisher` in the [global settings file](./guides/global-settings.md). If none resolves, the command fails with guidance rather than guessing. The first upload of a package binds it to the named publisher; later versions must be uploaded under the same publisher or the platform returns a 400.
|
|
2357
|
+
|
|
2358
|
+
**API key.** The CLI looks up `SERIOUSGAMING_API_KEY` in the standard precedence order: global settings file, then `.env` file, then `process.env`, then the `--api-key` flag, each overriding the one before. Keep the key in your `.env`, shell environment, or global settings so it stays out of shell history.
|
|
2359
|
+
|
|
2360
|
+
`--host` takes an origin only, not a full path. With `--json`, the [envelope](#json-output)'s `data` is the server's `PackageVersionResponse`.
|
|
2361
|
+
|
|
2362
|
+
The environment variables it reads are listed in [Environment variables](./environment-variables.md#package-publishing-pnpm-run-sdk-package-publish).
|
|
2363
|
+
|
|
2364
|
+
**Examples:**
|
|
2365
|
+
|
|
2366
|
+
```bash
|
|
2367
|
+
# Default: bundle if needed, upload to production under the named publisher
|
|
2368
|
+
pnpm run sdk package publish --publisher acme
|
|
2369
|
+
|
|
2370
|
+
# Upload an explicit zip without re-bundling
|
|
2371
|
+
pnpm run sdk package publish artifacts/release.zip --publisher acme
|
|
2372
|
+
|
|
2373
|
+
# Target a staging environment
|
|
2374
|
+
pnpm run sdk package publish --host https://staging.example.com --publisher acme
|
|
2375
|
+
|
|
2376
|
+
# Capture the server response for CI
|
|
2377
|
+
pnpm run --silent sdk package publish --json > publish.json
|
|
2378
|
+
```
|
|
2379
|
+
|
|
2380
|
+
**Errors:**
|
|
2381
|
+
|
|
2382
|
+
- `400` (`PLATFORM_REJECTED`, exit 3): each structured validation error (`{field, message}`) in the server's `errors[]` array is rendered as `field: message` on its own line. A version uploaded against the wrong publisher surfaces here
|
|
2383
|
+
- `401` and `403` (`PLATFORM_UNAUTHORISED`, exit 5): 'Invalid API key. Check $SERIOUSGAMING_API_KEY and that it has not been revoked.', or 'The account that created this API key does not have publishing access. Ask Business Simulations to grant it.'
|
|
2384
|
+
- `409` (`VERSION_EXISTS`, exit 3): 'Version {x.y.z} of {identifier} already exists. Bump it with `seriousgaming-sdk package version patch` and try again.'
|
|
2385
|
+
- Any other status (`PLATFORM_ERROR`, exit 5)
|
|
2386
|
+
- Network errors (`PLATFORM_UNREACHABLE`, exit 5) are surfaced with the original message
|
|
2387
|
+
- No API key (`API_KEY_MISSING`, exit 5), or no publisher (`PUBLISHER_MISSING`, exit 2)
|
|
2388
|
+
|
|
2389
|
+
## Global settings
|
|
2390
|
+
|
|
2391
|
+
The `config` commands read and write the global settings file at `~/.seriousgaming-sdk/config.json`. It stores API keys and defaults once so every project picks them up, instead of re-exporting environment variables in each shell.
|
|
2392
|
+
|
|
2393
|
+
The file is the lowest-priority configuration source: a `.env` file, environment variables, and CLI flags all override it. See the [global settings guide](./guides/global-settings.md) for the full file shape, precedence rules, and security guidance.
|
|
2394
|
+
|
|
2395
|
+
The available keys are `elevenLabs.apiKey`, `platform.apiHost`, `platform.apiKey`, and `platform.defaultPublisher`.
|
|
2396
|
+
|
|
2397
|
+
### Get a setting
|
|
2398
|
+
|
|
2399
|
+
```text
|
|
2400
|
+
pnpm run sdk config get <key>
|
|
2401
|
+
```
|
|
2402
|
+
|
|
2403
|
+
Print the value of a setting.
|
|
2404
|
+
|
|
2405
|
+
Prints the value of a single setting, or nothing if the key is valid but unset.
|
|
2406
|
+
|
|
2407
|
+
```bash
|
|
2408
|
+
pnpm run sdk config get platform.apiKey
|
|
2409
|
+
```
|
|
2410
|
+
|
|
2411
|
+
### Set a setting
|
|
2412
|
+
|
|
2413
|
+
```text
|
|
2414
|
+
pnpm run sdk config set <key> <value>
|
|
2415
|
+
```
|
|
2416
|
+
|
|
2417
|
+
Set a setting in the global settings file.
|
|
2418
|
+
|
|
2419
|
+
Writes a single setting, creating the file (with owner-only permissions on macOS and Linux) if it does not exist.
|
|
2420
|
+
|
|
2421
|
+
```bash
|
|
2422
|
+
pnpm run sdk config set platform.apiKey sg_...
|
|
2423
|
+
```
|
|
2424
|
+
|
|
2425
|
+
### Print the settings path
|
|
2426
|
+
|
|
2427
|
+
```text
|
|
2428
|
+
pnpm run sdk config path
|
|
2429
|
+
```
|
|
2430
|
+
|
|
2431
|
+
Print the resolved path to the global settings file.
|
|
2432
|
+
|
|
2433
|
+
Prints the resolved path to the global settings file. Honours the `SERIOUSGAMING_SDK_CONFIG` override.
|
|
2434
|
+
|
|
2435
|
+
## Help and documentation
|
|
2436
|
+
|
|
2437
|
+
### Command help
|
|
2438
|
+
|
|
2439
|
+
```bash
|
|
2440
|
+
pnpm run sdk --help
|
|
2441
|
+
pnpm run sdk <command> --help
|
|
2442
|
+
```
|
|
2443
|
+
|
|
2444
|
+
Shows the available commands and their options.
|
|
2445
|
+
|
|
2446
|
+
### Print the SDK version
|
|
2447
|
+
|
|
2448
|
+
```text
|
|
2449
|
+
pnpm run sdk version
|
|
2450
|
+
```
|
|
2451
|
+
|
|
2452
|
+
Print the SDK version to stdout.
|
|
2453
|
+
|
|
2454
|
+
```bash
|
|
2455
|
+
pnpm run --silent sdk version
|
|
2456
|
+
```
|
|
2457
|
+
|
|
2458
|
+
Prints the installed SDK version to stdout.
|
|
2459
|
+
|
|
2460
|
+
### Browse the documentation
|
|
2461
|
+
|
|
2462
|
+
```text
|
|
2463
|
+
pnpm run sdk docs view [file]
|
|
2464
|
+
```
|
|
2465
|
+
|
|
2466
|
+
View Serious Gaming SDK documentation.
|
|
2467
|
+
|
|
2468
|
+
```text
|
|
2469
|
+
pnpm run sdk docs export [dir]
|
|
2470
|
+
```
|
|
2471
|
+
|
|
2472
|
+
Export SDK documentation to your project.
|
|
2473
|
+
|
|
2474
|
+
The docs ship inside the package at `node_modules/@seriousgaming/sdk-tools/dist/docs`, so they match the installed version and need no network. Search them with your editor or `grep`.
|
|
2475
|
+
|
|
2476
|
+
- `docs view` with no argument prints the tree of documents; with a path (for example `guides/engine.md`) it prints that document
|
|
2477
|
+
- `docs export` copies every document to `dir`, or `.seriousgaming-sdk/docs` by default, so an editor or agent can search them locally
|
|
2478
|
+
|
|
2479
|
+
## Environment variables
|
|
2480
|
+
|
|
2481
|
+
LLM access, speech, publishing, the global settings path, the port a background dev server starts from, the server session commands target (`SERIOUSGAMING_DEV_URL`), where the lock file lives (`SERIOUSGAMING_DEV_STATE_DIR`), and JSON output (`SERIOUSGAMING_JSON=1`) are all set through environment variables. [Environment variables](./environment-variables.md) lists every one. Logging is `--verbose`, a flag only.
|
|
2482
|
+
|
|
2483
|
+
## Next steps
|
|
2484
|
+
|
|
2485
|
+
- [Drive a game from the CLI](./cli-simulation-testing.md): the session commands as one workflow
|
|
2486
|
+
- [Getting started](./getting-started.md): your first game
|
|
2487
|
+
- [Guides](./guides/index.md): each resource type and topic in depth
|
|
2488
|
+
- [Troubleshooting](./troubleshooting.md): symptoms, causes, and fixes
|