dreamboard 0.1.21 → 0.1.23

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 (186) hide show
  1. package/dist/{chunk-EYYWGWTO.js → chunk-2RCUHMGL.js} +343 -1911
  2. package/dist/chunk-2RCUHMGL.js.map +1 -0
  3. package/dist/{chunk-MOVHYB6E.js → chunk-GN7232BY.js} +1025 -695
  4. package/dist/chunk-GN7232BY.js.map +1 -0
  5. package/dist/{chunk-BMYC6772.js → chunk-H3O43F5P.js} +9765 -3068
  6. package/dist/chunk-H3O43F5P.js.map +1 -0
  7. package/dist/dev-host/dev-api-proxy-plugin.ts +330 -0
  8. package/dist/dev-host/dev-diagnostics.ts +62 -0
  9. package/dist/dev-host/dev-fallback-stylesheet.ts +50 -0
  10. package/dist/dev-host/dev-host-controller.ts +686 -0
  11. package/dist/dev-host/dev-host-player-query.ts +17 -0
  12. package/dist/dev-host/dev-host-session-transport.ts +52 -0
  13. package/dist/dev-host/dev-host-storage.ts +56 -0
  14. package/dist/dev-host/dev-log-relay-plugin.ts +469 -0
  15. package/dist/dev-host/dev-runtime-config.ts +14 -0
  16. package/dist/dev-host/dev-runtime-platform.ts +419 -0
  17. package/dist/dev-host/dev-virtual-modules-plugin.ts +63 -0
  18. package/dist/dev-host/host-main.css +182 -0
  19. package/dist/dev-host/host-main.tsx +754 -0
  20. package/dist/dev-host/index.html +56 -0
  21. package/dist/dev-host/plugin-main.ts +55 -0
  22. package/dist/dev-host/plugin.html +24 -0
  23. package/dist/dev-host/start-dev-server.ts +138 -0
  24. package/dist/dev-host/virtual-modules.d.ts +27 -0
  25. package/dist/dist-FEPN3BDN.js +16543 -0
  26. package/dist/dist-FEPN3BDN.js.map +1 -0
  27. package/dist/{dist-WJRJNFLI.js → dist-FRURQI7Q.js} +4 -2
  28. package/dist/index.js +3 -3
  29. package/dist/internal.js +159 -124
  30. package/dist/internal.js.map +1 -1
  31. package/dist/runtime-packages/tailwind-config/shared-styles.css +146 -0
  32. package/dist/runtime-packages/ui/src/components/.gitkeep +0 -0
  33. package/dist/runtime-packages/ui/src/components/accordion.tsx +66 -0
  34. package/dist/runtime-packages/ui/src/components/ai-elements/actions.tsx +65 -0
  35. package/dist/runtime-packages/ui/src/components/ai-elements/artifact.tsx +147 -0
  36. package/dist/runtime-packages/ui/src/components/ai-elements/branch.tsx +215 -0
  37. package/dist/runtime-packages/ui/src/components/ai-elements/canvas.tsx +22 -0
  38. package/dist/runtime-packages/ui/src/components/ai-elements/chain-of-thought.tsx +228 -0
  39. package/dist/runtime-packages/ui/src/components/ai-elements/code-block.tsx +179 -0
  40. package/dist/runtime-packages/ui/src/components/ai-elements/confirmation.tsx +158 -0
  41. package/dist/runtime-packages/ui/src/components/ai-elements/connection.tsx +28 -0
  42. package/dist/runtime-packages/ui/src/components/ai-elements/context.tsx +408 -0
  43. package/dist/runtime-packages/ui/src/components/ai-elements/controls.tsx +18 -0
  44. package/dist/runtime-packages/ui/src/components/ai-elements/conversation.tsx +97 -0
  45. package/dist/runtime-packages/ui/src/components/ai-elements/edge.tsx +140 -0
  46. package/dist/runtime-packages/ui/src/components/ai-elements/image.tsx +24 -0
  47. package/dist/runtime-packages/ui/src/components/ai-elements/inline-citation.tsx +287 -0
  48. package/dist/runtime-packages/ui/src/components/ai-elements/loader.tsx +96 -0
  49. package/dist/runtime-packages/ui/src/components/ai-elements/message.tsx +463 -0
  50. package/dist/runtime-packages/ui/src/components/ai-elements/node.tsx +71 -0
  51. package/dist/runtime-packages/ui/src/components/ai-elements/open-in-chat.tsx +365 -0
  52. package/dist/runtime-packages/ui/src/components/ai-elements/panel.tsx +15 -0
  53. package/dist/runtime-packages/ui/src/components/ai-elements/plan.tsx +142 -0
  54. package/dist/runtime-packages/ui/src/components/ai-elements/prompt-input.tsx +1380 -0
  55. package/dist/runtime-packages/ui/src/components/ai-elements/queue.tsx +274 -0
  56. package/dist/runtime-packages/ui/src/components/ai-elements/reasoning.tsx +182 -0
  57. package/dist/runtime-packages/ui/src/components/ai-elements/response.tsx +22 -0
  58. package/dist/runtime-packages/ui/src/components/ai-elements/shimmer.tsx +64 -0
  59. package/dist/runtime-packages/ui/src/components/ai-elements/sources.tsx +77 -0
  60. package/dist/runtime-packages/ui/src/components/ai-elements/suggestion.tsx +53 -0
  61. package/dist/runtime-packages/ui/src/components/ai-elements/task.tsx +87 -0
  62. package/dist/runtime-packages/ui/src/components/ai-elements/tool.tsx +165 -0
  63. package/dist/runtime-packages/ui/src/components/ai-elements/toolbar.tsx +16 -0
  64. package/dist/runtime-packages/ui/src/components/ai-elements/web-preview.tsx +263 -0
  65. package/dist/runtime-packages/ui/src/components/alert-dialog.tsx +157 -0
  66. package/dist/runtime-packages/ui/src/components/alert.tsx +66 -0
  67. package/dist/runtime-packages/ui/src/components/avatar.tsx +53 -0
  68. package/dist/runtime-packages/ui/src/components/badge.tsx +46 -0
  69. package/dist/runtime-packages/ui/src/components/button-group.tsx +83 -0
  70. package/dist/runtime-packages/ui/src/components/button.tsx +65 -0
  71. package/dist/runtime-packages/ui/src/components/card.tsx +92 -0
  72. package/dist/runtime-packages/ui/src/components/carousel.tsx +241 -0
  73. package/dist/runtime-packages/ui/src/components/collapsible.tsx +33 -0
  74. package/dist/runtime-packages/ui/src/components/command.tsx +184 -0
  75. package/dist/runtime-packages/ui/src/components/context-menu.tsx +252 -0
  76. package/dist/runtime-packages/ui/src/components/counter.tsx +11 -0
  77. package/dist/runtime-packages/ui/src/components/dialog.tsx +146 -0
  78. package/dist/runtime-packages/ui/src/components/drawer.tsx +132 -0
  79. package/dist/runtime-packages/ui/src/components/dropdown-menu.tsx +257 -0
  80. package/dist/runtime-packages/ui/src/components/form.tsx +168 -0
  81. package/dist/runtime-packages/ui/src/components/header.tsx +13 -0
  82. package/dist/runtime-packages/ui/src/components/hover-card.tsx +44 -0
  83. package/dist/runtime-packages/ui/src/components/input-group.tsx +178 -0
  84. package/dist/runtime-packages/ui/src/components/input.tsx +21 -0
  85. package/dist/runtime-packages/ui/src/components/item.tsx +193 -0
  86. package/dist/runtime-packages/ui/src/components/label.tsx +24 -0
  87. package/dist/runtime-packages/ui/src/components/navigation-menu.tsx +168 -0
  88. package/dist/runtime-packages/ui/src/components/popover.tsx +55 -0
  89. package/dist/runtime-packages/ui/src/components/progress.tsx +31 -0
  90. package/dist/runtime-packages/ui/src/components/radio-group.tsx +45 -0
  91. package/dist/runtime-packages/ui/src/components/resizable.tsx +56 -0
  92. package/dist/runtime-packages/ui/src/components/scroll-area.tsx +58 -0
  93. package/dist/runtime-packages/ui/src/components/select.tsx +187 -0
  94. package/dist/runtime-packages/ui/src/components/separator.tsx +28 -0
  95. package/dist/runtime-packages/ui/src/components/skeleton.tsx +13 -0
  96. package/dist/runtime-packages/ui/src/components/sonner.tsx +25 -0
  97. package/dist/runtime-packages/ui/src/components/spinner.tsx +16 -0
  98. package/dist/runtime-packages/ui/src/components/switch.tsx +31 -0
  99. package/dist/runtime-packages/ui/src/components/table.tsx +137 -0
  100. package/dist/runtime-packages/ui/src/components/tabs.tsx +74 -0
  101. package/dist/runtime-packages/ui/src/components/textarea.tsx +23 -0
  102. package/dist/runtime-packages/ui/src/components/theme-provider.tsx +73 -0
  103. package/dist/runtime-packages/ui/src/components/tooltip.tsx +61 -0
  104. package/dist/runtime-packages/ui/src/components/ui/file-upload.tsx +195 -0
  105. package/dist/runtime-packages/ui/src/hooks/.gitkeep +0 -0
  106. package/dist/runtime-packages/ui/src/index.ts +68 -0
  107. package/dist/runtime-packages/ui/src/lib/utils.ts +6 -0
  108. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +68 -0
  109. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +359 -0
  110. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +274 -0
  111. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +214 -0
  112. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +135 -0
  113. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +5 -0
  114. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +194 -0
  115. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +1 -0
  116. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +1 -0
  117. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +162 -0
  118. package/dist/runtime-packages/ui-host-runtime/src/index.ts +2 -0
  119. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +11 -0
  120. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +253 -0
  121. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +195 -0
  122. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +138 -0
  123. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +159 -0
  124. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +524 -0
  125. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +12 -0
  126. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +122 -0
  127. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +26 -0
  128. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +477 -0
  129. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +209 -0
  130. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +112 -0
  131. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +318 -0
  132. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +211 -0
  133. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +814 -0
  134. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +334 -0
  135. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +180 -0
  136. package/dist/scaffold/assets/static/app/tsconfig.framework.json +3 -1
  137. package/dist/scaffold/assets/static/ui/tsconfig.framework.json +7 -19
  138. package/package.json +52 -17
  139. package/skills/dreamboard/SKILL.md +41 -75
  140. package/LICENSE +0 -89
  141. package/NOTICE +0 -1
  142. package/dist/chunk-BMYC6772.js.map +0 -1
  143. package/dist/chunk-EYYWGWTO.js.map +0 -1
  144. package/dist/chunk-MOVHYB6E.js.map +0 -1
  145. package/dist/scaffold/assets/static/ui/App.tsx +0 -22
  146. package/dist/src-CUL7EGGG.js +0 -634
  147. package/dist/src-CUL7EGGG.js.map +0 -1
  148. package/skills/dreamboard/references/authoring-lifecycle.md +0 -102
  149. package/skills/dreamboard/references/board-surfaces.md +0 -36
  150. package/skills/dreamboard/references/board-topology.md +0 -443
  151. package/skills/dreamboard/references/boards-and-topology.md +0 -100
  152. package/skills/dreamboard/references/card-actions.md +0 -107
  153. package/skills/dreamboard/references/cli.md +0 -120
  154. package/skills/dreamboard/references/core-concepts.md +0 -514
  155. package/skills/dreamboard/references/custom-renderers.md +0 -26
  156. package/skills/dreamboard/references/derived-values.md +0 -55
  157. package/skills/dreamboard/references/effects.md +0 -111
  158. package/skills/dreamboard/references/game-contract.md +0 -89
  159. package/skills/dreamboard/references/game-definition.md +0 -89
  160. package/skills/dreamboard/references/game-shell.md +0 -80
  161. package/skills/dreamboard/references/hand-surfaces.md +0 -33
  162. package/skills/dreamboard/references/index.md +0 -112
  163. package/skills/dreamboard/references/inputs-and-targets.md +0 -160
  164. package/skills/dreamboard/references/interactions.md +0 -158
  165. package/skills/dreamboard/references/manifest-fields.md +0 -137
  166. package/skills/dreamboard/references/manifest.md +0 -81
  167. package/skills/dreamboard/references/package-surfaces.md +0 -69
  168. package/skills/dreamboard/references/phases.md +0 -145
  169. package/skills/dreamboard/references/prompts-and-choices.md +0 -55
  170. package/skills/dreamboard/references/quickstart.md +0 -71
  171. package/skills/dreamboard/references/rule-authoring.md +0 -144
  172. package/skills/dreamboard/references/setup-bootstrap.md +0 -78
  173. package/skills/dreamboard/references/stages-and-zones.md +0 -59
  174. package/skills/dreamboard/references/static-views.md +0 -67
  175. package/skills/dreamboard/references/table-queries-and-ops.md +0 -103
  176. package/skills/dreamboard/references/testing-bases.md +0 -147
  177. package/skills/dreamboard/references/testing-generated-contracts.md +0 -142
  178. package/skills/dreamboard/references/testing-runtime-assertions.md +0 -124
  179. package/skills/dreamboard/references/testing-scenarios.md +0 -148
  180. package/skills/dreamboard/references/testing-ui-tests.md +0 -174
  181. package/skills/dreamboard/references/testing.md +0 -161
  182. package/skills/dreamboard/references/ui-architecture.md +0 -137
  183. package/skills/dreamboard/references/ui-components.md +0 -34
  184. package/skills/dreamboard/references/views.md +0 -72
  185. package/skills/dreamboard/references/workspace-layout.md +0 -136
  186. /package/dist/{dist-WJRJNFLI.js.map → dist-FRURQI7Q.js.map} +0 -0
@@ -32,7 +32,7 @@ import {
32
32
  } from "./chunk-4S67A2YA.js";
