@sfmc-bds/cli 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/services.ts"],
4
- "sourcesContent": ["/**\n * services.ts \u2014 CLI \u8FDB\u7A0B\u7F16\u6392\u4E0E\u670D\u52A1\u751F\u547D\u5468\u671F\u7BA1\u7406\n *\n * \u6838\u5FC3\u7BA1\u7406\u5BF9\u8C61\uFF08ServiceName\uFF09\uFF1A\n * - `bds`\uFF1AMinecraft \u57FA\u5CA9\u7248\u670D\u52A1\u7AEF\uFF08\u652F\u6301 stdin \u7BA1\u9053\u6307\u4EE4\u4EA4\u4E92\u4E0E\u4F18\u96C5\u505C\u670D\uFF09\n * - `db`\uFF1Adb-server SQLite HTTP \u670D\u52A1\uFF08\u7AEF\u53E3\u5065\u5EB7\u68C0\u67E5\u4E0E loopback \u63A2\u6D3B\uFF09\n * - `tunnel`\uFF1A\u4E91\u7AEF QQ Webhook \u5230\u672C\u673A db-server \u7684 SSH \u53CD\u5411\u96A7\u9053\n * - `qq`\uFF1Aqq-bridge \u6D88\u606F\u7F51\u6865\u670D\u52A1\uFF08\u652F\u6301\u5B98\u65B9 Bot \u4E0E LLBot \u53CC\u540E\u7AEF\uFF09\n * - `llbot`\uFF1ALLBot \u72EC\u7ACB\u673A\u5668\u4EBA\u8FDB\u7A0B\uFF08\u6761\u4EF6\u542F\u52A8\uFF09\n *\n * \u6838\u5FC3\u80FD\u529B\uFF1A\n * - \u8FDB\u7A0B\u751F\u547D\u5468\u671F\uFF1A\u6309\u4F9D\u8D56\u6B21\u5E8F\u7F16\u6392\u670D\u52A1\u542F\u52A8\uFF08db \u2192 qq \u2192 bds\uFF09\u3001\u4F18\u96C5\u505C\u6B62\u4E0E\u5F02\u5E38\u81EA\u52A8\u62C9\u8D77\n * - \u591A\u6E90\u63A2\u6D3B\u611F\u77E5\uFF1A\u81EA\u52A8\u63A2\u6D4B\u6258\u7BA1\u8FDB\u7A0B\u4E0E\u5916\u90E8\u72EC\u7ACB\u8FDB\u7A0B\u72B6\u6001\n * - \u65E5\u5FD7\u6D41\u7EDF\u4E00\u805A\u5408\uFF1A\u6355\u83B7\u5E76\u5F52\u4E00\u5316\u5404\u670D\u52A1\u7684 stdout / stderr \u6570\u636E\u6D41\n */\n\nimport type { BdsUpdaterConfig, DBConfig, QQBackend, QQBridgeConfig } from \"@sfmc-bds/sdk/node/config\";\nimport {\n DEFAULT_BDS_UPDATER_CONFIG,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n ensureCoreConfigs,\n loadEnsuredConfig,\n qqRuntimeStatusPath,\n readJson,\n type QqRuntimeStatus,\n} from \"@sfmc-bds/sdk/node/config\";\n\nimport { bdsExePath, bdsSpawnEnvExtra, ensureBdsExecutable } from \"@sfmc-bds/bds-tools/host-platform\";\nimport {\n clearBdsPidFile,\n findBedrockServerPids,\n isProcessAlive,\n killBedrockServerByImage,\n probeBdsStatus,\n readBdsPidFile,\n writeBdsPidFile,\n} from \"@sfmc-bds/bds-tools/process-probe\";\nimport { postBdsLifecycleEvent } from \"@sfmc-bds/bds-tools/qq-events-notify\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { isDaemonServer } from \"./daemon/role.js\";\nimport { onRemoteServiceStateChange } from \"./daemon/client.js\";\nimport { t } from \"./i18n/index.js\";\nimport { resolveLlbotLaunch } from \"./llbot-launch.js\";\nimport { inferLevel, pushLog as pushUnifiedLog } from \"./logs.js\";\nimport { findNodeServicePids, killNodeServiceByScript } from \"./node-service-probe.js\";\nimport { ensurePackUpdateConfigFile } from \"./pack-update/index.js\";\nimport { recordBdsVersion } from \"./bds-runtime-version.js\";\nimport { reportBdsPlayerSession } from \"./player-session.js\";\nimport { startModuleSidecars, stopModuleSidecars } from \"./module-sidecars.js\";\nimport { ROOT, spawnService, type ServiceId } from \"./runtime.js\";\n\nexport { ROOT } from \"./runtime.js\";\n\nexport interface LogLine {\n time: Date;\n text: string;\n stream: \"stdout\" | \"stderr\";\n}\n\n/** \u5B50\u8FDB\u7A0B\u8F93\u51FA\u5206\u884C\uFF1A\u8FC7\u6EE4\u7A7A\u4E32\u4EE5\u53CA Windows CRLF \u62C6\u5206\u540E\u6B8B\u7559\u7684\u7EAF\u7A7A\u767D\u884C\u3002 */\nexport function nonBlankOutputLines(text: string): string[] {\n return text.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n}\n\nexport type ServiceName = \"bds\" | \"db\" | \"tunnel\" | \"qq\" | \"llbot\";\nexport const SERVICE_NAMES: ServiceName[] = [\"bds\", \"db\", \"tunnel\", \"qq\", \"llbot\"];\n\n/** \u5355\u670D\u52A1 start \u7ED3\u679C\uFF1Aoptional \u670D\u52A1 validate \u5931\u8D25\u8BB0\u4E3A skipped\uFF0C\u4E0D\u629B\u9519 */\nexport type StartOutcome = { status: \"started\" } | { status: \"already\" } | { status: \"skipped\"; reason: string };\n\n/**\n * \u5355\u670D\u52A1 stop \u7ED3\u679C\uFF0C\u4F9B CLI \u533A\u5206\u6587\u6848\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A`stop <name>` / `restart <name>` \u4E0E `stop all` \u90FD\u8D70 Service.stop\uFF0C\u4F46\u53EA\u6709\u524D\u8005\u4F1A\u5F97\u5230 external\u3002\n * - managed\uFF1A\u505C\u7684\u662F\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u5B50\u8FDB\u7A0B\n * - external\uFF1A\u6CA1\u6709\u6258\u7BA1\u53E5\u67C4\uFF0C\u4F46\u6E05\u6389\u4E86\u5916\u90E8\u5B9E\u4F8B\uFF08\u4EC5 external=true \u65F6\uFF09\n * - idle\uFF1A\u672C\u6765\u5C31\u6CA1\u5728\u8DD1\uFF0C\u6216\u6279\u91CF\u505C\u6B62\u65F6\u6545\u610F\u4E0D\u52A8\u5916\u90E8\u5B9E\u4F8B\n */\nexport type StopKind = \"managed\" | \"external\" | \"idle\";\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\nconst tunnelRuntimePath = path.join(ROOT, \".sfmc\", \"tunnel.runtime.json\");\n\nasync function probeTunnelRuntime(): Promise<number> {\n const pid = readJson<{ pid?: number }>(tunnelRuntimePath)?.pid;\n return typeof pid === \"number\" && pid > 0 && (await isProcessAlive(pid)) ? pid : 0;\n}\n\nfunction writeTunnelRuntime(pid: number): void {\n fs.mkdirSync(path.dirname(tunnelRuntimePath), { recursive: true });\n fs.writeFileSync(tunnelRuntimePath, JSON.stringify({ pid, startedAt: Date.now() }) + \"\\n\");\n}\n\nfunction clearTunnelRuntime(pid: number): void {\n if (readJson<{ pid?: number }>(tunnelRuntimePath)?.pid !== pid) return;\n try {\n fs.unlinkSync(tunnelRuntimePath);\n } catch {\n /* \u8FDB\u7A0B\u9000\u51FA\u65F6\u5141\u8BB8\u6587\u4EF6\u5DF2\u88AB\u79FB\u9664 */\n }\n}\n\n/** \u6E05\u6389 qq-bridge \u8FD0\u884C\u65F6\u6587\u4EF6\uFF0C\u907F\u514D status \u4ECD\u628A\u5DF2\u9000\u51FA\u7684\u5916\u90E8\u8FDB\u7A0B\u5F53\u6210\u5B58\u6D3B\u3002 */\nfunction clearQqRuntimeFile(): void {\n try {\n const file = qqRuntimeStatusPath(ROOT);\n if (fs.existsSync(file)) fs.unlinkSync(file);\n } catch {\n /* \u8FD0\u884C\u65F6\u6587\u4EF6\u53EF\u80FD\u5DF2\u88AB\u8FDB\u7A0B\u81EA\u5DF1\u5220\u6389 */\n }\n}\n\n/**\n * \u6309\u955C\u50CF\u540D\u7ED3\u675F\u5916\u90E8 BDS\uFF0C\u5E76\u7B49\u5230\u8FDB\u7A0B\u4ECE\u8FDB\u7A0B\u8868\u6D88\u5931\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u4EC5\u5355\u670D\u52A1 stop / restart\uFF08Service.stop \u7684 external=true\uFF09\u6E05\u6389\u975E\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684 bedrock\u3002\n * stop all \u4E0E\u5B88\u62A4\u8FDB\u7A0B shutdown \u4E0D\u8C03\u7528\u8FD9\u91CC\uFF0C\u907F\u514D taskkill \u8BEF\u6740\u540C\u673A\u5176\u4ED6 Bedrock\u3002\n * taskkill \u8FD4\u56DE\u540E\u8FDB\u7A0B\u8868\u53EF\u80FD\u4ECD\u77ED\u6682\u53EF\u89C1\uFF0Crestart \u4F1A\u7ACB\u523B\u63A2\u6D3B\uFF0C\u56E0\u6B64\u8FD9\u91CC\u7B49\u5230\u6D88\u5931\u518D\u8FD4\u56DE\u3002\n */\nasync function killExternalBedrock(): Promise<void> {\n await killBedrockServerByImage();\n clearBdsPidFile(ROOT);\n const deadline = Date.now() + 8000;\n while (Date.now() < deadline) {\n if ((await findBedrockServerPids()).length === 0) return;\n await new Promise((r) => setTimeout(r, 200));\n }\n await killBedrockServerByImage();\n clearBdsPidFile(ROOT);\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 /** \u539F\u59CB\u65E5\u5FD7\u884C\u89C2\u5BDF\u5668\uFF0C\u4E0D\u5F97\u963B\u585E\u5B50\u8FDB\u7A0B\u8F93\u51FA\u3002 */\n onLogLine?: (line: string) => 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 private updateInProgress = false;\n private restartTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(def: ServiceDef) {\n this.name = def.name;\n this.title = def.title;\n this.def = def;\n if (def.name === \"tunnel\") {\n this.events.on(\"output\", (text: string, level: \"info\" | \"error\") => {\n pushUnifiedLog(text, \"tunnel\", level);\n });\n }\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 this.def.onLogLine?.(text);\n }\n\n async start(): Promise<StartOutcome> {\n if (this.updateInProgress) throw new Error(\"BDS \u6B63\u5728\u66F4\u65B0\uFF0C\u6682\u4E0D\u53EF\u542F\u52A8\");\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\", {\n pid: String(probe.pid),\n kind: t(probe.state === \"managed\" ? \"svc.running\" : \"svc.runningExternal\"),\n })\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.name === \"tunnel\" && (await probeTunnelRuntime())) return { status: \"already\" };\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 if (this.name === \"bds\") {\n await startModuleSidecars(ROOT, (line, stream) => this.pushLog(line, stream));\n }\n // beforeStart \u542B\u5F02\u6B65\u68C0\u67E5\uFF1B\u66F4\u65B0\u53EF\u80FD\u5728\u7B49\u5F85\u671F\u95F4\u5F00\u59CB\u3002\n if (this.updateInProgress) throw new Error(\"BDS \u6B63\u5728\u66F4\u65B0\uFF0C\u6682\u4E0D\u53EF\u542F\u52A8\");\n this.manualStop = false;\n /* \u5B50\u8FDB\u7A0B\u59CB\u7EC8\u7531\u5B88\u62A4\u8FDB\u7A0B\u7528\u7BA1\u9053\u6301\u6709\uFF08stdin \u53D1 stop\u3001stdout \u65E5\u5FD7\u3001autoRestart\uFF09\uFF1B\n * \u4E0D\u518D\u5BF9\u5B50\u670D\u52A1\u505A detached/unref\u2014\u2014\u8131\u79BB\u7EC8\u7AEF\u7531 daemon \u8FDB\u7A0B\u81EA\u8EAB\u8D1F\u8D23\u3002\n * windowsHide\uFF1AWindows \u4E0A\u907F\u514D\u4E3A\u6BCF\u4E2A\u670D\u52A1\u5F39\u51FA\u7A7A\u767D\u63A7\u5236\u53F0\uFF08stdout \u5DF2 pipe\uFF0C\u7A97\u5185\u65E0\u8F93\u51FA\uFF09\u3002 */\n const spawnOpts = {\n cwd: this.def.cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"] as Array<\"pipe\">,\n env: this.def.env ? { ...process.env, ...this.def.env } : process.env,\n windowsHide: true,\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 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 if (this.name === \"tunnel\" && this.pid > 0) writeTunnelRuntime(this.pid);\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 let lifecycleReported = false;\n const reportExit = (code?: number | null) => {\n if (this.name !== \"bds\" || lifecycleReported) return;\n lifecycleReported = true;\n const planned = this.manualStop || this.updateInProgress;\n void postBdsLifecycleEvent(planned ? \"stop\" : \"crash\", planned ? undefined : `code=${code ?? \"?\"}`, {\n port: dbHealthPort,\n });\n };\n if (this.name === \"bds\") {\n child.once(\"spawn\", () => {\n void postBdsLifecycleEvent(\"start\", undefined, { port: dbHealthPort });\n });\n }\n\n child.on(\"error\", (e) => {\n this.events.emit(\"output\", `process error: ${e.message}`, \"error\");\n reportExit();\n this.cleanup();\n this.scheduleRestart();\n });\n\n let versionLineBuffer = \"\";\n child.stdout?.on(\"data\", (d: Buffer) => {\n if (this.name === \"bds\" && this.startTime) {\n versionLineBuffer += d.toString();\n const versionLines = versionLineBuffer.split(/\\r?\\n/);\n versionLineBuffer = (versionLines.pop() ?? \"\").slice(-4096);\n for (const versionLine of versionLines) recordBdsVersion(ROOT, versionLine, this.pid, this.startTime.getTime());\n }\n for (const line of nonBlankOutputLines(d.toString())) {\n this.pushLog(line, \"stdout\");\n }\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n for (const line of nonBlankOutputLines(d.toString())) {\n this.pushLog(line, \"stderr\");\n }\n });\n\n child.on(\"exit\", (code) => {\n if (this.proc && this.proc !== child) return;\n this.events.emit(\"output\", `exited (code: ${code})`, \"info\");\n reportExit(code);\n this.cleanup();\n this.scheduleRestart();\n });\n return { status: \"started\" };\n }\n\n private scheduleRestart(): void {\n if (this.manualStop || this.updateInProgress || !this.def.autoRestart || this.restartTimer) return;\n this.restartTimer = setTimeout(() => {\n this.restartTimer = null;\n if (!this.updateInProgress && !this.manualStop && !this.running) {\n void this.start().catch((e: Error) => {\n this.events.emit(\"output\", `restart failed: ${e.message}`, \"error\");\n });\n }\n }, this.def.restartDelay);\n }\n\n /** \u66F4\u65B0\u5668\u72EC\u7ACB\u8FDB\u7A0B\u505C\u670D\u65F6\uFF0C\u7981\u6B62\u5C06\u8BA1\u5212\u5185\u9000\u51FA\u5F53\u4F5C\u5D29\u6E83\u5E76\u81EA\u52A8\u62C9\u8D77\u3002 */\n beginUpdate(): void {\n if (this.name !== \"bds\") return;\n if (this.updateInProgress) throw new Error(\"BDS \u66F4\u65B0\u5DF2\u5728\u8FDB\u884C\u4E2D\");\n this.updateInProgress = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n }\n\n endUpdate(): void {\n this.updateInProgress = false;\n }\n\n /**\n * \u505C\u6B62\u672C\u670D\u52A1\u3002\u6258\u7BA1\u5B50\u8FDB\u7A0B\u59CB\u7EC8\u8D70\u539F\u6765\u7684\u4F18\u96C5\u505C\u6B62\uFF08stdin stop / SIGTERM\uFF09\u3002\n * @param external \u662F\u5426\u989D\u5916\u6E05\u6389\u975E\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u5916\u90E8\u5B9E\u4F8B\u3002\u9ED8\u8BA4 false\uFF0C\u53EA\u505C\u6258\u7BA1\u5B50\u8FDB\u7A0B\u3002\n * \u4E24\u79CD\u8C03\u7528\u573A\u666F\uFF1A\n * - true\uFF1A\u5355\u670D\u52A1 `stop <name>` / `restart <name>`\uFF08cmdStopLocal\uFF0C\u4EE5\u53CA\u4ECD\u5B58\u5728\u7684 Service.restart\uFF09\u3002\n * BDS \u5916\u90E8\u8D70 killExternalBedrock\uFF1Bdb/qq \u5916\u90E8\u8D70 killNodeServiceByScript\u3002\n * - false \u6216\u4E0D\u4F20\uFF1A`stop all`\u3001`restart -all`\u3001\u5B88\u62A4\u8FDB\u7A0B shutdown / SIGTERM\uFF08\u7ECF stopAll\uFF09\u3002\n * \u4E0D\u6309\u955C\u50CF\u540D\u6216\u811A\u672C\u540D\u6740\u5916\u90E8\u8FDB\u7A0B\uFF0C\u907F\u514D\u8BEF\u6740\u540C\u673A\u5176\u4ED6 Bedrock\u3001db\u3001qq\u3002\n */\n async stop(external = false, forceOnTimeout = true): Promise<StopKind> {\n this.manualStop = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n\n /* \u4E0E\u539F\u5148 cmdStop \u4E00\u81F4\uFF1A\u4EC5\u5355\u670D\u52A1\u505C\u6B62\u65F6\uFF0CBDS \u88AB\u5224\u5B9A\u4E3A\u5916\u90E8\u624D\u6309\u955C\u50CF\u7ED3\u675F\uFF0C\u4E0D\u8D70 stdin stop */\n if (external && this.name === \"bds\") {\n const probe = await probeBdsStatus({\n managedPid: this.pid,\n hasStdin: Boolean(this.proc?.stdin),\n rootDir: ROOT,\n });\n if (probe.state === \"external\") {\n await killExternalBedrock();\n this.dropStaleHandle();\n return \"external\";\n }\n }\n\n const managed = Boolean(this.proc && this.running);\n if (managed) await this.stopManagedChild(forceOnTimeout);\n\n /* db / qq\uFF1A\u4EC5\u5355\u670D\u52A1\u505C\u6B62\u65F6\uFF0C\u6258\u7BA1\u505C\u5B8C\u540E\u4ECD\u6309\u811A\u672C\u518D\u626B\u4E00\u904D\uFF0C\u6E05\u6389\u540C\u673A\u4E0A\u7684\u5916\u90E8\u5B9E\u4F8B */\n if (external && (this.name === \"db\" || this.name === \"qq\")) {\n const killed = await killNodeServiceByScript(this.name);\n if (this.name === \"qq\") clearQqRuntimeFile();\n if (managed) return \"managed\";\n return killed.length > 0 ? \"external\" : \"idle\";\n }\n\n if (managed) return \"managed\";\n return \"idle\";\n }\n\n /**\n * \u4F18\u96C5\u505C\u6B62\u5F53\u524D\u6258\u7BA1\u5B50\u8FDB\u7A0B\uFF08stdin stop \u6216 SIGTERM\uFF0C\u8D85\u65F6\u540E SIGKILL\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AService.stop \u786E\u8BA4\u672C\u8FDB\u7A0B\u4ECD\u6301\u6709\u5B50\u8FDB\u7A0B\u65F6\u8C03\u7528\uFF1B\u903B\u8F91\u4E0E\u539F\u5148 stop \u4E3B\u4F53\u76F8\u540C\u3002\n */\n private async stopManagedChild(forceOnTimeout = true): Promise<void> {\n if (!this.proc || !this.running) return;\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, reject) => {\n const timeout = setTimeout(() => {\n if (!forceOnTimeout && this.proc) {\n reject(new Error(`${this.name} \u672A\u5728\u8D85\u65F6\u5185\u4F18\u96C5\u9000\u51FA\uFF1B\u5DF2\u4E2D\u6B62\u7EF4\u62A4\uFF0C\u4E0D\u5F3A\u5236\u7ED3\u675F\u8FDB\u7A0B`));\n return;\n }\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 /**\n * \u5916\u90E8\u505C\u670D\u540E\u4E22\u6389\u5931\u6548\u7684\u6258\u7BA1\u53E5\u67C4\uFF0C\u907F\u514D\u7D27\u63A5\u7740\u7684 start/restart \u8BEF\u5224\u300C\u5DF2\u5728\u8FD0\u884C\u300D\u3002\n * \u4E0D\u8D70 cleanup\uFF1A\u90A3\u4F1A\u8FDE\u5E26\u505C\u6389\u6A21\u5757\u9644\u5C5E\u8FDB\u7A0B\uFF0C\u800C\u539F\u5148\u7684\u5916\u90E8 BDS stop \u5E76\u4E0D\u8FD9\u4E48\u505A\u3002\n */\n private dropStaleHandle(): void {\n if (!this.running && !this.proc) return;\n const stale = this.proc;\n this.proc = null;\n this.running = false;\n this.pid = 0;\n this.startTime = null;\n this.events.emit(\"state\", { name: this.name, running: false, pid: 0 });\n if (stale && stale.exitCode === null) {\n try {\n stale.kill(\"SIGKILL\");\n } catch {\n /* \u5916\u90E8\u955C\u50CF\u7ED3\u675F\u65F6\u8FD9\u4E2A\u53E5\u67C4\u53EF\u80FD\u5DF2\u7ECF\u9000\u51FA */\n }\n }\n }\n\n forceStop(): void {\n const child = this.proc;\n this.manualStop = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n this.cleanup();\n if (!child) return;\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n\n /**\n * \u5355\u670D\u52A1\u91CD\u542F\uFF1A\u5148\u505C\u518D\u8D77\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u82E5\u4ECD\u6709\u8C03\u7528\u65B9\u76F4\u63A5\u8D70 Service.restart\uFF08\u4E0D\u7ECF cmdStopLocal\uFF09\uFF0C\u4E0E\u5355\u670D\u52A1 stop \u4E00\u6837\u6E05\u5916\u90E8\u5B9E\u4F8B\uFF08external true\uFF09\u3002\n * \u6279\u91CF `restart -all` \u548C\u5B88\u62A4\u8FDB\u7A0B shutdown \u4E0D\u8D70\u8FD9\u91CC\uFF0C\u5B83\u4EEC\u7ECF stopAll \u8C03\u7528 stop(false)\uFF0C\u53EA\u505C\u6258\u7BA1\u5B50\u8FDB\u7A0B\u3002\n */\n async restart(): Promise<StartOutcome> {\n await this.stop(true);\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 stopModuleSidecars();\n }\n if (this.name === \"tunnel\" && exitingPid > 0) clearTunnelRuntime(exitingPid);\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\", \"qq_link\"]);\n ensurePackUpdateConfigFile();\n void import(\"./module-update/index.js\")\n .then((mod) => mod.ensureModuleUpdateConfigFile())\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n pushUnifiedLog(message, \"module\", \"warn\");\n });\n const bdsCfg = loadEnsuredConfig(ROOT, \"bds_updater.json\", \"bds_updater\", { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<\n string,\n unknown\n >) as BdsUpdaterConfig;\n const qqCfg = loadEnsuredConfig(ROOT, \"qq_config.json\", \"qq_config\", { ...DEFAULT_QQ_CONFIG } as Record<\n string,\n unknown\n >) as QQBridgeConfig;\n const dbCfg = loadEnsuredConfig(ROOT, \"db_config.json\", \"db_config\", { ...DEFAULT_DB_CONFIG } as Record<\n string,\n unknown\n >) as DBConfig;\n const rawBdsPath = String(bdsCfg.bds_path ?? \"\").trim();\n if (process.platform !== \"win32\" && /^[A-Za-z]:[\\\\/]/.test(rawBdsPath)) {\n throw new Error(\n `configs/bds_updater.json \u7684 bds_path \u662F Windows \u8DEF\u5F84\uFF08${rawBdsPath}\uFF09\u3002` +\n `\u8BF7\u6539\u6210\u76F8\u5BF9 SFMC_ROOT \u7684\u8DEF\u5F84\uFF0C\u4F8B\u5982 \"BDS\"\u3002`\n );\n }\n const bdsPath = path.resolve(ROOT, rawBdsPath || \".\");\n const useLlbotBackend = qqCfg.qq_backend === \"llbot\";\n const qqEnabled = qqCfg.qq_enabled !== false;\n // \u5B98\u65B9 Webhook \u7531\u4E91\u7AEF\u63A5\u6536\uFF1B\u4EC5\u5207\u6362\u4F20\u8F93\u65B9\u5F0F\u5373\u53EF\u907F\u514D\u672C\u673A\u518D\u542F\u52A8\u4E00\u4E2A\u6865\u3002\n const qqExternal = !useLlbotBackend && qqCfg.official?.transport === \"webhook\";\n const tunnelCfg = qqCfg.official?.tunnel;\n const tunnelEnabled = qqEnabled && qqExternal && tunnelCfg?.enabled === true;\n const tunnelHost = String(tunnelCfg?.host ?? \"\").trim();\n const tunnelRemotePort = tunnelCfg?.remotePort ?? 13001;\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(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 /* \u5D29\u6E83\u62C9\u8D77\u7531 sfmc daemon \u56FA\u5B9A\u5F00\u542F\uFF1B\u4E0D\u518D\u8BFB bds_updater.crash_restart */\n autoRestart: true,\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 /* \u4E1A\u52A1\u6A21\u5757\u66F4\u65B0\u53EA\u8D70\u663E\u5F0F\u547D\u4EE4\uFF0C\u4E0D\u8FDB\u5F00\u670D\u94A9\u5B50\u3002 */\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 onLogLine: (line) =>\n reportBdsPlayerSession(line, {\n port: dbPort,\n ...(dbCfg.http_auth ? { authToken: dbCfg.http_auth } : {}),\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 tunnel: new Service({\n name: \"tunnel\",\n title: \"QQ SSH Tunnel\",\n cmd: \"ssh\",\n args: [\n \"-N\", \"-T\", \"-o\", \"BatchMode=yes\", \"-o\", \"ConnectTimeout=10\",\n \"-o\", \"ExitOnForwardFailure=yes\", \"-o\", \"ServerAliveInterval=30\",\n \"-o\", \"ServerAliveCountMax=3\",\n \"-R\", `127.0.0.1:${tunnelRemotePort}:127.0.0.1:${dbPort}`,\n tunnelHost,\n ],\n cwd: ROOT,\n stopTimeout: 10000,\n autoRestart: true,\n restartDelay: 5000,\n optional: !tunnelEnabled,\n validate: () => {\n if (!tunnelEnabled) return \"QQ tunnel disabled (official webhook tunnel.enabled=false)\";\n if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(tunnelHost)) return \"invalid official.tunnel.host\";\n if (!Number.isInteger(tunnelRemotePort) || tunnelRemotePort < 1 || tunnelRemotePort > 65535) {\n return \"invalid official.tunnel.remotePort\";\n }\n return null;\n },\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 || qqExternal,\n validate: () => {\n if (!qqEnabled) return \"QQ bridge disabled (qq_enabled=false)\";\n if (qqExternal) return \"QQ bridge runs externally (official.transport=webhook)\";\n if (!useLlbotBackend) {\n if (!String(qqCfg.official?.app_id ?? \"\").trim() || !String(qqCfg.official?.app_secret ?? \"\").trim()) {\n return \"missing official.app_id / official.app_secret\";\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\", \"tunnel\", \"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\n/**\n * \u6309\u542F\u52A8\u9006\u5E8F\u505C\u6B62\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u6258\u7BA1\u5B50\u8FDB\u7A0B\uFF08\u4F18\u96C5 stop / stdin stop\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A`stop all`\u3001`restart -all`\u3001\u5B88\u62A4\u8FDB\u7A0B shutdown / SIGTERM\u3002\n * \u663E\u5F0F\u4F20 external false\uFF1A\u4E0D\u6309\u955C\u50CF\u540D\u6216\u811A\u672C\u540D\u6740\u5916\u90E8 BDS / db / qq\u3002\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))\n .map((service) => service.stop(false));\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 /* CLI \u8FDB\u7A0B\u4E0D\u6301\u6709 Service \u5B50\u8FDB\u7A0B\uFF1A\u6539\u8BA2\u5B88\u62A4\u8FDB\u7A0B\u63A8\u9001\u7684\u8FDC\u7A0B\u72B6\u6001\u4E8B\u4EF6 */\n if (!isDaemonServer()) {\n return onRemoteServiceStateChange(fn);\n }\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 * CLI \u8FDB\u7A0B\u7ECF\u5B88\u62A4\u8FDB\u7A0B RPC \u83B7\u53D6\uFF1B\u5B88\u62A4\u8FDB\u7A0B\u5185\u8D70\u672C\u5730\u63A2\u6D3B\u3002\n */\nexport async function queryServicesRuntime(): Promise<ServiceStatus[]> {\n if (!isDaemonServer()) {\n const { queryRuntimeViaDaemon } = await import(\"./daemon/client.js\");\n return queryRuntimeViaDaemon();\n }\n return queryServicesRuntimeLocal();\n}\n\n/** \u5B88\u62A4\u8FDB\u7A0B\u5185\u672C\u5730\u63A2\u6D3B\u5B9E\u73B0\uFF08\u4EA6\u4F9B server status \u7EC4\u88C5 rows\uFF09 */\nexport async function queryServicesRuntimeLocal(): 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 if (name === \"tunnel\") {\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 pid = await probeTunnelRuntime();\n running = pid > 0;\n if (running) 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/** \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": "AAiBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,YAAY,kBAAkB,2BAA2B;AAClE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,6BAA6B;AACtC,SAAS,aAAgC;AACzC,SAAS,oBAAoB;AAC7B,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,sBAAsB;AAC/B,SAAS,kCAAkC;AAC3C,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,YAAY,WAAW,sBAAsB;AACtD,SAAS,qBAAqB,+BAA+B;AAC7D,SAAS,kCAAkC;AAC3C,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,SAAS,qBAAqB,0BAA0B;AACxD,SAAS,MAAM,oBAAoC;AAEnD,SAAS,QAAAA,aAAY;AASd,SAAS,oBAAoB,MAAwB;AAC1D,SAAO,KAAK,MAAM,OAAO,EAAE,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC;AACpE;AAGO,MAAM,gBAA+B,CAAC,OAAO,MAAM,UAAU,MAAM,OAAO;AA8BjF,IAAI,eAAe;AAEnB,IAAI,gBAA2B;AAExB,SAAS,mBAA8B;AAC5C,SAAO;AACT;AAEA,eAAe,cAAc,MAAgC;AAC3D,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,oBAAoB,IAAI,eAAe,EAAE,QAAQ,YAAY,QAAQ,GAAI,EAAE,CAAC;AACpG,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAe,iBAA2D;AACxE,QAAM,SAAS,SAA0B,oBAAoB,IAAI,CAAC;AAClE,MAAI,CAAC,QAAQ,OAAO,OAAO,OAAO,EAAG,QAAO,EAAE,OAAO,OAAO,KAAK,EAAE;AACnE,MAAI,CAAE,MAAM,eAAe,OAAO,GAAG,EAAI,QAAO,EAAE,OAAO,OAAO,KAAK,EAAE;AACvE,SAAO,EAAE,OAAO,MAAM,KAAK,OAAO,IAAI;AACxC;AAEA,MAAM,oBAAoB,KAAK,KAAK,MAAM,SAAS,qBAAqB;AAExE,eAAe,qBAAsC;AACnD,QAAM,MAAM,SAA2B,iBAAiB,GAAG;AAC3D,SAAO,OAAO,QAAQ,YAAY,MAAM,KAAM,MAAM,eAAe,GAAG,IAAK,MAAM;AACnF;AAEA,SAAS,mBAAmB,KAAmB;AAC7C,KAAG,UAAU,KAAK,QAAQ,iBAAiB,GAAG,EAAE,WAAW,KAAK,CAAC;AACjE,KAAG,cAAc,mBAAmB,KAAK,UAAU,EAAE,KAAK,WAAW,KAAK,IAAI,EAAE,CAAC,IAAI,IAAI;AAC3F;AAEA,SAAS,mBAAmB,KAAmB;AAC7C,MAAI,SAA2B,iBAAiB,GAAG,QAAQ,IAAK;AAChE,MAAI;AACF,OAAG,WAAW,iBAAiB;AAAA,EACjC,QAAQ;AAAA,EAER;AACF;AAGA,SAAS,qBAA2B;AAClC,MAAI;AACF,UAAM,OAAO,oBAAoB,IAAI;AACrC,QAAI,GAAG,WAAW,IAAI,EAAG,IAAG,WAAW,IAAI;AAAA,EAC7C,QAAQ;AAAA,EAER;AACF;AAQA,eAAe,sBAAqC;AAClD,QAAM,yBAAyB;AAC/B,kBAAgB,IAAI;AACpB,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,SAAK,MAAM,sBAAsB,GAAG,WAAW,EAAG;AAClD,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAAA,EAC7C;AACA,QAAM,yBAAyB;AAC/B,kBAAgB,IAAI;AACtB;AA0BA,MAAM,QAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACA,OAA4B;AAAA,EAC5B,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAyB;AAAA,EACzB,OAAkB,CAAC;AAAA,EACnB,SAAS,IAAI,aAAa;AAAA,EAElB;AAAA,EACA,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,eAAqD;AAAA,EAE7D,YAAY,KAAiB;AAC3B,SAAK,OAAO,IAAI;AAChB,SAAK,QAAQ,IAAI;AACjB,SAAK,MAAM;AACX,QAAI,IAAI,SAAS,UAAU;AACzB,WAAK,OAAO,GAAG,UAAU,CAAC,MAAc,UAA4B;AAClE,uBAAe,MAAM,UAAU,KAAK;AAAA,MACtC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,IAAI,SAAiB;AACnB,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,QAAS,QAAO;AAC7C,UAAM,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,QAAQ;AAC/C,UAAM,IAAI,KAAK,MAAM,KAAK,GAAK;AAC/B,UAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,QAAI,IAAI,EAAG,QAAO,GAAG,CAAC,KAAK,IAAI,EAAE;AACjC,QAAI,IAAI,EAAG,QAAO,GAAG,CAAC;AACtB,WAAO,GAAG,KAAK,MAAM,KAAK,GAAI,CAAC;AAAA,EACjC;AAAA,EAEA,QAAQ,MAAc,QAAmC;AACvD,UAAM,OAAgB,EAAE,MAAM,oBAAI,KAAK,GAAG,MAAM,OAAO;AACvD,SAAK,KAAK,KAAK,IAAI;AACnB,QAAI,KAAK,KAAK,SAAS,IAAM,MAAK,KAAK,OAAO,GAAG,KAAK,KAAK,SAAS,GAAI;AACxE,SAAK,OAAO,KAAK,OAAO,IAAI;AAG5B,UAAM,QAAQ,WAAW,WAAW,UAAU,WAAW,IAAI;AAC7D,mBAAe,MAAM,KAAK,MAAM,KAAK;AACrC,SAAK,IAAI,YAAY,IAAI;AAAA,EAC3B;AAAA,EAEA,MAAM,QAA+B;AACnC,QAAI,KAAK,iBAAkB,OAAM,IAAI,MAAM,kEAAgB;AAC3D,QAAI,KAAK,QAAS,QAAO,EAAE,QAAQ,UAAU;AAC7C,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,QAAQ,MAAM,eAAe,EAAE,SAAS,KAAK,CAAC;AACpD,UAAI,MAAM,UAAU,WAAW;AAC7B,cAAM,IAAI;AAAA,UACR,EAAE,yBAAyB;AAAA,YACzB,KAAK,OAAO,MAAM,GAAG;AAAA,YACrB,MAAM,EAAE,MAAM,UAAU,YAAY,gBAAgB,qBAAqB;AAAA,UAC3E,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,SAAS,QAAQ,KAAK,SAAS,MAAM;AAC5C,YAAM,WAAW,MAAM,oBAAoB,KAAK,IAAI;AACpD,UAAI,SAAS,SAAS,GAAG;AACvB,eAAO,EAAE,QAAQ,UAAU;AAAA,MAC7B;AAAA,IACF;AACA,QAAI,KAAK,SAAS,YAAa,MAAM,mBAAmB,EAAI,QAAO,EAAE,QAAQ,UAAU;AACvF,QAAI,KAAK,IAAI,UAAU;AACrB,YAAM,IAAI,KAAK,IAAI,SAAS;AAC5B,UAAI,GAAG;AAEL,YAAI,KAAK,IAAI,SAAU,QAAO,EAAE,QAAQ,WAAW,QAAQ,EAAE;AAC7D,cAAM,IAAI,MAAM,CAAC;AAAA,MACnB;AAAA,IACF;AACA,QAAI,KAAK,IAAI,aAAa;AACxB,YAAM,KAAK,IAAI,YAAY;AAAA,IAC7B;AACA,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,oBAAoB,MAAM,CAAC,MAAM,WAAW,KAAK,QAAQ,MAAM,MAAM,CAAC;AAAA,IAC9E;AAEA,QAAI,KAAK,iBAAkB,OAAM,IAAI,MAAM,kEAAgB;AAC3D,SAAK,aAAa;AAIlB,UAAM,YAAY;AAAA,MAChB,KAAK,KAAK,IAAI;AAAA,MACd,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,MAC9B,KAAK,KAAK,IAAI,MAAM,EAAE,GAAG,QAAQ,KAAK,GAAG,KAAK,IAAI,IAAI,IAAI,QAAQ;AAAA,MAClE,aAAa;AAAA,IACf;AACA,UAAM,QAAQ,KAAK,IAAI,UACnB,aAAa,KAAK,IAAI,SAAS,KAAK,IAAI,QAAQ,CAAC,GAAG,SAAS,IAC7D,MAAM,KAAK,IAAI,KAAe,KAAK,IAAI,QAAQ,CAAC,GAAG,SAAS;AAChE,SAAK,OAAO;AACZ,SAAK,MAAM,MAAM,OAAO;AACxB,SAAK,UAAU;AACf,SAAK,YAAY,oBAAI,KAAK;AAC1B,QAAI,KAAK,SAAS,SAAS,KAAK,MAAM,GAAG;AACvC,sBAAgB,KAAK,KAAK,IAAI;AAAA,IAChC;AACA,QAAI,KAAK,SAAS,YAAY,KAAK,MAAM,EAAG,oBAAmB,KAAK,GAAG;AACvE,SAAK,OAAO,KAAK,UAAU,gBAAgB,KAAK,GAAG,KAAK,MAAM;AAC9D,SAAK,OAAO,KAAK,SAAS,EAAE,MAAM,KAAK,MAAM,SAAS,MAAM,KAAK,KAAK,IAAI,CAAC;AAE3E,QAAI,oBAAoB;AACxB,UAAM,aAAa,CAAC,SAAyB;AAC3C,UAAI,KAAK,SAAS,SAAS,kBAAmB;AAC9C,0BAAoB;AACpB,YAAM,UAAU,KAAK,cAAc,KAAK;AACxC,WAAK,sBAAsB,UAAU,SAAS,SAAS,UAAU,SAAY,QAAQ,QAAQ,GAAG,IAAI;AAAA,QAClG,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AACA,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,KAAK,SAAS,MAAM;AACxB,aAAK,sBAAsB,SAAS,QAAW,EAAE,MAAM,aAAa,CAAC;AAAA,MACvE,CAAC;AAAA,IACH;AAEA,UAAM,GAAG,SAAS,CAAC,MAAM;AACvB,WAAK,OAAO,KAAK,UAAU,kBAAkB,EAAE,OAAO,IAAI,OAAO;AACjE,iBAAW;AACX,WAAK,QAAQ;AACb,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,QAAI,oBAAoB;AACxB,UAAM,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACtC,UAAI,KAAK,SAAS,SAAS,KAAK,WAAW;AACzC,6BAAqB,EAAE,SAAS;AAChC,cAAM,eAAe,kBAAkB,MAAM,OAAO;AACpD,6BAAqB,aAAa,IAAI,KAAK,IAAI,MAAM,KAAK;AAC1D,mBAAW,eAAe,aAAc,kBAAiB,MAAM,aAAa,KAAK,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MAChH;AACA,iBAAW,QAAQ,oBAAoB,EAAE,SAAS,CAAC,GAAG;AACpD,aAAK,QAAQ,MAAM,QAAQ;AAAA,MAC7B;AAAA,IACF,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,MAAc;AACtC,iBAAW,QAAQ,oBAAoB,EAAE,SAAS,CAAC,GAAG;AACpD,aAAK,QAAQ,MAAM,QAAQ;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,KAAK,QAAQ,KAAK,SAAS,MAAO;AACtC,WAAK,OAAO,KAAK,UAAU,iBAAiB,IAAI,KAAK,MAAM;AAC3D,iBAAW,IAAI;AACf,WAAK,QAAQ;AACb,WAAK,gBAAgB;AAAA,IACvB,CAAC;AACD,WAAO,EAAE,QAAQ,UAAU;AAAA,EAC7B;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,cAAc,KAAK,oBAAoB,CAAC,KAAK,IAAI,eAAe,KAAK,aAAc;AAC5F,SAAK,eAAe,WAAW,MAAM;AACnC,WAAK,eAAe;AACpB,UAAI,CAAC,KAAK,oBAAoB,CAAC,KAAK,cAAc,CAAC,KAAK,SAAS;AAC/D,aAAK,KAAK,MAAM,EAAE,MAAM,CAAC,MAAa;AACpC,eAAK,OAAO,KAAK,UAAU,mBAAmB,EAAE,OAAO,IAAI,OAAO;AAAA,QACpE,CAAC;AAAA,MACH;AAAA,IACF,GAAG,KAAK,IAAI,YAAY;AAAA,EAC1B;AAAA;AAAA,EAGA,cAAoB;AAClB,QAAI,KAAK,SAAS,MAAO;AACzB,QAAI,KAAK,iBAAkB,OAAM,IAAI,MAAM,gDAAa;AACxD,SAAK,mBAAmB;AACxB,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,KAAK,WAAW,OAAO,iBAAiB,MAAyB;AACrE,SAAK,aAAa;AAClB,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AAGA,QAAI,YAAY,KAAK,SAAS,OAAO;AACnC,YAAM,QAAQ,MAAM,eAAe;AAAA,QACjC,YAAY,KAAK;AAAA,QACjB,UAAU,QAAQ,KAAK,MAAM,KAAK;AAAA,QAClC,SAAS;AAAA,MACX,CAAC;AACD,UAAI,MAAM,UAAU,YAAY;AAC9B,cAAM,oBAAoB;AAC1B,aAAK,gBAAgB;AACrB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,UAAU,QAAQ,KAAK,QAAQ,KAAK,OAAO;AACjD,QAAI,QAAS,OAAM,KAAK,iBAAiB,cAAc;AAGvD,QAAI,aAAa,KAAK,SAAS,QAAQ,KAAK,SAAS,OAAO;AAC1D,YAAM,SAAS,MAAM,wBAAwB,KAAK,IAAI;AACtD,UAAI,KAAK,SAAS,KAAM,oBAAmB;AAC3C,UAAI,QAAS,QAAO;AACpB,aAAO,OAAO,SAAS,IAAI,aAAa;AAAA,IAC1C;AAEA,QAAI,QAAS,QAAO;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAAiB,iBAAiB,MAAqB;AACnE,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,QAAS;AACjC,SAAK,OAAO,KAAK,UAAU,eAAe,MAAM;AAEhD,QAAI,KAAK,IAAI,eAAe,KAAK,KAAK,OAAO;AAC3C,WAAK,KAAK,MAAM,MAAM,KAAK,IAAI,cAAc,IAAI;AAAA,IACnD,OAAO;AACL,WAAK,KAAK,KAAK,SAAS;AAAA,IAC1B;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,CAAC,kBAAkB,KAAK,MAAM;AAChC,iBAAO,IAAI,MAAM,GAAG,KAAK,IAAI,6IAA0B,CAAC;AACxD;AAAA,QACF;AACA,YAAI,KAAK,MAAM;AACb,eAAK,OAAO,KAAK,UAAU,cAAc,OAAO;AAChD,cAAI;AACF,iBAAK,KAAK,KAAK,SAAS;AAAA,UAC1B,QAAQ;AAAA,UAER;AAAA,QACF;AACA,gBAAQ;AAAA,MACV,GAAG,KAAK,IAAI,WAAW;AAEvB,WAAK,MAAM,GAAG,QAAQ,MAAM;AAC1B,qBAAa,OAAO;AACpB,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,KAAM;AACjC,UAAM,QAAQ,KAAK;AACnB,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,SAAK,OAAO,KAAK,SAAS,EAAE,MAAM,KAAK,MAAM,SAAS,OAAO,KAAK,EAAE,CAAC;AACrE,QAAI,SAAS,MAAM,aAAa,MAAM;AACpC,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,UAAM,QAAQ,KAAK;AACnB,SAAK,aAAa;AAClB,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AACA,SAAK,QAAQ;AACb,QAAI,CAAC,MAAO;AACZ,QAAI;AACF,YAAM,KAAK,SAAS;AAAA,IACtB,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAiC;AACrC,UAAM,KAAK,KAAK,IAAI;AACpB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,cAAc,GAAsB;AAClC,WAAO,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,uBAA6B;AAC3B,QAAI,CAAC,KAAK,WAAW,CAAC,KAAK,KAAM;AACjC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,UAAgB;AACtB,UAAM,aAAa,KAAK,WAAW,KAAK,SAAS;AACjD,UAAM,aAAa,KAAK;AACxB,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,QAAI,KAAK,SAAS,SAAS,aAAa,GAAG;AACzC,YAAM,UAAU,eAAe,IAAI;AACnC,UAAI,YAAY,YAAY;AAC1B,wBAAgB,IAAI;AAAA,MACtB;AACA,yBAAmB;AAAA,IACrB;AACA,QAAI,KAAK,SAAS,YAAY,aAAa,EAAG,oBAAmB,UAAU;AAC3E,QAAI,YAAY;AACd,WAAK,OAAO,KAAK,SAAS,EAAE,MAAM,KAAK,MAAM,SAAS,OAAO,KAAK,EAAE,CAAC;AAAA,IACvE;AAAA,EACF;AACF;AAEA,SAAS,iBAA+C;AAEtD,oBAAkB,MAAM,CAAC,eAAe,aAAa,aAAa,SAAS,CAAC;AAC5E,6BAA2B;AAC3B,OAAK,OAAO,0BAA0B,EACnC,KAAK,CAAC,QAAQ,IAAI,6BAA6B,CAAC,EAChD,MAAM,CAAC,UAAmB;AACzB,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,mBAAe,SAAS,UAAU,MAAM;AAAA,EAC1C,CAAC;AACH,QAAM,SAAS,kBAAkB,MAAM,oBAAoB,eAAe,EAAE,GAAG,2BAA2B,CAGzG;AACD,QAAM,QAAQ,kBAAkB,MAAM,kBAAkB,aAAa,EAAE,GAAG,kBAAkB,CAG3F;AACD,QAAM,QAAQ,kBAAkB,MAAM,kBAAkB,aAAa,EAAE,GAAG,kBAAkB,CAG3F;AACD,QAAM,aAAa,OAAO,OAAO,YAAY,EAAE,EAAE,KAAK;AACtD,MAAI,QAAQ,aAAa,WAAW,kBAAkB,KAAK,UAAU,GAAG;AACtE,UAAM,IAAI;AAAA,MACR,6EAAoD,UAAU;AAAA,IAEhE;AAAA,EACF;AACA,QAAM,UAAU,KAAK,QAAQ,MAAM,cAAc,GAAG;AACpD,QAAM,kBAAkB,MAAM,eAAe;AAC7C,QAAM,YAAY,MAAM,eAAe;AAEvC,QAAM,aAAa,CAAC,mBAAmB,MAAM,UAAU,cAAc;AACrE,QAAM,YAAY,MAAM,UAAU;AAClC,QAAM,gBAAgB,aAAa,cAAc,WAAW,YAAY;AACxE,QAAM,aAAa,OAAO,WAAW,QAAQ,EAAE,EAAE,KAAK;AACtD,QAAM,mBAAmB,WAAW,cAAc;AAClD,QAAM,eAAe,MAAM,OAAO,YAAY;AAC9C,QAAM,cAAc,mBAAmB,MAAM,OAAO,MAAM,MAAM,OAAO,GAAG;AAC1E,QAAM,YAAY,YAAY;AAC9B,QAAM,WAAW,YAAY;AAC7B,QAAM,SAAS,MAAM,WAAW;AAChC,iBAAe;AACf,kBAAgB,kBAAkB,UAAU;AAC5C,QAAM,SAAS,WAAW,OAAO;AACjC,QAAM,UAAU,kBAAkB,eAAe;AAEjD,SAAO;AAAA,IACL,KAAK,IAAI,QAAQ;AAAA,MACf,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM,CAAC;AAAA,MACP,KAAK;AAAA,MACL,KAAK,iBAAiB,OAAO;AAAA,MAC7B,aAAa;AAAA,MACb,aAAa;AAAA;AAAA,MAEb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU,MAAM;AACd,YAAI,CAAC,GAAG,WAAW,MAAM,EAAG,QAAO,cAAc,MAAM;AACvD,eAAO;AAAA,MACT;AAAA,MACA,aAAa,YAAY;AACvB,4BAAoB,MAAM;AAG1B,cAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,kBAAkB;AAC/D,cAAM,oBAAoB,EAAE,aAAa,MAAM,CAAC;AAChD,cAAM,EAAE,yBAAyB,IAAI,MAAM,OAAO,wBAAwB;AAC1E,cAAM,yBAAyB;AAC/B,cAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,qBAAqB;AAC/D,cAAM,iBAAiB;AAAA,MACzB;AAAA,MACA,WAAW,CAAC,SACV,uBAAuB,MAAM;AAAA,QAC3B,MAAM;AAAA,QACN,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;AAAA,MAC1D,CAAC;AAAA,IACL,CAAC;AAAA,IAED,IAAI,IAAI,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,KAAK,EAAE,SAAS,OAAO,MAAM,EAAE;AAAA,IACjC,CAAC;AAAA,IAED,QAAQ,IAAI,QAAQ;AAAA,MAClB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QAAiB;AAAA,QAAM;AAAA,QACzC;AAAA,QAAM;AAAA,QAA4B;AAAA,QAAM;AAAA,QACxC;AAAA,QAAM;AAAA,QACN;AAAA,QAAM,aAAa,gBAAgB,cAAc,MAAM;AAAA,QACvD;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU,CAAC;AAAA,MACX,UAAU,MAAM;AACd,YAAI,CAAC,cAAe,QAAO;AAC3B,YAAI,CAAC,gCAAgC,KAAK,UAAU,EAAG,QAAO;AAC9D,YAAI,CAAC,OAAO,UAAU,gBAAgB,KAAK,mBAAmB,KAAK,mBAAmB,OAAO;AAC3F,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IAED,IAAI,IAAI,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,aAAa;AAAA;AAAA,MAEb,aAAa;AAAA,MACb,cAAc;AAAA,MACd,UAAU,CAAC,aAAa;AAAA,MACxB,UAAU,MAAM;AACd,YAAI,CAAC,UAAW,QAAO;AACvB,YAAI,WAAY,QAAO;AACvB,YAAI,CAAC,iBAAiB;AACpB,cAAI,CAAC,OAAO,MAAM,UAAU,UAAU,EAAE,EAAE,KAAK,KAAK,CAAC,OAAO,MAAM,UAAU,cAAc,EAAE,EAAE,KAAK,GAAG;AACpG,mBAAO;AAAA,UACT;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,IAED,OAAO,IAAI,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,MACL,MAAM,CAAC;AAAA,MACP,KAAK;AAAA,MACL,aAAa;AAAA,MACb,aAAa;AAAA,MACb,cAAc;AAAA;AAAA,MAEd,UAAU,CAAC,mBAAmB,CAAC;AAAA,MAC/B,UAAU,MAAM;AACd,YAAI,CAAC,gBAAiB,QAAO;AAC7B,YAAI,CAAC,aAAc,QAAO;AAC1B,YAAI,CAAC,GAAG,WAAW,SAAS,EAAG,QAAO,cAAc,SAAS;AAC7D,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEO,IAAI,WAAyC,eAAe;AAE5D,SAAS,kBAAwB;AACtC,eAAa;AACb,aAAW,eAAe;AAC5B;AAEO,MAAM,cAA6B,CAAC,MAAM,UAAU,MAAM,SAAS,KAAK;AAE/E,eAAsB,WAAoC;AACxD,QAAM,SAAyB,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE;AACtE,aAAW,QAAQ,aAAa;AAC9B,UAAM,MAAM,SAAS,IAAI;AACzB,QAAI,CAAC,IAAK;AACV,QAAI;AACF,YAAM,UAAU,MAAM,IAAI,MAAM;AAChC,UAAI,QAAQ,WAAW,WAAW;AAChC,eAAO,QAAQ,KAAK,EAAE,MAAM,QAAQ,QAAQ,OAAO,CAAC;AACpD,YAAI,OAAO,KAAK,UAAU,YAAY,QAAQ,MAAM,IAAI,MAAM;AAAA,MAChE,OAAO;AACL,eAAO,QAAQ,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF,SAAS,GAAG;AACV,YAAM,SAAU,EAAY;AAC5B,aAAO,OAAO,KAAK,EAAE,MAAM,OAAO,CAAC;AACnC,UAAI,OAAO,KAAK,UAAU,gBAAgB,MAAM,IAAI,OAAO;AAAA,IAC7D;AAAA,EACF;AACA,SAAO;AACT;AAOA,eAAsB,UAAyB;AAC7C,QAAM,UAAU,CAAC,GAAG,WAAW,EAC5B,QAAQ,EACR,IAAI,CAAC,SAAS,SAAS,IAAI,CAAC,EAC5B,OAAO,CAAC,YAAgC,QAAQ,OAAO,CAAC,EACxD,IAAI,CAAC,YAAY,QAAQ,KAAK,KAAK,CAAC;AACvC,QAAM,QAAQ,WAAW,OAAO;AAClC;AAEO,SAAS,eAAqB;AACnC,aAAW,WAAW,OAAO,OAAO,QAAQ,EAAG,SAAQ,UAAU;AACnE;AAKO,SAAS,qBAAqB,IAAiD;AAEpF,MAAI,CAAC,eAAe,GAAG;AACrB,WAAO,2BAA2B,EAAE;AAAA,EACtC;AACA,QAAM,UAAU,CAAC,OAAgC;AAC/C,OAAG,EAAE;AAAA,EACP;AACA,aAAW,WAAW,OAAO,OAAO,QAAQ,GAAG;AAC7C,YAAQ,OAAO,GAAG,SAAS,OAAO;AAAA,EACpC;AACA,SAAO,MAAM;AACX,eAAW,WAAW,OAAO,OAAO,QAAQ,GAAG;AAC7C,cAAQ,OAAO,IAAI,SAAS,OAAO;AAAA,IACrC;AAAA,EACF;AACF;AAGA,eAAe,sBAAsB,SAAoC;AACvE,MAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,MAAI,QAAQ,MAAM,KAAK,CAAE,MAAM,eAAe,QAAQ,GAAG,GAAI;AAC3D,YAAQ,qBAAqB;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,QAAQ;AACjB;AAOA,eAAsB,uBAAiD;AACrE,MAAI,CAAC,eAAe,GAAG;AACrB,UAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oBAAoB;AACnE,WAAO,sBAAsB;AAAA,EAC/B;AACA,SAAO,0BAA0B;AACnC;AAGA,eAAsB,4BAAsD;AAC1E,SAAO,QAAQ;AAAA,IACb,cAAc,IAAI,OAAO,SAAS;AAChC,YAAM,UAAU,SAAS,IAAI;AAC7B,UAAI,UAAU;AACd,UAAI,MAAM;AACV,UAAI,SAAS;AACb,UAAI;AAEJ,UAAI,SAAS,OAAO;AAClB,cAAM,QAAQ,MAAM,eAAe;AAAA,UACjC,YAAY,QAAQ;AAAA,UACpB,UAAU,QAAQ,QAAQ,MAAM,KAAK;AAAA,UACrC,SAAS;AAAA,QACX,CAAC;AACD,YAAI,MAAM,UAAU,WAAW;AAC7B,oBAAU;AACV,gBAAM,MAAM;AACZ,mBAAS,QAAQ;AACjB,sBAAY;AAAA,QAEd,WAAW,MAAM,UAAU,YAAY;AACrC,oBAAU;AACV,gBAAM,MAAM;AACZ,sBAAY;AAEZ,cAAI,QAAQ,WAAW,QAAQ,QAAQ,MAAM,KAAK;AAChD,oBAAQ,qBAAqB;AAAA,UAC/B,WAAW,QAAQ,WAAW,CAAE,MAAM,eAAe,QAAQ,GAAG,GAAI;AAClE,oBAAQ,qBAAqB;AAAA,UAC/B;AAAA,QACF,OAAO;AACL,oBAAU;AACV,cAAI,QAAQ,WAAW,QAAQ,MAAM;AACnC,oBAAQ,qBAAqB;AAAA,UAC/B;AAAA,QACF;AAAA,MACF,WAAW,SAAS,MAAM;AACxB,cAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,YAAI,SAAS;AACX,oBAAU;AACV,gBAAM,QAAQ;AACd,mBAAS,QAAQ;AACjB,sBAAY;AAAA,QACd,WAAW,MAAM,cAAc,YAAY,GAAG;AAC5C,oBAAU;AACV,sBAAY;AACZ,gBAAM,OAAO,MAAM,oBAAoB,IAAI;AAC3C,gBAAM,KAAK,CAAC,KAAK;AAAA,QACnB;AAAA,MACF,WAAW,SAAS,MAAM;AACxB,cAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,YAAI,SAAS;AACX,oBAAU;AACV,gBAAM,QAAQ;AACd,mBAAS,QAAQ;AACjB,sBAAY;AAAA,QACd,OAAO;AACL,gBAAM,QAAQ,MAAM,eAAe;AACnC,cAAI,MAAM,OAAO;AACf,sBAAU;AACV,kBAAM,MAAM;AACZ,wBAAY;AAAA,UACd,OAAO;AACL,kBAAM,OAAO,MAAM,oBAAoB,IAAI;AAC3C,gBAAI,KAAK,SAAS,GAAG;AACnB,wBAAU;AACV,oBAAM,KAAK,CAAC;AACZ,0BAAY;AAAA,YACd;AAAA,UACF;AAAA,QACF;AAAA,MACF,WAAW,SAAS,UAAU;AAC5B,cAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,YAAI,SAAS;AACX,oBAAU;AACV,gBAAM,QAAQ;AACd,mBAAS,QAAQ;AACjB,sBAAY;AAAA,QACd,OAAO;AACL,gBAAM,MAAM,mBAAmB;AAC/B,oBAAU,MAAM;AAChB,cAAI,QAAS,aAAY;AAAA,QAC3B;AAAA,MACF,OAAO;AACL,cAAM,UAAU,MAAM,sBAAsB,OAAO;AACnD,YAAI,SAAS;AACX,oBAAU;AACV,gBAAM,QAAQ;AACd,mBAAS,QAAQ;AACjB,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,aAAO;AAAA,QACL;AAAA,QACA,OAAO,QAAQ;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAGA,eAAsB,iBAAiB,MAAqC;AAC1E,QAAM,OAAO,MAAM,qBAAqB;AACxC,SAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,OAAO;AACtD;",
4
+ "sourcesContent": ["/**\n * services.ts \u2014 CLI \u8FDB\u7A0B\u7F16\u6392\u4E0E\u670D\u52A1\u751F\u547D\u5468\u671F\u7BA1\u7406\n *\n * \u6838\u5FC3\u7BA1\u7406\u5BF9\u8C61\uFF08ServiceName\uFF09\uFF1A\n * - `bds`\uFF1AMinecraft \u57FA\u5CA9\u7248\u670D\u52A1\u7AEF\uFF08\u652F\u6301 stdin \u7BA1\u9053\u6307\u4EE4\u4EA4\u4E92\u4E0E\u4F18\u96C5\u505C\u670D\uFF09\n * - `db`\uFF1Adb-server SQLite HTTP \u670D\u52A1\uFF08\u7AEF\u53E3\u5065\u5EB7\u68C0\u67E5\u4E0E loopback \u63A2\u6D3B\uFF09\n * - `tunnel`\uFF1A\u4E91\u7AEF QQ Webhook \u5230\u672C\u673A db-server \u7684 SSH \u53CD\u5411\u96A7\u9053\n * - `qq`\uFF1Aqq-bridge \u6D88\u606F\u7F51\u6865\u670D\u52A1\uFF08\u652F\u6301\u5B98\u65B9 Bot \u4E0E LLBot \u53CC\u540E\u7AEF\uFF09\n * - `llbot`\uFF1ALLBot \u72EC\u7ACB\u673A\u5668\u4EBA\u8FDB\u7A0B\uFF08\u6761\u4EF6\u542F\u52A8\uFF09\n *\n * \u6838\u5FC3\u80FD\u529B\uFF1A\n * - \u8FDB\u7A0B\u751F\u547D\u5468\u671F\uFF1A\u6309\u4F9D\u8D56\u6B21\u5E8F\u7F16\u6392\u670D\u52A1\u542F\u52A8\uFF08db \u2192 qq \u2192 bds\uFF09\u3001\u4F18\u96C5\u505C\u6B62\u4E0E\u5F02\u5E38\u81EA\u52A8\u62C9\u8D77\n * - \u591A\u6E90\u63A2\u6D3B\u611F\u77E5\uFF1A\u81EA\u52A8\u63A2\u6D4B\u6258\u7BA1\u8FDB\u7A0B\u4E0E\u5916\u90E8\u72EC\u7ACB\u8FDB\u7A0B\u72B6\u6001\n * - \u65E5\u5FD7\u6D41\u7EDF\u4E00\u805A\u5408\uFF1A\u6355\u83B7\u5E76\u5F52\u4E00\u5316\u5404\u670D\u52A1\u7684 stdout / stderr \u6570\u636E\u6D41\n */\n\nimport type { BdsUpdaterConfig, DBConfig, QQBackend, QQBridgeConfig } from \"@sfmc-bds/sdk/node/config\";\nimport {\n DEFAULT_BDS_UPDATER_CONFIG,\n DEFAULT_DB_CONFIG,\n DEFAULT_QQ_CONFIG,\n ensureCoreConfigs,\n loadEnsuredConfig,\n qqRuntimeStatusPath,\n readJson,\n type QqRuntimeStatus,\n} from \"@sfmc-bds/sdk/node/config\";\n\nimport { bdsExePath, bdsSpawnEnvExtra, ensureBdsExecutable } from \"@sfmc-bds/bds-tools/host-platform\";\nimport {\n clearBdsPidFile,\n findBedrockServerPids,\n isProcessAlive,\n killBedrockServerByImage,\n probeBdsStatus,\n readBdsPidFile,\n writeBdsPidFile,\n} from \"@sfmc-bds/bds-tools/process-probe\";\nimport { postBdsLifecycleEvent } from \"@sfmc-bds/bds-tools/qq-events-notify\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { isDaemonServer } from \"./daemon/role.js\";\nimport { onRemoteServiceStateChange } from \"./daemon/client.js\";\nimport { t } from \"./i18n/index.js\";\nimport { resolveLlbotLaunch } from \"./llbot-launch.js\";\nimport { inferLevel, pushLog as pushUnifiedLog } from \"./logs.js\";\nimport { findNodeServicePids, killNodeServiceByScript } from \"./node-service-probe.js\";\nimport { ensurePackUpdateConfigFile } from \"./pack-update/index.js\";\nimport { recordBdsVersion } from \"./bds-runtime-version.js\";\nimport { reportBdsPlayerSession } from \"./player-session.js\";\nimport { startModuleSidecars, stopModuleSidecars } from \"./module-sidecars.js\";\nimport { ROOT, spawnService, type ServiceId } from \"./runtime.js\";\n\nexport { ROOT } from \"./runtime.js\";\n\nexport interface LogLine {\n time: Date;\n text: string;\n stream: \"stdout\" | \"stderr\";\n}\n\n/** \u5B50\u8FDB\u7A0B\u8F93\u51FA\u5206\u884C\uFF1A\u8FC7\u6EE4\u7A7A\u4E32\u4EE5\u53CA Windows CRLF \u62C6\u5206\u540E\u6B8B\u7559\u7684\u7EAF\u7A7A\u767D\u884C\u3002 */\nexport function nonBlankOutputLines(text: string): string[] {\n return text.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n}\n\nexport type ServiceName = \"bds\" | \"db\" | \"tunnel\" | \"qq\" | \"llbot\";\nexport const SERVICE_NAMES: ServiceName[] = [\"bds\", \"db\", \"tunnel\", \"qq\", \"llbot\"];\n\n/** \u5355\u670D\u52A1 start \u7ED3\u679C\uFF1Aoptional \u670D\u52A1 validate \u5931\u8D25\u8BB0\u4E3A skipped\uFF0C\u4E0D\u629B\u9519 */\nexport type StartOutcome = { status: \"started\" } | { status: \"already\" } | { status: \"skipped\"; reason: string };\n\n/**\n * \u5355\u670D\u52A1 stop \u7ED3\u679C\uFF0C\u4F9B CLI \u533A\u5206\u6587\u6848\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A`stop <name>` / `restart <name>` \u4E0E `stop all` \u90FD\u8D70 Service.stop\uFF0C\u4F46\u53EA\u6709\u524D\u8005\u4F1A\u5F97\u5230 external\u3002\n * - managed\uFF1A\u505C\u7684\u662F\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u5B50\u8FDB\u7A0B\n * - external\uFF1A\u6CA1\u6709\u6258\u7BA1\u53E5\u67C4\uFF0C\u4F46\u6E05\u6389\u4E86\u5916\u90E8\u5B9E\u4F8B\uFF08\u4EC5 external=true \u65F6\uFF09\n * - idle\uFF1A\u672C\u6765\u5C31\u6CA1\u5728\u8DD1\uFF0C\u6216\u6279\u91CF\u505C\u6B62\u65F6\u6545\u610F\u4E0D\u52A8\u5916\u90E8\u5B9E\u4F8B\n */\nexport type StopKind = \"managed\" | \"external\" | \"idle\";\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\nconst tunnelRuntimePath = path.join(ROOT, \".sfmc\", \"tunnel.runtime.json\");\n\nasync function probeTunnelRuntime(): Promise<number> {\n const pid = readJson<{ pid?: number }>(tunnelRuntimePath)?.pid;\n return typeof pid === \"number\" && pid > 0 && (await isProcessAlive(pid)) ? pid : 0;\n}\n\nfunction writeTunnelRuntime(pid: number): void {\n fs.mkdirSync(path.dirname(tunnelRuntimePath), { recursive: true });\n fs.writeFileSync(tunnelRuntimePath, JSON.stringify({ pid, startedAt: Date.now() }) + \"\\n\");\n}\n\nfunction clearTunnelRuntime(pid: number): void {\n if (readJson<{ pid?: number }>(tunnelRuntimePath)?.pid !== pid) return;\n try {\n fs.unlinkSync(tunnelRuntimePath);\n } catch {\n /* \u8FDB\u7A0B\u9000\u51FA\u65F6\u5141\u8BB8\u6587\u4EF6\u5DF2\u88AB\u79FB\u9664 */\n }\n}\n\n/** \u6E05\u6389 qq-bridge \u8FD0\u884C\u65F6\u6587\u4EF6\uFF0C\u907F\u514D status \u4ECD\u628A\u5DF2\u9000\u51FA\u7684\u5916\u90E8\u8FDB\u7A0B\u5F53\u6210\u5B58\u6D3B\u3002 */\nfunction clearQqRuntimeFile(): void {\n try {\n const file = qqRuntimeStatusPath(ROOT);\n if (fs.existsSync(file)) fs.unlinkSync(file);\n } catch {\n /* \u8FD0\u884C\u65F6\u6587\u4EF6\u53EF\u80FD\u5DF2\u88AB\u8FDB\u7A0B\u81EA\u5DF1\u5220\u6389 */\n }\n}\n\n/**\n * \u6309\u955C\u50CF\u540D\u7ED3\u675F\u5916\u90E8 BDS\uFF0C\u5E76\u7B49\u5230\u8FDB\u7A0B\u4ECE\u8FDB\u7A0B\u8868\u6D88\u5931\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u4EC5\u5355\u670D\u52A1 stop / restart\uFF08Service.stop \u7684 external=true\uFF09\u6E05\u6389\u975E\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684 bedrock\u3002\n * stop all \u4E0E\u5B88\u62A4\u8FDB\u7A0B shutdown \u4E0D\u8C03\u7528\u8FD9\u91CC\uFF0C\u907F\u514D taskkill \u8BEF\u6740\u540C\u673A\u5176\u4ED6 Bedrock\u3002\n * taskkill \u8FD4\u56DE\u540E\u8FDB\u7A0B\u8868\u53EF\u80FD\u4ECD\u77ED\u6682\u53EF\u89C1\uFF0Crestart \u4F1A\u7ACB\u523B\u63A2\u6D3B\uFF0C\u56E0\u6B64\u8FD9\u91CC\u7B49\u5230\u6D88\u5931\u518D\u8FD4\u56DE\u3002\n */\nasync function killExternalBedrock(): Promise<void> {\n await killBedrockServerByImage();\n clearBdsPidFile(ROOT);\n const deadline = Date.now() + 8000;\n while (Date.now() < deadline) {\n if ((await findBedrockServerPids()).length === 0) return;\n await new Promise((r) => setTimeout(r, 200));\n }\n await killBedrockServerByImage();\n clearBdsPidFile(ROOT);\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 /** \u539F\u59CB\u65E5\u5FD7\u884C\u89C2\u5BDF\u5668\uFF0C\u4E0D\u5F97\u963B\u585E\u5B50\u8FDB\u7A0B\u8F93\u51FA\u3002 */\n onLogLine?: (line: string) => 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 private updateInProgress = false;\n private restartTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(def: ServiceDef) {\n this.name = def.name;\n this.title = def.title;\n this.def = def;\n if (def.name === \"tunnel\") {\n this.events.on(\"output\", (text: string, level: \"info\" | \"error\") => {\n pushUnifiedLog(text, \"tunnel\", level);\n });\n }\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 this.def.onLogLine?.(text);\n }\n\n async start(): Promise<StartOutcome> {\n if (this.updateInProgress) throw new Error(\"BDS \u6B63\u5728\u66F4\u65B0\uFF0C\u6682\u4E0D\u53EF\u542F\u52A8\");\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\", {\n pid: String(probe.pid),\n kind: t(probe.state === \"managed\" ? \"svc.running\" : \"svc.runningExternal\"),\n })\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.name === \"tunnel\" && (await probeTunnelRuntime())) return { status: \"already\" };\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 if (this.name === \"bds\") {\n await startModuleSidecars(ROOT, (line, stream) => this.pushLog(line, stream));\n }\n // beforeStart \u542B\u5F02\u6B65\u68C0\u67E5\uFF1B\u66F4\u65B0\u53EF\u80FD\u5728\u7B49\u5F85\u671F\u95F4\u5F00\u59CB\u3002\n if (this.updateInProgress) throw new Error(\"BDS \u6B63\u5728\u66F4\u65B0\uFF0C\u6682\u4E0D\u53EF\u542F\u52A8\");\n this.manualStop = false;\n /* \u5B50\u8FDB\u7A0B\u59CB\u7EC8\u7531\u5B88\u62A4\u8FDB\u7A0B\u7528\u7BA1\u9053\u6301\u6709\uFF08stdin \u53D1 stop\u3001stdout \u65E5\u5FD7\u3001autoRestart\uFF09\uFF1B\n * \u4E0D\u518D\u5BF9\u5B50\u670D\u52A1\u505A detached/unref\u2014\u2014\u8131\u79BB\u7EC8\u7AEF\u7531 daemon \u8FDB\u7A0B\u81EA\u8EAB\u8D1F\u8D23\u3002\n * windowsHide\uFF1AWindows \u4E0A\u907F\u514D\u4E3A\u6BCF\u4E2A\u670D\u52A1\u5F39\u51FA\u7A7A\u767D\u63A7\u5236\u53F0\uFF08stdout \u5DF2 pipe\uFF0C\u7A97\u5185\u65E0\u8F93\u51FA\uFF09\u3002 */\n const spawnOpts = {\n cwd: this.def.cwd,\n stdio: [\"pipe\", \"pipe\", \"pipe\"] as Array<\"pipe\">,\n env: this.def.env ? { ...process.env, ...this.def.env } : process.env,\n windowsHide: true,\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 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 if (this.name === \"tunnel\" && this.pid > 0) writeTunnelRuntime(this.pid);\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 let lifecycleReported = false;\n const reportExit = (code?: number | null) => {\n if (this.name !== \"bds\" || lifecycleReported) return;\n lifecycleReported = true;\n const planned = this.manualStop || this.updateInProgress;\n void postBdsLifecycleEvent(planned ? \"stop\" : \"crash\", planned ? undefined : `code=${code ?? \"?\"}`, {\n port: dbHealthPort,\n });\n };\n if (this.name === \"bds\") {\n child.once(\"spawn\", () => {\n void postBdsLifecycleEvent(\"start\", undefined, { port: dbHealthPort });\n });\n }\n\n child.on(\"error\", (e) => {\n this.events.emit(\"output\", `process error: ${e.message}`, \"error\");\n reportExit();\n this.cleanup();\n this.scheduleRestart();\n });\n\n let versionLineBuffer = \"\";\n child.stdout?.on(\"data\", (d: Buffer) => {\n if (this.name === \"bds\" && this.startTime) {\n versionLineBuffer += d.toString();\n const versionLines = versionLineBuffer.split(/\\r?\\n/);\n versionLineBuffer = (versionLines.pop() ?? \"\").slice(-4096);\n for (const versionLine of versionLines) recordBdsVersion(ROOT, versionLine, this.pid, this.startTime.getTime());\n }\n for (const line of nonBlankOutputLines(d.toString())) {\n this.pushLog(line, \"stdout\");\n }\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n for (const line of nonBlankOutputLines(d.toString())) {\n this.pushLog(line, \"stderr\");\n }\n });\n\n child.on(\"exit\", (code) => {\n if (this.proc && this.proc !== child) return;\n this.events.emit(\"output\", `exited (code: ${code})`, \"info\");\n reportExit(code);\n this.cleanup();\n this.scheduleRestart();\n });\n return { status: \"started\" };\n }\n\n private scheduleRestart(): void {\n if (this.manualStop || this.updateInProgress || !this.def.autoRestart || this.restartTimer) return;\n this.restartTimer = setTimeout(() => {\n this.restartTimer = null;\n if (!this.updateInProgress && !this.manualStop && !this.running) {\n void this.start().catch((e: Error) => {\n this.events.emit(\"output\", `restart failed: ${e.message}`, \"error\");\n });\n }\n }, this.def.restartDelay);\n }\n\n /** \u66F4\u65B0\u5668\u72EC\u7ACB\u8FDB\u7A0B\u505C\u670D\u65F6\uFF0C\u7981\u6B62\u5C06\u8BA1\u5212\u5185\u9000\u51FA\u5F53\u4F5C\u5D29\u6E83\u5E76\u81EA\u52A8\u62C9\u8D77\u3002 */\n beginUpdate(): void {\n if (this.name !== \"bds\") return;\n if (this.updateInProgress) throw new Error(\"BDS \u66F4\u65B0\u5DF2\u5728\u8FDB\u884C\u4E2D\");\n this.updateInProgress = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n }\n\n endUpdate(): void {\n this.updateInProgress = false;\n }\n\n /**\n * \u505C\u6B62\u672C\u670D\u52A1\u3002\u6258\u7BA1\u5B50\u8FDB\u7A0B\u59CB\u7EC8\u8D70\u539F\u6765\u7684\u4F18\u96C5\u505C\u6B62\uFF08stdin stop / SIGTERM\uFF09\u3002\n * @param external \u662F\u5426\u989D\u5916\u6E05\u6389\u975E\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u5916\u90E8\u5B9E\u4F8B\u3002\u9ED8\u8BA4 false\uFF0C\u53EA\u505C\u6258\u7BA1\u5B50\u8FDB\u7A0B\u3002\n * \u4E24\u79CD\u8C03\u7528\u573A\u666F\uFF1A\n * - true\uFF1A\u5355\u670D\u52A1 `stop <name>` / `restart <name>`\uFF08cmdStopLocal\uFF0C\u4EE5\u53CA\u4ECD\u5B58\u5728\u7684 Service.restart\uFF09\u3002\n * BDS \u5916\u90E8\u8D70 killExternalBedrock\uFF1Bdb/qq \u5916\u90E8\u8D70 killNodeServiceByScript\u3002\n * - false \u6216\u4E0D\u4F20\uFF1A`stop all`\u3001`restart -all`\u3001\u5B88\u62A4\u8FDB\u7A0B shutdown / SIGTERM\uFF08\u7ECF stopAll\uFF09\u3002\n * \u4E0D\u6309\u955C\u50CF\u540D\u6216\u811A\u672C\u540D\u6740\u5916\u90E8\u8FDB\u7A0B\uFF0C\u907F\u514D\u8BEF\u6740\u540C\u673A\u5176\u4ED6 Bedrock\u3001db\u3001qq\u3002\n */\n async stop(external = false, forceOnTimeout = true): Promise<StopKind> {\n this.manualStop = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n\n /* \u4E0E\u539F\u5148 cmdStop \u4E00\u81F4\uFF1A\u4EC5\u5355\u670D\u52A1\u505C\u6B62\u65F6\uFF0CBDS \u88AB\u5224\u5B9A\u4E3A\u5916\u90E8\u624D\u6309\u955C\u50CF\u7ED3\u675F\uFF0C\u4E0D\u8D70 stdin stop */\n if (external && this.name === \"bds\") {\n const probe = await probeBdsStatus({\n managedPid: this.pid,\n hasStdin: Boolean(this.proc?.stdin),\n rootDir: ROOT,\n });\n if (probe.state === \"external\") {\n await killExternalBedrock();\n this.dropStaleHandle();\n return \"external\";\n }\n }\n\n const managed = Boolean(this.proc && this.running);\n if (managed) await this.stopManagedChild(forceOnTimeout);\n\n /* db / qq\uFF1A\u4EC5\u5355\u670D\u52A1\u505C\u6B62\u65F6\uFF0C\u6258\u7BA1\u505C\u5B8C\u540E\u4ECD\u6309\u811A\u672C\u518D\u626B\u4E00\u904D\uFF0C\u6E05\u6389\u540C\u673A\u4E0A\u7684\u5916\u90E8\u5B9E\u4F8B */\n if (external && (this.name === \"db\" || this.name === \"qq\")) {\n const killed = await killNodeServiceByScript(this.name);\n if (this.name === \"qq\") clearQqRuntimeFile();\n if (managed) return \"managed\";\n return killed.length > 0 ? \"external\" : \"idle\";\n }\n\n if (managed) return \"managed\";\n return \"idle\";\n }\n\n /**\n * \u4F18\u96C5\u505C\u6B62\u5F53\u524D\u6258\u7BA1\u5B50\u8FDB\u7A0B\uFF08stdin stop \u6216 SIGTERM\uFF0C\u8D85\u65F6\u540E SIGKILL\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1AService.stop \u786E\u8BA4\u672C\u8FDB\u7A0B\u4ECD\u6301\u6709\u5B50\u8FDB\u7A0B\u65F6\u8C03\u7528\uFF1B\u903B\u8F91\u4E0E\u539F\u5148 stop \u4E3B\u4F53\u76F8\u540C\u3002\n */\n private async stopManagedChild(forceOnTimeout = true): Promise<void> {\n if (!this.proc || !this.running) return;\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, reject) => {\n const timeout = setTimeout(() => {\n if (!forceOnTimeout && this.proc) {\n reject(new Error(`${this.name} \u672A\u5728\u8D85\u65F6\u5185\u4F18\u96C5\u9000\u51FA\uFF1B\u5DF2\u4E2D\u6B62\u7EF4\u62A4\uFF0C\u4E0D\u5F3A\u5236\u7ED3\u675F\u8FDB\u7A0B`));\n return;\n }\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 /**\n * \u5916\u90E8\u505C\u670D\u540E\u4E22\u6389\u5931\u6548\u7684\u6258\u7BA1\u53E5\u67C4\uFF0C\u907F\u514D\u7D27\u63A5\u7740\u7684 start/restart \u8BEF\u5224\u300C\u5DF2\u5728\u8FD0\u884C\u300D\u3002\n * \u4E0D\u8D70 cleanup\uFF1A\u90A3\u4F1A\u8FDE\u5E26\u505C\u6389\u6A21\u5757\u9644\u5C5E\u8FDB\u7A0B\uFF0C\u800C\u539F\u5148\u7684\u5916\u90E8 BDS stop \u5E76\u4E0D\u8FD9\u4E48\u505A\u3002\n */\n private dropStaleHandle(): void {\n if (!this.running && !this.proc) return;\n const stale = this.proc;\n this.proc = null;\n this.running = false;\n this.pid = 0;\n this.startTime = null;\n this.events.emit(\"state\", { name: this.name, running: false, pid: 0 });\n if (stale && stale.exitCode === null) {\n try {\n stale.kill(\"SIGKILL\");\n } catch {\n /* \u5916\u90E8\u955C\u50CF\u7ED3\u675F\u65F6\u8FD9\u4E2A\u53E5\u67C4\u53EF\u80FD\u5DF2\u7ECF\u9000\u51FA */\n }\n }\n }\n\n forceStop(): void {\n const child = this.proc;\n this.manualStop = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n this.cleanup();\n if (!child) return;\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n\n /**\n * \u5355\u670D\u52A1\u91CD\u542F\uFF1A\u5148\u505C\u518D\u8D77\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A\u82E5\u4ECD\u6709\u8C03\u7528\u65B9\u76F4\u63A5\u8D70 Service.restart\uFF08\u4E0D\u7ECF cmdStopLocal\uFF09\uFF0C\u4E0E\u5355\u670D\u52A1 stop \u4E00\u6837\u6E05\u5916\u90E8\u5B9E\u4F8B\uFF08external true\uFF09\u3002\n * \u6279\u91CF `restart -all` \u548C\u5B88\u62A4\u8FDB\u7A0B shutdown \u4E0D\u8D70\u8FD9\u91CC\uFF0C\u5B83\u4EEC\u7ECF stopAll \u8C03\u7528 stop(false)\uFF0C\u53EA\u505C\u6258\u7BA1\u5B50\u8FDB\u7A0B\u3002\n */\n async restart(): Promise<StartOutcome> {\n await this.stop(true);\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 stopModuleSidecars();\n }\n if (this.name === \"tunnel\" && exitingPid > 0) clearTunnelRuntime(exitingPid);\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\", \"qq_link\"]);\n ensurePackUpdateConfigFile();\n void import(\"./module-update/index.js\")\n .then((mod) => mod.ensureModuleUpdateConfigFile())\n .catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n pushUnifiedLog(message, \"module\", \"warn\");\n });\n const bdsCfg = loadEnsuredConfig(ROOT, \"bds_updater.json\", \"bds_updater\", { ...DEFAULT_BDS_UPDATER_CONFIG } as Record<\n string,\n unknown\n >) as BdsUpdaterConfig;\n const qqCfg = loadEnsuredConfig(ROOT, \"qq_config.json\", \"qq_config\", { ...DEFAULT_QQ_CONFIG } as Record<\n string,\n unknown\n >) as QQBridgeConfig;\n const dbCfg = loadEnsuredConfig(ROOT, \"db_config.json\", \"db_config\", { ...DEFAULT_DB_CONFIG } as Record<\n string,\n unknown\n >) as DBConfig;\n const rawBdsPath = String(bdsCfg.bds_path ?? \"\").trim();\n if (process.platform !== \"win32\" && /^[A-Za-z]:[\\\\/]/.test(rawBdsPath)) {\n throw new Error(\n `configs/bds_updater.json \u7684 bds_path \u662F Windows \u8DEF\u5F84\uFF08${rawBdsPath}\uFF09\u3002` +\n `\u8BF7\u6539\u6210\u76F8\u5BF9 SFMC_ROOT \u7684\u8DEF\u5F84\uFF0C\u4F8B\u5982 \"BDS\"\u3002`\n );\n }\n const bdsPath = path.resolve(ROOT, rawBdsPath || \".\");\n const useLlbotBackend = qqCfg.qq_backend === \"llbot\";\n const qqEnabled = qqCfg.qq_enabled !== false;\n // \u5B98\u65B9 Webhook \u7531\u4E91\u7AEF\u63A5\u6536\uFF1B\u4EC5\u5207\u6362\u4F20\u8F93\u65B9\u5F0F\u5373\u53EF\u907F\u514D\u672C\u673A\u518D\u542F\u52A8\u4E00\u4E2A\u6865\u3002\n const qqExternal = !useLlbotBackend && qqCfg.official?.transport === \"webhook\";\n const tunnelCfg = qqCfg.official?.tunnel;\n const tunnelEnabled = qqEnabled && qqExternal && tunnelCfg?.enabled === true;\n const tunnelHost = String(tunnelCfg?.host ?? \"\").trim();\n const tunnelRemotePort = tunnelCfg?.remotePort ?? 13001;\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(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 /* \u5D29\u6E83\u62C9\u8D77\u7531 sfmc daemon \u56FA\u5B9A\u5F00\u542F\uFF1B\u4E0D\u518D\u8BFB bds_updater.crash_restart */\n autoRestart: true,\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 /* \u4E1A\u52A1\u6A21\u5757\u66F4\u65B0\u53EA\u8D70\u663E\u5F0F\u547D\u4EE4\uFF0C\u4E0D\u8FDB\u5F00\u670D\u94A9\u5B50\u3002 */\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 onLogLine: (line) =>\n reportBdsPlayerSession(line, {\n port: dbPort,\n ...(dbCfg.http_auth ? { authToken: dbCfg.http_auth } : {}),\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 tunnel: new Service({\n name: \"tunnel\",\n title: \"QQ SSH Tunnel\",\n cmd: \"ssh\",\n args: [\n \"-N\", \"-T\", \"-o\", \"BatchMode=yes\", \"-o\", \"ConnectTimeout=10\",\n \"-o\", \"ExitOnForwardFailure=yes\", \"-o\", \"ServerAliveInterval=30\",\n \"-o\", \"ServerAliveCountMax=3\",\n \"-R\", `127.0.0.1:${tunnelRemotePort}:127.0.0.1:${dbPort}`,\n tunnelHost,\n ],\n cwd: ROOT,\n stopTimeout: 10000,\n autoRestart: true,\n restartDelay: 5000,\n optional: !tunnelEnabled,\n validate: () => {\n if (!tunnelEnabled) return \"QQ tunnel disabled (official webhook tunnel.enabled=false)\";\n if (!/^[A-Za-z0-9_][A-Za-z0-9_.-]*$/.test(tunnelHost)) return \"invalid official.tunnel.host\";\n if (!Number.isInteger(tunnelRemotePort) || tunnelRemotePort < 1 || tunnelRemotePort > 65535) {\n return \"invalid official.tunnel.remotePort\";\n }\n return null;\n },\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 || qqExternal,\n validate: () => {\n if (!qqEnabled) return \"QQ bridge disabled (qq_enabled=false)\";\n if (qqExternal) return \"QQ bridge runs externally (official.transport=webhook)\";\n if (!useLlbotBackend) {\n if (!String(qqCfg.official?.app_id ?? \"\").trim() || !String(qqCfg.official?.app_secret ?? \"\").trim()) {\n return \"missing official.app_id / official.app_secret\";\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\n/** \u914D\u7F6E\u5237\u65B0\u540E\uFF0C\u5C06\u5DF2\u6709\u8BA2\u9605\u91CD\u65B0\u7ED1\u5B9A\u5230\u65B0\u670D\u52A1\u5BF9\u8C61\u3002 */\nconst serviceStateListeners = new Set<(event: ServiceStateEvent) => void>();\nexport let services: Record<ServiceName, Service> = createServices();\n\n/** \u53EF\u53EA\u5237\u65B0\u5373\u5C06\u542F\u52A8\u7684\u670D\u52A1\u5B9A\u4E49\uFF0C\u4FDD\u7559\u5176\u4ED6\u8FD0\u884C\u4E2D\u7684\u670D\u52A1\u53CA\u5176\u63A2\u6D3B\u53C2\u6570\u3002 */\nexport function refreshServices(names: readonly ServiceName[] = SERVICE_NAMES): void {\n const previousDbPort = dbHealthPort;\n const previousQqBackend = qqBackendMode;\n const latest = createServices();\n if (!names.includes(\"db\")) dbHealthPort = previousDbPort;\n if (!names.includes(\"qq\")) qqBackendMode = previousQqBackend;\n for (const name of names) {\n const previous = services[name];\n previous.forceStop();\n for (const listener of serviceStateListeners) previous.events.off(\"state\", listener);\n services[name] = latest[name];\n for (const listener of serviceStateListeners) services[name].events.on(\"state\", listener);\n }\n}\n\nexport const START_ORDER: ServiceName[] = [\"db\", \"tunnel\", \"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\n/**\n * \u6309\u542F\u52A8\u9006\u5E8F\u505C\u6B62\u672C\u8FDB\u7A0B\u62C9\u8D77\u7684\u6258\u7BA1\u5B50\u8FDB\u7A0B\uFF08\u4F18\u96C5 stop / stdin stop\uFF09\u3002\n * \u4F7F\u7528\u573A\u666F\uFF1A`stop all`\u3001`restart -all`\u3001\u5B88\u62A4\u8FDB\u7A0B shutdown / SIGTERM\u3002\n * \u663E\u5F0F\u4F20 external false\uFF1A\u4E0D\u6309\u955C\u50CF\u540D\u6216\u811A\u672C\u540D\u6740\u5916\u90E8 BDS / db / qq\u3002\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))\n .map((service) => service.stop(false));\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 /* CLI \u8FDB\u7A0B\u4E0D\u6301\u6709 Service \u5B50\u8FDB\u7A0B\uFF1A\u6539\u8BA2\u5B88\u62A4\u8FDB\u7A0B\u63A8\u9001\u7684\u8FDC\u7A0B\u72B6\u6001\u4E8B\u4EF6 */\n if (!isDaemonServer()) {\n return onRemoteServiceStateChange(fn);\n }\n const handler = (ev: ServiceStateEvent): void => {\n fn(ev);\n };\n serviceStateListeners.add(handler);\n for (const service of Object.values(services)) {\n service.events.on(\"state\", handler);\n }\n return () => {\n serviceStateListeners.delete(handler);\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 * CLI \u8FDB\u7A0B\u7ECF\u5B88\u62A4\u8FDB\u7A0B RPC \u83B7\u53D6\uFF1B\u5B88\u62A4\u8FDB\u7A0B\u5185\u8D70\u672C\u5730\u63A2\u6D3B\u3002\n */\nexport async function queryServicesRuntime(): Promise<ServiceStatus[]> {\n if (!isDaemonServer()) {\n const { queryRuntimeViaDaemon } = await import(\"./daemon/client.js\");\n return queryRuntimeViaDaemon();\n }\n return queryServicesRuntimeLocal();\n}\n\n/** \u5B88\u62A4\u8FDB\u7A0B\u5185\u672C\u5730\u63A2\u6D3B\u5B9E\u73B0\uFF08\u4EA6\u4F9B server status \u7EC4\u88C5 rows\uFF09 */\nexport async function queryServicesRuntimeLocal(): 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 if (name === \"tunnel\") {\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 pid = await probeTunnelRuntime();\n running = pid > 0;\n if (running) 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/** \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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfmc-bds/cli",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
4
4
  "description": "SFMC management CLI — REPL, service supervisor, module install, behavior-pack build/deploy",
5
5
  "author": "Shiroha7z",
6
6
  "license": "AGPL-3.0-only",
@@ -55,14 +55,14 @@
55
55
  "esbuild": "^0.28.1",
56
56
  "ajv": "8.20.0",
57
57
  "jsonc-parser": "3.3.1",
58
- "@sfmc-bds/bds-tools": "0.2.8",
59
- "@sfmc-bds/sdk": "0.4.0",
60
- "@sfmc-bds/db-server": "0.5.1",
61
- "@sfmc-bds/devkit": "2.0.4",
62
- "@sfmc-bds/management": "0.3.3"
58
+ "@sfmc-bds/bds-tools": "0.2.9",
59
+ "@sfmc-bds/devkit": "2.0.5",
60
+ "@sfmc-bds/sdk": "0.5.0",
61
+ "@sfmc-bds/db-server": "0.5.2",
62
+ "@sfmc-bds/management": "0.5.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@sfmc-bds/tools": "0.2.8"
65
+ "@sfmc-bds/tools": "0.2.9"
66
66
  },
67
67
  "publishConfig": {
68
68
  "access": "public",