@sfmc-bds/bds-tools 0.2.0-beta.0 → 0.2.0-beta.1

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/pack-manager.ts"],
4
- "sourcesContent": ["/**\n * pack-manager.ts \u2014 Bedrock \u884C\u4E3A\u5305/\u8D44\u6E90\u5305 \u88C5\u914D + \u90E8\u7F72\u5230 BDS \u6839\u3002\n *\n * \u7EAF\u51FD\u6570\u5E93,\u4E24\u6761\u6D88\u8D39\u8DEF\u5F84:\n *\n * - \u540C\u8FDB\u7A0B(\u63A8\u8350): sfmc/pack-lifecycle \u7ECF `@sfmc-bds/bds-tools/pack-manager-lib`\n * \u76F4\u8FDE\u672C\u6A21\u5757\uFF08DIP\uFF09\uFF1Bworld-packs \u7B49\u540C\u7406\u3002\n * - CLI: `cli-pack-manager.js` \u4ECD\u66B4\u9732\u76F8\u540C\u52A8\u8BCD\uFF0C\u4F9B\u5916\u90E8\u811A\u672C/\u624B\u5DE5\u8C03\u8BD5\uFF1B\n * CLI \u53EA\u662F\u672C\u5E93\u7684\u8584\u9002\u914D\uFF0C\u4E0D\u518D\u662F sfmc \u4E3B\u8DEF\u5F84\u3002\n *\n * \u7EA6\u675F:\u672C\u6587\u4EF6\u4E0D\u5F15\u5165 esbuild / \u91CD\u578B npm-only \u5305\uFF0C\u4FDD\u6301\u53EF\u88AB Node \u5B50\u8FDB\u7A0B\u76F4\u63A5\u52A0\u8F7D\u3002\n *\n * \u5DF2\u6709\u4F9D\u8D56 (bds-tools/package.json):\n * - @sfmc-bds/sdk/logs createTerminalProgress: \u8FDB\u5EA6\u6761\uFF08BDS \u66F4\u65B0\u7B49\uFF09\n * - node-html-parser: changelog \u6293\u53D6 (\u672C\u6587\u4EF6\u7528\u4E0D\u5230)\n * - jszip: zip \u89E3\u538B(\u6A21\u5757 zip / BDS server.zip)\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { copyDirAsync, copyFileAsync } from \"./fsx.js\";\n\n/* \u2500\u2500 \u7C7B\u578B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface AssembleBehaviorPackOpts {\n /** Where the bundled scripts/main.js already exists (esbuild output dir) */\n srcDir: string;\n /** Output behavior pack directory (created if missing) */\n outDir: string;\n /** BP \u76EE\u5F55\u540D \u2014 \u9ED8\u8BA4 'sfmc-modules' */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** pack_icon.png \u6E90\u6587\u4EF6 (optional, \u4E0D\u63D0\u4F9B\u5219\u8DF3\u8FC7) */\n iconSrc?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A script module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResourcePackOpts {\n /** Modules whose resource_pack/** should be merged. Map<moduleId, resourcePackDir>. */\n moduleResourceDirs: Record<string, string>;\n /** Output resource pack directory (created if missing) */\n outDir: string;\n /** RP \u76EE\u5F55\u540D */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A resources module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResult {\n uuid: string;\n version: [number, number, number];\n}\n\nexport interface DeployOpts {\n bdsRoot: string;\n levelName: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 BP \u6E90\u76EE\u5F55 */\n behaviorPackSrc: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 RP \u6E90\u76EE\u5F55 (\u53EF\u7701\u7565,\u53EA\u7528 BP \u4E5F\u5408\u6CD5) */\n resourcePackSrc?: string;\n /** BP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/behavior_packs/<bpName>) */\n bpName: string;\n /** RP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/resource_packs/<rpName>);\u7701\u7565\u65F6\u590D\u7528 bpName + '-rp' */\n rpName?: string;\n /**\n * \u65E0 resourcePackSrc \u65F6\u662F\u5426\u5220\u9664\u4E16\u754C\u5185\u5DF2\u6709 RP \u76EE\u5F55\u3002\n * \u7528\u4E8E\u6A21\u5757\u4E0D\u518D\u63D0\u4F9B RP \u65F6\u6E05\u7406\u805A\u5408\u5305\u6B8B\u7559(\u9ED8\u8BA4 false,\u907F\u514D\u8BEF\u5220\u672A\u58F0\u660E\u7684 RP)\u3002\n */\n clearResourcePack?: boolean;\n}\n\nexport interface DeployResult {\n bpDir: string;\n rpDir: string | null;\n}\n\nexport interface EnablePackOpts {\n worldsDir: string;\n levelName: string;\n kind: \"behavior\" | \"resource\";\n packUuid: string;\n version: [number, number, number];\n}\n\n/* \u2500\u2500 \u8DEF\u5F84\u5E38\u91CF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** SFMC \u5408\u6210 BP \u7684\u56FA\u5B9A @minecraft/* permissions,\u6240\u6709\u7528\u5230\u7684\u547D\u540D\u7A7A\u95F4\u90FD\u6253\u5F00\u3002 */\nexport const SFMC_PERMISSIONS = [\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-net\",\n \"@minecraft/server-editor\",\n \"@minecraft/diagnostics\",\n] as const;\n\n/** `<bdsRoot>/server.properties` \u2014 level-name / telemetry \u7B49\u5171\u7528\uFF08DRY\uFF09 */\nexport function serverPropertiesPath(bdsRoot: string): string {\n return path.join(bdsRoot, \"server.properties\");\n}\n\n/** `<bdsRoot>/worlds` \u2014 enable-list / \u90E8\u7F72\u8C03\u7528\u65B9\u52FF\u518D\u786C\u62FC\uFF08Demeter\uFF09 */\nexport function bdsWorldsDir(bdsRoot: string): string {\n return path.join(bdsRoot, \"worlds\");\n}\n\n/** `<bdsRoot>/worlds/<level>` */\nexport function bdsWorldLevelDir(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldsDir(bdsRoot), levelName);\n}\n\n/** \u4E16\u754C enable-list JSON \u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5355\u4E00\u6743\u5A01\uFF0C\u4F9B\u8BFB\u5199\u4E24\u4FA7\uFF09 */\nexport function worldPackListFile(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): string {\n const name = kind === \"behavior\" ? \"world_behavior_packs.json\" : \"world_resource_packs.json\";\n return path.join(worldsDir, levelName, name);\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permission.json` \u2014 Script API \u6743\u9650\u6587\u4EF6\u6743\u5A01\u8DEF\u5F84 */\nexport function configPermissionPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permission.json\");\n}\n\n/** \u662F\u5426\u5DF2\u6709 Script API permission.json\uFF08\u53EA\u8BFB\uFF0C\u4F9B preflight/status\uFF09 */\nexport function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean {\n return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));\n}\n\n/** \u968F\u673A\u751F\u6210 BP/RP manifest.json header.uuid (RFC 4122 v4) */\nexport function randomUuid(): string {\n /* crypto.randomUUID \u662F Node 19+ \u5185\u7F6E,\u8FD9\u91CC\u76F4\u63A5\u7528 */\n return crypto.randomUUID();\n}\n\n/* \u2500\u2500 \u9AA8\u67B6\u51FD\u6570 (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt\n * `srcDir` (which must already contain `scripts/main.js` plus whatever else\n * was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.\n *\n * The caller is responsible for running esbuild first; pack-manager does not\n * bundle scripts. That decoupling keeps pack assembly independent of the bundler.\n */\nexport async function assembleBehaviorPack(opts: AssembleBehaviorPackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const bpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n if (fs.existsSync(opts.srcDir)) {\n await copyDirAsync(opts.srcDir, opts.outDir);\n } else {\n await fs.promises.mkdir(path.join(opts.outDir, \"scripts\"), { recursive: true });\n await fs.promises.writeFile(path.join(opts.outDir, \"scripts\", \"main.js\"), \"/* no scripts */\\n\", \"utf8\");\n }\n await writeBehaviorPackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: bpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {\n await copyFileAsync(opts.iconSrc, path.join(opts.outDir, \"pack_icon.png\"));\n }\n await writePermissionsJson(opts.outDir);\n return { uuid: bpUuid, version };\n}\n\n/**\n * Merge every enabled module's `resource_pack/**` tree into one RP directory\n * at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are\n * preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).\n */\nexport async function assembleResourcePack(opts: AssembleResourcePackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const rpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {\n if (!fs.existsSync(rpDir)) continue;\n const dst = path.join(opts.outDir, moduleId);\n await fs.promises.mkdir(dst, { recursive: true });\n await copyDirAsync(rpDir, dst);\n }\n await writeResourcePackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: rpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n return { uuid: rpUuid, version };\n}\n\n/**\n * Read the `level-name=` value from `<bdsRoot>/server.properties`.\n * Falls back to \"Bedrock level\" (BDS default) when the file is missing or\n * the key is absent.\n */\nfunction parseLevelNameFromProperties(text: string): string {\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*level-name\\s*=\\s*(.+?)\\s*$/.exec(line);\n if (m && m[1]) return m[1];\n }\n return \"Bedrock level\";\n}\n\n/** \u540C\u6B65\u8BFB level-name\uFF08\u4F9B sfmc resolveBdsContext \u7B49\u540C\u8FDB\u7A0B\u8C03\u7528\u65B9\uFF0CDRY\uFF09\u3002 */\nexport function readLevelNameSync(bdsRoot: string): string {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return \"Bedrock level\";\n return parseLevelNameFromProperties(fs.readFileSync(file, \"utf8\"));\n}\n\n/** \u4E0E sync \u540C\u5951\u7EA6\uFF1BCLI / async \u8C03\u7528\u65B9\u8D70\u6B64\u5165\u53E3\uFF08LSP\uFF09 */\nexport async function readLevelName(bdsRoot: string): Promise<string> {\n return readLevelNameSync(bdsRoot);\n}\n\n/**\n * Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/\n * folders, and write a fresh `permissions.json` into the BP target.\n *\n * Does NOT edit world_behavior_packs.json \u2014 that's a separate step the caller\n * must invoke after restart, because BDS only reads that file at startup.\n */\nexport async function deployToBDS(opts: DeployOpts): Promise<DeployResult> {\n /* levelDir = worlds/<level>\uFF1B\u4E0E EnablePackOpts.worldsDir(=worlds/) \u8BED\u4E49\u4E0D\u540C \u2014 \u52FF\u6DF7\u7528\uFF08LSP\uFF09 */\n const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);\n const bpDst = path.join(levelDir, \"behavior_packs\", opts.bpName);\n const rpDst = path.join(levelDir, \"resource_packs\", opts.rpName ?? `${opts.bpName}-rp`);\n await fs.promises.mkdir(levelDir, { recursive: true });\n await fs.promises.rm(bpDst, { recursive: true, force: true });\n await copyDirAsync(opts.behaviorPackSrc, bpDst);\n await writePermissionsJson(bpDst);\n let rpDir: string | null = null;\n if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n await copyDirAsync(opts.resourcePackSrc, rpDst);\n rpDir = rpDst;\n } else if (opts.clearResourcePack) {\n /* \u8C03\u7528\u65B9\u663E\u5F0F\u58F0\u660E\u4E0D\u518D\u90E8\u7F72 RP \u2014 \u6E05\u6389\u805A\u5408 RP \u76EE\u5F55\u6B8B\u7559 */\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n }\n return { bpDir: bpDst, rpDir };\n}\n\n/**\n * \u786E\u4FDD BDS Script API \u4FA7 `<bdsRoot>/config/<bpUuid>/permission.json` \u5B58\u5728\u3002\n * \u5DF2\u5B58\u5728\u5219\u8DF3\u8FC7(\u4E0D\u8986\u76D6\u7528\u6237\u624B\u5DE5\u6539\u52A8)\u3002\n * @returns true = \u65B0\u5199\u5165; false = \u5DF2\u5B58\u5728\u8DF3\u8FC7\n */\nexport async function ensureConfigPermission(bdsRoot: string, bpUuid: string): Promise<boolean> {\n const file = configPermissionPath(bdsRoot, bpUuid);\n if (fs.existsSync(file)) return false;\n const dir = path.dirname(file);\n await fs.promises.mkdir(dir, { recursive: true });\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n const tmp = path.join(dir, `.permission.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n return true;\n}\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 header.uuid + version;\u5931\u8D25\u8FD4\u56DE null\u3002 */\nexport function readPackManifestHeader(\n packDir: string\n): { uuid: string; version: [number, number, number]; moduleUuid?: string } | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = JSON.parse(fs.readFileSync(file, \"utf8\")) as {\n header?: { uuid?: string; version?: number[] };\n modules?: Array<{ uuid?: string }>;\n };\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n if (typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const moduleUuid = raw.modules?.[0]?.uuid;\n return { uuid, version, ...(typeof moduleUuid === \"string\" ? { moduleUuid } : {}) };\n } catch {\n return null;\n }\n}\n\n/**\n * Write the seven `@minecraft/*` allowed_modules into a behavior pack's\n * `permissions.json`. Idempotent: rewrites any pre-existing file.\n */\nexport async function writePermissionsJson(bpDir: string): Promise<void> {\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n await fs.promises.mkdir(bpDir, { recursive: true });\n const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, path.join(bpDir, \"permissions.json\"));\n}\n\n/**\n * Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`\n * (or `world_resource_packs.json`). If the pack_id already exists, replace its\n * version. File missing \u2192 initialize as `[]`.\n */\nexport async function enablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"enable\");\n}\n\n/** Remove a pack_id from the world's enable-list JSON. */\nexport async function disablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"disable\");\n}\n\ninterface WorldPackEntry {\n pack_id: string;\n version: [number, number, number];\n}\n\nasync function editWorldPackList(\n opts: EnablePackOpts,\n mode: \"enable\" | \"disable\"\n): Promise<void> {\n const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);\n /* \u4E0E readWorldPackList \u540C\u6E90\u89E3\u6790,\u518D\u5199\u56DE(DRY);\u5F02\u6B65\u5199\u8DEF\u5F84\u4FDD\u7559\u539F\u8BED\u4E49 */\n let entries: WorldPackEntry[] = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);\n const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);\n if (mode === \"enable\") {\n const next: WorldPackEntry = { pack_id: opts.packUuid, version: opts.version };\n if (idx >= 0) entries[idx] = next;\n else entries.push(next);\n } else {\n if (idx >= 0) entries.splice(idx, 1);\n }\n await fs.promises.mkdir(path.dirname(file), { recursive: true });\n const tmp = `${file}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n}\n\n/* \u2500\u2500 \u4F4E\u5C42 helpers (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport async function writeBehaviorPackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (behavior pack)` : \"SFMC behavior pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"script\",\n language: \"javascript\",\n entry: \"scripts/main.js\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n dependencies: [\n { module_name: \"@minecraft/server\", version: \"1.18.0\" },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\nexport async function writeResourcePackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (resource pack)` : \"SFMC resource pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"resources\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\n/* Re-export copyFileAsync so callers can copy icon without\n * pulling in the full fsx surface area. */\nexport { copyFileAsync, copyDirAsync };\n\n/* \u2500\u2500 Discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Walk `<modulesDir>/<id>/resource_pack/` for every installed module and\n * return a map { id: absoluteDir }. Modules without a resource_pack folder\n * are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which\n * modules to merge into the resource pack output.\n */\nexport function scanModuleResourcePacks(modulesDir: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!fs.existsSync(modulesDir)) return out;\n for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const rpDir = path.join(modulesDir, entry.name, \"resource_pack\");\n if (fs.existsSync(rpDir)) {\n out[entry.name] = rpDir;\n }\n }\n return out;\n}\n\n/**\n * \u4ECE JSON \u6587\u4EF6\u52A0\u8F7D\u663E\u5F0F moduleId \u2192 resource_pack \u76EE\u5F55\u6620\u5C04\u3002\n * \u4F9B assemble-rp --modules-json \u4F7F\u7528,\u907F\u514D\u8C03\u7528\u65B9\u518D\u505A\u4E34\u65F6\u76EE\u5F55\u955C\u50CF(OCP/DRY)\u3002\n */\nexport function loadModuleResourcePackMap(jsonPath: string): Record<string, string> {\n const raw = JSON.parse(fs.readFileSync(jsonPath, \"utf8\")) as unknown;\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new Error(`modules-json must be an object: ${jsonPath}`);\n }\n const out: Record<string, string> = {};\n for (const [id, dir] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof id !== \"string\" || !id || typeof dir !== \"string\" || !dir) continue;\n const abs = path.resolve(dir);\n if (!fs.existsSync(abs)) {\n throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);\n }\n out[id] = abs;\n }\n return out;\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C enable-list(\u5355\u4E00\u6743\u5A01,\u4F9B has-pack / list-packs / \u8C03\u7528\u65B9\u590D\u7528 \u2014 DRY)\u3002\n * \u6587\u4EF6\u7F3A\u5931 \u2192 entries=[]\uFF1BJSON \u635F\u574F \u2192 entries=[] \u4E14 parseFailedFile \u6709\u503C\uFF08\u4F9B doctor \u533A\u5206\uFF09\u3002\n */\nexport type WorldPackListReadResult = {\n entries: Array<{ pack_id: string; version: [number, number, number] }>;\n /** \u6587\u4EF6\u5B58\u5728\u4F46\u89E3\u6790\u5931\u8D25\u65F6\u4E3A\u8BE5 JSON \u7EDD\u5BF9\u8DEF\u5F84 */\n parseFailedFile?: string;\n};\n\nexport function readWorldPackListResult(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): WorldPackListReadResult {\n const file = worldPackListFile(worldsDir, levelName, kind);\n if (!fs.existsSync(file)) return { entries: [] };\n try {\n const arr = JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown;\n if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };\n const out: Array<{ pack_id: string; version: [number, number, number] }> = [];\n for (const e of arr) {\n if (!e || typeof e !== \"object\") continue;\n const packId = (e as { pack_id?: unknown }).pack_id;\n const ver = (e as { version?: unknown }).version;\n if (typeof packId !== \"string\" || !packId) continue;\n const version: [number, number, number] =\n Array.isArray(ver) && ver.length >= 3\n ? [Number(ver[0]), Number(ver[1]), Number(ver[2])]\n : [1, 0, 0];\n out.push({ pack_id: packId, version });\n }\n return { entries: out };\n } catch {\n return { entries: [], parseFailedFile: file };\n }\n}\n\n/** \u517C\u5BB9\u8BFB\u4FA7\uFF1A\u53EA\u8981 entries\uFF08\u635F\u574F\u65F6\u4E0E\u7F3A\u5931\u540C\u4E3A []\uFF09\u3002\u8BE6\u7EC6\u7ED3\u679C\u89C1 readWorldPackListResult\u3002 */\nexport function readWorldPackList(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return readWorldPackListResult(worldsDir, levelName, kind).entries;\n}\n\n/** \u4E16\u754C enable-list \u662F\u5426\u5DF2\u542B\u6307\u5B9A pack_id(\u53EA\u8BFB,\u4F9B preflight \u590D\u7528)\u3002 */\nexport function worldPackListHas(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\",\n packUuid: string\n): boolean {\n return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);\n}"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * pack-manager.ts \u2014 Bedrock \u884C\u4E3A\u5305/\u8D44\u6E90\u5305 \u88C5\u914D + \u90E8\u7F72\u5230 BDS \u6839\u3002\n *\n * \u7EAF\u51FD\u6570\u5E93,\u4E24\u6761\u6D88\u8D39\u8DEF\u5F84:\n *\n * - \u540C\u8FDB\u7A0B(\u63A8\u8350): sfmc/pack-lifecycle \u7ECF `@sfmc-bds/bds-tools/pack-manager-lib`\n * \u76F4\u8FDE\u672C\u6A21\u5757\uFF08DIP\uFF09\uFF1Bworld-packs \u7B49\u540C\u7406\u3002\n * - CLI: `cli-pack-manager.js` \u4ECD\u66B4\u9732\u76F8\u540C\u52A8\u8BCD\uFF0C\u4F9B\u5916\u90E8\u811A\u672C/\u624B\u5DE5\u8C03\u8BD5\uFF1B\n * CLI \u53EA\u662F\u672C\u5E93\u7684\u8584\u9002\u914D\uFF0C\u4E0D\u518D\u662F sfmc \u4E3B\u8DEF\u5F84\u3002\n *\n * \u7EA6\u675F:\u672C\u6587\u4EF6\u4E0D\u5F15\u5165 esbuild / \u91CD\u578B npm-only \u5305\uFF0C\u4FDD\u6301\u53EF\u88AB Node \u5B50\u8FDB\u7A0B\u76F4\u63A5\u52A0\u8F7D\u3002\n *\n * \u5DF2\u6709\u4F9D\u8D56 (bds-tools/package.json):\n * - @sfmc-bds/sdk/logs createTerminalProgress: \u8FDB\u5EA6\u6761\uFF08BDS \u66F4\u65B0\u7B49\uFF09\n * - node-html-parser: changelog \u6293\u53D6 (\u672C\u6587\u4EF6\u7528\u4E0D\u5230)\n * - jszip: zip \u89E3\u538B(\u6A21\u5757 zip / BDS server.zip)\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { copyDirAsync, copyFileAsync, readJsonFile, Utf8BomError } from \"./fsx.js\";\n\n/* \u2500\u2500 \u7C7B\u578B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface AssembleBehaviorPackOpts {\n /** Where the bundled scripts/main.js already exists (esbuild output dir) */\n srcDir: string;\n /** Output behavior pack directory (created if missing) */\n outDir: string;\n /** BP \u76EE\u5F55\u540D \u2014 \u9ED8\u8BA4 'sfmc-modules' */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** pack_icon.png \u6E90\u6587\u4EF6 (optional, \u4E0D\u63D0\u4F9B\u5219\u8DF3\u8FC7) */\n iconSrc?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A script module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResourcePackOpts {\n /** Modules whose resource_pack/** should be merged. Map<moduleId, resourcePackDir>. */\n moduleResourceDirs: Record<string, string>;\n /** Output resource pack directory (created if missing) */\n outDir: string;\n /** RP \u76EE\u5F55\u540D */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A resources module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResult {\n uuid: string;\n version: [number, number, number];\n}\n\nexport interface DeployOpts {\n bdsRoot: string;\n levelName: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 BP \u6E90\u76EE\u5F55 */\n behaviorPackSrc: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 RP \u6E90\u76EE\u5F55 (\u53EF\u7701\u7565,\u53EA\u7528 BP \u4E5F\u5408\u6CD5) */\n resourcePackSrc?: string;\n /** BP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/behavior_packs/<bpName>) */\n bpName: string;\n /** RP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/resource_packs/<rpName>);\u7701\u7565\u65F6\u590D\u7528 bpName + '-rp' */\n rpName?: string;\n /**\n * \u65E0 resourcePackSrc \u65F6\u662F\u5426\u5220\u9664\u4E16\u754C\u5185\u5DF2\u6709 RP \u76EE\u5F55\u3002\n * \u7528\u4E8E\u6A21\u5757\u4E0D\u518D\u63D0\u4F9B RP \u65F6\u6E05\u7406\u805A\u5408\u5305\u6B8B\u7559(\u9ED8\u8BA4 false,\u907F\u514D\u8BEF\u5220\u672A\u58F0\u660E\u7684 RP)\u3002\n */\n clearResourcePack?: boolean;\n}\n\nexport interface DeployResult {\n bpDir: string;\n rpDir: string | null;\n}\n\nexport interface EnablePackOpts {\n worldsDir: string;\n levelName: string;\n kind: \"behavior\" | \"resource\";\n packUuid: string;\n version: [number, number, number];\n}\n\n/* \u2500\u2500 \u8DEF\u5F84\u5E38\u91CF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** SFMC \u5408\u6210 BP \u7684\u56FA\u5B9A @minecraft/* permissions,\u6240\u6709\u7528\u5230\u7684\u547D\u540D\u7A7A\u95F4\u90FD\u6253\u5F00\u3002 */\nexport const SFMC_PERMISSIONS = [\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-net\",\n \"@minecraft/server-editor\",\n \"@minecraft/diagnostics\",\n] as const;\n\n/** `<bdsRoot>/server.properties` \u2014 level-name / telemetry \u7B49\u5171\u7528\uFF08DRY\uFF09 */\nexport function serverPropertiesPath(bdsRoot: string): string {\n return path.join(bdsRoot, \"server.properties\");\n}\n\n/** `<bdsRoot>/worlds` \u2014 enable-list / \u90E8\u7F72\u8C03\u7528\u65B9\u52FF\u518D\u786C\u62FC\uFF08Demeter\uFF09 */\nexport function bdsWorldsDir(bdsRoot: string): string {\n return path.join(bdsRoot, \"worlds\");\n}\n\n/** `<bdsRoot>/worlds/<level>` */\nexport function bdsWorldLevelDir(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldsDir(bdsRoot), levelName);\n}\n\n/** \u4E16\u754C enable-list JSON \u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5355\u4E00\u6743\u5A01\uFF0C\u4F9B\u8BFB\u5199\u4E24\u4FA7\uFF09 */\nexport function worldPackListFile(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): string {\n const name = kind === \"behavior\" ? \"world_behavior_packs.json\" : \"world_resource_packs.json\";\n return path.join(worldsDir, levelName, name);\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permission.json` \u2014 Script API \u6743\u9650\u6587\u4EF6\u6743\u5A01\u8DEF\u5F84 */\nexport function configPermissionPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permission.json\");\n}\n\n/** \u662F\u5426\u5DF2\u6709 Script API permission.json\uFF08\u53EA\u8BFB\uFF0C\u4F9B preflight/status\uFF09 */\nexport function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean {\n return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));\n}\n\n/** \u968F\u673A\u751F\u6210 BP/RP manifest.json header.uuid (RFC 4122 v4) */\nexport function randomUuid(): string {\n /* crypto.randomUUID \u662F Node 19+ \u5185\u7F6E,\u8FD9\u91CC\u76F4\u63A5\u7528 */\n return crypto.randomUUID();\n}\n\n/* \u2500\u2500 \u9AA8\u67B6\u51FD\u6570 (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt\n * `srcDir` (which must already contain `scripts/main.js` plus whatever else\n * was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.\n *\n * The caller is responsible for running esbuild first; pack-manager does not\n * bundle scripts. That decoupling keeps pack assembly independent of the bundler.\n */\nexport async function assembleBehaviorPack(opts: AssembleBehaviorPackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const bpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n if (fs.existsSync(opts.srcDir)) {\n await copyDirAsync(opts.srcDir, opts.outDir);\n } else {\n await fs.promises.mkdir(path.join(opts.outDir, \"scripts\"), { recursive: true });\n await fs.promises.writeFile(path.join(opts.outDir, \"scripts\", \"main.js\"), \"/* no scripts */\\n\", \"utf8\");\n }\n await writeBehaviorPackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: bpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {\n await copyFileAsync(opts.iconSrc, path.join(opts.outDir, \"pack_icon.png\"));\n }\n await writePermissionsJson(opts.outDir);\n return { uuid: bpUuid, version };\n}\n\n/**\n * Merge every enabled module's `resource_pack/**` tree into one RP directory\n * at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are\n * preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).\n */\nexport async function assembleResourcePack(opts: AssembleResourcePackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const rpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {\n if (!fs.existsSync(rpDir)) continue;\n const dst = path.join(opts.outDir, moduleId);\n await fs.promises.mkdir(dst, { recursive: true });\n await copyDirAsync(rpDir, dst);\n }\n await writeResourcePackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: rpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n return { uuid: rpUuid, version };\n}\n\n/**\n * Read the `level-name=` value from `<bdsRoot>/server.properties`.\n * Falls back to \"Bedrock level\" (BDS default) when the file is missing or\n * the key is absent.\n */\nfunction parseLevelNameFromProperties(text: string): string {\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*level-name\\s*=\\s*(.+?)\\s*$/.exec(line);\n if (m && m[1]) return m[1];\n }\n return \"Bedrock level\";\n}\n\n/** \u540C\u6B65\u8BFB level-name\uFF08\u4F9B sfmc resolveBdsContext \u7B49\u540C\u8FDB\u7A0B\u8C03\u7528\u65B9\uFF0CDRY\uFF09\u3002 */\nexport function readLevelNameSync(bdsRoot: string): string {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return \"Bedrock level\";\n return parseLevelNameFromProperties(fs.readFileSync(file, \"utf8\"));\n}\n\n/** \u4E0E sync \u540C\u5951\u7EA6\uFF1BCLI / async \u8C03\u7528\u65B9\u8D70\u6B64\u5165\u53E3\uFF08LSP\uFF09 */\nexport async function readLevelName(bdsRoot: string): Promise<string> {\n return readLevelNameSync(bdsRoot);\n}\n\n/**\n * Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/\n * folders, and write a fresh `permissions.json` into the BP target.\n *\n * Does NOT edit world_behavior_packs.json \u2014 that's a separate step the caller\n * must invoke after restart, because BDS only reads that file at startup.\n */\nexport async function deployToBDS(opts: DeployOpts): Promise<DeployResult> {\n /* levelDir = worlds/<level>\uFF1B\u4E0E EnablePackOpts.worldsDir(=worlds/) \u8BED\u4E49\u4E0D\u540C \u2014 \u52FF\u6DF7\u7528\uFF08LSP\uFF09 */\n const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);\n const bpDst = path.join(levelDir, \"behavior_packs\", opts.bpName);\n const rpDst = path.join(levelDir, \"resource_packs\", opts.rpName ?? `${opts.bpName}-rp`);\n await fs.promises.mkdir(levelDir, { recursive: true });\n await fs.promises.rm(bpDst, { recursive: true, force: true });\n await copyDirAsync(opts.behaviorPackSrc, bpDst);\n await writePermissionsJson(bpDst);\n let rpDir: string | null = null;\n if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n await copyDirAsync(opts.resourcePackSrc, rpDst);\n rpDir = rpDst;\n } else if (opts.clearResourcePack) {\n /* \u8C03\u7528\u65B9\u663E\u5F0F\u58F0\u660E\u4E0D\u518D\u90E8\u7F72 RP \u2014 \u6E05\u6389\u805A\u5408 RP \u76EE\u5F55\u6B8B\u7559 */\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n }\n return { bpDir: bpDst, rpDir };\n}\n\n/**\n * \u786E\u4FDD BDS Script API \u4FA7 `<bdsRoot>/config/<bpUuid>/permission.json` \u5B58\u5728\u3002\n * \u5DF2\u5B58\u5728\u5219\u8DF3\u8FC7(\u4E0D\u8986\u76D6\u7528\u6237\u624B\u5DE5\u6539\u52A8)\u3002\n * @returns true = \u65B0\u5199\u5165; false = \u5DF2\u5B58\u5728\u8DF3\u8FC7\n */\nexport async function ensureConfigPermission(bdsRoot: string, bpUuid: string): Promise<boolean> {\n const file = configPermissionPath(bdsRoot, bpUuid);\n if (fs.existsSync(file)) return false;\n const dir = path.dirname(file);\n await fs.promises.mkdir(dir, { recursive: true });\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n const tmp = path.join(dir, `.permission.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n return true;\n}\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 header.uuid + version;\u5931\u8D25\u8FD4\u56DE null\u3002 */\nexport function readPackManifestHeader(\n packDir: string\n): { uuid: string; version: [number, number, number]; moduleUuid?: string } | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = readJsonFile<{\n header?: { uuid?: string; version?: number[] };\n modules?: Array<{ uuid?: string }>;\n }>(file);\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n if (typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const moduleUuid = raw.modules?.[0]?.uuid;\n return { uuid, version, ...(typeof moduleUuid === \"string\" ? { moduleUuid } : {}) };\n } catch (e) {\n if (e instanceof Utf8BomError) throw e;\n return null;\n }\n}\n\n/**\n * Write the seven `@minecraft/*` allowed_modules into a behavior pack's\n * `permissions.json`. Idempotent: rewrites any pre-existing file.\n */\nexport async function writePermissionsJson(bpDir: string): Promise<void> {\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n await fs.promises.mkdir(bpDir, { recursive: true });\n const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, path.join(bpDir, \"permissions.json\"));\n}\n\n/**\n * Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`\n * (or `world_resource_packs.json`). If the pack_id already exists, replace its\n * version. File missing \u2192 initialize as `[]`.\n */\nexport async function enablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"enable\");\n}\n\n/** Remove a pack_id from the world's enable-list JSON. */\nexport async function disablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"disable\");\n}\n\ninterface WorldPackEntry {\n pack_id: string;\n version: [number, number, number];\n}\n\nasync function editWorldPackList(\n opts: EnablePackOpts,\n mode: \"enable\" | \"disable\"\n): Promise<void> {\n const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);\n /* \u4E0E readWorldPackList \u540C\u6E90\u89E3\u6790,\u518D\u5199\u56DE(DRY);\u5F02\u6B65\u5199\u8DEF\u5F84\u4FDD\u7559\u539F\u8BED\u4E49 */\n let entries: WorldPackEntry[] = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);\n const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);\n if (mode === \"enable\") {\n const next: WorldPackEntry = { pack_id: opts.packUuid, version: opts.version };\n if (idx >= 0) entries[idx] = next;\n else entries.push(next);\n } else {\n if (idx >= 0) entries.splice(idx, 1);\n }\n await fs.promises.mkdir(path.dirname(file), { recursive: true });\n const tmp = `${file}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n}\n\n/* \u2500\u2500 \u4F4E\u5C42 helpers (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport async function writeBehaviorPackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (behavior pack)` : \"SFMC behavior pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"script\",\n language: \"javascript\",\n entry: \"scripts/main.js\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n dependencies: [\n { module_name: \"@minecraft/server\", version: \"1.18.0\" },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\nexport async function writeResourcePackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (resource pack)` : \"SFMC resource pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"resources\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\n/* Re-export copyFileAsync so callers can copy icon without\n * pulling in the full fsx surface area. */\nexport { copyFileAsync, copyDirAsync };\n\n/* \u2500\u2500 Discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Walk `<modulesDir>/<id>/resource_pack/` for every installed module and\n * return a map { id: absoluteDir }. Modules without a resource_pack folder\n * are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which\n * modules to merge into the resource pack output.\n */\nexport function scanModuleResourcePacks(modulesDir: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!fs.existsSync(modulesDir)) return out;\n for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const rpDir = path.join(modulesDir, entry.name, \"resource_pack\");\n if (fs.existsSync(rpDir)) {\n out[entry.name] = rpDir;\n }\n }\n return out;\n}\n\n/**\n * \u4ECE JSON \u6587\u4EF6\u52A0\u8F7D\u663E\u5F0F moduleId \u2192 resource_pack \u76EE\u5F55\u6620\u5C04\u3002\n * \u4F9B assemble-rp --modules-json \u4F7F\u7528,\u907F\u514D\u8C03\u7528\u65B9\u518D\u505A\u4E34\u65F6\u76EE\u5F55\u955C\u50CF(OCP/DRY)\u3002\n */\nexport function loadModuleResourcePackMap(jsonPath: string): Record<string, string> {\n const raw = JSON.parse(fs.readFileSync(jsonPath, \"utf8\")) as unknown;\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new Error(`modules-json must be an object: ${jsonPath}`);\n }\n const out: Record<string, string> = {};\n for (const [id, dir] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof id !== \"string\" || !id || typeof dir !== \"string\" || !dir) continue;\n const abs = path.resolve(dir);\n if (!fs.existsSync(abs)) {\n throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);\n }\n out[id] = abs;\n }\n return out;\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C enable-list(\u5355\u4E00\u6743\u5A01,\u4F9B has-pack / list-packs / \u8C03\u7528\u65B9\u590D\u7528 \u2014 DRY)\u3002\n * \u6587\u4EF6\u7F3A\u5931 \u2192 entries=[]\uFF1BJSON \u635F\u574F \u2192 entries=[] \u4E14 parseFailedFile \u6709\u503C\uFF08\u4F9B doctor \u533A\u5206\uFF09\u3002\n */\nexport type WorldPackListReadResult = {\n entries: Array<{ pack_id: string; version: [number, number, number] }>;\n /** \u6587\u4EF6\u5B58\u5728\u4F46\u89E3\u6790\u5931\u8D25\u65F6\u4E3A\u8BE5 JSON \u7EDD\u5BF9\u8DEF\u5F84 */\n parseFailedFile?: string;\n};\n\nexport function readWorldPackListResult(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): WorldPackListReadResult {\n const file = worldPackListFile(worldsDir, levelName, kind);\n if (!fs.existsSync(file)) return { entries: [] };\n try {\n const arr = JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown;\n if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };\n const out: Array<{ pack_id: string; version: [number, number, number] }> = [];\n for (const e of arr) {\n if (!e || typeof e !== \"object\") continue;\n const packId = (e as { pack_id?: unknown }).pack_id;\n const ver = (e as { version?: unknown }).version;\n if (typeof packId !== \"string\" || !packId) continue;\n const version: [number, number, number] =\n Array.isArray(ver) && ver.length >= 3\n ? [Number(ver[0]), Number(ver[1]), Number(ver[2])]\n : [1, 0, 0];\n out.push({ pack_id: packId, version });\n }\n return { entries: out };\n } catch {\n return { entries: [], parseFailedFile: file };\n }\n}\n\n/** \u517C\u5BB9\u8BFB\u4FA7\uFF1A\u53EA\u8981 entries\uFF08\u635F\u574F\u65F6\u4E0E\u7F3A\u5931\u540C\u4E3A []\uFF09\u3002\u8BE6\u7EC6\u7ED3\u679C\u89C1 readWorldPackListResult\u3002 */\nexport function readWorldPackList(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return readWorldPackListResult(worldsDir, levelName, kind).entries;\n}\n\n/** \u4E16\u754C enable-list \u662F\u5426\u5DF2\u542B\u6307\u5B9A pack_id(\u53EA\u8BFB,\u4F9B preflight \u590D\u7528)\u3002 */\nexport function worldPackListHas(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\",\n packUuid: string\n): boolean {\n return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);\n}"],
5
+ "mappings": "AAkBA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,cAAc,eAAe,cAAc,oBAAoB;AA+EjE,MAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,SAAS,qBAAqB,SAAyB;AAC5D,SAAO,KAAK,KAAK,SAAS,mBAAmB;AAC/C;AAGO,SAAS,aAAa,SAAyB;AACpD,SAAO,KAAK,KAAK,SAAS,QAAQ;AACpC;AAGO,SAAS,iBAAiB,SAAiB,WAA2B;AAC3E,SAAO,KAAK,KAAK,aAAa,OAAO,GAAG,SAAS;AACnD;AAGO,SAAS,kBACd,WACA,WACA,MACQ;AACR,QAAM,OAAO,SAAS,aAAa,8BAA8B;AACjE,SAAO,KAAK,KAAK,WAAW,WAAW,IAAI;AAC7C;AAGO,SAAS,qBAAqB,SAAiB,QAAwB;AAC5E,SAAO,KAAK,KAAK,SAAS,UAAU,QAAQ,iBAAiB;AAC/D;AAGO,SAAS,oBAAoB,SAAiB,QAAyB;AAC5E,SAAO,GAAG,WAAW,qBAAqB,SAAS,MAAM,CAAC;AAC5D;AAGO,SAAS,aAAqB;AAEnC,SAAO,OAAO,WAAW;AAC3B;AAYA,eAAsB,qBAAqB,MAAyD;AAClG,QAAM,UAAU,KAAK,WAAW,CAAC,GAAG,GAAG,CAAC;AACxC,QAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,QAAM,GAAG,SAAS,GAAG,KAAK,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClE,QAAM,GAAG,SAAS,MAAM,KAAK,QAAQ,EAAE,WAAW,KAAK,CAAC;AACxD,MAAI,GAAG,WAAW,KAAK,MAAM,GAAG;AAC9B,UAAM,aAAa,KAAK,QAAQ,KAAK,MAAM;AAAA,EAC7C,OAAO;AACL,UAAM,GAAG,SAAS,MAAM,KAAK,KAAK,KAAK,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9E,UAAM,GAAG,SAAS,UAAU,KAAK,KAAK,KAAK,QAAQ,WAAW,SAAS,GAAG,sBAAsB,MAAM;AAAA,EACxG;AACA,QAAM,0BAA0B,KAAK,QAAQ;AAAA,IAC3C,MAAM,KAAK;AAAA,IACX,MAAM;AAAA,IACN;AAAA,IACA,aAAa,KAAK;AAAA,IAClB,YAAY,KAAK;AAAA,EACnB,CAAC;AACD,MAAI,KAAK,WAAW,GAAG,WAAW,KAAK,OAAO,GAAG;AAC/C,UAAM,cAAc,KAAK,SAAS,KAAK,KAAK,KAAK,QAAQ,eAAe,CAAC;AAAA,EAC3E;AACA,QAAM,qBAAqB,KAAK,MAAM;AACtC,SAAO,EAAE,MAAM,QAAQ,QAAQ;AACjC;AAOA,eAAsB,qBAAqB,MAAyD;AAClG,QAAM,UAAU,KAAK,WAAW,CAAC,GAAG,GAAG,CAAC;AACxC,QAAM,SAAS,KAAK,QAAQ,WAAW;AACvC,QAAM,GAAG,SAAS,GAAG,KAAK,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClE,QAAM,GAAG,SAAS,MAAM,KAAK,QAAQ,EAAE,WAAW,KAAK,CAAC;AACxD,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,KAAK,kBAAkB,GAAG;AACvE,QAAI,CAAC,GAAG,WAAW,KAAK,EAAG;AAC3B,UAAM,MAAM,KAAK,KAAK,KAAK,QAAQ,QAAQ;AAC3C,UAAM,GAAG,SAAS,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAChD,UAAM,aAAa,OAAO,GAAG;AAAA,EAC/B;AACA,QAAM,0BAA0B,KAAK,QAAQ;AAAA,IAC3C,MAAM,KAAK;AAAA,IACX,MAAM;AAAA,IACN;AAAA,IACA,aAAa,KAAK;AAAA,IAClB,YAAY,KAAK;AAAA,EACnB,CAAC;AACD,SAAO,EAAE,MAAM,QAAQ,QAAQ;AACjC;AAOA,SAAS,6BAA6B,MAAsB;AAC1D,aAAW,QAAQ,KAAK,MAAM,OAAO,GAAG;AACtC,UAAM,IAAI,iCAAiC,KAAK,IAAI;AACpD,QAAI,KAAK,EAAE,CAAC,EAAG,QAAO,EAAE,CAAC;AAAA,EAC3B;AACA,SAAO;AACT;AAGO,SAAS,kBAAkB,SAAyB;AACzD,QAAM,OAAO,qBAAqB,OAAO;AACzC,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO;AACjC,SAAO,6BAA6B,GAAG,aAAa,MAAM,MAAM,CAAC;AACnE;AAGA,eAAsB,cAAc,SAAkC;AACpE,SAAO,kBAAkB,OAAO;AAClC;AASA,eAAsB,YAAY,MAAyC;AAEzE,QAAM,WAAW,iBAAiB,KAAK,SAAS,KAAK,SAAS;AAC9D,QAAM,QAAQ,KAAK,KAAK,UAAU,kBAAkB,KAAK,MAAM;AAC/D,QAAM,QAAQ,KAAK,KAAK,UAAU,kBAAkB,KAAK,UAAU,GAAG,KAAK,MAAM,KAAK;AACtF,QAAM,GAAG,SAAS,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AACrD,QAAM,GAAG,SAAS,GAAG,OAAO,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC5D,QAAM,aAAa,KAAK,iBAAiB,KAAK;AAC9C,QAAM,qBAAqB,KAAK;AAChC,MAAI,QAAuB;AAC3B,MAAI,KAAK,mBAAmB,GAAG,WAAW,KAAK,eAAe,GAAG;AAC/D,UAAM,GAAG,SAAS,GAAG,OAAO,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC5D,UAAM,aAAa,KAAK,iBAAiB,KAAK;AAC9C,YAAQ;AAAA,EACV,WAAW,KAAK,mBAAmB;AAEjC,UAAM,GAAG,SAAS,GAAG,OAAO,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EAC9D;AACA,SAAO,EAAE,OAAO,OAAO,MAAM;AAC/B;AAOA,eAAsB,uBAAuB,SAAiB,QAAkC;AAC9F,QAAM,OAAO,qBAAqB,SAAS,MAAM;AACjD,MAAI,GAAG,WAAW,IAAI,EAAG,QAAO;AAChC,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,QAAM,GAAG,SAAS,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAChD,QAAM,UAAU,EAAE,iBAAiB,CAAC,GAAG,gBAAgB,EAAE;AACzD,QAAM,MAAM,KAAK,KAAK,KAAK,eAAe,QAAQ,GAAG,MAAM;AAC3D,QAAM,GAAG,SAAS,UAAU,KAAK,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,MAAM,MAAM;AAChF,QAAM,GAAG,SAAS,OAAO,KAAK,IAAI;AAClC,SAAO;AACT;AAGO,SAAS,uBACd,SACiF;AACjF,QAAM,OAAO,KAAK,KAAK,SAAS,eAAe;AAC/C,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO;AACjC,MAAI;AACF,UAAM,MAAM,aAGT,IAAI;AACP,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,MAAM,IAAI,QAAQ;AACxB,QAAI,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,EAAG,QAAO;AAC9E,UAAM,UAAoC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC;AACzF,UAAM,aAAa,IAAI,UAAU,CAAC,GAAG;AACrC,WAAO,EAAE,MAAM,SAAS,GAAI,OAAO,eAAe,WAAW,EAAE,WAAW,IAAI,CAAC,EAAG;AAAA,EACpF,SAAS,GAAG;AACV,QAAI,aAAa,aAAc,OAAM;AACrC,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,qBAAqB,OAA8B;AACvE,QAAM,UAAU,EAAE,iBAAiB,CAAC,GAAG,gBAAgB,EAAE;AACzD,QAAM,GAAG,SAAS,MAAM,OAAO,EAAE,WAAW,KAAK,CAAC;AAClD,QAAM,MAAM,KAAK,KAAK,OAAO,gBAAgB,QAAQ,GAAG,MAAM;AAC9D,QAAM,GAAG,SAAS,UAAU,KAAK,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,MAAM,MAAM;AAChF,QAAM,GAAG,SAAS,OAAO,KAAK,KAAK,KAAK,OAAO,kBAAkB,CAAC;AACpE;AAOA,eAAsB,kBAAkB,MAAqC;AAC3E,QAAM,kBAAkB,MAAM,QAAQ;AACxC;AAGA,eAAsB,mBAAmB,MAAqC;AAC5E,QAAM,kBAAkB,MAAM,SAAS;AACzC;AAOA,eAAe,kBACb,MACA,MACe;AACf,QAAM,OAAO,kBAAkB,KAAK,WAAW,KAAK,WAAW,KAAK,IAAI;AAExE,MAAI,UAA4B,kBAAkB,KAAK,WAAW,KAAK,WAAW,KAAK,IAAI;AAC3F,QAAM,MAAM,QAAQ,UAAU,CAAC,MAAM,EAAE,YAAY,KAAK,QAAQ;AAChE,MAAI,SAAS,UAAU;AACrB,UAAM,OAAuB,EAAE,SAAS,KAAK,UAAU,SAAS,KAAK,QAAQ;AAC7E,QAAI,OAAO,EAAG,SAAQ,GAAG,IAAI;AAAA,QACxB,SAAQ,KAAK,IAAI;AAAA,EACxB,OAAO;AACL,QAAI,OAAO,EAAG,SAAQ,OAAO,KAAK,CAAC;AAAA,EACrC;AACA,QAAM,GAAG,SAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/D,QAAM,MAAM,GAAG,IAAI,IAAI,QAAQ,GAAG;AAClC,QAAM,GAAG,SAAS,UAAU,KAAK,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,MAAM,MAAM;AAChF,QAAM,GAAG,SAAS,OAAO,KAAK,IAAI;AACpC;AAIA,eAAsB,0BACpB,QACA,QAOe;AACf,QAAM,WAAW;AAAA,IACf,gBAAgB;AAAA,IAChB,QAAQ;AAAA,MACN,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,OAAO,cAAc,GAAG,OAAO,WAAW,qBAAqB;AAAA,MAC5E,oBAAoB,CAAC,GAAG,IAAI,CAAC;AAAA,IAC/B;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,UAAU;AAAA,QACV,OAAO;AAAA,QACP,MAAM,OAAO,cAAc,OAAO,WAAW;AAAA,QAC7C,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IACA,cAAc;AAAA,MACZ,EAAE,aAAa,qBAAqB,SAAS,SAAS;AAAA,IACxD;AAAA,EACF;AACA,QAAM,OAAO,KAAK,KAAK,QAAQ,eAAe;AAC9C,QAAM,GAAG,SAAS,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACnD,QAAM,GAAG,SAAS,UAAU,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,MAAM;AACpF;AAEA,eAAsB,0BACpB,QACA,QAOe;AACf,QAAM,WAAW;AAAA,IACf,gBAAgB;AAAA,IAChB,QAAQ;AAAA,MACN,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,OAAO,cAAc,GAAG,OAAO,WAAW,qBAAqB;AAAA,MAC5E,oBAAoB,CAAC,GAAG,IAAI,CAAC;AAAA,IAC/B;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM,OAAO,cAAc,OAAO,WAAW;AAAA,QAC7C,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,KAAK,KAAK,QAAQ,eAAe;AAC9C,QAAM,GAAG,SAAS,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACnD,QAAM,GAAG,SAAS,UAAU,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,MAAM;AACpF;AAcO,SAAS,wBAAwB,YAA4C;AAClF,QAAM,MAA8B,CAAC;AACrC,MAAI,CAAC,GAAG,WAAW,UAAU,EAAG,QAAO;AACvC,aAAW,SAAS,GAAG,YAAY,YAAY,EAAE,eAAe,KAAK,CAAC,GAAG;AACvE,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,UAAM,QAAQ,KAAK,KAAK,YAAY,MAAM,MAAM,eAAe;AAC/D,QAAI,GAAG,WAAW,KAAK,GAAG;AACxB,UAAI,MAAM,IAAI,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,0BAA0B,UAA0C;AAClF,QAAM,MAAM,KAAK,MAAM,GAAG,aAAa,UAAU,MAAM,CAAC;AACxD,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,IAAI,MAAM,mCAAmC,QAAQ,EAAE;AAAA,EAC/D;AACA,QAAM,MAA8B,CAAC;AACrC,aAAW,CAAC,IAAI,GAAG,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACtE,QAAI,OAAO,OAAO,YAAY,CAAC,MAAM,OAAO,QAAQ,YAAY,CAAC,IAAK;AACtE,UAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,QAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AACvB,YAAM,IAAI,MAAM,+BAA+B,EAAE,WAAM,GAAG,EAAE;AAAA,IAC9D;AACA,QAAI,EAAE,IAAI;AAAA,EACZ;AACA,SAAO;AACT;AAYO,SAAS,wBACd,WACA,WACA,MACyB;AACzB,QAAM,OAAO,kBAAkB,WAAW,WAAW,IAAI;AACzD,MAAI,CAAC,GAAG,WAAW,IAAI,EAAG,QAAO,EAAE,SAAS,CAAC,EAAE;AAC/C,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,GAAG,aAAa,MAAM,MAAM,CAAC;AACpD,QAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,iBAAiB,KAAK;AACrE,UAAM,MAAqE,CAAC;AAC5E,eAAW,KAAK,KAAK;AACnB,UAAI,CAAC,KAAK,OAAO,MAAM,SAAU;AACjC,YAAM,SAAU,EAA4B;AAC5C,YAAM,MAAO,EAA4B;AACzC,UAAI,OAAO,WAAW,YAAY,CAAC,OAAQ;AAC3C,YAAM,UACJ,MAAM,QAAQ,GAAG,KAAK,IAAI,UAAU,IAChC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,IAC/C,CAAC,GAAG,GAAG,CAAC;AACd,UAAI,KAAK,EAAE,SAAS,QAAQ,QAAQ,CAAC;AAAA,IACvC;AACA,WAAO,EAAE,SAAS,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO,EAAE,SAAS,CAAC,GAAG,iBAAiB,KAAK;AAAA,EAC9C;AACF;AAGO,SAAS,kBACd,WACA,WACA,MAC+D;AAC/D,SAAO,wBAAwB,WAAW,WAAW,IAAI,EAAE;AAC7D;AAGO,SAAS,iBACd,WACA,WACA,MACA,UACS;AACT,SAAO,kBAAkB,WAAW,WAAW,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY,QAAQ;AACzF;",
6
6
  "names": []
7
7
  }
@@ -2,11 +2,17 @@
2
2
  * update-result.ts — BDS updater ↔ sfmc 监督器机器可读结果契约(DRY / DIP)
3
3
  *
4
4
  * 勿依赖本地化日志文案判断「是否真正部署」;一律解析本标记。
5
+ * 写出走统一 Logger(bare stdout),避免 console.log 旁路。
5
6
  */
7
+ import type { Logger } from "@sfmc-bds/sdk/logs";
6
8
  export declare const UPDATE_RESULT_PREFIX = "SFMC_UPDATE_RESULT=";
7
9
  export type UpdateResultKind = "uptodate" | "skipped" | "check-only" | "deployed";
8
- /** stdout 打印机器标记(供父进程捕获)。 */
9
- export declare function emitUpdateResult(kind: UpdateResultKind): void;
10
+ type InfoLogger = Pick<Logger, "info">;
11
+ /** logger 打印机器标记(bare stdout 下仍为可解析纯文本)。 */
12
+ export declare function emitUpdateResult(kind: UpdateResultKind, log: InfoLogger): void;
13
+ /** KEY=value 机器行(CURRENT/LATEST/CHANNEL/URLS 等) */
14
+ export declare function emitUpdateKv(key: string, value: string, log: InfoLogger): void;
10
15
  /** 从 updater 合并输出中解析是否完成部署。 */
11
16
  export declare function didUpdateDeploy(out: string): boolean;
17
+ export {};
12
18
  //# sourceMappingURL=update-result.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-result.d.ts","sourceRoot":"","sources":["../src/update-result.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;AAElF,+BAA+B;AAC/B,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAE7D;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIpD"}
1
+ {"version":3,"file":"update-result.d.ts","sourceRoot":"","sources":["../src/update-result.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;AAElF,KAAK,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,8CAA8C;AAC9C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAE9E;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAE9E;AAED,+BAA+B;AAC/B,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD"}
@@ -1,15 +1,17 @@
1
1
  const UPDATE_RESULT_PREFIX = "SFMC_UPDATE_RESULT=";
2
- function emitUpdateResult(kind) {
3
- console.log(`${UPDATE_RESULT_PREFIX}${kind}`);
2
+ function emitUpdateResult(kind, log) {
3
+ log.info(`${UPDATE_RESULT_PREFIX}${kind}`);
4
+ }
5
+ function emitUpdateKv(key, value, log) {
6
+ log.info(`${key}=${value}`);
4
7
  }
5
8
  function didUpdateDeploy(out) {
6
- return new RegExp(
7
- `(?:^|\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\r?\\n|$)`
8
- ).test(out);
9
+ return new RegExp(`(?:^|\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\r?\\n|$)`).test(out);
9
10
  }
10
11
  export {
11
12
  UPDATE_RESULT_PREFIX,
12
13
  didUpdateDeploy,
14
+ emitUpdateKv,
13
15
  emitUpdateResult
14
16
  };
15
17
  //# sourceMappingURL=update-result.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/update-result.ts"],
4
- "sourcesContent": ["/**\n * update-result.ts \u2014 BDS updater \u2194 sfmc \u76D1\u7763\u5668\u673A\u5668\u53EF\u8BFB\u7ED3\u679C\u5951\u7EA6\uFF08DRY / DIP\uFF09\n *\n * \u52FF\u4F9D\u8D56\u672C\u5730\u5316\u65E5\u5FD7\u6587\u6848\u5224\u65AD\u300C\u662F\u5426\u771F\u6B63\u90E8\u7F72\u300D\uFF1B\u4E00\u5F8B\u89E3\u6790\u672C\u6807\u8BB0\u3002\n */\nexport const UPDATE_RESULT_PREFIX = \"SFMC_UPDATE_RESULT=\";\n\nexport type UpdateResultKind = \"uptodate\" | \"skipped\" | \"check-only\" | \"deployed\";\n\n/** \u5411 stdout \u6253\u5370\u673A\u5668\u6807\u8BB0\uFF08\u4F9B\u7236\u8FDB\u7A0B\u6355\u83B7\uFF09\u3002 */\nexport function emitUpdateResult(kind: UpdateResultKind): void {\n console.log(`${UPDATE_RESULT_PREFIX}${kind}`);\n}\n\n/** \u4ECE updater \u5408\u5E76\u8F93\u51FA\u4E2D\u89E3\u6790\u662F\u5426\u5B8C\u6210\u90E8\u7F72\u3002 */\nexport function didUpdateDeploy(out: string): boolean {\n return new RegExp(\n `(?:^|\\\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\\\r?\\\\n|$)`\n ).test(out);\n}\n"],
5
- "mappings": "AAKO,MAAM,uBAAuB;AAK7B,SAAS,iBAAiB,MAA8B;AAC7D,UAAQ,IAAI,GAAG,oBAAoB,GAAG,IAAI,EAAE;AAC9C;AAGO,SAAS,gBAAgB,KAAsB;AACpD,SAAO,IAAI;AAAA,IACT,YAAY,oBAAoB;AAAA,EAClC,EAAE,KAAK,GAAG;AACZ;",
4
+ "sourcesContent": ["/**\n * update-result.ts \u2014 BDS updater \u2194 sfmc \u76D1\u7763\u5668\u673A\u5668\u53EF\u8BFB\u7ED3\u679C\u5951\u7EA6\uFF08DRY / DIP\uFF09\n *\n * \u52FF\u4F9D\u8D56\u672C\u5730\u5316\u65E5\u5FD7\u6587\u6848\u5224\u65AD\u300C\u662F\u5426\u771F\u6B63\u90E8\u7F72\u300D\uFF1B\u4E00\u5F8B\u89E3\u6790\u672C\u6807\u8BB0\u3002\n * \u5199\u51FA\u8D70\u7EDF\u4E00 Logger\uFF08bare stdout\uFF09\uFF0C\u907F\u514D console.log \u65C1\u8DEF\u3002\n */\nimport type { Logger } from \"@sfmc-bds/sdk/logs\";\n\nexport const UPDATE_RESULT_PREFIX = \"SFMC_UPDATE_RESULT=\";\n\nexport type UpdateResultKind = \"uptodate\" | \"skipped\" | \"check-only\" | \"deployed\";\n\ntype InfoLogger = Pick<Logger, \"info\">;\n\n/** \u5411 logger \u6253\u5370\u673A\u5668\u6807\u8BB0\uFF08bare stdout \u4E0B\u4ECD\u4E3A\u53EF\u89E3\u6790\u7EAF\u6587\u672C\uFF09\u3002 */\nexport function emitUpdateResult(kind: UpdateResultKind, log: InfoLogger): void {\n log.info(`${UPDATE_RESULT_PREFIX}${kind}`);\n}\n\n/** KEY=value \u673A\u5668\u884C\uFF08CURRENT/LATEST/CHANNEL/URLS \u7B49\uFF09 */\nexport function emitUpdateKv(key: string, value: string, log: InfoLogger): void {\n log.info(`${key}=${value}`);\n}\n\n/** \u4ECE updater \u5408\u5E76\u8F93\u51FA\u4E2D\u89E3\u6790\u662F\u5426\u5B8C\u6210\u90E8\u7F72\u3002 */\nexport function didUpdateDeploy(out: string): boolean {\n return new RegExp(`(?:^|\\\\n)${UPDATE_RESULT_PREFIX}deployed(?:\\\\r?\\\\n|$)`).test(out);\n}\n"],
5
+ "mappings": "AAQO,MAAM,uBAAuB;AAO7B,SAAS,iBAAiB,MAAwB,KAAuB;AAC9E,MAAI,KAAK,GAAG,oBAAoB,GAAG,IAAI,EAAE;AAC3C;AAGO,SAAS,aAAa,KAAa,OAAe,KAAuB;AAC9E,MAAI,KAAK,GAAG,GAAG,IAAI,KAAK,EAAE;AAC5B;AAGO,SAAS,gBAAgB,KAAsB;AACpD,SAAO,IAAI,OAAO,YAAY,oBAAoB,uBAAuB,EAAE,KAAK,GAAG;AACrF;",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { Utf8BomError } from "./fsx.js";
1
2
  import { type WorldPackListReadResult } from "./pack-manager.js";
2
3
  export type WorldPackKind = "behavior" | "resource";
3
4
  export interface PackManifestInfo {
@@ -18,6 +19,23 @@ export interface InstalledWorldPack {
18
19
  }
19
20
  /** 滤掉 §x(Minecraft 格式码)、残余压缩后缀,加 [BP]/[RP] 前缀 */
20
21
  export declare function formatWorldPackFolderName(rawName: string, kind: WorldPackKind): string;
22
+ /** 去掉已有 [BP]/[RP] 前缀,得到文件夹名主干 */
23
+ export declare function stripWorldPackFolderPrefix(rawName: string): string;
24
+ /**
25
+ * 归档内常见占位目录名(B / R / BP / RP)过短或过泛,不能作为世界目录名,
26
+ * 否则不同包会撞到同一路径并被误判为「覆盖」。
27
+ */
28
+ export declare function isGenericPackFolderStem(rawName: string): boolean;
29
+ /**
30
+ * 选定安装文件夹名:hint 过泛时改用 manifest.name;再与 dest 内已有目录避让(不同 uuid 不互相覆盖)。
31
+ */
32
+ export declare function choosePackInstallFolderName(opts: {
33
+ hint?: string;
34
+ info: PackManifestInfo;
35
+ destParent: string;
36
+ /** 同 uuid 更新时允许占用的已有目录名(不触发避让) */
37
+ allowFolderName?: string;
38
+ }): string;
21
39
  /** 根据 manifest modules[].type 判定 BP / RP */
22
40
  export declare function detectPackKindFromManifest(raw: {
23
41
  modules?: Array<{
@@ -25,11 +43,41 @@ export declare function detectPackKindFromManifest(raw: {
25
43
  }>;
26
44
  }): WorldPackKind | null;
27
45
  export declare function readPackManifestInfo(packDir: string): PackManifestInfo | null;
46
+ export { Utf8BomError };
28
47
  /** 深度优先找含 manifest.json 的包根(默认 maxDepth=2,root 自身为 depth 0) */
29
48
  export declare function discoverPackRoots(root: string, opts?: {
30
49
  maxDepth?: number;
31
50
  }): string[];
32
51
  export declare function isPackArchive(filePath: string): boolean;
52
+ /**
53
+ * 列出目录树内的包归档文件。
54
+ * 已是包根(含 manifest.json)的目录不再下钻,避免误解压包内资源。
55
+ */
56
+ export declare function listPackArchiveFiles(root: string, opts?: {
57
+ maxDepth?: number;
58
+ }): string[];
59
+ /**
60
+ * 在临时树内原地展开嵌套归档:解压到同级目录并删除归档文件,多轮直至没有新归档。
61
+ * 仅应对我们自己的 staging,禁止用于用户 inbox 原目录。
62
+ */
63
+ export declare function expandNestedArchivesInPlace(workDir: string, opts?: {
64
+ maxRounds?: number;
65
+ maxScanDepth?: number;
66
+ }): Promise<number>;
67
+ export type ResolvePackRootsResult = {
68
+ roots: string[];
69
+ /** 清理本轮创建的全部临时目录(可安全多次调用) */
70
+ dispose: () => void;
71
+ };
72
+ /**
73
+ * 统一包根解析:目录 / 顶层归档 / 嵌套 .mcpack|.zip|.mcaddon。
74
+ * 规则:先展开归档为目录树,再只认含 manifest.json 的目录为包根。
75
+ * 用户目录内的嵌套归档解到独立 temp,不修改原目录。
76
+ */
77
+ export declare function resolvePackRoots(src: string, opts?: {
78
+ maxDirDepth?: number;
79
+ maxArchiveRounds?: number;
80
+ }): Promise<ResolvePackRootsResult>;
33
81
  /** 解压 zip/mcpack/mcaddon 到临时目录,返回该目录(经 zipx 防 zip-slip) */
34
82
  export declare function extractArchiveToTemp(filePath: string): Promise<string>;
35
83
  /** 扫描世界内已安装 BP/RP 目录 */
@@ -40,8 +88,22 @@ export declare function bumpPackPatchVersion(packDir: string): [number, number,
40
88
  export declare function writePackHeaderVersion(packDir: string, next: [number, number, number]): [number, number, number];
41
89
  /** 读取 BP manifest 中依赖的资源包 uuid(非 @minecraft 模块) */
42
90
  export declare function readPackDependencyUuids(packDir: string): string[];
43
- /** 确保版本严格大于 floor(patch/minor 抬一级) */
44
- export declare function ensureVersionGreaterThan(packDir: string, floor: [number, number, number], component?: "patch" | "minor"): [number, number, number];
91
+ /** 比较 SemVer 三元组;a>b 正,a<b 负,相等 0 */
92
+ export declare function compareSemVer3(a: [number, number, number], b: [number, number, number]): number;
93
+ /** 取较大的 SemVer 三元组 */
94
+ export declare function maxSemVer3(a: [number, number, number], b: [number, number, number]): [number, number, number];
95
+ /** 按 component 抬一级 */
96
+ export declare function bumpSemVer3(v: [number, number, number], component: "patch" | "minor"): [number, number, number];
97
+ /**
98
+ * 进服启用版本:max(远程/新包, 旧启用) 再抬一级。
99
+ * 单一规则,禁止 while 追赶(作者乱写高版本如 [1,21,100] 时也能一次算完)。
100
+ */
101
+ export declare function nextEnabledVersion(remote: [number, number, number], previous: [number, number, number], component?: "patch" | "minor"): [number, number, number];
102
+ /**
103
+ * 将包目录 manifest 抬到 nextEnabledVersion(当前, previous)。
104
+ * previous 一般为更新前已安装 RP / 世界 enable 列表中的版本。
105
+ */
106
+ export declare function ensureVersionGreaterThan(packDir: string, previous: [number, number, number], component?: "patch" | "minor"): [number, number, number];
45
107
  export interface InstallPackResult {
46
108
  ok: boolean;
47
109
  skipped?: boolean;
@@ -58,7 +120,7 @@ export interface InstallPackResult {
58
120
  }
59
121
  /**
60
122
  * 将包目录安装到 destParent(behavior_packs 或 resource_packs)。
61
- * force=true 时覆盖冲突;否则返回 conflict 供上层询问。
123
+ * force=true 时覆盖「同 uuid」冲突;同名不同 uuid 会自动换文件夹名,不删别人的包。
62
124
  */
63
125
  export declare function installPackDirectory(opts: {
64
126
  srcDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"world-packs.d.ts","sourceRoot":"","sources":["../src/world-packs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world-packs.d.ts","sourceRoot":"","sources":["../src/world-packs.ts"],"names":[],"mappings":"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"}