mioku 0.9.8 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ const consola = require_exec.__toESM(require("consola"));
7
7
  const dedent = require_exec.__toESM(require("dedent"));
8
8
 
9
9
  //#region package.json
10
- var version = "0.9.8";
10
+ var version = "0.9.9";
11
11
 
12
12
  //#endregion
13
13
  //#region src/cli/shared.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["cmd: string","args: string[]","options: { cwd?: string }","args","dir: string","err: any","packages: string[]","cwd?: string","cwd: string","pkgName: string","p: string","packageName: string","fileTree: Record<string, string | Record<string, unknown>>","base: string","version: string","version","message: string","options?: OmitTypeWithRequired<{ initial?: boolean }>","options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>","cmdArgs: string[]","helpInfo: string","pkgName: string","packages: string[]","cwd: string","prefix: string","name?: string","cmdArgs: string[]","name: string","fileTree: Record<string, string | Record<string, unknown>>","args","version: string","version"],"sources":["../../package.json","../../src/cli/shared.ts","../../src/cli/install.ts","../../src/cli/update.ts","../../src/cli/scaffold.ts","../../src/cli/index.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"0.9.8\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - Plugin framework extended from mioki for NapCat OneBot v11\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioki\",\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/jerryplusy/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/jerryplusy/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jerryplusy/mioku.git\",\n \"directory\": \"src/packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\"\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 \"mioki\": \"^0.16.0\",\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 \"openai\": \"^4.0.0\",\n \"puppeteer\": \"^23.10.0\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"systeminformation\": \"^5.30.7\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"@types/puppeteer\": \"^7.0.4\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import fs, { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport consola from \"consola\";\nimport dedent from \"dedent\";\nimport {\n clearCommandCache,\n commandExists,\n resolveCommand,\n runCommandInherit,\n} from \"../core/exec\";\n\nexport const DEFAULT_PACKAGES = [\n \"mioku\",\n \"mioku-plugin-boot\",\n \"mioku-plugin-help\",\n \"mioku-plugin-chat\",\n \"mioku-service-config\",\n \"mioku-service-ai\",\n \"mioku-service-screenshot\",\n \"mioku-service-help\",\n];\n\nexport const PLUGIN_PREFIX = \"mioku-plugin-\";\nexport const SERVICE_PREFIX = \"mioku-service-\";\n\nexport function run(\n cmd: string,\n args: string[] = [],\n options: { cwd?: string } = {},\n): void {\n runCommandInherit(cmd, args, options);\n}\n\nexport async function rmrf(dir: string, retries = 5): Promise<void> {\n for (let i = 0; i < retries; i++) {\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n return;\n } catch (err: any) {\n if (i === retries - 1) throw err;\n const code = err?.code;\n if (\n code === \"EPERM\" ||\n code === \"EBUSY\" ||\n code === \"ENOTEMPTY\" ||\n code === \"ENOENT\"\n ) {\n await new Promise((resolve) => setTimeout(resolve, 300 * (i + 1)));\n } else {\n throw err;\n }\n }\n }\n}\n\nexport function hasCommand(cmd: string): boolean {\n return commandExists(cmd);\n}\n\nfunction findNpmPath(): string | null {\n const resolved = resolveCommand(\"npm\");\n if (resolved) return resolved;\n if (process.platform !== \"win32\") return null;\n\n const fallbacks = [\n path.join(process.env.ProgramFiles || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env[\"ProgramFiles(x86)\"] || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env.APPDATA || \"\", \"npm\", \"npm.cmd\"),\n ];\n\n return fallbacks.find((candidate) => resolveCommand(candidate)) ?? null;\n}\n\nexport function ensurePackageManager(): void {\n if (hasCommand(\"bun\")) return;\n console.log(\"安装 bun...\");\n const npmPath = findNpmPath();\n if (!npmPath) {\n consola.error(\"未找到 npm,请确保 Node.js 已安装并包含 npm\");\n process.exit(1);\n }\n run(npmPath, [\"install\", \"-g\", \"bun\"]);\n // bun was just put on PATH; drop the cached miss so the next lookup finds it.\n clearCommandCache();\n}\n\nexport function getAddCommand(packages: string[]): [string, string[]] {\n return [\"bun\", [\"add\", ...packages]];\n}\n\nexport function normalizePackageName(input: string): string {\n if (input.startsWith(PLUGIN_PREFIX) || input.startsWith(SERVICE_PREFIX)) {\n return input;\n }\n if (input.startsWith(\"mioku-\")) return input;\n return `${PLUGIN_PREFIX}${input}`;\n}\n\nexport function detectType(name: string): \"plugin\" | \"service\" | \"unknown\" {\n if (name.startsWith(PLUGIN_PREFIX)) return \"plugin\";\n if (name.startsWith(SERVICE_PREFIX)) return \"service\";\n return \"unknown\";\n}\n\nexport function execAdd(packages: string[], cwd?: string): void {\n const [cmd, args] = getAddCommand(packages);\n console.log(`执行: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd });\n}\n\nexport function appendToMiokiPlugins(cwd: string, pkgName: string): boolean {\n if (!pkgName.startsWith(PLUGIN_PREFIX)) return false;\n const shortName = pkgName.slice(PLUGIN_PREFIX.length);\n\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n const mioki = pkg.mioki ?? {};\n const plugins = Array.isArray(mioki.plugins) ? [...mioki.plugins] : [];\n if (plugins.includes(shortName)) return false;\n\n plugins.push(shortName);\n pkg.mioki = { ...mioki, plugins };\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n return true;\n}\n\nexport async function getInstalledPackages(cwd: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(readFileSync(path.join(cwd, \"package.json\"), \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return Object.keys(deps).filter((k) => k.startsWith(\"mioku-\"));\n } catch {\n return [];\n }\n}\n\nexport function withRoot(p: string): string {\n return path.resolve(process.cwd(), p);\n}\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport async function fetchNpmKeywords(\n packageName: string,\n): Promise<string[] | null> {\n try {\n const res = await fetch(`${NPM_REGISTRY}/${encodeURIComponent(packageName)}`, {\n headers: { Accept: \"application/json\", \"User-Agent\": \"mioku-cli\" },\n });\n if (!res.ok) return null;\n const data = (await res.json()) as any;\n const latestVersion = String(data?.[\"dist-tags\"]?.latest || \"\").trim();\n const keywords = latestVersion\n ? data?.versions?.[latestVersion]?.keywords\n : data?.keywords;\n return Array.isArray(keywords) ? keywords.map(String) : [];\n } catch {\n return null;\n }\n}\n\nexport function gracefullyExit(): void {\n console.log(\"Bye!\");\n process.exit(0);\n}\n\nexport function makeFileTree(\n fileTree: Record<string, string | Record<string, unknown>>,\n base: string,\n): void {\n for (const [name, content] of Object.entries(fileTree)) {\n if (typeof content === \"object\" && content !== null) {\n const subPath = `${base}/${name}`;\n if (!fs.existsSync(subPath)) fs.mkdirSync(subPath, { recursive: true });\n for (const [subName, subContent] of Object.entries(content)) {\n if (typeof subContent === \"object\") {\n makeFileTree(\n subContent as Record<string, string | Record<string, unknown>>,\n path.join(subPath, subName),\n );\n } else {\n fs.writeFileSync(`${subPath}/${subName}`, subContent as string);\n }\n }\n } else {\n const filePath = `${base}/${name}`;\n const dirname = path.dirname(filePath);\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });\n fs.writeFileSync(filePath, content as string);\n }\n }\n}\n\nexport function buildHelpInfo(version: string): string {\n return dedent(`\n mioku 命令行工具 v${version}\n\n 用法: mioku <命令> [选项]\n\n 命令:\n install plugin <名称> 安装插件,自动补全 mioku-plugin- 前缀\n install service <名称> 安装服务,自动补全 mioku-service- 前缀\n update [包名|self|all] 更新插件或服务\n update - 检查可用更新\n update all - 更新所有 mioku- 包\n update self - 更新 mioku 框架\n update xxx - 更新指定包\n\n 选项:\n -h, --help 显示帮助信息\n -v, --version 显示版本号\n --name <name> 指定项目/文件夹名称,默认 mioku-bot\n --protocol <protocol> 指定 NapCat 协议,默认 ws\n --host <host> 指定 NapCat 主机,默认 localhost\n --port <port> 指定 NapCat 端口,默认 3001\n --token <token> 指定 NapCat 连接 Token,默认空\n --prefix <prefix> 指定命令前缀,默认 #\n --owners <owners> 指定主人 QQ,英文逗号分隔,必填\n --admins <admins> 指定管理员 QQ,英文逗号分隔,可空\n --use-npm-mirror 使用 npm 镜像源加速依赖安装,默认否\n `);\n}\n\ntype OmitTypeWithRequired<T> = Omit<T, \"type\" | \"required\"> & {\n required?: boolean;\n};\n\nexport async function confirm(\n message: string,\n options?: OmitTypeWithRequired<{ initial?: boolean }>,\n): Promise<boolean> {\n return consola.prompt(message, {\n type: \"confirm\",\n cancel: \"reject\",\n ...options,\n });\n}\n\nexport async function input(\n message: string,\n options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>,\n): Promise<string> {\n const result = await consola.prompt(message, {\n type: \"text\",\n cancel: \"reject\",\n ...options,\n });\n if (options?.required && !result) return input(message, options);\n return result;\n}\n","import consola from \"consola\";\nimport {\n ensurePackageManager,\n appendToMiokiPlugins,\n execAdd,\n fetchNpmKeywords,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n confirm,\n} from \"./shared\";\n\nexport async function installCommand(\n cmdArgs: string[],\n helpInfo: string,\n): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [type, name] = cmdArgs;\n\n if (!type || !name) {\n consola.error(\n \"请指定类型和名称: mioku install plugin <名称> 或 mioku install service <名称>\",\n );\n console.log(helpInfo);\n return 1;\n }\n\n if (type !== \"plugin\" && type !== \"service\") {\n consola.error(`无效的类型 \"${type}\",请使用 plugin 或 service`);\n console.log(helpInfo);\n return 1;\n }\n\n const prefix = type === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n const normalized = `${prefix}${name}`;\n\n if (type === \"plugin\") {\n const proceed = await warnIfPrivatePlugin(normalized);\n if (!proceed) {\n consola.info(\"已取消安装\");\n return 1;\n }\n }\n\n try {\n execAdd([normalized], cwd);\n consola.success(`已安装 ${normalized}`);\n\n if (type === \"plugin\") {\n const shortName = normalized.slice(PLUGIN_PREFIX.length);\n if (appendToMiokiPlugins(cwd, normalized)) {\n consola.success(`已在 mioki.plugins 中启用 ${shortName}`);\n } else {\n consola.info(`${shortName} 已在 mioki.plugins 中,跳过`);\n }\n }\n return 0;\n } catch {\n consola.error(`安装失败: ${normalized}`);\n return 1;\n }\n}\n\nasync function warnIfPrivatePlugin(pkgName: string): Promise<boolean> {\n const keywords = await fetchNpmKeywords(pkgName);\n if (keywords === null) return true;\n if (keywords.includes(\"mioku\")) return true;\n\n consola.warn(`${pkgName} 看起来是私有插件\"`);\n consola.warn(\"该插件未上架插件市场,可能存在风险\");\n return confirm(\"仍要继续安装吗?\", { initial: false });\n}\n","import consola from \"consola\";\nimport {\n run,\n ensurePackageManager,\n getInstalledPackages,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n} from \"./shared\";\n\nasync function updatePackages(packages: string[], cwd: string): Promise<void> {\n if (packages.length === 0) {\n consola.info(\"未找到 mioku- 相关依赖\");\n return;\n }\n console.log(`执行: bun update ${packages.join(\" \")} --latest`);\n run(\"bun\", [\"update\", ...packages, \"--latest\"], { cwd });\n}\n\nasync function updateByPrefix(\n prefix: string,\n cwd: string,\n name?: string,\n): Promise<void> {\n if (name) {\n const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;\n console.log(`执行: bun update ${normalized} --latest`);\n run(\"bun\", [\"update\", normalized, \"--latest\"], { cwd });\n return;\n }\n const packages = (await getInstalledPackages(cwd)).filter((p) =>\n p.startsWith(prefix),\n );\n if (packages.length === 0) {\n consola.info(`未找到 ${prefix}* 相关依赖`);\n return;\n }\n await updatePackages(packages, cwd);\n}\n\nexport async function updateCommand(cmdArgs: string[]): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [target, name] = cmdArgs;\n\n if (!target || target === \"check\") {\n run(\"bun\", [\"update\", \"-i\"], { cwd });\n return 0;\n }\n\n if (target === \"all\") {\n await updatePackages(await getInstalledPackages(cwd), cwd);\n return 0;\n }\n\n if (target === \"self\") {\n console.log(\"执行: bun update mioku --latest\");\n run(\"bun\", [\"update\", \"mioku\", \"--latest\"], { cwd });\n return 0;\n }\n\n if (target === \"plugin\" || target === \"service\") {\n const prefix = target === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n await updateByPrefix(prefix, cwd, name);\n return 0;\n }\n\n console.log(`执行: bun update ${target} --latest`);\n run(\"bun\", [\"update\", target, \"--latest\"], { cwd });\n return 0;\n}\n","import fs from \"node:fs\";\nimport dedent from \"dedent\";\nimport {\n DEFAULT_PACKAGES,\n ensurePackageManager,\n getAddCommand,\n run,\n rmrf,\n withRoot,\n gracefullyExit,\n makeFileTree,\n input,\n confirm,\n} from \"./shared\";\n\nasync function createNewProject(\n name: string,\n fileTree: Record<string, string | Record<string, unknown>>,\n installWebui = false,\n): Promise<void> {\n const projectPath = withRoot(`./${name}`);\n\n if (fs.existsSync(projectPath)) {\n const overwrite = await confirm(`项目 ${name} 已存在,是否覆盖?`);\n if (!overwrite) gracefullyExit();\n\n if (projectPath === process.cwd()) {\n if (fs.readdirSync(projectPath).length !== 0) {\n const confirmOver = await confirm(\n \"项目路径与当前路径相同,将删除当前目录下所有内容再创建,是否继续?\",\n );\n if (!confirmOver) gracefullyExit();\n }\n }\n await rmrf(projectPath);\n }\n\n fs.mkdirSync(projectPath, { recursive: true });\n makeFileTree(fileTree, projectPath);\n console.log(`项目 ${name} 创建成功!`);\n\n const packages = installWebui\n ? [...DEFAULT_PACKAGES, \"mioku-service-webui\"]\n : DEFAULT_PACKAGES;\n const [cmd, args] = getAddCommand(packages);\n console.log(`正在安装 Mioku 依赖: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd: projectPath });\n}\n\nexport async function scaffoldCommand(version: string): Promise<number> {\n const name = await input(\"请输入项目名称\", {\n default: \"mioku-bot\",\n placeholder: \"mioku-bot\",\n required: true,\n });\n const owners = await input(\"请输入主人 QQ (最高权限,英文逗号分隔,必填)\", {\n placeholder: \"请输入\",\n default: \"\",\n required: true,\n });\n const host = await input(\"请输入 NapCat WS 主机\", {\n default: \"localhost\",\n placeholder: \"localhost\",\n required: true,\n });\n const port = parseInt(\n await input(\"请输入 NapCat WS 端口\", {\n default: \"3001\",\n placeholder: \"3001\",\n required: true,\n }),\n 10,\n );\n const token = await input(\"请输入 NapCat WS Token(如无则留空)\", {\n placeholder: \"请输入\",\n });\n\n ensurePackageManager();\n\n const ownersList = String(owners)\n .split(\",\")\n .map((o) => o.trim())\n .join(\", \");\n\n const pkgJson = dedent(`\n {\n \"name\": \"${name}\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {},\n \"mioki\": {\n \"prefix\": \"#\",\n \"owners\": [${ownersList}],\n \"admins\": [],\n \"plugins\": [\"boot\", \"help\", \"chat\", \"demo\"],\n \"log_level\": \"info\",\n \"online_push\": false,\n \"error_push\": false,\n \"napcat\": [\n {\n \"protocol\": \"ws\",\n \"port\": ${port},\n \"host\": \"${host}\",\n \"token\": \"${token}\"\n }\n ]\n },\n \"scripts\": {\n \"start\": \"bun run app.ts\",\n \"dev\": \"bun run --watch app.ts\"\n }\n }\n `);\n\n const pluginCode = dedent(`\n import { definePlugin } from 'mioku'\n\n export default definePlugin({\n name: 'demo',\n version: '${version}',\n async setup(ctx) {\n ctx.logger.info('Demo 插件已加载')\n\n ctx.handle('message', async (e) => {\n if (e.raw_message === 'hello') {\n e.reply('world', true)\n }\n })\n\n return () => {\n ctx.logger.info('Demo 插件已卸载')\n }\n },\n })\n `);\n\n const fileTree: Record<string, string | Record<string, unknown>> = {\n \"app.ts\":\n \"import { start } from 'mioku'\\n\\nstart({ cwd: import.meta.dirname }).then()\\n\",\n \"package.json\": pkgJson,\n plugins: { demo: { \"index.ts\": pluginCode } },\n config: {},\n data: {},\n };\n\n const installWebui = await confirm(\"是否安装 WebUI 管理面板?(建议安装)\", {\n initial: true,\n });\n\n await createNewProject(name, fileTree, installWebui);\n\n console.log(\"\\n若需启动机器人,请运行:\");\n console.log(\" cd\", name);\n console.log(\" bun run start\");\n return 0;\n}\n","#!/usr/bin/env node\n\nimport mri from \"mri\";\nimport { version } from \"../../package.json\";\nimport { buildHelpInfo } from \"./shared\";\nimport { installCommand } from \"./install\";\nimport { updateCommand } from \"./update\";\nimport { scaffoldCommand } from \"./scaffold\";\n\ninterface CliOptions {\n help?: boolean;\n version?: boolean;\n}\n\nconst args = process.argv.slice(2);\n\n(async () => {\n const cli = mri<CliOptions>(args, { alias: { v: \"version\", h: \"help\" } });\n const helpInfo = buildHelpInfo(version);\n const [cmd, ...cmdArgs] = args;\n\n switch (cmd) {\n case \"install\":\n process.exitCode = await installCommand(cmdArgs, helpInfo);\n return;\n case \"update\":\n process.exitCode = await updateCommand(cmdArgs);\n return;\n default:\n if (cli.version) {\n console.log(`v${version}`);\n return;\n }\n if (cli.help) {\n console.log(helpInfo);\n return;\n }\n process.exitCode = await scaffoldCommand(version);\n return;\n }\n})();\n"],"mappings":";;;;;;;;;cAGa;;;;ACQb,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAED,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;AAE9B,SAAgB,IACdA,KACAC,SAAiB,CAAE,GACnBC,UAA4B,CAAE,GACxB;AACN,gCAAkB,KAAKC,QAAM,QAAQ;AACtC;AAED,eAAsB,KAAKC,KAAa,UAAU,GAAkB;AAClE,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,IAC3B,KAAI;AACF,kBAAG,OAAO,KAAK;GAAE,WAAW;GAAM,OAAO;EAAM,EAAC;AAChD;CACD,SAAQC,KAAU;AACjB,MAAI,MAAM,UAAU,EAAG,OAAM;EAC7B,MAAM,OAAO,KAAK;AAClB,MACE,SAAS,WACT,SAAS,WACT,SAAS,eACT,SAAS,SAET,OAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,OAAO,IAAI,GAAG;MAEjE,OAAM;CAET;AAEJ;AAED,SAAgB,WAAWL,KAAsB;AAC/C,QAAO,2BAAc,IAAI;AAC1B;AAED,SAAS,cAA6B;CACpC,MAAM,WAAW,4BAAe,MAAM;AACtC,KAAI,SAAU,QAAO;AACrB,KAAI,QAAQ,aAAa,QAAS,QAAO;CAEzC,MAAM,YAAY;EAChB,kBAAK,KAAK,QAAQ,IAAI,gBAAgB,IAAI,UAAU,UAAU;EAC9D,kBAAK,KAAK,QAAQ,IAAI,wBAAwB,IAAI,UAAU,UAAU;EACtE,kBAAK,KAAK,QAAQ,IAAI,WAAW,IAAI,OAAO,UAAU;CACvD;AAED,QAAO,UAAU,KAAK,CAAC,cAAc,4BAAe,UAAU,CAAC,IAAI;AACpE;AAED,SAAgB,uBAA6B;AAC3C,KAAI,WAAW,MAAM,CAAE;AACvB,SAAQ,IAAI,YAAY;CACxB,MAAM,UAAU,aAAa;AAC7B,MAAK,SAAS;AACZ,kBAAQ,MAAM,iCAAiC;AAC/C,UAAQ,KAAK,EAAE;CAChB;AACD,KAAI,SAAS;EAAC;EAAW;EAAM;CAAM,EAAC;AAEtC,iCAAmB;AACpB;AAED,SAAgB,cAAcM,UAAwC;AACpE,QAAO,CAAC,OAAO,CAAC,OAAO,GAAG,QAAS,CAAC;AACrC;AAgBD,SAAgB,QAAQA,UAAoBC,KAAoB;CAC9D,MAAM,CAAC,KAAKJ,OAAK,GAAG,cAAc,SAAS;AAC3C,SAAQ,KAAK,MAAM,IAAI,GAAG,OAAK,KAAK,IAAI,CAAC,EAAE;AAC3C,KAAI,KAAKA,QAAM,EAAE,IAAK,EAAC;AACxB;AAED,SAAgB,qBAAqBK,KAAaC,SAA0B;AAC1E,MAAK,QAAQ,WAAW,cAAc,CAAE,QAAO;CAC/C,MAAM,YAAY,QAAQ,MAAM,cAAc,OAAO;CAErD,MAAM,kBAAkB,kBAAK,KAAK,KAAK,eAAe;AACtD,MAAK,gBAAG,WAAW,gBAAgB,CAAE,QAAO;CAE5C,MAAM,MAAM,KAAK,MAAM,0BAAa,iBAAiB,QAAQ,CAAC;CAC9D,MAAM,QAAQ,IAAI,SAAS,CAAE;CAC7B,MAAM,UAAU,MAAM,QAAQ,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,OAAQ,IAAG,CAAE;AACtE,KAAI,QAAQ,SAAS,UAAU,CAAE,QAAO;AAExC,SAAQ,KAAK,UAAU;AACvB,KAAI,QAAQ;EAAE,GAAG;EAAO;CAAS;AACjC,iBAAG,cAAc,kBAAkB,EAAE,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC,IAAI;AACtE,QAAO;AACR;AAED,eAAsB,qBAAqBD,KAAgC;AACzE,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,0BAAa,kBAAK,KAAK,KAAK,eAAe,EAAE,QAAQ,CAAC;EAC7E,MAAM,OAAO;GAAE,GAAG,IAAI;GAAc,GAAG,IAAI;EAAiB;AAC5D,SAAO,OAAO,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC;CAC/D,QAAO;AACN,SAAO,CAAE;CACV;AACF;AAED,SAAgB,SAASE,GAAmB;AAC1C,QAAO,kBAAK,QAAQ,QAAQ,KAAK,EAAE,EAAE;AACtC;AAED,MAAM,eAAe;AAErB,eAAsB,iBACpBC,aAC0B;AAC1B,KAAI;EACF,MAAM,MAAM,MAAM,OAAO,EAAE,aAAa,GAAG,mBAAmB,YAAY,CAAC,GAAG,EAC5E,SAAS;GAAE,QAAQ;GAAoB,cAAc;EAAa,EACnE,EAAC;AACF,OAAK,IAAI,GAAI,QAAO;EACpB,MAAM,OAAQ,MAAM,IAAI,MAAM;EAC9B,MAAM,gBAAgB,OAAO,OAAO,cAAc,UAAU,GAAG,CAAC,MAAM;EACtE,MAAM,WAAW,gBACb,MAAM,WAAW,gBAAgB,WACjC,MAAM;AACV,SAAO,MAAM,QAAQ,SAAS,GAAG,SAAS,IAAI,OAAO,GAAG,CAAE;CAC3D,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAgB,iBAAuB;AACrC,SAAQ,IAAI,OAAO;AACnB,SAAQ,KAAK,EAAE;AAChB;AAED,SAAgB,aACdC,UACAC,MACM;AACN,MAAK,MAAM,CAAC,MAAM,QAAQ,IAAI,OAAO,QAAQ,SAAS,CACpD,YAAW,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,WAAW,EAAE,KAAK,GAAG,KAAK;AAChC,OAAK,gBAAG,WAAW,QAAQ,CAAE,iBAAG,UAAU,SAAS,EAAE,WAAW,KAAM,EAAC;AACvE,OAAK,MAAM,CAAC,SAAS,WAAW,IAAI,OAAO,QAAQ,QAAQ,CACzD,YAAW,eAAe,SACxB,cACE,YACA,kBAAK,KAAK,SAAS,QAAQ,CAC5B;MAED,iBAAG,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAqB;CAGpE,OAAM;EACL,MAAM,YAAY,EAAE,KAAK,GAAG,KAAK;EACjC,MAAM,UAAU,kBAAK,QAAQ,SAAS;AACtC,OAAK,gBAAG,WAAW,QAAQ,CAAE,iBAAG,UAAU,SAAS,EAAE,WAAW,KAAM,EAAC;AACvE,kBAAG,cAAc,UAAU,QAAkB;CAC9C;AAEJ;AAED,SAAgB,cAAcC,WAAyB;AACrD,QAAO,qBAAQ;iBACAC,UAAQ;;;;;;;;;;;;;;;;;;;;;;;;;IAyBrB;AACH;AAMD,eAAsB,QACpBC,SACAC,SACkB;AAClB,QAAO,gBAAQ,OAAO,SAAS;EAC7B,MAAM;EACN,QAAQ;EACR,GAAG;CACJ,EAAC;AACH;AAED,eAAsB,MACpBD,SACAE,SACiB;CACjB,MAAM,SAAS,MAAM,gBAAQ,OAAO,SAAS;EAC3C,MAAM;EACN,QAAQ;EACR,GAAG;CACJ,EAAC;AACF,KAAI,SAAS,aAAa,OAAQ,QAAO,MAAM,SAAS,QAAQ;AAChE,QAAO;AACR;;;;AChPD,eAAsB,eACpBC,SACAC,UACiB;AACjB,uBAAsB;CACtB,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,CAAC,MAAM,KAAK,GAAG;AAErB,MAAK,SAAS,MAAM;AAClB,kBAAQ,MACN,mEACD;AACD,UAAQ,IAAI,SAAS;AACrB,SAAO;CACR;AAED,KAAI,SAAS,YAAY,SAAS,WAAW;AAC3C,kBAAQ,OAAO,SAAS,KAAK,wBAAwB;AACrD,UAAQ,IAAI,SAAS;AACrB,SAAO;CACR;CAED,MAAM,SAAS,SAAS,WAAW,gBAAgB;CACnD,MAAM,cAAc,EAAE,OAAO,EAAE,KAAK;AAEpC,KAAI,SAAS,UAAU;EACrB,MAAM,UAAU,MAAM,oBAAoB,WAAW;AACrD,OAAK,SAAS;AACZ,mBAAQ,KAAK,QAAQ;AACrB,UAAO;EACR;CACF;AAED,KAAI;AACF,UAAQ,CAAC,UAAW,GAAE,IAAI;AAC1B,kBAAQ,SAAS,MAAM,WAAW,EAAE;AAEpC,MAAI,SAAS,UAAU;GACrB,MAAM,YAAY,WAAW,MAAM,cAAc,OAAO;AACxD,OAAI,qBAAqB,KAAK,WAAW,CACvC,iBAAQ,SAAS,uBAAuB,UAAU,EAAE;OAEpD,iBAAQ,MAAM,EAAE,UAAU,wBAAwB;EAErD;AACD,SAAO;CACR,QAAO;AACN,kBAAQ,OAAO,QAAQ,WAAW,EAAE;AACpC,SAAO;CACR;AACF;AAED,eAAe,oBAAoBC,SAAmC;CACpE,MAAM,WAAW,MAAM,iBAAiB,QAAQ;AAChD,KAAI,aAAa,KAAM,QAAO;AAC9B,KAAI,SAAS,SAAS,QAAQ,CAAE,QAAO;AAEvC,iBAAQ,MAAM,EAAE,QAAQ,YAAY;AACpC,iBAAQ,KAAK,oBAAoB;AACjC,QAAO,QAAQ,YAAY,EAAE,SAAS,MAAO,EAAC;AAC/C;;;;AC9DD,eAAe,eAAeC,UAAoBC,KAA4B;AAC5E,KAAI,SAAS,WAAW,GAAG;AACzB,kBAAQ,KAAK,kBAAkB;AAC/B;CACD;AACD,SAAQ,KAAK,iBAAiB,SAAS,KAAK,IAAI,CAAC,WAAW;AAC5D,KAAI,OAAO;EAAC;EAAU,GAAG;EAAU;CAAW,GAAE,EAAE,IAAK,EAAC;AACzD;AAED,eAAe,eACbC,QACAD,KACAE,MACe;AACf,KAAI,MAAM;EACR,MAAM,aAAa,KAAK,WAAW,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK;AACrE,UAAQ,KAAK,iBAAiB,WAAW,WAAW;AACpD,MAAI,OAAO;GAAC;GAAU;GAAY;EAAW,GAAE,EAAE,IAAK,EAAC;AACvD;CACD;CACD,MAAM,WAAW,CAAC,MAAM,qBAAqB,IAAI,EAAE,OAAO,CAAC,MACzD,EAAE,WAAW,OAAO,CACrB;AACD,KAAI,SAAS,WAAW,GAAG;AACzB,kBAAQ,MAAM,MAAM,OAAO,QAAQ;AACnC;CACD;AACD,OAAM,eAAe,UAAU,IAAI;AACpC;AAED,eAAsB,cAAcC,SAAoC;AACtE,uBAAsB;CACtB,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,CAAC,QAAQ,KAAK,GAAG;AAEvB,MAAK,UAAU,WAAW,SAAS;AACjC,MAAI,OAAO,CAAC,UAAU,IAAK,GAAE,EAAE,IAAK,EAAC;AACrC,SAAO;CACR;AAED,KAAI,WAAW,OAAO;AACpB,QAAM,eAAe,MAAM,qBAAqB,IAAI,EAAE,IAAI;AAC1D,SAAO;CACR;AAED,KAAI,WAAW,QAAQ;AACrB,UAAQ,IAAI,gCAAgC;AAC5C,MAAI,OAAO;GAAC;GAAU;GAAS;EAAW,GAAE,EAAE,IAAK,EAAC;AACpD,SAAO;CACR;AAED,KAAI,WAAW,YAAY,WAAW,WAAW;EAC/C,MAAM,SAAS,WAAW,WAAW,gBAAgB;AACrD,QAAM,eAAe,QAAQ,KAAK,KAAK;AACvC,SAAO;CACR;AAED,SAAQ,KAAK,iBAAiB,OAAO,WAAW;AAChD,KAAI,OAAO;EAAC;EAAU;EAAQ;CAAW,GAAE,EAAE,IAAK,EAAC;AACnD,QAAO;AACR;;;;ACtDD,eAAe,iBACbC,MACAC,UACA,eAAe,OACA;CACf,MAAM,cAAc,UAAU,IAAI,KAAK,EAAE;AAEzC,KAAI,gBAAG,WAAW,YAAY,EAAE;EAC9B,MAAM,YAAY,MAAM,SAAS,KAAK,KAAK,YAAY;AACvD,OAAK,UAAW,iBAAgB;AAEhC,MAAI,gBAAgB,QAAQ,KAAK,EAC/B;OAAI,gBAAG,YAAY,YAAY,CAAC,WAAW,GAAG;IAC5C,MAAM,cAAc,MAAM,QACxB,oCACD;AACD,SAAK,YAAa,iBAAgB;GACnC;;AAEH,QAAM,KAAK,YAAY;CACxB;AAED,iBAAG,UAAU,aAAa,EAAE,WAAW,KAAM,EAAC;AAC9C,cAAa,UAAU,YAAY;AACnC,SAAQ,KAAK,KAAK,KAAK,QAAQ;CAE/B,MAAM,WAAW,eACb,CAAC,GAAG,kBAAkB,qBAAsB,IAC5C;CACJ,MAAM,CAAC,KAAKC,OAAK,GAAG,cAAc,SAAS;AAC3C,SAAQ,KAAK,iBAAiB,IAAI,GAAG,OAAK,KAAK,IAAI,CAAC,EAAE;AACtD,KAAI,KAAKA,QAAM,EAAE,KAAK,YAAa,EAAC;AACrC;AAED,eAAsB,gBAAgBC,WAAkC;CACtE,MAAM,OAAO,MAAM,MAAM,WAAW;EAClC,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC;CACF,MAAM,SAAS,MAAM,MAAM,6BAA6B;EACtD,aAAa;EACb,SAAS;EACT,UAAU;CACX,EAAC;CACF,MAAM,OAAO,MAAM,MAAM,oBAAoB;EAC3C,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC;CACF,MAAM,OAAO,SACX,MAAM,MAAM,oBAAoB;EAC9B,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC,EACF,GACD;CACD,MAAM,QAAQ,MAAM,MAAM,8BAA8B,EACtD,aAAa,MACd,EAAC;AAEF,uBAAsB;CAEtB,MAAM,aAAa,OAAO,OAAO,CAC9B,MAAM,IAAI,CACV,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CACpB,KAAK,KAAK;CAEb,MAAM,UAAU,qBAAQ;;iBAET,KAAK;;;;;;qBAMD,WAAW;;;;;;;;;sBASV,KAAK;uBACJ,KAAK;wBACJ,MAAM;;;;;;;;;IAS1B;CAEF,MAAM,aAAa,qBAAQ;;;;;kBAKXC,UAAQ;;;;;;;;;;;;;;;IAetB;CAEF,MAAMH,WAA6D;EACjE,UACE;EACF,gBAAgB;EAChB,SAAS,EAAE,MAAM,EAAE,YAAY,WAAY,EAAE;EAC7C,QAAQ,CAAE;EACV,MAAM,CAAE;CACT;CAED,MAAM,eAAe,MAAM,QAAQ,0BAA0B,EAC3D,SAAS,KACV,EAAC;AAEF,OAAM,iBAAiB,MAAM,UAAU,aAAa;AAEpD,SAAQ,IAAI,iBAAiB;AAC7B,SAAQ,IAAI,QAAQ,KAAK;AACzB,SAAQ,IAAI,kBAAkB;AAC9B,QAAO;AACR;;;;AC7ID,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAElC,CAAC,YAAY;CACX,MAAM,MAAM,iBAAgB,MAAM,EAAE,OAAO;EAAE,GAAG;EAAW,GAAG;CAAQ,EAAE,EAAC;CACzE,MAAM,WAAW,cAAc,QAAQ;CACvC,MAAM,CAAC,KAAK,GAAG,QAAQ,GAAG;AAE1B,SAAQ,KAAR;EACE,KAAK;AACH,WAAQ,WAAW,MAAM,eAAe,SAAS,SAAS;AAC1D;EACF,KAAK;AACH,WAAQ,WAAW,MAAM,cAAc,QAAQ;AAC/C;EACF;AACE,OAAI,IAAI,SAAS;AACf,YAAQ,KAAK,GAAG,QAAQ,EAAE;AAC1B;GACD;AACD,OAAI,IAAI,MAAM;AACZ,YAAQ,IAAI,SAAS;AACrB;GACD;AACD,WAAQ,WAAW,MAAM,gBAAgB,QAAQ;AACjD;CACH;AACF,IAAG"}
