@sfmc-bds/cli 0.2.0-beta.7 → 0.2.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/argv-parse.d.ts +0 -2
  2. package/dist/argv-parse.d.ts.map +1 -1
  3. package/dist/argv-parse.js +1 -5
  4. package/dist/argv-parse.js.map +2 -2
  5. package/dist/cli-gate.d.ts.map +1 -1
  6. package/dist/cli-gate.js +0 -2
  7. package/dist/cli-gate.js.map +2 -2
  8. package/dist/command-surface.d.ts +2 -12
  9. package/dist/command-surface.d.ts.map +1 -1
  10. package/dist/command-surface.js +2 -34
  11. package/dist/command-surface.js.map +2 -2
  12. package/dist/commands.d.ts.map +1 -1
  13. package/dist/commands.js +123 -10
  14. package/dist/commands.js.map +2 -2
  15. package/dist/help-text.d.ts.map +1 -1
  16. package/dist/help-text.js +1 -5
  17. package/dist/help-text.js.map +2 -2
  18. package/dist/i18n/locales/en.d.ts +27 -38
  19. package/dist/i18n/locales/en.d.ts.map +1 -1
  20. package/dist/i18n/locales/en.js +27 -41
  21. package/dist/i18n/locales/en.js.map +2 -2
  22. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  23. package/dist/i18n/locales/zh-CN.js +27 -41
  24. package/dist/i18n/locales/zh-CN.js.map +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +3 -4
  28. package/dist/index.js.map +2 -2
  29. package/dist/llbot-launch.d.ts +20 -0
  30. package/dist/llbot-launch.d.ts.map +1 -0
  31. package/dist/llbot-launch.js +40 -0
  32. package/dist/llbot-launch.js.map +7 -0
  33. package/dist/main.js +7 -12
  34. package/dist/main.js.map +2 -2
  35. package/dist/module-commands.d.ts +5 -18
  36. package/dist/module-commands.d.ts.map +1 -1
  37. package/dist/module-commands.js +89 -87
  38. package/dist/module-commands.js.map +2 -2
  39. package/dist/module-pack-build.d.ts.map +1 -1
  40. package/dist/module-pack-build.js +4 -0
  41. package/dist/module-pack-build.js.map +2 -2
  42. package/dist/module-toggle.d.ts +33 -0
  43. package/dist/module-toggle.d.ts.map +1 -0
  44. package/dist/module-toggle.js +28 -0
  45. package/dist/module-toggle.js.map +7 -0
  46. package/dist/node-service-probe.d.ts +18 -0
  47. package/dist/node-service-probe.d.ts.map +1 -0
  48. package/dist/node-service-probe.js +97 -0
  49. package/dist/node-service-probe.js.map +7 -0
  50. package/dist/pack-lifecycle.d.ts.map +1 -1
  51. package/dist/pack-lifecycle.js +11 -1
  52. package/dist/pack-lifecycle.js.map +2 -2
  53. package/dist/repl-windows/service-window.d.ts +1 -1
  54. package/dist/repl-windows/service-window.d.ts.map +1 -1
  55. package/dist/repl-windows/service-window.js +8 -1
  56. package/dist/repl-windows/service-window.js.map +2 -2
  57. package/dist/repl.d.ts +0 -2
  58. package/dist/repl.d.ts.map +1 -1
  59. package/dist/repl.js +0 -19
  60. package/dist/repl.js.map +2 -2
  61. package/dist/runtime.d.ts +4 -13
  62. package/dist/runtime.d.ts.map +1 -1
  63. package/dist/runtime.js +15 -27
  64. package/dist/runtime.js.map +2 -2
  65. package/dist/send-target.d.ts.map +1 -1
  66. package/dist/send-target.js +6 -2
  67. package/dist/send-target.js.map +2 -2
  68. package/dist/services.d.ts +32 -6
  69. package/dist/services.d.ts.map +1 -1
  70. package/dist/services.js +101 -16
  71. package/dist/services.js.map +2 -2
  72. package/dist/wizard.d.ts.map +1 -1
  73. package/dist/wizard.js +65 -7
  74. package/dist/wizard.js.map +2 -2
  75. package/package.json +7 -8
  76. package/dist/cmd-remote.d.ts +0 -13
  77. package/dist/cmd-remote.d.ts.map +0 -1
  78. package/dist/cmd-remote.js +0 -38
  79. package/dist/cmd-remote.js.map +0 -7
  80. package/dist/module-publish.d.ts +0 -69
  81. package/dist/module-publish.d.ts.map +0 -1
  82. package/dist/module-publish.js +0 -478
  83. package/dist/module-publish.js.map +0 -7
  84. package/dist/module-watch.d.ts +0 -32
  85. package/dist/module-watch.d.ts.map +0 -1
  86. package/dist/module-watch.js +0 -171
  87. package/dist/module-watch.js.map +0 -7
  88. package/dist/remote-agent.d.ts +0 -18
  89. package/dist/remote-agent.d.ts.map +0 -1
  90. package/dist/remote-agent.js +0 -198
  91. package/dist/remote-agent.js.map +0 -7
@@ -1,3 +1,4 @@
1
+ import type { QQBackend } from "@sfmc-bds/sdk/node/config";
1
2
  import { type ChildProcess } from "node:child_process";
2
3
  import { EventEmitter } from "node:events";
3
4
  import { type ServiceId } from "./runtime.js";
@@ -9,6 +10,27 @@ export interface LogLine {
9
10
  }
10
11
  export type ServiceName = "bds" | "db" | "qq" | "llbot";
11
12
  export declare const SERVICE_NAMES: ServiceName[];
