@sfmc-bds/cli 0.1.0 → 0.2.0-beta.0
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 +7 -1
- package/dist/cli-result.d.ts +12 -0
- package/dist/cli-result.d.ts.map +1 -0
- package/dist/cli-result.js +15 -0
- package/dist/cli-result.js.map +7 -0
- package/dist/commands-behavior-pack.d.ts +11 -42
- package/dist/commands-behavior-pack.d.ts.map +1 -1
- package/dist/commands-behavior-pack.js +40 -159
- package/dist/commands-behavior-pack.js.map +7 -1
- package/dist/commands-reload.d.ts +9 -0
- package/dist/commands-reload.d.ts.map +1 -0
- package/dist/commands-reload.js +30 -0
- package/dist/commands-reload.js.map +7 -0
- package/dist/commands.d.ts +7 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +182 -172
- package/dist/commands.js.map +7 -1
- package/dist/i18n/index.d.ts +26 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +107 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/locales/en.d.ts +381 -0
- package/dist/i18n/locales/en.d.ts.map +1 -0
- package/dist/i18n/locales/en.js +393 -0
- package/dist/i18n/locales/en.js.map +7 -0
- package/dist/i18n/locales/zh-CN.d.ts +4 -0
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -0
- package/dist/i18n/locales/zh-CN.js +379 -0
- package/dist/i18n/locales/zh-CN.js.map +7 -0
- package/dist/i18n/types.d.ts +7 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +17 -0
- package/dist/i18n/types.js.map +7 -0
- package/dist/index.d.ts +5 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -43
- package/dist/index.js.map +7 -1
- package/dist/interactive-prompts.d.ts +8 -0
- package/dist/interactive-prompts.d.ts.map +1 -0
- package/dist/interactive-prompts.js +57 -0
- package/dist/interactive-prompts.js.map +7 -0
- package/dist/locale-command.d.ts +3 -0
- package/dist/locale-command.d.ts.map +1 -0
- package/dist/locale-command.js +19 -0
- package/dist/locale-command.js.map +7 -0
- package/dist/logs.d.ts +22 -4
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +208 -193
- package/dist/logs.js.map +7 -1
- package/dist/main.js +135 -173
- package/dist/main.js.map +7 -1
- package/dist/module-commands.d.ts +43 -4
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +440 -327
- package/dist/module-commands.js.map +7 -1
- package/dist/module-fingerprint.d.ts +7 -0
- package/dist/module-fingerprint.d.ts.map +1 -0
- package/dist/module-fingerprint.js +31 -0
- package/dist/module-fingerprint.js.map +7 -0
- package/dist/module-wizard.d.ts +14 -0
- package/dist/module-wizard.d.ts.map +1 -0
- package/dist/module-wizard.js +313 -0
- package/dist/module-wizard.js.map +7 -0
- package/dist/pack-lifecycle.d.ts +95 -0
- package/dist/pack-lifecycle.d.ts.map +1 -0
- package/dist/pack-lifecycle.js +634 -0
- package/dist/pack-lifecycle.js.map +7 -0
- package/dist/pack-update/bindings.d.ts +12 -0
- package/dist/pack-update/bindings.d.ts.map +1 -0
- package/dist/pack-update/bindings.js +64 -0
- package/dist/pack-update/bindings.js.map +7 -0
- package/dist/pack-update/config.d.ts +22 -0
- package/dist/pack-update/config.d.ts.map +1 -0
- package/dist/pack-update/config.js +141 -0
- package/dist/pack-update/config.js.map +7 -0
- package/dist/pack-update/providers/curseforge.d.ts +23 -0
- package/dist/pack-update/providers/curseforge.d.ts.map +1 -0
- package/dist/pack-update/providers/curseforge.js +209 -0
- package/dist/pack-update/providers/curseforge.js.map +7 -0
- package/dist/pack-update/providers/index.d.ts +16 -0
- package/dist/pack-update/providers/index.d.ts.map +1 -0
- package/dist/pack-update/providers/index.js +37 -0
- package/dist/pack-update/providers/index.js.map +7 -0
- package/dist/pack-update/service.d.ts +21 -0
- package/dist/pack-update/service.d.ts.map +1 -0
- package/dist/pack-update/service.js +567 -0
- package/dist/pack-update/service.js.map +7 -0
- package/dist/pack-update/types.d.ts +126 -0
- package/dist/pack-update/types.d.ts.map +1 -0
- package/dist/pack-update/types.js +8 -0
- package/dist/pack-update/types.js.map +7 -0
- package/dist/pack-update/version-policy.d.ts +80 -0
- package/dist/pack-update/version-policy.d.ts.map +1 -0
- package/dist/pack-update/version-policy.js +216 -0
- package/dist/pack-update/version-policy.js.map +7 -0
- package/dist/registry.d.ts +12 -4
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +73 -106
- package/dist/registry.js.map +7 -1
- package/dist/remote-agent.d.ts.map +1 -1
- package/dist/remote-agent.js +160 -176
- package/dist/remote-agent.js.map +7 -1
- package/dist/repl.d.ts +4 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +683 -605
- package/dist/repl.js.map +7 -1
- package/dist/runtime.d.ts +40 -14
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +185 -62
- package/dist/runtime.js.map +7 -1
- package/dist/services.d.ts +2 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +251 -238
- package/dist/services.js.map +7 -1
- package/dist/sfmc-modules-root.d.ts +24 -0
- package/dist/sfmc-modules-root.d.ts.map +1 -0
- package/dist/sfmc-modules-root.js +70 -0
- package/dist/sfmc-modules-root.js.map +7 -0
- package/dist/theme.d.ts +4 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +134 -48
- package/dist/theme.js.map +7 -1
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +363 -438
- package/dist/wizard.js.map +7 -1
- package/dist/world-packs.d.ts +22 -0
- package/dist/world-packs.d.ts.map +1 -0
- package/dist/world-packs.js +872 -0
- package/dist/world-packs.js.map +7 -0
- package/package.json +10 -10
- package/dist/dispatcher.d.ts +0 -13
- package/dist/dispatcher.d.ts.map +0 -1
- package/dist/dispatcher.js +0 -23
- package/dist/dispatcher.js.map +0 -1
- package/dist/terminal.d.ts +0 -3
- package/dist/terminal.d.ts.map +0 -1
- package/dist/terminal.js +0 -178
- package/dist/terminal.js.map +0 -1
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
import {
|
|
2
|
+
configPath,
|
|
3
|
+
modulePath,
|
|
4
|
+
readJson,
|
|
5
|
+
writeJson
|
|
6
|
+
} from "@sfmc-bds/sdk/node/config";
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import fs from "node:fs/promises";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { pushLog } from "./logs.js";
|
|
11
|
+
import { dirFingerprint } from "./module-fingerprint.js";
|
|
12
|
+
import { failResult, okResult } from "./cli-result.js";
|
|
13
|
+
import { t } from "./i18n/index.js";
|
|
14
|
+
import {
|
|
15
|
+
assembleBehaviorPack,
|
|
16
|
+
assembleResourcePack,
|
|
17
|
+
bdsWorldLevelDir,
|
|
18
|
+
bdsWorldsDir,
|
|
19
|
+
configPermissionPath,
|
|
20
|
+
deployToBDS,
|
|
21
|
+
disablePackInWorld,
|
|
22
|
+
enablePackInWorld,
|
|
23
|
+
ensureConfigPermission,
|
|
24
|
+
hasConfigPermission,
|
|
25
|
+
readLevelNameSync,
|
|
26
|
+
readPackManifestHeader,
|
|
27
|
+
readWorldPackList,
|
|
28
|
+
worldPackListHas as pmWorldPackListHas
|
|
29
|
+
} from "@sfmc-bds/bds-tools/pack-manager-lib";
|
|
30
|
+
import { ROOT, PACKAGES_DIR, resolveSdkPackageRoot } from "./runtime.js";
|
|
31
|
+
import { c } from "./theme.js";
|
|
32
|
+
const BP_NAME = "sfmc-modules";
|
|
33
|
+
const RP_NAME = "sfmc-modules-rp";
|
|
34
|
+
const DEPLOY_CATALOG_NAME = "sfmc-deploy-catalog.json";
|
|
35
|
+
const DEFAULT_PACK_VERSION = [1, 0, 0];
|
|
36
|
+
function createSdkResolvePlugin(sdkRoot) {
|
|
37
|
+
const pkg = JSON.parse(readFileSync(path.join(sdkRoot, "package.json"), "utf8"));
|
|
38
|
+
const exportsMap = pkg.exports ?? {};
|
|
39
|
+
function resolveExportSubpath(subpath) {
|
|
40
|
+
const key = subpath === "" ? "." : `./${subpath}`;
|
|
41
|
+
const entry = exportsMap[key];
|
|
42
|
+
if (!entry) return null;
|
|
43
|
+
const rel = typeof entry === "string" ? entry : entry.import ?? entry.default;
|
|
44
|
+
if (!rel || typeof rel !== "string") return null;
|
|
45
|
+
const abs = path.join(sdkRoot, rel);
|
|
46
|
+
return existsSync(abs) ? abs : null;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
name: "sfmc-sdk-resolve",
|
|
50
|
+
setup(build) {
|
|
51
|
+
build.onResolve({ filter: /^@sfmc(?:-bds)?\/sdk(?:\/|$)/ }, (args) => {
|
|
52
|
+
const normalized = args.path.replace(/^@sfmc\/sdk/, "@sfmc-bds/sdk");
|
|
53
|
+
const sub = normalized === "@sfmc-bds/sdk" ? "" : normalized.slice("@sfmc-bds/sdk/".length);
|
|
54
|
+
const resolved = resolveExportSubpath(sub);
|
|
55
|
+
if (!resolved) {
|
|
56
|
+
return {
|
|
57
|
+
errors: [
|
|
58
|
+
{
|
|
59
|
+
text: `Cannot resolve ${args.path} under SDK at ${sdkRoot} (export "./${sub || "."}" missing or file absent; run sdk:build?)`
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { path: resolved };
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function buildRoot() {
|
|
70
|
+
return path.join(ROOT, "packs", "_build");
|
|
71
|
+
}
|
|
72
|
+
function bpSrc() {
|
|
73
|
+
return path.join(buildRoot(), `${BP_NAME}-bp`);
|
|
74
|
+
}
|
|
75
|
+
function bpOut() {
|
|
76
|
+
return path.join(buildRoot(), BP_NAME);
|
|
77
|
+
}
|
|
78
|
+
function rpOut() {
|
|
79
|
+
return path.join(buildRoot(), RP_NAME);
|
|
80
|
+
}
|
|
81
|
+
function packLog(text, level = "info") {
|
|
82
|
+
pushLog(text, "pack", level);
|
|
83
|
+
}
|
|
84
|
+
function packagesDir() {
|
|
85
|
+
return PACKAGES_DIR || path.join(ROOT, "modules", "packages");
|
|
86
|
+
}
|
|
87
|
+
function lockPath() {
|
|
88
|
+
return modulePath(path.join(ROOT, "modules"), "module-lock.json");
|
|
89
|
+
}
|
|
90
|
+
function catalogPath() {
|
|
91
|
+
return modulePath(path.join(ROOT, "modules"), "catalog.json");
|
|
92
|
+
}
|
|
93
|
+
function resolveBdsContext() {
|
|
94
|
+
const cfg = readJson(configPath(ROOT, "bds_updater.json")) ?? {};
|
|
95
|
+
const bdsRoot = cfg.bds_path;
|
|
96
|
+
if (!bdsRoot) {
|
|
97
|
+
throw new Error("bds_path not configured. Run `sfmc init` first.");
|
|
98
|
+
}
|
|
99
|
+
return { bdsRoot, levelName: readLevelNameSync(bdsRoot) };
|
|
100
|
+
}
|
|
101
|
+
function deployedBpDir(bdsRoot, levelName) {
|
|
102
|
+
return path.join(bdsWorldLevelDir(bdsRoot, levelName), "behavior_packs", BP_NAME);
|
|
103
|
+
}
|
|
104
|
+
function deployedRpDir(bdsRoot, levelName) {
|
|
105
|
+
return path.join(bdsWorldLevelDir(bdsRoot, levelName), "resource_packs", RP_NAME);
|
|
106
|
+
}
|
|
107
|
+
function deployedCatalogPath(bdsRoot, levelName) {
|
|
108
|
+
return path.join(deployedBpDir(bdsRoot, levelName), DEPLOY_CATALOG_NAME);
|
|
109
|
+
}
|
|
110
|
+
function isModuleEnabled(logicalId, lock, catalogDefaults) {
|
|
111
|
+
const st = lock.modules?.[logicalId];
|
|
112
|
+
if (st && typeof st.enabled === "boolean") return st.enabled;
|
|
113
|
+
return catalogDefaults.get(logicalId) ?? false;
|
|
114
|
+
}
|
|
115
|
+
function collectDeployedPackUuids(bdsRoot, levelName) {
|
|
116
|
+
const bp = /* @__PURE__ */ new Set();
|
|
117
|
+
const rp = /* @__PURE__ */ new Set();
|
|
118
|
+
const cat = readDeployedCatalog(bdsRoot, levelName);
|
|
119
|
+
if (cat?.bpUuid) bp.add(cat.bpUuid);
|
|
120
|
+
if (cat?.rpUuid) rp.add(cat.rpUuid);
|
|
121
|
+
const liveBp = readPackManifestHeader(deployedBpDir(bdsRoot, levelName));
|
|
122
|
+
const liveRp = readPackManifestHeader(deployedRpDir(bdsRoot, levelName));
|
|
123
|
+
if (liveBp?.uuid) bp.add(liveBp.uuid);
|
|
124
|
+
if (liveRp?.uuid) rp.add(liveRp.uuid);
|
|
125
|
+
return { bp, rp };
|
|
126
|
+
}
|
|
127
|
+
async function scanLocalModules() {
|
|
128
|
+
const dir = packagesDir();
|
|
129
|
+
if (!existsSync(dir)) return [];
|
|
130
|
+
const lock = readJson(lockPath()) ?? { version: 1, modules: {} };
|
|
131
|
+
const cat = readJson(catalogPath()) ?? {};
|
|
132
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
133
|
+
if (Array.isArray(cat.modules)) {
|
|
134
|
+
for (const m of cat.modules) {
|
|
135
|
+
const id = typeof m.id === "string" ? m.id : "";
|
|
136
|
+
if (!id) continue;
|
|
137
|
+
defaults.set(id, m.enabledByDefault !== false);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
141
|
+
const out = [];
|
|
142
|
+
for (const e of entries) {
|
|
143
|
+
if (!e.isDirectory()) continue;
|
|
144
|
+
const folderId = e.name;
|
|
145
|
+
const modPath = path.join(dir, folderId);
|
|
146
|
+
const manifestPath = path.join(modPath, "sapi", "manifest.json");
|
|
147
|
+
const entryPath = path.join(modPath, "sapi", "src", "index.ts");
|
|
148
|
+
let logicalId = folderId;
|
|
149
|
+
let version = "0.0.0";
|
|
150
|
+
if (existsSync(manifestPath)) {
|
|
151
|
+
try {
|
|
152
|
+
const man = JSON.parse(await fs.readFile(manifestPath, "utf8"));
|
|
153
|
+
if (typeof man.id === "string" && man.id) logicalId = man.id;
|
|
154
|
+
if (typeof man.version === "string" && man.version) version = man.version;
|
|
155
|
+
else if (typeof man.schemaVersion === "number") version = `schema-${man.schemaVersion}`;
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const hasSapi = existsSync(entryPath);
|
|
160
|
+
const hasResourcePack = existsSync(path.join(modPath, "resource_pack"));
|
|
161
|
+
const fingerprint = await dirFingerprint(modPath);
|
|
162
|
+
const enabled = isModuleEnabled(logicalId, lock, defaults);
|
|
163
|
+
out.push({
|
|
164
|
+
folderId,
|
|
165
|
+
logicalId,
|
|
166
|
+
version,
|
|
167
|
+
enabled,
|
|
168
|
+
hasSapi,
|
|
169
|
+
hasResourcePack,
|
|
170
|
+
fingerprint,
|
|
171
|
+
entryPath: hasSapi ? entryPath : null
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
out.sort((a, b) => a.folderId.localeCompare(b.folderId));
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
async function computeDesiredCatalog(opts) {
|
|
178
|
+
const mods = await scanLocalModules();
|
|
179
|
+
const modules = {};
|
|
180
|
+
let anyRp = false;
|
|
181
|
+
for (const m of mods) {
|
|
182
|
+
modules[m.folderId] = {
|
|
183
|
+
logicalId: m.logicalId,
|
|
184
|
+
enabled: m.enabled,
|
|
185
|
+
version: m.version,
|
|
186
|
+
fingerprint: m.fingerprint,
|
|
187
|
+
hasResourcePack: m.hasResourcePack
|
|
188
|
+
};
|
|
189
|
+
if (m.enabled && m.hasResourcePack) anyRp = true;
|
|
190
|
+
}
|
|
191
|
+
const localBp = readPackManifestHeader(bpOut());
|
|
192
|
+
const localRp = readPackManifestHeader(rpOut());
|
|
193
|
+
const bpUuid = opts?.bpUuid ?? localBp?.uuid ?? crypto.randomUUID();
|
|
194
|
+
const bpVersion = opts?.bpVersion ?? localBp?.version ?? DEFAULT_PACK_VERSION;
|
|
195
|
+
const bpModuleUuid = opts?.bpModuleUuid ?? localBp?.moduleUuid;
|
|
196
|
+
let rpUuid = null;
|
|
197
|
+
let rpVersion = null;
|
|
198
|
+
let rpModuleUuid;
|
|
199
|
+
if (anyRp) {
|
|
200
|
+
rpUuid = opts?.rpUuid ?? localRp?.uuid ?? crypto.randomUUID();
|
|
201
|
+
rpVersion = opts?.rpVersion ?? localRp?.version ?? DEFAULT_PACK_VERSION;
|
|
202
|
+
rpModuleUuid = opts?.rpModuleUuid ?? localRp?.moduleUuid;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
schemaVersion: 1,
|
|
206
|
+
bpUuid,
|
|
207
|
+
rpUuid,
|
|
208
|
+
bpVersion,
|
|
209
|
+
rpVersion,
|
|
210
|
+
...bpModuleUuid ? { bpModuleUuid } : {},
|
|
211
|
+
...rpModuleUuid ? { rpModuleUuid } : {},
|
|
212
|
+
generatedAt: Date.now(),
|
|
213
|
+
modules
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function readDeployedCatalog(bdsRoot, levelName) {
|
|
217
|
+
const file = deployedCatalogPath(bdsRoot, levelName);
|
|
218
|
+
if (!existsSync(file)) return null;
|
|
219
|
+
try {
|
|
220
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
221
|
+
} catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function catalogsEqual(a, b) {
|
|
226
|
+
if (a.bpUuid !== b.bpUuid) return false;
|
|
227
|
+
if ((a.rpUuid ?? null) !== (b.rpUuid ?? null)) return false;
|
|
228
|
+
const aKeys = Object.keys(a.modules).sort();
|
|
229
|
+
const bKeys = Object.keys(b.modules).sort();
|
|
230
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
231
|
+
for (let i = 0; i < aKeys.length; i++) {
|
|
232
|
+
if (aKeys[i] !== bKeys[i]) return false;
|
|
233
|
+
}
|
|
234
|
+
for (const k of aKeys) {
|
|
235
|
+
const x = a.modules[k];
|
|
236
|
+
const y = b.modules[k];
|
|
237
|
+
if (x.logicalId !== y.logicalId || x.enabled !== y.enabled || x.version !== y.version || x.fingerprint !== y.fingerprint || x.hasResourcePack !== y.hasResourcePack) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
function worldPackListHas(bdsRoot, levelName, kind, uuid) {
|
|
244
|
+
return pmWorldPackListHas(bdsWorldsDir(bdsRoot), levelName, kind, uuid);
|
|
245
|
+
}
|
|
246
|
+
async function buildPacks(desired) {
|
|
247
|
+
await fs.mkdir(buildRoot(), { recursive: true });
|
|
248
|
+
const catalog = desired ?? await computeDesiredCatalog();
|
|
249
|
+
packLog(`building BP/RP (modules=${Object.keys(catalog.modules).length})\u2026`);
|
|
250
|
+
const mods = await scanLocalModules();
|
|
251
|
+
const entries = mods.filter((m) => m.enabled && m.entryPath).map((m) => m.entryPath);
|
|
252
|
+
const rpDirs = {};
|
|
253
|
+
for (const m of mods) {
|
|
254
|
+
if (!m.enabled || !m.hasResourcePack) continue;
|
|
255
|
+
rpDirs[m.folderId] = path.join(packagesDir(), m.folderId, "resource_pack");
|
|
256
|
+
}
|
|
257
|
+
const { build } = await import("esbuild");
|
|
258
|
+
const outFile = path.join(bpSrc(), "scripts", "main.js");
|
|
259
|
+
await fs.mkdir(path.dirname(outFile), { recursive: true });
|
|
260
|
+
if (entries.length === 0) {
|
|
261
|
+
await fs.writeFile(outFile, "/* no modules enabled */\n", "utf8");
|
|
262
|
+
packLog("no enabled SAPI modules \u2014 empty main.js", "warn");
|
|
263
|
+
} else {
|
|
264
|
+
const sdkRoot = resolveSdkPackageRoot();
|
|
265
|
+
packLog(`SDK root: ${sdkRoot}`);
|
|
266
|
+
await build({
|
|
267
|
+
entryPoints: entries,
|
|
268
|
+
outfile: outFile,
|
|
269
|
+
bundle: true,
|
|
270
|
+
platform: "neutral",
|
|
271
|
+
format: "esm",
|
|
272
|
+
target: "es2022",
|
|
273
|
+
logLevel: "warning",
|
|
274
|
+
sourcemap: false,
|
|
275
|
+
external: ["@minecraft/*"],
|
|
276
|
+
// 避免读取模块内残缺的 extends(如 ../../../sdk/@sfmc-sdk/tsconfig.json)
|
|
277
|
+
tsconfigRaw: JSON.stringify({
|
|
278
|
+
compilerOptions: {
|
|
279
|
+
module: "ESNext",
|
|
280
|
+
moduleResolution: "bundler",
|
|
281
|
+
target: "ES2022",
|
|
282
|
+
strict: true,
|
|
283
|
+
skipLibCheck: true
|
|
284
|
+
}
|
|
285
|
+
}),
|
|
286
|
+
plugins: [createSdkResolvePlugin(sdkRoot)]
|
|
287
|
+
});
|
|
288
|
+
packLog(`esbuild bundled ${entries.length} entr(y/ies)`, "success");
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
await assembleBehaviorPack({
|
|
292
|
+
srcDir: bpSrc(),
|
|
293
|
+
outDir: bpOut(),
|
|
294
|
+
projectName: BP_NAME,
|
|
295
|
+
version: catalog.bpVersion,
|
|
296
|
+
description: "ScriptsForMinecraftServer aggregated behavior pack",
|
|
297
|
+
uuid: catalog.bpUuid,
|
|
298
|
+
...catalog.bpModuleUuid ? { moduleUuid: catalog.bpModuleUuid } : {}
|
|
299
|
+
});
|
|
300
|
+
} catch (e) {
|
|
301
|
+
throw new Error(`assemble-bp failed: ${e.message}`);
|
|
302
|
+
}
|
|
303
|
+
packLog(`assembled BP uuid=${catalog.bpUuid}`, "success");
|
|
304
|
+
if (Object.keys(rpDirs).length > 0 && catalog.rpUuid) {
|
|
305
|
+
try {
|
|
306
|
+
await assembleResourcePack({
|
|
307
|
+
moduleResourceDirs: rpDirs,
|
|
308
|
+
outDir: rpOut(),
|
|
309
|
+
projectName: RP_NAME,
|
|
310
|
+
version: catalog.rpVersion ?? DEFAULT_PACK_VERSION,
|
|
311
|
+
description: "ScriptsForMinecraftServer aggregated resource pack",
|
|
312
|
+
uuid: catalog.rpUuid,
|
|
313
|
+
...catalog.rpModuleUuid ? { moduleUuid: catalog.rpModuleUuid } : {}
|
|
314
|
+
});
|
|
315
|
+
} catch (e) {
|
|
316
|
+
throw new Error(`assemble-rp failed: ${e.message}`);
|
|
317
|
+
}
|
|
318
|
+
packLog(`assembled RP uuid=${catalog.rpUuid} (${Object.keys(rpDirs).length} modules)`, "success");
|
|
319
|
+
} else {
|
|
320
|
+
await fs.rm(rpOut(), { recursive: true, force: true });
|
|
321
|
+
catalog.rpUuid = null;
|
|
322
|
+
catalog.rpVersion = null;
|
|
323
|
+
packLog("no enabled resource packs \u2014 RP skipped");
|
|
324
|
+
}
|
|
325
|
+
catalog.generatedAt = Date.now();
|
|
326
|
+
writeJson(path.join(bpOut(), DEPLOY_CATALOG_NAME), catalog);
|
|
327
|
+
return catalog;
|
|
328
|
+
}
|
|
329
|
+
async function deployPacks(catalog) {
|
|
330
|
+
const { bdsRoot, levelName } = resolveBdsContext();
|
|
331
|
+
if (!existsSync(bpOut())) {
|
|
332
|
+
throw new Error(`BP not built at ${bpOut()}. Run build first.`);
|
|
333
|
+
}
|
|
334
|
+
const previous = collectDeployedPackUuids(bdsRoot, levelName);
|
|
335
|
+
try {
|
|
336
|
+
await deployToBDS({
|
|
337
|
+
bdsRoot,
|
|
338
|
+
levelName,
|
|
339
|
+
behaviorPackSrc: bpOut(),
|
|
340
|
+
bpName: BP_NAME,
|
|
341
|
+
rpName: RP_NAME,
|
|
342
|
+
...catalog.rpUuid && existsSync(rpOut()) ? { resourcePackSrc: rpOut() } : { clearResourcePack: true }
|
|
343
|
+
});
|
|
344
|
+
} catch (e) {
|
|
345
|
+
throw new Error(`deploy failed: ${e.message}`);
|
|
346
|
+
}
|
|
347
|
+
packLog(`deployed to worlds/${levelName}`, "success");
|
|
348
|
+
writeJson(path.join(deployedBpDir(bdsRoot, levelName), DEPLOY_CATALOG_NAME), catalog);
|
|
349
|
+
const worldsDir = bdsWorldsDir(bdsRoot);
|
|
350
|
+
try {
|
|
351
|
+
await enablePackInWorld({
|
|
352
|
+
worldsDir,
|
|
353
|
+
levelName,
|
|
354
|
+
kind: "behavior",
|
|
355
|
+
packUuid: catalog.bpUuid,
|
|
356
|
+
version: catalog.bpVersion
|
|
357
|
+
});
|
|
358
|
+
} catch (e) {
|
|
359
|
+
throw new Error(`enable BP failed: ${e.message}`);
|
|
360
|
+
}
|
|
361
|
+
packLog(`enabled behavior pack ${catalog.bpUuid} in world list`, "success");
|
|
362
|
+
if (catalog.rpUuid && catalog.rpVersion) {
|
|
363
|
+
try {
|
|
364
|
+
await enablePackInWorld({
|
|
365
|
+
worldsDir,
|
|
366
|
+
levelName,
|
|
367
|
+
kind: "resource",
|
|
368
|
+
packUuid: catalog.rpUuid,
|
|
369
|
+
version: catalog.rpVersion
|
|
370
|
+
});
|
|
371
|
+
} catch (e) {
|
|
372
|
+
throw new Error(`enable RP failed: ${e.message}`);
|
|
373
|
+
}
|
|
374
|
+
packLog(`enabled resource pack ${catalog.rpUuid} in world list`, "success");
|
|
375
|
+
}
|
|
376
|
+
for (const staleRp of previous.rp) {
|
|
377
|
+
if (staleRp === (catalog.rpUuid ?? null)) continue;
|
|
378
|
+
try {
|
|
379
|
+
await disablePackInWorld({
|
|
380
|
+
worldsDir,
|
|
381
|
+
levelName,
|
|
382
|
+
kind: "resource",
|
|
383
|
+
packUuid: staleRp,
|
|
384
|
+
version: DEFAULT_PACK_VERSION
|
|
385
|
+
});
|
|
386
|
+
packLog(`disabled stale resource pack ${staleRp}`, "success");
|
|
387
|
+
} catch (e) {
|
|
388
|
+
packLog(`disable stale RP ${staleRp} failed: ${e.message}`, "warn");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const staleBp of previous.bp) {
|
|
392
|
+
if (staleBp === catalog.bpUuid) continue;
|
|
393
|
+
try {
|
|
394
|
+
await disablePackInWorld({
|
|
395
|
+
worldsDir,
|
|
396
|
+
levelName,
|
|
397
|
+
kind: "behavior",
|
|
398
|
+
packUuid: staleBp,
|
|
399
|
+
version: DEFAULT_PACK_VERSION
|
|
400
|
+
});
|
|
401
|
+
packLog(`disabled stale behavior pack ${staleBp}`, "success");
|
|
402
|
+
} catch (e) {
|
|
403
|
+
packLog(`disable stale BP ${staleBp} failed: ${e.message}`, "warn");
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
const wrote = await ensureConfigPermission(bdsRoot, catalog.bpUuid);
|
|
408
|
+
const permRel = path.relative(bdsRoot, configPermissionPath(bdsRoot, catalog.bpUuid));
|
|
409
|
+
packLog(wrote ? `wrote ${permRel}` : `${permRel} already exists \u2014 skipped`);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
throw new Error(`ensure-permission failed: ${e.message}`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function formatPackLoadInfo(catalog, rebuilt) {
|
|
415
|
+
const mods = Object.entries(catalog.modules);
|
|
416
|
+
const enabled = mods.filter(([, m]) => m.enabled);
|
|
417
|
+
const disabled = mods.filter(([, m]) => !m.enabled);
|
|
418
|
+
const lines = [
|
|
419
|
+
`pack load ${rebuilt ? "(rebuilt)" : "(catalog match \u2014 skip rebuild)"}`,
|
|
420
|
+
` BP ${catalog.bpUuid} v${catalog.bpVersion.join(".")}`,
|
|
421
|
+
catalog.rpUuid ? ` RP ${catalog.rpUuid} v${(catalog.rpVersion ?? DEFAULT_PACK_VERSION).join(".")}` : ` RP (none)`,
|
|
422
|
+
` modules: ${enabled.length} enabled / ${disabled.length} disabled / ${mods.length} installed`
|
|
423
|
+
];
|
|
424
|
+
for (const [folderId, m] of enabled.sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
425
|
+
lines.push(` \u25CF ${folderId} (${m.logicalId}) ${m.version}${m.hasResourcePack ? " +rp" : ""}`);
|
|
426
|
+
}
|
|
427
|
+
for (const [folderId, m] of disabled.sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
428
|
+
lines.push(` \u25CB ${folderId} (${m.logicalId}) disabled`);
|
|
429
|
+
}
|
|
430
|
+
return lines.join("\n");
|
|
431
|
+
}
|
|
432
|
+
function reusePackIds(deployed) {
|
|
433
|
+
return {
|
|
434
|
+
bpUuid: deployed.bpUuid,
|
|
435
|
+
rpUuid: deployed.rpUuid,
|
|
436
|
+
bpVersion: deployed.bpVersion,
|
|
437
|
+
rpVersion: deployed.rpVersion,
|
|
438
|
+
...deployed.bpModuleUuid ? { bpModuleUuid: deployed.bpModuleUuid } : {},
|
|
439
|
+
...deployed.rpModuleUuid ? { rpModuleUuid: deployed.rpModuleUuid } : {}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async function ensurePacksReady() {
|
|
443
|
+
const { bdsRoot, levelName } = resolveBdsContext();
|
|
444
|
+
packLog(`preflight: checking packs for ${bdsRoot} / ${levelName}`);
|
|
445
|
+
const deployed = readDeployedCatalog(bdsRoot, levelName);
|
|
446
|
+
let desired = await computeDesiredCatalog(deployed ? reusePackIds(deployed) : void 0);
|
|
447
|
+
const needsRp = Object.values(desired.modules).some((m) => m.enabled && m.hasResourcePack);
|
|
448
|
+
if (needsRp && !desired.rpUuid) {
|
|
449
|
+
desired = await computeDesiredCatalog({
|
|
450
|
+
bpUuid: desired.bpUuid,
|
|
451
|
+
bpVersion: desired.bpVersion,
|
|
452
|
+
...desired.bpModuleUuid ? { bpModuleUuid: desired.bpModuleUuid } : {},
|
|
453
|
+
rpUuid: crypto.randomUUID(),
|
|
454
|
+
rpVersion: DEFAULT_PACK_VERSION
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
if (!needsRp) {
|
|
458
|
+
desired.rpUuid = null;
|
|
459
|
+
desired.rpVersion = null;
|
|
460
|
+
}
|
|
461
|
+
let needRebuild = !deployed || !catalogsEqual(desired, deployed);
|
|
462
|
+
if (!needRebuild && deployed) {
|
|
463
|
+
if (!worldPackListHas(bdsRoot, levelName, "behavior", deployed.bpUuid)) needRebuild = true;
|
|
464
|
+
if (deployed.rpUuid && !worldPackListHas(bdsRoot, levelName, "resource", deployed.rpUuid)) {
|
|
465
|
+
needRebuild = true;
|
|
466
|
+
}
|
|
467
|
+
if (!hasConfigPermission(bdsRoot, deployed.bpUuid)) {
|
|
468
|
+
try {
|
|
469
|
+
const wrote = await ensureConfigPermission(bdsRoot, deployed.bpUuid);
|
|
470
|
+
const permRel = path.relative(bdsRoot, configPermissionPath(bdsRoot, deployed.bpUuid));
|
|
471
|
+
packLog(wrote ? `wrote ${permRel}` : `${permRel} already exists \u2014 skipped`);
|
|
472
|
+
} catch (e) {
|
|
473
|
+
throw new Error(`ensure-permission failed: ${e.message}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
let rebuilt = false;
|
|
478
|
+
if (needRebuild) {
|
|
479
|
+
packLog("catalog mismatch \u2014 rebuilding packs\u2026", "warn");
|
|
480
|
+
desired = await buildPacks(desired);
|
|
481
|
+
await deployPacks(desired);
|
|
482
|
+
rebuilt = true;
|
|
483
|
+
} else {
|
|
484
|
+
packLog("catalog match \u2014 skip rebuild", "success");
|
|
485
|
+
}
|
|
486
|
+
const summary = formatPackLoadInfo(desired, rebuilt);
|
|
487
|
+
for (const line of summary.split("\n")) packLog(line, rebuilt ? "success" : "info");
|
|
488
|
+
return {
|
|
489
|
+
rebuilt,
|
|
490
|
+
skipped: !rebuilt,
|
|
491
|
+
catalog: desired,
|
|
492
|
+
bdsRoot,
|
|
493
|
+
levelName,
|
|
494
|
+
summary
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async function cmdPackBuild(_args) {
|
|
498
|
+
try {
|
|
499
|
+
const cat = await buildPacks();
|
|
500
|
+
return okResult(c.green(t("pack.built", { path: bpOut() })) + `
|
|
501
|
+
` + formatPackLoadInfo(cat, true) + "\n");
|
|
502
|
+
} catch (e) {
|
|
503
|
+
packLog(e.message, "error");
|
|
504
|
+
return failResult(c.red(t("pack.buildFailed", { message: e.message })));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
async function cmdPackDeploy(_args) {
|
|
508
|
+
try {
|
|
509
|
+
const localCatFile = path.join(bpOut(), DEPLOY_CATALOG_NAME);
|
|
510
|
+
let cat;
|
|
511
|
+
if (existsSync(localCatFile)) {
|
|
512
|
+
cat = JSON.parse(await fs.readFile(localCatFile, "utf8"));
|
|
513
|
+
} else {
|
|
514
|
+
cat = await buildPacks();
|
|
515
|
+
}
|
|
516
|
+
await deployPacks(cat);
|
|
517
|
+
return okResult(c.green(t("pack.deployed")) + "\n" + formatPackLoadInfo(cat, true) + "\n");
|
|
518
|
+
} catch (e) {
|
|
519
|
+
packLog(e.message, "error");
|
|
520
|
+
return failResult(c.red(t("pack.deployFailed", { message: e.message })));
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
async function cmdPackStatus(_args) {
|
|
524
|
+
try {
|
|
525
|
+
const { bdsRoot, levelName } = resolveBdsContext();
|
|
526
|
+
const deployed = readDeployedCatalog(bdsRoot, levelName);
|
|
527
|
+
const desired = await computeDesiredCatalog(deployed ? reusePackIds(deployed) : void 0);
|
|
528
|
+
const match = deployed ? catalogsEqual(desired, deployed) : false;
|
|
529
|
+
const permPath = deployed ? configPermissionPath(bdsRoot, deployed.bpUuid) : null;
|
|
530
|
+
const lines = [
|
|
531
|
+
c.bold("\nPack status"),
|
|
532
|
+
` bds : ${bdsRoot}`,
|
|
533
|
+
` level : ${levelName}`,
|
|
534
|
+
` catalog : ${match ? c.green("in sync") : c.yellow(deployed ? "mismatch \u2014 will rebuild on start" : "missing")}`,
|
|
535
|
+
` BP dir : ${deployedBpDir(bdsRoot, levelName)} ${existsSync(deployedBpDir(bdsRoot, levelName)) ? c.green("\u2713") : c.red("\u2717")}`,
|
|
536
|
+
` RP dir : ${deployedRpDir(bdsRoot, levelName)} ${existsSync(deployedRpDir(bdsRoot, levelName)) ? c.green("\u2713") : c.dim("\u2014")}`,
|
|
537
|
+
` permission : ${permPath ? existsSync(permPath) ? c.green(permPath) : c.yellow("missing") : c.dim("n/a")}`
|
|
538
|
+
];
|
|
539
|
+
if (deployed) {
|
|
540
|
+
lines.push(` BP uuid : ${deployed.bpUuid}`);
|
|
541
|
+
if (deployed.rpUuid) lines.push(` RP uuid : ${deployed.rpUuid}`);
|
|
542
|
+
lines.push(
|
|
543
|
+
` world BP : ${worldPackListHas(bdsRoot, levelName, "behavior", deployed.bpUuid) ? c.green("listed") : c.red("not listed")}`
|
|
544
|
+
);
|
|
545
|
+
if (deployed.rpUuid) {
|
|
546
|
+
lines.push(
|
|
547
|
+
` world RP : ${worldPackListHas(bdsRoot, levelName, "resource", deployed.rpUuid) ? c.green("listed") : c.red("not listed")}`
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
lines.push(formatPackLoadInfo(desired, false));
|
|
552
|
+
return lines.join("\n") + "\n";
|
|
553
|
+
} catch (e) {
|
|
554
|
+
return c.red(t("pack.statusFailed", { message: e.message }));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async function cmdPackList(_args) {
|
|
558
|
+
try {
|
|
559
|
+
const { bdsRoot, levelName } = resolveBdsContext();
|
|
560
|
+
const mods = await scanLocalModules();
|
|
561
|
+
const lines = [c.bold("\nModules / resource packs"), c.dim(` ${packagesDir()}`)];
|
|
562
|
+
for (const m of mods) {
|
|
563
|
+
const mark = m.enabled ? c.green("\u25CF") : c.dim("\u25CB");
|
|
564
|
+
lines.push(
|
|
565
|
+
` ${mark} ${m.folderId.padEnd(24)} ${m.logicalId.padEnd(24)} ${m.enabled ? "on " : "off"} ${m.hasResourcePack ? "+rp" : " "} ${m.version}`
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
const worldsDir = bdsWorldsDir(bdsRoot);
|
|
569
|
+
lines.push(c.bold("\nWorld enable lists"));
|
|
570
|
+
for (const kind of ["behavior", "resource"]) {
|
|
571
|
+
const arr = readWorldPackList(worldsDir, levelName, kind);
|
|
572
|
+
if (!arr.length) lines.push(c.dim(` ${kind}: (empty)`));
|
|
573
|
+
for (const e of arr) {
|
|
574
|
+
lines.push(` ${kind}: ${e.pack_id} v${(e.version ?? []).join(".")}`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return lines.join("\n") + "\n";
|
|
578
|
+
} catch (e) {
|
|
579
|
+
return c.red(t("pack.listFailed", { message: e.message }));
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
async function cmdPackEnableDisable(action, args) {
|
|
583
|
+
try {
|
|
584
|
+
const kind = args[0] === "resource" || args[0] === "rp" ? "resource" : "behavior";
|
|
585
|
+
const { bdsRoot, levelName } = resolveBdsContext();
|
|
586
|
+
const deployed = readDeployedCatalog(bdsRoot, levelName);
|
|
587
|
+
if (!deployed) return c.red(t("pack.noCatalog"));
|
|
588
|
+
const uuid = kind === "behavior" ? deployed.bpUuid : deployed.rpUuid;
|
|
589
|
+
const version = kind === "behavior" ? deployed.bpVersion : deployed.rpVersion;
|
|
590
|
+
if (!uuid || !version) return c.red(t("pack.noUuid", { kind }));
|
|
591
|
+
const worldsDir = bdsWorldsDir(bdsRoot);
|
|
592
|
+
try {
|
|
593
|
+
const opts = { worldsDir, levelName, kind, packUuid: uuid, version };
|
|
594
|
+
if (action === "enable") await enablePackInWorld(opts);
|
|
595
|
+
else await disablePackInWorld(opts);
|
|
596
|
+
} catch (e) {
|
|
597
|
+
return c.red(t("pack.actionFailed", { action, detail: e.message }));
|
|
598
|
+
}
|
|
599
|
+
packLog(`${action}d ${kind} pack ${uuid}`, "success");
|
|
600
|
+
return c.green(
|
|
601
|
+
action === "enable" ? t("pack.enabledOk", { kind, uuid }) : t("pack.disabledOk", { kind, uuid })
|
|
602
|
+
);
|
|
603
|
+
} catch (e) {
|
|
604
|
+
return c.red(t("pack.actionErr", { action, message: e.message }));
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
export {
|
|
608
|
+
BP_NAME,
|
|
609
|
+
DEFAULT_PACK_VERSION,
|
|
610
|
+
DEPLOY_CATALOG_NAME,
|
|
611
|
+
RP_NAME,
|
|
612
|
+
bpOut,
|
|
613
|
+
bpSrc,
|
|
614
|
+
buildPacks,
|
|
615
|
+
buildRoot,
|
|
616
|
+
catalogsEqual,
|
|
617
|
+
cmdPackBuild,
|
|
618
|
+
cmdPackDeploy,
|
|
619
|
+
cmdPackEnableDisable,
|
|
620
|
+
cmdPackList,
|
|
621
|
+
cmdPackStatus,
|
|
622
|
+
computeDesiredCatalog,
|
|
623
|
+
deployPacks,
|
|
624
|
+
deployedBpDir,
|
|
625
|
+
deployedCatalogPath,
|
|
626
|
+
deployedRpDir,
|
|
627
|
+
ensurePacksReady,
|
|
628
|
+
formatPackLoadInfo,
|
|
629
|
+
readDeployedCatalog,
|
|
630
|
+
resolveBdsContext,
|
|
631
|
+
rpOut,
|
|
632
|
+
scanLocalModules
|
|
633
|
+
};
|
|
634
|
+
//# sourceMappingURL=pack-lifecycle.js.map
|