1
+ {"version":3,"file":"index.cjs","names":["cmd: string","args: string[]","options: { cwd?: string }","args","dir: string","err: any","packages: string[]","cwd?: string","cwd: string","pkgName: string","p: string","packageName: string","fileTree: Record<string, string | Record<string, unknown>>","base: string","version: string","version","message: string","options?: OmitTypeWithRequired<{ initial?: boolean }>","options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>","cmdArgs: string[]","helpInfo: string","pkgName: string","packages: string[]","cwd: string","prefix: string","name?: string","cmdArgs: string[]","name: string","fileTree: Record<string, string | Record<string, unknown>>","args","version: string","version"],"sources":["../../package.json","../../src/cli/shared.ts","../../src/cli/install.ts","../../src/cli/update.ts","../../src/cli/scaffold.ts","../../src/cli/index.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"0.9.9\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - Plugin framework extended from mioki for NapCat OneBot v11\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioki\",\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/jerryplusy/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/jerryplusy/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jerryplusy/mioku.git\",\n \"directory\": \"src/packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\"\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 \"mioki\": \"^0.16.0\",\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 \"openai\": \"^4.0.0\",\n \"puppeteer\": \"^23.10.0\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"systeminformation\": \"^5.30.7\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"@types/puppeteer\": \"^7.0.4\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import fs, { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport consola from \"consola\";\nimport dedent from \"dedent\";\nimport {\n clearCommandCache,\n commandExists,\n resolveCommand,\n runCommandInherit,\n} from \"../core/exec\";\n\nexport const DEFAULT_PACKAGES = [\n \"mioku\",\n \"mioku-plugin-boot\",\n \"mioku-plugin-help\",\n \"mioku-plugin-chat\",\n \"mioku-service-config\",\n \"mioku-service-ai\",\n \"mioku-service-screenshot\",\n \"mioku-service-help\",\n];\n\nexport const PLUGIN_PREFIX = \"mioku-plugin-\";\nexport const SERVICE_PREFIX = \"mioku-service-\";\n\nexport function run(\n cmd: string,\n args: string[] = [],\n options: { cwd?: string } = {},\n): void {\n runCommandInherit(cmd, args, options);\n}\n\nexport async function rmrf(dir: string, retries = 5): Promise<void> {\n for (let i = 0; i < retries; i++) {\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n return;\n } catch (err: any) {\n if (i === retries - 1) throw err;\n const code = err?.code;\n if (\n code === \"EPERM\" ||\n code === \"EBUSY\" ||\n code === \"ENOTEMPTY\" ||\n code === \"ENOENT\"\n ) {\n await new Promise((resolve) => setTimeout(resolve, 300 * (i + 1)));\n } else {\n throw err;\n }\n }\n }\n}\n\nexport function hasCommand(cmd: string): boolean {\n return commandExists(cmd);\n}\n\nfunction findNpmPath(): string | null {\n const resolved = resolveCommand(\"npm\");\n if (resolved) return resolved;\n if (process.platform !== \"win32\") return null;\n\n const fallbacks = [\n path.join(process.env.ProgramFiles || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env[\"ProgramFiles(x86)\"] || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env.APPDATA || \"\", \"npm\", \"npm.cmd\"),\n ];\n\n return fallbacks.find((candidate) => resolveCommand(candidate)) ?? null;\n}\n\nexport function ensurePackageManager(): void {\n if (hasCommand(\"bun\")) return;\n console.log(\"安装 bun...\");\n const npmPath = findNpmPath();\n if (!npmPath) {\n consola.error(\"未找到 npm,请确保 Node.js 已安装并包含 npm\");\n process.exit(1);\n }\n run(npmPath, [\"install\", \"-g\", \"bun\"]);\n // bun was just put on PATH; drop the cached miss so the next lookup finds it.\n clearCommandCache();\n}\n\nexport function getAddCommand(packages: string[]): [string, string[]] {\n return [\"bun\", [\"add\", ...packages]];\n}\n\nexport function normalizePackageName(input: string): string {\n if (input.startsWith(PLUGIN_PREFIX) || input.startsWith(SERVICE_PREFIX)) {\n return input;\n }\n if (input.startsWith(\"mioku-\")) return input;\n return `${PLUGIN_PREFIX}${input}`;\n}\n\nexport function detectType(name: string): \"plugin\" | \"service\" | \"unknown\" {\n if (name.startsWith(PLUGIN_PREFIX)) return \"plugin\";\n if (name.startsWith(SERVICE_PREFIX)) return \"service\";\n return \"unknown\";\n}\n\nexport function execAdd(packages: string[], cwd?: string): void {\n const [cmd, args] = getAddCommand(packages);\n console.log(`执行: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd });\n}\n\nexport function appendToMiokiPlugins(cwd: string, pkgName: string): boolean {\n if (!pkgName.startsWith(PLUGIN_PREFIX)) return false;\n const shortName = pkgName.slice(PLUGIN_PREFIX.length);\n\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n const mioki = pkg.mioki ?? {};\n const plugins = Array.isArray(mioki.plugins) ? [...mioki.plugins] : [];\n if (plugins.includes(shortName)) return false;\n\n plugins.push(shortName);\n pkg.mioki = { ...mioki, plugins };\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n return true;\n}\n\nexport async function getInstalledPackages(cwd: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(readFileSync(path.join(cwd, \"package.json\"), \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return Object.keys(deps).filter((k) => k.startsWith(\"mioku-\"));\n } catch {\n return [];\n }\n}\n\nexport function withRoot(p: string): string {\n return path.resolve(process.cwd(), p);\n}\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport async function fetchNpmKeywords(\n packageName: string,\n): Promise<string[] | null> {\n try {\n const res = await fetch(`${NPM_REGISTRY}/${encodeURIComponent(packageName)}`, {\n headers: { Accept: \"application/json\", \"User-Agent\": \"mioku-cli\" },\n });\n if (!res.ok) return null;\n const data = (await res.json()) as any;\n const latestVersion = String(data?.[\"dist-tags\"]?.latest || \"\").trim();\n const keywords = latestVersion\n ? data?.versions?.[latestVersion]?.keywords\n : data?.keywords;\n return Array.isArray(keywords) ? keywords.map(String) : [];\n } catch {\n return null;\n }\n}\n\nexport function gracefullyExit(): void {\n console.log(\"Bye!\");\n process.exit(0);\n}\n\nexport function makeFileTree(\n fileTree: Record<string, string | Record<string, unknown>>,\n base: string,\n): void {\n for (const [name, content] of Object.entries(fileTree)) {\n if (typeof content === \"object\" && content !== null) {\n const subPath = `${base}/${name}`;\n if (!fs.existsSync(subPath)) fs.mkdirSync(subPath, { recursive: true });\n for (const [subName, subContent] of Object.entries(content)) {\n if (typeof subContent === \"object\") {\n makeFileTree(\n subContent as Record<string, string | Record<string, unknown>>,\n path.join(subPath, subName),\n );\n } else {\n fs.writeFileSync(`${subPath}/${subName}`, subContent as string);\n }\n }\n } else {\n const filePath = `${base}/${name}`;\n const dirname = path.dirname(filePath);\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });\n fs.writeFileSync(filePath, content as string);\n }\n }\n}\n\nexport function buildHelpInfo(version: string): string {\n return dedent(`\n mioku 命令行工具 v${version}\n\n 用法: mioku <命令> [选项]\n\n 命令:\n install plugin <名称> 安装插件,自动补全 mioku-plugin- 前缀\n install service <名称> 安装服务,自动补全 mioku-service- 前缀\n update [包名|self|all] 更新插件或服务\n update - 检查可用更新\n update all - 更新所有 mioku- 包\n update self - 更新 mioku 框架\n update xxx - 更新指定包\n\n 选项:\n -h, --help 显示帮助信息\n -v, --version 显示版本号\n --name <name> 指定项目/文件夹名称,默认 mioku-bot\n --protocol <protocol> 指定 NapCat 协议,默认 ws\n --host <host> 指定 NapCat 主机,默认 localhost\n --port <port> 指定 NapCat 端口,默认 3001\n --token <token> 指定 NapCat 连接 Token,默认空\n --prefix <prefix> 指定命令前缀,默认 #\n --owners <owners> 指定主人 QQ,英文逗号分隔,必填\n --admins <admins> 指定管理员 QQ,英文逗号分隔,可空\n --use-npm-mirror 使用 npm 镜像源加速依赖安装,默认否\n `);\n}\n\ntype OmitTypeWithRequired<T> = Omit<T, \"type\" | \"required\"> & {\n required?: boolean;\n};\n\nexport async function confirm(\n message: string,\n options?: OmitTypeWithRequired<{ initial?: boolean }>,\n): Promise<boolean> {\n return consola.prompt(message, {\n type: \"confirm\",\n cancel: \"reject\",\n ...options,\n });\n}\n\nexport async function input(\n message: string,\n options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>,\n): Promise<string> {\n const result = await consola.prompt(message, {\n type: \"text\",\n cancel: \"reject\",\n ...options,\n });\n if (options?.required && !result) return input(message, options);\n return result;\n}\n","import consola from \"consola\";\nimport {\n ensurePackageManager,\n appendToMiokiPlugins,\n execAdd,\n fetchNpmKeywords,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n confirm,\n} from \"./shared\";\n\nexport async function installCommand(\n cmdArgs: string[],\n helpInfo: string,\n): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [type, name] = cmdArgs;\n\n if (!type || !name) {\n consola.error(\n \"请指定类型和名称: mioku install plugin <名称> 或 mioku install service <名称>\",\n );\n console.log(helpInfo);\n return 1;\n }\n\n if (type !== \"plugin\" && type !== \"service\") {\n consola.error(`无效的类型 \"${type}\",请使用 plugin 或 service`);\n console.log(helpInfo);\n return 1;\n }\n\n const prefix = type === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n const normalized = `${prefix}${name}`;\n\n if (type === \"plugin\") {\n const proceed = await warnIfPrivatePlugin(normalized);\n if (!proceed) {\n consola.info(\"已取消安装\");\n return 1;\n }\n }\n\n try {\n execAdd([normalized], cwd);\n consola.success(`已安装 ${normalized}`);\n\n if (type === \"plugin\") {\n const shortName = normalized.slice(PLUGIN_PREFIX.length);\n if (appendToMiokiPlugins(cwd, normalized)) {\n consola.success(`已在 mioki.plugins 中启用 ${shortName}`);\n } else {\n consola.info(`${shortName} 已在 mioki.plugins 中,跳过`);\n }\n }\n return 0;\n } catch {\n consola.error(`安装失败: ${normalized}`);\n return 1;\n }\n}\n\nasync function warnIfPrivatePlugin(pkgName: string): Promise<boolean> {\n const keywords = await fetchNpmKeywords(pkgName);\n if (keywords === null) return true;\n if (keywords.includes(\"mioku\")) return true;\n\n consola.warn(`${pkgName} 看起来是私有插件\"`);\n consola.warn(\"该插件未上架插件市场,可能存在风险\");\n return confirm(\"仍要继续安装吗?\", { initial: false });\n}\n","import consola from \"consola\";\nimport {\n run,\n ensurePackageManager,\n getInstalledPackages,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n} from \"./shared\";\n\nasync function updatePackages(packages: string[], cwd: string): Promise<void> {\n if (packages.length === 0) {\n consola.info(\"未找到 mioku- 相关依赖\");\n return;\n }\n console.log(`执行: bun update ${packages.join(\" \")} --latest`);\n run(\"bun\", [\"update\", ...packages, \"--latest\"], { cwd });\n}\n\nasync function updateByPrefix(\n prefix: string,\n cwd: string,\n name?: string,\n): Promise<void> {\n if (name) {\n const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;\n console.log(`执行: bun update ${normalized} --latest`);\n run(\"bun\", [\"update\", normalized, \"--latest\"], { cwd });\n return;\n }\n const packages = (await getInstalledPackages(cwd)).filter((p) =>\n p.startsWith(prefix),\n );\n if (packages.length === 0) {\n consola.info(`未找到 ${prefix}* 相关依赖`);\n return;\n }\n await updatePackages(packages, cwd);\n}\n\nexport async function updateCommand(cmdArgs: string[]): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [target, name] = cmdArgs;\n\n if (!target || target === \"check\") {\n run(\"bun\", [\"update\", \"-i\"], { cwd });\n return 0;\n }\n\n if (target === \"all\") {\n await updatePackages(await getInstalledPackages(cwd), cwd);\n return 0;\n }\n\n if (target === \"self\") {\n console.log(\"执行: bun update mioku --latest\");\n run(\"bun\", [\"update\", \"mioku\", \"--latest\"], { cwd });\n return 0;\n }\n\n if (target === \"plugin\" || target === \"service\") {\n const prefix = target === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n await updateByPrefix(prefix, cwd, name);\n return 0;\n }\n\n console.log(`执行: bun update ${target} --latest`);\n run(\"bun\", [\"update\", target, \"--latest\"], { cwd });\n return 0;\n}\n","import fs from \"node:fs\";\nimport dedent from \"dedent\";\nimport {\n DEFAULT_PACKAGES,\n ensurePackageManager,\n getAddCommand,\n run,\n rmrf,\n withRoot,\n gracefullyExit,\n makeFileTree,\n input,\n confirm,\n} from \"./shared\";\n\nasync function createNewProject(\n name: string,\n fileTree: Record<string, string | Record<string, unknown>>,\n installWebui = false,\n): Promise<void> {\n const projectPath = withRoot(`./${name}`);\n\n if (fs.existsSync(projectPath)) {\n const overwrite = await confirm(`项目 ${name} 已存在,是否覆盖?`);\n if (!overwrite) gracefullyExit();\n\n if (projectPath === process.cwd()) {\n if (fs.readdirSync(projectPath).length !== 0) {\n const confirmOver = await confirm(\n \"项目路径与当前路径相同,将删除当前目录下所有内容再创建,是否继续?\",\n );\n if (!confirmOver) gracefullyExit();\n }\n }\n await rmrf(projectPath);\n }\n\n fs.mkdirSync(projectPath, { recursive: true });\n makeFileTree(fileTree, projectPath);\n console.log(`项目 ${name} 创建成功!`);\n\n const packages = installWebui\n ? [...DEFAULT_PACKAGES, \"mioku-service-webui\"]\n : DEFAULT_PACKAGES;\n const [cmd, args] = getAddCommand(packages);\n console.log(`正在安装 Mioku 依赖: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd: projectPath });\n}\n\nexport async function scaffoldCommand(version: string): Promise<number> {\n const name = await input(\"请输入项目名称\", {\n default: \"mioku-bot\",\n placeholder: \"mioku-bot\",\n required: true,\n });\n const owners = await input(\"请输入主人 QQ (最高权限,英文逗号分隔,必填)\", {\n placeholder: \"请输入\",\n default: \"\",\n required: true,\n });\n const host = await input(\"请输入 NapCat WS 主机\", {\n default: \"localhost\",\n placeholder: \"localhost\",\n required: true,\n });\n const port = parseInt(\n await input(\"请输入 NapCat WS 端口\", {\n default: \"3001\",\n placeholder: \"3001\",\n required: true,\n }),\n 10,\n );\n const token = await input(\"请输入 NapCat WS Token(如无则留空)\", {\n placeholder: \"请输入\",\n });\n\n ensurePackageManager();\n\n const ownersList = String(owners)\n .split(\",\")\n .map((o) => o.trim())\n .join(\", \");\n\n const pkgJson = dedent(`\n {\n \"name\": \"${name}\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {},\n \"mioki\": {\n \"prefix\": \"#\",\n \"owners\": [${ownersList}],\n \"admins\": [],\n \"plugins\": [\"boot\", \"help\", \"chat\", \"demo\"],\n \"log_level\": \"info\",\n \"online_push\": false,\n \"error_push\": false,\n \"napcat\": [\n {\n \"protocol\": \"ws\",\n \"port\": ${port},\n \"host\": \"${host}\",\n \"token\": \"${token}\"\n }\n ]\n },\n \"scripts\": {\n \"start\": \"bun run app.ts\",\n \"dev\": \"bun run --watch app.ts\"\n }\n }\n `);\n\n const pluginCode = dedent(`\n import { definePlugin } from 'mioku'\n\n export default definePlugin({\n name: 'demo',\n version: '${version}',\n async setup(ctx) {\n ctx.logger.info('Demo 插件已加载')\n\n ctx.handle('message', async (e) => {\n if (e.raw_message === 'hello') {\n e.reply('world', true)\n }\n })\n\n return () => {\n ctx.logger.info('Demo 插件已卸载')\n }\n },\n })\n `);\n\n const fileTree: Record<string, string | Record<string, unknown>> = {\n \"app.ts\":\n \"import { start } from 'mioku'\\n\\nstart({ cwd: import.meta.dirname }).then()\\n\",\n \"package.json\": pkgJson,\n plugins: { demo: { \"index.ts\": pluginCode } },\n config: {},\n data: {},\n };\n\n const installWebui = await confirm(\"是否安装 WebUI 管理面板?(建议安装)\", {\n initial: true,\n });\n\n await createNewProject(name, fileTree, installWebui);\n\n console.log(\"\\n若需启动机器人,请运行:\");\n console.log(\" cd\", name);\n console.log(\" bun run start\");\n return 0;\n}\n","#!/usr/bin/env node\n\nimport mri from \"mri\";\nimport { version } from \"../../package.json\";\nimport { buildHelpInfo } from \"./shared\";\nimport { installCommand } from \"./install\";\nimport { updateCommand } from \"./update\";\nimport { scaffoldCommand } from \"./scaffold\";\n\ninterface CliOptions {\n help?: boolean;\n version?: boolean;\n}\n\nconst args = process.argv.slice(2);\n\n(async () => {\n const cli = mri<CliOptions>(args, { alias: { v: \"version\", h: \"help\" } });\n const helpInfo = buildHelpInfo(version);\n const [cmd, ...cmdArgs] = args;\n\n switch (cmd) {\n case \"install\":\n process.exitCode = await installCommand(cmdArgs, helpInfo);\n return;\n case \"update\":\n process.exitCode = await updateCommand(cmdArgs);\n return;\n default:\n if (cli.version) {\n console.log(`v${version}`);\n return;\n }\n if (cli.help) {\n console.log(helpInfo);\n return;\n }\n process.exitCode = await scaffoldCommand(version);\n return;\n }\n})();\n"],"mappings":";;;;;;;;;cAGa;;;;ACQb,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AAED,MAAa,gBAAgB;AAC7B,MAAa,iBAAiB;AAE9B,SAAgB,IACdA,KACAC,SAAiB,CAAE,GACnBC,UAA4B,CAAE,GACxB;AACN,gCAAkB,KAAKC,QAAM,QAAQ;AACtC;AAED,eAAsB,KAAKC,KAAa,UAAU,GAAkB;AAClE,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,IAC3B,KAAI;AACF,kBAAG,OAAO,KAAK;GAAE,WAAW;GAAM,OAAO;EAAM,EAAC;AAChD;CACD,SAAQC,KAAU;AACjB,MAAI,MAAM,UAAU,EAAG,OAAM;EAC7B,MAAM,OAAO,KAAK;AAClB,MACE,SAAS,WACT,SAAS,WACT,SAAS,eACT,SAAS,SAET,OAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,OAAO,IAAI,GAAG;MAEjE,OAAM;CAET;AAEJ;AAED,SAAgB,WAAWL,KAAsB;AAC/C,QAAO,2BAAc,IAAI;AAC1B;AAED,SAAS,cAA6B;CACpC,MAAM,WAAW,4BAAe,MAAM;AACtC,KAAI,SAAU,QAAO;AACrB,KAAI,QAAQ,aAAa,QAAS,QAAO;CAEzC,MAAM,YAAY;EAChB,kBAAK,KAAK,QAAQ,IAAI,gBAAgB,IAAI,UAAU,UAAU;EAC9D,kBAAK,KAAK,QAAQ,IAAI,wBAAwB,IAAI,UAAU,UAAU;EACtE,kBAAK,KAAK,QAAQ,IAAI,WAAW,IAAI,OAAO,UAAU;CACvD;AAED,QAAO,UAAU,KAAK,CAAC,cAAc,4BAAe,UAAU,CAAC,IAAI;AACpE;AAED,SAAgB,uBAA6B;AAC3C,KAAI,WAAW,MAAM,CAAE;AACvB,SAAQ,IAAI,YAAY;CACxB,MAAM,UAAU,aAAa;AAC7B,MAAK,SAAS;AACZ,kBAAQ,MAAM,iCAAiC;AAC/C,UAAQ,KAAK,EAAE;CAChB;AACD,KAAI,SAAS;EAAC;EAAW;EAAM;CAAM,EAAC;AAEtC,iCAAmB;AACpB;AAED,SAAgB,cAAcM,UAAwC;AACpE,QAAO,CAAC,OAAO,CAAC,OAAO,GAAG,QAAS,CAAC;AACrC;AAgBD,SAAgB,QAAQA,UAAoBC,KAAoB;CAC9D,MAAM,CAAC,KAAKJ,OAAK,GAAG,cAAc,SAAS;AAC3C,SAAQ,KAAK,MAAM,IAAI,GAAG,OAAK,KAAK,IAAI,CAAC,EAAE;AAC3C,KAAI,KAAKA,QAAM,EAAE,IAAK,EAAC;AACxB;AAED,SAAgB,qBAAqBK,KAAaC,SAA0B;AAC1E,MAAK,QAAQ,WAAW,cAAc,CAAE,QAAO;CAC/C,MAAM,YAAY,QAAQ,MAAM,cAAc,OAAO;CAErD,MAAM,kBAAkB,kBAAK,KAAK,KAAK,eAAe;AACtD,MAAK,gBAAG,WAAW,gBAAgB,CAAE,QAAO;CAE5C,MAAM,MAAM,KAAK,MAAM,0BAAa,iBAAiB,QAAQ,CAAC;CAC9D,MAAM,QAAQ,IAAI,SAAS,CAAE;CAC7B,MAAM,UAAU,MAAM,QAAQ,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,OAAQ,IAAG,CAAE;AACtE,KAAI,QAAQ,SAAS,UAAU,CAAE,QAAO;AAExC,SAAQ,KAAK,UAAU;AACvB,KAAI,QAAQ;EAAE,GAAG;EAAO;CAAS;AACjC,iBAAG,cAAc,kBAAkB,EAAE,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC,IAAI;AACtE,QAAO;AACR;AAED,eAAsB,qBAAqBD,KAAgC;AACzE,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,0BAAa,kBAAK,KAAK,KAAK,eAAe,EAAE,QAAQ,CAAC;EAC7E,MAAM,OAAO;GAAE,GAAG,IAAI;GAAc,GAAG,IAAI;EAAiB;AAC5D,SAAO,OAAO,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,CAAC;CAC/D,QAAO;AACN,SAAO,CAAE;CACV;AACF;AAED,SAAgB,SAASE,GAAmB;AAC1C,QAAO,kBAAK,QAAQ,QAAQ,KAAK,EAAE,EAAE;AACtC;AAED,MAAM,eAAe;AAErB,eAAsB,iBACpBC,aAC0B;AAC1B,KAAI;EACF,MAAM,MAAM,MAAM,OAAO,EAAE,aAAa,GAAG,mBAAmB,YAAY,CAAC,GAAG,EAC5E,SAAS;GAAE,QAAQ;GAAoB,cAAc;EAAa,EACnE,EAAC;AACF,OAAK,IAAI,GAAI,QAAO;EACpB,MAAM,OAAQ,MAAM,IAAI,MAAM;EAC9B,MAAM,gBAAgB,OAAO,OAAO,cAAc,UAAU,GAAG,CAAC,MAAM;EACtE,MAAM,WAAW,gBACb,MAAM,WAAW,gBAAgB,WACjC,MAAM;AACV,SAAO,MAAM,QAAQ,SAAS,GAAG,SAAS,IAAI,OAAO,GAAG,CAAE;CAC3D,QAAO;AACN,SAAO;CACR;AACF;AAED,SAAgB,iBAAuB;AACrC,SAAQ,IAAI,OAAO;AACnB,SAAQ,KAAK,EAAE;AAChB;AAED,SAAgB,aACdC,UACAC,MACM;AACN,MAAK,MAAM,CAAC,MAAM,QAAQ,IAAI,OAAO,QAAQ,SAAS,CACpD,YAAW,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,WAAW,EAAE,KAAK,GAAG,KAAK;AAChC,OAAK,gBAAG,WAAW,QAAQ,CAAE,iBAAG,UAAU,SAAS,EAAE,WAAW,KAAM,EAAC;AACvE,OAAK,MAAM,CAAC,SAAS,WAAW,IAAI,OAAO,QAAQ,QAAQ,CACzD,YAAW,eAAe,SACxB,cACE,YACA,kBAAK,KAAK,SAAS,QAAQ,CAC5B;MAED,iBAAG,eAAe,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAqB;CAGpE,OAAM;EACL,MAAM,YAAY,EAAE,KAAK,GAAG,KAAK;EACjC,MAAM,UAAU,kBAAK,QAAQ,SAAS;AACtC,OAAK,gBAAG,WAAW,QAAQ,CAAE,iBAAG,UAAU,SAAS,EAAE,WAAW,KAAM,EAAC;AACvE,kBAAG,cAAc,UAAU,QAAkB;CAC9C;AAEJ;AAED,SAAgB,cAAcC,WAAyB;AACrD,QAAO,qBAAQ;iBACAC,UAAQ;;;;;;;;;;;;;;;;;;;;;;;;;IAyBrB;AACH;AAMD,eAAsB,QACpBC,SACAC,SACkB;AAClB,QAAO,gBAAQ,OAAO,SAAS;EAC7B,MAAM;EACN,QAAQ;EACR,GAAG;CACJ,EAAC;AACH;AAED,eAAsB,MACpBD,SACAE,SACiB;CACjB,MAAM,SAAS,MAAM,gBAAQ,OAAO,SAAS;EAC3C,MAAM;EACN,QAAQ;EACR,GAAG;CACJ,EAAC;AACF,KAAI,SAAS,aAAa,OAAQ,QAAO,MAAM,SAAS,QAAQ;AAChE,QAAO;AACR;;;;AChPD,eAAsB,eACpBC,SACAC,UACiB;AACjB,uBAAsB;CACtB,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,CAAC,MAAM,KAAK,GAAG;AAErB,MAAK,SAAS,MAAM;AAClB,kBAAQ,MACN,mEACD;AACD,UAAQ,IAAI,SAAS;AACrB,SAAO;CACR;AAED,KAAI,SAAS,YAAY,SAAS,WAAW;AAC3C,kBAAQ,OAAO,SAAS,KAAK,wBAAwB;AACrD,UAAQ,IAAI,SAAS;AACrB,SAAO;CACR;CAED,MAAM,SAAS,SAAS,WAAW,gBAAgB;CACnD,MAAM,cAAc,EAAE,OAAO,EAAE,KAAK;AAEpC,KAAI,SAAS,UAAU;EACrB,MAAM,UAAU,MAAM,oBAAoB,WAAW;AACrD,OAAK,SAAS;AACZ,mBAAQ,KAAK,QAAQ;AACrB,UAAO;EACR;CACF;AAED,KAAI;AACF,UAAQ,CAAC,UAAW,GAAE,IAAI;AAC1B,kBAAQ,SAAS,MAAM,WAAW,EAAE;AAEpC,MAAI,SAAS,UAAU;GACrB,MAAM,YAAY,WAAW,MAAM,cAAc,OAAO;AACxD,OAAI,qBAAqB,KAAK,WAAW,CACvC,iBAAQ,SAAS,uBAAuB,UAAU,EAAE;OAEpD,iBAAQ,MAAM,EAAE,UAAU,wBAAwB;EAErD;AACD,SAAO;CACR,QAAO;AACN,kBAAQ,OAAO,QAAQ,WAAW,EAAE;AACpC,SAAO;CACR;AACF;AAED,eAAe,oBAAoBC,SAAmC;CACpE,MAAM,WAAW,MAAM,iBAAiB,QAAQ;AAChD,KAAI,aAAa,KAAM,QAAO;AAC9B,KAAI,SAAS,SAAS,QAAQ,CAAE,QAAO;AAEvC,iBAAQ,MAAM,EAAE,QAAQ,YAAY;AACpC,iBAAQ,KAAK,oBAAoB;AACjC,QAAO,QAAQ,YAAY,EAAE,SAAS,MAAO,EAAC;AAC/C;;;;AC9DD,eAAe,eAAeC,UAAoBC,KAA4B;AAC5E,KAAI,SAAS,WAAW,GAAG;AACzB,kBAAQ,KAAK,kBAAkB;AAC/B;CACD;AACD,SAAQ,KAAK,iBAAiB,SAAS,KAAK,IAAI,CAAC,WAAW;AAC5D,KAAI,OAAO;EAAC;EAAU,GAAG;EAAU;CAAW,GAAE,EAAE,IAAK,EAAC;AACzD;AAED,eAAe,eACbC,QACAD,KACAE,MACe;AACf,KAAI,MAAM;EACR,MAAM,aAAa,KAAK,WAAW,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,KAAK;AACrE,UAAQ,KAAK,iBAAiB,WAAW,WAAW;AACpD,MAAI,OAAO;GAAC;GAAU;GAAY;EAAW,GAAE,EAAE,IAAK,EAAC;AACvD;CACD;CACD,MAAM,WAAW,CAAC,MAAM,qBAAqB,IAAI,EAAE,OAAO,CAAC,MACzD,EAAE,WAAW,OAAO,CACrB;AACD,KAAI,SAAS,WAAW,GAAG;AACzB,kBAAQ,MAAM,MAAM,OAAO,QAAQ;AACnC;CACD;AACD,OAAM,eAAe,UAAU,IAAI;AACpC;AAED,eAAsB,cAAcC,SAAoC;AACtE,uBAAsB;CACtB,MAAM,MAAM,QAAQ,KAAK;CACzB,MAAM,CAAC,QAAQ,KAAK,GAAG;AAEvB,MAAK,UAAU,WAAW,SAAS;AACjC,MAAI,OAAO,CAAC,UAAU,IAAK,GAAE,EAAE,IAAK,EAAC;AACrC,SAAO;CACR;AAED,KAAI,WAAW,OAAO;AACpB,QAAM,eAAe,MAAM,qBAAqB,IAAI,EAAE,IAAI;AAC1D,SAAO;CACR;AAED,KAAI,WAAW,QAAQ;AACrB,UAAQ,IAAI,gCAAgC;AAC5C,MAAI,OAAO;GAAC;GAAU;GAAS;EAAW,GAAE,EAAE,IAAK,EAAC;AACpD,SAAO;CACR;AAED,KAAI,WAAW,YAAY,WAAW,WAAW;EAC/C,MAAM,SAAS,WAAW,WAAW,gBAAgB;AACrD,QAAM,eAAe,QAAQ,KAAK,KAAK;AACvC,SAAO;CACR;AAED,SAAQ,KAAK,iBAAiB,OAAO,WAAW;AAChD,KAAI,OAAO;EAAC;EAAU;EAAQ;CAAW,GAAE,EAAE,IAAK,EAAC;AACnD,QAAO;AACR;;;;ACtDD,eAAe,iBACbC,MACAC,UACA,eAAe,OACA;CACf,MAAM,cAAc,UAAU,IAAI,KAAK,EAAE;AAEzC,KAAI,gBAAG,WAAW,YAAY,EAAE;EAC9B,MAAM,YAAY,MAAM,SAAS,KAAK,KAAK,YAAY;AACvD,OAAK,UAAW,iBAAgB;AAEhC,MAAI,gBAAgB,QAAQ,KAAK,EAC/B;OAAI,gBAAG,YAAY,YAAY,CAAC,WAAW,GAAG;IAC5C,MAAM,cAAc,MAAM,QACxB,oCACD;AACD,SAAK,YAAa,iBAAgB;GACnC;;AAEH,QAAM,KAAK,YAAY;CACxB;AAED,iBAAG,UAAU,aAAa,EAAE,WAAW,KAAM,EAAC;AAC9C,cAAa,UAAU,YAAY;AACnC,SAAQ,KAAK,KAAK,KAAK,QAAQ;CAE/B,MAAM,WAAW,eACb,CAAC,GAAG,kBAAkB,qBAAsB,IAC5C;CACJ,MAAM,CAAC,KAAKC,OAAK,GAAG,cAAc,SAAS;AAC3C,SAAQ,KAAK,iBAAiB,IAAI,GAAG,OAAK,KAAK,IAAI,CAAC,EAAE;AACtD,KAAI,KAAKA,QAAM,EAAE,KAAK,YAAa,EAAC;AACrC;AAED,eAAsB,gBAAgBC,WAAkC;CACtE,MAAM,OAAO,MAAM,MAAM,WAAW;EAClC,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC;CACF,MAAM,SAAS,MAAM,MAAM,6BAA6B;EACtD,aAAa;EACb,SAAS;EACT,UAAU;CACX,EAAC;CACF,MAAM,OAAO,MAAM,MAAM,oBAAoB;EAC3C,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC;CACF,MAAM,OAAO,SACX,MAAM,MAAM,oBAAoB;EAC9B,SAAS;EACT,aAAa;EACb,UAAU;CACX,EAAC,EACF,GACD;CACD,MAAM,QAAQ,MAAM,MAAM,8BAA8B,EACtD,aAAa,MACd,EAAC;AAEF,uBAAsB;CAEtB,MAAM,aAAa,OAAO,OAAO,CAC9B,MAAM,IAAI,CACV,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CACpB,KAAK,KAAK;CAEb,MAAM,UAAU,qBAAQ;;iBAET,KAAK;;;;;;qBAMD,WAAW;;;;;;;;;sBASV,KAAK;uBACJ,KAAK;wBACJ,MAAM;;;;;;;;;IAS1B;CAEF,MAAM,aAAa,qBAAQ;;;;;kBAKXC,UAAQ;;;;;;;;;;;;;;;IAetB;CAEF,MAAMH,WAA6D;EACjE,UACE;EACF,gBAAgB;EAChB,SAAS,EAAE,MAAM,EAAE,YAAY,WAAY,EAAE;EAC7C,QAAQ,CAAE;EACV,MAAM,CAAE;CACT;CAED,MAAM,eAAe,MAAM,QAAQ,0BAA0B,EAC3D,SAAS,KACV,EAAC;AAEF,OAAM,iBAAiB,MAAM,UAAU,aAAa;AAEpD,SAAQ,IAAI,iBAAiB;AAC7B,SAAQ,IAAI,QAAQ,KAAK;AACzB,SAAQ,IAAI,kBAAkB;AAC9B,QAAO;AACR;;;;AC7ID,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AAElC,CAAC,YAAY;CACX,MAAM,MAAM,iBAAgB,MAAM,EAAE,OAAO;EAAE,GAAG;EAAW,GAAG;CAAQ,EAAE,EAAC;CACzE,MAAM,WAAW,cAAc,QAAQ;CACvC,MAAM,CAAC,KAAK,GAAG,QAAQ,GAAG;AAE1B,SAAQ,KAAR;EACE,KAAK;AACH,WAAQ,WAAW,MAAM,eAAe,SAAS,SAAS;AAC1D;EACF,KAAK;AACH,WAAQ,WAAW,MAAM,cAAc,QAAQ;AAC/C;EACF;AACE,OAAI,IAAI,SAAS;AACf,YAAQ,KAAK,GAAG,QAAQ,EAAE;AAC1B;GACD;AACD,OAAI,IAAI,MAAM;AACZ,YAAQ,IAAI,SAAS;AACrB;GACD;AACD,WAAQ,WAAW,MAAM,gBAAgB,QAAQ;AACjD;CACH;AACF,IAAG"}
package/dist/cli/index.js CHANGED
@@ -7,7 +7,7 @@ import consola from "consola";
7
7
  import dedent from "dedent";
8
8
 
9
9
  //#region package.json
10
- var version = "0.9.8";
10
+ var version = "0.9.9";
11
11
 
12
12
  //#endregion