33
33
  import {
34
34
  createClient
35
- } from "./chunk-BMYC6772.js";
35
+ } from "./chunk-H3O43F5P.js";
36
36
  import {
37
37
  CLIENT_PROBLEM_TYPES,
38
38
  SERVER_PROBLEM_TYPES,
@@ -50,7 +50,6 @@ import {
50
50
  ensureDevCompile,
51
51
  external_exports,
52
52
  findManifests,
53
- gameIdFromGameSource,
54
53
  getApiVersion,
55
54
  getAuthoringHead,
56
55
  getCompiledResult,
@@ -69,15 +68,16 @@ import {
69
68
  startGame,
70
69
  submitPlayerAction,
71
70
  subscribeToSessionEvents,
71
+ uploadInitialProjection,
72
72
  validatePlayerAction,
73
73
  zGameTopologyManifest,
74
74
  zProblemDetails
75
- } from "./chunk-EYYWGWTO.js";
75
+ } from "./chunk-2RCUHMGL.js";
76
76
  import {
77
77
  __export
78
78
  } from "./chunk-D4HDZEJT.js";
79
79
 
80
- // ../../node_modules/.pnpm/citty@0.2.1/node_modules/citty/dist/_chunks/libs/scule.mjs
80
+ // ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/_chunks/libs/scule.mjs
81
81
  var NUMBER_CHAR_RE = /\d/;
82
82
  var STR_SPLITTERS = [
83
83
  "-",
@@ -142,8 +142,11 @@ function camelCase(str, opts) {
142
142
  function kebabCase(str, joiner) {
143
143
  return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => p.toLowerCase()).join(joiner ?? "-") : "";
144
144
  }
145
+ function snakeCase(str) {
146
+ return kebabCase(str || "", "_");
147
+ }
145
148
 
146
- // ../../node_modules/.pnpm/citty@0.2.1/node_modules/citty/dist/index.mjs
149
+ // ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/index.mjs
147
150
  import { parseArgs as parseArgs$1 } from "util";
148
151
  function toArray(val) {
149
152
  if (Array.isArray(val)) return val;
@@ -190,6 +193,12 @@ function parseRawArgs(args = [], opts = {}) {
190
193
  for (const alias of aliases) if (booleans.has(alias)) return "boolean";
191
194
  return "string";
192
195
  }
196
+ function isStringType(name) {
197
+ if (strings.has(name)) return true;
198
+ const aliases = mainToAliases.get(name) || [];
199
+ for (const alias of aliases) if (strings.has(alias)) return true;
200
+ return false;
201
+ }
193
202
  const allOptions = /* @__PURE__ */ new Set([
194
203
  ...booleans,
195
204
  ...strings,
@@ -233,7 +242,12 @@ function parseRawArgs(args = [], opts = {}) {
233
242
  }
234
243
  const out = { _: [] };
235
244
  out._ = parsed.positionals;
236
- for (const [key, value] of Object.entries(parsed.values)) out[key] = value;
245
+ for (const [key, value] of Object.entries(parsed.values)) {
246
+ let coerced = value;
247
+ if (getType(key) === "boolean" && typeof value === "string") coerced = value !== "false";
248
+ else if (isStringType(key) && typeof value === "boolean") coerced = "";
249
+ out[key] = coerced;
250
+ }
237
251
  for (const [name] of Object.entries(negatedFlags)) {
238
252
  out[name] = false;
239
253
  const mainName = aliasToMain.get(name);
@@ -244,6 +258,7 @@ function parseRawArgs(args = [], opts = {}) {
244
258
  for (const [alias, main] of aliasToMain.entries()) {
245
259
  if (out[alias] !== void 0 && out[main] === void 0) out[main] = out[alias];
246
260
  if (out[main] !== void 0 && out[alias] === void 0) out[alias] = out[main];
261
+ if (out[alias] !== out[main] && defaults[main] === out[main]) out[main] = out[alias];
247
262
  }
248
263
  return out;
249
264
  }
@@ -305,6 +320,9 @@ function resolveArgs(argsDef) {
305
320
  });
306
321
  return args;
307
322
  }
323
+ async function resolvePlugins(plugins) {
324
+ return Promise.all(plugins.map((p) => resolveValue(p)));
325
+ }
308
326
  function defineCommand(def) {
309
327
  return def;
310
328
  }
@@ -317,35 +335,92 @@ async function runCommand(cmd, opts) {
317
335
  data: opts.data,
318
336
  cmd
319
337
  };
320
- if (typeof cmd.setup === "function") await cmd.setup(context);
338
+ const plugins = await resolvePlugins(cmd.plugins ?? []);
321
339
  let result;
340
+ let runError;
322
341
  try {
342
+ for (const plugin of plugins) await plugin.setup?.(context);
343
+ if (typeof cmd.setup === "function") await cmd.setup(context);
323
344
  const subCommands = await resolveValue(cmd.subCommands);
324
345
  if (subCommands && Object.keys(subCommands).length > 0) {
325
- const subCommandArgIndex = opts.rawArgs.findIndex((arg) => !arg.startsWith("-"));
326
- const subCommandName = opts.rawArgs[subCommandArgIndex];
327
- if (subCommandName) {
328
- if (!subCommands[subCommandName]) throw new CLIError(`Unknown command ${cyan(subCommandName)}`, "E_UNKNOWN_COMMAND");
329
- const subCommand = await resolveValue(subCommands[subCommandName]);
330
- if (subCommand) await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
331
- } else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
346
+ const subCommandArgIndex = findSubCommandIndex(opts.rawArgs, cmdArgs);
347
+ const explicitName = opts.rawArgs[subCommandArgIndex];
348
+ if (explicitName) {
349
+ const subCommand = await _findSubCommand(subCommands, explicitName);
350
+ if (!subCommand) throw new CLIError(`Unknown command ${cyan(explicitName)}`, "E_UNKNOWN_COMMAND");
351
+ await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
352
+ } else {
353
+ const defaultSubCommand = await resolveValue(cmd.default);
354
+ if (defaultSubCommand) {
355
+ if (cmd.run) throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
356
+ const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
357
+ if (!subCommand) throw new CLIError(`Default sub command ${cyan(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
358
+ await runCommand(subCommand, { rawArgs: opts.rawArgs });
359
+ } else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
360
+ }
332
361
  }
333
362
  if (typeof cmd.run === "function") result = await cmd.run(context);
334
- } finally {
335
- if (typeof cmd.cleanup === "function") await cmd.cleanup(context);
363
+ } catch (error) {
364
+ runError = error;
365
+ }
366
+ const cleanupErrors = [];
367
+ if (typeof cmd.cleanup === "function") try {
368
+ await cmd.cleanup(context);
369
+ } catch (error) {
370
+ cleanupErrors.push(error);
336
371
  }
372
+ for (const plugin of [...plugins].reverse()) try {
373
+ await plugin.cleanup?.(context);
374
+ } catch (error) {
375
+ cleanupErrors.push(error);
376
+ }
377
+ if (runError) throw runError;
378
+ if (cleanupErrors.length === 1) throw cleanupErrors[0];
379
+ if (cleanupErrors.length > 1) throw new Error("Multiple cleanup errors", { cause: cleanupErrors });
337
380
  return { result };
338
381
  }
339
382
  async function resolveSubCommand(cmd, rawArgs, parent) {
340
383
  const subCommands = await resolveValue(cmd.subCommands);
341
384
  if (subCommands && Object.keys(subCommands).length > 0) {
342
- const subCommandArgIndex = rawArgs.findIndex((arg) => !arg.startsWith("-"));
385
+ const subCommandArgIndex = findSubCommandIndex(rawArgs, await resolveValue(cmd.args || {}));
343
386
  const subCommandName = rawArgs[subCommandArgIndex];
344
- const subCommand = await resolveValue(subCommands[subCommandName]);
387
+ const subCommand = await _findSubCommand(subCommands, subCommandName);
345
388
  if (subCommand) return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
346
389
  }
347
390
  return [cmd, parent];
348
391
  }
392
+ async function _findSubCommand(subCommands, name) {
393
+ if (name in subCommands) return resolveValue(subCommands[name]);
394
+ for (const sub of Object.values(subCommands)) {
395
+ const resolved = await resolveValue(sub);
396
+ const meta = await resolveValue(resolved?.meta);
397
+ if (meta?.alias) {
398
+ if (toArray(meta.alias).includes(name)) return resolved;
399
+ }
400
+ }
401
+ }
402
+ function findSubCommandIndex(rawArgs, argsDef) {
403
+ for (let i2 = 0; i2 < rawArgs.length; i2++) {
404
+ const arg = rawArgs[i2];
405
+ if (arg === "--") return -1;
406
+ if (arg.startsWith("-")) {
407
+ if (!arg.includes("=") && _isValueFlag(arg, argsDef)) i2++;
408
+ continue;
409
+ }
410
+ return i2;
411
+ }
412
+ return -1;
413
+ }
414
+ function _isValueFlag(flag, argsDef) {
415
+ const name = flag.replace(/^-{1,2}/, "");
416
+ const normalized = camelCase(name);
417
+ for (const [key, def] of Object.entries(argsDef)) {
418
+ if (def.type !== "string" && def.type !== "enum") continue;
419
+ if (normalized === camelCase(key)) return true;
420
+ if ((Array.isArray(def.alias) ? def.alias : def.alias ? [def.alias] : []).includes(name)) return true;
421
+ }
422
+ return false;
423
+ }
349
424
  async function showUsage(cmd, parent) {
350
425
  try {
351
426
  console.log(await renderUsage(cmd, parent) + "\n");
@@ -366,22 +441,17 @@ async function renderUsage(cmd, parent) {
366
441
  for (const arg of cmdArgs) if (arg.type === "positional") {
367
442
  const name = arg.name.toUpperCase();
368
443
  const isRequired = arg.required !== false && arg.default === void 0;
369
- const defaultHint = arg.default ? `="${arg.default}"` : "";
370
- posLines.push([
371
- cyan(name + defaultHint),
372
- arg.description || "",
373
- arg.valueHint ? `<${arg.valueHint}>` : ""
374
- ]);
444
+ posLines.push([cyan(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
375
445
  usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
376
446
  } else {
377
447
  const isRequired = arg.required === true && arg.default === void 0;
378
- const argStr = [...(arg.alias || []).map((a2) => `-${a2}`), `--${arg.name}`].join(", ") + (arg.type === "string" && (arg.valueHint || arg.default) ? `=${arg.valueHint ? `<${arg.valueHint}>` : `"${arg.default || ""}"`}` : "") + (arg.type === "enum" && arg.options ? `=<${arg.options.join("|")}>` : "");
379
- argLines.push([cyan(argStr + (isRequired ? " (required)" : "")), arg.description || ""]);
448
+ const argStr = [...(arg.alias || []).map((a2) => `-${a2}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
449
+ argLines.push([cyan(argStr), renderDescription(arg, isRequired)]);
380
450
  if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
381
451
  const negativeArgStr = [...(arg.alias || []).map((a2) => `--no-${a2}`), `--no-${arg.name}`].join(", ");
382
- argLines.push([cyan(negativeArgStr + (isRequired ? " (required)" : "")), arg.negativeDescription || ""]);
452
+ argLines.push([cyan(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
383
453
  }
384
- if (isRequired) usageLine.push(argStr);
454
+ if (isRequired) usageLine.push(`--${arg.name}` + renderValueHint(arg));
385
455
  }
386
456
  if (cmd.subCommands) {
387
457
  const commandNames = [];
@@ -389,8 +459,10 @@ async function renderUsage(cmd, parent) {
389
459
  for (const [name, sub] of Object.entries(subCommands)) {
390
460
  const meta = await resolveValue((await resolveValue(sub))?.meta);
391
461
  if (meta?.hidden) continue;
392
- commandsLines.push([cyan(name), meta?.description || ""]);
393
- commandNames.push(name);
462
+ const aliases = toArray(meta?.alias);
463
+ const label = [name, ...aliases].join(", ");
464
+ commandsLines.push([cyan(label), meta?.description || ""]);
465
+ commandNames.push(name, ...aliases);
394
466
  }
395
467
  usageLine.push(commandNames.join("|"));
396
468
  }
@@ -416,14 +488,31 @@ async function renderUsage(cmd, parent) {
416
488
  }
417
489
  return usageLines.filter((l2) => typeof l2 === "string").join("\n");
418
490
  }
491
+ function renderValueHint(arg) {
492
+ const valueHint = arg.valueHint ? `=<${arg.valueHint}>` : "";
493
+ const fallbackValueHint = valueHint || `=<${snakeCase(arg.name)}>`;
494
+ if (!arg.type || arg.type === "positional" || arg.type === "boolean") return valueHint;
495
+ if (arg.type === "enum" && arg.options?.length) return `=<${arg.options.join("|")}>`;
496
+ return fallbackValueHint;
497
+ }
498
+ function renderDescription(arg, required) {
499
+ const requiredHint = required ? gray("(Required)") : "";
500
+ const defaultHint = arg.default === void 0 ? "" : gray(`(Default: ${arg.default})`);
501
+ return [
502
+ arg.description,
503
+ requiredHint,
504
+ defaultHint
505
+ ].filter(Boolean).join(" ");
506
+ }
419
507
  async function runMain(cmd, opts = {}) {
420
508
  const rawArgs = opts.rawArgs || process.argv.slice(2);
421
509
  const showUsage$1 = opts.showUsage || showUsage;
422
510
  try {
423
- if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
511
+ const builtinFlags = await _resolveBuiltinFlags(cmd);
512
+ if (builtinFlags.help.length > 0 && rawArgs.some((arg) => builtinFlags.help.includes(arg))) {
424
513
  await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
425
514
  process.exit(0);
426
- } else if (rawArgs.length === 1 && rawArgs[0] === "--version") {
515
+ } else if (rawArgs.length === 1 && builtinFlags.version.includes(rawArgs[0])) {
427
516
  const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
428
517
  if (!meta?.version) throw new CLIError("No version specified", "E_NO_VERSION");
429
518
  console.log(meta.version);
@@ -436,6 +525,24 @@ async function runMain(cmd, opts = {}) {
436
525
  process.exit(1);
437
526
  }
438
527
  }
528
+ async function _resolveBuiltinFlags(cmd) {
529
+ const argsDef = await resolveValue(cmd.args || {});
530
+ const userNames = /* @__PURE__ */ new Set();
531
+ const userAliases = /* @__PURE__ */ new Set();
532
+ for (const [name, def] of Object.entries(argsDef)) {
533
+ userNames.add(name);
534
+ for (const alias of toArray(def.alias)) userAliases.add(alias);
535
+ }
536
+ return {
537
+ help: _getBuiltinFlags("help", "h", userNames, userAliases),
538
+ version: _getBuiltinFlags("version", "v", userNames, userAliases)
539
+ };
540
+ }
541
+ function _getBuiltinFlags(long, short, userNames, userAliases) {
542
+ if (userNames.has(long) || userAliases.has(long)) return [];
543
+ if (userNames.has(short) || userAliases.has(short)) return [`--${long}`];
544
+ return [`--${long}`, `-${short}`];
545
+ }
439
546
 
440
547
  // ../../node_modules/.pnpm/consola@3.4.2/node_modules/consola/dist/core.mjs
441
548
  var LogLevels = {
@@ -1758,10 +1865,11 @@ function resolveConfig(globalConfig, flags, project, credentials) {
1758
1865
  if (IS_PUBLISHED_BUILD) {
1759
1866
  assertPublicRuntimeFlags(flags);
1760
1867
  }
1761
- const environment = IS_PUBLISHED_BUILD ? PUBLISHED_ENVIRONMENT : flags.env || globalConfig.environment || "dev";
1868
+ const envEnvironment = IS_PUBLISHED_BUILD ? void 0 : environmentFromProcess();
1869
+ const environment = IS_PUBLISHED_BUILD ? PUBLISHED_ENVIRONMENT : flags.env || envEnvironment || globalConfig.environment || "dev";
1762
1870
  const envConfig = ENVIRONMENT_CONFIGS[environment];
1763
1871
  const publishedEnvConfig = ENVIRONMENT_CONFIGS[PUBLISHED_ENVIRONMENT];
1764
- const hasExplicitEnvironmentOverride = !IS_PUBLISHED_BUILD && Boolean(flags.env);
1872
+ const hasExplicitEnvironmentOverride = !IS_PUBLISHED_BUILD && Boolean(flags.env || envEnvironment);
1765
1873
  const resolvedApiBaseUrl = IS_PUBLISHED_BUILD ? publishedEnvConfig?.apiBaseUrl ?? DEFAULT_API_BASE_URL : hasExplicitEnvironmentOverride ? envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL : project?.apiBaseUrl || envConfig?.apiBaseUrl || DEFAULT_API_BASE_URL;
1766
1874
  const apiBaseUrl = valueOrUndefined(process.env.DREAMBOARD_API_BASE_URL) ?? resolvedApiBaseUrl;
1767
1875
  const resolvedWebBaseUrl = IS_PUBLISHED_BUILD ? publishedEnvConfig?.webBaseUrl ?? DEFAULT_WEB_BASE_URL : hasExplicitEnvironmentOverride ? envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL : project?.webBaseUrl || envConfig?.webBaseUrl || DEFAULT_WEB_BASE_URL;
@@ -1815,6 +1923,16 @@ function buildCredentialSnapshot(flags, storedCredentials) {
1815
1923
  refreshTokenSource
1816
1924
  };
1817
1925
  }
1926
+ function environmentFromProcess() {
1927
+ const value = valueOrUndefined(process.env.DREAMBOARD_ENV);
1928
+ if (!value) return void 0;
1929
+ if (value === "local" || value === "dev" || value === "prod") {
1930
+ return value;
1931
+ }
1932
+ throw new Error(
1933
+ `Invalid DREAMBOARD_ENV '${value}'. Valid options: local, dev, prod`
1934
+ );
1935
+ }
1818
1936
  function assertPublicRuntimeFlags(flags) {
1819
1937
  const argv2 = process.argv.slice(2);
1820
1938
  if (flags.env || argv2.includes("--env")) {
@@ -1993,7 +2111,9 @@ var devCommandArgsSchema = configFlagsSchema.extend({
1993
2111
  "from-scenario": external_exports.string().optional(),
1994
2112
  "new-session": external_exports.boolean().default(false),
1995
2113
  open: external_exports.boolean().default(false),
1996
- port: external_exports.string().optional()
2114
+ port: external_exports.string().optional(),
2115
+ host: external_exports.union([external_exports.string(), external_exports.boolean()]).optional(),
2116
+ "allowed-host": external_exports.string().optional()
1997
2117
  });
1998
2118
  var joinCommandArgsSchema = configFlagsSchema.extend({
1999
2119
  session: external_exports.string().min(1).optional(),
@@ -2571,6 +2691,21 @@ async function saveRuleSdk(gameId, ruleText) {
2571
2691
  return { ruleId: data.ruleId };
2572
2692
  }
2573
2693
 
2694
+ // src/services/api/preview-api.ts
2695
+ async function uploadInitialProjectionSdk(gameId, projectionJson) {
2696
+ const { error, response } = await uploadInitialProjection({
2697
+ path: { gameId },
2698
+ body: { projectionJson }
2699
+ });
2700
+ if (error) {
2701
+ throw toDreamboardApiError(
2702
+ error,
2703
+ response,
2704
+ "Failed to upload initial preview projection"
2705
+ );
2706
+ }
2707
+ }
2708
+
2574
2709
  // ../../packages/api-client/src/source-revisions.ts
2575
2710
  var textEncoder = new TextEncoder();
2576
2711
  function bytesToHex(bytes) {
@@ -8589,7 +8724,7 @@ function validateSlotHostsAndHomes(manifest) {
8589
8724
  }
8590
8725
  slotIdsByHostKey.set(`die:${seed.id}`, new Set(slotIds));
8591
8726
  }
8592
- const validateHome = (home, path26) => {
8727
+ const validateHome = (home, path28) => {
8593
8728
  if (home?.type !== "slot") {
8594
8729
  return;
8595
8730
  }
@@ -8597,13 +8732,13 @@ function validateSlotHostsAndHomes(manifest) {
8597
8732
  const slotIds = slotIdsByHostKey.get(hostKey);
8598
8733
  if (!slotIds) {
8599
8734
  issues.push(
8600
- `${path26}.host: Unknown strict slot host '${home.host.kind}:${home.host.id}'. Hosts must be singleton piece/die seeds whose type declares slots.`
8735
+ `${path28}.host: Unknown strict slot host '${home.host.kind}:${home.host.id}'. Hosts must be singleton piece/die seeds whose type declares slots.`
8601
8736
  );
8602
8737
  return;
8603
8738
  }
8604
8739
  if (!slotIds.has(home.slotId)) {
8605
8740
  issues.push(
8606
- `${path26}.slotId: Unknown slot '${home.slotId}' for host '${home.host.kind}:${home.host.id}'.`
8741
+ `${path28}.slotId: Unknown slot '${home.slotId}' for host '${home.host.kind}:${home.host.id}'.`
8607
8742
  );
8608
8743
  }
8609
8744
  };
@@ -8669,20 +8804,20 @@ function validatePlayerScopedSeedHomes(manifest) {
8669
8804
  const zoneScopeById = new Map(
8670
8805
  (manifest.zones ?? []).map((zone) => [zone.id, zone.scope])
8671
8806
  );
8672
- const validateSeedHome = (seed, path26, label) => {
8807
+ const validateSeedHome = (seed, path28, label) => {
8673
8808
  const authoredId = seed.id ?? seed.typeId;
8674
8809
  if (seed.ownerId) {
8675
8810
  return;
8676
8811
  }
8677
8812
  if (homeTargetsBoard(seed.home) && boardScopeById.get(seed.home.boardId) === "perPlayer") {
8678
8813
  issues.push(
8679
- `${path26}.boardId: ${label} '${authoredId}' requires ownerId because board '${seed.home.boardId}' has scope 'perPlayer'. Add ownerId to resolve the player-scoped destination.`
8814
+ `${path28}.boardId: ${label} '${authoredId}' requires ownerId because board '${seed.home.boardId}' has scope 'perPlayer'. Add ownerId to resolve the player-scoped destination.`
8680
8815
  );
8681
8816
  return;
8682
8817
  }
8683
8818
  if (seed.home?.type === "zone" && zoneScopeById.get(seed.home.zoneId) === "perPlayer") {
8684
8819
  issues.push(
8685
- `${path26}.zoneId: ${label} '${authoredId}' requires ownerId because zone '${seed.home.zoneId}' has scope 'perPlayer'. Add ownerId to resolve the player-scoped destination.`
8820
+ `${path28}.zoneId: ${label} '${authoredId}' requires ownerId because zone '${seed.home.zoneId}' has scope 'perPlayer'. Add ownerId to resolve the player-scoped destination.`
8686
8821
  );
8687
8822
  }
8688
8823
  };
@@ -9158,30 +9293,30 @@ function normalizeProjectPath(filePath) {
9158
9293
  return filePath.replace(/^\.\//, "").replace(/^\/+/, "").replace(/\\/g, "/");
9159
9294
  }
9160
9295
  function isAllowedGamePath(filePath) {
9161
- const path26 = normalizeProjectPath(filePath);
9162
- if (WORKSPACE_CODEGEN_OWNERSHIP.allowedPaths.rootFiles.includes(path26)) {
9296
+ const path28 = normalizeProjectPath(filePath);
9297
+ if (WORKSPACE_CODEGEN_OWNERSHIP.allowedPaths.rootFiles.includes(path28)) {
9163
9298
  return true;
9164
9299
  }
9165
9300
  return WORKSPACE_CODEGEN_OWNERSHIP.allowedPaths.directoryPrefixes.some(
9166
- (prefix) => path26.startsWith(prefix)
9301
+ (prefix) => path28.startsWith(prefix)
9167
9302
  );
9168
9303
  }
9169
9304
  function isAuthoritativeGeneratedPath(filePath) {
9170
- const path26 = normalizeProjectPath(filePath);
9171
- return WORKSPACE_CODEGEN_OWNERSHIP.dynamic.generatedFiles.includes(path26);
9305
+ const path28 = normalizeProjectPath(filePath);
9306
+ return WORKSPACE_CODEGEN_OWNERSHIP.dynamic.generatedFiles.includes(path28);
9172
9307
  }
9173
9308
  function isDynamicSeedPath(filePath) {
9174
- const path26 = normalizeProjectPath(filePath);
9175
- if (WORKSPACE_CODEGEN_OWNERSHIP.dynamic.seedFiles.includes(path26)) {
9309
+ const path28 = normalizeProjectPath(filePath);
9310
+ if (WORKSPACE_CODEGEN_OWNERSHIP.dynamic.seedFiles.includes(path28)) {
9176
9311
  return true;
9177
9312
  }
9178
9313
  return WORKSPACE_CODEGEN_OWNERSHIP.dynamic.seedFilePatterns.some(
9179
- (pattern) => path26.startsWith(pattern.prefix) && path26.endsWith(pattern.suffix)
9314
+ (pattern) => path28.startsWith(pattern.prefix) && path28.endsWith(pattern.suffix)
9180
9315
  );
9181
9316
  }
9182
9317
  function isLibraryPath(filePath) {
9183
- const path26 = normalizeProjectPath(filePath);
9184
- return isAuthoritativeGeneratedPath(path26);
9318
+ const path28 = normalizeProjectPath(filePath);
9319
+ return isAuthoritativeGeneratedPath(path28);
9185
9320
  }
9186
9321
 
9187
9322
  // ../../packages/workspace-codegen/src/seeds.ts
@@ -9209,11 +9344,14 @@ import type {
9209
9344
  import {
9210
9345
  createDreamboardUI,
9211
9346
  createResourceCounter,
9347
+ InteractionField as InteractionFieldGeneric,
9212
9348
  type BoardHexGridProps as BoardHexGridPropsGeneric,
9213
9349
  type BoardHexViewProps as BoardHexViewPropsGeneric,
9214
9350
  type BoardSpaceIdOf,
9215
9351
  type ClientParamSchemaMap,
9216
9352
  type InteractionDescriptor,
9353
+ type InteractionFieldProps as InteractionFieldPropsGeneric,
9354
+ type InteractionFieldRenderMap,
9217
9355
  type InteractionHandle,
9218
9356
  type InteractionRouteMap as InteractionRouteMapGeneric,
9219
9357
  type InteractionSwitchProps as InteractionSwitchPropsGeneric,
@@ -9653,15 +9791,43 @@ export const Phase = UI.Phase;
9653
9791
  export const Zone = UI.Zone;
9654
9792
  export const ResourceCounter: WorkspaceUI["ResourceCounter"] = UI.ResourceCounter;
9655
9793
 
9794
+ export type InteractionFieldRenderers<Key extends InteractionKey> =
9795
+ InteractionFieldRenderMap<InteractionParamsShape<Key>>;
9796
+
9797
+ export type InteractionFieldProps<
9798
+ Key extends InteractionKey,
9799
+ InputKey extends keyof InteractionParamsShape<Key> & string,
9800
+ > = Omit<
9801
+ InteractionFieldPropsGeneric<InteractionParamsShape<Key>, InputKey>,
9802
+ "descriptor" | "handle"
9803
+ > & {
9804
+ descriptor: InteractionDescriptorFor<Key>;
9805
+ handle: InteractionHandle<
9806
+ InteractionParamsShape<Key>,
9807
+ InteractionHandleDefaultedKeys<Key>
9808
+ >;
9809
+ };
9810
+
9656
9811
  export const clientParamSchemasByPhase = createClientParamSchemasByPhase(
9657
9812
  game,
9658
9813
  ) as ClientParamSchemaMap;
9814
+
9815
+ export function InteractionField<
9816
+ Key extends InteractionKey,
9817
+ InputKey extends keyof InteractionParamsShape<Key> & string,
9818
+ >(props: InteractionFieldProps<Key, InputKey>): ReactElement | null {
9819
+ return createElement(
9820
+ InteractionFieldGeneric<InteractionParamsShape<Key>, InputKey>,
9821
+ props,
9822
+ );
9823
+ }
9659
9824
  `;
9660
9825
  }
9661
9826
  function generateReducerSupportSeed() {
9662
9827
  return `import {
9663
- createReducerEdit,
9828
+ createReducerOps,
9664
9829
  createStateQueries,
9830
+ pipe,
9665
9831
  } from "@dreamboard/app-sdk/reducer";
9666
9832
  import type { GameState } from "./game-contract";
9667
9833
 
@@ -9680,12 +9846,16 @@ import type { GameState } from "./game-contract";
9680
9846
  *
9681
9847
  * Recommended authoring pattern inside a phase reducer:
9682
9848
  *
9683
- * const tx = edit(state);
9684
- * tx.setActivePlayers([q.players.order()[0]]);
9685
- * return accept(tx.state);
9849
+ * const next = pipe(
9850
+ * state,
9851
+ * ops.setActivePlayers([q.players.order()[0]]),
9852
+ * );
9853
+ * return accept(next);
9686
9854
  */
9687
9855
 
9688
- export const edit = createReducerEdit<GameState>();
9856
+ export const ops = createReducerOps<GameState>();
9857
+
9858
+ export { pipe };
9689
9859
 
9690
9860
  export function stateQueries(state: GameState) {
9691
9861
  return createStateQueries(state);
@@ -10139,9 +10309,13 @@ function resolveRepoLocalPackageSource(specifier, options) {
10139
10309
  if (!parsedSpecifier) {
10140
10310
  return null;
10141
10311
  }
10142
- const packageInfo = readPackageInfos(normalizeRepoRoot(options)).get(
10143
- parsedSpecifier.packageName
10144
- );
10312
+ let repoRoot;
10313
+ try {
10314
+ repoRoot = normalizeRepoRoot(options);
10315
+ } catch {
10316
+ return null;
10317
+ }
10318
+ const packageInfo = readPackageInfos(repoRoot).get(parsedSpecifier.packageName);
10145
10319
  if (!packageInfo) {
10146
10320
  return null;
10147
10321
  }
@@ -10237,7 +10411,7 @@ async function evaluateManifestSource(projectRoot) {
10237
10411
  target: ["node20"],
10238
10412
  write: false,
10239
10413
  logLevel: "silent",
10240
- plugins: repoLocalPackageResolutionPlugins()
10414
+ plugins: [createRepoLocalPackageResolutionPlugin()]
10241
10415
  });
10242
10416
  outputText = buildResult.outputFiles[0]?.text;
10243
10417
  } catch (error) {
@@ -10272,14 +10446,6 @@ async function evaluateManifestSource(projectRoot) {
10272
10446
  }
10273
10447
  return moduleRecord.default;
10274
10448
  }
10275
- function repoLocalPackageResolutionPlugins() {
10276
- try {
10277
- const repoRoot = resolveCliRepoRoot(import.meta.url);
10278
- return [createRepoLocalPackageResolutionPlugin({ repoRoot })];
10279
- } catch {
10280
- return [];
10281
- }
10282
- }
10283
10449
  function renderManifestSource(manifest) {
10284
10450
  return [
10285
10451
  'import { defineTopologyManifest } from "@dreamboard/sdk-types";',
@@ -10441,6 +10607,7 @@ var REDUCER_TESTING_TYPES_WRAPPER_CONTENT = `// Generated by dreamboard \u2014 d
10441
10607
  import game from "../app/game";
10442
10608
  import { createReducerBundle } from "@dreamboard/app-sdk/reducer";
10443
10609
  import { createTestRuntime as createDreamboardTestRuntime } from "@dreamboard/testing";
10610
+ import type { CreateTestRuntimeOptions } from "@dreamboard/testing";
10444
10611
  import { literals } from "../shared/manifest-contract";
10445
10612
  import type { PhaseName } from "../shared/generated/ui-contract";
10446
10613
  import { BASE_STATES } from "./generated/base-states.generated";
@@ -10484,17 +10651,17 @@ export function createTestRuntime(options: {
10484
10651
  controllingPlayerId?: (typeof literals.playerIds)[number];
10485
10652
  userId?: string | null;
10486
10653
  }) {
10487
- const reducerBundle = createReducerBundle(game);
10654
+ const reducerBundle =
10655
+ createReducerBundle(game) satisfies CreateTestRuntimeOptions["bundle"];
10656
+ const baseStates =
10657
+ BASE_STATES satisfies CreateTestRuntimeOptions["baseStates"];
10488
10658
  const runtime = createDreamboardTestRuntime({
10489
10659
  baseId: options.baseId,
10490
- baseStates:
10491
- BASE_STATES as unknown as Parameters<
10492
- typeof createDreamboardTestRuntime
10493
- >[0]["baseStates"],
10494
- bundle: reducerBundle as never,
10660
+ baseStates,
10661
+ bundle: reducerBundle,
10495
10662
  phase: options.phase,
10496
10663
  userId: options.userId ?? "test-user",
10497
- playerIds: (literals.playerIds as readonly string[]).slice(
10664
+ playerIds: literals.playerIds.slice(
10498
10665
  0,
10499
10666
  BASE_STATES[options.baseId]?.fingerprint.players ?? literals.playerIds.length,
10500
10667
  ),
@@ -10589,6 +10756,13 @@ export interface BrowserRunnerDriver {
10589
10756
 
10590
10757
  export interface ScenarioGameApi {
10591
10758
  start(): Promise<void>;
10759
+ /**
10760
+ * Patch the reducer snapshot for deterministic setup-heavy scenarios.
10761
+ * This is limited to reducer snapshot materialization and is rejected by
10762
+ * live replay/browser runners so authored gameplay verification still
10763
+ * submits real interactions.
10764
+ */
10765
+ patchState(mutator: (state: Record<string, unknown>) => void): Promise<void>;
10592
10766
  /**
10593
10767
  * Submit a player interaction (action-kind or prompt-kind) to the game.
10594
10768
  * The \`interactionId\` matches an \`InteractionId\` from the generated
@@ -10674,6 +10848,18 @@ export type {
10674
10848
  `;
10675
10849
  }
10676
10850
 
10851
+ // src/services/project/framework-dependencies.ts
10852
+ var FRAMEWORK_REACT_VERSION = "19.2.6";
10853
+ var FRAMEWORK_ZOD_VERSION = "4.4.3";
10854
+ var FRAMEWORK_REACT_DEPENDENCIES = {
10855
+ react: FRAMEWORK_REACT_VERSION,
10856
+ "react-dom": FRAMEWORK_REACT_VERSION
10857
+ };
10858
+ var FRAMEWORK_PNPM_OVERRIDES = {
10859
+ ...FRAMEWORK_REACT_DEPENDENCIES,
10860
+ zod: FRAMEWORK_ZOD_VERSION
10861
+ };
10862
+
10677
10863
  // src/services/project/static-scaffold.ts
10678
10864
  var DREAMBOARD_SYNC_COMMAND = "dreamboard sync";
10679
10865
  var TESTING_TYPES_STUB = "export function defineScenario(scenario) { return scenario; }\n";
@@ -10734,14 +10920,10 @@ var FRAMEWORK_SCRIPTS = {
10734
10920
  "typecheck:ui": "tsc --noEmit -p ui/tsconfig.json"
10735
10921
  };
10736
10922
  var SHARED_DEPENDENCIES = {
10737
- react: "^19.2.0",
10738
- "react-dom": "^19.2.0"
10923
+ ...FRAMEWORK_REACT_DEPENDENCIES
10739
10924
  };
10740
10925
  var ROOT_APP_DEPENDENCIES = {
10741
- zod: "4.4.3"
10742
- };
10743
- var FRAMEWORK_PNPM_OVERRIDES = {
10744
- zod: "4.4.3"
10926
+ zod: FRAMEWORK_ZOD_VERSION
10745
10927
  };
10746
10928
  var SHARED_DEV_DEPENDENCIES = {
10747
10929
  typescript: "^5.9.2",
@@ -11272,13 +11454,6 @@ function readPackagedSdkDependencyRange(packageName, importMetaUrl = import.meta
11272
11454
  return packagedRange.trim();
11273
11455
  }
11274
11456
  function resolveSdkDependencyRange(packageName, importMetaUrl = import.meta.url) {
11275
- const packagedRange = readPackagedSdkDependencyRange(
11276
- packageName,
11277
- importMetaUrl
11278
- );
11279
- if (packagedRange) {
11280
- return packagedRange;
11281
- }
11282
11457
  try {
11283
11458
  const repoRoot = resolveCliRepoRoot(importMetaUrl);
11284
11459
  const packageJsonPath = path7.join(
@@ -11291,6 +11466,13 @@ function resolveSdkDependencyRange(packageName, importMetaUrl = import.meta.url)
11291
11466
  }
11292
11467
  } catch {
11293
11468
  }
11469
+ const packagedRange = readPackagedSdkDependencyRange(
11470
+ packageName,
11471
+ importMetaUrl
11472
+ );
11473
+ if (packagedRange) {
11474
+ return packagedRange;
11475
+ }
11294
11476
  return DEFAULT_SDK_DEPENDENCY_RANGES[packageName];
11295
11477
  }
11296
11478
  function normalizeImportPath(relativePath) {
@@ -11391,19 +11573,7 @@ function setLatestCompileAttempt(projectConfig, attempt) {
11391
11573
  function updateProjectLocalMaintainerRegistry(projectConfig, localMaintainerRegistry) {
11392
11574
  return {
11393
11575
  ...projectConfig,
11394
- localMaintainerRegistry: sanitizeProjectLocalMaintainerRegistry(
11395
- localMaintainerRegistry
11396
- )
11397
- };
11398
- }
11399
- function sanitizeProjectLocalMaintainerRegistry(localMaintainerRegistry) {
11400
- if (!localMaintainerRegistry?.packages.dreamboard) {
11401
- return localMaintainerRegistry;
11402
- }
11403
- const { dreamboard: _dreamboard, ...packages } = localMaintainerRegistry.packages;
11404
- return {
11405
- ...localMaintainerRegistry,
11406
- packages
11576
+ localMaintainerRegistry
11407
11577
  };
11408
11578
  }
11409
11579
 
@@ -11675,7 +11845,7 @@ function buildRemoteAlignedSnapshotFiles(options) {
11675
11845
 
11676
11846
  // src/services/project/local-maintainer-registry.ts
11677
11847
  import { spawn } from "child_process";
11678
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
11848
+ import { existsSync as existsSync4 } from "fs";
11679
11849
  import path10 from "path";
11680
11850
  import { fileURLToPath as fileURLToPath3 } from "url";
11681
11851
 
@@ -11714,29 +11884,7 @@ function getCliPackageRoot() {
11714
11884
  "dreamboard-cli"
11715
11885
  );
11716
11886
  } catch {
11717
- return resolveInstalledCliPackageRoot(MODULE_DIR);
11718
- }
11719
- }
11720
- function resolveInstalledCliPackageRoot(moduleDir) {
11721
- let current = moduleDir;
11722
- while (true) {
11723
- const packageJsonPath = path10.join(current, "package.json");
11724
- if (existsSync4(packageJsonPath)) {
11725
- try {
11726
- const packageJson = JSON.parse(
11727
- readFileSync3(packageJsonPath, "utf8")
11728
- );
11729
- if (packageJson.name === "dreamboard" || packageJson.name === "dreamboard-cli") {
11730
- return current;
11731
- }
11732
- } catch {
11733
- }
11734
- }
11735
- const parent = path10.dirname(current);
11736
- if (parent === current) {
11737
- return moduleDir;
11738
- }
11739
- current = parent;
11887
+ return path10.resolve(MODULE_DIR, "../../..");
11740
11888
  }
11741
11889
  }
11742
11890
  function getScriptInvocation() {
@@ -11911,9 +12059,6 @@ var CLI_ROOT = path11.resolve(MODULE_DIR2, "../../..");
11911
12059
  var REPO_ROOT = path11.resolve(CLI_ROOT, "../..");
11912
12060
  var REPO_PACKAGE_JSON_PATH = path11.join(REPO_ROOT, "package.json");
11913
12061
  var DEFAULT_PACKAGE_MANAGER = "pnpm@10.4.1";
11914
- var FRAMEWORK_PNPM_OVERRIDES2 = {
11915
- zod: "4.4.3"
11916
- };
11917
12062
  var DEPENDENCY_INSTALL_METADATA_PATH_SEGMENTS = [
11918
12063
  ".dreamboard",
11919
12064
  "dependency-install.json"
@@ -11927,6 +12072,8 @@ var LockfileGenerationError = class extends Error {
11927
12072
  this.details = details;
11928
12073
  this.name = "LockfileGenerationError";
11929
12074
  }
12075
+ binary;
12076
+ details;
11930
12077
  };
11931
12078
  async function installWorkspaceDependencies(projectRoot, _options = {}) {
11932
12079
  const result = await reconcileWorkspaceDependencies(projectRoot);
@@ -12044,7 +12191,7 @@ function mergePnpmConfig2(existingPnpm) {
12044
12191
  ...existingPnpm ?? {},
12045
12192
  overrides: {
12046
12193
  ...existingOverrides,
12047
- ...FRAMEWORK_PNPM_OVERRIDES2
12194
+ ...FRAMEWORK_PNPM_OVERRIDES
12048
12195
  }
12049
12196
  };
12050
12197
  }
@@ -12350,31 +12497,142 @@ var clone_default = defineCommand({
12350
12497
  }
12351
12498
  });
12352
12499
 
12500
+ // src/services/project/dependency-portability.ts
12501
+ import path13 from "path";
12502
+ var DEPENDENCY_FIELDS = [
12503
+ "dependencies",
12504
+ "devDependencies",
12505
+ "optionalDependencies",
12506
+ "peerDependencies"
12507
+ ];
12508
+ var UNPORTABLE_SPECIFIER_PATTERN = /^(file|link|portal|workspace):/;
12509
+ async function buildSourceDependencyProfile(options) {
12510
+ const packageJson = await readProjectPackageJson(options.projectRoot);
12511
+ const packages = collectDreamboardPackageSpecifiers(packageJson);
12512
+ return {
12513
+ kind: "npm-registry",
12514
+ packageManager: packageJson.packageManager,
12515
+ dreamboardRegistryUrl: await readDreamboardRegistryFromNpmrc(options.projectRoot) ?? options.projectConfig?.localMaintainerRegistry?.registryUrl,
12516
+ localSnapshotId: options.projectConfig?.localMaintainerRegistry?.snapshotId,
12517
+ packages
12518
+ };
12519
+ }
12520
+ async function assertCompilerPortableDependencies(options) {
12521
+ const packageJson = await readProjectPackageJson(options.projectRoot);
12522
+ const problems = collectUnportableDreamboardSpecifiers(packageJson);
12523
+ if (problems.length > 0) {
12524
+ const details = problems.map(
12525
+ (problem) => `${problem.location} ${problem.packageName} -> ${problem.specifier}`
12526
+ ).join("; ");
12527
+ throw new Error(
12528
+ [
12529
+ "Compiler-bound workspaces must install Dreamboard packages from a registry.",
12530
+ `Found unportable Dreamboard dependency specifier(s): ${details}.`,
12531
+ "Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard/* and dreamboard versions before compiling."
12532
+ ].join(" ")
12533
+ );
12534
+ }
12535
+ const profile = await buildSourceDependencyProfile(options);
12536
+ const hasLocalSnapshotPackage = Object.values(profile.packages).some(
12537
+ (value) => value.includes("-local.")
12538
+ );
12539
+ if (hasLocalSnapshotPackage && !profile.dreamboardRegistryUrl) {
12540
+ throw new Error(
12541
+ "This workspace references local Dreamboard snapshot versions but has no @dreamboard registry configured. Run `dreamboard sync --env local` to refresh .npmrc before compiling."
12542
+ );
12543
+ }
12544
+ return profile;
12545
+ }
12546
+ async function readProjectPackageJson(projectRoot) {
12547
+ return readJsonFile(
12548
+ path13.join(projectRoot, "package.json")
12549
+ );
12550
+ }
12551
+ function collectDreamboardPackageSpecifiers(packageJson) {
12552
+ const packages = {};
12553
+ for (const field of DEPENDENCY_FIELDS) {
12554
+ const dependencies = packageJson[field];
12555
+ if (!dependencies) continue;
12556
+ for (const [packageName, specifier] of Object.entries(dependencies)) {
12557
+ if (isDreamboardPackage(packageName)) {
12558
+ packages[packageName] = specifier;
12559
+ }
12560
+ }
12561
+ }
12562
+ const overrides = packageJson.pnpm?.overrides;
12563
+ if (overrides) {
12564
+ for (const [packageName, specifier] of Object.entries(overrides)) {
12565
+ if (isDreamboardPackage(packageName) && typeof specifier === "string" && packages[packageName] === void 0) {
12566
+ packages[packageName] = specifier;
12567
+ }
12568
+ }
12569
+ }
12570
+ return packages;
12571
+ }
12572
+ function collectUnportableDreamboardSpecifiers(packageJson) {
12573
+ const problems = [];
12574
+ for (const field of DEPENDENCY_FIELDS) {
12575
+ const dependencies = packageJson[field];
12576
+ if (!dependencies) continue;
12577
+ for (const [packageName, specifier] of Object.entries(dependencies)) {
12578
+ if (isDreamboardPackage(packageName) && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
12579
+ problems.push({ location: field, packageName, specifier });
12580
+ }
12581
+ }
12582
+ }
12583
+ const overrides = packageJson.pnpm?.overrides;
12584
+ if (overrides) {
12585
+ for (const [packageName, specifier] of Object.entries(overrides)) {
12586
+ if (isDreamboardPackage(packageName) && typeof specifier === "string" && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
12587
+ problems.push({
12588
+ location: "pnpm.overrides",
12589
+ packageName,
12590
+ specifier
12591
+ });
12592
+ }
12593
+ }
12594
+ }
12595
+ return problems;
12596
+ }
12597
+ function isDreamboardPackage(packageName) {
12598
+ return packageName === "dreamboard" || packageName.startsWith("@dreamboard/");
12599
+ }
12600
+ async function readDreamboardRegistryFromNpmrc(projectRoot) {
12601
+ const npmrc = await readTextFileIfExists(path13.join(projectRoot, ".npmrc"));
12602
+ if (!npmrc) return void 0;
12603
+ for (const line of npmrc.split(/\r?\n/)) {
12604
+ const trimmed = line.trim();
12605
+ if (!trimmed.startsWith("@dreamboard:registry=")) continue;
12606
+ return trimmed.slice("@dreamboard:registry=".length).trim() || void 0;
12607
+ }
12608
+ return void 0;
12609
+ }
12610
+
12353
12611
  // src/services/project/local-typecheck.ts
12354
12612
  import { spawn as spawn3 } from "child_process";
12355
12613
  import { lstat as lstat2 } from "fs/promises";
12356
- import path13 from "path";
12614
+ import path14 from "path";
12357
12615
  import { fileURLToPath as fileURLToPath5 } from "url";
12358
- var MODULE_DIR3 = path13.dirname(fileURLToPath5(import.meta.url));
12359
- var REPO_ROOT2 = path13.resolve(MODULE_DIR3, "../../../../..");
12360
- var TYPESCRIPT_NODE_MODULES = path13.join(REPO_ROOT2, "node_modules");
12616
+ var MODULE_DIR3 = path14.dirname(fileURLToPath5(import.meta.url));
12617
+ var REPO_ROOT2 = path14.resolve(MODULE_DIR3, "../../../../..");
12618
+ var TYPESCRIPT_NODE_MODULES = path14.join(REPO_ROOT2, "node_modules");
12361
12619
  var TYPESCRIPT_BIN_PATH_SEGMENTS = [
12362
12620
  "node_modules",
12363
12621
  "typescript",
12364
12622
  "bin",
12365
12623
  "tsc"
12366
12624
  ];
12367
- var TYPESCRIPT_CLI = path13.join(
12625
+ var TYPESCRIPT_CLI = path14.join(
12368
12626
  TYPESCRIPT_NODE_MODULES,
12369
12627
  "typescript",
12370
12628
  "bin",
12371
12629
  "tsc"
12372
12630
  );
12373
12631
  function getProjectNodeModules(projectRoot) {
12374
- return path13.join(projectRoot, "node_modules");
12632
+ return path14.join(projectRoot, "node_modules");
12375
12633
  }
12376
12634
  function getProjectTypescriptCli(projectRoot) {
12377
- return path13.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);
12635
+ return path14.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);
12378
12636
  }
12379
12637
  async function pathExists2(targetPath) {
12380
12638
  try {
@@ -12565,6 +12823,7 @@ var compile_default = defineCommand({
12565
12823
  async run({ args }) {
12566
12824
  const parsedArgs = parseCompileCommandArgs(args);
12567
12825
  const { projectRoot, projectConfig } = await resolveProjectContext(parsedArgs);
12826
+ await assertCompilerPortableDependencies({ projectRoot, projectConfig });
12568
12827
  const diff = await getLocalDiff(projectRoot);
12569
12828
  await assertCliStaticScaffoldComplete(projectRoot, diff.deleted);
12570
12829
  if (diff.modified.length > 0 || diff.added.length > 0 || diff.deleted.length > 0) {
@@ -12809,9 +13068,137 @@ var config_default = defineCommand({
12809
13068
  });
12810
13069
 
12811
13070
  // src/commands/dev.ts
12812
- import path23 from "path";
13071
+ import path24 from "path";
12813
13072
  import { createHash as createHash3 } from "crypto";
12814
13073
 
13074
+ // ../../packages/ui-host-runtime/src/actor-principal.ts
13075
+ function gameIdFromGameSource(source) {
13076
+ if (source.kind === "USER_COMPILED") {
13077
+ return source.gameId;
13078
+ }
13079
+ return `demo:${source.slug}:${source.revisionId}`;
13080
+ }
13081
+
13082
+ // ../../packages/ui-host-runtime/src/plugin-messages.ts
13083
+ var InitMessageSchema = external_exports.object({
13084
+ type: external_exports.literal("init"),
13085
+ sessionId: external_exports.string(),
13086
+ controllablePlayerIds: external_exports.array(external_exports.string()),
13087
+ controllingPlayerId: external_exports.string(),
13088
+ userId: external_exports.string().nullable()
13089
+ });
13090
+ var PingMessageSchema = external_exports.object({
13091
+ type: external_exports.literal("ping")
13092
+ });
13093
+ var StateSyncMessageSchema = external_exports.object({
13094
+ type: external_exports.literal("state-sync"),
13095
+ syncId: external_exports.number(),
13096
+ state: external_exports.custom((data) => {
13097
+ return typeof data === "object" && data !== null && "session" in data && "notifications" in data;
13098
+ })
13099
+ });
13100
+ var SubmitResultMessageSchema = external_exports.object({
13101
+ type: external_exports.literal("submit-result"),
13102
+ messageId: external_exports.string(),
13103
+ accepted: external_exports.boolean(),
13104
+ errorCode: external_exports.string().optional(),
13105
+ message: external_exports.string().optional()
13106
+ });
13107
+ var MainToPluginMessageSchema = external_exports.discriminatedUnion("type", [
13108
+ InitMessageSchema,
13109
+ PingMessageSchema,
13110
+ StateSyncMessageSchema,
13111
+ SubmitResultMessageSchema
13112
+ ]);
13113
+ var ReadyMessageSchema = external_exports.object({
13114
+ type: external_exports.literal("ready")
13115
+ });
13116
+ var InteractionMessageSchema = external_exports.object({
13117
+ type: external_exports.literal("interaction"),
13118
+ messageId: external_exports.string(),
13119
+ playerId: external_exports.string(),
13120
+ interactionId: external_exports.string(),
13121
+ params: external_exports.unknown(),
13122
+ // Optional client-minted correlation id (UUID) that lets the whole
13123
+ // click-to-render path be stitched across plugin iframe, web host,
13124
+ // backend spans/logs and SSE. Added for Tier-0 input-latency
13125
+ // observability; the backend rides it through as an HTTP header
13126
+ // (`X-Dreamboard-Client-Action-Id`) but no wire contract changed.
13127
+ clientActionId: external_exports.string().optional(),
13128
+ // Plugin-iframe `Date.now()` captured right before the postMessage
13129
+ // is sent, used as the `t0_click` timestamp on the host-side perf
13130
+ // buffer. Date.now() is intentional: the iframe and the host share
13131
+ // a wall-clock base, but not a `performance.now()` origin.
13132
+ clientSubmittedAtMs: external_exports.number().optional()
13133
+ });
13134
+ var ValidateInteractionMessageSchema = external_exports.object({
13135
+ type: external_exports.literal("validate-interaction"),
13136
+ playerId: external_exports.string(),
13137
+ interactionId: external_exports.string(),
13138
+ params: external_exports.unknown(),
13139
+ messageId: external_exports.string()
13140
+ });
13141
+ var ValidateInteractionResultMessageSchema = external_exports.object({
13142
+ type: external_exports.literal("validate-interaction-result"),
13143
+ messageId: external_exports.string(),
13144
+ result: external_exports.object({
13145
+ valid: external_exports.boolean(),
13146
+ errorCode: external_exports.string().optional(),
13147
+ message: external_exports.string().optional()
13148
+ })
13149
+ });
13150
+ var PluginErrorMessageSchema = external_exports.object({
13151
+ type: external_exports.literal("error"),
13152
+ message: external_exports.string(),
13153
+ code: external_exports.string().optional()
13154
+ });
13155
+ var PongMessageSchema = external_exports.object({
13156
+ type: external_exports.literal("pong")
13157
+ });
13158
+ var SwitchPlayerMessageSchema = external_exports.object({
13159
+ type: external_exports.literal("switch-player"),
13160
+ playerId: external_exports.string()
13161
+ });
13162
+ var StateAckMessageSchema = external_exports.object({
13163
+ type: external_exports.literal("state-ack"),
13164
+ syncId: external_exports.number(),
13165
+ // Plugin-iframe `Date.now()` captured when the state-sync message
13166
+ // was received. Threaded so the host-side perf HUD can compute the
13167
+ // `t7_state_sync_received` mark without needing perf to be enabled
13168
+ // inside the plugin iframe itself.
13169
+ clientReceivedAtMs: external_exports.number().optional()
13170
+ });
13171
+ var StateRenderedMessageSchema = external_exports.object({
13172
+ type: external_exports.literal("state-rendered"),
13173
+ syncId: external_exports.number(),
13174
+ clientReceivedAtMs: external_exports.number(),
13175
+ clientRenderedAtMs: external_exports.number()
13176
+ });
13177
+ var MarkNotificationReadMessageSchema = external_exports.object({
13178
+ type: external_exports.literal("mark-notification-read"),
13179
+ notificationId: external_exports.string()
13180
+ });
13181
+ var RestoreHistoryMessageSchema = external_exports.object({
13182
+ type: external_exports.literal("restore-history"),
13183
+ entryId: external_exports.string()
13184
+ });
13185
+ var PluginToMainMessageSchema = external_exports.discriminatedUnion("type", [
13186
+ ReadyMessageSchema,
13187
+ InteractionMessageSchema,
13188
+ ValidateInteractionMessageSchema,
13189
+ PluginErrorMessageSchema,
13190
+ PongMessageSchema,
13191
+ SwitchPlayerMessageSchema,
13192
+ StateAckMessageSchema,
13193
+ StateRenderedMessageSchema,
13194
+ MarkNotificationReadMessageSchema,
13195
+ RestoreHistoryMessageSchema
13196
+ ]);
13197
+
13198
+ // ../../packages/ui-host-runtime/src/unified-session-store.ts
13199
+ import { createStore } from "zustand/vanilla";
13200
+ import { subscribeWithSelector } from "zustand/middleware";
13201
+
12815
13202
  // src/utils/dev-session.ts
12816
13203
  import { randomInt } from "crypto";
12817
13204
  var DEFAULT_DEV_SEED = 1337;
@@ -13011,6 +13398,7 @@ function openBrowser(url) {
13011
13398
  // src/dev-host/start-dev-server.ts
13012
13399
  import { rmSync } from "fs";
13013
13400
  import { createRequire as createRequire2 } from "module";
13401
+ import os from "os";
13014
13402
  import react from "@vitejs/plugin-react";
13015
13403
  import tailwindcssPostcss from "@tailwindcss/postcss";
13016
13404
  import { createServer as createServer2 } from "vite";
@@ -13085,12 +13473,7 @@ function createStreamingProxy(target) {
13085
13473
  },
13086
13474
  web(req, res, _options, callback) {
13087
13475
  const upstreamUrl = new URL(req.url ?? "/", targetUrl);
13088
- const headers = {
13089
- ...req.headers,
13090
- host: targetUrl.host,
13091
- "x-forwarded-host": req.headers.host,
13092
- "x-forwarded-proto": targetUrl.protocol.replace(":", "")
13093
- };
13476
+ const headers = createForwardHeaders(req, targetUrl);
13094
13477
  const client2 = targetUrl.protocol === "https:" ? https : http;
13095
13478
  const upstreamReq = client2.request(
13096
13479
  upstreamUrl,
@@ -13128,6 +13511,16 @@ function createStreamingProxy(target) {
13128
13511
  };
13129
13512
  return proxy;
13130
13513
  }
13514
+ function createForwardHeaders(req, targetUrl) {
13515
+ const headers = { ...req.headers };
13516
+ delete headers.origin;
13517
+ delete headers["access-control-request-headers"];
13518
+ delete headers["access-control-request-method"];
13519
+ headers.host = targetUrl.host;
13520
+ headers["x-forwarded-host"] = req.headers.host;
13521
+ headers["x-forwarded-proto"] = targetUrl.protocol.replace(":", "");
13522
+ return headers;
13523
+ }
13131
13524
  async function resolveDevBearer(config) {
13132
13525
  if (!usesStoredSession2(config)) {
13133
13526
  return { kind: "ok", token: config.authToken ?? null };
@@ -13210,7 +13603,7 @@ function formatUnknown(value) {
13210
13603
 
13211
13604
  // src/dev-host/dev-runtime-platform.ts
13212
13605
  import { createRequire } from "module";
13213
- import path14 from "path";
13606
+ import path15 from "path";
13214
13607
  import { fileURLToPath as fileURLToPath6 } from "url";
13215
13608
  import { existsSync as existsSync6 } from "fs";
13216
13609
 
@@ -13229,6 +13622,36 @@ function createDevRuntimePlatform(options) {
13229
13622
  const repoRoot = resolveRepoRoot(cliRoot);
13230
13623
  const require3 = createRequire(options.importMetaUrl);
13231
13624
  const diagnosticsLevel = resolveDevDiagnosticsLevel(options.debug);
13625
+ const uiSdkRoot = resolvePackageRoot(
13626
+ require3,
13627
+ cliRoot,
13628
+ "@dreamboard/ui-sdk",
13629
+ "@dreamboard-games/ui-sdk",
13630
+ "packages/ui-sdk"
13631
+ );
13632
+ const apiClientClientGen = resolvePackageSubpath(
13633
+ require3,
13634
+ "@dreamboard/api-client/client.gen",
13635
+ "@dreamboard-games/api-client/client.gen"
13636
+ );
13637
+ const uiHostRuntimeRoot = resolveWorkspaceOrPackagedSource(
13638
+ repoRoot,
13639
+ cliRoot,
13640
+ "packages/ui-host-runtime",
13641
+ "dist/runtime-packages/ui-host-runtime"
13642
+ );
13643
+ const uiRoot = resolveWorkspaceOrPackagedSource(
13644
+ repoRoot,
13645
+ cliRoot,
13646
+ "packages/ui",
13647
+ "dist/runtime-packages/ui"
13648
+ );
13649
+ const tailwindConfigRoot = resolveWorkspaceOrPackagedSource(
13650
+ repoRoot,
13651
+ cliRoot,
13652
+ "packages/tailwind-config",
13653
+ "dist/runtime-packages/tailwind-config"
13654
+ );
13232
13655
  return {
13233
13656
  devHostRoot,
13234
13657
  repoRoot,
@@ -13236,11 +13659,12 @@ function createDevRuntimePlatform(options) {
13236
13659
  diagnosticsLevel,
13237
13660
  viteLogLevel: diagnosticsLevel === "verbose" ? "info" : "warn",
13238
13661
  serverConfig: {
13239
- host: "localhost",
13240
- port: options.port ?? 5173,
13662
+ host: options.host ?? "localhost",
13663
+ allowedHosts: options.allowedHosts,
13664
+ port: options.port ?? 5352,
13241
13665
  strictPort: false,
13242
13666
  watch: {
13243
- ignored: [/[\\/]\.dreamboard[\\/]/]
13667
+ ignored: createProjectOnlyWatchIgnored(options.projectRoot)
13244
13668
  },
13245
13669
  headers: {
13246
13670
  "Access-Control-Allow-Origin": "*",
@@ -13304,11 +13728,11 @@ function createDevRuntimePlatform(options) {
13304
13728
  },
13305
13729
  {
13306
13730
  find: /^@dreamboard\/ui-sdk$/,
13307
- replacement: path14.resolve(repoRoot, "packages/ui-sdk/src/index.ts")
13731
+ replacement: path15.resolve(uiSdkRoot, "src/index.ts")
13308
13732
  },
13309
13733
  {
13310
13734
  find: /^@dreamboard\/ui-sdk\/reducer$/,
13311
- replacement: path14.resolve(repoRoot, "packages/ui-sdk/src/reducer.ts")
13735
+ replacement: path15.resolve(uiSdkRoot, "src/reducer.ts")
13312
13736
  },
13313
13737
  {
13314
13738
  // Must resolve to the same source tree as the `@dreamboard/ui-sdk`
@@ -13317,91 +13741,110 @@ function createDevRuntimePlatform(options) {
13317
13741
  // `useRuntimeContext` on the workspace-source copy will never find
13318
13742
  // the provider that's set up via the dist copy (and vice versa).
13319
13743
  find: /^@dreamboard\/ui-sdk\/components$/,
13320
- replacement: path14.resolve(
13321
- repoRoot,
13322
- "packages/ui-sdk/src/components/index.ts"
13323
- )
13744
+ replacement: path15.resolve(uiSdkRoot, "src/components/index.ts")
13745
+ },
13746
+ {
13747
+ // Keep generated workspace adapters and legacy internal imports on the
13748
+ // same source instance as PluginRuntime so React context identity stays
13749
+ // shared in dev.
13750
+ find: /^@dreamboard\/ui-sdk\/internal$/,
13751
+ replacement: path15.resolve(uiSdkRoot, "src/internal.ts")
13752
+ },
13753
+ {
13754
+ find: /^@dreamboard\/ui-sdk\/workspace-contract$/,
13755
+ replacement: path15.resolve(uiSdkRoot, "src/workspace-contract.ts")
13324
13756
  },
13325
13757
  {
13326
13758
  find: /^@dreamboard\/ui-sdk\/internal\/runtime-context$/,
13327
- replacement: path14.resolve(
13328
- repoRoot,
13329
- "packages/ui-sdk/src/context/RuntimeContext.tsx"
13759
+ replacement: path15.resolve(
13760
+ uiSdkRoot,
13761
+ "src/context/RuntimeContext.tsx"
13330
13762
  )
13331
13763
  },
13332
13764
  {
13333
13765
  find: /^@dreamboard\/ui-sdk\/internal\/usePluginRuntime$/,
13334
- replacement: path14.resolve(
13335
- repoRoot,
13336
- "packages/ui-sdk/src/hooks/usePluginRuntime.ts"
13766
+ replacement: path15.resolve(
13767
+ uiSdkRoot,
13768
+ "src/hooks/usePluginRuntime.ts"
13337
13769
  )
13338
13770
  },
13339
13771
  {
13340
13772
  find: /^@dreamboard\/ui-sdk\/internal\/createPluginRuntimeAPI$/,
13341
- replacement: path14.resolve(
13342
- repoRoot,
13343
- "packages/ui-sdk/src/runtime/createPluginRuntimeAPI.ts"
13773
+ replacement: path15.resolve(
13774
+ uiSdkRoot,
13775
+ "src/runtime/createPluginRuntimeAPI.ts"
13344
13776
  )
13345
13777
  },
13346
13778
  {
13347
13779
  find: /^@dreamboard\/ui-sdk\/internal\/useHandLayout$/,
13348
- replacement: path14.resolve(
13349
- repoRoot,
13350
- "packages/ui-sdk/src/hooks/useHandLayout.ts"
13351
- )
13780
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/useHandLayout.ts")
13352
13781
  },
13353
13782
  {
13354
13783
  find: /^@dreamboard\/ui-sdk\/internal\/usePanZoom$/,
13355
- replacement: path14.resolve(
13356
- repoRoot,
13357
- "packages/ui-sdk/src/hooks/usePanZoom.ts"
13358
- )
13784
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/usePanZoom.ts")
13359
13785
  },
13360
13786
  {
13361
13787
  find: /^@dreamboard\/ui-sdk\/internal\/useIsMobile$/,
13362
- replacement: path14.resolve(
13363
- repoRoot,
13364
- "packages/ui-sdk/src/hooks/useIsMobile.ts"
13365
- )
13788
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/useIsMobile.ts")
13366
13789
  },
13367
13790
  {
13368
13791
  find: /^@dreamboard\/ui-sdk\/internal\/player-state$/,
13369
- replacement: path14.resolve(
13370
- repoRoot,
13371
- "packages/ui-sdk/src/types/player-state.ts"
13792
+ replacement: path15.resolve(
13793
+ uiSdkRoot,
13794
+ "src/types/player-state.ts"
13372
13795
  )
13373
13796
  },
13374
13797
  {
13375
13798
  find: /^@dreamboard\/ui-sdk\/internal\/tiled-board$/,
13376
- replacement: path14.resolve(
13377
- repoRoot,
13378
- "packages/ui-sdk/src/types/tiled-board.ts"
13799
+ replacement: path15.resolve(
13800
+ uiSdkRoot,
13801
+ "src/types/tiled-board.ts"
13379
13802
  )
13380
13803
  },
13381
13804
  {
13382
13805
  find: /^@dreamboard\/ui-sdk\/internal\/plugin-state$/,
13383
- replacement: path14.resolve(
13384
- repoRoot,
13385
- "packages/ui-sdk/src/types/plugin-state.ts"
13806
+ replacement: path15.resolve(
13807
+ uiSdkRoot,
13808
+ "src/types/plugin-state.ts"
13386
13809
  )
13387
13810
  },
13388
13811
  {
13389
13812
  find: /^@dreamboard\/ui-sdk\/types\/runtime-api$/,
13390
- replacement: path14.resolve(
13391
- repoRoot,
13392
- "packages/ui-sdk/src/types/runtime-api.ts"
13813
+ replacement: path15.resolve(
13814
+ uiSdkRoot,
13815
+ "src/types/runtime-api.ts"
13393
13816
  )
13394
13817
  },
13818
+ {
13819
+ find: /^@dreamboard\/ui-host-runtime\/components$/,
13820
+ replacement: path15.resolve(uiHostRuntimeRoot, "src/components/index.ts")
13821
+ },
13822
+ {
13823
+ find: /^@dreamboard\/ui-host-runtime\/runtime$/,
13824
+ replacement: path15.resolve(uiHostRuntimeRoot, "src/runtime/index.ts")
13825
+ },
13826
+ {
13827
+ find: /^@dreamboard\/ui\/components\/(.*)$/,
13828
+ replacement: path15.resolve(uiRoot, "src/components/$1.tsx")
13829
+ },
13830
+ {
13831
+ find: /^@dreamboard\/ui\/lib\/(.*)$/,
13832
+ replacement: path15.resolve(uiRoot, "src/lib/$1.ts")
13833
+ },
13834
+ {
13835
+ find: /^@dreamboard\/tailwind-config$/,
13836
+ replacement: path15.resolve(tailwindConfigRoot, "shared-styles.css")
13837
+ },
13395
13838
  {
13396
13839
  find: /^@dreamboard\/manifest-contract$/,
13397
- replacement: path14.resolve(
13840
+ replacement: path15.resolve(
13398
13841
  options.projectRoot,
13399
13842
  "shared/manifest-contract.ts"
13400
13843
  )
13401
13844
  },
13402
13845
  {
13403
13846
  find: /^@dreamboard\/ui-contract$/,
13404
- replacement: path14.resolve(
13847
+ replacement: path15.resolve(
13405
13848
  options.projectRoot,
13406
13849
  "shared/generated/ui-contract.ts"
13407
13850
  )
@@ -13415,9 +13858,13 @@ function createDevRuntimePlatform(options) {
13415
13858
  "packages/ui-sdk/src/plugin-styles.css"
13416
13859
  )
13417
13860
  },
13861
+ {
13862
+ find: /^@dreamboard\/api-client\/client\.gen$/,
13863
+ replacement: apiClientClientGen
13864
+ },
13418
13865
  {
13419
13866
  find: /^@shared\/(.*)$/,
13420
- replacement: path14.resolve(options.projectRoot, "shared/$1")
13867
+ replacement: path15.resolve(options.projectRoot, "shared/$1")
13421
13868
  },
13422
13869
  {
13423
13870
  find: /^tailwindcss$/,
@@ -13429,33 +13876,72 @@ function createDevRuntimePlatform(options) {
13429
13876
  // older local snapshot after `dreamboard sync`.
13430
13877
  optimizeDepsExclude: [
13431
13878
  "@dreamboard/ui-sdk",
13879
+ "@dreamboard/ui-sdk/workspace-contract",
13432
13880
  "@dreamboard/app-sdk",
13433
13881
  "@dreamboard/app-sdk/reducer",
13434
13882
  "@dreamboard/sdk-types"
13435
13883
  ]
13436
13884
  };
13437
13885
  }
13886
+ function createProjectOnlyWatchIgnored(projectRoot) {
13887
+ const normalizedProjectRoot = path15.resolve(projectRoot);
13888
+ return (file) => {
13889
+ const normalizedFile = path15.resolve(file);
13890
+ const relativePath = path15.relative(normalizedProjectRoot, normalizedFile);
13891
+ const isInsideProject = relativePath === "" || relativePath.length > 0 && !relativePath.startsWith("..") && !path15.isAbsolute(relativePath);
13892
+ if (!isInsideProject) {
13893
+ return true;
13894
+ }
13895
+ const pathSegments = relativePath.split(path15.sep);
13896
+ return pathSegments.includes(".dreamboard") || pathSegments.includes("node_modules");
13897
+ };
13898
+ }
13899
+ function resolveWorkspaceOrPackagedSource(repoRoot, cliRoot, workspaceRelativePath, packagedRelativePath) {
13900
+ const workspacePath = path15.resolve(repoRoot, workspaceRelativePath);
13901
+ if (existsSync6(workspacePath)) return workspacePath;
13902
+ return path15.resolve(cliRoot, packagedRelativePath);
13903
+ }
13904
+ function resolvePackageRoot(require3, cliRoot, specifier, publicSpecifier, fallbackRelativePath) {
13905
+ try {
13906
+ return path15.dirname(require3.resolve(`${specifier}/package.json`));
13907
+ } catch {
13908
+ try {
13909
+ return path15.dirname(require3.resolve(`${publicSpecifier}/package.json`));
13910
+ } catch {
13911
+ return path15.resolve(cliRoot, "..", "..", fallbackRelativePath);
13912
+ }
13913
+ }
13914
+ }
13915
+ function resolvePackageSubpath(require3, specifier, publicSpecifier) {
13916
+ try {
13917
+ return require3.resolve(specifier);
13918
+ } catch {
13919
+ return require3.resolve(publicSpecifier);
13920
+ }
13921
+ }
13438
13922
  function resolveCliDependency(require3, cliRoot, specifier, fallbackRelativePath) {
13439
13923
  try {
13440
13924
  return require3.resolve(specifier);
13441
13925
  } catch {
13442
- return path14.resolve(cliRoot, fallbackRelativePath);
13926
+ return path15.resolve(cliRoot, fallbackRelativePath);
13443
13927
  }
13444
13928
  }
13445
13929
  function resolveDevHostRoot(importMetaUrl) {
13446
- const currentDir = path14.dirname(fileURLToPath6(importMetaUrl));
13447
- const sourceDirCandidate = path14.resolve(currentDir, "../src/dev-host");
13930
+ const currentDir = path15.dirname(fileURLToPath6(importMetaUrl));
13931
+ const packagedDirCandidate = path15.resolve(currentDir, "dev-host");
13932
+ if (existsSync6(packagedDirCandidate)) return packagedDirCandidate;
13933
+ const sourceDirCandidate = path15.resolve(currentDir, "../src/dev-host");
13448
13934
  return existsSync6(sourceDirCandidate) ? sourceDirCandidate : currentDir;
13449
13935
  }
13450
13936
  function resolveCliRoot(importMetaUrl) {
13451
- let currentDir = path14.dirname(fileURLToPath6(importMetaUrl));
13937
+ let currentDir = path15.dirname(fileURLToPath6(importMetaUrl));
13452
13938
  while (true) {
13453
- if (existsSync6(path14.join(currentDir, "package.json"))) {
13939
+ if (existsSync6(path15.join(currentDir, "package.json"))) {
13454
13940
  return currentDir;
13455
13941
  }
13456
- const parentDir = path14.dirname(currentDir);
13942
+ const parentDir = path15.dirname(currentDir);
13457
13943
  if (parentDir === currentDir) {
13458
- return path14.resolve(resolveDevHostRoot(importMetaUrl), "../..");
13944
+ return path15.resolve(resolveDevHostRoot(importMetaUrl), "../..");
13459
13945
  }
13460
13946
  currentDir = parentDir;
13461
13947
  }
@@ -13463,10 +13949,10 @@ function resolveCliRoot(importMetaUrl) {
13463
13949
  function resolveRepoRoot(cliRoot) {
13464
13950
  let currentDir = cliRoot;
13465
13951
  while (true) {
13466
- if (existsSync6(path14.join(currentDir, "pnpm-workspace.yaml"))) {
13952
+ if (existsSync6(path15.join(currentDir, "pnpm-workspace.yaml"))) {
13467
13953
  return currentDir;
13468
13954
  }
13469
- const parentDir = path14.dirname(currentDir);
13955
+ const parentDir = path15.dirname(currentDir);
13470
13956
  if (parentDir === currentDir) {
13471
13957
  return cliRoot;
13472
13958
  }
@@ -13475,15 +13961,15 @@ function resolveRepoRoot(cliRoot) {
13475
13961
  }
13476
13962
 
13477
13963
  // src/dev-host/dev-virtual-modules-plugin.ts
13478
- import path15 from "path";
13964
+ import path16 from "path";
13479
13965
  import { normalizePath } from "vite";
13480
13966
  function createVirtualDevModulesPlugin(options) {
13481
13967
  const configModuleId = "virtual:dreamboard-dev-config";
13482
13968
  const resolvedConfigModuleId = `\0${configModuleId}`;
13483
13969
  const projectEntryModuleId = "virtual:dreamboard-project-entry";
13484
13970
  const resolvedProjectEntryModuleId = `\0${projectEntryModuleId}`;
13485
- const projectAppPath = path15.resolve(options.projectRoot, "ui/App.tsx");
13486
- const projectStylePath = path15.resolve(options.projectRoot, "ui/style.css");
13971
+ const projectAppPath = path16.resolve(options.projectRoot, "ui/App.tsx");
13972
+ const projectStylePath = path16.resolve(options.projectRoot, "ui/style.css");
13487
13973
  return {
13488
13974
  name: "dreamboard-dev-virtual-modules",
13489
13975
  resolveId(id) {
@@ -13741,7 +14227,7 @@ function extractQueryParam(req, name) {
13741
14227
  );
13742
14228
  return value?.trim() || null;
13743
14229
  }
13744
- function appendQuery(path26, query) {
14230
+ function appendQuery(path28, query) {
13745
14231
  const params = new URLSearchParams();
13746
14232
  for (const [key, value] of Object.entries(query)) {
13747
14233
  if (value) {
@@ -13749,7 +14235,7 @@ function appendQuery(path26, query) {
13749
14235
  }
13750
14236
  }
13751
14237
  const serialized = params.toString();
13752
- return serialized ? `${path26}?${serialized}` : path26;
14238
+ return serialized ? `${path28}?${serialized}` : path28;
13753
14239
  }
13754
14240
  async function loadCurrentSession(options) {
13755
14241
  if (!await exists(options.sessionFilePath)) {
@@ -13768,12 +14254,12 @@ async function persistSessionId(sessionFilePath, sessionId) {
13768
14254
  createPersistedDevSession({ sessionId })
13769
14255
  );
13770
14256
  }
13771
- async function fetchBackendJson(config, path26, options = {}) {
14257
+ async function fetchBackendJson(config, path28, options = {}) {
13772
14258
  const bearer = await resolveDevBearer(config);
13773
14259
  if (bearer.kind === "permanent_invalid") {
13774
14260
  throw new HttpError(401, bearer.message);
13775
14261
  }
13776
- const response = await fetch(`${config.apiBaseUrl}${path26}`, {
14262
+ const response = await fetch(`${config.apiBaseUrl}${path28}`, {
13777
14263
  method: options.method ?? "GET",
13778
14264
  headers: {
13779
14265
  ...bearer.token ? { authorization: `Bearer ${bearer.token}` } : {},
@@ -13827,6 +14313,7 @@ var HttpError = class extends Error {
13827
14313
  super(message);
13828
14314
  this.statusCode = statusCode;
13829
14315
  }
14316
+ statusCode;
13830
14317
  };
13831
14318
  function parsePersistedSessionPointer(value, runtimeConfig) {
13832
14319
  if (!value || typeof value !== "object") {
@@ -13876,29 +14363,29 @@ function formatUnknown2(value) {
13876
14363
  // src/dev-host/dev-fallback-stylesheet.ts
13877
14364
  import { createHash, randomUUID } from "crypto";
13878
14365
  import { existsSync as existsSync7, mkdirSync, writeFileSync } from "fs";
13879
- import path16 from "path";
14366
+ import path17 from "path";
13880
14367
  import { normalizePath as normalizePath2 } from "vite";
13881
14368
  function prepareFallbackStylesheet(options) {
13882
- const projectStylePath = path16.resolve(options.projectRoot, "ui/style.css");
14369
+ const projectStylePath = path17.resolve(options.projectRoot, "ui/style.css");
13883
14370
  if (existsSync7(projectStylePath)) {
13884
14371
  return null;
13885
14372
  }
13886
- const generatedDir = path16.resolve(options.repoRoot, ".dreamboard-dev");
14373
+ const generatedDir = path17.resolve(options.repoRoot, ".dreamboard-dev");
13887
14374
  mkdirSync(generatedDir, { recursive: true });
13888
14375
  const fingerprint = createHash("sha256").update(options.projectRoot, "utf8").digest("hex").slice(0, 8);
13889
14376
  const instanceId = randomUUID().replaceAll("-", "").slice(0, 8);
13890
- const generatedPath = path16.join(
14377
+ const generatedPath = path17.join(
13891
14378
  generatedDir,
13892
14379
  `plugin-styles-${fingerprint}-${instanceId}.css`
13893
14380
  );
13894
14381
  const sharedStylesPath = normalizePath2(
13895
- path16.resolve(options.repoRoot, "packages/ui-sdk/src/plugin-styles.css")
14382
+ path17.resolve(options.repoRoot, "packages/ui-sdk/src/plugin-styles.css")
13896
14383
  );
13897
14384
  const uiSourcePath = normalizePath2(
13898
- path16.resolve(options.projectRoot, "ui/**/*.{ts,tsx}")
14385
+ path17.resolve(options.projectRoot, "ui/**/*.{ts,tsx}")
13899
14386
  );
13900
14387
  const sharedSourcePath = normalizePath2(
13901
- path16.resolve(options.projectRoot, "shared/**/*.{ts,tsx}")
14388
+ path17.resolve(options.projectRoot, "shared/**/*.{ts,tsx}")
13902
14389
  );
13903
14390
  writeFileSync(
13904
14391
  generatedPath,
@@ -13918,12 +14405,14 @@ function prepareFallbackStylesheet(options) {
13918
14405
  var require2 = createRequire2(import.meta.url);
13919
14406
  var tailwindCssEntry = require2.resolve("tailwindcss/index.css");
13920
14407
  async function startDreamboardDevServer(options) {
13921
- const { projectRoot, port, runtimeConfig, config } = options;
14408
+ const { projectRoot, port, host, allowedHosts, runtimeConfig, config } = options;
13922
14409
  const platform2 = createDevRuntimePlatform({
13923
14410
  importMetaUrl: import.meta.url,
13924
14411
  projectRoot,
13925
14412
  debug: runtimeConfig.debug,
13926
14413
  port,
14414
+ host,
14415
+ allowedHosts,
13927
14416
  tailwindCssEntry
13928
14417
  });
13929
14418
  const generatedFallbackStylesheetPath = prepareFallbackStylesheet({
@@ -13965,8 +14454,10 @@ async function startDreamboardDevServer(options) {
13965
14454
  });
13966
14455
  await server.listen();
13967
14456
  const resolvedPort = getBoundPort(server);
14457
+ const url = `http://localhost:${resolvedPort}/index.html`;
13968
14458
  return {
13969
- url: `http://localhost:${resolvedPort}/index.html`,
14459
+ url,
14460
+ networkUrls: getNetworkUrls(host, resolvedPort),
13970
14461
  close: async () => {
13971
14462
  await server.close();
13972
14463
  if (generatedFallbackStylesheetPath) {
@@ -13976,6 +14467,23 @@ async function startDreamboardDevServer(options) {
13976
14467
  server
13977
14468
  };
13978
14469
  }
14470
+ function getNetworkUrls(host, port) {
14471
+ if (!host) return [];
14472
+ if (typeof host === "string" && isLoopbackHost(host)) return [];
14473
+ const hosts = host === true || host === "0.0.0.0" || host === "::" ? getLanIpv4Addresses() : [host];
14474
+ return hosts.map(
14475
+ (value) => `http://${formatUrlHost(value)}:${port}/index.html`
14476
+ );
14477
+ }
14478
+ function isLoopbackHost(host) {
14479
+ return host === "localhost" || host === "127.0.0.1" || host === "::1";
14480
+ }
14481
+ function getLanIpv4Addresses() {
14482
+ return Object.values(os.networkInterfaces()).flatMap((interfaces) => interfaces ?? []).filter((details) => details.family === "IPv4" && !details.internal).map((details) => details.address);
14483
+ }
14484
+ function formatUrlHost(host) {
14485
+ return host.includes(":") ? `[${host}]` : host;
14486
+ }
13979
14487
  function getBoundPort(server) {
13980
14488
  const address = server.httpServer?.address();
13981
14489
  if (!address || typeof address === "string") {
@@ -13985,11 +14493,11 @@ function getBoundPort(server) {
13985
14493
  }
13986
14494
 
13987
14495
  // src/services/testing/reducer-native-test-harness.ts
13988
- import path20 from "path";
14496
+ import path21 from "path";
13989
14497
  import {
13990
14498
  existsSync as existsSync8,
13991
14499
  mkdirSync as mkdirSync2,
13992
- readFileSync as readFileSync4,
14500
+ readFileSync as readFileSync3,
13993
14501
  rmSync as rmSync2,
13994
14502
  writeFileSync as writeFileSync2
13995
14503
  } from "fs";
@@ -14098,9 +14606,6 @@ var ProjectSeatsDynamicRequestSchema = external_exports.object({ "state": Reduce
14098
14606
  var BoardStaticProjectionSchema = external_exports.object({ "view": JsonValueSchema, "hash": external_exports.string().min(1), "manifestVersion": external_exports.string() }).strict();
14099
14607
 
14100
14608
  // ../../packages/app-sdk/src/reducer/per-player.ts
14101
- function asPlayerId(raw) {
14102
- return raw;
14103
- }
14104
14609
  function perPlayerGet(value, id) {
14105
14610
  for (const [candidate, v] of value.entries) {
14106
14611
  if (candidate === id) {
@@ -14222,33 +14727,6 @@ function resolveDependentDomainChoices(choices, context) {
14222
14727
  disabledReason: choice.disabledReason
14223
14728
  }));
14224
14729
  }
14225
- function choiceValuesInclude(choices, value) {
14226
- return choices.some((choice) => Object.is(choice.value, value));
14227
- }
14228
- function assertChoiceDefaultInChoices(inputName, choices, defaultValue) {
14229
- if (choiceValuesInclude(choices, defaultValue)) return;
14230
- const printable = defaultValue === null ? "null" : `'${defaultValue}'`;
14231
- throw new Error(
14232
- `${inputName} defaultValue ${printable} must be one of its choices. If null is a valid value, add an explicit { value: null, label: ... } choice.`
14233
- );
14234
- }
14235
- function choiceSchema(choices) {
14236
- const values = choices.map((choice) => choice.value);
14237
- const stringValues = values.filter(
14238
- (value) => value !== null
14239
- );
14240
- const hasNull = values.some((value) => value === null);
14241
- if (stringValues.length === 0) {
14242
- return external_exports.null();
14243
- }
14244
- const stringSchema = external_exports.enum(
14245
- stringValues
14246
- );
14247
- if (hasNull) {
14248
- return external_exports.union([stringSchema, external_exports.null()]);
14249
- }
14250
- return stringSchema;
14251
- }
14252
14730
  function resolveResourceMapChoices(choices, context) {
14253
14731
  const resources = context.state.table.resources;
14254
14732
  const firstResourceMap = isPerPlayer(resources) && resources.entries.length > 0 ? resources.entries[0]?.[1] : resources;
@@ -14332,76 +14810,38 @@ function choiceInput(options) {
14332
14810
  if (Array.isArray(options.choices) && options.choices.length === 0) {
14333
14811
  throw new Error("formInput.choice requires at least one choice.");
14334
14812
  }
14335
- const staticChoices = Array.isArray(options.choices) ? options.choices : null;
14336
- const hasStaticDefault = typeof options.defaultValue !== "function";
14337
- const staticDefault = options.defaultValue;
14338
- if (staticChoices && hasStaticDefault) {
14339
- assertChoiceDefaultInChoices(
14340
- "formInput.choice",
14341
- staticChoices,
14342
- staticDefault
14343
- );
14344
- }
14345
- const schema = staticChoices ? choiceSchema(staticChoices) : external_exports.string().nullable();
14346
- const dynamicDefault = typeof options.defaultValue === "function" ? options.defaultValue : void 0;
14813
+ const schema = Array.isArray(options.choices) ? external_exports.enum(
14814
+ options.choices.map((choice) => choice.value)
14815
+ ) : external_exports.string();
14347
14816
  return {
14348
14817
  kind: "form",
14349
14818
  schema,
14350
- ...hasStaticDefault ? { defaultValue: staticDefault } : {},
14819
+ ..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
14351
14820
  ...dependsOn ? { dependsOn } : {},
14352
14821
  domain: (state, playerId, q, derived, values) => {
14353
- const context = {
14354
- state,
14355
- playerId,
14356
- q,
14357
- derived
14358
- };
14359
- const choices = dependsOn ? resolveDependentDomainChoices(
14360
- options.choices,
14361
- {
14362
- ...context,
14363
- values: values ?? {}
14364
- }
14365
- ) : resolveDomainChoices(options.choices, {
14366
- ...context,
14367
- values: {}
14368
- });
14369
- if (hasStaticDefault) {
14370
- assertChoiceDefaultInChoices(
14371
- "formInput.choice",
14372
- choices,
14373
- staticDefault
14374
- );
14375
- }
14376
14822
  return {
14377
14823
  type: "choice",
14378
- choices
14824
+ choices: dependsOn ? resolveDependentDomainChoices(
14825
+ options.choices,
14826
+ {
14827
+ state,
14828
+ playerId,
14829
+ q,
14830
+ derived,
14831
+ values: values ?? {}
14832
+ }
14833
+ ) : resolveDomainChoices(
14834
+ options.choices,
14835
+ {
14836
+ state,
14837
+ playerId,
14838
+ q,
14839
+ derived,
14840
+ values: {}
14841
+ }
14842
+ )
14379
14843
  };
14380
- },
14381
- ...dynamicDefault ? {
14382
- resolveDefaultValue: (state, playerId, q, derived, domain) => {
14383
- const choices = domain.type === "choice" ? domain.choices.map((choice) => ({
14384
- value: choice.value,
14385
- label: choice.label,
14386
- icon: choice.icon,
14387
- badge: choice.badge,
14388
- description: choice.description,
14389
- disabled: choice.disabled,
14390
- disabledReason: choice.disabledReason
14391
- })) : [];
14392
- const resolved = dynamicDefault({
14393
- state,
14394
- playerId,
14395
- q,
14396
- derived,
14397
- values: {},
14398
- choices
14399
- });
14400
- if (resolved === void 0) return void 0;
14401
- assertChoiceDefaultInChoices("formInput.choice", choices, resolved);
14402
- return resolved;
14403
- }
14404
- } : {}
14844
+ }
14405
14845
  };
14406
14846
  }
14407
14847
  function choiceListInput(options) {
@@ -14422,12 +14862,7 @@ function choiceListInput(options) {
14422
14862
  derived,
14423
14863
  values: {}
14424
14864
  };
14425
- const choices = resolveDomainChoices(options.choices, context).map(
14426
- (choice) => ({
14427
- ...choice,
14428
- value: choice.value
14429
- })
14430
- );
14865
+ const choices = resolveDomainChoices(options.choices, context);
14431
14866
  return {
14432
14867
  type: "choiceList",
14433
14868
  choices,
@@ -16909,126 +17344,6 @@ function createReducerFx(_state) {
16909
17344
  function updateTable(state, nextTable) {
16910
17345
  return { ...state, table: nextTable };
16911
17346
  }
16912
- function computePlayerZoneVisibility(table, zoneId, playerId) {
16913
- const mode = table.handVisibility[zoneId];
16914
- if (mode === "all" || mode === "public") {
16915
- return { faceUp: true };
16916
- }
16917
- return { faceUp: false, visibleTo: [playerId] };
16918
- }
16919
- function readPlayerZoneCards(table, zoneId, playerId) {
16920
- const zone = table.zones.perPlayer[zoneId] ?? table.hands[zoneId];
16921
- if (!zone) {
16922
- throw new Error(`Player zone '${zoneId}' does not exist.`);
16923
- }
16924
- return perPlayerGet(zone, asPlayerId(playerId)) ?? [];
16925
- }
16926
- function writePlayerZoneCards(table, zoneId, playerId, cards) {
16927
- const currentZone = table.zones.perPlayer[zoneId];
16928
- const currentHand = table.hands[zoneId];
16929
- const player = asPlayerId(playerId);
16930
- if (currentZone) {
16931
- table.zones.perPlayer[zoneId] = perPlayerSet(
16932
- currentZone,
16933
- player,
16934
- [...cards]
16935
- );
16936
- }
16937
- if (currentHand) {
16938
- table.hands[zoneId] = perPlayerSet(
16939
- currentHand,
16940
- player,
16941
- [...cards]
16942
- );
16943
- }
16944
- }
16945
- function assertCardAllowedInPlayerZone(table, zoneId, cardId) {
16946
- const allowedCardSetIds = table.zones.cardSetIdsByZoneId?.[zoneId];
16947
- if (!allowedCardSetIds || allowedCardSetIds.length === 0) {
16948
- return;
16949
- }
16950
- const card = table.cards[cardId];
16951
- if (!card) {
16952
- throw new Error(`Card '${cardId}' does not exist.`);
16953
- }
16954
- if (!allowedCardSetIds.includes(card.cardSetId)) {
16955
- throw new Error(
16956
- `Card '${cardId}' from set '${card.cardSetId}' is not allowed in player zone '${zoneId}'.`
16957
- );
16958
- }
16959
- }
16960
- function rotatePlayerZoneTable(options) {
16961
- const nextTable = cloneRuntimeTable(options.table);
16962
- const zoneId = options.zoneId;
16963
- if (!nextTable.zones.perPlayer[zoneId] && !nextTable.hands[zoneId]) {
16964
- throw new Error(`Player zone '${zoneId}' does not exist.`);
16965
- }
16966
- const players = [...options.players ?? nextTable.playerOrder];
16967
- if (players.length === 0) {
16968
- return nextTable;
16969
- }
16970
- const playerSet = new Set(nextTable.playerOrder);
16971
- for (const playerId of players) {
16972
- if (!playerSet.has(playerId)) {
16973
- throw new Error(
16974
- `Cannot rotate player zone '${zoneId}': player '${playerId}' is not in player order.`
16975
- );
16976
- }
16977
- }
16978
- const selectedByPlayer = /* @__PURE__ */ new Map();
16979
- for (const playerId of players) {
16980
- const sourceCards = readPlayerZoneCards(nextTable, zoneId, playerId);
16981
- const selected = options.cardIdsByPlayer?.[playerId] ?? sourceCards;
16982
- for (const cardId of selected) {
16983
- if (!sourceCards.includes(cardId)) {
16984
- throw new Error(
16985
- `Cannot rotate player zone '${zoneId}': card '${cardId}' is not in zone for player '${playerId}'.`
16986
- );
16987
- }
16988
- assertCardAllowedInPlayerZone(nextTable, zoneId, cardId);
16989
- }
16990
- selectedByPlayer.set(playerId, [...selected]);
16991
- }
16992
- const removeByPlayer = /* @__PURE__ */ new Map();
16993
- for (const playerId of players) {
16994
- const selected = new Set(selectedByPlayer.get(playerId) ?? []);
16995
- removeByPlayer.set(
16996
- playerId,
16997
- readPlayerZoneCards(nextTable, zoneId, playerId).filter(
16998
- (cardId) => !selected.has(cardId)
16999
- )
17000
- );
17001
- }
17002
- const additionsByPlayer = new Map(
17003
- players.map((playerId) => [playerId, []])
17004
- );
17005
- for (const [index, fromPlayerId] of players.entries()) {
17006
- const offset = options.direction === "left" ? 1 : -1;
17007
- const recipient = players[(index + offset + players.length) % players.length];
17008
- additionsByPlayer.get(recipient).push(...selectedByPlayer.get(fromPlayerId) ?? []);
17009
- }
17010
- for (const playerId of players) {
17011
- const remaining = removeByPlayer.get(playerId) ?? [];
17012
- const additions = additionsByPlayer.get(playerId) ?? [];
17013
- const nextCards = options.position === "top" ? [...additions, ...remaining] : [...remaining, ...additions];
17014
- writePlayerZoneCards(nextTable, zoneId, playerId, nextCards);
17015
- for (const [position, cardId] of nextCards.entries()) {
17016
- nextTable.componentLocations[cardId] = {
17017
- type: "InHand",
17018
- handId: zoneId,
17019
- playerId,
17020
- position
17021
- };
17022
- nextTable.ownerOfCard[cardId] = playerId;
17023
- nextTable.visibility[cardId] = computePlayerZoneVisibility(
17024
- nextTable,
17025
- zoneId,
17026
- playerId
17027
- );
17028
- }
17029
- }
17030
- return nextTable;
17031
- }
17032
17347
  var moveComponentToEdgeInternal = moveComponentToEdge;
17033
17348
  var moveComponentToVertexInternal = moveComponentToVertex;
17034
17349
  var dealCardsFromDeckToHandInternal = dealCardsFromDeckToHand;
@@ -17212,19 +17527,6 @@ function createReducerOps() {
17212
17527
  return updateTable(state, nextTable);
17213
17528
  };
17214
17529
  },
17215
- rotatePlayerZone(args) {
17216
- return (state) => {
17217
- const nextTable = rotatePlayerZoneTable({
17218
- table: state.table,
17219
- zoneId: args.zoneId,
17220
- direction: args.direction,
17221
- players: args.players,
17222
- cardIdsByPlayer: args.cardIdsByPlayer,
17223
- position: args.position ?? "bottom"
17224
- });
17225
- return updateTable(state, nextTable);
17226
- };
17227
- },
17228
17530
  moveComponentToSpace(args) {
17229
17531
  return (state) => {
17230
17532
  const nextTable = moveComponentToSpace(
@@ -17324,47 +17626,6 @@ function createReducerOps() {
17324
17626
  return impl;
17325
17627
  }
17326
17628
 
17327
- // ../../packages/app-sdk/src/reducer/transaction.ts
17328
- function createReducerTransaction(initialState, ops = createReducerOps()) {
17329
- let currentState = initialState;
17330
- let currentQueries = createStateQueries(currentState);
17331
- const refresh = (nextState) => {
17332
- currentState = nextState;
17333
- currentQueries = createStateQueries(currentState);
17334
- return currentState;
17335
- };
17336
- const apply = (op) => refresh(op(currentState));
17337
- const base = {
17338
- get state() {
17339
- return currentState;
17340
- },
17341
- get q() {
17342
- return currentQueries;
17343
- },
17344
- apply
17345
- };
17346
- return new Proxy(base, {
17347
- get(target, property, receiver) {
17348
- if (property in target) {
17349
- return Reflect.get(target, property, receiver);
17350
- }
17351
- const opFactory = ops[property];
17352
- if (typeof opFactory !== "function") {
17353
- return void 0;
17354
- }
17355
- return (...args) => {
17356
- const op = opFactory(
17357
- ...args
17358
- );
17359
- return apply(op);
17360
- };
17361
- }
17362
- });
17363
- }
17364
- function createReducerEdit(ops = createReducerOps()) {
17365
- return (state) => createReducerTransaction(state, ops);
17366
- }
17367
-
17368
17629
  // ../../packages/app-sdk/src/reducer/definition-index.ts
17369
17630
  function phaseEntriesOf(definition) {
17370
17631
  return Object.entries(definition.phases);
@@ -17666,8 +17927,7 @@ function createTrustedRuntimeScope(definition) {
17666
17927
  }
17667
17928
  const helpers = {
17668
17929
  ...runtimeResultHelpers,
17669
- ops: createReducerOps(),
17670
- edit: createReducerEdit()
17930
+ ops: createReducerOps()
17671
17931
  };
17672
17932
  function fxForState2(state) {
17673
17933
  return fxForState(state);
@@ -18004,10 +18264,10 @@ function createTrustedInstructionRunner(scope, interactions, lifecycle) {
18004
18264
 
18005
18265
  // ../../packages/app-sdk/src/reducer/parse-utils.ts
18006
18266
  function formatIssue(label, issue) {
18007
- const path26 = issue.path.map(
18267
+ const path28 = issue.path.map(
18008
18268
  (segment) => typeof segment === "symbol" ? segment.toString() : String(segment)
18009
18269
  ).join(".");
18010
- return `${path26 || label}: ${issue.message}`;
18270
+ return `${path28 || label}: ${issue.message}`;
18011
18271
  }
18012
18272
  function safeParseOrThrow(schema, value, label) {
18013
18273
  const parsed = schema.safeParse(value);
@@ -18074,9 +18334,7 @@ function finiteValuesForDependency(key, domain) {
18074
18334
  return [...domain.eligibleTargets];
18075
18335
  }
18076
18336
  if (domain.type === "choice") {
18077
- return domain.choices.flatMap(
18078
- (choice) => choice.value === null ? [] : [choice.value]
18079
- );
18337
+ return domain.choices.map((choice) => choice.value);
18080
18338
  }
18081
18339
  throw new Error(
18082
18340
  `Interaction input '${key}' cannot be used as a dependency. V1 supports finite target and choice dependencies only.`
@@ -18644,7 +18902,7 @@ function enrichResourceInputPresentation(inputs, manifest) {
18644
18902
  }
18645
18903
  const resources = presentationById;
18646
18904
  const enrichChoice = (choice) => {
18647
- const presentation = choice.value === null ? void 0 : resources[choice.value];
18905
+ const presentation = resources[choice.value];
18648
18906
  return {
18649
18907
  ...choice,
18650
18908
  label: typeof presentation?.label === "string" && (!choice.label || choice.label === choice.value) ? presentation.label : choice.label || (typeof presentation?.label === "string" ? presentation.label : ""),
@@ -18652,16 +18910,7 @@ function enrichResourceInputPresentation(inputs, manifest) {
18652
18910
  };
18653
18911
  };
18654
18912
  return inputs.map((input) => {
18655
- if (input.domain.type === "choice") {
18656
- return {
18657
- ...input,
18658
- domain: {
18659
- ...input.domain,
18660
- choices: input.domain.choices.map(enrichChoice)
18661
- }
18662
- };
18663
- }
18664
- if (input.domain.type === "choiceList") {
18913
+ if (input.domain.type === "choice" || input.domain.type === "choiceList") {
18665
18914
  return {
18666
18915
  ...input,
18667
18916
  domain: {
@@ -19173,15 +19422,16 @@ function resolveContainerRef(table, ref) {
19173
19422
  throw new Error(`Unknown board '${ref.boardId}'.`);
19174
19423
  }
19175
19424
  const space2 = board2?.spaces[ref.spaceId];
19176
- if (!space2) {
19425
+ if (!space2?.zoneId) {
19177
19426
  throw new Error(
19178
- `Unknown board space '${ref.spaceId}' on board '${ref.boardId}'.`
19427
+ `Board space '${ref.spaceId}' on board '${ref.boardId}' has no container zone.`
19179
19428
  );
19180
19429
  }
19181
19430
  return {
19182
19431
  kind: "space",
19183
19432
  boardId: board2.id,
19184
- spaceId: ref.spaceId
19433
+ spaceId: ref.spaceId,
19434
+ zoneId: space2.zoneId
19185
19435
  };
19186
19436
  }
19187
19437
  const board = table.boards.byId[resolveRuntimeBoardId(table, ref.boardId, ref.playerId)];
@@ -19191,15 +19441,16 @@ function resolveContainerRef(table, ref) {
19191
19441
  );
19192
19442
  }
19193
19443
  const space = board?.spaces[ref.spaceId];
19194
- if (!space) {
19444
+ if (!space?.zoneId) {
19195
19445
  throw new Error(
19196
- `Unknown board space '${ref.spaceId}' on board '${ref.boardId}' for '${ref.playerId}'.`
19446
+ `Board space '${ref.spaceId}' on board '${ref.boardId}' for '${ref.playerId}' has no container zone.`
19197
19447
  );
19198
19448
  }
19199
19449
  return {
19200
19450
  kind: "space",
19201
19451
  boardId: board.id,
19202
- spaceId: ref.spaceId
19452
+ spaceId: ref.spaceId,
19453
+ zoneId: space.zoneId
19203
19454
  };
19204
19455
  }
19205
19456
  function readContainerComponents(table, ref) {
@@ -20150,7 +20401,7 @@ function materializeAccept(pending) {
20150
20401
  }
20151
20402
 
20152
20403
  // ../../packages/reducer-contract/generated/version.ts
20153
- var REDUCER_CONTRACT_VERSION = "7.0.1";
20404
+ var REDUCER_CONTRACT_VERSION = "7.0.0";
20154
20405
 
20155
20406
  // ../../packages/app-sdk/src/reducer/ingress/runtime-payload.ts
20156
20407
  var runtimePayloadSchema = external_exports.lazy(
@@ -20826,7 +21077,7 @@ function createReducerBundle(definition) {
20826
21077
  // src/utils/ts-module-loader.ts
20827
21078
  import { mkdtemp as mkdtemp2, rm as rm4, writeFile as writeFile3 } from "fs/promises";
20828
21079
  import { tmpdir as tmpdir2 } from "os";
20829
- import path17 from "path";
21080
+ import path18 from "path";
20830
21081
  import { pathToFileURL as pathToFileURL2 } from "url";
20831
21082
  import { build as build2 } from "esbuild";
20832
21083
  var ESBUILD_EXTERNALS = [
@@ -20840,14 +21091,14 @@ function resolveSourceCheckoutBuildContext() {
20840
21091
  const repoRoot = resolveCliRepoRoot(import.meta.url);
20841
21092
  return {
20842
21093
  nodePaths: [
20843
- path17.join(repoRoot, "apps", "dreamboard-cli", "node_modules"),
20844
- path17.join(repoRoot, "node_modules")
21094
+ path18.join(repoRoot, "apps", "dreamboard-cli", "node_modules"),
21095
+ path18.join(repoRoot, "node_modules")
20845
21096
  ],
20846
21097
  plugins: [createRepoLocalPackageResolutionPlugin({ repoRoot })]
20847
21098
  };
20848
21099
  } catch {
20849
21100
  return {
20850
- nodePaths: [path17.join(process.cwd(), "node_modules")],
21101
+ nodePaths: [path18.join(process.cwd(), "node_modules")],
20851
21102
  plugins: []
20852
21103
  };
20853
21104
  }
@@ -20873,10 +21124,10 @@ async function bundleTypeScriptModuleText(entryPath, options = {}) {
20873
21124
  return output.text;
20874
21125
  }
20875
21126
  async function importTypeScriptModule(entryPath) {
20876
- const tempDir = await mkdtemp2(path17.join(tmpdir2(), "dreamboard-ts-module-"));
20877
- const outfile = path17.join(
21127
+ const tempDir = await mkdtemp2(path18.join(tmpdir2(), "dreamboard-ts-module-"));
21128
+ const outfile = path18.join(
20878
21129
  tempDir,
20879
- `${path17.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
21130
+ `${path18.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
20880
21131
  );
20881
21132
  try {
20882
21133
  const bundledText = await bundleTypeScriptModuleText(entryPath);
@@ -20901,7 +21152,7 @@ import {
20901
21152
  symlink
20902
21153
  } from "fs/promises";
20903
21154
  import { tmpdir as tmpdir3 } from "os";
20904
- import path18 from "path";
21155
+ import path19 from "path";
20905
21156
  import { createInterface } from "readline";
20906
21157
  import { fileURLToPath as fileURLToPath7 } from "url";
20907
21158
  var READY_PREFIX = "HARNESS_READY ";
@@ -20909,15 +21160,15 @@ var HARNESS_START_IDLE_TIMEOUT_MS = 18e4;
20909
21160
  var HARNESS_START_MAX_TIMEOUT_MS = 6e5;
20910
21161
  var HARNESS_STOP_TIMEOUT_MS = 1e4;
20911
21162
  var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
20912
- var MODULE_DIR4 = path18.dirname(fileURLToPath7(import.meta.url));
20913
- var REPO_ROOT3 = path18.resolve(MODULE_DIR4, "../../../../..");
20914
- var PROJECT_DEPENDENCY_NODE_MODULES = path18.join(
21163
+ var MODULE_DIR4 = path19.dirname(fileURLToPath7(import.meta.url));
21164
+ var REPO_ROOT3 = path19.resolve(MODULE_DIR4, "../../../../..");
21165
+ var PROJECT_DEPENDENCY_NODE_MODULES = path19.join(
20915
21166
  REPO_ROOT3,
20916
21167
  "apps",
20917
21168
  "dreamboard-cli",
20918
21169
  "node_modules"
20919
21170
  );
20920
- var UI_SDK_NODE_MODULES = path18.join(
21171
+ var UI_SDK_NODE_MODULES = path19.join(
20921
21172
  REPO_ROOT3,
20922
21173
  "packages",
20923
21174
  "ui-sdk",
@@ -20927,8 +21178,8 @@ async function startEmbeddedHarnessSession(options) {
20927
21178
  const repoRoot = await resolveRepoRoot2(options.projectRoot);
20928
21179
  const gradlew = await resolveGradleLauncher(repoRoot);
20929
21180
  const fixture = await prepareLocalHarnessFixture(options);
20930
- const logDir = path18.join(options.projectRoot, "test", "generated");
20931
- const logFilePath = path18.join(logDir, "embedded-harness.log");
21181
+ const logDir = path19.join(options.projectRoot, "test", "generated");
21182
+ const logFilePath = path19.join(logDir, "embedded-harness.log");
20932
21183
  await mkdir2(logDir, { recursive: true });
20933
21184
  const previousClientConfig = client.getConfig();
20934
21185
  const child = spawn5(
@@ -20937,7 +21188,7 @@ async function startEmbeddedHarnessSession(options) {
20937
21188
  ...gradlew.args,
20938
21189
  "--console=plain",
20939
21190
  ":apps:backend:runEmbeddedHarness",
20940
- `-PharnessManifestPath=${path18.join(options.projectRoot, MATERIALIZED_MANIFEST_FILE)}`,
21191
+ `-PharnessManifestPath=${path19.join(options.projectRoot, MATERIALIZED_MANIFEST_FILE)}`,
20941
21192
  `-PharnessBundlePath=${fixture.bundleRoot}`,
20942
21193
  `-PharnessGameId=${fixture.gameId}`,
20943
21194
  `-PharnessManifestId=${fixture.manifestId}`,
@@ -21004,7 +21255,7 @@ async function ensureSymlink(targetPath, linkPath) {
21004
21255
  if (await pathExists3(linkPath)) {
21005
21256
  return;
21006
21257
  }
21007
- await mkdir2(path18.dirname(linkPath), { recursive: true });
21258
+ await mkdir2(path19.dirname(linkPath), { recursive: true });
21008
21259
  await symlink(
21009
21260
  targetPath,
21010
21261
  linkPath,
@@ -21015,13 +21266,13 @@ async function ensureEmbeddedHarnessDependencies(projectRoot) {
21015
21266
  if (await pathExists3(PROJECT_DEPENDENCY_NODE_MODULES)) {
21016
21267
  await ensureSymlink(
21017
21268
  PROJECT_DEPENDENCY_NODE_MODULES,
21018
- path18.join(projectRoot, "node_modules")
21269
+ path19.join(projectRoot, "node_modules")
21019
21270
  );
21020
21271
  }
21021
21272
  if (await pathExists3(UI_SDK_NODE_MODULES)) {
21022
21273
  await ensureSymlink(
21023
21274
  UI_SDK_NODE_MODULES,
21024
- path18.join(projectRoot, "ui", "node_modules")
21275
+ path19.join(projectRoot, "ui", "node_modules")
21025
21276
  );
21026
21277
  }
21027
21278
  }
@@ -21031,15 +21282,15 @@ async function prepareLocalHarnessFixture(options) {
21031
21282
  const manifestContent = await readMaterializedManifestText(
21032
21283
  options.projectRoot
21033
21284
  );
21034
- const appEntryPath = path18.join(options.projectRoot, "app", "index.ts");
21285
+ const appEntryPath = path19.join(options.projectRoot, "app", "index.ts");
21035
21286
  if (!await exists(appEntryPath)) {
21036
21287
  throw new Error(
21037
- `Embedded harness requires ${path18.relative(options.projectRoot, appEntryPath)}.`
21288
+ `Embedded harness requires ${path19.relative(options.projectRoot, appEntryPath)}.`
21038
21289
  );
21039
21290
  }
21040
- const bundleRoot = await mkdtemp3(path18.join(tmpdir3(), "dreamboard-harness-"));
21041
- const bundleEntryPath = path18.join(bundleRoot, "src", "app", "index.js");
21042
- await mkdir2(path18.dirname(bundleEntryPath), { recursive: true });
21291
+ const bundleRoot = await mkdtemp3(path19.join(tmpdir3(), "dreamboard-harness-"));
21292
+ const bundleEntryPath = path19.join(bundleRoot, "src", "app", "index.js");
21293
+ await mkdir2(path19.dirname(bundleEntryPath), { recursive: true });
21043
21294
  const bunExecutable = await resolveBunExecutable();
21044
21295
  if (!bunExecutable) {
21045
21296
  await rm5(bundleRoot, { recursive: true, force: true });
@@ -21076,7 +21327,7 @@ async function prepareLocalHarnessFixture(options) {
21076
21327
  const bundleContent = await readFile3(bundleEntryPath, "utf8");
21077
21328
  const manifestHash = hashContent(manifestContent);
21078
21329
  const bundleHash = hashContent(bundleContent);
21079
- const gameSlug = options.projectConfig.slug || path18.basename(options.projectRoot);
21330
+ const gameSlug = options.projectConfig.slug || path19.basename(options.projectRoot);
21080
21331
  const authoring = getProjectAuthoringState(options.projectConfig);
21081
21332
  return {
21082
21333
  bundleRoot,
@@ -21096,14 +21347,14 @@ async function prepareLocalHarnessFixture(options) {
21096
21347
  };
21097
21348
  }
21098
21349
  async function resolveBunExecutable() {
21099
- const currentExecutable = path18.basename(process.execPath).toLowerCase();
21350
+ const currentExecutable = path19.basename(process.execPath).toLowerCase();
21100
21351
  if (currentExecutable === "bun" || currentExecutable === "bun.exe") {
21101
21352
  return process.execPath;
21102
21353
  }
21103
21354
  const candidatePaths = [
21104
- ...(process.env.PATH ?? "").split(path18.delimiter).filter((directory) => directory.length > 0).flatMap((directory) => executableCandidates(directory, "bun")),
21105
- ...process.env.BUN_INSTALL ? executableCandidates(path18.join(process.env.BUN_INSTALL, "bin"), "bun") : [],
21106
- ...process.env.HOME ? executableCandidates(path18.join(process.env.HOME, ".bun", "bin"), "bun") : []
21355
+ ...(process.env.PATH ?? "").split(path19.delimiter).filter((directory) => directory.length > 0).flatMap((directory) => executableCandidates(directory, "bun")),
21356
+ ...process.env.BUN_INSTALL ? executableCandidates(path19.join(process.env.BUN_INSTALL, "bin"), "bun") : [],
21357
+ ...process.env.HOME ? executableCandidates(path19.join(process.env.HOME, ".bun", "bin"), "bun") : []
21107
21358
  ];
21108
21359
  for (const candidate of candidatePaths) {
21109
21360
  try {
@@ -21119,11 +21370,11 @@ function executableCandidates(directory, executableName) {
21119
21370
  return [];
21120
21371
  }
21121
21372
  if (process.platform !== "win32") {
21122
- return [path18.join(directory, executableName)];
21373
+ return [path19.join(directory, executableName)];
21123
21374
  }
21124
21375
  const extensions = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter((extension) => extension.length > 0);
21125
21376
  return extensions.map(
21126
- (extension) => path18.join(directory, `${executableName}${extension.toLowerCase()}`)
21377
+ (extension) => path19.join(directory, `${executableName}${extension.toLowerCase()}`)
21127
21378
  );
21128
21379
  }
21129
21380
  async function waitForExitCode(child) {
@@ -21281,13 +21532,13 @@ async function waitForExit(child, timeoutMs) {
21281
21532
  }
21282
21533
  async function resolveGradleLauncher(repoRoot) {
21283
21534
  if (process.platform === "win32") {
21284
- const gradleBat = path18.join(repoRoot, "gradlew.bat");
21535
+ const gradleBat = path19.join(repoRoot, "gradlew.bat");
21285
21536
  if (!await exists(gradleBat)) {
21286
21537
  throw new Error(`Missing Gradle launcher at ${gradleBat}`);
21287
21538
  }
21288
21539
  return { command: gradleBat, args: [] };
21289
21540
  }
21290
- const gradleShell = path18.join(repoRoot, "gradlew");
21541
+ const gradleShell = path19.join(repoRoot, "gradlew");
21291
21542
  if (!await exists(gradleShell)) {
21292
21543
  throw new Error(`Missing Gradle launcher at ${gradleShell}`);
21293
21544
  }
@@ -21295,7 +21546,7 @@ async function resolveGradleLauncher(repoRoot) {
21295
21546
  }
21296
21547
  async function resolveRepoRoot2(projectRoot) {
21297
21548
  const currentFile = fileURLToPath7(import.meta.url);
21298
- const searchRoots = [path18.dirname(currentFile), projectRoot, process.cwd()];
21549
+ const searchRoots = [path19.dirname(currentFile), projectRoot, process.cwd()];
21299
21550
  for (const root of searchRoots) {
21300
21551
  const repoRoot = await findSourceCheckoutRepoRoot(root);
21301
21552
  if (repoRoot) {
@@ -21307,12 +21558,12 @@ async function resolveRepoRoot2(projectRoot) {
21307
21558
  );
21308
21559
  }
21309
21560
  async function findSourceCheckoutRepoRoot(startDir) {
21310
- let currentDir = path18.resolve(startDir);
21561
+ let currentDir = path19.resolve(startDir);
21311
21562
  while (true) {
21312
21563
  if (await isSourceCheckoutRepoRoot(currentDir)) {
21313
21564
  return currentDir;
21314
21565
  }
21315
- const parentDir = path18.dirname(currentDir);
21566
+ const parentDir = path19.dirname(currentDir);
21316
21567
  if (parentDir === currentDir) {
21317
21568
  return null;
21318
21569
  }
@@ -21320,7 +21571,7 @@ async function findSourceCheckoutRepoRoot(startDir) {
21320
21571
  }
21321
21572
  }
21322
21573
  async function isSourceCheckoutRepoRoot(rootDir) {
21323
- return await exists(path18.join(rootDir, "gradlew")) && await exists(path18.join(rootDir, "apps", "backend", "build.gradle.kts"));
21574
+ return await exists(path19.join(rootDir, "gradlew")) && await exists(path19.join(rootDir, "apps", "backend", "build.gradle.kts"));
21324
21575
  }
21325
21576
  function normalizeUuid(candidate, fallbackSeed) {
21326
21577
  if (candidate && UUID_PATTERN.test(candidate)) {
@@ -21371,8 +21622,8 @@ async function subscribeToCliSessionEvents(options) {
21371
21622
  }
21372
21623
 
21373
21624
  // src/ui/playwright-runner.ts
21374
- import os from "os";
21375
- import path19 from "path";
21625
+ import os2 from "os";
21626
+ import path20 from "path";
21376
21627
  function configurePlaywrightBrowsersPath() {
21377
21628
  if (process.env.PLAYWRIGHT_BROWSERS_PATH) {
21378
21629
  return;
@@ -21380,14 +21631,14 @@ function configurePlaywrightBrowsersPath() {
21380
21631
  const runtimeHome = process.env.HOME;
21381
21632
  let realHome;
21382
21633
  try {
21383
- realHome = os.userInfo().homedir;
21634
+ realHome = os2.userInfo().homedir;
21384
21635
  } catch {
21385
21636
  return;
21386
21637
  }
21387
- if (!runtimeHome || path19.resolve(runtimeHome) === path19.resolve(realHome)) {
21638
+ if (!runtimeHome || path20.resolve(runtimeHome) === path20.resolve(realHome)) {
21388
21639
  return;
21389
21640
  }
21390
- const browserCachePath = process.platform === "darwin" ? path19.join(realHome, "Library", "Caches", "ms-playwright") : process.platform === "win32" ? path19.join(realHome, "AppData", "Local", "ms-playwright") : path19.join(realHome, ".cache", "ms-playwright");
21641
+ const browserCachePath = process.platform === "darwin" ? path20.join(realHome, "Library", "Caches", "ms-playwright") : process.platform === "win32" ? path20.join(realHome, "AppData", "Local", "ms-playwright") : path20.join(realHome, ".cache", "ms-playwright");
21391
21642
  process.env.PLAYWRIGHT_BROWSERS_PATH = browserCachePath;
21392
21643
  }
21393
21644
  async function buildBrowserAuthInitScript(config) {
@@ -21396,7 +21647,7 @@ async function buildBrowserAuthInitScript(config) {
21396
21647
  return `(function(){localStorage.setItem('supabase_token',${JSON.stringify(config.authToken)});})();`;
21397
21648
  }
21398
21649
  try {
21399
- const { createClient: createClient2 } = await import("./dist-WJRJNFLI.js");
21650
+ const { createClient: createClient2 } = await import("./dist-FRURQI7Q.js");
21400
21651
  const supabase = createClient2(config.supabaseUrl, config.supabaseAnonKey);
21401
21652
  let sessionData = null;
21402
21653
  if (!sessionData) {
@@ -21490,42 +21741,9 @@ var TESTING_TYPES_STUB2 = "export function defineScenario(scenario) { return sce
21490
21741
  var DEFAULT_TIMEOUT_MS = 1e4;
21491
21742
  var BASE_SUFFIX = ".base.ts";
21492
21743
  var SCENARIO_SUFFIX = ".scenario.ts";
21493
- function formatScenarioErrorForDisplay(options) {
21494
- const message = options.error.message || "Scenario failed.";
21495
- const scenarioFrame = findScenarioStackFrame({
21496
- stack: options.error.stack,
21497
- projectRoot: options.projectRoot,
21498
- scenarioFilePath: options.scenarioFilePath
21499
- });
21500
- return scenarioFrame ? `${message}
21501
- ${scenarioFrame}` : message;
21502
- }
21503
- function findScenarioStackFrame(options) {
21504
- if (!options.stack) {
21505
- return null;
21506
- }
21507
- const absolutePath = path20.resolve(options.scenarioFilePath);
21508
- const relativePath = path20.relative(options.projectRoot, absolutePath);
21509
- const normalizedRelativePath = relativePath.split(path20.sep).join("/");
21510
- const escapedAbsolutePath = escapeRegExp(absolutePath);
21511
- const escapedRelativePath = escapeRegExp(normalizedRelativePath);
21512
- const absoluteFrame = new RegExp(`${escapedAbsolutePath}:(\\d+):(\\d+)`);
21513
- const relativeFrame = new RegExp(`${escapedRelativePath}:(\\d+):(\\d+)`);
21514
- for (const line of options.stack.split("\n")) {
21515
- const normalizedLine = line.split(path20.sep).join("/");
21516
- const match = normalizedLine.match(absoluteFrame) ?? normalizedLine.match(relativeFrame);
21517
- if (match?.[1] && match?.[2]) {
21518
- return `at ${normalizedRelativePath}:${match[1]}:${match[2]}`;
21519
- }
21520
- }
21521
- return null;
21522
- }
21523
- function escapeRegExp(value) {
21524
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21525
- }
21526
21744
  var testingExpectApiFactoryPromise;
21527
21745
  async function loadTestingExpectApiFactory() {
21528
- testingExpectApiFactoryPromise ??= import("./src-CUL7EGGG.js").then(
21746
+ testingExpectApiFactoryPromise ??= import("./dist-FEPN3BDN.js").then(
21529
21747
  (module) => module.createExpectApi
21530
21748
  );
21531
21749
  return testingExpectApiFactoryPromise;
@@ -21565,7 +21783,7 @@ async function discoverFiles(root, suffix) {
21565
21783
  const entries = await readdir3(root, { withFileTypes: true });
21566
21784
  const files = [];
21567
21785
  for (const entry of entries) {
21568
- const entryPath = path20.join(root, entry.name);
21786
+ const entryPath = path21.join(root, entry.name);
21569
21787
  if (entry.isDirectory()) {
21570
21788
  files.push(...await discoverFiles(entryPath, suffix));
21571
21789
  continue;
@@ -21614,38 +21832,38 @@ function parseTypedScenarioDefinition(value) {
21614
21832
  };
21615
21833
  }
21616
21834
  async function isReducerNativeTestingWorkspace(projectRoot) {
21617
- return await exists(path20.join(projectRoot, "app", "game.ts")) && await exists(
21618
- path20.join(projectRoot, "shared", "generated", "ui-contract.ts")
21835
+ return await exists(path21.join(projectRoot, "app", "game.ts")) && await exists(
21836
+ path21.join(projectRoot, "shared", "generated", "ui-contract.ts")
21619
21837
  );
21620
21838
  }
21621
21839
  async function ensureReducerNativeTestingFiles(projectRoot) {
21622
- const testingTypesPath = path20.join(projectRoot, "test", "testing-types.ts");
21623
- const testingContractPath = path20.join(
21840
+ const testingTypesPath = path21.join(projectRoot, "test", "testing-types.ts");
21841
+ const testingContractPath = path21.join(
21624
21842
  projectRoot,
21625
21843
  "test",
21626
21844
  "generated",
21627
21845
  "testing-contract.ts"
21628
21846
  );
21629
- const baseStatesPath = path20.join(
21847
+ const baseStatesPath = path21.join(
21630
21848
  projectRoot,
21631
21849
  "test",
21632
21850
  "generated",
21633
21851
  "base-states.generated.ts"
21634
21852
  );
21635
- const baseStatesDtsPath = path20.join(
21853
+ const baseStatesDtsPath = path21.join(
21636
21854
  projectRoot,
21637
21855
  "test",
21638
21856
  "generated",
21639
21857
  "base-states.generated.d.ts"
21640
21858
  );
21641
- const scenarioManifestPath = path20.join(
21859
+ const scenarioManifestPath = path21.join(
21642
21860
  projectRoot,
21643
21861
  "test",
21644
21862
  "generated",
21645
21863
  "scenario-manifest.generated.ts"
21646
21864
  );
21647
- await ensureDir(path20.dirname(testingTypesPath));
21648
- await ensureDir(path20.dirname(testingContractPath));
21865
+ await ensureDir(path21.dirname(testingTypesPath));
21866
+ await ensureDir(path21.dirname(testingContractPath));
21649
21867
  const existingTestingTypes = await readTextFileIfExists(testingTypesPath);
21650
21868
  if (shouldRefreshReducerTestingTypes(existingTestingTypes)) {
21651
21869
  await writeTextFile(
@@ -21689,7 +21907,7 @@ var DEFAULT_REJECTION_CODES2 = [
21689
21907
  ];
21690
21908
  async function collectKnownRejectionCodes(projectRoot) {
21691
21909
  const knownCodes = new Set(DEFAULT_REJECTION_CODES2);
21692
- const gamePath = path20.join(projectRoot, "app", "game.ts");
21910
+ const gamePath = path21.join(projectRoot, "app", "game.ts");
21693
21911
  if (!await exists(gamePath)) {
21694
21912
  return Array.from(knownCodes).sort(
21695
21913
  (left, right) => left.localeCompare(right)
@@ -21716,7 +21934,7 @@ async function collectKnownRejectionCodes(projectRoot) {
21716
21934
  }
21717
21935
  async function loadTypedBases(projectRoot) {
21718
21936
  const baseFiles = await discoverFiles(
21719
- path20.join(projectRoot, "test", "bases"),
21937
+ path21.join(projectRoot, "test", "bases"),
21720
21938
  BASE_SUFFIX
21721
21939
  );
21722
21940
  const loaded = [];
@@ -21735,8 +21953,8 @@ async function loadTypedBases(projectRoot) {
21735
21953
  return loaded;
21736
21954
  }
21737
21955
  async function loadTypedScenarios(projectRoot, options) {
21738
- const scenarioFiles = options.scenarioPath ? [path20.resolve(projectRoot, options.scenarioPath)] : await discoverFiles(
21739
- path20.join(projectRoot, "test", "scenarios"),
21956
+ const scenarioFiles = options.scenarioPath ? [path21.resolve(projectRoot, options.scenarioPath)] : await discoverFiles(
21957
+ path21.join(projectRoot, "test", "scenarios"),
21740
21958
  SCENARIO_SUFFIX
21741
21959
  );
21742
21960
  const loaded = [];
@@ -21755,8 +21973,8 @@ async function loadTypedScenarios(projectRoot, options) {
21755
21973
  return loaded;
21756
21974
  }
21757
21975
  function reducerNativeTestHelperExternals(projectRoot, filePath) {
21758
- const testingTypesPath = path20.join(projectRoot, "test", "testing-types");
21759
- const relative = path20.relative(path20.dirname(filePath), testingTypesPath).replaceAll("\\", "/");
21976
+ const testingTypesPath = path21.join(projectRoot, "test", "testing-types");
21977
+ const relative = path21.relative(path21.dirname(filePath), testingTypesPath).replaceAll("\\", "/");
21760
21978
  const specifier = relative.startsWith(".") ? relative : `./${relative}`;
21761
21979
  return [specifier, `${specifier}.ts`];
21762
21980
  }
@@ -21957,6 +22175,13 @@ var ShadowReducerRuntime = class {
21957
22175
  (_2, index) => `player-${index + 1}`
21958
22176
  );
21959
22177
  }
22178
+ manifest;
22179
+ gameModuleDefault;
22180
+ createInitialTable;
22181
+ seed;
22182
+ players;
22183
+ setupProfileId;
22184
+ debug;
21960
22185
  bundle;
21961
22186
  runtime;
21962
22187
  playerIds;
@@ -22101,6 +22326,8 @@ var EmbeddedGameplayTracker = class {
22101
22326
  this.playerId = playerId;
22102
22327
  this.state.playerId = playerId;
22103
22328
  }
22329
+ sessionId;
22330
+ playerId;
22104
22331
  abortController = new AbortController();
22105
22332
  state = {
22106
22333
  version: -1,
@@ -22252,7 +22479,7 @@ async function assertLiveMatchesShadow(runner, shadow, live) {
22252
22479
  }
22253
22480
  }
22254
22481
  async function loadBrowserDriver(projectRoot) {
22255
- const filePath = path20.join(projectRoot, "test", "browser-driver.ts");
22482
+ const filePath = path21.join(projectRoot, "test", "browser-driver.ts");
22256
22483
  if (!await exists(filePath)) {
22257
22484
  return null;
22258
22485
  }
@@ -22280,7 +22507,7 @@ function sanitizeSnapshotSegment(value) {
22280
22507
  function createScenarioSnapshotMatcher(options) {
22281
22508
  return (filename, actual) => {
22282
22509
  const suffix = filename ? `.${sanitizeSnapshotSegment(filename)}` : "";
22283
- const snapshotPath = path20.join(
22510
+ const snapshotPath = path21.join(
22284
22511
  options.projectRoot,
22285
22512
  "test",
22286
22513
  "generated",
@@ -22292,15 +22519,15 @@ function createScenarioSnapshotMatcher(options) {
22292
22519
  };
22293
22520
  const serialized = `${JSON.stringify(wrappedValue, null, 2)}
22294
22521
  `;
22295
- mkdirSync2(path20.dirname(snapshotPath), { recursive: true });
22522
+ mkdirSync2(path21.dirname(snapshotPath), { recursive: true });
22296
22523
  if (!existsSync8(snapshotPath) || options.updateSnapshots) {
22297
22524
  writeFileSync2(snapshotPath, serialized, "utf8");
22298
22525
  return;
22299
22526
  }
22300
- const previous = JSON.parse(readFileSync4(snapshotPath, "utf8"));
22527
+ const previous = JSON.parse(readFileSync3(snapshotPath, "utf8"));
22301
22528
  if (!deepEqual(previous.value, actual)) {
22302
22529
  throw new Error(
22303
- `Snapshot mismatch for scenario '${options.scenarioId}'. Re-run with --update-snapshots to refresh ${path20.relative(options.projectRoot, snapshotPath)}.`
22530
+ `Snapshot mismatch for scenario '${options.scenarioId}'. Re-run with --update-snapshots to refresh ${path21.relative(options.projectRoot, snapshotPath)}.`
22304
22531
  );
22305
22532
  }
22306
22533
  };
@@ -22561,7 +22788,7 @@ async function createSessionFromScenario(options) {
22561
22788
  }
22562
22789
  var MATERIALIZED_SCENARIO_CACHE_VERSION = 1;
22563
22790
  function materializedScenarioCachePath(options) {
22564
- return path20.join(
22791
+ return path21.join(
22565
22792
  options.projectRoot,
22566
22793
  PROJECT_DIR_NAME,
22567
22794
  "dev",
@@ -22589,7 +22816,7 @@ async function readMaterializedScenarioCache(options) {
22589
22816
  }
22590
22817
  async function writeMaterializedScenarioCache(options) {
22591
22818
  const cachePath = materializedScenarioCachePath(options);
22592
- await ensureDir(path20.dirname(cachePath));
22819
+ await ensureDir(path21.dirname(cachePath));
22593
22820
  await writeJsonFile(cachePath, {
22594
22821
  cacheVersion: MATERIALIZED_SCENARIO_CACHE_VERSION,
22595
22822
  fingerprintHash: options.fingerprintHash,
@@ -22686,10 +22913,10 @@ async function materializeScenarioReducerState(options) {
22686
22913
  }
22687
22914
  const [gameModule, manifestContractModule] = await Promise.all([
22688
22915
  importTypeScriptModule(
22689
- path20.join(options.projectRoot, "app", "game.ts")
22916
+ path21.join(options.projectRoot, "app", "game.ts")
22690
22917
  ),
22691
22918
  importTypeScriptModule(
22692
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
22919
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
22693
22920
  )
22694
22921
  ]);
22695
22922
  const createInitialTable = typeof manifestContractModule.createInitialTable === "function" ? manifestContractModule.createInitialTable : null;
@@ -22771,10 +22998,10 @@ async function createScenarioActionPlan(options) {
22771
22998
  loadGeneratedBaseStates(options.projectRoot),
22772
22999
  loadManifest(options.projectRoot),
22773
23000
  importTypeScriptModule(
22774
- path20.join(options.projectRoot, "app", "game.ts")
23001
+ path21.join(options.projectRoot, "app", "game.ts")
22775
23002
  ),
22776
23003
  importTypeScriptModule(
22777
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23004
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
22778
23005
  )
22779
23006
  ]);
22780
23007
  const matchingScenarios = scenarios.filter(
@@ -23041,7 +23268,7 @@ function sortBasesForArtifacts(bases, basesById) {
23041
23268
  return ordered;
23042
23269
  }
23043
23270
  function writeProjectionSnapshots(options) {
23044
- const projectionDir = path20.join(
23271
+ const projectionDir = path21.join(
23045
23272
  options.projectRoot,
23046
23273
  "test",
23047
23274
  "generated",
@@ -23052,7 +23279,7 @@ function writeProjectionSnapshots(options) {
23052
23279
  mkdirSync2(projectionDir, { recursive: true });
23053
23280
  const projection = options.shadow.projectAllSeats();
23054
23281
  for (const [playerId, seatProjection] of Object.entries(projection.seats)) {
23055
- const outputPath = path20.join(projectionDir, `${playerId}.projection.json`);
23282
+ const outputPath = path21.join(projectionDir, `${playerId}.projection.json`);
23056
23283
  writeFileSync2(
23057
23284
  outputPath,
23058
23285
  `${JSON.stringify(
@@ -23072,7 +23299,7 @@ function writeProjectionSnapshots(options) {
23072
23299
  function validateTypedScenarioBases(scenarios, basesById) {
23073
23300
  const available = new Set(basesById.keys());
23074
23301
  const invalid = scenarios.filter((scenario) => !available.has(scenario.definition.from)).map(
23075
- (scenario) => path20.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.definition.from}'`
23302
+ (scenario) => path21.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.definition.from}'`
23076
23303
  );
23077
23304
  if (invalid.length > 0) {
23078
23305
  throw new Error(
@@ -23086,23 +23313,23 @@ async function writeReducerNativeGeneratedFiles(options) {
23086
23313
  const manifestHash = hashContent(JSON.stringify(manifest));
23087
23314
  const appBundleHash = hashContent(
23088
23315
  await bundleTypeScriptModuleText(
23089
- path20.join(options.projectRoot, "app", "game.ts")
23316
+ path21.join(options.projectRoot, "app", "game.ts")
23090
23317
  )
23091
23318
  );
23092
23319
  const uiContractHash = hashContent(
23093
23320
  await bundleTypeScriptModuleText(
23094
- path20.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23321
+ path21.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23095
23322
  )
23096
23323
  );
23097
- const generatedDir = path20.join(options.projectRoot, "test", "generated");
23324
+ const generatedDir = path21.join(options.projectRoot, "test", "generated");
23098
23325
  await ensureDir(generatedDir);
23099
23326
  const baseStates = {};
23100
23327
  const [gameModule, manifestContractModule] = await Promise.all([
23101
23328
  importTypeScriptModule(
23102
- path20.join(options.projectRoot, "app", "game.ts")
23329
+ path21.join(options.projectRoot, "app", "game.ts")
23103
23330
  ),
23104
23331
  importTypeScriptModule(
23105
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23332
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
23106
23333
  )
23107
23334
  ]);
23108
23335
  const createInitialTable = typeof manifestContractModule.createInitialTable === "function" ? manifestContractModule.createInitialTable : null;
@@ -23190,21 +23417,21 @@ async function writeReducerNativeGeneratedFiles(options) {
23190
23417
  }
23191
23418
  const header = "// Generated by dreamboard test generate. Do not edit by hand.\n";
23192
23419
  await writeTextFile(
23193
- path20.join(generatedDir, "base-states.generated.ts"),
23420
+ path21.join(generatedDir, "base-states.generated.ts"),
23194
23421
  `${header}export const BASE_STATES = ${JSON.stringify(baseStates, null, 2)} as const;
23195
23422
  `
23196
23423
  );
23197
23424
  await writeTextFile(
23198
- path20.join(generatedDir, "base-states.generated.d.ts"),
23425
+ path21.join(generatedDir, "base-states.generated.d.ts"),
23199
23426
  `${header}export declare const BASE_STATES: Record<string, unknown>;
23200
23427
  `
23201
23428
  );
23202
23429
  await writeTextFile(
23203
- path20.join(generatedDir, "scenario-manifest.generated.ts"),
23430
+ path21.join(generatedDir, "scenario-manifest.generated.ts"),
23204
23431
  `${header}export const SCENARIO_MANIFEST = ${JSON.stringify(
23205
23432
  options.scenarios.map((scenario) => ({
23206
23433
  id: scenario.definition.id,
23207
- filePath: path20.relative(generatedDir, scenario.filePath),
23434
+ filePath: path21.relative(generatedDir, scenario.filePath),
23208
23435
  base: scenario.definition.from,
23209
23436
  runners: normalizeScenarioRunners(scenario.definition.runners)
23210
23437
  })),
@@ -23213,14 +23440,14 @@ async function writeReducerNativeGeneratedFiles(options) {
23213
23440
  )} as const;
23214
23441
  `
23215
23442
  );
23216
- await writeJsonFile(path20.join(generatedDir, ".generation-meta.json"), {
23443
+ await writeJsonFile(path21.join(generatedDir, ".generation-meta.json"), {
23217
23444
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
23218
23445
  scenarioCount: options.scenarios.length,
23219
23446
  baseStateCount: options.bases.length
23220
23447
  });
23221
23448
  }
23222
23449
  async function loadGeneratedBaseStates(projectRoot) {
23223
- const filePath = path20.join(
23450
+ const filePath = path21.join(
23224
23451
  projectRoot,
23225
23452
  "test",
23226
23453
  "generated",
@@ -23233,7 +23460,7 @@ async function loadGeneratedBaseStates(projectRoot) {
23233
23460
  return module.BASE_STATES ?? null;
23234
23461
  }
23235
23462
  async function loadGeneratedScenarioManifest(projectRoot) {
23236
- const filePath = path20.join(
23463
+ const filePath = path21.join(
23237
23464
  projectRoot,
23238
23465
  "test",
23239
23466
  "generated",
@@ -23323,12 +23550,12 @@ async function currentFingerprint(options) {
23323
23550
  manifestHash: hashContent(JSON.stringify(manifest)),
23324
23551
  appBundleHash: hashContent(
23325
23552
  await bundleTypeScriptModuleText(
23326
- path20.join(options.projectRoot, "app", "game.ts")
23553
+ path21.join(options.projectRoot, "app", "game.ts")
23327
23554
  )
23328
23555
  ),
23329
23556
  uiContractHash: hashContent(
23330
23557
  await bundleTypeScriptModuleText(
23331
- path20.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23558
+ path21.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23332
23559
  )
23333
23560
  ),
23334
23561
  setupProfileId: effectiveSetup.setupProfileId,
@@ -23375,10 +23602,10 @@ async function runReducerNativeScenarios(options) {
23375
23602
  loadGeneratedBaseStates(options.projectRoot),
23376
23603
  loadManifest(options.projectRoot),
23377
23604
  importTypeScriptModule(
23378
- path20.join(options.projectRoot, "app", "game.ts")
23605
+ path21.join(options.projectRoot, "app", "game.ts")
23379
23606
  ),
23380
23607
  importTypeScriptModule(
23381
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23608
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
23382
23609
  )
23383
23610
  ]);
23384
23611
  let generatedBaseStates = initialGeneratedBaseStates;
@@ -23596,11 +23823,7 @@ async function runReducerNativeScenarios(options) {
23596
23823
  results.push({
23597
23824
  id: scenario.definition.id,
23598
23825
  success: false,
23599
- error: error instanceof Error ? formatScenarioErrorForDisplay({
23600
- error,
23601
- projectRoot: options.projectRoot,
23602
- scenarioFilePath: scenario.filePath
23603
- }) : `Scenario '${scenario.definition.id}' failed.`
23826
+ error: error instanceof Error ? error.message : `Scenario '${scenario.definition.id}' failed.`
23604
23827
  });
23605
23828
  }
23606
23829
  }
@@ -23616,8 +23839,8 @@ async function runReducerNativeScenarios(options) {
23616
23839
  }
23617
23840
 
23618
23841
  // src/services/project/reducer-contract-preflight.ts
23619
- import path21 from "path";
23620
- var GAME_CONTRACT_ENTRY_PATH = path21.join("app", "game-contract.ts");
23842
+ import path22 from "path";
23843
+ var GAME_CONTRACT_ENTRY_PATH = path22.join("app", "game-contract.ts");
23621
23844
  function normalizeErrorMessage(error) {
23622
23845
  const rawMessage = error instanceof Error ? error.message : String(error ?? "Unknown error");
23623
23846
  return rawMessage.split("\n").map((line) => line.trim()).find(Boolean)?.replace(/^Error:\s*/u, "") ?? "Unknown error";
@@ -23626,7 +23849,7 @@ function isManifestScopedIdBrandingError(message) {
23626
23849
  return message.includes("defineGameContract:") && message.includes("manifest-scoped") && (message.includes("uses a raw z.string()") || message.includes("uses z.array(z.string())"));
23627
23850
  }
23628
23851
  async function assertReducerContractPreflight(projectRoot) {
23629
- const entryPath = path21.join(projectRoot, GAME_CONTRACT_ENTRY_PATH);
23852
+ const entryPath = path22.join(projectRoot, GAME_CONTRACT_ENTRY_PATH);
23630
23853
  try {
23631
23854
  await importTypeScriptModule(entryPath);
23632
23855
  } catch (error) {
@@ -23652,8 +23875,8 @@ async function assertReducerContractPreflight(projectRoot) {
23652
23875
  }
23653
23876
 
23654
23877
  // src/services/project/reducer-bundle-preflight.ts
23655
- import path22 from "path";
23656
- var REDUCER_BUNDLE_ENTRY_PATH = path22.join("app", "index.ts");
23878
+ import path23 from "path";
23879
+ var REDUCER_BUNDLE_ENTRY_PATH = path23.join("app", "index.ts");
23657
23880
  var PREFLIGHT_RNG_SEED = 1337;
23658
23881
  function buildPlayerIds(playerCount) {
23659
23882
  const ids = [];
@@ -23841,7 +24064,7 @@ async function runReducerBundleSmoke(options) {
23841
24064
  if (scenarios.length === 0) {
23842
24065
  return [];
23843
24066
  }
23844
- const entryPath = path22.join(projectRoot, REDUCER_BUNDLE_ENTRY_PATH);
24067
+ const entryPath = path23.join(projectRoot, REDUCER_BUNDLE_ENTRY_PATH);
23845
24068
  let module;
23846
24069
  try {
23847
24070
  module = await importTypeScriptModule(
@@ -23893,6 +24116,64 @@ async function runLoggedStep(message, task) {
23893
24116
  consola.start(message);
23894
24117
  return task();
23895
24118
  }
24119
+ function clearPreflightOutput() {
24120
+ if (!process.stdout.isTTY || process.env.CI) return;
24121
+ console.clear();
24122
+ }
24123
+ function formatDevReadyOutput(options) {
24124
+ const lines = ["Dreamboard dev", "", `Local: ${options.url}`];
24125
+ for (const networkUrl of options.networkUrls) {
24126
+ lines.push(`Network: ${networkUrl}`);
24127
+ }
24128
+ if (options.networkUrls.length > 0) {
24129
+ lines.push("Access: LAN only; use trusted networks.");
24130
+ }
24131
+ for (const allowedHost of options.allowedHosts) {
24132
+ lines.push(`Allowed: ${allowedHost}`);
24133
+ }
24134
+ lines.push(
24135
+ `Session: ${options.shortCode} (${options.sessionId}, ${options.sessionStatus})`,
24136
+ `Seed: ${options.seed}`
24137
+ );
24138
+ if (options.setupProfile) {
24139
+ const label = options.setupProfile.name ? `${options.setupProfile.name} (${options.setupProfile.id})` : options.setupProfile.id;
24140
+ lines.push(`Setup: ${label}`);
24141
+ }
24142
+ if (options.scenarioId) {
24143
+ lines.push(`Scenario: ${options.scenarioId}`);
24144
+ }
24145
+ if (options.materialization) {
24146
+ lines.push(
24147
+ `Snapshot: ${options.materialization.totalMs}ms total (${options.materialization.reducerHarnessMs}ms reducer, ${options.materialization.backendHydrateMs}ms backend)`
24148
+ );
24149
+ }
24150
+ lines.push(
24151
+ `Backend: ${options.apiBaseUrl}`,
24152
+ "",
24153
+ "UI edits hot-reload. Rule, manifest, and app changes need restart.",
24154
+ `Debug logs: ${options.debug ? "on" : "off (--debug)"}`,
24155
+ ""
24156
+ );
24157
+ return lines.join("\n");
24158
+ }
24159
+ function parseDevHost(value) {
24160
+ if (value === void 0 || value === false) return void 0;
24161
+ if (value === true) return true;
24162
+ const trimmed = value.trim();
24163
+ return trimmed.length > 0 ? trimmed : true;
24164
+ }
24165
+ function parseAllowedHosts(value) {
24166
+ if (!value) return [];
24167
+ return value.split(",").map((host) => normalizeAllowedHost(host)).filter((host) => Boolean(host));
24168
+ }
24169
+ function normalizeAllowedHost(value) {
24170
+ const trimmed = value.trim();
24171
+ if (!trimmed) return null;
24172
+ if (trimmed.includes("://")) {
24173
+ return new URL(trimmed).hostname;
24174
+ }
24175
+ return trimmed.split("/")[0]?.replace(/:\d+$/, "") || null;
24176
+ }
23896
24177
  var dev_default = defineCommand({
23897
24178
  meta: {
23898
24179
  name: "dev",
@@ -23940,7 +24221,17 @@ var dev_default = defineCommand({
23940
24221
  },
23941
24222
  port: {
23942
24223
  type: "string",
23943
- description: "Preferred local Vite port (defaults to 5173)"
24224
+ description: "Preferred local Vite port (defaults to 5352)"
24225
+ },
24226
+ host: {
24227
+ type: "string",
24228
+ description: "Expose the local dev host on the network. Pass without a value to bind all interfaces, or provide an address.",
24229
+ valueHint: "address"
24230
+ },
24231
+ "allowed-host": {
24232
+ type: "string",
24233
+ description: "Additional Host header to allow, for example a Cloudflare Tunnel hostname.",
24234
+ valueHint: "hostname"
23944
24235
  },
23945
24236
  ...CONFIG_FLAG_ARGS
23946
24237
  },
@@ -23958,9 +24249,9 @@ var dev_default = defineCommand({
23958
24249
  env: parsedArgs.env ?? "dev",
23959
24250
  debug: parsedArgs.debug
23960
24251
  });
23961
- const devDir = path23.join(projectRoot, PROJECT_DIR_NAME, "dev");
24252
+ const devDir = path24.join(projectRoot, PROJECT_DIR_NAME, "dev");
23962
24253
  await ensureDir(devDir);
23963
- const sessionFilePath = path23.join(devDir, "session.json");
24254
+ const sessionFilePath = path24.join(devDir, "session.json");
23964
24255
  const requestedResumeSessionId = parsedArgs.resume?.trim() || null;
23965
24256
  const requestedScenarioId = parsedArgs["from-scenario"]?.trim() || null;
23966
24257
  if (requestedResumeSessionId && parsedArgs["new-session"]) {
@@ -24043,10 +24334,13 @@ var dev_default = defineCommand({
24043
24334
  if (preferredPort !== void 0 && (!Number.isFinite(preferredPort) || preferredPort <= 0)) {
24044
24335
  throw new Error("Invalid --port value. Expected a positive integer.");
24045
24336
  }
24337
+ const allowedHosts = parseAllowedHosts(parsedArgs["allowed-host"]);
24046
24338
  const devServer = await startDreamboardDevServer({
24047
24339
  projectRoot,
24048
24340
  sessionFilePath,
24049
24341
  port: preferredPort,
24342
+ host: parseDevHost(parsedArgs.host),
24343
+ allowedHosts,
24050
24344
  config,
24051
24345
  runtimeConfig: {
24052
24346
  apiBaseUrl: config.apiBaseUrl,
@@ -24066,42 +24360,26 @@ var dev_default = defineCommand({
24066
24360
  }
24067
24361
  }
24068
24362
  });
24069
- consola.success(`Dreamboard dev host ready at ${devServer.url}`);
24070
- consola.info(
24071
- scenarioSeededSession ? `Seeded session ${runSession.shortCode} (${runSession.sessionId}) from scenario ${requestedScenarioId}.` : resumedExistingSession ? `Reusing session ${runSession.shortCode} (${runSession.sessionId}).` : `Created session ${runSession.shortCode} (${runSession.sessionId}).`
24072
- );
24073
- if (requestedScenarioId && scenarioSeededSession) {
24074
- const materialization = runSession.materialization;
24075
- if (materialization) {
24076
- consola.info(
24077
- `Scenario materialization: mode=${materialization.mode} totalMs=${materialization.totalMs} reducerHarnessMs=${materialization.reducerHarnessMs} backendHydrateMs=${materialization.backendHydrateMs}`
24078
- );
24079
- }
24080
- }
24081
- consola.info(`Backend session id: ${runSession.sessionId}`);
24082
- consola.info(
24083
- `RNG seed: ${runSession.seed ?? "unknown"}${parsedArgs.seed ? " (from --seed)." : " (default 1337; change it in the dev host or pass --seed)."}`
24084
- );
24085
- if (selectedSetupProfile?.source === "implicit-single") {
24086
- consola.info(
24087
- `Using setup profile ${selectedSetupProfileId} (${selectedSetupProfile.name ?? selectedSetupProfileId}) because it is the only declared manifest profile.`
24088
- );
24089
- }
24090
- if (selectedSetupProfile?.source === "implicit-first") {
24091
- consola.info(
24092
- `Using setup profile ${selectedSetupProfileId} (${selectedSetupProfile.name ?? selectedSetupProfileId}) because it is the first declared manifest profile.`
24093
- );
24094
- }
24095
- consola.info(
24096
- parsedArgs.debug ? "Verbose dev logging enabled via --debug." : "Verbose browser and SSE logging is off by default. Pass --debug to enable it."
24097
- );
24098
- consola.info(
24099
- "UI edits will hot-reload in the iframe. Rule, manifest, and app changes require rerunning `dreamboard dev`."
24363
+ clearPreflightOutput();
24364
+ console.log(
24365
+ formatDevReadyOutput({
24366
+ url: devServer.url,
24367
+ networkUrls: devServer.networkUrls,
24368
+ allowedHosts,
24369
+ apiBaseUrl: config.apiBaseUrl,
24370
+ sessionStatus: scenarioSeededSession ? "seeded" : resumedExistingSession ? "reused" : "created",
24371
+ shortCode: runSession.shortCode,
24372
+ sessionId: runSession.sessionId,
24373
+ seed: runSession.seed ?? "unknown",
24374
+ debug: parsedArgs.debug,
24375
+ scenarioId: scenarioSeededSession ? requestedScenarioId : null,
24376
+ materialization: runSession.materialization,
24377
+ setupProfile: selectedSetupProfileId ? {
24378
+ id: selectedSetupProfileId,
24379
+ name: selectedSetupProfile?.name
24380
+ } : null
24381
+ })
24100
24382
  );
24101
- console.log(`
24102
- Open Dreamboard dev host:
24103
- ${devServer.url}
24104
- `);
24105
24383
  if (parsedArgs.open) {
24106
24384
  openBrowser(devServer.url);
24107
24385
  }
@@ -24308,7 +24586,7 @@ async function resolveBackendVersionMetadata() {
24308
24586
  }
24309
24587
  async function readWorkspacePackageJson(projectRoot) {
24310
24588
  try {
24311
- const raw = await readTextFile(path23.join(projectRoot, "package.json"));
24589
+ const raw = await readTextFile(path24.join(projectRoot, "package.json"));
24312
24590
  const parsed = JSON.parse(raw);
24313
24591
  return {
24314
24592
  dependencies: Object.fromEntries(
@@ -24446,7 +24724,7 @@ function extractUserIdFromJwt(token) {
24446
24724
  }
24447
24725
 
24448
24726
  // src/commands/join.ts
24449
- import path24 from "path";
24727
+ import path25 from "path";
24450
24728
 
24451
24729
  // src/services/join/jsonl-bot-session.ts
24452
24730
  import { createInterface as createInterface2 } from "readline";
@@ -24454,6 +24732,7 @@ var JsonlWriter = class {
24454
24732
  constructor(output) {
24455
24733
  this.output = output;
24456
24734
  }
24735
+ output;
24457
24736
  writeChain = Promise.resolve();
24458
24737
  write(envelope) {
24459
24738
  this.writeChain = this.writeChain.then(
@@ -24704,6 +24983,7 @@ var JoinBotState = class {
24704
24983
  constructor(playerId) {
24705
24984
  this.playerId = playerId;
24706
24985
  }
24986
+ playerId;
24707
24987
  hasBootstrap = false;
24708
24988
  latestGameplay;
24709
24989
  latestActions;
@@ -25366,7 +25646,7 @@ async function resolveDefaultSessionId(projectRoot) {
25366
25646
  "No session id provided and this directory is not a Dreamboard project. Pass --session or run from a workspace with .dreamboard/dev/session.json."
25367
25647
  );
25368
25648
  }
25369
- const sessionFilePath = path24.join(
25649
+ const sessionFilePath = path25.join(
25370
25650
  projectRoot,
25371
25651
  PROJECT_DIR_NAME,
25372
25652
  "dev",
@@ -25478,7 +25758,7 @@ var logout_default = defineCommand({
25478
25758
  });
25479
25759
 
25480
25760
  // src/commands/new.ts
25481
- import path25 from "path";
25761
+ import path26 from "path";
25482
25762
  var new_default = defineCommand({
25483
25763
  meta: {
25484
25764
  name: "new",
@@ -25599,7 +25879,7 @@ var new_default = defineCommand({
25599
25879
  ruleId
25600
25880
  );
25601
25881
  consola.start("Scaffolding local workspace...");
25602
- const targetDir = path25.resolve(process.cwd(), normalizedSlug);
25882
+ const targetDir = path26.resolve(process.cwd(), normalizedSlug);
25603
25883
  await ensureDir(targetDir);
25604
25884
  await writeManifest(targetDir, blankManifest);
25605
25885
  await writeRule(targetDir, "");
@@ -25631,7 +25911,6 @@ var new_default = defineCommand({
25631
25911
  )
25632
25912
  );
25633
25913
  await writeSnapshot(targetDir);
25634
- await writeTextFile(path25.join(targetDir, "feedback.md"), "");
25635
25914
  consola.success(`Created new game in ${targetDir}`);
25636
25915
  consola.info(
25637
25916
  "Next: edit your files, then run 'dreamboard sync' followed by 'dreamboard compile'."
@@ -25956,9 +26235,9 @@ function buildSourceChanges(options) {
25956
26235
  if (mode === "replace") {
25957
26236
  return Object.entries(localFiles).filter(
25958
26237
  ([filePath]) => isSourceRevisionPath(filePath) || shouldAlwaysUpsertSourcePath(filePath)
25959
- ).sort(([left], [right]) => left.localeCompare(right)).map(([path26, content]) => ({
26238
+ ).sort(([left], [right]) => left.localeCompare(right)).map(([path28, content]) => ({
25960
26239
  kind: "upsert",
25961
- path: path26,
26240
+ path: path28,
25962
26241
  content
25963
26242
  }));
25964
26243
  }
@@ -26510,6 +26789,10 @@ var sync_default = defineCommand({
26510
26789
  }
26511
26790
  });
26512
26791
 
26792
+ // src/commands/test.ts
26793
+ import { readFile as readFile4 } from "fs/promises";
26794
+ import path27 from "path";
26795
+
26513
26796
  // src/services/testing/runtime-mode.ts
26514
26797
  function isRemoteTestEnvironment(environment) {
26515
26798
  return environment === "dev" || environment === "prod";
@@ -26559,6 +26842,40 @@ async function resolveLatestCompiledResult(projectRoot, projectConfig) {
26559
26842
  var REDUCER_NATIVE_TEST_WORKSPACE_ERROR = "dreamboard test now requires a reducer-native workspace with app/game.ts, shared/generated/ui-contract.ts, test/bases/*.base.ts, and test/scenarios/*.scenario.ts. Legacy test/base-scenarios.json workspaces are no longer supported.";
26560
26843
  var NO_REDUCER_NATIVE_BASES_FOUND_ERROR = "No bases found under test/bases/*.base.ts";
26561
26844
  var NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR = "No scenarios found under test/scenarios/*.scenario.ts";
26845
+ function isPreviewProjectionEndpointUnavailable(error) {
26846
+ if (!isDreamboardApiError(error) || error.status !== 404) {
26847
+ return false;
26848
+ }
26849
+ const endpoint = error.problem.instance ?? error.problem.context?.endpoint;
26850
+ const message = error.problem.detail ?? error.problem.title;
26851
+ return endpoint?.includes("/preview/initial-projection") === true && message?.toLowerCase() === "not found";
26852
+ }
26853
+ async function uploadGeneratedPreviewProjection(options) {
26854
+ const previewBase = options.bases.find((base) => base.definition.id === "initial-turn") ?? options.bases[0];
26855
+ if (!previewBase) {
26856
+ return;
26857
+ }
26858
+ const projectionPath = path27.join(
26859
+ options.projectRoot,
26860
+ "test",
26861
+ "generated",
26862
+ "bases",
26863
+ previewBase.definition.id,
26864
+ "player-1.projection.json"
26865
+ );
26866
+ const projectionJson = await readFile4(projectionPath, "utf8");
26867
+ try {
26868
+ await uploadInitialProjectionSdk(options.gameId, projectionJson);
26869
+ } catch (error) {
26870
+ if (isPreviewProjectionEndpointUnavailable(error)) {
26871
+ consola.warn(
26872
+ "Skipping preview projection upload because the selected backend does not expose the preview projection endpoint."
26873
+ );
26874
+ return;
26875
+ }
26876
+ throw error;
26877
+ }
26878
+ }
26562
26879
  function resolveRequestedRunner(value) {
26563
26880
  if (value == null || value === "") {
26564
26881
  return void 0;
@@ -26617,7 +26934,7 @@ var generateCommand = defineCommand({
26617
26934
  async run({ args }) {
26618
26935
  const parsedFlags = parseConfigFlags(args);
26619
26936
  const useRemoteRuntime = shouldUseRemoteTestRuntime(parsedFlags.env);
26620
- const { projectRoot, projectConfig } = await resolveProjectContext(
26937
+ const { projectRoot, projectConfig, config } = await resolveProjectContext(
26621
26938
  parsedFlags,
26622
26939
  { requireAuth: useRemoteRuntime }
26623
26940
  );
@@ -26640,6 +26957,18 @@ var generateCommand = defineCommand({
26640
26957
  if (scenarios.length === 0) {
26641
26958
  throw new Error(NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR);
26642
26959
  }
26960
+ if (config.authToken) {
26961
+ await configureClient(config);
26962
+ await uploadGeneratedPreviewProjection({
26963
+ projectRoot,
26964
+ gameId: runtimeIdentity.gameId,
26965
+ bases
26966
+ });
26967
+ } else {
26968
+ consola.info(
26969
+ "Skipping preview projection upload because this CLI invocation is not authenticated."
26970
+ );
26971
+ }
26643
26972
  consola.success(
26644
26973
  `Generated ${bases.length} base state(s) for ${scenarios.length} scenario(s).`
26645
26974
  );
@@ -26786,7 +27115,7 @@ function runDreamboardCli(internalSubCommands = {}) {
26786
27115
  const main = defineCommand({
26787
27116
  meta: {
26788
27117
  name: "dreamboard",
26789
- version: "0.1.7",
27118
+ version: "0.1.23",
26790
27119
  description: "Dreamboard CLI \u2014 game development platform"
26791
27120
  },
26792
27121
  subCommands
@@ -26823,6 +27152,7 @@ export {
26823
27152
  getProjectLocalMaintainerRegistry,
26824
27153
  applyWorkspaceCodegen,
26825
27154
  reconcileWorkspaceDependencies,
27155
+ assertCompilerPortableDependencies,
26826
27156
  runLocalTypecheck,
26827
27157
  compile_default,
26828
27158
  startCliAuthServer,
@@ -26841,4 +27171,4 @@ export {
26841
27171
  test_default,
26842
27172
  runDreamboardCli
26843
27173
  };
26844
- //# sourceMappingURL=chunk-MOVHYB6E.js.map
27174
+ //# sourceMappingURL=chunk-GN7232BY.js.map