@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +179 -22
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +30 -30
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  4. package/dist/agent-verifier/{chunk-JH22JNYD.mjs → chunk-3UKQVWLV.mjs} +82 -19
  5. package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
  6. package/dist/agent-verifier/{chunk-4WD3YU2E.mjs → chunk-776W3UGV.mjs} +4 -3
  7. package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
  8. package/dist/agent-verifier/{chunk-CJEEA6NJ.mjs → chunk-7WWGFAAU.mjs} +9 -10
  9. package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
  10. package/dist/agent-verifier/{chunk-2SZHMP6F.mjs → chunk-A64ZZUZV.mjs} +6 -9
  11. package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
  12. package/dist/agent-verifier/{chunk-6A5HRJMQ.mjs → chunk-E7SSWJXJ.mjs} +62 -99
  13. package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
  14. package/dist/agent-verifier/{chunk-2GBBP27W.mjs → chunk-F2DIOJJZ.mjs} +1 -0
  15. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  16. package/dist/agent-verifier/{chunk-CFU5EWIC.mjs → chunk-G42BGGG2.mjs} +7 -6
  17. package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
  18. package/dist/agent-verifier/{chunk-SHUMAVAP.mjs → chunk-H76MT5UR.mjs} +7 -9
  19. package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
  20. package/dist/agent-verifier/{chunk-7E65UQLY.mjs → chunk-HGMUAL33.mjs} +3 -2
  21. package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
  22. package/dist/agent-verifier/{chunk-LM3OZLZG.mjs → chunk-IAYRNVUC.mjs} +1 -0
  23. package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
  24. package/dist/agent-verifier/{chunk-VYJTHSYR.mjs → chunk-JGT4P4UD.mjs} +2 -1
  25. package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
  26. package/dist/agent-verifier/{chunk-CEDUHGNH.mjs → chunk-LUZ7KE6H.mjs} +8 -3
  27. package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
  28. package/dist/agent-verifier/{chunk-2E5P5NWG.mjs → chunk-NAK77WXW.mjs} +58 -126
  29. package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
  30. package/dist/agent-verifier/{chunk-SYPLYRGB.mjs → chunk-O4YCPU7C.mjs} +116 -15
  31. package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
  32. package/dist/agent-verifier/{chunk-BVVNBJM4.mjs → chunk-S34FRJHS.mjs} +2 -1
  33. package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
  34. package/dist/agent-verifier/{chunk-HJFQDSTU.mjs → chunk-SH5JKYOB.mjs} +6 -5
  35. package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
  36. package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
  37. package/dist/agent-verifier/{chunk-MINCYHXN.mjs → chunk-TAEQKBJB.mjs} +1 -0
  38. package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
  39. package/dist/agent-verifier/{chunk-CEQ2VJWN.mjs → chunk-UIOLGH4A.mjs} +2 -1
  40. package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
  41. package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
  42. package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
  43. package/dist/agent-verifier/{chunk-2QMNAVV4.mjs → chunk-VS573ERH.mjs} +2 -1
  44. package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
  45. package/dist/agent-verifier/{chunk-EOQIV6PS.mjs → chunk-W3N3QJ4V.mjs} +75 -100
  46. package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
  47. package/dist/agent-verifier/{chunk-EIQWDQWJ.mjs → chunk-XGWCY624.mjs} +11 -12
  48. package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
  49. package/dist/agent-verifier/{chunk-7653FPGJ.mjs → chunk-XQXDOBYB.mjs} +3 -2
  50. package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
  51. package/dist/agent-verifier/{chunk-MRCUP5SW.mjs → chunk-YE7UAO3T.mjs} +1 -0
  52. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  53. package/dist/agent-verifier/{chunk-RBDDIIPM.mjs → chunk-ZEELHSY3.mjs} +1 -0
  54. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  55. package/dist/agent-verifier/{compile-5QSPIOUT.mjs → compile-TEQVA46V.mjs} +24 -25
  56. package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
  57. package/dist/agent-verifier/{global-config-WX3ZZIVU.mjs → global-config-Y2NTSK4R.mjs} +6 -5
  58. package/dist/{keychain-backend-JHTXAKWC.js → agent-verifier/keychain-backend-SPQWGKZN.mjs} +2 -2
  59. package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
  60. package/dist/agent-verifier/{local-files-MTPLP62S.mjs → local-files-JFOQQZDL.mjs} +10 -11
  61. package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
  62. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
  63. package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
  64. package/dist/agent-verifier/{materialize-workspace-FKALAE2T.mjs → materialize-workspace-ZAVGQQSF.mjs} +17 -18
  65. package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
  66. package/dist/agent-verifier/{project-state-7GR6BQTQ.mjs → project-state-K576C2TE.mjs} +3 -2
  67. package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
  68. package/dist/{prompt-GMZABCJC.js → agent-verifier/prompt-MJRJMOGQ.mjs} +2 -2
  69. package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
  70. package/dist/agent-verifier/{reducer-bundle-preflight-C73LEXI2.mjs → reducer-bundle-preflight-LXNJUBKL.mjs} +6 -9
  71. package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
  72. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
  73. package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
  74. package/dist/agent-verifier/{reducer-native-test-harness-GMWBUISX.mjs → reducer-native-test-harness-CHX5MBL5.mjs} +14 -17
  75. package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
  76. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
  77. package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
  78. package/dist/agent-verifier/{sync-3DUQH32H.mjs → sync-THAI546U.mjs} +31 -37
  79. package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
  80. package/dist/agent-verifier/{test-P4U5INTD.mjs → test-AFAQFKOB.mjs} +28 -31
  81. package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
  82. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
  83. package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
  84. package/dist/agent-verifier/{workspace-dependencies-HZ6VVS4G.mjs → workspace-dependencies-NOOQBK6I.mjs} +5 -4
  85. package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
  86. package/dist/{chunk-C6UAT6EH.js → chunk-N7XPNNUI.js} +9 -12
  87. package/dist/chunk-N7XPNNUI.js.map +1 -0
  88. package/dist/chunk-SEGVTWSK.js +44 -0
  89. package/dist/chunk-SEGVTWSK.js.map +1 -0
  90. package/dist/{chunk-RS7UXJZV.js → chunk-TAQKH67O.js} +21300 -35881
  91. package/dist/chunk-TAQKH67O.js.map +1 -0
  92. package/dist/{global-config-AGFBDFYD.js → global-config-S4ZIPECE.js} +3 -3
  93. package/dist/global-config-S4ZIPECE.js.map +1 -0
  94. package/dist/index.js +415 -37
  95. package/dist/index.js.map +1 -1
  96. package/dist/internal.js +3 -4
  97. package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
  98. package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
  99. package/package.json +8 -7
  100. package/skills/dreamboard/references/building-your-first-game.md +510 -0
  101. package/skills/dreamboard/references/cli.md +104 -0
  102. package/skills/dreamboard/references/game-interface.md +548 -0
  103. package/skills/dreamboard/references/manifest-authoring.md +597 -0
  104. package/skills/dreamboard/references/quickstart.md +66 -0
  105. package/skills/dreamboard/references/reducer.md +864 -0
  106. package/skills/dreamboard/references/rule-authoring.md +147 -0
  107. package/skills/dreamboard/references/testing.md +249 -0
  108. package/skills/dreamboard/scripts/events-extract.mjs +218 -0
  109. package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
  110. package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
  111. package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
  112. package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
  113. package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
  114. package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
  115. package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
  116. package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
  117. package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
  118. package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
  119. package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
  120. package/dist/chunk-2H7UOFLK.js +0 -11
  121. package/dist/chunk-7FOO4AJI.js +0 -50
  122. package/dist/chunk-7FOO4AJI.js.map +0 -1
  123. package/dist/chunk-C6UAT6EH.js.map +0 -1
  124. package/dist/chunk-RS7UXJZV.js.map +0 -1
  125. package/dist/internal.d.ts +0 -311
  126. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
  127. package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
  128. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
  129. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
  130. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
  131. package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
  132. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
  133. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
  134. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
  135. package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
  136. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
  137. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
  138. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
  139. package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
  140. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
  141. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
  142. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
  143. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
  144. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
  145. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
  146. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
  147. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
  148. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
  149. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
  150. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
  151. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
  152. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
  153. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
  154. package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
  155. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
  156. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
  157. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
  158. package/dist/testing-KLSV6CPJ.js +0 -674
  159. package/dist/testing-KLSV6CPJ.js.map +0 -1
  160. /package/dist/{chunk-2H7UOFLK.js.map → agent-verifier/chunk-SKI2ESE5.mjs.map} +0 -0
  161. /package/dist/{global-config-AGFBDFYD.js.map → agent-verifier/global-config-Y2NTSK4R.mjs.map} +0 -0
  162. /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
  163. /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.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
- };