@sfmc-bds/cli 0.2.0-beta.9 → 0.2.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.
Files changed (128) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +4 -5
  3. package/dist/bds-runtime-version.d.ts +3 -0
  4. package/dist/bds-runtime-version.d.ts.map +1 -0
  5. package/dist/bds-runtime-version.js +15 -0
  6. package/dist/bds-runtime-version.js.map +7 -0
  7. package/dist/command-surface.d.ts.map +1 -1
  8. package/dist/command-surface.js +3 -1
  9. package/dist/command-surface.js.map +2 -2
  10. package/dist/commands.d.ts +57 -4
  11. package/dist/commands.d.ts.map +1 -1
  12. package/dist/commands.js +78 -75
  13. package/dist/commands.js.map +2 -2
  14. package/dist/directory-picker.d.ts +27 -0
  15. package/dist/directory-picker.d.ts.map +1 -0
  16. package/dist/directory-picker.js +112 -0
  17. package/dist/directory-picker.js.map +7 -0
  18. package/dist/i18n/locales/en.d.ts +25 -1
  19. package/dist/i18n/locales/en.d.ts.map +1 -1
  20. package/dist/i18n/locales/en.js +25 -1
  21. package/dist/i18n/locales/en.js.map +2 -2
  22. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  23. package/dist/i18n/locales/zh-CN.js +26 -2
  24. package/dist/i18n/locales/zh-CN.js.map +2 -2
  25. package/dist/interactive-prompts.d.ts +1 -2
  26. package/dist/interactive-prompts.d.ts.map +1 -1
  27. package/dist/interactive-prompts.js +12 -23
  28. package/dist/interactive-prompts.js.map +3 -3
  29. package/dist/llbot-launch.d.ts +3 -3
  30. package/dist/llbot-launch.js.map +1 -1
  31. package/dist/log-filter.d.ts +18 -2
  32. package/dist/log-filter.d.ts.map +1 -1
  33. package/dist/log-filter.js +54 -4
  34. package/dist/log-filter.js.map +2 -2
  35. package/dist/log-translator.d.ts +36 -0
  36. package/dist/log-translator.d.ts.map +1 -0
  37. package/dist/log-translator.js +279 -0
  38. package/dist/log-translator.js.map +7 -0
  39. package/dist/logs.d.ts +2 -0
  40. package/dist/logs.d.ts.map +1 -1
  41. package/dist/logs.js +24 -11
  42. package/dist/logs.js.map +2 -2
  43. package/dist/main.js +5 -0
  44. package/dist/main.js.map +2 -2
  45. package/dist/module-commands.d.ts.map +1 -1
  46. package/dist/module-commands.js +34 -13
  47. package/dist/module-commands.js.map +2 -2
  48. package/dist/module-fingerprint.d.ts.map +1 -1
  49. package/dist/module-fingerprint.js +1 -0
  50. package/dist/module-fingerprint.js.map +2 -2
  51. package/dist/module-pack-build.d.ts +14 -4
  52. package/dist/module-pack-build.d.ts.map +1 -1
  53. package/dist/module-pack-build.js +81 -108
  54. package/dist/module-pack-build.js.map +2 -2
  55. package/dist/module-toggle.d.ts +1 -1
  56. package/dist/module-toggle.d.ts.map +1 -1
  57. package/dist/module-toggle.js.map +1 -1
  58. package/dist/pack-lifecycle.d.ts +15 -1
  59. package/dist/pack-lifecycle.d.ts.map +1 -1
  60. package/dist/pack-lifecycle.js +242 -15
  61. package/dist/pack-lifecycle.js.map +2 -2
  62. package/dist/player-session.d.ts +13 -0
  63. package/dist/player-session.d.ts.map +1 -0
  64. package/dist/player-session.js +26 -0
  65. package/dist/player-session.js.map +7 -0
  66. package/dist/registry.d.ts +1 -1
  67. package/dist/registry.d.ts.map +1 -1
  68. package/dist/registry.js +4 -1
  69. package/dist/registry.js.map +2 -2
  70. package/dist/repl-windows/format-display.d.ts.map +1 -1
  71. package/dist/repl-windows/format-display.js +5 -1
  72. package/dist/repl-windows/format-display.js.map +2 -2
  73. package/dist/repl-windows/host.d.ts +6 -3
  74. package/dist/repl-windows/host.d.ts.map +1 -1
  75. package/dist/repl-windows/host.js +12 -6
  76. package/dist/repl-windows/host.js.map +2 -2
  77. package/dist/repl-windows/index.d.ts +1 -0
  78. package/dist/repl-windows/index.d.ts.map +1 -1
  79. package/dist/repl-windows/index.js +3 -0
  80. package/dist/repl-windows/index.js.map +2 -2
  81. package/dist/repl-windows/service-window.d.ts.map +1 -1
  82. package/dist/repl-windows/service-window.js +1 -0
  83. package/dist/repl-windows/service-window.js.map +2 -2
  84. package/dist/repl-windows/sfmc-window.d.ts +7 -0
  85. package/dist/repl-windows/sfmc-window.d.ts.map +1 -0
  86. package/dist/repl-windows/sfmc-window.js +28 -0
  87. package/dist/repl-windows/sfmc-window.js.map +7 -0
  88. package/dist/repl.d.ts.map +1 -1
  89. package/dist/repl.js +38 -13
  90. package/dist/repl.js.map +2 -2
  91. package/dist/runtime.d.ts +2 -2
  92. package/dist/runtime.d.ts.map +1 -1
  93. package/dist/runtime.js +15 -2
  94. package/dist/runtime.js.map +2 -2
  95. package/dist/send-target.d.ts +2 -0
  96. package/dist/send-target.d.ts.map +1 -1
  97. package/dist/send-target.js +6 -0
  98. package/dist/send-target.js.map +2 -2
  99. package/dist/services.d.ts +26 -1
  100. package/dist/services.d.ts.map +1 -1
  101. package/dist/services.js +179 -45
  102. package/dist/services.js.map +2 -2
  103. package/dist/sfmc-modules-root.d.ts.map +1 -1
  104. package/dist/sfmc-modules-root.js +6 -2
  105. package/dist/sfmc-modules-root.js.map +2 -2
  106. package/dist/ui-command.d.ts +6 -0
  107. package/dist/ui-command.d.ts.map +1 -0
  108. package/dist/ui-command.js +68 -0
  109. package/dist/ui-command.js.map +7 -0
  110. package/dist/wizard.d.ts.map +1 -1
  111. package/dist/wizard.js +36 -31
  112. package/dist/wizard.js.map +2 -2
  113. package/dist/world-packs.d.ts +2 -0
  114. package/dist/world-packs.d.ts.map +1 -1
  115. package/dist/world-packs.js +161 -18
  116. package/dist/world-packs.js.map +2 -2
  117. package/package.json +22 -15
  118. package/scripts/module-install/check-modules.mjs +178 -0
  119. package/scripts/module-install/fetch-module.mjs +1088 -0
  120. package/scripts/module-install/lib/catalog.mjs +96 -0
  121. package/scripts/module-install/lib/config-seeding.mjs +128 -0
  122. package/scripts/module-install/lib/io.mjs +37 -0
  123. package/scripts/module-install/lib/link-from.mjs +80 -0
  124. package/scripts/module-install/lib/lock.mjs +78 -0
  125. package/scripts/module-install/lib/npm-resolver.mjs +55 -0
  126. package/scripts/module-install/lib/packages.mjs +136 -0
  127. package/scripts/module-install/lib/paths.mjs +48 -0
  128. package/scripts/module-install/lib/registry-index.mjs +50 -0
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  configPath,
3
+ DEFAULT_DB_CONFIG,
3
4
  modulePath,
