@dreamboard-games/cli 0.1.30-alpha.2 → 0.1.30-alpha.21

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 (136) hide show
  1. package/README.md +25 -107
  2. package/dist/agent-verifier/agent-workspace-verifier.mjs +1682 -0
  3. package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
  4. package/dist/agent-verifier/chunk-22U6RMWO.mjs +722 -0
  5. package/dist/agent-verifier/chunk-22U6RMWO.mjs.map +1 -0
  6. package/dist/agent-verifier/chunk-4I2WWAPK.mjs +399 -0
  7. package/dist/agent-verifier/chunk-4I2WWAPK.mjs.map +1 -0
  8. package/dist/agent-verifier/chunk-BWBN2TDJ.mjs +2811 -0
  9. package/dist/agent-verifier/chunk-BWBN2TDJ.mjs.map +1 -0
  10. package/dist/agent-verifier/chunk-DQUYBIGQ.mjs +353 -0
  11. package/dist/agent-verifier/chunk-DQUYBIGQ.mjs.map +1 -0
  12. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs +302 -0
  13. package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
  14. package/dist/agent-verifier/chunk-GWRZRWCF.mjs +107 -0
  15. package/dist/agent-verifier/chunk-GWRZRWCF.mjs.map +1 -0
  16. package/dist/agent-verifier/chunk-H6XDQJ3N.mjs +11 -0
  17. package/dist/agent-verifier/chunk-HUBV22JQ.mjs +89 -0
  18. package/dist/agent-verifier/chunk-HUBV22JQ.mjs.map +1 -0
  19. package/dist/agent-verifier/chunk-IWB4L2HV.mjs +273 -0
  20. package/dist/agent-verifier/chunk-IWB4L2HV.mjs.map +1 -0
  21. package/dist/agent-verifier/chunk-JZTH3EMV.mjs +14523 -0
  22. package/dist/agent-verifier/chunk-JZTH3EMV.mjs.map +1 -0
  23. package/dist/agent-verifier/chunk-KDAQ4CZY.mjs +192 -0
  24. package/dist/agent-verifier/chunk-KDAQ4CZY.mjs.map +1 -0
  25. package/dist/agent-verifier/chunk-M7UVBANQ.mjs +58 -0
  26. package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
  27. package/dist/agent-verifier/chunk-MYMVXTZT.mjs +766 -0
  28. package/dist/agent-verifier/chunk-MYMVXTZT.mjs.map +1 -0
  29. package/dist/agent-verifier/chunk-OJFZVGEL.mjs +492 -0
  30. package/dist/agent-verifier/chunk-OJFZVGEL.mjs.map +1 -0
  31. package/dist/agent-verifier/chunk-QD4SQNUP.mjs +75 -0
  32. package/dist/agent-verifier/chunk-QD4SQNUP.mjs.map +1 -0
  33. package/dist/agent-verifier/chunk-RDYXWXXC.mjs +47 -0
  34. package/dist/agent-verifier/chunk-RDYXWXXC.mjs.map +1 -0
  35. package/dist/agent-verifier/chunk-TIDX3YLW.mjs +158 -0
  36. package/dist/agent-verifier/chunk-TIDX3YLW.mjs.map +1 -0
  37. package/dist/agent-verifier/chunk-TTB7AIHZ.mjs +214 -0
  38. package/dist/agent-verifier/chunk-TTB7AIHZ.mjs.map +1 -0
  39. package/dist/agent-verifier/chunk-UXGTT25Q.mjs +59 -0
  40. package/dist/agent-verifier/chunk-UXGTT25Q.mjs.map +1 -0
  41. package/dist/agent-verifier/chunk-YE7UAO3T.mjs +129 -0
  42. package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
  43. package/dist/agent-verifier/chunk-ZEELHSY3.mjs +20 -0
  44. package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
  45. package/dist/agent-verifier/global-config-IXZLY4BS.mjs +19 -0
  46. package/dist/agent-verifier/keychain-backend-UF3Z26JM.mjs +140 -0
  47. package/dist/agent-verifier/keychain-backend-UF3Z26JM.mjs.map +1 -0
  48. package/dist/agent-verifier/local-files-OF4QFISU.mjs +45 -0
  49. package/dist/agent-verifier/local-files-OF4QFISU.mjs.map +1 -0
  50. package/dist/agent-verifier/local-typecheck-DHVLM37Z.mjs +150 -0
  51. package/dist/agent-verifier/local-typecheck-DHVLM37Z.mjs.map +1 -0
  52. package/dist/agent-verifier/materialize-workspace-7DFE45ZH.mjs +90 -0
  53. package/dist/agent-verifier/materialize-workspace-7DFE45ZH.mjs.map +1 -0
  54. package/dist/agent-verifier/project-state-XKUSCFSV.mjs +33 -0
  55. package/dist/agent-verifier/project-state-XKUSCFSV.mjs.map +1 -0
  56. package/dist/agent-verifier/prompt-VKHMCQT6.mjs +756 -0
  57. package/dist/agent-verifier/prompt-VKHMCQT6.mjs.map +1 -0
  58. package/dist/agent-verifier/reducer-bundle-preflight-GLUJKTWU.mjs +312 -0
  59. package/dist/agent-verifier/reducer-bundle-preflight-GLUJKTWU.mjs.map +1 -0
  60. package/dist/agent-verifier/reducer-contract-preflight-WVQQPW5F.mjs +46 -0
  61. package/dist/agent-verifier/reducer-contract-preflight-WVQQPW5F.mjs.map +1 -0
  62. package/dist/agent-verifier/reducer-native-test-harness-H6G6RBRY.mjs +3436 -0
  63. package/dist/agent-verifier/reducer-native-test-harness-H6G6RBRY.mjs.map +1 -0
  64. package/dist/agent-verifier/static-scaffold-CC4KL6K7.mjs +24 -0
  65. package/dist/agent-verifier/static-scaffold-CC4KL6K7.mjs.map +1 -0
  66. package/dist/agent-verifier/workspace-codegen-SPPVHURX.mjs +10 -0
  67. package/dist/agent-verifier/workspace-codegen-SPPVHURX.mjs.map +1 -0
  68. package/dist/agent-verifier/workspace-dependencies-5HEEKZFP.mjs +17 -0
  69. package/dist/agent-verifier/workspace-dependencies-5HEEKZFP.mjs.map +1 -0
  70. package/dist/authoring-compatibility-internal.js +12 -0
  71. package/dist/authoring-compatibility-internal.js.map +1 -0
  72. package/dist/chunk-2H7UOFLK.js +11 -0
  73. package/dist/chunk-2H7UOFLK.js.map +1 -0
  74. package/dist/{chunk-TAQKH67O.js → chunk-2Z65YI7P.js} +2702 -7338
  75. package/dist/chunk-2Z65YI7P.js.map +1 -0
  76. package/dist/chunk-EQNBQVIW.js +204 -0
  77. package/dist/chunk-EQNBQVIW.js.map +1 -0
  78. package/dist/chunk-GQ3ZEAEG.js +4281 -0
  79. package/dist/chunk-GQ3ZEAEG.js.map +1 -0
  80. package/dist/chunk-UI7NWSYA.js +334 -0
  81. package/dist/chunk-UI7NWSYA.js.map +1 -0
  82. package/dist/{global-config-S4ZIPECE.js → global-config-GK2UC2X6.js} +4 -3
  83. package/dist/global-config-GK2UC2X6.js.map +1 -0
  84. package/dist/index.js +3421 -6435
  85. package/dist/index.js.map +1 -1
  86. package/dist/internal.js +15 -9
  87. package/dist/{keychain-backend-HDF4TZDL.js → keychain-backend-GO34KGTG.js} +12 -7
  88. package/dist/keychain-backend-GO34KGTG.js.map +1 -0
  89. package/dist/{prompt-NDV3AE5L.js → prompt-GMZABCJC.js} +2 -2
  90. package/package.json +11 -20
  91. package/release/authoring-release-set.json +38 -0
  92. package/skills/dreamboard/SKILL.md +30 -28
  93. package/skills/dreamboard/references/building-your-first-game.md +15 -15
  94. package/skills/dreamboard/references/cli.md +48 -47
  95. package/skills/dreamboard/references/manifest-authoring.md +11 -3
  96. package/skills/dreamboard/references/quickstart.md +16 -13
  97. package/skills/dreamboard/references/testing.md +10 -10
  98. package/dist/chunk-N7XPNNUI.js +0 -432
  99. package/dist/chunk-N7XPNNUI.js.map +0 -1
  100. package/dist/chunk-SEGVTWSK.js +0 -44
  101. package/dist/chunk-TAQKH67O.js.map +0 -1
  102. package/dist/dev-host/components/drawer.tsx +0 -132
  103. package/dist/dev-host/components/input.tsx +0 -21
  104. package/dist/dev-host/dev-api-proxy-plugin.ts +0 -328
  105. package/dist/dev-host/dev-author-dom-warnings.ts +0 -100
  106. package/dist/dev-host/dev-diagnostics.ts +0 -62
  107. package/dist/dev-host/dev-fallback-stylesheet.ts +0 -53
  108. package/dist/dev-host/dev-hmr-guard-plugin.ts +0 -47
  109. package/dist/dev-host/dev-host-controller.ts +0 -674
  110. package/dist/dev-host/dev-host-player-query.ts +0 -17
  111. package/dist/dev-host/dev-host-session-transport.ts +0 -52
  112. package/dist/dev-host/dev-host-storage.ts +0 -56
  113. package/dist/dev-host/dev-log-relay-plugin.ts +0 -510
  114. package/dist/dev-host/dev-runtime-config.ts +0 -14
  115. package/dist/dev-host/dev-runtime-platform.ts +0 -335
  116. package/dist/dev-host/dev-virtual-modules-plugin.ts +0 -64
  117. package/dist/dev-host/host-main.css +0 -224
  118. package/dist/dev-host/host-main.tsx +0 -948
  119. package/dist/dev-host/index.html +0 -56
  120. package/dist/dev-host/lib/utils.ts +0 -6
  121. package/dist/dev-host/plugin-main.ts +0 -61
  122. package/dist/dev-host/plugin.html +0 -24
  123. package/dist/dev-host/shared-styles.css +0 -144
  124. package/dist/dev-host/start-dev-server.ts +0 -140
  125. package/dist/dev-host/virtual-modules.d.ts +0 -27
  126. package/dist/keychain-backend-HDF4TZDL.js.map +0 -1
  127. package/skills/dreamboard/scripts/events-extract.mjs +0 -218
  128. /package/dist/{chunk-SEGVTWSK.js.map → agent-verifier/chunk-H6XDQJ3N.mjs.map} +0 -0
  129. /package/dist/{global-config-S4ZIPECE.js.map → agent-verifier/global-config-IXZLY4BS.mjs.map} +0 -0
  130. /package/dist/{prompt-NDV3AE5L.js.map → prompt-GMZABCJC.js.map} +0 -0
  131. /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.framework.json +0 -0
  132. /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.json +0 -0
  133. /package/{dist/scaffold → scaffold}/assets/static/ui/index.tsx +0 -0
  134. /package/{dist/scaffold → scaffold}/assets/static/ui/style.css +0 -0
  135. /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.framework.json +0 -0
  136. /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.json +0 -0
