#!/usr/bin/env node
import {
  REDUCER_TESTING_TYPES_WRAPPER_CONTENT
} from "./chunk-F2DIOJJZ.mjs";
import {
  IS_PUBLISHED_BUILD,
  loadProjectConfig
} from "./chunk-776W3UGV.mjs";
import {
  isDynamicSeedPath,
  materializeManifest
} from "./chunk-C3VW3DTA.mjs";
import {
  resolveCliRepoRoot
} from "./chunk-QBAF7EYR.mjs";
import {
  ensureDir,
  exists,
  readJsonFile,
  readTextFile,
  readTextFileIfExists,
  writeTextFile
} from "./chunk-IAYRNVUC.mjs";
import {
  FRAMEWORK_PNPM_OVERRIDES,
  FRAMEWORK_REACT_DEPENDENCIES,
  FRAMEWORK_ZOD_VERSION
} from "./chunk-ZEELHSY3.mjs";
import {
  MANIFEST_TYPECHECK_CONFIG_FILE,
  PROJECT_CONFIG_FILE,
  PROJECT_DIR_NAME
} from "./chunk-H76MT5UR.mjs";

// src/services/project/static-scaffold.ts
import { existsSync, readFileSync } from "fs";
import { readdir, readFile, rm, rmdir, unlink } from "fs/promises";
import path from "path";
import { fileURLToPath } from "url";
var DREAMBOARD_SYNC_COMMAND = "dreamboard sync";
var DREAMBOARD_GITIGNORE_BLOCK = [
  "# Dreamboard local state",
  ".dreamboard/state.json",
  ".dreamboard/snapshot.json",
  ".dreamboard/dev/",
  ".dreamboard/generated/",
  ""
].join("\n");
var TESTING_TYPES_STUB = "export function defineScenario(scenario) { return scenario; }\n";
var GENERATED_TESTING_TYPES_PREFIX = "// Generated by dreamboard";
var GENERATED_SCENARIO_PREFIX = "// Generated by dreamboard scaffold.";
var LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = `export {
  ErrorBoundary,
  type ErrorBoundaryProps,
} from "@dreamboard-games/sdk/ui";
export { PluginRuntime, type PluginRuntimeProps } from "@dreamboard-games/sdk/runtime";
`;
var OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = [
  "export {",
  "  ErrorBoundary,",
  "  PluginRuntime,",
  "  type ErrorBoundaryProps,",
  "  type PluginRuntimeProps,",
  `} from "@dreamboard/ui-${"sdk"}";`,
  ""
].join("\n");
var OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT = [
  "export {",
  "  ErrorBoundary,",
  "  PluginRuntime,",
  "  type ErrorBoundaryProps,",
  "  type PluginRuntimeProps,",
  `} from "@dreamboard-games/ui-${"sdk"}";`,
  ""
].join("\n");
var INITIAL_SCENARIO_CONTENT = `${GENERATED_SCENARIO_PREFIX}
import { defineScenario } from "../testing-types";

export default defineScenario({
  id: "smoke-initial-turn",
  description:
    "Sanity check that the scaffolded workspace boots into its initial phase.",
  from: "initial-turn",
  when: async () => undefined,
  then: ({ expect, interactions, players, state }) => {
    const playerIds = players();
    expect(playerIds).toHaveLength(playerIds.length);
    expect(playerIds.length).toBeGreaterThanOrEqual(1);
    expect(state()).toBe("setup");
    for (const playerId of playerIds) {
      expect(interactions(playerId)).toEqual([]);
    }
  },
});
`;
var STATIC_ASSET_ROOT = resolveStaticAssetRoot();
var SDK_PACKAGE_PATHS = {
  "@dreamboard-games/sdk": ["packages", "sdk", "package.json"]
};
var DEFAULT_SDK_DEPENDENCY_RANGES = {
  "@dreamboard-games/sdk": "0.4.0-alpha.0"
};
var SDK_DEPENDENCY_RANGES = {
  "@dreamboard-games/sdk": resolveSdkDependencyRange("@dreamboard-games/sdk")
};
var FRAMEWORK_SCRIPTS = {
  dev: "dreamboard dev",
  "test:ui": "tsx --tsconfig test/tsconfig.tsx-runtime.json --test test/ui/**/*.test.tsx",
  typecheck: `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE} && tsc --noEmit -p app/tsconfig.json && tsc --noEmit -p ui/tsconfig.json`,
  "typecheck:manifest": `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE}`,
  "typecheck:app": "tsc --noEmit -p app/tsconfig.json",
  "typecheck:ui": "tsc --noEmit -p ui/tsconfig.json"
};
var SHARED_DEPENDENCIES = {
  ...FRAMEWORK_REACT_DEPENDENCIES
};
var ROOT_APP_DEPENDENCIES = {
  zod: FRAMEWORK_ZOD_VERSION
};
var SHARED_DEV_DEPENDENCIES = {
  typescript: "^5.9.2",
  "@types/node": "^24.5.2",
  "@types/react": "^19.0.0",
  "@types/react-dom": "^19.0.0",
  csstype: "^3.1.3",
  tsx: "^4.20.5"
};
async function scaffoldStaticWorkspace(projectRoot, mode, options = {}) {
  await writeFrameworkStaticFiles(projectRoot, mode, options);
  await ensureDreamboardGitignore(projectRoot);
  await writeManifestTypecheckTsconfig(
    path.join(projectRoot, MANIFEST_TYPECHECK_CONFIG_FILE)
  );
  await removeLegacyVendoredSdkPaths(projectRoot);
  await removeLegacyDreamboardComponentPath(projectRoot);
  const testDir = path.join(projectRoot, "test");
  const basesDir = path.join(testDir, "bases");
  const scenariosDir = path.join(testDir, "scenarios");
  const generatedDir = path.join(testDir, "generated");
  await ensureDir(basesDir);
  await ensureDir(scenariosDir);
  await ensureDir(generatedDir);
  await writeTestReadme(path.join(testDir, "README.md"));
  await writeGeneratedTestingStubs(generatedDir, mode);
  const initialTestPlayerCount = await inferInitialTestPlayerCount(projectRoot);
  await writeInitialBase(
    path.join(basesDir, "initial-turn.base.ts"),
    mode,
    initialTestPlayerCount
  );
  await writeInitialScenario(
    path.join(scenariosDir, "smoke-initial-turn.scenario.ts"),
    mode
  );
  await writeTestingTypes(path.join(testDir, "testing-types.ts"), mode);
  await writeTestTsconfig(path.join(testDir, "tsconfig.json"));
  const staleDtsPath = path.join(testDir, "testing-types.d.ts");
  if (await exists(staleDtsPath)) {
    await unlink(staleDtsPath);
  }
  const staleBaseScenariosPath = path.join(testDir, "base-scenarios.json");
  if (await exists(staleBaseScenariosPath)) {
    await unlink(staleBaseScenariosPath);
  }
  await migrateLegacyScenarioImports(projectRoot);
}
async function ensureDreamboardGitignore(projectRoot) {
  const gitignorePath = path.join(projectRoot, ".gitignore");
  const existing = await readTextFileIfExists(gitignorePath);
  if (existing?.includes(".dreamboard/state.json")) {
    return;
  }
  await writeTextFile(
    gitignorePath,
    `${existing ? `${existing.trimEnd()}

` : ""}${DREAMBOARD_GITIGNORE_BLOCK}`
  );
}
async function assertCliStaticScaffoldComplete(projectRoot, deletedPaths = []) {
  const expectedEntries = await getExpectedStaticEntries(projectRoot);
  const missingOrBlankPaths = [];
  for (const entry of expectedEntries) {
    const fullPath = path.join(projectRoot, entry.targetPath);
    const content = await readTextFileIfExists(fullPath);
    if (content === null || content.trim().length === 0) {
      missingOrBlankPaths.push(entry.targetPath);
    }
  }
  const staticPaths = new Set(expectedEntries.map((entry) => entry.targetPath));
  const deletedStaticPaths = deletedPaths.map(normalizeProjectPath).filter((filePath) => staticPaths.has(filePath)).sort();
  if (missingOrBlankPaths.length === 0 && deletedStaticPaths.length === 0) {
    return;
  }
  const problems = [];
  if (missingOrBlankPaths.length > 0) {
    problems.push(
      `missing or blank: ${summarizePaths(missingOrBlankPaths.sort())}`
    );
  }
  if (deletedStaticPaths.length > 0) {
    problems.push(`deleted: ${summarizePaths(deletedStaticPaths)}`);
  }
  throw new Error(
    `CLI static scaffold is incomplete (${problems.join("; ")}). Run \`${DREAMBOARD_SYNC_COMMAND}\` to refresh the scaffold before compiling.`
  );
}
async function writeFrameworkStaticFiles(projectRoot, mode, options) {
  const assetEntries = await getStaticAssetEntries();
  for (const entry of assetEntries) {
    const fullPath = path.join(projectRoot, entry.targetPath);
    if (mode === "update" && isDynamicSeedPath(entry.targetPath)) {
      const existing = await readTextFileIfExists(fullPath);
      if (existing !== null && existing.trim().length > 0) {
        continue;
      }
    }
    await writeTextFile(fullPath, entry.content);
  }
  for (const entry of await getDynamicStaticEntries(
    projectRoot,
    mode,
    options
  )) {
    await writeTextFile(
      path.join(projectRoot, entry.targetPath),
      entry.content
    );
  }
  if (!options.localMaintainerRegistry) {
    await rm(path.join(projectRoot, ".npmrc"), { force: true });
  }
}
async function removeLegacyVendoredSdkPaths(projectRoot) {
  await rm(path.join(projectRoot, "app", "sdk"), {
    recursive: true,
    force: true
  });
  await rm(path.join(projectRoot, "ui", "sdk"), {
    recursive: true,
    force: true
  });
}
async function removeLegacyDreamboardComponentPath(projectRoot) {
  const legacyDirPath = path.join(
    projectRoot,
    "ui",
    "components",
    "dreamboard"
  );
  const legacyIndexPath = path.join(legacyDirPath, "index.ts");
  const existing = await readTextFileIfExists(legacyIndexPath);
  const removableLegacyContents = /* @__PURE__ */ new Set([
    LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),
    OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),
    OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim()
  ]);
  if (existing === null || !removableLegacyContents.has(existing.trim())) {
    return;
  }
  await unlink(legacyIndexPath);
  const remainingEntries = await readdir(legacyDirPath).catch(() => []);
  if (remainingEntries.length === 0) {
    await rmdir(legacyDirPath);
  }
}
async function writeTestReadme(filePath) {
  await writeTextFile(
    filePath,
    "# Dreamboard Test Workspace\n\nTypeScript bases live in `test/bases/*.base.ts` and scenarios live in `test/scenarios/*.scenario.ts`.\n\n1. Define reusable seeded bases with `defineBase({ id, seed, players, setupProfileId?, setup })`.\n2. Define scenarios with `defineScenario({ id, from, when, then })`.\n3. Scenario assertions can read `players()`, `state()`, `view(playerId)`, and `interactions(playerId)`.\n4. Generate deterministic base snapshots: `dreamboard test generate`.\n5. Run tests: `dreamboard test run`.\n\nImport test helpers from `../testing-types`.\n\nGenerated artifacts are written to `test/generated/*` and should not be edited manually.\n"
  );
}
async function writeInitialBase(filePath, mode, players) {
  if (mode === "update") {
    return;
  }
  await writeTextFile(
    filePath,
    `import { defineBase } from "../testing-types";

export default defineBase({
  id: "initial-turn",
  seed: 1337,
  players: ${players},
  setup: async () => undefined,
});
`
  );
}
async function writeInitialScenario(filePath, mode) {
  if (mode === "new") {
    await writeTextFile(filePath, INITIAL_SCENARIO_CONTENT);
    return;
  }
  const existing = await readTextFileIfExists(filePath);
  if (existing === null || existing.trim().length === 0 || existing === INITIAL_SCENARIO_CONTENT) {
    await writeTextFile(filePath, INITIAL_SCENARIO_CONTENT);
  }
}
async function writeTestingTypes(filePath, mode) {
  if (mode === "new") {
    await writeTextFile(filePath, REDUCER_TESTING_TYPES_WRAPPER_CONTENT);
    return;
  }
  const existing = await readTextFileIfExists(filePath);
  if (shouldRefreshGeneratedTestingTypes(existing)) {
    await writeTextFile(filePath, REDUCER_TESTING_TYPES_WRAPPER_CONTENT);
  }
}
async function writeGeneratedTestingStubs(generatedDir, mode) {
  const header = "// Generated by dreamboard scaffold. Do not edit by hand.\n";
  await writeGeneratedTestingStubFile(
    path.join(generatedDir, "base-states.generated.ts"),
    `${header}export const BASE_STATES = {} as const;
export const BASE_STATES_CONTRACT_FINGERPRINT = undefined;
`,
    mode
  );
  await writeGeneratedTestingStubFile(
    path.join(generatedDir, "base-states.generated.d.ts"),
    `${header}export declare const BASE_STATES: Record<string, unknown>;
export declare const BASE_STATES_CONTRACT_FINGERPRINT: string | undefined;
`,
    mode
  );
  await writeGeneratedTestingStubFile(
    path.join(generatedDir, "testing-contract.ts"),
    `${header}export type BaseId = string;
export type GameView = unknown;
export type InteractionId = string;
export type InteractionParamsOf<_Id extends string> = Record<string, unknown>;
export type PhaseName = string;
export type PlayerId = string;
export type RejectionCode = string;
export type StateName = string;
export type TestRunner = "reducer" | "remote" | "browser";
export type ViewByPhase = Record<string, GameView>;
export type WorkspaceStageName<_Phase extends string = string> = string;
export type Expectation = { [matcher: string]: (...args: unknown[]) => unknown; not: Expectation };
export type ExpectFn = (actual: unknown) => Expectation;
export type InteractionExplanation = { interactionId: string; phase: string; step: string | null; availability: "available" | "notYourTurn" | "wrongPhase" | "wrongStep" | "blocked"; rules: readonly { ruleId: string; outcome: "passed" | "failed" | "notEvaluated"; errorCode?: string; message?: string; }[]; actor: { required: readonly string[]; playerIsActor: boolean }; inputs: readonly { key: string; kind: string; eligibleCount: number | "lazy"; }[]; };
export interface InteractionDescriptorFor<Id extends string = string> { interactionId: Id; [key: string]: unknown; }
export interface ScenarioGameApi { start(): Promise<void>; submit<Id extends InteractionId>(playerId: PlayerId, interactionId: Id, params?: InteractionParamsOf<Id>): Promise<void>; }
export interface BaseContext { game: ScenarioGameApi; players(): readonly PlayerId[]; seat(index: number): PlayerId; }
export interface SharedScenarioContext { game: ScenarioGameApi; players(): readonly PlayerId[]; seat(index: number): PlayerId; state(): StateName; view(playerId: PlayerId): GameView; interactions(playerId: PlayerId): readonly InteractionDescriptorFor[]; explain(playerId: PlayerId, interactionId: InteractionId): InteractionExplanation; expect: ExpectFn; }
export type ScenarioContext<Phase extends PhaseName | undefined = undefined> = Omit<SharedScenarioContext, "state" | "view"> & { state(): Phase extends PhaseName ? Phase : StateName; view(playerId: PlayerId): Phase extends PhaseName ? ViewByPhase[Phase] : GameView; };
export type ScenarioThenContext<_Runners extends readonly TestRunner[] = readonly ["reducer"], Phase extends PhaseName | undefined = undefined> = ScenarioContext<Phase>;
export interface BaseDefinition { id: string; seed?: number; players?: number; setupProfileId?: string; extends?: BaseId | string; setup: (ctx: BaseContext) => void | Promise<void>; }
export interface ScenarioDefinition<Runners extends readonly TestRunner[] = readonly ["reducer"], Phase extends PhaseName | undefined = undefined> { id: string; description?: string; from: BaseId | string; runners?: Runners; phase?: Phase; stage?: Phase extends PhaseName ? WorkspaceStageName<Phase> : never; when: (ctx: ScenarioContext<Phase>) => void | Promise<void>; then: (ctx: ScenarioThenContext<Runners, Phase>) => void | Promise<void>; }
`,
    mode
  );
  await writeGeneratedTestingStubFile(
    path.join(generatedDir, "scenario-manifest.generated.ts"),
    `${header}export const SCENARIO_MANIFEST = [] as const;
`,
    mode
  );
}
async function writeGeneratedTestingStubFile(filePath, content, mode) {
  if (mode === "new") {
    await writeTextFile(filePath, content);
    return;
  }
  const existing = await readTextFileIfExists(filePath);
  if (existing === null || existing.trim().length === 0 || existing.startsWith(GENERATED_SCENARIO_PREFIX)) {
    await writeTextFile(filePath, content);
  }
}
async function writeTestTsconfig(filePath) {
  await writeTextFile(
    filePath,
    `${JSON.stringify(
      {
        compilerOptions: {
          target: "ES2022",
          module: "ESNext",
          moduleResolution: "bundler",
          strict: true,
          esModuleInterop: true,
          skipLibCheck: true,
          noEmit: true
        },
        include: [
          "./**/*.ts",
          "./**/*.d.ts",
          "../shared/**/*.ts",
          "../shared/**/*.d.ts"
        ]
      },
      null,
      2
    )}
`
  );
}
async function writeManifestTypecheckTsconfig(filePath) {
  await writeTextFile(
    filePath,
    `${JSON.stringify(
      {
        compilerOptions: {
          target: "ES2022",
          module: "ESNext",
          moduleResolution: "bundler",
          strict: true,
          esModuleInterop: true,
          skipLibCheck: true,
          noEmit: true,
          allowImportingTsExtensions: true
        },
        include: ["./manifest.ts"]
      },
      null,
      2
    )}
`
  );
}
async function migrateLegacyScenarioImports(projectRoot) {
  const scenariosRoot = path.join(projectRoot, "test", "scenarios");
  if (!await exists(scenariosRoot)) return;
  const scenarioFiles = await collectScenarioFiles(scenariosRoot);
  for (const filePath of scenarioFiles) {
    const content = await readTextFile(filePath);
    if (!content.includes("@dreamboard/cli/testing")) continue;
    const relativeToTestingTypes = normalizeImportPath(
      path.relative(
        path.dirname(filePath),
        path.join(projectRoot, "test", "testing-types")
      )
    );
    const migrated = content.replaceAll('"@dreamboard/cli/testing"', `"${relativeToTestingTypes}"`).replaceAll("'@dreamboard/cli/testing'", `'${relativeToTestingTypes}'`);
    if (migrated !== content) {
      await writeTextFile(filePath, migrated);
    }
  }
}
function shouldRefreshGeneratedTestingTypes(existingContent) {
  if (existingContent === null || existingContent.trim().length === 0) {
    return true;
  }
  if (existingContent === TESTING_TYPES_STUB) {
    return true;
  }
  return existingContent.startsWith(GENERATED_TESTING_TYPES_PREFIX);
}
async function inferInitialTestPlayerCount(projectRoot) {
  const manifestPath = path.join(projectRoot, "manifest.ts");
  if (!await exists(manifestPath)) {
    return 4;
  }
  try {
    const manifest = await materializeManifest(projectRoot);
    return manifest.players.optimalPlayers ?? manifest.players.minPlayers ?? 4;
  } catch {
    return 4;
  }
}
async function collectScenarioFiles(rootDir) {
  const files = [];
  const stack = [rootDir];
  while (stack.length > 0) {
    const dir = stack.pop();
    if (!dir) continue;
    const entries = await readdir(dir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (entry.isDirectory()) {
        stack.push(fullPath);
      } else if (entry.isFile() && entry.name.endsWith(".ts")) {
        files.push(fullPath);
      }
    }
  }
  return files;
}
function resolveStaticAssetRoot(importUrl = import.meta.url) {
  const candidates = [
    fileURLToPath(new URL("../../scaffold/assets/static/", importUrl)),
    fileURLToPath(new URL("./scaffold/assets/static/", importUrl)),
    fileURLToPath(new URL("../scaffold/assets/static/", importUrl))
  ];
  for (const candidate of candidates) {
    if (existsSync(candidate)) {
      return candidate;
    }
  }
  throw new Error(
    `Unable to locate CLI static scaffold assets. Checked: ${candidates.join(", ")}`
  );
}
async function getStaticAssetEntries() {
  const files = await walkFiles(STATIC_ASSET_ROOT);
  const entries = [];
  for (const filePath of files) {
    const targetPath = normalizeProjectPath(
      path.relative(STATIC_ASSET_ROOT, filePath)
    );
    entries.push({
      targetPath,
      content: await readFile(filePath, "utf8")
    });
  }
  entries.sort(
    (left, right) => left.targetPath.localeCompare(right.targetPath)
  );
  return entries;
}
async function getDynamicStaticEntries(projectRoot, mode, options = {}) {
  const entries = [
    {
      targetPath: "package.json",
      content: await buildRootPackageJson(projectRoot, mode, options)
    },
    {
      targetPath: "ui/package.json",
      content: buildUiPackageJson()
    }
  ];
  if (options.localMaintainerRegistry) {
    entries.push({
      targetPath: ".npmrc",
      content: buildWorkspaceNpmrc(options.localMaintainerRegistry.registryUrl)
    });
  }
  return entries;
}
async function readProjectLocalMaintainerRegistry(projectRoot) {
  const projectConfigPath = path.join(
    projectRoot,
    PROJECT_DIR_NAME,
    PROJECT_CONFIG_FILE
  );
  if (!await exists(projectConfigPath)) {
    return null;
  }
  const projectConfig = await loadProjectConfig(projectRoot);
  return projectConfig.localMaintainerRegistry ?? null;
}
async function getExpectedStaticEntries(projectRoot) {
  const entries = [
    ...await getStaticAssetEntries(),
    ...await getDynamicStaticEntries(projectRoot, "update", {
      localMaintainerRegistry: await readProjectLocalMaintainerRegistry(projectRoot)
    })
  ];
  entries.sort(
    (left, right) => left.targetPath.localeCompare(right.targetPath)
  );
  return entries;
}
async function walkFiles(rootDir) {
  const files = [];
  const stack = [rootDir];
  while (stack.length > 0) {
    const currentDir = stack.pop();
    if (!currentDir) continue;
    const entries = await readdir(currentDir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(currentDir, entry.name);
      if (entry.isDirectory()) {
        stack.push(fullPath);
      } else if (entry.isFile()) {
        files.push(fullPath);
      }
    }
  }
  files.sort((left, right) => left.localeCompare(right));
  return files;
}
async function buildRootPackageJson(projectRoot, mode, options) {
  const sdkPackageRanges = {
    ...SDK_DEPENDENCY_RANGES,
    ...options.localMaintainerRegistry?.packages ?? {}
  };
  const packageJsonPath = path.join(projectRoot, "package.json");
  const existingPackageJson = mode === "update" && await exists(packageJsonPath) ? await readJsonFile(packageJsonPath) : null;
  const {
    dreamboardFrameworkVersion: _legacyFrameworkVersion,
    ...existingPackageJsonWithoutLegacyVersion
  } = existingPackageJson ?? {};
  const frameworkDependencies = {
    "@dreamboard-games/sdk": sdkPackageRanges["@dreamboard-games/sdk"] ?? SDK_DEPENDENCY_RANGES["@dreamboard-games/sdk"],
    ...SHARED_DEPENDENCIES,
    ...ROOT_APP_DEPENDENCIES
  };
  const frameworkDevDependencies = {
    ...SHARED_DEV_DEPENDENCIES
  };
  const nextPackageJson = {
    ...existingPackageJsonWithoutLegacyVersion,
    private: true,
    scripts: {
      ...existingPackageJson?.scripts ?? {},
      ...FRAMEWORK_SCRIPTS
    },
    dependencies: {
      ...existingPackageJson?.dependencies ?? {},
      ...frameworkDependencies
    },
    devDependencies: {
      ...existingPackageJson?.devDependencies ?? {},
      ...frameworkDevDependencies
    },
    pnpm: mergePnpmConfig(existingPackageJson?.pnpm)
  };
  return `${JSON.stringify(nextPackageJson, null, 2)}
`;
}
function mergePnpmConfig(existingPnpm) {
  const existingOverrides = existingPnpm?.overrides && typeof existingPnpm.overrides === "object" && !Array.isArray(existingPnpm.overrides) ? existingPnpm.overrides : {};
  return {
    ...existingPnpm ?? {},
    overrides: {
      ...existingOverrides,
      ...FRAMEWORK_PNPM_OVERRIDES
    }
  };
}
function buildWorkspaceNpmrc(registryUrl) {
  return `@dreamboard-games:registry=${registryUrl}
`;
}
function buildUiPackageJson() {
  return `${JSON.stringify(
    {
      private: true,
      dependencies: SHARED_DEPENDENCIES,
      devDependencies: SHARED_DEV_DEPENDENCIES
    },
    null,
    2
  )}
`;
}
function readPackageVersion(packageJsonPath, packageName) {
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
  if (typeof packageJson.version !== "string" || packageJson.version.trim().length === 0) {
    return null;
  }
  return `^${packageJson.version.trim()}`;
}
function findNearestPackageJsonPath(importMetaUrl = import.meta.url) {
  let current = path.dirname(fileURLToPath(importMetaUrl));
  while (true) {
    const candidate = path.join(current, "package.json");
    if (existsSync(candidate)) {
      return candidate;
    }
    const parent = path.dirname(current);
    if (parent === current) {
      return null;
    }
    current = parent;
  }
}
function isSourceCheckoutCliPackageJsonPath(packageJsonPath, importMetaUrl = import.meta.url) {
  try {
    return path.resolve(packageJsonPath) === path.join(
      resolveCliRepoRoot(importMetaUrl),
      "apps",
      "dreamboard-cli",
      "package.json"
    );
  } catch {
    return false;
  }
}
function readPackagedSdkDependencyRange(packageName, importMetaUrl = import.meta.url) {
  const packageJsonPath = findNearestPackageJsonPath(importMetaUrl);
  if (!packageJsonPath) {
    return null;
  }
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
  const packagedRange = packageJson.dependencies?.[packageName];
  if (typeof packagedRange !== "string" || packagedRange.trim().length === 0 || packagedRange.startsWith("workspace:") || packagedRange.startsWith("link:") || packagedRange.startsWith("file:") && !IS_PUBLISHED_BUILD && isSourceCheckoutCliPackageJsonPath(packageJsonPath, importMetaUrl)) {
    return null;
  }
  return packagedRange.trim();
}
function stripLocalSnapshotSuffix(range) {
  return range.replace(/-local\..*$/, "");
}
function resolveSdkDependencyRange(packageName, importMetaUrl = import.meta.url) {
  const packagedRange = readPackagedSdkDependencyRange(
    packageName,
    importMetaUrl
  );
  if (packagedRange) {
    return stripLocalSnapshotSuffix(packagedRange);
  }
  try {
    const repoRoot = resolveCliRepoRoot(importMetaUrl);
    const packageJsonPath = path.join(
      repoRoot,
      ...SDK_PACKAGE_PATHS[packageName]
    );
    const repoRange = readPackageVersion(packageJsonPath, packageName);
    if (repoRange) {
      return stripLocalSnapshotSuffix(repoRange);
    }
  } catch {
  }
  return DEFAULT_SDK_DEPENDENCY_RANGES[packageName];
}
function normalizeImportPath(relativePath) {
  const normalized = relativePath.replaceAll("\\", "/");
  if (normalized.startsWith(".")) return normalized;
  return `./${normalized}`;
}
function normalizeProjectPath(filePath) {
  return filePath.replace(/^\.\//, "").replace(/^\/+/, "").replace(/\\/g, "/");
}
function summarizePaths(paths) {
  const maxShown = 5;
  const shown = paths.slice(0, maxShown).join(", ");
  if (paths.length <= maxShown) return shown;
  return `${shown}, and ${paths.length - maxShown} more`;
}

export {
  scaffoldStaticWorkspace,
  assertCliStaticScaffoldComplete,
  migrateLegacyScenarioImports,
  resolveStaticAssetRoot,
  resolveSdkDependencyRange
};
//# sourceMappingURL=chunk-MW2QIWWA.mjs.map