13
13
  //#region src/cli/shared.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["cmd: string","args: string[]","options: { cwd?: string }","args","dir: string","err: any","packages: string[]","cwd?: string","cwd: string","pkgName: string","p: string","packageName: string","fileTree: Record<string, string | Record<string, unknown>>","base: string","version: string","version","message: string","options?: OmitTypeWithRequired<{ initial?: boolean }>","options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>","cmdArgs: string[]","helpInfo: string","pkgName: string","packages: string[]","cwd: string","prefix: string","name?: string","cmdArgs: string[]","name: string","fileTree: Record<string, string | Record<string, unknown>>","args","version: string","version"],"sources":["../../package.json","../../src/cli/shared.ts","../../src/cli/install.ts","../../src/cli/update.ts","../../src/cli/scaffold.ts","../../src/cli/index.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"0.9.8\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - Plugin framework extended from mioki for NapCat OneBot v11\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioki\",\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/jerryplusy/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/jerryplusy/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jerryplusy/mioku.git\",\n \"directory\": \"src/packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\"\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 \"mioki\": \"^0.16.0\",\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 \"openai\": \"^4.0.0\",\n \"puppeteer\": \"^23.10.0\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"systeminformation\": \"^5.30.7\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"@types/puppeteer\": \"^7.0.4\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import fs, { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport consola from \"consola\";\nimport dedent from \"dedent\";\nimport {\n clearCommandCache,\n commandExists,\n resolveCommand,\n runCommandInherit,\n} from \"../core/exec\";\n\nexport const DEFAULT_PACKAGES = [\n \"mioku\",\n \"mioku-plugin-boot\",\n \"mioku-plugin-help\",\n \"mioku-plugin-chat\",\n \"mioku-service-config\",\n \"mioku-service-ai\",\n \"mioku-service-screenshot\",\n \"mioku-service-help\",\n];\n\nexport const PLUGIN_PREFIX = \"mioku-plugin-\";\nexport const SERVICE_PREFIX = \"mioku-service-\";\n\nexport function run(\n cmd: string,\n args: string[] = [],\n options: { cwd?: string } = {},\n): void {\n runCommandInherit(cmd, args, options);\n}\n\nexport async function rmrf(dir: string, retries = 5): Promise<void> {\n for (let i = 0; i < retries; i++) {\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n return;\n } catch (err: any) {\n if (i === retries - 1) throw err;\n const code = err?.code;\n if (\n code === \"EPERM\" ||\n code === \"EBUSY\" ||\n code === \"ENOTEMPTY\" ||\n code === \"ENOENT\"\n ) {\n await new Promise((resolve) => setTimeout(resolve, 300 * (i + 1)));\n } else {\n throw err;\n }\n }\n }\n}\n\nexport function hasCommand(cmd: string): boolean {\n return commandExists(cmd);\n}\n\nfunction findNpmPath(): string | null {\n const resolved = resolveCommand(\"npm\");\n if (resolved) return resolved;\n if (process.platform !== \"win32\") return null;\n\n const fallbacks = [\n path.join(process.env.ProgramFiles || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env[\"ProgramFiles(x86)\"] || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env.APPDATA || \"\", \"npm\", \"npm.cmd\"),\n ];\n\n return fallbacks.find((candidate) => resolveCommand(candidate)) ?? null;\n}\n\nexport function ensurePackageManager(): void {\n if (hasCommand(\"bun\")) return;\n console.log(\"安装 bun...\");\n const npmPath = findNpmPath();\n if (!npmPath) {\n consola.error(\"未找到 npm,请确保 Node.js 已安装并包含 npm\");\n process.exit(1);\n }\n run(npmPath, [\"install\", \"-g\", \"bun\"]);\n // bun was just put on PATH; drop the cached miss so the next lookup finds it.\n clearCommandCache();\n}\n\nexport function getAddCommand(packages: string[]): [string, string[]] {\n return [\"bun\", [\"add\", ...packages]];\n}\n\nexport function normalizePackageName(input: string): string {\n if (input.startsWith(PLUGIN_PREFIX) || input.startsWith(SERVICE_PREFIX)) {\n return input;\n }\n if (input.startsWith(\"mioku-\")) return input;\n return `${PLUGIN_PREFIX}${input}`;\n}\n\nexport function detectType(name: string): \"plugin\" | \"service\" | \"unknown\" {\n if (name.startsWith(PLUGIN_PREFIX)) return \"plugin\";\n if (name.startsWith(SERVICE_PREFIX)) return \"service\";\n return \"unknown\";\n}\n\nexport function execAdd(packages: string[], cwd?: string): void {\n const [cmd, args] = getAddCommand(packages);\n console.log(`执行: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd });\n}\n\nexport function appendToMiokiPlugins(cwd: string, pkgName: string): boolean {\n if (!pkgName.startsWith(PLUGIN_PREFIX)) return false;\n const shortName = pkgName.slice(PLUGIN_PREFIX.length);\n\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n const mioki = pkg.mioki ?? {};\n const plugins = Array.isArray(mioki.plugins) ? [...mioki.plugins] : [];\n if (plugins.includes(shortName)) return false;\n\n plugins.push(shortName);\n pkg.mioki = { ...mioki, plugins };\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n return true;\n}\n\nexport async function getInstalledPackages(cwd: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(readFileSync(path.join(cwd, \"package.json\"), \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return Object.keys(deps).filter((k) => k.startsWith(\"mioku-\"));\n } catch {\n return [];\n }\n}\n\nexport function withRoot(p: string): string {\n return path.resolve(process.cwd(), p);\n}\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport async function fetchNpmKeywords(\n packageName: string,\n): Promise<string[] | null> {\n try {\n const res = await fetch(`${NPM_REGISTRY}/${encodeURIComponent(packageName)}`, {\n headers: { Accept: \"application/json\", \"User-Agent\": \"mioku-cli\" },\n });\n if (!res.ok) return null;\n const data = (await res.json()) as any;\n const latestVersion = String(data?.[\"dist-tags\"]?.latest || \"\").trim();\n const keywords = latestVersion\n ? data?.versions?.[latestVersion]?.keywords\n : data?.keywords;\n return Array.isArray(keywords) ? keywords.map(String) : [];\n } catch {\n return null;\n }\n}\n\nexport function gracefullyExit(): void {\n console.log(\"Bye!\");\n process.exit(0);\n}\n\nexport function makeFileTree(\n fileTree: Record<string, string | Record<string, unknown>>,\n base: string,\n): void {\n for (const [name, content] of Object.entries(fileTree)) {\n if (typeof content === \"object\" && content !== null) {\n const subPath = `${base}/${name}`;\n if (!fs.existsSync(subPath)) fs.mkdirSync(subPath, { recursive: true });\n for (const [subName, subContent] of Object.entries(content)) {\n if (typeof subContent === \"object\") {\n makeFileTree(\n subContent as Record<string, string | Record<string, unknown>>,\n path.join(subPath, subName),\n );\n } else {\n fs.writeFileSync(`${subPath}/${subName}`, subContent as string);\n }\n }\n } else {\n const filePath = `${base}/${name}`;\n const dirname = path.dirname(filePath);\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });\n fs.writeFileSync(filePath, content as string);\n }\n }\n}\n\nexport function buildHelpInfo(version: string): string {\n return dedent(`\n mioku 命令行工具 v${version}\n\n 用法: mioku <命令> [选项]\n\n 命令:\n install plugin <名称> 安装插件,自动补全 mioku-plugin- 前缀\n install service <名称> 安装服务,自动补全 mioku-service- 前缀\n update [包名|self|all] 更新插件或服务\n update - 检查可用更新\n update all - 更新所有 mioku- 包\n update self - 更新 mioku 框架\n update xxx - 更新指定包\n\n 选项:\n -h, --help 显示帮助信息\n -v, --version 显示版本号\n --name <name> 指定项目/文件夹名称,默认 mioku-bot\n --protocol <protocol> 指定 NapCat 协议,默认 ws\n --host <host> 指定 NapCat 主机,默认 localhost\n --port <port> 指定 NapCat 端口,默认 3001\n --token <token> 指定 NapCat 连接 Token,默认空\n --prefix <prefix> 指定命令前缀,默认 #\n --owners <owners> 指定主人 QQ,英文逗号分隔,必填\n --admins <admins> 指定管理员 QQ,英文逗号分隔,可空\n --use-npm-mirror 使用 npm 镜像源加速依赖安装,默认否\n `);\n}\n\ntype OmitTypeWithRequired<T> = Omit<T, \"type\" | \"required\"> & {\n required?: boolean;\n};\n\nexport async function confirm(\n message: string,\n options?: OmitTypeWithRequired<{ initial?: boolean }>,\n): Promise<boolean> {\n return consola.prompt(message, {\n type: \"confirm\",\n cancel: \"reject\",\n ...options,\n });\n}\n\nexport async function input(\n message: string,\n options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>,\n): Promise<string> {\n const result = await consola.prompt(message, {\n type: \"text\",\n cancel: \"reject\",\n ...options,\n });\n if (options?.required && !result) return input(message, options);\n return result;\n}\n","import consola from \"consola\";\nimport {\n ensurePackageManager,\n appendToMiokiPlugins,\n execAdd,\n fetchNpmKeywords,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n confirm,\n} from \"./shared\";\n\nexport async function installCommand(\n cmdArgs: string[],\n helpInfo: string,\n): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [type, name] = cmdArgs;\n\n if (!type || !name) {\n consola.error(\n \"请指定类型和名称: mioku install plugin <名称> 或 mioku install service <名称>\",\n );\n console.log(helpInfo);\n return 1;\n }\n\n if (type !== \"plugin\" && type !== \"service\") {\n consola.error(`无效的类型 \"${type}\",请使用 plugin 或 service`);\n console.log(helpInfo);\n return 1;\n }\n\n const prefix = type === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n const normalized = `${prefix}${name}`;\n\n if (type === \"plugin\") {\n const proceed = await warnIfPrivatePlugin(normalized);\n if (!proceed) {\n consola.info(\"已取消安装\");\n return 1;\n }\n }\n\n try {\n execAdd([normalized], cwd);\n consola.success(`已安装 ${normalized}`);\n\n if (type === \"plugin\") {\n const shortName = normalized.slice(PLUGIN_PREFIX.length);\n if (appendToMiokiPlugins(cwd, normalized)) {\n consola.success(`已在 mioki.plugins 中启用 ${shortName}`);\n } else {\n consola.info(`${shortName} 已在 mioki.plugins 中,跳过`);\n }\n }\n return 0;\n } catch {\n consola.error(`安装失败: ${normalized}`);\n return 1;\n }\n}\n\nasync function warnIfPrivatePlugin(pkgName: string): Promise<boolean> {\n const keywords = await fetchNpmKeywords(pkgName);\n if (keywords === null) return true;\n if (keywords.includes(\"mioku\")) return true;\n\n consola.warn(`${pkgName} 看起来是私有插件\"`);\n consola.warn(\"该插件未上架插件市场,可能存在风险\");\n return confirm(\"仍要继续安装吗?\", { initial: false });\n}\n","import consola from \"consola\";\nimport {\n run,\n ensurePackageManager,\n getInstalledPackages,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n} from \"./shared\";\n\nasync function updatePackages(packages: string[], cwd: string): Promise<void> {\n if (packages.length === 0) {\n consola.info(\"未找到 mioku- 相关依赖\");\n return;\n }\n console.log(`执行: bun update ${packages.join(\" \")} --latest`);\n run(\"bun\", [\"update\", ...packages, \"--latest\"], { cwd });\n}\n\nasync function updateByPrefix(\n prefix: string,\n cwd: string,\n name?: string,\n): Promise<void> {\n if (name) {\n const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;\n console.log(`执行: bun update ${normalized} --latest`);\n run(\"bun\", [\"update\", normalized, \"--latest\"], { cwd });\n return;\n }\n const packages = (await getInstalledPackages(cwd)).filter((p) =>\n p.startsWith(prefix),\n );\n if (packages.length === 0) {\n consola.info(`未找到 ${prefix}* 相关依赖`);\n return;\n }\n await updatePackages(packages, cwd);\n}\n\nexport async function updateCommand(cmdArgs: string[]): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [target, name] = cmdArgs;\n\n if (!target || target === \"check\") {\n run(\"bun\", [\"update\", \"-i\"], { cwd });\n return 0;\n }\n\n if (target === \"all\") {\n await updatePackages(await getInstalledPackages(cwd), cwd);\n return 0;\n }\n\n if (target === \"self\") {\n console.log(\"执行: bun update mioku --latest\");\n run(\"bun\", [\"update\", \"mioku\", \"--latest\"], { cwd });\n return 0;\n }\n\n if (target === \"plugin\" || target === \"service\") {\n const prefix = target === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n await updateByPrefix(prefix, cwd, name);\n return 0;\n }\n\n console.log(`执行: bun update ${target} --latest`);\n run(\"bun\", [\"update\", target, \"--latest\"], { cwd });\n return 0;\n}\n","import fs from \"node:fs\";\nimport dedent from \"dedent\";\nimport {\n DEFAULT_PACKAGES,\n ensurePackageManager,\n getAddCommand,\n run,\n rmrf,\n withRoot,\n gracefullyExit,\n makeFileTree,\n input,\n confirm,\n} from \"./shared\";\n\nasync function createNewProject(\n name: string,\n fileTree: Record<string, string | Record<string, unknown>>,\n installWebui = false,\n): Promise<void> {\n const projectPath = withRoot(`./${name}`);\n\n if (fs.existsSync(projectPath)) {\n const overwrite = await confirm(`项目 ${name} 已存在,是否覆盖?`);\n if (!overwrite) gracefullyExit();\n\n if (projectPath === process.cwd()) {\n if (fs.readdirSync(projectPath).length !== 0) {\n const confirmOver = await confirm(\n \"项目路径与当前路径相同,将删除当前目录下所有内容再创建,是否继续?\",\n );\n if (!confirmOver) gracefullyExit();\n }\n }\n await rmrf(projectPath);\n }\n\n fs.mkdirSync(projectPath, { recursive: true });\n makeFileTree(fileTree, projectPath);\n console.log(`项目 ${name} 创建成功!`);\n\n const packages = installWebui\n ? [...DEFAULT_PACKAGES, \"mioku-service-webui\"]\n : DEFAULT_PACKAGES;\n const [cmd, args] = getAddCommand(packages);\n console.log(`正在安装 Mioku 依赖: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd: projectPath });\n}\n\nexport async function scaffoldCommand(version: string): Promise<number> {\n const name = await input(\"请输入项目名称\", {\n default: \"mioku-bot\",\n placeholder: \"mioku-bot\",\n required: true,\n });\n const owners = await input(\"请输入主人 QQ (最高权限,英文逗号分隔,必填)\", {\n placeholder: \"请输入\",\n default: \"\",\n required: true,\n });\n const host = await input(\"请输入 NapCat WS 主机\", {\n default: \"localhost\",\n placeholder: \"localhost\",\n required: true,\n });\n const port = parseInt(\n await input(\"请输入 NapCat WS 端口\", {\n default: \"3001\",\n placeholder: \"3001\",\n required: true,\n }),\n 10,\n );\n const token = await input(\"请输入 NapCat WS Token(如无则留空)\", {\n placeholder: \"请输入\",\n });\n\n ensurePackageManager();\n\n const ownersList = String(owners)\n .split(\",\")\n .map((o) => o.trim())\n .join(\", \");\n\n const pkgJson = dedent(`\n {\n \"name\": \"${name}\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {},\n \"mioki\": {\n \"prefix\": \"#\",\n \"owners\": [${ownersList}],\n \"admins\": [],\n \"plugins\": [\"boot\", \"help\", \"chat\", \"demo\"],\n \"log_level\": \"info\",\n \"online_push\": false,\n \"error_push\": false,\n \"napcat\": [\n {\n \"protocol\": \"ws\",\n \"port\": ${port},\n \"host\": \"${host}\",\n \"token\": \"${token}\"\n }\n ]\n },\n \"scripts\": {\n \"start\": \"bun run app.ts\",\n \"dev\": \"bun run --watch app.ts\"\n }\n }\n `);\n\n const pluginCode = dedent(`\n import { definePlugin } from 'mioku'\n\n export default definePlugin({\n name: 'demo',\n version: '${version}',\n async setup(ctx) {\n ctx.logger.info('Demo 插件已加载')\n\n ctx.handle('message', async (e) => {\n if (e.raw_message === 'hello') {\n e.reply('world', true)\n }\n })\n\n return () => {\n ctx.logger.info('Demo 插件已卸载')\n }\n },\n })\n `);\n\n const fileTree: Record<string, string | Record<string, unknown>> = {\n \"app.ts\":\n \"import { start } from 'mioku'\\n\\nstart({ cwd: import.meta.dirname }).then()\\n\",\n \"package.json\": pkgJson,\n plugins: { demo: { \"index.ts\": pluginCode } },\n config: {},\n data: {},\n };\n\n const installWebui = await confirm(\"是否安装 WebUI 管理面板?(建议安装)\", {\n initial: true,\n });\n\n await createNewProject(name, fileTree, installWebui);\n\n console.log(\"\\n若需启动机器人,请运行:\");\n console.log(\" cd\", name);\n console.log(\" bun run start\");\n return 0;\n}\n","#!/usr/bin/env node\n\nimport mri from \"mri\";\nimport { version } from \"../../package.json\";\nimport { buildHelpInfo } from \"./shared\";\nimport { installCommand } from \"./install\";\nimport { updateCommand } from \"./update\";\nimport { scaffoldCommand } from \"./scaffold\";\n\ninterface CliOptions {\n help?: boolean;\n version?: boolean;\n}\n\nconst args = process.argv.slice(2);\n\n(async () => {\n const cli = mri<CliOptions>(args, { alias: { v: \"version\", h: \"help\" } });\n const helpInfo = buildHelpInfo(version);\n const [cmd, ...cmdArgs] = args;\n\n switch (cmd) {\n case \"install\":\n process.exitCode = await installCommand(cmdArgs, helpInfo);\n return;\n case \"update\":\n process.exitCode = await updateCommand(cmdArgs);\n return;\n default:\n if (cli.version) {\n console.log(`v${version}`);\n return;\n }\n if (cli.help) {\n console.log(helpInfo);\n return;\n }\n process.exitCode = await scaffoldCommand(version);\n return;\n }\n})();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["cmd: string","args: string[]","options: { cwd?: string }","args","dir: string","err: any","packages: string[]","cwd?: string","cwd: string","pkgName: string","p: string","packageName: string","fileTree: Record<string, string | Record<string, unknown>>","base: string","version: string","version","message: string","options?: OmitTypeWithRequired<{ initial?: boolean }>","options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>","cmdArgs: string[]","helpInfo: string","pkgName: string","packages: string[]","cwd: string","prefix: string","name?: string","cmdArgs: string[]","name: string","fileTree: Record<string, string | Record<string, unknown>>","args","version: string","version"],"sources":["../../package.json","../../src/cli/shared.ts","../../src/cli/install.ts","../../src/cli/update.ts","../../src/cli/scaffold.ts","../../src/cli/index.ts"],"sourcesContent":["{\n \"name\": \"mioku\",\n \"type\": \"module\",\n \"version\": \"0.9.9\",\n \"packageManager\": \"bun@1.2.0\",\n \"description\": \"Mioku - Plugin framework extended from mioki for NapCat OneBot v11\",\n \"keywords\": [\n \"onebot\",\n \"framework\",\n \"bot\",\n \"mioki\",\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/jerryplusy/mioku#readme\",\n \"files\": [\n \"dist\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/jerryplusy/mioku/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jerryplusy/mioku.git\",\n \"directory\": \"src/packages/mioku\"\n },\n \"scripts\": {\n \"dev\": \"tsdown -w\",\n \"build\": \"tsdown\"\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 \"mioki\": \"^0.16.0\",\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 \"openai\": \"^4.0.0\",\n \"puppeteer\": \"^23.10.0\",\n \"pretty-ms\": \"^9.3.0\",\n \"string2argv\": \"^1.0.2\",\n \"systeminformation\": \"^5.30.7\",\n \"lodash\": \"^4.17.21\"\n },\n \"devDependencies\": {\n \"@types/lodash\": \"^4.17.0\",\n \"@types/node\": \"^22.0.0\",\n \"@types/puppeteer\": \"^7.0.4\",\n \"tsdown\": \"^0.11.0\",\n \"typescript\": \"^5.8.0\"\n }\n}\n","import fs, { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport consola from \"consola\";\nimport dedent from \"dedent\";\nimport {\n clearCommandCache,\n commandExists,\n resolveCommand,\n runCommandInherit,\n} from \"../core/exec\";\n\nexport const DEFAULT_PACKAGES = [\n \"mioku\",\n \"mioku-plugin-boot\",\n \"mioku-plugin-help\",\n \"mioku-plugin-chat\",\n \"mioku-service-config\",\n \"mioku-service-ai\",\n \"mioku-service-screenshot\",\n \"mioku-service-help\",\n];\n\nexport const PLUGIN_PREFIX = \"mioku-plugin-\";\nexport const SERVICE_PREFIX = \"mioku-service-\";\n\nexport function run(\n cmd: string,\n args: string[] = [],\n options: { cwd?: string } = {},\n): void {\n runCommandInherit(cmd, args, options);\n}\n\nexport async function rmrf(dir: string, retries = 5): Promise<void> {\n for (let i = 0; i < retries; i++) {\n try {\n fs.rmSync(dir, { recursive: true, force: true });\n return;\n } catch (err: any) {\n if (i === retries - 1) throw err;\n const code = err?.code;\n if (\n code === \"EPERM\" ||\n code === \"EBUSY\" ||\n code === \"ENOTEMPTY\" ||\n code === \"ENOENT\"\n ) {\n await new Promise((resolve) => setTimeout(resolve, 300 * (i + 1)));\n } else {\n throw err;\n }\n }\n }\n}\n\nexport function hasCommand(cmd: string): boolean {\n return commandExists(cmd);\n}\n\nfunction findNpmPath(): string | null {\n const resolved = resolveCommand(\"npm\");\n if (resolved) return resolved;\n if (process.platform !== \"win32\") return null;\n\n const fallbacks = [\n path.join(process.env.ProgramFiles || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env[\"ProgramFiles(x86)\"] || \"\", \"nodejs\", \"npm.cmd\"),\n path.join(process.env.APPDATA || \"\", \"npm\", \"npm.cmd\"),\n ];\n\n return fallbacks.find((candidate) => resolveCommand(candidate)) ?? null;\n}\n\nexport function ensurePackageManager(): void {\n if (hasCommand(\"bun\")) return;\n console.log(\"安装 bun...\");\n const npmPath = findNpmPath();\n if (!npmPath) {\n consola.error(\"未找到 npm,请确保 Node.js 已安装并包含 npm\");\n process.exit(1);\n }\n run(npmPath, [\"install\", \"-g\", \"bun\"]);\n // bun was just put on PATH; drop the cached miss so the next lookup finds it.\n clearCommandCache();\n}\n\nexport function getAddCommand(packages: string[]): [string, string[]] {\n return [\"bun\", [\"add\", ...packages]];\n}\n\nexport function normalizePackageName(input: string): string {\n if (input.startsWith(PLUGIN_PREFIX) || input.startsWith(SERVICE_PREFIX)) {\n return input;\n }\n if (input.startsWith(\"mioku-\")) return input;\n return `${PLUGIN_PREFIX}${input}`;\n}\n\nexport function detectType(name: string): \"plugin\" | \"service\" | \"unknown\" {\n if (name.startsWith(PLUGIN_PREFIX)) return \"plugin\";\n if (name.startsWith(SERVICE_PREFIX)) return \"service\";\n return \"unknown\";\n}\n\nexport function execAdd(packages: string[], cwd?: string): void {\n const [cmd, args] = getAddCommand(packages);\n console.log(`执行: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd });\n}\n\nexport function appendToMiokiPlugins(cwd: string, pkgName: string): boolean {\n if (!pkgName.startsWith(PLUGIN_PREFIX)) return false;\n const shortName = pkgName.slice(PLUGIN_PREFIX.length);\n\n const packageJsonPath = path.join(cwd, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) return false;\n\n const pkg = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n const mioki = pkg.mioki ?? {};\n const plugins = Array.isArray(mioki.plugins) ? [...mioki.plugins] : [];\n if (plugins.includes(shortName)) return false;\n\n plugins.push(shortName);\n pkg.mioki = { ...mioki, plugins };\n fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\\n`);\n return true;\n}\n\nexport async function getInstalledPackages(cwd: string): Promise<string[]> {\n try {\n const pkg = JSON.parse(readFileSync(path.join(cwd, \"package.json\"), \"utf-8\"));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return Object.keys(deps).filter((k) => k.startsWith(\"mioku-\"));\n } catch {\n return [];\n }\n}\n\nexport function withRoot(p: string): string {\n return path.resolve(process.cwd(), p);\n}\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport async function fetchNpmKeywords(\n packageName: string,\n): Promise<string[] | null> {\n try {\n const res = await fetch(`${NPM_REGISTRY}/${encodeURIComponent(packageName)}`, {\n headers: { Accept: \"application/json\", \"User-Agent\": \"mioku-cli\" },\n });\n if (!res.ok) return null;\n const data = (await res.json()) as any;\n const latestVersion = String(data?.[\"dist-tags\"]?.latest || \"\").trim();\n const keywords = latestVersion\n ? data?.versions?.[latestVersion]?.keywords\n : data?.keywords;\n return Array.isArray(keywords) ? keywords.map(String) : [];\n } catch {\n return null;\n }\n}\n\nexport function gracefullyExit(): void {\n console.log(\"Bye!\");\n process.exit(0);\n}\n\nexport function makeFileTree(\n fileTree: Record<string, string | Record<string, unknown>>,\n base: string,\n): void {\n for (const [name, content] of Object.entries(fileTree)) {\n if (typeof content === \"object\" && content !== null) {\n const subPath = `${base}/${name}`;\n if (!fs.existsSync(subPath)) fs.mkdirSync(subPath, { recursive: true });\n for (const [subName, subContent] of Object.entries(content)) {\n if (typeof subContent === \"object\") {\n makeFileTree(\n subContent as Record<string, string | Record<string, unknown>>,\n path.join(subPath, subName),\n );\n } else {\n fs.writeFileSync(`${subPath}/${subName}`, subContent as string);\n }\n }\n } else {\n const filePath = `${base}/${name}`;\n const dirname = path.dirname(filePath);\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });\n fs.writeFileSync(filePath, content as string);\n }\n }\n}\n\nexport function buildHelpInfo(version: string): string {\n return dedent(`\n mioku 命令行工具 v${version}\n\n 用法: mioku <命令> [选项]\n\n 命令:\n install plugin <名称> 安装插件,自动补全 mioku-plugin- 前缀\n install service <名称> 安装服务,自动补全 mioku-service- 前缀\n update [包名|self|all] 更新插件或服务\n update - 检查可用更新\n update all - 更新所有 mioku- 包\n update self - 更新 mioku 框架\n update xxx - 更新指定包\n\n 选项:\n -h, --help 显示帮助信息\n -v, --version 显示版本号\n --name <name> 指定项目/文件夹名称,默认 mioku-bot\n --protocol <protocol> 指定 NapCat 协议,默认 ws\n --host <host> 指定 NapCat 主机,默认 localhost\n --port <port> 指定 NapCat 端口,默认 3001\n --token <token> 指定 NapCat 连接 Token,默认空\n --prefix <prefix> 指定命令前缀,默认 #\n --owners <owners> 指定主人 QQ,英文逗号分隔,必填\n --admins <admins> 指定管理员 QQ,英文逗号分隔,可空\n --use-npm-mirror 使用 npm 镜像源加速依赖安装,默认否\n `);\n}\n\ntype OmitTypeWithRequired<T> = Omit<T, \"type\" | \"required\"> & {\n required?: boolean;\n};\n\nexport async function confirm(\n message: string,\n options?: OmitTypeWithRequired<{ initial?: boolean }>,\n): Promise<boolean> {\n return consola.prompt(message, {\n type: \"confirm\",\n cancel: \"reject\",\n ...options,\n });\n}\n\nexport async function input(\n message: string,\n options?: OmitTypeWithRequired<{ default?: string; placeholder?: string }>,\n): Promise<string> {\n const result = await consola.prompt(message, {\n type: \"text\",\n cancel: \"reject\",\n ...options,\n });\n if (options?.required && !result) return input(message, options);\n return result;\n}\n","import consola from \"consola\";\nimport {\n ensurePackageManager,\n appendToMiokiPlugins,\n execAdd,\n fetchNpmKeywords,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n confirm,\n} from \"./shared\";\n\nexport async function installCommand(\n cmdArgs: string[],\n helpInfo: string,\n): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [type, name] = cmdArgs;\n\n if (!type || !name) {\n consola.error(\n \"请指定类型和名称: mioku install plugin <名称> 或 mioku install service <名称>\",\n );\n console.log(helpInfo);\n return 1;\n }\n\n if (type !== \"plugin\" && type !== \"service\") {\n consola.error(`无效的类型 \"${type}\",请使用 plugin 或 service`);\n console.log(helpInfo);\n return 1;\n }\n\n const prefix = type === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n const normalized = `${prefix}${name}`;\n\n if (type === \"plugin\") {\n const proceed = await warnIfPrivatePlugin(normalized);\n if (!proceed) {\n consola.info(\"已取消安装\");\n return 1;\n }\n }\n\n try {\n execAdd([normalized], cwd);\n consola.success(`已安装 ${normalized}`);\n\n if (type === \"plugin\") {\n const shortName = normalized.slice(PLUGIN_PREFIX.length);\n if (appendToMiokiPlugins(cwd, normalized)) {\n consola.success(`已在 mioki.plugins 中启用 ${shortName}`);\n } else {\n consola.info(`${shortName} 已在 mioki.plugins 中,跳过`);\n }\n }\n return 0;\n } catch {\n consola.error(`安装失败: ${normalized}`);\n return 1;\n }\n}\n\nasync function warnIfPrivatePlugin(pkgName: string): Promise<boolean> {\n const keywords = await fetchNpmKeywords(pkgName);\n if (keywords === null) return true;\n if (keywords.includes(\"mioku\")) return true;\n\n consola.warn(`${pkgName} 看起来是私有插件\"`);\n consola.warn(\"该插件未上架插件市场,可能存在风险\");\n return confirm(\"仍要继续安装吗?\", { initial: false });\n}\n","import consola from \"consola\";\nimport {\n run,\n ensurePackageManager,\n getInstalledPackages,\n PLUGIN_PREFIX,\n SERVICE_PREFIX,\n} from \"./shared\";\n\nasync function updatePackages(packages: string[], cwd: string): Promise<void> {\n if (packages.length === 0) {\n consola.info(\"未找到 mioku- 相关依赖\");\n return;\n }\n console.log(`执行: bun update ${packages.join(\" \")} --latest`);\n run(\"bun\", [\"update\", ...packages, \"--latest\"], { cwd });\n}\n\nasync function updateByPrefix(\n prefix: string,\n cwd: string,\n name?: string,\n): Promise<void> {\n if (name) {\n const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;\n console.log(`执行: bun update ${normalized} --latest`);\n run(\"bun\", [\"update\", normalized, \"--latest\"], { cwd });\n return;\n }\n const packages = (await getInstalledPackages(cwd)).filter((p) =>\n p.startsWith(prefix),\n );\n if (packages.length === 0) {\n consola.info(`未找到 ${prefix}* 相关依赖`);\n return;\n }\n await updatePackages(packages, cwd);\n}\n\nexport async function updateCommand(cmdArgs: string[]): Promise<number> {\n ensurePackageManager();\n const cwd = process.cwd();\n const [target, name] = cmdArgs;\n\n if (!target || target === \"check\") {\n run(\"bun\", [\"update\", \"-i\"], { cwd });\n return 0;\n }\n\n if (target === \"all\") {\n await updatePackages(await getInstalledPackages(cwd), cwd);\n return 0;\n }\n\n if (target === \"self\") {\n console.log(\"执行: bun update mioku --latest\");\n run(\"bun\", [\"update\", \"mioku\", \"--latest\"], { cwd });\n return 0;\n }\n\n if (target === \"plugin\" || target === \"service\") {\n const prefix = target === \"plugin\" ? PLUGIN_PREFIX : SERVICE_PREFIX;\n await updateByPrefix(prefix, cwd, name);\n return 0;\n }\n\n console.log(`执行: bun update ${target} --latest`);\n run(\"bun\", [\"update\", target, \"--latest\"], { cwd });\n return 0;\n}\n","import fs from \"node:fs\";\nimport dedent from \"dedent\";\nimport {\n DEFAULT_PACKAGES,\n ensurePackageManager,\n getAddCommand,\n run,\n rmrf,\n withRoot,\n gracefullyExit,\n makeFileTree,\n input,\n confirm,\n} from \"./shared\";\n\nasync function createNewProject(\n name: string,\n fileTree: Record<string, string | Record<string, unknown>>,\n installWebui = false,\n): Promise<void> {\n const projectPath = withRoot(`./${name}`);\n\n if (fs.existsSync(projectPath)) {\n const overwrite = await confirm(`项目 ${name} 已存在,是否覆盖?`);\n if (!overwrite) gracefullyExit();\n\n if (projectPath === process.cwd()) {\n if (fs.readdirSync(projectPath).length !== 0) {\n const confirmOver = await confirm(\n \"项目路径与当前路径相同,将删除当前目录下所有内容再创建,是否继续?\",\n );\n if (!confirmOver) gracefullyExit();\n }\n }\n await rmrf(projectPath);\n }\n\n fs.mkdirSync(projectPath, { recursive: true });\n makeFileTree(fileTree, projectPath);\n console.log(`项目 ${name} 创建成功!`);\n\n const packages = installWebui\n ? [...DEFAULT_PACKAGES, \"mioku-service-webui\"]\n : DEFAULT_PACKAGES;\n const [cmd, args] = getAddCommand(packages);\n console.log(`正在安装 Mioku 依赖: ${cmd} ${args.join(\" \")}`);\n run(cmd, args, { cwd: projectPath });\n}\n\nexport async function scaffoldCommand(version: string): Promise<number> {\n const name = await input(\"请输入项目名称\", {\n default: \"mioku-bot\",\n placeholder: \"mioku-bot\",\n required: true,\n });\n const owners = await input(\"请输入主人 QQ (最高权限,英文逗号分隔,必填)\", {\n placeholder: \"请输入\",\n default: \"\",\n required: true,\n });\n const host = await input(\"请输入 NapCat WS 主机\", {\n default: \"localhost\",\n placeholder: \"localhost\",\n required: true,\n });\n const port = parseInt(\n await input(\"请输入 NapCat WS 端口\", {\n default: \"3001\",\n placeholder: \"3001\",\n required: true,\n }),\n 10,\n );\n const token = await input(\"请输入 NapCat WS Token(如无则留空)\", {\n placeholder: \"请输入\",\n });\n\n ensurePackageManager();\n\n const ownersList = String(owners)\n .split(\",\")\n .map((o) => o.trim())\n .join(\", \");\n\n const pkgJson = dedent(`\n {\n \"name\": \"${name}\",\n \"private\": true,\n \"type\": \"module\",\n \"dependencies\": {},\n \"mioki\": {\n \"prefix\": \"#\",\n \"owners\": [${ownersList}],\n \"admins\": [],\n \"plugins\": [\"boot\", \"help\", \"chat\", \"demo\"],\n \"log_level\": \"info\",\n \"online_push\": false,\n \"error_push\": false,\n \"napcat\": [\n {\n \"protocol\": \"ws\",\n \"port\": ${port},\n \"host\": \"${host}\",\n \"token\": \"${token}\"\n }\n ]\n },\n \"scripts\": {\n \"start\": \"bun run app.ts\",\n \"dev\": \"bun run --watch app.ts\"\n }\n }\n `);\n\n const pluginCode = dedent(`\n import { definePlugin } from 'mioku'\n\n export default definePlugin({\n name: 'demo',\n version: '${version}',\n async setup(ctx) {\n ctx.logger.info('Demo 插件已加载')\n\n ctx.handle('message', async (e) => {\n if (e.raw_message === 'hello') {\n e.reply('world', true)\n }\n })\n\n return () => {\n ctx.logger.info('Demo 插件已卸载')\n }\n },\n })\n `);\n\n const fileTree: Record<string, string | Record<string, unknown>> = {\n \"app.ts\":\n \"import { start } from 'mioku'\\n\\nstart({ cwd: import.meta.dirname }).then()\\n\",\n \"package.json\": pkgJson,\n plugins: { demo: { \"index.ts\": pluginCode } },\n config: {},\n data: {},\n };\n\n const installWebui = await confirm(\"是否安装 WebUI 管理面板?(建议安装)\", {\n initial: true,\n });\n\n await createNewProject(name, fileTree, installWebui);\n\n console.log(\"\\n若需启动机器人,请运行:\");\n console.log(\" cd\", name);\n console.log(\" bun run start\");\n return 0;\n}\n","#!/usr/bin/env node\n\nimport mri from \"mri\";\nimport { version } from \"../../package.json\";\nimport { buildHelpInfo } from \"./shared\";\nimport { installCommand } from \"./install\";\nimport { updateCommand } from \"./update\";\nimport { scaffoldCommand } from \"./scaffold\";\n\ninterface CliOptions {\n help?: boolean;\n version?: boolean;\n}\n\nconst args = process.argv.slice(2);\n\n(async () => {\n const cli = mri<CliOptions>(args, { alias: { v: \"version\", h: \"help\" } });\n const helpInfo = buildHelpInfo(version);\n const [cmd, ...cmdArgs] = args;\n\n switch (cmd) {\n case \"install\":\n process.exitCode = await installCommand(cmdArgs, helpInfo);\n return;\n case \"update\":\n process.exitCode = await updateCommand(cmdArgs);\n return;\n default:\n if (cli.version) {\n console.log(`v${version}`);\n return;\n }\n if (cli.help) {\n console.log(helpInfo);\n return;\n }\n process.exitCode = await scaffoldCommand(version);\n return;\n }\n})();\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -191,6 +191,11 @@ const ACCESS_HOOK_KEYS = new Set([
191
191
  "event",
192
192
  "description"
193
193
  ]);
