dreamboard 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -529,6 +529,11 @@ var createCompiledResult = (options) => (options.client ?? client).post({
529
529
  ...options.headers
530
530
  }
531
531
  });
532
+ var getCompiledResult = (options) => (options.client ?? client).get({
533
+ security: [{ scheme: "bearer", type: "http" }],
534
+ url: "/api/games/{gameId}/compiled-results/{compiledResultId}",
535
+ ...options
536
+ });
532
537
  var getGameSources = (options) => (options.client ?? client).get({
533
538
  security: [{ scheme: "bearer", type: "http" }],
534
539
  url: "/api/games/{gameId}/sources",
@@ -609,6 +614,11 @@ var submitAction = (options) => (options.client ?? client).post({
609
614
  ...options.headers
610
615
  }
611
616
  });
617
+ var getJob = (options) => (options.client ?? client).get({
618
+ security: [{ scheme: "bearer", type: "http" }],
619
+ url: "/api/jobs/{jobId}",
620
+ ...options
621
+ });
612
622
 
613
623
  // src/config/global-config.ts
614
624
  import os from "os";
@@ -1513,10 +1523,10 @@ function mergeDefs(...defs) {
1513
1523
  function cloneDef(schema) {
1514
1524
  return mergeDefs(schema._zod.def);
1515
1525
  }
1516
- function getElementAtPath(obj, path14) {
1517
- if (!path14)
1526
+ function getElementAtPath(obj, path15) {
1527
+ if (!path15)
1518
1528
  return obj;
1519
- return path14.reduce((acc, key) => acc?.[key], obj);
1529
+ return path15.reduce((acc, key) => acc?.[key], obj);
1520
1530
  }
1521
1531
  function promiseAllObject(promisesObj) {
1522
1532
  const keys = Object.keys(promisesObj);
@@ -1899,11 +1909,11 @@ function aborted(x, startIndex = 0) {
1899
1909
  }
1900
1910
  return false;
1901
1911
  }
1902
- function prefixIssues(path14, issues) {
1912
+ function prefixIssues(path15, issues) {
1903
1913
  return issues.map((iss) => {
1904
1914
  var _a2;
1905
1915
  (_a2 = iss).path ?? (_a2.path = []);
1906
- iss.path.unshift(path14);
1916
+ iss.path.unshift(path15);
1907
1917
  return iss;
1908
1918
  });
1909
1919
  }
@@ -2086,7 +2096,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
2086
2096
  }
2087
2097
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
2088
2098
  const result = { errors: [] };
2089
- const processError = (error49, path14 = []) => {
2099
+ const processError = (error49, path15 = []) => {
2090
2100
  var _a2, _b;
2091
2101
  for (const issue2 of error49.issues) {
2092
2102
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -2096,7 +2106,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
2096
2106
  } else if (issue2.code === "invalid_element") {
2097
2107
  processError({ issues: issue2.issues }, issue2.path);
2098
2108
  } else {
2099
- const fullpath = [...path14, ...issue2.path];
2109
+ const fullpath = [...path15, ...issue2.path];
2100
2110
  if (fullpath.length === 0) {
2101
2111
  result.errors.push(mapper(issue2));
2102
2112
  continue;
@@ -2128,8 +2138,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
2128
2138
  }
2129
2139
  function toDotPath(_path) {
2130
2140
  const segs = [];
2131
- const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2132
- for (const seg of path14) {
2141
+ const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2142
+ for (const seg of path15) {
2133
2143
  if (typeof seg === "number")
2134
2144
  segs.push(`[${seg}]`);
2135
2145
  else if (typeof seg === "symbol")
@@ -14106,13 +14116,13 @@ function resolveRef(ref, ctx) {
14106
14116
  if (!ref.startsWith("#")) {
14107
14117
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14108
14118
  }
14109
- const path14 = ref.slice(1).split("/").filter(Boolean);
14110
- if (path14.length === 0) {
14119
+ const path15 = ref.slice(1).split("/").filter(Boolean);
14120
+ if (path15.length === 0) {
14111
14121
  return ctx.rootSchema;
14112
14122
  }
14113
14123
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14114
- if (path14[0] === defsKey) {
14115
- const key = path14[1];
14124
+ if (path15[0] === defsKey) {
14125
+ const key = path15[1];
14116
14126
  if (!key || !ctx.defs[key]) {
14117
14127
  throw new Error(`Reference not found: ${ref}`);
14118
14128
  }
@@ -14543,7 +14553,8 @@ var pullCommandArgsSchema = configFlagsSchema.extend({
14543
14553
  });
14544
14554
  var pushCommandArgsSchema = configFlagsSchema.extend({
14545
14555
  force: external_exports.boolean().default(false),
14546
- debug: external_exports.boolean().default(false)
14556
+ debug: external_exports.boolean().default(false),
14557
+ "skip-local-check": external_exports.boolean().default(false)
14547
14558
  });
14548
14559
  var statusCommandArgsSchema = configFlagsSchema.extend({
14549
14560
  json: external_exports.boolean().default(false)
@@ -14702,6 +14713,61 @@ async function findLatestSuccessfulCompiledResult(gameId) {
14702
14713
  });
14703
14714
  return data ?? null;
14704
14715
  }
14716
+ async function getCompiledResultSdk(gameId, compiledResultId) {
14717
+ const { data, error: error48, response } = await getCompiledResult({
14718
+ path: {
14719
+ gameId,
14720
+ compiledResultId
14721
+ }
14722
+ });
14723
+ if (error48 || !data) {
14724
+ throw new Error(
14725
+ formatApiError(error48, response, "Failed to fetch compiled result")
14726
+ );
14727
+ }
14728
+ return data;
14729
+ }
14730
+ async function waitForCompiledResultJobSdk(options) {
14731
+ const { gameId, jobId, onProgress } = options;
14732
+ let previousTransitionKey = null;
14733
+ for (let attempt = 0; attempt < 180; attempt += 1) {
14734
+ const {
14735
+ data: job,
14736
+ error: error48,
14737
+ response
14738
+ } = await getJob({
14739
+ path: { jobId }
14740
+ });
14741
+ if (error48 || !job) {
14742
+ throw new Error(formatApiError(error48, response, "Failed to get job"));
14743
+ }
14744
+ const transitionKey = `${job.status}:${job.phase ?? ""}`;
14745
+ if (transitionKey !== previousTransitionKey) {
14746
+ previousTransitionKey = transitionKey;
14747
+ onProgress?.(job);
14748
+ }
14749
+ if (job.status === "COMPLETED" || job.status === "FAILED") {
14750
+ const compiledResultId = job.createdCompiledResultId ?? job.createdAppScriptId;
14751
+ if (!compiledResultId) {
14752
+ throw new Error(
14753
+ job.errorMessage ?? `Compile job ${jobId} finished without a result.`
14754
+ );
14755
+ }
14756
+ const compiledResult = await getCompiledResultSdk(
14757
+ gameId,
14758
+ compiledResultId
14759
+ );
14760
+ return { job, compiledResult };
14761
+ }
14762
+ if (job.status === "CANCELLED" || job.status === "INTERRUPTED") {
14763
+ throw new Error(
14764
+ job.errorMessage ?? `Compile job ${jobId} ${job.status.toLowerCase()}.`
14765
+ );
14766
+ }
14767
+ await sleep(1e3);
14768
+ }
14769
+ throw new Error(`Compile job ${jobId} did not complete in time.`);
14770
+ }
14705
14771
 
14706
14772
  // src/services/api/game-api.ts
14707
14773
  async function tryGetGameBySlug(slug, opts) {
@@ -14849,7 +14915,7 @@ async function createCompiledResultSdk(options) {
14849
14915
  });
14850
14916
  if (error48 || !data) {
14851
14917
  throw new Error(
14852
- formatApiError(error48, response, "Failed to create compiled result")
14918
+ formatApiError(error48, response, "Failed to create compile job")
14853
14919
  );
14854
14920
  }
14855
14921
  return data;
@@ -22313,6 +22379,149 @@ var clone_default = defineCommand({
22313
22379
  }
22314
22380
  });
22315
22381
 
22382
+ // src/services/project/local-typecheck.ts
22383
+ import { spawn } from "child_process";
22384
+ import { lstat, mkdir, symlink } from "fs/promises";
22385
+ import path8 from "path";
22386
+ import { fileURLToPath } from "url";
22387
+ var MODULE_DIR = path8.dirname(fileURLToPath(import.meta.url));
22388
+ var REPO_ROOT = path8.resolve(MODULE_DIR, "../../../../..");
22389
+ var WORKSPACE_NODE_MODULES = path8.join(REPO_ROOT, "node_modules");
22390
+ var UI_SDK_NODE_MODULES = path8.join(
22391
+ REPO_ROOT,
22392
+ "packages",
22393
+ "ui-sdk",
22394
+ "node_modules"
22395
+ );
22396
+ var TYPESCRIPT_CLI = path8.join(
22397
+ WORKSPACE_NODE_MODULES,
22398
+ "typescript",
22399
+ "bin",
22400
+ "tsc"
22401
+ );
22402
+ async function pathExists(targetPath) {
22403
+ try {
22404
+ await lstat(targetPath);
22405
+ return true;
22406
+ } catch {
22407
+ return false;
22408
+ }
22409
+ }
22410
+ async function ensureSymlink(targetPath, linkPath) {
22411
+ if (await pathExists(linkPath)) {
22412
+ return;
22413
+ }
22414
+ await mkdir(path8.dirname(linkPath), { recursive: true });
22415
+ await symlink(
22416
+ targetPath,
22417
+ linkPath,
22418
+ process.platform === "win32" ? "junction" : "dir"
22419
+ );
22420
+ }
22421
+ async function ensureTypecheckDependencies(projectRoot) {
22422
+ if (!await pathExists(WORKSPACE_NODE_MODULES)) {
22423
+ return `Skipping local typecheck: workspace dependencies are not installed at ${WORKSPACE_NODE_MODULES}.`;
22424
+ }
22425
+ if (!await pathExists(UI_SDK_NODE_MODULES)) {
22426
+ return `Skipping local typecheck: ui-sdk dependencies are not installed at ${UI_SDK_NODE_MODULES}.`;
22427
+ }
22428
+ await ensureSymlink(
22429
+ WORKSPACE_NODE_MODULES,
22430
+ path8.join(projectRoot, "node_modules")
22431
+ );
22432
+ await ensureSymlink(
22433
+ UI_SDK_NODE_MODULES,
22434
+ path8.join(projectRoot, "ui", "node_modules")
22435
+ );
22436
+ return null;
22437
+ }
22438
+ async function resolveTypecheckRunner() {
22439
+ if (await pathExists(TYPESCRIPT_CLI)) {
22440
+ return {
22441
+ command: process.execPath,
22442
+ argsPrefix: [TYPESCRIPT_CLI]
22443
+ };
22444
+ }
22445
+ const globalTscAvailable = await new Promise((resolve) => {
22446
+ const child = spawn("tsc", ["--version"], {
22447
+ env: process.env,
22448
+ stdio: "ignore"
22449
+ });
22450
+ child.on("error", () => {
22451
+ resolve(false);
22452
+ });
22453
+ child.on("close", (code) => {
22454
+ resolve(code === 0);
22455
+ });
22456
+ });
22457
+ if (!globalTscAvailable) {
22458
+ return null;
22459
+ }
22460
+ return {
22461
+ command: "tsc",
22462
+ argsPrefix: []
22463
+ };
22464
+ }
22465
+ async function runTypecheckProject(runner, projectRoot, projectPath) {
22466
+ return new Promise((resolve, reject) => {
22467
+ const child = spawn(
22468
+ runner.command,
22469
+ [...runner.argsPrefix, "--noEmit", "-p", projectPath],
22470
+ {
22471
+ cwd: projectRoot,
22472
+ env: process.env,
22473
+ stdio: ["ignore", "pipe", "pipe"]
22474
+ }
22475
+ );
22476
+ let stdout = "";
22477
+ let stderr = "";
22478
+ child.stdout.on("data", (chunk) => {
22479
+ stdout += chunk.toString();
22480
+ });
22481
+ child.stderr.on("data", (chunk) => {
22482
+ stderr += chunk.toString();
22483
+ });
22484
+ child.on("error", (error48) => {
22485
+ reject(new Error(`Failed to start local typecheck. ${error48.message}`));
22486
+ });
22487
+ child.on("close", (code) => {
22488
+ const output = [stdout, stderr].filter(Boolean).join("\n").trim();
22489
+ resolve({
22490
+ success: code === 0,
22491
+ output
22492
+ });
22493
+ });
22494
+ });
22495
+ }
22496
+ async function runLocalTypecheck(projectRoot) {
22497
+ const dependencySkipReason = await ensureTypecheckDependencies(projectRoot);
22498
+ if (dependencySkipReason) {
22499
+ return {
22500
+ success: true,
22501
+ skipped: true,
22502
+ output: dependencySkipReason
22503
+ };
22504
+ }
22505
+ const runner = await resolveTypecheckRunner();
22506
+ if (!runner) {
22507
+ return {
22508
+ success: true,
22509
+ skipped: true,
22510
+ output: "Skipping local typecheck: TypeScript CLI was not found in workspace dependencies or on PATH."
22511
+ };
22512
+ }
22513
+ for (const projectPath of ["app/tsconfig.json", "ui/tsconfig.json"]) {
22514
+ const result = await runTypecheckProject(runner, projectRoot, projectPath);
22515
+ if (!result.success) {
22516
+ return result;
22517
+ }
22518
+ }
22519
+ return {
22520
+ success: true,
22521
+ output: ""
22522
+ };
22523
+ }
22524
+
22316
22525
  // src/commands/push.ts
22317
22526
  function isSourcePath(filePath) {
22318
22527
  return filePath !== MANIFEST_FILE && filePath !== RULE_FILE && isAllowedGamePath2(filePath);
@@ -22320,33 +22529,48 @@ function isSourcePath(filePath) {
22320
22529
  function buildSourceChanges(options) {
22321
22530
  const { mode, localFiles, diff } = options;
22322
22531
  if (mode === "replace") {
22323
- return Object.entries(localFiles).filter(([filePath]) => isSourcePath(filePath)).sort(([left], [right]) => left.localeCompare(right)).map(([path14, content]) => ({
22532
+ return Object.entries(localFiles).filter(([filePath]) => isSourcePath(filePath)).sort(([left], [right]) => left.localeCompare(right)).map(([path15, content]) => ({
22324
22533
  kind: "upsert",
22325
- path: path14,
22534
+ path: path15,
22326
22535
  content
22327
22536
  }));
22328
22537
  }
22329
22538
  const changes = [];
22330
22539
  const upsertPaths = [...diff.modified, ...diff.added].filter(isSourcePath).sort((left, right) => left.localeCompare(right));
22331
- for (const path14 of upsertPaths) {
22332
- const content = localFiles[path14];
22540
+ for (const path15 of upsertPaths) {
22541
+ const content = localFiles[path15];
22333
22542
  if (content === void 0) {
22334
22543
  continue;
22335
22544
  }
22336
22545
  changes.push({
22337
22546
  kind: "upsert",
22338
- path: path14,
22547
+ path: path15,
22339
22548
  content
22340
22549
  });
22341
22550
  }
22342
- for (const path14 of diff.deleted.filter(isSourcePath).sort()) {
22551
+ for (const path15 of diff.deleted.filter(isSourcePath).sort()) {
22343
22552
  changes.push({
22344
22553
  kind: "delete",
22345
- path: path14
22554
+ path: path15
22346
22555
  });
22347
22556
  }
22348
22557
  return changes;
22349
22558
  }
22559
+ function formatCompileJobProgressMessage(job) {
22560
+ const phase = job.phase ? ` [${job.phase}]` : "";
22561
+ const detail = job.message ? ` ${job.message}` : "";
22562
+ if (job.status === "PENDING") {
22563
+ const queue = typeof job.queuePosition === "number" ? ` (queue ${job.queuePosition + 1})` : "";
22564
+ return `Compile queued${queue}${phase}${detail}`.trim();
22565
+ }
22566
+ if (job.status === "RUNNING") {
22567
+ return `Compile running${phase}${detail}`.trim();
22568
+ }
22569
+ if (job.status === "FAILED") {
22570
+ return `Compile failed${phase}${detail}`.trim();
22571
+ }
22572
+ return `Compile ${job.status.toLowerCase()}${phase}${detail}`.trim();
22573
+ }
22350
22574
  var push_default = defineCommand({
22351
22575
  meta: {
22352
22576
  name: "push",
@@ -22363,6 +22587,11 @@ var push_default = defineCommand({
22363
22587
  description: "Print debug details including source revision payloads",
22364
22588
  default: false
22365
22589
  },
22590
+ "skip-local-check": {
22591
+ type: "boolean",
22592
+ description: "Skip the best-effort local typecheck before remote mutations",
22593
+ default: false
22594
+ },
22366
22595
  ...CONFIG_FLAG_ARGS
22367
22596
  },
22368
22597
  async run({ args }) {
@@ -22406,6 +22635,24 @@ var push_default = defineCommand({
22406
22635
  `Remote drift detected. Local base=${knownBaseResultId}, remote latest=${latest.id}. Run 'dreamboard update --pull' to reconcile before pushing.`
22407
22636
  );
22408
22637
  }
22638
+ if (!parsedArgs["skip-local-check"]) {
22639
+ consola.start("Running local typecheck...");
22640
+ const typecheckResult = await runLocalTypecheck(projectRoot);
22641
+ if (typecheckResult.skipped) {
22642
+ if (typecheckResult.output) {
22643
+ consola.warn(typecheckResult.output);
22644
+ }
22645
+ } else if (!typecheckResult.success) {
22646
+ if (typecheckResult.output) {
22647
+ consola.error(typecheckResult.output);
22648
+ }
22649
+ throw new Error(
22650
+ "Local typecheck failed. Fix the diagnostics or re-run with --skip-local-check."
22651
+ );
22652
+ } else {
22653
+ consola.success("Local typecheck passed.");
22654
+ }
22655
+ }
22409
22656
  const ruleChanged = diff.modified.includes(RULE_FILE) || diff.added.includes(RULE_FILE);
22410
22657
  const manifestChanged = diff.modified.includes(MANIFEST_FILE) || diff.added.includes(MANIFEST_FILE);
22411
22658
  let manifestId = currentProjectConfig.manifestId;
@@ -22494,12 +22741,22 @@ ${sourceChanges.map((change) => ` - ${change.kind} ${change.path}`).join("\n")}
22494
22741
  if (shouldCheckpointPrecompileState) {
22495
22742
  await persistProjectProgress();
22496
22743
  }
22497
- const compiledResult = await createCompiledResultSdk({
22744
+ const compileJob = await createCompiledResultSdk({
22498
22745
  gameId: currentProjectConfig.gameId,
22499
22746
  sourceRevisionId,
22500
22747
  manifestId,
22501
22748
  ruleId
22502
22749
  });
22750
+ if (debug) {
22751
+ consola.info(`[push --debug] compile job=${compileJob.jobId}`);
22752
+ }
22753
+ const { compiledResult } = await waitForCompiledResultJobSdk({
22754
+ gameId: currentProjectConfig.gameId,
22755
+ jobId: compileJob.jobId,
22756
+ onProgress: (job) => {
22757
+ consola.info(formatCompileJobProgressMessage(job));
22758
+ }
22759
+ });
22503
22760
  await persistProjectProgress({
22504
22761
  resultId: compiledResult.id,
22505
22762
  sourceRevisionId: compiledResult.sourceRevisionId
@@ -22637,7 +22894,7 @@ var status_default = defineCommand({
22637
22894
  });
22638
22895
 
22639
22896
  // src/commands/update.ts
22640
- import path8 from "path";
22897
+ import path9 from "path";
22641
22898
 
22642
22899
  // src/utils/prompts.ts
22643
22900
  import { createInterface } from "readline/promises";
@@ -22805,14 +23062,14 @@ function findStalePhaseFiles(localFiles, expectedPhasePaths) {
22805
23062
  async function mergeUiArgsFileIfNeeded(projectRoot, files) {
22806
23063
  const incomingUiArgs = files[UI_ARGS_PATH];
22807
23064
  if (incomingUiArgs === null || incomingUiArgs === void 0) return;
22808
- const localPath = path8.join(projectRoot, UI_ARGS_PATH);
23065
+ const localPath = path9.join(projectRoot, UI_ARGS_PATH);
22809
23066
  const localUiArgs = await readTextFileIfExists(localPath);
22810
23067
  if (localUiArgs === null) return;
22811
23068
  if (localUiArgs.trim().length === 0) return;
22812
23069
  if (localUiArgs === incomingUiArgs) return;
22813
23070
  const mergeResult = mergeUiArgsContent(localUiArgs, incomingUiArgs);
22814
23071
  files[UI_ARGS_PATH] = mergeResult.content;
22815
- await ensureDir(path8.dirname(localPath));
23072
+ await ensureDir(path9.dirname(localPath));
22816
23073
  await writeTextFile(localPath, mergeResult.content);
22817
23074
  if (mergeResult.conflicted) {
22818
23075
  throw new Error(
@@ -23104,7 +23361,7 @@ var update_default = defineCommand({
23104
23361
  });
23105
23362
 
23106
23363
  // src/commands/run.ts
23107
- import path10 from "path";
23364
+ import path11 from "path";
23108
23365
  import { appendFile } from "fs/promises";
23109
23366
 
23110
23367
  // src/services/workflows/resolve-run-result.ts
@@ -23132,7 +23389,7 @@ async function resolveCompiledResultForRun(projectRoot, projectConfig) {
23132
23389
  }
23133
23390
 
23134
23391
  // src/ui/playwright-runner.ts
23135
- import path9 from "path";
23392
+ import path10 from "path";
23136
23393
  async function runUiSteps(page, steps, outputDir, turnTracker) {
23137
23394
  let stepIndex = 0;
23138
23395
  for (const step of steps) {
@@ -23168,7 +23425,7 @@ async function runUiSteps(page, steps, outputDir, turnTracker) {
23168
23425
  const turns = typeof step.turns === "number" ? step.turns : 1;
23169
23426
  await turnTracker.waitForTurns(Math.max(0, Math.floor(turns)));
23170
23427
  await page.screenshot({
23171
- path: path9.join(outputDir, `step-${stepIndex}.png`)
23428
+ path: path10.join(outputDir, `step-${stepIndex}.png`)
23172
23429
  });
23173
23430
  stepIndex++;
23174
23431
  }
@@ -23398,12 +23655,12 @@ var run_default = defineCommand({
23398
23655
  webBaseUrl: config2.webBaseUrl,
23399
23656
  parsedArgs
23400
23657
  });
23401
- const runDir = path10.join(projectRoot, PROJECT_DIR_NAME, "run");
23658
+ const runDir = path11.join(projectRoot, PROJECT_DIR_NAME, "run");
23402
23659
  await ensureDir(runDir);
23403
- const sessionFilePath = path10.join(runDir, "session.json");
23404
- const eventsFilePath = path10.join(runDir, "events.ndjson");
23405
- const yourTurnFilePath = path10.join(runDir, "latest-your-turn.json");
23406
- const summaryFilePath = path10.join(runDir, "last-run-summary.json");
23660
+ const sessionFilePath = path11.join(runDir, "session.json");
23661
+ const eventsFilePath = path11.join(runDir, "events.ndjson");
23662
+ const yourTurnFilePath = path11.join(runDir, "latest-your-turn.json");
23663
+ const summaryFilePath = path11.join(runDir, "last-run-summary.json");
23407
23664
  const shouldResume = !runtime.isEmbeddedHarness && parsedArgs.resume && !parsedArgs["new-session"];
23408
23665
  const until = parsedArgs.until;
23409
23666
  const observeEvents = parsedArgs["observe-events"];
@@ -23510,7 +23767,7 @@ var run_default = defineCommand({
23510
23767
  "UI scenario execution requires Playwright page context, but browser was not initialized."
23511
23768
  );
23512
23769
  }
23513
- const outputDir = path10.join(
23770
+ const outputDir = path11.join(
23514
23771
  projectRoot,
23515
23772
  PROJECT_DIR_NAME,
23516
23773
  "screenshots"
@@ -23593,13 +23850,13 @@ var run_default = defineCommand({
23593
23850
  "Screenshot capture requires Playwright page context, but browser was not initialized."
23594
23851
  );
23595
23852
  }
23596
- const outputDir = path10.join(
23853
+ const outputDir = path11.join(
23597
23854
  projectRoot,
23598
23855
  PROJECT_DIR_NAME,
23599
23856
  "screenshots"
23600
23857
  );
23601
23858
  await ensureDir(outputDir);
23602
- const screenshotPath = parsedArgs.output ?? path10.join(outputDir, `run-${Date.now()}.png`);
23859
+ const screenshotPath = parsedArgs.output ?? path11.join(outputDir, `run-${Date.now()}.png`);
23603
23860
  if (screenshotDelayMs && screenshotDelayMs > 0) {
23604
23861
  await sleep(screenshotDelayMs);
23605
23862
  }
@@ -24501,13 +24758,13 @@ function extractGameStatePhase(event) {
24501
24758
  }
24502
24759
 
24503
24760
  // src/commands/start.ts
24504
- import path11 from "path";
24761
+ import path12 from "path";
24505
24762
 
24506
24763
  // src/auth/auth-server.ts
24507
24764
  import {
24508
24765
  createServer
24509
24766
  } from "http";
24510
- import { spawn } from "child_process";
24767
+ import { spawn as spawn2 } from "child_process";
24511
24768
  async function startCliAuthServer(state, timeoutMs) {
24512
24769
  let resolveToken;
24513
24770
  let rejectToken;
@@ -24622,7 +24879,7 @@ function openBrowser(url2) {
24622
24879
  } else {
24623
24880
  command = ["xdg-open", url2];
24624
24881
  }
24625
- const child = spawn(command[0], command.slice(1), {
24882
+ const child = spawn2(command[0], command.slice(1), {
24626
24883
  stdio: "ignore",
24627
24884
  detached: true
24628
24885
  });
@@ -24691,8 +24948,8 @@ var start_default = defineCommand({
24691
24948
  formatApiError(startError, startResponse, "Failed to start game")
24692
24949
  );
24693
24950
  }
24694
- const runDir = path11.join(projectRoot, PROJECT_DIR_NAME, "run");
24695
- const sessionFilePath = path11.join(runDir, "session.json");
24951
+ const runDir = path12.join(projectRoot, PROJECT_DIR_NAME, "run");
24952
+ const sessionFilePath = path12.join(runDir, "session.json");
24696
24953
  await ensureDir(runDir);
24697
24954
  const persistedSession = createPersistedRunSession({
24698
24955
  sessionId: session.sessionId,
@@ -25061,7 +25318,7 @@ var config_default = defineCommand({
25061
25318
  });
25062
25319
 
25063
25320
  // src/commands/test.ts
25064
- import path13 from "path";
25321
+ import path14 from "path";
25065
25322
  import { readdir as readdir2, unlink as unlink3 } from "fs/promises";
25066
25323
  import { isDeepStrictEqual } from "util";
25067
25324
 
@@ -25076,7 +25333,7 @@ function shouldUseRemoteTestRuntime(environment) {
25076
25333
  // src/utils/ts-module-loader.ts
25077
25334
  import { mkdtemp, rm } from "fs/promises";
25078
25335
  import { tmpdir } from "os";
25079
- import path12 from "path";
25336
+ import path13 from "path";
25080
25337
  import { pathToFileURL } from "url";
25081
25338
  import { build } from "esbuild";
25082
25339
  var ESBUILD_EXTERNALS = [
@@ -25086,10 +25343,10 @@ var ESBUILD_EXTERNALS = [
25086
25343
  "electron"
25087
25344
  ];
25088
25345
  async function importTypeScriptModule(entryPath) {
25089
- const tempDir = await mkdtemp(path12.join(tmpdir(), "dreamboard-ts-module-"));
25090
- const outfile = path12.join(
25346
+ const tempDir = await mkdtemp(path13.join(tmpdir(), "dreamboard-ts-module-"));
25347
+ const outfile = path13.join(
25091
25348
  tempDir,
25092
- `${path12.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
25349
+ `${path13.basename(entryPath).replace(/\.[^.]+$/u, "")}.mjs`
25093
25350
  );
25094
25351
  try {
25095
25352
  await build({
@@ -25215,7 +25472,7 @@ var generateCommand = defineCommand({
25215
25472
  }
25216
25473
  };
25217
25474
  }
25218
- const generatedDir = path13.join(projectRoot, "test", "generated");
25475
+ const generatedDir = path14.join(projectRoot, "test", "generated");
25219
25476
  await ensureDir(generatedDir);
25220
25477
  await writeGeneratedFiles({
25221
25478
  generatedDir,
@@ -25415,7 +25672,7 @@ async function runSingleScenario(options) {
25415
25672
  });
25416
25673
  }
25417
25674
  async function loadGeneratedBaseStates(projectRoot) {
25418
- const filePath = path13.join(
25675
+ const filePath = path14.join(
25419
25676
  projectRoot,
25420
25677
  "test",
25421
25678
  "generated",
@@ -25434,7 +25691,7 @@ async function loadGeneratedBaseStates(projectRoot) {
25434
25691
  return baseStates;
25435
25692
  }
25436
25693
  async function loadScenarios(projectRoot, options) {
25437
- const scenarioFiles = options.scenarioPath ? [path13.resolve(projectRoot, options.scenarioPath)] : await discoverScenarioFiles(path13.join(projectRoot, "test", "scenarios"));
25694
+ const scenarioFiles = options.scenarioPath ? [path14.resolve(projectRoot, options.scenarioPath)] : await discoverScenarioFiles(path14.join(projectRoot, "test", "scenarios"));
25438
25695
  const loaded = [];
25439
25696
  for (const scenarioFile of scenarioFiles) {
25440
25697
  const module = await importTypeScriptModule(scenarioFile);
@@ -25463,7 +25720,7 @@ async function discoverScenarioFiles(root) {
25463
25720
  const entries = await readdir2(root, { withFileTypes: true });
25464
25721
  const files = [];
25465
25722
  for (const entry of entries) {
25466
- const entryPath = path13.join(root, entry.name);
25723
+ const entryPath = path14.join(root, entry.name);
25467
25724
  if (entry.isDirectory()) {
25468
25725
  files.push(...await discoverScenarioFiles(entryPath));
25469
25726
  continue;
@@ -25549,8 +25806,8 @@ async function writeGeneratedFiles(options) {
25549
25806
  `;
25550
25807
  const manifest = options.scenarios.map((scenario) => ({
25551
25808
  id: scenario.scenario.meta.id,
25552
- filePath: path13.relative(
25553
- path13.dirname(options.generatedDir),
25809
+ filePath: path14.relative(
25810
+ path14.dirname(options.generatedDir),
25554
25811
  scenario.filePath
25555
25812
  ),
25556
25813
  base: scenario.scenario.given.base
@@ -25558,19 +25815,19 @@ async function writeGeneratedFiles(options) {
25558
25815
  const scenarioManifestContent = `${generatedHeader}export const SCENARIO_MANIFEST = ${JSON.stringify(manifest, null, 2)} as const;
25559
25816
  `;
25560
25817
  await writeTextFile(
25561
- path13.join(options.generatedDir, "base-states.generated.ts"),
25818
+ path14.join(options.generatedDir, "base-states.generated.ts"),
25562
25819
  baseStatesContent
25563
25820
  );
25564
25821
  await writeTextFile(
25565
- path13.join(options.generatedDir, "base-states.generated.d.ts"),
25822
+ path14.join(options.generatedDir, "base-states.generated.d.ts"),
25566
25823
  baseStatesDtsContent
25567
25824
  );
25568
25825
  await writeTextFile(
25569
- path13.join(options.generatedDir, "scenario-manifest.generated.ts"),
25826
+ path14.join(options.generatedDir, "scenario-manifest.generated.ts"),
25570
25827
  scenarioManifestContent
25571
25828
  );
25572
25829
  await writeJsonFile(
25573
- path13.join(options.generatedDir, ".generation-meta.json"),
25830
+ path14.join(options.generatedDir, ".generation-meta.json"),
25574
25831
  {
25575
25832
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
25576
25833
  scenarioCount: options.scenarios.length,
@@ -25579,7 +25836,7 @@ async function writeGeneratedFiles(options) {
25579
25836
  );
25580
25837
  }
25581
25838
  async function ensureScenarioImportShim(projectRoot) {
25582
- const testingTypesRuntimePath = path13.join(
25839
+ const testingTypesRuntimePath = path14.join(
25583
25840
  projectRoot,
25584
25841
  "test",
25585
25842
  "testing-types.ts"
@@ -25588,11 +25845,11 @@ async function ensureScenarioImportShim(projectRoot) {
25588
25845
  testingTypesRuntimePath
25589
25846
  );
25590
25847
  if (shouldRefreshGeneratedTestingTypes2(existingTestingTypes)) {
25591
- await ensureDir(path13.dirname(testingTypesRuntimePath));
25848
+ await ensureDir(path14.dirname(testingTypesRuntimePath));
25592
25849
  await writeTextFile(testingTypesRuntimePath, TESTING_TYPES_CONTENT);
25593
25850
  }
25594
25851
  await migrateLegacyScenarioImports(projectRoot);
25595
- const staleDtsPath = path13.join(projectRoot, "test", "testing-types.d.ts");
25852
+ const staleDtsPath = path14.join(projectRoot, "test", "testing-types.d.ts");
25596
25853
  if (await exists(staleDtsPath)) {
25597
25854
  await unlink3(staleDtsPath);
25598
25855
  }
@@ -25837,7 +26094,7 @@ function validateFingerprint(options) {
25837
26094
  }
25838
26095
  }
25839
26096
  async function loadBaseScenarioDefinitions(projectRoot) {
25840
- const filePath = path13.join(projectRoot, "test", "base-scenarios.json");
26097
+ const filePath = path14.join(projectRoot, "test", "base-scenarios.json");
25841
26098
  if (!await exists(filePath)) {
25842
26099
  throw new Error(
25843
26100
  "Missing test/base-scenarios.json. Define base checkpoints there, including 'initial-turn'."
@@ -25871,7 +26128,7 @@ async function loadBaseScenarioDefinitions(projectRoot) {
25871
26128
  function validateScenarioBases(scenarios, baseScenarios) {
25872
26129
  const available = new Set(Object.keys(baseScenarios));
25873
26130
  const invalid = scenarios.filter((scenario) => !available.has(scenario.scenario.given.base)).map(
25874
- (scenario) => path13.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.scenario.given.base}'`
26131
+ (scenario) => path14.relative(process.cwd(), scenario.filePath) + ` -> '${scenario.scenario.given.base}'`
25875
26132
  );
25876
26133
  if (invalid.length === 0) {
25877
26134
  return;
@@ -25956,7 +26213,7 @@ var subCommands = {
25956
26213
  var main = defineCommand({
25957
26214
  meta: {
25958
26215
  name: "dreamboard",
25959
- version: "0.1.4",
26216
+ version: "0.1.6",
25960
26217
  description: "Dreamboard CLI \u2014 game development platform"
25961
26218
  },
25962
26219
  subCommands