mioku 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_exec = require('../exec-Cg19J7Dn.cjs');
2
+ const require_exec = require('../exec-DcNz1txh.cjs');
3
3
  const node_fs = require_exec.__toESM(require("node:fs"));
4
4
  const node_path = require_exec.__toESM(require("node:path"));
5
5
  const mri = require_exec.__toESM(require("mri"));
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { clearCommandCache, commandExists, resolveCommand, runCommandInherit, version } from "../exec-Xxd1F2u8.js";
2
+ import { clearCommandCache, commandExists, resolveCommand, runCommandInherit, version } from "../exec-B5iAOUft.js";
3
3
  import fs, { readFileSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import mri from "mri";
@@ -4,7 +4,7 @@ import * as os$1 from "node:os";
4
4
  import { spawn, spawnSync } from "node:child_process";
5
5
 
6
6
  //#region package.json
7
- var version = "1.0.10";
7
+ var version = "1.1.0";
8
8
 
9
9
  //#endregion
10
10
  //#region src/internal/exec.ts
@@ -180,4 +180,4 @@ function commandExists(command) {
180
180
 
181
181
  //#endregion
182
182
  export { buildSpawnPlan, clearCommandCache, commandExists, resolveCommand, runCommand, runCommandInherit, version };
183
- //# sourceMappingURL=exec-Xxd1F2u8.js.map
183
+ //# sourceMappingURL=exec-B5iAOUft.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec-B5iAOUft.js","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","args: string[]","options: { cwd?: string; env?: NodeJS.ProcessEnv }","options: { cwd?: string }"],"sources":["../package.json","../src/internal/exec.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"1.1.0\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - A plugin-based QQ bot framework\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioku\"\n ],\n \"bin\": {\n \"mioku\": \"./dist/cli/index.js\"\n },\n \"engines\": {\n \"node\": \">= 22.18.0\"\n },\n \"homepage\": \"https://github.com/mioku-lab/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/mioku-lab/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/mioku-lab/mioku.git\",\n \"directory\": \"packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"author\": \"Jerryplusy <jerryplusy@outlook.com>\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"napcat-sdk\": \"^0.16.0\",\n \"consola\": \"^3.4.2\",\n \"dayjs\": \"^1.11.19\",\n \"dedent\": \"^1.7.1\",\n \"filesize\": \"^11.0.13\",\n \"inquirer\": \"^10.0.0\",\n \"jiti\": \"^2.6.1\",\n \"lowdb\": \"^7.0.1\",\n \"mri\": \"^1.2.0\",\n \"node-cron\": \"^4.2.1\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import { spawn, spawnSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nconst isWindows = process.platform === \"win32\";\n\nconst resolveCache = new Map<string, string | null>();\n\nfunction windowsExtensions(): string[] {\n const raw = process.env.PATHEXT || \".COM;.EXE;.BAT;.CMD\";\n return raw\n .split(\";\")\n .map((ext) => ext.trim())\n .filter(Boolean);\n}\n\n// PATH is a snapshot taken at process start, so a package manager installed\n// mid-run won't be on it. We enumerate every plausible install prefix for\n// bun / npm / scoop / chocolatey so the CLI can find bun in one shot.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw\n .split(path.delimiter)\n .map((d) => d.trim())\n .filter(Boolean);\n const home = os.homedir();\n const appData = process.env.APPDATA || path.join(home, \"AppData\", \"Roaming\");\n const localAppData =\n process.env.LOCALAPPDATA || path.join(home, \"AppData\", \"Local\");\n const programFiles = process.env.ProgramFiles || \"C:\\\\Program Files\";\n const programFilesX86 =\n process.env[\"ProgramFiles(x86)\"] || \"C:\\\\Program Files (x86)\";\n\n const extra = isWindows\n ? [\n // 官方安装器\n path.join(home, \".bun\", \"bin\"),\n // npm 全局(带 .cmd shim)\n path.join(appData, \"npm\"),\n path.join(appData, \"npm\", \"node_modules\", \".bin\"),\n // 备用 bun 位置\n path.join(localAppData, \"bun\", \"bin\"),\n path.join(programFiles, \"bun\", \"bin\"),\n path.join(programFilesX86, \"bun\", \"bin\"),\n // scoop\n path.join(home, \"scoop\", \"shims\"),\n // chocolatey\n \"C:\\\\ProgramData\\\\chocolatey\\\\bin\",\n // node 自带(很多用户 npm i -g 装到 node 目录)\n path.join(programFiles, \"nodejs\"),\n path.join(programFilesX86, \"nodejs\"),\n ]\n : [\n path.join(home, \".bun\", \"bin\"),\n \"/usr/local/bin\",\n \"/opt/homebrew/bin\",\n path.join(home, \".npm-global\", \"bin\"),\n ];\n\n return [...dirs, ...extra.filter((dir) => dir && !dir.endsWith(path.sep))];\n}\n\nfunction isExecutableFile(candidate: string): boolean {\n try {\n return fs.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\nfunction searchCommandViaShell(command: string): string | null {\n if (command.includes(\"/\") || command.includes(path.sep)) return null;\n const shellCmd = isWindows ? \"where\" : \"which\";\n try {\n const result = spawnSync(shellCmd, [command], {\n encoding: \"utf-8\",\n windowsHide: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: 5000,\n });\n if (result.status === 0 && result.stdout) {\n const first = result.stdout\n .split(/\\r?\\n/)\n .map((s) => s.trim())\n .find(Boolean);\n if (first && isExecutableFile(first)) return first;\n }\n } catch {}\n return null;\n}\n\n/** 在 PATH 及常见安装目录中解析命令的完整路径,结果带缓存 */\nexport function resolveCommand(command: string): string | null {\n if (resolveCache.has(command)) return resolveCache.get(command) ?? null;\n\n let resolved: string | null = null;\n\n if (command.includes(\"/\") || command.includes(path.sep)) {\n resolved = isExecutableFile(command) ? path.resolve(command) : null;\n } else {\n const exts = isWindows ? windowsExtensions() : [\"\"];\n const hasKnownExt =\n isWindows &&\n exts.some((ext) => command.toLowerCase().endsWith(ext.toLowerCase()));\n\n outer: for (const dir of searchDirs()) {\n if (hasKnownExt) {\n const direct = path.join(dir, command);\n if (isExecutableFile(direct)) {\n resolved = direct;\n break;\n }\n continue;\n }\n for (const ext of exts) {\n const candidate = path.join(dir, command + ext);\n if (isExecutableFile(candidate)) {\n resolved = candidate;\n break outer;\n }\n }\n }\n\n if (!resolved) resolved = searchCommandViaShell(command);\n }\n\n resolveCache.set(command, resolved);\n return resolved;\n}\n\nexport function clearCommandCache(): void {\n resolveCache.clear();\n}\n\nfunction needsCmdShell(resolved: string): boolean {\n if (!isWindows) return false;\n const ext = path.extname(resolved).toLowerCase();\n return ext === \".cmd\" || ext === \".bat\";\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\n shell?: boolean | string;\n}\n\n// Windows can't CreateProcess a .cmd/.bat shim directly (npm installs bun as\n// bun.cmd), so those get routed through cmd.exe via shell: true. Previously\n// we hand-rolled a cmd.exe invocation with windowsVerbatimArguments: true,\n// but that combination misbehaves with spawnSync + stdio:\"inherit\" on\n// Node.js >= 20 (manifests as the spawned process printing \"undefined\" or\n// a spurious EINVAL), so we let Node's shell wrapper do the quoting.\n/** 生成跨平台的 spawn 参数,Windows 下 .cmd/.bat 会改经 cmd.exe 执行 */\nexport function buildSpawnPlan(command: string, args: string[]): SpawnPlan {\n const resolved = resolveCommand(command);\n\n if (!resolved) {\n return { file: command, args };\n }\n\n if (!needsCmdShell(resolved)) {\n return { file: resolved, args };\n }\n\n return {\n file: resolved,\n args,\n shell: true,\n };\n}\n\nexport interface RunCommandResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\n/** 执行命令并收集 stdout/stderr 与退出码,失败不抛异常 */\nexport function runCommand(\n command: string,\n args: string[],\n options: { cwd?: string; env?: NodeJS.ProcessEnv } = {},\n): Promise<RunCommandResult> {\n const plan = buildSpawnPlan(command, args);\n\n return new Promise((resolve) => {\n const child = spawn(plan.file, plan.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: plan.shell,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (chunk) => {\n stdout += String(chunk);\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += String(chunk);\n });\n\n child.on(\"close\", (code) => {\n resolve({ stdout, stderr, code: code ?? 1 });\n });\n child.on(\"error\", (error) => {\n resolve({\n stdout,\n stderr: `${stderr}\\n${error.message}`.trim(),\n code: 1,\n });\n });\n });\n}\n\n/** 同步执行命令并继承当前终端的输入输出,非零退出码时抛错 */\nexport function runCommandInherit(\n command: string,\n args: string[],\n options: { cwd?: string } = {},\n): void {\n const plan = buildSpawnPlan(command, args);\n const result = spawnSync(plan.file, plan.args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: plan.shell,\n });\n\n if (result.error) throw result.error;\n if (result.status !== 0) {\n throw new Error(`${command} 退出码 ${result.status}`);\n }\n}\n\n/** 判断命令是否可用 */\nexport function commandExists(command: string): boolean {\n return resolveCommand(command) !== null;\n}\n"],"mappings":"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"}
@@ -27,7 +27,7 @@ const node_os = __toESM(require("node:os"));
27
27
  const node_child_process = __toESM(require("node:child_process"));
28
28
 
29
29
  //#region package.json
30
- var version = "1.0.10";
30
+ var version = "1.1.0";
31
31
 
32
32
  //#endregion
33
33
  //#region src/internal/exec.ts
@@ -250,4 +250,4 @@ Object.defineProperty(exports, 'version', {
250
250
  return version;
251
251
  }
252
252
  });
253
- //# sourceMappingURL=exec-Cg19J7Dn.cjs.map
253
+ //# sourceMappingURL=exec-DcNz1txh.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"exec-Xxd1F2u8.js","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","args: string[]","options: { cwd?: string; env?: NodeJS.ProcessEnv }","options: { cwd?: string }"],"sources":["../package.json","../src/internal/exec.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"1.0.10\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - A plugin-based QQ bot framework\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioku\"\n ],\n \"bin\": {\n \"mioku\": \"./dist/cli/index.js\"\n },\n \"engines\": {\n \"node\": \">= 22.18.0\"\n },\n \"homepage\": \"https://github.com/mioku-lab/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/mioku-lab/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/mioku-lab/mioku.git\",\n \"directory\": \"packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"author\": \"Jerryplusy <jerryplusy@outlook.com>\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"napcat-sdk\": \"^0.16.0\",\n \"consola\": \"^3.4.2\",\n \"dayjs\": \"^1.11.19\",\n \"dedent\": \"^1.7.1\",\n \"filesize\": \"^11.0.13\",\n \"inquirer\": \"^10.0.0\",\n \"jiti\": \"^2.6.1\",\n \"lowdb\": \"^7.0.1\",\n \"mri\": \"^1.2.0\",\n \"node-cron\": \"^4.2.1\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import { spawn, spawnSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nconst isWindows = process.platform === \"win32\";\n\nconst resolveCache = new Map<string, string | null>();\n\nfunction windowsExtensions(): string[] {\n const raw = process.env.PATHEXT || \".COM;.EXE;.BAT;.CMD\";\n return raw\n .split(\";\")\n .map((ext) => ext.trim())\n .filter(Boolean);\n}\n\n// PATH is a snapshot taken at process start, so a package manager installed\n// mid-run won't be on it. We enumerate every plausible install prefix for\n// bun / npm / scoop / chocolatey so the CLI can find bun in one shot.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw\n .split(path.delimiter)\n .map((d) => d.trim())\n .filter(Boolean);\n const home = os.homedir();\n const appData = process.env.APPDATA || path.join(home, \"AppData\", \"Roaming\");\n const localAppData =\n process.env.LOCALAPPDATA || path.join(home, \"AppData\", \"Local\");\n const programFiles = process.env.ProgramFiles || \"C:\\\\Program Files\";\n const programFilesX86 =\n process.env[\"ProgramFiles(x86)\"] || \"C:\\\\Program Files (x86)\";\n\n const extra = isWindows\n ? [\n // 官方安装器\n path.join(home, \".bun\", \"bin\"),\n // npm 全局(带 .cmd shim)\n path.join(appData, \"npm\"),\n path.join(appData, \"npm\", \"node_modules\", \".bin\"),\n // 备用 bun 位置\n path.join(localAppData, \"bun\", \"bin\"),\n path.join(programFiles, \"bun\", \"bin\"),\n path.join(programFilesX86, \"bun\", \"bin\"),\n // scoop\n path.join(home, \"scoop\", \"shims\"),\n // chocolatey\n \"C:\\\\ProgramData\\\\chocolatey\\\\bin\",\n // node 自带(很多用户 npm i -g 装到 node 目录)\n path.join(programFiles, \"nodejs\"),\n path.join(programFilesX86, \"nodejs\"),\n ]\n : [\n path.join(home, \".bun\", \"bin\"),\n \"/usr/local/bin\",\n \"/opt/homebrew/bin\",\n path.join(home, \".npm-global\", \"bin\"),\n ];\n\n return [...dirs, ...extra.filter((dir) => dir && !dir.endsWith(path.sep))];\n}\n\nfunction isExecutableFile(candidate: string): boolean {\n try {\n return fs.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\nfunction searchCommandViaShell(command: string): string | null {\n if (command.includes(\"/\") || command.includes(path.sep)) return null;\n const shellCmd = isWindows ? \"where\" : \"which\";\n try {\n const result = spawnSync(shellCmd, [command], {\n encoding: \"utf-8\",\n windowsHide: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: 5000,\n });\n if (result.status === 0 && result.stdout) {\n const first = result.stdout\n .split(/\\r?\\n/)\n .map((s) => s.trim())\n .find(Boolean);\n if (first && isExecutableFile(first)) return first;\n }\n } catch {}\n return null;\n}\n\n/** 在 PATH 及常见安装目录中解析命令的完整路径,结果带缓存 */\nexport function resolveCommand(command: string): string | null {\n if (resolveCache.has(command)) return resolveCache.get(command) ?? null;\n\n let resolved: string | null = null;\n\n if (command.includes(\"/\") || command.includes(path.sep)) {\n resolved = isExecutableFile(command) ? path.resolve(command) : null;\n } else {\n const exts = isWindows ? windowsExtensions() : [\"\"];\n const hasKnownExt =\n isWindows &&\n exts.some((ext) => command.toLowerCase().endsWith(ext.toLowerCase()));\n\n outer: for (const dir of searchDirs()) {\n if (hasKnownExt) {\n const direct = path.join(dir, command);\n if (isExecutableFile(direct)) {\n resolved = direct;\n break;\n }\n continue;\n }\n for (const ext of exts) {\n const candidate = path.join(dir, command + ext);\n if (isExecutableFile(candidate)) {\n resolved = candidate;\n break outer;\n }\n }\n }\n\n if (!resolved) resolved = searchCommandViaShell(command);\n }\n\n resolveCache.set(command, resolved);\n return resolved;\n}\n\nexport function clearCommandCache(): void {\n resolveCache.clear();\n}\n\nfunction needsCmdShell(resolved: string): boolean {\n if (!isWindows) return false;\n const ext = path.extname(resolved).toLowerCase();\n return ext === \".cmd\" || ext === \".bat\";\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\n shell?: boolean | string;\n}\n\n// Windows can't CreateProcess a .cmd/.bat shim directly (npm installs bun as\n// bun.cmd), so those get routed through cmd.exe via shell: true. Previously\n// we hand-rolled a cmd.exe invocation with windowsVerbatimArguments: true,\n// but that combination misbehaves with spawnSync + stdio:\"inherit\" on\n// Node.js >= 20 (manifests as the spawned process printing \"undefined\" or\n// a spurious EINVAL), so we let Node's shell wrapper do the quoting.\n/** 生成跨平台的 spawn 参数,Windows 下 .cmd/.bat 会改经 cmd.exe 执行 */\nexport function buildSpawnPlan(command: string, args: string[]): SpawnPlan {\n const resolved = resolveCommand(command);\n\n if (!resolved) {\n return { file: command, args };\n }\n\n if (!needsCmdShell(resolved)) {\n return { file: resolved, args };\n }\n\n return {\n file: resolved,\n args,\n shell: true,\n };\n}\n\nexport interface RunCommandResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\n/** 执行命令并收集 stdout/stderr 与退出码,失败不抛异常 */\nexport function runCommand(\n command: string,\n args: string[],\n options: { cwd?: string; env?: NodeJS.ProcessEnv } = {},\n): Promise<RunCommandResult> {\n const plan = buildSpawnPlan(command, args);\n\n return new Promise((resolve) => {\n const child = spawn(plan.file, plan.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: plan.shell,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (chunk) => {\n stdout += String(chunk);\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += String(chunk);\n });\n\n child.on(\"close\", (code) => {\n resolve({ stdout, stderr, code: code ?? 1 });\n });\n child.on(\"error\", (error) => {\n resolve({\n stdout,\n stderr: `${stderr}\\n${error.message}`.trim(),\n code: 1,\n });\n });\n });\n}\n\n/** 同步执行命令并继承当前终端的输入输出,非零退出码时抛错 */\nexport function runCommandInherit(\n command: string,\n args: string[],\n options: { cwd?: string } = {},\n): void {\n const plan = buildSpawnPlan(command, args);\n const result = spawnSync(plan.file, plan.args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: plan.shell,\n });\n\n if (result.error) throw result.error;\n if (result.status !== 0) {\n throw new Error(`${command} 退出码 ${result.status}`);\n }\n}\n\n/** 判断命令是否可用 */\nexport function commandExists(command: string): boolean {\n return resolveCommand(command) !== null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"exec-DcNz1txh.cjs","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","args: string[]","options: { cwd?: string; env?: NodeJS.ProcessEnv }","options: { cwd?: string }"],"sources":["../package.json","../src/internal/exec.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"1.1.0\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - A plugin-based QQ bot framework\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioku\"\n ],\n \"bin\": {\n \"mioku\": \"./dist/cli/index.js\"\n },\n \"engines\": {\n \"node\": \">= 22.18.0\"\n },\n \"homepage\": \"https://github.com/mioku-lab/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/mioku-lab/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/mioku-lab/mioku.git\",\n \"directory\": \"packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"exports\": {\n \".\": {\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"author\": \"Jerryplusy <jerryplusy@outlook.com>\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"napcat-sdk\": \"^0.16.0\",\n \"consola\": \"^3.4.2\",\n \"dayjs\": \"^1.11.19\",\n \"dedent\": \"^1.7.1\",\n \"filesize\": \"^11.0.13\",\n \"inquirer\": \"^10.0.0\",\n \"jiti\": \"^2.6.1\",\n \"lowdb\": \"^7.0.1\",\n \"mri\": \"^1.2.0\",\n \"node-cron\": \"^4.2.1\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import { spawn, spawnSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nconst isWindows = process.platform === \"win32\";\n\nconst resolveCache = new Map<string, string | null>();\n\nfunction windowsExtensions(): string[] {\n const raw = process.env.PATHEXT || \".COM;.EXE;.BAT;.CMD\";\n return raw\n .split(\";\")\n .map((ext) => ext.trim())\n .filter(Boolean);\n}\n\n// PATH is a snapshot taken at process start, so a package manager installed\n// mid-run won't be on it. We enumerate every plausible install prefix for\n// bun / npm / scoop / chocolatey so the CLI can find bun in one shot.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw\n .split(path.delimiter)\n .map((d) => d.trim())\n .filter(Boolean);\n const home = os.homedir();\n const appData = process.env.APPDATA || path.join(home, \"AppData\", \"Roaming\");\n const localAppData =\n process.env.LOCALAPPDATA || path.join(home, \"AppData\", \"Local\");\n const programFiles = process.env.ProgramFiles || \"C:\\\\Program Files\";\n const programFilesX86 =\n process.env[\"ProgramFiles(x86)\"] || \"C:\\\\Program Files (x86)\";\n\n const extra = isWindows\n ? [\n // 官方安装器\n path.join(home, \".bun\", \"bin\"),\n // npm 全局(带 .cmd shim)\n path.join(appData, \"npm\"),\n path.join(appData, \"npm\", \"node_modules\", \".bin\"),\n // 备用 bun 位置\n path.join(localAppData, \"bun\", \"bin\"),\n path.join(programFiles, \"bun\", \"bin\"),\n path.join(programFilesX86, \"bun\", \"bin\"),\n // scoop\n path.join(home, \"scoop\", \"shims\"),\n // chocolatey\n \"C:\\\\ProgramData\\\\chocolatey\\\\bin\",\n // node 自带(很多用户 npm i -g 装到 node 目录)\n path.join(programFiles, \"nodejs\"),\n path.join(programFilesX86, \"nodejs\"),\n ]\n : [\n path.join(home, \".bun\", \"bin\"),\n \"/usr/local/bin\",\n \"/opt/homebrew/bin\",\n path.join(home, \".npm-global\", \"bin\"),\n ];\n\n return [...dirs, ...extra.filter((dir) => dir && !dir.endsWith(path.sep))];\n}\n\nfunction isExecutableFile(candidate: string): boolean {\n try {\n return fs.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\nfunction searchCommandViaShell(command: string): string | null {\n if (command.includes(\"/\") || command.includes(path.sep)) return null;\n const shellCmd = isWindows ? \"where\" : \"which\";\n try {\n const result = spawnSync(shellCmd, [command], {\n encoding: \"utf-8\",\n windowsHide: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n timeout: 5000,\n });\n if (result.status === 0 && result.stdout) {\n const first = result.stdout\n .split(/\\r?\\n/)\n .map((s) => s.trim())\n .find(Boolean);\n if (first && isExecutableFile(first)) return first;\n }\n } catch {}\n return null;\n}\n\n/** 在 PATH 及常见安装目录中解析命令的完整路径,结果带缓存 */\nexport function resolveCommand(command: string): string | null {\n if (resolveCache.has(command)) return resolveCache.get(command) ?? null;\n\n let resolved: string | null = null;\n\n if (command.includes(\"/\") || command.includes(path.sep)) {\n resolved = isExecutableFile(command) ? path.resolve(command) : null;\n } else {\n const exts = isWindows ? windowsExtensions() : [\"\"];\n const hasKnownExt =\n isWindows &&\n exts.some((ext) => command.toLowerCase().endsWith(ext.toLowerCase()));\n\n outer: for (const dir of searchDirs()) {\n if (hasKnownExt) {\n const direct = path.join(dir, command);\n if (isExecutableFile(direct)) {\n resolved = direct;\n break;\n }\n continue;\n }\n for (const ext of exts) {\n const candidate = path.join(dir, command + ext);\n if (isExecutableFile(candidate)) {\n resolved = candidate;\n break outer;\n }\n }\n }\n\n if (!resolved) resolved = searchCommandViaShell(command);\n }\n\n resolveCache.set(command, resolved);\n return resolved;\n}\n\nexport function clearCommandCache(): void {\n resolveCache.clear();\n}\n\nfunction needsCmdShell(resolved: string): boolean {\n if (!isWindows) return false;\n const ext = path.extname(resolved).toLowerCase();\n return ext === \".cmd\" || ext === \".bat\";\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\n shell?: boolean | string;\n}\n\n// Windows can't CreateProcess a .cmd/.bat shim directly (npm installs bun as\n// bun.cmd), so those get routed through cmd.exe via shell: true. Previously\n// we hand-rolled a cmd.exe invocation with windowsVerbatimArguments: true,\n// but that combination misbehaves with spawnSync + stdio:\"inherit\" on\n// Node.js >= 20 (manifests as the spawned process printing \"undefined\" or\n// a spurious EINVAL), so we let Node's shell wrapper do the quoting.\n/** 生成跨平台的 spawn 参数,Windows 下 .cmd/.bat 会改经 cmd.exe 执行 */\nexport function buildSpawnPlan(command: string, args: string[]): SpawnPlan {\n const resolved = resolveCommand(command);\n\n if (!resolved) {\n return { file: command, args };\n }\n\n if (!needsCmdShell(resolved)) {\n return { file: resolved, args };\n }\n\n return {\n file: resolved,\n args,\n shell: true,\n };\n}\n\nexport interface RunCommandResult {\n stdout: string;\n stderr: string;\n code: number;\n}\n\n/** 执行命令并收集 stdout/stderr 与退出码,失败不抛异常 */\nexport function runCommand(\n command: string,\n args: string[],\n options: { cwd?: string; env?: NodeJS.ProcessEnv } = {},\n): Promise<RunCommandResult> {\n const plan = buildSpawnPlan(command, args);\n\n return new Promise((resolve) => {\n const child = spawn(plan.file, plan.args, {\n cwd: options.cwd,\n env: options.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: plan.shell,\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout?.on(\"data\", (chunk) => {\n stdout += String(chunk);\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += String(chunk);\n });\n\n child.on(\"close\", (code) => {\n resolve({ stdout, stderr, code: code ?? 1 });\n });\n child.on(\"error\", (error) => {\n resolve({\n stdout,\n stderr: `${stderr}\\n${error.message}`.trim(),\n code: 1,\n });\n });\n });\n}\n\n/** 同步执行命令并继承当前终端的输入输出,非零退出码时抛错 */\nexport function runCommandInherit(\n command: string,\n args: string[],\n options: { cwd?: string } = {},\n): void {\n const plan = buildSpawnPlan(command, args);\n const result = spawnSync(plan.file, plan.args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: plan.shell,\n });\n\n if (result.error) throw result.error;\n if (result.status !== 0) {\n throw new Error(`${command} 退出码 ${result.status}`);\n }\n}\n\n/** 判断命令是否可用 */\nexport function commandExists(command: string): boolean {\n return resolveCommand(command) !== null;\n}\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_exec = require('./exec-Cg19J7Dn.cjs');
1
+ const require_exec = require('./exec-DcNz1txh.cjs');
2
2
  const node_fs = require_exec.__toESM(require("node:fs"));
3
3
  const node_path = require_exec.__toESM(require("node:path"));
4
4
  const node_url = require_exec.__toESM(require("node:url"));
@@ -2685,6 +2685,16 @@ var CommandManager = class {
2685
2685
  setAccessControl(config) {
2686
2686
  this.#access = config;
2687
2687
  }
2688
+ canUsePlugin(plugin, event) {
2689
+ return this.#pluginAllowed(plugin, event);
2690
+ }
2691
+ canUseCommand(plugin, command, event) {
2692
+ const registered = this.#resolveRegistered(plugin, command);
2693
+ if (registered) return this.#canUse(registered, event);
2694
+ const key = commandKey$1(command);
2695
+ const action = this.#resolveAction(plugin, key, event) ?? this.#resolveAction(plugin, command, event);
2696
+ return action !== "block";
2697
+ }
2688
2698
  syncMetadata(metadata) {
2689
2699
  this.#legacy.set(metadata.name, { metadata });
2690
2700
  }
@@ -2718,6 +2728,7 @@ var CommandManager = class {
2718
2728
  seen.add(key);
2719
2729
  commands.push({
2720
2730
  cmd,
2731
+ id: runtimeCommand.id,
2721
2732
  desc: runtimeCommand.description || command.desc || cmd,
2722
2733
  usage: runtimeCommand.usage ?? command.usage,
2723
2734
  role: runtimeCommand.permission
@@ -2733,6 +2744,7 @@ var CommandManager = class {
2733
2744
  seen.add(commandKey$1(cmd));
2734
2745
  commands.push({
2735
2746
  cmd,
2747
+ id: command.id,
2736
2748
  desc: command.description || cmd,
2737
2749
  usage: command.usage,
2738
2750
  role: command.permission
@@ -2871,6 +2883,13 @@ var CommandManager = class {
2871
2883
  }
2872
2884
  return void 0;
2873
2885
  }
2886
+ #resolveRegistered(plugin, ref) {
2887
+ const raw = String(ref ?? "").trim();
2888
+ if (!raw) return void 0;
2889
+ const key = commandKey$1(raw);
2890
+ const candidates = this.#commands.filter((item) => item.plugin === plugin);
2891
+ return candidates.find((item) => item.id === raw) ?? candidates.find((item) => item.name === raw) ?? candidates.find((item) => item.aliases.includes(raw)) ?? candidates.find((item) => commandKey$1(item.id) === key) ?? candidates.find((item) => commandKey$1(item.name) === key) ?? candidates.find((item) => item.aliases.some((alias) => commandKey$1(alias) === key));
2892
+ }
2874
2893
  #canUse(command, event) {
2875
2894
  const userId = userIdOf(event);
2876
2895
  const master = Boolean(userId && this.#isMaster(userId));
@@ -2962,6 +2981,45 @@ const resetPluginMetadata = () => {
2962
2981
  getActiveCommandManager()?.clear();
2963
2982
  };
2964
2983
 
2984
+ //#endregion
2985
+ //#region src/runtime/plugin-artifacts.ts
2986
+ const commandKey = (value) => String(value).trim().replace(/^[#/.]+\s*/, "").split(/\s+/)[0].toLowerCase();
2987
+ async function registerPluginArtifacts(ctx) {
2988
+ const helpService = ctx ? getService(ctx, Services.Help) : servicesRegistry["help"];
2989
+ const plugins = getPluginMetadataList();
2990
+ const commandManager = getActiveCommandManager();
2991
+ const metadataByName = new Map(plugins.map((meta) => [meta.name, meta]));
2992
+ const pluginNames = new Set([...metadataByName.keys(), ...(commandManager?.catalog() ?? []).filter((item) => item.kind === "plugin").map((item) => item.plugin)]);
2993
+ if (helpService) {
2994
+ for (const name of [...helpService.getAllHelp().keys()]) if (!pluginNames.has(name)) helpService.unregisterHelp(name);
2995
+ }
2996
+ let helpCount = 0;
2997
+ for (const pluginName of pluginNames) {
2998
+ const meta = metadataByName.get(pluginName);
2999
+ const generated = commandManager?.getPluginHelp(pluginName) ?? meta?.config?.help;
3000
+ const existing = helpService?.getHelp(pluginName);
3001
+ const help = generated ? {
3002
+ ...generated,
3003
+ title: existing?.title || generated.title,
3004
+ description: existing?.description || generated.description,
3005
+ commands: [...existing?.commands ?? [], ...generated.commands.filter((command) => {
3006
+ const key = commandKey(command.cmd);
3007
+ return !(existing?.commands ?? []).some((item) => commandKey(item.cmd) === key);
3008
+ })]
3009
+ } : existing;
3010
+ if (help) if (helpService) {
3011
+ helpService.registerHelp(pluginName, help);
3012
+ helpCount++;
3013
+ } else rootLogger.warn(`[plugin-artifacts] 帮助服务未加载,跳过插件 "${pluginName}" 的帮助注册`);
3014
+ const required = meta?.config?.services;
3015
+ if (required && required.length > 0) {
3016
+ const missing = required.filter((name) => !servicesRegistry[name]);
3017
+ if (missing.length > 0) rootLogger.warn(`插件 "${pluginName}" 声明依赖服务 [${missing.join(", ")}],但它们未加载`);
3018
+ }
3019
+ }
3020
+ rootLogger.info(`[plugin-artifacts] 已处理 ${pluginNames.size} 个插件,注册帮助 ${helpCount} 个`);
3021
+ }
3022
+
2965
3023
  //#endregion
2966
3024
  //#region src/runtime/plugin-state.ts
2967
3025
  const store = getOrCreate("plugin-runtime-state", () => ({}));
@@ -4092,17 +4150,19 @@ function triggerRestart(marker) {
4092
4150
  function formatUptime(ms) {
4093
4151
  return formatDuration(ms);
4094
4152
  }
4095
- async function waitForBot(timeoutMs = 6e4) {
4153
+ async function waitForBot(timeoutMs = 6e4, adapter, botId) {
4096
4154
  const deadline = Date.now() + timeoutMs;
4097
4155
  while (Date.now() < deadline) {
4098
4156
  const bots = Array.from(connectedBots.values());
4099
- if (bots.length > 0) return bots[0];
4157
+ const matched = bots.find((bot) => (adapter ? bot.adapter === adapter : true) && (botId ? String(bot.bot_id) === botId : true));
4158
+ if (matched) return matched;
4159
+ if (!adapter && !botId && bots.length > 0) return bots[0];
4100
4160
  await new Promise((resolve) => setTimeout(resolve, 2e3));
4101
4161
  }
4102
4162
  return null;
4103
4163
  }
4104
4164
  async function notifyRestartComplete(ctx, marker) {
4105
- const bot = await waitForBot();
4165
+ const bot = await waitForBot(6e4, marker.adapter, marker.selfId);
4106
4166
  if (!bot) {
4107
4167
  rootLogger.warn("[core] 重启完成但未等到 bot 上线,跳过通知");
4108
4168
  return;
@@ -4135,9 +4195,10 @@ function getPendingMap() {
4135
4195
  return state[RUNTIME_KEY];
4136
4196
  }
4137
4197
  function conversationKey(event) {
4138
- const selfId = Number(event?.self_id || 0);
4139
- if (event?.message_type === "group" && event?.group_id) return `${selfId}:g:${event.group_id}`;
4140
- return `${selfId}:p:${event?.user_id || 0}`;
4198
+ const selfId = String(event?.self_id ?? "");
4199
+ const adapter = String(event?.bot?.adapter ?? "");
4200
+ if (event?.message_type === "group" && event?.group_id) return `${adapter}:${selfId}:g:${String(event.group_id)}`;
4201
+ return `${adapter}:${selfId}:p:${String(event?.user_id ?? "")}`;
4141
4202
  }
4142
4203
  function typeLabel$1(type) {
4143
4204
  if (type === "plugin") return "plugin";
@@ -4198,14 +4259,15 @@ async function performUpdateAndReport(ctx, event, names) {
4198
4259
  if (unchanged.length > 0) parts.push("", `另有 ${unchanged.length} 个包已是最新`);
4199
4260
  parts.push("", "即将重启...");
4200
4261
  await replyText(event, parts.join("\n"));
4201
- const selfId = Number(event?.self_id || 0);
4202
- const groupId = event?.message_type === "group" && event?.group_id ? Number(event.group_id) : null;
4203
- const userId = Number(event?.user_id || 0);
4262
+ const selfId = String(event?.self_id ?? "");
4263
+ const groupId = event?.message_type === "group" && event?.group_id ? String(event.group_id) : null;
4264
+ const userId = String(event?.user_id ?? "");
4204
4265
  const marker = {
4205
4266
  initiatedAt: Date.now(),
4206
4267
  selfId,
4207
4268
  groupId,
4208
- userId
4269
+ userId,
4270
+ adapter: event?.bot?.adapter
4209
4271
  };
4210
4272
  triggerRestart(marker);
4211
4273
  }
@@ -4462,16 +4524,17 @@ function registerRestartCommand(ctx) {
4462
4524
  priority: -1e3,
4463
4525
  description: "重启机器人进程",
4464
4526
  handler: async ({ event }) => {
4465
- if (event?.user_id === event?.self_id) return;
4527
+ if (String(event?.user_id ?? "") === String(event?.self_id ?? "")) return;
4466
4528
  const uptimeMs = process.uptime() * 1e3;
4467
- const selfId = Number(event?.self_id || 0);
4468
- const groupId = event?.message_type === "group" && event?.group_id ? Number(event.group_id) : null;
4469
- const userId = Number(event?.user_id || 0);
4529
+ const selfId = String(event?.self_id ?? "");
4530
+ const groupId = event?.message_type === "group" && event?.group_id ? String(event.group_id) : null;
4531
+ const userId = String(event?.user_id ?? "");
4470
4532
  const marker = {
4471
4533
  initiatedAt: Date.now(),
4472
4534
  selfId,
4473
4535
  groupId,
4474
- userId
4536
+ userId,
4537
+ adapter: event?.bot?.adapter
4475
4538
  };
4476
4539
  try {
4477
4540
  await replyText(event, `Bot已运行${formatUptime(uptimeMs)},正在重启...`);
@@ -4646,9 +4709,9 @@ function startAutoUpdateScheduler(enabled, time, frequency) {
4646
4709
  rootLogger.info("[core] 自动更新成功,准备重启...");
4647
4710
  const marker = {
4648
4711
  initiatedAt: Date.now(),
4649
- selfId: 0,
4712
+ selfId: "",
4650
4713
  groupId: null,
4651
- userId: 0
4714
+ userId: ""
4652
4715
  };
4653
4716
  triggerRestart(marker);
4654
4717
  } catch (error) {
@@ -5224,6 +5287,7 @@ const HELP_KEYS = new Set([
5224
5287
  ]);
5225
5288
  const HELP_COMMAND_KEYS = new Set([
5226
5289
  "cmd",
5290
+ "id",
5227
5291
  "desc",
5228
5292
  "usage",
5229
5293
  "role"
@@ -5269,6 +5333,7 @@ function validateHelp(value, pluginName) {
5269
5333
  }
5270
5334
  commands.push({
5271
5335
  cmd: cmdName,
5336
+ id: typeof cmd.id === "string" && cmd.id.trim() ? cmd.id.trim() : void 0,
5272
5337
  desc,
5273
5338
  usage: typeof cmd.usage === "string" ? cmd.usage : void 0,
5274
5339
  role: typeof cmd.role === "string" ? cmd.role : void 0
@@ -5680,6 +5745,7 @@ var MiokuRuntime = class {
5680
5745
  const plugin = await loadLocalPlugin(jiti$1, name, local.absPath);
5681
5746
  await this.#loadPlugin(plugin, "external");
5682
5747
  setPluginMetadata(buildPluginMetadata(name, local.absPath, pkg));
5748
+ await this.#refreshPluginArtifacts();
5683
5749
  return;
5684
5750
  }
5685
5751
  const candidates = discoverPluginCandidates(this.#cwd, appPkg);
@@ -5688,6 +5754,7 @@ var MiokuRuntime = class {
5688
5754
  const plugin = await loadNpmPlugin(jiti$1, candidate);
5689
5755
  await this.#loadPlugin(plugin, "external");
5690
5756
  setPluginMetadata(buildPluginMetadata(candidate.name, candidate.resolvedPath, candidate.packageJson));
5757
+ await this.#refreshPluginArtifacts();
5691
5758
  return;
5692
5759
  }
5693
5760
  throw new Error(`插件 ${name} 不存在`);
@@ -5705,6 +5772,7 @@ var MiokuRuntime = class {
5705
5772
  this.#enabledPlugins.delete(key);
5706
5773
  removePluginMetadata(name);
5707
5774
  }
5775
+ await this.#refreshPluginArtifacts();
5708
5776
  this.#logger.info(`禁用插件 => ${name}`);
5709
5777
  }
5710
5778
  async reloadPlugin(name) {
@@ -5720,11 +5788,20 @@ var MiokuRuntime = class {
5720
5788
  await this.#enabledPlugins.get(`builtin:${name}`)?.cleanup?.();
5721
5789
  this.#enabledPlugins.delete(`builtin:${name}`);
5722
5790
  await this.#loadPlugin(plugin, "builtin");
5791
+ await this.#refreshPluginArtifacts();
5723
5792
  return;
5724
5793
  }
5725
5794
  await this.disablePlugin(name);
5726
5795
  await this.enablePlugin(name);
5727
5796
  }
5797
+ /** 插件增删后同步帮助注册表;失败只告警,不能影响插件本身 */
5798
+ async #refreshPluginArtifacts() {
5799
+ try {
5800
+ await registerPluginArtifacts();
5801
+ } catch (error) {
5802
+ this.#logger.warn(`刷新插件帮助注册表失败: ${error}`);
5803
+ }
5804
+ }
5728
5805
  async #emitLifecycle(event) {
5729
5806
  const lifecycleEvent = {
5730
5807
  kind: "adapter",
@@ -6075,42 +6152,6 @@ const createRuntime = (options) => {
6075
6152
  return new MiokuRuntime(options);
6076
6153
  };
6077
6154
 
6078
- //#endregion
6079
- //#region src/runtime/plugin-artifacts.ts
6080
- const commandKey = (value) => String(value).trim().replace(/^[#/.]+\s*/, "").split(/\s+/)[0].toLowerCase();
6081
- async function registerPluginArtifacts(ctx) {
6082
- const helpService = ctx ? getService(ctx, Services.Help) : servicesRegistry["help"];
6083
- const plugins = getPluginMetadataList();
6084
- const commandManager = getActiveCommandManager();
6085
- const metadataByName = new Map(plugins.map((meta) => [meta.name, meta]));
6086
- const pluginNames = new Set([...metadataByName.keys(), ...(commandManager?.catalog() ?? []).filter((item) => item.kind === "plugin").map((item) => item.plugin)]);
6087
- let helpCount = 0;
6088
- for (const pluginName of pluginNames) {
6089
- const meta = metadataByName.get(pluginName);
6090
- const generated = commandManager?.getPluginHelp(pluginName) ?? meta?.config?.help;
6091
- const existing = helpService?.getHelp(pluginName);
6092
- const help = generated ? {
6093
- ...generated,
6094
- title: existing?.title || generated.title,
6095
- description: existing?.description || generated.description,
6096
- commands: [...existing?.commands ?? [], ...generated.commands.filter((command) => {
6097
- const key = commandKey(command.cmd);
6098
- return !(existing?.commands ?? []).some((item) => commandKey(item.cmd) === key);
6099
- })]
6100
- } : existing;
6101
- if (help) if (helpService) {
6102
- helpService.registerHelp(pluginName, help);
6103
- helpCount++;
6104
- } else rootLogger.warn(`[plugin-artifacts] 帮助服务未加载,跳过插件 "${pluginName}" 的帮助注册`);
6105
- const required = meta?.config?.services;
6106
- if (required && required.length > 0) {
6107
- const missing = required.filter((name) => !servicesRegistry[name]);
6108
- if (missing.length > 0) rootLogger.warn(`插件 "${pluginName}" 声明依赖服务 [${missing.join(", ")}],但它们未加载`);
6109
- }
6110
- }
6111
- rootLogger.info(`[plugin-artifacts] 已处理 ${pluginNames.size} 个插件,注册帮助 ${helpCount} 个`);
6112
- }
6113
-
6114
6155
  //#endregion
6115
6156
  //#region src/start.ts
6116
6157
  /** 启动 mioku 运行时:加载服务、拉起适配器与插件,返回用于优雅停机的 stop */