194
+ const HELP_KEYS = new Set([
195
+ "title",
196
+ "description",
197
+ "commands"
198
+ ]);
194
199
  const HELP_COMMAND_KEYS = new Set([
195
200
  "cmd",
196
201
  "desc",
@@ -209,7 +214,7 @@ function validateHelp(value, pluginName) {
209
214
  logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);
210
215
  return void 0;
211
216
  }
212
- warnUnknownFields(`${pluginName}.help`, value, HELP_COMMAND_KEYS);
217
+ warnUnknownFields(`${pluginName}.help`, value, HELP_KEYS);
213
218
  const title = String(value.title ?? "").trim();
214
219
  const description = String(value.description ?? "").trim();
215
220
  const rawCommands = value.commands;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["fallbackLogger: MiokuLogger","activeLogger: MiokuLogger","logger: MiokuLogger | undefined","logger","logger: MiokuLogger","filePath: string","p: string","dir: string","results: DiscoveredModule[]","entries: import(\"fs\").Dirent[]","prefix: string","entryPath: string","linkPath: string","targetPath: string","runtimePluginsDir: string","metadata: PluginMetadata","plugins: PluginMetadata[]","linkedNames: string[]","store","key: string","factory: () => T","prefix: string","obj: Record<string, unknown>","allowed: Set<string>","value: unknown","pluginName: string","commands: PluginHelp[\"commands\"]","hooks: AccessHook[]","raw: unknown","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","pluginPath: string","packageJson: PackageJsonLike | null","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","servicePath: string","packageJson: PackageJsonLike","required: Set<string>","missing: string[]","ctx: MiokiContext","metadata: ServiceMetadata","service: MiokuService","miokuConfig: MiokuRuntimeConfig","botConfig: BotConfigLike","linkedPluginNames: string[]","deps: BootstrapDeps","botConfig","id: string","ctx: MiokiContext","ref: ServiceRef<T>","keywords: unknown","ctx: MiokiContext","botConfig","serviceName: string","configName: string","defaults: Record<string, unknown>","value: Record<string, unknown>","result: Record<string, Record<string, unknown>>","role: unknown","pluginName: string","serviceName: string","name: string","initial: T","next: T","state: T","plugin: T","options: MiokuStartOptions","logger","signal: string","version: string"],"sources":["../src/core/logger.ts","../src/core/module-scanner.ts","../src/core/plugin-linker.ts","../src/core/registry.ts","../src/core/plugin-manifest.ts","../src/core/plugin-manager.ts","../src/core/service-manager.ts","../src/core/bootstrap.ts","../src/core/service.ts","../src/core/services.ts","../src/core/plugin-artifact-registry.ts","../src/core/service-config.ts","../src/types.ts","../src/core/data-paths.ts","../src/core/plugin-runtime-state.ts","../src/index.ts"],"sourcesContent":["type LogMethod = (...args: unknown[]) => void;\n\nexport interface MiokuLogger {\n error: LogMethod;\n warn: LogMethod;\n info: LogMethod;\n debug: LogMethod;\n trace?: LogMethod;\n}\n\nconst fallbackLogger: MiokuLogger = {\n error: (...args) => console.error(...args),\n warn: (...args) => console.warn(...args),\n info: (...args) => console.info(...args),\n debug: (...args) => console.debug(...args),\n trace: (...args) => console.debug(...args),\n};\n\nlet activeLogger: MiokuLogger = fallbackLogger;\n\nexport function setMiokuLogger(logger: MiokuLogger | undefined): void {\n activeLogger = logger || fallbackLogger;\n}\n\nexport function getMiokuLogger(): MiokuLogger {\n return activeLogger;\n}\n\nexport const logger: MiokuLogger = {\n error: (...args) => activeLogger.error(...args),\n warn: (...args) => activeLogger.warn(...args),\n info: (...args) => activeLogger.info(...args),\n debug: (...args) => activeLogger.debug(...args),\n trace: (...args) => activeLogger.trace?.(...args),\n};\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport interface DiscoveredModule {\n name: string;\n path: string;\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function resolveRealpath(p: string): Promise<string> {\n try {\n return await fs.realpath(p);\n } catch {\n return p;\n }\n}\n\n// Windows requires file:// URLs for absolute paths in dynamic import().\n// pathToFileURL also percent-encodes spaces and non-ASCII segments, which a\n// hand-rolled string replace leaves broken (e.g. \"C:\\用户\\my bot\").\nexport function toImportPath(filePath: string): string {\n if (process.platform === \"win32\") {\n return pathToFileURL(filePath).href;\n }\n return filePath;\n}\n\nexport async function scanLocalDir(dir: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n if (!(await pathExists(dir))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return results;\n }\n\n for (const entry of entries) {\n const entryPath = path.join(dir, entry.name);\n try {\n const stat = await fs.stat(entryPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n results.push({ name: entry.name, path: await resolveRealpath(entryPath) });\n }\n return results;\n}\n\nexport async function scanNodeModules(prefix: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n const nodeModulesPath = path.resolve(process.cwd(), \"node_modules\");\n if (!(await pathExists(nodeModulesPath))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(nodeModulesPath, { withFileTypes: true });\n } catch {\n return results;\n }\n\n // Don't filter by isDirectory(): node_modules entries are often symlinks\n // into the workspace, and Dirent.isDirectory() returns false for symlinks.\n for (const entry of entries) {\n if (!entry.name.startsWith(prefix)) continue;\n const name = entry.name.slice(prefix.length);\n const fullPath = path.join(nodeModulesPath, entry.name);\n results.push({ name, path: await resolveRealpath(fullPath) });\n }\n return results;\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport type { PluginMetadata } from \"../types\";\nimport { logger } from \"./logger\";\nimport { pathExists } from \"./module-scanner\";\n\nexport const DEFAULT_RUNTIME_PLUGINS_DIR = \".mioku/plugins\";\n\ntype SymlinkState = \"ok\" | \"blocked\" | \"removed\";\n\nasync function removeIfBrokenSymlink(entryPath: string): Promise<SymlinkState> {\n let stat;\n try {\n stat = await fs.lstat(entryPath);\n } catch {\n return \"removed\";\n }\n if (!stat.isSymbolicLink()) return \"blocked\";\n try {\n await fs.realpath(entryPath);\n return \"ok\";\n } catch {\n await fs.rm(entryPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${entryPath}`);\n return \"removed\";\n }\n}\n\nfunction relativeSymlinkTarget(linkPath: string, targetPath: string): string {\n return path.relative(path.dirname(linkPath), targetPath) || \".\";\n}\n\nasync function ensurePluginLink(\n runtimePluginsDir: string,\n metadata: PluginMetadata,\n): Promise<boolean> {\n const linkPath = path.join(runtimePluginsDir, metadata.name);\n const targetPath = metadata.path;\n\n let stat;\n try {\n stat = await fs.lstat(linkPath);\n } catch {\n stat = null;\n }\n\n if (stat?.isSymbolicLink()) {\n try {\n const currentTarget = await fs.realpath(linkPath);\n const expectedTarget = await fs.realpath(targetPath);\n if (currentTarget === expectedTarget) return true;\n await fs.rm(linkPath, { force: true });\n logger.info(`[plugin-linker] Rebuilding plugin link: ${metadata.name}`);\n } catch {\n await fs.rm(linkPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${linkPath}`);\n }\n } else if (stat) {\n logger.warn(\n `[plugin-linker] ${linkPath} exists and is not a symlink, skip linking ${metadata.name}`,\n );\n return false;\n }\n\n if (!(await pathExists(targetPath))) {\n logger.warn(\n `[plugin-linker] Plugin target missing, skip linking ${metadata.name}: ${targetPath}`,\n );\n return false;\n }\n\n // Junctions on Windows don't require admin rights; relative dir symlinks elsewhere.\n if (process.platform === \"win32\") {\n await fs.symlink(targetPath, linkPath, \"junction\");\n } else {\n await fs.symlink(relativeSymlinkTarget(linkPath, targetPath), linkPath, \"dir\");\n }\n return true;\n}\n\nexport async function prepareRuntimePluginLinks(\n plugins: PluginMetadata[],\n runtimePluginsDir = path.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR),\n): Promise<string[]> {\n await fs.mkdir(runtimePluginsDir, { recursive: true });\n\n const discoveredNames = new Set(plugins.map((p) => p.name));\n const entries = await fs.readdir(runtimePluginsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(runtimePluginsDir, entry.name);\n if ((await removeIfBrokenSymlink(entryPath)) !== \"ok\") continue;\n if (entry.isSymbolicLink() && !discoveredNames.has(entry.name)) {\n await fs.rm(entryPath, { force: true });\n logger.info(`[plugin-linker] Removed stale plugin link: ${entry.name}`);\n }\n }\n\n const linkedNames: string[] = [];\n for (const metadata of plugins) {\n if (await ensurePluginLink(runtimePluginsDir, metadata)) {\n linkedNames.push(metadata.name);\n }\n }\n return linkedNames;\n}\n","// Framework singletons are stashed on globalThis so they survive jiti's\n// moduleCache-off re-evaluation (mioki loads plugins via jiti). Callers that\n// live in the normally-cached `mioku` dist could use a plain module-level\n// const, but the global indirection keeps things stable if a plugin ever\n// re-imports the framework through jiti.\n\nconst STORE_SYMBOL = Symbol.for(\"mioku.globalStore\");\ntype GlobalStore = Record<string, unknown>;\n\nfunction store(): GlobalStore {\n const g = globalThis as unknown as Record<symbol, GlobalStore>;\n if (!g[STORE_SYMBOL]) g[STORE_SYMBOL] = {};\n return g[STORE_SYMBOL]!;\n}\n\nexport function getOrCreate<T>(key: string, factory: () => T): T {\n const s = store();\n if (s[key] === undefined) s[key] = factory();\n return s[key] as T;\n}\n","import { logger } from \"./logger\";\nimport type {\n AccessHook,\n PluginHelp,\n PluginPackageConfig,\n} from \"../types\";\n\nconst PLUGIN_CONFIG_KEYS = new Set([\n \"services\",\n \"help\",\n \"accessHooks\",\n]);\n\nconst ACCESS_HOOK_KEYS = new Set([\n \"id\",\n \"match\",\n \"event\",\n \"description\",\n]);\n\nconst HELP_COMMAND_KEYS = new Set([\"cmd\", \"desc\", \"usage\", \"role\"]);\n\nfunction warnUnknownFields(\n prefix: string,\n obj: Record<string, unknown>,\n allowed: Set<string>,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key)) {\n logger.warn(`[plugin-manifest] ${prefix} 含未知字段 \"${key}\"(将被忽略)`);\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction validateHelp(value: unknown, pluginName: string): PluginHelp | undefined {\n if (value === undefined) return undefined;\n if (!isPlainObject(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);\n return undefined;\n }\n warnUnknownFields(`${pluginName}.help`, value, HELP_COMMAND_KEYS);\n\n const title = String(value.title ?? \"\").trim();\n const description = String(value.description ?? \"\").trim();\n const rawCommands = value.commands;\n\n if (!title) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.title 缺失或为空`);\n }\n if (!description) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.description 缺失或为空`);\n }\n if (!Array.isArray(rawCommands)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 必须是数组`);\n return { title, description, commands: [] };\n }\n\n const commands: PluginHelp[\"commands\"] = [];\n for (const cmd of rawCommands) {\n if (!isPlainObject(cmd)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.help.commands[]`,\n cmd,\n HELP_COMMAND_KEYS,\n );\n const cmdName = String(cmd.cmd ?? \"\").trim();\n const desc = String(cmd.desc ?? \"\").trim();\n if (!cmdName || !desc) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.help.commands 项缺少 cmd 或 desc`,\n );\n continue;\n }\n commands.push({\n cmd: cmdName,\n desc,\n usage: typeof cmd.usage === \"string\" ? cmd.usage : undefined,\n role: typeof cmd.role === \"string\" ? (cmd.role as never) : undefined,\n });\n }\n\n return { title, description, commands };\n}\n\nfunction validateAccessHooks(\n value: unknown,\n pluginName: string,\n): AccessHook[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 必须是数组`);\n return undefined;\n }\n\n const hooks: AccessHook[] = [];\n for (const hook of value) {\n if (!isPlainObject(hook)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.accessHooks[]`,\n hook,\n ACCESS_HOOK_KEYS,\n );\n const id = String(hook.id ?? \"\").trim();\n if (!id) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.accessHooks 项缺少 id,已忽略`,\n );\n continue;\n }\n hooks.push({\n id,\n match: typeof hook.match === \"string\" ? hook.match : undefined,\n event: typeof hook.event === \"string\" ? hook.event : undefined,\n description:\n typeof hook.description === \"string\" ? hook.description : undefined,\n });\n }\n return hooks;\n}\n\nexport function validatePluginPackageConfig(\n raw: unknown,\n pluginName: string,\n): PluginPackageConfig {\n const config: PluginPackageConfig = {};\n\n if (raw === undefined || raw === null) {\n return config;\n }\n if (!isPlainObject(raw)) {\n logger.warn(\n `[plugin-manifest] ${pluginName} 的 mioku 字段必须是对象,已使用空配置`,\n );\n return config;\n }\n\n warnUnknownFields(`${pluginName}.mioku`, raw, PLUGIN_CONFIG_KEYS);\n\n if (raw.services !== undefined) {\n if (Array.isArray(raw.services)) {\n const services = raw.services.filter(\n (s): s is string => typeof s === \"string\" && s.length > 0,\n );\n const dropped = raw.services.length - services.length;\n if (dropped > 0) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.services 丢弃 ${dropped} 个非字符串项`,\n );\n }\n config.services = services;\n } else {\n logger.warn(`[plugin-manifest] ${pluginName}.services 必须是字符串数组`);\n }\n }\n\n const help = validateHelp(raw.help, pluginName);\n if (help) config.help = help;\n\n const hooks = validateAccessHooks(raw.accessHooks, pluginName);\n if (hooks) config.accessHooks = hooks;\n\n return config;\n}","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { mkdirSync } from \"fs\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n PluginPackageConfig,\n} from \"../types\";\nimport { DEFAULT_RUNTIME_PLUGINS_DIR } from \"./plugin-linker\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n resolveRealpath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\nimport { validatePluginPackageConfig } from \"./plugin-manifest\";\n\nconst PLUGIN_PREFIX = \"mioku-plugin-\";\n\nexport class PluginManager {\n private plugins = new Map<string, PluginMetadata>();\n\n static getInstance(): PluginManager {\n return getOrCreate(\"plugin-manager\", () => new PluginManager());\n }\n\n async discoverPlugins(miokuConfig: MiokuRuntimeConfig = {}): Promise<PluginMetadata[]> {\n const configuredDir = miokuConfig.plugins_dir;\n const pluginsDir =\n configuredDir && configuredDir !== DEFAULT_RUNTIME_PLUGINS_DIR\n ? path.resolve(process.cwd(), configuredDir)\n : path.resolve(process.cwd(), \"plugins\");\n\n this.plugins.clear();\n\n if (!(await pathExists(pluginsDir))) {\n mkdirSync(pluginsDir, { recursive: true });\n }\n\n const local = await scanLocalDir(pluginsDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n const external = await scanNodeModules(PLUGIN_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n logger.info(`O.o 发现了 ${this.plugins.size} 个插件`);\n return [...this.plugins.values()];\n }\n\n private async loadPluginMetadata(\n name: string,\n pluginPath: string,\n ): Promise<PluginMetadata | null> {\n const resolvedPath = await resolveRealpath(pluginPath);\n let packageJson: PackageJsonLike | null = null;\n try {\n packageJson = JSON.parse(\n await fs.readFile(path.join(resolvedPath, \"package.json\"), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);\n }\n\nconst config: PluginPackageConfig = validatePluginPackageConfig(\n packageJson?.mioku,\n name,\n );\n return {\n name,\n version: packageJson?.version ?? \"0.0.0\",\n description: packageJson?.description,\n path: resolvedPath,\n packageJson: packageJson ?? {},\n config,\n };\n }\n\n collectRequiredServices(): Set<string> {\n const services = new Set<string>();\n for (const metadata of this.plugins.values()) {\n for (const service of metadata.config.services ?? []) services.add(service);\n }\n return services;\n }\n\n getPluginMetadata(name: string): PluginMetadata | undefined {\n return this.plugins.get(name);\n }\n\n getAllMetadata(): PluginMetadata[] {\n return [...this.plugins.values()];\n }\n\n reset(): void {\n this.plugins.clear();\n }\n}\n\nexport default PluginManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokiContext } from \"mioki\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n ServiceMetadata,\n MiokuService,\n} from \"../types\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n toImportPath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\n\nconst SERVICE_PREFIX = \"mioku-service-\";\n\nexport class ServiceManager {\n private services = new Map<string, MiokuService>();\n private serviceMetadata = new Map<string, ServiceMetadata>();\n\n static getInstance(): ServiceManager {\n return getOrCreate(\"service-manager\", () => new ServiceManager());\n }\n\n async discoverServices(miokuConfig: MiokuRuntimeConfig = {}): Promise<ServiceMetadata[]> {\n const servicesDir = miokuConfig.services_dir\n ? path.resolve(process.cwd(), miokuConfig.services_dir)\n : path.resolve(process.cwd(), \"services\");\n\n this.serviceMetadata.clear();\n\n if (existsSync(servicesDir)) {\n const local = await scanLocalDir(servicesDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n } else {\n mkdirSync(servicesDir, { recursive: true });\n }\n\n const external = await scanNodeModules(SERVICE_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n\n logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);\n return [...this.serviceMetadata.values()];\n }\n\n private async loadServiceMetadata(\n name: string,\n servicePath: string,\n ): Promise<ServiceMetadata | null> {\n const packageJsonPath = path.join(servicePath, \"package.json\");\n if (!(await pathExists(packageJsonPath))) return null;\n\n try {\n const packageJson: PackageJsonLike = JSON.parse(\n await fs.readFile(packageJsonPath, \"utf-8\"),\n );\n return {\n name,\n version: packageJson.version ?? \"0.0.0\",\n description: packageJson.description,\n path: servicePath,\n packageJson,\n };\n } catch (error) {\n logger.warn(`[service-manager] 解析服务 ${name} 失败: ${error}`);\n return null;\n }\n }\n\n async checkMissingServices(required: Set<string>): Promise<string[]> {\n const missing: string[] = [];\n for (const name of required) {\n if (!this.serviceMetadata.has(name)) missing.push(name);\n }\n return missing;\n }\n\n async loadAllServices(ctx: MiokiContext): Promise<void> {\n const all = [...this.serviceMetadata.values()];\n logger.info(`O.o 准备加载 ${all.length} 个服务...`);\n for (const metadata of all) {\n await this.loadService(metadata, ctx);\n }\n }\n\n private async loadService(\n metadata: ServiceMetadata,\n ctx: MiokiContext,\n ): Promise<boolean> {\n try {\n const tsEntry = path.join(metadata.path, \"index.ts\");\n const jsEntry = path.join(metadata.path, \"index.js\");\n const entry = (await pathExists(tsEntry))\n ? tsEntry\n : (await pathExists(jsEntry))\n ? jsEntry\n : null;\n if (!entry) {\n logger.error(`[service-manager] 服务 ${metadata.name} 入口丢失`);\n return false;\n }\n\n const serviceModule = await import(toImportPath(entry));\n const service: MiokuService = serviceModule.default ?? serviceModule;\n if (!service || typeof service.init !== \"function\") {\n logger.warn(`[service-manager] 服务 ${metadata.name} 无效:缺少 init()`);\n return false;\n }\n\n await service.init();\n if (service.api) {\n ctx.services[metadata.name] = service.api;\n }\n this.services.set(metadata.name, service);\n return true;\n } catch (error) {\n logger.error(`[service-manager] 加载服务 ${metadata.name} 失败: ${error}`);\n return false;\n }\n }\n\n registerBuiltinService(name: string, service: MiokuService): void {\n this.services.set(name, service);\n }\n\n getService(name: string): MiokuService | undefined {\n return this.services.get(name);\n }\n\n async disposeAll(): Promise<void> {\n for (const [, service] of this.services) {\n await service.dispose?.();\n }\n this.services.clear();\n }\n\n reset(): void {\n this.services.clear();\n this.serviceMetadata.clear();\n }\n}\n\nexport default ServiceManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokuRuntimeConfig } from \"../types\";\nimport pluginManager from \"./plugin-manager\";\nimport serviceManager from \"./service-manager\";\nimport {\n prepareRuntimePluginLinks,\n DEFAULT_RUNTIME_PLUGINS_DIR,\n} from \"./plugin-linker\";\nimport { logger } from \"./logger\";\n\ninterface BotConfigLike {\n plugins: string[];\n plugins_dir?: string;\n}\n\nexport interface BootstrapDeps {\n cwd: string;\n botConfig: BotConfigLike;\n startMioki: (opts: { cwd: string }) => Promise<void>;\n}\n\nexport async function readMiokuConfig(): Promise<MiokuRuntimeConfig> {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n try {\n const pkg = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n return (pkg.mioki ?? {}) as MiokuRuntimeConfig;\n } catch {\n return {};\n }\n}\n\nfunction ensureRuntimeDirectories(): void {\n for (const dir of [\"data\", \"config\", \"temp\"]) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n }\n}\n\nasync function discoverAndLinkPlugins(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<string[]> {\n logger.info(\"O.o Miku 正在翻找插件..\");\n const discovered = await pluginManager.discoverPlugins(miokuConfig);\n logger.info(\n `O.o 共发现 ${discovered.length} 个插件: ${discovered.map((p) => p.name).join(\", \")}`,\n );\n const runtimePluginsDir = path.resolve(\n process.cwd(),\n DEFAULT_RUNTIME_PLUGINS_DIR,\n );\n return prepareRuntimePluginLinks(discovered, runtimePluginsDir);\n}\n\nasync function discoverAndValidateServices(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<void> {\n logger.info(\"o.O Miku 正在翻找服务..\");\n await serviceManager.discoverServices(miokuConfig);\n const requiredServices = pluginManager.collectRequiredServices();\n const missing = await serviceManager.checkMissingServices(requiredServices);\n if (missing.length > 0) logger.warn(`发现缺失服务: ${missing.join(\", \")}`);\n}\n\nfunction applyPluginAllowlist(\n miokuConfig: MiokuRuntimeConfig,\n botConfig: BotConfigLike,\n linkedPluginNames: string[],\n): void {\n botConfig.plugins_dir = DEFAULT_RUNTIME_PLUGINS_DIR;\n // Respect an explicit plugins list; only auto-load when undefined.\n if (miokuConfig.plugins !== undefined) return;\n for (const name of linkedPluginNames) {\n if (!botConfig.plugins.includes(name)) botConfig.plugins.push(name);\n }\n}\n\nexport async function bootstrapMioku(deps: BootstrapDeps): Promise<void> {\n const { cwd, botConfig, startMioki } = deps;\n const miokuConfig = await readMiokuConfig();\n ensureRuntimeDirectories();\n const linkedPluginNames = await discoverAndLinkPlugins(miokuConfig);\n await discoverAndValidateServices(miokuConfig);\n applyPluginAllowlist(miokuConfig, botConfig, linkedPluginNames);\n await startMioki({ cwd });\n}\n","import type { MiokiContext } from \"mioki\";\n\nexport interface ServiceRef<T> {\n readonly id: string;\n}\n\nexport function defineService<T>(id: string): ServiceRef<T> {\n return { id };\n}\n\nexport function getService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T | undefined {\n return ctx.services[ref.id] as T | undefined;\n}\n\nexport function requireService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T {\n const svc = ctx.services[ref.id] as T | undefined;\n if (svc === undefined) {\n throw new Error(\n `[mioku] required service \"${ref.id}\" is not available`,\n );\n }\n return svc;\n}\n\nexport function hasService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): boolean {\n return ctx.services[ref.id] !== undefined;\n}","import type {\n AIService,\n ConfigService,\n ScreenshotService,\n HelpService,\n} from \"../types\";\nimport { defineService } from \"./service\";\n\nexport const Services = {\n AI: defineService<AIService>(\"ai\"),\n Config: defineService<ConfigService>(\"config\"),\n Screenshot: defineService<ScreenshotService>(\"screenshot\"),\n Help: defineService<HelpService>(\"help\"),\n} as const;\n\nexport type BuiltinServiceRef =\n | typeof Services.AI\n | typeof Services.Config\n | typeof Services.Screenshot\n | typeof Services.Help;","import type { MiokiContext } from \"mioki\";\nimport { botConfig } from \"mioki\";\nimport { getService } from \"./service\";\nimport { Services } from \"./services\";\nimport pluginManager from \"./plugin-manager\";\nimport { logger } from \"./logger\";\n\nfunction hasPublicKeyword(keywords: unknown): boolean {\n return Array.isArray(keywords) && keywords.includes(\"mioku\");\n}\n\nexport async function registerPluginArtifacts(ctx: MiokiContext): Promise<void> {\n const enabledPlugins = new Set<string>(botConfig.plugins ?? []);\n const pluginMetadata = pluginManager.getAllMetadata().filter((metadata) =>\n enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true,\n );\n\n const helpService = getService(ctx, Services.Help);\n if (!helpService) return;\n\n let helpCount = 0;\n for (const metadata of pluginMetadata) {\n if (!metadata.config.help) continue;\n if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;\n helpService.registerHelp(metadata.name, metadata.config.help);\n helpCount += 1;\n }\n logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport { logger } from \"./logger\";\n\nconst SERVICE_CONFIG_ROOT = \"service\";\n\nfunction resolveConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", SERVICE_CONFIG_ROOT, serviceName);\n}\n\nfunction resolveConfigPath(serviceName: string, configName: string): string {\n return path.join(resolveConfigDir(serviceName), `${configName}.json`);\n}\n\nfunction ensureDir(serviceName: string): void {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport async function registerServiceConfig(\n serviceName: string,\n configName: string,\n defaults: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) {\n await fs.writeFile(configPath, JSON.stringify(defaults, null, 2), \"utf-8\");\n }\n}\n\nexport async function getServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<Record<string, unknown>> {\n const configPath = resolveConfigPath(serviceName, configName);\n try {\n return JSON.parse(await fs.readFile(configPath, \"utf-8\"));\n } catch (error) {\n if (!existsSync(configPath)) return {};\n logger.warn(`[service-config] 读取 ${serviceName}/${configName} 失败: ${error}`);\n return {};\n }\n}\n\nexport async function updateServiceConfig(\n serviceName: string,\n configName: string,\n value: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n await fs.writeFile(\n resolveConfigPath(serviceName, configName),\n JSON.stringify(value, null, 2),\n \"utf-8\",\n );\n}\n\nexport async function getServiceConfigs(\n serviceName: string,\n): Promise<Record<string, Record<string, unknown>>> {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) return {};\n\n const result: Record<string, Record<string, unknown>> = {};\n const files = (await fs.readdir(dir)).filter((name) => name.endsWith(\".json\"));\n for (const file of files) {\n try {\n result[path.basename(file, \".json\")] = JSON.parse(\n await fs.readFile(path.join(dir, file), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[service-config] 读取 ${serviceName}/${file} 失败: ${error}`);\n }\n }\n return result;\n}\n\nexport async function deleteServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<boolean> {\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) return false;\n await fs.unlink(configPath);\n return true;\n}\n","// Mioku framework types — single source of truth for the public API surface.\n\n// ---------- framework ----------\n\nexport interface MiokuService {\n name: string;\n version: string;\n description?: string;\n init(): Promise<void>;\n api: Record<string, any>;\n dispose?(): Promise<void>;\n}\n\nexport interface MiokuRuntimeConfig {\n plugins?: string[];\n plugins_dir?: string;\n services_dir?: string;\n [key: string]: unknown;\n}\n\nexport interface PackageJsonLike {\n name?: string;\n version?: string;\n description?: string;\n keywords?: string[];\n mioki?: MiokuRuntimeConfig;\n mioku?: PluginPackageConfig;\n dependencies?: Record<string, string>;\n}\n\nexport interface PluginMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n config: PluginPackageConfig;\n}\n\nexport interface ServiceMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n}\n\n// ---------- plugin package config ----------\n\nexport interface PluginPackageConfig {\n services?: string[];\n help?: PluginHelp;\n accessHooks?: AccessHook[];\n}\n\nexport interface PluginHelp {\n title: string;\n description: string;\n commands: Array<{\n cmd: string;\n desc: string;\n usage?: string;\n role?: CommandRole;\n }>;\n}\n\nexport type CommandRole = \"master\" | \"admin\" | \"owner\" | \"member\";\n\n/**\n * - `\"master\"`:仅 bot 主人可触发\n * - `\"owner\"`:legacy alias\n * - `\"admin\"`:bot 主人或管理员\n * - `\"member\"`:群内任意成员\n *\n */\nexport type SkillPermissionRole = \"master\" | \"owner\" | \"admin\" | \"member\";\n\nexport function normalizeSkillPermissionRole(\n role: unknown,\n): SkillPermissionRole {\n const normalized = String(role ?? \"\")\n .trim()\n .toLowerCase();\n if (\n normalized === \"master\" ||\n normalized === \"owner\" ||\n normalized === \"admin\" ||\n normalized === \"member\"\n ) {\n return normalized as SkillPermissionRole;\n }\n return \"member\";\n}\n\nexport interface AccessHook {\n id: string;\n match?: string;\n event?: string;\n description?: string;\n}\n\nexport type AccessAction = \"allow\" | \"block\";\n\nexport interface AccessRuleEntry {\n action: AccessAction;\n}\n\nexport interface AccessScopeConfig {\n plugins?: Record<string, AccessRuleEntry>;\n commands?: Record<string, Record<string, AccessRuleEntry>>;\n}\n\nexport interface AccessControlConfig {\n version: 1;\n global: AccessScopeConfig;\n groups: Record<string, AccessScopeConfig>;\n users: Record<string, AccessScopeConfig>;\n}\n\n// ---------- built-in service contracts ----------\n\nexport interface ConfigService {\n registerConfig(\n pluginName: string,\n configName: string,\n initialConfig: any,\n ): Promise<boolean>;\n updateConfig(\n pluginName: string,\n configName: string,\n updates: any,\n ): Promise<boolean>;\n getConfig(pluginName: string, configName: string): Promise<any>;\n getPluginConfigs(pluginName: string): Promise<Record<string, any>>;\n onConfigChange(\n pluginName: string,\n configName: string,\n callback: (newConfig: any) => void,\n ): () => void;\n}\n\nexport interface ScreenshotService {\n screenshot(html: string, options?: any): Promise<string>;\n screenshotMarkdown(markdownContent: string, options?: any): Promise<string>;\n screenshotFromUrl(url: string, options?: any): Promise<string>;\n cleanupTemp(olderThanMs?: number): Promise<number>;\n}\n\nexport interface HelpService {\n registerHelp(pluginName: string, help: PluginHelp): void;\n getHelp(pluginName: string): PluginHelp | undefined;\n getAllHelp(): Map<string, PluginHelp>;\n unregisterHelp(pluginName: string): boolean;\n}\n\nexport interface WebUIService {\n getSettings(): { port: number; host: string; packageManager: string };\n}\n\n// ---------- AI service ----------\n\nexport interface AITool {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n handler: (args: any, event?: any) => Promise<any> | any;\n}\n\nexport interface AISkill {\n name: string;\n description: string;\n permission?: SkillPermissionRole;\n tools: AITool[];\n}\n\nexport interface TextMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface MultimodalContentItem {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"auto\" | \"low\" | \"high\";\n };\n}\n\nexport interface MultimodalMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string | MultimodalContentItem[];\n}\n\nexport interface ToolCallRecord {\n name: string;\n arguments: any;\n result: any;\n}\n\nexport interface SessionToolDefinition {\n name: string;\n tool: AITool;\n}\n\nexport interface CompleteOptions {\n model?: string;\n messages: any[];\n temperature?: number;\n max_tokens?: number;\n stream?: boolean;\n tools?: any[];\n executableTools?: SessionToolDefinition[];\n executableToolsProvider?: () => SessionToolDefinition[];\n maxIterations?: number;\n onTextDelta?: (delta: string) => void | Promise<void>;\n usageContext?: AIUsageContext;\n usageContextTokens?: number;\n usageBreakdown?: AIUsageFinalization[\"breakdown\"];\n}\n\nexport interface CompleteResponse {\n content: string | null;\n reasoning: string | null;\n toolCalls: Array<{ id: string; name: string; arguments: string }>;\n raw: any;\n turnMessages: any[];\n iterations?: number;\n allToolCalls?: ToolCallRecord[];\n}\n\nexport type AIProtocol =\n | \"openai-chat\"\n | \"openai-response\"\n | \"anthropic\"\n | \"gemini\";\n\nexport type AIModelCapability = \"text\" | \"vision\" | \"tool-use\" | \"reasoning\";\n\nexport type AIModelRole = \"main\" | \"working\" | \"vision\";\n\nexport interface AIProviderConfig {\n id: string;\n name: string;\n protocol: AIProtocol;\n apiUrl: string;\n apiKey: string;\n enabled: boolean;\n headers?: Record<string, string>;\n}\n\nexport interface AIModelDescriptor {\n id: string;\n providerId: string;\n modelId: string;\n name: string;\n capabilities: AIModelCapability[];\n contextWindow?: number;\n maxOutputTokens?: number;\n isCustom?: boolean;\n}\n\nexport interface AIInstanceInfo {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n}\n\nexport interface AIInstance {\n generateText(options: {\n prompt?: string;\n messages: TextMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n generateMultimodal(options: {\n prompt?: string;\n messages: MultimodalMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n complete(options: CompleteOptions): Promise<CompleteResponse>;\n generateWithTools(options: {\n prompt?: string;\n messages: TextMessage[] | MultimodalMessage[];\n model?: string;\n temperature?: number;\n maxIterations?: number;\n }): Promise<any>;\n setUsageContext?(context: AIUsageContext | undefined): void;\n withUsageContext?<T>(\n context: AIUsageContext | undefined,\n fn: () => Promise<T>,\n ): Promise<T>;\n registerPrompt(name: string, prompt: string): boolean;\n getPrompt(name: string): string | undefined;\n getAllPrompts(): Record<string, string>;\n removePrompt(name: string): boolean;\n}\n\nexport interface AIService {\n create(options: {\n name: string;\n apiUrl: string;\n apiKey: string;\n modelType: \"text\" | \"multimodal\";\n model?: string;\n }): Promise<AIInstance>;\n createInstance?(options: {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n }): Promise<AIInstance>;\n get(name: string): AIInstance | undefined;\n list(): string[];\n listInstances?(): AIInstanceInfo[];\n remove(name: string): boolean;\n setDefault(name: string): boolean;\n getDefault(): AIInstance | undefined;\n listProviders?(): AIProviderConfig[];\n getProvider?(id: string): AIProviderConfig | undefined;\n createProvider?(\n input: Omit<AIProviderConfig, \"id\"> & { id?: string },\n ): Promise<AIProviderConfig>;\n updateProvider?(\n id: string,\n input: Partial<AIProviderConfig>,\n ): Promise<AIProviderConfig>;\n removeProvider?(id: string): boolean;\n testProvider?(\n id: string,\n ): Promise<{ ok: boolean; error?: string; models?: AIModelDescriptor[] }>;\n listModels?(providerId?: string): AIModelDescriptor[];\n refreshModels?(providerId: string): Promise<AIModelDescriptor[]>;\n registerCustomModel?(input: {\n providerId: string;\n modelId: string;\n name?: string;\n capabilities?: AIModelCapability[];\n }): AIModelDescriptor;\n removeCustomModel?(modelFullId: string): boolean;\n getRoleBindings?(): Record<AIModelRole, string | undefined>;\n setRoleBinding?(role: AIModelRole, modelFullId: string | undefined): boolean;\n getInstanceByRole?(role: AIModelRole): AIInstance | undefined;\n setMainFallbackChain?(modelFullIds: string[]): void;\n getMainFallbackChain?(): string[];\n registerChatRuntime(runtime: any): boolean;\n getChatRuntime(): any;\n removeChatRuntime(): boolean;\n registerSkill(skill: AISkill): boolean;\n getSkill(skillName: string): AISkill | undefined;\n getAllSkills(): Map<string, AISkill>;\n removeSkill(skillName: string): boolean;\n getTool(toolName: string): AITool | undefined;\n getAllTools(): Map<string, AITool>;\n getUsageSummary?(options: {\n range: AIUsageRange;\n botId?: number;\n }): AIUsageSummary;\n cleanupUsageStats?(retentionMs?: number): number;\n finalizeUsage?(usageId: string, finalization: AIUsageFinalization): boolean;\n}\n\n// ---------- chat runtime ----------\n\nexport interface ChatRuntime {\n generateNotice(options: ChatRuntimeNoticeOptions): Promise<ChatRuntimeResult>;\n requestInformation(\n options: ChatRuntimeInformationRequestOptions,\n ): Promise<ChatRuntimeResult>;\n}\n\nexport const TOOL_RESULT_FOLLOWUP_KEY = \"__miokuFollowup\";\n\nexport interface ToolResultFollowup {\n text: string;\n images?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n videos?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n}\n\nexport interface ChatRuntimePromptInjection {\n content: string;\n title?: string;\n}\n\nexport interface ChatRuntimeGroupTarget {\n selfId: number;\n groupId: number;\n}\n\nexport interface ChatRuntimePrivateTarget {\n selfId: number;\n userId: number;\n}\n\nexport type ChatRuntimeSource =\n | { event: any }\n | ChatRuntimeGroupTarget\n | ChatRuntimePrivateTarget;\n\nexport type ChatRuntimeBaseOptions = ChatRuntimeSource & {\n targetMessage?: string;\n promptInjections?: ChatRuntimePromptInjection[];\n send?: boolean;\n};\n\nexport type ChatRuntimeNoticeOptions = ChatRuntimeBaseOptions & {\n instruction: string;\n};\n\nexport type ChatRuntimeInformationRequestOptions = ChatRuntimeBaseOptions & {\n task: string;\n schema: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n toolName?: string;\n toolDescription?: string;\n};\n\nexport interface ChatRuntimeCollectedInfo {\n data: any;\n isComplete?: boolean;\n confidence?: number;\n notes?: string;\n}\n\nexport interface ChatRuntimeResult {\n messages: string[];\n toolCalls: ToolCallRecord[];\n collectedInfo: ChatRuntimeCollectedInfo | null;\n pendingAt?: number[];\n pendingPoke?: number[];\n pendingQuote?: number;\n emojiPath?: string | null;\n protocolMessages?: any[];\n}\n\n// ---------- usage tracking ----------\n\nexport type AIUsageRange = \"today\" | \"7d\" | \"30d\";\n\nexport type AIUsageScope = \"all\" | \"bot\";\n\nexport interface AIUsageContext {\n usageId?: string;\n source?: string;\n botId?: number;\n groupId?: number;\n groupName?: string;\n userId?: number;\n userName?: string;\n sessionId?: string;\n fallbackUsed?: boolean;\n fallbackFrom?: string;\n}\n\nexport interface AIUsageBreakdown {\n systemPromptTokens?: number;\n chatHistoryTokens?: number;\n toolDefinitionTokens?: number;\n toolUseTokens?: number;\n otherContextTokens?: number;\n}\n\nexport interface AIUsageFinalization {\n sentUserMessages?: number;\n sentAssistantMessages?: number;\n breakdown?: AIUsageBreakdown;\n}\n\nexport interface AIUsageBotOption {\n botId: number;\n label: string;\n}\n\nexport interface AIUsageSummary {\n generatedAt: number;\n range: AIUsageRange;\n scope: AIUsageScope;\n botId?: number;\n bots: AIUsageBotOption[];\n totals: {\n requests: number;\n successfulRequests: number;\n failedRequests: number;\n userMessages: number;\n assistantMessages: number;\n systemMessages: number;\n toolMessages: number;\n sentUserMessages: number;\n sentAssistantMessages: number;\n inputTokens: number;\n outputTokens: number;\n systemPromptTokens: number;\n totalTokens: number;\n cacheWriteTokens: number;\n cacheReadTokens: number;\n toolDefinitionTokens: number;\n toolUseTokens: number;\n chatHistoryTokens: number;\n otherContextTokens: number;\n durationMs: number;\n toolCalls: number;\n };\n rates: {\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n };\n toolRanking: Array<{ name: string; count: number }>;\n groupRanking: Array<{\n groupId: number;\n groupName: string;\n requests: number;\n totalTokens: number;\n userMessages: number;\n assistantMessages: number;\n errorRate: number;\n }>;\n tokenFlow: Array<{\n name: \"输入\" | \"输出\" | \"缓存写入\" | \"缓存读取\";\n value: number;\n }>;\n tokenCategories: Array<{\n name: \"系统提示词\" | \"工具定义\" | \"工具使用\" | \"聊天上下文\" | \"其他上下文\";\n value: number;\n }>;\n dailyActivity: Array<{\n day: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n hourlyActivity: Array<{\n hour: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n}\n","import * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\n\nexport function getPluginDataDir(pluginName: string): string {\n return path.join(process.cwd(), \"data\", pluginName);\n}\n\nexport function getServiceDataDir(serviceName: string): string {\n return path.join(process.cwd(), \"data\", serviceName);\n}\n\nexport function getDataDir(): string {\n return path.join(process.cwd(), \"data\");\n}\n\nexport function getPluginConfigDir(pluginName: string): string {\n return path.join(process.cwd(), \"config\", pluginName);\n}\n\nexport function getServiceConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", \"service\", serviceName);\n}\n\nexport function getConfigDir(): string {\n return path.join(process.cwd(), \"config\");\n}\n\nexport function ensureDataDir(pluginName: string): string {\n const dir = getPluginDataDir(pluginName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n","import { getOrCreate } from \"./registry\";\n\nconst store = getOrCreate<Record<string, unknown>>(\n \"plugin-runtime-state\",\n () => ({}),\n);\n\nexport interface PluginStateRef<T> {\n readonly name: string;\n get(): T;\n set(next: T): void;\n reset(): void;\n}\n\nexport function defineState<T>(name: string, initial: T): PluginStateRef<T> {\n return {\n name,\n get(): T {\n const current = store[name];\n return (current === undefined ? initial : current) as T;\n },\n set(next: T): void {\n store[name] = next;\n },\n reset(): void {\n delete store[name];\n },\n };\n}\n\nexport function hasPluginState(name: string): boolean {\n return store[name] !== undefined;\n}\n\nexport function getPluginRuntimeState<T = Record<string, any>>(\n name: string,\n): T {\n if (!store[name]) store[name] = {};\n return store[name] as T;\n}\n\nexport function setPluginRuntimeState<T>(name: string, state: T): void {\n store[name] = state;\n}\n\nexport function resetPluginRuntimeState(name: string): void {\n delete store[name];\n}\n\nexport function getAllPluginRuntimeStates(): Record<string, unknown> {\n return { ...store };\n}","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { bootstrapMioku } from \"./core/bootstrap\";\nimport { setMiokuLogger } from \"./core/logger\";\nimport { default as serviceManager } from \"./core/service-manager\";\n\nexport type { MiokiPlugin, MiokiContext } from \"mioki\";\nexport type { EventMap } from \"napcat-sdk\";\n\nexport function definePlugin<T extends import(\"mioki\").MiokiPlugin>(\n plugin: T,\n): T {\n return plugin;\n}\n\nexport { default as pluginManager } from \"./core/plugin-manager\";\nexport { default as serviceManager } from \"./core/service-manager\";\nexport { registerPluginArtifacts } from \"./core/plugin-artifact-registry\";\n\nexport {\n registerServiceConfig,\n getServiceConfig,\n updateServiceConfig,\n getServiceConfigs,\n deleteServiceConfig,\n} from \"./core/service-config\";\n\nexport type {\n MiokuService,\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n ServiceMetadata,\n PluginPackageConfig,\n PluginHelp,\n CommandRole,\n AccessHook,\n AccessAction,\n AccessRuleEntry,\n AccessScopeConfig,\n AccessControlConfig,\n ConfigService,\n ScreenshotService,\n HelpService,\n WebUIService,\n AITool,\n AISkill,\n AIInstance,\n AIService,\n AIProtocol,\n AIModelCapability,\n AIModelRole,\n AIProviderConfig,\n AIModelDescriptor,\n AIInstanceInfo,\n ChatRuntime,\n TextMessage,\n MultimodalMessage,\n ToolCallRecord,\n CompleteOptions,\n CompleteResponse,\n SessionToolDefinition,\n SkillPermissionRole,\n MultimodalContentItem,\n ToolResultFollowup,\n ChatRuntimePromptInjection,\n ChatRuntimeGroupTarget,\n ChatRuntimePrivateTarget,\n ChatRuntimeSource,\n ChatRuntimeBaseOptions,\n ChatRuntimeNoticeOptions,\n ChatRuntimeInformationRequestOptions,\n ChatRuntimeCollectedInfo,\n ChatRuntimeResult,\n AIUsageRange,\n AIUsageScope,\n AIUsageBotOption,\n AIUsageContext,\n AIUsageBreakdown,\n AIUsageFinalization,\n AIUsageSummary,\n} from \"./types\";\n\nexport {\n TOOL_RESULT_FOLLOWUP_KEY,\n normalizeSkillPermissionRole,\n} from \"./types\";\n\nexport {\n defineService,\n getService,\n requireService,\n hasService,\n} from \"./core/service\";\nexport type { ServiceRef } from \"./core/service\";\nexport { Services } from \"./core/services\";\nexport type { BuiltinServiceRef } from \"./core/services\";\n\nexport interface MiokuStartOptions {\n cwd?: string;\n}\n\nexport async function start(options: MiokuStartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options;\n if (cwd) process.chdir(cwd);\n\n const { start: startMioki, logger, botConfig } = await import(\"mioki\");\n setMiokuLogger(logger);\n\n let shuttingDown = false;\n const shutdown = async (signal: string) => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info(`收到 ${signal} 信号,正在关闭服务...`);\n const timer = setTimeout(() => {\n logger.error(\"服务关闭超时,强制退出\");\n process.exit(1);\n }, 15_000);\n timer.unref();\n await serviceManager.disposeAll();\n clearTimeout(timer);\n logger.info(\"Mioku 服务已完全关闭\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n logger.info(\"こんにちは..\");\n logger.info(\"---------------------------------------\");\n logger.info(\"---------- Mioku 正在启动 ------------\");\n logger.info(\"---------------------------------------\");\n\n await bootstrapMioku({ cwd, botConfig, startMioki });\n}\n\nfunction readVersion(): string {\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const pkgPath = path.join(here, \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const version: string = readVersion();\n\nexport {\n getDataDir,\n getPluginDataDir,\n getServiceDataDir,\n getConfigDir,\n getPluginConfigDir,\n getServiceConfigDir,\n ensureDataDir,\n} from \"./core/data-paths\";\n\nexport {\n defineState,\n hasPluginState,\n getPluginRuntimeState,\n setPluginRuntimeState,\n resetPluginRuntimeState,\n getAllPluginRuntimeStates,\n} from \"./core/plugin-runtime-state\";\nexport type { PluginStateRef } from \"./core/plugin-runtime-state\";\n\nexport {\n resolveCommand,\n commandExists,\n buildSpawnPlan,\n runCommand,\n runCommandInherit,\n} from \"./core/exec\";\n\nexport type { RunCommandResult, SpawnPlan } from \"./core/exec\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["fallbackLogger: MiokuLogger","activeLogger: MiokuLogger","logger: MiokuLogger | undefined","logger","logger: MiokuLogger","filePath: string","p: string","dir: string","results: DiscoveredModule[]","entries: import(\"fs\").Dirent[]","prefix: string","entryPath: string","linkPath: string","targetPath: string","runtimePluginsDir: string","metadata: PluginMetadata","plugins: PluginMetadata[]","linkedNames: string[]","store","key: string","factory: () => T","prefix: string","obj: Record<string, unknown>","allowed: Set<string>","value: unknown","pluginName: string","commands: PluginHelp[\"commands\"]","hooks: AccessHook[]","raw: unknown","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","pluginPath: string","packageJson: PackageJsonLike | null","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","servicePath: string","packageJson: PackageJsonLike","required: Set<string>","missing: string[]","ctx: MiokiContext","metadata: ServiceMetadata","service: MiokuService","miokuConfig: MiokuRuntimeConfig","botConfig: BotConfigLike","linkedPluginNames: string[]","deps: BootstrapDeps","botConfig","id: string","ctx: MiokiContext","ref: ServiceRef<T>","keywords: unknown","ctx: MiokiContext","botConfig","serviceName: string","configName: string","defaults: Record<string, unknown>","value: Record<string, unknown>","result: Record<string, Record<string, unknown>>","role: unknown","pluginName: string","serviceName: string","name: string","initial: T","next: T","state: T","plugin: T","options: MiokuStartOptions","logger","signal: string","version: string"],"sources":["../src/core/logger.ts","../src/core/module-scanner.ts","../src/core/plugin-linker.ts","../src/core/registry.ts","../src/core/plugin-manifest.ts","../src/core/plugin-manager.ts","../src/core/service-manager.ts","../src/core/bootstrap.ts","../src/core/service.ts","../src/core/services.ts","../src/core/plugin-artifact-registry.ts","../src/core/service-config.ts","../src/types.ts","../src/core/data-paths.ts","../src/core/plugin-runtime-state.ts","../src/index.ts"],"sourcesContent":["type LogMethod = (...args: unknown[]) => void;\n\nexport interface MiokuLogger {\n error: LogMethod;\n warn: LogMethod;\n info: LogMethod;\n debug: LogMethod;\n trace?: LogMethod;\n}\n\nconst fallbackLogger: MiokuLogger = {\n error: (...args) => console.error(...args),\n warn: (...args) => console.warn(...args),\n info: (...args) => console.info(...args),\n debug: (...args) => console.debug(...args),\n trace: (...args) => console.debug(...args),\n};\n\nlet activeLogger: MiokuLogger = fallbackLogger;\n\nexport function setMiokuLogger(logger: MiokuLogger | undefined): void {\n activeLogger = logger || fallbackLogger;\n}\n\nexport function getMiokuLogger(): MiokuLogger {\n return activeLogger;\n}\n\nexport const logger: MiokuLogger = {\n error: (...args) => activeLogger.error(...args),\n warn: (...args) => activeLogger.warn(...args),\n info: (...args) => activeLogger.info(...args),\n debug: (...args) => activeLogger.debug(...args),\n trace: (...args) => activeLogger.trace?.(...args),\n};\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport interface DiscoveredModule {\n name: string;\n path: string;\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function resolveRealpath(p: string): Promise<string> {\n try {\n return await fs.realpath(p);\n } catch {\n return p;\n }\n}\n\n// Windows requires file:// URLs for absolute paths in dynamic import().\n// pathToFileURL also percent-encodes spaces and non-ASCII segments, which a\n// hand-rolled string replace leaves broken (e.g. \"C:\\用户\\my bot\").\nexport function toImportPath(filePath: string): string {\n if (process.platform === \"win32\") {\n return pathToFileURL(filePath).href;\n }\n return filePath;\n}\n\nexport async function scanLocalDir(dir: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n if (!(await pathExists(dir))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return results;\n }\n\n for (const entry of entries) {\n const entryPath = path.join(dir, entry.name);\n try {\n const stat = await fs.stat(entryPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n results.push({ name: entry.name, path: await resolveRealpath(entryPath) });\n }\n return results;\n}\n\nexport async function scanNodeModules(prefix: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n const nodeModulesPath = path.resolve(process.cwd(), \"node_modules\");\n if (!(await pathExists(nodeModulesPath))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(nodeModulesPath, { withFileTypes: true });\n } catch {\n return results;\n }\n\n // Don't filter by isDirectory(): node_modules entries are often symlinks\n // into the workspace, and Dirent.isDirectory() returns false for symlinks.\n for (const entry of entries) {\n if (!entry.name.startsWith(prefix)) continue;\n const name = entry.name.slice(prefix.length);\n const fullPath = path.join(nodeModulesPath, entry.name);\n results.push({ name, path: await resolveRealpath(fullPath) });\n }\n return results;\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport type { PluginMetadata } from \"../types\";\nimport { logger } from \"./logger\";\nimport { pathExists } from \"./module-scanner\";\n\nexport const DEFAULT_RUNTIME_PLUGINS_DIR = \".mioku/plugins\";\n\ntype SymlinkState = \"ok\" | \"blocked\" | \"removed\";\n\nasync function removeIfBrokenSymlink(entryPath: string): Promise<SymlinkState> {\n let stat;\n try {\n stat = await fs.lstat(entryPath);\n } catch {\n return \"removed\";\n }\n if (!stat.isSymbolicLink()) return \"blocked\";\n try {\n await fs.realpath(entryPath);\n return \"ok\";\n } catch {\n await fs.rm(entryPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${entryPath}`);\n return \"removed\";\n }\n}\n\nfunction relativeSymlinkTarget(linkPath: string, targetPath: string): string {\n return path.relative(path.dirname(linkPath), targetPath) || \".\";\n}\n\nasync function ensurePluginLink(\n runtimePluginsDir: string,\n metadata: PluginMetadata,\n): Promise<boolean> {\n const linkPath = path.join(runtimePluginsDir, metadata.name);\n const targetPath = metadata.path;\n\n let stat;\n try {\n stat = await fs.lstat(linkPath);\n } catch {\n stat = null;\n }\n\n if (stat?.isSymbolicLink()) {\n try {\n const currentTarget = await fs.realpath(linkPath);\n const expectedTarget = await fs.realpath(targetPath);\n if (currentTarget === expectedTarget) return true;\n await fs.rm(linkPath, { force: true });\n logger.info(`[plugin-linker] Rebuilding plugin link: ${metadata.name}`);\n } catch {\n await fs.rm(linkPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${linkPath}`);\n }\n } else if (stat) {\n logger.warn(\n `[plugin-linker] ${linkPath} exists and is not a symlink, skip linking ${metadata.name}`,\n );\n return false;\n }\n\n if (!(await pathExists(targetPath))) {\n logger.warn(\n `[plugin-linker] Plugin target missing, skip linking ${metadata.name}: ${targetPath}`,\n );\n return false;\n }\n\n // Junctions on Windows don't require admin rights; relative dir symlinks elsewhere.\n if (process.platform === \"win32\") {\n await fs.symlink(targetPath, linkPath, \"junction\");\n } else {\n await fs.symlink(relativeSymlinkTarget(linkPath, targetPath), linkPath, \"dir\");\n }\n return true;\n}\n\nexport async function prepareRuntimePluginLinks(\n plugins: PluginMetadata[],\n runtimePluginsDir = path.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR),\n): Promise<string[]> {\n await fs.mkdir(runtimePluginsDir, { recursive: true });\n\n const discoveredNames = new Set(plugins.map((p) => p.name));\n const entries = await fs.readdir(runtimePluginsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(runtimePluginsDir, entry.name);\n if ((await removeIfBrokenSymlink(entryPath)) !== \"ok\") continue;\n if (entry.isSymbolicLink() && !discoveredNames.has(entry.name)) {\n await fs.rm(entryPath, { force: true });\n logger.info(`[plugin-linker] Removed stale plugin link: ${entry.name}`);\n }\n }\n\n const linkedNames: string[] = [];\n for (const metadata of plugins) {\n if (await ensurePluginLink(runtimePluginsDir, metadata)) {\n linkedNames.push(metadata.name);\n }\n }\n return linkedNames;\n}\n","// Framework singletons are stashed on globalThis so they survive jiti's\n// moduleCache-off re-evaluation (mioki loads plugins via jiti). Callers that\n// live in the normally-cached `mioku` dist could use a plain module-level\n// const, but the global indirection keeps things stable if a plugin ever\n// re-imports the framework through jiti.\n\nconst STORE_SYMBOL = Symbol.for(\"mioku.globalStore\");\ntype GlobalStore = Record<string, unknown>;\n\nfunction store(): GlobalStore {\n const g = globalThis as unknown as Record<symbol, GlobalStore>;\n if (!g[STORE_SYMBOL]) g[STORE_SYMBOL] = {};\n return g[STORE_SYMBOL]!;\n}\n\nexport function getOrCreate<T>(key: string, factory: () => T): T {\n const s = store();\n if (s[key] === undefined) s[key] = factory();\n return s[key] as T;\n}\n","import { logger } from \"./logger\";\nimport type {\n AccessHook,\n PluginHelp,\n PluginPackageConfig,\n} from \"../types\";\n\nconst PLUGIN_CONFIG_KEYS = new Set([\n \"services\",\n \"help\",\n \"accessHooks\",\n]);\n\nconst ACCESS_HOOK_KEYS = new Set([\n \"id\",\n \"match\",\n \"event\",\n \"description\",\n]);\n\nconst HELP_KEYS = new Set([\"title\", \"description\", \"commands\"]);\n\nconst HELP_COMMAND_KEYS = new Set([\"cmd\", \"desc\", \"usage\", \"role\"]);\n\nfunction warnUnknownFields(\n prefix: string,\n obj: Record<string, unknown>,\n allowed: Set<string>,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key)) {\n logger.warn(`[plugin-manifest] ${prefix} 含未知字段 \"${key}\"(将被忽略)`);\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction validateHelp(value: unknown, pluginName: string): PluginHelp | undefined {\n if (value === undefined) return undefined;\n if (!isPlainObject(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);\n return undefined;\n }\n warnUnknownFields(`${pluginName}.help`, value, HELP_KEYS);\n\n const title = String(value.title ?? \"\").trim();\n const description = String(value.description ?? \"\").trim();\n const rawCommands = value.commands;\n\n if (!title) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.title 缺失或为空`);\n }\n if (!description) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.description 缺失或为空`);\n }\n if (!Array.isArray(rawCommands)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 必须是数组`);\n return { title, description, commands: [] };\n }\n\n const commands: PluginHelp[\"commands\"] = [];\n for (const cmd of rawCommands) {\n if (!isPlainObject(cmd)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.help.commands[]`,\n cmd,\n HELP_COMMAND_KEYS,\n );\n const cmdName = String(cmd.cmd ?? \"\").trim();\n const desc = String(cmd.desc ?? \"\").trim();\n if (!cmdName || !desc) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.help.commands 项缺少 cmd 或 desc`,\n );\n continue;\n }\n commands.push({\n cmd: cmdName,\n desc,\n usage: typeof cmd.usage === \"string\" ? cmd.usage : undefined,\n role: typeof cmd.role === \"string\" ? (cmd.role as never) : undefined,\n });\n }\n\n return { title, description, commands };\n}\n\nfunction validateAccessHooks(\n value: unknown,\n pluginName: string,\n): AccessHook[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 必须是数组`);\n return undefined;\n }\n\n const hooks: AccessHook[] = [];\n for (const hook of value) {\n if (!isPlainObject(hook)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.accessHooks[]`,\n hook,\n ACCESS_HOOK_KEYS,\n );\n const id = String(hook.id ?? \"\").trim();\n if (!id) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.accessHooks 项缺少 id,已忽略`,\n );\n continue;\n }\n hooks.push({\n id,\n match: typeof hook.match === \"string\" ? hook.match : undefined,\n event: typeof hook.event === \"string\" ? hook.event : undefined,\n description:\n typeof hook.description === \"string\" ? hook.description : undefined,\n });\n }\n return hooks;\n}\n\nexport function validatePluginPackageConfig(\n raw: unknown,\n pluginName: string,\n): PluginPackageConfig {\n const config: PluginPackageConfig = {};\n\n if (raw === undefined || raw === null) {\n return config;\n }\n if (!isPlainObject(raw)) {\n logger.warn(\n `[plugin-manifest] ${pluginName} 的 mioku 字段必须是对象,已使用空配置`,\n );\n return config;\n }\n\n warnUnknownFields(`${pluginName}.mioku`, raw, PLUGIN_CONFIG_KEYS);\n\n if (raw.services !== undefined) {\n if (Array.isArray(raw.services)) {\n const services = raw.services.filter(\n (s): s is string => typeof s === \"string\" && s.length > 0,\n );\n const dropped = raw.services.length - services.length;\n if (dropped > 0) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.services 丢弃 ${dropped} 个非字符串项`,\n );\n }\n config.services = services;\n } else {\n logger.warn(`[plugin-manifest] ${pluginName}.services 必须是字符串数组`);\n }\n }\n\n const help = validateHelp(raw.help, pluginName);\n if (help) config.help = help;\n\n const hooks = validateAccessHooks(raw.accessHooks, pluginName);\n if (hooks) config.accessHooks = hooks;\n\n return config;\n}","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { mkdirSync } from \"fs\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n PluginPackageConfig,\n} from \"../types\";\nimport { DEFAULT_RUNTIME_PLUGINS_DIR } from \"./plugin-linker\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n resolveRealpath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\nimport { validatePluginPackageConfig } from \"./plugin-manifest\";\n\nconst PLUGIN_PREFIX = \"mioku-plugin-\";\n\nexport class PluginManager {\n private plugins = new Map<string, PluginMetadata>();\n\n static getInstance(): PluginManager {\n return getOrCreate(\"plugin-manager\", () => new PluginManager());\n }\n\n async discoverPlugins(miokuConfig: MiokuRuntimeConfig = {}): Promise<PluginMetadata[]> {\n const configuredDir = miokuConfig.plugins_dir;\n const pluginsDir =\n configuredDir && configuredDir !== DEFAULT_RUNTIME_PLUGINS_DIR\n ? path.resolve(process.cwd(), configuredDir)\n : path.resolve(process.cwd(), \"plugins\");\n\n this.plugins.clear();\n\n if (!(await pathExists(pluginsDir))) {\n mkdirSync(pluginsDir, { recursive: true });\n }\n\n const local = await scanLocalDir(pluginsDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n const external = await scanNodeModules(PLUGIN_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n logger.info(`O.o 发现了 ${this.plugins.size} 个插件`);\n return [...this.plugins.values()];\n }\n\n private async loadPluginMetadata(\n name: string,\n pluginPath: string,\n ): Promise<PluginMetadata | null> {\n const resolvedPath = await resolveRealpath(pluginPath);\n let packageJson: PackageJsonLike | null = null;\n try {\n packageJson = JSON.parse(\n await fs.readFile(path.join(resolvedPath, \"package.json\"), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);\n }\n\nconst config: PluginPackageConfig = validatePluginPackageConfig(\n packageJson?.mioku,\n name,\n );\n return {\n name,\n version: packageJson?.version ?? \"0.0.0\",\n description: packageJson?.description,\n path: resolvedPath,\n packageJson: packageJson ?? {},\n config,\n };\n }\n\n collectRequiredServices(): Set<string> {\n const services = new Set<string>();\n for (const metadata of this.plugins.values()) {\n for (const service of metadata.config.services ?? []) services.add(service);\n }\n return services;\n }\n\n getPluginMetadata(name: string): PluginMetadata | undefined {\n return this.plugins.get(name);\n }\n\n getAllMetadata(): PluginMetadata[] {\n return [...this.plugins.values()];\n }\n\n reset(): void {\n this.plugins.clear();\n }\n}\n\nexport default PluginManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokiContext } from \"mioki\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n ServiceMetadata,\n MiokuService,\n} from \"../types\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n toImportPath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\n\nconst SERVICE_PREFIX = \"mioku-service-\";\n\nexport class ServiceManager {\n private services = new Map<string, MiokuService>();\n private serviceMetadata = new Map<string, ServiceMetadata>();\n\n static getInstance(): ServiceManager {\n return getOrCreate(\"service-manager\", () => new ServiceManager());\n }\n\n async discoverServices(miokuConfig: MiokuRuntimeConfig = {}): Promise<ServiceMetadata[]> {\n const servicesDir = miokuConfig.services_dir\n ? path.resolve(process.cwd(), miokuConfig.services_dir)\n : path.resolve(process.cwd(), \"services\");\n\n this.serviceMetadata.clear();\n\n if (existsSync(servicesDir)) {\n const local = await scanLocalDir(servicesDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n } else {\n mkdirSync(servicesDir, { recursive: true });\n }\n\n const external = await scanNodeModules(SERVICE_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n\n logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);\n return [...this.serviceMetadata.values()];\n }\n\n private async loadServiceMetadata(\n name: string,\n servicePath: string,\n ): Promise<ServiceMetadata | null> {\n const packageJsonPath = path.join(servicePath, \"package.json\");\n if (!(await pathExists(packageJsonPath))) return null;\n\n try {\n const packageJson: PackageJsonLike = JSON.parse(\n await fs.readFile(packageJsonPath, \"utf-8\"),\n );\n return {\n name,\n version: packageJson.version ?? \"0.0.0\",\n description: packageJson.description,\n path: servicePath,\n packageJson,\n };\n } catch (error) {\n logger.warn(`[service-manager] 解析服务 ${name} 失败: ${error}`);\n return null;\n }\n }\n\n async checkMissingServices(required: Set<string>): Promise<string[]> {\n const missing: string[] = [];\n for (const name of required) {\n if (!this.serviceMetadata.has(name)) missing.push(name);\n }\n return missing;\n }\n\n async loadAllServices(ctx: MiokiContext): Promise<void> {\n const all = [...this.serviceMetadata.values()];\n logger.info(`O.o 准备加载 ${all.length} 个服务...`);\n for (const metadata of all) {\n await this.loadService(metadata, ctx);\n }\n }\n\n private async loadService(\n metadata: ServiceMetadata,\n ctx: MiokiContext,\n ): Promise<boolean> {\n try {\n const tsEntry = path.join(metadata.path, \"index.ts\");\n const jsEntry = path.join(metadata.path, \"index.js\");\n const entry = (await pathExists(tsEntry))\n ? tsEntry\n : (await pathExists(jsEntry))\n ? jsEntry\n : null;\n if (!entry) {\n logger.error(`[service-manager] 服务 ${metadata.name} 入口丢失`);\n return false;\n }\n\n const serviceModule = await import(toImportPath(entry));\n const service: MiokuService = serviceModule.default ?? serviceModule;\n if (!service || typeof service.init !== \"function\") {\n logger.warn(`[service-manager] 服务 ${metadata.name} 无效:缺少 init()`);\n return false;\n }\n\n await service.init();\n if (service.api) {\n ctx.services[metadata.name] = service.api;\n }\n this.services.set(metadata.name, service);\n return true;\n } catch (error) {\n logger.error(`[service-manager] 加载服务 ${metadata.name} 失败: ${error}`);\n return false;\n }\n }\n\n registerBuiltinService(name: string, service: MiokuService): void {\n this.services.set(name, service);\n }\n\n getService(name: string): MiokuService | undefined {\n return this.services.get(name);\n }\n\n async disposeAll(): Promise<void> {\n for (const [, service] of this.services) {\n await service.dispose?.();\n }\n this.services.clear();\n }\n\n reset(): void {\n this.services.clear();\n this.serviceMetadata.clear();\n }\n}\n\nexport default ServiceManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokuRuntimeConfig } from \"../types\";\nimport pluginManager from \"./plugin-manager\";\nimport serviceManager from \"./service-manager\";\nimport {\n prepareRuntimePluginLinks,\n DEFAULT_RUNTIME_PLUGINS_DIR,\n} from \"./plugin-linker\";\nimport { logger } from \"./logger\";\n\ninterface BotConfigLike {\n plugins: string[];\n plugins_dir?: string;\n}\n\nexport interface BootstrapDeps {\n cwd: string;\n botConfig: BotConfigLike;\n startMioki: (opts: { cwd: string }) => Promise<void>;\n}\n\nexport async function readMiokuConfig(): Promise<MiokuRuntimeConfig> {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n try {\n const pkg = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n return (pkg.mioki ?? {}) as MiokuRuntimeConfig;\n } catch {\n return {};\n }\n}\n\nfunction ensureRuntimeDirectories(): void {\n for (const dir of [\"data\", \"config\", \"temp\"]) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n }\n}\n\nasync function discoverAndLinkPlugins(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<string[]> {\n logger.info(\"O.o Miku 正在翻找插件..\");\n const discovered = await pluginManager.discoverPlugins(miokuConfig);\n logger.info(\n `O.o 共发现 ${discovered.length} 个插件: ${discovered.map((p) => p.name).join(\", \")}`,\n );\n const runtimePluginsDir = path.resolve(\n process.cwd(),\n DEFAULT_RUNTIME_PLUGINS_DIR,\n );\n return prepareRuntimePluginLinks(discovered, runtimePluginsDir);\n}\n\nasync function discoverAndValidateServices(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<void> {\n logger.info(\"o.O Miku 正在翻找服务..\");\n await serviceManager.discoverServices(miokuConfig);\n const requiredServices = pluginManager.collectRequiredServices();\n const missing = await serviceManager.checkMissingServices(requiredServices);\n if (missing.length > 0) logger.warn(`发现缺失服务: ${missing.join(\", \")}`);\n}\n\nfunction applyPluginAllowlist(\n miokuConfig: MiokuRuntimeConfig,\n botConfig: BotConfigLike,\n linkedPluginNames: string[],\n): void {\n botConfig.plugins_dir = DEFAULT_RUNTIME_PLUGINS_DIR;\n // Respect an explicit plugins list; only auto-load when undefined.\n if (miokuConfig.plugins !== undefined) return;\n for (const name of linkedPluginNames) {\n if (!botConfig.plugins.includes(name)) botConfig.plugins.push(name);\n }\n}\n\nexport async function bootstrapMioku(deps: BootstrapDeps): Promise<void> {\n const { cwd, botConfig, startMioki } = deps;\n const miokuConfig = await readMiokuConfig();\n ensureRuntimeDirectories();\n const linkedPluginNames = await discoverAndLinkPlugins(miokuConfig);\n await discoverAndValidateServices(miokuConfig);\n applyPluginAllowlist(miokuConfig, botConfig, linkedPluginNames);\n await startMioki({ cwd });\n}\n","import type { MiokiContext } from \"mioki\";\n\nexport interface ServiceRef<T> {\n readonly id: string;\n}\n\nexport function defineService<T>(id: string): ServiceRef<T> {\n return { id };\n}\n\nexport function getService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T | undefined {\n return ctx.services[ref.id] as T | undefined;\n}\n\nexport function requireService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T {\n const svc = ctx.services[ref.id] as T | undefined;\n if (svc === undefined) {\n throw new Error(\n `[mioku] required service \"${ref.id}\" is not available`,\n );\n }\n return svc;\n}\n\nexport function hasService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): boolean {\n return ctx.services[ref.id] !== undefined;\n}","import type {\n AIService,\n ConfigService,\n ScreenshotService,\n HelpService,\n} from \"../types\";\nimport { defineService } from \"./service\";\n\nexport const Services = {\n AI: defineService<AIService>(\"ai\"),\n Config: defineService<ConfigService>(\"config\"),\n Screenshot: defineService<ScreenshotService>(\"screenshot\"),\n Help: defineService<HelpService>(\"help\"),\n} as const;\n\nexport type BuiltinServiceRef =\n | typeof Services.AI\n | typeof Services.Config\n | typeof Services.Screenshot\n | typeof Services.Help;","import type { MiokiContext } from \"mioki\";\nimport { botConfig } from \"mioki\";\nimport { getService } from \"./service\";\nimport { Services } from \"./services\";\nimport pluginManager from \"./plugin-manager\";\nimport { logger } from \"./logger\";\n\nfunction hasPublicKeyword(keywords: unknown): boolean {\n return Array.isArray(keywords) && keywords.includes(\"mioku\");\n}\n\nexport async function registerPluginArtifacts(ctx: MiokiContext): Promise<void> {\n const enabledPlugins = new Set<string>(botConfig.plugins ?? []);\n const pluginMetadata = pluginManager.getAllMetadata().filter((metadata) =>\n enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true,\n );\n\n const helpService = getService(ctx, Services.Help);\n if (!helpService) return;\n\n let helpCount = 0;\n for (const metadata of pluginMetadata) {\n if (!metadata.config.help) continue;\n if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;\n helpService.registerHelp(metadata.name, metadata.config.help);\n helpCount += 1;\n }\n logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport { logger } from \"./logger\";\n\nconst SERVICE_CONFIG_ROOT = \"service\";\n\nfunction resolveConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", SERVICE_CONFIG_ROOT, serviceName);\n}\n\nfunction resolveConfigPath(serviceName: string, configName: string): string {\n return path.join(resolveConfigDir(serviceName), `${configName}.json`);\n}\n\nfunction ensureDir(serviceName: string): void {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport async function registerServiceConfig(\n serviceName: string,\n configName: string,\n defaults: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) {\n await fs.writeFile(configPath, JSON.stringify(defaults, null, 2), \"utf-8\");\n }\n}\n\nexport async function getServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<Record<string, unknown>> {\n const configPath = resolveConfigPath(serviceName, configName);\n try {\n return JSON.parse(await fs.readFile(configPath, \"utf-8\"));\n } catch (error) {\n if (!existsSync(configPath)) return {};\n logger.warn(`[service-config] 读取 ${serviceName}/${configName} 失败: ${error}`);\n return {};\n }\n}\n\nexport async function updateServiceConfig(\n serviceName: string,\n configName: string,\n value: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n await fs.writeFile(\n resolveConfigPath(serviceName, configName),\n JSON.stringify(value, null, 2),\n \"utf-8\",\n );\n}\n\nexport async function getServiceConfigs(\n serviceName: string,\n): Promise<Record<string, Record<string, unknown>>> {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) return {};\n\n const result: Record<string, Record<string, unknown>> = {};\n const files = (await fs.readdir(dir)).filter((name) => name.endsWith(\".json\"));\n for (const file of files) {\n try {\n result[path.basename(file, \".json\")] = JSON.parse(\n await fs.readFile(path.join(dir, file), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[service-config] 读取 ${serviceName}/${file} 失败: ${error}`);\n }\n }\n return result;\n}\n\nexport async function deleteServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<boolean> {\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) return false;\n await fs.unlink(configPath);\n return true;\n}\n","// Mioku framework types — single source of truth for the public API surface.\n\n// ---------- framework ----------\n\nexport interface MiokuService {\n name: string;\n version: string;\n description?: string;\n init(): Promise<void>;\n api: Record<string, any>;\n dispose?(): Promise<void>;\n}\n\nexport interface MiokuRuntimeConfig {\n plugins?: string[];\n plugins_dir?: string;\n services_dir?: string;\n [key: string]: unknown;\n}\n\nexport interface PackageJsonLike {\n name?: string;\n version?: string;\n description?: string;\n keywords?: string[];\n mioki?: MiokuRuntimeConfig;\n mioku?: PluginPackageConfig;\n dependencies?: Record<string, string>;\n}\n\nexport interface PluginMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n config: PluginPackageConfig;\n}\n\nexport interface ServiceMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n}\n\n// ---------- plugin package config ----------\n\nexport interface PluginPackageConfig {\n services?: string[];\n help?: PluginHelp;\n accessHooks?: AccessHook[];\n}\n\nexport interface PluginHelp {\n title: string;\n description: string;\n commands: Array<{\n cmd: string;\n desc: string;\n usage?: string;\n role?: CommandRole;\n }>;\n}\n\nexport type CommandRole = \"master\" | \"admin\" | \"owner\" | \"member\";\n\n/**\n * - `\"master\"`:仅 bot 主人可触发\n * - `\"owner\"`:legacy alias\n * - `\"admin\"`:bot 主人或管理员\n * - `\"member\"`:群内任意成员\n *\n */\nexport type SkillPermissionRole = \"master\" | \"owner\" | \"admin\" | \"member\";\n\nexport function normalizeSkillPermissionRole(\n role: unknown,\n): SkillPermissionRole {\n const normalized = String(role ?? \"\")\n .trim()\n .toLowerCase();\n if (\n normalized === \"master\" ||\n normalized === \"owner\" ||\n normalized === \"admin\" ||\n normalized === \"member\"\n ) {\n return normalized as SkillPermissionRole;\n }\n return \"member\";\n}\n\nexport interface AccessHook {\n id: string;\n match?: string;\n event?: string;\n description?: string;\n}\n\nexport type AccessAction = \"allow\" | \"block\";\n\nexport interface AccessRuleEntry {\n action: AccessAction;\n}\n\nexport interface AccessScopeConfig {\n plugins?: Record<string, AccessRuleEntry>;\n commands?: Record<string, Record<string, AccessRuleEntry>>;\n}\n\nexport interface AccessControlConfig {\n version: 1;\n global: AccessScopeConfig;\n groups: Record<string, AccessScopeConfig>;\n users: Record<string, AccessScopeConfig>;\n}\n\n// ---------- built-in service contracts ----------\n\nexport interface ConfigService {\n registerConfig(\n pluginName: string,\n configName: string,\n initialConfig: any,\n ): Promise<boolean>;\n updateConfig(\n pluginName: string,\n configName: string,\n updates: any,\n ): Promise<boolean>;\n getConfig(pluginName: string, configName: string): Promise<any>;\n getPluginConfigs(pluginName: string): Promise<Record<string, any>>;\n onConfigChange(\n pluginName: string,\n configName: string,\n callback: (newConfig: any) => void,\n ): () => void;\n}\n\nexport interface ScreenshotService {\n screenshot(html: string, options?: any): Promise<string>;\n screenshotMarkdown(markdownContent: string, options?: any): Promise<string>;\n screenshotFromUrl(url: string, options?: any): Promise<string>;\n cleanupTemp(olderThanMs?: number): Promise<number>;\n}\n\nexport interface HelpService {\n registerHelp(pluginName: string, help: PluginHelp): void;\n getHelp(pluginName: string): PluginHelp | undefined;\n getAllHelp(): Map<string, PluginHelp>;\n unregisterHelp(pluginName: string): boolean;\n}\n\nexport interface WebUIService {\n getSettings(): { port: number; host: string; packageManager: string };\n}\n\n// ---------- AI service ----------\n\nexport interface AITool {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n handler: (args: any, event?: any) => Promise<any> | any;\n}\n\nexport interface AISkill {\n name: string;\n description: string;\n permission?: SkillPermissionRole;\n tools: AITool[];\n}\n\nexport interface TextMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface MultimodalContentItem {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"auto\" | \"low\" | \"high\";\n };\n}\n\nexport interface MultimodalMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string | MultimodalContentItem[];\n}\n\nexport interface ToolCallRecord {\n name: string;\n arguments: any;\n result: any;\n}\n\nexport interface SessionToolDefinition {\n name: string;\n tool: AITool;\n}\n\nexport interface CompleteOptions {\n model?: string;\n messages: any[];\n temperature?: number;\n max_tokens?: number;\n stream?: boolean;\n tools?: any[];\n executableTools?: SessionToolDefinition[];\n executableToolsProvider?: () => SessionToolDefinition[];\n maxIterations?: number;\n onTextDelta?: (delta: string) => void | Promise<void>;\n usageContext?: AIUsageContext;\n usageContextTokens?: number;\n usageBreakdown?: AIUsageFinalization[\"breakdown\"];\n}\n\nexport interface CompleteResponse {\n content: string | null;\n reasoning: string | null;\n toolCalls: Array<{ id: string; name: string; arguments: string }>;\n raw: any;\n turnMessages: any[];\n iterations?: number;\n allToolCalls?: ToolCallRecord[];\n}\n\nexport type AIProtocol =\n | \"openai-chat\"\n | \"openai-response\"\n | \"anthropic\"\n | \"gemini\";\n\nexport type AIModelCapability = \"text\" | \"vision\" | \"tool-use\" | \"reasoning\";\n\nexport type AIModelRole = \"main\" | \"working\" | \"vision\";\n\nexport interface AIProviderConfig {\n id: string;\n name: string;\n protocol: AIProtocol;\n apiUrl: string;\n apiKey: string;\n enabled: boolean;\n headers?: Record<string, string>;\n}\n\nexport interface AIModelDescriptor {\n id: string;\n providerId: string;\n modelId: string;\n name: string;\n capabilities: AIModelCapability[];\n contextWindow?: number;\n maxOutputTokens?: number;\n isCustom?: boolean;\n}\n\nexport interface AIInstanceInfo {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n}\n\nexport interface AIInstance {\n generateText(options: {\n prompt?: string;\n messages: TextMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n generateMultimodal(options: {\n prompt?: string;\n messages: MultimodalMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n complete(options: CompleteOptions): Promise<CompleteResponse>;\n generateWithTools(options: {\n prompt?: string;\n messages: TextMessage[] | MultimodalMessage[];\n model?: string;\n temperature?: number;\n maxIterations?: number;\n }): Promise<any>;\n setUsageContext?(context: AIUsageContext | undefined): void;\n withUsageContext?<T>(\n context: AIUsageContext | undefined,\n fn: () => Promise<T>,\n ): Promise<T>;\n registerPrompt(name: string, prompt: string): boolean;\n getPrompt(name: string): string | undefined;\n getAllPrompts(): Record<string, string>;\n removePrompt(name: string): boolean;\n}\n\nexport interface AIService {\n create(options: {\n name: string;\n apiUrl: string;\n apiKey: string;\n modelType: \"text\" | \"multimodal\";\n model?: string;\n }): Promise<AIInstance>;\n createInstance?(options: {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n }): Promise<AIInstance>;\n get(name: string): AIInstance | undefined;\n list(): string[];\n listInstances?(): AIInstanceInfo[];\n remove(name: string): boolean;\n setDefault(name: string): boolean;\n getDefault(): AIInstance | undefined;\n listProviders?(): AIProviderConfig[];\n getProvider?(id: string): AIProviderConfig | undefined;\n createProvider?(\n input: Omit<AIProviderConfig, \"id\"> & { id?: string },\n ): Promise<AIProviderConfig>;\n updateProvider?(\n id: string,\n input: Partial<AIProviderConfig>,\n ): Promise<AIProviderConfig>;\n removeProvider?(id: string): boolean;\n testProvider?(\n id: string,\n ): Promise<{ ok: boolean; error?: string; models?: AIModelDescriptor[] }>;\n listModels?(providerId?: string): AIModelDescriptor[];\n refreshModels?(providerId: string): Promise<AIModelDescriptor[]>;\n registerCustomModel?(input: {\n providerId: string;\n modelId: string;\n name?: string;\n capabilities?: AIModelCapability[];\n }): AIModelDescriptor;\n removeCustomModel?(modelFullId: string): boolean;\n getRoleBindings?(): Record<AIModelRole, string | undefined>;\n setRoleBinding?(role: AIModelRole, modelFullId: string | undefined): boolean;\n getInstanceByRole?(role: AIModelRole): AIInstance | undefined;\n setMainFallbackChain?(modelFullIds: string[]): void;\n getMainFallbackChain?(): string[];\n registerChatRuntime(runtime: any): boolean;\n getChatRuntime(): any;\n removeChatRuntime(): boolean;\n registerSkill(skill: AISkill): boolean;\n getSkill(skillName: string): AISkill | undefined;\n getAllSkills(): Map<string, AISkill>;\n removeSkill(skillName: string): boolean;\n getTool(toolName: string): AITool | undefined;\n getAllTools(): Map<string, AITool>;\n getUsageSummary?(options: {\n range: AIUsageRange;\n botId?: number;\n }): AIUsageSummary;\n cleanupUsageStats?(retentionMs?: number): number;\n finalizeUsage?(usageId: string, finalization: AIUsageFinalization): boolean;\n}\n\n// ---------- chat runtime ----------\n\nexport interface ChatRuntime {\n generateNotice(options: ChatRuntimeNoticeOptions): Promise<ChatRuntimeResult>;\n requestInformation(\n options: ChatRuntimeInformationRequestOptions,\n ): Promise<ChatRuntimeResult>;\n}\n\nexport const TOOL_RESULT_FOLLOWUP_KEY = \"__miokuFollowup\";\n\nexport interface ToolResultFollowup {\n text: string;\n images?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n videos?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n}\n\nexport interface ChatRuntimePromptInjection {\n content: string;\n title?: string;\n}\n\nexport interface ChatRuntimeGroupTarget {\n selfId: number;\n groupId: number;\n}\n\nexport interface ChatRuntimePrivateTarget {\n selfId: number;\n userId: number;\n}\n\nexport type ChatRuntimeSource =\n | { event: any }\n | ChatRuntimeGroupTarget\n | ChatRuntimePrivateTarget;\n\nexport type ChatRuntimeBaseOptions = ChatRuntimeSource & {\n targetMessage?: string;\n promptInjections?: ChatRuntimePromptInjection[];\n send?: boolean;\n};\n\nexport type ChatRuntimeNoticeOptions = ChatRuntimeBaseOptions & {\n instruction: string;\n};\n\nexport type ChatRuntimeInformationRequestOptions = ChatRuntimeBaseOptions & {\n task: string;\n schema: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n toolName?: string;\n toolDescription?: string;\n};\n\nexport interface ChatRuntimeCollectedInfo {\n data: any;\n isComplete?: boolean;\n confidence?: number;\n notes?: string;\n}\n\nexport interface ChatRuntimeResult {\n messages: string[];\n toolCalls: ToolCallRecord[];\n collectedInfo: ChatRuntimeCollectedInfo | null;\n pendingAt?: number[];\n pendingPoke?: number[];\n pendingQuote?: number;\n emojiPath?: string | null;\n protocolMessages?: any[];\n}\n\n// ---------- usage tracking ----------\n\nexport type AIUsageRange = \"today\" | \"7d\" | \"30d\";\n\nexport type AIUsageScope = \"all\" | \"bot\";\n\nexport interface AIUsageContext {\n usageId?: string;\n source?: string;\n botId?: number;\n groupId?: number;\n groupName?: string;\n userId?: number;\n userName?: string;\n sessionId?: string;\n fallbackUsed?: boolean;\n fallbackFrom?: string;\n}\n\nexport interface AIUsageBreakdown {\n systemPromptTokens?: number;\n chatHistoryTokens?: number;\n toolDefinitionTokens?: number;\n toolUseTokens?: number;\n otherContextTokens?: number;\n}\n\nexport interface AIUsageFinalization {\n sentUserMessages?: number;\n sentAssistantMessages?: number;\n breakdown?: AIUsageBreakdown;\n}\n\nexport interface AIUsageBotOption {\n botId: number;\n label: string;\n}\n\nexport interface AIUsageSummary {\n generatedAt: number;\n range: AIUsageRange;\n scope: AIUsageScope;\n botId?: number;\n bots: AIUsageBotOption[];\n totals: {\n requests: number;\n successfulRequests: number;\n failedRequests: number;\n userMessages: number;\n assistantMessages: number;\n systemMessages: number;\n toolMessages: number;\n sentUserMessages: number;\n sentAssistantMessages: number;\n inputTokens: number;\n outputTokens: number;\n systemPromptTokens: number;\n totalTokens: number;\n cacheWriteTokens: number;\n cacheReadTokens: number;\n toolDefinitionTokens: number;\n toolUseTokens: number;\n chatHistoryTokens: number;\n otherContextTokens: number;\n durationMs: number;\n toolCalls: number;\n };\n rates: {\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n };\n toolRanking: Array<{ name: string; count: number }>;\n groupRanking: Array<{\n groupId: number;\n groupName: string;\n requests: number;\n totalTokens: number;\n userMessages: number;\n assistantMessages: number;\n errorRate: number;\n }>;\n tokenFlow: Array<{\n name: \"输入\" | \"输出\" | \"缓存写入\" | \"缓存读取\";\n value: number;\n }>;\n tokenCategories: Array<{\n name: \"系统提示词\" | \"工具定义\" | \"工具使用\" | \"聊天上下文\" | \"其他上下文\";\n value: number;\n }>;\n dailyActivity: Array<{\n day: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n hourlyActivity: Array<{\n hour: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n}\n","import * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\n\nexport function getPluginDataDir(pluginName: string): string {\n return path.join(process.cwd(), \"data\", pluginName);\n}\n\nexport function getServiceDataDir(serviceName: string): string {\n return path.join(process.cwd(), \"data\", serviceName);\n}\n\nexport function getDataDir(): string {\n return path.join(process.cwd(), \"data\");\n}\n\nexport function getPluginConfigDir(pluginName: string): string {\n return path.join(process.cwd(), \"config\", pluginName);\n}\n\nexport function getServiceConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", \"service\", serviceName);\n}\n\nexport function getConfigDir(): string {\n return path.join(process.cwd(), \"config\");\n}\n\nexport function ensureDataDir(pluginName: string): string {\n const dir = getPluginDataDir(pluginName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n","import { getOrCreate } from \"./registry\";\n\nconst store = getOrCreate<Record<string, unknown>>(\n \"plugin-runtime-state\",\n () => ({}),\n);\n\nexport interface PluginStateRef<T> {\n readonly name: string;\n get(): T;\n set(next: T): void;\n reset(): void;\n}\n\nexport function defineState<T>(name: string, initial: T): PluginStateRef<T> {\n return {\n name,\n get(): T {\n const current = store[name];\n return (current === undefined ? initial : current) as T;\n },\n set(next: T): void {\n store[name] = next;\n },\n reset(): void {\n delete store[name];\n },\n };\n}\n\nexport function hasPluginState(name: string): boolean {\n return store[name] !== undefined;\n}\n\nexport function getPluginRuntimeState<T = Record<string, any>>(\n name: string,\n): T {\n if (!store[name]) store[name] = {};\n return store[name] as T;\n}\n\nexport function setPluginRuntimeState<T>(name: string, state: T): void {\n store[name] = state;\n}\n\nexport function resetPluginRuntimeState(name: string): void {\n delete store[name];\n}\n\nexport function getAllPluginRuntimeStates(): Record<string, unknown> {\n return { ...store };\n}","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { bootstrapMioku } from \"./core/bootstrap\";\nimport { setMiokuLogger } from \"./core/logger\";\nimport { default as serviceManager } from \"./core/service-manager\";\n\nexport type { MiokiPlugin, MiokiContext } from \"mioki\";\nexport type { EventMap } from \"napcat-sdk\";\n\nexport function definePlugin<T extends import(\"mioki\").MiokiPlugin>(\n plugin: T,\n): T {\n return plugin;\n}\n\nexport { default as pluginManager } from \"./core/plugin-manager\";\nexport { default as serviceManager } from \"./core/service-manager\";\nexport { registerPluginArtifacts } from \"./core/plugin-artifact-registry\";\n\nexport {\n registerServiceConfig,\n getServiceConfig,\n updateServiceConfig,\n getServiceConfigs,\n deleteServiceConfig,\n} from \"./core/service-config\";\n\nexport type {\n MiokuService,\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n ServiceMetadata,\n PluginPackageConfig,\n PluginHelp,\n CommandRole,\n AccessHook,\n AccessAction,\n AccessRuleEntry,\n AccessScopeConfig,\n AccessControlConfig,\n ConfigService,\n ScreenshotService,\n HelpService,\n WebUIService,\n AITool,\n AISkill,\n AIInstance,\n AIService,\n AIProtocol,\n AIModelCapability,\n AIModelRole,\n AIProviderConfig,\n AIModelDescriptor,\n AIInstanceInfo,\n ChatRuntime,\n TextMessage,\n MultimodalMessage,\n ToolCallRecord,\n CompleteOptions,\n CompleteResponse,\n SessionToolDefinition,\n SkillPermissionRole,\n MultimodalContentItem,\n ToolResultFollowup,\n ChatRuntimePromptInjection,\n ChatRuntimeGroupTarget,\n ChatRuntimePrivateTarget,\n ChatRuntimeSource,\n ChatRuntimeBaseOptions,\n ChatRuntimeNoticeOptions,\n ChatRuntimeInformationRequestOptions,\n ChatRuntimeCollectedInfo,\n ChatRuntimeResult,\n AIUsageRange,\n AIUsageScope,\n AIUsageBotOption,\n AIUsageContext,\n AIUsageBreakdown,\n AIUsageFinalization,\n AIUsageSummary,\n} from \"./types\";\n\nexport {\n TOOL_RESULT_FOLLOWUP_KEY,\n normalizeSkillPermissionRole,\n} from \"./types\";\n\nexport {\n defineService,\n getService,\n requireService,\n hasService,\n} from \"./core/service\";\nexport type { ServiceRef } from \"./core/service\";\nexport { Services } from \"./core/services\";\nexport type { BuiltinServiceRef } from \"./core/services\";\n\nexport interface MiokuStartOptions {\n cwd?: string;\n}\n\nexport async function start(options: MiokuStartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options;\n if (cwd) process.chdir(cwd);\n\n const { start: startMioki, logger, botConfig } = await import(\"mioki\");\n setMiokuLogger(logger);\n\n let shuttingDown = false;\n const shutdown = async (signal: string) => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info(`收到 ${signal} 信号,正在关闭服务...`);\n const timer = setTimeout(() => {\n logger.error(\"服务关闭超时,强制退出\");\n process.exit(1);\n }, 15_000);\n timer.unref();\n await serviceManager.disposeAll();\n clearTimeout(timer);\n logger.info(\"Mioku 服务已完全关闭\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n logger.info(\"こんにちは..\");\n logger.info(\"---------------------------------------\");\n logger.info(\"---------- Mioku 正在启动 ------------\");\n logger.info(\"---------------------------------------\");\n\n await bootstrapMioku({ cwd, botConfig, startMioki });\n}\n\nfunction readVersion(): string {\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const pkgPath = path.join(here, \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const version: string = readVersion();\n\nexport {\n getDataDir,\n getPluginDataDir,\n getServiceDataDir,\n getConfigDir,\n getPluginConfigDir,\n getServiceConfigDir,\n ensureDataDir,\n} from \"./core/data-paths\";\n\nexport {\n defineState,\n hasPluginState,\n getPluginRuntimeState,\n setPluginRuntimeState,\n resetPluginRuntimeState,\n getAllPluginRuntimeStates,\n} from \"./core/plugin-runtime-state\";\nexport type { PluginStateRef } from \"./core/plugin-runtime-state\";\n\nexport {\n resolveCommand,\n commandExists,\n buildSpawnPlan,\n runCommand,\n runCommandInherit,\n} from \"./core/exec\";\n\nexport type { RunCommandResult, SpawnPlan } from \"./core/exec\";\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -204,6 +204,11 @@ const ACCESS_HOOK_KEYS = new Set([
204
204
  "event",
205
205
  "description"
206
206
  ]);
207
+ const HELP_KEYS = new Set([
208
+ "title",
209
+ "description",
210
+ "commands"
211
+ ]);
207
212
  const HELP_COMMAND_KEYS = new Set([
208
213
  "cmd",
209
214
  "desc",
@@ -222,7 +227,7 @@ function validateHelp(value, pluginName) {
222
227
  logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);
223
228
  return void 0;
224
229
  }
225
- warnUnknownFields(`${pluginName}.help`, value, HELP_COMMAND_KEYS);
230
+ warnUnknownFields(`${pluginName}.help`, value, HELP_KEYS);
226
231
  const title = String(value.title ?? "").trim();
227
232
  const description = String(value.description ?? "").trim();
228
233
  const rawCommands = value.commands;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["fallbackLogger: MiokuLogger","activeLogger: MiokuLogger","logger: MiokuLogger | undefined","logger","logger: MiokuLogger","filePath: string","p: string","dir: string","results: DiscoveredModule[]","entries: import(\"fs\").Dirent[]","prefix: string","entryPath: string","linkPath: string","targetPath: string","runtimePluginsDir: string","metadata: PluginMetadata","plugins: PluginMetadata[]","linkedNames: string[]","store","key: string","factory: () => T","prefix: string","obj: Record<string, unknown>","allowed: Set<string>","value: unknown","pluginName: string","commands: PluginHelp[\"commands\"]","hooks: AccessHook[]","raw: unknown","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","pluginPath: string","packageJson: PackageJsonLike | null","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","servicePath: string","packageJson: PackageJsonLike","required: Set<string>","missing: string[]","ctx: MiokiContext","metadata: ServiceMetadata","service: MiokuService","miokuConfig: MiokuRuntimeConfig","botConfig: BotConfigLike","linkedPluginNames: string[]","deps: BootstrapDeps","botConfig","id: string","ctx: MiokiContext","ref: ServiceRef<T>","keywords: unknown","ctx: MiokiContext","serviceName: string","configName: string","defaults: Record<string, unknown>","value: Record<string, unknown>","result: Record<string, Record<string, unknown>>","role: unknown","pluginName: string","serviceName: string","name: string","initial: T","next: T","state: T","plugin: T","options: MiokuStartOptions","logger","signal: string","version: string"],"sources":["../src/core/logger.ts","../src/core/module-scanner.ts","../src/core/plugin-linker.ts","../src/core/registry.ts","../src/core/plugin-manifest.ts","../src/core/plugin-manager.ts","../src/core/service-manager.ts","../src/core/bootstrap.ts","../src/core/service.ts","../src/core/services.ts","../src/core/plugin-artifact-registry.ts","../src/core/service-config.ts","../src/types.ts","../src/core/data-paths.ts","../src/core/plugin-runtime-state.ts","../src/index.ts"],"sourcesContent":["type LogMethod = (...args: unknown[]) => void;\n\nexport interface MiokuLogger {\n error: LogMethod;\n warn: LogMethod;\n info: LogMethod;\n debug: LogMethod;\n trace?: LogMethod;\n}\n\nconst fallbackLogger: MiokuLogger = {\n error: (...args) => console.error(...args),\n warn: (...args) => console.warn(...args),\n info: (...args) => console.info(...args),\n debug: (...args) => console.debug(...args),\n trace: (...args) => console.debug(...args),\n};\n\nlet activeLogger: MiokuLogger = fallbackLogger;\n\nexport function setMiokuLogger(logger: MiokuLogger | undefined): void {\n activeLogger = logger || fallbackLogger;\n}\n\nexport function getMiokuLogger(): MiokuLogger {\n return activeLogger;\n}\n\nexport const logger: MiokuLogger = {\n error: (...args) => activeLogger.error(...args),\n warn: (...args) => activeLogger.warn(...args),\n info: (...args) => activeLogger.info(...args),\n debug: (...args) => activeLogger.debug(...args),\n trace: (...args) => activeLogger.trace?.(...args),\n};\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport interface DiscoveredModule {\n name: string;\n path: string;\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function resolveRealpath(p: string): Promise<string> {\n try {\n return await fs.realpath(p);\n } catch {\n return p;\n }\n}\n\n// Windows requires file:// URLs for absolute paths in dynamic import().\n// pathToFileURL also percent-encodes spaces and non-ASCII segments, which a\n// hand-rolled string replace leaves broken (e.g. \"C:\\用户\\my bot\").\nexport function toImportPath(filePath: string): string {\n if (process.platform === \"win32\") {\n return pathToFileURL(filePath).href;\n }\n return filePath;\n}\n\nexport async function scanLocalDir(dir: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n if (!(await pathExists(dir))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return results;\n }\n\n for (const entry of entries) {\n const entryPath = path.join(dir, entry.name);\n try {\n const stat = await fs.stat(entryPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n results.push({ name: entry.name, path: await resolveRealpath(entryPath) });\n }\n return results;\n}\n\nexport async function scanNodeModules(prefix: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n const nodeModulesPath = path.resolve(process.cwd(), \"node_modules\");\n if (!(await pathExists(nodeModulesPath))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(nodeModulesPath, { withFileTypes: true });\n } catch {\n return results;\n }\n\n // Don't filter by isDirectory(): node_modules entries are often symlinks\n // into the workspace, and Dirent.isDirectory() returns false for symlinks.\n for (const entry of entries) {\n if (!entry.name.startsWith(prefix)) continue;\n const name = entry.name.slice(prefix.length);\n const fullPath = path.join(nodeModulesPath, entry.name);\n results.push({ name, path: await resolveRealpath(fullPath) });\n }\n return results;\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport type { PluginMetadata } from \"../types\";\nimport { logger } from \"./logger\";\nimport { pathExists } from \"./module-scanner\";\n\nexport const DEFAULT_RUNTIME_PLUGINS_DIR = \".mioku/plugins\";\n\ntype SymlinkState = \"ok\" | \"blocked\" | \"removed\";\n\nasync function removeIfBrokenSymlink(entryPath: string): Promise<SymlinkState> {\n let stat;\n try {\n stat = await fs.lstat(entryPath);\n } catch {\n return \"removed\";\n }\n if (!stat.isSymbolicLink()) return \"blocked\";\n try {\n await fs.realpath(entryPath);\n return \"ok\";\n } catch {\n await fs.rm(entryPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${entryPath}`);\n return \"removed\";\n }\n}\n\nfunction relativeSymlinkTarget(linkPath: string, targetPath: string): string {\n return path.relative(path.dirname(linkPath), targetPath) || \".\";\n}\n\nasync function ensurePluginLink(\n runtimePluginsDir: string,\n metadata: PluginMetadata,\n): Promise<boolean> {\n const linkPath = path.join(runtimePluginsDir, metadata.name);\n const targetPath = metadata.path;\n\n let stat;\n try {\n stat = await fs.lstat(linkPath);\n } catch {\n stat = null;\n }\n\n if (stat?.isSymbolicLink()) {\n try {\n const currentTarget = await fs.realpath(linkPath);\n const expectedTarget = await fs.realpath(targetPath);\n if (currentTarget === expectedTarget) return true;\n await fs.rm(linkPath, { force: true });\n logger.info(`[plugin-linker] Rebuilding plugin link: ${metadata.name}`);\n } catch {\n await fs.rm(linkPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${linkPath}`);\n }\n } else if (stat) {\n logger.warn(\n `[plugin-linker] ${linkPath} exists and is not a symlink, skip linking ${metadata.name}`,\n );\n return false;\n }\n\n if (!(await pathExists(targetPath))) {\n logger.warn(\n `[plugin-linker] Plugin target missing, skip linking ${metadata.name}: ${targetPath}`,\n );\n return false;\n }\n\n // Junctions on Windows don't require admin rights; relative dir symlinks elsewhere.\n if (process.platform === \"win32\") {\n await fs.symlink(targetPath, linkPath, \"junction\");\n } else {\n await fs.symlink(relativeSymlinkTarget(linkPath, targetPath), linkPath, \"dir\");\n }\n return true;\n}\n\nexport async function prepareRuntimePluginLinks(\n plugins: PluginMetadata[],\n runtimePluginsDir = path.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR),\n): Promise<string[]> {\n await fs.mkdir(runtimePluginsDir, { recursive: true });\n\n const discoveredNames = new Set(plugins.map((p) => p.name));\n const entries = await fs.readdir(runtimePluginsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(runtimePluginsDir, entry.name);\n if ((await removeIfBrokenSymlink(entryPath)) !== \"ok\") continue;\n if (entry.isSymbolicLink() && !discoveredNames.has(entry.name)) {\n await fs.rm(entryPath, { force: true });\n logger.info(`[plugin-linker] Removed stale plugin link: ${entry.name}`);\n }\n }\n\n const linkedNames: string[] = [];\n for (const metadata of plugins) {\n if (await ensurePluginLink(runtimePluginsDir, metadata)) {\n linkedNames.push(metadata.name);\n }\n }\n return linkedNames;\n}\n","// Framework singletons are stashed on globalThis so they survive jiti's\n// moduleCache-off re-evaluation (mioki loads plugins via jiti). Callers that\n// live in the normally-cached `mioku` dist could use a plain module-level\n// const, but the global indirection keeps things stable if a plugin ever\n// re-imports the framework through jiti.\n\nconst STORE_SYMBOL = Symbol.for(\"mioku.globalStore\");\ntype GlobalStore = Record<string, unknown>;\n\nfunction store(): GlobalStore {\n const g = globalThis as unknown as Record<symbol, GlobalStore>;\n if (!g[STORE_SYMBOL]) g[STORE_SYMBOL] = {};\n return g[STORE_SYMBOL]!;\n}\n\nexport function getOrCreate<T>(key: string, factory: () => T): T {\n const s = store();\n if (s[key] === undefined) s[key] = factory();\n return s[key] as T;\n}\n","import { logger } from \"./logger\";\nimport type {\n AccessHook,\n PluginHelp,\n PluginPackageConfig,\n} from \"../types\";\n\nconst PLUGIN_CONFIG_KEYS = new Set([\n \"services\",\n \"help\",\n \"accessHooks\",\n]);\n\nconst ACCESS_HOOK_KEYS = new Set([\n \"id\",\n \"match\",\n \"event\",\n \"description\",\n]);\n\nconst HELP_COMMAND_KEYS = new Set([\"cmd\", \"desc\", \"usage\", \"role\"]);\n\nfunction warnUnknownFields(\n prefix: string,\n obj: Record<string, unknown>,\n allowed: Set<string>,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key)) {\n logger.warn(`[plugin-manifest] ${prefix} 含未知字段 \"${key}\"(将被忽略)`);\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction validateHelp(value: unknown, pluginName: string): PluginHelp | undefined {\n if (value === undefined) return undefined;\n if (!isPlainObject(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);\n return undefined;\n }\n warnUnknownFields(`${pluginName}.help`, value, HELP_COMMAND_KEYS);\n\n const title = String(value.title ?? \"\").trim();\n const description = String(value.description ?? \"\").trim();\n const rawCommands = value.commands;\n\n if (!title) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.title 缺失或为空`);\n }\n if (!description) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.description 缺失或为空`);\n }\n if (!Array.isArray(rawCommands)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 必须是数组`);\n return { title, description, commands: [] };\n }\n\n const commands: PluginHelp[\"commands\"] = [];\n for (const cmd of rawCommands) {\n if (!isPlainObject(cmd)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.help.commands[]`,\n cmd,\n HELP_COMMAND_KEYS,\n );\n const cmdName = String(cmd.cmd ?? \"\").trim();\n const desc = String(cmd.desc ?? \"\").trim();\n if (!cmdName || !desc) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.help.commands 项缺少 cmd 或 desc`,\n );\n continue;\n }\n commands.push({\n cmd: cmdName,\n desc,\n usage: typeof cmd.usage === \"string\" ? cmd.usage : undefined,\n role: typeof cmd.role === \"string\" ? (cmd.role as never) : undefined,\n });\n }\n\n return { title, description, commands };\n}\n\nfunction validateAccessHooks(\n value: unknown,\n pluginName: string,\n): AccessHook[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 必须是数组`);\n return undefined;\n }\n\n const hooks: AccessHook[] = [];\n for (const hook of value) {\n if (!isPlainObject(hook)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.accessHooks[]`,\n hook,\n ACCESS_HOOK_KEYS,\n );\n const id = String(hook.id ?? \"\").trim();\n if (!id) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.accessHooks 项缺少 id,已忽略`,\n );\n continue;\n }\n hooks.push({\n id,\n match: typeof hook.match === \"string\" ? hook.match : undefined,\n event: typeof hook.event === \"string\" ? hook.event : undefined,\n description:\n typeof hook.description === \"string\" ? hook.description : undefined,\n });\n }\n return hooks;\n}\n\nexport function validatePluginPackageConfig(\n raw: unknown,\n pluginName: string,\n): PluginPackageConfig {\n const config: PluginPackageConfig = {};\n\n if (raw === undefined || raw === null) {\n return config;\n }\n if (!isPlainObject(raw)) {\n logger.warn(\n `[plugin-manifest] ${pluginName} 的 mioku 字段必须是对象,已使用空配置`,\n );\n return config;\n }\n\n warnUnknownFields(`${pluginName}.mioku`, raw, PLUGIN_CONFIG_KEYS);\n\n if (raw.services !== undefined) {\n if (Array.isArray(raw.services)) {\n const services = raw.services.filter(\n (s): s is string => typeof s === \"string\" && s.length > 0,\n );\n const dropped = raw.services.length - services.length;\n if (dropped > 0) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.services 丢弃 ${dropped} 个非字符串项`,\n );\n }\n config.services = services;\n } else {\n logger.warn(`[plugin-manifest] ${pluginName}.services 必须是字符串数组`);\n }\n }\n\n const help = validateHelp(raw.help, pluginName);\n if (help) config.help = help;\n\n const hooks = validateAccessHooks(raw.accessHooks, pluginName);\n if (hooks) config.accessHooks = hooks;\n\n return config;\n}","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { mkdirSync } from \"fs\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n PluginPackageConfig,\n} from \"../types\";\nimport { DEFAULT_RUNTIME_PLUGINS_DIR } from \"./plugin-linker\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n resolveRealpath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\nimport { validatePluginPackageConfig } from \"./plugin-manifest\";\n\nconst PLUGIN_PREFIX = \"mioku-plugin-\";\n\nexport class PluginManager {\n private plugins = new Map<string, PluginMetadata>();\n\n static getInstance(): PluginManager {\n return getOrCreate(\"plugin-manager\", () => new PluginManager());\n }\n\n async discoverPlugins(miokuConfig: MiokuRuntimeConfig = {}): Promise<PluginMetadata[]> {\n const configuredDir = miokuConfig.plugins_dir;\n const pluginsDir =\n configuredDir && configuredDir !== DEFAULT_RUNTIME_PLUGINS_DIR\n ? path.resolve(process.cwd(), configuredDir)\n : path.resolve(process.cwd(), \"plugins\");\n\n this.plugins.clear();\n\n if (!(await pathExists(pluginsDir))) {\n mkdirSync(pluginsDir, { recursive: true });\n }\n\n const local = await scanLocalDir(pluginsDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n const external = await scanNodeModules(PLUGIN_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n logger.info(`O.o 发现了 ${this.plugins.size} 个插件`);\n return [...this.plugins.values()];\n }\n\n private async loadPluginMetadata(\n name: string,\n pluginPath: string,\n ): Promise<PluginMetadata | null> {\n const resolvedPath = await resolveRealpath(pluginPath);\n let packageJson: PackageJsonLike | null = null;\n try {\n packageJson = JSON.parse(\n await fs.readFile(path.join(resolvedPath, \"package.json\"), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);\n }\n\nconst config: PluginPackageConfig = validatePluginPackageConfig(\n packageJson?.mioku,\n name,\n );\n return {\n name,\n version: packageJson?.version ?? \"0.0.0\",\n description: packageJson?.description,\n path: resolvedPath,\n packageJson: packageJson ?? {},\n config,\n };\n }\n\n collectRequiredServices(): Set<string> {\n const services = new Set<string>();\n for (const metadata of this.plugins.values()) {\n for (const service of metadata.config.services ?? []) services.add(service);\n }\n return services;\n }\n\n getPluginMetadata(name: string): PluginMetadata | undefined {\n return this.plugins.get(name);\n }\n\n getAllMetadata(): PluginMetadata[] {\n return [...this.plugins.values()];\n }\n\n reset(): void {\n this.plugins.clear();\n }\n}\n\nexport default PluginManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokiContext } from \"mioki\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n ServiceMetadata,\n MiokuService,\n} from \"../types\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n toImportPath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\n\nconst SERVICE_PREFIX = \"mioku-service-\";\n\nexport class ServiceManager {\n private services = new Map<string, MiokuService>();\n private serviceMetadata = new Map<string, ServiceMetadata>();\n\n static getInstance(): ServiceManager {\n return getOrCreate(\"service-manager\", () => new ServiceManager());\n }\n\n async discoverServices(miokuConfig: MiokuRuntimeConfig = {}): Promise<ServiceMetadata[]> {\n const servicesDir = miokuConfig.services_dir\n ? path.resolve(process.cwd(), miokuConfig.services_dir)\n : path.resolve(process.cwd(), \"services\");\n\n this.serviceMetadata.clear();\n\n if (existsSync(servicesDir)) {\n const local = await scanLocalDir(servicesDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n } else {\n mkdirSync(servicesDir, { recursive: true });\n }\n\n const external = await scanNodeModules(SERVICE_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n\n logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);\n return [...this.serviceMetadata.values()];\n }\n\n private async loadServiceMetadata(\n name: string,\n servicePath: string,\n ): Promise<ServiceMetadata | null> {\n const packageJsonPath = path.join(servicePath, \"package.json\");\n if (!(await pathExists(packageJsonPath))) return null;\n\n try {\n const packageJson: PackageJsonLike = JSON.parse(\n await fs.readFile(packageJsonPath, \"utf-8\"),\n );\n return {\n name,\n version: packageJson.version ?? \"0.0.0\",\n description: packageJson.description,\n path: servicePath,\n packageJson,\n };\n } catch (error) {\n logger.warn(`[service-manager] 解析服务 ${name} 失败: ${error}`);\n return null;\n }\n }\n\n async checkMissingServices(required: Set<string>): Promise<string[]> {\n const missing: string[] = [];\n for (const name of required) {\n if (!this.serviceMetadata.has(name)) missing.push(name);\n }\n return missing;\n }\n\n async loadAllServices(ctx: MiokiContext): Promise<void> {\n const all = [...this.serviceMetadata.values()];\n logger.info(`O.o 准备加载 ${all.length} 个服务...`);\n for (const metadata of all) {\n await this.loadService(metadata, ctx);\n }\n }\n\n private async loadService(\n metadata: ServiceMetadata,\n ctx: MiokiContext,\n ): Promise<boolean> {\n try {\n const tsEntry = path.join(metadata.path, \"index.ts\");\n const jsEntry = path.join(metadata.path, \"index.js\");\n const entry = (await pathExists(tsEntry))\n ? tsEntry\n : (await pathExists(jsEntry))\n ? jsEntry\n : null;\n if (!entry) {\n logger.error(`[service-manager] 服务 ${metadata.name} 入口丢失`);\n return false;\n }\n\n const serviceModule = await import(toImportPath(entry));\n const service: MiokuService = serviceModule.default ?? serviceModule;\n if (!service || typeof service.init !== \"function\") {\n logger.warn(`[service-manager] 服务 ${metadata.name} 无效:缺少 init()`);\n return false;\n }\n\n await service.init();\n if (service.api) {\n ctx.services[metadata.name] = service.api;\n }\n this.services.set(metadata.name, service);\n return true;\n } catch (error) {\n logger.error(`[service-manager] 加载服务 ${metadata.name} 失败: ${error}`);\n return false;\n }\n }\n\n registerBuiltinService(name: string, service: MiokuService): void {\n this.services.set(name, service);\n }\n\n getService(name: string): MiokuService | undefined {\n return this.services.get(name);\n }\n\n async disposeAll(): Promise<void> {\n for (const [, service] of this.services) {\n await service.dispose?.();\n }\n this.services.clear();\n }\n\n reset(): void {\n this.services.clear();\n this.serviceMetadata.clear();\n }\n}\n\nexport default ServiceManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokuRuntimeConfig } from \"../types\";\nimport pluginManager from \"./plugin-manager\";\nimport serviceManager from \"./service-manager\";\nimport {\n prepareRuntimePluginLinks,\n DEFAULT_RUNTIME_PLUGINS_DIR,\n} from \"./plugin-linker\";\nimport { logger } from \"./logger\";\n\ninterface BotConfigLike {\n plugins: string[];\n plugins_dir?: string;\n}\n\nexport interface BootstrapDeps {\n cwd: string;\n botConfig: BotConfigLike;\n startMioki: (opts: { cwd: string }) => Promise<void>;\n}\n\nexport async function readMiokuConfig(): Promise<MiokuRuntimeConfig> {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n try {\n const pkg = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n return (pkg.mioki ?? {}) as MiokuRuntimeConfig;\n } catch {\n return {};\n }\n}\n\nfunction ensureRuntimeDirectories(): void {\n for (const dir of [\"data\", \"config\", \"temp\"]) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n }\n}\n\nasync function discoverAndLinkPlugins(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<string[]> {\n logger.info(\"O.o Miku 正在翻找插件..\");\n const discovered = await pluginManager.discoverPlugins(miokuConfig);\n logger.info(\n `O.o 共发现 ${discovered.length} 个插件: ${discovered.map((p) => p.name).join(\", \")}`,\n );\n const runtimePluginsDir = path.resolve(\n process.cwd(),\n DEFAULT_RUNTIME_PLUGINS_DIR,\n );\n return prepareRuntimePluginLinks(discovered, runtimePluginsDir);\n}\n\nasync function discoverAndValidateServices(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<void> {\n logger.info(\"o.O Miku 正在翻找服务..\");\n await serviceManager.discoverServices(miokuConfig);\n const requiredServices = pluginManager.collectRequiredServices();\n const missing = await serviceManager.checkMissingServices(requiredServices);\n if (missing.length > 0) logger.warn(`发现缺失服务: ${missing.join(\", \")}`);\n}\n\nfunction applyPluginAllowlist(\n miokuConfig: MiokuRuntimeConfig,\n botConfig: BotConfigLike,\n linkedPluginNames: string[],\n): void {\n botConfig.plugins_dir = DEFAULT_RUNTIME_PLUGINS_DIR;\n // Respect an explicit plugins list; only auto-load when undefined.\n if (miokuConfig.plugins !== undefined) return;\n for (const name of linkedPluginNames) {\n if (!botConfig.plugins.includes(name)) botConfig.plugins.push(name);\n }\n}\n\nexport async function bootstrapMioku(deps: BootstrapDeps): Promise<void> {\n const { cwd, botConfig, startMioki } = deps;\n const miokuConfig = await readMiokuConfig();\n ensureRuntimeDirectories();\n const linkedPluginNames = await discoverAndLinkPlugins(miokuConfig);\n await discoverAndValidateServices(miokuConfig);\n applyPluginAllowlist(miokuConfig, botConfig, linkedPluginNames);\n await startMioki({ cwd });\n}\n","import type { MiokiContext } from \"mioki\";\n\nexport interface ServiceRef<T> {\n readonly id: string;\n}\n\nexport function defineService<T>(id: string): ServiceRef<T> {\n return { id };\n}\n\nexport function getService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T | undefined {\n return ctx.services[ref.id] as T | undefined;\n}\n\nexport function requireService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T {\n const svc = ctx.services[ref.id] as T | undefined;\n if (svc === undefined) {\n throw new Error(\n `[mioku] required service \"${ref.id}\" is not available`,\n );\n }\n return svc;\n}\n\nexport function hasService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): boolean {\n return ctx.services[ref.id] !== undefined;\n}","import type {\n AIService,\n ConfigService,\n ScreenshotService,\n HelpService,\n} from \"../types\";\nimport { defineService } from \"./service\";\n\nexport const Services = {\n AI: defineService<AIService>(\"ai\"),\n Config: defineService<ConfigService>(\"config\"),\n Screenshot: defineService<ScreenshotService>(\"screenshot\"),\n Help: defineService<HelpService>(\"help\"),\n} as const;\n\nexport type BuiltinServiceRef =\n | typeof Services.AI\n | typeof Services.Config\n | typeof Services.Screenshot\n | typeof Services.Help;","import type { MiokiContext } from \"mioki\";\nimport { botConfig } from \"mioki\";\nimport { getService } from \"./service\";\nimport { Services } from \"./services\";\nimport pluginManager from \"./plugin-manager\";\nimport { logger } from \"./logger\";\n\nfunction hasPublicKeyword(keywords: unknown): boolean {\n return Array.isArray(keywords) && keywords.includes(\"mioku\");\n}\n\nexport async function registerPluginArtifacts(ctx: MiokiContext): Promise<void> {\n const enabledPlugins = new Set<string>(botConfig.plugins ?? []);\n const pluginMetadata = pluginManager.getAllMetadata().filter((metadata) =>\n enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true,\n );\n\n const helpService = getService(ctx, Services.Help);\n if (!helpService) return;\n\n let helpCount = 0;\n for (const metadata of pluginMetadata) {\n if (!metadata.config.help) continue;\n if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;\n helpService.registerHelp(metadata.name, metadata.config.help);\n helpCount += 1;\n }\n logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport { logger } from \"./logger\";\n\nconst SERVICE_CONFIG_ROOT = \"service\";\n\nfunction resolveConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", SERVICE_CONFIG_ROOT, serviceName);\n}\n\nfunction resolveConfigPath(serviceName: string, configName: string): string {\n return path.join(resolveConfigDir(serviceName), `${configName}.json`);\n}\n\nfunction ensureDir(serviceName: string): void {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport async function registerServiceConfig(\n serviceName: string,\n configName: string,\n defaults: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) {\n await fs.writeFile(configPath, JSON.stringify(defaults, null, 2), \"utf-8\");\n }\n}\n\nexport async function getServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<Record<string, unknown>> {\n const configPath = resolveConfigPath(serviceName, configName);\n try {\n return JSON.parse(await fs.readFile(configPath, \"utf-8\"));\n } catch (error) {\n if (!existsSync(configPath)) return {};\n logger.warn(`[service-config] 读取 ${serviceName}/${configName} 失败: ${error}`);\n return {};\n }\n}\n\nexport async function updateServiceConfig(\n serviceName: string,\n configName: string,\n value: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n await fs.writeFile(\n resolveConfigPath(serviceName, configName),\n JSON.stringify(value, null, 2),\n \"utf-8\",\n );\n}\n\nexport async function getServiceConfigs(\n serviceName: string,\n): Promise<Record<string, Record<string, unknown>>> {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) return {};\n\n const result: Record<string, Record<string, unknown>> = {};\n const files = (await fs.readdir(dir)).filter((name) => name.endsWith(\".json\"));\n for (const file of files) {\n try {\n result[path.basename(file, \".json\")] = JSON.parse(\n await fs.readFile(path.join(dir, file), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[service-config] 读取 ${serviceName}/${file} 失败: ${error}`);\n }\n }\n return result;\n}\n\nexport async function deleteServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<boolean> {\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) return false;\n await fs.unlink(configPath);\n return true;\n}\n","// Mioku framework types — single source of truth for the public API surface.\n\n// ---------- framework ----------\n\nexport interface MiokuService {\n name: string;\n version: string;\n description?: string;\n init(): Promise<void>;\n api: Record<string, any>;\n dispose?(): Promise<void>;\n}\n\nexport interface MiokuRuntimeConfig {\n plugins?: string[];\n plugins_dir?: string;\n services_dir?: string;\n [key: string]: unknown;\n}\n\nexport interface PackageJsonLike {\n name?: string;\n version?: string;\n description?: string;\n keywords?: string[];\n mioki?: MiokuRuntimeConfig;\n mioku?: PluginPackageConfig;\n dependencies?: Record<string, string>;\n}\n\nexport interface PluginMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n config: PluginPackageConfig;\n}\n\nexport interface ServiceMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n}\n\n// ---------- plugin package config ----------\n\nexport interface PluginPackageConfig {\n services?: string[];\n help?: PluginHelp;\n accessHooks?: AccessHook[];\n}\n\nexport interface PluginHelp {\n title: string;\n description: string;\n commands: Array<{\n cmd: string;\n desc: string;\n usage?: string;\n role?: CommandRole;\n }>;\n}\n\nexport type CommandRole = \"master\" | \"admin\" | \"owner\" | \"member\";\n\n/**\n * - `\"master\"`:仅 bot 主人可触发\n * - `\"owner\"`:legacy alias\n * - `\"admin\"`:bot 主人或管理员\n * - `\"member\"`:群内任意成员\n *\n */\nexport type SkillPermissionRole = \"master\" | \"owner\" | \"admin\" | \"member\";\n\nexport function normalizeSkillPermissionRole(\n role: unknown,\n): SkillPermissionRole {\n const normalized = String(role ?? \"\")\n .trim()\n .toLowerCase();\n if (\n normalized === \"master\" ||\n normalized === \"owner\" ||\n normalized === \"admin\" ||\n normalized === \"member\"\n ) {\n return normalized as SkillPermissionRole;\n }\n return \"member\";\n}\n\nexport interface AccessHook {\n id: string;\n match?: string;\n event?: string;\n description?: string;\n}\n\nexport type AccessAction = \"allow\" | \"block\";\n\nexport interface AccessRuleEntry {\n action: AccessAction;\n}\n\nexport interface AccessScopeConfig {\n plugins?: Record<string, AccessRuleEntry>;\n commands?: Record<string, Record<string, AccessRuleEntry>>;\n}\n\nexport interface AccessControlConfig {\n version: 1;\n global: AccessScopeConfig;\n groups: Record<string, AccessScopeConfig>;\n users: Record<string, AccessScopeConfig>;\n}\n\n// ---------- built-in service contracts ----------\n\nexport interface ConfigService {\n registerConfig(\n pluginName: string,\n configName: string,\n initialConfig: any,\n ): Promise<boolean>;\n updateConfig(\n pluginName: string,\n configName: string,\n updates: any,\n ): Promise<boolean>;\n getConfig(pluginName: string, configName: string): Promise<any>;\n getPluginConfigs(pluginName: string): Promise<Record<string, any>>;\n onConfigChange(\n pluginName: string,\n configName: string,\n callback: (newConfig: any) => void,\n ): () => void;\n}\n\nexport interface ScreenshotService {\n screenshot(html: string, options?: any): Promise<string>;\n screenshotMarkdown(markdownContent: string, options?: any): Promise<string>;\n screenshotFromUrl(url: string, options?: any): Promise<string>;\n cleanupTemp(olderThanMs?: number): Promise<number>;\n}\n\nexport interface HelpService {\n registerHelp(pluginName: string, help: PluginHelp): void;\n getHelp(pluginName: string): PluginHelp | undefined;\n getAllHelp(): Map<string, PluginHelp>;\n unregisterHelp(pluginName: string): boolean;\n}\n\nexport interface WebUIService {\n getSettings(): { port: number; host: string; packageManager: string };\n}\n\n// ---------- AI service ----------\n\nexport interface AITool {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n handler: (args: any, event?: any) => Promise<any> | any;\n}\n\nexport interface AISkill {\n name: string;\n description: string;\n permission?: SkillPermissionRole;\n tools: AITool[];\n}\n\nexport interface TextMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface MultimodalContentItem {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"auto\" | \"low\" | \"high\";\n };\n}\n\nexport interface MultimodalMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string | MultimodalContentItem[];\n}\n\nexport interface ToolCallRecord {\n name: string;\n arguments: any;\n result: any;\n}\n\nexport interface SessionToolDefinition {\n name: string;\n tool: AITool;\n}\n\nexport interface CompleteOptions {\n model?: string;\n messages: any[];\n temperature?: number;\n max_tokens?: number;\n stream?: boolean;\n tools?: any[];\n executableTools?: SessionToolDefinition[];\n executableToolsProvider?: () => SessionToolDefinition[];\n maxIterations?: number;\n onTextDelta?: (delta: string) => void | Promise<void>;\n usageContext?: AIUsageContext;\n usageContextTokens?: number;\n usageBreakdown?: AIUsageFinalization[\"breakdown\"];\n}\n\nexport interface CompleteResponse {\n content: string | null;\n reasoning: string | null;\n toolCalls: Array<{ id: string; name: string; arguments: string }>;\n raw: any;\n turnMessages: any[];\n iterations?: number;\n allToolCalls?: ToolCallRecord[];\n}\n\nexport type AIProtocol =\n | \"openai-chat\"\n | \"openai-response\"\n | \"anthropic\"\n | \"gemini\";\n\nexport type AIModelCapability = \"text\" | \"vision\" | \"tool-use\" | \"reasoning\";\n\nexport type AIModelRole = \"main\" | \"working\" | \"vision\";\n\nexport interface AIProviderConfig {\n id: string;\n name: string;\n protocol: AIProtocol;\n apiUrl: string;\n apiKey: string;\n enabled: boolean;\n headers?: Record<string, string>;\n}\n\nexport interface AIModelDescriptor {\n id: string;\n providerId: string;\n modelId: string;\n name: string;\n capabilities: AIModelCapability[];\n contextWindow?: number;\n maxOutputTokens?: number;\n isCustom?: boolean;\n}\n\nexport interface AIInstanceInfo {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n}\n\nexport interface AIInstance {\n generateText(options: {\n prompt?: string;\n messages: TextMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n generateMultimodal(options: {\n prompt?: string;\n messages: MultimodalMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n complete(options: CompleteOptions): Promise<CompleteResponse>;\n generateWithTools(options: {\n prompt?: string;\n messages: TextMessage[] | MultimodalMessage[];\n model?: string;\n temperature?: number;\n maxIterations?: number;\n }): Promise<any>;\n setUsageContext?(context: AIUsageContext | undefined): void;\n withUsageContext?<T>(\n context: AIUsageContext | undefined,\n fn: () => Promise<T>,\n ): Promise<T>;\n registerPrompt(name: string, prompt: string): boolean;\n getPrompt(name: string): string | undefined;\n getAllPrompts(): Record<string, string>;\n removePrompt(name: string): boolean;\n}\n\nexport interface AIService {\n create(options: {\n name: string;\n apiUrl: string;\n apiKey: string;\n modelType: \"text\" | \"multimodal\";\n model?: string;\n }): Promise<AIInstance>;\n createInstance?(options: {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n }): Promise<AIInstance>;\n get(name: string): AIInstance | undefined;\n list(): string[];\n listInstances?(): AIInstanceInfo[];\n remove(name: string): boolean;\n setDefault(name: string): boolean;\n getDefault(): AIInstance | undefined;\n listProviders?(): AIProviderConfig[];\n getProvider?(id: string): AIProviderConfig | undefined;\n createProvider?(\n input: Omit<AIProviderConfig, \"id\"> & { id?: string },\n ): Promise<AIProviderConfig>;\n updateProvider?(\n id: string,\n input: Partial<AIProviderConfig>,\n ): Promise<AIProviderConfig>;\n removeProvider?(id: string): boolean;\n testProvider?(\n id: string,\n ): Promise<{ ok: boolean; error?: string; models?: AIModelDescriptor[] }>;\n listModels?(providerId?: string): AIModelDescriptor[];\n refreshModels?(providerId: string): Promise<AIModelDescriptor[]>;\n registerCustomModel?(input: {\n providerId: string;\n modelId: string;\n name?: string;\n capabilities?: AIModelCapability[];\n }): AIModelDescriptor;\n removeCustomModel?(modelFullId: string): boolean;\n getRoleBindings?(): Record<AIModelRole, string | undefined>;\n setRoleBinding?(role: AIModelRole, modelFullId: string | undefined): boolean;\n getInstanceByRole?(role: AIModelRole): AIInstance | undefined;\n setMainFallbackChain?(modelFullIds: string[]): void;\n getMainFallbackChain?(): string[];\n registerChatRuntime(runtime: any): boolean;\n getChatRuntime(): any;\n removeChatRuntime(): boolean;\n registerSkill(skill: AISkill): boolean;\n getSkill(skillName: string): AISkill | undefined;\n getAllSkills(): Map<string, AISkill>;\n removeSkill(skillName: string): boolean;\n getTool(toolName: string): AITool | undefined;\n getAllTools(): Map<string, AITool>;\n getUsageSummary?(options: {\n range: AIUsageRange;\n botId?: number;\n }): AIUsageSummary;\n cleanupUsageStats?(retentionMs?: number): number;\n finalizeUsage?(usageId: string, finalization: AIUsageFinalization): boolean;\n}\n\n// ---------- chat runtime ----------\n\nexport interface ChatRuntime {\n generateNotice(options: ChatRuntimeNoticeOptions): Promise<ChatRuntimeResult>;\n requestInformation(\n options: ChatRuntimeInformationRequestOptions,\n ): Promise<ChatRuntimeResult>;\n}\n\nexport const TOOL_RESULT_FOLLOWUP_KEY = \"__miokuFollowup\";\n\nexport interface ToolResultFollowup {\n text: string;\n images?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n videos?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n}\n\nexport interface ChatRuntimePromptInjection {\n content: string;\n title?: string;\n}\n\nexport interface ChatRuntimeGroupTarget {\n selfId: number;\n groupId: number;\n}\n\nexport interface ChatRuntimePrivateTarget {\n selfId: number;\n userId: number;\n}\n\nexport type ChatRuntimeSource =\n | { event: any }\n | ChatRuntimeGroupTarget\n | ChatRuntimePrivateTarget;\n\nexport type ChatRuntimeBaseOptions = ChatRuntimeSource & {\n targetMessage?: string;\n promptInjections?: ChatRuntimePromptInjection[];\n send?: boolean;\n};\n\nexport type ChatRuntimeNoticeOptions = ChatRuntimeBaseOptions & {\n instruction: string;\n};\n\nexport type ChatRuntimeInformationRequestOptions = ChatRuntimeBaseOptions & {\n task: string;\n schema: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n toolName?: string;\n toolDescription?: string;\n};\n\nexport interface ChatRuntimeCollectedInfo {\n data: any;\n isComplete?: boolean;\n confidence?: number;\n notes?: string;\n}\n\nexport interface ChatRuntimeResult {\n messages: string[];\n toolCalls: ToolCallRecord[];\n collectedInfo: ChatRuntimeCollectedInfo | null;\n pendingAt?: number[];\n pendingPoke?: number[];\n pendingQuote?: number;\n emojiPath?: string | null;\n protocolMessages?: any[];\n}\n\n// ---------- usage tracking ----------\n\nexport type AIUsageRange = \"today\" | \"7d\" | \"30d\";\n\nexport type AIUsageScope = \"all\" | \"bot\";\n\nexport interface AIUsageContext {\n usageId?: string;\n source?: string;\n botId?: number;\n groupId?: number;\n groupName?: string;\n userId?: number;\n userName?: string;\n sessionId?: string;\n fallbackUsed?: boolean;\n fallbackFrom?: string;\n}\n\nexport interface AIUsageBreakdown {\n systemPromptTokens?: number;\n chatHistoryTokens?: number;\n toolDefinitionTokens?: number;\n toolUseTokens?: number;\n otherContextTokens?: number;\n}\n\nexport interface AIUsageFinalization {\n sentUserMessages?: number;\n sentAssistantMessages?: number;\n breakdown?: AIUsageBreakdown;\n}\n\nexport interface AIUsageBotOption {\n botId: number;\n label: string;\n}\n\nexport interface AIUsageSummary {\n generatedAt: number;\n range: AIUsageRange;\n scope: AIUsageScope;\n botId?: number;\n bots: AIUsageBotOption[];\n totals: {\n requests: number;\n successfulRequests: number;\n failedRequests: number;\n userMessages: number;\n assistantMessages: number;\n systemMessages: number;\n toolMessages: number;\n sentUserMessages: number;\n sentAssistantMessages: number;\n inputTokens: number;\n outputTokens: number;\n systemPromptTokens: number;\n totalTokens: number;\n cacheWriteTokens: number;\n cacheReadTokens: number;\n toolDefinitionTokens: number;\n toolUseTokens: number;\n chatHistoryTokens: number;\n otherContextTokens: number;\n durationMs: number;\n toolCalls: number;\n };\n rates: {\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n };\n toolRanking: Array<{ name: string; count: number }>;\n groupRanking: Array<{\n groupId: number;\n groupName: string;\n requests: number;\n totalTokens: number;\n userMessages: number;\n assistantMessages: number;\n errorRate: number;\n }>;\n tokenFlow: Array<{\n name: \"输入\" | \"输出\" | \"缓存写入\" | \"缓存读取\";\n value: number;\n }>;\n tokenCategories: Array<{\n name: \"系统提示词\" | \"工具定义\" | \"工具使用\" | \"聊天上下文\" | \"其他上下文\";\n value: number;\n }>;\n dailyActivity: Array<{\n day: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n hourlyActivity: Array<{\n hour: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n}\n","import * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\n\nexport function getPluginDataDir(pluginName: string): string {\n return path.join(process.cwd(), \"data\", pluginName);\n}\n\nexport function getServiceDataDir(serviceName: string): string {\n return path.join(process.cwd(), \"data\", serviceName);\n}\n\nexport function getDataDir(): string {\n return path.join(process.cwd(), \"data\");\n}\n\nexport function getPluginConfigDir(pluginName: string): string {\n return path.join(process.cwd(), \"config\", pluginName);\n}\n\nexport function getServiceConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", \"service\", serviceName);\n}\n\nexport function getConfigDir(): string {\n return path.join(process.cwd(), \"config\");\n}\n\nexport function ensureDataDir(pluginName: string): string {\n const dir = getPluginDataDir(pluginName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n","import { getOrCreate } from \"./registry\";\n\nconst store = getOrCreate<Record<string, unknown>>(\n \"plugin-runtime-state\",\n () => ({}),\n);\n\nexport interface PluginStateRef<T> {\n readonly name: string;\n get(): T;\n set(next: T): void;\n reset(): void;\n}\n\nexport function defineState<T>(name: string, initial: T): PluginStateRef<T> {\n return {\n name,\n get(): T {\n const current = store[name];\n return (current === undefined ? initial : current) as T;\n },\n set(next: T): void {\n store[name] = next;\n },\n reset(): void {\n delete store[name];\n },\n };\n}\n\nexport function hasPluginState(name: string): boolean {\n return store[name] !== undefined;\n}\n\nexport function getPluginRuntimeState<T = Record<string, any>>(\n name: string,\n): T {\n if (!store[name]) store[name] = {};\n return store[name] as T;\n}\n\nexport function setPluginRuntimeState<T>(name: string, state: T): void {\n store[name] = state;\n}\n\nexport function resetPluginRuntimeState(name: string): void {\n delete store[name];\n}\n\nexport function getAllPluginRuntimeStates(): Record<string, unknown> {\n return { ...store };\n}","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { bootstrapMioku } from \"./core/bootstrap\";\nimport { setMiokuLogger } from \"./core/logger\";\nimport { default as serviceManager } from \"./core/service-manager\";\n\nexport type { MiokiPlugin, MiokiContext } from \"mioki\";\nexport type { EventMap } from \"napcat-sdk\";\n\nexport function definePlugin<T extends import(\"mioki\").MiokiPlugin>(\n plugin: T,\n): T {\n return plugin;\n}\n\nexport { default as pluginManager } from \"./core/plugin-manager\";\nexport { default as serviceManager } from \"./core/service-manager\";\nexport { registerPluginArtifacts } from \"./core/plugin-artifact-registry\";\n\nexport {\n registerServiceConfig,\n getServiceConfig,\n updateServiceConfig,\n getServiceConfigs,\n deleteServiceConfig,\n} from \"./core/service-config\";\n\nexport type {\n MiokuService,\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n ServiceMetadata,\n PluginPackageConfig,\n PluginHelp,\n CommandRole,\n AccessHook,\n AccessAction,\n AccessRuleEntry,\n AccessScopeConfig,\n AccessControlConfig,\n ConfigService,\n ScreenshotService,\n HelpService,\n WebUIService,\n AITool,\n AISkill,\n AIInstance,\n AIService,\n AIProtocol,\n AIModelCapability,\n AIModelRole,\n AIProviderConfig,\n AIModelDescriptor,\n AIInstanceInfo,\n ChatRuntime,\n TextMessage,\n MultimodalMessage,\n ToolCallRecord,\n CompleteOptions,\n CompleteResponse,\n SessionToolDefinition,\n SkillPermissionRole,\n MultimodalContentItem,\n ToolResultFollowup,\n ChatRuntimePromptInjection,\n ChatRuntimeGroupTarget,\n ChatRuntimePrivateTarget,\n ChatRuntimeSource,\n ChatRuntimeBaseOptions,\n ChatRuntimeNoticeOptions,\n ChatRuntimeInformationRequestOptions,\n ChatRuntimeCollectedInfo,\n ChatRuntimeResult,\n AIUsageRange,\n AIUsageScope,\n AIUsageBotOption,\n AIUsageContext,\n AIUsageBreakdown,\n AIUsageFinalization,\n AIUsageSummary,\n} from \"./types\";\n\nexport {\n TOOL_RESULT_FOLLOWUP_KEY,\n normalizeSkillPermissionRole,\n} from \"./types\";\n\nexport {\n defineService,\n getService,\n requireService,\n hasService,\n} from \"./core/service\";\nexport type { ServiceRef } from \"./core/service\";\nexport { Services } from \"./core/services\";\nexport type { BuiltinServiceRef } from \"./core/services\";\n\nexport interface MiokuStartOptions {\n cwd?: string;\n}\n\nexport async function start(options: MiokuStartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options;\n if (cwd) process.chdir(cwd);\n\n const { start: startMioki, logger, botConfig } = await import(\"mioki\");\n setMiokuLogger(logger);\n\n let shuttingDown = false;\n const shutdown = async (signal: string) => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info(`收到 ${signal} 信号,正在关闭服务...`);\n const timer = setTimeout(() => {\n logger.error(\"服务关闭超时,强制退出\");\n process.exit(1);\n }, 15_000);\n timer.unref();\n await serviceManager.disposeAll();\n clearTimeout(timer);\n logger.info(\"Mioku 服务已完全关闭\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n logger.info(\"こんにちは..\");\n logger.info(\"---------------------------------------\");\n logger.info(\"---------- Mioku 正在启动 ------------\");\n logger.info(\"---------------------------------------\");\n\n await bootstrapMioku({ cwd, botConfig, startMioki });\n}\n\nfunction readVersion(): string {\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const pkgPath = path.join(here, \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const version: string = readVersion();\n\nexport {\n getDataDir,\n getPluginDataDir,\n getServiceDataDir,\n getConfigDir,\n getPluginConfigDir,\n getServiceConfigDir,\n ensureDataDir,\n} from \"./core/data-paths\";\n\nexport {\n defineState,\n hasPluginState,\n getPluginRuntimeState,\n setPluginRuntimeState,\n resetPluginRuntimeState,\n getAllPluginRuntimeStates,\n} from \"./core/plugin-runtime-state\";\nexport type { PluginStateRef } from \"./core/plugin-runtime-state\";\n\nexport {\n resolveCommand,\n commandExists,\n buildSpawnPlan,\n runCommand,\n runCommandInherit,\n} from \"./core/exec\";\n\nexport type { RunCommandResult, SpawnPlan } from \"./core/exec\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["fallbackLogger: MiokuLogger","activeLogger: MiokuLogger","logger: MiokuLogger | undefined","logger","logger: MiokuLogger","filePath: string","p: string","dir: string","results: DiscoveredModule[]","entries: import(\"fs\").Dirent[]","prefix: string","entryPath: string","linkPath: string","targetPath: string","runtimePluginsDir: string","metadata: PluginMetadata","plugins: PluginMetadata[]","linkedNames: string[]","store","key: string","factory: () => T","prefix: string","obj: Record<string, unknown>","allowed: Set<string>","value: unknown","pluginName: string","commands: PluginHelp[\"commands\"]","hooks: AccessHook[]","raw: unknown","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","pluginPath: string","packageJson: PackageJsonLike | null","config: PluginPackageConfig","miokuConfig: MiokuRuntimeConfig","name: string","servicePath: string","packageJson: PackageJsonLike","required: Set<string>","missing: string[]","ctx: MiokiContext","metadata: ServiceMetadata","service: MiokuService","miokuConfig: MiokuRuntimeConfig","botConfig: BotConfigLike","linkedPluginNames: string[]","deps: BootstrapDeps","botConfig","id: string","ctx: MiokiContext","ref: ServiceRef<T>","keywords: unknown","ctx: MiokiContext","serviceName: string","configName: string","defaults: Record<string, unknown>","value: Record<string, unknown>","result: Record<string, Record<string, unknown>>","role: unknown","pluginName: string","serviceName: string","name: string","initial: T","next: T","state: T","plugin: T","options: MiokuStartOptions","logger","signal: string","version: string"],"sources":["../src/core/logger.ts","../src/core/module-scanner.ts","../src/core/plugin-linker.ts","../src/core/registry.ts","../src/core/plugin-manifest.ts","../src/core/plugin-manager.ts","../src/core/service-manager.ts","../src/core/bootstrap.ts","../src/core/service.ts","../src/core/services.ts","../src/core/plugin-artifact-registry.ts","../src/core/service-config.ts","../src/types.ts","../src/core/data-paths.ts","../src/core/plugin-runtime-state.ts","../src/index.ts"],"sourcesContent":["type LogMethod = (...args: unknown[]) => void;\n\nexport interface MiokuLogger {\n error: LogMethod;\n warn: LogMethod;\n info: LogMethod;\n debug: LogMethod;\n trace?: LogMethod;\n}\n\nconst fallbackLogger: MiokuLogger = {\n error: (...args) => console.error(...args),\n warn: (...args) => console.warn(...args),\n info: (...args) => console.info(...args),\n debug: (...args) => console.debug(...args),\n trace: (...args) => console.debug(...args),\n};\n\nlet activeLogger: MiokuLogger = fallbackLogger;\n\nexport function setMiokuLogger(logger: MiokuLogger | undefined): void {\n activeLogger = logger || fallbackLogger;\n}\n\nexport function getMiokuLogger(): MiokuLogger {\n return activeLogger;\n}\n\nexport const logger: MiokuLogger = {\n error: (...args) => activeLogger.error(...args),\n warn: (...args) => activeLogger.warn(...args),\n info: (...args) => activeLogger.info(...args),\n debug: (...args) => activeLogger.debug(...args),\n trace: (...args) => activeLogger.trace?.(...args),\n};\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { pathToFileURL } from \"node:url\";\n\nexport interface DiscoveredModule {\n name: string;\n path: string;\n}\n\nexport async function pathExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function resolveRealpath(p: string): Promise<string> {\n try {\n return await fs.realpath(p);\n } catch {\n return p;\n }\n}\n\n// Windows requires file:// URLs for absolute paths in dynamic import().\n// pathToFileURL also percent-encodes spaces and non-ASCII segments, which a\n// hand-rolled string replace leaves broken (e.g. \"C:\\用户\\my bot\").\nexport function toImportPath(filePath: string): string {\n if (process.platform === \"win32\") {\n return pathToFileURL(filePath).href;\n }\n return filePath;\n}\n\nexport async function scanLocalDir(dir: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n if (!(await pathExists(dir))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return results;\n }\n\n for (const entry of entries) {\n const entryPath = path.join(dir, entry.name);\n try {\n const stat = await fs.stat(entryPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n results.push({ name: entry.name, path: await resolveRealpath(entryPath) });\n }\n return results;\n}\n\nexport async function scanNodeModules(prefix: string): Promise<DiscoveredModule[]> {\n const results: DiscoveredModule[] = [];\n const nodeModulesPath = path.resolve(process.cwd(), \"node_modules\");\n if (!(await pathExists(nodeModulesPath))) return results;\n\n let entries: import(\"fs\").Dirent[];\n try {\n entries = await fs.readdir(nodeModulesPath, { withFileTypes: true });\n } catch {\n return results;\n }\n\n // Don't filter by isDirectory(): node_modules entries are often symlinks\n // into the workspace, and Dirent.isDirectory() returns false for symlinks.\n for (const entry of entries) {\n if (!entry.name.startsWith(prefix)) continue;\n const name = entry.name.slice(prefix.length);\n const fullPath = path.join(nodeModulesPath, entry.name);\n results.push({ name, path: await resolveRealpath(fullPath) });\n }\n return results;\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport type { PluginMetadata } from \"../types\";\nimport { logger } from \"./logger\";\nimport { pathExists } from \"./module-scanner\";\n\nexport const DEFAULT_RUNTIME_PLUGINS_DIR = \".mioku/plugins\";\n\ntype SymlinkState = \"ok\" | \"blocked\" | \"removed\";\n\nasync function removeIfBrokenSymlink(entryPath: string): Promise<SymlinkState> {\n let stat;\n try {\n stat = await fs.lstat(entryPath);\n } catch {\n return \"removed\";\n }\n if (!stat.isSymbolicLink()) return \"blocked\";\n try {\n await fs.realpath(entryPath);\n return \"ok\";\n } catch {\n await fs.rm(entryPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${entryPath}`);\n return \"removed\";\n }\n}\n\nfunction relativeSymlinkTarget(linkPath: string, targetPath: string): string {\n return path.relative(path.dirname(linkPath), targetPath) || \".\";\n}\n\nasync function ensurePluginLink(\n runtimePluginsDir: string,\n metadata: PluginMetadata,\n): Promise<boolean> {\n const linkPath = path.join(runtimePluginsDir, metadata.name);\n const targetPath = metadata.path;\n\n let stat;\n try {\n stat = await fs.lstat(linkPath);\n } catch {\n stat = null;\n }\n\n if (stat?.isSymbolicLink()) {\n try {\n const currentTarget = await fs.realpath(linkPath);\n const expectedTarget = await fs.realpath(targetPath);\n if (currentTarget === expectedTarget) return true;\n await fs.rm(linkPath, { force: true });\n logger.info(`[plugin-linker] Rebuilding plugin link: ${metadata.name}`);\n } catch {\n await fs.rm(linkPath, { force: true });\n logger.warn(`[plugin-linker] Removed broken plugin link: ${linkPath}`);\n }\n } else if (stat) {\n logger.warn(\n `[plugin-linker] ${linkPath} exists and is not a symlink, skip linking ${metadata.name}`,\n );\n return false;\n }\n\n if (!(await pathExists(targetPath))) {\n logger.warn(\n `[plugin-linker] Plugin target missing, skip linking ${metadata.name}: ${targetPath}`,\n );\n return false;\n }\n\n // Junctions on Windows don't require admin rights; relative dir symlinks elsewhere.\n if (process.platform === \"win32\") {\n await fs.symlink(targetPath, linkPath, \"junction\");\n } else {\n await fs.symlink(relativeSymlinkTarget(linkPath, targetPath), linkPath, \"dir\");\n }\n return true;\n}\n\nexport async function prepareRuntimePluginLinks(\n plugins: PluginMetadata[],\n runtimePluginsDir = path.resolve(process.cwd(), DEFAULT_RUNTIME_PLUGINS_DIR),\n): Promise<string[]> {\n await fs.mkdir(runtimePluginsDir, { recursive: true });\n\n const discoveredNames = new Set(plugins.map((p) => p.name));\n const entries = await fs.readdir(runtimePluginsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = path.join(runtimePluginsDir, entry.name);\n if ((await removeIfBrokenSymlink(entryPath)) !== \"ok\") continue;\n if (entry.isSymbolicLink() && !discoveredNames.has(entry.name)) {\n await fs.rm(entryPath, { force: true });\n logger.info(`[plugin-linker] Removed stale plugin link: ${entry.name}`);\n }\n }\n\n const linkedNames: string[] = [];\n for (const metadata of plugins) {\n if (await ensurePluginLink(runtimePluginsDir, metadata)) {\n linkedNames.push(metadata.name);\n }\n }\n return linkedNames;\n}\n","// Framework singletons are stashed on globalThis so they survive jiti's\n// moduleCache-off re-evaluation (mioki loads plugins via jiti). Callers that\n// live in the normally-cached `mioku` dist could use a plain module-level\n// const, but the global indirection keeps things stable if a plugin ever\n// re-imports the framework through jiti.\n\nconst STORE_SYMBOL = Symbol.for(\"mioku.globalStore\");\ntype GlobalStore = Record<string, unknown>;\n\nfunction store(): GlobalStore {\n const g = globalThis as unknown as Record<symbol, GlobalStore>;\n if (!g[STORE_SYMBOL]) g[STORE_SYMBOL] = {};\n return g[STORE_SYMBOL]!;\n}\n\nexport function getOrCreate<T>(key: string, factory: () => T): T {\n const s = store();\n if (s[key] === undefined) s[key] = factory();\n return s[key] as T;\n}\n","import { logger } from \"./logger\";\nimport type {\n AccessHook,\n PluginHelp,\n PluginPackageConfig,\n} from \"../types\";\n\nconst PLUGIN_CONFIG_KEYS = new Set([\n \"services\",\n \"help\",\n \"accessHooks\",\n]);\n\nconst ACCESS_HOOK_KEYS = new Set([\n \"id\",\n \"match\",\n \"event\",\n \"description\",\n]);\n\nconst HELP_KEYS = new Set([\"title\", \"description\", \"commands\"]);\n\nconst HELP_COMMAND_KEYS = new Set([\"cmd\", \"desc\", \"usage\", \"role\"]);\n\nfunction warnUnknownFields(\n prefix: string,\n obj: Record<string, unknown>,\n allowed: Set<string>,\n): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.has(key)) {\n logger.warn(`[plugin-manifest] ${prefix} 含未知字段 \"${key}\"(将被忽略)`);\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction validateHelp(value: unknown, pluginName: string): PluginHelp | undefined {\n if (value === undefined) return undefined;\n if (!isPlainObject(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help 必须是对象,已忽略`);\n return undefined;\n }\n warnUnknownFields(`${pluginName}.help`, value, HELP_KEYS);\n\n const title = String(value.title ?? \"\").trim();\n const description = String(value.description ?? \"\").trim();\n const rawCommands = value.commands;\n\n if (!title) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.title 缺失或为空`);\n }\n if (!description) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.description 缺失或为空`);\n }\n if (!Array.isArray(rawCommands)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 必须是数组`);\n return { title, description, commands: [] };\n }\n\n const commands: PluginHelp[\"commands\"] = [];\n for (const cmd of rawCommands) {\n if (!isPlainObject(cmd)) {\n logger.warn(`[plugin-manifest] ${pluginName}.help.commands 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.help.commands[]`,\n cmd,\n HELP_COMMAND_KEYS,\n );\n const cmdName = String(cmd.cmd ?? \"\").trim();\n const desc = String(cmd.desc ?? \"\").trim();\n if (!cmdName || !desc) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.help.commands 项缺少 cmd 或 desc`,\n );\n continue;\n }\n commands.push({\n cmd: cmdName,\n desc,\n usage: typeof cmd.usage === \"string\" ? cmd.usage : undefined,\n role: typeof cmd.role === \"string\" ? (cmd.role as never) : undefined,\n });\n }\n\n return { title, description, commands };\n}\n\nfunction validateAccessHooks(\n value: unknown,\n pluginName: string,\n): AccessHook[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 必须是数组`);\n return undefined;\n }\n\n const hooks: AccessHook[] = [];\n for (const hook of value) {\n if (!isPlainObject(hook)) {\n logger.warn(`[plugin-manifest] ${pluginName}.accessHooks 项不是对象`);\n continue;\n }\n warnUnknownFields(\n `${pluginName}.accessHooks[]`,\n hook,\n ACCESS_HOOK_KEYS,\n );\n const id = String(hook.id ?? \"\").trim();\n if (!id) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.accessHooks 项缺少 id,已忽略`,\n );\n continue;\n }\n hooks.push({\n id,\n match: typeof hook.match === \"string\" ? hook.match : undefined,\n event: typeof hook.event === \"string\" ? hook.event : undefined,\n description:\n typeof hook.description === \"string\" ? hook.description : undefined,\n });\n }\n return hooks;\n}\n\nexport function validatePluginPackageConfig(\n raw: unknown,\n pluginName: string,\n): PluginPackageConfig {\n const config: PluginPackageConfig = {};\n\n if (raw === undefined || raw === null) {\n return config;\n }\n if (!isPlainObject(raw)) {\n logger.warn(\n `[plugin-manifest] ${pluginName} 的 mioku 字段必须是对象,已使用空配置`,\n );\n return config;\n }\n\n warnUnknownFields(`${pluginName}.mioku`, raw, PLUGIN_CONFIG_KEYS);\n\n if (raw.services !== undefined) {\n if (Array.isArray(raw.services)) {\n const services = raw.services.filter(\n (s): s is string => typeof s === \"string\" && s.length > 0,\n );\n const dropped = raw.services.length - services.length;\n if (dropped > 0) {\n logger.warn(\n `[plugin-manifest] ${pluginName}.services 丢弃 ${dropped} 个非字符串项`,\n );\n }\n config.services = services;\n } else {\n logger.warn(`[plugin-manifest] ${pluginName}.services 必须是字符串数组`);\n }\n }\n\n const help = validateHelp(raw.help, pluginName);\n if (help) config.help = help;\n\n const hooks = validateAccessHooks(raw.accessHooks, pluginName);\n if (hooks) config.accessHooks = hooks;\n\n return config;\n}","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { mkdirSync } from \"fs\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n PluginPackageConfig,\n} from \"../types\";\nimport { DEFAULT_RUNTIME_PLUGINS_DIR } from \"./plugin-linker\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n resolveRealpath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\nimport { validatePluginPackageConfig } from \"./plugin-manifest\";\n\nconst PLUGIN_PREFIX = \"mioku-plugin-\";\n\nexport class PluginManager {\n private plugins = new Map<string, PluginMetadata>();\n\n static getInstance(): PluginManager {\n return getOrCreate(\"plugin-manager\", () => new PluginManager());\n }\n\n async discoverPlugins(miokuConfig: MiokuRuntimeConfig = {}): Promise<PluginMetadata[]> {\n const configuredDir = miokuConfig.plugins_dir;\n const pluginsDir =\n configuredDir && configuredDir !== DEFAULT_RUNTIME_PLUGINS_DIR\n ? path.resolve(process.cwd(), configuredDir)\n : path.resolve(process.cwd(), \"plugins\");\n\n this.plugins.clear();\n\n if (!(await pathExists(pluginsDir))) {\n mkdirSync(pluginsDir, { recursive: true });\n }\n\n const local = await scanLocalDir(pluginsDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n const external = await scanNodeModules(PLUGIN_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadPluginMetadata(name, p);\n if (metadata) this.plugins.set(metadata.name, metadata);\n }\n\n logger.info(`O.o 发现了 ${this.plugins.size} 个插件`);\n return [...this.plugins.values()];\n }\n\n private async loadPluginMetadata(\n name: string,\n pluginPath: string,\n ): Promise<PluginMetadata | null> {\n const resolvedPath = await resolveRealpath(pluginPath);\n let packageJson: PackageJsonLike | null = null;\n try {\n packageJson = JSON.parse(\n await fs.readFile(path.join(resolvedPath, \"package.json\"), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[plugin-manager] 读取 ${name} 的 package.json 失败: ${error}`);\n }\n\nconst config: PluginPackageConfig = validatePluginPackageConfig(\n packageJson?.mioku,\n name,\n );\n return {\n name,\n version: packageJson?.version ?? \"0.0.0\",\n description: packageJson?.description,\n path: resolvedPath,\n packageJson: packageJson ?? {},\n config,\n };\n }\n\n collectRequiredServices(): Set<string> {\n const services = new Set<string>();\n for (const metadata of this.plugins.values()) {\n for (const service of metadata.config.services ?? []) services.add(service);\n }\n return services;\n }\n\n getPluginMetadata(name: string): PluginMetadata | undefined {\n return this.plugins.get(name);\n }\n\n getAllMetadata(): PluginMetadata[] {\n return [...this.plugins.values()];\n }\n\n reset(): void {\n this.plugins.clear();\n }\n}\n\nexport default PluginManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokiContext } from \"mioki\";\nimport type {\n MiokuRuntimeConfig,\n PackageJsonLike,\n ServiceMetadata,\n MiokuService,\n} from \"../types\";\nimport { logger } from \"./logger\";\nimport {\n scanLocalDir,\n scanNodeModules,\n pathExists,\n toImportPath,\n} from \"./module-scanner\";\nimport { getOrCreate } from \"./registry\";\n\nconst SERVICE_PREFIX = \"mioku-service-\";\n\nexport class ServiceManager {\n private services = new Map<string, MiokuService>();\n private serviceMetadata = new Map<string, ServiceMetadata>();\n\n static getInstance(): ServiceManager {\n return getOrCreate(\"service-manager\", () => new ServiceManager());\n }\n\n async discoverServices(miokuConfig: MiokuRuntimeConfig = {}): Promise<ServiceMetadata[]> {\n const servicesDir = miokuConfig.services_dir\n ? path.resolve(process.cwd(), miokuConfig.services_dir)\n : path.resolve(process.cwd(), \"services\");\n\n this.serviceMetadata.clear();\n\n if (existsSync(servicesDir)) {\n const local = await scanLocalDir(servicesDir);\n for (const { name, path: p } of local) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n } else {\n mkdirSync(servicesDir, { recursive: true });\n }\n\n const external = await scanNodeModules(SERVICE_PREFIX);\n for (const { name, path: p } of external) {\n const metadata = await this.loadServiceMetadata(name, p);\n if (metadata) this.serviceMetadata.set(name, metadata);\n }\n\n logger.info(`o.O 发现了 ${this.serviceMetadata.size} 个服务`);\n return [...this.serviceMetadata.values()];\n }\n\n private async loadServiceMetadata(\n name: string,\n servicePath: string,\n ): Promise<ServiceMetadata | null> {\n const packageJsonPath = path.join(servicePath, \"package.json\");\n if (!(await pathExists(packageJsonPath))) return null;\n\n try {\n const packageJson: PackageJsonLike = JSON.parse(\n await fs.readFile(packageJsonPath, \"utf-8\"),\n );\n return {\n name,\n version: packageJson.version ?? \"0.0.0\",\n description: packageJson.description,\n path: servicePath,\n packageJson,\n };\n } catch (error) {\n logger.warn(`[service-manager] 解析服务 ${name} 失败: ${error}`);\n return null;\n }\n }\n\n async checkMissingServices(required: Set<string>): Promise<string[]> {\n const missing: string[] = [];\n for (const name of required) {\n if (!this.serviceMetadata.has(name)) missing.push(name);\n }\n return missing;\n }\n\n async loadAllServices(ctx: MiokiContext): Promise<void> {\n const all = [...this.serviceMetadata.values()];\n logger.info(`O.o 准备加载 ${all.length} 个服务...`);\n for (const metadata of all) {\n await this.loadService(metadata, ctx);\n }\n }\n\n private async loadService(\n metadata: ServiceMetadata,\n ctx: MiokiContext,\n ): Promise<boolean> {\n try {\n const tsEntry = path.join(metadata.path, \"index.ts\");\n const jsEntry = path.join(metadata.path, \"index.js\");\n const entry = (await pathExists(tsEntry))\n ? tsEntry\n : (await pathExists(jsEntry))\n ? jsEntry\n : null;\n if (!entry) {\n logger.error(`[service-manager] 服务 ${metadata.name} 入口丢失`);\n return false;\n }\n\n const serviceModule = await import(toImportPath(entry));\n const service: MiokuService = serviceModule.default ?? serviceModule;\n if (!service || typeof service.init !== \"function\") {\n logger.warn(`[service-manager] 服务 ${metadata.name} 无效:缺少 init()`);\n return false;\n }\n\n await service.init();\n if (service.api) {\n ctx.services[metadata.name] = service.api;\n }\n this.services.set(metadata.name, service);\n return true;\n } catch (error) {\n logger.error(`[service-manager] 加载服务 ${metadata.name} 失败: ${error}`);\n return false;\n }\n }\n\n registerBuiltinService(name: string, service: MiokuService): void {\n this.services.set(name, service);\n }\n\n getService(name: string): MiokuService | undefined {\n return this.services.get(name);\n }\n\n async disposeAll(): Promise<void> {\n for (const [, service] of this.services) {\n await service.dispose?.();\n }\n this.services.clear();\n }\n\n reset(): void {\n this.services.clear();\n this.serviceMetadata.clear();\n }\n}\n\nexport default ServiceManager.getInstance();\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport type { MiokuRuntimeConfig } from \"../types\";\nimport pluginManager from \"./plugin-manager\";\nimport serviceManager from \"./service-manager\";\nimport {\n prepareRuntimePluginLinks,\n DEFAULT_RUNTIME_PLUGINS_DIR,\n} from \"./plugin-linker\";\nimport { logger } from \"./logger\";\n\ninterface BotConfigLike {\n plugins: string[];\n plugins_dir?: string;\n}\n\nexport interface BootstrapDeps {\n cwd: string;\n botConfig: BotConfigLike;\n startMioki: (opts: { cwd: string }) => Promise<void>;\n}\n\nexport async function readMiokuConfig(): Promise<MiokuRuntimeConfig> {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n try {\n const pkg = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n return (pkg.mioki ?? {}) as MiokuRuntimeConfig;\n } catch {\n return {};\n }\n}\n\nfunction ensureRuntimeDirectories(): void {\n for (const dir of [\"data\", \"config\", \"temp\"]) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n }\n}\n\nasync function discoverAndLinkPlugins(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<string[]> {\n logger.info(\"O.o Miku 正在翻找插件..\");\n const discovered = await pluginManager.discoverPlugins(miokuConfig);\n logger.info(\n `O.o 共发现 ${discovered.length} 个插件: ${discovered.map((p) => p.name).join(\", \")}`,\n );\n const runtimePluginsDir = path.resolve(\n process.cwd(),\n DEFAULT_RUNTIME_PLUGINS_DIR,\n );\n return prepareRuntimePluginLinks(discovered, runtimePluginsDir);\n}\n\nasync function discoverAndValidateServices(\n miokuConfig: MiokuRuntimeConfig,\n): Promise<void> {\n logger.info(\"o.O Miku 正在翻找服务..\");\n await serviceManager.discoverServices(miokuConfig);\n const requiredServices = pluginManager.collectRequiredServices();\n const missing = await serviceManager.checkMissingServices(requiredServices);\n if (missing.length > 0) logger.warn(`发现缺失服务: ${missing.join(\", \")}`);\n}\n\nfunction applyPluginAllowlist(\n miokuConfig: MiokuRuntimeConfig,\n botConfig: BotConfigLike,\n linkedPluginNames: string[],\n): void {\n botConfig.plugins_dir = DEFAULT_RUNTIME_PLUGINS_DIR;\n // Respect an explicit plugins list; only auto-load when undefined.\n if (miokuConfig.plugins !== undefined) return;\n for (const name of linkedPluginNames) {\n if (!botConfig.plugins.includes(name)) botConfig.plugins.push(name);\n }\n}\n\nexport async function bootstrapMioku(deps: BootstrapDeps): Promise<void> {\n const { cwd, botConfig, startMioki } = deps;\n const miokuConfig = await readMiokuConfig();\n ensureRuntimeDirectories();\n const linkedPluginNames = await discoverAndLinkPlugins(miokuConfig);\n await discoverAndValidateServices(miokuConfig);\n applyPluginAllowlist(miokuConfig, botConfig, linkedPluginNames);\n await startMioki({ cwd });\n}\n","import type { MiokiContext } from \"mioki\";\n\nexport interface ServiceRef<T> {\n readonly id: string;\n}\n\nexport function defineService<T>(id: string): ServiceRef<T> {\n return { id };\n}\n\nexport function getService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T | undefined {\n return ctx.services[ref.id] as T | undefined;\n}\n\nexport function requireService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): T {\n const svc = ctx.services[ref.id] as T | undefined;\n if (svc === undefined) {\n throw new Error(\n `[mioku] required service \"${ref.id}\" is not available`,\n );\n }\n return svc;\n}\n\nexport function hasService<T>(\n ctx: MiokiContext,\n ref: ServiceRef<T>,\n): boolean {\n return ctx.services[ref.id] !== undefined;\n}","import type {\n AIService,\n ConfigService,\n ScreenshotService,\n HelpService,\n} from \"../types\";\nimport { defineService } from \"./service\";\n\nexport const Services = {\n AI: defineService<AIService>(\"ai\"),\n Config: defineService<ConfigService>(\"config\"),\n Screenshot: defineService<ScreenshotService>(\"screenshot\"),\n Help: defineService<HelpService>(\"help\"),\n} as const;\n\nexport type BuiltinServiceRef =\n | typeof Services.AI\n | typeof Services.Config\n | typeof Services.Screenshot\n | typeof Services.Help;","import type { MiokiContext } from \"mioki\";\nimport { botConfig } from \"mioki\";\nimport { getService } from \"./service\";\nimport { Services } from \"./services\";\nimport pluginManager from \"./plugin-manager\";\nimport { logger } from \"./logger\";\n\nfunction hasPublicKeyword(keywords: unknown): boolean {\n return Array.isArray(keywords) && keywords.includes(\"mioku\");\n}\n\nexport async function registerPluginArtifacts(ctx: MiokiContext): Promise<void> {\n const enabledPlugins = new Set<string>(botConfig.plugins ?? []);\n const pluginMetadata = pluginManager.getAllMetadata().filter((metadata) =>\n enabledPlugins.size > 0 ? enabledPlugins.has(metadata.name) : true,\n );\n\n const helpService = getService(ctx, Services.Help);\n if (!helpService) return;\n\n let helpCount = 0;\n for (const metadata of pluginMetadata) {\n if (!metadata.config.help) continue;\n if (!hasPublicKeyword(metadata.packageJson?.keywords)) continue;\n helpService.registerHelp(metadata.name, metadata.config.help);\n helpCount += 1;\n }\n logger.info(`[plugin-artifacts] Registered ${helpCount} help manifest(s)`);\n}\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\nimport { logger } from \"./logger\";\n\nconst SERVICE_CONFIG_ROOT = \"service\";\n\nfunction resolveConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", SERVICE_CONFIG_ROOT, serviceName);\n}\n\nfunction resolveConfigPath(serviceName: string, configName: string): string {\n return path.join(resolveConfigDir(serviceName), `${configName}.json`);\n}\n\nfunction ensureDir(serviceName: string): void {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport async function registerServiceConfig(\n serviceName: string,\n configName: string,\n defaults: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) {\n await fs.writeFile(configPath, JSON.stringify(defaults, null, 2), \"utf-8\");\n }\n}\n\nexport async function getServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<Record<string, unknown>> {\n const configPath = resolveConfigPath(serviceName, configName);\n try {\n return JSON.parse(await fs.readFile(configPath, \"utf-8\"));\n } catch (error) {\n if (!existsSync(configPath)) return {};\n logger.warn(`[service-config] 读取 ${serviceName}/${configName} 失败: ${error}`);\n return {};\n }\n}\n\nexport async function updateServiceConfig(\n serviceName: string,\n configName: string,\n value: Record<string, unknown>,\n): Promise<void> {\n ensureDir(serviceName);\n await fs.writeFile(\n resolveConfigPath(serviceName, configName),\n JSON.stringify(value, null, 2),\n \"utf-8\",\n );\n}\n\nexport async function getServiceConfigs(\n serviceName: string,\n): Promise<Record<string, Record<string, unknown>>> {\n const dir = resolveConfigDir(serviceName);\n if (!existsSync(dir)) return {};\n\n const result: Record<string, Record<string, unknown>> = {};\n const files = (await fs.readdir(dir)).filter((name) => name.endsWith(\".json\"));\n for (const file of files) {\n try {\n result[path.basename(file, \".json\")] = JSON.parse(\n await fs.readFile(path.join(dir, file), \"utf-8\"),\n );\n } catch (error) {\n logger.warn(`[service-config] 读取 ${serviceName}/${file} 失败: ${error}`);\n }\n }\n return result;\n}\n\nexport async function deleteServiceConfig(\n serviceName: string,\n configName: string,\n): Promise<boolean> {\n const configPath = resolveConfigPath(serviceName, configName);\n if (!existsSync(configPath)) return false;\n await fs.unlink(configPath);\n return true;\n}\n","// Mioku framework types — single source of truth for the public API surface.\n\n// ---------- framework ----------\n\nexport interface MiokuService {\n name: string;\n version: string;\n description?: string;\n init(): Promise<void>;\n api: Record<string, any>;\n dispose?(): Promise<void>;\n}\n\nexport interface MiokuRuntimeConfig {\n plugins?: string[];\n plugins_dir?: string;\n services_dir?: string;\n [key: string]: unknown;\n}\n\nexport interface PackageJsonLike {\n name?: string;\n version?: string;\n description?: string;\n keywords?: string[];\n mioki?: MiokuRuntimeConfig;\n mioku?: PluginPackageConfig;\n dependencies?: Record<string, string>;\n}\n\nexport interface PluginMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n config: PluginPackageConfig;\n}\n\nexport interface ServiceMetadata {\n name: string;\n version: string;\n description?: string;\n path: string;\n packageJson: PackageJsonLike;\n}\n\n// ---------- plugin package config ----------\n\nexport interface PluginPackageConfig {\n services?: string[];\n help?: PluginHelp;\n accessHooks?: AccessHook[];\n}\n\nexport interface PluginHelp {\n title: string;\n description: string;\n commands: Array<{\n cmd: string;\n desc: string;\n usage?: string;\n role?: CommandRole;\n }>;\n}\n\nexport type CommandRole = \"master\" | \"admin\" | \"owner\" | \"member\";\n\n/**\n * - `\"master\"`:仅 bot 主人可触发\n * - `\"owner\"`:legacy alias\n * - `\"admin\"`:bot 主人或管理员\n * - `\"member\"`:群内任意成员\n *\n */\nexport type SkillPermissionRole = \"master\" | \"owner\" | \"admin\" | \"member\";\n\nexport function normalizeSkillPermissionRole(\n role: unknown,\n): SkillPermissionRole {\n const normalized = String(role ?? \"\")\n .trim()\n .toLowerCase();\n if (\n normalized === \"master\" ||\n normalized === \"owner\" ||\n normalized === \"admin\" ||\n normalized === \"member\"\n ) {\n return normalized as SkillPermissionRole;\n }\n return \"member\";\n}\n\nexport interface AccessHook {\n id: string;\n match?: string;\n event?: string;\n description?: string;\n}\n\nexport type AccessAction = \"allow\" | \"block\";\n\nexport interface AccessRuleEntry {\n action: AccessAction;\n}\n\nexport interface AccessScopeConfig {\n plugins?: Record<string, AccessRuleEntry>;\n commands?: Record<string, Record<string, AccessRuleEntry>>;\n}\n\nexport interface AccessControlConfig {\n version: 1;\n global: AccessScopeConfig;\n groups: Record<string, AccessScopeConfig>;\n users: Record<string, AccessScopeConfig>;\n}\n\n// ---------- built-in service contracts ----------\n\nexport interface ConfigService {\n registerConfig(\n pluginName: string,\n configName: string,\n initialConfig: any,\n ): Promise<boolean>;\n updateConfig(\n pluginName: string,\n configName: string,\n updates: any,\n ): Promise<boolean>;\n getConfig(pluginName: string, configName: string): Promise<any>;\n getPluginConfigs(pluginName: string): Promise<Record<string, any>>;\n onConfigChange(\n pluginName: string,\n configName: string,\n callback: (newConfig: any) => void,\n ): () => void;\n}\n\nexport interface ScreenshotService {\n screenshot(html: string, options?: any): Promise<string>;\n screenshotMarkdown(markdownContent: string, options?: any): Promise<string>;\n screenshotFromUrl(url: string, options?: any): Promise<string>;\n cleanupTemp(olderThanMs?: number): Promise<number>;\n}\n\nexport interface HelpService {\n registerHelp(pluginName: string, help: PluginHelp): void;\n getHelp(pluginName: string): PluginHelp | undefined;\n getAllHelp(): Map<string, PluginHelp>;\n unregisterHelp(pluginName: string): boolean;\n}\n\nexport interface WebUIService {\n getSettings(): { port: number; host: string; packageManager: string };\n}\n\n// ---------- AI service ----------\n\nexport interface AITool {\n name: string;\n description: string;\n parameters: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n handler: (args: any, event?: any) => Promise<any> | any;\n}\n\nexport interface AISkill {\n name: string;\n description: string;\n permission?: SkillPermissionRole;\n tools: AITool[];\n}\n\nexport interface TextMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface MultimodalContentItem {\n type: \"text\" | \"image_url\";\n text?: string;\n image_url?: {\n url: string;\n detail?: \"auto\" | \"low\" | \"high\";\n };\n}\n\nexport interface MultimodalMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string | MultimodalContentItem[];\n}\n\nexport interface ToolCallRecord {\n name: string;\n arguments: any;\n result: any;\n}\n\nexport interface SessionToolDefinition {\n name: string;\n tool: AITool;\n}\n\nexport interface CompleteOptions {\n model?: string;\n messages: any[];\n temperature?: number;\n max_tokens?: number;\n stream?: boolean;\n tools?: any[];\n executableTools?: SessionToolDefinition[];\n executableToolsProvider?: () => SessionToolDefinition[];\n maxIterations?: number;\n onTextDelta?: (delta: string) => void | Promise<void>;\n usageContext?: AIUsageContext;\n usageContextTokens?: number;\n usageBreakdown?: AIUsageFinalization[\"breakdown\"];\n}\n\nexport interface CompleteResponse {\n content: string | null;\n reasoning: string | null;\n toolCalls: Array<{ id: string; name: string; arguments: string }>;\n raw: any;\n turnMessages: any[];\n iterations?: number;\n allToolCalls?: ToolCallRecord[];\n}\n\nexport type AIProtocol =\n | \"openai-chat\"\n | \"openai-response\"\n | \"anthropic\"\n | \"gemini\";\n\nexport type AIModelCapability = \"text\" | \"vision\" | \"tool-use\" | \"reasoning\";\n\nexport type AIModelRole = \"main\" | \"working\" | \"vision\";\n\nexport interface AIProviderConfig {\n id: string;\n name: string;\n protocol: AIProtocol;\n apiUrl: string;\n apiKey: string;\n enabled: boolean;\n headers?: Record<string, string>;\n}\n\nexport interface AIModelDescriptor {\n id: string;\n providerId: string;\n modelId: string;\n name: string;\n capabilities: AIModelCapability[];\n contextWindow?: number;\n maxOutputTokens?: number;\n isCustom?: boolean;\n}\n\nexport interface AIInstanceInfo {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n}\n\nexport interface AIInstance {\n generateText(options: {\n prompt?: string;\n messages: TextMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n generateMultimodal(options: {\n prompt?: string;\n messages: MultimodalMessage[];\n model?: string;\n temperature?: number;\n max_tokens?: number;\n }): Promise<string>;\n complete(options: CompleteOptions): Promise<CompleteResponse>;\n generateWithTools(options: {\n prompt?: string;\n messages: TextMessage[] | MultimodalMessage[];\n model?: string;\n temperature?: number;\n maxIterations?: number;\n }): Promise<any>;\n setUsageContext?(context: AIUsageContext | undefined): void;\n withUsageContext?<T>(\n context: AIUsageContext | undefined,\n fn: () => Promise<T>,\n ): Promise<T>;\n registerPrompt(name: string, prompt: string): boolean;\n getPrompt(name: string): string | undefined;\n getAllPrompts(): Record<string, string>;\n removePrompt(name: string): boolean;\n}\n\nexport interface AIService {\n create(options: {\n name: string;\n apiUrl: string;\n apiKey: string;\n modelType: \"text\" | \"multimodal\";\n model?: string;\n }): Promise<AIInstance>;\n createInstance?(options: {\n name: string;\n providerId: string;\n modelId: string;\n role?: AIModelRole;\n }): Promise<AIInstance>;\n get(name: string): AIInstance | undefined;\n list(): string[];\n listInstances?(): AIInstanceInfo[];\n remove(name: string): boolean;\n setDefault(name: string): boolean;\n getDefault(): AIInstance | undefined;\n listProviders?(): AIProviderConfig[];\n getProvider?(id: string): AIProviderConfig | undefined;\n createProvider?(\n input: Omit<AIProviderConfig, \"id\"> & { id?: string },\n ): Promise<AIProviderConfig>;\n updateProvider?(\n id: string,\n input: Partial<AIProviderConfig>,\n ): Promise<AIProviderConfig>;\n removeProvider?(id: string): boolean;\n testProvider?(\n id: string,\n ): Promise<{ ok: boolean; error?: string; models?: AIModelDescriptor[] }>;\n listModels?(providerId?: string): AIModelDescriptor[];\n refreshModels?(providerId: string): Promise<AIModelDescriptor[]>;\n registerCustomModel?(input: {\n providerId: string;\n modelId: string;\n name?: string;\n capabilities?: AIModelCapability[];\n }): AIModelDescriptor;\n removeCustomModel?(modelFullId: string): boolean;\n getRoleBindings?(): Record<AIModelRole, string | undefined>;\n setRoleBinding?(role: AIModelRole, modelFullId: string | undefined): boolean;\n getInstanceByRole?(role: AIModelRole): AIInstance | undefined;\n setMainFallbackChain?(modelFullIds: string[]): void;\n getMainFallbackChain?(): string[];\n registerChatRuntime(runtime: any): boolean;\n getChatRuntime(): any;\n removeChatRuntime(): boolean;\n registerSkill(skill: AISkill): boolean;\n getSkill(skillName: string): AISkill | undefined;\n getAllSkills(): Map<string, AISkill>;\n removeSkill(skillName: string): boolean;\n getTool(toolName: string): AITool | undefined;\n getAllTools(): Map<string, AITool>;\n getUsageSummary?(options: {\n range: AIUsageRange;\n botId?: number;\n }): AIUsageSummary;\n cleanupUsageStats?(retentionMs?: number): number;\n finalizeUsage?(usageId: string, finalization: AIUsageFinalization): boolean;\n}\n\n// ---------- chat runtime ----------\n\nexport interface ChatRuntime {\n generateNotice(options: ChatRuntimeNoticeOptions): Promise<ChatRuntimeResult>;\n requestInformation(\n options: ChatRuntimeInformationRequestOptions,\n ): Promise<ChatRuntimeResult>;\n}\n\nexport const TOOL_RESULT_FOLLOWUP_KEY = \"__miokuFollowup\";\n\nexport interface ToolResultFollowup {\n text: string;\n images?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n videos?: Array<{ url: string; detail?: \"auto\" | \"low\" | \"high\" }>;\n}\n\nexport interface ChatRuntimePromptInjection {\n content: string;\n title?: string;\n}\n\nexport interface ChatRuntimeGroupTarget {\n selfId: number;\n groupId: number;\n}\n\nexport interface ChatRuntimePrivateTarget {\n selfId: number;\n userId: number;\n}\n\nexport type ChatRuntimeSource =\n | { event: any }\n | ChatRuntimeGroupTarget\n | ChatRuntimePrivateTarget;\n\nexport type ChatRuntimeBaseOptions = ChatRuntimeSource & {\n targetMessage?: string;\n promptInjections?: ChatRuntimePromptInjection[];\n send?: boolean;\n};\n\nexport type ChatRuntimeNoticeOptions = ChatRuntimeBaseOptions & {\n instruction: string;\n};\n\nexport type ChatRuntimeInformationRequestOptions = ChatRuntimeBaseOptions & {\n task: string;\n schema: {\n type: \"object\";\n properties: Record<string, any>;\n required?: string[];\n };\n toolName?: string;\n toolDescription?: string;\n};\n\nexport interface ChatRuntimeCollectedInfo {\n data: any;\n isComplete?: boolean;\n confidence?: number;\n notes?: string;\n}\n\nexport interface ChatRuntimeResult {\n messages: string[];\n toolCalls: ToolCallRecord[];\n collectedInfo: ChatRuntimeCollectedInfo | null;\n pendingAt?: number[];\n pendingPoke?: number[];\n pendingQuote?: number;\n emojiPath?: string | null;\n protocolMessages?: any[];\n}\n\n// ---------- usage tracking ----------\n\nexport type AIUsageRange = \"today\" | \"7d\" | \"30d\";\n\nexport type AIUsageScope = \"all\" | \"bot\";\n\nexport interface AIUsageContext {\n usageId?: string;\n source?: string;\n botId?: number;\n groupId?: number;\n groupName?: string;\n userId?: number;\n userName?: string;\n sessionId?: string;\n fallbackUsed?: boolean;\n fallbackFrom?: string;\n}\n\nexport interface AIUsageBreakdown {\n systemPromptTokens?: number;\n chatHistoryTokens?: number;\n toolDefinitionTokens?: number;\n toolUseTokens?: number;\n otherContextTokens?: number;\n}\n\nexport interface AIUsageFinalization {\n sentUserMessages?: number;\n sentAssistantMessages?: number;\n breakdown?: AIUsageBreakdown;\n}\n\nexport interface AIUsageBotOption {\n botId: number;\n label: string;\n}\n\nexport interface AIUsageSummary {\n generatedAt: number;\n range: AIUsageRange;\n scope: AIUsageScope;\n botId?: number;\n bots: AIUsageBotOption[];\n totals: {\n requests: number;\n successfulRequests: number;\n failedRequests: number;\n userMessages: number;\n assistantMessages: number;\n systemMessages: number;\n toolMessages: number;\n sentUserMessages: number;\n sentAssistantMessages: number;\n inputTokens: number;\n outputTokens: number;\n systemPromptTokens: number;\n totalTokens: number;\n cacheWriteTokens: number;\n cacheReadTokens: number;\n toolDefinitionTokens: number;\n toolUseTokens: number;\n chatHistoryTokens: number;\n otherContextTokens: number;\n durationMs: number;\n toolCalls: number;\n };\n rates: {\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n };\n toolRanking: Array<{ name: string; count: number }>;\n groupRanking: Array<{\n groupId: number;\n groupName: string;\n requests: number;\n totalTokens: number;\n userMessages: number;\n assistantMessages: number;\n errorRate: number;\n }>;\n tokenFlow: Array<{\n name: \"输入\" | \"输出\" | \"缓存写入\" | \"缓存读取\";\n value: number;\n }>;\n tokenCategories: Array<{\n name: \"系统提示词\" | \"工具定义\" | \"工具使用\" | \"聊天上下文\" | \"其他上下文\";\n value: number;\n }>;\n dailyActivity: Array<{\n day: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n hourlyActivity: Array<{\n hour: string;\n requests: number;\n userMessages: number;\n assistantMessages: number;\n totalTokens: number;\n inputTokens: number;\n cacheReadTokens: number;\n throughputTokPerMin: number;\n averageTokensPerUserMessage: number;\n averageTokensPerSentMessage: number;\n errorRate: number;\n cacheHitRate: number;\n }>;\n}\n","import * as path from \"path\";\nimport { existsSync, mkdirSync } from \"fs\";\n\nexport function getPluginDataDir(pluginName: string): string {\n return path.join(process.cwd(), \"data\", pluginName);\n}\n\nexport function getServiceDataDir(serviceName: string): string {\n return path.join(process.cwd(), \"data\", serviceName);\n}\n\nexport function getDataDir(): string {\n return path.join(process.cwd(), \"data\");\n}\n\nexport function getPluginConfigDir(pluginName: string): string {\n return path.join(process.cwd(), \"config\", pluginName);\n}\n\nexport function getServiceConfigDir(serviceName: string): string {\n return path.join(process.cwd(), \"config\", \"service\", serviceName);\n}\n\nexport function getConfigDir(): string {\n return path.join(process.cwd(), \"config\");\n}\n\nexport function ensureDataDir(pluginName: string): string {\n const dir = getPluginDataDir(pluginName);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n","import { getOrCreate } from \"./registry\";\n\nconst store = getOrCreate<Record<string, unknown>>(\n \"plugin-runtime-state\",\n () => ({}),\n);\n\nexport interface PluginStateRef<T> {\n readonly name: string;\n get(): T;\n set(next: T): void;\n reset(): void;\n}\n\nexport function defineState<T>(name: string, initial: T): PluginStateRef<T> {\n return {\n name,\n get(): T {\n const current = store[name];\n return (current === undefined ? initial : current) as T;\n },\n set(next: T): void {\n store[name] = next;\n },\n reset(): void {\n delete store[name];\n },\n };\n}\n\nexport function hasPluginState(name: string): boolean {\n return store[name] !== undefined;\n}\n\nexport function getPluginRuntimeState<T = Record<string, any>>(\n name: string,\n): T {\n if (!store[name]) store[name] = {};\n return store[name] as T;\n}\n\nexport function setPluginRuntimeState<T>(name: string, state: T): void {\n store[name] = state;\n}\n\nexport function resetPluginRuntimeState(name: string): void {\n delete store[name];\n}\n\nexport function getAllPluginRuntimeStates(): Record<string, unknown> {\n return { ...store };\n}","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { bootstrapMioku } from \"./core/bootstrap\";\nimport { setMiokuLogger } from \"./core/logger\";\nimport { default as serviceManager } from \"./core/service-manager\";\n\nexport type { MiokiPlugin, MiokiContext } from \"mioki\";\nexport type { EventMap } from \"napcat-sdk\";\n\nexport function definePlugin<T extends import(\"mioki\").MiokiPlugin>(\n plugin: T,\n): T {\n return plugin;\n}\n\nexport { default as pluginManager } from \"./core/plugin-manager\";\nexport { default as serviceManager } from \"./core/service-manager\";\nexport { registerPluginArtifacts } from \"./core/plugin-artifact-registry\";\n\nexport {\n registerServiceConfig,\n getServiceConfig,\n updateServiceConfig,\n getServiceConfigs,\n deleteServiceConfig,\n} from \"./core/service-config\";\n\nexport type {\n MiokuService,\n MiokuRuntimeConfig,\n PackageJsonLike,\n PluginMetadata,\n ServiceMetadata,\n PluginPackageConfig,\n PluginHelp,\n CommandRole,\n AccessHook,\n AccessAction,\n AccessRuleEntry,\n AccessScopeConfig,\n AccessControlConfig,\n ConfigService,\n ScreenshotService,\n HelpService,\n WebUIService,\n AITool,\n AISkill,\n AIInstance,\n AIService,\n AIProtocol,\n AIModelCapability,\n AIModelRole,\n AIProviderConfig,\n AIModelDescriptor,\n AIInstanceInfo,\n ChatRuntime,\n TextMessage,\n MultimodalMessage,\n ToolCallRecord,\n CompleteOptions,\n CompleteResponse,\n SessionToolDefinition,\n SkillPermissionRole,\n MultimodalContentItem,\n ToolResultFollowup,\n ChatRuntimePromptInjection,\n ChatRuntimeGroupTarget,\n ChatRuntimePrivateTarget,\n ChatRuntimeSource,\n ChatRuntimeBaseOptions,\n ChatRuntimeNoticeOptions,\n ChatRuntimeInformationRequestOptions,\n ChatRuntimeCollectedInfo,\n ChatRuntimeResult,\n AIUsageRange,\n AIUsageScope,\n AIUsageBotOption,\n AIUsageContext,\n AIUsageBreakdown,\n AIUsageFinalization,\n AIUsageSummary,\n} from \"./types\";\n\nexport {\n TOOL_RESULT_FOLLOWUP_KEY,\n normalizeSkillPermissionRole,\n} from \"./types\";\n\nexport {\n defineService,\n getService,\n requireService,\n hasService,\n} from \"./core/service\";\nexport type { ServiceRef } from \"./core/service\";\nexport { Services } from \"./core/services\";\nexport type { BuiltinServiceRef } from \"./core/services\";\n\nexport interface MiokuStartOptions {\n cwd?: string;\n}\n\nexport async function start(options: MiokuStartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options;\n if (cwd) process.chdir(cwd);\n\n const { start: startMioki, logger, botConfig } = await import(\"mioki\");\n setMiokuLogger(logger);\n\n let shuttingDown = false;\n const shutdown = async (signal: string) => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info(`收到 ${signal} 信号,正在关闭服务...`);\n const timer = setTimeout(() => {\n logger.error(\"服务关闭超时,强制退出\");\n process.exit(1);\n }, 15_000);\n timer.unref();\n await serviceManager.disposeAll();\n clearTimeout(timer);\n logger.info(\"Mioku 服务已完全关闭\");\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n logger.info(\"こんにちは..\");\n logger.info(\"---------------------------------------\");\n logger.info(\"---------- Mioku 正在启动 ------------\");\n logger.info(\"---------------------------------------\");\n\n await bootstrapMioku({ cwd, botConfig, startMioki });\n}\n\nfunction readVersion(): string {\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const pkgPath = path.join(here, \"..\", \"package.json\");\n return JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")).version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const version: string = readVersion();\n\nexport {\n getDataDir,\n getPluginDataDir,\n getServiceDataDir,\n getConfigDir,\n getPluginConfigDir,\n getServiceConfigDir,\n ensureDataDir,\n} from \"./core/data-paths\";\n\nexport {\n defineState,\n hasPluginState,\n getPluginRuntimeState,\n setPluginRuntimeState,\n resetPluginRuntimeState,\n getAllPluginRuntimeStates,\n} from \"./core/plugin-runtime-state\";\nexport type { PluginStateRef } from \"./core/plugin-runtime-state\";\n\nexport {\n resolveCommand,\n commandExists,\n buildSpawnPlan,\n runCommand,\n runCommandInherit,\n} from \"./core/exec\";\n\nexport type { RunCommandResult, SpawnPlan } from \"./core/exec\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mioku",
3
3
  "type": "module",
4
- "version": "0.9.8",
4
+ "version": "0.9.9",
5
5
  "packageManager": "bun@1.2.0",
6
6
  "description": "Mioku - Plugin framework extended from mioki for NapCat OneBot v11",
7
7
  "keywords": [