dreamboard 0.1.21 → 0.1.22

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-AQ5UUNJS.js} +1018 -692
  4. package/dist/chunk-AQ5UUNJS.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);
@@ -10237,7 +10407,7 @@ async function evaluateManifestSource(projectRoot) {
10237
10407
  target: ["node20"],
10238
10408
  write: false,
10239
10409
  logLevel: "silent",
10240
- plugins: repoLocalPackageResolutionPlugins()
10410
+ plugins: [createRepoLocalPackageResolutionPlugin()]
10241
10411
  });
10242
10412
  outputText = buildResult.outputFiles[0]?.text;
10243
10413
  } catch (error) {
@@ -10272,14 +10442,6 @@ async function evaluateManifestSource(projectRoot) {
10272
10442
  }
10273
10443
  return moduleRecord.default;
10274
10444
  }
10275
- function repoLocalPackageResolutionPlugins() {
10276
- try {
10277
- const repoRoot = resolveCliRepoRoot(import.meta.url);
10278
- return [createRepoLocalPackageResolutionPlugin({ repoRoot })];
10279
- } catch {
10280
- return [];
10281
- }
10282
- }
10283
10445
  function renderManifestSource(manifest) {
10284
10446
  return [
10285
10447
  'import { defineTopologyManifest } from "@dreamboard/sdk-types";',
@@ -10441,6 +10603,7 @@ var REDUCER_TESTING_TYPES_WRAPPER_CONTENT = `// Generated by dreamboard \u2014 d
10441
10603
  import game from "../app/game";
10442
10604
  import { createReducerBundle } from "@dreamboard/app-sdk/reducer";
10443
10605
  import { createTestRuntime as createDreamboardTestRuntime } from "@dreamboard/testing";
10606
+ import type { CreateTestRuntimeOptions } from "@dreamboard/testing";
10444
10607
  import { literals } from "../shared/manifest-contract";
10445
10608
  import type { PhaseName } from "../shared/generated/ui-contract";
10446
10609
  import { BASE_STATES } from "./generated/base-states.generated";
@@ -10484,17 +10647,17 @@ export function createTestRuntime(options: {
10484
10647
  controllingPlayerId?: (typeof literals.playerIds)[number];
10485
10648
  userId?: string | null;
10486
10649
  }) {
10487
- const reducerBundle = createReducerBundle(game);
10650
+ const reducerBundle =
10651
+ createReducerBundle(game) satisfies CreateTestRuntimeOptions["bundle"];
10652
+ const baseStates =
10653
+ BASE_STATES satisfies CreateTestRuntimeOptions["baseStates"];
10488
10654
  const runtime = createDreamboardTestRuntime({
10489
10655
  baseId: options.baseId,
10490
- baseStates:
10491
- BASE_STATES as unknown as Parameters<
10492
- typeof createDreamboardTestRuntime
10493
- >[0]["baseStates"],
10494
- bundle: reducerBundle as never,
10656
+ baseStates,
10657
+ bundle: reducerBundle,
10495
10658
  phase: options.phase,
10496
10659
  userId: options.userId ?? "test-user",
10497
- playerIds: (literals.playerIds as readonly string[]).slice(
10660
+ playerIds: literals.playerIds.slice(
10498
10661
  0,
10499
10662
  BASE_STATES[options.baseId]?.fingerprint.players ?? literals.playerIds.length,
10500
10663
  ),
@@ -10589,6 +10752,13 @@ export interface BrowserRunnerDriver {
10589
10752
 
10590
10753
  export interface ScenarioGameApi {
10591
10754
  start(): Promise<void>;
10755
+ /**
10756
+ * Patch the reducer snapshot for deterministic setup-heavy scenarios.
10757
+ * This is limited to reducer snapshot materialization and is rejected by
10758
+ * live replay/browser runners so authored gameplay verification still
10759
+ * submits real interactions.
10760
+ */
10761
+ patchState(mutator: (state: Record<string, unknown>) => void): Promise<void>;
10592
10762
  /**
10593
10763
  * Submit a player interaction (action-kind or prompt-kind) to the game.
10594
10764
  * The \`interactionId\` matches an \`InteractionId\` from the generated
@@ -10674,6 +10844,18 @@ export type {
10674
10844
  `;
10675
10845
  }
10676
10846
 
10847
+ // src/services/project/framework-dependencies.ts
10848
+ var FRAMEWORK_REACT_VERSION = "19.2.6";
10849
+ var FRAMEWORK_ZOD_VERSION = "4.4.3";
10850
+ var FRAMEWORK_REACT_DEPENDENCIES = {
10851
+ react: FRAMEWORK_REACT_VERSION,
10852
+ "react-dom": FRAMEWORK_REACT_VERSION
10853
+ };
10854
+ var FRAMEWORK_PNPM_OVERRIDES = {
10855
+ ...FRAMEWORK_REACT_DEPENDENCIES,
10856
+ zod: FRAMEWORK_ZOD_VERSION
10857
+ };
10858
+
10677
10859
  // src/services/project/static-scaffold.ts
10678
10860
  var DREAMBOARD_SYNC_COMMAND = "dreamboard sync";
10679
10861
  var TESTING_TYPES_STUB = "export function defineScenario(scenario) { return scenario; }\n";
@@ -10734,14 +10916,10 @@ var FRAMEWORK_SCRIPTS = {
10734
10916
  "typecheck:ui": "tsc --noEmit -p ui/tsconfig.json"
10735
10917
  };
10736
10918
  var SHARED_DEPENDENCIES = {
10737
- react: "^19.2.0",
10738
- "react-dom": "^19.2.0"
10919
+ ...FRAMEWORK_REACT_DEPENDENCIES
10739
10920
  };
10740
10921
  var ROOT_APP_DEPENDENCIES = {
10741
- zod: "4.4.3"
10742
- };
10743
- var FRAMEWORK_PNPM_OVERRIDES = {
10744
- zod: "4.4.3"
10922
+ zod: FRAMEWORK_ZOD_VERSION
10745
10923
  };
10746
10924
  var SHARED_DEV_DEPENDENCIES = {
10747
10925
  typescript: "^5.9.2",
@@ -11272,13 +11450,6 @@ function readPackagedSdkDependencyRange(packageName, importMetaUrl = import.meta
11272
11450
  return packagedRange.trim();
11273
11451
  }
11274
11452
  function resolveSdkDependencyRange(packageName, importMetaUrl = import.meta.url) {
11275
- const packagedRange = readPackagedSdkDependencyRange(
11276
- packageName,
11277
- importMetaUrl
11278
- );
11279
- if (packagedRange) {
11280
- return packagedRange;
11281
- }
11282
11453
  try {
11283
11454
  const repoRoot = resolveCliRepoRoot(importMetaUrl);
11284
11455
  const packageJsonPath = path7.join(
@@ -11291,6 +11462,13 @@ function resolveSdkDependencyRange(packageName, importMetaUrl = import.meta.url)
11291
11462
  }
11292
11463
  } catch {
11293
11464
  }
11465
+ const packagedRange = readPackagedSdkDependencyRange(
11466
+ packageName,
11467
+ importMetaUrl
11468
+ );
11469
+ if (packagedRange) {
11470
+ return packagedRange;
11471
+ }
11294
11472
  return DEFAULT_SDK_DEPENDENCY_RANGES[packageName];
11295
11473
  }
11296
11474
  function normalizeImportPath(relativePath) {
@@ -11391,19 +11569,7 @@ function setLatestCompileAttempt(projectConfig, attempt) {
11391
11569
  function updateProjectLocalMaintainerRegistry(projectConfig, localMaintainerRegistry) {
11392
11570
  return {
11393
11571
  ...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
11572
+ localMaintainerRegistry
11407
11573
  };
11408
11574
  }
11409
11575
 
@@ -11675,7 +11841,7 @@ function buildRemoteAlignedSnapshotFiles(options) {
11675
11841
 
11676
11842
  // src/services/project/local-maintainer-registry.ts
11677
11843
  import { spawn } from "child_process";
11678
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
11844
+ import { existsSync as existsSync4 } from "fs";
11679
11845
  import path10 from "path";
11680
11846
  import { fileURLToPath as fileURLToPath3 } from "url";
11681
11847
 
@@ -11714,29 +11880,7 @@ function getCliPackageRoot() {
11714
11880
  "dreamboard-cli"
11715
11881
  );
11716
11882
  } 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;
11883
+ return path10.resolve(MODULE_DIR, "../../..");
11740
11884
  }
11741
11885
  }
11742
11886
  function getScriptInvocation() {
@@ -11911,9 +12055,6 @@ var CLI_ROOT = path11.resolve(MODULE_DIR2, "../../..");
11911
12055
  var REPO_ROOT = path11.resolve(CLI_ROOT, "../..");
11912
12056
  var REPO_PACKAGE_JSON_PATH = path11.join(REPO_ROOT, "package.json");
11913
12057
  var DEFAULT_PACKAGE_MANAGER = "pnpm@10.4.1";
11914
- var FRAMEWORK_PNPM_OVERRIDES2 = {
11915
- zod: "4.4.3"
11916
- };
11917
12058
  var DEPENDENCY_INSTALL_METADATA_PATH_SEGMENTS = [
11918
12059
  ".dreamboard",
11919
12060
  "dependency-install.json"
@@ -11927,6 +12068,8 @@ var LockfileGenerationError = class extends Error {
11927
12068
  this.details = details;
11928
12069
  this.name = "LockfileGenerationError";
11929
12070
  }
12071
+ binary;
12072
+ details;
11930
12073
  };
11931
12074
  async function installWorkspaceDependencies(projectRoot, _options = {}) {
11932
12075
  const result = await reconcileWorkspaceDependencies(projectRoot);
@@ -12044,7 +12187,7 @@ function mergePnpmConfig2(existingPnpm) {
12044
12187
  ...existingPnpm ?? {},
12045
12188
  overrides: {
12046
12189
  ...existingOverrides,
12047
- ...FRAMEWORK_PNPM_OVERRIDES2
12190
+ ...FRAMEWORK_PNPM_OVERRIDES
12048
12191
  }
12049
12192
  };
12050
12193
  }
@@ -12350,31 +12493,142 @@ var clone_default = defineCommand({
12350
12493
  }
12351
12494
  });
12352
12495
 
12496
+ // src/services/project/dependency-portability.ts
12497
+ import path13 from "path";
12498
+ var DEPENDENCY_FIELDS = [
12499
+ "dependencies",
12500
+ "devDependencies",
12501
+ "optionalDependencies",
12502
+ "peerDependencies"
12503
+ ];
12504
+ var UNPORTABLE_SPECIFIER_PATTERN = /^(file|link|portal|workspace):/;
12505
+ async function buildSourceDependencyProfile(options) {
12506
+ const packageJson = await readProjectPackageJson(options.projectRoot);
12507
+ const packages = collectDreamboardPackageSpecifiers(packageJson);
12508
+ return {
12509
+ kind: "npm-registry",
12510
+ packageManager: packageJson.packageManager,
12511
+ dreamboardRegistryUrl: await readDreamboardRegistryFromNpmrc(options.projectRoot) ?? options.projectConfig?.localMaintainerRegistry?.registryUrl,
12512
+ localSnapshotId: options.projectConfig?.localMaintainerRegistry?.snapshotId,
12513
+ packages
12514
+ };
12515
+ }
12516
+ async function assertCompilerPortableDependencies(options) {
12517
+ const packageJson = await readProjectPackageJson(options.projectRoot);
12518
+ const problems = collectUnportableDreamboardSpecifiers(packageJson);
12519
+ if (problems.length > 0) {
12520
+ const details = problems.map(
12521
+ (problem) => `${problem.location} ${problem.packageName} -> ${problem.specifier}`
12522
+ ).join("; ");
12523
+ throw new Error(
12524
+ [
12525
+ "Compiler-bound workspaces must install Dreamboard packages from a registry.",
12526
+ `Found unportable Dreamboard dependency specifier(s): ${details}.`,
12527
+ "Run `dreamboard sync` from a workspace that uses registry-pinned @dreamboard/* and dreamboard versions before compiling."
12528
+ ].join(" ")
12529
+ );
12530
+ }
12531
+ const profile = await buildSourceDependencyProfile(options);
12532
+ const hasLocalSnapshotPackage = Object.values(profile.packages).some(
12533
+ (value) => value.includes("-local.")
12534
+ );
12535
+ if (hasLocalSnapshotPackage && !profile.dreamboardRegistryUrl) {
12536
+ throw new Error(
12537
+ "This workspace references local Dreamboard snapshot versions but has no @dreamboard registry configured. Run `dreamboard sync --env local` to refresh .npmrc before compiling."
12538
+ );
12539
+ }
12540
+ return profile;
12541
+ }
12542
+ async function readProjectPackageJson(projectRoot) {
12543
+ return readJsonFile(
12544
+ path13.join(projectRoot, "package.json")
12545
+ );
12546
+ }
12547
+ function collectDreamboardPackageSpecifiers(packageJson) {
12548
+ const packages = {};
12549
+ for (const field of DEPENDENCY_FIELDS) {
12550
+ const dependencies = packageJson[field];
12551
+ if (!dependencies) continue;
12552
+ for (const [packageName, specifier] of Object.entries(dependencies)) {
12553
+ if (isDreamboardPackage(packageName)) {
12554
+ packages[packageName] = specifier;
12555
+ }
12556
+ }
12557
+ }
12558
+ const overrides = packageJson.pnpm?.overrides;
12559
+ if (overrides) {
12560
+ for (const [packageName, specifier] of Object.entries(overrides)) {
12561
+ if (isDreamboardPackage(packageName) && typeof specifier === "string" && packages[packageName] === void 0) {
12562
+ packages[packageName] = specifier;
12563
+ }
12564
+ }
12565
+ }
12566
+ return packages;
12567
+ }
12568
+ function collectUnportableDreamboardSpecifiers(packageJson) {
12569
+ const problems = [];
12570
+ for (const field of DEPENDENCY_FIELDS) {
12571
+ const dependencies = packageJson[field];
12572
+ if (!dependencies) continue;
12573
+ for (const [packageName, specifier] of Object.entries(dependencies)) {
12574
+ if (isDreamboardPackage(packageName) && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
12575
+ problems.push({ location: field, packageName, specifier });
12576
+ }
12577
+ }
12578
+ }
12579
+ const overrides = packageJson.pnpm?.overrides;
12580
+ if (overrides) {
12581
+ for (const [packageName, specifier] of Object.entries(overrides)) {
12582
+ if (isDreamboardPackage(packageName) && typeof specifier === "string" && UNPORTABLE_SPECIFIER_PATTERN.test(specifier)) {
12583
+ problems.push({
12584
+ location: "pnpm.overrides",
12585
+ packageName,
12586
+ specifier
12587
+ });
12588
+ }
12589
+ }
12590
+ }
12591
+ return problems;
12592
+ }
12593
+ function isDreamboardPackage(packageName) {
12594
+ return packageName === "dreamboard" || packageName.startsWith("@dreamboard/");
12595
+ }
12596
+ async function readDreamboardRegistryFromNpmrc(projectRoot) {
12597
+ const npmrc = await readTextFileIfExists(path13.join(projectRoot, ".npmrc"));
12598
+ if (!npmrc) return void 0;
12599
+ for (const line of npmrc.split(/\r?\n/)) {
12600
+ const trimmed = line.trim();
12601
+ if (!trimmed.startsWith("@dreamboard:registry=")) continue;
12602
+ return trimmed.slice("@dreamboard:registry=".length).trim() || void 0;
12603
+ }
12604
+ return void 0;
12605
+ }
12606
+
12353
12607
  // src/services/project/local-typecheck.ts
12354
12608
  import { spawn as spawn3 } from "child_process";
12355
12609
  import { lstat as lstat2 } from "fs/promises";
12356
- import path13 from "path";
12610
+ import path14 from "path";
12357
12611
  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");
12612
+ var MODULE_DIR3 = path14.dirname(fileURLToPath5(import.meta.url));
12613
+ var REPO_ROOT2 = path14.resolve(MODULE_DIR3, "../../../../..");
12614
+ var TYPESCRIPT_NODE_MODULES = path14.join(REPO_ROOT2, "node_modules");
12361
12615
  var TYPESCRIPT_BIN_PATH_SEGMENTS = [
12362
12616
  "node_modules",
12363
12617
  "typescript",
12364
12618
  "bin",
12365
12619
  "tsc"
12366
12620
  ];
12367
- var TYPESCRIPT_CLI = path13.join(
12621
+ var TYPESCRIPT_CLI = path14.join(
12368
12622
  TYPESCRIPT_NODE_MODULES,
12369
12623
  "typescript",
12370
12624
  "bin",
12371
12625
  "tsc"
12372
12626
  );
12373
12627
  function getProjectNodeModules(projectRoot) {
12374
- return path13.join(projectRoot, "node_modules");
12628
+ return path14.join(projectRoot, "node_modules");
12375
12629
  }
12376
12630
  function getProjectTypescriptCli(projectRoot) {
12377
- return path13.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);
12631
+ return path14.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);
12378
12632
  }
12379
12633
  async function pathExists2(targetPath) {
12380
12634
  try {
@@ -12565,6 +12819,7 @@ var compile_default = defineCommand({
12565
12819
  async run({ args }) {
12566
12820
  const parsedArgs = parseCompileCommandArgs(args);
12567
12821
  const { projectRoot, projectConfig } = await resolveProjectContext(parsedArgs);
12822
+ await assertCompilerPortableDependencies({ projectRoot, projectConfig });
12568
12823
  const diff = await getLocalDiff(projectRoot);
12569
12824
  await assertCliStaticScaffoldComplete(projectRoot, diff.deleted);
12570
12825
  if (diff.modified.length > 0 || diff.added.length > 0 || diff.deleted.length > 0) {
@@ -12809,9 +13064,137 @@ var config_default = defineCommand({
12809
13064
  });
12810
13065
 
12811
13066
  // src/commands/dev.ts
12812
- import path23 from "path";
13067
+ import path24 from "path";
12813
13068
  import { createHash as createHash3 } from "crypto";
12814
13069
 
13070
+ // ../../packages/ui-host-runtime/src/actor-principal.ts
13071
+ function gameIdFromGameSource(source) {
13072
+ if (source.kind === "USER_COMPILED") {
13073
+ return source.gameId;
13074
+ }
13075
+ return `demo:${source.slug}:${source.revisionId}`;
13076
+ }
13077
+
13078
+ // ../../packages/ui-host-runtime/src/plugin-messages.ts
13079
+ var InitMessageSchema = external_exports.object({
13080
+ type: external_exports.literal("init"),
13081
+ sessionId: external_exports.string(),
13082
+ controllablePlayerIds: external_exports.array(external_exports.string()),
13083
+ controllingPlayerId: external_exports.string(),
13084
+ userId: external_exports.string().nullable()
13085
+ });
13086
+ var PingMessageSchema = external_exports.object({
13087
+ type: external_exports.literal("ping")
13088
+ });
13089
+ var StateSyncMessageSchema = external_exports.object({
13090
+ type: external_exports.literal("state-sync"),
13091
+ syncId: external_exports.number(),
13092
+ state: external_exports.custom((data) => {
13093
+ return typeof data === "object" && data !== null && "session" in data && "notifications" in data;
13094
+ })
13095
+ });
13096
+ var SubmitResultMessageSchema = external_exports.object({
13097
+ type: external_exports.literal("submit-result"),
13098
+ messageId: external_exports.string(),
13099
+ accepted: external_exports.boolean(),
13100
+ errorCode: external_exports.string().optional(),
13101
+ message: external_exports.string().optional()
13102
+ });
13103
+ var MainToPluginMessageSchema = external_exports.discriminatedUnion("type", [
13104
+ InitMessageSchema,
13105
+ PingMessageSchema,
13106
+ StateSyncMessageSchema,
13107
+ SubmitResultMessageSchema
13108
+ ]);
13109
+ var ReadyMessageSchema = external_exports.object({
13110
+ type: external_exports.literal("ready")
13111
+ });
13112
+ var InteractionMessageSchema = external_exports.object({
13113
+ type: external_exports.literal("interaction"),
13114
+ messageId: external_exports.string(),
13115
+ playerId: external_exports.string(),
13116
+ interactionId: external_exports.string(),
13117
+ params: external_exports.unknown(),
13118
+ // Optional client-minted correlation id (UUID) that lets the whole
13119
+ // click-to-render path be stitched across plugin iframe, web host,
13120
+ // backend spans/logs and SSE. Added for Tier-0 input-latency
13121
+ // observability; the backend rides it through as an HTTP header
13122
+ // (`X-Dreamboard-Client-Action-Id`) but no wire contract changed.
13123
+ clientActionId: external_exports.string().optional(),
13124
+ // Plugin-iframe `Date.now()` captured right before the postMessage
13125
+ // is sent, used as the `t0_click` timestamp on the host-side perf
13126
+ // buffer. Date.now() is intentional: the iframe and the host share
13127
+ // a wall-clock base, but not a `performance.now()` origin.
13128
+ clientSubmittedAtMs: external_exports.number().optional()
13129
+ });
13130
+ var ValidateInteractionMessageSchema = external_exports.object({
13131
+ type: external_exports.literal("validate-interaction"),
13132
+ playerId: external_exports.string(),
13133
+ interactionId: external_exports.string(),
13134
+ params: external_exports.unknown(),
13135
+ messageId: external_exports.string()
13136
+ });
13137
+ var ValidateInteractionResultMessageSchema = external_exports.object({
13138
+ type: external_exports.literal("validate-interaction-result"),
13139
+ messageId: external_exports.string(),
13140
+ result: external_exports.object({
13141
+ valid: external_exports.boolean(),
13142
+ errorCode: external_exports.string().optional(),
13143
+ message: external_exports.string().optional()
13144
+ })
13145
+ });
13146
+ var PluginErrorMessageSchema = external_exports.object({
13147
+ type: external_exports.literal("error"),
13148
+ message: external_exports.string(),
13149
+ code: external_exports.string().optional()
13150
+ });
13151
+ var PongMessageSchema = external_exports.object({
13152
+ type: external_exports.literal("pong")
13153
+ });
13154
+ var SwitchPlayerMessageSchema = external_exports.object({
13155
+ type: external_exports.literal("switch-player"),
13156
+ playerId: external_exports.string()
13157
+ });
13158
+ var StateAckMessageSchema = external_exports.object({
13159
+ type: external_exports.literal("state-ack"),
13160
+ syncId: external_exports.number(),
13161
+ // Plugin-iframe `Date.now()` captured when the state-sync message
13162
+ // was received. Threaded so the host-side perf HUD can compute the
13163
+ // `t7_state_sync_received` mark without needing perf to be enabled
13164
+ // inside the plugin iframe itself.
13165
+ clientReceivedAtMs: external_exports.number().optional()
13166
+ });
13167
+ var StateRenderedMessageSchema = external_exports.object({
13168
+ type: external_exports.literal("state-rendered"),
13169
+ syncId: external_exports.number(),
13170
+ clientReceivedAtMs: external_exports.number(),
13171
+ clientRenderedAtMs: external_exports.number()
13172
+ });
13173
+ var MarkNotificationReadMessageSchema = external_exports.object({
13174
+ type: external_exports.literal("mark-notification-read"),
13175
+ notificationId: external_exports.string()
13176
+ });
13177
+ var RestoreHistoryMessageSchema = external_exports.object({
13178
+ type: external_exports.literal("restore-history"),
13179
+ entryId: external_exports.string()
13180
+ });
13181
+ var PluginToMainMessageSchema = external_exports.discriminatedUnion("type", [
13182
+ ReadyMessageSchema,
13183
+ InteractionMessageSchema,
13184
+ ValidateInteractionMessageSchema,
13185
+ PluginErrorMessageSchema,
13186
+ PongMessageSchema,
13187
+ SwitchPlayerMessageSchema,
13188
+ StateAckMessageSchema,
13189
+ StateRenderedMessageSchema,
13190
+ MarkNotificationReadMessageSchema,
13191
+ RestoreHistoryMessageSchema
13192
+ ]);
13193
+
13194
+ // ../../packages/ui-host-runtime/src/unified-session-store.ts
13195
+ import { createStore } from "zustand/vanilla";
13196
+ import { subscribeWithSelector } from "zustand/middleware";
13197
+
12815
13198
  // src/utils/dev-session.ts
12816
13199
  import { randomInt } from "crypto";
12817
13200
  var DEFAULT_DEV_SEED = 1337;
@@ -13011,6 +13394,7 @@ function openBrowser(url) {
13011
13394
  // src/dev-host/start-dev-server.ts
13012
13395
  import { rmSync } from "fs";
13013
13396
  import { createRequire as createRequire2 } from "module";
13397
+ import os from "os";
13014
13398
  import react from "@vitejs/plugin-react";
13015
13399
  import tailwindcssPostcss from "@tailwindcss/postcss";
13016
13400
  import { createServer as createServer2 } from "vite";
@@ -13085,12 +13469,7 @@ function createStreamingProxy(target) {
13085
13469
  },
13086
13470
  web(req, res, _options, callback) {
13087
13471
  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
- };
13472
+ const headers = createForwardHeaders(req, targetUrl);
13094
13473
  const client2 = targetUrl.protocol === "https:" ? https : http;
13095
13474
  const upstreamReq = client2.request(
13096
13475
  upstreamUrl,
@@ -13128,6 +13507,16 @@ function createStreamingProxy(target) {
13128
13507
  };
13129
13508
  return proxy;
13130
13509
  }
13510
+ function createForwardHeaders(req, targetUrl) {
13511
+ const headers = { ...req.headers };
13512
+ delete headers.origin;
13513
+ delete headers["access-control-request-headers"];
13514
+ delete headers["access-control-request-method"];
13515
+ headers.host = targetUrl.host;
13516
+ headers["x-forwarded-host"] = req.headers.host;
13517
+ headers["x-forwarded-proto"] = targetUrl.protocol.replace(":", "");
13518
+ return headers;
13519
+ }
13131
13520
  async function resolveDevBearer(config) {
13132
13521
  if (!usesStoredSession2(config)) {
13133
13522
  return { kind: "ok", token: config.authToken ?? null };
@@ -13210,7 +13599,7 @@ function formatUnknown(value) {
13210
13599
 
13211
13600
  // src/dev-host/dev-runtime-platform.ts
13212
13601
  import { createRequire } from "module";
13213
- import path14 from "path";
13602
+ import path15 from "path";
13214
13603
  import { fileURLToPath as fileURLToPath6 } from "url";
13215
13604
  import { existsSync as existsSync6 } from "fs";
13216
13605
 
@@ -13229,6 +13618,36 @@ function createDevRuntimePlatform(options) {
13229
13618
  const repoRoot = resolveRepoRoot(cliRoot);
13230
13619
  const require3 = createRequire(options.importMetaUrl);
13231
13620
  const diagnosticsLevel = resolveDevDiagnosticsLevel(options.debug);
13621
+ const uiSdkRoot = resolvePackageRoot(
13622
+ require3,
13623
+ cliRoot,
13624
+ "@dreamboard/ui-sdk",
13625
+ "@dreamboard-games/ui-sdk",
13626
+ "packages/ui-sdk"
13627
+ );
13628
+ const apiClientClientGen = resolvePackageSubpath(
13629
+ require3,
13630
+ "@dreamboard/api-client/client.gen",
13631
+ "@dreamboard-games/api-client/client.gen"
13632
+ );
13633
+ const uiHostRuntimeRoot = resolveWorkspaceOrPackagedSource(
13634
+ repoRoot,
13635
+ cliRoot,
13636
+ "packages/ui-host-runtime",
13637
+ "dist/runtime-packages/ui-host-runtime"
13638
+ );
13639
+ const uiRoot = resolveWorkspaceOrPackagedSource(
13640
+ repoRoot,
13641
+ cliRoot,
13642
+ "packages/ui",
13643
+ "dist/runtime-packages/ui"
13644
+ );
13645
+ const tailwindConfigRoot = resolveWorkspaceOrPackagedSource(
13646
+ repoRoot,
13647
+ cliRoot,
13648
+ "packages/tailwind-config",
13649
+ "dist/runtime-packages/tailwind-config"
13650
+ );
13232
13651
  return {
13233
13652
  devHostRoot,
13234
13653
  repoRoot,
@@ -13236,11 +13655,12 @@ function createDevRuntimePlatform(options) {
13236
13655
  diagnosticsLevel,
13237
13656
  viteLogLevel: diagnosticsLevel === "verbose" ? "info" : "warn",
13238
13657
  serverConfig: {
13239
- host: "localhost",
13240
- port: options.port ?? 5173,
13658
+ host: options.host ?? "localhost",
13659
+ allowedHosts: options.allowedHosts,
13660
+ port: options.port ?? 5352,
13241
13661
  strictPort: false,
13242
13662
  watch: {
13243
- ignored: [/[\\/]\.dreamboard[\\/]/]
13663
+ ignored: createProjectOnlyWatchIgnored(options.projectRoot)
13244
13664
  },
13245
13665
  headers: {
13246
13666
  "Access-Control-Allow-Origin": "*",
@@ -13304,11 +13724,11 @@ function createDevRuntimePlatform(options) {
13304
13724
  },
13305
13725
  {
13306
13726
  find: /^@dreamboard\/ui-sdk$/,
13307
- replacement: path14.resolve(repoRoot, "packages/ui-sdk/src/index.ts")
13727
+ replacement: path15.resolve(uiSdkRoot, "src/index.ts")
13308
13728
  },
13309
13729
  {
13310
13730
  find: /^@dreamboard\/ui-sdk\/reducer$/,
13311
- replacement: path14.resolve(repoRoot, "packages/ui-sdk/src/reducer.ts")
13731
+ replacement: path15.resolve(uiSdkRoot, "src/reducer.ts")
13312
13732
  },
13313
13733
  {
13314
13734
  // Must resolve to the same source tree as the `@dreamboard/ui-sdk`
@@ -13317,91 +13737,110 @@ function createDevRuntimePlatform(options) {
13317
13737
  // `useRuntimeContext` on the workspace-source copy will never find
13318
13738
  // the provider that's set up via the dist copy (and vice versa).
13319
13739
  find: /^@dreamboard\/ui-sdk\/components$/,
13320
- replacement: path14.resolve(
13321
- repoRoot,
13322
- "packages/ui-sdk/src/components/index.ts"
13323
- )
13740
+ replacement: path15.resolve(uiSdkRoot, "src/components/index.ts")
13741
+ },
13742
+ {
13743
+ // Keep generated workspace adapters and legacy internal imports on the
13744
+ // same source instance as PluginRuntime so React context identity stays
13745
+ // shared in dev.
13746
+ find: /^@dreamboard\/ui-sdk\/internal$/,
13747
+ replacement: path15.resolve(uiSdkRoot, "src/internal.ts")
13748
+ },
13749
+ {
13750
+ find: /^@dreamboard\/ui-sdk\/workspace-contract$/,
13751
+ replacement: path15.resolve(uiSdkRoot, "src/workspace-contract.ts")
13324
13752
  },
13325
13753
  {
13326
13754
  find: /^@dreamboard\/ui-sdk\/internal\/runtime-context$/,
13327
- replacement: path14.resolve(
13328
- repoRoot,
13329
- "packages/ui-sdk/src/context/RuntimeContext.tsx"
13755
+ replacement: path15.resolve(
13756
+ uiSdkRoot,
13757
+ "src/context/RuntimeContext.tsx"
13330
13758
  )
13331
13759
  },
13332
13760
  {
13333
13761
  find: /^@dreamboard\/ui-sdk\/internal\/usePluginRuntime$/,
13334
- replacement: path14.resolve(
13335
- repoRoot,
13336
- "packages/ui-sdk/src/hooks/usePluginRuntime.ts"
13762
+ replacement: path15.resolve(
13763
+ uiSdkRoot,
13764
+ "src/hooks/usePluginRuntime.ts"
13337
13765
  )
13338
13766
  },
13339
13767
  {
13340
13768
  find: /^@dreamboard\/ui-sdk\/internal\/createPluginRuntimeAPI$/,
13341
- replacement: path14.resolve(
13342
- repoRoot,
13343
- "packages/ui-sdk/src/runtime/createPluginRuntimeAPI.ts"
13769
+ replacement: path15.resolve(
13770
+ uiSdkRoot,
13771
+ "src/runtime/createPluginRuntimeAPI.ts"
13344
13772
  )
13345
13773
  },
13346
13774
  {
13347
13775
  find: /^@dreamboard\/ui-sdk\/internal\/useHandLayout$/,
13348
- replacement: path14.resolve(
13349
- repoRoot,
13350
- "packages/ui-sdk/src/hooks/useHandLayout.ts"
13351
- )
13776
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/useHandLayout.ts")
13352
13777
  },
13353
13778
  {
13354
13779
  find: /^@dreamboard\/ui-sdk\/internal\/usePanZoom$/,
13355
- replacement: path14.resolve(
13356
- repoRoot,
13357
- "packages/ui-sdk/src/hooks/usePanZoom.ts"
13358
- )
13780
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/usePanZoom.ts")
13359
13781
  },
13360
13782
  {
13361
13783
  find: /^@dreamboard\/ui-sdk\/internal\/useIsMobile$/,
13362
- replacement: path14.resolve(
13363
- repoRoot,
13364
- "packages/ui-sdk/src/hooks/useIsMobile.ts"
13365
- )
13784
+ replacement: path15.resolve(uiSdkRoot, "src/hooks/useIsMobile.ts")
13366
13785
  },
13367
13786
  {
13368
13787
  find: /^@dreamboard\/ui-sdk\/internal\/player-state$/,
13369
- replacement: path14.resolve(
13370
- repoRoot,
13371
- "packages/ui-sdk/src/types/player-state.ts"
13788
+ replacement: path15.resolve(
13789
+ uiSdkRoot,
13790
+ "src/types/player-state.ts"
13372
13791
  )
13373
13792
  },
13374
13793
  {
13375
13794
  find: /^@dreamboard\/ui-sdk\/internal\/tiled-board$/,
13376
- replacement: path14.resolve(
13377
- repoRoot,
13378
- "packages/ui-sdk/src/types/tiled-board.ts"
13795
+ replacement: path15.resolve(
13796
+ uiSdkRoot,
13797
+ "src/types/tiled-board.ts"
13379
13798
  )
13380
13799
  },
13381
13800
  {
13382
13801
  find: /^@dreamboard\/ui-sdk\/internal\/plugin-state$/,
13383
- replacement: path14.resolve(
13384
- repoRoot,
13385
- "packages/ui-sdk/src/types/plugin-state.ts"
13802
+ replacement: path15.resolve(
13803
+ uiSdkRoot,
13804
+ "src/types/plugin-state.ts"
13386
13805
  )
13387
13806
  },
13388
13807
  {
13389
13808
  find: /^@dreamboard\/ui-sdk\/types\/runtime-api$/,
13390
- replacement: path14.resolve(
13391
- repoRoot,
13392
- "packages/ui-sdk/src/types/runtime-api.ts"
13809
+ replacement: path15.resolve(
13810
+ uiSdkRoot,
13811
+ "src/types/runtime-api.ts"
13393
13812
  )
13394
13813
  },
13814
+ {
13815
+ find: /^@dreamboard\/ui-host-runtime\/components$/,
13816
+ replacement: path15.resolve(uiHostRuntimeRoot, "src/components/index.ts")
13817
+ },
13818
+ {
13819
+ find: /^@dreamboard\/ui-host-runtime\/runtime$/,
13820
+ replacement: path15.resolve(uiHostRuntimeRoot, "src/runtime/index.ts")
13821
+ },
13822
+ {
13823
+ find: /^@dreamboard\/ui\/components\/(.*)$/,
13824
+ replacement: path15.resolve(uiRoot, "src/components/$1.tsx")
13825
+ },
13826
+ {
13827
+ find: /^@dreamboard\/ui\/lib\/(.*)$/,
13828
+ replacement: path15.resolve(uiRoot, "src/lib/$1.ts")
13829
+ },
13830
+ {
13831
+ find: /^@dreamboard\/tailwind-config$/,
13832
+ replacement: path15.resolve(tailwindConfigRoot, "shared-styles.css")
13833
+ },
13395
13834
  {
13396
13835
  find: /^@dreamboard\/manifest-contract$/,
13397
- replacement: path14.resolve(
13836
+ replacement: path15.resolve(
13398
13837
  options.projectRoot,
13399
13838
  "shared/manifest-contract.ts"
13400
13839
  )
13401
13840
  },
13402
13841
  {
13403
13842
  find: /^@dreamboard\/ui-contract$/,
13404
- replacement: path14.resolve(
13843
+ replacement: path15.resolve(
13405
13844
  options.projectRoot,
13406
13845
  "shared/generated/ui-contract.ts"
13407
13846
  )
@@ -13415,9 +13854,13 @@ function createDevRuntimePlatform(options) {
13415
13854
  "packages/ui-sdk/src/plugin-styles.css"
13416
13855
  )
13417
13856
  },
13857
+ {
13858
+ find: /^@dreamboard\/api-client\/client\.gen$/,
13859
+ replacement: apiClientClientGen
13860
+ },
13418
13861
  {
13419
13862
  find: /^@shared\/(.*)$/,
13420
- replacement: path14.resolve(options.projectRoot, "shared/$1")
13863
+ replacement: path15.resolve(options.projectRoot, "shared/$1")
13421
13864
  },
13422
13865
  {
13423
13866
  find: /^tailwindcss$/,
@@ -13429,33 +13872,72 @@ function createDevRuntimePlatform(options) {
13429
13872
  // older local snapshot after `dreamboard sync`.
13430
13873
  optimizeDepsExclude: [
13431
13874
  "@dreamboard/ui-sdk",
13875
+ "@dreamboard/ui-sdk/workspace-contract",
13432
13876
  "@dreamboard/app-sdk",
13433
13877
  "@dreamboard/app-sdk/reducer",
13434
13878
  "@dreamboard/sdk-types"
13435
13879
  ]
13436
13880
  };
13437
13881
  }
13882
+ function createProjectOnlyWatchIgnored(projectRoot) {
13883
+ const normalizedProjectRoot = path15.resolve(projectRoot);
13884
+ return (file) => {
13885
+ const normalizedFile = path15.resolve(file);
13886
+ const relativePath = path15.relative(normalizedProjectRoot, normalizedFile);
13887
+ const isInsideProject = relativePath === "" || relativePath.length > 0 && !relativePath.startsWith("..") && !path15.isAbsolute(relativePath);
13888
+ if (!isInsideProject) {
13889
+ return true;
13890
+ }
13891
+ const pathSegments = relativePath.split(path15.sep);
13892
+ return pathSegments.includes(".dreamboard") || pathSegments.includes("node_modules");
13893
+ };
13894
+ }
13895
+ function resolveWorkspaceOrPackagedSource(repoRoot, cliRoot, workspaceRelativePath, packagedRelativePath) {
13896
+ const workspacePath = path15.resolve(repoRoot, workspaceRelativePath);
13897
+ if (existsSync6(workspacePath)) return workspacePath;
13898
+ return path15.resolve(cliRoot, packagedRelativePath);
13899
+ }
13900
+ function resolvePackageRoot(require3, cliRoot, specifier, publicSpecifier, fallbackRelativePath) {
13901
+ try {
13902
+ return path15.dirname(require3.resolve(`${specifier}/package.json`));
13903
+ } catch {
13904
+ try {
13905
+ return path15.dirname(require3.resolve(`${publicSpecifier}/package.json`));
13906
+ } catch {
13907
+ return path15.resolve(cliRoot, "..", "..", fallbackRelativePath);
13908
+ }
13909
+ }
13910
+ }
13911
+ function resolvePackageSubpath(require3, specifier, publicSpecifier) {
13912
+ try {
13913
+ return require3.resolve(specifier);
13914
+ } catch {
13915
+ return require3.resolve(publicSpecifier);
13916
+ }
13917
+ }
13438
13918
  function resolveCliDependency(require3, cliRoot, specifier, fallbackRelativePath) {
13439
13919
  try {
13440
13920
  return require3.resolve(specifier);
13441
13921
  } catch {
13442
- return path14.resolve(cliRoot, fallbackRelativePath);
13922
+ return path15.resolve(cliRoot, fallbackRelativePath);
13443
13923
  }
13444
13924
  }
13445
13925
  function resolveDevHostRoot(importMetaUrl) {
13446
- const currentDir = path14.dirname(fileURLToPath6(importMetaUrl));
13447
- const sourceDirCandidate = path14.resolve(currentDir, "../src/dev-host");
13926
+ const currentDir = path15.dirname(fileURLToPath6(importMetaUrl));
13927
+ const packagedDirCandidate = path15.resolve(currentDir, "dev-host");
13928
+ if (existsSync6(packagedDirCandidate)) return packagedDirCandidate;
13929
+ const sourceDirCandidate = path15.resolve(currentDir, "../src/dev-host");
13448
13930
  return existsSync6(sourceDirCandidate) ? sourceDirCandidate : currentDir;
13449
13931
  }
13450
13932
  function resolveCliRoot(importMetaUrl) {
13451
- let currentDir = path14.dirname(fileURLToPath6(importMetaUrl));
13933
+ let currentDir = path15.dirname(fileURLToPath6(importMetaUrl));
13452
13934
  while (true) {
13453
- if (existsSync6(path14.join(currentDir, "package.json"))) {
13935
+ if (existsSync6(path15.join(currentDir, "package.json"))) {
13454
13936
  return currentDir;
13455
13937
  }
13456
- const parentDir = path14.dirname(currentDir);
13938
+ const parentDir = path15.dirname(currentDir);
13457
13939
  if (parentDir === currentDir) {
13458
- return path14.resolve(resolveDevHostRoot(importMetaUrl), "../..");
13940
+ return path15.resolve(resolveDevHostRoot(importMetaUrl), "../..");
13459
13941
  }
13460
13942
  currentDir = parentDir;
13461
13943
  }
@@ -13463,10 +13945,10 @@ function resolveCliRoot(importMetaUrl) {
13463
13945
  function resolveRepoRoot(cliRoot) {
13464
13946
  let currentDir = cliRoot;
13465
13947
  while (true) {
13466
- if (existsSync6(path14.join(currentDir, "pnpm-workspace.yaml"))) {
13948
+ if (existsSync6(path15.join(currentDir, "pnpm-workspace.yaml"))) {
13467
13949
  return currentDir;
13468
13950
  }
13469
- const parentDir = path14.dirname(currentDir);
13951
+ const parentDir = path15.dirname(currentDir);
13470
13952
  if (parentDir === currentDir) {
13471
13953
  return cliRoot;
13472
13954
  }
@@ -13475,15 +13957,15 @@ function resolveRepoRoot(cliRoot) {
13475
13957
  }
13476
13958
 
13477
13959
  // src/dev-host/dev-virtual-modules-plugin.ts
13478
- import path15 from "path";
13960
+ import path16 from "path";
13479
13961
  import { normalizePath } from "vite";
13480
13962
  function createVirtualDevModulesPlugin(options) {
13481
13963
  const configModuleId = "virtual:dreamboard-dev-config";
13482
13964
  const resolvedConfigModuleId = `\0${configModuleId}`;
13483
13965
  const projectEntryModuleId = "virtual:dreamboard-project-entry";
13484
13966
  const resolvedProjectEntryModuleId = `\0${projectEntryModuleId}`;
13485
- const projectAppPath = path15.resolve(options.projectRoot, "ui/App.tsx");
13486
- const projectStylePath = path15.resolve(options.projectRoot, "ui/style.css");
13967
+ const projectAppPath = path16.resolve(options.projectRoot, "ui/App.tsx");
13968
+ const projectStylePath = path16.resolve(options.projectRoot, "ui/style.css");
13487
13969
  return {
13488
13970
  name: "dreamboard-dev-virtual-modules",
13489
13971
  resolveId(id) {
@@ -13741,7 +14223,7 @@ function extractQueryParam(req, name) {
13741
14223
  );
13742
14224
  return value?.trim() || null;
13743
14225
  }
13744
- function appendQuery(path26, query) {
14226
+ function appendQuery(path28, query) {
13745
14227
  const params = new URLSearchParams();
13746
14228
  for (const [key, value] of Object.entries(query)) {
13747
14229
  if (value) {
@@ -13749,7 +14231,7 @@ function appendQuery(path26, query) {
13749
14231
  }
13750
14232
  }
13751
14233
  const serialized = params.toString();
13752
- return serialized ? `${path26}?${serialized}` : path26;
14234
+ return serialized ? `${path28}?${serialized}` : path28;
13753
14235
  }
13754
14236
  async function loadCurrentSession(options) {
13755
14237
  if (!await exists(options.sessionFilePath)) {
@@ -13768,12 +14250,12 @@ async function persistSessionId(sessionFilePath, sessionId) {
13768
14250
  createPersistedDevSession({ sessionId })
13769
14251
  );
13770
14252
  }
13771
- async function fetchBackendJson(config, path26, options = {}) {
14253
+ async function fetchBackendJson(config, path28, options = {}) {
13772
14254
  const bearer = await resolveDevBearer(config);
13773
14255
  if (bearer.kind === "permanent_invalid") {
13774
14256
  throw new HttpError(401, bearer.message);
13775
14257
  }
13776
- const response = await fetch(`${config.apiBaseUrl}${path26}`, {
14258
+ const response = await fetch(`${config.apiBaseUrl}${path28}`, {
13777
14259
  method: options.method ?? "GET",
13778
14260
  headers: {
13779
14261
  ...bearer.token ? { authorization: `Bearer ${bearer.token}` } : {},
@@ -13827,6 +14309,7 @@ var HttpError = class extends Error {
13827
14309
  super(message);
13828
14310
  this.statusCode = statusCode;
13829
14311
  }
14312
+ statusCode;
13830
14313
  };
13831
14314
  function parsePersistedSessionPointer(value, runtimeConfig) {
13832
14315
  if (!value || typeof value !== "object") {
@@ -13876,29 +14359,29 @@ function formatUnknown2(value) {
13876
14359
  // src/dev-host/dev-fallback-stylesheet.ts
13877
14360
  import { createHash, randomUUID } from "crypto";
13878
14361
  import { existsSync as existsSync7, mkdirSync, writeFileSync } from "fs";
13879
- import path16 from "path";
14362
+ import path17 from "path";
13880
14363
  import { normalizePath as normalizePath2 } from "vite";
13881
14364
  function prepareFallbackStylesheet(options) {
13882
- const projectStylePath = path16.resolve(options.projectRoot, "ui/style.css");
14365
+ const projectStylePath = path17.resolve(options.projectRoot, "ui/style.css");
13883
14366
  if (existsSync7(projectStylePath)) {
13884
14367
  return null;
13885
14368
  }
13886
- const generatedDir = path16.resolve(options.repoRoot, ".dreamboard-dev");
14369
+ const generatedDir = path17.resolve(options.repoRoot, ".dreamboard-dev");
13887
14370
  mkdirSync(generatedDir, { recursive: true });
13888
14371
  const fingerprint = createHash("sha256").update(options.projectRoot, "utf8").digest("hex").slice(0, 8);
13889
14372
  const instanceId = randomUUID().replaceAll("-", "").slice(0, 8);
13890
- const generatedPath = path16.join(
14373
+ const generatedPath = path17.join(
13891
14374
  generatedDir,
13892
14375
  `plugin-styles-${fingerprint}-${instanceId}.css`
13893
14376
  );
13894
14377
  const sharedStylesPath = normalizePath2(
13895
- path16.resolve(options.repoRoot, "packages/ui-sdk/src/plugin-styles.css")
14378
+ path17.resolve(options.repoRoot, "packages/ui-sdk/src/plugin-styles.css")
13896
14379
  );
13897
14380
  const uiSourcePath = normalizePath2(
13898
- path16.resolve(options.projectRoot, "ui/**/*.{ts,tsx}")
14381
+ path17.resolve(options.projectRoot, "ui/**/*.{ts,tsx}")
13899
14382
  );
13900
14383
  const sharedSourcePath = normalizePath2(
13901
- path16.resolve(options.projectRoot, "shared/**/*.{ts,tsx}")
14384
+ path17.resolve(options.projectRoot, "shared/**/*.{ts,tsx}")
13902
14385
  );
13903
14386
  writeFileSync(
13904
14387
  generatedPath,
@@ -13918,12 +14401,14 @@ function prepareFallbackStylesheet(options) {
13918
14401
  var require2 = createRequire2(import.meta.url);
13919
14402
  var tailwindCssEntry = require2.resolve("tailwindcss/index.css");
13920
14403
  async function startDreamboardDevServer(options) {
13921
- const { projectRoot, port, runtimeConfig, config } = options;
14404
+ const { projectRoot, port, host, allowedHosts, runtimeConfig, config } = options;
13922
14405
  const platform2 = createDevRuntimePlatform({
13923
14406
  importMetaUrl: import.meta.url,
13924
14407
  projectRoot,
13925
14408
  debug: runtimeConfig.debug,
13926
14409
  port,
14410
+ host,
14411
+ allowedHosts,
13927
14412
  tailwindCssEntry
13928
14413
  });
13929
14414
  const generatedFallbackStylesheetPath = prepareFallbackStylesheet({
@@ -13965,8 +14450,10 @@ async function startDreamboardDevServer(options) {
13965
14450
  });
13966
14451
  await server.listen();
13967
14452
  const resolvedPort = getBoundPort(server);
14453
+ const url = `http://localhost:${resolvedPort}/index.html`;
13968
14454
  return {
13969
- url: `http://localhost:${resolvedPort}/index.html`,
14455
+ url,
14456
+ networkUrls: getNetworkUrls(host, resolvedPort),
13970
14457
  close: async () => {
13971
14458
  await server.close();
13972
14459
  if (generatedFallbackStylesheetPath) {
@@ -13976,6 +14463,23 @@ async function startDreamboardDevServer(options) {
13976
14463
  server
13977
14464
  };
13978
14465
  }
14466
+ function getNetworkUrls(host, port) {
14467
+ if (!host) return [];
14468
+ if (typeof host === "string" && isLoopbackHost(host)) return [];
14469
+ const hosts = host === true || host === "0.0.0.0" || host === "::" ? getLanIpv4Addresses() : [host];
14470
+ return hosts.map(
14471
+ (value) => `http://${formatUrlHost(value)}:${port}/index.html`
14472
+ );
14473
+ }
14474
+ function isLoopbackHost(host) {
14475
+ return host === "localhost" || host === "127.0.0.1" || host === "::1";
14476
+ }
14477
+ function getLanIpv4Addresses() {
14478
+ return Object.values(os.networkInterfaces()).flatMap((interfaces) => interfaces ?? []).filter((details) => details.family === "IPv4" && !details.internal).map((details) => details.address);
14479
+ }
14480
+ function formatUrlHost(host) {
14481
+ return host.includes(":") ? `[${host}]` : host;
14482
+ }
13979
14483
  function getBoundPort(server) {
13980
14484
  const address = server.httpServer?.address();
13981
14485
  if (!address || typeof address === "string") {
@@ -13985,11 +14489,11 @@ function getBoundPort(server) {
13985
14489
  }
13986
14490
 
13987
14491
  // src/services/testing/reducer-native-test-harness.ts
13988
- import path20 from "path";
14492
+ import path21 from "path";
13989
14493
  import {
13990
14494
  existsSync as existsSync8,
13991
14495
  mkdirSync as mkdirSync2,
13992
- readFileSync as readFileSync4,
14496
+ readFileSync as readFileSync3,
13993
14497
  rmSync as rmSync2,
13994
14498
  writeFileSync as writeFileSync2
13995
14499
  } from "fs";
@@ -14098,9 +14602,6 @@ var ProjectSeatsDynamicRequestSchema = external_exports.object({ "state": Reduce
14098
14602
  var BoardStaticProjectionSchema = external_exports.object({ "view": JsonValueSchema, "hash": external_exports.string().min(1), "manifestVersion": external_exports.string() }).strict();
14099
14603
 
14100
14604
  // ../../packages/app-sdk/src/reducer/per-player.ts
14101
- function asPlayerId(raw) {
14102
- return raw;
14103
- }
14104
14605
  function perPlayerGet(value, id) {
14105
14606
  for (const [candidate, v] of value.entries) {
14106
14607
  if (candidate === id) {
@@ -14222,33 +14723,6 @@ function resolveDependentDomainChoices(choices, context) {
14222
14723
  disabledReason: choice.disabledReason
14223
14724
  }));
14224
14725
  }
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
14726
  function resolveResourceMapChoices(choices, context) {
14253
14727
  const resources = context.state.table.resources;
14254
14728
  const firstResourceMap = isPerPlayer(resources) && resources.entries.length > 0 ? resources.entries[0]?.[1] : resources;
@@ -14332,76 +14806,38 @@ function choiceInput(options) {
14332
14806
  if (Array.isArray(options.choices) && options.choices.length === 0) {
14333
14807
  throw new Error("formInput.choice requires at least one choice.");
14334
14808
  }
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;
14809
+ const schema = Array.isArray(options.choices) ? external_exports.enum(
14810
+ options.choices.map((choice) => choice.value)
14811
+ ) : external_exports.string();
14347
14812
  return {
14348
14813
  kind: "form",
14349
14814
  schema,
14350
- ...hasStaticDefault ? { defaultValue: staticDefault } : {},
14815
+ ..."defaultValue" in options ? { defaultValue: options.defaultValue } : {},
14351
14816
  ...dependsOn ? { dependsOn } : {},
14352
14817
  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
14818
  return {
14377
14819
  type: "choice",
14378
- choices
14820
+ choices: dependsOn ? resolveDependentDomainChoices(
14821
+ options.choices,
14822
+ {
14823
+ state,
14824
+ playerId,
14825
+ q,
14826
+ derived,
14827
+ values: values ?? {}
14828
+ }
14829
+ ) : resolveDomainChoices(
14830
+ options.choices,
14831
+ {
14832
+ state,
14833
+ playerId,
14834
+ q,
14835
+ derived,
14836
+ values: {}
14837
+ }
14838
+ )
14379
14839
  };
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
- } : {}
14840
+ }
14405
14841
  };
14406
14842
  }
14407
14843
  function choiceListInput(options) {
@@ -14422,12 +14858,7 @@ function choiceListInput(options) {
14422
14858
  derived,
14423
14859
  values: {}
14424
14860
  };
14425
- const choices = resolveDomainChoices(options.choices, context).map(
14426
- (choice) => ({
14427
- ...choice,
14428
- value: choice.value
14429
- })
14430
- );
14861
+ const choices = resolveDomainChoices(options.choices, context);
14431
14862
  return {
14432
14863
  type: "choiceList",
14433
14864
  choices,
@@ -16909,126 +17340,6 @@ function createReducerFx(_state) {
16909
17340
  function updateTable(state, nextTable) {
16910
17341
  return { ...state, table: nextTable };
16911
17342
  }
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
17343
  var moveComponentToEdgeInternal = moveComponentToEdge;
17033
17344
  var moveComponentToVertexInternal = moveComponentToVertex;
17034
17345
  var dealCardsFromDeckToHandInternal = dealCardsFromDeckToHand;
@@ -17212,19 +17523,6 @@ function createReducerOps() {
17212
17523
  return updateTable(state, nextTable);
17213
17524
  };
17214
17525
  },
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
17526
  moveComponentToSpace(args) {
17229
17527
  return (state) => {
17230
17528
  const nextTable = moveComponentToSpace(
@@ -17324,47 +17622,6 @@ function createReducerOps() {
17324
17622
  return impl;
17325
17623
  }
17326
17624
 
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
17625
  // ../../packages/app-sdk/src/reducer/definition-index.ts
17369
17626
  function phaseEntriesOf(definition) {
17370
17627
  return Object.entries(definition.phases);
@@ -17666,8 +17923,7 @@ function createTrustedRuntimeScope(definition) {
17666
17923
  }
17667
17924
  const helpers = {
17668
17925
  ...runtimeResultHelpers,
17669
- ops: createReducerOps(),
17670
- edit: createReducerEdit()
17926
+ ops: createReducerOps()
17671
17927
  };
17672
17928
  function fxForState2(state) {
17673
17929
  return fxForState(state);
@@ -18004,10 +18260,10 @@ function createTrustedInstructionRunner(scope, interactions, lifecycle) {
18004
18260
 
18005
18261
  // ../../packages/app-sdk/src/reducer/parse-utils.ts
18006
18262
  function formatIssue(label, issue) {
18007
- const path26 = issue.path.map(
18263
+ const path28 = issue.path.map(
18008
18264
  (segment) => typeof segment === "symbol" ? segment.toString() : String(segment)
18009
18265
  ).join(".");
18010
- return `${path26 || label}: ${issue.message}`;
18266
+ return `${path28 || label}: ${issue.message}`;
18011
18267
  }
18012
18268
  function safeParseOrThrow(schema, value, label) {
18013
18269
  const parsed = schema.safeParse(value);
@@ -18074,9 +18330,7 @@ function finiteValuesForDependency(key, domain) {
18074
18330
  return [...domain.eligibleTargets];
18075
18331
  }
18076
18332
  if (domain.type === "choice") {
18077
- return domain.choices.flatMap(
18078
- (choice) => choice.value === null ? [] : [choice.value]
18079
- );
18333
+ return domain.choices.map((choice) => choice.value);
18080
18334
  }
18081
18335
  throw new Error(
18082
18336
  `Interaction input '${key}' cannot be used as a dependency. V1 supports finite target and choice dependencies only.`
@@ -18644,7 +18898,7 @@ function enrichResourceInputPresentation(inputs, manifest) {
18644
18898
  }
18645
18899
  const resources = presentationById;
18646
18900
  const enrichChoice = (choice) => {
18647
- const presentation = choice.value === null ? void 0 : resources[choice.value];
18901
+ const presentation = resources[choice.value];
18648
18902
  return {
18649
18903
  ...choice,
18650
18904
  label: typeof presentation?.label === "string" && (!choice.label || choice.label === choice.value) ? presentation.label : choice.label || (typeof presentation?.label === "string" ? presentation.label : ""),
@@ -18652,16 +18906,7 @@ function enrichResourceInputPresentation(inputs, manifest) {
18652
18906
  };
18653
18907
  };
18654
18908
  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") {
18909
+ if (input.domain.type === "choice" || input.domain.type === "choiceList") {
18665
18910
  return {
18666
18911
  ...input,
18667
18912
  domain: {
@@ -19173,15 +19418,16 @@ function resolveContainerRef(table, ref) {
19173
19418
  throw new Error(`Unknown board '${ref.boardId}'.`);
19174
19419
  }
19175
19420
  const space2 = board2?.spaces[ref.spaceId];
19176
- if (!space2) {
19421
+ if (!space2?.zoneId) {
19177
19422
  throw new Error(
19178
- `Unknown board space '${ref.spaceId}' on board '${ref.boardId}'.`
19423
+ `Board space '${ref.spaceId}' on board '${ref.boardId}' has no container zone.`
19179
19424
  );
19180
19425
  }
19181
19426
  return {
19182
19427
  kind: "space",
19183
19428
  boardId: board2.id,
19184
- spaceId: ref.spaceId
19429
+ spaceId: ref.spaceId,
19430
+ zoneId: space2.zoneId
19185
19431
  };
19186
19432
  }
19187
19433
  const board = table.boards.byId[resolveRuntimeBoardId(table, ref.boardId, ref.playerId)];
@@ -19191,15 +19437,16 @@ function resolveContainerRef(table, ref) {
19191
19437
  );
19192
19438
  }
19193
19439
  const space = board?.spaces[ref.spaceId];
19194
- if (!space) {
19440
+ if (!space?.zoneId) {
19195
19441
  throw new Error(
19196
- `Unknown board space '${ref.spaceId}' on board '${ref.boardId}' for '${ref.playerId}'.`
19442
+ `Board space '${ref.spaceId}' on board '${ref.boardId}' for '${ref.playerId}' has no container zone.`
19197
19443
  );
19198
19444
  }
19199
19445
  return {
19200
19446
  kind: "space",
19201
19447
  boardId: board.id,
19202
- spaceId: ref.spaceId
19448
+ spaceId: ref.spaceId,
19449
+ zoneId: space.zoneId
19203
19450
  };
19204
19451
  }
19205
19452
  function readContainerComponents(table, ref) {
@@ -20150,7 +20397,7 @@ function materializeAccept(pending) {
20150
20397
  }
20151
20398
 
20152
20399
  // ../../packages/reducer-contract/generated/version.ts
20153
- var REDUCER_CONTRACT_VERSION = "7.0.1";
20400
+ var REDUCER_CONTRACT_VERSION = "7.0.0";
20154
20401
 
20155
20402
  // ../../packages/app-sdk/src/reducer/ingress/runtime-payload.ts
20156
20403
  var runtimePayloadSchema = external_exports.lazy(
@@ -20826,7 +21073,7 @@ function createReducerBundle(definition) {
20826
21073
  // src/utils/ts-module-loader.ts
20827
21074
  import { mkdtemp as mkdtemp2, rm as rm4, writeFile as writeFile3 } from "fs/promises";
20828
21075
  import { tmpdir as tmpdir2 } from "os";
20829
- import path17 from "path";
21076
+ import path18 from "path";
20830
21077
  import { pathToFileURL as pathToFileURL2 } from "url";
20831
21078
  import { build as build2 } from "esbuild";
20832
21079
  var ESBUILD_EXTERNALS = [
@@ -20840,14 +21087,14 @@ function resolveSourceCheckoutBuildContext() {
20840
21087
  const repoRoot = resolveCliRepoRoot(import.meta.url);
20841
21088
  return {
20842
21089
  nodePaths: [
20843
- path17.join(repoRoot, "apps", "dreamboard-cli", "node_modules"),
20844
- path17.join(repoRoot, "node_modules")
21090
+ path18.join(repoRoot, "apps", "dreamboard-cli", "node_modules"),
21091
+ path18.join(repoRoot, "node_modules")
20845
21092
  ],
20846
21093
  plugins: [createRepoLocalPackageResolutionPlugin({ repoRoot })]
20847
21094
  };
20848
21095
  } catch {
20849
21096
  return {
20850
- nodePaths: [path17.join(process.cwd(), "node_modules")],
21097
+ nodePaths: [path18.join(process.cwd(), "node_modules")],
20851
21098
  plugins: []
20852
21099
  };
20853
21100
  }
@@ -20873,10 +21120,10 @@ async function bundleTypeScriptModuleText(entryPath, options = {}) {
20873
21120
  return output.text;
20874
21121
  }
20875
21122
  async function importTypeScriptModule(entryPath) {
20876
- const tempDir = await mkdtemp2(path17.join(tmpdir2(), "dreamboard-ts-module-"));
20877
- const outfile = path17.join(
21123
+ const tempDir = await mkdtemp2(path18.join(tmpdir2(), "dreamboard-ts-module-"));
21124
+ const outfile = path18.join(
20878
21125
  tempDir,
20879
- `${path17.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
21126
+ `${path18.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
20880
21127
  );
20881
21128
  try {
20882
21129
  const bundledText = await bundleTypeScriptModuleText(entryPath);
@@ -20901,7 +21148,7 @@ import {
20901
21148
  symlink
20902
21149
  } from "fs/promises";
20903
21150
  import { tmpdir as tmpdir3 } from "os";
20904
- import path18 from "path";
21151
+ import path19 from "path";
20905
21152
  import { createInterface } from "readline";
20906
21153
  import { fileURLToPath as fileURLToPath7 } from "url";
20907
21154
  var READY_PREFIX = "HARNESS_READY ";
@@ -20909,15 +21156,15 @@ var HARNESS_START_IDLE_TIMEOUT_MS = 18e4;
20909
21156
  var HARNESS_START_MAX_TIMEOUT_MS = 6e5;
20910
21157
  var HARNESS_STOP_TIMEOUT_MS = 1e4;
20911
21158
  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(
21159
+ var MODULE_DIR4 = path19.dirname(fileURLToPath7(import.meta.url));
21160
+ var REPO_ROOT3 = path19.resolve(MODULE_DIR4, "../../../../..");
21161
+ var PROJECT_DEPENDENCY_NODE_MODULES = path19.join(
20915
21162
  REPO_ROOT3,
20916
21163
  "apps",
20917
21164
  "dreamboard-cli",
20918
21165
  "node_modules"
20919
21166
  );
20920
- var UI_SDK_NODE_MODULES = path18.join(
21167
+ var UI_SDK_NODE_MODULES = path19.join(
20921
21168
  REPO_ROOT3,
20922
21169
  "packages",
20923
21170
  "ui-sdk",
@@ -20927,8 +21174,8 @@ async function startEmbeddedHarnessSession(options) {
20927
21174
  const repoRoot = await resolveRepoRoot2(options.projectRoot);
20928
21175
  const gradlew = await resolveGradleLauncher(repoRoot);
20929
21176
  const fixture = await prepareLocalHarnessFixture(options);
20930
- const logDir = path18.join(options.projectRoot, "test", "generated");
20931
- const logFilePath = path18.join(logDir, "embedded-harness.log");
21177
+ const logDir = path19.join(options.projectRoot, "test", "generated");
21178
+ const logFilePath = path19.join(logDir, "embedded-harness.log");
20932
21179
  await mkdir2(logDir, { recursive: true });
20933
21180
  const previousClientConfig = client.getConfig();
20934
21181
  const child = spawn5(
@@ -20937,7 +21184,7 @@ async function startEmbeddedHarnessSession(options) {
20937
21184
  ...gradlew.args,
20938
21185
  "--console=plain",
20939
21186
  ":apps:backend:runEmbeddedHarness",
20940
- `-PharnessManifestPath=${path18.join(options.projectRoot, MATERIALIZED_MANIFEST_FILE)}`,
21187
+ `-PharnessManifestPath=${path19.join(options.projectRoot, MATERIALIZED_MANIFEST_FILE)}`,
20941
21188
  `-PharnessBundlePath=${fixture.bundleRoot}`,
20942
21189
  `-PharnessGameId=${fixture.gameId}`,
20943
21190
  `-PharnessManifestId=${fixture.manifestId}`,
@@ -21004,7 +21251,7 @@ async function ensureSymlink(targetPath, linkPath) {
21004
21251
  if (await pathExists3(linkPath)) {
21005
21252
  return;
21006
21253
  }
21007
- await mkdir2(path18.dirname(linkPath), { recursive: true });
21254
+ await mkdir2(path19.dirname(linkPath), { recursive: true });
21008
21255
  await symlink(
21009
21256
  targetPath,
21010
21257
  linkPath,
@@ -21015,13 +21262,13 @@ async function ensureEmbeddedHarnessDependencies(projectRoot) {
21015
21262
  if (await pathExists3(PROJECT_DEPENDENCY_NODE_MODULES)) {
21016
21263
  await ensureSymlink(
21017
21264
  PROJECT_DEPENDENCY_NODE_MODULES,
21018
- path18.join(projectRoot, "node_modules")
21265
+ path19.join(projectRoot, "node_modules")
21019
21266
  );
21020
21267
  }
21021
21268
  if (await pathExists3(UI_SDK_NODE_MODULES)) {
21022
21269
  await ensureSymlink(
21023
21270
  UI_SDK_NODE_MODULES,
21024
- path18.join(projectRoot, "ui", "node_modules")
21271
+ path19.join(projectRoot, "ui", "node_modules")
21025
21272
  );
21026
21273
  }
21027
21274
  }
@@ -21031,15 +21278,15 @@ async function prepareLocalHarnessFixture(options) {
21031
21278
  const manifestContent = await readMaterializedManifestText(
21032
21279
  options.projectRoot
21033
21280
  );
21034
- const appEntryPath = path18.join(options.projectRoot, "app", "index.ts");
21281
+ const appEntryPath = path19.join(options.projectRoot, "app", "index.ts");
21035
21282
  if (!await exists(appEntryPath)) {
21036
21283
  throw new Error(
21037
- `Embedded harness requires ${path18.relative(options.projectRoot, appEntryPath)}.`
21284
+ `Embedded harness requires ${path19.relative(options.projectRoot, appEntryPath)}.`
21038
21285
  );
21039
21286
  }
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 });
21287
+ const bundleRoot = await mkdtemp3(path19.join(tmpdir3(), "dreamboard-harness-"));
21288
+ const bundleEntryPath = path19.join(bundleRoot, "src", "app", "index.js");
21289
+ await mkdir2(path19.dirname(bundleEntryPath), { recursive: true });
21043
21290
  const bunExecutable = await resolveBunExecutable();
21044
21291
  if (!bunExecutable) {
21045
21292
  await rm5(bundleRoot, { recursive: true, force: true });
@@ -21076,7 +21323,7 @@ async function prepareLocalHarnessFixture(options) {
21076
21323
  const bundleContent = await readFile3(bundleEntryPath, "utf8");
21077
21324
  const manifestHash = hashContent(manifestContent);
21078
21325
  const bundleHash = hashContent(bundleContent);
21079
- const gameSlug = options.projectConfig.slug || path18.basename(options.projectRoot);
21326
+ const gameSlug = options.projectConfig.slug || path19.basename(options.projectRoot);
21080
21327
  const authoring = getProjectAuthoringState(options.projectConfig);
21081
21328
  return {
21082
21329
  bundleRoot,
@@ -21096,14 +21343,14 @@ async function prepareLocalHarnessFixture(options) {
21096
21343
  };
21097
21344
  }
21098
21345
  async function resolveBunExecutable() {
21099
- const currentExecutable = path18.basename(process.execPath).toLowerCase();
21346
+ const currentExecutable = path19.basename(process.execPath).toLowerCase();
21100
21347
  if (currentExecutable === "bun" || currentExecutable === "bun.exe") {
21101
21348
  return process.execPath;
21102
21349
  }
21103
21350
  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") : []
21351
+ ...(process.env.PATH ?? "").split(path19.delimiter).filter((directory) => directory.length > 0).flatMap((directory) => executableCandidates(directory, "bun")),
21352
+ ...process.env.BUN_INSTALL ? executableCandidates(path19.join(process.env.BUN_INSTALL, "bin"), "bun") : [],
21353
+ ...process.env.HOME ? executableCandidates(path19.join(process.env.HOME, ".bun", "bin"), "bun") : []
21107
21354
  ];
21108
21355
  for (const candidate of candidatePaths) {
21109
21356
  try {
@@ -21119,11 +21366,11 @@ function executableCandidates(directory, executableName) {
21119
21366
  return [];
21120
21367
  }
21121
21368
  if (process.platform !== "win32") {
21122
- return [path18.join(directory, executableName)];
21369
+ return [path19.join(directory, executableName)];
21123
21370
  }
21124
21371
  const extensions = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter((extension) => extension.length > 0);
21125
21372
  return extensions.map(
21126
- (extension) => path18.join(directory, `${executableName}${extension.toLowerCase()}`)
21373
+ (extension) => path19.join(directory, `${executableName}${extension.toLowerCase()}`)
21127
21374
  );
21128
21375
  }
21129
21376
  async function waitForExitCode(child) {
@@ -21281,13 +21528,13 @@ async function waitForExit(child, timeoutMs) {
21281
21528
  }
21282
21529
  async function resolveGradleLauncher(repoRoot) {
21283
21530
  if (process.platform === "win32") {
21284
- const gradleBat = path18.join(repoRoot, "gradlew.bat");
21531
+ const gradleBat = path19.join(repoRoot, "gradlew.bat");
21285
21532
  if (!await exists(gradleBat)) {
21286
21533
  throw new Error(`Missing Gradle launcher at ${gradleBat}`);
21287
21534
  }
21288
21535
  return { command: gradleBat, args: [] };
21289
21536
  }
21290
- const gradleShell = path18.join(repoRoot, "gradlew");
21537
+ const gradleShell = path19.join(repoRoot, "gradlew");
21291
21538
  if (!await exists(gradleShell)) {
21292
21539
  throw new Error(`Missing Gradle launcher at ${gradleShell}`);
21293
21540
  }
@@ -21295,7 +21542,7 @@ async function resolveGradleLauncher(repoRoot) {
21295
21542
  }
21296
21543
  async function resolveRepoRoot2(projectRoot) {
21297
21544
  const currentFile = fileURLToPath7(import.meta.url);
21298
- const searchRoots = [path18.dirname(currentFile), projectRoot, process.cwd()];
21545
+ const searchRoots = [path19.dirname(currentFile), projectRoot, process.cwd()];
21299
21546
  for (const root of searchRoots) {
21300
21547
  const repoRoot = await findSourceCheckoutRepoRoot(root);
21301
21548
  if (repoRoot) {
@@ -21307,12 +21554,12 @@ async function resolveRepoRoot2(projectRoot) {
21307
21554
  );
21308
21555
  }
21309
21556
  async function findSourceCheckoutRepoRoot(startDir) {
21310
- let currentDir = path18.resolve(startDir);
21557
+ let currentDir = path19.resolve(startDir);
21311
21558
  while (true) {
21312
21559
  if (await isSourceCheckoutRepoRoot(currentDir)) {
21313
21560
  return currentDir;
21314
21561
  }
21315
- const parentDir = path18.dirname(currentDir);
21562
+ const parentDir = path19.dirname(currentDir);
21316
21563
  if (parentDir === currentDir) {
21317
21564
  return null;
21318
21565
  }
@@ -21320,7 +21567,7 @@ async function findSourceCheckoutRepoRoot(startDir) {
21320
21567
  }
21321
21568
  }
21322
21569
  async function isSourceCheckoutRepoRoot(rootDir) {
21323
- return await exists(path18.join(rootDir, "gradlew")) && await exists(path18.join(rootDir, "apps", "backend", "build.gradle.kts"));
21570
+ return await exists(path19.join(rootDir, "gradlew")) && await exists(path19.join(rootDir, "apps", "backend", "build.gradle.kts"));
21324
21571
  }
21325
21572
  function normalizeUuid(candidate, fallbackSeed) {
21326
21573
  if (candidate && UUID_PATTERN.test(candidate)) {
@@ -21371,8 +21618,8 @@ async function subscribeToCliSessionEvents(options) {
21371
21618
  }
21372
21619
 
21373
21620
  // src/ui/playwright-runner.ts
21374
- import os from "os";
21375
- import path19 from "path";
21621
+ import os2 from "os";
21622
+ import path20 from "path";
21376
21623
  function configurePlaywrightBrowsersPath() {
21377
21624
  if (process.env.PLAYWRIGHT_BROWSERS_PATH) {
21378
21625
  return;
@@ -21380,14 +21627,14 @@ function configurePlaywrightBrowsersPath() {
21380
21627
  const runtimeHome = process.env.HOME;
21381
21628
  let realHome;
21382
21629
  try {
21383
- realHome = os.userInfo().homedir;
21630
+ realHome = os2.userInfo().homedir;
21384
21631
  } catch {
21385
21632
  return;
21386
21633
  }
21387
- if (!runtimeHome || path19.resolve(runtimeHome) === path19.resolve(realHome)) {
21634
+ if (!runtimeHome || path20.resolve(runtimeHome) === path20.resolve(realHome)) {
21388
21635
  return;
21389
21636
  }
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");
21637
+ 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
21638
  process.env.PLAYWRIGHT_BROWSERS_PATH = browserCachePath;
21392
21639
  }
21393
21640
  async function buildBrowserAuthInitScript(config) {
@@ -21396,7 +21643,7 @@ async function buildBrowserAuthInitScript(config) {
21396
21643
  return `(function(){localStorage.setItem('supabase_token',${JSON.stringify(config.authToken)});})();`;
21397
21644
  }
21398
21645
  try {
21399
- const { createClient: createClient2 } = await import("./dist-WJRJNFLI.js");
21646
+ const { createClient: createClient2 } = await import("./dist-FRURQI7Q.js");
21400
21647
  const supabase = createClient2(config.supabaseUrl, config.supabaseAnonKey);
21401
21648
  let sessionData = null;
21402
21649
  if (!sessionData) {
@@ -21490,42 +21737,9 @@ var TESTING_TYPES_STUB2 = "export function defineScenario(scenario) { return sce
21490
21737
  var DEFAULT_TIMEOUT_MS = 1e4;
21491
21738
  var BASE_SUFFIX = ".base.ts";
21492
21739
  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
21740
  var testingExpectApiFactoryPromise;
21527
21741
  async function loadTestingExpectApiFactory() {
21528
- testingExpectApiFactoryPromise ??= import("./src-CUL7EGGG.js").then(
21742
+ testingExpectApiFactoryPromise ??= import("./dist-FEPN3BDN.js").then(
21529
21743
  (module) => module.createExpectApi
21530
21744
  );
21531
21745
  return testingExpectApiFactoryPromise;
@@ -21565,7 +21779,7 @@ async function discoverFiles(root, suffix) {
21565
21779
  const entries = await readdir3(root, { withFileTypes: true });
21566
21780
  const files = [];
21567
21781
  for (const entry of entries) {
21568
- const entryPath = path20.join(root, entry.name);
21782
+ const entryPath = path21.join(root, entry.name);
21569
21783
  if (entry.isDirectory()) {
21570
21784
  files.push(...await discoverFiles(entryPath, suffix));
21571
21785
  continue;
@@ -21614,38 +21828,38 @@ function parseTypedScenarioDefinition(value) {
21614
21828
  };
21615
21829
  }
21616
21830
  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")
21831
+ return await exists(path21.join(projectRoot, "app", "game.ts")) && await exists(
21832
+ path21.join(projectRoot, "shared", "generated", "ui-contract.ts")
21619
21833
  );
21620
21834
  }
21621
21835
  async function ensureReducerNativeTestingFiles(projectRoot) {
21622
- const testingTypesPath = path20.join(projectRoot, "test", "testing-types.ts");
21623
- const testingContractPath = path20.join(
21836
+ const testingTypesPath = path21.join(projectRoot, "test", "testing-types.ts");
21837
+ const testingContractPath = path21.join(
21624
21838
  projectRoot,
21625
21839
  "test",
21626
21840
  "generated",
21627
21841
  "testing-contract.ts"
21628
21842
  );
21629
- const baseStatesPath = path20.join(
21843
+ const baseStatesPath = path21.join(
21630
21844
  projectRoot,
21631
21845
  "test",
21632
21846
  "generated",
21633
21847
  "base-states.generated.ts"
21634
21848
  );
21635
- const baseStatesDtsPath = path20.join(
21849
+ const baseStatesDtsPath = path21.join(
21636
21850
  projectRoot,
21637
21851
  "test",
21638
21852
  "generated",
21639
21853
  "base-states.generated.d.ts"
21640
21854
  );
21641
- const scenarioManifestPath = path20.join(
21855
+ const scenarioManifestPath = path21.join(
21642
21856
  projectRoot,
21643
21857
  "test",
21644
21858
  "generated",
21645
21859
  "scenario-manifest.generated.ts"
21646
21860
  );
21647
- await ensureDir(path20.dirname(testingTypesPath));
21648
- await ensureDir(path20.dirname(testingContractPath));
21861
+ await ensureDir(path21.dirname(testingTypesPath));
21862
+ await ensureDir(path21.dirname(testingContractPath));
21649
21863
  const existingTestingTypes = await readTextFileIfExists(testingTypesPath);
21650
21864
  if (shouldRefreshReducerTestingTypes(existingTestingTypes)) {
21651
21865
  await writeTextFile(
@@ -21689,7 +21903,7 @@ var DEFAULT_REJECTION_CODES2 = [
21689
21903
  ];
21690
21904
  async function collectKnownRejectionCodes(projectRoot) {
21691
21905
  const knownCodes = new Set(DEFAULT_REJECTION_CODES2);
21692
- const gamePath = path20.join(projectRoot, "app", "game.ts");
21906
+ const gamePath = path21.join(projectRoot, "app", "game.ts");
21693
21907
  if (!await exists(gamePath)) {
21694
21908
  return Array.from(knownCodes).sort(
21695
21909
  (left, right) => left.localeCompare(right)
@@ -21716,7 +21930,7 @@ async function collectKnownRejectionCodes(projectRoot) {
21716
21930
  }
21717
21931
  async function loadTypedBases(projectRoot) {
21718
21932
  const baseFiles = await discoverFiles(
21719
- path20.join(projectRoot, "test", "bases"),
21933
+ path21.join(projectRoot, "test", "bases"),
21720
21934
  BASE_SUFFIX
21721
21935
  );
21722
21936
  const loaded = [];
@@ -21735,8 +21949,8 @@ async function loadTypedBases(projectRoot) {
21735
21949
  return loaded;
21736
21950
  }
21737
21951
  async function loadTypedScenarios(projectRoot, options) {
21738
- const scenarioFiles = options.scenarioPath ? [path20.resolve(projectRoot, options.scenarioPath)] : await discoverFiles(
21739
- path20.join(projectRoot, "test", "scenarios"),
21952
+ const scenarioFiles = options.scenarioPath ? [path21.resolve(projectRoot, options.scenarioPath)] : await discoverFiles(
21953
+ path21.join(projectRoot, "test", "scenarios"),
21740
21954
  SCENARIO_SUFFIX
21741
21955
  );
21742
21956
  const loaded = [];
@@ -21755,8 +21969,8 @@ async function loadTypedScenarios(projectRoot, options) {
21755
21969
  return loaded;
21756
21970
  }
21757
21971
  function reducerNativeTestHelperExternals(projectRoot, filePath) {
21758
- const testingTypesPath = path20.join(projectRoot, "test", "testing-types");
21759
- const relative = path20.relative(path20.dirname(filePath), testingTypesPath).replaceAll("\\", "/");
21972
+ const testingTypesPath = path21.join(projectRoot, "test", "testing-types");
21973
+ const relative = path21.relative(path21.dirname(filePath), testingTypesPath).replaceAll("\\", "/");
21760
21974
  const specifier = relative.startsWith(".") ? relative : `./${relative}`;
21761
21975
  return [specifier, `${specifier}.ts`];
21762
21976
  }
@@ -21957,6 +22171,13 @@ var ShadowReducerRuntime = class {
21957
22171
  (_2, index) => `player-${index + 1}`
21958
22172
  );
21959
22173
  }
22174
+ manifest;
22175
+ gameModuleDefault;
22176
+ createInitialTable;
22177
+ seed;
22178
+ players;
22179
+ setupProfileId;
22180
+ debug;
21960
22181
  bundle;
21961
22182
  runtime;
21962
22183
  playerIds;
@@ -22101,6 +22322,8 @@ var EmbeddedGameplayTracker = class {
22101
22322
  this.playerId = playerId;
22102
22323
  this.state.playerId = playerId;
22103
22324
  }
22325
+ sessionId;
22326
+ playerId;
22104
22327
  abortController = new AbortController();
22105
22328
  state = {
22106
22329
  version: -1,
@@ -22252,7 +22475,7 @@ async function assertLiveMatchesShadow(runner, shadow, live) {
22252
22475
  }
22253
22476
  }
22254
22477
  async function loadBrowserDriver(projectRoot) {
22255
- const filePath = path20.join(projectRoot, "test", "browser-driver.ts");
22478
+ const filePath = path21.join(projectRoot, "test", "browser-driver.ts");
22256
22479
  if (!await exists(filePath)) {
22257
22480
  return null;
22258
22481
  }
@@ -22280,7 +22503,7 @@ function sanitizeSnapshotSegment(value) {
22280
22503
  function createScenarioSnapshotMatcher(options) {
22281
22504
  return (filename, actual) => {
22282
22505
  const suffix = filename ? `.${sanitizeSnapshotSegment(filename)}` : "";
22283
- const snapshotPath = path20.join(
22506
+ const snapshotPath = path21.join(
22284
22507
  options.projectRoot,
22285
22508
  "test",
22286
22509
  "generated",
@@ -22292,15 +22515,15 @@ function createScenarioSnapshotMatcher(options) {
22292
22515
  };
22293
22516
  const serialized = `${JSON.stringify(wrappedValue, null, 2)}
22294
22517
  `;
22295
- mkdirSync2(path20.dirname(snapshotPath), { recursive: true });
22518
+ mkdirSync2(path21.dirname(snapshotPath), { recursive: true });
22296
22519
  if (!existsSync8(snapshotPath) || options.updateSnapshots) {
22297
22520
  writeFileSync2(snapshotPath, serialized, "utf8");
22298
22521
  return;
22299
22522
  }
22300
- const previous = JSON.parse(readFileSync4(snapshotPath, "utf8"));
22523
+ const previous = JSON.parse(readFileSync3(snapshotPath, "utf8"));
22301
22524
  if (!deepEqual(previous.value, actual)) {
22302
22525
  throw new Error(
22303
- `Snapshot mismatch for scenario '${options.scenarioId}'. Re-run with --update-snapshots to refresh ${path20.relative(options.projectRoot, snapshotPath)}.`
22526
+ `Snapshot mismatch for scenario '${options.scenarioId}'. Re-run with --update-snapshots to refresh ${path21.relative(options.projectRoot, snapshotPath)}.`
22304
22527
  );
22305
22528
  }
22306
22529
  };
@@ -22561,7 +22784,7 @@ async function createSessionFromScenario(options) {
22561
22784
  }
22562
22785
  var MATERIALIZED_SCENARIO_CACHE_VERSION = 1;
22563
22786
  function materializedScenarioCachePath(options) {
22564
- return path20.join(
22787
+ return path21.join(
22565
22788
  options.projectRoot,
22566
22789
  PROJECT_DIR_NAME,
22567
22790
  "dev",
@@ -22589,7 +22812,7 @@ async function readMaterializedScenarioCache(options) {
22589
22812
  }
22590
22813
  async function writeMaterializedScenarioCache(options) {
22591
22814
  const cachePath = materializedScenarioCachePath(options);
22592
- await ensureDir(path20.dirname(cachePath));
22815
+ await ensureDir(path21.dirname(cachePath));
22593
22816
  await writeJsonFile(cachePath, {
22594
22817
  cacheVersion: MATERIALIZED_SCENARIO_CACHE_VERSION,
22595
22818
  fingerprintHash: options.fingerprintHash,
@@ -22686,10 +22909,10 @@ async function materializeScenarioReducerState(options) {
22686
22909
  }
22687
22910
  const [gameModule, manifestContractModule] = await Promise.all([
22688
22911
  importTypeScriptModule(
22689
- path20.join(options.projectRoot, "app", "game.ts")
22912
+ path21.join(options.projectRoot, "app", "game.ts")
22690
22913
  ),
22691
22914
  importTypeScriptModule(
22692
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
22915
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
22693
22916
  )
22694
22917
  ]);
22695
22918
  const createInitialTable = typeof manifestContractModule.createInitialTable === "function" ? manifestContractModule.createInitialTable : null;
@@ -22771,10 +22994,10 @@ async function createScenarioActionPlan(options) {
22771
22994
  loadGeneratedBaseStates(options.projectRoot),
22772
22995
  loadManifest(options.projectRoot),
22773
22996
  importTypeScriptModule(
22774
- path20.join(options.projectRoot, "app", "game.ts")
22997
+ path21.join(options.projectRoot, "app", "game.ts")
22775
22998
  ),
22776
22999
  importTypeScriptModule(
22777
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23000
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
22778
23001
  )
22779
23002
  ]);
22780
23003
  const matchingScenarios = scenarios.filter(
@@ -23041,7 +23264,7 @@ function sortBasesForArtifacts(bases, basesById) {
23041
23264
  return ordered;
23042
23265
  }
23043
23266
  function writeProjectionSnapshots(options) {
23044
- const projectionDir = path20.join(
23267
+ const projectionDir = path21.join(
23045
23268
  options.projectRoot,
23046
23269
  "test",
23047
23270
  "generated",
@@ -23052,7 +23275,7 @@ function writeProjectionSnapshots(options) {
23052
23275
  mkdirSync2(projectionDir, { recursive: true });
23053
23276
  const projection = options.shadow.projectAllSeats();
23054
23277
  for (const [playerId, seatProjection] of Object.entries(projection.seats)) {
23055
- const outputPath = path20.join(projectionDir, `${playerId}.projection.json`);
23278
+ const outputPath = path21.join(projectionDir, `${playerId}.projection.json`);
23056
23279
  writeFileSync2(
23057
23280
  outputPath,
23058
23281
  `${JSON.stringify(
@@ -23072,7 +23295,7 @@ function writeProjectionSnapshots(options) {
23072
23295
  function validateTypedScenarioBases(scenarios, basesById) {
23073
23296
  const available = new Set(basesById.keys());
23074
23297
  const invalid = scenarios.filter((scenario) => !available.has(scenario.definition.from)).map(
23075
- (scenario) => path20.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.definition.from}'`
23298
+ (scenario) => path21.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.definition.from}'`
23076
23299
  );
23077
23300
  if (invalid.length > 0) {
23078
23301
  throw new Error(
@@ -23086,23 +23309,23 @@ async function writeReducerNativeGeneratedFiles(options) {
23086
23309
  const manifestHash = hashContent(JSON.stringify(manifest));
23087
23310
  const appBundleHash = hashContent(
23088
23311
  await bundleTypeScriptModuleText(
23089
- path20.join(options.projectRoot, "app", "game.ts")
23312
+ path21.join(options.projectRoot, "app", "game.ts")
23090
23313
  )
23091
23314
  );
23092
23315
  const uiContractHash = hashContent(
23093
23316
  await bundleTypeScriptModuleText(
23094
- path20.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23317
+ path21.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23095
23318
  )
23096
23319
  );
23097
- const generatedDir = path20.join(options.projectRoot, "test", "generated");
23320
+ const generatedDir = path21.join(options.projectRoot, "test", "generated");
23098
23321
  await ensureDir(generatedDir);
23099
23322
  const baseStates = {};
23100
23323
  const [gameModule, manifestContractModule] = await Promise.all([
23101
23324
  importTypeScriptModule(
23102
- path20.join(options.projectRoot, "app", "game.ts")
23325
+ path21.join(options.projectRoot, "app", "game.ts")
23103
23326
  ),
23104
23327
  importTypeScriptModule(
23105
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23328
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
23106
23329
  )
23107
23330
  ]);
23108
23331
  const createInitialTable = typeof manifestContractModule.createInitialTable === "function" ? manifestContractModule.createInitialTable : null;
@@ -23190,21 +23413,21 @@ async function writeReducerNativeGeneratedFiles(options) {
23190
23413
  }
23191
23414
  const header = "// Generated by dreamboard test generate. Do not edit by hand.\n";
23192
23415
  await writeTextFile(
23193
- path20.join(generatedDir, "base-states.generated.ts"),
23416
+ path21.join(generatedDir, "base-states.generated.ts"),
23194
23417
  `${header}export const BASE_STATES = ${JSON.stringify(baseStates, null, 2)} as const;
23195
23418
  `
23196
23419
  );
23197
23420
  await writeTextFile(
23198
- path20.join(generatedDir, "base-states.generated.d.ts"),
23421
+ path21.join(generatedDir, "base-states.generated.d.ts"),
23199
23422
  `${header}export declare const BASE_STATES: Record<string, unknown>;
23200
23423
  `
23201
23424
  );
23202
23425
  await writeTextFile(
23203
- path20.join(generatedDir, "scenario-manifest.generated.ts"),
23426
+ path21.join(generatedDir, "scenario-manifest.generated.ts"),
23204
23427
  `${header}export const SCENARIO_MANIFEST = ${JSON.stringify(
23205
23428
  options.scenarios.map((scenario) => ({
23206
23429
  id: scenario.definition.id,
23207
- filePath: path20.relative(generatedDir, scenario.filePath),
23430
+ filePath: path21.relative(generatedDir, scenario.filePath),
23208
23431
  base: scenario.definition.from,
23209
23432
  runners: normalizeScenarioRunners(scenario.definition.runners)
23210
23433
  })),
@@ -23213,14 +23436,14 @@ async function writeReducerNativeGeneratedFiles(options) {
23213
23436
  )} as const;
23214
23437
  `
23215
23438
  );
23216
- await writeJsonFile(path20.join(generatedDir, ".generation-meta.json"), {
23439
+ await writeJsonFile(path21.join(generatedDir, ".generation-meta.json"), {
23217
23440
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
23218
23441
  scenarioCount: options.scenarios.length,
23219
23442
  baseStateCount: options.bases.length
23220
23443
  });
23221
23444
  }
23222
23445
  async function loadGeneratedBaseStates(projectRoot) {
23223
- const filePath = path20.join(
23446
+ const filePath = path21.join(
23224
23447
  projectRoot,
23225
23448
  "test",
23226
23449
  "generated",
@@ -23233,7 +23456,7 @@ async function loadGeneratedBaseStates(projectRoot) {
23233
23456
  return module.BASE_STATES ?? null;
23234
23457
  }
23235
23458
  async function loadGeneratedScenarioManifest(projectRoot) {
23236
- const filePath = path20.join(
23459
+ const filePath = path21.join(
23237
23460
  projectRoot,
23238
23461
  "test",
23239
23462
  "generated",
@@ -23323,12 +23546,12 @@ async function currentFingerprint(options) {
23323
23546
  manifestHash: hashContent(JSON.stringify(manifest)),
23324
23547
  appBundleHash: hashContent(
23325
23548
  await bundleTypeScriptModuleText(
23326
- path20.join(options.projectRoot, "app", "game.ts")
23549
+ path21.join(options.projectRoot, "app", "game.ts")
23327
23550
  )
23328
23551
  ),
23329
23552
  uiContractHash: hashContent(
23330
23553
  await bundleTypeScriptModuleText(
23331
- path20.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23554
+ path21.join(options.projectRoot, "shared", "generated", "ui-contract.ts")
23332
23555
  )
23333
23556
  ),
23334
23557
  setupProfileId: effectiveSetup.setupProfileId,
@@ -23375,10 +23598,10 @@ async function runReducerNativeScenarios(options) {
23375
23598
  loadGeneratedBaseStates(options.projectRoot),
23376
23599
  loadManifest(options.projectRoot),
23377
23600
  importTypeScriptModule(
23378
- path20.join(options.projectRoot, "app", "game.ts")
23601
+ path21.join(options.projectRoot, "app", "game.ts")
23379
23602
  ),
23380
23603
  importTypeScriptModule(
23381
- path20.join(options.projectRoot, "shared", "manifest-contract.ts")
23604
+ path21.join(options.projectRoot, "shared", "manifest-contract.ts")
23382
23605
  )
23383
23606
  ]);
23384
23607
  let generatedBaseStates = initialGeneratedBaseStates;
@@ -23596,11 +23819,7 @@ async function runReducerNativeScenarios(options) {
23596
23819
  results.push({
23597
23820
  id: scenario.definition.id,
23598
23821
  success: false,
23599
- error: error instanceof Error ? formatScenarioErrorForDisplay({
23600
- error,
23601
- projectRoot: options.projectRoot,
23602
- scenarioFilePath: scenario.filePath
23603
- }) : `Scenario '${scenario.definition.id}' failed.`
23822
+ error: error instanceof Error ? error.message : `Scenario '${scenario.definition.id}' failed.`
23604
23823
  });
23605
23824
  }
23606
23825
  }
@@ -23616,8 +23835,8 @@ async function runReducerNativeScenarios(options) {
23616
23835
  }
23617
23836
 
23618
23837
  // src/services/project/reducer-contract-preflight.ts
23619
- import path21 from "path";
23620
- var GAME_CONTRACT_ENTRY_PATH = path21.join("app", "game-contract.ts");
23838
+ import path22 from "path";
23839
+ var GAME_CONTRACT_ENTRY_PATH = path22.join("app", "game-contract.ts");
23621
23840
  function normalizeErrorMessage(error) {
23622
23841
  const rawMessage = error instanceof Error ? error.message : String(error ?? "Unknown error");
23623
23842
  return rawMessage.split("\n").map((line) => line.trim()).find(Boolean)?.replace(/^Error:\s*/u, "") ?? "Unknown error";
@@ -23626,7 +23845,7 @@ function isManifestScopedIdBrandingError(message) {
23626
23845
  return message.includes("defineGameContract:") && message.includes("manifest-scoped") && (message.includes("uses a raw z.string()") || message.includes("uses z.array(z.string())"));
23627
23846
  }
23628
23847
  async function assertReducerContractPreflight(projectRoot) {
23629
- const entryPath = path21.join(projectRoot, GAME_CONTRACT_ENTRY_PATH);
23848
+ const entryPath = path22.join(projectRoot, GAME_CONTRACT_ENTRY_PATH);
23630
23849
  try {
23631
23850
  await importTypeScriptModule(entryPath);
23632
23851
  } catch (error) {
@@ -23652,8 +23871,8 @@ async function assertReducerContractPreflight(projectRoot) {
23652
23871
  }
23653
23872
 
23654
23873
  // src/services/project/reducer-bundle-preflight.ts
23655
- import path22 from "path";
23656
- var REDUCER_BUNDLE_ENTRY_PATH = path22.join("app", "index.ts");
23874
+ import path23 from "path";
23875
+ var REDUCER_BUNDLE_ENTRY_PATH = path23.join("app", "index.ts");
23657
23876
  var PREFLIGHT_RNG_SEED = 1337;
23658
23877
  function buildPlayerIds(playerCount) {
23659
23878
  const ids = [];
@@ -23841,7 +24060,7 @@ async function runReducerBundleSmoke(options) {
23841
24060
  if (scenarios.length === 0) {
23842
24061
  return [];
23843
24062
  }
23844
- const entryPath = path22.join(projectRoot, REDUCER_BUNDLE_ENTRY_PATH);
24063
+ const entryPath = path23.join(projectRoot, REDUCER_BUNDLE_ENTRY_PATH);
23845
24064
  let module;
23846
24065
  try {
23847
24066
  module = await importTypeScriptModule(
@@ -23893,6 +24112,64 @@ async function runLoggedStep(message, task) {
23893
24112
  consola.start(message);
23894
24113
  return task();
23895
24114
  }
24115
+ function clearPreflightOutput() {
24116
+ if (!process.stdout.isTTY || process.env.CI) return;
24117
+ console.clear();
24118
+ }
24119
+ function formatDevReadyOutput(options) {
24120
+ const lines = ["Dreamboard dev", "", `Local: ${options.url}`];
24121
+ for (const networkUrl of options.networkUrls) {
24122
+ lines.push(`Network: ${networkUrl}`);
24123
+ }
24124
+ if (options.networkUrls.length > 0) {
24125
+ lines.push("Access: LAN only; use trusted networks.");
24126
+ }
24127
+ for (const allowedHost of options.allowedHosts) {
24128
+ lines.push(`Allowed: ${allowedHost}`);
24129
+ }
24130
+ lines.push(
24131
+ `Session: ${options.shortCode} (${options.sessionId}, ${options.sessionStatus})`,
24132
+ `Seed: ${options.seed}`
24133
+ );
24134
+ if (options.setupProfile) {
24135
+ const label = options.setupProfile.name ? `${options.setupProfile.name} (${options.setupProfile.id})` : options.setupProfile.id;
24136
+ lines.push(`Setup: ${label}`);
24137
+ }
24138
+ if (options.scenarioId) {
24139
+ lines.push(`Scenario: ${options.scenarioId}`);
24140
+ }
24141
+ if (options.materialization) {
24142
+ lines.push(
24143
+ `Snapshot: ${options.materialization.totalMs}ms total (${options.materialization.reducerHarnessMs}ms reducer, ${options.materialization.backendHydrateMs}ms backend)`
24144
+ );
24145
+ }
24146
+ lines.push(
24147
+ `Backend: ${options.apiBaseUrl}`,
24148
+ "",
24149
+ "UI edits hot-reload. Rule, manifest, and app changes need restart.",
24150
+ `Debug logs: ${options.debug ? "on" : "off (--debug)"}`,
24151
+ ""
24152
+ );
24153
+ return lines.join("\n");
24154
+ }
24155
+ function parseDevHost(value) {
24156
+ if (value === void 0 || value === false) return void 0;
24157
+ if (value === true) return true;
24158
+ const trimmed = value.trim();
24159
+ return trimmed.length > 0 ? trimmed : true;
24160
+ }
24161
+ function parseAllowedHosts(value) {
24162
+ if (!value) return [];
24163
+ return value.split(",").map((host) => normalizeAllowedHost(host)).filter((host) => Boolean(host));
24164
+ }
24165
+ function normalizeAllowedHost(value) {
24166
+ const trimmed = value.trim();
24167
+ if (!trimmed) return null;
24168
+ if (trimmed.includes("://")) {
24169
+ return new URL(trimmed).hostname;
24170
+ }
24171
+ return trimmed.split("/")[0]?.replace(/:\d+$/, "") || null;
24172
+ }
23896
24173
  var dev_default = defineCommand({
23897
24174
  meta: {
23898
24175
  name: "dev",
@@ -23940,7 +24217,17 @@ var dev_default = defineCommand({
23940
24217
  },
23941
24218
  port: {
23942
24219
  type: "string",
23943
- description: "Preferred local Vite port (defaults to 5173)"
24220
+ description: "Preferred local Vite port (defaults to 5352)"
24221
+ },
24222
+ host: {
24223
+ type: "string",
24224
+ description: "Expose the local dev host on the network. Pass without a value to bind all interfaces, or provide an address.",
24225
+ valueHint: "address"
24226
+ },
24227
+ "allowed-host": {
24228
+ type: "string",
24229
+ description: "Additional Host header to allow, for example a Cloudflare Tunnel hostname.",
24230
+ valueHint: "hostname"
23944
24231
  },
23945
24232
  ...CONFIG_FLAG_ARGS
23946
24233
  },
@@ -23958,9 +24245,9 @@ var dev_default = defineCommand({
23958
24245
  env: parsedArgs.env ?? "dev",
23959
24246
  debug: parsedArgs.debug
23960
24247
  });
23961
- const devDir = path23.join(projectRoot, PROJECT_DIR_NAME, "dev");
24248
+ const devDir = path24.join(projectRoot, PROJECT_DIR_NAME, "dev");
23962
24249
  await ensureDir(devDir);
23963
- const sessionFilePath = path23.join(devDir, "session.json");
24250
+ const sessionFilePath = path24.join(devDir, "session.json");
23964
24251
  const requestedResumeSessionId = parsedArgs.resume?.trim() || null;
23965
24252
  const requestedScenarioId = parsedArgs["from-scenario"]?.trim() || null;
23966
24253
  if (requestedResumeSessionId && parsedArgs["new-session"]) {
@@ -24043,10 +24330,13 @@ var dev_default = defineCommand({
24043
24330
  if (preferredPort !== void 0 && (!Number.isFinite(preferredPort) || preferredPort <= 0)) {
24044
24331
  throw new Error("Invalid --port value. Expected a positive integer.");
24045
24332
  }
24333
+ const allowedHosts = parseAllowedHosts(parsedArgs["allowed-host"]);
24046
24334
  const devServer = await startDreamboardDevServer({
24047
24335
  projectRoot,
24048
24336
  sessionFilePath,
24049
24337
  port: preferredPort,
24338
+ host: parseDevHost(parsedArgs.host),
24339
+ allowedHosts,
24050
24340
  config,
24051
24341
  runtimeConfig: {
24052
24342
  apiBaseUrl: config.apiBaseUrl,
@@ -24066,42 +24356,26 @@ var dev_default = defineCommand({
24066
24356
  }
24067
24357
  }
24068
24358
  });
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`."
24359
+ clearPreflightOutput();
24360
+ console.log(
24361
+ formatDevReadyOutput({
24362
+ url: devServer.url,
24363
+ networkUrls: devServer.networkUrls,
24364
+ allowedHosts,
24365
+ apiBaseUrl: config.apiBaseUrl,
24366
+ sessionStatus: scenarioSeededSession ? "seeded" : resumedExistingSession ? "reused" : "created",
24367
+ shortCode: runSession.shortCode,
24368
+ sessionId: runSession.sessionId,
24369
+ seed: runSession.seed ?? "unknown",
24370
+ debug: parsedArgs.debug,
24371
+ scenarioId: scenarioSeededSession ? requestedScenarioId : null,
24372
+ materialization: runSession.materialization,
24373
+ setupProfile: selectedSetupProfileId ? {
24374
+ id: selectedSetupProfileId,
24375
+ name: selectedSetupProfile?.name
24376
+ } : null
24377
+ })
24100
24378
  );
24101
- console.log(`
24102
- Open Dreamboard dev host:
24103
- ${devServer.url}
24104
- `);
24105
24379
  if (parsedArgs.open) {
24106
24380
  openBrowser(devServer.url);
24107
24381
  }
@@ -24308,7 +24582,7 @@ async function resolveBackendVersionMetadata() {
24308
24582
  }
24309
24583
  async function readWorkspacePackageJson(projectRoot) {
24310
24584
  try {
24311
- const raw = await readTextFile(path23.join(projectRoot, "package.json"));
24585
+ const raw = await readTextFile(path24.join(projectRoot, "package.json"));
24312
24586
  const parsed = JSON.parse(raw);
24313
24587
  return {
24314
24588
  dependencies: Object.fromEntries(
@@ -24446,7 +24720,7 @@ function extractUserIdFromJwt(token) {
24446
24720
  }
24447
24721
 
24448
24722
  // src/commands/join.ts
24449
- import path24 from "path";
24723
+ import path25 from "path";
24450
24724
 
24451
24725
  // src/services/join/jsonl-bot-session.ts
24452
24726
  import { createInterface as createInterface2 } from "readline";
@@ -24454,6 +24728,7 @@ var JsonlWriter = class {
24454
24728
  constructor(output) {
24455
24729
  this.output = output;
24456
24730
  }
24731
+ output;
24457
24732
  writeChain = Promise.resolve();
24458
24733
  write(envelope) {
24459
24734
  this.writeChain = this.writeChain.then(
@@ -24704,6 +24979,7 @@ var JoinBotState = class {
24704
24979
  constructor(playerId) {
24705
24980
  this.playerId = playerId;
24706
24981
  }
24982
+ playerId;
24707
24983
  hasBootstrap = false;
24708
24984
  latestGameplay;
24709
24985
  latestActions;
@@ -25366,7 +25642,7 @@ async function resolveDefaultSessionId(projectRoot) {
25366
25642
  "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
25643
  );
25368
25644
  }
25369
- const sessionFilePath = path24.join(
25645
+ const sessionFilePath = path25.join(
25370
25646
  projectRoot,
25371
25647
  PROJECT_DIR_NAME,
25372
25648
  "dev",
@@ -25478,7 +25754,7 @@ var logout_default = defineCommand({
25478
25754
  });
25479
25755
 
25480
25756
  // src/commands/new.ts
25481
- import path25 from "path";
25757
+ import path26 from "path";
25482
25758
  var new_default = defineCommand({
25483
25759
  meta: {
25484
25760
  name: "new",
@@ -25599,7 +25875,7 @@ var new_default = defineCommand({
25599
25875
  ruleId
25600
25876
  );
25601
25877
  consola.start("Scaffolding local workspace...");
25602
- const targetDir = path25.resolve(process.cwd(), normalizedSlug);
25878
+ const targetDir = path26.resolve(process.cwd(), normalizedSlug);
25603
25879
  await ensureDir(targetDir);
25604
25880
  await writeManifest(targetDir, blankManifest);
25605
25881
  await writeRule(targetDir, "");
@@ -25631,7 +25907,6 @@ var new_default = defineCommand({
25631
25907
  )
25632
25908
  );
25633
25909
  await writeSnapshot(targetDir);
25634
- await writeTextFile(path25.join(targetDir, "feedback.md"), "");
25635
25910
  consola.success(`Created new game in ${targetDir}`);
25636
25911
  consola.info(
25637
25912
  "Next: edit your files, then run 'dreamboard sync' followed by 'dreamboard compile'."
@@ -25956,9 +26231,9 @@ function buildSourceChanges(options) {
25956
26231
  if (mode === "replace") {
25957
26232
  return Object.entries(localFiles).filter(
25958
26233
  ([filePath]) => isSourceRevisionPath(filePath) || shouldAlwaysUpsertSourcePath(filePath)
25959
- ).sort(([left], [right]) => left.localeCompare(right)).map(([path26, content]) => ({
26234
+ ).sort(([left], [right]) => left.localeCompare(right)).map(([path28, content]) => ({
25960
26235
  kind: "upsert",
25961
- path: path26,
26236
+ path: path28,
25962
26237
  content
25963
26238
  }));
25964
26239
  }
@@ -26510,6 +26785,10 @@ var sync_default = defineCommand({
26510
26785
  }
26511
26786
  });
26512
26787
 
26788
+ // src/commands/test.ts
26789
+ import { readFile as readFile4 } from "fs/promises";
26790
+ import path27 from "path";
26791
+
26513
26792
  // src/services/testing/runtime-mode.ts
26514
26793
  function isRemoteTestEnvironment(environment) {
26515
26794
  return environment === "dev" || environment === "prod";
@@ -26559,6 +26838,40 @@ async function resolveLatestCompiledResult(projectRoot, projectConfig) {
26559
26838
  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
26839
  var NO_REDUCER_NATIVE_BASES_FOUND_ERROR = "No bases found under test/bases/*.base.ts";
26561
26840
  var NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR = "No scenarios found under test/scenarios/*.scenario.ts";
26841
+ function isPreviewProjectionEndpointUnavailable(error) {
26842
+ if (!isDreamboardApiError(error) || error.status !== 404) {
26843
+ return false;
26844
+ }
26845
+ const endpoint = error.problem.instance ?? error.problem.context?.endpoint;
26846
+ const message = error.problem.detail ?? error.problem.title;
26847
+ return endpoint?.includes("/preview/initial-projection") === true && message?.toLowerCase() === "not found";
26848
+ }
26849
+ async function uploadGeneratedPreviewProjection(options) {
26850
+ const previewBase = options.bases.find((base) => base.definition.id === "initial-turn") ?? options.bases[0];
26851
+ if (!previewBase) {
26852
+ return;
26853
+ }
26854
+ const projectionPath = path27.join(
26855
+ options.projectRoot,
26856
+ "test",
26857
+ "generated",
26858
+ "bases",
26859
+ previewBase.definition.id,
26860
+ "player-1.projection.json"
26861
+ );
26862
+ const projectionJson = await readFile4(projectionPath, "utf8");
26863
+ try {
26864
+ await uploadInitialProjectionSdk(options.gameId, projectionJson);
26865
+ } catch (error) {
26866
+ if (isPreviewProjectionEndpointUnavailable(error)) {
26867
+ consola.warn(
26868
+ "Skipping preview projection upload because the selected backend does not expose the preview projection endpoint."
26869
+ );
26870
+ return;
26871
+ }
26872
+ throw error;
26873
+ }
26874
+ }
26562
26875
  function resolveRequestedRunner(value) {
26563
26876
  if (value == null || value === "") {
26564
26877
  return void 0;
@@ -26617,7 +26930,7 @@ var generateCommand = defineCommand({
26617
26930
  async run({ args }) {
26618
26931
  const parsedFlags = parseConfigFlags(args);
26619
26932
  const useRemoteRuntime = shouldUseRemoteTestRuntime(parsedFlags.env);
26620
- const { projectRoot, projectConfig } = await resolveProjectContext(
26933
+ const { projectRoot, projectConfig, config } = await resolveProjectContext(
26621
26934
  parsedFlags,
26622
26935
  { requireAuth: useRemoteRuntime }
26623
26936
  );
@@ -26640,6 +26953,18 @@ var generateCommand = defineCommand({
26640
26953
  if (scenarios.length === 0) {
26641
26954
  throw new Error(NO_REDUCER_NATIVE_SCENARIOS_FOUND_ERROR);
26642
26955
  }
26956
+ if (config.authToken) {
26957
+ await configureClient(config);
26958
+ await uploadGeneratedPreviewProjection({
26959
+ projectRoot,
26960
+ gameId: runtimeIdentity.gameId,
26961
+ bases
26962
+ });
26963
+ } else {
26964
+ consola.info(
26965
+ "Skipping preview projection upload because this CLI invocation is not authenticated."
26966
+ );
26967
+ }
26643
26968
  consola.success(
26644
26969
  `Generated ${bases.length} base state(s) for ${scenarios.length} scenario(s).`
26645
26970
  );
@@ -26786,7 +27111,7 @@ function runDreamboardCli(internalSubCommands = {}) {
26786
27111
  const main = defineCommand({
26787
27112
  meta: {
26788
27113
  name: "dreamboard",
26789
- version: "0.1.7",
27114
+ version: "0.1.22",
26790
27115
  description: "Dreamboard CLI \u2014 game development platform"
26791
27116
  },
26792
27117
  subCommands
@@ -26823,6 +27148,7 @@ export {
26823
27148
  getProjectLocalMaintainerRegistry,
26824
27149
  applyWorkspaceCodegen,
26825
27150
  reconcileWorkspaceDependencies,
27151
+ assertCompilerPortableDependencies,
26826
27152
  runLocalTypecheck,
26827
27153
  compile_default,
26828
27154
  startCliAuthServer,
@@ -26841,4 +27167,4 @@ export {
26841
27167
  test_default,
26842
27168
  runDreamboardCli
26843
27169
  };
26844
- //# sourceMappingURL=chunk-MOVHYB6E.js.map
27170
+ //# sourceMappingURL=chunk-AQ5UUNJS.js.map