13
+ export declare function setArgvDaemonize(on: boolean): void;
14
+ /** 单服务 start 结果:optional 服务 validate 失败记为 skipped,不抛错 */
15
+ export type StartOutcome = {
16
+ status: "started";
17
+ } | {
18
+ status: "already";
19
+ } | {
20
+ status: "skipped";
21
+ reason: string;
22
+ };
23
+ export interface StartAllResult {
24
+ started: ServiceName[];
25
+ skipped: Array<{
26
+ name: ServiceName;
27
+ reason: string;
28
+ }>;
29
+ failed: Array<{
30
+ name: ServiceName;
31
+ reason: string;
32
+ }>;
33
+ }
12
34
  export interface ServiceStatus {
13
35
  name: ServiceName;
14
36
  title: string;
@@ -17,6 +39,7 @@ export interface ServiceStatus {
17
39
  uptime: string;
18
40
  ownership?: "managed" | "external";
19
41
  }
42
+ export declare function getQqBackendMode(): QQBackend;
20
43
  interface ServiceDef {
21
44
  name: ServiceName;
22
45
  title: string;
@@ -29,6 +52,11 @@ interface ServiceDef {
29
52
  stopTimeout: number;
30
53
  autoRestart: boolean;
31
54
  restartDelay: number;
55
+ /**
56
+ * 可选服务:validate 失败时 start 返回 skipped(startAll 不当作失败)。
57
+ * 用于 official 下跳过 llbot、以及 qq_enabled=false。
58
+ */
59
+ optional?: boolean;
32
60
  validate?: () => string | null;
33
61
  /** 启动前钩子(如 BDS 装载一致性校验);失败则禁止 spawn */
34
62
  beforeStart?: () => Promise<void>;
@@ -47,10 +75,10 @@ declare class Service {
47
75
  constructor(def: ServiceDef);
48
76
  get uptime(): string;
49
77
  pushLog(text: string, stream: "stdout" | "stderr"): void;
50
- start(): Promise<void>;
78
+ start(): Promise<StartOutcome>;
51
79
  stop(): Promise<void>;
52
80
  forceStop(): void;
53
- restart(): Promise<void>;
81
+ restart(): Promise<StartOutcome>;
54
82
  getRecentLogs(n: number): LogLine[];
55
83
  /**
56
84
  * 探测发现进程已死后回写本地状态(不设 manualStop,以便 exit 回调仍可按需 autoRestart)。
@@ -61,7 +89,7 @@ declare class Service {
61
89
  export declare let services: Record<ServiceName, Service>;
62
90
  export declare function refreshServices(): void;
63
91
  export declare const START_ORDER: ServiceName[];
64
- export declare function startAll(): Promise<void>;
92
+ export declare function startAll(): Promise<StartAllResult>;
65
93
  export declare function stopAll(): Promise<void>;
66
94
  export declare function forceStopAll(): void;
67
95
  export type ServiceStateEvent = {
@@ -73,11 +101,9 @@ export type ServiceStateEvent = {
73
101
  export declare function onServiceStateChange(fn: (ev: ServiceStateEvent) => void): () => void;
74
102
  /**
75
103
  * 统一运行态查询(权威入口):OS/健康探测 + 回写 Service 内存标志。
76
- * status / Tab 发送目标 / remote / reload 等均应走此接口,勿直接读 `service.running`。
104
+ * status / Tab 发送目标 / reload 等均应走此接口,勿直接读 `service.running`。
77
105
  */
78
106
  export declare function queryServicesRuntime(): Promise<ServiceStatus[]>;
79
- /** @deprecated 请用 queryServicesRuntime;保留别名以免破坏现有调用 */
80
- export declare function serviceStatus(): Promise<ServiceStatus[]>;
81
107
  /** 单服务是否在跑(含外部实例) */
82
108
  export declare function isServiceRunning(name: ServiceName): Promise<boolean>;
83
109
  //# sourceMappingURL=services.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
package/dist/services.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  ensureCoreConfigs,
3
3
  loadEnsuredConfig,
4
+ qqRuntimeStatusPath,
5
+ readJson,
4
6
  DEFAULT_BDS_UPDATER_CONFIG,
5
7
  DEFAULT_DB_CONFIG,
6
8
  DEFAULT_QQ_CONFIG
@@ -12,17 +14,28 @@ import {
12
14
  readBdsPidFile,
13
15
  writeBdsPidFile
14
16
  } from "@sfmc-bds/bds-tools/process-probe";
17
+ import { bdsExePath, bdsSpawnEnvExtra, ensureBdsExecutable } from "@sfmc-bds/bds-tools/host-platform";
15
18
  import { spawn } from "node:child_process";
16
19
  import { EventEmitter } from "node:events";
17
20
  import fs from "node:fs";
18
21
  import path from "node:path";
19
22
  import { inferLevel, pushLog as pushUnifiedLog } from "./logs.js";
23
+ import { resolveLlbotLaunch } from "./llbot-launch.js";
24
+ import { findNodeServicePids } from "./node-service-probe.js";
20
25
  import { ROOT, spawnService } from "./runtime.js";
21
26
  import { ensurePackUpdateConfigFile } from "./pack-update/index.js";
22
27
  import { t } from "./i18n/index.js";
23
28
  import { ROOT as ROOT2 } from "./runtime.js";
24
29
  const SERVICE_NAMES = ["bds", "db", "qq", "llbot"];
30
+ let argvDaemonize = false;
31
+ function setArgvDaemonize(on) {
32
+ argvDaemonize = on;
33
+ }
25
34
  let dbHealthPort = 3001;
35
+ let qqBackendMode = "official";
36
+ function getQqBackendMode() {
37
+ return qqBackendMode;
38
+ }
26
39
  async function probeDbHealth(port) {
27
40
  try {
28
41
  const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(2e3) });
@@ -31,6 +44,12 @@ async function probeDbHealth(port) {
31
44
  return false;
32
45
  }
33
46
  }
47
+ async function probeQqRuntime() {
48
+ const status = readJson(qqRuntimeStatusPath(ROOT));
49
+ if (!status?.pid || status.pid <= 0) return { alive: false, pid: 0 };
50
+ if (!await isProcessAlive(status.pid)) return { alive: false, pid: 0 };
51
+ return { alive: true, pid: status.pid };
52
+ }
34
53
  class Service {
35
54
  name;
36
55
  title;
@@ -65,7 +84,7 @@ class Service {
65
84
  pushUnifiedLog(text, this.name, level);
66
85
  }
67
86
  async start() {
68
- if (this.running) return;
87
+ if (this.running) return { status: "already" };
69
88
  if (this.name === "bds") {
70
89
  const probe = await probeBdsStatus({ rootDir: ROOT });
71
90
  if (probe.state !== "stopped") {
@@ -74,20 +93,32 @@ class Service {
74
93
  );
75
94
  }
76
95
  }
96
+ if (this.name === "db" || this.name === "qq") {
97
+ const external = await findNodeServicePids(this.name);
98
+ if (external.length > 0) {
99
+ return { status: "already" };
100
+ }
101
+ }
77
102
  if (this.def.validate) {
78
103
  const v = this.def.validate();
79
- if (v) throw new Error(v);
104
+ if (v) {
105
+ if (this.def.optional) return { status: "skipped", reason: v };
106
+ throw new Error(v);
107
+ }
80
108
  }
81
109
  if (this.def.beforeStart) {
82
110
  await this.def.beforeStart();
83
111
  }
84
112
  this.manualStop = false;
113
+ const daemonize = argvDaemonize && process.platform !== "win32";
85
114
  const spawnOpts = {
86
115
  cwd: this.def.cwd,
87
- stdio: ["pipe", "pipe", "pipe"],
88
- env: this.def.env ? { ...process.env, ...this.def.env } : process.env
116
+ stdio: daemonize ? "ignore" : ["pipe", "pipe", "pipe"],
117
+ env: this.def.env ? { ...process.env, ...this.def.env } : process.env,
118
+ detached: daemonize
89
119
  };
90
120
  const child = this.def.service ? spawnService(this.def.service, this.def.args ?? [], spawnOpts) : spawn(this.def.cmd, this.def.args ?? [], spawnOpts);
121
+ if (daemonize) child.unref();
91
122
  this.proc = child;
92
123
  this.pid = child.pid ?? 0;
93
124
  this.running = true;
@@ -120,6 +151,7 @@ class Service {
120
151
  }, this.def.restartDelay);
121
152
  }
122
153
  });
154
+ return { status: "started" };
123
155
  }
