@dreamboard-games/cli 0.1.30-alpha.3 → 0.1.30-alpha.31
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/README.md +27 -108
- package/dist/agent-verifier/agent-workspace-verifier.mjs +1988 -57
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -1
- package/dist/agent-verifier/{chunk-XQXDOBYB.mjs → chunk-4I2WWAPK.mjs} +27 -10
- package/dist/agent-verifier/chunk-4I2WWAPK.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-O4YCPU7C.mjs → chunk-BWBN2TDJ.mjs} +539 -641
- package/dist/agent-verifier/chunk-BWBN2TDJ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-TAEQKBJB.mjs → chunk-GWRZRWCF.mjs} +1 -1
- package/dist/agent-verifier/chunk-GWRZRWCF.mjs.map +1 -0
- package/dist/agent-verifier/chunk-H6XDQJ3N.mjs +11 -0
- package/dist/agent-verifier/chunk-HUBV22JQ.mjs +89 -0
- package/dist/agent-verifier/chunk-HUBV22JQ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-VS573ERH.mjs → chunk-JZTH3EMV.mjs} +2 -2
- package/dist/agent-verifier/{chunk-XGWCY624.mjs → chunk-KDAQ4CZY.mjs} +34 -27
- package/dist/agent-verifier/chunk-KDAQ4CZY.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-IAYRNVUC.mjs → chunk-LMW66VBH.mjs} +2 -13
- package/dist/agent-verifier/{chunk-IAYRNVUC.mjs.map → chunk-LMW66VBH.mjs.map} +1 -1
- package/dist/agent-verifier/{chunk-776W3UGV.mjs → chunk-M6YNQZCC.mjs} +4 -13
- package/dist/agent-verifier/chunk-M6YNQZCC.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-H76MT5UR.mjs → chunk-M7UVBANQ.mjs} +2 -1
- package/dist/agent-verifier/chunk-M7UVBANQ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-SH5JKYOB.mjs → chunk-MIRGCMUC.mjs} +112 -26
- package/dist/agent-verifier/chunk-MIRGCMUC.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-NAK77WXW.mjs → chunk-MYMVXTZT.mjs} +4 -5
- package/dist/agent-verifier/chunk-MYMVXTZT.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-7WWGFAAU.mjs → chunk-NBRUEJUK.mjs} +215 -223
- package/dist/agent-verifier/chunk-NBRUEJUK.mjs.map +1 -0
- package/dist/agent-verifier/chunk-OJFZVGEL.mjs +492 -0
- package/dist/agent-verifier/chunk-OJFZVGEL.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-LUZ7KE6H.mjs → chunk-QD4SQNUP.mjs} +4 -8
- package/dist/agent-verifier/{chunk-LUZ7KE6H.mjs.map → chunk-QD4SQNUP.mjs.map} +1 -1
- package/dist/agent-verifier/chunk-TTB7AIHZ.mjs +214 -0
- package/dist/agent-verifier/chunk-TTB7AIHZ.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-F2DIOJJZ.mjs → chunk-XCQQIPCO.mjs} +5 -46
- package/dist/agent-verifier/chunk-XCQQIPCO.mjs.map +1 -0
- package/dist/agent-verifier/{global-config-Y2NTSK4R.mjs → global-config-2NUESNEQ.mjs} +6 -6
- package/dist/agent-verifier/{keychain-backend-SPQWGKZN.mjs → keychain-backend-FF4I6ODB.mjs} +12 -7
- package/dist/agent-verifier/keychain-backend-FF4I6ODB.mjs.map +1 -0
- package/dist/agent-verifier/{local-files-JFOQQZDL.mjs → local-files-OF4QFISU.mjs} +10 -10
- package/dist/agent-verifier/{chunk-UIOLGH4A.mjs → local-typecheck-DHVLM37Z.mjs} +4 -4
- package/dist/agent-verifier/local-typecheck-DHVLM37Z.mjs.map +1 -0
- package/dist/agent-verifier/{materialize-workspace-ZAVGQQSF.mjs → materialize-workspace-MAGKDMK5.mjs} +23 -22
- package/dist/agent-verifier/materialize-workspace-MAGKDMK5.mjs.map +1 -0
- package/dist/agent-verifier/{project-state-K576C2TE.mjs → project-state-XKUSCFSV.mjs} +2 -2
- package/dist/agent-verifier/{prompt-MJRJMOGQ.mjs → prompt-VKHMCQT6.mjs} +2 -2
- package/dist/agent-verifier/{chunk-A64ZZUZV.mjs → reducer-bundle-preflight-GLUJKTWU.mjs} +76 -25
- package/dist/agent-verifier/reducer-bundle-preflight-GLUJKTWU.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-JGT4P4UD.mjs → reducer-contract-preflight-WVQQPW5F.mjs} +7 -6
- package/dist/agent-verifier/reducer-contract-preflight-WVQQPW5F.mjs.map +1 -0
- package/dist/agent-verifier/{chunk-E7SSWJXJ.mjs → reducer-native-test-harness-UFMSNNDY.mjs} +463 -686
- package/dist/agent-verifier/reducer-native-test-harness-UFMSNNDY.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-CLRRWXON.mjs +24 -0
- package/dist/agent-verifier/workspace-codegen-SPPVHURX.mjs +10 -0
- package/dist/agent-verifier/{workspace-dependencies-NOOQBK6I.mjs → workspace-dependencies-5HEEKZFP.mjs} +6 -4
- package/dist/authoring-compatibility-internal.js +12 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-6NYVJYN4.js +313 -0
- package/dist/chunk-6NYVJYN4.js.map +1 -0
- package/dist/chunk-EQNBQVIW.js +204 -0
- package/dist/chunk-EQNBQVIW.js.map +1 -0
- package/dist/chunk-X244CUU4.js +3815 -0
- package/dist/chunk-X244CUU4.js.map +1 -0
- package/dist/{chunk-TAQKH67O.js → chunk-YNJVKC2T.js} +2587 -7278
- package/dist/chunk-YNJVKC2T.js.map +1 -0
- package/dist/{global-config-S4ZIPECE.js → global-config-RBMW7IVA.js} +4 -3
- package/dist/index.js +3099 -6187
- package/dist/index.js.map +1 -1
- package/dist/internal.js +36 -10
- package/dist/internal.js.map +1 -1
- package/dist/{keychain-backend-HDF4TZDL.js → keychain-backend-FSNTNTZE.js} +12 -7
- package/dist/keychain-backend-FSNTNTZE.js.map +1 -0
- package/dist/{prompt-NDV3AE5L.js → prompt-GMZABCJC.js} +2 -2
- package/package.json +9 -19
- package/release/authoring-release-set.json +38 -0
- package/skills/dreamboard/SKILL.md +30 -28
- package/skills/dreamboard/references/building-your-first-game.md +15 -15
- package/skills/dreamboard/references/cli.md +46 -47
- package/skills/dreamboard/references/manifest-authoring.md +11 -3
- package/skills/dreamboard/references/quickstart.md +16 -13
- package/skills/dreamboard/references/testing.md +6 -13
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs +0 -1744
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +0 -1
- package/dist/agent-verifier/chunk-776W3UGV.mjs.map +0 -1
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +0 -1
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +0 -1
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +0 -1
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +0 -1
- package/dist/agent-verifier/chunk-G42BGGG2.mjs +0 -70
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +0 -1
- package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +0 -1
- package/dist/agent-verifier/chunk-HGMUAL33.mjs +0 -39
- package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +0 -1
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +0 -1
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +0 -1
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +0 -1
- package/dist/agent-verifier/chunk-S34FRJHS.mjs +0 -222
- package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +0 -1
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +0 -1
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs +0 -44
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +0 -1
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +0 -1
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs +0 -2432
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +0 -1
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs +0 -624
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +0 -1
- package/dist/agent-verifier/chunk-XGWCY624.mjs.map +0 -1
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +0 -1
- package/dist/agent-verifier/compile-TEQVA46V.mjs +0 -312
- package/dist/agent-verifier/compile-TEQVA46V.mjs.map +0 -1
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +0 -1
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +0 -10
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +0 -1
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs +0 -20
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +0 -11
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs +0 -50
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +0 -27
- package/dist/agent-verifier/sync-THAI546U.mjs +0 -588
- package/dist/agent-verifier/sync-THAI546U.mjs.map +0 -1
- package/dist/agent-verifier/test-AFAQFKOB.mjs +0 -353
- package/dist/agent-verifier/test-AFAQFKOB.mjs.map +0 -1
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +0 -10
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +0 -1
- package/dist/chunk-N7XPNNUI.js +0 -432
- package/dist/chunk-N7XPNNUI.js.map +0 -1
- package/dist/chunk-SEGVTWSK.js +0 -44
- package/dist/chunk-SEGVTWSK.js.map +0 -1
- package/dist/chunk-TAQKH67O.js.map +0 -1
- package/dist/dev-host/components/drawer.tsx +0 -132
- package/dist/dev-host/components/input.tsx +0 -21
- package/dist/dev-host/dev-api-proxy-plugin.ts +0 -328
- package/dist/dev-host/dev-author-dom-warnings.ts +0 -100
- package/dist/dev-host/dev-diagnostics.ts +0 -62
- package/dist/dev-host/dev-fallback-stylesheet.ts +0 -53
- package/dist/dev-host/dev-hmr-guard-plugin.ts +0 -47
- package/dist/dev-host/dev-host-controller.ts +0 -674
- package/dist/dev-host/dev-host-player-query.ts +0 -17
- package/dist/dev-host/dev-host-session-transport.ts +0 -52
- package/dist/dev-host/dev-host-storage.ts +0 -56
- package/dist/dev-host/dev-log-relay-plugin.ts +0 -510
- package/dist/dev-host/dev-runtime-config.ts +0 -14
- package/dist/dev-host/dev-runtime-platform.ts +0 -335
- package/dist/dev-host/dev-virtual-modules-plugin.ts +0 -64
- package/dist/dev-host/host-main.css +0 -224
- package/dist/dev-host/host-main.tsx +0 -948
- package/dist/dev-host/index.html +0 -56
- package/dist/dev-host/lib/utils.ts +0 -6
- package/dist/dev-host/plugin-main.ts +0 -61
- package/dist/dev-host/plugin.html +0 -24
- package/dist/dev-host/shared-styles.css +0 -144
- package/dist/dev-host/start-dev-server.ts +0 -140
- package/dist/dev-host/virtual-modules.d.ts +0 -27
- package/dist/global-config-S4ZIPECE.js.map +0 -1
- package/dist/keychain-backend-HDF4TZDL.js.map +0 -1
- package/skills/dreamboard/scripts/events-extract.mjs +0 -218
- /package/dist/agent-verifier/{chunk-SKI2ESE5.mjs.map → chunk-H6XDQJ3N.mjs.map} +0 -0
- /package/dist/agent-verifier/{chunk-VS573ERH.mjs.map → chunk-JZTH3EMV.mjs.map} +0 -0
- /package/dist/agent-verifier/{global-config-Y2NTSK4R.mjs.map → global-config-2NUESNEQ.mjs.map} +0 -0
- /package/dist/agent-verifier/{local-files-JFOQQZDL.mjs.map → local-files-OF4QFISU.mjs.map} +0 -0
- /package/dist/agent-verifier/{local-typecheck-XVGWI75X.mjs.map → project-state-XKUSCFSV.mjs.map} +0 -0
- /package/dist/agent-verifier/{prompt-MJRJMOGQ.mjs.map → prompt-VKHMCQT6.mjs.map} +0 -0
- /package/dist/agent-verifier/{project-state-K576C2TE.mjs.map → static-scaffold-CLRRWXON.mjs.map} +0 -0
- /package/dist/agent-verifier/{reducer-bundle-preflight-LXNJUBKL.mjs.map → workspace-codegen-SPPVHURX.mjs.map} +0 -0
- /package/dist/agent-verifier/{reducer-contract-preflight-TUMQ43JV.mjs.map → workspace-dependencies-5HEEKZFP.mjs.map} +0 -0
- /package/dist/{agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map → authoring-compatibility-internal.js.map} +0 -0
- /package/dist/{agent-verifier/static-scaffold-R7SVDRQI.mjs.map → chunk-2H7UOFLK.js.map} +0 -0
- /package/dist/{agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map → global-config-RBMW7IVA.js.map} +0 -0
- /package/dist/{prompt-NDV3AE5L.js.map → prompt-GMZABCJC.js.map} +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.framework.json +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/app/tsconfig.json +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/ui/index.tsx +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/ui/style.css +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.framework.json +0 -0
- /package/{dist/scaffold → scaffold}/assets/static/ui/tsconfig.json +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/project/static-scaffold.ts","../../src/release/authoring-release-set.generated.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile, rmdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { GameTopologyManifest } from \"@dreamboard-games/sdk/types\";\nimport { AUTHORING_RELEASE_SET } from \"../../release/authoring-release-set.js\";\nimport { REDUCER_TESTING_TYPES_WRAPPER_CONTENT } from \"../../templates/testing-types-content.js\";\nimport {\n MANIFEST_TYPECHECK_CONFIG_FILE,\n PROJECT_CONFIG_FILE,\n PROJECT_DIR_NAME,\n} from \"../../constants.js\";\nimport type { LocalMaintainerRegistryConfig } from \"../../types.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport { materializeManifest } from \"./manifest-authoring.js\";\nimport { isDynamicSeedPath } from \"./scaffold-ownership.js\";\nimport {\n normalizeOwnedProjectPath,\n readWorkspaceTextFile,\n readWorkspaceTextFileIfExists,\n removeWorkspacePath,\n resolveWorkspacePath,\n unlinkWorkspaceFile,\n workspacePathExists,\n writeWorkspaceTextFile,\n} from \"./workspace-path.js\";\nimport {\n FRAMEWORK_PNPM_OVERRIDES,\n FRAMEWORK_REACT_DEPENDENCIES,\n FRAMEWORK_ZOD_VERSION,\n} from \"./framework-dependencies.js\";\n\ntype StaticScaffoldMode = \"new\" | \"update\";\ntype StaticAssetEntry = {\n targetPath: string;\n content: string;\n};\ntype StaticScaffoldOptions = {\n localMaintainerRegistry?: LocalMaintainerRegistryConfig | null;\n};\ntype RootPackageJsonShape = {\n private?: boolean;\n packageManager?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n overrides?: Record<string, unknown>;\n pnpm?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nconst DREAMBOARD_SCAFFOLD_REFRESH_COMMAND =\n \"dreamboard project create or dreamboard project clone\";\nconst DREAMBOARD_GITIGNORE_BLOCK = [\n \"# Dreamboard local state\",\n \".dreamboard/state.json\",\n \".dreamboard/snapshot.json\",\n \".dreamboard/dev/\",\n \".dreamboard/generated/\",\n \"node_modules/\",\n \"ui/node_modules/\",\n \"\",\n].join(\"\\n\");\nconst TESTING_TYPES_STUB =\n \"export function defineScenario(scenario) { return scenario; }\\n\";\nconst GENERATED_TESTING_TYPES_PREFIX = \"// Generated by dreamboard\";\nconst GENERATED_SCENARIO_PREFIX = \"// Generated by dreamboard scaffold.\";\nconst LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = `export {\n ErrorBoundary,\n type ErrorBoundaryProps,\n} from \"@dreamboard-games/sdk/ui\";\nexport { PluginRuntime, type PluginRuntimeProps } from \"@dreamboard-games/sdk/runtime\";\n`;\nconst OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT = [\n \"export {\",\n \" ErrorBoundary,\",\n \" PluginRuntime,\",\n \" type ErrorBoundaryProps,\",\n \" type PluginRuntimeProps,\",\n `} from \"@dreamboard/ui-${\"sdk\"}\";`,\n \"\",\n].join(\"\\n\");\nconst OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT = [\n \"export {\",\n \" ErrorBoundary,\",\n \" PluginRuntime,\",\n \" type ErrorBoundaryProps,\",\n \" type PluginRuntimeProps,\",\n `} from \"@dreamboard-games/ui-${\"sdk\"}\";`,\n \"\",\n].join(\"\\n\");\nconst INITIAL_SCENARIO_CONTENT = `${GENERATED_SCENARIO_PREFIX}\nimport { defineScenario } from \"../testing-types\";\n\nexport default defineScenario({\n id: \"smoke-initial-turn\",\n description:\n \"Sanity check that the scaffolded workspace boots into its initial phase.\",\n from: \"initial-turn\",\n when: async () => undefined,\n then: ({ expect, players, state }) => {\n const playerIds = players();\n expect(playerIds).toHaveLength(playerIds.length);\n expect(playerIds.length).toBeGreaterThanOrEqual(1);\n expect(state()).toBe(\"setup\");\n },\n});\n`;\nconst STATIC_ASSET_ROOT = resolveStaticAssetRoot();\nconst SDK_DEPENDENCY_RANGES = {\n \"@dreamboard-games/sdk\": AUTHORING_RELEASE_SET.packages.sdk.version,\n} as const;\nconst DEV_HOST_DEPENDENCY_RANGES = {\n \"@dreamboard-games/dev-host\": AUTHORING_RELEASE_SET.packages.devHost.version,\n} as const;\nconst DREAMBOARD_PACKAGE_OVERRIDES = {\n \"@dreamboard-games/api-client\":\n AUTHORING_RELEASE_SET.packages.apiClient.version,\n \"@dreamboard-games/dev-host\": AUTHORING_RELEASE_SET.packages.devHost.version,\n \"@dreamboard-games/sdk\": AUTHORING_RELEASE_SET.packages.sdk.version,\n} as const;\n\nconst FRAMEWORK_SCRIPTS = {\n dev: \"dreamboard dev\",\n \"test:ui\":\n \"tsx --tsconfig test/tsconfig.tsx-runtime.json --test test/ui/**/*.test.tsx\",\n typecheck: `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE} && tsc --noEmit -p app/tsconfig.json && tsc --noEmit -p ui/tsconfig.json`,\n \"typecheck:manifest\": `tsc --noEmit -p ${MANIFEST_TYPECHECK_CONFIG_FILE}`,\n \"typecheck:app\": \"tsc --noEmit -p app/tsconfig.json\",\n \"typecheck:ui\": \"tsc --noEmit -p ui/tsconfig.json\",\n} as const;\nconst SHARED_DEPENDENCIES = {\n ...FRAMEWORK_REACT_DEPENDENCIES,\n} as const;\nconst ROOT_APP_DEPENDENCIES = {\n zod: FRAMEWORK_ZOD_VERSION,\n} as const;\nconst SHARED_DEV_DEPENDENCIES = {\n typescript: \"^5.9.2\",\n \"@types/node\": \"^24.5.2\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n csstype: \"^3.1.3\",\n tsx: \"^4.20.5\",\n} as const;\n\nexport async function scaffoldStaticWorkspace(\n projectRoot: string,\n mode: StaticScaffoldMode,\n options: StaticScaffoldOptions = {},\n): Promise<void> {\n await writeFrameworkStaticFiles(projectRoot, mode, options);\n await ensureDreamboardGitignore(projectRoot);\n await writeManifestTypecheckTsconfig(projectRoot);\n await removeLegacyVendoredSdkPaths(projectRoot);\n await removeLegacyDreamboardComponentPath(projectRoot);\n\n await ensureDir(resolveWorkspacePath(projectRoot, \"test/bases\"));\n await ensureDir(resolveWorkspacePath(projectRoot, \"test/scenarios\"));\n await ensureDir(resolveWorkspacePath(projectRoot, \"test/generated\"));\n\n await writeTestReadme(projectRoot);\n await writeGeneratedTestingStubs(projectRoot, mode);\n const initialTestPlayerCount = await inferInitialTestPlayerCount(projectRoot);\n await writeInitialBase(projectRoot, mode, initialTestPlayerCount);\n await writeInitialScenario(projectRoot, mode);\n await writeTestingTypes(projectRoot, mode);\n await writeTestTsconfig(projectRoot);\n\n if (await workspacePathExists(projectRoot, \"test/testing-types.d.ts\")) {\n await unlinkWorkspaceFile(projectRoot, \"test/testing-types.d.ts\");\n }\n if (await workspacePathExists(projectRoot, \"test/base-scenarios.json\")) {\n await unlinkWorkspaceFile(projectRoot, \"test/base-scenarios.json\");\n }\n\n await migrateLegacyScenarioImports(projectRoot);\n}\n\nasync function ensureDreamboardGitignore(projectRoot: string): Promise<void> {\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n \".gitignore\",\n );\n if (existing?.includes(\".dreamboard/state.json\")) {\n return;\n }\n await writeWorkspaceTextFile(\n projectRoot,\n \".gitignore\",\n `${existing ? `${existing.trimEnd()}\\n\\n` : \"\"}${DREAMBOARD_GITIGNORE_BLOCK}`,\n );\n}\n\nexport async function assertCliStaticScaffoldComplete(\n projectRoot: string,\n deletedPaths: readonly string[] = [],\n): Promise<void> {\n const expectedEntries = await getExpectedStaticEntries(projectRoot);\n const missingOrBlankPaths: string[] = [];\n\n for (const entry of expectedEntries) {\n const content = await readWorkspaceTextFileIfExists(\n projectRoot,\n entry.targetPath,\n );\n\n if (content === null || content.trim().length === 0) {\n missingOrBlankPaths.push(entry.targetPath);\n }\n }\n\n const staticPaths = new Set(expectedEntries.map((entry) => entry.targetPath));\n const deletedStaticPaths = deletedPaths\n .map(normalizeOwnedProjectPath)\n .filter(\n (filePath): filePath is string =>\n filePath !== null && staticPaths.has(filePath),\n )\n .sort();\n\n if (missingOrBlankPaths.length === 0 && deletedStaticPaths.length === 0) {\n return;\n }\n\n const problems: string[] = [];\n if (missingOrBlankPaths.length > 0) {\n problems.push(\n `missing or blank: ${summarizePaths(missingOrBlankPaths.sort())}`,\n );\n }\n if (deletedStaticPaths.length > 0) {\n problems.push(`deleted: ${summarizePaths(deletedStaticPaths)}`);\n }\n\n throw new Error(\n `CLI static scaffold is incomplete (${problems.join(\"; \")}). Refresh the project scaffold with ${DREAMBOARD_SCAFFOLD_REFRESH_COMMAND} before building or testing.`,\n );\n}\n\nasync function writeFrameworkStaticFiles(\n projectRoot: string,\n mode: StaticScaffoldMode,\n options: StaticScaffoldOptions,\n): Promise<void> {\n const assetEntries = await getStaticAssetEntries();\n\n for (const entry of assetEntries) {\n // Dynamic seed files are user-customizable: only write them on first\n // scaffold; preserve existing content on subsequent updates.\n if (mode === \"update\" && isDynamicSeedPath(entry.targetPath)) {\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n entry.targetPath,\n );\n if (existing !== null && existing.trim().length > 0) {\n continue;\n }\n }\n await writeWorkspaceTextFile(projectRoot, entry.targetPath, entry.content);\n }\n\n for (const entry of await getDynamicStaticEntries(\n projectRoot,\n mode,\n options,\n )) {\n await writeWorkspaceTextFile(projectRoot, entry.targetPath, entry.content);\n }\n\n if (!options.localMaintainerRegistry) {\n await removeWorkspacePath(projectRoot, \".npmrc\", { force: true });\n }\n}\n\nasync function removeLegacyVendoredSdkPaths(\n projectRoot: string,\n): Promise<void> {\n await removeWorkspacePath(projectRoot, \"app/sdk\", {\n recursive: true,\n force: true,\n });\n await removeWorkspacePath(projectRoot, \"ui/sdk\", {\n recursive: true,\n force: true,\n });\n}\n\nasync function removeLegacyDreamboardComponentPath(\n projectRoot: string,\n): Promise<void> {\n const legacyIndexProjectPath = \"ui/components/dreamboard/index.ts\";\n const legacyDirPath = resolveWorkspacePath(\n projectRoot,\n \"ui/components/dreamboard\",\n );\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n legacyIndexProjectPath,\n );\n\n const removableLegacyContents = new Set([\n LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),\n OLD_LEGACY_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),\n OLD_PUBLIC_DREAMBOARD_COMPONENT_INDEX_CONTENT.trim(),\n ]);\n\n if (existing === null || !removableLegacyContents.has(existing.trim())) {\n return;\n }\n\n await unlinkWorkspaceFile(projectRoot, legacyIndexProjectPath);\n const remainingEntries = await readdir(legacyDirPath).catch(() => []);\n if (remainingEntries.length === 0) {\n await rmdir(legacyDirPath);\n }\n}\n\nasync function writeTestReadme(projectRoot: string): Promise<void> {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/README.md\",\n \"# Dreamboard Test Workspace\\n\\nTypeScript bases live in `test/bases/*.base.ts` and scenarios live in `test/scenarios/*.scenario.ts`.\\n\\n1. Define reusable seeded bases with `defineBase({ id, seed, players, setupProfileId?, setup })`.\\n2. Define scenarios with `defineScenario({ id, from, when, then })`.\\n3. Scenario assertions can read `players()`, `state()`, `view(playerId)`, and `interactions(playerId)`.\\n4. Run deterministic scenario tests: `dreamboard test`.\\n5. Run a single scenario when needed: `dreamboard test --scenario <scenario-id>`.\\n\\nImport test helpers from `../testing-types`.\\n\\nGenerated artifacts are written to `test/generated/*` and should not be edited manually.\\n\",\n );\n}\n\nasync function writeInitialBase(\n projectRoot: string,\n mode: StaticScaffoldMode,\n players: number,\n): Promise<void> {\n if (mode === \"update\") {\n return;\n }\n\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/bases/initial-turn.base.ts\",\n `import { defineBase } from \"../testing-types\";\n\nexport default defineBase({\n id: \"initial-turn\",\n seed: 1337,\n players: ${players},\n setup: async () => undefined,\n});\n`,\n );\n}\n\nasync function writeInitialScenario(\n projectRoot: string,\n mode: StaticScaffoldMode,\n): Promise<void> {\n if (mode === \"new\") {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/scenarios/smoke-initial-turn.scenario.ts\",\n INITIAL_SCENARIO_CONTENT,\n );\n return;\n }\n\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n \"test/scenarios/smoke-initial-turn.scenario.ts\",\n );\n if (\n existing === null ||\n existing.trim().length === 0 ||\n existing.startsWith(GENERATED_SCENARIO_PREFIX)\n ) {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/scenarios/smoke-initial-turn.scenario.ts\",\n INITIAL_SCENARIO_CONTENT,\n );\n }\n}\n\nasync function writeTestingTypes(\n projectRoot: string,\n mode: StaticScaffoldMode,\n): Promise<void> {\n if (mode === \"new\") {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/testing-types.ts\",\n REDUCER_TESTING_TYPES_WRAPPER_CONTENT,\n );\n return;\n }\n\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n \"test/testing-types.ts\",\n );\n if (shouldRefreshGeneratedTestingTypes(existing)) {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/testing-types.ts\",\n REDUCER_TESTING_TYPES_WRAPPER_CONTENT,\n );\n }\n}\n\nasync function writeGeneratedTestingStubs(\n projectRoot: string,\n mode: StaticScaffoldMode,\n): Promise<void> {\n const header = \"// Generated by dreamboard scaffold. Do not edit by hand.\\n\";\n await writeGeneratedTestingStubFile(\n projectRoot,\n \"test/generated/base-states.generated.ts\",\n `${header}export const BASE_STATES = {} as const;\\nexport const BASE_STATES_CONTRACT_FINGERPRINT = undefined;\\n`,\n mode,\n );\n await writeGeneratedTestingStubFile(\n projectRoot,\n \"test/generated/base-states.generated.d.ts\",\n `${header}export declare const BASE_STATES: Record<string, unknown>;\\nexport declare const BASE_STATES_CONTRACT_FINGERPRINT: string | undefined;\\n`,\n mode,\n );\n await writeGeneratedTestingStubFile(\n projectRoot,\n \"test/generated/testing-contract.ts\",\n `${header}export type BaseId = string;\\nexport type GameView = unknown;\\nexport type InteractionId = string;\\nexport type InteractionParamsOf<_Id extends string> = Record<string, unknown>;\\nexport type PhaseName = string;\\nexport type PlayerId = string;\\nexport type RejectionCode = string;\\nexport type StateName = string;\\nexport type ViewByPhase = Record<string, GameView>;\\nexport type WorkspaceStageName<_Phase extends string = string> = string;\\nexport type Expectation = { [matcher: string]: (...args: unknown[]) => unknown; not: Expectation };\\nexport type ExpectFn = (actual: unknown) => Expectation;\\nexport 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\"; }[]; };\\nexport interface InteractionDescriptorFor<Id extends string = string> { interactionId: Id; [key: string]: unknown; }\\nexport interface ScenarioGameApi { start(): Promise<void>; submit<Id extends InteractionId>(playerId: PlayerId, interactionId: Id, params?: InteractionParamsOf<Id>): Promise<void>; }\\nexport interface BaseContext { game: ScenarioGameApi; players(): readonly PlayerId[]; seat(index: number): PlayerId; }\\nexport 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; }\\nexport 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; };\\nexport type ScenarioThenContext<Phase extends PhaseName | undefined = undefined> = ScenarioContext<Phase>;\\nexport interface BaseDefinition { id: string; seed?: number; players?: number; setupProfileId?: string; extends?: BaseId | string; setup: (ctx: BaseContext) => void | Promise<void>; }\\nexport interface ScenarioDefinition<Phase extends PhaseName | undefined = undefined> { id: string; description?: string; from: BaseId | string; phase?: Phase; stage?: Phase extends PhaseName ? WorkspaceStageName<Phase> : never; when: (ctx: ScenarioContext<Phase>) => void | Promise<void>; then: (ctx: ScenarioThenContext<Phase>) => void | Promise<void>; }\\n`,\n mode,\n );\n await writeGeneratedTestingStubFile(\n projectRoot,\n \"test/generated/scenario-manifest.generated.ts\",\n `${header}export const SCENARIO_MANIFEST = [] as const;\\n`,\n mode,\n );\n}\n\nasync function writeGeneratedTestingStubFile(\n projectRoot: string,\n projectPath: string,\n content: string,\n mode: StaticScaffoldMode,\n): Promise<void> {\n if (mode === \"new\") {\n await writeWorkspaceTextFile(projectRoot, projectPath, content);\n return;\n }\n\n const existing = await readWorkspaceTextFileIfExists(\n projectRoot,\n projectPath,\n );\n if (\n existing === null ||\n existing.trim().length === 0 ||\n existing.startsWith(GENERATED_SCENARIO_PREFIX)\n ) {\n await writeWorkspaceTextFile(projectRoot, projectPath, content);\n }\n}\n\nasync function writeTestTsconfig(projectRoot: string): Promise<void> {\n await writeWorkspaceTextFile(\n projectRoot,\n \"test/tsconfig.json\",\n `${JSON.stringify(\n {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n noEmit: true,\n },\n include: [\n \"./**/*.ts\",\n \"./**/*.d.ts\",\n \"../shared/**/*.ts\",\n \"../shared/**/*.d.ts\",\n ],\n },\n null,\n 2,\n )}\\n`,\n );\n}\n\nasync function writeManifestTypecheckTsconfig(\n projectRoot: string,\n): Promise<void> {\n await writeWorkspaceTextFile(\n projectRoot,\n MANIFEST_TYPECHECK_CONFIG_FILE,\n `${JSON.stringify(\n {\n compilerOptions: {\n target: \"ES2022\",\n module: \"ESNext\",\n moduleResolution: \"bundler\",\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n noEmit: true,\n allowImportingTsExtensions: true,\n },\n include: [\"./manifest.ts\"],\n },\n null,\n 2,\n )}\\n`,\n );\n}\n\nexport async function migrateLegacyScenarioImports(\n projectRoot: string,\n): Promise<void> {\n if (!(await workspacePathExists(projectRoot, \"test/scenarios\"))) return;\n\n const scenariosRoot = resolveWorkspacePath(projectRoot, \"test/scenarios\");\n const scenarioFiles = await collectScenarioFiles(scenariosRoot);\n for (const filePath of scenarioFiles) {\n const projectPath = toWorkspaceProjectPath(projectRoot, filePath);\n const content = await readWorkspaceTextFile(projectRoot, projectPath);\n if (!content.includes(\"@dreamboard/cli/testing\")) continue;\n\n const relativeToTestingTypes = normalizeImportPath(\n path.relative(\n path.dirname(filePath),\n path.join(projectRoot, \"test\", \"testing-types\"),\n ),\n );\n\n const migrated = content\n .replaceAll('\"@dreamboard/cli/testing\"', `\"${relativeToTestingTypes}\"`)\n .replaceAll(\"'@dreamboard/cli/testing'\", `'${relativeToTestingTypes}'`);\n\n if (migrated !== content) {\n await writeWorkspaceTextFile(projectRoot, projectPath, migrated);\n }\n }\n}\n\nfunction shouldRefreshGeneratedTestingTypes(\n existingContent: string | null,\n): boolean {\n if (existingContent === null || existingContent.trim().length === 0) {\n return true;\n }\n if (existingContent === TESTING_TYPES_STUB) {\n return true;\n }\n return existingContent.startsWith(GENERATED_TESTING_TYPES_PREFIX);\n}\n\nasync function inferInitialTestPlayerCount(\n projectRoot: string,\n): Promise<number> {\n if (!(await workspacePathExists(projectRoot, \"manifest.ts\"))) {\n return 4;\n }\n\n try {\n const manifest = await materializeManifest(projectRoot);\n return manifest.players.optimalPlayers ?? manifest.players.minPlayers ?? 4;\n } catch {\n return 4;\n }\n}\n\nasync function collectScenarioFiles(rootDir: string): Promise<string[]> {\n const files: string[] = [];\n const stack = [rootDir];\n\n while (stack.length > 0) {\n const dir = stack.pop();\n if (!dir) continue;\n\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n stack.push(fullPath);\n } else if (entry.isFile() && entry.name.endsWith(\".ts\")) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n}\n\nexport function resolveStaticAssetRoot(\n importUrl: string = import.meta.url,\n): string {\n const candidates = [\n fileURLToPath(new URL(\"../../scaffold/assets/static/\", importUrl)),\n fileURLToPath(new URL(\"./scaffold/assets/static/\", importUrl)),\n fileURLToPath(new URL(\"../scaffold/assets/static/\", importUrl)),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n throw new Error(\n `Unable to locate CLI static scaffold assets. Checked: ${candidates.join(\", \")}`,\n );\n}\n\nasync function getStaticAssetEntries(): Promise<StaticAssetEntry[]> {\n const files = await walkFiles(STATIC_ASSET_ROOT);\n const entries: StaticAssetEntry[] = [];\n\n for (const filePath of files) {\n const targetPath = normalizeOwnedProjectPath(\n path.relative(STATIC_ASSET_ROOT, filePath).replaceAll(path.sep, \"/\"),\n );\n if (targetPath === null) {\n throw new Error(`Unsafe static scaffold asset path: ${filePath}`);\n }\n entries.push({\n targetPath,\n content: await readFile(filePath, \"utf8\"),\n });\n }\n\n entries.sort((left, right) =>\n left.targetPath.localeCompare(right.targetPath),\n );\n return entries;\n}\n\nasync function getDynamicStaticEntries(\n projectRoot: string,\n mode: StaticScaffoldMode,\n options: StaticScaffoldOptions = {},\n): Promise<StaticAssetEntry[]> {\n const entries: StaticAssetEntry[] = [\n {\n targetPath: \"package.json\",\n content: await buildRootPackageJson(projectRoot, mode, options),\n },\n {\n targetPath: \"ui/package.json\",\n content: buildUiPackageJson(),\n },\n ];\n\n if (options.localMaintainerRegistry) {\n entries.push({\n targetPath: \".npmrc\",\n content: buildWorkspaceNpmrc(options.localMaintainerRegistry.registryUrl),\n });\n }\n\n return entries;\n}\n\nasync function getExpectedStaticEntries(\n projectRoot: string,\n): Promise<StaticAssetEntry[]> {\n const entries = [\n ...(await getStaticAssetEntries()).filter(\n (entry) => entry.targetPath !== \".npmrc\",\n ),\n ...(await getDynamicStaticEntries(projectRoot, \"update\")),\n ];\n entries.sort((left, right) =>\n left.targetPath.localeCompare(right.targetPath),\n );\n return entries;\n}\n\nasync function walkFiles(rootDir: string): Promise<string[]> {\n const files: string[] = [];\n const stack = [rootDir];\n\n while (stack.length > 0) {\n const currentDir = stack.pop();\n if (!currentDir) continue;\n\n const entries = await readdir(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n stack.push(fullPath);\n } else if (entry.isFile()) {\n files.push(fullPath);\n }\n }\n }\n\n files.sort((left, right) => left.localeCompare(right));\n return files;\n}\n\nasync function buildRootPackageJson(\n projectRoot: string,\n mode: StaticScaffoldMode,\n options: StaticScaffoldOptions,\n): Promise<string> {\n const sdkPackageRanges = {\n ...SDK_DEPENDENCY_RANGES,\n ...(options.localMaintainerRegistry?.packages ?? {}),\n };\n const existingPackageJson =\n mode === \"update\" &&\n (await workspacePathExists(projectRoot, \"package.json\"))\n ? (JSON.parse(\n await readWorkspaceTextFile(projectRoot, \"package.json\"),\n ) as RootPackageJsonShape)\n : null;\n const {\n dreamboardFrameworkVersion: _legacyFrameworkVersion,\n ...existingPackageJsonWithoutLegacyVersion\n } = existingPackageJson ?? {};\n const frameworkDependencies = {\n \"@dreamboard-games/sdk\":\n sdkPackageRanges[\"@dreamboard-games/sdk\"] ??\n SDK_DEPENDENCY_RANGES[\"@dreamboard-games/sdk\"],\n ...SHARED_DEPENDENCIES,\n ...ROOT_APP_DEPENDENCIES,\n };\n const frameworkDevDependencies = {\n ...SHARED_DEV_DEPENDENCIES,\n ...DEV_HOST_DEPENDENCY_RANGES,\n };\n const nextPackageJson: RootPackageJsonShape = {\n ...existingPackageJsonWithoutLegacyVersion,\n private: true,\n packageManager: AUTHORING_RELEASE_SET.packageManager,\n scripts: {\n ...(existingPackageJson?.scripts ?? {}),\n ...FRAMEWORK_SCRIPTS,\n },\n dependencies: {\n ...(existingPackageJson?.dependencies ?? {}),\n ...frameworkDependencies,\n },\n devDependencies: {\n ...(existingPackageJson?.devDependencies ?? {}),\n ...frameworkDevDependencies,\n },\n pnpm: mergePnpmConfig(existingPackageJson?.pnpm),\n };\n return `${JSON.stringify(nextPackageJson, null, 2)}\\n`;\n}\n\nfunction mergePnpmConfig(\n existingPnpm: Record<string, unknown> | undefined,\n): Record<string, unknown> {\n const existingOverrides =\n existingPnpm?.overrides &&\n typeof existingPnpm.overrides === \"object\" &&\n !Array.isArray(existingPnpm.overrides)\n ? (existingPnpm.overrides as Record<string, unknown>)\n : {};\n return {\n ...(existingPnpm ?? {}),\n overrides: {\n ...existingOverrides,\n ...FRAMEWORK_PNPM_OVERRIDES,\n ...DREAMBOARD_PACKAGE_OVERRIDES,\n },\n };\n}\n\nfunction buildWorkspaceNpmrc(registryUrl: string): string {\n return `@dreamboard-games:registry=${registryUrl}\\n`;\n}\n\nfunction buildUiPackageJson(): string {\n return `${JSON.stringify(\n {\n private: true,\n dependencies: SHARED_DEPENDENCIES,\n devDependencies: SHARED_DEV_DEPENDENCIES,\n },\n null,\n 2,\n )}\\n`;\n}\n\nfunction normalizeImportPath(relativePath: string): string {\n const normalized = relativePath.replaceAll(\"\\\\\", \"/\");\n if (normalized.startsWith(\".\")) return normalized;\n return `./${normalized}`;\n}\n\nfunction toWorkspaceProjectPath(projectRoot: string, filePath: string): string {\n const relativePath = path\n .relative(path.resolve(projectRoot), path.resolve(filePath))\n .replaceAll(path.sep, \"/\");\n const projectPath = normalizeOwnedProjectPath(relativePath);\n if (projectPath === null) {\n throw new Error(`Unsafe project path: ${relativePath}`);\n }\n return projectPath;\n}\n\nfunction summarizePaths(paths: readonly string[]): string {\n const maxShown = 5;\n const shown = paths.slice(0, maxShown).join(\", \");\n if (paths.length <= maxShown) return shown;\n return `${shown}, and ${paths.length - maxShown} more`;\n}\n","// Generated by scripts/generate-authoring-release-set.ts. Do not edit by hand.\nimport type { AuthoringReleaseSetV1 } from \"./authoring-release-set.js\";\n\nexport const AUTHORING_RELEASE_SET = {\n \"schemaVersion\": 1,\n \"channel\": \"public\",\n \"packages\": {\n \"cli\": {\n \"name\": \"@dreamboard-games/cli\",\n \"version\": \"0.1.30-alpha.31\"\n },\n \"sdk\": {\n \"name\": \"@dreamboard-games/sdk\",\n \"version\": \"0.4.0-alpha.6\"\n },\n \"apiClient\": {\n \"name\": \"@dreamboard-games/api-client\",\n \"version\": \"0.3.0-alpha.4\"\n },\n \"devHost\": {\n \"name\": \"@dreamboard-games/dev-host\",\n \"version\": \"0.1.30-alpha.19\"\n }\n },\n \"protocols\": {\n \"authoringAdapter\": 1,\n \"devHost\": 1,\n \"verifier\": 1\n },\n \"schemas\": {\n \"scaffold\": 2,\n \"manifest\": 2,\n \"generatedArtifacts\": 1\n },\n \"registry\": {\n \"kind\": \"public-npm\",\n \"portable\": true\n },\n \"packageManager\": \"pnpm@10.4.1\",\n \"releaseSetId\": \"sha256:d4c979aab04c28c64e3b2f069051eecd00b968ec67fcbe5a7b133ca370e24462\"\n} as const satisfies AuthoringReleaseSetV1;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/services/project-authoring/validation.ts
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { createHash } from "crypto";
|
|
6
|
+
|
|
7
|
+
// src/services/project-authoring/contract.ts
|
|
8
|
+
var ProjectAuthoringError = class extends Error {
|
|
9
|
+
code;
|
|
10
|
+
constructor(code, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "ProjectAuthoringError";
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/services/project-authoring/validation.ts
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
function isValidGeneratedPath(relativePath) {
|
|
22
|
+
if (relativePath.length === 0 || relativePath.startsWith("/") || relativePath.includes("\\")) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const normalized = path.posix.normalize(relativePath);
|
|
26
|
+
if (normalized !== relativePath) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return !relativePath.split("/").some((segment) => segment.length === 0 || segment === "." || segment === "..");
|
|
30
|
+
}
|
|
31
|
+
var ALLOWED_GENERATED_PREFIXES = [
|
|
32
|
+
"app/",
|
|
33
|
+
"shared/",
|
|
34
|
+
"test/generated/",
|
|
35
|
+
"ui/"
|
|
36
|
+
];
|
|
37
|
+
function isAllowedGeneratedPath(relativePath) {
|
|
38
|
+
return ALLOWED_GENERATED_PREFIXES.some(
|
|
39
|
+
(prefix) => relativePath.startsWith(prefix)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function assertGeneratedPath(pathValue, label) {
|
|
43
|
+
if (typeof pathValue !== "string" || !isValidGeneratedPath(pathValue) || !isAllowedGeneratedPath(pathValue)) {
|
|
44
|
+
throw new ProjectAuthoringError(
|
|
45
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
46
|
+
`${label} must be a normalized relative workspace path.`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return pathValue;
|
|
50
|
+
}
|
|
51
|
+
function assertGeneratedArtifact(value) {
|
|
52
|
+
if (!isRecord(value)) {
|
|
53
|
+
throw new ProjectAuthoringError(
|
|
54
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
55
|
+
"Generated artifact must be an object."
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const artifactPath = assertGeneratedPath(value.path, "Generated artifact path");
|
|
59
|
+
if (value.ownership !== "authoritative" && value.ownership !== "seed" && value.ownership !== "derived-test") {
|
|
60
|
+
throw new ProjectAuthoringError(
|
|
61
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
62
|
+
`Generated artifact '${artifactPath}' has invalid ownership.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (typeof value.content !== "string") {
|
|
66
|
+
throw new ProjectAuthoringError(
|
|
67
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
68
|
+
`Generated artifact '${artifactPath}' content must be a string.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const expectedHash = createHash("sha256").update(value.content).digest("hex");
|
|
72
|
+
if (value.contentSha256 !== expectedHash) {
|
|
73
|
+
throw new ProjectAuthoringError(
|
|
74
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
75
|
+
`Generated artifact '${artifactPath}' has a stale content hash.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
function validateProjectAuthoringAdapter(adapter) {
|
|
81
|
+
if (!isRecord(adapter)) {
|
|
82
|
+
throw new ProjectAuthoringError(
|
|
83
|
+
"AUTHORING_PROTOCOL_UNSUPPORTED",
|
|
84
|
+
"SDK authoring export did not provide an adapter object."
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
if (adapter.protocolVersion !== 1) {
|
|
88
|
+
throw new ProjectAuthoringError(
|
|
89
|
+
"AUTHORING_PROTOCOL_UNSUPPORTED",
|
|
90
|
+
`Unsupported SDK authoring protocol '${String(adapter.protocolVersion)}'.`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (!isRecord(adapter.metadata)) {
|
|
94
|
+
throw new ProjectAuthoringError(
|
|
95
|
+
"AUTHORING_PROTOCOL_UNSUPPORTED",
|
|
96
|
+
"SDK authoring adapter metadata is missing."
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
for (const key of [
|
|
100
|
+
"sdkVersion",
|
|
101
|
+
"codegenVersion",
|
|
102
|
+
"manifestSchemaVersion",
|
|
103
|
+
"generatedArtifactSchemaVersion"
|
|
104
|
+
]) {
|
|
105
|
+
if (adapter.metadata[key] === void 0 || key.endsWith("Version") && typeof adapter.metadata[key] !== "string" && typeof adapter.metadata[key] !== "number") {
|
|
106
|
+
throw new ProjectAuthoringError(
|
|
107
|
+
"AUTHORING_PROTOCOL_UNSUPPORTED",
|
|
108
|
+
`SDK authoring adapter metadata '${key}' is missing.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const method of [
|
|
113
|
+
"validateManifest",
|
|
114
|
+
"materializeManifest",
|
|
115
|
+
"generateWorkspaceArtifacts",
|
|
116
|
+
"generateTestArtifacts"
|
|
117
|
+
]) {
|
|
118
|
+
if (typeof adapter[method] !== "function") {
|
|
119
|
+
throw new ProjectAuthoringError(
|
|
120
|
+
"AUTHORING_PROTOCOL_UNSUPPORTED",
|
|
121
|
+
`SDK authoring adapter method '${method}' is missing.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (!Array.isArray(adapter.generatedPaths)) {
|
|
126
|
+
throw new ProjectAuthoringError(
|
|
127
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
128
|
+
"SDK authoring adapter generatedPaths must be an array."
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
const seen = /* @__PURE__ */ new Set();
|
|
132
|
+
for (const [index, generatedPath] of adapter.generatedPaths.entries()) {
|
|
133
|
+
const normalized = assertGeneratedPath(
|
|
134
|
+
generatedPath,
|
|
135
|
+
`generatedPaths[${index}]`
|
|
136
|
+
);
|
|
137
|
+
if (seen.has(normalized)) {
|
|
138
|
+
throw new ProjectAuthoringError(
|
|
139
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
140
|
+
`Generated path '${normalized}' is declared more than once.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
seen.add(normalized);
|
|
144
|
+
}
|
|
145
|
+
if (adapter.generatedPathPatterns !== void 0 && !Array.isArray(adapter.generatedPathPatterns)) {
|
|
146
|
+
throw new ProjectAuthoringError(
|
|
147
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
148
|
+
"SDK authoring adapter generatedPathPatterns must be an array."
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
for (const [index, pattern] of (adapter.generatedPathPatterns ?? []).entries()) {
|
|
152
|
+
if (!isRecord(pattern) || typeof pattern.prefix !== "string" || typeof pattern.suffix !== "string" || !isValidGeneratedPath(`${pattern.prefix}placeholder${pattern.suffix}`) || !isAllowedGeneratedPath(`${pattern.prefix}placeholder${pattern.suffix}`)) {
|
|
153
|
+
throw new ProjectAuthoringError(
|
|
154
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
155
|
+
`generatedPathPatterns[${index}] must describe a normalized allowlisted workspace path.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return adapter;
|
|
160
|
+
}
|
|
161
|
+
function validateGeneratedArtifacts(adapter, artifacts) {
|
|
162
|
+
const seen = /* @__PURE__ */ new Set();
|
|
163
|
+
const validated = artifacts.map(assertGeneratedArtifact);
|
|
164
|
+
for (const artifact of validated) {
|
|
165
|
+
if (seen.has(artifact.path)) {
|
|
166
|
+
throw new ProjectAuthoringError(
|
|
167
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
168
|
+
`Generated artifact path '${artifact.path}' was emitted more than once.`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
const declared = adapter.generatedPaths.includes(artifact.path) || (adapter.generatedPathPatterns ?? []).some(
|
|
172
|
+
(pattern) => artifact.path.startsWith(pattern.prefix) && artifact.path.endsWith(pattern.suffix) && artifact.path.length > pattern.prefix.length + pattern.suffix.length
|
|
173
|
+
);
|
|
174
|
+
if (!declared) {
|
|
175
|
+
throw new ProjectAuthoringError(
|
|
176
|
+
"GENERATED_PATH_CONTRACT_INVALID",
|
|
177
|
+
`Generated artifact path '${artifact.path}' is not declared by the SDK authoring adapter.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
seen.add(artifact.path);
|
|
181
|
+
}
|
|
182
|
+
return validated;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/services/project-authoring/loader.ts
|
|
186
|
+
import { readFile } from "fs/promises";
|
|
187
|
+
import path2 from "path";
|
|
188
|
+
import { createRequire } from "module";
|
|
189
|
+
import { setTimeout as delay } from "timers/promises";
|
|
190
|
+
import { pathToFileURL } from "url";
|
|
191
|
+
var PROJECT_SDK_RESOLUTION_RETRY_DELAYS_MS = [50, 150, 300];
|
|
192
|
+
function problemFromResolveError(error) {
|
|
193
|
+
if (error instanceof ProjectAuthoringError) {
|
|
194
|
+
return error;
|
|
195
|
+
}
|
|
196
|
+
const code = error?.code === "ERR_PACKAGE_PATH_NOT_EXPORTED" ? "AUTHORING_ADAPTER_NOT_EXPORTED" : "SDK_NOT_INSTALLED";
|
|
197
|
+
return new ProjectAuthoringError(
|
|
198
|
+
code,
|
|
199
|
+
code === "AUTHORING_ADAPTER_NOT_EXPORTED" ? "Installed @dreamboard-games/sdk does not export @dreamboard-games/sdk/authoring." : "Install @dreamboard-games/sdk in this workspace before running authoring commands."
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
function assertResolvedInsidePackage(options) {
|
|
203
|
+
const packageRoot = path2.resolve(options.packageRoot);
|
|
204
|
+
const resolvedPath = path2.resolve(options.resolvedPath);
|
|
205
|
+
const relative = path2.relative(packageRoot, resolvedPath);
|
|
206
|
+
if (relative.startsWith("..") || path2.isAbsolute(relative)) {
|
|
207
|
+
throw new ProjectAuthoringError(
|
|
208
|
+
"AUTHORING_ADAPTER_NOT_EXPORTED",
|
|
209
|
+
`${options.label} resolved outside the installed @dreamboard-games/sdk package.`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function isRecord2(value) {
|
|
214
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
215
|
+
}
|
|
216
|
+
function resolveExportTarget(value) {
|
|
217
|
+
if (typeof value === "string") {
|
|
218
|
+
return value;
|
|
219
|
+
}
|
|
220
|
+
if (!isRecord2(value)) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
for (const condition of ["import", "default"]) {
|
|
224
|
+
const resolved = resolveExportTarget(value[condition]);
|
|
225
|
+
if (resolved) {
|
|
226
|
+
return resolved;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
async function resolveDirectProjectAuthoringAdapter(projectRoot) {
|
|
232
|
+
const packageRoot = path2.join(
|
|
233
|
+
projectRoot,
|
|
234
|
+
"node_modules",
|
|
235
|
+
"@dreamboard-games",
|
|
236
|
+
"sdk"
|
|
237
|
+
);
|
|
238
|
+
const packageJsonPath = path2.join(packageRoot, "package.json");
|
|
239
|
+
let packageJson;
|
|
240
|
+
try {
|
|
241
|
+
packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const authoringExport = isRecord2(packageJson.exports) ? resolveExportTarget(packageJson.exports["./authoring"]) : null;
|
|
246
|
+
if (!authoringExport) {
|
|
247
|
+
throw new ProjectAuthoringError(
|
|
248
|
+
"AUTHORING_ADAPTER_NOT_EXPORTED",
|
|
249
|
+
"Installed @dreamboard-games/sdk does not export @dreamboard-games/sdk/authoring."
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
const adapterPath = path2.resolve(packageRoot, authoringExport);
|
|
253
|
+
assertResolvedInsidePackage({
|
|
254
|
+
packageRoot,
|
|
255
|
+
resolvedPath: adapterPath,
|
|
256
|
+
label: "@dreamboard-games/sdk/authoring"
|
|
257
|
+
});
|
|
258
|
+
return { packageJsonPath, adapterPath };
|
|
259
|
+
}
|
|
260
|
+
async function resolveProjectAuthoringAdapter(projectRoot) {
|
|
261
|
+
const requireFromProject = createRequire(path2.join(projectRoot, "package.json"));
|
|
262
|
+
let lastError;
|
|
263
|
+
for (let attempt = 0; attempt <= PROJECT_SDK_RESOLUTION_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
264
|
+
try {
|
|
265
|
+
const packageJsonPath = requireFromProject.resolve(
|
|
266
|
+
"@dreamboard-games/sdk/package.json"
|
|
267
|
+
);
|
|
268
|
+
const adapterPath = requireFromProject.resolve(
|
|
269
|
+
"@dreamboard-games/sdk/authoring"
|
|
270
|
+
);
|
|
271
|
+
return { packageJsonPath, adapterPath };
|
|
272
|
+
} catch (error) {
|
|
273
|
+
lastError = error;
|
|
274
|
+
if (error?.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
277
|
+
const directResolved = await resolveDirectProjectAuthoringAdapter(projectRoot);
|
|
278
|
+
if (directResolved) {
|
|
279
|
+
return directResolved;
|
|
280
|
+
}
|
|
281
|
+
const retryDelay = PROJECT_SDK_RESOLUTION_RETRY_DELAYS_MS[attempt];
|
|
282
|
+
if (retryDelay === void 0) {
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
await delay(retryDelay);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
throw lastError;
|
|
289
|
+
}
|
|
290
|
+
async function loadProjectAuthoringAdapter(projectRoot) {
|
|
291
|
+
let packageJsonPath;
|
|
292
|
+
let adapterPath;
|
|
293
|
+
try {
|
|
294
|
+
({ packageJsonPath, adapterPath } = await resolveProjectAuthoringAdapter(projectRoot));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
throw problemFromResolveError(error);
|
|
297
|
+
}
|
|
298
|
+
const packageRoot = path2.dirname(packageJsonPath);
|
|
299
|
+
assertResolvedInsidePackage({
|
|
300
|
+
packageRoot,
|
|
301
|
+
resolvedPath: adapterPath,
|
|
302
|
+
label: "@dreamboard-games/sdk/authoring"
|
|
303
|
+
});
|
|
304
|
+
const packageJson = JSON.parse(
|
|
305
|
+
await readFile(packageJsonPath, "utf8")
|
|
306
|
+
);
|
|
307
|
+
if (packageJson.name !== "@dreamboard-games/sdk" || typeof packageJson.version !== "string" || packageJson.version.trim().length === 0) {
|
|
308
|
+
throw new ProjectAuthoringError(
|
|
309
|
+
"SDK_METADATA_MISMATCH",
|
|
310
|
+
"Installed SDK package metadata is invalid."
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const moduleRecord = await import(pathToFileURL(adapterPath).href);
|
|
314
|
+
const adapter = validateProjectAuthoringAdapter(
|
|
315
|
+
moduleRecord.projectAuthoringAdapter ?? moduleRecord.default
|
|
316
|
+
);
|
|
317
|
+
if (adapter.metadata.sdkVersion !== packageJson.version) {
|
|
318
|
+
throw new ProjectAuthoringError(
|
|
319
|
+
"SDK_METADATA_MISMATCH",
|
|
320
|
+
`SDK authoring adapter reports version ${adapter.metadata.sdkVersion}, but package metadata is ${packageJson.version}.`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
packageRoot,
|
|
325
|
+
packageVersion: packageJson.version,
|
|
326
|
+
adapterPath,
|
|
327
|
+
adapter
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/services/project/workspace-path.ts
|
|
332
|
+
import {
|
|
333
|
+
mkdir,
|
|
334
|
+
readFile as readFile2,
|
|
335
|
+
realpath,
|
|
336
|
+
rm,
|
|
337
|
+
stat,
|
|
338
|
+
unlink,
|
|
339
|
+
writeFile
|
|
340
|
+
} from "fs/promises";
|
|
341
|
+
import path3 from "path";
|
|
342
|
+
var CONTROL_CHARS = /[\x00-\x1f\x7f]/;
|
|
343
|
+
var URL_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
344
|
+
var WINDOWS_DEVICE_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/i;
|
|
345
|
+
var ENCODED_SEPARATOR = /%(?:2f|5c)/i;
|
|
346
|
+
function isWindowsDeviceSegment(segment) {
|
|
347
|
+
return WINDOWS_DEVICE_NAME.test(segment.replace(/[. ]+$/g, ""));
|
|
348
|
+
}
|
|
349
|
+
function isPathInside(parent, candidate) {
|
|
350
|
+
const relative = path3.relative(parent, candidate);
|
|
351
|
+
return relative === "" || !relative.startsWith("..") && !path3.isAbsolute(relative);
|
|
352
|
+
}
|
|
353
|
+
function assertContained(parent, candidate, label) {
|
|
354
|
+
if (!isPathInside(parent, candidate)) {
|
|
355
|
+
throw new Error(`${label} escapes the workspace.`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function isMissingFileError(error) {
|
|
359
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
360
|
+
}
|
|
361
|
+
function normalizeOwnedProjectPath(input) {
|
|
362
|
+
if (input.length === 0 || input.trim().length === 0 || input.startsWith("/") || input.includes("\\") || input.includes(":") || URL_SCHEME.test(input) || CONTROL_CHARS.test(input) || ENCODED_SEPARATOR.test(input) || path3.win32.isAbsolute(input)) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
const segments = input.split("/");
|
|
366
|
+
if (segments.some(
|
|
367
|
+
(segment) => segment.length === 0 || segment.trim().length === 0 || segment === "." || segment === ".." || isWindowsDeviceSegment(segment)
|
|
368
|
+
)) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
return segments.join("/");
|
|
372
|
+
}
|
|
373
|
+
function resolveWorkspacePath(rootDir, projectPath) {
|
|
374
|
+
const normalized = normalizeOwnedProjectPath(projectPath);
|
|
375
|
+
if (normalized === null) {
|
|
376
|
+
throw new Error(`Unsafe project path: ${projectPath}`);
|
|
377
|
+
}
|
|
378
|
+
const rootPath = path3.resolve(rootDir);
|
|
379
|
+
const resolvedPath = path3.resolve(rootPath, normalized);
|
|
380
|
+
assertContained(rootPath, resolvedPath, `Project path ${projectPath}`);
|
|
381
|
+
return resolvedPath;
|
|
382
|
+
}
|
|
383
|
+
async function realpathIfExists(filePath) {
|
|
384
|
+
try {
|
|
385
|
+
return await realpath(filePath);
|
|
386
|
+
} catch (error) {
|
|
387
|
+
if (isMissingFileError(error)) return null;
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function nearestExistingAncestor(filePath) {
|
|
392
|
+
let current = filePath;
|
|
393
|
+
while (true) {
|
|
394
|
+
try {
|
|
395
|
+
await stat(current);
|
|
396
|
+
return current;
|
|
397
|
+
} catch (error) {
|
|
398
|
+
if (!isMissingFileError(error)) throw error;
|
|
399
|
+
const parent = path3.dirname(current);
|
|
400
|
+
if (parent === current) throw error;
|
|
401
|
+
current = parent;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async function assertRealpathContained(rootDir, filePath, label) {
|
|
406
|
+
const rootRealpath = await realpath(rootDir);
|
|
407
|
+
const targetRealpath = await realpath(filePath);
|
|
408
|
+
assertContained(rootRealpath, targetRealpath, label);
|
|
409
|
+
}
|
|
410
|
+
async function assertNearestParentContained(rootDir, filePath, label) {
|
|
411
|
+
const rootRealpath = await realpath(rootDir);
|
|
412
|
+
const nearestParent = await nearestExistingAncestor(path3.dirname(filePath));
|
|
413
|
+
const nearestParentRealpath = await realpath(nearestParent);
|
|
414
|
+
assertContained(rootRealpath, nearestParentRealpath, label);
|
|
415
|
+
}
|
|
416
|
+
async function assertExistingTargetContained(rootDir, filePath, label) {
|
|
417
|
+
const targetRealpath = await realpathIfExists(filePath);
|
|
418
|
+
if (targetRealpath === null) return;
|
|
419
|
+
const rootRealpath = await realpath(rootDir);
|
|
420
|
+
assertContained(rootRealpath, targetRealpath, label);
|
|
421
|
+
}
|
|
422
|
+
async function prepareWorkspaceWriteTarget(rootDir, filePath) {
|
|
423
|
+
await assertNearestParentContained(rootDir, filePath, "Project path");
|
|
424
|
+
await mkdir(path3.dirname(filePath), { recursive: true });
|
|
425
|
+
await assertRealpathContained(
|
|
426
|
+
rootDir,
|
|
427
|
+
path3.dirname(filePath),
|
|
428
|
+
"Project path"
|
|
429
|
+
);
|
|
430
|
+
await assertExistingTargetContained(rootDir, filePath, "Project path");
|
|
431
|
+
}
|
|
432
|
+
async function readWorkspaceTextFile(rootDir, projectPath) {
|
|
433
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
434
|
+
await assertExistingTargetContained(rootDir, filePath, "Project path");
|
|
435
|
+
return readFile2(filePath, "utf8");
|
|
436
|
+
}
|
|
437
|
+
async function readWorkspaceTextFileIfExists(rootDir, projectPath) {
|
|
438
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
439
|
+
const targetRealpath = await realpathIfExists(filePath);
|
|
440
|
+
if (targetRealpath === null) return null;
|
|
441
|
+
const rootRealpath = await realpath(rootDir);
|
|
442
|
+
assertContained(rootRealpath, targetRealpath, "Project path");
|
|
443
|
+
return readFile2(filePath, "utf8");
|
|
444
|
+
}
|
|
445
|
+
async function writeWorkspaceTextFile(rootDir, projectPath, content) {
|
|
446
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
447
|
+
await prepareWorkspaceWriteTarget(rootDir, filePath);
|
|
448
|
+
await writeFile(filePath, content, "utf8");
|
|
449
|
+
}
|
|
450
|
+
async function writeWorkspaceJsonFile(rootDir, projectPath, data) {
|
|
451
|
+
await writeWorkspaceTextFile(
|
|
452
|
+
rootDir,
|
|
453
|
+
projectPath,
|
|
454
|
+
`${JSON.stringify(data, null, 2)}
|
|
455
|
+
`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
async function workspacePathExists(rootDir, projectPath) {
|
|
459
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
460
|
+
const targetRealpath = await realpathIfExists(filePath);
|
|
461
|
+
if (targetRealpath === null) return false;
|
|
462
|
+
const rootRealpath = await realpath(rootDir);
|
|
463
|
+
assertContained(rootRealpath, targetRealpath, "Project path");
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
async function unlinkWorkspaceFile(rootDir, projectPath) {
|
|
467
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
468
|
+
await assertNearestParentContained(rootDir, filePath, "Project path");
|
|
469
|
+
await assertExistingTargetContained(rootDir, filePath, "Project path");
|
|
470
|
+
await unlink(filePath);
|
|
471
|
+
}
|
|
472
|
+
async function removeWorkspacePath(rootDir, projectPath, options = {}) {
|
|
473
|
+
const filePath = resolveWorkspacePath(rootDir, projectPath);
|
|
474
|
+
await assertNearestParentContained(rootDir, filePath, "Project path");
|
|
475
|
+
await assertExistingTargetContained(rootDir, filePath, "Project path");
|
|
476
|
+
await rm(filePath, options);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export {
|
|
480
|
+
validateGeneratedArtifacts,
|
|
481
|
+
loadProjectAuthoringAdapter,
|
|
482
|
+
normalizeOwnedProjectPath,
|
|
483
|
+
resolveWorkspacePath,
|
|
484
|
+
readWorkspaceTextFile,
|
|
485
|
+
readWorkspaceTextFileIfExists,
|
|
486
|
+
writeWorkspaceTextFile,
|
|
487
|
+
writeWorkspaceJsonFile,
|
|
488
|
+
workspacePathExists,
|
|
489
|
+
unlinkWorkspaceFile,
|
|
490
|
+
removeWorkspacePath
|
|
491
|
+
};
|
|
492
|
+
//# sourceMappingURL=chunk-OJFZVGEL.mjs.map
|