mioku 1.0.0 → 1.0.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.
- package/dist/cli/index.cjs +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/{exec-gpip41w9.cjs → exec-B2aL-jrd.cjs} +2 -2
- package/dist/{exec-gpip41w9.cjs.map → exec-B2aL-jrd.cjs.map} +1 -1
- package/dist/{exec-CUvS9y6X.js → exec-DGQCm_XV.js} +2 -2
- package/dist/{exec-CUvS9y6X.js.map → exec-DGQCm_XV.js.map} +1 -1
- package/dist/index.cjs +146 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +77 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_exec = require('../exec-
|
|
2
|
+
const require_exec = require('../exec-B2aL-jrd.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-
|
|
2
|
+
import { clearCommandCache, commandExists, resolveCommand, runCommandInherit, version } from "../exec-DGQCm_XV.js";
|
|
3
3
|
import fs, { readFileSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import mri from "mri";
|
|
@@ -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.
|
|
30
|
+
var version = "1.0.1";
|
|
31
31
|
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region src/internal/exec.ts
|
|
@@ -229,4 +229,4 @@ Object.defineProperty(exports, 'version', {
|
|
|
229
229
|
return version;
|
|
230
230
|
}
|
|
231
231
|
});
|
|
232
|
-
//# sourceMappingURL=exec-
|
|
232
|
+
//# sourceMappingURL=exec-B2aL-jrd.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec-gpip41w9.cjs","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","arg: 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.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. These are the standard install prefixes for bun and\n// for npm's global bin, which is where `npm i -g bun` actually lands.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw.split(path.delimiter).map((d) => d.trim()).filter(Boolean);\n const home = os.homedir();\n\n const extra = isWindows\n ? [\n path.join(home, \".bun\", \"bin\"),\n path.join(process.env.APPDATA || \"\", \"npm\"),\n path.join(process.env.ProgramFiles || \"\", \"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\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 && 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\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\n// cmd.exe argument quoting: escape embedded quotes and any run of backslashes\n// that precedes a quote, then wrap the whole thing so metacharacters inside\n// (&, |, <, >, ^) are inert.\nfunction quoteForCmd(arg: string): string {\n if (arg === \"\") return '\"\"';\n const escaped = arg\n .replace(/(\\\\*)\"/g, '$1$1\\\\\"')\n .replace(/(\\\\+)$/, \"$1$1\");\n return `\"${escaped}\"`;\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\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 with hand-quoted arguments\n// rather than shell: true, which would leave the args unquoted.\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 const comspec = process.env.ComSpec || process.env.COMSPEC || \"cmd.exe\";\n const line = [resolved, ...args].map(quoteForCmd).join(\" \");\n return {\n file: comspec,\n args: [\"/d\", \"/s\", \"/c\", `\"${line}\"`],\n windowsVerbatimArguments: 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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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-B2aL-jrd.cjs","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","arg: 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.1\",\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. These are the standard install prefixes for bun and\n// for npm's global bin, which is where `npm i -g bun` actually lands.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw.split(path.delimiter).map((d) => d.trim()).filter(Boolean);\n const home = os.homedir();\n\n const extra = isWindows\n ? [\n path.join(home, \".bun\", \"bin\"),\n path.join(process.env.APPDATA || \"\", \"npm\"),\n path.join(process.env.ProgramFiles || \"\", \"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\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 && 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\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\n// cmd.exe argument quoting: escape embedded quotes and any run of backslashes\n// that precedes a quote, then wrap the whole thing so metacharacters inside\n// (&, |, <, >, ^) are inert.\nfunction quoteForCmd(arg: string): string {\n if (arg === \"\") return '\"\"';\n const escaped = arg\n .replace(/(\\\\*)\"/g, '$1$1\\\\\"')\n .replace(/(\\\\+)$/, \"$1$1\");\n return `\"${escaped}\"`;\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\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 with hand-quoted arguments\n// rather than shell: true, which would leave the args unquoted.\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 const comspec = process.env.ComSpec || process.env.COMSPEC || \"cmd.exe\";\n const line = [resolved, ...args].map(quoteForCmd).join(\" \");\n return {\n file: comspec,\n args: [\"/d\", \"/s\", \"/c\", `\"${line}\"`],\n windowsVerbatimArguments: 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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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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"}
|
|
@@ -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.
|
|
7
|
+
var version = "1.0.1";
|
|
8
8
|
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/internal/exec.ts
|
|
@@ -159,4 +159,4 @@ function commandExists(command) {
|
|
|
159
159
|
|
|
160
160
|
//#endregion
|
|
161
161
|
export { buildSpawnPlan, clearCommandCache, commandExists, resolveCommand, runCommand, runCommandInherit, version };
|
|
162
|
-
//# sourceMappingURL=exec-
|
|
162
|
+
//# sourceMappingURL=exec-DGQCm_XV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec-CUvS9y6X.js","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","arg: 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.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. These are the standard install prefixes for bun and\n// for npm's global bin, which is where `npm i -g bun` actually lands.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw.split(path.delimiter).map((d) => d.trim()).filter(Boolean);\n const home = os.homedir();\n\n const extra = isWindows\n ? [\n path.join(home, \".bun\", \"bin\"),\n path.join(process.env.APPDATA || \"\", \"npm\"),\n path.join(process.env.ProgramFiles || \"\", \"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\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 && 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\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\n// cmd.exe argument quoting: escape embedded quotes and any run of backslashes\n// that precedes a quote, then wrap the whole thing so metacharacters inside\n// (&, |, <, >, ^) are inert.\nfunction quoteForCmd(arg: string): string {\n if (arg === \"\") return '\"\"';\n const escaped = arg\n .replace(/(\\\\*)\"/g, '$1$1\\\\\"')\n .replace(/(\\\\+)$/, \"$1$1\");\n return `\"${escaped}\"`;\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\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 with hand-quoted arguments\n// rather than shell: true, which would leave the args unquoted.\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 const comspec = process.env.ComSpec || process.env.COMSPEC || \"cmd.exe\";\n const line = [resolved, ...args].map(quoteForCmd).join(\" \");\n return {\n file: comspec,\n args: [\"/d\", \"/s\", \"/c\", `\"${line}\"`],\n windowsVerbatimArguments: 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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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-DGQCm_XV.js","names":["path","candidate: string","command: string","resolved: string | null","resolved: string","arg: 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.1\",\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. These are the standard install prefixes for bun and\n// for npm's global bin, which is where `npm i -g bun` actually lands.\nfunction searchDirs(): string[] {\n const raw = process.env.PATH || process.env.Path || \"\";\n const dirs = raw.split(path.delimiter).map((d) => d.trim()).filter(Boolean);\n const home = os.homedir();\n\n const extra = isWindows\n ? [\n path.join(home, \".bun\", \"bin\"),\n path.join(process.env.APPDATA || \"\", \"npm\"),\n path.join(process.env.ProgramFiles || \"\", \"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\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 && 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\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\n// cmd.exe argument quoting: escape embedded quotes and any run of backslashes\n// that precedes a quote, then wrap the whole thing so metacharacters inside\n// (&, |, <, >, ^) are inert.\nfunction quoteForCmd(arg: string): string {\n if (arg === \"\") return '\"\"';\n const escaped = arg\n .replace(/(\\\\*)\"/g, '$1$1\\\\\"')\n .replace(/(\\\\+)$/, \"$1$1\");\n return `\"${escaped}\"`;\n}\n\nexport interface SpawnPlan {\n file: string;\n args: string[];\n windowsVerbatimArguments?: boolean;\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 with hand-quoted arguments\n// rather than shell: true, which would leave the args unquoted.\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 const comspec = process.env.ComSpec || process.env.COMSPEC || \"cmd.exe\";\n const line = [resolved, ...args].map(quoteForCmd).join(\" \");\n return {\n file: comspec,\n args: [\"/d\", \"/s\", \"/c\", `\"${line}\"`],\n windowsVerbatimArguments: 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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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 windowsVerbatimArguments: plan.windowsVerbatimArguments,\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":";;;;;;cAGa;;;;ACEb,MAAM,YAAY,QAAQ,aAAa;AAEvC,MAAM,eAAe,IAAI;AAEzB,SAAS,oBAA8B;CACrC,MAAM,MAAM,QAAQ,IAAI,WAAW;AACnC,QAAO,IACJ,MAAM,KAAK,CACX,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,CACxB,OAAO,QAAQ;AACnB;AAKD,SAAS,aAAuB;CAC9B,MAAM,MAAM,QAAQ,IAAI,QAAQ,QAAQ,IAAI,QAAQ;CACpD,MAAM,OAAO,IAAI,MAAMA,OAAK,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ;CAC3E,MAAM,OAAO,KAAG,SAAS;CAEzB,MAAM,QAAQ,YACV;EACE,OAAK,KAAK,MAAM,QAAQ,MAAM;EAC9B,OAAK,KAAK,QAAQ,IAAI,WAAW,IAAI,MAAM;EAC3C,OAAK,KAAK,QAAQ,IAAI,gBAAgB,IAAI,SAAS;CACpD,IACD;EACE,OAAK,KAAK,MAAM,QAAQ,MAAM;EAC9B;EACA;EACA,OAAK,KAAK,MAAM,eAAe,MAAM;CACtC;AAEL,QAAO,CAAC,GAAG,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,QAAQ,IAAI,SAASA,OAAK,IAAI,CAAC,AAAC;AAC3E;AAED,SAAS,iBAAiBC,WAA4B;AACpD,KAAI;AACF,SAAO,KAAG,SAAS,UAAU,CAAC,QAAQ;CACvC,QAAO;AACN,SAAO;CACR;AACF;;AAGD,SAAgB,eAAeC,SAAgC;AAC7D,KAAI,aAAa,IAAI,QAAQ,CAAE,QAAO,aAAa,IAAI,QAAQ,IAAI;CAEnE,IAAIC,WAA0B;AAE9B,KAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAASH,OAAK,IAAI,CACrD,YAAW,iBAAiB,QAAQ,GAAG,OAAK,QAAQ,QAAQ,GAAG;MAC1D;EACL,MAAM,OAAO,YAAY,mBAAmB,GAAG,CAAC,EAAG;EACnD,MAAM,cACJ,aAAa,KAAK,KAAK,CAAC,QAAQ,QAAQ,aAAa,CAAC,SAAS,IAAI,aAAa,CAAC,CAAC;AAEpF,QAAO,MAAK,MAAM,OAAO,YAAY,EAAE;AACrC,OAAI,aAAa;IACf,MAAM,SAAS,OAAK,KAAK,KAAK,QAAQ;AACtC,QAAI,iBAAiB,OAAO,EAAE;AAC5B,gBAAW;AACX;IACD;AACD;GACD;AACD,QAAK,MAAM,OAAO,MAAM;IACtB,MAAM,YAAY,OAAK,KAAK,KAAK,UAAU,IAAI;AAC/C,QAAI,iBAAiB,UAAU,EAAE;AAC/B,gBAAW;AACX,WAAM;IACP;GACF;EACF;CACF;AAED,cAAa,IAAI,SAAS,SAAS;AACnC,QAAO;AACR;AAED,SAAgB,oBAA0B;AACxC,cAAa,OAAO;AACrB;AAED,SAAS,cAAcI,UAA2B;AAChD,MAAK,UAAW,QAAO;CACvB,MAAM,MAAM,OAAK,QAAQ,SAAS,CAAC,aAAa;AAChD,QAAO,QAAQ,UAAU,QAAQ;AAClC;AAKD,SAAS,YAAYC,KAAqB;AACxC,KAAI,QAAQ,GAAI,QAAO;CACvB,MAAM,UAAU,IACb,QAAQ,WAAW,WAAU,CAC7B,QAAQ,UAAU,OAAO;AAC5B,SAAQ,GAAG,QAAQ;AACpB;;AAYD,SAAgB,eAAeH,SAAiBI,MAA2B;CACzE,MAAM,WAAW,eAAe,QAAQ;AAExC,MAAK,SACH,QAAO;EAAE,MAAM;EAAS;CAAM;AAGhC,MAAK,cAAc,SAAS,CAC1B,QAAO;EAAE,MAAM;EAAU;CAAM;CAGjC,MAAM,UAAU,QAAQ,IAAI,WAAW,QAAQ,IAAI,WAAW;CAC9D,MAAM,OAAO,CAAC,UAAU,GAAG,IAAK,EAAC,IAAI,YAAY,CAAC,KAAK,IAAI;AAC3D,QAAO;EACL,MAAM;EACN,MAAM;GAAC;GAAM;GAAM;IAAO,GAAG,KAAK;EAAG;EACrC,0BAA0B;CAC3B;AACF;;AASD,SAAgB,WACdJ,SACAI,MACAC,UAAqD,CAAE,GAC5B;CAC3B,MAAM,OAAO,eAAe,SAAS,KAAK;AAE1C,QAAO,IAAI,QAAQ,CAAC,YAAY;EAC9B,MAAM,QAAQ,MAAM,KAAK,MAAM,KAAK,MAAM;GACxC,KAAK,QAAQ;GACb,KAAK,QAAQ;GACb,OAAO;IAAC;IAAU;IAAQ;GAAO;GACjC,0BAA0B,KAAK;EAChC,EAAC;EAEF,IAAI,SAAS;EACb,IAAI,SAAS;AAEb,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,aAAU,OAAO,MAAM;EACxB,EAAC;AACF,QAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,aAAU,OAAO,MAAM;EACxB,EAAC;AAEF,QAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,WAAQ;IAAE;IAAQ;IAAQ,MAAM,QAAQ;GAAG,EAAC;EAC7C,EAAC;AACF,QAAM,GAAG,SAAS,CAAC,UAAU;AAC3B,WAAQ;IACN;IACA,QAAQ,CAAC,EAAE,OAAO,IAAI,MAAM,QAAQ,EAAE,MAAM;IAC5C,MAAM;GACP,EAAC;EACH,EAAC;CACH;AACF;;AAGD,SAAgB,kBACdL,SACAI,MACAE,UAA4B,CAAE,GACxB;CACN,MAAM,OAAO,eAAe,SAAS,KAAK;CAC1C,MAAM,SAAS,UAAU,KAAK,MAAM,KAAK,MAAM;EAC7C,KAAK,QAAQ;EACb,OAAO;EACP,0BAA0B,KAAK;CAChC,EAAC;AAEF,KAAI,OAAO,MAAO,OAAM,OAAO;AAC/B,KAAI,OAAO,WAAW,EACpB,OAAM,IAAI,OAAO,EAAE,QAAQ,OAAO,OAAO,OAAO;AAEnD;;AAGD,SAAgB,cAAcN,SAA0B;AACtD,QAAO,eAAe,QAAQ,KAAK;AACpC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_exec = require('./exec-
|
|
1
|
+
const require_exec = require('./exec-B2aL-jrd.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"));
|
|
@@ -502,6 +502,12 @@ const segment = {
|
|
|
502
502
|
json(data) {
|
|
503
503
|
return new MessageSegmentImpl("json", { data: typeof data === "string" ? data : JSON.stringify(data) });
|
|
504
504
|
},
|
|
505
|
+
markdown(content) {
|
|
506
|
+
return new MessageSegmentImpl("markdown", { content });
|
|
507
|
+
},
|
|
508
|
+
button(options) {
|
|
509
|
+
return new MessageSegmentImpl("button", { ...options });
|
|
510
|
+
},
|
|
505
511
|
raw(type, data, attachment) {
|
|
506
512
|
return new MessageSegmentImpl(type, data, attachment);
|
|
507
513
|
}
|
|
@@ -847,6 +853,7 @@ var AdapterContextImpl = class {
|
|
|
847
853
|
#logger;
|
|
848
854
|
#emit;
|
|
849
855
|
#pendingStarts = new Set();
|
|
856
|
+
#crossDedup;
|
|
850
857
|
constructor(options) {
|
|
851
858
|
this.#state = options.state;
|
|
852
859
|
this.#bots = options.bots;
|
|
@@ -855,6 +862,7 @@ var AdapterContextImpl = class {
|
|
|
855
862
|
this.#capabilities = options.capabilities;
|
|
856
863
|
this.#logger = options.logger;
|
|
857
864
|
this.#emit = options.emit;
|
|
865
|
+
this.#crossDedup = options.crossDedup ?? null;
|
|
858
866
|
}
|
|
859
867
|
registerBot(bot) {
|
|
860
868
|
return this.#bots.register(bot);
|
|
@@ -918,6 +926,20 @@ var AdapterContextImpl = class {
|
|
|
918
926
|
};
|
|
919
927
|
}
|
|
920
928
|
async dispatch(event) {
|
|
929
|
+
if (event.kind === "message") {
|
|
930
|
+
const senderId = event.user_id;
|
|
931
|
+
if (senderId != null) {
|
|
932
|
+
const senderBot = this.#bots.pick(senderId);
|
|
933
|
+
if (senderBot && senderBot.bot_id !== event.self_id) {
|
|
934
|
+
this.#logger.debug(`拦截来自其他已连接 bot 的消息: sender=${senderId} self=${event.self_id}`);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (this.#crossDedup?.isDuplicate(event)) {
|
|
939
|
+
this.#logger.debug(`丢弃跨适配器重复消息: adapter=${event.identity?.adapter ?? ""} sender=${event.user_id ?? ""}`);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
921
943
|
await this.#bus.dispatch(event);
|
|
922
944
|
}
|
|
923
945
|
listen(route, handler) {
|
|
@@ -2399,6 +2421,9 @@ const toInstance = (bot, status) => {
|
|
|
2399
2421
|
connected_at: bot.connected_at,
|
|
2400
2422
|
impl: status?.impl,
|
|
2401
2423
|
version: status?.version,
|
|
2424
|
+
protocol: status?.protocol,
|
|
2425
|
+
platform: status?.platform,
|
|
2426
|
+
platformVersion: status?.platform_version,
|
|
2402
2427
|
stats: normalizeStats(status?.stats, data),
|
|
2403
2428
|
data
|
|
2404
2429
|
};
|
|
@@ -2425,6 +2450,7 @@ const buildAdapterReport = async (options) => {
|
|
|
2425
2450
|
return {
|
|
2426
2451
|
name,
|
|
2427
2452
|
version: known?.version,
|
|
2453
|
+
impl: known?.impl,
|
|
2428
2454
|
loaded: known != null,
|
|
2429
2455
|
instances: paired.filter((entry) => entry.adapter === name).map((entry) => entry.instance)
|
|
2430
2456
|
};
|
|
@@ -2449,8 +2475,11 @@ const formatStats = (stats) => {
|
|
|
2449
2475
|
return segments.join(" · ");
|
|
2450
2476
|
};
|
|
2451
2477
|
const formatInstance = (instance) => {
|
|
2452
|
-
const
|
|
2453
|
-
|
|
2478
|
+
const tags = [
|
|
2479
|
+
[instance.impl, instance.version].filter(Boolean).join("/"),
|
|
2480
|
+
instance.platform ? `${instance.platform}${instance.platformVersion ? ` v${instance.platformVersion}` : ""}` : "",
|
|
2481
|
+
instance.online ? "" : "🔴 离线"
|
|
2482
|
+
].filter(Boolean);
|
|
2454
2483
|
const lines = [`👤 ${instance.nickname || "(未命名)"} (${instance.bot_id})${tags.length ? ` · ${tags.join(" · ")}` : ""}`];
|
|
2455
2484
|
const uptime = instance.online && instance.connected_at != null ? `⏳ 已连接 ${(0, pretty_ms.default)(Date.now() - instance.connected_at, {
|
|
2456
2485
|
hideYear: true,
|
|
@@ -2467,9 +2496,16 @@ const summarize = (entry) => {
|
|
|
2467
2496
|
if (online === total) return `🟢 ${localNum(total)} 实例`;
|
|
2468
2497
|
return `${online === 0 ? "🔴" : "🟡"} ${localNum(online)}/${localNum(total)} 实例在线`;
|
|
2469
2498
|
};
|
|
2499
|
+
/** `名称@包版本[/实现库 v版本]` */
|
|
2500
|
+
const formatAdapterName = (entry) => {
|
|
2501
|
+
const base = `${entry.name}${entry.version ? `@${entry.version}` : ""}`;
|
|
2502
|
+
if (!entry.impl) return base;
|
|
2503
|
+
const impl = `${entry.impl.name}${entry.impl.version ? ` v${entry.impl.version}` : ""}`;
|
|
2504
|
+
return `${base}/${impl}`;
|
|
2505
|
+
};
|
|
2470
2506
|
const formatAdapterReport = (report) => {
|
|
2471
2507
|
if (!report.adapters.length) return "〓 🔌 mioku 适配器 〓\n(未加载任何适配器)";
|
|
2472
|
-
const lines = report.adapters.flatMap((entry) => [`🔌 ${entry
|
|
2508
|
+
const lines = report.adapters.flatMap((entry) => [`🔌 ${formatAdapterName(entry)} · ${summarize(entry)}`, ...entry.instances.flatMap(formatInstance)]);
|
|
2473
2509
|
return ["〓 🔌 mioku 适配器 〓", ...lines].join("\n");
|
|
2474
2510
|
};
|
|
2475
2511
|
|
|
@@ -4012,19 +4048,21 @@ const core = definePlugin({
|
|
|
4012
4048
|
const collectBots = () => ctx.bots;
|
|
4013
4049
|
/** 已加载的适配器优先,再补上只在 bot 上出现过的适配器名 */
|
|
4014
4050
|
const collectAdapters = () => {
|
|
4015
|
-
const
|
|
4016
|
-
name
|
|
4017
|
-
version: adapter
|
|
4018
|
-
|
|
4051
|
+
const describe = (name, adapter) => ({
|
|
4052
|
+
name,
|
|
4053
|
+
version: adapter?.version,
|
|
4054
|
+
impl: adapter?.impl ? {
|
|
4055
|
+
name: adapter.impl.name,
|
|
4056
|
+
version: adapter.impl.version
|
|
4057
|
+
} : void 0
|
|
4058
|
+
});
|
|
4059
|
+
const list = ctx.adapters.map((adapter) => describe(adapter.name, adapter));
|
|
4019
4060
|
const seen = new Set(list.map((adapter) => adapter.name));
|
|
4020
4061
|
for (const bot of ctx.bots) {
|
|
4021
4062
|
const name = String(bot.adapter);
|
|
4022
4063
|
if (seen.has(name)) continue;
|
|
4023
4064
|
seen.add(name);
|
|
4024
|
-
list.push(
|
|
4025
|
-
name,
|
|
4026
|
-
version: ctx.getAdapter(name)?.version
|
|
4027
|
-
});
|
|
4065
|
+
list.push(describe(name, ctx.getAdapter(name)));
|
|
4028
4066
|
}
|
|
4029
4067
|
return list;
|
|
4030
4068
|
};
|
|
@@ -4678,6 +4716,96 @@ const loadLocalPlugin = async (jiti$1, name, resolvedPath) => {
|
|
|
4678
4716
|
return await loadFromEntry(jiti$1, entry, name);
|
|
4679
4717
|
};
|
|
4680
4718
|
|
|
4719
|
+
//#endregion
|
|
4720
|
+
//#region src/runtime/cross-adapter-dedup.ts
|
|
4721
|
+
const BUCKET_SLACK = 1;
|
|
4722
|
+
const PRUNE_INTERVAL = 128;
|
|
4723
|
+
const TTL_MS = 15e3;
|
|
4724
|
+
const MAX_SIZE = 4096;
|
|
4725
|
+
const MAX_SEGMENTS = 16;
|
|
4726
|
+
const MAX_TEXT = 256;
|
|
4727
|
+
/**
|
|
4728
|
+
* 把消息段序列化为跨适配器稳定的内容指纹:
|
|
4729
|
+
* 文本/@/表情取内容,媒体段只取类型(url/文件名跨协议不稳定)
|
|
4730
|
+
*/
|
|
4731
|
+
const contentFingerprintOf = (event) => {
|
|
4732
|
+
const parts = [];
|
|
4733
|
+
for (const seg of event.message) {
|
|
4734
|
+
if (parts.length >= MAX_SEGMENTS) break;
|
|
4735
|
+
if (seg.type === "reply") continue;
|
|
4736
|
+
const data = seg.data ?? {};
|
|
4737
|
+
if (seg.type === "text") {
|
|
4738
|
+
const text$1 = typeof data.text === "string" ? data.text : "";
|
|
4739
|
+
parts.push(`t:${text$1.slice(0, MAX_TEXT)}`);
|
|
4740
|
+
} else if (seg.type === "at") {
|
|
4741
|
+
const target = data.qq ?? data.target;
|
|
4742
|
+
parts.push(`a:${target == null ? "" : String(target)}`);
|
|
4743
|
+
} else if (seg.type === "face") parts.push(`f:${data.id == null ? "" : String(data.id)}`);
|
|
4744
|
+
else parts.push(seg.type);
|
|
4745
|
+
}
|
|
4746
|
+
return parts.join("|");
|
|
4747
|
+
};
|
|
4748
|
+
const scopeKeyOf = (event, content) => [
|
|
4749
|
+
event.self_id ?? "",
|
|
4750
|
+
event.message_type ?? "",
|
|
4751
|
+
event.group_id ?? event.user_id ?? "",
|
|
4752
|
+
event.user_id ?? "",
|
|
4753
|
+
content
|
|
4754
|
+
].join("|");
|
|
4755
|
+
/**
|
|
4756
|
+
* 跨适配器消息去重(L2)
|
|
4757
|
+
*/
|
|
4758
|
+
var CrossAdapterMessageDeduplicator = class {
|
|
4759
|
+
#entries = new Map();
|
|
4760
|
+
#inserts = 0;
|
|
4761
|
+
#dropped = 0;
|
|
4762
|
+
/** 本次运行以来被丢弃的跨适配器重复消息数 */
|
|
4763
|
+
get dropped() {
|
|
4764
|
+
return this.#dropped;
|
|
4765
|
+
}
|
|
4766
|
+
isDuplicate(event) {
|
|
4767
|
+
if (event.kind !== "message") return false;
|
|
4768
|
+
const messageEvent = event;
|
|
4769
|
+
const adapter = messageEvent.identity?.adapter ?? "";
|
|
4770
|
+
const now = Date.now();
|
|
4771
|
+
const bucket = Math.floor((messageEvent.time ?? now) / 1e3);
|
|
4772
|
+
const key = scopeKeyOf(messageEvent, contentFingerprintOf(messageEvent));
|
|
4773
|
+
const existing = this.#entries.get(key);
|
|
4774
|
+
if (existing) {
|
|
4775
|
+
if (Math.abs(existing.bucket - bucket) <= BUCKET_SLACK) {
|
|
4776
|
+
if (existing.adapter !== adapter) {
|
|
4777
|
+
this.#dropped++;
|
|
4778
|
+
return true;
|
|
4779
|
+
}
|
|
4780
|
+
existing.bucket = bucket;
|
|
4781
|
+
existing.at = now;
|
|
4782
|
+
return false;
|
|
4783
|
+
}
|
|
4784
|
+
existing.bucket = bucket;
|
|
4785
|
+
existing.at = now;
|
|
4786
|
+
existing.adapter = adapter;
|
|
4787
|
+
return false;
|
|
4788
|
+
}
|
|
4789
|
+
this.#entries.set(key, {
|
|
4790
|
+
adapter,
|
|
4791
|
+
bucket,
|
|
4792
|
+
at: now
|
|
4793
|
+
});
|
|
4794
|
+
this.#inserts++;
|
|
4795
|
+
if (this.#inserts >= PRUNE_INTERVAL || this.#entries.size > MAX_SIZE) {
|
|
4796
|
+
this.#inserts = 0;
|
|
4797
|
+
this.#prune(now);
|
|
4798
|
+
}
|
|
4799
|
+
return false;
|
|
4800
|
+
}
|
|
4801
|
+
#prune(now) {
|
|
4802
|
+
for (const [key, entry] of this.#entries) if (now - entry.at > TTL_MS) this.#entries.delete(key);
|
|
4803
|
+
}
|
|
4804
|
+
clear() {
|
|
4805
|
+
this.#entries.clear();
|
|
4806
|
+
}
|
|
4807
|
+
};
|
|
4808
|
+
|
|
4681
4809
|
//#endregion
|
|
4682
4810
|
//#region src/runtime/runtime.ts
|
|
4683
4811
|
const BUILTIN_PLUGINS$1 = [...BUILTIN_PLUGINS];
|
|
@@ -4698,6 +4826,7 @@ var MiokuRuntime = class {
|
|
|
4698
4826
|
#enabledPlugins = new Map();
|
|
4699
4827
|
#driverFactory;
|
|
4700
4828
|
#builtinPlugins;
|
|
4829
|
+
#crossDedup;
|
|
4701
4830
|
#started = false;
|
|
4702
4831
|
#stopped = false;
|
|
4703
4832
|
constructor(options) {
|
|
@@ -4714,6 +4843,7 @@ var MiokuRuntime = class {
|
|
|
4714
4843
|
});
|
|
4715
4844
|
this.#bots = new BotRegistry();
|
|
4716
4845
|
this.#capabilities = new CapabilityRegistry();
|
|
4846
|
+
this.#crossDedup = options.dedup?.crossAdapter === false ? null : new CrossAdapterMessageDeduplicator();
|
|
4717
4847
|
}
|
|
4718
4848
|
get cwd() {
|
|
4719
4849
|
return this.#cwd;
|
|
@@ -4834,7 +4964,8 @@ var MiokuRuntime = class {
|
|
|
4834
4964
|
driver: this.#driver,
|
|
4835
4965
|
capabilities: this.#capabilities,
|
|
4836
4966
|
logger: this.#logger.child({ adapter: state.definition.name }),
|
|
4837
|
-
emit: (event) => this.#emitLifecycle(event)
|
|
4967
|
+
emit: (event) => this.#emitLifecycle(event),
|
|
4968
|
+
crossDedup: this.#crossDedup
|
|
4838
4969
|
});
|
|
4839
4970
|
}
|
|
4840
4971
|
async #loadPlugin(plugin, type) {
|
|
@@ -5184,7 +5315,8 @@ const startRuntime = async (options = {}) => {
|
|
|
5184
5315
|
const runtime = createRuntime({
|
|
5185
5316
|
cwd,
|
|
5186
5317
|
logger,
|
|
5187
|
-
builtinPlugins: getBuiltinPlugins()
|
|
5318
|
+
builtinPlugins: getBuiltinPlugins(),
|
|
5319
|
+
dedup: { crossAdapter: botConfig.dedup?.cross_adapter ?? true }
|
|
5188
5320
|
});
|
|
5189
5321
|
const pluginDir = node_path.default.resolve(cwd, botConfig.plugins_dir ?? "plugins");
|
|
5190
5322
|
logger.info(consola_utils.colors.dim("=".repeat(40)));
|