124
156
  async stop() {
125
157
  if (!this.proc || !this.running) return;
@@ -159,7 +191,7 @@ class Service {
159
191
  }
160
192
  async restart() {
161
193
  await this.stop();
162
- await this.start();
194
+ return this.start();
163
195
  }
164
196
  getRecentLogs(n) {
165
197
  return this.logs.slice(-n);
@@ -211,12 +243,17 @@ function createServices() {
211
243
  { ...DEFAULT_DB_CONFIG }
212
244
  );
213
245
  const bdsPath = bdsCfg.bds_path ?? ROOT;
246
+ const useLlbotBackend = qqCfg.qq_backend === "llbot";
247
+ const qqEnabled = qqCfg.qq_enabled !== false;
214
248
  const llbotEnabled = qqCfg.llbot_enabled !== false;
215
- const llbotPath = qqCfg.llbot_path ?? "D:\\LLBot-CLI-win-x64\\llbot.exe";
216
- const llbotCwd = qqCfg.llbot_cwd ?? "D:\\LLBot-CLI-win-x64";
249
+ const llbotLaunch = resolveLlbotLaunch(qqCfg.llbot_path, qqCfg.llbot_cwd);
250
+ const llbotPath = llbotLaunch.exe;
251
+ const llbotCwd = llbotLaunch.cwd;
217
252
  const dbPort = dbCfg.db_port ?? 3001;
218
253
  dbHealthPort = dbPort;
219
- const bdsExe = path.resolve(bdsPath, "bedrock_server.exe");
254
+ qqBackendMode = useLlbotBackend ? "llbot" : "official";
255
+ const bdsExe = bdsExePath(path.resolve(bdsPath));
256
+ const qqTitle = useLlbotBackend ? "QQ (llbot)" : "QQ (official)";
220
257
  return {
221
258
  bds: new Service({
222
259
  name: "bds",
@@ -224,6 +261,7 @@ function createServices() {
224
261
  cmd: bdsExe,
225
262
  args: [],
226
263
  cwd: bdsPath,
264
+ env: bdsSpawnEnvExtra(bdsPath),
227
265
  stopCommand: "stop",
228
266
  stopTimeout: 3e4,
229
267
  autoRestart: bdsCfg.crash_restart !== false,
@@ -233,6 +271,7 @@ function createServices() {
233
271
  return null;
234
272
  },
235
273
  beforeStart: async () => {
274
+ ensureBdsExecutable(bdsExe);
236
275
  const { scanAndInstallInbox } = await import("./world-packs.js");
237
276
  await scanAndInstallInbox({ interactive: false });
238
277
  const { runPackUpdatesOnBdsStart } = await import("./pack-update/index.js");
@@ -253,12 +292,23 @@ function createServices() {
253
292
  }),
254
293
  qq: new Service({
255
294
  name: "qq",
256
- title: "QQ Bridge",
295
+ title: qqTitle,
257
296
  service: "qq",
258
297
  cwd: ROOT,
259
298
  stopTimeout: 1e4,
299
+ // 缺凭据时 validate 拦下,不会 spawn→exit(1)→autoRestart 死循环
260
300
  autoRestart: true,
261
- restartDelay: 3e3
301
+ restartDelay: 3e3,
302
+ optional: !qqEnabled,
303
+ validate: () => {
304
+ if (!qqEnabled) return "QQ bridge disabled (qq_enabled=false)";
305
+ if (!useLlbotBackend) {
306
+ if (!String(qqCfg.qq_app_id ?? "").trim() || !String(qqCfg.qq_app_secret ?? "").trim()) {
307
+ return "missing qq_app_id / qq_app_secret (official backend)";
308
+ }
309
+ }
310
+ return null;
311
+ }
262
312
  }),
263
313
  llbot: new Service({
264
314
  name: "llbot",
@@ -269,7 +319,10 @@ function createServices() {
269
319
  stopTimeout: 1e4,
270
320
  autoRestart: false,
271
321
  restartDelay: 5e3,
322
+ // official 或未启用时真正 skip,不 throw
323
+ optional: !useLlbotBackend || !llbotEnabled,
272
324
  validate: () => {
325
+ if (!useLlbotBackend) return "LLBot skipped (qq_backend!=llbot)";
273
326
  if (!llbotEnabled) return "LLBot disabled (llbot_enabled=false)";
274
327
  if (!fs.existsSync(llbotPath)) return `not found: ${llbotPath}`;
275
328
  return null;
@@ -284,15 +337,25 @@ function refreshServices() {
284
337
  }
285
338
  const START_ORDER = ["db", "qq", "llbot", "bds"];
286
339
  async function startAll() {
340
+ const result = { started: [], skipped: [], failed: [] };
287
341
  for (const name of START_ORDER) {
288
342
  const svc = services[name];
289
343
  if (!svc) continue;
290
344
  try {
291
- await svc.start();
345
+ const outcome = await svc.start();
346
+ if (outcome.status === "skipped") {
347
+ result.skipped.push({ name, reason: outcome.reason });
348
+ svc.events.emit("output", `skipped: ${outcome.reason}`, "info");
349
+ } else {
350
+ result.started.push(name);
351
+ }
292
352
  } catch (e) {
293
- svc.events.emit("output", `start error: ${e.message}`, "error");
353
+ const reason = e.message;
354
+ result.failed.push({ name, reason });
355
+ svc.events.emit("output", `start error: ${reason}`, "error");
294
356
  }
295
357
  }
358
+ return result;
296
359
  }
297
360
  async function stopAll() {
298
361
  const pending = [...START_ORDER].reverse().map((name) => services[name]).filter((service) => Boolean(service?.running)).map((service) => service.stop());
@@ -366,6 +429,30 @@ async function queryServicesRuntime() {
366
429
  } else if (await probeDbHealth(dbHealthPort)) {
367
430
  running = true;
368
431
  ownership = "external";
432
+ const pids = await findNodeServicePids("db");
433
+ pid = pids[0] ?? 0;
434
+ }
435
+ } else if (name === "qq") {
436
+ const managed = await reconcileManagedAlive(service);
437
+ if (managed) {
438
+ running = true;
439
+ pid = service.pid;
440
+ uptime = service.uptime;
441
+ ownership = "managed";
442
+ } else {
443
+ const probe = await probeQqRuntime();
444
+ if (probe.alive) {
445
+ running = true;
446
+ pid = probe.pid;
447
+ ownership = "external";
448
+ } else {
449
+ const pids = await findNodeServicePids("qq");
450
+ if (pids.length > 0) {
451
+ running = true;
452
+ pid = pids[0];
453
+ ownership = "external";
454
+ }
455
+ }
369
456
  }
370
457
  } else {
371
458
  const managed = await reconcileManagedAlive(service);
@@ -387,9 +474,6 @@ async function queryServicesRuntime() {
387
474
  })
388
475
  );
389
476
  }
390
- async function serviceStatus() {
391
- return queryServicesRuntime();
392
- }
393
477
  async function isServiceRunning(name) {
394
478
  const rows = await queryServicesRuntime();
395
479
  return rows.some((r) => r.name === name && r.running);
@@ -399,12 +483,13 @@ export {
399
483
  SERVICE_NAMES,
400
484
  START_ORDER,
401
485
  forceStopAll,
486
+ getQqBackendMode,
402
487
  isServiceRunning,
403
488
  onServiceStateChange,
404
489
  queryServicesRuntime,
405
490
  refreshServices,
406
- serviceStatus,
407
491
  services,
492
+ setArgvDaemonize,
408
493
  startAll,
409
494
  stopAll
410
495
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/services.ts"],
4
- "sourcesContent": ["import type { BdsUpdaterConfig, DBConfig, QQBridgeConfig } from \"@sfmc-bds/sdk/node/config\";\nimport {\n ensureCoreConfigs,\n loadEnsuredConfig,\n DEFAULT_BDS_UPDATER_CONFIG,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n} from \"@sfmc-bds/sdk/node/config\";\nimport {\n clearBdsPidFile,\n isProcessAlive,\n probeBdsStatus,\n readBdsPidFile,\n writeBdsPidFile,\n} from \"@sfmc-bds/bds-tools/process-probe\";\nimport { spawn, type ChildProcess, type IOType } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { inferLevel, pushLog as pushUnifiedLog } from \"./logs.js\";\nimport { ROOT, spawnService, type ServiceId } from \"./runtime.js\";\nimport { ensurePackUpdateConfigFile } from \"./pack-update/index.js\";\nimport { t } from \"./i18n/index.js\";\n\nexport { ROOT } from \"./runtime.js\";\n\nexport interface LogLine {\n time: Date;\n text: string;\n stream: \"stdout\" | \"stderr\";\n}\n\nexport type ServiceName = \"bds\" | \"db\" | \"qq\" | \"llbot\";\nexport const SERVICE_NAMES: ServiceName[] = [\"bds\", \"db\", \"qq\", \"llbot\"];\n\nexport interface ServiceStatus {\n name: ServiceName;\n title: string;\n running: boolean;\n pid: number;\n uptime: string;\n ownership?: \"managed\" | \"external\";\n}\n\n/** \u5F53\u524D db \u5065\u5EB7\u63A2\u6D4B\u7AEF\u53E3\uFF08\u4E0E createServices \u540C\u6B65\uFF09 */\nlet dbHealthPort = 3001;\n\nasync function probeDbHealth(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(2000) });\n return res.ok;\n } catch {\n return false;\n }\n}\n\ninterface ServiceDef {\n name: ServiceName;\n title: string;\n service?: ServiceId;\n cmd?: string;\n args?: string[];\n cwd: string;\n env?: Record<string, string>;\n stopCommand?: string;\n stopTimeout: number;\n autoRestart: boolean;\n restartDelay: number;\n validate?: () => string | null;\n /** \u542F\u52A8\u524D\u94A9\u5B50(\u5982 BDS \u88C5\u8F7D\u4E00\u81F4\u6027\u6821\u9A8C);\u5931\u8D25\u5219\u7981\u6B62 spawn */\n beforeStart?: () => Promise<void>;\n}\n\nclass Service {\n name: ServiceName;\n title: string;\n proc: ChildProcess | null = null;\n running = false;\n pid = 0;\n startTime: Date | null = null;\n logs: LogLine[] = [];\n events = new EventEmitter();\n\n private def: ServiceDef;\n private manualStop = false;\n\n constructor(def: ServiceDef) {\n this.name = def.name;\n this.title = def.title;\n this.def = def;\n }\n\n get uptime(): string {\n if (!this.startTime || !this.running) return \"\u2014\";\n const ms = Date.now() - this.startTime.getTime();\n const m = Math.floor(ms / 60000);\n const h = Math.floor(m / 60);\n if (h > 0) return `${h}h ${m % 60}m`;\n if (m > 0) return `${m}m`;\n return `${Math.floor(ms / 1000)}s`;\n }\n\n pushLog(text: string, stream: \"stdout\" | \"stderr\"): void {\n const line: LogLine = { time: new Date(), text, stream };\n this.logs.push(line);\n if (this.logs.length > 2000) this.logs.splice(0, this.logs.length - 2000);\n this.events.emit(\"log\", line);\n // stderr \u89C6\u4E3A error; stdout \u7528 inferLevel \u63A8\u65AD (bare \u5B50\u8FDB\u7A0B\u7EAF text \u65F6\u9ED8\u8BA4 info,\n // BDS \u7B49\u81EA\u5E26 [LEVEL] \u6807\u7B7E\u7684\u4ECD\u53EF\u6B63\u786E\u63A8\u65AD)\n const level = stream === \"stderr\" ? \"error\" : inferLevel(text);\n pushUnifiedLog(text, this.name, level);\n }\n\n async start(): Promise<void> {\n if (this.running) return;\n if (this.name === \"bds\") {\n const probe = await probeBdsStatus({ rootDir: ROOT });\n if (probe.state !== \"stopped\") {\n throw new Error(\n t(\"svc.bdsAlreadyRunning\", { pid: String(probe.pid), kind: t(probe.state === \"managed\" ? \"svc.running\" : \"svc.runningExternal\") })\n );\n }\n }\n if (this.def.validate) {\n const v = this.def.validate();\n if (v) throw new Error(v);\n }\n if (this.def.beforeStart) {\n await this.def.beforeStart();\n }\n this.manualStop = false;\n const spawnOpts = {\n cwd: this.def.cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"] as Array<IOType>,\n env: this.def.env ? { ...process.env, ...this.def.env } : process.env,\n };\n const child = this.def.service\n ? spawnService(this.def.service, this.def.args ?? [], spawnOpts)\n : spawn(this.def.cmd as string, this.def.args ?? [], spawnOpts);\n //child.unref();\n this.proc = child;\n this.pid = child.pid ?? 0;\n this.running = true;\n this.startTime = new Date();\n if (this.name === \"bds\" && this.pid > 0) {\n writeBdsPidFile(this.pid, ROOT);\n }\n this.events.emit(\"output\", `started (PID ${this.pid})`, \"info\");\n this.events.emit(\"state\", { name: this.name, running: true, pid: this.pid });\n\n child.on(\"error\", (e) => {\n this.events.emit(\"output\", `process error: ${e.message}`, \"error\");\n this.cleanup();\n });\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n for (const line of d.toString().split(\"\\n\").filter(Boolean)) {\n this.pushLog(line, \"stdout\");\n }\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n for (const line of d.toString().split(\"\\n\").filter(Boolean)) {\n this.pushLog(line, \"stderr\");\n }\n });\n\n child.on(\"exit\", (code) => {\n this.events.emit(\"output\", `exited (code: ${code})`, \"info\");\n this.cleanup();\n if (!this.manualStop && this.def.autoRestart) {\n setTimeout(() => {\n void this.start();\n }, this.def.restartDelay);\n }\n });\n }\n\n async stop(): Promise<void> {\n if (!this.proc || !this.running) return;\n this.manualStop = true;\n this.events.emit(\"output\", \"stopping...\", \"info\");\n\n if (this.def.stopCommand && this.proc.stdin) {\n this.proc.stdin.write(this.def.stopCommand + \"\\n\");\n } else {\n this.proc.kill(\"SIGTERM\");\n }\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n if (this.proc) {\n this.events.emit(\"output\", \"force kill\", \"error\");\n try {\n this.proc.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n resolve();\n }, this.def.stopTimeout);\n\n this.proc?.on(\"exit\", () => {\n clearTimeout(timeout);\n resolve();\n });\n });\n }\n\n forceStop(): void {\n const child = this.proc;\n this.manualStop = true;\n this.cleanup();\n if (!child) return;\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n\n async restart(): Promise<void> {\n await this.stop();\n await this.start();\n }\n\n getRecentLogs(n: number): LogLine[] {\n return this.logs.slice(-n);\n }\n\n /**\n * \u63A2\u6D4B\u53D1\u73B0\u8FDB\u7A0B\u5DF2\u6B7B\u540E\u56DE\u5199\u672C\u5730\u72B6\u6001\uFF08\u4E0D\u8BBE manualStop\uFF0C\u4EE5\u4FBF exit \u56DE\u8C03\u4ECD\u53EF\u6309\u9700 autoRestart\uFF09\u3002\n */\n markStoppedFromProbe(): void {\n if (!this.running && !this.proc) return;\n this.cleanup();\n }\n\n private cleanup(): void {\n const wasRunning = this.running || this.proc !== null;\n const exitingPid = this.pid;\n this.proc = null;\n this.running = false;\n this.pid = 0;\n this.startTime = null;\n if (this.name === \"bds\" && exitingPid > 0) {\n const filePid = readBdsPidFile(ROOT);\n if (filePid === exitingPid) {\n clearBdsPidFile(ROOT);\n }\n }\n if (wasRunning) {\n this.events.emit(\"state\", { name: this.name, running: false, pid: 0 });\n }\n }\n}\n\nfunction createServices(): Record<ServiceName, Service> {\n /* \u5404\u670D\u52A1/CLI \u7528 SDK ensureCoreConfigs \u64AD\u79CD\uFF08\u542B $schema\uFF09\uFF0C\u4E0D\u518D\u4ECE configs-default \u62F7\u8D1D\u3002 */\n ensureCoreConfigs(ROOT, [\"bds_updater\", \"qq_config\", \"db_config\"]);\n ensurePackUpdateConfigFile();\n const bdsCfg = loadEnsuredConfig(\n ROOT,\n \"bds_updater.json\",\n \"bds_updater\",\n { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<string, unknown>\n ) as BdsUpdaterConfig;\n const qqCfg = loadEnsuredConfig(\n ROOT,\n \"qq_config.json\",\n \"qq_config\",\n { ...DEFAULT_QQ_CONFIG } as Record<string, unknown>\n ) as QQBridgeConfig;\n const dbCfg = loadEnsuredConfig(\n ROOT,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n ) as DBConfig;\n const bdsPath = bdsCfg.bds_path ?? ROOT;\n const llbotEnabled = qqCfg.llbot_enabled !== false;\n const llbotPath = qqCfg.llbot_path ?? \"D:\\\\LLBot-CLI-win-x64\\\\llbot.exe\";\n const llbotCwd = qqCfg.llbot_cwd ?? \"D:\\\\LLBot-CLI-win-x64\";\n const dbPort = dbCfg.db_port ?? 3001;\n dbHealthPort = dbPort;\n const bdsExe = path.resolve(bdsPath, \"bedrock_server.exe\");\n\n return {\n bds: new Service({\n name: \"bds\",\n title: \"BDS\",\n cmd: bdsExe,\n args: [],\n cwd: bdsPath,\n stopCommand: \"stop\",\n stopTimeout: 30000,\n autoRestart: bdsCfg.crash_restart !== false,\n restartDelay: 5000,\n validate: () => {\n if (!fs.existsSync(bdsExe)) return `not found: ${bdsExe}`;\n return null;\n },\n beforeStart: async () => {\n /* \u5148\u88C5\u6536\u4EF6\u7BB1\u7B2C\u4E09\u65B9\u5305\uFF0C\u518D\u68C0\u67E5 CF \u66F4\u65B0\uFF0C\u518D\u8DD1\u6A21\u5757\u805A\u5408\u95F8\u95E8 */\n const { scanAndInstallInbox } = await import(\"./world-packs.js\");\n await scanAndInstallInbox({ interactive: false });\n const { runPackUpdatesOnBdsStart } = await import(\"./pack-update/index.js\");\n await runPackUpdatesOnBdsStart();\n const { ensurePacksReady } = await import(\"./pack-lifecycle.js\");\n await ensurePacksReady();\n },\n }),\n\n db: new Service({\n name: \"db\",\n title: \"DB Server\",\n service: \"db\",\n cwd: ROOT,\n stopTimeout: 10000,\n autoRestart: true,\n restartDelay: 3000,\n env: { DB_PORT: String(dbPort) },\n }),\n\n qq: new Service({\n name: \"qq\",\n title: \"QQ Bridge\",\n service: \"qq\",\n cwd: ROOT,\n stopTimeout: 10000,\n autoRestart: true,\n restartDelay: 3000,\n }),\n\n llbot: new Service({\n name: \"llbot\",\n title: \"LLBot\",\n cmd: llbotPath,\n args: [],\n cwd: llbotCwd,\n stopTimeout: 10000,\n autoRestart: false,\n restartDelay: 5000,\n validate: () => {\n if (!llbotEnabled) return \"LLBot disabled (llbot_enabled=false)\";\n if (!fs.existsSync(llbotPath)) return `not found: ${llbotPath}`;\n return null;\n },\n }),\n };\n}\n\nexport let services: Record<ServiceName, Service> = createServices();\n\nexport function refreshServices(): void {\n forceStopAll();\n services = createServices();\n}\n\nexport const START_ORDER: ServiceName[] = [\"db\", \"qq\", \"llbot\", \"bds\"];\n\nexport async function startAll(): Promise<void> {\n for (const name of START_ORDER) {\n const svc = services[name];\n if (!svc) continue;\n try {\n await svc.start();\n } catch (e) {\n svc.events.emit(\"output\", `start error: ${(e as Error).message}`, \"error\");\n }\n }\n}\n\nexport async function stopAll(): Promise<void> {\n const pending = [...START_ORDER]\n .reverse()\n .map((name) => services[name])\n .filter((service): service is Service => Boolean(service?.running))\n .map((service) => service.stop());\n await Promise.allSettled(pending);\n}\n\nexport function forceStopAll(): void {\n for (const service of Object.values(services)) service.forceStop();\n}\n\nexport type ServiceStateEvent = { name: ServiceName; running: boolean; pid: number };\n\n/** \u8BA2\u9605\u4EFB\u610F\u670D\u52A1\u542F\u505C\uFF08\u542B\u63A2\u6D4B\u56DE\u5199\uFF09\uFF1B\u8FD4\u56DE\u53D6\u6D88\u51FD\u6570 */\nexport function onServiceStateChange(fn: (ev: ServiceStateEvent) => void): () => void {\n const handler = (ev: ServiceStateEvent): void => {\n fn(ev);\n };\n for (const service of Object.values(services)) {\n service.events.on(\"state\", handler);\n }\n return () => {\n for (const service of Object.values(services)) {\n service.events.off(\"state\", handler);\n }\n };\n}\n\n/** \u82E5\u672C\u5730\u6807\u8BB0 running \u4F46 OS \u8FDB\u7A0B\u5DF2\u6B7B\uFF0C\u56DE\u6536\u5185\u5B58\u6807\u5FD7 */\nasync function reconcileManagedAlive(service: Service): Promise<boolean> {\n if (!service.running) return false;\n if (service.pid > 0 && !(await isProcessAlive(service.pid))) {\n service.markStoppedFromProbe();\n return false;\n }\n return service.running;\n}\n\n/**\n * \u7EDF\u4E00\u8FD0\u884C\u6001\u67E5\u8BE2\uFF08\u6743\u5A01\u5165\u53E3\uFF09\uFF1AOS/\u5065\u5EB7\u63A2\u6D4B + \u56DE\u5199 Service \u5185\u5B58\u6807\u5FD7\u3002\n * status / Tab \u53D1\u9001\u76EE\u6807 / remote / reload \u7B49\u5747\u5E94\u8D70\u6B64\u63A5\u53E3\uFF0C\u52FF\u76F4\u63A5\u8BFB `service.running`\u3002\n */\nexport async function queryServicesRuntime(): Promise<ServiceStatus[]> {\n return Promise.all(\n SERVICE_NAMES.map(async (name) => {\n const service = services[name];\n let running = false;\n let pid = 0;\n let uptime = \"\u2014\";\n let ownership: \"managed\" | \"external\" | undefined;\n\n if (name === \"bds\") {\n const probe = await probeBdsStatus({\n managedPid: service.pid,\n hasStdin: Boolean(service.proc?.stdin),\n rootDir: ROOT,\n });\n if (probe.state === \"managed\") {\n running = true;\n pid = probe.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n /* \u63A2\u6D4B\u4E3A managed \u4F46\u672C\u5730\u5DF2\u6807\u505C\uFF1A\u4FDD\u6301\u63A2\u6D4B\u7ED3\u679C\uFF0C\u4E0D\u5F3A\u5236\u6539\u5185\u5B58\uFF08stdin \u4ECD\u53EF\u7528\uFF09 */\n } else if (probe.state === \"external\") {\n running = true;\n pid = probe.pid;\n ownership = \"external\";\n /* \u5916\u90E8\u8FDB\u7A0B\uFF1A\u672C\u5730 managed \u53E5\u67C4\u5DF2\u5931\u6548\u5219\u56DE\u6536 */\n if (service.running && service.pid !== probe.pid) {\n service.markStoppedFromProbe();\n } else if (service.running && !(await isProcessAlive(service.pid))) {\n service.markStoppedFromProbe();\n }\n } else {\n running = false;\n if (service.running || service.proc) {\n service.markStoppedFromProbe();\n }\n }\n } else if (name === \"db\") {\n const managed = await reconcileManagedAlive(service);\n if (managed) {\n running = true;\n pid = service.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n } else if (await probeDbHealth(dbHealthPort)) {\n running = true;\n ownership = \"external\";\n }\n } else {\n const managed = await reconcileManagedAlive(service);\n if (managed) {\n running = true;\n pid = service.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n }\n }\n\n return {\n name,\n title: service.title,\n running,\n pid,\n uptime,\n ...(ownership ? { ownership } : {}),\n };\n })\n );\n}\n\n/** @deprecated \u8BF7\u7528 queryServicesRuntime\uFF1B\u4FDD\u7559\u522B\u540D\u4EE5\u514D\u7834\u574F\u73B0\u6709\u8C03\u7528 */\nexport async function serviceStatus(): Promise<ServiceStatus[]> {\n return queryServicesRuntime();\n}\n\n/** \u5355\u670D\u52A1\u662F\u5426\u5728\u8DD1\uFF08\u542B\u5916\u90E8\u5B9E\u4F8B\uFF09 */\nexport async function isServiceRunning(name: ServiceName): Promise<boolean> {\n const rows = await queryServicesRuntime();\n return rows.some((r) => r.name === name && r.running);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { BdsUpdaterConfig, DBConfig, QQBackend, QQBridgeConfig } from \"@sfmc-bds/sdk/node/config\";\nimport {\n ensureCoreConfigs,\n loadEnsuredConfig,\n qqRuntimeStatusPath,\n readJson,\n DEFAULT_BDS_UPDATER_CONFIG,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n type QqRuntimeStatus,\n} from \"@sfmc-bds/sdk/node/config\";\nimport {\n clearBdsPidFile,\n isProcessAlive,\n probeBdsStatus,\n readBdsPidFile,\n writeBdsPidFile,\n} from \"@sfmc-bds/bds-tools/process-probe\";\nimport { bdsExePath, bdsSpawnEnvExtra, ensureBdsExecutable } from \"@sfmc-bds/bds-tools/host-platform\";\nimport { spawn, type ChildProcess, type IOType } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { inferLevel, pushLog as pushUnifiedLog } from \"./logs.js\";\nimport { resolveLlbotLaunch } from \"./llbot-launch.js\";\nimport { findNodeServicePids } from \"./node-service-probe.js\";\nimport { ROOT, spawnService, type ServiceId } from \"./runtime.js\";\nimport { ensurePackUpdateConfigFile } from \"./pack-update/index.js\";\nimport { t } from \"./i18n/index.js\";\n\nexport { ROOT } from \"./runtime.js\";\n\nexport interface LogLine {\n time: Date;\n text: string;\n stream: \"stdout\" | \"stderr\";\n}\n\nexport type ServiceName = \"bds\" | \"db\" | \"qq\" | \"llbot\";\nexport const SERVICE_NAMES: ServiceName[] = [\"bds\", \"db\", \"qq\", \"llbot\"];\n\n/** argv \u4E00\u6B21\u6027 start \u5728 POSIX \u4E0A\u987B daemonize\uFF0C\u5426\u5219\u7236\u8FDB\u7A0B\u9000\u51FA\u4F1A\u5E26\u8D70\u5B50\u8FDB\u7A0B\uFF08Windows \u4E0D\u9700\u8981\uFF09 */\nlet argvDaemonize = false;\nexport function setArgvDaemonize(on: boolean): void {\n argvDaemonize = on;\n}\n\n/** \u5355\u670D\u52A1 start \u7ED3\u679C\uFF1Aoptional \u670D\u52A1 validate \u5931\u8D25\u8BB0\u4E3A skipped\uFF0C\u4E0D\u629B\u9519 */\nexport type StartOutcome =\n | { status: \"started\" }\n | { status: \"already\" }\n | { status: \"skipped\"; reason: string };\n\nexport interface StartAllResult {\n started: ServiceName[];\n skipped: Array<{ name: ServiceName; reason: string }>;\n failed: Array<{ name: ServiceName; reason: string }>;\n}\n\nexport interface ServiceStatus {\n name: ServiceName;\n title: string;\n running: boolean;\n pid: number;\n uptime: string;\n ownership?: \"managed\" | \"external\";\n}\n\n/** \u5F53\u524D db \u5065\u5EB7\u63A2\u6D4B\u7AEF\u53E3\uFF08\u4E0E createServices \u540C\u6B65\uFF09 */\nlet dbHealthPort = 3001;\n/** \u5F53\u524D QQ \u540E\u7AEF\uFF08\u4E0E createServices \u540C\u6B65\uFF0C\u4F9B Tab/\u7A97\u6807\u9898\uFF09 */\nlet qqBackendMode: QQBackend = \"official\";\n\nexport function getQqBackendMode(): QQBackend {\n return qqBackendMode;\n}\n\nasync function probeDbHealth(port: number): Promise<boolean> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(2000) });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/** \u8BFB `.sfmc/qq.runtime.json` + pid \u5B58\u6D3B\uFF0C\u63A2\u6D4B\u5916\u90E8/\u672C\u673A qq-bridge */\nasync function probeQqRuntime(): Promise<{ alive: boolean; pid: number }> {\n const status = readJson<QqRuntimeStatus>(qqRuntimeStatusPath(ROOT));\n if (!status?.pid || status.pid <= 0) return { alive: false, pid: 0 };\n if (!(await isProcessAlive(status.pid))) return { alive: false, pid: 0 };\n return { alive: true, pid: status.pid };\n}\n\ninterface ServiceDef {\n name: ServiceName;\n title: string;\n service?: ServiceId;\n cmd?: string;\n args?: string[];\n cwd: string;\n env?: Record<string, string>;\n stopCommand?: string;\n stopTimeout: number;\n autoRestart: boolean;\n restartDelay: number;\n /**\n * \u53EF\u9009\u670D\u52A1\uFF1Avalidate \u5931\u8D25\u65F6 start \u8FD4\u56DE skipped\uFF08startAll \u4E0D\u5F53\u4F5C\u5931\u8D25\uFF09\u3002\n * \u7528\u4E8E official \u4E0B\u8DF3\u8FC7 llbot\u3001\u4EE5\u53CA qq_enabled=false\u3002\n */\n optional?: boolean;\n validate?: () => string | null;\n /** \u542F\u52A8\u524D\u94A9\u5B50(\u5982 BDS \u88C5\u8F7D\u4E00\u81F4\u6027\u6821\u9A8C);\u5931\u8D25\u5219\u7981\u6B62 spawn */\n beforeStart?: () => Promise<void>;\n}\n\nclass Service {\n name: ServiceName;\n title: string;\n proc: ChildProcess | null = null;\n running = false;\n pid = 0;\n startTime: Date | null = null;\n logs: LogLine[] = [];\n events = new EventEmitter();\n\n private def: ServiceDef;\n private manualStop = false;\n\n constructor(def: ServiceDef) {\n this.name = def.name;\n this.title = def.title;\n this.def = def;\n }\n\n get uptime(): string {\n if (!this.startTime || !this.running) return \"\u2014\";\n const ms = Date.now() - this.startTime.getTime();\n const m = Math.floor(ms / 60000);\n const h = Math.floor(m / 60);\n if (h > 0) return `${h}h ${m % 60}m`;\n if (m > 0) return `${m}m`;\n return `${Math.floor(ms / 1000)}s`;\n }\n\n pushLog(text: string, stream: \"stdout\" | \"stderr\"): void {\n const line: LogLine = { time: new Date(), text, stream };\n this.logs.push(line);\n if (this.logs.length > 2000) this.logs.splice(0, this.logs.length - 2000);\n this.events.emit(\"log\", line);\n // stderr \u89C6\u4E3A error; stdout \u7528 inferLevel \u63A8\u65AD (bare \u5B50\u8FDB\u7A0B\u7EAF text \u65F6\u9ED8\u8BA4 info,\n // BDS \u7B49\u81EA\u5E26 [LEVEL] \u6807\u7B7E\u7684\u4ECD\u53EF\u6B63\u786E\u63A8\u65AD)\n const level = stream === \"stderr\" ? \"error\" : inferLevel(text);\n pushUnifiedLog(text, this.name, level);\n }\n\n async start(): Promise<StartOutcome> {\n if (this.running) return { status: \"already\" };\n if (this.name === \"bds\") {\n const probe = await probeBdsStatus({ rootDir: ROOT });\n if (probe.state !== \"stopped\") {\n throw new Error(\n t(\"svc.bdsAlreadyRunning\", { pid: String(probe.pid), kind: t(probe.state === \"managed\" ? \"svc.running\" : \"svc.runningExternal\") })\n );\n }\n }\n if (this.name === \"db\" || this.name === \"qq\") {\n const external = await findNodeServicePids(this.name);\n if (external.length > 0) {\n return { status: \"already\" };\n }\n }\n if (this.def.validate) {\n const v = this.def.validate();\n if (v) {\n // optional\uFF1A\u914D\u7F6E\u5C42\u9762\u8DF3\u8FC7\uFF08\u5982 official \u4E0B llbot\uFF09\uFF0C\u4E0D\u5F53\u5931\u8D25\u3001\u4E5F\u4E0D spawn\n if (this.def.optional) return { status: \"skipped\", reason: v };\n throw new Error(v);\n }\n }\n if (this.def.beforeStart) {\n await this.def.beforeStart();\n }\n this.manualStop = false;\n const daemonize = argvDaemonize && process.platform !== \"win32\";\n const spawnOpts = {\n cwd: this.def.cwd,\n stdio: (daemonize ? \"ignore\" : [\"pipe\", \"pipe\", \"pipe\"]) as \"ignore\" | Array<IOType>,\n env: this.def.env ? { ...process.env, ...this.def.env } : process.env,\n detached: daemonize,\n };\n const child = this.def.service\n ? spawnService(this.def.service, this.def.args ?? [], spawnOpts)\n : spawn(this.def.cmd as string, this.def.args ?? [], spawnOpts);\n if (daemonize) child.unref();\n this.proc = child;\n this.pid = child.pid ?? 0;\n this.running = true;\n this.startTime = new Date();\n if (this.name === \"bds\" && this.pid > 0) {\n writeBdsPidFile(this.pid, ROOT);\n }\n this.events.emit(\"output\", `started (PID ${this.pid})`, \"info\");\n this.events.emit(\"state\", { name: this.name, running: true, pid: this.pid });\n\n child.on(\"error\", (e) => {\n this.events.emit(\"output\", `process error: ${e.message}`, \"error\");\n this.cleanup();\n });\n\n child.stdout?.on(\"data\", (d: Buffer) => {\n for (const line of d.toString().split(\"\\n\").filter(Boolean)) {\n this.pushLog(line, \"stdout\");\n }\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n for (const line of d.toString().split(\"\\n\").filter(Boolean)) {\n this.pushLog(line, \"stderr\");\n }\n });\n\n child.on(\"exit\", (code) => {\n this.events.emit(\"output\", `exited (code: ${code})`, \"info\");\n this.cleanup();\n if (!this.manualStop && this.def.autoRestart) {\n setTimeout(() => {\n void this.start();\n }, this.def.restartDelay);\n }\n });\n return { status: \"started\" };\n }\n\n async stop(): Promise<void> {\n if (!this.proc || !this.running) return;\n this.manualStop = true;\n this.events.emit(\"output\", \"stopping...\", \"info\");\n\n if (this.def.stopCommand && this.proc.stdin) {\n this.proc.stdin.write(this.def.stopCommand + \"\\n\");\n } else {\n this.proc.kill(\"SIGTERM\");\n }\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n if (this.proc) {\n this.events.emit(\"output\", \"force kill\", \"error\");\n try {\n this.proc.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n resolve();\n }, this.def.stopTimeout);\n\n this.proc?.on(\"exit\", () => {\n clearTimeout(timeout);\n resolve();\n });\n });\n }\n\n forceStop(): void {\n const child = this.proc;\n this.manualStop = true;\n this.cleanup();\n if (!child) return;\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n\n async restart(): Promise<StartOutcome> {\n await this.stop();\n return this.start();\n }\n\n getRecentLogs(n: number): LogLine[] {\n return this.logs.slice(-n);\n }\n\n /**\n * \u63A2\u6D4B\u53D1\u73B0\u8FDB\u7A0B\u5DF2\u6B7B\u540E\u56DE\u5199\u672C\u5730\u72B6\u6001\uFF08\u4E0D\u8BBE manualStop\uFF0C\u4EE5\u4FBF exit \u56DE\u8C03\u4ECD\u53EF\u6309\u9700 autoRestart\uFF09\u3002\n */\n markStoppedFromProbe(): void {\n if (!this.running && !this.proc) return;\n this.cleanup();\n }\n\n private cleanup(): void {\n const wasRunning = this.running || this.proc !== null;\n const exitingPid = this.pid;\n this.proc = null;\n this.running = false;\n this.pid = 0;\n this.startTime = null;\n if (this.name === \"bds\" && exitingPid > 0) {\n const filePid = readBdsPidFile(ROOT);\n if (filePid === exitingPid) {\n clearBdsPidFile(ROOT);\n }\n }\n if (wasRunning) {\n this.events.emit(\"state\", { name: this.name, running: false, pid: 0 });\n }\n }\n}\n\nfunction createServices(): Record<ServiceName, Service> {\n /* \u5404\u670D\u52A1/CLI \u7528 SDK ensureCoreConfigs \u64AD\u79CD\uFF08\u542B $schema\uFF09\uFF0C\u4E0D\u518D\u4ECE configs-default \u62F7\u8D1D\u3002 */\n ensureCoreConfigs(ROOT, [\"bds_updater\", \"qq_config\", \"db_config\"]);\n ensurePackUpdateConfigFile();\n const bdsCfg = loadEnsuredConfig(\n ROOT,\n \"bds_updater.json\",\n \"bds_updater\",\n { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<string, unknown>\n ) as BdsUpdaterConfig;\n const qqCfg = loadEnsuredConfig(\n ROOT,\n \"qq_config.json\",\n \"qq_config\",\n { ...DEFAULT_QQ_CONFIG } as Record<string, unknown>\n ) as QQBridgeConfig;\n const dbCfg = loadEnsuredConfig(\n ROOT,\n \"db_config.json\",\n \"db_config\",\n { ...DEFAULT_DB_CONFIG } as Record<string, unknown>\n ) as DBConfig;\n const bdsPath = bdsCfg.bds_path ?? ROOT;\n const useLlbotBackend = qqCfg.qq_backend === \"llbot\";\n const qqEnabled = qqCfg.qq_enabled !== false;\n const llbotEnabled = qqCfg.llbot_enabled !== false;\n const llbotLaunch = resolveLlbotLaunch(qqCfg.llbot_path, qqCfg.llbot_cwd);\n const llbotPath = llbotLaunch.exe;\n const llbotCwd = llbotLaunch.cwd;\n const dbPort = dbCfg.db_port ?? 3001;\n dbHealthPort = dbPort;\n qqBackendMode = useLlbotBackend ? \"llbot\" : \"official\";\n const bdsExe = bdsExePath(path.resolve(bdsPath));\n const qqTitle = useLlbotBackend ? \"QQ (llbot)\" : \"QQ (official)\";\n\n return {\n bds: new Service({\n name: \"bds\",\n title: \"BDS\",\n cmd: bdsExe,\n args: [],\n cwd: bdsPath,\n env: bdsSpawnEnvExtra(bdsPath),\n stopCommand: \"stop\",\n stopTimeout: 30000,\n autoRestart: bdsCfg.crash_restart !== false,\n restartDelay: 5000,\n validate: () => {\n if (!fs.existsSync(bdsExe)) return `not found: ${bdsExe}`;\n return null;\n },\n beforeStart: async () => {\n ensureBdsExecutable(bdsExe);\n /* \u5148\u88C5\u6536\u4EF6\u7BB1\u7B2C\u4E09\u65B9\u5305\uFF0C\u518D\u68C0\u67E5 CF \u66F4\u65B0\uFF0C\u518D\u8DD1\u6A21\u5757\u805A\u5408\u95F8\u95E8 */\n const { scanAndInstallInbox } = await import(\"./world-packs.js\");\n await scanAndInstallInbox({ interactive: false });\n const { runPackUpdatesOnBdsStart } = await import(\"./pack-update/index.js\");\n await runPackUpdatesOnBdsStart();\n const { ensurePacksReady } = await import(\"./pack-lifecycle.js\");\n await ensurePacksReady();\n },\n }),\n\n db: new Service({\n name: \"db\",\n title: \"DB Server\",\n service: \"db\",\n cwd: ROOT,\n stopTimeout: 10000,\n autoRestart: true,\n restartDelay: 3000,\n env: { DB_PORT: String(dbPort) },\n }),\n\n qq: new Service({\n name: \"qq\",\n title: qqTitle,\n service: \"qq\",\n cwd: ROOT,\n stopTimeout: 10000,\n // \u7F3A\u51ED\u636E\u65F6 validate \u62E6\u4E0B\uFF0C\u4E0D\u4F1A spawn\u2192exit(1)\u2192autoRestart \u6B7B\u5FAA\u73AF\n autoRestart: true,\n restartDelay: 3000,\n optional: !qqEnabled,\n validate: () => {\n if (!qqEnabled) return \"QQ bridge disabled (qq_enabled=false)\";\n if (!useLlbotBackend) {\n if (!String(qqCfg.qq_app_id ?? \"\").trim() || !String(qqCfg.qq_app_secret ?? \"\").trim()) {\n return \"missing qq_app_id / qq_app_secret (official backend)\";\n }\n }\n return null;\n },\n }),\n\n llbot: new Service({\n name: \"llbot\",\n title: \"LLBot\",\n cmd: llbotPath,\n args: [],\n cwd: llbotCwd,\n stopTimeout: 10000,\n autoRestart: false,\n restartDelay: 5000,\n // official \u6216\u672A\u542F\u7528\u65F6\u771F\u6B63 skip\uFF0C\u4E0D throw\n optional: !useLlbotBackend || !llbotEnabled,\n validate: () => {\n if (!useLlbotBackend) return \"LLBot skipped (qq_backend!=llbot)\";\n if (!llbotEnabled) return \"LLBot disabled (llbot_enabled=false)\";\n if (!fs.existsSync(llbotPath)) return `not found: ${llbotPath}`;\n return null;\n },\n }),\n };\n}\n\nexport let services: Record<ServiceName, Service> = createServices();\n\nexport function refreshServices(): void {\n forceStopAll();\n services = createServices();\n}\n\nexport const START_ORDER: ServiceName[] = [\"db\", \"qq\", \"llbot\", \"bds\"];\n\nexport async function startAll(): Promise<StartAllResult> {\n const result: StartAllResult = { started: [], skipped: [], failed: [] };\n for (const name of START_ORDER) {\n const svc = services[name];\n if (!svc) continue;\n try {\n const outcome = await svc.start();\n if (outcome.status === \"skipped\") {\n result.skipped.push({ name, reason: outcome.reason });\n svc.events.emit(\"output\", `skipped: ${outcome.reason}`, \"info\");\n } else {\n result.started.push(name);\n }\n } catch (e) {\n const reason = (e as Error).message;\n result.failed.push({ name, reason });\n svc.events.emit(\"output\", `start error: ${reason}`, \"error\");\n }\n }\n return result;\n}\n\nexport async function stopAll(): Promise<void> {\n const pending = [...START_ORDER]\n .reverse()\n .map((name) => services[name])\n .filter((service): service is Service => Boolean(service?.running))\n .map((service) => service.stop());\n await Promise.allSettled(pending);\n}\n\nexport function forceStopAll(): void {\n for (const service of Object.values(services)) service.forceStop();\n}\n\nexport type ServiceStateEvent = { name: ServiceName; running: boolean; pid: number };\n\n/** \u8BA2\u9605\u4EFB\u610F\u670D\u52A1\u542F\u505C\uFF08\u542B\u63A2\u6D4B\u56DE\u5199\uFF09\uFF1B\u8FD4\u56DE\u53D6\u6D88\u51FD\u6570 */\nexport function onServiceStateChange(fn: (ev: ServiceStateEvent) => void): () => void {\n const handler = (ev: ServiceStateEvent): void => {\n fn(ev);\n };\n for (const service of Object.values(services)) {\n service.events.on(\"state\", handler);\n }\n return () => {\n for (const service of Object.values(services)) {\n service.events.off(\"state\", handler);\n }\n };\n}\n\n/** \u82E5\u672C\u5730\u6807\u8BB0 running \u4F46 OS \u8FDB\u7A0B\u5DF2\u6B7B\uFF0C\u56DE\u6536\u5185\u5B58\u6807\u5FD7 */\nasync function reconcileManagedAlive(service: Service): Promise<boolean> {\n if (!service.running) return false;\n if (service.pid > 0 && !(await isProcessAlive(service.pid))) {\n service.markStoppedFromProbe();\n return false;\n }\n return service.running;\n}\n\n/**\n * \u7EDF\u4E00\u8FD0\u884C\u6001\u67E5\u8BE2\uFF08\u6743\u5A01\u5165\u53E3\uFF09\uFF1AOS/\u5065\u5EB7\u63A2\u6D4B + \u56DE\u5199 Service \u5185\u5B58\u6807\u5FD7\u3002\n * status / Tab \u53D1\u9001\u76EE\u6807 / reload \u7B49\u5747\u5E94\u8D70\u6B64\u63A5\u53E3\uFF0C\u52FF\u76F4\u63A5\u8BFB `service.running`\u3002\n */\nexport async function queryServicesRuntime(): Promise<ServiceStatus[]> {\n return Promise.all(\n SERVICE_NAMES.map(async (name) => {\n const service = services[name];\n let running = false;\n let pid = 0;\n let uptime = \"\u2014\";\n let ownership: \"managed\" | \"external\" | undefined;\n\n if (name === \"bds\") {\n const probe = await probeBdsStatus({\n managedPid: service.pid,\n hasStdin: Boolean(service.proc?.stdin),\n rootDir: ROOT,\n });\n if (probe.state === \"managed\") {\n running = true;\n pid = probe.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n /* \u63A2\u6D4B\u4E3A managed \u4F46\u672C\u5730\u5DF2\u6807\u505C\uFF1A\u4FDD\u6301\u63A2\u6D4B\u7ED3\u679C\uFF0C\u4E0D\u5F3A\u5236\u6539\u5185\u5B58\uFF08stdin \u4ECD\u53EF\u7528\uFF09 */\n } else if (probe.state === \"external\") {\n running = true;\n pid = probe.pid;\n ownership = \"external\";\n /* \u5916\u90E8\u8FDB\u7A0B\uFF1A\u672C\u5730 managed \u53E5\u67C4\u5DF2\u5931\u6548\u5219\u56DE\u6536 */\n if (service.running && service.pid !== probe.pid) {\n service.markStoppedFromProbe();\n } else if (service.running && !(await isProcessAlive(service.pid))) {\n service.markStoppedFromProbe();\n }\n } else {\n running = false;\n if (service.running || service.proc) {\n service.markStoppedFromProbe();\n }\n }\n } else if (name === \"db\") {\n const managed = await reconcileManagedAlive(service);\n if (managed) {\n running = true;\n pid = service.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n } else if (await probeDbHealth(dbHealthPort)) {\n running = true;\n ownership = \"external\";\n const pids = await findNodeServicePids(\"db\");\n pid = pids[0] ?? 0;\n }\n } else if (name === \"qq\") {\n const managed = await reconcileManagedAlive(service);\n if (managed) {\n running = true;\n pid = service.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n } else {\n const probe = await probeQqRuntime();\n if (probe.alive) {\n running = true;\n pid = probe.pid;\n ownership = \"external\";\n } else {\n const pids = await findNodeServicePids(\"qq\");\n if (pids.length > 0) {\n running = true;\n pid = pids[0]!;\n ownership = \"external\";\n }\n }\n }\n } else {\n const managed = await reconcileManagedAlive(service);\n if (managed) {\n running = true;\n pid = service.pid;\n uptime = service.uptime;\n ownership = \"managed\";\n }\n }\n\n return {\n name,\n title: service.title,\n running,\n pid,\n uptime,\n ...(ownership ? { ownership } : {}),\n };\n })\n );\n}\n\n/** \u5355\u670D\u52A1\u662F\u5426\u5728\u8DD1\uFF08\u542B\u5916\u90E8\u5B9E\u4F8B\uFF09 */\nexport async function isServiceRunning(name: ServiceName): Promise<boolean> {\n const rows = await queryServicesRuntime();\n return rows.some((r) => r.name === name && r.running);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["ROOT"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AA8GA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAqR/C"}
1
+ {"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAgHA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAoV/C"}
package/dist/wizard.js CHANGED
@@ -1,4 +1,4 @@
1
- import { confirm, intro, isCancel, multiselect, note, outro, select, tasks, text } from "@clack/prompts";
1
+ import { confirm, intro, isCancel, multiselect, note, outro, password, select, tasks, text } from "@clack/prompts";
2
2
  import {
3
3
  configPath,
4
4
  ensureCoreConfigs,
@@ -8,11 +8,13 @@ import {
8
8
  withConfigSchema,
9
9
  writeJson
10
10
  } from "@sfmc-bds/sdk/node/config";
11
+ import { bdsExePath } from "@sfmc-bds/bds-tools/host-platform";
11
12
  import { execFileSync } from "node:child_process";
12
13
  import fs from "node:fs";
13
14
  import path from "node:path";
14
15
  import { ensureDirectory, pickDirectory } from "./interactive-prompts.js";
15
16
  import { persistLocale, t } from "./i18n/index.js";
17
+ import { llbotExeName } from "./llbot-launch.js";
16
18
  import { ROOT, isMonorepoLayout, isRuntimeInitialized, resolveFetchModule, spawnService } from "./runtime.js";
17
19
  import { ensurePackUpdateConfigFile } from "./pack-update/index.js";
18
20
  import { c } from "./theme.js";
@@ -121,9 +123,29 @@ async function runWizard() {
121
123
  outro(c.red(t("wizard.cannotCreateBds", { dir: bdsResolved })));
122
124
  return;
123
125
  }
126
+ const qqBackendPick = await select({
127
+ message: t("wizard.qqBackend"),
128
+ options: [
129
+ { value: "official", label: t("wizard.qqBackend.official"), hint: t("wizard.qqBackend.officialHint") },
130
+ { value: "llbot", label: t("wizard.qqBackend.llbot"), hint: t("wizard.qqBackend.llbotHint") },
131
+ { value: "disabled", label: t("wizard.qqBackend.disabled"), hint: t("wizard.qqBackend.disabledHint") }
132
+ ],
133
+ initialValue: "official"
134
+ });
135
+ const qqBackendChoice = isCancel(qqBackendPick) || !qqBackendPick ? "official" : String(qqBackendPick);
136
+ let qqEnabled = true;
137
+ let qqBackend = "official";
138
+ let qqAppId = "";
139
+ let qqAppSecret = "";
140
+ let qqSandbox = false;
141
+ let qqGroupOpenid = "";
124
142
  let llbotPath;
125
- const llbotEnabled = await confirm({ message: t("wizard.enableLlbot"), initialValue: false });
126
- if (!isCancel(llbotEnabled) && llbotEnabled) {
143
+ let llbotEnabled = false;
144
+ if (qqBackendChoice === "disabled") {
145
+ qqEnabled = false;
146
+ } else if (qqBackendChoice === "llbot") {
147
+ qqBackend = "llbot";
148
+ llbotEnabled = true;
127
149
  const picked = await pickDirectory(t("wizard.llbotDir"), path.join(rootDir, "LLBOT"));
128
150
  if (ensureDirectory(picked)) {
129
151
  llbotPath = picked;
@@ -131,6 +153,33 @@ async function runWizard() {
131
153
  llbotPath = path.join(rootDir, "LLBOT");
132
154
  note(c.text(t("wizard.usingDefault", { path: llbotPath })), t("common.tips"));
133
155
  }
156
+ } else {
157
+ qqBackend = "official";
158
+ const appIdRaw = await text({
159
+ message: t("wizard.qqAppId"),
160
+ placeholder: "102xxxxx",
161
+ validate: (v) => {
162
+ if (!String(v ?? "").trim()) return t("wizard.valueRequired");
163
+ }
164
+ });
165
+ if (!isCancel(appIdRaw)) qqAppId = String(appIdRaw).trim();
166
+ const secretRaw = await password({
167
+ message: t("wizard.qqAppSecret"),
168
+ validate: (v) => {
169
+ if (!String(v ?? "").trim()) return t("wizard.valueRequired");
170
+ }
171
+ });
172
+ if (!isCancel(secretRaw)) qqAppSecret = String(secretRaw).trim();
173
+ const sandboxPick = await confirm({
174
+ message: t("wizard.qqSandbox"),
175
+ initialValue: false
176
+ });
177
+ if (!isCancel(sandboxPick)) qqSandbox = !!sandboxPick;
178
+ const openidRaw = await text({
179
+ message: t("wizard.qqGroupOpenid"),
180
+ placeholder: t("wizard.qqGroupOpenidHint")
181
+ });
182
+ if (!isCancel(openidRaw)) qqGroupOpenid = String(openidRaw).trim();
134
183
  }
135
184
  const dbDirInput = await pickDirectory(t("wizard.dbDir"), path.join(rootDir, "data"));
136
185
  const dbDir = ensureDirectory(dbDirInput) ? dbDirInput : path.join(rootDir, "data");
@@ -147,7 +196,7 @@ async function runWizard() {
147
196
  }
148
197
  });
149
198
  const dbPort = isCancel(dbPortRaw) ? 3001 : parseInt(dbPortRaw, 10);
150
- const bdsExe = path.join(bdsResolved, "bedrock_server.exe");
199
+ const bdsExe = bdsExePath(bdsResolved);
151
200
  const bdsExists = fs.existsSync(bdsExe);
152
201
  note(
153
202
  bdsExists ? c.green(t("wizard.bdsFound", { path: bdsResolved })) : c.yellow(t("wizard.bdsNotFound", { path: bdsResolved })),
@@ -258,10 +307,19 @@ async function runWizard() {
258
307
  dbDir: slashPath(path.relative(rootDir, path.join(dbDir, "sfmc_data.db"))),
259
308
  modulesDir: "modules"
260
309
  });
261
- const llbotOn = !!llbotEnabled && !!llbotPath;
310
+ const llbotOn = qqBackend === "llbot" && !!llbotEnabled && !!llbotPath;
311
+ const qqNotify = qqEnabled && (qqBackend === "official" || llbotOn);
312
+ const exeName = llbotExeName();
262
313
  patchJson(rootDir, "qq_config.json", {
314
+ qq_enabled: qqEnabled,
315
+ qq_backend: qqBackend,
316
+ qq_app_id: qqAppId,
317
+ qq_app_secret: qqAppSecret,
318
+ qq_sandbox: qqSandbox,
319
+ qq_group_openid: qqGroupOpenid,
263
320
  llbot_enabled: llbotOn,
264
- llbot_path: llbotPath ? slashPath(llbotPath) : "",
321
+ // path = 可执行文件;cwd = 运行目录(向导选的是目录)
322
+ llbot_path: llbotPath ? slashPath(path.join(llbotPath, exeName)) : "",
265
323
  llbot_cwd: llbotPath ? slashPath(llbotPath) : ""
266
324
  });
267
325
  patchJson(rootDir, "bds_updater.json", {
@@ -269,7 +327,7 @@ async function runWizard() {
269
327
  channel: bdsChannel,
270
328
  backup_dir: slashPath(backupDir),
271
329
  preserve,
272
- qq_notify: llbotOn
330
+ qq_notify: qqNotify
273
331
  });
274
332
  patchJson(rootDir, "runtime.json", {
275
333
  runtime_root: rootDir,