@sfmc-bds/cli 0.5.3 → 0.7.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/dist/logs.d.ts +21 -0
- package/dist/logs.d.ts.map +1 -1
- package/dist/logs.js +67 -1
- package/dist/logs.js.map +2 -2
- package/dist/management/deployment.js +1 -1
- package/dist/management/deployment.js.map +2 -2
- package/dist/management/domain.d.ts +46 -2
- package/dist/management/domain.d.ts.map +1 -1
- package/dist/management/domain.js +112 -26
- package/dist/management/domain.js.map +2 -2
- package/dist/management/maintenance.d.ts +14 -1
- package/dist/management/maintenance.d.ts.map +1 -1
- package/dist/management/maintenance.js +46 -38
- package/dist/management/maintenance.js.map +2 -2
- package/dist/management/pack-import.d.ts +29 -0
- package/dist/management/pack-import.d.ts.map +1 -0
- package/dist/management/pack-import.js +108 -0
- package/dist/management/pack-import.js.map +7 -0
- package/dist/management/platform-worker.js +5 -6
- package/dist/management/platform-worker.js.map +2 -2
- package/dist/management/server.d.ts.map +1 -1
- package/dist/management/server.js +113 -33
- package/dist/management/server.js.map +2 -2
- package/dist/management/tasks.js +1 -1
- package/dist/management/tasks.js.map +2 -2
- package/dist/registry.d.ts +11 -5
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +35 -11
- package/dist/registry.js.map +2 -2
- package/dist/services.d.ts +2 -1
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +16 -3
- package/dist/services.js.map +2 -2
- package/dist/world-packs.d.ts +47 -0
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +38 -11
- package/dist/world-packs.js.map +2 -2
- package/package.json +6 -6
- package/scripts/module-install/lib/registry-index.mjs +50 -13
package/dist/logs.d.ts
CHANGED
|
@@ -48,12 +48,33 @@ export type ReadDiskLogsOpts = {
|
|
|
48
48
|
dir?: string;
|
|
49
49
|
/** 仅保留时间序最后 N 条;省略则返回全部解析结果 */
|
|
50
50
|
limit?: number;
|
|
51
|
+
/** 含此时间。设置后读取整个日志文件,不再只取文件末尾 */
|
|
52
|
+
since?: Date;
|
|
53
|
+
/** 含此时间 */
|
|
54
|
+
until?: Date;
|
|
55
|
+
};
|
|
56
|
+
/** 删除落盘日志时的筛选。使用场景:桌面 logs.delete。 */
|
|
57
|
+
export type DeleteDiskLogsOpts = {
|
|
58
|
+
since: Date;
|
|
59
|
+
until: Date;
|
|
60
|
+
source?: string;
|
|
61
|
+
text?: string;
|
|
62
|
+
/** 覆盖日志目录(测试用) */
|
|
63
|
+
dir?: string;
|
|
51
64
|
};
|
|
52
65
|
/**
|
|
53
66
|
* 从 `.sfmc/logs/*.log` 读取并解析为 UnifiedLog(按时间升序)。
|
|
54
67
|
* CLI 重连后主面板 /logs 的历史权威来源;内存缓冲仅承载本进程订阅到的实时增量。
|
|
55
68
|
*/
|
|
56
69
|
export declare function readDiskLogs(opts?: ReadDiskLogsOpts): UnifiedLog[];
|
|
70
|
+
/**
|
|
71
|
+
* 按时间范围删除已知日志文件中的行。
|
|
72
|
+
* 使用场景:桌面 logs.delete。符号链接和非文件直接拒绝。
|
|
73
|
+
* 写入前会再读一次期间追加的内容;替换文件的瞬间新写入的行可能留下来。
|
|
74
|
+
*/
|
|
75
|
+
export declare function deleteStoredLogs(opts: DeleteDiskLogsOpts): {
|
|
76
|
+
removed: number;
|
|
77
|
+
};
|
|
57
78
|
export interface SourceMeta {
|
|
58
79
|
value: string;
|
|
59
80
|
/** 方括号内固定 3 字符,与 [INF] 对齐 */
|
package/dist/logs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAQL,KAAK,QAAQ,EACb,KAAK,QAAQ,IAAI,cAAc,EAChC,MAAM,oBAAoB,CAAC;AAa5B,MAAM,MAAM,QAAQ,GAAG,cAAc,CAAC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAC/B,MAAM,WAAW,UAAW,SAAQ,QAAQ;CAAG;AAE/C,wDAAwD;AACxD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAShG,yCAAyC;AACzC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/D;AAwBD,yBAAyB;AACzB,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CA+C9E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEtF;AAED,uBAAuB;AACvB,wBAAgB,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAE/D;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAG/F;AAED,qDAAqD;AACrD,wBAAgB,UAAU,IAAI,UAAU,EAAE,CAGzC;AASD,6BAA6B;AAC7B,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIxD;AAuBD,2BAA2B;AAC3B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAS/D;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IACtB,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"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"}
|
package/dist/logs.js
CHANGED
|
@@ -134,6 +134,9 @@ function readDiskLogs(opts = {}) {
|
|
|
134
134
|
const levels = opts.levels ?? [];
|
|
135
135
|
const sources = opts.sources ?? [];
|
|
136
136
|
const dir = opts.dir ?? logsDir(ROOT);
|
|
137
|
+
const sinceMs = opts.since?.getTime();
|
|
138
|
+
const untilMs = opts.until?.getTime();
|
|
139
|
+
const ranged = sinceMs !== void 0 || untilMs !== void 0;
|
|
137
140
|
const fileNames = /* @__PURE__ */ new Set();
|
|
138
141
|
if (sources.length === 0) {
|
|
139
142
|
for (const n of DISK_LOG_FILES) fileNames.add(n);
|
|
@@ -145,7 +148,7 @@ function readDiskLogs(opts = {}) {
|
|
|
145
148
|
const fp = path.join(dir, name.endsWith(".log") ? name : `${name}.log`);
|
|
146
149
|
let text;
|
|
147
150
|
try {
|
|
148
|
-
if (opts.limit) {
|
|
151
|
+
if (opts.limit && !ranged) {
|
|
149
152
|
const fd = fs.openSync(fp, "r");
|
|
150
153
|
try {
|
|
151
154
|
const size = fs.fstatSync(fd).size;
|
|
@@ -165,6 +168,9 @@ function readDiskLogs(opts = {}) {
|
|
|
165
168
|
if (!raw) continue;
|
|
166
169
|
const entry = parseDiskLogLine(raw);
|
|
167
170
|
if (!entry) continue;
|
|
171
|
+
const time = entry.time.getTime();
|
|
172
|
+
if (sinceMs !== void 0 && time < sinceMs) continue;
|
|
173
|
+
if (untilMs !== void 0 && time > untilMs) continue;
|
|
168
174
|
if (sources.length && !sources.includes(entry.source)) continue;
|
|
169
175
|
if (levels.length && !levels.includes(entry.level)) continue;
|
|
170
176
|
out.push(entry);
|
|
@@ -177,6 +183,65 @@ function readDiskLogs(opts = {}) {
|
|
|
177
183
|
}
|
|
178
184
|
return out;
|
|
179
185
|
}
|
|
186
|
+
function diskLineMatchesRemoval(entry, opts) {
|
|
187
|
+
const time = entry.time.getTime();
|
|
188
|
+
if (time < opts.since.getTime() || time > opts.until.getTime()) return false;
|
|
189
|
+
if (opts.source !== void 0 && entry.source !== opts.source) return false;
|
|
190
|
+
if (opts.text !== void 0 && entry.text !== opts.text) return false;
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
function filterLogText(text, opts) {
|
|
194
|
+
if (!text) return { text: "", removed: 0 };
|
|
195
|
+
const newline = text.includes("\r\n") ? "\r\n" : "\n";
|
|
196
|
+
const ended = text.endsWith("\n");
|
|
197
|
+
const lines = text.split(/\r?\n/);
|
|
198
|
+
if (ended) lines.pop();
|
|
199
|
+
let removed = 0;
|
|
200
|
+
const kept = [];
|
|
201
|
+
for (const raw of lines) {
|
|
202
|
+
const entry = raw ? parseDiskLogLine(raw) : null;
|
|
203
|
+
if (entry && diskLineMatchesRemoval(entry, opts)) {
|
|
204
|
+
removed++;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
kept.push(raw);
|
|
208
|
+
}
|
|
209
|
+
if (!kept.length) return { text: "", removed };
|
|
210
|
+
return { text: kept.join(newline) + (ended ? newline : ""), removed };
|
|
211
|
+
}
|
|
212
|
+
function deleteStoredLogs(opts) {
|
|
213
|
+
if (opts.until.getTime() < opts.since.getTime()) throw new Error("\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4");
|
|
214
|
+
const dir = opts.dir ?? logsDir(ROOT);
|
|
215
|
+
let removed = 0;
|
|
216
|
+
for (const name of DISK_LOG_FILES) {
|
|
217
|
+
const file = path.join(dir, `${name}.log`);
|
|
218
|
+
removed += rewriteLogFile(file, opts);
|
|
219
|
+
}
|
|
220
|
+
return { removed };
|
|
221
|
+
}
|
|
222
|
+
function rewriteLogFile(file, opts) {
|
|
223
|
+
let stat;
|
|
224
|
+
try {
|
|
225
|
+
stat = fs.lstatSync(file);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error.code === "ENOENT") return 0;
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
if (stat.isSymbolicLink()) throw new Error(`\u62D2\u7EDD\u6539\u5199\u7B26\u53F7\u94FE\u63A5\u65E5\u5FD7 ${path.basename(file)}`);
|
|
231
|
+
if (!stat.isFile()) throw new Error(`\u62D2\u7EDD\u6539\u5199\u975E\u6587\u4EF6\u65E5\u5FD7 ${path.basename(file)}`);
|
|
232
|
+
let text = fs.readFileSync(file, "utf8");
|
|
233
|
+
if (fs.statSync(file).size > Buffer.byteLength(text)) text = fs.readFileSync(file, "utf8");
|
|
234
|
+
const filtered = filterLogText(text, opts);
|
|
235
|
+
if (!filtered.removed) return 0;
|
|
236
|
+
const temp = `${file}.${process.pid}.filtering`;
|
|
237
|
+
fs.writeFileSync(temp, filtered.text, "utf8");
|
|
238
|
+
try {
|
|
239
|
+
fs.copyFileSync(temp, file);
|
|
240
|
+
} finally {
|
|
241
|
+
fs.rmSync(temp, { force: true });
|
|
242
|
+
}
|
|
243
|
+
return filtered.removed;
|
|
244
|
+
}
|
|
180
245
|
const SOURCE_META = [
|
|
181
246
|
{ value: "bds", name: "BDS", paint: (s) => c.green(s) },
|
|
182
247
|
{ value: "db", name: "DB ", paint: (s) => c.blue(s) },
|
|
@@ -319,6 +384,7 @@ function wrapSegment(s, cols, startPad, hangIndent) {
|
|
|
319
384
|
}
|
|
320
385
|
export {
|
|
321
386
|
SOURCE_META,
|
|
387
|
+
deleteStoredLogs,
|
|
322
388
|
diskFileForSource,
|
|
323
389
|
formatLog,
|
|
324
390
|
formatSourceTag,
|
package/dist/logs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/logs.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * logs.ts \u2014 sfmc \u4E3B\u8FDB\u7A0B\u7EDF\u4E00\u65E5\u5FD7\u805A\u5408\u5C42\n *\n * \u5185\u90E8\u59D4\u6258 @sfmc-bds/logs \u5171\u4EAB\u5305\u7684 createMemoryBuffer + inferLevel,\n * \u4FDD\u6301\u5411\u540E\u517C\u5BB9\u7684 pushLog / onLog / getAllLogs / getRecentLogs API\n * (services.ts \u6355\u83B7\u5B50\u8FDB\u7A0B stdout \u540E\u8C03\u7528 pushLog \u6C47\u805A\u5230\u6B64)\u3002\n *\n * \u843D\u76D8\u7B56\u7565(\u4E0E\u5B50\u8FDB\u7A0B\u81EA\u5199\u6587\u4EF6\u5206\u5DE5,\u907F\u514D\u91CD\u590D):\n * - db / qq / update \u2192 \u5B50\u8FDB\u7A0B\u5DF2\u5199 `.sfmc/logs/{db,qq,bds-update}.log`,\u6B64\u5904\u8DF3\u8FC7\n * - bds / llbot \u2192 `.sfmc/logs/{bds,llbot}.log`(\u5916\u90E8\u8FDB\u7A0B\u65E0\u81EA\u5E26 file sink)\n * - \u5176\u4F59(system / pack / \u2026) \u2192 `.sfmc/logs/sfmc.log`\n *\n * CLI \u91CD\u8FDE\u540E\u5386\u53F2\u56DE\u653E\u4EE5\u843D\u76D8\u4E3A\u51C6\uFF08readDiskLogs\uFF09\uFF1B\u5185\u5B58\u7F13\u51B2\u53EA\u670D\u52A1\u672C\u8FDB\u7A0B\u5B9E\u65F6\u8BA2\u9605\u3002\n *\n * formatLog \u4FDD\u7559 theme.ts (chalk) \u914D\u8272,\u6BD4\u5171\u4EAB\u5305\u7684\u7EAF ANSI \u7248\u672C\u89C6\u89C9\u66F4\u4E30\u5BCC\u3002\n */\n\nimport {\n createFileSink,\n createMemoryBuffer,\n formatLogLine,\n inferLevel as sharedInferLevel,\n parseBdsEmbeddedLevel,\n stripBdsLogPrefix,\n type FileSink,\n type LogEntry,\n type LogLevel as SharedLogLevel,\n} from \"@sfmc-bds/sdk/logs\";\nimport { logFile, logsDir } from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n getCompiledLogFilter,\n shouldDropForDisk,\n shouldDropForDisplay,\n transformLogEntry,\n} from \"./log-filter.js\";\nimport { c, highlightLogLine } from \"./theme.js\";\nimport { ROOT } from \"./runtime.js\";\n\nexport type LogLevel = SharedLogLevel;\nexport type LogSource = string;\nexport interface UnifiedLog extends LogEntry {}\n\n/** \u518D\u5BFC\u51FA SDK BDS \u89E3\u6790\uFF08\u6D4B\u8BD5\u4E0E\u8C03\u7528\u65B9\u7EDF\u4E00\u5165\u53E3\uFF0C\u6743\u5A01\u5728 @sfmc-bds/sdk/logs\uFF09 */\nexport { mapBdsLevelToken, parseBdsEmbeddedLevel, stripBdsLogPrefix } from \"@sfmc-bds/sdk/logs\";\n\nconst buffer = createMemoryBuffer(5000);\n\n/** \u5B50\u8FDB\u7A0B\u5DF2\u7528 createNodeServiceLogger \u81EA\u884C\u843D\u76D8\u7684 source */\nconst CHILD_OWNED_SOURCES = new Set([\"db\", \"qq\", \"update\"]);\n\nconst fileSinks = new Map<string, FileSink>();\n\n/** \u5265\u79BB BDS \u81EA\u5E26\u524D\u7F00\uFF1B\u82E5\u524D\u7F00\u540E\u6CA1\u6709\u6B63\u6587\uFF0C\u5219\u5224\u5B9A\u4E3A\u4EC5\u7528\u4E8E\u6392\u7248\u7684\u7A7A\u884C\u3002 */\nexport function normalizeBdsLogBody(text: string): string | null {\n const body = stripBdsLogPrefix(text);\n return body.trim().length > 0 ? body : null;\n}\n\n/** \u89E3\u6790\u672C\u6761\u65E5\u5FD7\u5E94\u5199\u5165\u7684\u6587\u4EF6\u540D(\u4E0D\u542B .log);null \u8868\u793A\u8DF3\u8FC7(\u5B50\u8FDB\u7A0B\u5DF2\u5199) */\nfunction resolveDiskLogName(source: string): string | null {\n if (CHILD_OWNED_SOURCES.has(source)) return null;\n if (source === \"bds\" || source === \"llbot\" || source === \"tunnel\") return source;\n return \"sfmc\";\n}\n\nfunction sinkFor(source: string): FileSink | null {\n const name = resolveDiskLogName(source);\n if (!name) return null;\n let sink = fileSinks.get(name);\n if (!sink) {\n sink = createFileSink(logFile(ROOT, name));\n fileSinks.set(name, sink);\n }\n return sink;\n}\n\nprocess.on(\"exit\", () => {\n for (const sink of fileSinks.values()) sink.close();\n});\n\n/** \u63A8\u9001\u4E00\u6761\u65E5\u5FD7\u5230\u5185\u5B58\u7F13\u51B2,\u5E76\u6309\u7B56\u7565\u843D\u76D8 */\nexport function pushLog(text: string, source: LogSource, level: LogLevel): void {\n let body = text;\n let lvl = level;\n /* BDS\uFF1A\u5148\u63D0\u53D6\u5185\u5D4C\u7EA7\u522B\uFF0C\u518D\u5265\u6389\u81EA\u5E26\u65F6\u95F4\u6233+\u7B49\u7EA7\uFF0C\u907F\u514D\u5C55\u793A/\u843D\u76D8\u91CD\u590D */\n if (source === \"bds\") {\n const embedded = parseBdsEmbeddedLevel(text);\n if (embedded) lvl = embedded;\n const normalized = normalizeBdsLogBody(text);\n if (normalized === null) return;\n body = normalized;\n }\n\n const rawEntry: LogEntry = { time: new Date(), text: body, source, level: lvl };\n const filter = getCompiledLogFilter((src) => {\n /* \u907F\u514D\u9012\u5F52\uFF1A\u975E\u6CD5\u6B63\u5219\u53EA\u5199\u6587\u4EF6 sink\uFF0C\u4E0D\u7ECF pushLog */\n try {\n const sink = sinkFor(\"system\");\n if (!sink) return;\n const warn: LogEntry = {\n time: new Date(),\n text: `log-filter: invalid regex skipped: ${src}`,\n source: \"system\",\n level: \"warn\",\n };\n sink.write(warn, formatLogLine(warn, false));\n } catch {\n /* ignore */\n }\n });\n\n const dropDisplay = shouldDropForDisplay(rawEntry, filter);\n const dropDisk = shouldDropForDisk(rawEntry, filter);\n const { entry: transformedEntry } = transformLogEntry(rawEntry, filter);\n\n if (!dropDisplay) {\n buffer.pushDirect(transformedEntry.text, source, lvl);\n }\n\n if (dropDisk) return;\n const sink = sinkFor(source);\n if (!sink) return;\n try {\n const diskEntry: LogEntry = filter.applyTo === \"all\" ? { ...rawEntry, text: transformedEntry.text } : rawEntry;\n sink.write(diskEntry, formatLogLine(diskEntry, false));\n } catch {\n /* \u843D\u76D8\u5931\u8D25\u4E0D\u963B\u65AD\u4E3B\u6D41\u7A0B */\n }\n}\n\n/**\n * \u6444\u5165\u5B88\u62A4\u8FDB\u7A0B\u8F6C\u53D1\u7684\u8FDC\u7A0B\u65E5\u5FD7\uFF1A\u53EA\u5199\u5165\u672C\u8FDB\u7A0B\u5185\u5B58\u7F13\u51B2\u5E76\u901A\u77E5\u8BA2\u9605\u8005\uFF0C\u4E0D\u518D\u843D\u76D8\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1ACLI \u5BA2\u6237\u7AEF subscribe \u540E\u628A daemon \u63A8\u9001\u7684 log \u4E8B\u4EF6\u704C\u5165\u672C\u5730\uFF0C\u4F9B REPL \u4E3B\u9762\u677F\u5B9E\u65F6\u5C55\u793A\uFF1B\n * \u843D\u76D8\u5DF2\u7531\u5B88\u62A4\u8FDB\u7A0B\u5B8C\u6210\uFF0C\u6B64\u5904\u8DF3\u8FC7\u907F\u514D\u91CD\u590D\u5199 `.sfmc/logs/*`\u3002\n */\nexport function ingestRemoteLog(text: string, source: LogSource, level: LogLevel): void {\n buffer.pushDirect(text, source, level);\n}\n\n/** \u8BA2\u9605\u65B0\u65E5\u5FD7\u4E8B\u4EF6,\u8FD4\u56DE\u53D6\u6D88\u8BA2\u9605\u51FD\u6570 */\nexport function onLog(fn: (log: UnifiedLog) => void): () => void {\n return buffer.subscribe(fn);\n}\n\n/** \u83B7\u53D6\u6700\u8FD1 n \u6761,\u53EF\u6309 level / source \u8FC7\u6EE4\uFF1B\u518D\u5957\u914D\u7F6E\u8FC7\u6EE4\uFF08display\uFF09 */\nexport function getRecentLogs(n: number, levels: LogLevel[], sources: LogSource[]): UnifiedLog[] {\n const filter = getCompiledLogFilter();\n return buffer.getRecent(n, levels, sources).filter((l) => !shouldDropForDisplay(l, filter));\n}\n\n/** \u83B7\u53D6\u5168\u90E8\u65E5\u5FD7\uFF1B\u914D\u7F6E\u8FC7\u6EE4\u4EC5\u5F71\u54CD\u8FD4\u56DE\u89C6\u56FE\uFF08\u7F13\u51B2\u5185\u53EF\u80FD\u4ECD\u6709\u5168\u91CF\uFF0C\u89C6 push \u65F6 applyTo\uFF09 */\nexport function getAllLogs(): UnifiedLog[] {\n const filter = getCompiledLogFilter();\n return buffer.getAll().filter((l) => !shouldDropForDisplay(l, filter));\n}\n\n/* ==================================================================\n * \u843D\u76D8\u6587\u4EF6\u8BFB\u53D6\uFF08/logs \u7A97\u7528\uFF0C\u4E0D\u8D70\u5185\u5B58\u7F13\u51B2\uFF09\n * ================================================================== */\n\n/** \u4E0E\u843D\u76D8\u7B56\u7565\u5BF9\u5E94\u7684\u6587\u4EF6\u57FA\u540D\uFF08\u4E0D\u542B .log\uFF09 */\nconst DISK_LOG_FILES = [\"bds\", \"llbot\", \"tunnel\", \"db\", \"qq\", \"bds-update\", \"sfmc\"] as const;\n\n/** source \u2192 \u843D\u76D8\u6587\u4EF6\u540D\uFF08\u542B\u5B50\u8FDB\u7A0B\u81EA\u5199\uFF09 */\nexport function diskFileForSource(source: string): string {\n if (source === \"update\") return \"bds-update\";\n if (source === \"bds\" || source === \"llbot\" || source === \"tunnel\" || source === \"db\" || source === \"qq\") return source;\n return \"sfmc\";\n}\n\n/** formatLogLine \u65E0\u8272\u884C\uFF1A`YYYY-MM-DD HH:mm:ss [source] [LEVEL] text` */\nconst DISK_LINE_RE =\n /^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[([^\\]]+)\\] \\[(INFO|WARN|ERROR|OK|DEBUG|SUCCESS|FATAL)\\]\\s?(.*)$/;\n\nfunction mapDiskLevelTag(tag: string): LogLevel {\n switch (tag) {\n case \"ERROR\":\n case \"FATAL\":\n return \"error\";\n case \"WARN\":\n return \"warn\";\n case \"OK\":\n case \"SUCCESS\":\n return \"success\";\n case \"DEBUG\":\n return \"debug\";\n default:\n return \"info\";\n }\n}\n\n/** \u89E3\u6790\u5355\u884C\u843D\u76D8\u65E5\u5FD7\uFF1B\u4E0D\u7B26\u683C\u5F0F\u8FD4\u56DE null */\nexport function parseDiskLogLine(raw: string): UnifiedLog | null {\n const m = DISK_LINE_RE.exec(raw);\n if (!m) return null;\n const ts = m[1]!;\n const source = m[2]!.trim();\n const level = mapDiskLevelTag(m[3]!);\n const body = m[4] ?? \"\";\n const time = new Date(ts.replace(\" \", \"T\") + \"Z\");\n return { time, source, level, text: body };\n}\n\nexport type ReadDiskLogsOpts = {\n levels?: LogLevel[];\n sources?: LogSource[];\n /** \u8986\u76D6\u65E5\u5FD7\u76EE\u5F55\uFF08\u6D4B\u8BD5\u7528\uFF09\uFF1B\u9ED8\u8BA4 `<ROOT>/.sfmc/logs` */\n dir?: string;\n /** \u4EC5\u4FDD\u7559\u65F6\u95F4\u5E8F\u6700\u540E N \u6761\uFF1B\u7701\u7565\u5219\u8FD4\u56DE\u5168\u90E8\u89E3\u6790\u7ED3\u679C */\n limit?: number;\n};\n\n/**\n * \u4ECE `.sfmc/logs/*.log` \u8BFB\u53D6\u5E76\u89E3\u6790\u4E3A UnifiedLog\uFF08\u6309\u65F6\u95F4\u5347\u5E8F\uFF09\u3002\n * CLI \u91CD\u8FDE\u540E\u4E3B\u9762\u677F /logs \u7684\u5386\u53F2\u6743\u5A01\u6765\u6E90\uFF1B\u5185\u5B58\u7F13\u51B2\u4EC5\u627F\u8F7D\u672C\u8FDB\u7A0B\u8BA2\u9605\u5230\u7684\u5B9E\u65F6\u589E\u91CF\u3002\n */\nexport function readDiskLogs(opts: ReadDiskLogsOpts = {}): UnifiedLog[] {\n const levels = opts.levels ?? [];\n const sources = opts.sources ?? [];\n const dir = opts.dir ?? logsDir(ROOT);\n const fileNames = new Set<string>();\n if (sources.length === 0) {\n for (const n of DISK_LOG_FILES) fileNames.add(n);\n } else {\n for (const s of sources) fileNames.add(diskFileForSource(s));\n }\n\n const out: UnifiedLog[] = [];\n for (const name of fileNames) {\n const fp = path.join(dir, name.endsWith(\".log\") ? name : `${name}.log`);\n let text: string;\n try {\n if (opts.limit) {\n const fd = fs.openSync(fp, \"r\");\n try {\n const size = fs.fstatSync(fd).size;\n const start = Math.max(0, size - 4 * 1024 * 1024);\n const bytes = Buffer.alloc(size - start);\n fs.readSync(fd, bytes, 0, bytes.length, start);\n text = bytes.toString(\"utf8\");\n if (start > 0) text = text.slice(text.indexOf(\"\\n\") + 1);\n } finally { fs.closeSync(fd); }\n } else text = fs.readFileSync(fp, \"utf8\");\n } catch {\n continue;\n }\n for (const raw of text.split(/\\r?\\n/)) {\n if (!raw) continue;\n const entry = parseDiskLogLine(raw);\n if (!entry) continue;\n if (sources.length && !sources.includes(entry.source)) continue;\n if (levels.length && !levels.includes(entry.level)) continue;\n out.push(entry);\n }\n }\n out.sort((a, b) => a.time.getTime() - b.time.getTime());\n const limit = opts.limit;\n if (limit !== undefined && limit > 0 && out.length > limit) {\n return out.slice(out.length - limit);\n }\n return out;\n}\n\n/* ==================================================================\n * \u6765\u6E90\u6807\u7B7E\u5143\u6570\u636E (\u65B9\u62EC\u53F7\u4E0E\u6587\u5B57\u540C\u8272,\u5BF9\u9F50 levelTag)\n * ================================================================== */\n\nexport interface SourceMeta {\n value: string;\n /** \u65B9\u62EC\u53F7\u5185\u56FA\u5B9A 3 \u5B57\u7B26\uFF0C\u4E0E [INF] \u5BF9\u9F50 */\n name: string;\n paint: (s: string) => string;\n}\n\nexport const SOURCE_META: SourceMeta[] = [\n { value: \"bds\", name: \"BDS\", paint: (s) => c.green(s) },\n { value: \"db\", name: \"DB \", paint: (s) => c.blue(s) },\n { value: \"qq\", name: \"QQ \", paint: (s) => c.purple(s) },\n { value: \"llbot\", name: \"BOT\", paint: (s) => c.yellow(s) },\n { value: \"system\", name: \"SYS\", paint: (s) => c.cyan(s) },\n { value: \"update\", name: \"UPD\", paint: (s) => c.orange(s) },\n { value: \"pack\", name: \"PAK\", paint: (s) => c.purple(s) },\n { value: \"bds-tools\", name: \"TOL\", paint: (s) => c.red(s) },\n];\n\n/** \u6E90\u6807\u7B7E\u65E0\u8272\u6587\u672C\uFF08formatSourceTag / logPrefixWidth \u5171\u7528\uFF09 */\nfunction sourceTagPlain(source: string): string {\n const meta = SOURCE_META.find((m) => m.value === source);\n if (meta) return `[${meta.name}]`;\n return `[${source.toUpperCase().padEnd(3).slice(0, 3)}]`;\n}\n\nexport function formatSourceTag(source: string): string {\n const meta = SOURCE_META.find((m) => m.value === source);\n const plain = sourceTagPlain(source);\n if (meta) return meta.paint(plain);\n return c.bold(plain);\n}\n\n/**\n * \u5C55\u793A\u7528\u7EA7\u522B\uFF1ABDS \u82E5\u4ECD\u5E26\u65F6\u95F4\u6233\u524D\u7F00\u5219\u89E3\u6790\u5185\u5D4C\u7EA7\u522B\uFF1B\u5DF2\u5265\u79BB\uFF08pushLog \u5165\u5E93\uFF09\u5219\u4FE1\u4EFB entry.level\u3002\n * \u7981\u6B62\u5BF9\u6B63\u6587\u505A\u677E\u6563\u5173\u952E\u8BCD\u5339\u914D\uFF08\u4F1A\u628A `[Commands] Error on line` \u8BEF\u5224\u4E3A error\uFF09\u3002\n */\nexport function resolveDisplayLevel(l: UnifiedLog): LogLevel {\n if (l.source === \"bds\") {\n const embedded = parseBdsEmbeddedLevel(l.text);\n if (embedded) return embedded;\n }\n return l.level;\n}\n\n/** \u4ECE\u539F\u59CB\u6587\u672C\u63A8\u65AD\u7EA7\u522B\uFF1A\u59D4\u6258\u5171\u4EAB\u5305\uFF08\u5185\u542B BDS \u65F6\u95F4\u6233\u89E3\u6790\uFF09 */\nexport function inferLevel(text: string): LogLevel {\n return sharedInferLevel(text);\n}\n\n/** \u65E0\u8272\u7EA7\u522B\u6807\u7B7E\u6587\u672C\uFF08\u53EF\u89C1\u5BBD\u5EA6\u6743\u5A01\u6E90\uFF1B\u62EC\u53F7\u5185\u5747\u4E3A 3 \u5B57\u7B26\uFF09 */\nconst LEVEL_TAG_TEXT: Record<LogLevel, string> = {\n error: \"[ERR]\",\n warn: \"[WRN]\",\n success: \"[SUC]\",\n debug: \"[DBG]\",\n info: \"[INF]\",\n};\n\nfunction levelTagPlain(lvl: LogLevel): string {\n return LEVEL_TAG_TEXT[lvl] ?? LEVEL_TAG_TEXT.info;\n}\n\nfunction levelTag(lvl: LogLevel): string {\n const text = levelTagPlain(lvl);\n switch (lvl) {\n case \"error\":\n return c.red(text);\n case \"warn\":\n return c.yellow(text);\n case \"success\":\n return c.green(c.bold(text));\n case \"debug\":\n return c.dim(text);\n default:\n return c.blue(text);\n }\n}\n\n/** \u683C\u5F0F\u5316\u65E5\u5FD7\u7528\u4E8E REPL \u5C55\u793A (\u7528 theme.ts chalk \u914D\u8272) */\nexport function formatLog(l: UnifiedLog): string {\n const ts = c.dim(l.time.toLocaleTimeString());\n const level = resolveDisplayLevel(l);\n const lvl = levelTag(level);\n const src = formatSourceTag(l.source);\n /* BDS\uFF1A\u53BB\u6389\u81EA\u5E26\u65F6\u95F4\u6233+\u7B49\u7EA7\u524D\u7F00\u540E\u518D\u672C\u5730\u5316\u7FFB\u8BD1\u4E0E\u9AD8\u4EAE\u6B63\u6587\uFF08push \u65F6\u591A\u534A\u5DF2\u8F6C\u8FC7\uFF0C\u6B64\u5904\u5E42\u7B49\u4E14\u8986\u76D6\u56DE\u653E\uFF09 */\n const body = l.source === \"bds\" ? stripBdsLogPrefix(l.text) : l.text;\n const filter = getCompiledLogFilter();\n const { entry } = transformLogEntry({ text: body, source: l.source, level }, filter);\n const txt = highlightLogLine(entry.text);\n return `${ts} ${src} ${lvl} ${txt}`;\n}\n\n/* ==================================================================\n * \u8F6F\u6362\u884C: \u8D85\u7EC8\u7AEF\u5BBD\u5EA6\u65F6\u6362\u884C,\u540E\u7EED\u884C\u7F29\u8FDB\u5BF9\u9F50\n * ================================================================== */\n\n/** \u5355\u4E2A\u5B57\u7B26\u5728\u7EC8\u7AEF\u7684\u663E\u793A\u5BBD\u5EA6 (CJK \u5168\u89D2=2, \u5176\u4F59=1) */\nfunction charWidth(ch: string): number {\n const cp = ch.codePointAt(0) ?? 0;\n if (\n cp >= 0x1100 &&\n (cp <= 0x115f ||\n (cp >= 0x2e80 && cp <= 0xa4cf && cp !== 0x303f) ||\n (cp >= 0xac00 && cp <= 0xd7a3) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0xfe30 && cp <= 0xfe4f) ||\n (cp >= 0xff00 && cp <= 0xff60) ||\n (cp >= 0xffe0 && cp <= 0xffe6) ||\n (cp >= 0x20000 && cp <= 0x2fffd))\n )\n return 2;\n return 1;\n}\n\n/** \u5B57\u7B26\u4E32\u5728\u7EC8\u7AEF\u7684\u53EF\u89C1\u5BBD\u5EA6 (strip ANSI \u540E\u6309 CJK \u5BBD\u5EA6\u7D2F\u52A0) */\nexport function visibleWidth(s: string): number {\n const stripped = s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n let w = 0;\n for (const ch of stripped) w += charWidth(ch);\n return w;\n}\n\n/**\n * \u65E5\u5FD7\u524D\u7F00\u53EF\u89C1\u5BBD\u5EA6(\u65F6\u95F4 + \u6E90 + \u7EA7\u522B + \u5C3E\u7A7A\u683C),\u4F9B\u60AC\u6302\u7F29\u8FDB\u5BF9\u9F50\u6B63\u6587\u8D77\u70B9\u3002\n * \u4E0E formatLog \u62FC\u63A5\u987A\u5E8F\u4FDD\u6301\u4E00\u81F4\uFF08\u5171\u7528 resolveDisplayLevel / sourceTagPlain / levelTagPlain\uFF09\u3002\n */\nexport function logPrefixWidth(l: UnifiedLog): number {\n const ts = l.time.toLocaleTimeString();\n const src = sourceTagPlain(l.source);\n const level = resolveDisplayLevel(l);\n return visibleWidth(`${ts} ${src} ${levelTagPlain(level)} `);\n}\n\n/**\n * \u6309\u7EC8\u7AEF\u53EF\u89C1\u5BBD\u5EA6\u6362\u884C;\u663E\u5F0F \\\\n \u4E0E\u8F6F\u6362\u884C\u7684\u540E\u7EED\u884C\u4E00\u5F8B\u5DE6\u4FA7\u7F29\u8FDB indent \u5217\u3002\n * \u4FDD\u7559 ANSI:\u6362\u884C\u65F6 reset,\u65B0\u884C\u6062\u590D\u5F53\u524D\u989C\u8272\u72B6\u6001(\u53EF\u591A\u5C42\u53E0\u52A0)\u3002\n * \u5BBD\u5B57\u7B26(CJK)\u6309 2 \u5217;cols \u9884\u7559 1 \u5217,\u907F\u514D Windows Terminal \u8FB9\u754C\u518D\u8F6F\u6298\u5230\u7B2C 0 \u5217\u3002\n */\nexport function wrapLogLine(s: string, indent: number): string {\n const rawCols = process.stdout.columns || 80;\n /* \u81F3\u5C11\u7559\u7ED9\u6B63\u6587\u82E5\u5E72\u5217,\u907F\u514D indent >= cols \u65F6\u6B7B\u5FAA\u73AF */\n const cols = Math.max(rawCols - 1, indent + 4);\n const segments = s.split(/\\r?\\n/);\n const out: string[] = [];\n for (let si = 0; si < segments.length; si++) {\n const raw = segments[si]!;\n /* \u663E\u5F0F\u6362\u884C\u6BB5\u53BB\u6389\u6587\u6848\u81EA\u5E26\u7684\u5DE6\u7A7A\u683C,\u7EDF\u4E00\u7531 hang indent \u5BF9\u9F50\u6B63\u6587 */\n const piece = si === 0 ? raw : raw.replace(/^[ \\t]+/, \"\");\n out.push(wrapSegment(piece, cols, si === 0 ? 0 : indent, indent));\n }\n return out.join(\"\\n\");\n}\n\n/** \u5355\u6BB5(\u65E0\u5185\u5D4C \\\\n)\u8F6F\u6362\u884C;startPad>0 \u8868\u793A\u672C\u6BB5\u5F00\u5934\u5DF2\u5360\u7528\u7684\u5217(\u663E\u5F0F\u6362\u884C\u540E\u7684\u60AC\u6302) */\nfunction wrapSegment(s: string, cols: number, startPad: number, hangIndent: number): string {\n if (s.length === 0) return startPad > 0 ? \" \".repeat(startPad) : \"\";\n\n const lines: string[] = [];\n let cur = startPad > 0 ? \" \".repeat(startPad) : \"\";\n let w = startPad;\n /** \u5F53\u524D\u751F\u6548\u7684 ANSI \u5F00\u7801\u6808(\u4E0D\u542B reset),\u6362\u884C\u540E\u91CD\u653E */\n const ansiStack: string[] = [];\n\n const resetIfNeeded = (): void => {\n if (ansiStack.length) cur += \"\\x1b[0m\";\n };\n const replayAnsi = (): void => {\n for (const code of ansiStack) cur += code;\n };\n\n let i = 0;\n while (i < s.length) {\n const m = /^\\x1b\\[[0-9;]*m/.exec(s.slice(i));\n if (m) {\n const code = m[0]!;\n cur += code;\n if (code === \"\\x1b[0m\") ansiStack.length = 0;\n else ansiStack.push(code);\n i += code.length;\n continue;\n }\n\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const cw = charWidth(ch);\n const advance = ch.length;\n\n /* w > startPad:\u5F53\u524D\u884C\u9664\u5DE6\u57AB\u5916\u5DF2\u6709\u5185\u5BB9,\u53EF\u4EE5\u62C6\u884C;\u5426\u5219\u5F3A\u5236\u585E\u5165\u907F\u514D\u6B7B\u5FAA\u73AF */\n if (w + cw > cols && w > startPad) {\n resetIfNeeded();\n lines.push(cur);\n cur = \" \".repeat(hangIndent);\n replayAnsi();\n w = hangIndent;\n startPad = hangIndent;\n }\n\n cur += ch;\n w += cw;\n i += advance;\n }\n\n if (ansiStack.length) cur += \"\\x1b[0m\";\n lines.push(cur);\n return lines.join(\"\\n\");\n}\n\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * logs.ts \u2014 sfmc \u4E3B\u8FDB\u7A0B\u7EDF\u4E00\u65E5\u5FD7\u805A\u5408\u5C42\n *\n * \u5185\u90E8\u59D4\u6258 @sfmc-bds/logs \u5171\u4EAB\u5305\u7684 createMemoryBuffer + inferLevel,\n * \u4FDD\u6301\u5411\u540E\u517C\u5BB9\u7684 pushLog / onLog / getAllLogs / getRecentLogs API\n * (services.ts \u6355\u83B7\u5B50\u8FDB\u7A0B stdout \u540E\u8C03\u7528 pushLog \u6C47\u805A\u5230\u6B64)\u3002\n *\n * \u843D\u76D8\u7B56\u7565(\u4E0E\u5B50\u8FDB\u7A0B\u81EA\u5199\u6587\u4EF6\u5206\u5DE5,\u907F\u514D\u91CD\u590D):\n * - db / qq / update \u2192 \u5B50\u8FDB\u7A0B\u5DF2\u5199 `.sfmc/logs/{db,qq,bds-update}.log`,\u6B64\u5904\u8DF3\u8FC7\n * - bds / llbot \u2192 `.sfmc/logs/{bds,llbot}.log`(\u5916\u90E8\u8FDB\u7A0B\u65E0\u81EA\u5E26 file sink)\n * - \u5176\u4F59(system / pack / \u2026) \u2192 `.sfmc/logs/sfmc.log`\n *\n * CLI \u91CD\u8FDE\u540E\u5386\u53F2\u56DE\u653E\u4EE5\u843D\u76D8\u4E3A\u51C6\uFF08readDiskLogs\uFF09\uFF1B\u5185\u5B58\u7F13\u51B2\u53EA\u670D\u52A1\u672C\u8FDB\u7A0B\u5B9E\u65F6\u8BA2\u9605\u3002\n *\n * formatLog \u4FDD\u7559 theme.ts (chalk) \u914D\u8272,\u6BD4\u5171\u4EAB\u5305\u7684\u7EAF ANSI \u7248\u672C\u89C6\u89C9\u66F4\u4E30\u5BCC\u3002\n */\n\nimport {\n createFileSink,\n createMemoryBuffer,\n formatLogLine,\n inferLevel as sharedInferLevel,\n parseBdsEmbeddedLevel,\n stripBdsLogPrefix,\n type FileSink,\n type LogEntry,\n type LogLevel as SharedLogLevel,\n} from \"@sfmc-bds/sdk/logs\";\nimport { logFile, logsDir } from \"@sfmc-bds/sdk/node/config\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n getCompiledLogFilter,\n shouldDropForDisk,\n shouldDropForDisplay,\n transformLogEntry,\n} from \"./log-filter.js\";\nimport { c, highlightLogLine } from \"./theme.js\";\nimport { ROOT } from \"./runtime.js\";\n\nexport type LogLevel = SharedLogLevel;\nexport type LogSource = string;\nexport interface UnifiedLog extends LogEntry {}\n\n/** \u518D\u5BFC\u51FA SDK BDS \u89E3\u6790\uFF08\u6D4B\u8BD5\u4E0E\u8C03\u7528\u65B9\u7EDF\u4E00\u5165\u53E3\uFF0C\u6743\u5A01\u5728 @sfmc-bds/sdk/logs\uFF09 */\nexport { mapBdsLevelToken, parseBdsEmbeddedLevel, stripBdsLogPrefix } from \"@sfmc-bds/sdk/logs\";\n\nconst buffer = createMemoryBuffer(5000);\n\n/** \u5B50\u8FDB\u7A0B\u5DF2\u7528 createNodeServiceLogger \u81EA\u884C\u843D\u76D8\u7684 source */\nconst CHILD_OWNED_SOURCES = new Set([\"db\", \"qq\", \"update\"]);\n\nconst fileSinks = new Map<string, FileSink>();\n\n/** \u5265\u79BB BDS \u81EA\u5E26\u524D\u7F00\uFF1B\u82E5\u524D\u7F00\u540E\u6CA1\u6709\u6B63\u6587\uFF0C\u5219\u5224\u5B9A\u4E3A\u4EC5\u7528\u4E8E\u6392\u7248\u7684\u7A7A\u884C\u3002 */\nexport function normalizeBdsLogBody(text: string): string | null {\n const body = stripBdsLogPrefix(text);\n return body.trim().length > 0 ? body : null;\n}\n\n/** \u89E3\u6790\u672C\u6761\u65E5\u5FD7\u5E94\u5199\u5165\u7684\u6587\u4EF6\u540D(\u4E0D\u542B .log);null \u8868\u793A\u8DF3\u8FC7(\u5B50\u8FDB\u7A0B\u5DF2\u5199) */\nfunction resolveDiskLogName(source: string): string | null {\n if (CHILD_OWNED_SOURCES.has(source)) return null;\n if (source === \"bds\" || source === \"llbot\" || source === \"tunnel\") return source;\n return \"sfmc\";\n}\n\nfunction sinkFor(source: string): FileSink | null {\n const name = resolveDiskLogName(source);\n if (!name) return null;\n let sink = fileSinks.get(name);\n if (!sink) {\n sink = createFileSink(logFile(ROOT, name));\n fileSinks.set(name, sink);\n }\n return sink;\n}\n\nprocess.on(\"exit\", () => {\n for (const sink of fileSinks.values()) sink.close();\n});\n\n/** \u63A8\u9001\u4E00\u6761\u65E5\u5FD7\u5230\u5185\u5B58\u7F13\u51B2,\u5E76\u6309\u7B56\u7565\u843D\u76D8 */\nexport function pushLog(text: string, source: LogSource, level: LogLevel): void {\n let body = text;\n let lvl = level;\n /* BDS\uFF1A\u5148\u63D0\u53D6\u5185\u5D4C\u7EA7\u522B\uFF0C\u518D\u5265\u6389\u81EA\u5E26\u65F6\u95F4\u6233+\u7B49\u7EA7\uFF0C\u907F\u514D\u5C55\u793A/\u843D\u76D8\u91CD\u590D */\n if (source === \"bds\") {\n const embedded = parseBdsEmbeddedLevel(text);\n if (embedded) lvl = embedded;\n const normalized = normalizeBdsLogBody(text);\n if (normalized === null) return;\n body = normalized;\n }\n\n const rawEntry: LogEntry = { time: new Date(), text: body, source, level: lvl };\n const filter = getCompiledLogFilter((src) => {\n /* \u907F\u514D\u9012\u5F52\uFF1A\u975E\u6CD5\u6B63\u5219\u53EA\u5199\u6587\u4EF6 sink\uFF0C\u4E0D\u7ECF pushLog */\n try {\n const sink = sinkFor(\"system\");\n if (!sink) return;\n const warn: LogEntry = {\n time: new Date(),\n text: `log-filter: invalid regex skipped: ${src}`,\n source: \"system\",\n level: \"warn\",\n };\n sink.write(warn, formatLogLine(warn, false));\n } catch {\n /* ignore */\n }\n });\n\n const dropDisplay = shouldDropForDisplay(rawEntry, filter);\n const dropDisk = shouldDropForDisk(rawEntry, filter);\n const { entry: transformedEntry } = transformLogEntry(rawEntry, filter);\n\n if (!dropDisplay) {\n buffer.pushDirect(transformedEntry.text, source, lvl);\n }\n\n if (dropDisk) return;\n const sink = sinkFor(source);\n if (!sink) return;\n try {\n const diskEntry: LogEntry = filter.applyTo === \"all\" ? { ...rawEntry, text: transformedEntry.text } : rawEntry;\n sink.write(diskEntry, formatLogLine(diskEntry, false));\n } catch {\n /* \u843D\u76D8\u5931\u8D25\u4E0D\u963B\u65AD\u4E3B\u6D41\u7A0B */\n }\n}\n\n/**\n * \u6444\u5165\u5B88\u62A4\u8FDB\u7A0B\u8F6C\u53D1\u7684\u8FDC\u7A0B\u65E5\u5FD7\uFF1A\u53EA\u5199\u5165\u672C\u8FDB\u7A0B\u5185\u5B58\u7F13\u51B2\u5E76\u901A\u77E5\u8BA2\u9605\u8005\uFF0C\u4E0D\u518D\u843D\u76D8\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1ACLI \u5BA2\u6237\u7AEF subscribe \u540E\u628A daemon \u63A8\u9001\u7684 log \u4E8B\u4EF6\u704C\u5165\u672C\u5730\uFF0C\u4F9B REPL \u4E3B\u9762\u677F\u5B9E\u65F6\u5C55\u793A\uFF1B\n * \u843D\u76D8\u5DF2\u7531\u5B88\u62A4\u8FDB\u7A0B\u5B8C\u6210\uFF0C\u6B64\u5904\u8DF3\u8FC7\u907F\u514D\u91CD\u590D\u5199 `.sfmc/logs/*`\u3002\n */\nexport function ingestRemoteLog(text: string, source: LogSource, level: LogLevel): void {\n buffer.pushDirect(text, source, level);\n}\n\n/** \u8BA2\u9605\u65B0\u65E5\u5FD7\u4E8B\u4EF6,\u8FD4\u56DE\u53D6\u6D88\u8BA2\u9605\u51FD\u6570 */\nexport function onLog(fn: (log: UnifiedLog) => void): () => void {\n return buffer.subscribe(fn);\n}\n\n/** \u83B7\u53D6\u6700\u8FD1 n \u6761,\u53EF\u6309 level / source \u8FC7\u6EE4\uFF1B\u518D\u5957\u914D\u7F6E\u8FC7\u6EE4\uFF08display\uFF09 */\nexport function getRecentLogs(n: number, levels: LogLevel[], sources: LogSource[]): UnifiedLog[] {\n const filter = getCompiledLogFilter();\n return buffer.getRecent(n, levels, sources).filter((l) => !shouldDropForDisplay(l, filter));\n}\n\n/** \u83B7\u53D6\u5168\u90E8\u65E5\u5FD7\uFF1B\u914D\u7F6E\u8FC7\u6EE4\u4EC5\u5F71\u54CD\u8FD4\u56DE\u89C6\u56FE\uFF08\u7F13\u51B2\u5185\u53EF\u80FD\u4ECD\u6709\u5168\u91CF\uFF0C\u89C6 push \u65F6 applyTo\uFF09 */\nexport function getAllLogs(): UnifiedLog[] {\n const filter = getCompiledLogFilter();\n return buffer.getAll().filter((l) => !shouldDropForDisplay(l, filter));\n}\n\n/* ==================================================================\n * \u843D\u76D8\u6587\u4EF6\u8BFB\u53D6\uFF08/logs \u7A97\u7528\uFF0C\u4E0D\u8D70\u5185\u5B58\u7F13\u51B2\uFF09\n * ================================================================== */\n\n/** \u4E0E\u843D\u76D8\u7B56\u7565\u5BF9\u5E94\u7684\u6587\u4EF6\u57FA\u540D\uFF08\u4E0D\u542B .log\uFF09 */\nconst DISK_LOG_FILES = [\"bds\", \"llbot\", \"tunnel\", \"db\", \"qq\", \"bds-update\", \"sfmc\"] as const;\n\n/** source \u2192 \u843D\u76D8\u6587\u4EF6\u540D\uFF08\u542B\u5B50\u8FDB\u7A0B\u81EA\u5199\uFF09 */\nexport function diskFileForSource(source: string): string {\n if (source === \"update\") return \"bds-update\";\n if (source === \"bds\" || source === \"llbot\" || source === \"tunnel\" || source === \"db\" || source === \"qq\") return source;\n return \"sfmc\";\n}\n\n/** formatLogLine \u65E0\u8272\u884C\uFF1A`YYYY-MM-DD HH:mm:ss [source] [LEVEL] text` */\nconst DISK_LINE_RE =\n /^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[([^\\]]+)\\] \\[(INFO|WARN|ERROR|OK|DEBUG|SUCCESS|FATAL)\\]\\s?(.*)$/;\n\nfunction mapDiskLevelTag(tag: string): LogLevel {\n switch (tag) {\n case \"ERROR\":\n case \"FATAL\":\n return \"error\";\n case \"WARN\":\n return \"warn\";\n case \"OK\":\n case \"SUCCESS\":\n return \"success\";\n case \"DEBUG\":\n return \"debug\";\n default:\n return \"info\";\n }\n}\n\n/** \u89E3\u6790\u5355\u884C\u843D\u76D8\u65E5\u5FD7\uFF1B\u4E0D\u7B26\u683C\u5F0F\u8FD4\u56DE null */\nexport function parseDiskLogLine(raw: string): UnifiedLog | null {\n const m = DISK_LINE_RE.exec(raw);\n if (!m) return null;\n const ts = m[1]!;\n const source = m[2]!.trim();\n const level = mapDiskLevelTag(m[3]!);\n const body = m[4] ?? \"\";\n const time = new Date(ts.replace(\" \", \"T\") + \"Z\");\n return { time, source, level, text: body };\n}\n\nexport type ReadDiskLogsOpts = {\n levels?: LogLevel[];\n sources?: LogSource[];\n /** \u8986\u76D6\u65E5\u5FD7\u76EE\u5F55\uFF08\u6D4B\u8BD5\u7528\uFF09\uFF1B\u9ED8\u8BA4 `<ROOT>/.sfmc/logs` */\n dir?: string;\n /** \u4EC5\u4FDD\u7559\u65F6\u95F4\u5E8F\u6700\u540E N \u6761\uFF1B\u7701\u7565\u5219\u8FD4\u56DE\u5168\u90E8\u89E3\u6790\u7ED3\u679C */\n limit?: number;\n /** \u542B\u6B64\u65F6\u95F4\u3002\u8BBE\u7F6E\u540E\u8BFB\u53D6\u6574\u4E2A\u65E5\u5FD7\u6587\u4EF6\uFF0C\u4E0D\u518D\u53EA\u53D6\u6587\u4EF6\u672B\u5C3E */\n since?: Date;\n /** \u542B\u6B64\u65F6\u95F4 */\n until?: Date;\n};\n\n/** \u5220\u9664\u843D\u76D8\u65E5\u5FD7\u65F6\u7684\u7B5B\u9009\u3002\u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762 logs.delete\u3002 */\nexport type DeleteDiskLogsOpts = {\n since: Date;\n until: Date;\n source?: string;\n text?: string;\n /** \u8986\u76D6\u65E5\u5FD7\u76EE\u5F55\uFF08\u6D4B\u8BD5\u7528\uFF09 */\n dir?: string;\n};\n\n/**\n * \u4ECE `.sfmc/logs/*.log` \u8BFB\u53D6\u5E76\u89E3\u6790\u4E3A UnifiedLog\uFF08\u6309\u65F6\u95F4\u5347\u5E8F\uFF09\u3002\n * CLI \u91CD\u8FDE\u540E\u4E3B\u9762\u677F /logs \u7684\u5386\u53F2\u6743\u5A01\u6765\u6E90\uFF1B\u5185\u5B58\u7F13\u51B2\u4EC5\u627F\u8F7D\u672C\u8FDB\u7A0B\u8BA2\u9605\u5230\u7684\u5B9E\u65F6\u589E\u91CF\u3002\n */\nexport function readDiskLogs(opts: ReadDiskLogsOpts = {}): UnifiedLog[] {\n const levels = opts.levels ?? [];\n const sources = opts.sources ?? [];\n const dir = opts.dir ?? logsDir(ROOT);\n const sinceMs = opts.since?.getTime();\n const untilMs = opts.until?.getTime();\n const ranged = sinceMs !== undefined || untilMs !== undefined;\n const fileNames = new Set<string>();\n if (sources.length === 0) {\n for (const n of DISK_LOG_FILES) fileNames.add(n);\n } else {\n for (const s of sources) fileNames.add(diskFileForSource(s));\n }\n\n const out: UnifiedLog[] = [];\n for (const name of fileNames) {\n const fp = path.join(dir, name.endsWith(\".log\") ? name : `${name}.log`);\n let text: string;\n try {\n if (opts.limit && !ranged) {\n const fd = fs.openSync(fp, \"r\");\n try {\n const size = fs.fstatSync(fd).size;\n const start = Math.max(0, size - 4 * 1024 * 1024);\n const bytes = Buffer.alloc(size - start);\n fs.readSync(fd, bytes, 0, bytes.length, start);\n text = bytes.toString(\"utf8\");\n if (start > 0) text = text.slice(text.indexOf(\"\\n\") + 1);\n } finally { fs.closeSync(fd); }\n } else text = fs.readFileSync(fp, \"utf8\");\n } catch {\n continue;\n }\n for (const raw of text.split(/\\r?\\n/)) {\n if (!raw) continue;\n const entry = parseDiskLogLine(raw);\n if (!entry) continue;\n const time = entry.time.getTime();\n if (sinceMs !== undefined && time < sinceMs) continue;\n if (untilMs !== undefined && time > untilMs) continue;\n if (sources.length && !sources.includes(entry.source)) continue;\n if (levels.length && !levels.includes(entry.level)) continue;\n out.push(entry);\n }\n }\n out.sort((a, b) => a.time.getTime() - b.time.getTime());\n const limit = opts.limit;\n if (limit !== undefined && limit > 0 && out.length > limit) {\n return out.slice(out.length - limit);\n }\n return out;\n}\n\n/** \u8FD9\u4E00\u884C\u662F\u5426\u843D\u5728\u5220\u9664\u6761\u4EF6\u91CC\u3002\u89E3\u6790\u5931\u8D25\u7684\u884C\u4E0D\u5220\u3002 */\nfunction diskLineMatchesRemoval(entry: UnifiedLog, opts: DeleteDiskLogsOpts): boolean {\n const time = entry.time.getTime();\n if (time < opts.since.getTime() || time > opts.until.getTime()) return false;\n if (opts.source !== undefined && entry.source !== opts.source) return false;\n if (opts.text !== undefined && entry.text !== opts.text) return false;\n return true;\n}\n\n/**\n * \u4ECE\u4E00\u6BB5\u65E5\u5FD7\u6587\u672C\u91CC\u53BB\u6389\u547D\u4E2D\u7684\u884C\uFF0C\u4FDD\u7559\u65E0\u6CD5\u89E3\u6790\u7684\u884C\u548C\u539F\u6765\u7684\u6362\u884C\u98CE\u683C\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u6539\u5199 `.sfmc/logs/*.log` \u65F6\u4E0D\u628A\u574F\u884C\u4E00\u8D77\u4E22\u6389\u3002\n */\nfunction filterLogText(text: string, opts: DeleteDiskLogsOpts): { text: string; removed: number } {\n if (!text) return { text: \"\", removed: 0 };\n const newline = text.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const ended = text.endsWith(\"\\n\");\n const lines = text.split(/\\r?\\n/);\n if (ended) lines.pop();\n let removed = 0;\n const kept: string[] = [];\n for (const raw of lines) {\n const entry = raw ? parseDiskLogLine(raw) : null;\n if (entry && diskLineMatchesRemoval(entry, opts)) {\n removed++;\n continue;\n }\n kept.push(raw);\n }\n if (!kept.length) return { text: \"\", removed };\n return { text: kept.join(newline) + (ended ? newline : \"\"), removed };\n}\n\n/**\n * \u6309\u65F6\u95F4\u8303\u56F4\u5220\u9664\u5DF2\u77E5\u65E5\u5FD7\u6587\u4EF6\u4E2D\u7684\u884C\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u684C\u9762 logs.delete\u3002\u7B26\u53F7\u94FE\u63A5\u548C\u975E\u6587\u4EF6\u76F4\u63A5\u62D2\u7EDD\u3002\n * \u5199\u5165\u524D\u4F1A\u518D\u8BFB\u4E00\u6B21\u671F\u95F4\u8FFD\u52A0\u7684\u5185\u5BB9\uFF1B\u66FF\u6362\u6587\u4EF6\u7684\u77AC\u95F4\u65B0\u5199\u5165\u7684\u884C\u53EF\u80FD\u7559\u4E0B\u6765\u3002\n */\nexport function deleteStoredLogs(opts: DeleteDiskLogsOpts): { removed: number } {\n if (opts.until.getTime() < opts.since.getTime()) throw new Error(\"\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F00\u59CB\u65F6\u95F4\");\n const dir = opts.dir ?? logsDir(ROOT);\n let removed = 0;\n for (const name of DISK_LOG_FILES) {\n const file = path.join(dir, `${name}.log`);\n removed += rewriteLogFile(file, opts);\n }\n return { removed };\n}\n\n/** \u6539\u5199\u4E00\u4E2A\u65E5\u5FD7\u6587\u4EF6\u3002\u6587\u4EF6\u4E0D\u5B58\u5728\u5219\u8DF3\u8FC7\u3002 */\nfunction rewriteLogFile(file: string, opts: DeleteDiskLogsOpts): number {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(file);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return 0;\n throw error;\n }\n if (stat.isSymbolicLink()) throw new Error(`\u62D2\u7EDD\u6539\u5199\u7B26\u53F7\u94FE\u63A5\u65E5\u5FD7 ${path.basename(file)}`);\n if (!stat.isFile()) throw new Error(`\u62D2\u7EDD\u6539\u5199\u975E\u6587\u4EF6\u65E5\u5FD7 ${path.basename(file)}`);\n let text = fs.readFileSync(file, \"utf8\");\n if (fs.statSync(file).size > Buffer.byteLength(text)) text = fs.readFileSync(file, \"utf8\");\n const filtered = filterLogText(text, opts);\n if (!filtered.removed) return 0;\n const temp = `${file}.${process.pid}.filtering`;\n fs.writeFileSync(temp, filtered.text, \"utf8\");\n try {\n fs.copyFileSync(temp, file);\n } finally {\n fs.rmSync(temp, { force: true });\n }\n return filtered.removed;\n}\n\n/* ==================================================================\n * \u6765\u6E90\u6807\u7B7E\u5143\u6570\u636E (\u65B9\u62EC\u53F7\u4E0E\u6587\u5B57\u540C\u8272,\u5BF9\u9F50 levelTag)\n * ================================================================== */\n\nexport interface SourceMeta {\n value: string;\n /** \u65B9\u62EC\u53F7\u5185\u56FA\u5B9A 3 \u5B57\u7B26\uFF0C\u4E0E [INF] \u5BF9\u9F50 */\n name: string;\n paint: (s: string) => string;\n}\n\nexport const SOURCE_META: SourceMeta[] = [\n { value: \"bds\", name: \"BDS\", paint: (s) => c.green(s) },\n { value: \"db\", name: \"DB \", paint: (s) => c.blue(s) },\n { value: \"qq\", name: \"QQ \", paint: (s) => c.purple(s) },\n { value: \"llbot\", name: \"BOT\", paint: (s) => c.yellow(s) },\n { value: \"system\", name: \"SYS\", paint: (s) => c.cyan(s) },\n { value: \"update\", name: \"UPD\", paint: (s) => c.orange(s) },\n { value: \"pack\", name: \"PAK\", paint: (s) => c.purple(s) },\n { value: \"bds-tools\", name: \"TOL\", paint: (s) => c.red(s) },\n];\n\n/** \u6E90\u6807\u7B7E\u65E0\u8272\u6587\u672C\uFF08formatSourceTag / logPrefixWidth \u5171\u7528\uFF09 */\nfunction sourceTagPlain(source: string): string {\n const meta = SOURCE_META.find((m) => m.value === source);\n if (meta) return `[${meta.name}]`;\n return `[${source.toUpperCase().padEnd(3).slice(0, 3)}]`;\n}\n\nexport function formatSourceTag(source: string): string {\n const meta = SOURCE_META.find((m) => m.value === source);\n const plain = sourceTagPlain(source);\n if (meta) return meta.paint(plain);\n return c.bold(plain);\n}\n\n/**\n * \u5C55\u793A\u7528\u7EA7\u522B\uFF1ABDS \u82E5\u4ECD\u5E26\u65F6\u95F4\u6233\u524D\u7F00\u5219\u89E3\u6790\u5185\u5D4C\u7EA7\u522B\uFF1B\u5DF2\u5265\u79BB\uFF08pushLog \u5165\u5E93\uFF09\u5219\u4FE1\u4EFB entry.level\u3002\n * \u7981\u6B62\u5BF9\u6B63\u6587\u505A\u677E\u6563\u5173\u952E\u8BCD\u5339\u914D\uFF08\u4F1A\u628A `[Commands] Error on line` \u8BEF\u5224\u4E3A error\uFF09\u3002\n */\nexport function resolveDisplayLevel(l: UnifiedLog): LogLevel {\n if (l.source === \"bds\") {\n const embedded = parseBdsEmbeddedLevel(l.text);\n if (embedded) return embedded;\n }\n return l.level;\n}\n\n/** \u4ECE\u539F\u59CB\u6587\u672C\u63A8\u65AD\u7EA7\u522B\uFF1A\u59D4\u6258\u5171\u4EAB\u5305\uFF08\u5185\u542B BDS \u65F6\u95F4\u6233\u89E3\u6790\uFF09 */\nexport function inferLevel(text: string): LogLevel {\n return sharedInferLevel(text);\n}\n\n/** \u65E0\u8272\u7EA7\u522B\u6807\u7B7E\u6587\u672C\uFF08\u53EF\u89C1\u5BBD\u5EA6\u6743\u5A01\u6E90\uFF1B\u62EC\u53F7\u5185\u5747\u4E3A 3 \u5B57\u7B26\uFF09 */\nconst LEVEL_TAG_TEXT: Record<LogLevel, string> = {\n error: \"[ERR]\",\n warn: \"[WRN]\",\n success: \"[SUC]\",\n debug: \"[DBG]\",\n info: \"[INF]\",\n};\n\nfunction levelTagPlain(lvl: LogLevel): string {\n return LEVEL_TAG_TEXT[lvl] ?? LEVEL_TAG_TEXT.info;\n}\n\nfunction levelTag(lvl: LogLevel): string {\n const text = levelTagPlain(lvl);\n switch (lvl) {\n case \"error\":\n return c.red(text);\n case \"warn\":\n return c.yellow(text);\n case \"success\":\n return c.green(c.bold(text));\n case \"debug\":\n return c.dim(text);\n default:\n return c.blue(text);\n }\n}\n\n/** \u683C\u5F0F\u5316\u65E5\u5FD7\u7528\u4E8E REPL \u5C55\u793A (\u7528 theme.ts chalk \u914D\u8272) */\nexport function formatLog(l: UnifiedLog): string {\n const ts = c.dim(l.time.toLocaleTimeString());\n const level = resolveDisplayLevel(l);\n const lvl = levelTag(level);\n const src = formatSourceTag(l.source);\n /* BDS\uFF1A\u53BB\u6389\u81EA\u5E26\u65F6\u95F4\u6233+\u7B49\u7EA7\u524D\u7F00\u540E\u518D\u672C\u5730\u5316\u7FFB\u8BD1\u4E0E\u9AD8\u4EAE\u6B63\u6587\uFF08push \u65F6\u591A\u534A\u5DF2\u8F6C\u8FC7\uFF0C\u6B64\u5904\u5E42\u7B49\u4E14\u8986\u76D6\u56DE\u653E\uFF09 */\n const body = l.source === \"bds\" ? stripBdsLogPrefix(l.text) : l.text;\n const filter = getCompiledLogFilter();\n const { entry } = transformLogEntry({ text: body, source: l.source, level }, filter);\n const txt = highlightLogLine(entry.text);\n return `${ts} ${src} ${lvl} ${txt}`;\n}\n\n/* ==================================================================\n * \u8F6F\u6362\u884C: \u8D85\u7EC8\u7AEF\u5BBD\u5EA6\u65F6\u6362\u884C,\u540E\u7EED\u884C\u7F29\u8FDB\u5BF9\u9F50\n * ================================================================== */\n\n/** \u5355\u4E2A\u5B57\u7B26\u5728\u7EC8\u7AEF\u7684\u663E\u793A\u5BBD\u5EA6 (CJK \u5168\u89D2=2, \u5176\u4F59=1) */\nfunction charWidth(ch: string): number {\n const cp = ch.codePointAt(0) ?? 0;\n if (\n cp >= 0x1100 &&\n (cp <= 0x115f ||\n (cp >= 0x2e80 && cp <= 0xa4cf && cp !== 0x303f) ||\n (cp >= 0xac00 && cp <= 0xd7a3) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0xfe30 && cp <= 0xfe4f) ||\n (cp >= 0xff00 && cp <= 0xff60) ||\n (cp >= 0xffe0 && cp <= 0xffe6) ||\n (cp >= 0x20000 && cp <= 0x2fffd))\n )\n return 2;\n return 1;\n}\n\n/** \u5B57\u7B26\u4E32\u5728\u7EC8\u7AEF\u7684\u53EF\u89C1\u5BBD\u5EA6 (strip ANSI \u540E\u6309 CJK \u5BBD\u5EA6\u7D2F\u52A0) */\nexport function visibleWidth(s: string): number {\n const stripped = s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n let w = 0;\n for (const ch of stripped) w += charWidth(ch);\n return w;\n}\n\n/**\n * \u65E5\u5FD7\u524D\u7F00\u53EF\u89C1\u5BBD\u5EA6(\u65F6\u95F4 + \u6E90 + \u7EA7\u522B + \u5C3E\u7A7A\u683C),\u4F9B\u60AC\u6302\u7F29\u8FDB\u5BF9\u9F50\u6B63\u6587\u8D77\u70B9\u3002\n * \u4E0E formatLog \u62FC\u63A5\u987A\u5E8F\u4FDD\u6301\u4E00\u81F4\uFF08\u5171\u7528 resolveDisplayLevel / sourceTagPlain / levelTagPlain\uFF09\u3002\n */\nexport function logPrefixWidth(l: UnifiedLog): number {\n const ts = l.time.toLocaleTimeString();\n const src = sourceTagPlain(l.source);\n const level = resolveDisplayLevel(l);\n return visibleWidth(`${ts} ${src} ${levelTagPlain(level)} `);\n}\n\n/**\n * \u6309\u7EC8\u7AEF\u53EF\u89C1\u5BBD\u5EA6\u6362\u884C;\u663E\u5F0F \\\\n \u4E0E\u8F6F\u6362\u884C\u7684\u540E\u7EED\u884C\u4E00\u5F8B\u5DE6\u4FA7\u7F29\u8FDB indent \u5217\u3002\n * \u4FDD\u7559 ANSI:\u6362\u884C\u65F6 reset,\u65B0\u884C\u6062\u590D\u5F53\u524D\u989C\u8272\u72B6\u6001(\u53EF\u591A\u5C42\u53E0\u52A0)\u3002\n * \u5BBD\u5B57\u7B26(CJK)\u6309 2 \u5217;cols \u9884\u7559 1 \u5217,\u907F\u514D Windows Terminal \u8FB9\u754C\u518D\u8F6F\u6298\u5230\u7B2C 0 \u5217\u3002\n */\nexport function wrapLogLine(s: string, indent: number): string {\n const rawCols = process.stdout.columns || 80;\n /* \u81F3\u5C11\u7559\u7ED9\u6B63\u6587\u82E5\u5E72\u5217,\u907F\u514D indent >= cols \u65F6\u6B7B\u5FAA\u73AF */\n const cols = Math.max(rawCols - 1, indent + 4);\n const segments = s.split(/\\r?\\n/);\n const out: string[] = [];\n for (let si = 0; si < segments.length; si++) {\n const raw = segments[si]!;\n /* \u663E\u5F0F\u6362\u884C\u6BB5\u53BB\u6389\u6587\u6848\u81EA\u5E26\u7684\u5DE6\u7A7A\u683C,\u7EDF\u4E00\u7531 hang indent \u5BF9\u9F50\u6B63\u6587 */\n const piece = si === 0 ? raw : raw.replace(/^[ \\t]+/, \"\");\n out.push(wrapSegment(piece, cols, si === 0 ? 0 : indent, indent));\n }\n return out.join(\"\\n\");\n}\n\n/** \u5355\u6BB5(\u65E0\u5185\u5D4C \\\\n)\u8F6F\u6362\u884C;startPad>0 \u8868\u793A\u672C\u6BB5\u5F00\u5934\u5DF2\u5360\u7528\u7684\u5217(\u663E\u5F0F\u6362\u884C\u540E\u7684\u60AC\u6302) */\nfunction wrapSegment(s: string, cols: number, startPad: number, hangIndent: number): string {\n if (s.length === 0) return startPad > 0 ? \" \".repeat(startPad) : \"\";\n\n const lines: string[] = [];\n let cur = startPad > 0 ? \" \".repeat(startPad) : \"\";\n let w = startPad;\n /** \u5F53\u524D\u751F\u6548\u7684 ANSI \u5F00\u7801\u6808(\u4E0D\u542B reset),\u6362\u884C\u540E\u91CD\u653E */\n const ansiStack: string[] = [];\n\n const resetIfNeeded = (): void => {\n if (ansiStack.length) cur += \"\\x1b[0m\";\n };\n const replayAnsi = (): void => {\n for (const code of ansiStack) cur += code;\n };\n\n let i = 0;\n while (i < s.length) {\n const m = /^\\x1b\\[[0-9;]*m/.exec(s.slice(i));\n if (m) {\n const code = m[0]!;\n cur += code;\n if (code === \"\\x1b[0m\") ansiStack.length = 0;\n else ansiStack.push(code);\n i += code.length;\n continue;\n }\n\n const cp = s.codePointAt(i)!;\n const ch = String.fromCodePoint(cp);\n const cw = charWidth(ch);\n const advance = ch.length;\n\n /* w > startPad:\u5F53\u524D\u884C\u9664\u5DE6\u57AB\u5916\u5DF2\u6709\u5185\u5BB9,\u53EF\u4EE5\u62C6\u884C;\u5426\u5219\u5F3A\u5236\u585E\u5165\u907F\u514D\u6B7B\u5FAA\u73AF */\n if (w + cw > cols && w > startPad) {\n resetIfNeeded();\n lines.push(cur);\n cur = \" \".repeat(hangIndent);\n replayAnsi();\n w = hangIndent;\n startPad = hangIndent;\n }\n\n cur += ch;\n w += cw;\n i += advance;\n }\n\n if (ansiStack.length) cur += \"\\x1b[0m\";\n lines.push(cur);\n return lines.join(\"\\n\");\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["parseBdsEmbeddedLevel", "stripBdsLogPrefix", "sink"]
|
|
7
7
|
}
|
|
@@ -12,7 +12,7 @@ async function deploymentPreflight(ports) {
|
|
|
12
12
|
if (path.resolve(ROOT) === path.parse(ROOT).root) throw new Error("\u4E0D\u80FD\u5728\u78C1\u76D8\u6839\u76EE\u5F55\u521B\u5EFA\u90E8\u7F72");
|
|
13
13
|
for (const file of ["BDS/bedrock_server.exe", "BDS/bedrock_server", "data/sfmc_data.db"]) if (fs.existsSync(path.join(ROOT, file))) throw new Error("\u5DF2\u6709 BDS \u6216\u6570\u636E\u5E93\uFF0C\u8BF7\u63A5\u5165\u73B0\u6709\u90E8\u7F72\uFF0C\u4E0D\u8986\u76D6\u6570\u636E");
|
|
14
14
|
const space = fs.statfsSync(ROOT);
|
|
15
|
-
if (space.bavail * space.bsize < 1024 ** 3) throw new Error("\u53EF\u7528\u7A7A\u95F4\u4E0D\u8DB3 1 GiB\uFF0C\u65E0\u6CD5\u51C6\u5907\u8FD0\u884C\u65F6\
|
|
15
|
+
if (space.bavail * space.bsize < 1024 ** 3) throw new Error("\u53EF\u7528\u7A7A\u95F4\u4E0D\u8DB3 1 GiB\uFF0C\u65E0\u6CD5\u51C6\u5907\u8FD0\u884C\u65F6\u548C BDS");
|
|
16
16
|
await new Promise((resolve, reject) => {
|
|
17
17
|
const server = net.createServer();
|
|
18
18
|
server.once("error", (error) => reject(new Error(`DB \u7AEF\u53E3 ${ports.db} \u4E0D\u53EF\u7528: ${error.message}`)));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/management/deployment.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport net from \"node:net\";\nimport dgram from \"node:dgram\";\nimport { ROOT } from \"../runtime.js\";\nexport function deploymentPort(value: unknown, fallback: number) {\n const port = value === undefined ? fallback : Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(\"\u7AEF\u53E3\u5FC5\u987B\u4E3A 1 \u5230 65535 \u7684\u6574\u6570\");\n return port;\n}\nexport async function deploymentPreflight(ports: { db: number; bds: number; bds6: number }) {\n if (path.resolve(ROOT) === path.parse(ROOT).root) throw new Error(\"\u4E0D\u80FD\u5728\u78C1\u76D8\u6839\u76EE\u5F55\u521B\u5EFA\u90E8\u7F72\");\n for (const file of [\"BDS/bedrock_server.exe\", \"BDS/bedrock_server\", \"data/sfmc_data.db\"]) if (fs.existsSync(path.join(ROOT, file))) throw new Error(\"\u5DF2\u6709 BDS \u6216\u6570\u636E\u5E93\uFF0C\u8BF7\u63A5\u5165\u73B0\u6709\u90E8\u7F72\uFF0C\u4E0D\u8986\u76D6\u6570\u636E\");\n const space = fs.statfsSync(ROOT);\n if (space.bavail * space.bsize < 1024 ** 3) throw new Error(\"\u53EF\u7528\u7A7A\u95F4\u4E0D\u8DB3 1 GiB\uFF0C\u65E0\u6CD5\u51C6\u5907\u8FD0\u884C\u65F6\
|
|
5
|
-
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,SAAS,YAAY;AACd,SAAS,eAAe,OAAgB,UAAkB;AAC/D,QAAM,OAAO,UAAU,SAAY,WAAW,OAAO,KAAK;AAC1D,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,MAAO,OAAM,IAAI,MAAM,kEAAqB;AAC9F,SAAO;AACT;AACA,eAAsB,oBAAoB,OAAkD;AAC1F,MAAI,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,IAAI,EAAE,KAAM,OAAM,IAAI,MAAM,0EAAc;AAChF,aAAW,QAAQ,CAAC,0BAA0B,sBAAsB,mBAAmB,EAAG,KAAI,GAAG,WAAW,KAAK,KAAK,MAAM,IAAI,CAAC,EAAG,OAAM,IAAI,MAAM,+HAA2B;AAC/K,QAAM,QAAQ,GAAG,WAAW,IAAI;AAChC,MAAI,MAAM,SAAS,MAAM,QAAQ,QAAQ,EAAG,OAAM,IAAI,MAAM,
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport net from \"node:net\";\nimport dgram from \"node:dgram\";\nimport { ROOT } from \"../runtime.js\";\nexport function deploymentPort(value: unknown, fallback: number) {\n const port = value === undefined ? fallback : Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(\"\u7AEF\u53E3\u5FC5\u987B\u4E3A 1 \u5230 65535 \u7684\u6574\u6570\");\n return port;\n}\nexport async function deploymentPreflight(ports: { db: number; bds: number; bds6: number }) {\n if (path.resolve(ROOT) === path.parse(ROOT).root) throw new Error(\"\u4E0D\u80FD\u5728\u78C1\u76D8\u6839\u76EE\u5F55\u521B\u5EFA\u90E8\u7F72\");\n for (const file of [\"BDS/bedrock_server.exe\", \"BDS/bedrock_server\", \"data/sfmc_data.db\"]) if (fs.existsSync(path.join(ROOT, file))) throw new Error(\"\u5DF2\u6709 BDS \u6216\u6570\u636E\u5E93\uFF0C\u8BF7\u63A5\u5165\u73B0\u6709\u90E8\u7F72\uFF0C\u4E0D\u8986\u76D6\u6570\u636E\");\n const space = fs.statfsSync(ROOT);\n if (space.bavail * space.bsize < 1024 ** 3) throw new Error(\"\u53EF\u7528\u7A7A\u95F4\u4E0D\u8DB3 1 GiB\uFF0C\u65E0\u6CD5\u51C6\u5907\u8FD0\u884C\u65F6\u548C BDS\");\n await new Promise<void>((resolve, reject) => {\n const server = net.createServer(); server.once(\"error\", error => reject(new Error(`DB \u7AEF\u53E3 ${ports.db} \u4E0D\u53EF\u7528: ${error.message}`)));\n server.listen(ports.db, \"0.0.0.0\", () => server.close(error => error ? reject(error) : resolve()));\n });\n for (const [port, type, address] of [[ports.bds, \"udp4\", \"0.0.0.0\"], [ports.bds6, \"udp6\", \"::\"]] as const) {\n await new Promise<void>((resolve, reject) => {\n const socket = dgram.createSocket(type);\n socket.once(\"error\", error => { socket.close(); reject(new Error(`BDS \u7AEF\u53E3 ${port} \u4E0D\u53EF\u7528: ${error.message}`)); });\n socket.bind(port, address, () => socket.close(() => resolve()));\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,SAAS,YAAY;AACd,SAAS,eAAe,OAAgB,UAAkB;AAC/D,QAAM,OAAO,UAAU,SAAY,WAAW,OAAO,KAAK;AAC1D,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,MAAO,OAAM,IAAI,MAAM,kEAAqB;AAC9F,SAAO;AACT;AACA,eAAsB,oBAAoB,OAAkD;AAC1F,MAAI,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,IAAI,EAAE,KAAM,OAAM,IAAI,MAAM,0EAAc;AAChF,aAAW,QAAQ,CAAC,0BAA0B,sBAAsB,mBAAmB,EAAG,KAAI,GAAG,WAAW,KAAK,KAAK,MAAM,IAAI,CAAC,EAAG,OAAM,IAAI,MAAM,+HAA2B;AAC/K,QAAM,QAAQ,GAAG,WAAW,IAAI;AAChC,MAAI,MAAM,SAAS,MAAM,QAAQ,QAAQ,EAAG,OAAM,IAAI,MAAM,sGAA2B;AACvF,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,UAAM,SAAS,IAAI,aAAa;AAAG,WAAO,KAAK,SAAS,WAAS,OAAO,IAAI,MAAM,mBAAS,MAAM,EAAE,wBAAS,MAAM,OAAO,EAAE,CAAC,CAAC;AAC7H,WAAO,OAAO,MAAM,IAAI,WAAW,MAAM,OAAO,MAAM,WAAS,QAAQ,OAAO,KAAK,IAAI,QAAQ,CAAC,CAAC;AAAA,EACnG,CAAC;AACD,aAAW,CAAC,MAAM,MAAM,OAAO,KAAK,CAAC,CAAC,MAAM,KAAK,QAAQ,SAAS,GAAG,CAAC,MAAM,MAAM,QAAQ,IAAI,CAAC,GAAY;AACzG,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,YAAM,SAAS,MAAM,aAAa,IAAI;AACtC,aAAO,KAAK,SAAS,WAAS;AAAE,eAAO,MAAM;AAAG,eAAO,IAAI,MAAM,oBAAU,IAAI,wBAAS,MAAM,OAAO,EAAE,CAAC;AAAA,MAAG,CAAC;AAC5G,aAAO,KAAK,MAAM,SAAS,MAAM,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,IAChE,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,10 +22,22 @@ export declare function searchModules(query: string): Promise<{
|
|
|
22
22
|
sdk?: string;
|
|
23
23
|
repo?: string;
|
|
24
24
|
tag?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
category?: string;
|
|
28
|
+
license?: string;
|
|
29
|
+
official?: boolean;
|
|
30
|
+
requires?: string[];
|
|
25
31
|
id: string;
|
|
26
32
|
}[];
|
|
27
33
|
stale: boolean;
|
|
28
34
|
}>;
|
|
35
|
+
/**
|
|
36
|
+
* 安装前核对索引里的 requires。
|
|
37
|
+
* 使用场景:modules.install 在创建下载任务之前调用。索引没有这个 id 时返回 null,继续原来的安装路径。
|
|
38
|
+
* 有条目但没有合法 requires,或依赖未安装、未启用时返回说明,调用方不得开始安装。
|
|
39
|
+
*/
|
|
40
|
+
export declare function moduleInstallBlock(id: string): Promise<string | null>;
|
|
29
41
|
export declare function runFetch(args: string[]): Promise<{
|
|
30
42
|
changed: boolean;
|
|
31
43
|
}>;
|
|
@@ -44,13 +56,45 @@ export declare function listPacks(): {
|
|
|
44
56
|
kind: import("@sfmc-bds/bds-tools/world-packs").WorldPackKind;
|
|
45
57
|
enabled: boolean;
|
|
46
58
|
version: string;
|
|
59
|
+
iconStamp?: string;
|
|
60
|
+
protected?: boolean;
|
|
47
61
|
}[];
|
|
48
62
|
};
|
|
49
|
-
|
|
63
|
+
/**
|
|
64
|
+
* 读取某个已安装世界包的 pack_icon.png。
|
|
65
|
+
* 使用场景:桌面世界包列表按 iconStamp 按需拉取,不放进每 5 秒的 packs.list。
|
|
66
|
+
* 找不到包、文件缺失或内容不是 PNG 时返回空图标,不抛错。
|
|
67
|
+
*/
|
|
68
|
+
export declare function readPackIcon(id: string): {
|
|
69
|
+
id: string;
|
|
70
|
+
mime: "image/png" | null;
|
|
71
|
+
data: string | null;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* 卸载一个世界包,并沿用 CLI 的配对资源包与回收站规则。
|
|
75
|
+
* 使用场景:桌面 packs.uninstall。平台聚合包直接拒绝。
|
|
76
|
+
*/
|
|
77
|
+
export declare function uninstallPack(id: string): Promise<{
|
|
50
78
|
changed: boolean;
|
|
51
79
|
restartRequired: boolean;
|
|
80
|
+
removed: import("../world-packs.js").PackUninstallOutcome[];
|
|
52
81
|
}>;
|
|
53
|
-
|
|
82
|
+
/**
|
|
83
|
+
* 解析桌面传入的资源包版本。
|
|
84
|
+
* 使用场景:packs.version。只接受 major.minor.patch,每一段都是非负安全整数。
|
|
85
|
+
*/
|
|
86
|
+
export declare function parsePackVersion(value: unknown): [number, number, number];
|
|
87
|
+
/**
|
|
88
|
+
* 修改一个已安装资源包的清单版本,并在已启用时同步世界启用列表。
|
|
89
|
+
* 使用场景:桌面 packs.version。行为包直接拒绝。
|
|
90
|
+
* 模块条目写成与 header 相同的完整版本;命令行 packs bump 仍只抬修订号。
|
|
91
|
+
*/
|
|
92
|
+
export declare function setPackVersion(id: string, versionText: unknown): Promise<{
|
|
93
|
+
changed: boolean;
|
|
94
|
+
restartRequired: boolean;
|
|
95
|
+
version: string;
|
|
96
|
+
}>;
|
|
97
|
+
export declare function togglePack(id: string, enabled: boolean): Promise<{
|
|
54
98
|
changed: boolean;
|
|
55
99
|
restartRequired: boolean;
|
|
56
100
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/management/domain.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../../src/management/domain.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AACD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAGxD;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGjD;AACD,wBAAsB,WAAW;;;;;;;;;GAMhC;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;GAehD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ3E;AACD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE;;GAG5C;AACD,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvH;AACD,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAM,EAAO,oBAIlD;AACD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE;YAI+B;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE;GAQlH;AAkBD,wBAAgB,SAAS;IAEd,KAAK;;;;;;;;;EAYf;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAUtG;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM;;;;GAS7C;AACD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAezE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO;;;;GAcpE;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;;;GAO5D;AACD,wBAAgB,WAAW;IAEhB,SAAS;IAAoC,WAAW;IAAsC,eAAe;EACvH;AACD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAWzD,KAAK;EACf"}
|
|
@@ -5,8 +5,10 @@ import { spawn } from "node:child_process";
|
|
|
5
5
|
import { resolveRegistryIndex } from "../registry.js";
|
|
6
6
|
import { ROOT, resolveFetchModule } from "../runtime.js";
|
|
7
7
|
import { resolveBdsContext, scanLocalModules } from "../pack-lifecycle.js";
|
|
8
|
-
import { listInstalledWorldPacks,
|
|
8
|
+
import { listInstalledWorldPacks, enableInstalledPack, disableInstalledPack, writePackHeaderVersion } from "@sfmc-bds/bds-tools/world-packs";
|
|
9
|
+
import { buildPackUninstallQueue, isProtectedSfmcPack, resolveUninstallTargets, runPackUninstallQueue } from "../world-packs.js";
|
|
9
10
|
import { atomicJson } from "./tasks.js";
|
|
11
|
+
import { assessModuleRequires, moduleRequireBlockMessage } from "@sfmc-bds/management";
|
|
10
12
|
import { isRetiredPlatformModule } from "@sfmc-bds/sdk/contracts";
|
|
11
13
|
function stripBom(text) {
|
|
12
14
|
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
@@ -35,8 +37,28 @@ function fetchEntry() {
|
|
|
35
37
|
return entry;
|
|
36
38
|
}
|
|
37
39
|
async function searchModules(query) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
let result = await resolveRegistryIndex();
|
|
41
|
+
if (Object.values(result.index).some((entry) => !Array.isArray(entry.requires))) {
|
|
42
|
+
result = await resolveRegistryIndex({ force: true });
|
|
43
|
+
}
|
|
44
|
+
const needle = query.trim().toLowerCase();
|
|
45
|
+
return {
|
|
46
|
+
modules: Object.entries(result.index).filter(([id, metadata]) => {
|
|
47
|
+
if (isRetiredPlatformModule(id)) return false;
|
|
48
|
+
if (!needle) return true;
|
|
49
|
+
return [id, metadata.name, metadata.description, metadata.npm].some((value) => value?.toLowerCase().includes(needle));
|
|
50
|
+
}).map(([id, metadata]) => ({ id, ...metadata })),
|
|
51
|
+
stale: result.stale
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function moduleInstallBlock(id) {
|
|
55
|
+
let result = await resolveRegistryIndex();
|
|
56
|
+
const cached = result.index[id];
|
|
57
|
+
if (cached && !Array.isArray(cached.requires)) result = await resolveRegistryIndex({ force: true });
|
|
58
|
+
const entry = result.index[id];
|
|
59
|
+
if (!entry) return null;
|
|
60
|
+
const installed = (await listModules()).modules;
|
|
61
|
+
return moduleRequireBlockMessage(id, assessModuleRequires(entry.requires, installed));
|
|
40
62
|
}
|
|
41
63
|
async function runFetch(args) {
|
|
42
64
|
await runProcess(process.execPath, [fetchEntry(), ...args], ROOT);
|
|
@@ -69,9 +91,89 @@ async function applyModulePlan(ids) {
|
|
|
69
91
|
if (result.failed.length) throw new Error(JSON.stringify(result.failed));
|
|
70
92
|
return result;
|
|
71
93
|
}
|
|
94
|
+
const PACK_ICON_MAX_BYTES = 1572864;
|
|
95
|
+
const PNG_MAGIC = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
96
|
+
function packIconStamp(dir) {
|
|
97
|
+
const file = path.join(dir, "pack_icon.png");
|
|
98
|
+
let stat;
|
|
99
|
+
try {
|
|
100
|
+
stat = fs.lstatSync(file);
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size <= 0 || stat.size > PACK_ICON_MAX_BYTES) return null;
|
|
105
|
+
return `${stat.size}:${Math.trunc(stat.mtimeMs)}`;
|
|
106
|
+
}
|
|
72
107
|
function listPacks() {
|
|
73
108
|
const context = resolveBdsContext();
|
|
74
|
-
return { packs: listInstalledWorldPacks(context.bdsRoot, context.levelName).map((pack) =>
|
|
109
|
+
return { packs: listInstalledWorldPacks(context.bdsRoot, context.levelName).map((pack) => {
|
|
110
|
+
const iconStamp = packIconStamp(pack.dir);
|
|
111
|
+
return {
|
|
112
|
+
id: pack.uuid,
|
|
113
|
+
name: pack.name,
|
|
114
|
+
kind: pack.kind,
|
|
115
|
+
enabled: pack.enabled,
|
|
116
|
+
version: pack.version.join("."),
|
|
117
|
+
...iconStamp ? { iconStamp } : {},
|
|
118
|
+
...isProtectedSfmcPack(pack) ? { protected: true } : {}
|
|
119
|
+
};
|
|
120
|
+
}) };
|
|
121
|
+
}
|
|
122
|
+
function readPackIcon(id) {
|
|
123
|
+
const empty = { id, mime: null, data: null };
|
|
124
|
+
const context = resolveBdsContext();
|
|
125
|
+
const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find((row) => row.uuid.toLowerCase() === id.toLowerCase());
|
|
126
|
+
if (!pack || !packIconStamp(pack.dir)) return empty;
|
|
127
|
+
const file = path.join(pack.dir, "pack_icon.png");
|
|
128
|
+
let data;
|
|
129
|
+
try {
|
|
130
|
+
data = fs.readFileSync(file);
|
|
131
|
+
} catch {
|
|
132
|
+
return empty;
|
|
133
|
+
}
|
|
134
|
+
if (data.length < PNG_MAGIC.length || !data.subarray(0, PNG_MAGIC.length).equals(PNG_MAGIC) || data.length > PACK_ICON_MAX_BYTES) return empty;
|
|
135
|
+
return { id: pack.uuid, mime: "image/png", data: data.toString("base64") };
|
|
136
|
+
}
|
|
137
|
+
async function uninstallPack(id) {
|
|
138
|
+
const context = resolveBdsContext();
|
|
139
|
+
const packs = listInstalledWorldPacks(context.bdsRoot, context.levelName);
|
|
140
|
+
const resolved = resolveUninstallTargets(packs, [id]);
|
|
141
|
+
if (resolved.status === "not_found") throw new Error("\u627E\u4E0D\u5230\u4E16\u754C\u5305");
|
|
142
|
+
if (resolved.status === "protected") throw new Error("\u5E73\u53F0\u805A\u5408\u5305\u4E0D\u53EF\u901A\u8FC7\u4E16\u754C\u5305\u5378\u8F7D\uFF0C\u8BF7\u4F7F\u7528\u6A21\u5757\u7BA1\u7406");
|
|
143
|
+
const queue = buildPackUninstallQueue(resolved.selected, packs, false);
|
|
144
|
+
const removed = await runPackUninstallQueue(queue, { bdsRoot: context.bdsRoot, levelName: context.levelName, purge: false });
|
|
145
|
+
return { changed: true, restartRequired: true, removed };
|
|
146
|
+
}
|
|
147
|
+
function parsePackVersion(value) {
|
|
148
|
+
if (typeof value !== "string") throw new Error("\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch");
|
|
149
|
+
const parts = value.split(".");
|
|
150
|
+
if (parts.length !== 3) throw new Error("\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch");
|
|
151
|
+
const numbers = parts.map((part) => {
|
|
152
|
+
if (!/^\d+$/.test(part)) throw new Error("\u7248\u672C\u53F7\u5FC5\u987B\u4E3A\u975E\u8D1F\u6574\u6570");
|
|
153
|
+
const number = Number(part);
|
|
154
|
+
if (!Number.isSafeInteger(number)) throw new Error("\u7248\u672C\u53F7\u8D85\u51FA\u53EF\u7CBE\u786E\u8868\u793A\u7684\u6574\u6570\u8303\u56F4");
|
|
155
|
+
return number;
|
|
156
|
+
});
|
|
157
|
+
const major = numbers[0];
|
|
158
|
+
const minor = numbers[1];
|
|
159
|
+
const patch = numbers[2];
|
|
160
|
+
if (major === void 0 || minor === void 0 || patch === void 0) throw new Error("\u7248\u672C\u53F7\u5FC5\u987B\u4E3A major.minor.patch");
|
|
161
|
+
return [major, minor, patch];
|
|
162
|
+
}
|
|
163
|
+
async function setPackVersion(id, versionText) {
|
|
164
|
+
const version = parsePackVersion(versionText);
|
|
165
|
+
const context = resolveBdsContext();
|
|
166
|
+
const pack = listInstalledWorldPacks(context.bdsRoot, context.levelName).find((row) => row.uuid === id);
|
|
167
|
+
if (!pack) throw new Error("\u627E\u4E0D\u5230\u4E16\u754C\u5305");
|
|
168
|
+
if (pack.kind !== "resource") throw new Error("\u53EA\u80FD\u4FEE\u6539\u8D44\u6E90\u5305\u7684\u7248\u672C\u53F7");
|
|
169
|
+
if (pack.version[0] === version[0] && pack.version[1] === version[1] && pack.version[2] === version[2]) {
|
|
170
|
+
return { changed: false, restartRequired: false, version: pack.version.join(".") };
|
|
171
|
+
}
|
|
172
|
+
const next = writePackHeaderVersion(pack.dir, version, "full");
|
|
173
|
+
if (pack.enabled) {
|
|
174
|
+
await enableInstalledPack({ ...context, info: { uuid: pack.uuid, version: next, kind: "resource", name: pack.name } });
|
|
175
|
+
}
|
|
176
|
+
return { changed: true, restartRequired: true, version: next.join(".") };
|
|
75
177
|
}
|
|
76
178
|
async function togglePack(id, enabled) {
|
|
77
179
|
const context = resolveBdsContext();
|
|
@@ -81,26 +183,6 @@ async function togglePack(id, enabled) {
|
|
|
81
183
|
else await disableInstalledPack({ ...context, kind: pack.kind, packUuid: pack.uuid, version: pack.version });
|
|
82
184
|
return { changed: true, restartRequired: true };
|
|
83
185
|
}
|
|
84
|
-
async function importPack(filename) {
|
|
85
|
-
const inbox = path.resolve(ROOT, "packs", "_desktop-inbox");
|
|
86
|
-
const file = path.resolve(inbox, identifier(filename));
|
|
87
|
-
if (!file.startsWith(inbox + path.sep) || !fs.existsSync(file)) throw new Error("\u4E16\u754C\u5305\u5C1A\u672A\u4E0A\u4F20\u5230\u5B9E\u4F8B\u6536\u4EF6\u7BB1");
|
|
88
|
-
const context = resolveBdsContext();
|
|
89
|
-
const resolved = await resolvePackRoots(file);
|
|
90
|
-
try {
|
|
91
|
-
if (!resolved.roots.length) throw new Error("\u5F52\u6863\u4E0D\u542B\u53EF\u8BC6\u522B\u7684\u4E16\u754C\u5305");
|
|
92
|
-
for (const root of resolved.roots) {
|
|
93
|
-
const info = readPackManifestInfo(root);
|
|
94
|
-
if (!info) throw new Error("\u4E16\u754C\u5305 manifest \u65E0\u6548");
|
|
95
|
-
const result = await installPackDirectory({ srcDir: root, destParent: worldPackParentDir(context.bdsRoot, context.levelName, info.kind) });
|
|
96
|
-
if (!result.ok) throw new Error(result.reason ?? "\u5B89\u88C5\u5931\u8D25\uFF1B\u53EF\u80FD\u4E0E\u5DF2\u6709\u5305\u51B2\u7A81");
|
|
97
|
-
await enableInstalledPack({ ...context, info });
|
|
98
|
-
}
|
|
99
|
-
} finally {
|
|
100
|
-
resolved.dispose?.();
|
|
101
|
-
}
|
|
102
|
-
return { changed: true, restartRequired: true };
|
|
103
|
-
}
|
|
104
186
|
function playerFiles() {
|
|
105
187
|
const bds = resolveBdsContext().bdsRoot;
|
|
106
188
|
return { allowlist: path.join(bds, "allowlist.json"), permissions: path.join(bds, "permissions.json"), sfmcPermissions: path.join(ROOT, "configs", "permissions.json") };
|
|
@@ -121,17 +203,21 @@ function savePlayerPermissions(kind, entries) {
|
|
|
121
203
|
export {
|
|
122
204
|
applyModulePlan,
|
|
123
205
|
identifier,
|
|
124
|
-
importPack,
|
|
125
206
|
listModules,
|
|
126
207
|
listPacks,
|
|
208
|
+
moduleInstallBlock,
|
|
127
209
|
modulePlan,
|
|
210
|
+
parsePackVersion,
|
|
128
211
|
playerFiles,
|
|
129
212
|
readJson,
|
|
213
|
+
readPackIcon,
|
|
130
214
|
runFetch,
|
|
131
215
|
runProcess,
|
|
132
216
|
savePlayerPermissions,
|
|
133
217
|
searchModules,
|
|
218
|
+
setPackVersion,
|
|
134
219
|
stripBom,
|
|
135
|
-
togglePack
|
|
220
|
+
togglePack,
|
|
221
|
+
uninstallPack
|
|
136
222
|
};
|
|
137
223
|
//# sourceMappingURL=domain.js.map
|