@@ -0,0 +1,722 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ REDUCER_TESTING_TYPES_WRAPPER_CONTENT
4
+ } from "./chunk-F2DIOJJZ.mjs";
5
+ import {
6
+ ensureDir
7
+ } from "./chunk-RDYXWXXC.mjs";
8
+ import {
9
+ isDynamicSeedPath,
10
+ materializeManifest
11
+ } from "./chunk-BWBN2TDJ.mjs";
12
+ import {
13
+ normalizeOwnedProjectPath,
14
+ readWorkspaceTextFile,
15
+ readWorkspaceTextFileIfExists,
16
+ removeWorkspacePath,
17
+ resolveWorkspacePath,
18
+ unlinkWorkspaceFile,
19
+ workspacePathExists,
20
+ writeWorkspaceTextFile
21
+ } from "./chunk-OJFZVGEL.mjs";
22
+ import {
23
+ FRAMEWORK_PNPM_OVERRIDES,
24
+ FRAMEWORK_REACT_DEPENDENCIES,
25
+ FRAMEWORK_ZOD_VERSION
26
+ } from "./chunk-ZEELHSY3.mjs";
27
+ import {
28
+ MANIFEST_TYPECHECK_CONFIG_FILE
29
+ } from "./chunk-M7UVBANQ.mjs";
30
+
31
+ // src/services/project/static-scaffold.ts
32
+ import { existsSync } from "fs";
33
+ import { readdir, readFile, rmdir } from "fs/promises";
34
+ import path from "path";
35
+ import { fileURLToPath } from "url";
36
+
37
+ // src/release/authoring-release-set.generated.ts
38
+ var AUTHORING_RELEASE_SET = {
39
+ "schemaVersion": 1,
40
+ "channel": "public",
41
+ "packages": {
42
+ "cli": {
43
+ "name": "@dreamboard-games/cli",
44
+ "version": "0.1.30-alpha.21"
45
+ },
46
+ "sdk": {
47
+ "name": "@dreamboard-games/sdk",
48
+ "version": "0.4.0-alpha.6"
49
+ },
50
+ "apiClient": {
51
+ "name": "@dreamboard-games/api-client",
52
+ "version": "0.3.0-alpha.4"
53
+ },
54
+ "devHost": {
55
+ "name": "@dreamboard-games/dev-host",
56
+ "version": "0.1.30-alpha.19"
57
+ }
58
+ },
59
+ "protocols": {
60
+ "authoringAdapter": 1,
61
+ "devHost": 1,
62
+ "verifier": 1
63
+ },
64
+ "schemas": {
65
+ "scaffold": 2,
66
+ "manifest": 2,
67
+ "generatedArtifacts": 1
68
+ },
69
+ "registry": {
70
+ "kind": "public-npm",
71
+ "portable": true
72
+ },
73
+ "packageManager": "pnpm@10.4.1",
74
+ "releaseSetId": "sha256:9719136d41000ccb72a11154e402a320e5cefd56905b1555b05a05d710d1d7e4"
75
+ };
76
+
77
+ // src/services/project/static-scaffold.ts
78
+ var DREAMBOARD_SCAFFOLD_REFRESH_COMMAND = "dreamboard project create or dreamboard project clone";
79
+ var DREAMBOARD_GITIGNORE_BLOCK = [
80
+ "# Dreamboard local state",
81
+ ".dreamboard/state.json",
82
+ ".dreamboard/snapshot.json",
83
+ ".dreamboard/dev/",
84
+ ".dreamboard/generated/",
85
+ "node_modules/",
86
+ "ui/node_modules/",
87
+ ""
88
+ ].join("\n");
89
+ var TESTING_TYPES_STUB = "export function defineScenario(scenario) { return scenario; }\n";
90
+ var GENERATED_TESTING_TYPES_PREFIX = "// Generated by dreamboard";
91
+ var GENERATED_SCENARIO_PREFIX = "// Generated by dreamboard scaffold.";
92
+ var LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = `export {
93
+ ErrorBoundary,
94
+ type ErrorBoundaryProps,
95
+ } from "@dreamboard-games/sdk/ui";
96
+ export { PluginRuntime, type PluginRuntimeProps } from "@dreamboard-games/sdk/runtime";
97
+ `;
98
+ var OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = [
99
+ "export {",
100
+ " ErrorBoundary,",
101
+ " PluginRuntime,",
102
+ " type ErrorBoundaryProps,",
103
+ " type PluginRuntimeProps,",
104
+ `} from "@dreamboard/ui-${"sdk"}";`,
105
+ ""
106
+ ].join("\n");
107
+ var OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT = [
108
+ "export {",
109
+ " ErrorBoundary,",
110
+ " PluginRuntime,",
111
+ " type ErrorBoundaryProps,",
112
+ " type PluginRuntimeProps,",
113
+ `} from "@dreamboard-games/ui-${"sdk"}";`,
114
+ ""
115
+ ].join("\n");
116
+ var INITIAL_SCENARIO_CONTENT = `${GENERATED_SCENARIO_PREFIX}
117
+ import { defineScenario } from "../testing-types";
118
+
119
+ export default defineScenario({
120
+ id: "smoke-initial-turn",
121
+ description:
122
+ "Sanity check that the scaffolded workspace boots into its initial phase.",
123
+ from: "initial-turn",
124
+ when: async () => undefined,
125
+ then: ({ expect, players, state }) => {
126
+ const playerIds = players();
127
+ expect(playerIds).toHaveLength(playerIds.length);
128
+ expect(playerIds.length).toBeGreaterThanOrEqual(1);
129
+ expect(state()).toBe("setup");
130
+ },
131
+ });
132
+ `;
133
+ var STATIC_ASSET_ROOT = resolveStaticAssetRoot();
134
+ var SDK_DEPENDENCY_RANGES = {
135
+ "@dreamboard-games/sdk": AUTHORING_RELEASE_SET.packages.sdk.version
136
+ };
137
+ var DEV_HOST_DEPENDENCY_RANGES = {
138
+ "@dreamboard-games/dev-host": AUTHORING_RELEASE_SET.packages.devHost.version
139
+ };
140
+ var DREAMBOARD_PACKAGE_OVERRIDES = {
141
+ "@dreamboard-games/api-client": AUTHORING_RELEASE_SET.packages.apiClient.version,
142
+ "@dreamboard-games/dev-host": AUTHORING_RELEASE_SET.packages.devHost.version,
143
+ "@dreamboard-games/sdk": AUTHORING_RELEASE_SET.packages.sdk.version
144
+ };
145
+ var FRAMEWORK_SCRIPTS = {
146
+ dev: "dreamboard dev",
147
+ "test:ui": "tsx --tsconfig test/tsconfig.tsx-runtime.json --test test/ui/**/*.test.tsx",
148
+ typecheck: `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE} && tsc --noEmit -p app/tsconfig.json && tsc --noEmit -p ui/tsconfig.json`,
149
+ "typecheck:manifest": `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE}`,
150
+ "typecheck:app": "tsc --noEmit -p app/tsconfig.json",
151
+ "typecheck:ui": "tsc --noEmit -p ui/tsconfig.json"
152
+ };
153
+ var SHARED_DEPENDENCIES = {
154
+ ...FRAMEWORK_REACT_DEPENDENCIES
155
+ };
156
+ var ROOT_APP_DEPENDENCIES = {
157
+ zod: FRAMEWORK_ZOD_VERSION
158
+ };
159
+ var SHARED_DEV_DEPENDENCIES = {
160
+ typescript: "^5.9.2",
161
+ "@types/node": "^24.5.2",
162
+ "@types/react": "^19.0.0",
163
+ "@types/react-dom": "^19.0.0",
164
+ csstype: "^3.1.3",
165
+ tsx: "^4.20.5"
166
+ };
167
+ async function scaffoldStaticWorkspace(projectRoot, mode, options = {}) {
168
+ await writeFrameworkStaticFiles(projectRoot, mode, options);
169
+ await ensureDreamboardGitignore(projectRoot);
170
+ await writeManifestTypecheckTsconfig(projectRoot);
171
+ await removeLegacyVendoredSdkPaths(projectRoot);
172
+ await removeLegacyDreamboardComponentPath(projectRoot);
173
+ await ensureDir(resolveWorkspacePath(projectRoot, "test/bases"));
174
+ await ensureDir(resolveWorkspacePath(projectRoot, "test/scenarios"));
175
+ await ensureDir(resolveWorkspacePath(projectRoot, "test/generated"));
176
+ await writeTestReadme(projectRoot);
177
+ await writeGeneratedTestingStubs(projectRoot, mode);
178
+ const initialTestPlayerCount = await inferInitialTestPlayerCount(projectRoot);
179
+ await writeInitialBase(projectRoot, mode, initialTestPlayerCount);
180
+ await writeInitialScenario(projectRoot, mode);
181
+ await writeTestingTypes(projectRoot, mode);
182
+ await writeTestTsconfig(projectRoot);
183
+ if (await workspacePathExists(projectRoot, "test/testing-types.d.ts")) {
184
+ await unlinkWorkspaceFile(projectRoot, "test/testing-types.d.ts");
185
+ }
186
+ if (await workspacePathExists(projectRoot, "test/base-scenarios.json")) {
187
+ await unlinkWorkspaceFile(projectRoot, "test/base-scenarios.json");
188
+ }
189
+ await migrateLegacyScenarioImports(projectRoot);
190
+ }
191
+ async function ensureDreamboardGitignore(projectRoot) {
192
+ const existing = await readWorkspaceTextFileIfExists(
193
+ projectRoot,
194
+ ".gitignore"
195
+ );
196
+ if (existing?.includes(".dreamboard/state.json")) {
197
+ return;
198
+ }
199
+ await writeWorkspaceTextFile(
200
+ projectRoot,
201
+ ".gitignore",
202
+ `${existing ? `${existing.trimEnd()}
203
+
204
+ ` : ""}${DREAMBOARD_GITIGNORE_BLOCK}`
205
+ );
206
+ }
207
+ async function assertCliStaticScaffoldComplete(projectRoot, deletedPaths = []) {
208
+ const expectedEntries = await getExpectedStaticEntries(projectRoot);
209
+ const missingOrBlankPaths = [];
210
+ for (const entry of expectedEntries) {
211
+ const content = await readWorkspaceTextFileIfExists(
212
+ projectRoot,
213
+ entry.targetPath
214
+ );
215
+ if (content === null || content.trim().length === 0) {
216
+ missingOrBlankPaths.push(entry.targetPath);
217
+ }
218
+ }
219
+ const staticPaths = new Set(expectedEntries.map((entry) => entry.targetPath));
220
+ const deletedStaticPaths = deletedPaths.map(normalizeOwnedProjectPath).filter(
221
+ (filePath) => filePath !== null && staticPaths.has(filePath)
222
+ ).sort();
223
+ if (missingOrBlankPaths.length === 0 && deletedStaticPaths.length === 0) {
224
+ return;
225
+ }
226
+ const problems = [];
227
+ if (missingOrBlankPaths.length > 0) {
228
+ problems.push(
229
+ `missing or blank: ${summarizePaths(missingOrBlankPaths.sort())}`
230
+ );
231
+ }
232
+ if (deletedStaticPaths.length > 0) {
233
+ problems.push(`deleted: ${summarizePaths(deletedStaticPaths)}`);
234
+ }
235
+ throw new Error(
236
+ `CLI static scaffold is incomplete (${problems.join("; ")}). Refresh the project scaffold with ${DREAMBOARD_SCAFFOLD_REFRESH_COMMAND} before building or testing.`
237
+ );
238
+ }
239
+ async function writeFrameworkStaticFiles(projectRoot, mode, options) {
240
+ const assetEntries = await getStaticAssetEntries();
241
+ for (const entry of assetEntries) {
242
+ if (mode === "update" && isDynamicSeedPath(entry.targetPath)) {
243
+ const existing = await readWorkspaceTextFileIfExists(
244
+ projectRoot,
245
+ entry.targetPath
246
+ );
247
+ if (existing !== null && existing.trim().length > 0) {
248
+ continue;
249
+ }
250
+ }
251
+ await writeWorkspaceTextFile(projectRoot, entry.targetPath, entry.content);
252
+ }
253
+ for (const entry of await getDynamicStaticEntries(
254
+ projectRoot,
255
+ mode,
256
+ options
257
+ )) {
258
+ await writeWorkspaceTextFile(projectRoot, entry.targetPath, entry.content);
259
+ }
260
+ if (!options.localMaintainerRegistry) {
261
+ await removeWorkspacePath(projectRoot, ".npmrc", { force: true });
262
+ }
263
+ }
264
+ async function removeLegacyVendoredSdkPaths(projectRoot) {
265
+ await removeWorkspacePath(projectRoot, "app/sdk", {
266
+ recursive: true,
267
+ force: true
268
+ });
269
+ await removeWorkspacePath(projectRoot, "ui/sdk", {
270
+ recursive: true,
271
+ force: true
272
+ });
273
+ }
274
+ async function removeLegacyDreamboardComponentPath(projectRoot) {
275
+ const legacyIndexProjectPath = "ui/components/dreamboard/index.ts";
276
+ const legacyDirPath = resolveWorkspacePath(
277
+ projectRoot,
278
+ "ui/components/dreamboard"
279
+ );
280
+ const existing = await readWorkspaceTextFileIfExists(
281
+ projectRoot,
282
+ legacyIndexProjectPath
283
+ );
284
+ const removableLegacyContents = /* @__PURE__ */ new Set([
285
+ LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),
286
+ OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),
287
+ OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim()
288
+ ]);
289
+ if (existing === null || !removableLegacyContents.has(existing.trim())) {
290
+ return;
291
+ }
292
+ await unlinkWorkspaceFile(projectRoot, legacyIndexProjectPath);
293
+ const remainingEntries = await readdir(legacyDirPath).catch(() => []);
294
+ if (remainingEntries.length === 0) {
295
+ await rmdir(legacyDirPath);
296
+ }
297
+ }
298
+ async function writeTestReadme(projectRoot) {
299
+ await writeWorkspaceTextFile(
300
+ projectRoot,
301
+ "test/README.md",
302
+ "# Dreamboard Test Workspace\n\nTypeScript bases live in `test/bases/*.base.ts` and scenarios live in `test/scenarios/*.scenario.ts`.\n\n1. Define reusable seeded bases with `defineBase({ id, seed, players, setupProfileId?, setup })`.\n2. Define scenarios with `defineScenario({ id, from, when, then })`.\n3. Scenario assertions can read `players()`, `state()`, `view(playerId)`, and `interactions(playerId)`.\n4. Run deterministic scenario tests: `dreamboard test`.\n5. Run a single scenario when needed: `dreamboard test --scenario <scenario-id>`.\n\nImport test helpers from `../testing-types`.\n\nGenerated artifacts are written to `test/generated/*` and should not be edited manually.\n"
303
+ );
304
+ }
305
+ async function writeInitialBase(projectRoot, mode, players) {
306
+ if (mode === "update") {
307
+ return;
308
+ }
309
+ await writeWorkspaceTextFile(
310
+ projectRoot,
311
+ "test/bases/initial-turn.base.ts",
312
+ `import { defineBase } from "../testing-types";
313
+
314
+ export default defineBase({
315
+ id: "initial-turn",
316
+ seed: 1337,
317
+ players: ${players},
318
+ setup: async () => undefined,
319
+ });
320
+ `
321
+ );
322
+ }
323
+ async function writeInitialScenario(projectRoot, mode) {
324
+ if (mode === "new") {
325
+ await writeWorkspaceTextFile(
326
+ projectRoot,
327
+ "test/scenarios/smoke-initial-turn.scenario.ts",
328
+ INITIAL_SCENARIO_CONTENT
329
+ );
330
+ return;
331
+ }
332
+ const existing = await readWorkspaceTextFileIfExists(
333
+ projectRoot,
334
+ "test/scenarios/smoke-initial-turn.scenario.ts"
335
+ );
336
+ if (existing === null || existing.trim().length === 0 || existing.startsWith(GENERATED_SCENARIO_PREFIX)) {
337
+ await writeWorkspaceTextFile(
338
+ projectRoot,
339
+ "test/scenarios/smoke-initial-turn.scenario.ts",
340
+ INITIAL_SCENARIO_CONTENT
341
+ );
342
+ }
343
+ }
344
+ async function writeTestingTypes(projectRoot, mode) {
345
+ if (mode === "new") {
346
+ await writeWorkspaceTextFile(
347
+ projectRoot,
348
+ "test/testing-types.ts",
349
+ REDUCER_TESTING_TYPES_WRAPPER_CONTENT
350
+ );
351
+ return;
352
+ }
353
+ const existing = await readWorkspaceTextFileIfExists(
354
+ projectRoot,
355
+ "test/testing-types.ts"
356
+ );
357
+ if (shouldRefreshGeneratedTestingTypes(existing)) {
358
+ await writeWorkspaceTextFile(
359
+ projectRoot,
360
+ "test/testing-types.ts",
361
+ REDUCER_TESTING_TYPES_WRAPPER_CONTENT
362
+ );
363
+ }
364
+ }
365
+ async function writeGeneratedTestingStubs(projectRoot, mode) {
366
+ const header = "// Generated by dreamboard scaffold. Do not edit by hand.\n";
367
+ await writeGeneratedTestingStubFile(
368
+ projectRoot,
369
+ "test/generated/base-states.generated.ts",
370
+ `${header}export const BASE_STATES = {} as const;
371
+ export const BASE_STATES_CONTRACT_FINGERPRINT = undefined;
372
+ `,
373
+ mode
374
+ );
375
+ await writeGeneratedTestingStubFile(
376
+ projectRoot,
377
+ "test/generated/base-states.generated.d.ts",
378
+ `${header}export declare const BASE_STATES: Record<string, unknown>;
379
+ export declare const BASE_STATES_CONTRACT_FINGERPRINT: string | undefined;
380
+ `,
381
+ mode
382
+ );
383
+ await writeGeneratedTestingStubFile(
384
+ projectRoot,
385
+ "test/generated/testing-contract.ts",
386
+ `${header}export type BaseId = string;
387
+ export type GameView = unknown;
388
+ export type InteractionId = string;
389
+ export type InteractionParamsOf<_Id extends string> = Record<string, unknown>;
390
+ export type PhaseName = string;
391
+ export type PlayerId = string;
392
+ export type RejectionCode = string;
393
+ export type StateName = string;
394
+ export type TestRunner = "reducer" | "remote" | "browser";
395
+ export type ViewByPhase = Record<string, GameView>;
396
+ export type WorkspaceStageName<_Phase extends string = string> = string;
397
+ export type Expectation = { [matcher: string]: (...args: unknown[]) => unknown; not: Expectation };
398
+ export type ExpectFn = (actual: unknown) => Expectation;
399
+ export type InteractionExplanation = { interactionId: string; phase: string; step: string | null; availability: "available" | "notYourTurn" | "wrongPhase" | "wrongStep" | "blocked"; rules: readonly { ruleId: string; outcome: "passed" | "failed" | "notEvaluated"; errorCode?: string; message?: string; }[]; actor: { required: readonly string[]; playerIsActor: boolean }; inputs: readonly { key: string; kind: string; eligibleCount: number | "lazy"; }[]; };
400
+ export interface InteractionDescriptorFor<Id extends string = string> { interactionId: Id; [key: string]: unknown; }
401
+ export interface ScenarioGameApi { start(): Promise<void>; submit<Id extends InteractionId>(playerId: PlayerId, interactionId: Id, params?: InteractionParamsOf<Id>): Promise<void>; }
402
+ export interface BaseContext { game: ScenarioGameApi; players(): readonly PlayerId[]; seat(index: number): PlayerId; }
403
+ export interface SharedScenarioContext { game: ScenarioGameApi; players(): readonly PlayerId[]; seat(index: number): PlayerId; state(): StateName; view(playerId: PlayerId): GameView; interactions(playerId: PlayerId): readonly InteractionDescriptorFor[]; explain(playerId: PlayerId, interactionId: InteractionId): InteractionExplanation; expect: ExpectFn; }
404
+ export type ScenarioContext<Phase extends PhaseName | undefined = undefined> = Omit<SharedScenarioContext, "state" | "view"> & { state(): Phase extends PhaseName ? Phase : StateName; view(playerId: PlayerId): Phase extends PhaseName ? ViewByPhase[Phase] : GameView; };
405
+ export type ScenarioThenContext<_Runners extends readonly TestRunner[] = readonly ["reducer"], Phase extends PhaseName | undefined = undefined> = ScenarioContext<Phase>;
406
+ export interface BaseDefinition { id: string; seed?: number; players?: number; setupProfileId?: string; extends?: BaseId | string; setup: (ctx: BaseContext) => void | Promise<void>; }
407
+ export interface ScenarioDefinition<Runners extends readonly TestRunner[] = readonly ["reducer"], Phase extends PhaseName | undefined = undefined> { id: string; description?: string; from: BaseId | string; runners?: Runners; phase?: Phase; stage?: Phase extends PhaseName ? WorkspaceStageName<Phase> : never; when: (ctx: ScenarioContext<Phase>) => void | Promise<void>; then: (ctx: ScenarioThenContext<Runners, Phase>) => void | Promise<void>; }
408
+ `,
409
+ mode
410
+ );
411
+ await writeGeneratedTestingStubFile(
412
+ projectRoot,
413
+ "test/generated/scenario-manifest.generated.ts",
414
+ `${header}export const SCENARIO_MANIFEST = [] as const;
415
+ `,
416
+ mode
417
+ );
418
+ }
419
+ async function writeGeneratedTestingStubFile(projectRoot, projectPath, content, mode) {
420
+ if (mode === "new") {
421
+ await writeWorkspaceTextFile(projectRoot, projectPath, content);
422
+ return;
423
+ }
424
+ const existing = await readWorkspaceTextFileIfExists(
425
+ projectRoot,
426
+ projectPath
427
+ );
428
+ if (existing === null || existing.trim().length === 0 || existing.startsWith(GENERATED_SCENARIO_PREFIX)) {
429
+ await writeWorkspaceTextFile(projectRoot, projectPath, content);
430
+ }
431
+ }
432
+ async function writeTestTsconfig(projectRoot) {
433
+ await writeWorkspaceTextFile(
434
+ projectRoot,
435
+ "test/tsconfig.json",
436
+ `${JSON.stringify(
437
+ {
438
+ compilerOptions: {
439
+ target: "ES2022",
440
+ module: "ESNext",
441
+ moduleResolution: "bundler",
442
+ strict: true,
443
+ esModuleInterop: true,
444
+ skipLibCheck: true,
445
+ noEmit: true
446
+ },
447
+ include: [
448
+ "./**/*.ts",
449
+ "./**/*.d.ts",
450
+ "../shared/**/*.ts",
451
+ "../shared/**/*.d.ts"
452
+ ]
453
+ },
454
+ null,
455
+ 2
456
+ )}
457
+ `
458
+ );
459
+ }
460
+ async function writeManifestTypecheckTsconfig(projectRoot) {
461
+ await writeWorkspaceTextFile(
462
+ projectRoot,
463
+ MANIFEST_TYPECHECK_CONFIG_FILE,
464
+ `${JSON.stringify(
465
+ {
466
+ compilerOptions: {
467
+ target: "ES2022",
468
+ module: "ESNext",
469
+ moduleResolution: "bundler",
470
+ strict: true,
471
+ esModuleInterop: true,
472
+ skipLibCheck: true,
473
+ noEmit: true,
474
+ allowImportingTsExtensions: true
475
+ },
476
+ include: ["./manifest.ts"]
477
+ },
478
+ null,
479
+ 2
480
+ )}
481
+ `
482
+ );
483
+ }
484
+ async function migrateLegacyScenarioImports(projectRoot) {
485
+ if (!await workspacePathExists(projectRoot, "test/scenarios")) return;
486
+ const scenariosRoot = resolveWorkspacePath(projectRoot, "test/scenarios");
487
+ const scenarioFiles = await collectScenarioFiles(scenariosRoot);
488
+ for (const filePath of scenarioFiles) {
489
+ const projectPath = toWorkspaceProjectPath(projectRoot, filePath);
490
+ const content = await readWorkspaceTextFile(projectRoot, projectPath);
491
+ if (!content.includes("@dreamboard/cli/testing")) continue;
492
+ const relativeToTestingTypes = normalizeImportPath(
493
+ path.relative(
494
+ path.dirname(filePath),
495
+ path.join(projectRoot, "test", "testing-types")
496
+ )
497
+ );
498
+ const migrated = content.replaceAll('"@dreamboard/cli/testing"', `"${relativeToTestingTypes}"`).replaceAll("'@dreamboard/cli/testing'", `'${relativeToTestingTypes}'`);
499
+ if (migrated !== content) {
500
+ await writeWorkspaceTextFile(projectRoot, projectPath, migrated);
501
+ }
502
+ }
503
+ }
504
+ function shouldRefreshGeneratedTestingTypes(existingContent) {
505
+ if (existingContent === null || existingContent.trim().length === 0) {
506
+ return true;
507
+ }
508
+ if (existingContent === TESTING_TYPES_STUB) {
509
+ return true;
510
+ }
511
+ return existingContent.startsWith(GENERATED_TESTING_TYPES_PREFIX);
512
+ }
513
+ async function inferInitialTestPlayerCount(projectRoot) {
514
+ if (!await workspacePathExists(projectRoot, "manifest.ts")) {
515
+ return 4;
516
+ }
517
+ try {
518
+ const manifest = await materializeManifest(projectRoot);
519
+ return manifest.players.optimalPlayers ?? manifest.players.minPlayers ?? 4;
520
+ } catch {
521
+ return 4;
522
+ }
523
+ }
524
+ async function collectScenarioFiles(rootDir) {
525
+ const files = [];
526
+ const stack = [rootDir];
527
+ while (stack.length > 0) {
528
+ const dir = stack.pop();
529
+ if (!dir) continue;
530
+ const entries = await readdir(dir, { withFileTypes: true });
531
+ for (const entry of entries) {
532
+ const fullPath = path.join(dir, entry.name);
533
+ if (entry.isDirectory()) {
534
+ stack.push(fullPath);
535
+ } else if (entry.isFile() && entry.name.endsWith(".ts")) {
536
+ files.push(fullPath);
537
+ }
538
+ }
539
+ }
540
+ return files;
541
+ }
542
+ function resolveStaticAssetRoot(importUrl = import.meta.url) {
543
+ const candidates = [
544
+ fileURLToPath(new URL("../../scaffold/assets/static/", importUrl)),
545
+ fileURLToPath(new URL("./scaffold/assets/static/", importUrl)),
546
+ fileURLToPath(new URL("../scaffold/assets/static/", importUrl))
547
+ ];
548
+ for (const candidate of candidates) {
549
+ if (existsSync(candidate)) {
550
+ return candidate;
551
+ }
552
+ }
553
+ throw new Error(
554
+ `Unable to locate CLI static scaffold assets. Checked: ${candidates.join(", ")}`
555
+ );
556
+ }
557
+ async function getStaticAssetEntries() {
558
+ const files = await walkFiles(STATIC_ASSET_ROOT);
559
+ const entries = [];
560
+ for (const filePath of files) {
561
+ const targetPath = normalizeOwnedProjectPath(
562
+ path.relative(STATIC_ASSET_ROOT, filePath).replaceAll(path.sep, "/")
563
+ );
564
+ if (targetPath === null) {
565
+ throw new Error(`Unsafe static scaffold asset path: ${filePath}`);
566
+ }
567
+ entries.push({
568
+ targetPath,
569
+ content: await readFile(filePath, "utf8")
570
+ });
571
+ }
572
+ entries.sort(
573
+ (left, right) => left.targetPath.localeCompare(right.targetPath)
574
+ );
575
+ return entries;
576
+ }
577
+ async function getDynamicStaticEntries(projectRoot, mode, options = {}) {
578
+ const entries = [
579
+ {
580
+ targetPath: "package.json",
581
+ content: await buildRootPackageJson(projectRoot, mode, options)
582
+ },
583
+ {
584
+ targetPath: "ui/package.json",
585
+ content: buildUiPackageJson()
586
+ }
587
+ ];
588
+ if (options.localMaintainerRegistry) {
589
+ entries.push({
590
+ targetPath: ".npmrc",
591
+ content: buildWorkspaceNpmrc(options.localMaintainerRegistry.registryUrl)
592
+ });
593
+ }
594
+ return entries;
595
+ }
596
+ async function getExpectedStaticEntries(projectRoot) {
597
+ const entries = [
598
+ ...(await getStaticAssetEntries()).filter(
599
+ (entry) => entry.targetPath !== ".npmrc"
600
+ ),
601
+ ...await getDynamicStaticEntries(projectRoot, "update")
602
+ ];
603
+ entries.sort(
604
+ (left, right) => left.targetPath.localeCompare(right.targetPath)
605
+ );
606
+ return entries;
607
+ }
608
+ async function walkFiles(rootDir) {
609
+ const files = [];
610
+ const stack = [rootDir];
611
+ while (stack.length > 0) {
612
+ const currentDir = stack.pop();
613
+ if (!currentDir) continue;
614
+ const entries = await readdir(currentDir, { withFileTypes: true });
615
+ for (const entry of entries) {
616
+ const fullPath = path.join(currentDir, entry.name);
617
+ if (entry.isDirectory()) {
618
+ stack.push(fullPath);
619
+ } else if (entry.isFile()) {
620
+ files.push(fullPath);
621
+ }
622
+ }
623
+ }
624
+ files.sort((left, right) => left.localeCompare(right));
625
+ return files;
626
+ }
627
+ async function buildRootPackageJson(projectRoot, mode, options) {
628
+ const sdkPackageRanges = {
629
+ ...SDK_DEPENDENCY_RANGES,
630
+ ...options.localMaintainerRegistry?.packages ?? {}
631
+ };
632
+ const existingPackageJson = mode === "update" && await workspacePathExists(projectRoot, "package.json") ? JSON.parse(
633
+ await readWorkspaceTextFile(projectRoot, "package.json")
634
+ ) : null;
635
+ const {
636
+ dreamboardFrameworkVersion: _legacyFrameworkVersion,
637
+ ...existingPackageJsonWithoutLegacyVersion
638
+ } = existingPackageJson ?? {};
639
+ const frameworkDependencies = {
640
+ "@dreamboard-games/sdk": sdkPackageRanges["@dreamboard-games/sdk"] ?? SDK_DEPENDENCY_RANGES["@dreamboard-games/sdk"],
641
+ ...SHARED_DEPENDENCIES,
642
+ ...ROOT_APP_DEPENDENCIES
643
+ };
644
+ const frameworkDevDependencies = {
645
+ ...SHARED_DEV_DEPENDENCIES,
646
+ ...DEV_HOST_DEPENDENCY_RANGES
647
+ };
648
+ const nextPackageJson = {
649
+ ...existingPackageJsonWithoutLegacyVersion,
650
+ private: true,
651
+ packageManager: AUTHORING_RELEASE_SET.packageManager,
652
+ scripts: {
653
+ ...existingPackageJson?.scripts ?? {},
654
+ ...FRAMEWORK_SCRIPTS
655
+ },
656
+ dependencies: {
657
+ ...existingPackageJson?.dependencies ?? {},
658
+ ...frameworkDependencies
659
+ },
660
+ devDependencies: {
661
+ ...existingPackageJson?.devDependencies ?? {},
662
+ ...frameworkDevDependencies
663
+ },
664
+ pnpm: mergePnpmConfig(existingPackageJson?.pnpm)
665
+ };
666
+ return `${JSON.stringify(nextPackageJson, null, 2)}
667
+ `;
668
+ }
669
+ function mergePnpmConfig(existingPnpm) {
670
+ const existingOverrides = existingPnpm?.overrides && typeof existingPnpm.overrides === "object" && !Array.isArray(existingPnpm.overrides) ? existingPnpm.overrides : {};
671
+ return {
672
+ ...existingPnpm ?? {},
673
+ overrides: {
674
+ ...existingOverrides,
675
+ ...FRAMEWORK_PNPM_OVERRIDES,
676
+ ...DREAMBOARD_PACKAGE_OVERRIDES
677
+ }
678
+ };
679
+ }
680
+ function buildWorkspaceNpmrc(registryUrl) {
681
+ return `@dreamboard-games:registry=${registryUrl}
682
+ `;
683
+ }
684
+ function buildUiPackageJson() {
685
+ return `${JSON.stringify(
686
+ {
687
+ private: true,
688
+ dependencies: SHARED_DEPENDENCIES,
689
+ devDependencies: SHARED_DEV_DEPENDENCIES
690
+ },
691
+ null,
692
+ 2
693
+ )}
694
+ `;
695
+ }
696
+ function normalizeImportPath(relativePath) {
697
+ const normalized = relativePath.replaceAll("\\", "/");
698
+ if (normalized.startsWith(".")) return normalized;
699
+ return `./${normalized}`;
700
+ }
701
+ function toWorkspaceProjectPath(projectRoot, filePath) {
702
+ const relativePath = path.relative(path.resolve(projectRoot), path.resolve(filePath)).replaceAll(path.sep, "/");
703
+ const projectPath = normalizeOwnedProjectPath(relativePath);
704
+ if (projectPath === null) {
705
+ throw new Error(`Unsafe project path: ${relativePath}`);
706
+ }
707
+ return projectPath;
708
+ }
709
+ function summarizePaths(paths) {
710
+ const maxShown = 5;
711
+ const shown = paths.slice(0, maxShown).join(", ");
712
+ if (paths.length <= maxShown) return shown;
713
+ return `${shown}, and ${paths.length - maxShown} more`;
714
+ }
715
+
716
+ export {
717
+ scaffoldStaticWorkspace,
718
+ assertCliStaticScaffoldComplete,
719
+ migrateLegacyScenarioImports,
720
+ resolveStaticAssetRoot
721
+ };
722
+ //# sourceMappingURL=chunk-22U6RMWO.mjs.map