@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.11
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/README.md +179 -22
- package/dist/agent-verifier/agent-workspace-verifier.mjs +31 -30
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-4WD3YU2E.mjs → chunk-3IJBOLGT.mjs} +4 -12
- package/dist/agent-verifier/chunk-3IJBOLGT.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-4GU3PCHV.mjs} +62 -99
- package/dist/agent-verifier/chunk-4GU3PCHV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-6XRC5PWB.mjs} +119 -310
- package/dist/agent-verifier/chunk-6XRC5PWB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-COB56ESI.mjs} +2 -1
- package/dist/agent-verifier/chunk-COB56ESI.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-XYDL7GY6.mjs → chunk-H6XDQJ3N.mjs} +1 -0
- package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-JZTH3EMV.mjs} +2 -1
- package/dist/agent-verifier/chunk-JZTH3EMV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-KK47X7RV.mjs +14 -0
- package/dist/agent-verifier/chunk-KK47X7RV.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-M7UVBANQ.mjs} +8 -9
- package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-POBFNXD4.mjs} +2 -1
- package/dist/agent-verifier/chunk-POBFNXD4.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-6UUJEYDV.mjs → chunk-QBAF7EYR.mjs} +1 -0
- package/dist/agent-verifier/chunk-QBAF7EYR.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-RHI6S4SU.mjs} +3 -2
- package/dist/agent-verifier/chunk-RHI6S4SU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7E65UQLY.mjs → chunk-TLYGTHXU.mjs} +3 -2
- package/dist/agent-verifier/chunk-TLYGTHXU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-JH22JNYD.mjs → chunk-UIJ2NDG6.mjs} +93 -24
- package/dist/agent-verifier/chunk-UIJ2NDG6.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-UWJIZML3.mjs} +13 -14
- package/dist/agent-verifier/chunk-UWJIZML3.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CJEEA6NJ.mjs → chunk-VLOIZDR6.mjs} +15 -31
- package/dist/agent-verifier/chunk-VLOIZDR6.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-W2MDP5ZN.mjs} +6 -5
- package/dist/agent-verifier/chunk-W2MDP5ZN.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-XKCJBIRY.mjs} +2 -1
- package/dist/agent-verifier/chunk-XKCJBIRY.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-YDIOW2BO.mjs} +2 -1
- package/dist/agent-verifier/chunk-YDIOW2BO.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-YR664DJX.mjs} +111 -116
- package/dist/agent-verifier/chunk-YR664DJX.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-Z6OZWUIZ.mjs} +6 -9
- package/dist/agent-verifier/chunk-Z6OZWUIZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
- package/dist/agent-verifier/{compile-5QSPIOUT.mjs → compile-WZ7X6I2A.mjs} +27 -27
- package/dist/agent-verifier/compile-WZ7X6I2A.mjs.map +1 -0
- package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-XHL7BCKN.mjs} +6 -5
- package/dist/agent-verifier/global-config-XHL7BCKN.mjs.map +1 -0
- package/dist/agent-verifier/{keychain-backend-TNOPQV3Z.mjs → keychain-backend-A3MRWLPF.mjs} +2 -1
- package/dist/agent-verifier/keychain-backend-A3MRWLPF.mjs.map +1 -0
- package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-ZW52HSVT.mjs} +10 -11
- package/dist/agent-verifier/local-files-ZW52HSVT.mjs.map +1 -0
- package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs +10 -0
- package/dist/agent-verifier/local-typecheck-3JXL2NMG.mjs.map +1 -0
- package/dist/agent-verifier/{materialize-workspace-FKALAE2T.mjs → materialize-workspace-BKZLLFI4.mjs} +20 -20
- package/dist/agent-verifier/materialize-workspace-BKZLLFI4.mjs.map +1 -0
- package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-XKUSCFSV.mjs} +3 -2
- package/dist/agent-verifier/project-state-XKUSCFSV.mjs.map +1 -0
- package/dist/agent-verifier/{prompt-3BAINGAQ.mjs → prompt-VKHMCQT6.mjs} +2 -1
- package/dist/agent-verifier/prompt-VKHMCQT6.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-7NYZF5ZT.mjs} +6 -9
- package/dist/agent-verifier/reducer-bundle-preflight-7NYZF5ZT.mjs.map +1 -0
- package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs +11 -0
- package/dist/agent-verifier/reducer-contract-preflight-COD2CO22.mjs.map +1 -0
- package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-D4VWPIAC.mjs} +14 -17
- package/dist/agent-verifier/reducer-native-test-harness-D4VWPIAC.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs +26 -0
- package/dist/agent-verifier/static-scaffold-JCRBDKEH.mjs.map +1 -0
- package/dist/agent-verifier/{sync-3DUQH32H.mjs → sync-ELLJEWMB.mjs} +41 -39
- package/dist/agent-verifier/sync-ELLJEWMB.mjs.map +1 -0
- package/dist/agent-verifier/{test-P4U5INTD.mjs → test-OSXBPLSP.mjs} +29 -31
- package/dist/agent-verifier/test-OSXBPLSP.mjs.map +1 -0
- package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs +10 -0
- package/dist/agent-verifier/workspace-codegen-WPZHMATU.mjs.map +1 -0
- package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-ULZZZPNX.mjs} +5 -4
- package/dist/agent-verifier/workspace-dependencies-ULZZZPNX.mjs.map +1 -0
- package/dist/{chunk-C6UAT6EH.js → chunk-GXM7RRZJ.js} +9 -11
- package/dist/chunk-GXM7RRZJ.js.map +1 -0
- package/dist/{chunk-RS7UXJZV.js → chunk-P5TITCD3.js} +790 -17875
- package/dist/chunk-P5TITCD3.js.map +1 -0
- package/dist/{global-config-AGFBDFYD.js → global-config-WPJRXVDO.js} +2 -2
- package/dist/global-config-WPJRXVDO.js.map +1 -0
- package/dist/index.js +455 -54
- package/dist/index.js.map +1 -1
- package/dist/internal.js +2 -3
- package/package.json +8 -7
- package/skills/dreamboard/references/building-your-first-game.md +510 -0
- package/skills/dreamboard/references/cli.md +104 -0
- package/skills/dreamboard/references/game-interface.md +548 -0
- package/skills/dreamboard/references/manifest-authoring.md +597 -0
- package/skills/dreamboard/references/quickstart.md +66 -0
- package/skills/dreamboard/references/reducer.md +864 -0
- package/skills/dreamboard/references/rule-authoring.md +147 -0
- package/skills/dreamboard/references/testing.md +249 -0
- package/skills/dreamboard/scripts/events-extract.mjs +218 -0
- package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
- package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
- package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
- package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
- package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
- package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
- package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
- package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
- package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
- package/dist/chunk-7FOO4AJI.js +0 -50
- package/dist/chunk-7FOO4AJI.js.map +0 -1
- package/dist/chunk-C6UAT6EH.js.map +0 -1
- package/dist/chunk-RS7UXJZV.js.map +0 -1
- package/dist/internal.d.ts +0 -311
- package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
- package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
- package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
- package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
- package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
- package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
- package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
- package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
- package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
- package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
- package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
- package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
- package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
- package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
- package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
- package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
- package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
- package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
- package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
- package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
- package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
- package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
- package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
- package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
- package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
- package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
- package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
- package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
- package/dist/testing-KLSV6CPJ.js +0 -674
- package/dist/testing-KLSV6CPJ.js.map +0 -1
- /package/dist/{global-config-AGFBDFYD.js.map → agent-verifier/chunk-H6XDQJ3N.mjs.map} +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<!-- Generated by apps/dreamboard-cli/scripts/sync-skill-docs.ts. -->
|
|
2
|
+
<!-- Source: docs/reference/rule-authoring.mdx -->
|
|
3
|
+
|
|
4
|
+
# Rule authoring
|
|
5
|
+
|
|
6
|
+
Reference for authoring Dreamboard rule.md files.
|
|
7
|
+
|
|
8
|
+
`rule.md` is the game-design source of intent for a Dreamboard project. Use it
|
|
9
|
+
to describe the rules in plain language before you commit to reducer state,
|
|
10
|
+
manifest, or UI details.
|
|
11
|
+
|
|
12
|
+
## Responsibility
|
|
13
|
+
|
|
14
|
+
Use `rule.md` for:
|
|
15
|
+
|
|
16
|
+
- the game objective and match shape
|
|
17
|
+
- setup, turn flow, scoring, and victory rules
|
|
18
|
+
- player actions and their legality constraints
|
|
19
|
+
- visibility rules and information flow
|
|
20
|
+
- edge cases and deterministic tie-break rules
|
|
21
|
+
|
|
22
|
+
## Recommended structure
|
|
23
|
+
|
|
24
|
+
Use the same section order for every `rule.md`.
|
|
25
|
+
|
|
26
|
+
### `Overview`
|
|
27
|
+
|
|
28
|
+
State the core promise of the game in one short section.
|
|
29
|
+
|
|
30
|
+
- supported player count
|
|
31
|
+
- objective
|
|
32
|
+
- expected match length
|
|
33
|
+
- one-paragraph summary of how a turn feels
|
|
34
|
+
|
|
35
|
+
### `Components`
|
|
36
|
+
|
|
37
|
+
List the components the rules assume exist.
|
|
38
|
+
|
|
39
|
+
- cards, zones, boards, pieces, dice, and resources
|
|
40
|
+
- public versus hidden information
|
|
41
|
+
- per-player versus shared components
|
|
42
|
+
- hard limits such as hand size, stock limits, or caps
|
|
43
|
+
|
|
44
|
+
### `Setup`
|
|
45
|
+
|
|
46
|
+
Describe the initial state in ordered steps.
|
|
47
|
+
|
|
48
|
+
- how players are seated
|
|
49
|
+
- which player acts first
|
|
50
|
+
- which components start in which locations
|
|
51
|
+
- any setup options or setup-profile differences
|
|
52
|
+
|
|
53
|
+
### `Gameplay`
|
|
54
|
+
|
|
55
|
+
Describe the game loop in the order the reducer should implement it.
|
|
56
|
+
|
|
57
|
+
For each phase, name:
|
|
58
|
+
|
|
59
|
+
- who is allowed to act
|
|
60
|
+
- which actions are legal
|
|
61
|
+
- what input each action requires
|
|
62
|
+
- what ends the phase
|
|
63
|
+
- which phase follows next
|
|
64
|
+
|
|
65
|
+
When a game has repeated rounds, document the round loop explicitly instead of
|
|
66
|
+
implying it.
|
|
67
|
+
|
|
68
|
+
### `Scoring and progression`
|
|
69
|
+
|
|
70
|
+
Describe how players gain or lose progress.
|
|
71
|
+
|
|
72
|
+
- points, tracks, resources, or thresholds
|
|
73
|
+
- when scoring happens
|
|
74
|
+
- round-end or trick-end resolution
|
|
75
|
+
- tie-breakers for intermediate rankings
|
|
76
|
+
|
|
77
|
+
### `Winning conditions`
|
|
78
|
+
|
|
79
|
+
State the exact end trigger and winner resolution rule.
|
|
80
|
+
|
|
81
|
+
- when the game ends
|
|
82
|
+
- how the winner is chosen
|
|
83
|
+
- how ties are broken
|
|
84
|
+
- what happens if multiple end conditions become true at once
|
|
85
|
+
|
|
86
|
+
### `Special rules and edge cases`
|
|
87
|
+
|
|
88
|
+
List rules that are easy to miss during implementation.
|
|
89
|
+
|
|
90
|
+
- simultaneous actions
|
|
91
|
+
- empty-deck or empty-pool behavior
|
|
92
|
+
- no-op or invalid actions
|
|
93
|
+
- forced actions versus optional actions
|
|
94
|
+
- what happens when a player cannot act
|
|
95
|
+
|
|
96
|
+
## Example template
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
# <Game name>
|
|
100
|
+
|
|
101
|
+
## Overview
|
|
102
|
+
|
|
103
|
+
- Players: <min-max> (optimal: <n>)
|
|
104
|
+
- Objective: <how a player wins>
|
|
105
|
+
- Duration: <target minutes>
|
|
106
|
+
|
|
107
|
+
## Components
|
|
108
|
+
|
|
109
|
+
- Shared components:
|
|
110
|
+
- Per-player components:
|
|
111
|
+
- Public information:
|
|
112
|
+
- Hidden information:
|
|
113
|
+
|
|
114
|
+
## Setup
|
|
115
|
+
|
|
116
|
+
1. ...
|
|
117
|
+
2. ...
|
|
118
|
+
3. ...
|
|
119
|
+
|
|
120
|
+
## Gameplay
|
|
121
|
+
|
|
122
|
+
### Phase 1: <name>
|
|
123
|
+
|
|
124
|
+
- Acting player(s):
|
|
125
|
+
- Allowed actions:
|
|
126
|
+
- Validation:
|
|
127
|
+
- Completion:
|
|
128
|
+
- Next phase:
|
|
129
|
+
|
|
130
|
+
### Phase 2: <name>
|
|
131
|
+
|
|
132
|
+
- ...
|
|
133
|
+
|
|
134
|
+
## Scoring and progression
|
|
135
|
+
|
|
136
|
+
- ...
|
|
137
|
+
|
|
138
|
+
## Winning conditions
|
|
139
|
+
|
|
140
|
+
- End trigger:
|
|
141
|
+
- Winner determination:
|
|
142
|
+
- Tie-breaker:
|
|
143
|
+
|
|
144
|
+
## Special rules and edge cases
|
|
145
|
+
|
|
146
|
+
- ...
|
|
147
|
+
```
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
<!-- Generated by apps/dreamboard-cli/scripts/sync-skill-docs.ts. -->
|
|
2
|
+
<!-- Source: docs/reference/testing.mdx -->
|
|
3
|
+
|
|
4
|
+
# Testing
|
|
5
|
+
|
|
6
|
+
Reference for Dreamboard's reducer-native test framework.
|
|
7
|
+
|
|
8
|
+
Dreamboard's scaffolded test workspace is reducer-native. It uses typed base
|
|
9
|
+
definitions and typed scenarios that run against your compiled reducer and
|
|
10
|
+
generated contracts.
|
|
11
|
+
|
|
12
|
+
## Responsibility
|
|
13
|
+
|
|
14
|
+
Use the scaffolded test workspace for:
|
|
15
|
+
|
|
16
|
+
- reusable seeded base states
|
|
17
|
+
- reducer and view assertions
|
|
18
|
+
- happy-path coverage
|
|
19
|
+
- rejection and turn-gating coverage
|
|
20
|
+
- deterministic regression testing in CI or local development
|
|
21
|
+
|
|
22
|
+
## Workspace layout
|
|
23
|
+
|
|
24
|
+
The current scaffold uses these paths:
|
|
25
|
+
|
|
26
|
+
- `test/README.md`
|
|
27
|
+
- `test/bases/*.base.ts`
|
|
28
|
+
- `test/scenarios/*.scenario.ts`
|
|
29
|
+
- `test/testing-types.ts`
|
|
30
|
+
- `test/generated/*`
|
|
31
|
+
|
|
32
|
+
Generated files under `test/generated/*` are owned by Dreamboard and should not
|
|
33
|
+
be edited manually.
|
|
34
|
+
|
|
35
|
+
## Command flow
|
|
36
|
+
|
|
37
|
+
Generate reducer-native test artifacts:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
dreamboard test generate
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Run all scenarios:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
dreamboard test run
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Run one scenario:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
dreamboard test run --scenario test/scenarios/win-the-game.scenario.ts
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Re-run `dreamboard test generate` after changes that affect the runtime shape of
|
|
56
|
+
the game, including:
|
|
57
|
+
|
|
58
|
+
- `manifest.json`
|
|
59
|
+
- reducer code under `app/`
|
|
60
|
+
- setup-profile behavior
|
|
61
|
+
- generated contract output
|
|
62
|
+
|
|
63
|
+
## Base definitions
|
|
64
|
+
|
|
65
|
+
A base is a named, seeded checkpoint that scenarios can reuse.
|
|
66
|
+
|
|
67
|
+
Use `defineBase(...)` from `test/testing-types.ts`.
|
|
68
|
+
|
|
69
|
+
| Field | Required | Notes |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `id` | Yes | Stable base identifier referenced by scenarios |
|
|
72
|
+
| `seed` | Yes | Deterministic random seed |
|
|
73
|
+
| `players` | Yes | Player count used for that base |
|
|
74
|
+
| `setup` | Yes | Async setup callback that prepares the checkpoint |
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { defineBase } from "../testing-types";
|
|
78
|
+
|
|
79
|
+
export default defineBase({
|
|
80
|
+
id: "initial-turn",
|
|
81
|
+
seed: 1337,
|
|
82
|
+
players: 2,
|
|
83
|
+
setup: async ({ game }) => {
|
|
84
|
+
await game.start();
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The base `seed` drives runtime-owned randomness. Effects such as
|
|
90
|
+
`effects.rollDie(...)`, `effects.randomInt(...)`, `effects.sample(...)`, and
|
|
91
|
+
`effects.shuffleSharedZone(...)` consume the seeded reducer RNG, so repeated
|
|
92
|
+
test runs with the same base seed are reproducible.
|
|
93
|
+
|
|
94
|
+
Use bases for:
|
|
95
|
+
|
|
96
|
+
- opening-state invariants
|
|
97
|
+
- post-setup checkpoints shared by many scenarios
|
|
98
|
+
- seeded states that would be noisy to rebuild inline
|
|
99
|
+
|
|
100
|
+
Keep bases small and composable. A base should represent one meaningful
|
|
101
|
+
checkpoint, not a full playthrough.
|
|
102
|
+
|
|
103
|
+
## Scenario definitions
|
|
104
|
+
|
|
105
|
+
Scenarios are typed files under `test/scenarios/*.scenario.ts`.
|
|
106
|
+
|
|
107
|
+
Use `defineScenario(...)` from `test/testing-types.ts`.
|
|
108
|
+
|
|
109
|
+
| Field | Required | Notes |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `id` | Yes | Scenario identifier |
|
|
112
|
+
| `description` | No | Short human-readable summary |
|
|
113
|
+
| `from` | Yes | Base ID from `test/bases/*.base.ts` |
|
|
114
|
+
| `runners` | No | Defaults to reducer runner |
|
|
115
|
+
| `when` | Yes | Async action flow |
|
|
116
|
+
| `then` | Yes | Assertions over state, view, and history |
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { defineScenario } from "../testing-types";
|
|
120
|
+
|
|
121
|
+
export default defineScenario({
|
|
122
|
+
id: "player-two-wins",
|
|
123
|
+
description: "The deterministic roll sequence lets player 2 reach ten first",
|
|
124
|
+
from: "initial-turn",
|
|
125
|
+
when: async ({ game }) => {
|
|
126
|
+
await game.action("player-1", "rollDie", {});
|
|
127
|
+
await game.action("player-2", "rollDie", {});
|
|
128
|
+
await game.action("player-1", "rollDie", {});
|
|
129
|
+
await game.action("player-2", "rollDie", {});
|
|
130
|
+
await game.action("player-1", "rollDie", {});
|
|
131
|
+
await game.action("player-2", "rollDie", {});
|
|
132
|
+
},
|
|
133
|
+
then: ({ publicState, view, expect, history }) => {
|
|
134
|
+
const state = publicState();
|
|
135
|
+
|
|
136
|
+
expect(state.lastRoll).toBe(6);
|
|
137
|
+
expect(state.scores["player-1"]).toBe(9);
|
|
138
|
+
expect(state.scores["player-2"]).toBe(12);
|
|
139
|
+
expect(state.winnerPlayerId).toBe("player-2");
|
|
140
|
+
expect(view("player-2").winnerPlayerId).toBe("player-2");
|
|
141
|
+
expect(history().accepted().length).toBe(6);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Scenario context
|
|
147
|
+
|
|
148
|
+
`when(...)` and `then(...)` receive typed helpers from `test/testing-types.ts`.
|
|
149
|
+
|
|
150
|
+
### `game`
|
|
151
|
+
|
|
152
|
+
`game` is the typed scenario driver.
|
|
153
|
+
|
|
154
|
+
Use it to:
|
|
155
|
+
|
|
156
|
+
- `start()` the game inside base setup
|
|
157
|
+
- `action(playerId, actionType, params)` for reducer actions
|
|
158
|
+
- `action(playerId, command)` for generated command objects
|
|
159
|
+
- `respond(...)` for prompts
|
|
160
|
+
- `windowAction(...)` for reducer-owned window actions
|
|
161
|
+
- `expectPrompt(...)` and `expectWindow(...)` when testing prompt/window flow
|
|
162
|
+
|
|
163
|
+
### Shared state helpers
|
|
164
|
+
|
|
165
|
+
Use these in `when(...)` and `then(...)`:
|
|
166
|
+
|
|
167
|
+
| Helper | Notes |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| `phase()` | Current reducer phase name |
|
|
170
|
+
| `publicState()` | Current shared reducer state |
|
|
171
|
+
| `view(playerId)` | Projected player view |
|
|
172
|
+
| `runtime()` | Runtime metadata |
|
|
173
|
+
| `history()` | Accepted and rejected inputs |
|
|
174
|
+
| `expect(...)` | Built-in assertion API |
|
|
175
|
+
|
|
176
|
+
`then(...)` also exposes `hiddenState()` unless the active runner omits hidden
|
|
177
|
+
state access.
|
|
178
|
+
|
|
179
|
+
## Generated testing types
|
|
180
|
+
|
|
181
|
+
The scaffold writes `test/testing-types.ts` as the test-facing import surface.
|
|
182
|
+
|
|
183
|
+
It re-exports:
|
|
184
|
+
|
|
185
|
+
- `defineBase(...)`
|
|
186
|
+
- `defineScenario(...)`
|
|
187
|
+
- `phaseCommands`
|
|
188
|
+
- `windowCommands`
|
|
189
|
+
- reducer-derived types such as `GameState`, `GameView`, `ActionName`, and
|
|
190
|
+
`PromptId`
|
|
191
|
+
|
|
192
|
+
Import from `../testing-types` instead of reaching into `test/generated/*`
|
|
193
|
+
directly.
|
|
194
|
+
|
|
195
|
+
## Recommended coverage
|
|
196
|
+
|
|
197
|
+
Every game should have at least:
|
|
198
|
+
|
|
199
|
+
- one opening-state scenario that asserts the initial phase, active player, and
|
|
200
|
+
starting view
|
|
201
|
+
- one happy-path scenario that completes a typical turn or round
|
|
202
|
+
- one winning-condition scenario
|
|
203
|
+
- one rejection scenario for out-of-turn or otherwise illegal input
|
|
204
|
+
|
|
205
|
+
When the game uses prompts or windows, add at least one scenario that exercises
|
|
206
|
+
that continuation path end to end.
|
|
207
|
+
|
|
208
|
+
## Rejection-path coverage
|
|
209
|
+
|
|
210
|
+
Rejection scenarios are part of the main test harness, not a separate workflow.
|
|
211
|
+
|
|
212
|
+
Prefer direct reducer-native assertions for:
|
|
213
|
+
|
|
214
|
+
- wrong player acting out of turn
|
|
215
|
+
- wrong action for the current phase
|
|
216
|
+
- invalid parameters
|
|
217
|
+
- action attempts after game end
|
|
218
|
+
- repeated submission of one-time actions
|
|
219
|
+
|
|
220
|
+
Typical checks:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
then: ({ phase, history, expect, publicState }) => {
|
|
224
|
+
expect(history().rejected().length).toBe(1);
|
|
225
|
+
expect(history().accepted().length).toBe(0);
|
|
226
|
+
expect(phase()).toBe("takeTurn");
|
|
227
|
+
expect(publicState().winnerPlayerId).toBe(null);
|
|
228
|
+
};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Failure and staleness signals
|
|
232
|
+
|
|
233
|
+
If the generated test artifacts no longer match the compiled game, refresh them:
|
|
234
|
+
|
|
235
|
+
- `dreamboard test generate`
|
|
236
|
+
|
|
237
|
+
Common symptoms:
|
|
238
|
+
|
|
239
|
+
- generated files missing under `test/generated/*`
|
|
240
|
+
- type errors caused by stale generated contracts
|
|
241
|
+
- scenario runs using an outdated runtime shape after reducer or manifest edits
|
|
242
|
+
|
|
243
|
+
## Related workflows
|
|
244
|
+
|
|
245
|
+
This page documents the scaffolded reducer-native test workspace.
|
|
246
|
+
|
|
247
|
+
If you also use `dreamboard run` for manual debugging or operational inspection,
|
|
248
|
+
treat that as a separate workflow. It is useful for ad hoc runtime exploration,
|
|
249
|
+
but it is not the primary authored test surface for a new Dreamboard project.
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { access, readFile } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_EVENTS_PATH = ".dreamboard/run/events.ndjson";
|
|
6
|
+
|
|
7
|
+
function printHelp() {
|
|
8
|
+
console.log(`Extract fields from dreamboard run artifacts.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
node .agents/skills/dreamboard/scripts/events-extract.mjs [options]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--file, -f <path> NDJSON file path (default: ${DEFAULT_EVENTS_PATH})
|
|
15
|
+
--type <eventType> Filter by event type (repeatable)
|
|
16
|
+
--field <path> Dot path to extract (e.g. message.reason)
|
|
17
|
+
--player <playerId> Filter by player ID across common message fields
|
|
18
|
+
--limit <number> Limit output records
|
|
19
|
+
--no-index Omit line index in output
|
|
20
|
+
--help, -h Show this help
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
node .agents/skills/dreamboard/scripts/events-extract.mjs --type YOUR_TURN
|
|
24
|
+
node .agents/skills/dreamboard/scripts/events-extract.mjs --type ACTION_REJECTED --field message.reason
|
|
25
|
+
node .agents/skills/dreamboard/scripts/events-extract.mjs --player player-2 --field message.availableActions
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function parseCliArgs(argv) {
|
|
30
|
+
const options = {
|
|
31
|
+
filePath: DEFAULT_EVENTS_PATH,
|
|
32
|
+
types: new Set(),
|
|
33
|
+
includeIndex: true,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
37
|
+
const token = argv[index];
|
|
38
|
+
const nextToken = argv[index + 1];
|
|
39
|
+
|
|
40
|
+
if (token === "--help" || token === "-h") {
|
|
41
|
+
printHelp();
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
if (token === "--no-index") {
|
|
45
|
+
options.includeIndex = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (token === "--file" || token === "-f") {
|
|
49
|
+
if (!nextToken) {
|
|
50
|
+
throw new Error("--file requires a value");
|
|
51
|
+
}
|
|
52
|
+
options.filePath = nextToken;
|
|
53
|
+
index += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (token === "--type") {
|
|
57
|
+
if (!nextToken) {
|
|
58
|
+
throw new Error("--type requires a value");
|
|
59
|
+
}
|
|
60
|
+
options.types.add(nextToken);
|
|
61
|
+
index += 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (token === "--field") {
|
|
65
|
+
if (!nextToken) {
|
|
66
|
+
throw new Error("--field requires a value");
|
|
67
|
+
}
|
|
68
|
+
options.fieldPath = nextToken;
|
|
69
|
+
index += 1;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (token === "--player") {
|
|
73
|
+
if (!nextToken) {
|
|
74
|
+
throw new Error("--player requires a value");
|
|
75
|
+
}
|
|
76
|
+
options.playerId = nextToken;
|
|
77
|
+
index += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (token === "--limit") {
|
|
81
|
+
if (!nextToken) {
|
|
82
|
+
throw new Error("--limit requires a value");
|
|
83
|
+
}
|
|
84
|
+
const parsed = Number.parseInt(nextToken, 10);
|
|
85
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
86
|
+
throw new Error("--limit must be a positive integer");
|
|
87
|
+
}
|
|
88
|
+
options.limit = parsed;
|
|
89
|
+
index += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error(`Unknown argument: ${token}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return options;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getByPath(value, path) {
|
|
100
|
+
const segments = path.split(".").filter(Boolean);
|
|
101
|
+
let current = value;
|
|
102
|
+
|
|
103
|
+
for (const segment of segments) {
|
|
104
|
+
if (current === null || current === undefined) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
if (typeof current !== "object") {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
current = current[segment];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return current;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function extractPlayerCandidates(record) {
|
|
117
|
+
const message = record.message ?? {};
|
|
118
|
+
const players = new Set();
|
|
119
|
+
|
|
120
|
+
const singleCandidates = [
|
|
121
|
+
message.playerId,
|
|
122
|
+
message.targetPlayer,
|
|
123
|
+
message.toUser,
|
|
124
|
+
];
|
|
125
|
+
for (const candidate of singleCandidates) {
|
|
126
|
+
if (typeof candidate === "string") {
|
|
127
|
+
players.add(candidate);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const listCandidates = [
|
|
132
|
+
message.activePlayers,
|
|
133
|
+
message.previousPlayers,
|
|
134
|
+
message.currentPlayers,
|
|
135
|
+
message.controllablePlayerIds,
|
|
136
|
+
message.eligiblePlayerIds,
|
|
137
|
+
];
|
|
138
|
+
for (const candidate of listCandidates) {
|
|
139
|
+
if (!Array.isArray(candidate)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
for (const item of candidate) {
|
|
143
|
+
if (typeof item === "string") {
|
|
144
|
+
players.add(item);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return [...players];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function toOutputRecord(record, lineIndex, options) {
|
|
153
|
+
const output = {};
|
|
154
|
+
|
|
155
|
+
if (options.includeIndex) {
|
|
156
|
+
output.index = lineIndex;
|
|
157
|
+
}
|
|
158
|
+
output.observedAt = record.observedAt ?? null;
|
|
159
|
+
output.sessionId = record.sessionId ?? null;
|
|
160
|
+
output.eventId = record.eventId ?? null;
|
|
161
|
+
output.type = record.type ?? null;
|
|
162
|
+
|
|
163
|
+
if (options.fieldPath) {
|
|
164
|
+
output.field = options.fieldPath;
|
|
165
|
+
output.value = getByPath(record, options.fieldPath);
|
|
166
|
+
} else {
|
|
167
|
+
output.message = record.message ?? null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return output;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function main() {
|
|
174
|
+
const options = parseCliArgs(process.argv.slice(2));
|
|
175
|
+
await access(options.filePath);
|
|
176
|
+
|
|
177
|
+
const text = await readFile(options.filePath, "utf8");
|
|
178
|
+
const lines = text
|
|
179
|
+
.split(/\r?\n/u)
|
|
180
|
+
.map((line) => line.trim())
|
|
181
|
+
.filter((line) => line.length > 0);
|
|
182
|
+
|
|
183
|
+
let emitted = 0;
|
|
184
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
185
|
+
const line = lines[lineIndex];
|
|
186
|
+
let record;
|
|
187
|
+
try {
|
|
188
|
+
record = JSON.parse(line);
|
|
189
|
+
} catch {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (options.types.size > 0 && !options.types.has(record.type ?? "")) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (options.playerId) {
|
|
198
|
+
const players = extractPlayerCandidates(record);
|
|
199
|
+
if (!players.includes(options.playerId)) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const output = toOutputRecord(record, lineIndex + 1, options);
|
|
205
|
+
console.log(JSON.stringify(output));
|
|
206
|
+
emitted += 1;
|
|
207
|
+
|
|
208
|
+
if (options.limit !== undefined && emitted >= options.limit) {
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
main().catch((error) => {
|
|
215
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
216
|
+
console.error(`events-extract failed: ${message}`);
|
|
217
|
+
process.exit(1);
|
|
218
|
+
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// ../../node_modules/.pnpm/@dreamboard-games+sdk@0.4.0-alpha.0_@types+react-dom@19.2.3_@types+react@19.2.17__@type_b74cbe125b074769500a56e94fa7f664/node_modules/@dreamboard-games/sdk/dist/chunk-PZ5AY32C.js
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __export = (target, all) => {
|
|
6
|
-
for (var name in all)
|
|
7
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
__export
|
|
12
|
-
};
|