4
5
  readJson,
5
6
  writeJson
@@ -25,7 +26,10 @@ import {
25
26
  readLevelNameSync,
26
27
  readPackManifestHeader,
27
28
  readWorldPackList,
28
- worldPackListHas as pmWorldPackListHas
29
+ worldPackListHas as pmWorldPackListHas,
30
+ BASELINE_BEDROCK_DEPENDENCIES,
31
+ negotiateBedrockDependencies,
32
+ NATIVE_BEDROCK_SCRIPT_MODULES
29
33
  } from "@sfmc-bds/bds-tools/pack-manager-lib";
30
34
  import { ROOT, PACKAGES_DIR, resolveSdkPackageRoot, getRoot } from "./runtime.js";
31
35
  import { c } from "./theme.js";
@@ -33,7 +37,7 @@ const BP_NAME = "sfmc-modules";
33
37
  const RP_NAME = "sfmc-modules-rp";
34
38
  const DEPLOY_CATALOG_NAME = "sfmc-deploy-catalog.json";
35
39
  const DEFAULT_PACK_VERSION = [1, 0, 0];
36
- function createSdkResolvePlugin(sdkRoot) {
40
+ function createSdkResolvePlugin(sdkRoot, dbPort) {
37
41
  const pkg = JSON.parse(readFileSync(path.join(sdkRoot, "package.json"), "utf8"));
38
42
  const exportsMap = pkg.exports ?? {};
39
43
  function resolveExportSubpath(subpath) {
@@ -48,9 +52,59 @@ function createSdkResolvePlugin(sdkRoot) {
48
52
  return {
49
53
  name: "sfmc-sdk-resolve",
50
54
  setup(build) {
55
+ build.onResolve({ filter: /^sfmc:host$/ }, () => ({
56
+ path: "sfmc:host",
57
+ namespace: "sfmc-host"
58
+ }));
59
+ build.onLoad({ filter: /.*/, namespace: "sfmc-host" }, () => ({
60
+ contents: [
61
+ 'import { installHostBootstrap } from "@sfmc-bds/sdk/module-loader/install";',
62
+ `installHostBootstrap({ dbServerUrl: ${JSON.stringify(`http://127.0.0.1:${dbPort}`)} });`
63
+ ].join("\n"),
64
+ loader: "ts"
65
+ }));
51
66
  build.onResolve({ filter: /^@sfmc(?:-bds)?\/sdk(?:\/|$)/ }, (args) => {
52
67
  const normalized = args.path.replace(/^@sfmc\/sdk/, "@sfmc-bds/sdk");
53
68
  const sub = normalized === "@sfmc-bds/sdk" ? "" : normalized.slice("@sfmc-bds/sdk/".length);
69
+ const importerNorm = (args.importer || "").replace(/\\/g, "/");
70
+ const sapiIdx = importerNorm.indexOf("/sapi/");
71
+ if (sapiIdx !== -1 && !importerNorm.includes("@sfmc-sdk") && !importerNorm.includes("@sfmc/sdk")) {
72
+ const sapiDir = importerNorm.slice(0, sapiIdx + "/sapi".length);
73
+ const manifestFile = path.join(sapiDir, "manifest.json");
74
+ let logicalId = "";
75
+ let configKey = "";
76
+ if (existsSync(manifestFile)) {
77
+ try {
78
+ const man = JSON.parse(readFileSync(manifestFile, "utf8"));
79
+ if (man.id) logicalId = man.id;
80
+ if (man.configKey) configKey = man.configKey;
81
+ } catch {
82
+ }
83
+ }
84
+ if (!logicalId) {
85
+ const rootDir = importerNorm.slice(0, sapiIdx);
86
+ logicalId = path.basename(rootDir).replace(/^sfmc-module-/, "");
87
+ configKey = logicalId;
88
+ }
89
+ if (sub === "sapi/db") {
90
+ return {
91
+ path: `sfmc-scoped:db?mod=${encodeURIComponent(logicalId)}`,
92
+ namespace: "sfmc-scoped-db"
93
+ };
94
+ }
95
+ if (sub === "sapi/config") {
96
+ return {
97
+ path: `sfmc-scoped:config?cfg=${encodeURIComponent(configKey)}`,
98
+ namespace: "sfmc-scoped-config"
99
+ };
100
+ }
101
+ if (sub === "sapi/service") {
102
+ return {
103
+ path: `sfmc-scoped:service?mod=${encodeURIComponent(logicalId)}`,
104
+ namespace: "sfmc-scoped-service"
105
+ };
106
+ }
107
+ }
54
108
  const resolved = resolveExportSubpath(sub);
55
109
  if (!resolved) {
56
110
  return {
@@ -61,7 +115,64 @@ function createSdkResolvePlugin(sdkRoot) {
61
115
  ]
62
116
  };
63
117
  }
64
- return { path: resolved };
118
+ return { path: resolved, namespace: "file" };
119
+ });
120
+ build.onLoad({ filter: /.*/, namespace: "sfmc-scoped-db" }, (args) => {
121
+ const u = new URL(args.path);
122
+ const mod = u.searchParams.get("mod") || "";
123
+ return {
124
+ contents: [
125
+ 'import { getDbClient } from "@sfmc-bds/sdk/sapi/db";',
126
+ 'export * from "@sfmc-bds/sdk/sapi/db";',
127
+ "export const db = new Proxy({}, {",
128
+ " get(_t, prop) {",
129
+ ` const c = getDbClient(${JSON.stringify(mod)});`,
130
+ " const val = (c as any)[prop];",
131
+ ' return typeof val === "function" ? val.bind(c) : val;',
132
+ " }",
133
+ "});"
134
+ ].join("\n"),
135
+ loader: "ts",
136
+ resolveDir: sdkRoot
137
+ };
138
+ });
139
+ build.onLoad({ filter: /.*/, namespace: "sfmc-scoped-config" }, (args) => {
140
+ const u = new URL(args.path);
141
+ const cfg = u.searchParams.get("cfg") || "";
142
+ return {
143
+ contents: [
144
+ 'import { getConfigClient } from "@sfmc-bds/sdk/sapi/config";',
145
+ 'export * from "@sfmc-bds/sdk/sapi/config";',
146
+ "export const config = new Proxy({}, {",
147
+ " get(_t, prop) {",
148
+ ` const c = getConfigClient(${JSON.stringify(cfg)});`,
149
+ " const val = (c as any)[prop];",
150
+ ' return typeof val === "function" ? val.bind(c) : val;',
151
+ " }",
152
+ "});"
153
+ ].join("\n"),
154
+ loader: "ts",
155
+ resolveDir: sdkRoot
156
+ };
157
+ });
158
+ build.onLoad({ filter: /.*/, namespace: "sfmc-scoped-service" }, (args) => {
159
+ const u = new URL(args.path);
160
+ const mod = u.searchParams.get("mod") || "";
161
+ return {
162
+ contents: [
163
+ 'import { getServiceClient } from "@sfmc-bds/sdk/sapi/service";',
164
+ 'export * from "@sfmc-bds/sdk/sapi/service";',
165
+ "export const service = new Proxy({}, {",
166
+ " get(_t, prop) {",
167
+ ` const c = getServiceClient(${JSON.stringify(mod)});`,
168
+ " const val = (c as any)[prop];",
169
+ ' return typeof val === "function" ? val.bind(c) : val;',
170
+ " }",
171
+ "});"
172
+ ].join("\n"),
173
+ loader: "ts",
174
+ resolveDir: sdkRoot
175
+ };
65
176
  });
66
177
  }
67
178
  };
@@ -90,12 +201,21 @@ function lockPath() {
90
201
  function catalogPath() {
91
202
  return modulePath(path.join(ROOT, "modules"), "catalog.json");
92
203
  }
204
+ function configuredDbPort(root) {
205
+ const configured = readJson(configPath(root, "db_config.json"));
206
+ const port = configured?.db_port ?? DEFAULT_DB_CONFIG.db_port ?? 3001;
207
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
208
+ throw new Error(`configs/db_config.json: db_port \u5FC5\u987B\u662F 1\u201365535 \u7684\u6574\u6570 (\u5F53\u524D ${port})`);
209
+ }
210
+ return port;
211
+ }
93
212
  function resolveBdsContext(root = getRoot()) {
94
213
  const cfg = readJson(configPath(root, "bds_updater.json")) ?? {};
95
- const bdsRoot = cfg.bds_path;
96
- if (!bdsRoot) {
214
+ const rawBds = cfg.bds_path;
215
+ if (!rawBds) {
97
216
  throw new Error("bds_path not configured. Run `sfmc init` first.");
98
217
  }
218
+ const bdsRoot = path.isAbsolute(rawBds) ? rawBds : path.resolve(root, rawBds);
99
219
  return { bdsRoot, levelName: readLevelNameSync(bdsRoot) };
100
220
  }
101
221
  function deployedBpDir(bdsRoot, levelName) {
@@ -124,11 +244,71 @@ function collectDeployedPackUuids(bdsRoot, levelName) {
124
244
  if (liveRp?.uuid) rp.add(liveRp.uuid);
125
245
  return { bp, rp };
126
246
  }
247
+ async function extractModuleBedrockDependencies(modPath) {
248
+ const deps = [];
249
+ const seen = /* @__PURE__ */ new Set();
250
+ const manifestPath = path.join(modPath, "sapi", "manifest.json");
251
+ if (existsSync(manifestPath)) {
252
+ try {
253
+ const raw = JSON.parse(await fs.readFile(manifestPath, "utf8"));
254
+ if (Array.isArray(raw.dependencies)) {
255
+ for (const d of raw.dependencies) {
256
+ if (d && typeof d === "object" && typeof d.module_name === "string" && d.module_name.startsWith("@minecraft/") && NATIVE_BEDROCK_SCRIPT_MODULES.has(d.module_name)) {
257
+ const modName = d.module_name;
258
+ const ver = String(d.version ?? "1.0.0");
259
+ const uuid = typeof d.uuid === "string" ? d.uuid : void 0;
260
+ deps.push({ module_name: modName, version: ver, ...uuid ? { uuid } : {} });
261
+ seen.add(modName);
262
+ }
263
+ }
264
+ } else if (raw.dependencies && typeof raw.dependencies === "object") {
265
+ for (const [modName, ver] of Object.entries(raw.dependencies)) {
266
+ if (modName.startsWith("@minecraft/") && !seen.has(modName) && NATIVE_BEDROCK_SCRIPT_MODULES.has(modName)) {
267
+ deps.push({ module_name: modName, version: String(ver ?? "1.0.0") });
268
+ seen.add(modName);
269
+ }
270
+ }
271
+ }
272
+ if (raw.minecraft && typeof raw.minecraft === "object") {
273
+ const mc = raw.minecraft;
274
+ const mcDeps = Array.isArray(mc.dependencies) ? mc.dependencies : mc;
275
+ if (typeof mcDeps === "object" && !Array.isArray(mcDeps)) {
276
+ for (const [modName, ver] of Object.entries(mcDeps)) {
277
+ if (modName.startsWith("@minecraft/") && !seen.has(modName) && NATIVE_BEDROCK_SCRIPT_MODULES.has(modName)) {
278
+ deps.push({ module_name: modName, version: String(ver ?? "1.0.0") });
279
+ seen.add(modName);
280
+ }
281
+ }
282
+ }
283
+ }
284
+ } catch {
285
+ }
286
+ }
287
+ const pkgPath = path.join(modPath, "package.json");
288
+ if (existsSync(pkgPath)) {
289
+ try {
290
+ const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
291
+ const candidateMap = {
292
+ ...pkg.devDependencies ?? {},
293
+ ...pkg.dependencies ?? {},
294
+ ...pkg.peerDependencies ?? {}
295
+ };
296
+ for (const [modName, ver] of Object.entries(candidateMap)) {
297
+ if (modName.startsWith("@minecraft/") && !seen.has(modName) && NATIVE_BEDROCK_SCRIPT_MODULES.has(modName)) {
298
+ deps.push({ module_name: modName, version: ver });
299
+ seen.add(modName);
300
+ }
301
+ }
302
+ } catch {
303
+ }
304
+ }
305
+ return deps;
306
+ }
127
307
  async function scanLocalModules() {
128
308
  const dir = packagesDir();
129
309
  if (!existsSync(dir)) return [];
130
310
  const lock = readJson(lockPath()) ?? { version: 1, modules: {} };
131
- const cat = readJson(catalogPath()) ?? {};
311
+ const cat = readJson(catalogPath()) ?? { version: 1, modules: [] };
132
312
  const defaults = /* @__PURE__ */ new Map();
133
313
  if (Array.isArray(cat.modules)) {
134
314
  for (const m of cat.modules) {
@@ -166,6 +346,7 @@ async function scanLocalModules() {
166
346
  const hasResourcePack = existsSync(path.join(modPath, "resource_pack"));
167
347
  const fingerprint = await dirFingerprint(modPath);
168
348
  const enabled = isModuleEnabled(logicalId, lock, defaults);
349
+ const declaredDependencies = await extractModuleBedrockDependencies(modPath);
169
350
  out.push({
170
351
  folderId,
171
352
  logicalId,
@@ -174,7 +355,8 @@ async function scanLocalModules() {
174
355
  hasSapi,
175
356
  hasResourcePack,
176
357
  fingerprint,
177
- entryPath: hasSapi ? entryPath : null
358
+ entryPath: hasSapi ? entryPath : null,
359
+ declaredDependencies
178
360
  });
179
361
  }
180
362
  out.sort((a, b) => a.folderId.localeCompare(b.folderId));
@@ -207,8 +389,26 @@ async function computeDesiredCatalog(opts) {
207
389
  rpVersion = opts?.rpVersion ?? localRp?.version ?? DEFAULT_PACK_VERSION;
208
390
  rpModuleUuid = opts?.rpModuleUuid ?? localRp?.moduleUuid;
209
391
  }
392
+ let sdkVersion;
393
+ try {
394
+ const sdkRoot = resolveSdkPackageRoot();
395
+ const pkg = JSON.parse(readFileSync(path.join(sdkRoot, "package.json"), "utf8"));
396
+ sdkVersion = pkg.version;
397
+ } catch {
398
+ }
399
+ const enabledModuleReqs = mods.filter((m) => m.enabled && m.declaredDependencies.length > 0).map((m) => ({ folderId: m.folderId, dependencies: m.declaredDependencies }));
400
+ const negotiated = negotiateBedrockDependencies(BASELINE_BEDROCK_DEPENDENCIES, enabledModuleReqs);
401
+ if (negotiated.promotions.length > 0) {
402
+ for (const p of negotiated.promotions) {
403
+ packLog(
404
+ `promoted ${p.moduleName} ${p.from} -> ${p.to} (requested by: ${p.requestedBy.join(", ")})`,
405
+ "info"
406
+ );
407
+ }
408
+ }
210
409
  return {
211
410
  schemaVersion: 1,
411
+ dbPort: configuredDbPort(getRoot()),
212
412
  bpUuid,
213
413
  rpUuid,
214
414
  bpVersion,
@@ -216,6 +416,8 @@ async function computeDesiredCatalog(opts) {
216
416
  ...bpModuleUuid ? { bpModuleUuid } : {},
217
417
  ...rpModuleUuid ? { rpModuleUuid } : {},
218
418
  generatedAt: Date.now(),
419
+ ...sdkVersion ? { sdkVersion } : {},
420
+ dependencies: negotiated.dependencies,
219
421
  modules
220
422
  };
221
423
  }
@@ -229,8 +431,20 @@ function readDeployedCatalog(bdsRoot, levelName) {
229
431
  }
230
432
  }
231
433
  function catalogsEqual(a, b) {
434
+ if (a.dbPort !== b.dbPort) return false;
232
435
  if (a.bpUuid !== b.bpUuid) return false;
233
436
  if ((a.rpUuid ?? null) !== (b.rpUuid ?? null)) return false;
437
+ if ((a.sdkVersion ?? null) !== (b.sdkVersion ?? null)) return false;
438
+ const depsA = a.dependencies ?? [];
439
+ const depsB = b.dependencies ?? [];
440
+ if (depsA.length !== depsB.length) return false;
441
+ for (let i = 0; i < depsA.length; i++) {
442
+ const da = depsA[i];
443
+ const db = depsB[i];
444
+ if (!da || !db || da.module_name !== db.module_name || da.version !== db.version) {
445
+ return false;
446
+ }
447
+ }
234
448
  const aKeys = Object.keys(a.modules).sort();
235
449
  const bKeys = Object.keys(b.modules).sort();
236
450
  if (aKeys.length !== bKeys.length) return false;
@@ -270,19 +484,23 @@ async function buildPacks(desired) {
270
484
  const sdkRoot = resolveSdkPackageRoot();
271
485
  packLog(`SDK root: ${sdkRoot}`);
272
486
  await build({
273
- entryPoints: entries,
487
+ stdin: {
488
+ contents: [
489
+ 'import "sfmc:host";',
490
+ ...entries.map((e) => `import ${JSON.stringify(path.resolve(e).replace(/\\/g, "/"))};`)
491
+ ].join("\n"),
492
+ resolveDir: ROOT,
493
+ sourcefile: "bootstrap.ts",
494
+ loader: "ts"
495
+ },
274
496
  outfile: outFile,
275
497
  bundle: true,
276
498
  platform: "neutral",
277
499
  format: "esm",
278
500
  target: "es2022",
279
501
  logLevel: "warning",
280
- sourcemap: false,
502
+ sourcemap: true,
281
503
  external: ["@minecraft/*"],
282
- // BDS host 启动:与 module-loader barrel 分离(DIP),须在模块 register 之前执行
283
- banner: {
284
- js: 'import { installHostBootstrap } from "@sfmc-bds/sdk/module-loader/install";\ninstallHostBootstrap();\n'
285
- },
286
504
  // 避免读取模块内残缺的 extends(如 ../../../sdk/@sfmc-sdk/tsconfig.json)
287
505
  tsconfigRaw: JSON.stringify({
288
506
  compilerOptions: {
@@ -293,7 +511,7 @@ async function buildPacks(desired) {
293
511
  skipLibCheck: true
294
512
  }
295
513
  }),
296
- plugins: [createSdkResolvePlugin(sdkRoot)]
514
+ plugins: [createSdkResolvePlugin(sdkRoot, catalog.dbPort)]
297
515
  });
298
516
  packLog(`esbuild bundled ${entries.length} entr(y/ies)`, "success");
299
517
  }
@@ -305,7 +523,8 @@ async function buildPacks(desired) {
305
523
  version: catalog.bpVersion,
306
524
  description: "ScriptsForMinecraftServer aggregated behavior pack",
307
525
  uuid: catalog.bpUuid,
308
- ...catalog.bpModuleUuid ? { moduleUuid: catalog.bpModuleUuid } : {}
526
+ ...catalog.bpModuleUuid ? { moduleUuid: catalog.bpModuleUuid } : {},
527
+ ...catalog.dependencies ? { dependencies: catalog.dependencies } : {}
309
528
  });
310
529
  } catch (e) {
311
530
  throw new Error(`assemble-bp failed: ${e.message}`);
@@ -431,6 +650,10 @@ function formatPackLoadInfo(catalog, rebuilt) {
431
650
  catalog.rpUuid ? ` RP ${catalog.rpUuid} v${(catalog.rpVersion ?? DEFAULT_PACK_VERSION).join(".")}` : ` RP (none)`,
432
651
  ` modules: ${enabled.length} enabled / ${disabled.length} disabled / ${mods.length} installed`
433
652
  ];
653
+ if (catalog.dependencies && catalog.dependencies.length > 0) {
654
+ const depStr = catalog.dependencies.map((d) => `${d.module_name}@${d.version}`).join(" ");
655
+ lines.push(` dependencies: ${depStr}`);
656
+ }
434
657
  for (const [folderId, m] of enabled.sort((a, b) => a[0].localeCompare(b[0]))) {
435
658
  lines.push(` \u25CF ${folderId} (${m.logicalId}) ${m.version}${m.hasResourcePack ? " +rp" : ""}`);
436
659
  }
@@ -474,6 +697,8 @@ async function ensurePacksReady() {
474
697
  if (deployed.rpUuid && !worldPackListHas(bdsRoot, levelName, "resource", deployed.rpUuid)) {
475
698
  needRebuild = true;
476
699
  }
700
+ const deployedMainJs = path.join(deployedBpDir(bdsRoot, levelName), "scripts", "main.js");
701
+ if (!existsSync(deployedMainJs)) needRebuild = true;
477
702
  if (!hasConfigPermission(bdsRoot, deployed.bpUuid)) {
478
703
  try {
479
704
  const wrote = await ensureConfigPermission(bdsRoot, deployed.bpUuid);
@@ -630,11 +855,13 @@ export {
630
855
  cmdPackList,
631
856
  cmdPackStatus,
632
857
  computeDesiredCatalog,
858
+ createSdkResolvePlugin,
633
859
  deployPacks,
634
860
  deployedBpDir,
635
861
  deployedCatalogPath,
636
862
  deployedRpDir,
637
863
  ensurePacksReady,
864
+ extractModuleBedrockDependencies,
638
865
  formatPackLoadInfo,
639
866
  readDeployedCatalog,
640
867
  resolveBdsContext,