mioki 0.9.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["jiti: Jiti","Low","DataFile","segment","text","matches: RegExpMatchArray | null","__dirname","path","crypto","selected: number[]","start","cacheMsg","result: string","code","START_TIME: Date","BOT_CWD: { value: string }","fs","path","botConfig: MiokiConfig","isInPm2: boolean","LEVEL_MAP: Record<number, { name: string; color: ColorName }>","logger: Logger","path","fs","LogLevels","util","colors","utils.wait","utils.stringifyError","segment","uuid","crypto","randomID: string | number","code: number | undefined","utils.getMinicoTokenViaAuthCode","USER_SERVICE: MiokiServices","services: MiokiServices","runtimePlugins: Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n>","actionsExports","fs","path","start","hrtime","logger","context: MiokiContext","utilsExports","configExports","servicesExports.services","servicesExports.addService","name","nodeCron","version","err: any","colors","e: any","SystemMap: Record<string, string>","ArchMap: Record<string, string>","os","systemInfo","version","path","start","core: MiokiPlugin","text","e","err: any","BUILTIN_PLUGINS: MiokiPlugin[]","core","path","version","colors","NapCat","utils.stringifyError","actions.noticeMainOwner","fs","failedImportPlugins: [string, string][]","start","hrtime","failedEnablePlugins: [string, string][]","plugins","e: any"],"sources":["../src/utils.ts","../src/config.ts","../src/logger.ts","../src/actions.ts","../src/services.ts","../src/plugin.ts","../src/builtins/core/status.ts","../src/builtins/core/index.ts","../src/builtins/index.ts","../src/start.ts"],"sourcesContent":["import mri from 'mri'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport { Low } from 'lowdb'\nimport { DataFile } from 'lowdb/node'\nimport { createJiti, type Jiti } from 'jiti'\nimport { string2argv } from 'string2argv'\nimport { fileURLToPath } from 'node:url'\nimport { segment } from 'napcat-sdk'\n\nexport { default as prettyMs } from 'pretty-ms'\n\nimport type { BinaryLike, BinaryToTextEncoding } from 'node:crypto'\nimport type {\n MessageEvent,\n GroupMessageEvent,\n Sendable,\n PrivateMessageEvent,\n RecvElement,\n RecvImageElement,\n} from 'napcat-sdk'\n\nexport { filesize } from 'filesize'\nexport { string2argv } from 'string2argv'\nexport { default as fs } from 'node:fs'\nexport { default as mri } from 'mri'\nexport { default as path } from 'node:path'\nexport { default as dayjs } from 'dayjs'\nexport { default as dedent } from 'dedent'\nexport { colors, stripAnsi, box, colorize } from 'consola/utils'\nexport { default as systemInfo } from 'systeminformation'\n\nexport const ChromeUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0'\n\nexport type Noop = () => void\nexport type AnyFunc = (...args: any[]) => any\nexport type PureObject<T = any> = Record<PropertyKey, T>\nexport type Arrayable<T> = T | T[]\nexport type Gettable<T> = T | (() => T)\nexport type HasMessage = { message: RecvElement[] } | RecvElement[]\n\n/**\n * Jiti 实例\n */\nexport const jiti: Jiti = createJiti(__dirname, {\n extensions: ['.ts', '.js', '.cts', '.cjs', '.mts', '.mjs', '.tsx', '.jsx', '.json'],\n\n cache: false,\n fsCache: false,\n moduleCache: false,\n requireCache: false,\n\n sourceMaps: false,\n interopDefault: true,\n\n jsx: {\n importSource: 'react',\n runtime: 'automatic',\n },\n})\n\nexport interface CreateCmdOptions {\n prefix?: string\n onPrefix?(): void\n}\n\n/**\n * 解析命令字符串,返回命令和参数\n */\nexport function createCmd(\n cmdStr: string,\n options: CreateCmdOptions = {},\n): {\n cmd: string | undefined\n params: string[]\n options: Record<string, any>\n} {\n const { prefix = '', onPrefix = () => {} } = options\n const { _, ...cmdOptions } = mri(string2argv(cmdStr))\n const [cmd, ...params] = _\n\n if (prefix) {\n if (cmd !== prefix) {\n return {\n cmd: undefined,\n params: [],\n options: cmdOptions,\n }\n }\n\n if (params.length === 0) {\n onPrefix()\n }\n\n const prefixedCmd = params.shift()\n\n return {\n cmd: prefixedCmd,\n params,\n options: cmdOptions,\n }\n }\n\n return {\n cmd,\n params,\n options: cmdOptions,\n }\n}\n\n/**\n * 带有表情反应的函数执行包装器\n */\nexport async function runWithReaction<T extends AnyFunc>(\n e: GroupMessageEvent,\n fn: T,\n id = '60',\n): Promise<ReturnType<T>> {\n await e.addReaction(id)\n const result = (await fn()) as ReturnType<T>\n await e.delReaction(id)\n return result\n}\n\n/**\n * 创建一个 LowDB 数据库实例\n */\nexport async function createDB<T extends object = object>(\n filename: string,\n options: {\n defaultData?: T\n compress?: boolean\n } = {},\n): Promise<Low<T>> {\n const { defaultData = {} as T, compress = false } = options\n\n const database = new Low<T>(\n new DataFile<T>(filename, {\n parse: JSON.parse,\n stringify: (data) => JSON.stringify(data, null, compress ? 0 : 2),\n }),\n defaultData,\n )\n\n await database.read()\n\n return database\n}\n\n/**\n * 确保返回一个可用的图片元素\n *\n * @param buffer 图片缓冲区\n * @param text 文本\n * @returns 图片元素\n */\nexport function ensureBuffer(buffer?: Buffer | null | undefined, text?: null): null\nexport function ensureBuffer(buffer?: Buffer | null | undefined, text?: string): Sendable\nexport function ensureBuffer(\n buffer?: Buffer | null | undefined,\n text: string | null = '图片渲染失败',\n): Sendable | null {\n return buffer ? segment.image(`data:image/png;base64,${buffer.toString('base64')}`) : text\n}\n\n/**\n * 格式化时间间隔为可读字符串\n *\n * @param ms 时间间隔(毫秒)\n * @returns 可读字符串\n */\nexport function formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) return `${days}天${hours % 24}小时`\n if (hours > 0) return `${hours}小时${minutes % 60}分钟`\n if (minutes > 0) return `${minutes}分钟${seconds % 60}秒`\n return `${seconds}秒`\n}\n\ntype MatchPatternItem = null | undefined | void | false | Sendable | Sendable[]\ntype MatchValue<E extends MessageEvent> =\n | MatchPatternItem\n | ((matches: RegExpMatchArray, event: E) => MatchPatternItem)\n | ((matches: RegExpMatchArray, event: E) => Promise<MatchPatternItem>)\n/**\n * 匹配输入文本与匹配模式,如果匹配成功,则回复匹配结果\n *\n * 支持:\n * - 精确匹配\n * - 正则表达式匹配(以 `/` 开头和结尾的字符串)\n * - 通配符匹配(使用 `*` 作为通配符)\n *\n * @param event 消息事件\n * @param pattern 匹配模式\n * @param quote 是否引用回复\n * @returns 匹配结果\n */\nexport async function match<E extends MessageEvent>(\n event: E,\n pattern: Record<string, MatchValue<E>>,\n quote: boolean = true,\n): Promise<{ message_id: number } | null> {\n const inputText = text(event)\n\n async function handleMatch(key: string, value: MatchValue<E>) {\n let isMatched = false\n let matches: RegExpMatchArray | null = null\n\n const isRegExpLikeString = key.match(/^\\/.+\\/$/)\n const hasWildcard = key.includes('*')\n\n if (isRegExpLikeString) {\n try {\n const regex = new RegExp(key.slice(1, -1))\n const matchesValue = inputText.match(regex)\n\n if (matchesValue) {\n isMatched = true\n matches = matchesValue\n }\n } catch (err) {\n throw new Error(`无效的正则表达式: ${key}`, { cause: err })\n }\n } else if (hasWildcard) {\n const regexPattern = `^${key.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`\n const regex = new RegExp(regexPattern)\n const matchesValue = inputText.match(regex)\n\n if (matchesValue) {\n isMatched = true\n matches = matchesValue\n }\n } else if (key === inputText) {\n isMatched = true\n }\n\n if (isMatched) {\n return typeof value === 'function' ? await value(matches as RegExpMatchArray, event) : value\n }\n }\n\n for (const [key, value] of Object.entries(pattern)) {\n const result = await handleMatch(key, value)\n\n if (result) {\n return event.reply(result, quote)\n }\n }\n\n return null\n}\n\n/**\n * 创建一个持久化数据库,基于 createDB 封装\n */\nexport async function createStore<T extends object = object>(\n defaultData: T,\n options?: {\n __dirname?: string\n importMeta?: ImportMeta\n compress?: boolean\n filename?: string\n },\n): Promise<Low<T>> {\n const { compress = false, __dirname, importMeta: meta, filename = 'data.json' } = options || {}\n const dirname = __dirname || meta?.dirname || (meta?.url ? path.dirname(fileURLToPath(meta.url)) : '')\n\n if (!dirname) {\n throw new Error('createStore: options.__dirname or options.meta must be provided')\n }\n\n const filePath = path.join(dirname, filename)\n\n const database = new Low<T>(\n new DataFile<T>(filePath, {\n parse: JSON.parse,\n stringify: (data) => JSON.stringify(data, null, compress ? 0 : 2),\n }),\n defaultData,\n )\n\n await database.read()\n await database.write()\n\n return database\n}\n\n/**\n * MD5 加密\n */\nexport function md5(text: BinaryLike, encoding: 'buffer'): Buffer\nexport function md5(text: BinaryLike, encoding?: BinaryToTextEncoding): string\nexport function md5(text: BinaryLike, encoding: BinaryToTextEncoding | 'buffer' = 'hex'): string | Buffer {\n const hash = crypto.createHash('md5').update(text)\n\n if (encoding === 'buffer') {\n return hash.digest()\n }\n\n return hash.digest(encoding)\n}\n\n/**\n * 数组去重\n */\nexport function unique<T>(array: T[]): T[] {\n return Array.from(new Set(array))\n}\n\n/**\n * 确保值为数组\n *\n */\nexport function toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n\n/**\n * 是否是群消息\n */\nexport const isGroupMsg = (event: MessageEvent): event is GroupMessageEvent => {\n return 'group' in event\n}\n\n/**\n * 是否是私聊消息\n */\nexport const isPrivateMsg = (event: MessageEvent): event is PrivateMessageEvent => {\n return !isGroupMsg(event)\n}\n\n/**\n * 异步延时函数\n *\n * @param {number} ms 等待毫秒数\n * @return {Promise<void>}\n */\nexport async function wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\ninterface FormatOptions {\n locale?: string\n timeZone?: string\n}\n\n/**\n * 获取今天的固定日期字符串,可用来作为「稳定随机」的参数,用于签到、每日任务等场景\n *\n * 格式: 2024/12/12,可选控制时区,默认为 'Asia/Shanghai' (亚洲/上海 时区)\n *\n * @param timeZone 指定的时区,默认为 'Asia/Shanghai'\n * @returns 返回当前日期的字符串格式\n */\nexport function localeDate(ts: number | string | Date = Date.now(), options: FormatOptions = {}): string {\n const { locale = 'zh-CN', timeZone = 'Asia/Shanghai' } = options\n const today = ts instanceof Date ? ts : new Date(ts)\n\n const formatter = new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n timeZone,\n })\n\n return formatter.format(today)\n}\n\n/**\n * 获取当前时间的固定时间字符串\n */\nexport function localeTime(\n ts: number | string | Date = Date.now(),\n options: FormatOptions & { seconds?: boolean } = {},\n): string {\n const { locale = 'zh-CN', timeZone = 'Asia/Shanghai', seconds = true } = options\n const now = ts instanceof Date ? ts : new Date(ts)\n\n const formatter = new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n hourCycle: 'h23',\n minute: '2-digit',\n second: seconds ? '2-digit' : undefined,\n timeZone,\n })\n\n return formatter.format(now)\n}\n\n/**\n * 生成指定范围(min ~ max)内的随机整数\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机数相同\n */\nexport function randomInt(min: number, max: number, ...hashArgs: any[]): number {\n if (min > max) throw new Error('min must be less than or equal to max')\n\n if (hashArgs.length === 0) {\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n const sortedArgs = hashArgs.slice().sort((a, b) => {\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return JSON.stringify(a).localeCompare(JSON.stringify(b))\n })\n\n const hash = md5(JSON.stringify(sortedArgs))\n const hashValue = Number.parseInt(hash.slice(0, 8), 16)\n\n const range = max - min + 1\n return (((hashValue % range) + range) % range) + min\n}\n\n/**\n * 取数组内随机一项\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机项\n */\nexport function randomItem<T = any>(array: readonly T[], ...hashArgs: any[]): T {\n if (!Array.isArray(array) || !array.length) throw new Error('randomItem: 参数必须是数组,且不能为空')\n return array[randomInt(0, array.length - 1, ...hashArgs)]\n}\n\n/**\n * 从数组中随机选出指定数量的项(不重复)\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机项相同\n *\n * @param array 源数组\n * @param count 要选择的项数量\n * @param hashArgs 稳定随机的额外参数\n * @returns 随机选出的项组成的数组\n */\nexport function randomItems<T = any>(array: readonly T[], count: number, ...hashArgs: any[]): T[] {\n if (!Array.isArray(array) || !array.length) throw new Error('randomItems: 参数必须是数组,且不能为空')\n if (count < 0) throw new Error('randomItems: count 必须为非负整数')\n if (count === 0) return []\n if (count > array.length) throw new Error(`randomItems: 要选择的数量 (${count}) 超过了数组长度 (${array.length})`)\n if (count === array.length) return [...array]\n\n const indices = Array.from({ length: array.length }, (_, i) => i)\n const selected: number[] = []\n\n for (let i = 0; i < count; i++) {\n const remainingCount = indices.length - i\n const randomIdx = randomInt(0, remainingCount - 1, ...hashArgs, `select_${i}`)\n selected.push(indices[randomIdx])\n const lastIdx = indices.length - 1 - i\n ;[indices[randomIdx], indices[lastIdx]] = [indices[lastIdx], indices[randomIdx]]\n }\n\n const hasString = array.some(isString)\n const items = selected.map((idx) => array[idx])\n\n return hasString ? items.sort((p, n) => (isString(p) && isString(n) ? p.localeCompare(n) : 0)) : items\n}\n\n/**\n * 包含大写字母与数字的 6 位随机 ID 生成器\n */\nexport function randomId(): string {\n return Math.random().toString(16).slice(2, 8).toUpperCase()\n}\n\n/**\n * 简单生成符合 UUID 规范的字符串,但不保证唯一性\n */\nexport function uuid() {\n return `${randStr(8)}-${randStr(4)}-${randStr(4)}-${randStr(4)}-${randStr(12)}`\n\n function randStr(length = 4) {\n return Math.random()\n .toString(16)\n .substring(2, length + 2)\n }\n}\n\n/**\n * clamp 操作,限制数值在指定范围内\n */\nexport function clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n))\n}\n\n/**\n * 排除 null 和 undefined\n */\nexport function noNullish<T>(val: T | null): val is T {\n return val !== null && val !== undefined\n}\n\n/**\n * 判断是否定义\n */\nexport function isDefined<T = unknown>(val?: T): val is T {\n return typeof val !== 'undefined'\n}\n\n/**\n * 通过消息事件生成唯一 id\n */\nexport function toMsgId(event: { seq: number; rand: number }) {\n return `${event.seq}_${event.rand}`\n}\n\n/**\n * 判断是否为函数\n */\nexport function isFunction<T extends AnyFunc>(val: unknown): val is T {\n return typeof val === 'function'\n}\n\n/**\n * 判断是否为数字\n */\nexport function isNumber(val: unknown): val is number {\n return typeof val === 'number'\n}\n\n/**\n * 判断是否为布尔值\n */\nexport function isBoolean(val: unknown): val is boolean {\n return typeof val === 'boolean'\n}\n\n/**\n * 判断是否为字符串\n */\nexport function isString(val: unknown): val is string {\n return typeof val === 'string'\n}\n\n/**\n * 判断是否为对象\n */\nexport function isObject(val: unknown): val is object {\n return Object.prototype.toString.call(val) === '[object Object]'\n}\n\n/**\n * 将数字转换为本地化数字字符串\n */\nexport function localNum(num: number, locale = 'zh-CN'): string {\n return num.toLocaleString(locale)\n}\n\n/**\n * 通过 QQ 号获取任意头像链接\n *\n * size 可选: 0 | 40 | 100 | 160 | 640,0 为原图\n */\nexport function getQQAvatarLink(qq: number, size = 640) {\n return `https://q.qlogo.cn/headimg_dl?dst_uin=${qq}&spec=${size}`\n}\n\n/**\n * 通过群号获取任意群头像链接\n *\n * size 可选: 40 | 100 | 640,0 为原图\n */\nexport function getGroupAvatarLink(group: number, size = 640) {\n // return `https://p.qlogo.cn/gh/${group}/${group}/${size}`\n return `https://p.qlogo.cn/gh/111111/${group}/${size}`\n}\n\nconst messageCacheMap = new Map<string, GroupMessageEvent | PrivateMessageEvent | 'loading' | null>()\n\n/** 获取引用回复的消息 */\nexport async function getQuoteMsg(\n event: MessageEvent,\n timeout = 3_000,\n): Promise<GroupMessageEvent | PrivateMessageEvent | null> {\n if (!event.quote_id) return null\n\n const quote_id = event.quote_id\n\n // 生成唯一 key\n const key = isGroupMsg(event) ? `${event.group_id}_${quote_id}` : `${event.sender.user_id}_${quote_id}`\n const cacheMsg = messageCacheMap.get(key)\n // 是否正在获取\n const isFetching = cacheMsg === 'loading'\n // 是否获取结束(已经获取过)\n const isFetchDone = cacheMsg !== undefined && !isFetching\n // 如果已经获取过,直接返回\n if (isFetchDone) return cacheMsg\n // 如果正在获取,等待获取完成\n if (isFetching) {\n const start = Date.now()\n return new Promise((resolve) => {\n const timer = setInterval(() => {\n const cacheMsg = messageCacheMap.get(key)\n const isFetching = cacheMsg === 'loading'\n const isFetchDone = cacheMsg !== undefined && !isFetching\n if (isFetchDone) {\n clearInterval(timer)\n resolve(cacheMsg)\n } else if (Date.now() - start > timeout) {\n clearInterval(timer)\n throw new Error(`获取引用消息超时 ${timeout}, Key: ${key}`)\n }\n }, 100)\n })\n }\n\n // 开始获取\n messageCacheMap.set(key, 'loading')\n\n const msg = await event.getQuoteMsg()\n\n // 如果缓存达到阈值则清空\n if (messageCacheMap.size > 100) messageCacheMap.clear()\n\n messageCacheMap.set(key, msg)\n\n return msg\n}\n\n/**\n * 获取原创表情包的图片链接\n */\nexport async function getBfaceUrl(file: string): Promise<string | null> {\n const id = file.slice(0, 2)\n const hash = file.slice(0, 32)\n const formats = ['raw300.gif', 'raw200.gif', 'raw100.gif', '300x300.png', '200x200.png', '100x100.png']\n\n for (const f of formats) {\n const url = `https://gxh.vip.qq.com/club/item/parcel/item/${id}/${hash}/${f}`\n const res = await fetch(url, { method: 'HEAD' })\n if (res.status === 200) return url\n }\n\n return null\n}\n\n/**\n * 获取消息中的图片链接\n */\nexport async function getImageUrl(event: HasMessage): Promise<string> {\n return find(event, 'image')?.url || ''\n}\n\n/**\n * 获取引用回复的消息中的图片链接\n */\nexport async function getQuoteImageUrl(event: MessageEvent): Promise<string> {\n const quoteMsg = await getQuoteMsg(event)\n if (!quoteMsg) return ''\n return await getImageUrl(quoteMsg)\n}\n\n/**\n * 获取消息提及的图片链接(消息或者引用消息)\n */\nexport async function getMentionedImageUrl(event: MessageEvent): Promise<string> {\n return (await getImageUrl(event)) || (await getQuoteImageUrl(event))\n}\n\n/**\n * 获取消息中的图片元素\n */\nexport function getImage(event: HasMessage): RecvImageElement | null {\n return find(Array.isArray(event) ? event : event.message, 'image') || null\n}\n\n/**\n * 获取引用回复的图片消息\n */\nexport async function getQuoteImage(event: MessageEvent): Promise<RecvImageElement | null> {\n const quoteMsg = await getQuoteMsg(event)\n if (quoteMsg) {\n return find(quoteMsg.message, 'image') || null\n }\n return null\n}\n\n/**\n * 获取消息提及的图片(消息或者引用消息)\n */\nexport async function getMentionedImage(event: MessageEvent): Promise<RecvImageElement | null> {\n return getImage(event) || (await getQuoteImage(event))\n}\n\n/**\n * 获取消息中的文本内容,默认采取 'whole' 模式,去除整体的首尾空格,可选 'each' 模式,去除每个文本的首尾空格\n *\n * 如: whole 模式下 => ' 123 [表情] 456 ' => '123 456'\n * 如: each 模式下 => ' 123 [表情] 456 ' => '123456'\n */\nexport function text(\n event: HasMessage,\n options: {\n trim?: boolean | 'whole' | 'each'\n } = {},\n): string {\n const { trim = true } = options\n const messages = Array.isArray(event) ? event : event.message\n const textMessages = messages.filter((msg): msg is { type: 'text'; text: string } => msg.type === 'text')\n const texts = textMessages.map((msg) => msg.text)\n\n let result: string\n\n if (trim === 'whole') {\n result = texts.join('').trim()\n } else if (trim === 'each') {\n result = texts.map((t) => t.trim()).join('')\n } else if (trim === true) {\n // 默认为 true, 也就是整体去除首尾空格\n result = texts.map((t) => t.trim()).join('')\n } else {\n result = texts.join('')\n }\n\n return result || ''\n}\n\n/**\n * 获取回复的消息中的文本内容\n */\nexport async function getQuoteText(event: MessageEvent): Promise<string> {\n const msg = await getQuoteMsg(event)\n if (!msg) return ''\n return text(msg)\n}\n\n/**\n * 获取提到的用户 QQ 号,可以通过 if(!qq) 判断是否提到了用户,返回 0 代表没有提到用户\n */\nexport async function getMentionedUserId(event: MessageEvent): Promise<number | 0> {\n const quoteId = (await getQuoteMsg(event))?.sender.user_id || 0\n const msgAtId = +(find(event.message, 'at')?.qq || 0)\n return Number.isNaN(msgAtId) || !msgAtId ? quoteId : msgAtId\n}\n\n/**\n * 获取 **一个** 指定类型的消息元素,如获取图片、表情等,如果没有则返回 undefined\n */\nexport function find<\n Type extends Pick<RecvElement, 'type'>['type'],\n TargetType extends Extract<RecvElement, { type: Type }> = Extract<RecvElement, { type: Type }>,\n>(event: HasMessage, type: Type): TargetType | undefined {\n const messages = Array.isArray(event) ? event : event.message\n return messages.find((msg): msg is TargetType => msg.type === type)\n}\n\n/**\n * 获取 **所有** 指定类型的消息元素,如获取图片、表情等,如果没有则返回 []\n */\nexport function filter<\n Type extends Pick<RecvElement, 'type'>['type'],\n TargetType extends Extract<RecvElement, { type: Type }> = Extract<RecvElement, { type: Type }>,\n>(event: HasMessage, type: Type): TargetType[] {\n const messages = Array.isArray(event) ? event : event.message\n return messages.filter((msg): msg is TargetType => msg.type === type)\n}\n\n/**\n * 错误信息字符串格式化\n *\n * @param {any} error 待处理错误\n * @return {string} stringify 结果\n */\nexport function stringifyError(error: any): string {\n if (typeof error === 'object') {\n const errorType = error.constructor?.name ?? '未知错误'\n const errorMessage = error.message ?? '[无报错信息]'\n return `${errorType}: ${errorMessage}`\n }\n\n return String(error)\n}\n\n/**\n * Encodes string | number | buffer using base64.\n */\nexport function base64Encode(str: string | number | Buffer): string {\n return Buffer.from(str.toString()).toString('base64')\n}\n\n/**\n * Decodes the string from base64 to UTF-8.\n *\n * @param {string} str - The base64-encoded string.\n */\nexport function base64Decode(str: string, type: 'buffer' | BufferEncoding = 'utf8'): string | Buffer {\n if (type === 'buffer') return Buffer.from(str, 'base64')\n return Buffer.from(str, 'base64').toString(type)\n}\n\n/**\n * JS 对象转换成 `urlencoded` 格式字符串 { name: 'Bob', age: 18 } => name=Bob&age=18\n *\n * @param {Record<number | string, any>} obj JS 对象\n * @return {string} 转换后的字符串\n */\nexport function qs(obj: Record<number | string, any>): string {\n return new URLSearchParams(obj).toString()\n}\n\n/**\n * 格式化展示 QQ 等级\n */\nexport function formatQQLevel(level: number): string {\n return (\n '👑'.repeat(Math.floor(level / 64)) +\n '☀️'.repeat(Math.floor((level % 64) / 16)) +\n '🌙'.repeat(Math.floor((level % 16) / 4)) +\n '⭐️'.repeat(level % 4)\n )\n}\n\n/**\n * 申请通过开发者工具登录,以获取 Cookie\n */\nexport async function requestLoginViaDevTools(): Promise<{ code: string; url: string }> {\n const code = await getDevToolsLoginCode()\n\n return {\n code: code,\n url: `https://h5.qzone.qq.com/qqq/code/${code}?_proxy=1&from=ide`,\n }\n\n /**\n * 获取开发者工具登录码\n */\n async function getDevToolsLoginCode(): Promise<string> {\n const response = await fetch('https://q.qq.com/ide/devtoolAuth/GetLoginCode', {\n method: 'GET',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n })\n\n if (!response.ok) return ''\n const { code, data } = await response.json()\n if (+code !== 0) return ''\n return data.code ?? ''\n }\n}\n\n/**\n * 获取开发者工具登录结果\n */\nexport async function queryDevToolsLoginStatus(code: string): Promise<{\n status: 'OK' | 'Wait' | 'Expired' | 'Used' | 'Error'\n ticket?: string\n}> {\n const response = await fetch(`https://q.qq.com/ide/devtoolAuth/syncScanSateGetTicket?code=${code}`, {\n method: 'GET',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n })\n\n if (!response.ok) return { status: 'Error' }\n\n // OK: { \"code\": 0, \"data\": { \"code\": \"xxx\", \"ticket\": \"xxx\", \"ok\": 1, \"uin\": \"xxx\" }, \"message\": \"\" }\n // Wait: { \"code\": 0, \"data\": { \"code\": \"xxx\" }, \"message\": \"\" }\n // Expired: { \"code\": 0, \"data\": { \"code\": \"xxx\" }, \"message\": \"\" }\n // Used: { \"code\": \"-10003\", \"message\": \"process fail\" }\n\n const { code: resCode, data } = await response.json()\n\n if (+resCode === 0) {\n if (+data.ok !== 1) return { status: 'Wait' }\n\n return {\n status: 'OK',\n ticket: data.ticket,\n }\n }\n\n if (+resCode === -10003) return { status: 'Used' }\n\n return { status: 'Error' }\n}\n\n/**\n * 通过开发者工具登录获取 AuthCode\n */\nexport async function getAuthCodeViaTicket(ticket: string, appid: number): Promise<string> {\n const response = await fetch('https://q.qq.com/ide/login', {\n method: 'POST',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ appid, ticket }),\n })\n\n if (!response.ok) return ''\n\n const { code } = await response.json()\n\n return code || ''\n}\n\n/**\n * 通过 Auth Code 获取 minico Token\n */\nexport async function getMinicoTokenViaAuthCode(authCode: string, appid: number): Promise<any> {\n const response = await fetch('https://minico.qq.com/minico/oauth20?uin=QQ%E5%AE%89%E5%85%A8%E4%B8%AD%E5%BF%83', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n appid,\n code: authCode,\n platform: 'qq',\n }),\n })\n\n if (!response.ok) return {}\n\n const { retcode, data } = await response.json()\n\n if (+retcode !== 0 || !data) return {}\n\n return data || {}\n}\n\n/**\n * 获取终端输入,返回 Promise,支持提示信息\n */\nexport async function getTerminalInput(inputTip = '请输入'): Promise<string> {\n return new Promise((resolve) => {\n if (inputTip) console.log(inputTip)\n\n function getInput() {\n process.stdin.once('data', async (e) => {\n const input = e.toString().trim()\n if (input) {\n resolve(input)\n return\n }\n getInput()\n })\n }\n getInput()\n })\n}\n\n/**\n * 当前 Node.js 进程的启动时间,常量,Date 类型\n */\nexport const START_TIME: Date = new Date()\n\n/**\n * 计算 GTK 值\n */\nexport function getGTk(pskey: string): number {\n let gkt = 5381\n for (let i = 0, len = pskey.length; i < len; ++i) {\n gkt += (gkt << 5) + pskey.charCodeAt(i)\n }\n return gkt & 0x7fffffff\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { logger } from './logger'\nimport { isNumber, unique } from './utils'\n\nimport type { LogLevel } from 'napcat-sdk'\n\n/**\n * mioki 配置\n */\nexport interface MiokiConfig {\n prefix?: string\n owners: number[]\n admins: number[]\n plugins: string[]\n error_push?: boolean\n online_push?: boolean\n log_level?: LogLevel\n plugins_dir?: string\n status_permission?: 'all' | 'admin-only'\n napcat: {\n protocol?: 'ws' | 'wss'\n port?: number\n host?: string\n token: string\n }\n}\n\n/**\n * 机器人根目录\n */\nexport const BOT_CWD: { value: string } = {\n value: process.cwd(),\n}\n\nexport function readPackageJson(): Record<'mioki' | (string & {}), any> {\n if (!fs.existsSync(path.join(BOT_CWD.value, 'package.json')))\n throw new Error(`无法在 ${BOT_CWD.value} 下找到 package.json 文件,请确认当前目录是否为机器人根目录`)\n\n return JSON.parse(fs.readFileSync(path.join(BOT_CWD.value, 'package.json'), 'utf-8')) || {}\n}\n\nexport function writePackageJson(pkg: Record<string, any>): void {\n fs.writeFileSync(path.join(BOT_CWD.value, 'package.json'), JSON.stringify(pkg, null, 2), 'utf-8')\n}\n\nexport function readMiokiConfig(): MiokiConfig {\n const config = readPackageJson().mioki\n\n if (!config) throw new Error(`无法在 package.json 中找到 mioki 配置,请确认 package.json 文件中是否包含 mioki 字段`)\n if (!config.napcat) throw new Error(`mioki 配置中缺少 napcat 字段,请补全后重试`)\n\n return readPackageJson().mioki\n}\n\n/**\n * `mioki` 框架相关配置\n */\nexport const botConfig: MiokiConfig = readMiokiConfig()\n\n/**\n * 更新 `mioki` 配置,同时同步更新本地配置文件\n */\nexport const updateBotConfig = async (draftFn: (config: MiokiConfig) => any): Promise<void> => {\n await draftFn(botConfig)\n\n botConfig.plugins = unique(botConfig.plugins).toSorted((prev, next) => prev.localeCompare(next))\n botConfig.admins = unique(botConfig.admins).toSorted((prev, next) => prev - next)\n\n const pkg = readPackageJson()\n pkg.mioki = structuredClone(botConfig)\n\n writePackageJson(pkg)\n\n logger.info(`检测到配置变动,已同步至 package.json 文件`)\n}\n\n/**\n * 更新机器人根目录\n */\nexport const updateBotCWD = (root: string): void => {\n BOT_CWD.value = root\n logger.info(`机器人根目录已设置为 ${root}`)\n}\n\n/**\n * 是否是主人\n */\nexport const isOwner = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n const owners = botConfig.owners\n\n return isNumber(id)\n ? owners.includes(id)\n : 'sender' in id\n ? owners.includes(id.sender.user_id)\n : owners.includes(id.user_id)\n}\n\n/**\n * 是否是管理员,注意: 主人不是管理员\n */\nexport const isAdmin = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n const admins = botConfig.admins\n\n return isNumber(id)\n ? admins.includes(id)\n : 'sender' in id\n ? admins.includes(id.sender.user_id)\n : admins.includes(id.user_id)\n}\n\n/**\n * 是否是主人或管理员\n */\nexport const isOwnerOrAdmin = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n return isOwner(id) || isAdmin(id)\n}\n\n/**\n * 是否有权限,即:主人或管理员\n */\nexport const hasRight = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n return isOwnerOrAdmin(id)\n}\n\n/**\n * 是否在 PM2 中运行\n */\nexport const isInPm2: boolean = Boolean('pm_id' in process.env || 'PM2_USAGE' in process.env)\n","import fs from 'node:fs'\nimport util from 'node:util'\nimport path from 'node:path'\nimport { dayjs } from './utils'\nimport { BOT_CWD, botConfig } from './config'\nimport { stripAnsi, ColorName, colors } from 'consola/utils'\nimport { createConsola, LogLevels } from 'consola/core'\n\nimport type { Logger, LogLevel } from 'napcat-sdk'\n\nconst LEVEL_MAP: Record<number, { name: string; color: ColorName }> = {\n 0: { name: 'ERROR', color: 'red' },\n 1: { name: 'WARN', color: 'yellow' },\n 2: { name: 'LOG', color: 'white' },\n 3: { name: 'INFO', color: 'green' },\n 4: { name: 'DEBUG', color: 'blue' },\n 5: { name: 'TRACE', color: 'gray' },\n}\n\nexport const logger: Logger = getMiokiLogger(botConfig.log_level || 'info')\n\n/**\n * 获取日志文件名\n */\nexport function getLogFilePath(type: string = ''): string {\n const startTime = dayjs().format('YYYY-MM-DD_HH-mm-ss')\n return path.join(BOT_CWD.value, `logs/${startTime}${type ? '.' + type : ''}.log`)\n}\n\nexport function getMiokiLogger(level: LogLevel): Logger {\n const logDir = path.join(BOT_CWD.value, 'logs')\n\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true })\n }\n\n const logFile = getLogFilePath()\n\n return createConsola({\n level: LogLevels[level],\n defaults: {\n tag: 'mioki',\n },\n reporters: [\n {\n log: (logObj) => {\n const message = stripAnsi(\n logObj.message ||\n logObj.args\n ?.map((e) => (typeof e === 'string' ? e : util.inspect(e, { colors: true, depth: null })))\n .join(' ') ||\n '',\n )\n\n const prefix = `[${logObj.date.toISOString()}] [${LEVEL_MAP[logObj.level].name}] ${logObj.tag ? `[${logObj.tag}] ` : ''}`\n const line = `${prefix}${message}`\n fs.appendFileSync(logFile, line + '\\n')\n },\n },\n {\n log: (logObj) => {\n const time = colors.gray(`[${logObj.date.toLocaleTimeString('zh-CN')}]`)\n const level = colors.bold(colors[LEVEL_MAP[logObj.level].color](LEVEL_MAP[logObj.level].name))\n const tag = logObj.tag ? colors.dim(`[${logObj.tag}] `) : ''\n\n const message =\n logObj.message ||\n logObj.args\n ?.map((e) => (typeof e === 'string' ? e : util.inspect(e, { colors: true, depth: null })))\n .join(' ') ||\n ''\n\n const line = `${time} ${level} ${tag} ${message}`\n\n if (logObj.level <= LogLevels['error']) {\n console.error(line)\n } else if (logObj.level === LogLevels['warn']) {\n console.warn(line)\n } else if (logObj.level === LogLevels['log']) {\n console.log(line)\n } else if (logObj.level === LogLevels['info']) {\n console.info(line)\n } else {\n console.debug(line)\n }\n },\n },\n ],\n formatOptions: {\n colors: true,\n compact: true,\n date: true,\n },\n })\n}\n","import crypto from 'node:crypto'\nimport { logger } from './logger'\nimport * as utils from './utils'\nimport { segment } from 'napcat-sdk'\nimport { botConfig } from './config'\n\nimport type { NapCat, Sendable } from 'napcat-sdk'\n\n/**\n * 群发群消息\n */\nexport async function noticeGroups(\n bot: NapCat,\n groupIdList: number[],\n message?: Sendable | null,\n delay = 1000,\n): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n for (const groupId of groupIdList) {\n const group = await bot.pickGroup(groupId)\n if (!group) continue\n await group.sendMsg(message)\n await utils.wait(delay)\n }\n}\n\n/**\n * 群发好友消息\n */\nexport async function noticeFriends(\n bot: NapCat,\n friendIdList: number[],\n message?: Sendable | null,\n delay = 1000,\n): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n for (const friendId of friendIdList) {\n await bot.sendPrivateMsg(friendId, message)\n await utils.wait(delay)\n }\n}\n\n/**\n * 群发通知给管理员\n */\nexport async function noticeAdmins(bot: NapCat, message?: Sendable | null, delay = 1000): Promise<void> {\n await noticeFriends(bot, botConfig.admins, message, delay)\n}\n\n/**\n * 群发通知给主人\n */\nexport async function noticeOwners(bot: NapCat, message?: Sendable | null, delay = 1000): Promise<void> {\n await noticeFriends(bot, botConfig.owners, message, delay)\n}\n\n/**\n * 群发通知给第一个主人\n */\nexport async function noticeMainOwner(bot: NapCat, message?: Sendable | null): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n const mainOwner = botConfig.owners[0]\n\n if (mainOwner) {\n await (await bot.pickFriend(mainOwner))?.sendMsg(message)\n return\n }\n\n throw new Error('请至少设置一个主人')\n}\n\n/**\n * 签名卡片 json\n */\nexport async function signArk(bot: NapCat, json: string): Promise<string> {\n const { cookie, gtk } = await bot.getCookie('qzone.qq.com')\n\n const fetchArk = (url: string) => {\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Cookie: cookie,\n },\n body: JSON.stringify({ ark: json }),\n })\n }\n\n const SignUrl = {\n normal: `https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenSignedArk?g_tk=${gtk}`,\n new: `https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=${gtk}`,\n }\n\n try {\n const { code, data = {} } = await (await fetchArk(SignUrl.normal)).json()\n if (+code === 0 && data?.signed_ark) return data.signed_ark\n throw new Error('签不了一点')\n } catch {\n const { code, data = {} } = await (await fetchArk(SignUrl.new)).json()\n if (+code === 0 && data?.signed_ark) return data.signed_ark\n throw new Error('签不了一点')\n }\n}\n\n/**\n * 运行函数并捕获错误, 并通过 event.reply 发送错误信息\n */\nexport async function runWithErrorHandler(\n bot: NapCat,\n fn: () => any,\n event?: { reply: (content: Sendable, quote?: boolean) => Promise<{ message_id: number }> },\n message: Sendable | ((error: string) => Sendable) = (err) => `报...报错了啦! 杂鱼~ 杂鱼~ \\n\\n${err}`,\n): Promise<any> {\n try {\n return await fn()\n } catch (error) {\n const errorMsg = typeof message === 'function' ? message(utils.stringifyError(error)) : message\n\n if (event) {\n await event.reply(errorMsg)\n } else {\n try {\n await noticeMainOwner(bot, '发送失败,可能被风控,请检查签名状态。')\n } catch {\n logger.error('发送失败,可能被风控,请检查签名状态。')\n }\n }\n }\n}\n\n/** 创建和并转发消息 */\nexport function createForwardMsg(\n bot: NapCat,\n message: Sendable[] = [],\n options: { user_id?: number; nickname?: string } = {},\n): Sendable {\n const { user_id = bot.uin, nickname } = options\n const content = message.map((msg) => (typeof msg === 'string' ? segment.text(msg) : msg))\n return segment.node({ user_id: String(user_id), nickname, content })\n}\n\n/**\n * 上传图片到收藏\n */\nexport async function uploadImageToCollection(bot: NapCat, buffer: ArrayBuffer): Promise<string> {\n const pskey = (await bot.getPskey('weiyun.com')) || ''\n const uuid = crypto.randomUUID()\n\n let randomID: string | number = crypto.randomInt(1, 99)\n if (randomID < 10) randomID = `0${randomID}`\n\n const options = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/octet-stream',\n Cookie: `uin=${bot.uin}; vt=27; vi=${pskey}; pid=00${randomID}/${uuid}; appid=30243`,\n 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',\n },\n body: buffer,\n }\n\n let code: number | undefined = undefined\n\n for (let i = 3; i > 0; i--) {\n const response = await fetch('https://uploader.collector.weiyun.com/pic_uploader.fcg', options)\n const headers = response.headers\n code = +(headers.get('user-returncode') || '')\n const msg = headers.get('user-errmsg')\n console.log(3 - i, 'uploadImageToCollector', response.status, code, msg)\n if (code === 0) break\n }\n\n return code === 0 ? `https://shp.qpic.cn/collector//${uuid}/0` : ''\n}\n\n/**\n * 上传图片到群作业\n */\nexport async function uploadImageToGroupHomework(bot: NapCat, imgBase64: string): Promise<string> {\n const { cookie, bkn } = await bot.getCookie('qun.qq.com')\n\n const res = await fetch('https://qun.qq.com/cgi-bin/hw/util/image', {\n method: 'POST',\n headers: {\n cookie,\n 'Content-Type': 'application/x-www-form-urlencoded',\n origin: 'https://qun.qq.com',\n referer: 'https://qun.qq.com/homework/p/features/index.html',\n },\n body: `pic=${encodeURIComponent(imgBase64)}&client_type=1&bkn=${bkn}`,\n })\n\n const data = await res.json()\n\n if (+data.retcode !== 0) return ''\n\n return data?.data?.url?.origin || ''\n}\n\n/**\n * 上传图片到群公告\n */\nexport async function uploadImageToGroupNotice(\n bot: NapCat,\n urlOrBlob: string | Blob,\n): Promise<{\n h: string\n w: string\n id: string\n url: string\n url2: string\n url3: string\n url4: string\n url5: string\n url6: string\n}> {\n const { bkn, legacyCookie } = await bot.getCookie('qun.qq.com')\n\n const blob = urlOrBlob instanceof Blob ? urlOrBlob : await (await fetch(urlOrBlob)).blob()\n const form = new FormData()\n\n form.append('m', '0')\n form.append('source', 'troopNotice')\n form.append('bkn', String(bkn))\n form.append('qid', '0')\n form.append('pic_up', blob, `image.${blob.type.split('/')[1]}`)\n\n const data = await (\n await fetch('https://web.qun.qq.com/cgi-bin/announce/upload_img', {\n method: 'POST',\n body: form,\n headers: { 'content-type': 'multipart/form-data', cookie: legacyCookie },\n })\n ).json()\n\n const { id, ec } = data || {}\n\n if (!id) {\n throw new Error(`图片上传失败,ec: ${ec}`)\n }\n\n const imgData = (JSON.parse(id.replace(/&quot;/g, '\"')) || {}) as {\n h: string\n w: string\n id: string\n }\n\n if (!imgData.id) {\n throw new Error('图片上传失败,未获取到图片 id')\n }\n\n return {\n ...imgData,\n url: `https://p.qpic.cn/gdynamic/${imgData.id}/0`,\n url2: `https://p.qlogo.cn/gdynamic/${imgData.id}/0`,\n url3: `https://p2.qpic.cn/gdynamic/${imgData.id}/0`,\n url4: `https://gdynamic.qpic.cn/gdynamic/${imgData.id}/0`,\n url5: `https://img.wecar.qq.com/gdynamic/${imgData.id}/0`,\n url6: `https://cross.store.qq.com/gdynamic/${imgData.id}/0`,\n }\n}\n\n/**\n * 获取 QQ 安全中心违规记录\n */\nexport async function getViolationRecords(\n bot: NapCat,\n authCode: string,\n appid: number,\n size = 100,\n): Promise<\n {\n type: string\n time: string\n duration: string\n reason: number\n }[]\n> {\n const minicoData = await utils.getMinicoTokenViaAuthCode(authCode, appid)\n\n if (!minicoData) return []\n\n const params = new URLSearchParams({\n ...minicoData,\n appid,\n token: minicoData.minico_token,\n })\n\n params.delete('expire')\n params.delete('minico_token')\n\n const response = await fetch(\n `https://minico.qq.com/minico/cgiproxy/v3_release/v3/getillegalityhistory?${params.toString()}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n com: {\n src: 0,\n scene: 1001,\n platform: 2,\n version: '8.9.85.12820',\n },\n pageNum: 0,\n pageSize: size,\n }),\n },\n )\n\n const { retcode, records } = await response.json()\n\n if (+retcode !== 0 || !records) return []\n\n return records || []\n}\n","import { logger } from './logger'\n\nimport type { MiokiCoreServiceContrib } from './builtins/core'\n\nexport interface MiokiServices extends Record<string, unknown>, MiokiCoreServiceContrib {}\n\nconst USER_SERVICE: MiokiServices = {} as MiokiServices\n\n/**\n * 服务,由其他插件贡献的方法、数据等\n */\nexport const services: MiokiServices = USER_SERVICE\n\n/**\n * 给 `Mioki` 添加公共服务,可用于插件间通信和共享数据\n *\n * 请注意合理设置插件的 `priority` 属性,以确保服务的正确加载顺序,`priority` 默认为 100,越小越先加载\n *\n * 建议需要调用 `addService` 的插件设置 `priority` 为 `10`\n */\nexport function addService(name: string, service: any, cover: boolean = true): () => void {\n logger.debug(`添加 mioki 服务: ${name} (覆盖: ${cover ? '是' : '否'})`)\n\n if (cover || !USER_SERVICE[name]) {\n USER_SERVICE[name] = service\n }\n\n return () => {\n logger.debug(`移除 mioki 服务: ${name}`)\n\n USER_SERVICE[name] = undefined\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport nodeCron from 'node-cron'\nimport { hrtime } from 'node:process'\nimport { colors } from 'consola/utils'\n\nimport * as utilsExports from './utils'\nimport * as configExports from './config'\nimport * as actionsExports from './actions'\nimport * as servicesExports from './services'\n\nimport type { EventMap, Logger, NapCat } from 'napcat-sdk'\nimport type { ScheduledTask, TaskContext } from 'node-cron'\nimport type { ConsolaInstance } from 'consola/core'\n\ntype Num = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n\ntype Utils = typeof utilsExports\ntype Configs = typeof configExports\ntype Actions = typeof actionsExports\ntype Services = typeof servicesExports\n\ntype StrictEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? true : false\n\n// 映射类型,用于遍历原始类型的每个键,并应用 RemoveFirstParam\ntype RemoveBotParam<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any\n ? StrictEqual<Parameters<T[K]>[0], NapCat> extends true\n ? OmitBotParamFromFunc<T[K]>\n : never\n : never\n}\n\nexport type OmitBotParamFromFunc<Func extends (bot: NapCat, ...args: any[]) => any> = Func extends (\n bot: NapCat,\n ...args: infer A\n) => infer Return\n ? (...args: A) => Return\n : never\n\nexport function bindBot<Params extends Array<any> = any[], Return = any>(\n bot: NapCat,\n func: (bot: NapCat, ...args: Params) => Return,\n): OmitBotParamFromFunc<(bot: NapCat, ...args: Params) => Return> {\n return (...args: Params): Return => func(bot, ...args)\n}\n\n/**\n * Mioki 上下文对象,包含 Mioki 运行时的信息和方法\n */\nexport interface MiokiContext extends Services, Configs, Utils, RemoveBotParam<Actions> {\n /** 机器人实例 */\n bot: NapCat\n /** 消息构造器 */\n segment: NapCat['segment']\n /** 通过域名获取 Cookies */\n getCookie: NapCat['getCookie']\n /** 注册事件处理器 */\n handle: <EventName extends keyof EventMap>(eventName: EventName, handler: (event: EventMap[EventName]) => any) => void\n /** 注册定时任务 */\n cron: (cronExpression: string, handler: (ctx: MiokiContext, task: TaskContext) => any) => ScheduledTask\n /** 待清理的函数集合,在插件卸载时会被调用 */\n clears: Set<(() => any) | null | undefined>\n /** 日志器 */\n logger: Logger\n}\n\nexport const runtimePlugins: Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n> = new Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n>()\n\nconst buildRemovedActions = (bot: NapCat) =>\n Object.fromEntries(\n Object.entries(actionsExports).map(([k, v]) => [k, bindBot(bot, v as any)]),\n ) as RemoveBotParam<Actions>\n\nexport interface MiokiPlugin {\n /** 插件 ID,请保持唯一,一般为插件目录名称,框架内部通过这个识别不同的插件 */\n name: string\n /** 插件版本,一般用于判断插件是否更新,暂只是用于区分 */\n version?: `${Num}.${Num}.${Num}` | `${Num}.${Num}` | (string & {})\n /** 插件加载优先级,默认 100,越小越被优先加载 */\n priority?: number\n /** 插件描述,额外提示信息,暂没有被使用到的地方 */\n description?: string\n /** 插件额外依赖,框架不处理,仅做参考提醒用途 */\n dependencies?: string[]\n /** 插件初始化,返回一个清理函数,用于在插件卸载时清理资源,比如定时器、数据库连接等 */\n setup?: (ctx: MiokiContext) => any\n}\n\n/**\n * 定义一个 Mioki 插件\n * @param plugin Mioki 插件对象\n * @returns Mioki 插件对象\n */\nexport function definePlugin(plugin: MiokiPlugin): MiokiPlugin {\n return plugin\n}\n\n/**\n * 确保插件目录存在\n */\nexport function ensurePluginDir(): void {\n const dir = getAbsPluginDir()\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n}\n\n/**\n * 获取插件目录的绝对路径\n */\nexport function getAbsPluginDir(defaultDir: string = 'plugins'): string {\n const cwd = configExports.BOT_CWD.value\n return path.join(cwd, configExports.botConfig.plugins_dir || defaultDir)\n}\n\nexport async function enablePlugin(\n bot: NapCat,\n plugin: MiokiPlugin,\n type: 'builtin' | 'external' = 'external',\n): Promise<MiokiPlugin> {\n const typeDesc = type === 'builtin' ? '内置' : '用户'\n const pluginName = plugin.name || 'null'\n const { name = pluginName, version = 'null', description = '-', setup = () => {} } = plugin\n\n try {\n const start = hrtime.bigint()\n const clears = new Set<() => any>()\n const userClears = new Set<(() => any) | undefined | null>()\n\n const logger = (bot.logger as ConsolaInstance).withDefaults({\n tag: `plugin:${name}`,\n args: [name],\n })\n\n const context: MiokiContext = {\n bot,\n segment: bot.segment,\n getCookie: bot.getCookie,\n ...utilsExports,\n ...configExports,\n ...buildRemovedActions(bot),\n logger,\n services: servicesExports.services,\n clears: userClears,\n addService: (name: string, service: any, cover?: boolean) => {\n const remove = servicesExports.addService(name, service, cover)\n clears.add(remove)\n return remove\n },\n handle: <EventName extends keyof EventMap>(\n eventName: EventName,\n handler: (event: EventMap[EventName]) => any,\n ) => {\n logger.debug(`Registering event handler for event: ${String(eventName)}`)\n\n bot.on(eventName, handler)\n\n const unsubscribe = () => {\n logger.debug(`Unregistering event handler for event: ${String(eventName)}`)\n bot.off(eventName, handler)\n }\n\n clears.add(unsubscribe)\n\n return unsubscribe\n },\n cron: (cronExpression, handler) => {\n logger.debug(`Scheduling cron job: ${cronExpression}`)\n const job = nodeCron.schedule(cronExpression, (now) => handler(context, now))\n\n const clear = () => {\n logger.debug(`Stopping cron job: ${cronExpression}`)\n job.stop()\n }\n\n clears.add(clear)\n return job\n },\n }\n\n clears.add((await setup(context)) || (() => {}))\n\n runtimePlugins.set(name, {\n name,\n type,\n version,\n description,\n plugin,\n disable: async () => {\n try {\n logger.debug(`Disabling plugin [${typeDesc}]${name}@${version}`)\n await Promise.all([...clears, ...userClears].map((fn) => fn?.()))\n runtimePlugins.delete(name)\n } catch (err: any) {\n throw new Error(\n `禁用插件 [${colors.yellow(typeDesc)}]${colors.yellow(`${name}@${version}`)} 失败: ${err?.message}`,\n )\n }\n },\n })\n\n const end = hrtime.bigint()\n const time = Math.round(Number(end - start)) / 1_000_000\n\n bot.logger.info(\n `- 启用插件 ${colors.yellow(`[${typeDesc}]`)} ${colors.yellow(`${name}@${version}`)} => 耗时 ${colors.green(time.toFixed(2))} 毫秒`,\n )\n } catch (e: any) {\n throw new Error(\n `启用插件 ${colors.yellow(`[${typeDesc}]`)} ${colors.yellow(`${name}@${version}`)} 失败: ${e?.message}`,\n )\n }\n\n return plugin\n}\n\nexport async function findLocalPlugins(): Promise<{ name: string; absPath: string }[]> {\n const dirents = await fs.promises.readdir(getAbsPluginDir(), { withFileTypes: true })\n\n return dirents\n .filter((e) => e.isDirectory() && !!e.name && !e.name.startsWith('_'))\n .map((e) => ({\n name: e.name,\n absPath: path.join(getAbsPluginDir(), e.name),\n }))\n}\n","import os from 'node:os'\nimport cp from 'node:child_process'\nimport pm from 'pretty-ms'\nimport { BUILTIN_PLUGINS } from '..'\nimport { filesize, localNum, systemInfo } from '../../utils'\nimport { findLocalPlugins, runtimePlugins } from '../../plugin'\nimport { version } from '../../../package.json' with { type: 'json' }\n\nimport type { NapCat } from 'napcat-sdk'\n\nexport const SystemMap: Record<string, string> = {\n Linux: 'Linux',\n Darwin: 'macOS',\n Windows_NT: 'Win',\n}\n\nexport const ArchMap: Record<string, string> = {\n ia32: 'x86',\n arm: 'arm',\n arm64: 'arm64',\n x64: 'x64',\n}\n\nexport interface MiokiStatus {\n bot: {\n uin: number\n nickname: string\n friends: number\n groups: number\n // guilds: number\n }\n plugins: {\n enabled: number\n total: number\n }\n stats: {\n uptime: number\n send: number\n receive: number\n }\n // platform: {\n // name: string\n // version: string\n // subid: string\n // }\n versions: {\n node: string\n mioki: string\n napcat: string\n protocol: string\n }\n system: {\n name: string\n version: string\n arch: string\n }\n memory: {\n used: number\n total: number\n percent: number\n rss: {\n used: number\n percent: number\n }\n }\n disk: {\n total: number\n used: number\n free: number\n percent: number\n }\n cpu: {\n name: string\n count: number\n percent: number\n }\n}\n\nexport async function getMiokiStatus(bot: NapCat): Promise<MiokiStatus> {\n const osType = os.type()\n const osArch = os.arch()\n const isInUnix = ['Linux', 'Darwin'].includes(osType)\n const arch = ArchMap[osArch] || osArch\n\n const [osInfo, localPlugins, versionInfo, friendList, groupList] = await Promise.all([\n systemInfo.osInfo(),\n findLocalPlugins(),\n bot.getVersionInfo(),\n bot.getFriendList(),\n bot.getGroupList(),\n ])\n\n const pluginCount = localPlugins.length + BUILTIN_PLUGINS.length\n\n const system = isInUnix\n ? { name: osInfo.distro, version: osInfo.release }\n : { name: SystemMap[osType] || osType, version: '-' }\n\n const totalMem = os.totalmem()\n const usedMem = totalMem - os.freemem()\n const rssMem = process.memoryUsage.rss()\n\n const nodeVersion = process.versions.node\n const cpu = getCpuInfo()\n\n return {\n bot: {\n uin: bot.uin,\n nickname: bot.nickname,\n friends: friendList.length,\n groups: groupList.length,\n // guilds: bot.guilds.size,\n },\n plugins: {\n enabled: runtimePlugins.size,\n total: pluginCount,\n },\n stats: {\n uptime: process.uptime() * 1000,\n send: bot.stat.send.group + bot.stat.send.private,\n receive: bot.stat.recv.group + bot.stat.recv.private,\n },\n versions: {\n node: nodeVersion,\n // icqq: oicqVersion,\n mioki: version,\n napcat: versionInfo.app_version,\n protocol: versionInfo.protocol_version,\n },\n system: {\n name: system.name || 'N/A',\n version: system.version || 'N/A',\n arch: arch,\n },\n memory: {\n used: usedMem,\n total: totalMem,\n percent: Number(((usedMem / totalMem) * 100).toFixed(1)),\n rss: {\n used: rssMem,\n percent: Number(((rssMem / totalMem) * 100).toFixed(1)),\n },\n },\n disk: isInUnix ? await getDiskUsageInUnix() : { total: 0, used: 0, free: 0, percent: 0 },\n cpu: {\n name: cpu.name.trim(),\n count: cpu.count,\n percent: Number((await measureCpuUsage()).toFixed(1)),\n },\n }\n}\n\nexport async function getMiokiStatusStr(client: NapCat): Promise<string> {\n const { bot, plugins, stats, system, disk, cpu, memory, versions } = await getMiokiStatus(client)\n\n const diskValid = disk.total > 0 && disk.free >= 0\n const diskDesc = `${disk.percent}%-${filesize(disk.used, { round: 1 })}/${filesize(disk.total, { round: 1 })}`\n\n return `\n👤 ${bot.nickname}\n🆔 ${bot.uin}\n📋 ${localNum(bot.friends)} 好友 / ${localNum(bot.groups)} 群\n🧩 启用了 ${localNum(plugins.enabled)} 个插件,共 ${localNum(plugins.total)} 个\n📮 收 ${localNum(stats.receive)} 条,发 ${localNum(stats.send)} 条\n🚀 ${filesize(memory.rss.used, { round: 1 })}/${memory.percent}%\n⏳ 已运行 ${pm(stats.uptime, { hideYear: true, secondsDecimalDigits: 0 })}\n🤖 mioki/${versions.mioki}-NapCat/${versions.napcat}\n🖥️ ${system.name.split(' ')[0]}/${system.version.split('.')[0]}-${system.name}-node/${versions.node.split('.')[0]}\n📊 ${memory.percent}%-${filesize(memory.used, { base: 2, round: 1 })}/${filesize(memory.total, { base: 2, round: 1 })}\n🧮 ${cpu.percent}%-${cpu.name}-${cpu.count}核\n${diskValid ? `💾 ${diskDesc}` : ''}\n `.trim()\n}\n\nasync function getDiskUsageInUnix(path = '/'): Promise<{ total: number; used: number; free: number; percent: number }> {\n return new Promise((resolve) => {\n cp.exec(`df -k ${path} | tail -1 | awk '{print $2,$4}'`, (err, stdout) => {\n if (err) {\n console.error(err)\n return resolve({ total: 0, used: 0, free: 0, percent: 0 })\n }\n\n const [_total, _free] = stdout.trim().split(' ')\n\n const total = Number(_total) * 1024\n const free = Number(_free) * 1024\n const used = total - free\n\n resolve({ total, free, used, percent: Number(((used / total) * 100).toFixed(1)) })\n })\n })\n}\n\nasync function measureCpuUsage(interval = 600): Promise<number> {\n const start = getCpuTimes()\n await new Promise((resolve) => setTimeout(resolve, interval))\n const end = getCpuTimes()\n const idleDiff = end.idle - start.idle\n const totalDiff = end.total - start.total\n const usage = 1 - idleDiff / totalDiff\n\n return usage * 100\n}\n\nfunction getCpuTimes(): { idle: number; total: number } {\n const cpus = os.cpus()\n let idle = 0\n let total = 0\n for (const cpu of cpus) {\n for (const type in cpu.times) total += cpu.times[type as never]\n idle += cpu.times.idle\n }\n return { idle, total }\n}\n\nfunction getCpuInfo() {\n const cpus = os.cpus()\n const cpu = cpus[0]\n\n return {\n name: cpu?.model || '[未知CPU]',\n count: cpus.length,\n }\n}\n","import { version } from '../../../package.json' with { type: 'json' }\nimport { getMiokiStatus, MiokiStatus, getMiokiStatusStr } from './status'\nimport { definePlugin, enablePlugin, findLocalPlugins, getAbsPluginDir, runtimePlugins } from '../..'\n\nimport type { MiokiPlugin } from '../..'\n\nconst corePlugins = ['mioki-core']\n\nexport interface MiokiCoreServiceContrib {\n /** 获取框架和系统的实时状态 */\n miokiStatus(): Promise<MiokiStatus>\n /** 获取框架和系统的实时状态字符串 */\n miokiStatusStr(): Promise<string>\n}\n\nconst core: MiokiPlugin = definePlugin({\n name: 'mioki-core',\n version,\n priority: 8,\n setup(ctx) {\n const prefix = (ctx.botConfig.prefix ?? '#').replace(/[-_.^$?[\\]{}]/g, '\\\\$&')\n\n const cmdPrefix = new RegExp(`^${prefix}`)\n const displayPrefix = prefix.replace(/\\\\\\\\/g, '\\\\')\n const statusAdminOnly = ctx.botConfig.status_permission === 'admin-only'\n\n const getStatusStr = () =>\n ctx.isFunction(ctx.services.customMiokiStatusStr)\n ? ctx.services.customMiokiStatusStr()\n : getMiokiStatusStr(ctx.bot)\n\n ctx.addService('miokiStatus', () => getMiokiStatus(ctx.bot))\n ctx.addService('miokiStatusStr', () => getMiokiStatusStr(ctx.bot))\n\n ctx.handle('message', (e) =>\n ctx.runWithErrorHandler(async () => {\n const text = ctx.text(e)\n\n if (!cmdPrefix.test(text)) return\n\n if (statusAdminOnly && !ctx.hasRight(e)) return\n\n if (text.replace(cmdPrefix, '') === '状态') {\n const status = await getStatusStr()\n await e.reply(`〓 🟢 mioki 状态 〓\\n${status}`.trim())\n return\n }\n\n if (!ctx.isOwner(e)) return\n\n const { cmd, params, ..._options } = ctx.createCmd(text)\n\n if (!cmd) return\n\n const [subCmd, target, ..._subParams] = params\n\n switch (cmd?.replace(/\\s+/g, '')) {\n case '帮助': {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 💡 mioki 帮助 〓\n ${displayPrefix}插件 👉 框架插件管理\n ${displayPrefix}状态 👉 显示框架状态\n ${displayPrefix}设置 👉 框架设置管理\n ${displayPrefix}帮助 👉 显示帮助信息\n ${displayPrefix}退出 👉 退出框架进程\n `,\n )\n .trim(),\n )\n break\n }\n\n case '插件': {\n if (corePlugins.includes(target)) {\n await e.reply('内置插件无法操作', true)\n return\n }\n\n switch (subCmd) {\n case '列表': {\n const localPlugins = await findLocalPlugins()\n\n const plugins = ctx\n .unique([...localPlugins.map((e) => e.name), ...runtimePlugins.keys()])\n .map((name) => {\n const isEnable = runtimePlugins.get(name)\n const tag = isEnable ? '🟢' : '🔴'\n const type = isEnable && isEnable?.type === 'builtin' ? '[内置]' : '[用户]'\n return `${tag} ${type} ${name}`\n })\n .toSorted((pre, next) => {\n function weight(str: string) {\n let w = 0\n if (str.includes('🟢')) w += 10\n if (str.includes('[内置]')) w += 1\n return w\n }\n\n const preWeight = weight(pre)\n const nextWeight = weight(next)\n\n return nextWeight - preWeight || pre.localeCompare(next)\n })\n\n await e.reply(\n ctx\n .dedent(\n `\n 〓 插件列表 〓\n ${plugins.join('\\n')}\n 共 ${plugins.length} 个,启用 ${runtimePlugins.size} 个\n `,\n )\n .trim(),\n )\n\n break\n }\n case '启用': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n if (runtimePlugins.has(target)) {\n await e.reply(`插件 ${target} 已经是启用状态`, true)\n return\n }\n\n const pluginPath = ctx.path.join(getAbsPluginDir(), target)\n\n if (!ctx.fs.existsSync(pluginPath)) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n try {\n const plugin = (await ctx.jiti.import(pluginPath, { default: true })) as MiokiPlugin\n\n if (plugin.name !== target) {\n const tip = `[插件目录名称: ${target}] 和插件代码中设置的 [name: ${plugin.name}] 不一致,可能导致重载异常,请修改后重启。`\n ctx.bot.logger.warn(tip)\n ctx.noticeMainOwner(tip)\n }\n\n await enablePlugin(ctx.bot, plugin)\n } catch (err: any) {\n await e.reply(`插件 ${target} 启用失败:${err?.message || '未知错误'}`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = [...ctx.botConfig.plugins, target]))\n\n await e.reply(`插件 ${target} 启用成功`, true)\n\n break\n }\n\n case '禁用': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n const plugin = runtimePlugins.get(target)\n\n if (!plugin) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n try {\n await plugin.disable()\n } catch (err: any) {\n await e.reply(err?.message, true)\n break\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = ctx.botConfig.plugins.filter((name) => name !== target)))\n\n ctx.bot.logger.info(`禁用插件 => ${target}`)\n\n await e.reply(`插件 ${target} 已禁用`, true)\n\n break\n }\n\n case '重载': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n let isOff = false\n const plugin = runtimePlugins.get(target)\n\n try {\n if (plugin) {\n await plugin.disable()\n }\n\n const pluginPath = ctx.path.join(getAbsPluginDir(), target)\n\n if (!ctx.fs.existsSync(pluginPath)) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n if (!plugin) {\n isOff = true\n // await e.reply(`插件 ${target} 还未启用,尝试直接启用...`, true)\n }\n\n const importedPlugin = (await ctx.jiti.import(pluginPath, { default: true })) as MiokiPlugin\n\n if (importedPlugin.name !== target) {\n const tip = `插件目录名称: ${target} 和插件代码中设置的 name: ${importedPlugin.name} 不一致,可能导致重载异常,请修改后重启。`\n ctx.bot.logger.warn(tip)\n ctx.noticeMainOwner(tip)\n }\n\n await enablePlugin(ctx.bot, importedPlugin)\n } catch (err: any) {\n await e.reply(err?.message, true)\n await ctx.updateBotConfig((c) => (c.plugins = c.plugins.filter((name) => name !== target)))\n break\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = [...c.plugins, target]))\n\n await e.reply(`插件 ${target} 已${isOff ? '直接启用' : '重载'}`, true)\n\n break\n }\n default: {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 🧩 mioki 插件 〓\n ${displayPrefix}插件 列表\n ${displayPrefix}插件 启用 <插件 ID>\n ${displayPrefix}插件 禁用 <插件 ID>\n ${displayPrefix}插件 重载 <插件 ID>\n `,\n )\n .trim(),\n )\n break\n }\n }\n break\n }\n\n case '设置': {\n switch (subCmd) {\n case '详情': {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 设置详情 〓\n 主人: ${ctx.botConfig.owners.join(', ')}\n 管理: ${ctx.botConfig.admins.join(', ').trim()}\n 启用插件: ${ctx.botConfig.plugins.join(', ').trim()}\n `,\n )\n .trim(),\n )\n break\n }\n\n case '加主人':\n case '添加主人': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定主人 QQ/AT', true)\n return\n }\n\n if (ctx.botConfig.owners.includes(uid)) {\n await e.reply(`主人 ${uid} 已存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.owners = [...c.owners, uid]))\n\n await e.reply(`已添加主人 ${uid}`, true)\n\n break\n }\n\n case '删主人':\n case '删除主人': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定主人 QQ/AT', true)\n return\n }\n\n if (uid === ctx.botConfig.admins[0]) {\n await e.reply('不能删除第一主人', true)\n return\n }\n\n const idx = ctx.botConfig.owners.indexOf(uid)\n\n if (idx === -1) {\n await e.reply(`主人 ${uid} 不存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => c.owners.splice(idx, 1))\n\n await e.reply(`已删除主人 ${uid}`, true)\n\n break\n }\n case '加管理':\n case '添加管理': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定管理 QQ/AT', true)\n return\n }\n\n if (ctx.botConfig.admins.includes(uid)) {\n await e.reply(`管理 ${uid} 已存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.admins = [...c.admins, uid]))\n\n await e.reply(`已添加管理 ${uid}`, true)\n\n break\n }\n case '删管理':\n case '删除管理': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定管理 QQ/AT', true)\n return\n }\n\n const idx = ctx.botConfig.admins.indexOf(uid)\n\n if (idx === -1) {\n await e.reply(`管理 ${uid} 不存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => c.admins.splice(idx, 1))\n\n await e.reply(`已删除管理 ${uid}`, true)\n\n break\n }\n default: {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 ⚙️ mioki 设置 〓\n ${displayPrefix}设置 详情\n ${displayPrefix}设置 [加/删]主人 <QQ/AT>\n ${displayPrefix}设置 [加/删]管理 <QQ/AT>\n `,\n )\n .trim(),\n )\n break\n }\n }\n break\n }\n\n case '退出': {\n await e.reply('またね~', true)\n ctx.bot.logger.info('接收到退出指令,即将退出... 如需自动重启,请使用 pm2 部署。')\n process.exit(0)\n }\n }\n }, e),\n )\n },\n})\n\nexport default core\n","import core from './core'\n\nimport type { MiokiPlugin } from '../plugin'\n\nexport const BUILTIN_PLUGINS: MiokiPlugin[] = [core]\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { hrtime } from 'node:process'\nimport * as cfg from './config'\nimport { NapCat } from 'napcat-sdk'\nimport { version } from '../package.json'\nimport * as utils from './utils'\nimport * as actions from './actions'\nimport { logger } from './logger'\nimport { colors } from 'consola/utils'\nimport { BUILTIN_PLUGINS } from './builtins'\nimport { enablePlugin, ensurePluginDir, getAbsPluginDir, runtimePlugins } from './plugin'\n\nimport type { MiokiPlugin } from './plugin'\nexport interface StartOptions {\n cwd?: string\n}\n\nexport async function start(options: StartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options\n\n if (cwd !== cfg.BOT_CWD.value) {\n cfg.updateBotCWD(path.resolve(cwd))\n }\n\n process.title = `mioki v${version}`\n\n const plugin_dir = getAbsPluginDir()\n\n logger.info(colors.dim('='.repeat(40)))\n logger.info(`欢迎使用 ${colors.bold(colors.redBright('mioki'))} 💓 ${colors.bold(colors.cyan(`v${version}`))}`)\n logger.info(colors.yellow(colors.underline(`一个基于 NapCat 的插件式 QQ 机器人框架`)))\n logger.info(colors.cyan(`轻量 * 跨平台 * 插件式 * 热重载 * 注重开发体验`))\n logger.info(colors.dim('='.repeat(40)))\n logger.info(colors.dim(colors.italic(`作者: Viki <hi@viki.moe> (https://github.com/vikiboss)`)))\n logger.info(colors.dim(colors.italic(`仓库: https://github.com/vikiboss/mioki`)))\n logger.info(colors.dim(colors.italic(`文档: https://mioki.viki.moe`)))\n logger.info(colors.dim('='.repeat(40)))\n logger.info(`${colors.dim('工作目录: ')}${colors.blue(cfg.BOT_CWD.value)}`)\n logger.info(`${colors.dim('插件目录: ')}${colors.blue(plugin_dir)}`)\n logger.info(`${colors.dim('配置文件: ')}${colors.blue(`${cfg.BOT_CWD.value}/package.json`)}`)\n logger.info(colors.dim('='.repeat(40)))\n\n const { protocol = 'ws', port = 3001, host = 'localhost', token = '' } = cfg.botConfig.napcat || {}\n const wsUrl = colors.green(`${protocol}://${host}:${port}${token ? '?access_token=***' : ''}`)\n\n logger.info(`>>> 正在连接 NapCat 实例: ${wsUrl}`)\n\n const napcat = new NapCat({ token, protocol, host, port, logger })\n\n napcat.on('ws.close', () => {\n logger.error('WS 连接失败,请确保 token 配置正确且 NapCat 实例正常运行')\n process.exit(1)\n })\n\n napcat.on('napcat.connected', async ({ user_id, nickname, app_name, app_version }) => {\n logger.info(`已连接到 NapCat 实例: ${colors.green(`${app_name}-v${app_version} ${nickname}(${user_id})`)}`)\n\n process.title = `mioki v${version} ${app_name}-v${app_version}-${user_id}`\n\n let lastNoticeTime = 0\n\n process.on('uncaughtException', async (err: any) => {\n const msg = utils.stringifyError(err)\n napcat.logger.error(`uncaughtException, 出错了: ${msg}`)\n\n if (cfg.botConfig.error_push) {\n if (Date.now() - lastNoticeTime < 1_000) return\n lastNoticeTime = Date.now()\n await actions.noticeMainOwner(napcat, `mioki 发生未捕获异常:\\n\\n${msg}`).catch(() => {\n napcat.logger.error('发送未捕获异常通知失败')\n })\n }\n })\n\n process.on('unhandledRejection', async (err: any) => {\n const msg = utils.stringifyError(err)\n napcat.logger.error(`unhandledRejection, 出错了: ${msg}`)\n\n if (cfg.botConfig.error_push) {\n if (Date.now() - lastNoticeTime < 1_000) return\n lastNoticeTime = Date.now()\n const date = new Date().toLocaleString()\n\n await actions.noticeMainOwner(napcat, `【${date}】\\n\\nmioki 发生未处理异常:\\n\\n${msg}`).catch(() => {\n napcat.logger.error('发送未处理异常通知失败')\n })\n }\n })\n\n ensurePluginDir()\n\n const plugins = cfg.botConfig.plugins\n .map((p) => ({ dirName: p, absPath: path.resolve(plugin_dir, p) }))\n .filter((p) => {\n if (!fs.existsSync(p.absPath)) {\n napcat.logger.warn(`插件 ${colors.red(p.dirName)} 不存在,已忽略`)\n return false\n }\n\n return true\n })\n\n const failedImportPlugins: [string, string][] = []\n\n const promises = plugins.map(async ({ absPath, dirName }) => {\n try {\n const plugin = (await utils.jiti.import(absPath, { default: true })) as MiokiPlugin\n\n if (plugin.name !== dirName) {\n const tip = `插件目录名 [${colors.yellow(dirName)}] 和插件声明的 name [${colors.yellow(plugin.name)}] 不一致,可能导致重载异常,请修改一致后重启。`\n napcat.logger.warn(tip)\n actions.noticeMainOwner(napcat, tip)\n }\n return plugin\n } catch (e) {\n const err = utils.stringifyError(e)\n failedImportPlugins.push([dirName, err])\n return null\n }\n })\n\n const start = hrtime.bigint()\n const userPlugins = (await Promise.all(promises)).filter(Boolean) as MiokiPlugin[]\n const sortedUserPlugins = userPlugins.toSorted((prev, next) => (prev.priority ?? 100) - (next.priority ?? 100))\n\n if (failedImportPlugins.length) {\n const tip = `${colors.red(failedImportPlugins.length)} 个插件加载失败: \\n\\n${failedImportPlugins.map(([dirName, err]) => `${dirName}: ${err}`).join('\\n\\n')}`\n napcat.logger.warn(tip)\n actions.noticeMainOwner(napcat, tip)\n }\n\n // 按 priority 分组\n const pluginGroups = new Map<number, MiokiPlugin[]>()\n for (const plugin of sortedUserPlugins) {\n const priority = plugin.priority ?? 100\n if (!pluginGroups.has(priority)) {\n pluginGroups.set(priority, [])\n }\n pluginGroups.get(priority)!.push(plugin)\n }\n\n // 按 priority 排序分组\n const sortedGroups = Array.from(pluginGroups.entries()).toSorted(([a], [b]) => a - b)\n\n const failedEnablePlugins: [string, string][] = []\n\n try {\n // 加载内置插件\n napcat.logger.info(`>>> 加载内置插件: ${BUILTIN_PLUGINS.map((p) => colors.cyan(p.name)).join(', ')}`)\n await Promise.all(BUILTIN_PLUGINS.map((p) => enablePlugin(napcat, p, 'builtin')))\n\n // 按优先级分组并行加载用户插件,相同优先级的插件可以并行加载\n napcat.logger.info(\n `>>> 加载用户插件: ${sortedGroups.map(([priority, plugins]) => `优先级 ${colors.yellow(priority)} (${plugins.map((p) => colors.cyan(p.name)).join(', ')})`).join(',')}`,\n )\n for (const [_, plugins] of sortedGroups) {\n await Promise.all(\n plugins.map(async (p) => {\n try {\n await enablePlugin(napcat, p, 'external')\n } catch (e) {\n failedEnablePlugins.push([p.name, utils.stringifyError(e)])\n }\n }),\n )\n }\n } catch (e: any) {\n napcat.logger.error(e?.message)\n await actions.noticeMainOwner(napcat, e?.message).catch(() => {\n napcat.logger.error('发送插件启用失败通知失败')\n })\n }\n\n const end = hrtime.bigint()\n const costTime = Math.round(Number(end - start)) / 1_000_000\n const failedCount = failedImportPlugins.length + failedEnablePlugins.length\n\n const failedInfo =\n failedCount > 0\n ? `${colors.red(failedCount)} 个失败 (导入 ${colors.red(failedImportPlugins.length)},启用 ${colors.red(failedEnablePlugins.length)})`\n : ''\n\n napcat.logger.info(\n `成功加载了 ${colors.green(runtimePlugins.size)} 个插件,${failedInfo ? failedInfo : ''}总耗时 ${colors.green(costTime.toFixed(2))} 毫秒`,\n )\n\n napcat.logger.info(\n colors.green(\n `mioki v${version} 启动完成,向机器人发送「${colors.magentaBright(`${cfg.botConfig.prefix}帮助`)}」查看消息指令`,\n ),\n )\n\n if (cfg.botConfig.online_push) {\n await actions.noticeMainOwner(napcat, `✅ mioki v${version} 已就绪`).catch((err) => {\n napcat.logger.error(`发送就绪通知失败: ${utils.stringifyError(err)}`)\n })\n }\n })\n\n await napcat.run()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["jiti: Jiti","Low","DataFile","segment","text","matches: RegExpMatchArray | null","__dirname","path","crypto","selected: number[]","start","cacheMsg","result: string","code","START_TIME: Date","BOT_CWD: { value: string }","fs","path","botConfig: MiokiConfig","isInPm2: boolean","LEVEL_MAP: Record<number, { name: string; color: ColorName }>","logger: Logger","path","fs","LogLevels","util","colors","utils.wait","utils.stringifyError","segment","uuid","crypto","randomID: string | number","code: number | undefined","utils.getMinicoTokenViaAuthCode","USER_SERVICE: MiokiServices","services: MiokiServices","runtimePlugins: Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n>","actionsExports","fs","path","start","hrtime","logger","context: MiokiContext","utilsExports","configExports","servicesExports.services","servicesExports.addService","name","nodeCron","version","err: any","colors","e: any","SystemMap: Record<string, string>","ArchMap: Record<string, string>","os","systemInfo","version","path","start","core: MiokiPlugin","text","e","err: any","BUILTIN_PLUGINS: MiokiPlugin[]","core","path","version","colors","NapCat","utils.stringifyError","actions.noticeMainOwner","fs","failedImportPlugins: [string, string][]","start","hrtime","failedEnablePlugins: [string, string][]","plugins","e: any"],"sources":["../src/utils.ts","../src/config.ts","../src/logger.ts","../src/actions.ts","../src/services.ts","../src/plugin.ts","../src/builtins/core/status.ts","../src/builtins/core/index.ts","../src/builtins/index.ts","../src/start.ts"],"sourcesContent":["import mri from 'mri'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\nimport { Low } from 'lowdb'\nimport { DataFile } from 'lowdb/node'\nimport { createJiti, type Jiti } from 'jiti'\nimport { string2argv } from 'string2argv'\nimport { fileURLToPath } from 'node:url'\nimport { segment } from 'napcat-sdk'\n\nexport { default as prettyMs } from 'pretty-ms'\n\nimport type { BinaryLike, BinaryToTextEncoding } from 'node:crypto'\nimport type {\n MessageEvent,\n GroupMessageEvent,\n Sendable,\n PrivateMessageEvent,\n RecvElement,\n RecvImageElement,\n} from 'napcat-sdk'\n\nexport { filesize } from 'filesize'\nexport { string2argv } from 'string2argv'\nexport { default as fs } from 'node:fs'\nexport { default as mri } from 'mri'\nexport { default as path } from 'node:path'\nexport { default as dayjs } from 'dayjs'\nexport { default as dedent } from 'dedent'\nexport { colors, stripAnsi, box, colorize } from 'consola/utils'\nexport { default as systemInfo } from 'systeminformation'\n\nexport const ChromeUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0'\n\nexport type Noop = () => void\nexport type AnyFunc = (...args: any[]) => any\nexport type PureObject<T = any> = Record<PropertyKey, T>\nexport type Arrayable<T> = T | T[]\nexport type Gettable<T> = T | (() => T)\nexport type HasMessage = { message: RecvElement[] } | RecvElement[]\n\n/**\n * Jiti 实例\n */\nexport const jiti: Jiti = createJiti(__dirname, {\n extensions: ['.ts', '.js', '.cts', '.cjs', '.mts', '.mjs', '.tsx', '.jsx', '.json'],\n\n cache: false,\n fsCache: false,\n moduleCache: false,\n requireCache: false,\n\n sourceMaps: false,\n interopDefault: true,\n\n jsx: {\n importSource: 'react',\n runtime: 'automatic',\n },\n})\n\nexport interface CreateCmdOptions {\n prefix?: string\n onPrefix?(): void\n}\n\n/**\n * 解析命令字符串,返回命令和参数\n */\nexport function createCmd(\n cmdStr: string,\n options: CreateCmdOptions = {},\n): {\n cmd: string | undefined\n params: string[]\n options: Record<string, any>\n} {\n const { prefix = '', onPrefix = () => {} } = options\n const { _, ...cmdOptions } = mri(string2argv(cmdStr))\n const [cmd, ...params] = _\n\n if (prefix) {\n if (cmd !== prefix) {\n return {\n cmd: undefined,\n params: [],\n options: cmdOptions,\n }\n }\n\n if (params.length === 0) {\n onPrefix()\n }\n\n const prefixedCmd = params.shift()\n\n return {\n cmd: prefixedCmd,\n params,\n options: cmdOptions,\n }\n }\n\n return {\n cmd,\n params,\n options: cmdOptions,\n }\n}\n\n/**\n * 带有表情反应的函数执行包装器\n */\nexport async function runWithReaction<T extends AnyFunc>(\n e: GroupMessageEvent,\n fn: T,\n id = '60',\n): Promise<ReturnType<T>> {\n await e.addReaction(id)\n const result = (await fn()) as ReturnType<T>\n await e.delReaction(id)\n return result\n}\n\n/**\n * 创建一个 LowDB 数据库实例\n */\nexport async function createDB<T extends object = object>(\n filename: string,\n options: {\n defaultData?: T\n compress?: boolean\n } = {},\n): Promise<Low<T>> {\n const { defaultData = {} as T, compress = false } = options\n\n const database = new Low<T>(\n new DataFile<T>(filename, {\n parse: JSON.parse,\n stringify: (data) => JSON.stringify(data, null, compress ? 0 : 2),\n }),\n defaultData,\n )\n\n await database.read()\n\n return database\n}\n\n/**\n * 确保返回一个可用的图片元素\n *\n * @param buffer 图片缓冲区\n * @param text 文本\n * @returns 图片元素\n */\nexport function ensureBuffer(buffer?: Buffer | null | undefined, text?: null): null\nexport function ensureBuffer(buffer?: Buffer | null | undefined, text?: string): Sendable\nexport function ensureBuffer(\n buffer?: Buffer | null | undefined,\n text: string | null = '图片渲染失败',\n): Sendable | null {\n return buffer ? segment.image(`data:image/png;base64,${buffer.toString('base64')}`) : text\n}\n\n/**\n * 格式化时间间隔为可读字符串\n *\n * @param ms 时间间隔(毫秒)\n * @returns 可读字符串\n */\nexport function formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000)\n const minutes = Math.floor(seconds / 60)\n const hours = Math.floor(minutes / 60)\n const days = Math.floor(hours / 24)\n\n if (days > 0) return `${days}天${hours % 24}小时`\n if (hours > 0) return `${hours}小时${minutes % 60}分钟`\n if (minutes > 0) return `${minutes}分钟${seconds % 60}秒`\n return `${seconds}秒`\n}\n\ntype MatchPatternItem = null | undefined | void | false | Sendable | Sendable[]\ntype MatchValue<E extends MessageEvent> =\n | MatchPatternItem\n | ((matches: RegExpMatchArray, event: E) => MatchPatternItem)\n | ((matches: RegExpMatchArray, event: E) => Promise<MatchPatternItem>)\n/**\n * 匹配输入文本与匹配模式,如果匹配成功,则回复匹配结果\n *\n * 支持:\n * - 精确匹配\n * - 正则表达式匹配(以 `/` 开头和结尾的字符串)\n * - 通配符匹配(使用 `*` 作为通配符)\n *\n * @param event 消息事件\n * @param pattern 匹配模式\n * @param quote 是否引用回复\n * @returns 匹配结果\n */\nexport async function match<E extends MessageEvent>(\n event: E,\n pattern: Record<string, MatchValue<E>>,\n quote: boolean = true,\n): Promise<{ message_id: number } | null> {\n const inputText = text(event)\n\n async function handleMatch(key: string, value: MatchValue<E>) {\n let isMatched = false\n let matches: RegExpMatchArray | null = null\n\n const isRegExpLikeString = key.match(/^\\/.+\\/$/)\n const hasWildcard = key.includes('*')\n\n if (isRegExpLikeString) {\n try {\n const regex = new RegExp(key.slice(1, -1))\n const matchesValue = inputText.match(regex)\n\n if (matchesValue) {\n isMatched = true\n matches = matchesValue\n }\n } catch (err) {\n throw new Error(`无效的正则表达式: ${key}`, { cause: err })\n }\n } else if (hasWildcard) {\n const regexPattern = `^${key.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*')}$`\n const regex = new RegExp(regexPattern)\n const matchesValue = inputText.match(regex)\n\n if (matchesValue) {\n isMatched = true\n matches = matchesValue\n }\n } else if (key === inputText) {\n isMatched = true\n }\n\n if (isMatched) {\n return typeof value === 'function' ? await value(matches as RegExpMatchArray, event) : value\n }\n }\n\n for (const [key, value] of Object.entries(pattern)) {\n const result = await handleMatch(key, value)\n\n if (result) {\n return event.reply(result, quote)\n }\n }\n\n return null\n}\n\n/**\n * 创建一个持久化数据库,基于 createDB 封装\n */\nexport async function createStore<T extends object = object>(\n defaultData: T,\n options?: {\n __dirname?: string\n importMeta?: ImportMeta\n compress?: boolean\n filename?: string\n },\n): Promise<Low<T>> {\n const { compress = false, __dirname, importMeta: meta, filename = 'data.json' } = options || {}\n const dirname = __dirname || meta?.dirname || (meta?.url ? path.dirname(fileURLToPath(meta.url)) : '')\n\n if (!dirname) {\n throw new Error('createStore: options.__dirname or options.meta must be provided')\n }\n\n const filePath = path.join(dirname, filename)\n\n const database = new Low<T>(\n new DataFile<T>(filePath, {\n parse: JSON.parse,\n stringify: (data) => JSON.stringify(data, null, compress ? 0 : 2),\n }),\n defaultData,\n )\n\n await database.read()\n await database.write()\n\n return database\n}\n\n/**\n * MD5 加密\n */\nexport function md5(text: BinaryLike, encoding: 'buffer'): Buffer\nexport function md5(text: BinaryLike, encoding?: BinaryToTextEncoding): string\nexport function md5(text: BinaryLike, encoding: BinaryToTextEncoding | 'buffer' = 'hex'): string | Buffer {\n const hash = crypto.createHash('md5').update(text)\n\n if (encoding === 'buffer') {\n return hash.digest()\n }\n\n return hash.digest(encoding)\n}\n\n/**\n * 数组去重\n */\nexport function unique<T>(array: T[]): T[] {\n return Array.from(new Set(array))\n}\n\n/**\n * 确保值为数组\n *\n */\nexport function toArray<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n\n/**\n * 是否是群消息\n */\nexport const isGroupMsg = (event: MessageEvent): event is GroupMessageEvent => {\n return 'group' in event\n}\n\n/**\n * 是否是私聊消息\n */\nexport const isPrivateMsg = (event: MessageEvent): event is PrivateMessageEvent => {\n return !isGroupMsg(event)\n}\n\n/**\n * 异步延时函数\n *\n * @param {number} ms 等待毫秒数\n * @return {Promise<void>}\n */\nexport async function wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\ninterface FormatOptions {\n locale?: string\n timeZone?: string\n}\n\n/**\n * 获取今天的固定日期字符串,可用来作为「稳定随机」的参数,用于签到、每日任务等场景\n *\n * 格式: 2024/12/12,可选控制时区,默认为 'Asia/Shanghai' (亚洲/上海 时区)\n *\n * @param timeZone 指定的时区,默认为 'Asia/Shanghai'\n * @returns 返回当前日期的字符串格式\n */\nexport function localeDate(ts: number | string | Date = Date.now(), options: FormatOptions = {}): string {\n const { locale = 'zh-CN', timeZone = 'Asia/Shanghai' } = options\n const today = ts instanceof Date ? ts : new Date(ts)\n\n const formatter = new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n timeZone,\n })\n\n return formatter.format(today)\n}\n\n/**\n * 获取当前时间的固定时间字符串\n */\nexport function localeTime(\n ts: number | string | Date = Date.now(),\n options: FormatOptions & { seconds?: boolean } = {},\n): string {\n const { locale = 'zh-CN', timeZone = 'Asia/Shanghai', seconds = true } = options\n const now = ts instanceof Date ? ts : new Date(ts)\n\n const formatter = new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n hourCycle: 'h23',\n minute: '2-digit',\n second: seconds ? '2-digit' : undefined,\n timeZone,\n })\n\n return formatter.format(now)\n}\n\n/**\n * 生成指定范围(min ~ max)内的随机整数\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机数相同\n */\nexport function randomInt(min: number, max: number, ...hashArgs: any[]): number {\n if (min > max) throw new Error('min must be less than or equal to max')\n\n if (hashArgs.length === 0) {\n return Math.floor(Math.random() * (max - min + 1)) + min\n }\n\n const sortedArgs = hashArgs.slice().sort((a, b) => {\n if (typeof a === 'number' && typeof b === 'number') return a - b\n return JSON.stringify(a).localeCompare(JSON.stringify(b))\n })\n\n const hash = md5(JSON.stringify(sortedArgs))\n const hashValue = Number.parseInt(hash.slice(0, 8), 16)\n\n const range = max - min + 1\n return (((hashValue % range) + range) % range) + min\n}\n\n/**\n * 取数组内随机一项\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机项\n */\nexport function randomItem<T = any>(array: readonly T[], ...hashArgs: any[]): T {\n if (!Array.isArray(array) || !array.length) throw new Error('randomItem: 参数必须是数组,且不能为空')\n return array[randomInt(0, array.length - 1, ...hashArgs)]\n}\n\n/**\n * 从数组中随机选出指定数量的项(不重复)\n *\n * 额外支持「稳定随机」,继续传入额外参数即可,如果额外参数相同(忽略顺序),则生成的随机项相同\n *\n * @param array 源数组\n * @param count 要选择的项数量\n * @param hashArgs 稳定随机的额外参数\n * @returns 随机选出的项组成的数组\n */\nexport function randomItems<T = any>(array: readonly T[], count: number, ...hashArgs: any[]): T[] {\n if (!Array.isArray(array) || !array.length) throw new Error('randomItems: 参数必须是数组,且不能为空')\n if (count < 0) throw new Error('randomItems: count 必须为非负整数')\n if (count === 0) return []\n if (count > array.length) throw new Error(`randomItems: 要选择的数量 (${count}) 超过了数组长度 (${array.length})`)\n if (count === array.length) return [...array]\n\n const indices = Array.from({ length: array.length }, (_, i) => i)\n const selected: number[] = []\n\n for (let i = 0; i < count; i++) {\n const remainingCount = indices.length - i\n const randomIdx = randomInt(0, remainingCount - 1, ...hashArgs, `select_${i}`)\n selected.push(indices[randomIdx])\n const lastIdx = indices.length - 1 - i\n ;[indices[randomIdx], indices[lastIdx]] = [indices[lastIdx], indices[randomIdx]]\n }\n\n const hasString = array.some(isString)\n const items = selected.map((idx) => array[idx])\n\n return hasString ? items.sort((p, n) => (isString(p) && isString(n) ? p.localeCompare(n) : 0)) : items\n}\n\n/**\n * 包含大写字母与数字的 6 位随机 ID 生成器\n */\nexport function randomId(): string {\n return Math.random().toString(16).slice(2, 8).toUpperCase()\n}\n\n/**\n * 简单生成符合 UUID 规范的字符串,但不保证唯一性\n */\nexport function uuid() {\n return `${randStr(8)}-${randStr(4)}-${randStr(4)}-${randStr(4)}-${randStr(12)}`\n\n function randStr(length = 4) {\n return Math.random()\n .toString(16)\n .substring(2, length + 2)\n }\n}\n\n/**\n * clamp 操作,限制数值在指定范围内\n */\nexport function clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n))\n}\n\n/**\n * 排除 null 和 undefined\n */\nexport function noNullish<T>(val: T | null): val is T {\n return val !== null && val !== undefined\n}\n\n/**\n * 判断是否定义\n */\nexport function isDefined<T = unknown>(val?: T): val is T {\n return typeof val !== 'undefined'\n}\n\n/**\n * 通过消息事件生成唯一 id\n */\nexport function toMsgId(event: { seq: number; rand: number }) {\n return `${event.seq}_${event.rand}`\n}\n\n/**\n * 判断是否为函数\n */\nexport function isFunction<T extends AnyFunc>(val: unknown): val is T {\n return typeof val === 'function'\n}\n\n/**\n * 判断是否为数字\n */\nexport function isNumber(val: unknown): val is number {\n return typeof val === 'number'\n}\n\n/**\n * 判断是否为布尔值\n */\nexport function isBoolean(val: unknown): val is boolean {\n return typeof val === 'boolean'\n}\n\n/**\n * 判断是否为字符串\n */\nexport function isString(val: unknown): val is string {\n return typeof val === 'string'\n}\n\n/**\n * 判断是否为对象\n */\nexport function isObject(val: unknown): val is object {\n return Object.prototype.toString.call(val) === '[object Object]'\n}\n\n/**\n * 将数字转换为本地化数字字符串\n */\nexport function localNum(num: number, locale = 'zh-CN'): string {\n return num.toLocaleString(locale)\n}\n\n/**\n * 通过 QQ 号获取任意头像链接\n *\n * size 可选: 0 | 40 | 100 | 160 | 640,0 为原图\n */\nexport function getQQAvatarLink(qq: number, size = 640) {\n return `https://q.qlogo.cn/headimg_dl?dst_uin=${qq}&spec=${size}`\n}\n\n/**\n * 通过群号获取任意群头像链接\n *\n * size 可选: 40 | 100 | 640,0 为原图\n */\nexport function getGroupAvatarLink(group: number, size = 640) {\n // return `https://p.qlogo.cn/gh/${group}/${group}/${size}`\n return `https://p.qlogo.cn/gh/111111/${group}/${size}`\n}\n\nconst messageCacheMap = new Map<string, GroupMessageEvent | PrivateMessageEvent | 'loading' | null>()\n\n/** 获取引用回复的消息 */\nexport async function getQuoteMsg(\n event: MessageEvent,\n timeout = 3_000,\n): Promise<GroupMessageEvent | PrivateMessageEvent | null> {\n if (!event.quote_id) return null\n\n const quote_id = event.quote_id\n\n // 生成唯一 key\n const key = isGroupMsg(event) ? `${event.group_id}_${quote_id}` : `${event.sender.user_id}_${quote_id}`\n const cacheMsg = messageCacheMap.get(key)\n // 是否正在获取\n const isFetching = cacheMsg === 'loading'\n // 是否获取结束(已经获取过)\n const isFetchDone = cacheMsg !== undefined && !isFetching\n // 如果已经获取过,直接返回\n if (isFetchDone) return cacheMsg\n // 如果正在获取,等待获取完成\n if (isFetching) {\n const start = Date.now()\n return new Promise((resolve) => {\n const timer = setInterval(() => {\n const cacheMsg = messageCacheMap.get(key)\n const isFetching = cacheMsg === 'loading'\n const isFetchDone = cacheMsg !== undefined && !isFetching\n if (isFetchDone) {\n clearInterval(timer)\n resolve(cacheMsg)\n } else if (Date.now() - start > timeout) {\n clearInterval(timer)\n throw new Error(`获取引用消息超时 ${timeout}, Key: ${key}`)\n }\n }, 100)\n })\n }\n\n // 开始获取\n messageCacheMap.set(key, 'loading')\n\n const msg = await event.getQuoteMsg()\n\n // 如果缓存达到阈值则清空\n if (messageCacheMap.size > 100) messageCacheMap.clear()\n\n messageCacheMap.set(key, msg)\n\n return msg\n}\n\n/**\n * 获取原创表情包的图片链接\n */\nexport async function getBfaceUrl(file: string): Promise<string | null> {\n const id = file.slice(0, 2)\n const hash = file.slice(0, 32)\n const formats = ['raw300.gif', 'raw200.gif', 'raw100.gif', '300x300.png', '200x200.png', '100x100.png']\n\n for (const f of formats) {\n const url = `https://gxh.vip.qq.com/club/item/parcel/item/${id}/${hash}/${f}`\n const res = await fetch(url, { method: 'HEAD' })\n if (res.status === 200) return url\n }\n\n return null\n}\n\n/**\n * 获取消息中的图片链接\n */\nexport async function getImageUrl(event: HasMessage): Promise<string> {\n return find(event, 'image')?.url || ''\n}\n\n/**\n * 获取引用回复的消息中的图片链接\n */\nexport async function getQuoteImageUrl(event: MessageEvent): Promise<string> {\n const quoteMsg = await getQuoteMsg(event)\n if (!quoteMsg) return ''\n return await getImageUrl(quoteMsg)\n}\n\n/**\n * 获取消息提及的图片链接(消息或者引用消息)\n */\nexport async function getMentionedImageUrl(event: MessageEvent): Promise<string> {\n return (await getImageUrl(event)) || (await getQuoteImageUrl(event))\n}\n\n/**\n * 获取消息中的图片元素\n */\nexport function getImage(event: HasMessage): RecvImageElement | null {\n return find(Array.isArray(event) ? event : event.message, 'image') || null\n}\n\n/**\n * 获取引用回复的图片消息\n */\nexport async function getQuoteImage(event: MessageEvent): Promise<RecvImageElement | null> {\n const quoteMsg = await getQuoteMsg(event)\n if (quoteMsg) {\n return find(quoteMsg.message, 'image') || null\n }\n return null\n}\n\n/**\n * 获取消息提及的图片(消息或者引用消息)\n */\nexport async function getMentionedImage(event: MessageEvent): Promise<RecvImageElement | null> {\n return getImage(event) || (await getQuoteImage(event))\n}\n\n/**\n * 获取消息中的文本内容,默认采取 'whole' 模式,去除整体的首尾空格,可选 'each' 模式,去除每个文本的首尾空格\n *\n * 如: whole 模式下 => ' 123 [表情] 456 ' => '123 456'\n * 如: each 模式下 => ' 123 [表情] 456 ' => '123456'\n */\nexport function text(\n event: HasMessage,\n options: {\n trim?: boolean | 'whole' | 'each'\n } = {},\n): string {\n const { trim = true } = options\n const messages = Array.isArray(event) ? event : event.message\n const textMessages = messages.filter((msg): msg is { type: 'text'; text: string } => msg.type === 'text')\n const texts = textMessages.map((msg) => msg.text)\n\n let result: string\n\n if (trim === 'whole') {\n result = texts.join('').trim()\n } else if (trim === 'each') {\n result = texts.map((t) => t.trim()).join('')\n } else if (trim === true) {\n // 默认为 true, 也就是整体去除首尾空格\n result = texts.map((t) => t.trim()).join('')\n } else {\n result = texts.join('')\n }\n\n return result || ''\n}\n\n/**\n * 获取回复的消息中的文本内容\n */\nexport async function getQuoteText(event: MessageEvent): Promise<string> {\n const msg = await getQuoteMsg(event)\n if (!msg) return ''\n return text(msg)\n}\n\n/**\n * 获取提到的用户 QQ 号,可以通过 if(!qq) 判断是否提到了用户,返回 0 代表没有提到用户\n */\nexport async function getMentionedUserId(event: MessageEvent): Promise<number | 0> {\n const quoteId = (await getQuoteMsg(event))?.sender.user_id || 0\n const msgAtId = +(find(event.message, 'at')?.qq || 0)\n return Number.isNaN(msgAtId) || !msgAtId ? quoteId : msgAtId\n}\n\n/**\n * 获取 **一个** 指定类型的消息元素,如获取图片、表情等,如果没有则返回 undefined\n */\nexport function find<\n Type extends Pick<RecvElement, 'type'>['type'],\n TargetType extends Extract<RecvElement, { type: Type }> = Extract<RecvElement, { type: Type }>,\n>(event: HasMessage, type: Type): TargetType | undefined {\n const messages = Array.isArray(event) ? event : event.message\n return messages.find((msg): msg is TargetType => msg.type === type)\n}\n\n/**\n * 获取 **所有** 指定类型的消息元素,如获取图片、表情等,如果没有则返回 []\n */\nexport function filter<\n Type extends Pick<RecvElement, 'type'>['type'],\n TargetType extends Extract<RecvElement, { type: Type }> = Extract<RecvElement, { type: Type }>,\n>(event: HasMessage, type: Type): TargetType[] {\n const messages = Array.isArray(event) ? event : event.message\n return messages.filter((msg): msg is TargetType => msg.type === type)\n}\n\n/**\n * 错误信息字符串格式化\n *\n * @param {any} error 待处理错误\n * @return {string} stringify 结果\n */\nexport function stringifyError(error: any): string {\n if (typeof error === 'object') {\n const errorType = error.constructor?.name ?? '未知错误'\n const errorMessage = error.message ?? '[无报错信息]'\n return `${errorType}: ${errorMessage}`\n }\n\n return String(error)\n}\n\n/**\n * Encodes string | number | buffer using base64.\n */\nexport function base64Encode(str: string | number | Buffer): string {\n return Buffer.from(str.toString()).toString('base64')\n}\n\n/**\n * Decodes the string from base64 to UTF-8.\n *\n * @param {string} str - The base64-encoded string.\n */\nexport function base64Decode(str: string, type: 'buffer' | BufferEncoding = 'utf8'): string | Buffer {\n if (type === 'buffer') return Buffer.from(str, 'base64')\n return Buffer.from(str, 'base64').toString(type)\n}\n\n/**\n * JS 对象转换成 `urlencoded` 格式字符串 { name: 'Bob', age: 18 } => name=Bob&age=18\n *\n * @param {Record<number | string, any>} obj JS 对象\n * @return {string} 转换后的字符串\n */\nexport function qs(obj: Record<number | string, any>): string {\n return new URLSearchParams(obj).toString()\n}\n\n/**\n * 格式化展示 QQ 等级\n */\nexport function formatQQLevel(level: number): string {\n return (\n '👑'.repeat(Math.floor(level / 64)) +\n '☀️'.repeat(Math.floor((level % 64) / 16)) +\n '🌙'.repeat(Math.floor((level % 16) / 4)) +\n '⭐️'.repeat(level % 4)\n )\n}\n\n/**\n * 申请通过开发者工具登录,以获取 Cookie\n */\nexport async function requestLoginViaDevTools(): Promise<{ code: string; url: string }> {\n const code = await getDevToolsLoginCode()\n\n return {\n code: code,\n url: `https://h5.qzone.qq.com/qqq/code/${code}?_proxy=1&from=ide`,\n }\n\n /**\n * 获取开发者工具登录码\n */\n async function getDevToolsLoginCode(): Promise<string> {\n const response = await fetch('https://q.qq.com/ide/devtoolAuth/GetLoginCode', {\n method: 'GET',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n })\n\n if (!response.ok) return ''\n const { code, data } = await response.json()\n if (+code !== 0) return ''\n return data.code ?? ''\n }\n}\n\n/**\n * 获取开发者工具登录结果\n */\nexport async function queryDevToolsLoginStatus(code: string): Promise<{\n status: 'OK' | 'Wait' | 'Expired' | 'Used' | 'Error'\n ticket?: string\n}> {\n const response = await fetch(`https://q.qq.com/ide/devtoolAuth/syncScanSateGetTicket?code=${code}`, {\n method: 'GET',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n })\n\n if (!response.ok) return { status: 'Error' }\n\n // OK: { \"code\": 0, \"data\": { \"code\": \"xxx\", \"ticket\": \"xxx\", \"ok\": 1, \"uin\": \"xxx\" }, \"message\": \"\" }\n // Wait: { \"code\": 0, \"data\": { \"code\": \"xxx\" }, \"message\": \"\" }\n // Expired: { \"code\": 0, \"data\": { \"code\": \"xxx\" }, \"message\": \"\" }\n // Used: { \"code\": \"-10003\", \"message\": \"process fail\" }\n\n const { code: resCode, data } = await response.json()\n\n if (+resCode === 0) {\n if (+data.ok !== 1) return { status: 'Wait' }\n\n return {\n status: 'OK',\n ticket: data.ticket,\n }\n }\n\n if (+resCode === -10003) return { status: 'Used' }\n\n return { status: 'Error' }\n}\n\n/**\n * 通过开发者工具登录获取 AuthCode\n */\nexport async function getAuthCodeViaTicket(ticket: string, appid: number): Promise<string> {\n const response = await fetch('https://q.qq.com/ide/login', {\n method: 'POST',\n headers: {\n qua: 'V1_HT5_QDT_0.70.2209190_x64_0_DEV_D',\n host: 'q.qq.com',\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ appid, ticket }),\n })\n\n if (!response.ok) return ''\n\n const { code } = await response.json()\n\n return code || ''\n}\n\n/**\n * 通过 Auth Code 获取 minico Token\n */\nexport async function getMinicoTokenViaAuthCode(authCode: string, appid: number): Promise<any> {\n const response = await fetch('https://minico.qq.com/minico/oauth20?uin=QQ%E5%AE%89%E5%85%A8%E4%B8%AD%E5%BF%83', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n appid,\n code: authCode,\n platform: 'qq',\n }),\n })\n\n if (!response.ok) return {}\n\n const { retcode, data } = await response.json()\n\n if (+retcode !== 0 || !data) return {}\n\n return data || {}\n}\n\n/**\n * 获取终端输入,返回 Promise,支持提示信息\n */\nexport async function getTerminalInput(inputTip = '请输入'): Promise<string> {\n return new Promise((resolve) => {\n if (inputTip) console.log(inputTip)\n\n function getInput() {\n process.stdin.once('data', async (e) => {\n const input = e.toString().trim()\n if (input) {\n resolve(input)\n return\n }\n getInput()\n })\n }\n getInput()\n })\n}\n\n/**\n * 当前 Node.js 进程的启动时间,常量,Date 类型\n */\nexport const START_TIME: Date = new Date()\n\n/**\n * 计算 GTK 值\n */\nexport function getGTk(pskey: string): number {\n let gkt = 5381\n for (let i = 0, len = pskey.length; i < len; ++i) {\n gkt += (gkt << 5) + pskey.charCodeAt(i)\n }\n return gkt & 0x7fffffff\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { logger } from './logger'\nimport { isNumber, unique } from './utils'\n\nimport type { LogLevel } from 'napcat-sdk'\n\n/**\n * mioki 配置\n */\nexport interface MiokiConfig {\n prefix?: string\n owners: number[]\n admins: number[]\n plugins: string[]\n error_push?: boolean\n online_push?: boolean\n log_level?: LogLevel\n plugins_dir?: string\n status_permission?: 'all' | 'admin-only'\n napcat: {\n protocol?: 'ws' | 'wss'\n port?: number\n host?: string\n token: string\n }\n}\n\n/**\n * 机器人根目录\n */\nexport const BOT_CWD: { value: string } = {\n value: process.cwd(),\n}\n\nexport function readPackageJson(): Record<'mioki' | (string & {}), any> {\n if (!fs.existsSync(path.join(BOT_CWD.value, 'package.json')))\n throw new Error(`无法在 ${BOT_CWD.value} 下找到 package.json 文件,请确认当前目录是否为机器人根目录`)\n\n return JSON.parse(fs.readFileSync(path.join(BOT_CWD.value, 'package.json'), 'utf-8')) || {}\n}\n\nexport function writePackageJson(pkg: Record<string, any>): void {\n fs.writeFileSync(path.join(BOT_CWD.value, 'package.json'), JSON.stringify(pkg, null, 2), 'utf-8')\n}\n\nexport function readMiokiConfig(): MiokiConfig {\n const config = readPackageJson().mioki\n\n if (!config) throw new Error(`无法在 package.json 中找到 mioki 配置,请确认 package.json 文件中是否包含 mioki 字段`)\n if (!config.napcat) throw new Error(`mioki 配置中缺少 napcat 字段,请补全后重试`)\n\n return readPackageJson().mioki\n}\n\n/**\n * `mioki` 框架相关配置\n */\nexport const botConfig: MiokiConfig = readMiokiConfig()\n\n/**\n * 更新 `mioki` 配置,同时同步更新本地配置文件\n */\nexport const updateBotConfig = async (draftFn: (config: MiokiConfig) => any): Promise<void> => {\n await draftFn(botConfig)\n\n botConfig.plugins = unique(botConfig.plugins).toSorted((prev, next) => prev.localeCompare(next))\n botConfig.admins = unique(botConfig.admins).toSorted((prev, next) => prev - next)\n\n const pkg = readPackageJson()\n pkg.mioki = structuredClone(botConfig)\n\n writePackageJson(pkg)\n\n logger.info(`检测到配置变动,已同步至 package.json 文件`)\n}\n\n/**\n * 更新机器人根目录\n */\nexport const updateBotCWD = (root: string): void => {\n BOT_CWD.value = root\n logger.info(`机器人根目录已设置为 ${root}`)\n}\n\n/**\n * 是否是主人\n */\nexport const isOwner = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n const owners = botConfig.owners\n\n return isNumber(id)\n ? owners.includes(id)\n : 'sender' in id\n ? owners.includes(id.sender.user_id)\n : owners.includes(id.user_id)\n}\n\n/**\n * 是否是管理员,注意: 主人不是管理员\n */\nexport const isAdmin = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n const admins = botConfig.admins\n\n return isNumber(id)\n ? admins.includes(id)\n : 'sender' in id\n ? admins.includes(id.sender.user_id)\n : admins.includes(id.user_id)\n}\n\n/**\n * 是否是主人或管理员\n */\nexport const isOwnerOrAdmin = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n return isOwner(id) || isAdmin(id)\n}\n\n/**\n * 是否有权限,即:主人或管理员\n */\nexport const hasRight = (id: number | { sender: { user_id: number } } | { user_id: number }): boolean => {\n return isOwnerOrAdmin(id)\n}\n\n/**\n * 是否在 PM2 中运行\n */\nexport const isInPm2: boolean = Boolean('pm_id' in process.env || 'PM2_USAGE' in process.env)\n","import fs from 'node:fs'\nimport util from 'node:util'\nimport path from 'node:path'\nimport { dayjs } from './utils'\nimport { BOT_CWD, botConfig } from './config'\nimport { stripAnsi, ColorName, colors } from 'consola/utils'\nimport { createConsola, LogLevels } from 'consola/core'\n\nimport type { Logger, LogLevel } from 'napcat-sdk'\n\nconst LEVEL_MAP: Record<number, { name: string; color: ColorName }> = {\n 0: { name: 'ERROR', color: 'red' },\n 1: { name: 'WARN', color: 'yellow' },\n 2: { name: 'LOG', color: 'white' },\n 3: { name: 'INFO', color: 'green' },\n 4: { name: 'DEBUG', color: 'blue' },\n 5: { name: 'TRACE', color: 'gray' },\n}\n\nexport const logger: Logger = getMiokiLogger(botConfig.log_level || 'info')\n\n/**\n * 获取日志文件名\n */\nexport function getLogFilePath(type: string = ''): string {\n const startTime = dayjs().format('YYYY-MM-DD_HH-mm-ss')\n return path.join(BOT_CWD.value, `logs/${startTime}${type ? '.' + type : ''}.log`)\n}\n\nexport function getMiokiLogger(level: LogLevel): Logger {\n const logDir = path.join(BOT_CWD.value, 'logs')\n\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true })\n }\n\n const logFile = getLogFilePath()\n\n return createConsola({\n level: LogLevels[level],\n defaults: {\n tag: 'mioki',\n },\n reporters: [\n {\n log: (logObj) => {\n const message = stripAnsi(\n logObj.message ||\n logObj.args\n ?.map((e) => (typeof e === 'string' ? e : util.inspect(e, { colors: true, depth: null })))\n .join(' ') ||\n '',\n )\n\n const prefix = `[${logObj.date.toISOString()}] [${LEVEL_MAP[logObj.level].name}] ${logObj.tag ? `[${logObj.tag}] ` : ''}`\n const line = `${prefix}${message}`\n fs.appendFileSync(logFile, line + '\\n')\n },\n },\n {\n log: (logObj) => {\n const time = colors.gray(`[${logObj.date.toLocaleTimeString('zh-CN')}]`)\n const level = colors.bold(colors[LEVEL_MAP[logObj.level].color](LEVEL_MAP[logObj.level].name))\n const tag = logObj.tag ? colors.dim(`[${logObj.tag}] `) : ''\n\n const message =\n logObj.message ||\n logObj.args\n ?.map((e) => (typeof e === 'string' ? e : util.inspect(e, { colors: true, depth: null })))\n .join(' ') ||\n ''\n\n const line = `${time} ${level} ${tag} ${message}`\n\n if (logObj.level <= LogLevels['error']) {\n console.error(line)\n } else if (logObj.level === LogLevels['warn']) {\n console.warn(line)\n } else if (logObj.level === LogLevels['log']) {\n console.log(line)\n } else if (logObj.level === LogLevels['info']) {\n console.info(line)\n } else {\n console.debug(line)\n }\n },\n },\n ],\n formatOptions: {\n colors: true,\n compact: true,\n date: true,\n },\n })\n}\n","import crypto from 'node:crypto'\nimport { logger } from './logger'\nimport * as utils from './utils'\nimport { segment } from 'napcat-sdk'\nimport { botConfig } from './config'\n\nimport type { NapCat, Sendable } from 'napcat-sdk'\n\n/**\n * 群发群消息\n */\nexport async function noticeGroups(\n bot: NapCat,\n groupIdList: number[],\n message?: Sendable | null,\n delay = 1000,\n): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n for (const groupId of groupIdList) {\n const group = await bot.pickGroup(groupId)\n if (!group) continue\n await group.sendMsg(message)\n await utils.wait(delay)\n }\n}\n\n/**\n * 群发好友消息\n */\nexport async function noticeFriends(\n bot: NapCat,\n friendIdList: number[],\n message?: Sendable | null,\n delay = 1000,\n): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n for (const friendId of friendIdList) {\n await bot.sendPrivateMsg(friendId, message)\n await utils.wait(delay)\n }\n}\n\n/**\n * 群发通知给管理员\n */\nexport async function noticeAdmins(bot: NapCat, message?: Sendable | null, delay = 1000): Promise<void> {\n await noticeFriends(bot, botConfig.admins, message, delay)\n}\n\n/**\n * 群发通知给主人\n */\nexport async function noticeOwners(bot: NapCat, message?: Sendable | null, delay = 1000): Promise<void> {\n await noticeFriends(bot, botConfig.owners, message, delay)\n}\n\n/**\n * 群发通知给第一个主人\n */\nexport async function noticeMainOwner(bot: NapCat, message?: Sendable | null): Promise<void> {\n if (!bot.isOnline()) {\n logger.error('发送失败,Bot 不在线')\n return\n }\n\n if (!message) {\n logger.warn('消息内容为空')\n return\n }\n\n const mainOwner = botConfig.owners[0]\n\n if (mainOwner) {\n await (await bot.pickFriend(mainOwner))?.sendMsg(message)\n return\n }\n\n throw new Error('请至少设置一个主人')\n}\n\n/**\n * 签名卡片 json\n */\nexport async function signArk(bot: NapCat, json: string): Promise<string> {\n const { cookie, gtk } = await bot.getCookie('qzone.qq.com')\n\n const fetchArk = (url: string) => {\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Cookie: cookie,\n },\n body: JSON.stringify({ ark: json }),\n })\n }\n\n const SignUrl = {\n normal: `https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenSignedArk?g_tk=${gtk}`,\n new: `https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=${gtk}`,\n }\n\n try {\n const { code, data = {} } = await (await fetchArk(SignUrl.normal)).json()\n if (+code === 0 && data?.signed_ark) return data.signed_ark\n throw new Error('签不了一点')\n } catch {\n const { code, data = {} } = await (await fetchArk(SignUrl.new)).json()\n if (+code === 0 && data?.signed_ark) return data.signed_ark\n throw new Error('签不了一点')\n }\n}\n\n/**\n * 运行函数并捕获错误, 并通过 event.reply 发送错误信息\n */\nexport async function runWithErrorHandler(\n bot: NapCat,\n fn: () => any,\n event?: { reply: (content: Sendable, quote?: boolean) => Promise<{ message_id: number }> },\n message: Sendable | ((error: string) => Sendable) = (err) => `报...报错了啦! 杂鱼~ 杂鱼~ \\n\\n${err}`,\n): Promise<any> {\n try {\n return await fn()\n } catch (error) {\n const errorMsg = typeof message === 'function' ? message(utils.stringifyError(error)) : message\n\n if (event) {\n await event.reply(errorMsg)\n } else {\n try {\n await noticeMainOwner(bot, '发送失败,可能被风控,请检查签名状态。')\n } catch {\n logger.error('发送失败,可能被风控,请检查签名状态。')\n }\n }\n }\n}\n\n/** 创建和并转发消息 */\nexport function createForwardMsg(\n bot: NapCat,\n message: Sendable[] = [],\n options: { user_id?: number; nickname?: string } = {},\n): Sendable {\n const { user_id = bot.uin, nickname } = options\n const content = message.map((msg) => (typeof msg === 'string' ? segment.text(msg) : msg))\n return segment.node({ user_id: String(user_id), nickname, content })\n}\n\n/**\n * 上传图片到收藏\n */\nexport async function uploadImageToCollection(bot: NapCat, buffer: ArrayBuffer): Promise<string> {\n const pskey = (await bot.getPskey('weiyun.com')) || ''\n const uuid = crypto.randomUUID()\n\n let randomID: string | number = crypto.randomInt(1, 99)\n if (randomID < 10) randomID = `0${randomID}`\n\n const options = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/octet-stream',\n Cookie: `uin=${bot.uin}; vt=27; vi=${pskey}; pid=00${randomID}/${uuid}; appid=30243`,\n 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',\n },\n body: buffer,\n }\n\n let code: number | undefined = undefined\n\n for (let i = 3; i > 0; i--) {\n const response = await fetch('https://uploader.collector.weiyun.com/pic_uploader.fcg', options)\n const headers = response.headers\n code = +(headers.get('user-returncode') || '')\n const msg = headers.get('user-errmsg')\n console.log(3 - i, 'uploadImageToCollector', response.status, code, msg)\n if (code === 0) break\n }\n\n return code === 0 ? `https://shp.qpic.cn/collector//${uuid}/0` : ''\n}\n\n/**\n * 上传图片到群作业\n */\nexport async function uploadImageToGroupHomework(bot: NapCat, imgBase64: string): Promise<string> {\n const { cookie, bkn } = await bot.getCookie('qun.qq.com')\n\n const res = await fetch('https://qun.qq.com/cgi-bin/hw/util/image', {\n method: 'POST',\n headers: {\n cookie,\n 'Content-Type': 'application/x-www-form-urlencoded',\n origin: 'https://qun.qq.com',\n referer: 'https://qun.qq.com/homework/p/features/index.html',\n },\n body: `pic=${encodeURIComponent(imgBase64)}&client_type=1&bkn=${bkn}`,\n })\n\n const data = await res.json()\n\n if (+data.retcode !== 0) return ''\n\n return data?.data?.url?.origin || ''\n}\n\n/**\n * 上传图片到群公告\n */\nexport async function uploadImageToGroupNotice(\n bot: NapCat,\n urlOrBlob: string | Blob,\n): Promise<{\n h: string\n w: string\n id: string\n url: string\n url2: string\n url3: string\n url4: string\n url5: string\n url6: string\n}> {\n const { bkn, legacyCookie } = await bot.getCookie('qun.qq.com')\n\n const blob = urlOrBlob instanceof Blob ? urlOrBlob : await (await fetch(urlOrBlob)).blob()\n const form = new FormData()\n\n form.append('m', '0')\n form.append('source', 'troopNotice')\n form.append('bkn', String(bkn))\n form.append('qid', '0')\n form.append('pic_up', blob, `image.${blob.type.split('/')[1]}`)\n\n const data = await (\n await fetch('https://web.qun.qq.com/cgi-bin/announce/upload_img', {\n method: 'POST',\n body: form,\n headers: { 'content-type': 'multipart/form-data', cookie: legacyCookie },\n })\n ).json()\n\n const { id, ec } = data || {}\n\n if (!id) {\n throw new Error(`图片上传失败,ec: ${ec}`)\n }\n\n const imgData = (JSON.parse(id.replace(/&quot;/g, '\"')) || {}) as {\n h: string\n w: string\n id: string\n }\n\n if (!imgData.id) {\n throw new Error('图片上传失败,未获取到图片 id')\n }\n\n return {\n ...imgData,\n url: `https://p.qpic.cn/gdynamic/${imgData.id}/0`,\n url2: `https://p.qlogo.cn/gdynamic/${imgData.id}/0`,\n url3: `https://p2.qpic.cn/gdynamic/${imgData.id}/0`,\n url4: `https://gdynamic.qpic.cn/gdynamic/${imgData.id}/0`,\n url5: `https://img.wecar.qq.com/gdynamic/${imgData.id}/0`,\n url6: `https://cross.store.qq.com/gdynamic/${imgData.id}/0`,\n }\n}\n\n/**\n * 获取 QQ 安全中心违规记录\n */\nexport async function getViolationRecords(\n bot: NapCat,\n authCode: string,\n appid: number,\n size = 100,\n): Promise<\n {\n type: string\n time: string\n duration: string\n reason: number\n }[]\n> {\n const minicoData = await utils.getMinicoTokenViaAuthCode(authCode, appid)\n\n if (!minicoData) return []\n\n const params = new URLSearchParams({\n ...minicoData,\n appid,\n token: minicoData.minico_token,\n })\n\n params.delete('expire')\n params.delete('minico_token')\n\n const response = await fetch(\n `https://minico.qq.com/minico/cgiproxy/v3_release/v3/getillegalityhistory?${params.toString()}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n com: {\n src: 0,\n scene: 1001,\n platform: 2,\n version: '8.9.85.12820',\n },\n pageNum: 0,\n pageSize: size,\n }),\n },\n )\n\n const { retcode, records } = await response.json()\n\n if (+retcode !== 0 || !records) return []\n\n return records || []\n}\n","import { logger } from './logger'\n\nimport type { MiokiCoreServiceContrib } from './builtins/core'\n\nexport interface MiokiServices extends Record<string, unknown>, MiokiCoreServiceContrib {}\n\nconst USER_SERVICE: MiokiServices = {} as MiokiServices\n\n/**\n * 服务,由其他插件贡献的方法、数据等\n */\nexport const services: MiokiServices = USER_SERVICE\n\n/**\n * 给 `Mioki` 添加公共服务,可用于插件间通信和共享数据\n *\n * 请注意合理设置插件的 `priority` 属性,以确保服务的正确加载顺序,`priority` 默认为 100,越小越先加载\n *\n * 建议需要调用 `addService` 的插件设置 `priority` 为 `10`\n */\nexport function addService(name: string, service: any, cover: boolean = true): () => void {\n logger.debug(`添加 mioki 服务: ${name} (覆盖: ${cover ? '是' : '否'})`)\n\n if (cover || !USER_SERVICE[name]) {\n USER_SERVICE[name] = service\n }\n\n return () => {\n logger.debug(`移除 mioki 服务: ${name}`)\n\n USER_SERVICE[name] = undefined\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport nodeCron from 'node-cron'\nimport { hrtime } from 'node:process'\nimport { colors } from 'consola/utils'\n\nimport * as utilsExports from './utils'\nimport * as configExports from './config'\nimport * as actionsExports from './actions'\nimport * as servicesExports from './services'\n\nimport type { EventMap, Logger, NapCat } from 'napcat-sdk'\nimport type { ScheduledTask, TaskContext } from 'node-cron'\nimport type { ConsolaInstance } from 'consola/core'\n\ntype Num = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n\ntype Utils = typeof utilsExports\ntype Configs = typeof configExports\ntype Actions = typeof actionsExports\ntype Services = typeof servicesExports\n\ntype StrictEqual<T, U> = (<G>() => G extends T ? 1 : 2) extends <G>() => G extends U ? 1 : 2 ? true : false\n\n// 映射类型,用于遍历原始类型的每个键,并应用 RemoveFirstParam\ntype RemoveBotParam<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any\n ? StrictEqual<Parameters<T[K]>[0], NapCat> extends true\n ? OmitBotParamFromFunc<T[K]>\n : never\n : never\n}\n\nexport type OmitBotParamFromFunc<Func extends (bot: NapCat, ...args: any[]) => any> = Func extends (\n bot: NapCat,\n ...args: infer A\n) => infer Return\n ? (...args: A) => Return\n : never\n\nexport function bindBot<Params extends Array<any> = any[], Return = any>(\n bot: NapCat,\n func: (bot: NapCat, ...args: Params) => Return,\n): OmitBotParamFromFunc<(bot: NapCat, ...args: Params) => Return> {\n return (...args: Params): Return => func(bot, ...args)\n}\n\n/**\n * Mioki 上下文对象,包含 Mioki 运行时的信息和方法\n */\nexport interface MiokiContext extends Services, Configs, Utils, RemoveBotParam<Actions> {\n /** 机器人实例 */\n bot: NapCat\n /** 消息构造器 */\n segment: NapCat['segment']\n /** 通过域名获取 Cookies */\n getCookie: NapCat['getCookie']\n /** 注册事件处理器 */\n handle: <EventName extends keyof EventMap>(eventName: EventName, handler: (event: EventMap[EventName]) => any) => void\n /** 注册定时任务 */\n cron: (cronExpression: string, handler: (ctx: MiokiContext, task: TaskContext) => any) => ScheduledTask\n /** 待清理的函数集合,在插件卸载时会被调用 */\n clears: Set<(() => any) | null | undefined>\n /** 日志器 */\n logger: Logger\n}\n\nexport const runtimePlugins: Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n> = new Map<\n string,\n {\n name: string\n type: 'builtin' | 'external'\n version: string\n description: string\n plugin: MiokiPlugin\n disable: () => any\n }\n>()\n\nconst buildRemovedActions = (bot: NapCat) =>\n Object.fromEntries(\n Object.entries(actionsExports).map(([k, v]) => [k, bindBot(bot, v as any)]),\n ) as RemoveBotParam<Actions>\n\nexport interface MiokiPlugin {\n /** 插件 ID,请保持唯一,一般为插件目录名称,框架内部通过这个识别不同的插件 */\n name: string\n /** 插件版本,一般用于判断插件是否更新,暂只是用于区分 */\n version?: `${Num}.${Num}.${Num}` | `${Num}.${Num}` | (string & {})\n /** 插件加载优先级,默认 100,越小越被优先加载 */\n priority?: number\n /** 插件描述,额外提示信息,暂没有被使用到的地方 */\n description?: string\n /** 插件额外依赖,框架不处理,仅做参考提醒用途 */\n dependencies?: string[]\n /** 插件初始化,返回一个清理函数,用于在插件卸载时清理资源,比如定时器、数据库连接等 */\n setup?: (ctx: MiokiContext) => any\n}\n\n/**\n * 定义一个 Mioki 插件\n * @param plugin Mioki 插件对象\n * @returns Mioki 插件对象\n */\nexport function definePlugin(plugin: MiokiPlugin): MiokiPlugin {\n return plugin\n}\n\n/**\n * 确保插件目录存在\n */\nexport function ensurePluginDir(): void {\n const dir = getAbsPluginDir()\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n}\n\n/**\n * 获取插件目录的绝对路径\n */\nexport function getAbsPluginDir(defaultDir: string = 'plugins'): string {\n const cwd = configExports.BOT_CWD.value\n return path.join(cwd, configExports.botConfig.plugins_dir || defaultDir)\n}\n\nexport async function enablePlugin(\n bot: NapCat,\n plugin: MiokiPlugin,\n type: 'builtin' | 'external' = 'external',\n): Promise<MiokiPlugin> {\n const typeDesc = type === 'builtin' ? '内置' : '用户'\n const pluginName = plugin.name || 'null'\n const { name = pluginName, version = 'null', description = '-', setup = () => {} } = plugin\n\n try {\n const start = hrtime.bigint()\n const clears = new Set<() => any>()\n const userClears = new Set<(() => any) | undefined | null>()\n\n const logger = (bot.logger as ConsolaInstance).withDefaults({\n tag: `plugin:${name}`,\n args: [name],\n })\n\n const context: MiokiContext = {\n bot,\n segment: bot.segment,\n getCookie: bot.getCookie,\n ...utilsExports,\n ...configExports,\n ...buildRemovedActions(bot),\n logger,\n services: servicesExports.services,\n clears: userClears,\n addService: (name: string, service: any, cover?: boolean) => {\n const remove = servicesExports.addService(name, service, cover)\n clears.add(remove)\n return remove\n },\n handle: <EventName extends keyof EventMap>(\n eventName: EventName,\n handler: (event: EventMap[EventName]) => any,\n ) => {\n logger.debug(`Registering event handler for event: ${String(eventName)}`)\n\n bot.on(eventName, handler)\n\n const unsubscribe = () => {\n logger.debug(`Unregistering event handler for event: ${String(eventName)}`)\n bot.off(eventName, handler)\n }\n\n clears.add(unsubscribe)\n\n return unsubscribe\n },\n cron: (cronExpression, handler) => {\n logger.debug(`Scheduling cron job: ${cronExpression}`)\n const job = nodeCron.schedule(cronExpression, (now) => handler(context, now))\n\n const clear = () => {\n logger.debug(`Stopping cron job: ${cronExpression}`)\n job.stop()\n }\n\n clears.add(clear)\n return job\n },\n }\n\n clears.add((await setup(context)) || (() => {}))\n\n runtimePlugins.set(name, {\n name,\n type,\n version,\n description,\n plugin,\n disable: async () => {\n try {\n logger.debug(`Disabling plugin [${typeDesc}]${name}@${version}`)\n await Promise.all([...clears, ...userClears].map((fn) => fn?.()))\n runtimePlugins.delete(name)\n } catch (err: any) {\n throw new Error(\n `禁用插件 [${colors.yellow(typeDesc)}]${colors.yellow(`${name}@${version}`)} 失败: ${err?.message}`,\n )\n }\n },\n })\n\n const end = hrtime.bigint()\n const time = Math.round(Number(end - start)) / 1_000_000\n\n bot.logger.info(\n `- 启用插件 ${colors.yellow(`[${typeDesc}]`)} ${colors.yellow(`${name}@${version}`)} => 耗时 ${colors.green(time.toFixed(2))} 毫秒`,\n )\n } catch (e: any) {\n throw new Error(\n `启用插件 ${colors.yellow(`[${typeDesc}]`)} ${colors.yellow(`${name}@${version}`)} 失败: ${e?.message}`,\n )\n }\n\n return plugin\n}\n\nexport async function findLocalPlugins(): Promise<{ name: string; absPath: string }[]> {\n const dirents = await fs.promises.readdir(getAbsPluginDir(), { withFileTypes: true })\n\n return dirents\n .filter((e) => e.isDirectory() && !!e.name && !e.name.startsWith('_'))\n .map((e) => ({\n name: e.name,\n absPath: path.join(getAbsPluginDir(), e.name),\n }))\n}\n","import os from 'node:os'\nimport cp from 'node:child_process'\nimport { version } from '../../../package.json' with { type: 'json' }\nimport { BUILTIN_PLUGINS } from '..'\nimport { findLocalPlugins, runtimePlugins } from '../../plugin'\nimport { prettyMs, filesize, localNum, systemInfo } from '../..'\n\nimport type { NapCat } from 'napcat-sdk'\n\nexport const SystemMap: Record<string, string> = {\n Linux: 'Linux',\n Darwin: 'macOS',\n Windows_NT: 'Win',\n}\n\nexport const ArchMap: Record<string, string> = {\n ia32: 'x86',\n arm: 'arm',\n arm64: 'arm64',\n x64: 'x64',\n}\n\nexport interface MiokiStatus {\n bot: {\n uin: number\n nickname: string\n friends: number\n groups: number\n // guilds: number\n }\n plugins: {\n enabled: number\n total: number\n }\n stats: {\n uptime: number\n send: number\n receive: number\n }\n // platform: {\n // name: string\n // version: string\n // subid: string\n // }\n versions: {\n node: string\n mioki: string\n napcat: string\n protocol: string\n }\n system: {\n name: string\n version: string\n arch: string\n }\n memory: {\n used: number\n total: number\n percent: number\n rss: {\n used: number\n percent: number\n }\n }\n disk: {\n total: number\n used: number\n free: number\n percent: number\n }\n cpu: {\n name: string\n count: number\n percent: number\n }\n}\n\nexport async function getMiokiStatus(bot: NapCat): Promise<MiokiStatus> {\n const osType = os.type()\n const osArch = os.arch()\n const isInUnix = ['Linux', 'Darwin'].includes(osType)\n const arch = ArchMap[osArch] || osArch\n\n const [osInfo, localPlugins, versionInfo, friendList, groupList] = await Promise.all([\n systemInfo.osInfo(),\n findLocalPlugins(),\n bot.getVersionInfo(),\n bot.getFriendList(),\n bot.getGroupList(),\n ])\n\n const pluginCount = localPlugins.length + BUILTIN_PLUGINS.length\n\n const system = isInUnix\n ? { name: osInfo.distro, version: osInfo.release }\n : { name: SystemMap[osType] || osType, version: '-' }\n\n const totalMem = os.totalmem()\n const usedMem = totalMem - os.freemem()\n const rssMem = process.memoryUsage.rss()\n\n const nodeVersion = process.versions.node\n const cpu = getCpuInfo()\n\n return {\n bot: {\n uin: bot.uin,\n nickname: bot.nickname,\n friends: friendList.length,\n groups: groupList.length,\n // guilds: bot.guilds.size,\n },\n plugins: {\n enabled: runtimePlugins.size,\n total: pluginCount,\n },\n stats: {\n uptime: process.uptime() * 1000,\n send: bot.stat.send.group + bot.stat.send.private,\n receive: bot.stat.recv.group + bot.stat.recv.private,\n },\n versions: {\n node: nodeVersion,\n // icqq: oicqVersion,\n mioki: version,\n napcat: versionInfo.app_version,\n protocol: versionInfo.protocol_version,\n },\n system: {\n name: system.name || 'N/A',\n version: system.version || 'N/A',\n arch: arch,\n },\n memory: {\n used: usedMem,\n total: totalMem,\n percent: Number(((usedMem / totalMem) * 100).toFixed(1)),\n rss: {\n used: rssMem,\n percent: Number(((rssMem / totalMem) * 100).toFixed(1)),\n },\n },\n disk: isInUnix ? await getDiskUsageInUnix() : { total: 0, used: 0, free: 0, percent: 0 },\n cpu: {\n name: cpu.name.trim(),\n count: cpu.count,\n percent: Number((await measureCpuUsage()).toFixed(1)),\n },\n }\n}\n\nexport async function formatMiokiStatus(status: MiokiStatus): Promise<string> {\n const { bot, plugins, stats, system, disk, cpu, memory, versions } = status\n\n const diskValid = disk.total > 0 && disk.free >= 0\n const diskDesc = `${disk.percent}%-${filesize(disk.used, { round: 1 })}/${filesize(disk.total, { round: 1 })}`\n\n return `\n👤 ${bot.nickname}\n🆔 ${bot.uin}\n📋 ${localNum(bot.friends)} 好友 / ${localNum(bot.groups)} 群\n🧩 启用了 ${localNum(plugins.enabled)} 个插件,共 ${localNum(plugins.total)} 个\n📮 收 ${localNum(stats.receive)} 条,发 ${localNum(stats.send)} 条\n🚀 ${filesize(memory.rss.used, { round: 1 })}/${memory.percent}%\n⏳ 已运行 ${prettyMs(stats.uptime, { hideYear: true, secondsDecimalDigits: 0 })}\n🤖 mioki/${versions.mioki}-NapCat/${versions.napcat}\n🖥️ ${system.name.split(' ')[0]}/${system.version.split('.')[0]}-${system.name}-node/${versions.node.split('.')[0]}\n📊 ${memory.percent}%-${filesize(memory.used, { base: 2, round: 1 })}/${filesize(memory.total, { base: 2, round: 1 })}\n🧮 ${cpu.percent}%-${cpu.name}-${cpu.count}核\n${diskValid ? `💾 ${diskDesc}` : ''}\n `.trim()\n}\n\nasync function getDiskUsageInUnix(path = '/'): Promise<{ total: number; used: number; free: number; percent: number }> {\n return new Promise((resolve) => {\n cp.exec(`df -k ${path} | tail -1 | awk '{print $2,$4}'`, (err, stdout) => {\n if (err) {\n console.error(err)\n return resolve({ total: 0, used: 0, free: 0, percent: 0 })\n }\n\n const [_total, _free] = stdout.trim().split(' ')\n\n const total = Number(_total) * 1024\n const free = Number(_free) * 1024\n const used = total - free\n\n resolve({ total, free, used, percent: Number(((used / total) * 100).toFixed(1)) })\n })\n })\n}\n\nasync function measureCpuUsage(interval = 600): Promise<number> {\n const start = getCpuTimes()\n await new Promise((resolve) => setTimeout(resolve, interval))\n const end = getCpuTimes()\n const idleDiff = end.idle - start.idle\n const totalDiff = end.total - start.total\n const usage = 1 - idleDiff / totalDiff\n\n return usage * 100\n}\n\nfunction getCpuTimes(): { idle: number; total: number } {\n const cpus = os.cpus()\n let idle = 0\n let total = 0\n for (const cpu of cpus) {\n for (const type in cpu.times) total += cpu.times[type as never]\n idle += cpu.times.idle\n }\n return { idle, total }\n}\n\nfunction getCpuInfo() {\n const cpus = os.cpus()\n const cpu = cpus[0]\n\n return {\n name: cpu?.model || '[未知CPU]',\n count: cpus.length,\n }\n}\n","import { version } from '../../../package.json' with { type: 'json' }\nimport { getMiokiStatus, formatMiokiStatus, type MiokiStatus } from './status'\nimport { definePlugin, enablePlugin, findLocalPlugins, getAbsPluginDir, runtimePlugins } from '../..'\n\nimport type { MiokiPlugin } from '../..'\n\nconst corePlugins = ['mioki-core']\n\nexport interface MiokiCoreServiceContrib {\n /** 获取框架和系统的实时状态 */\n getMiokiStatus(): Promise<MiokiStatus>\n /** 格式化框架状态字符串 */\n formatMiokiStatus(status: MiokiStatus): Promise<string>\n /** 自定义框架状态格式化函数 */\n customFormatMiokiStatus(formatter: (status: MiokiStatus) => string | Promise<string>): void\n}\n\nconst core: MiokiPlugin = definePlugin({\n name: 'mioki-core',\n version,\n priority: 8,\n setup(ctx) {\n const prefix = (ctx.botConfig.prefix ?? '#').replace(/[-_.^$?[\\]{}]/g, '\\\\$&')\n\n const cmdPrefix = new RegExp(`^${prefix}`)\n const displayPrefix = prefix.replace(/\\\\\\\\/g, '\\\\')\n const statusAdminOnly = ctx.botConfig.status_permission === 'admin-only'\n\n let statusFormatter = (status: MiokiStatus): string | Promise<string> => formatMiokiStatus(status)\n\n ctx.addService('getMiokiStatus', () => getMiokiStatus(ctx.bot))\n ctx.addService('formatMiokiStatus', formatMiokiStatus)\n ctx.addService('customFormatMiokiStatus', (formatter: (status: MiokiStatus) => string | Promise<string>) => {\n statusFormatter = formatter\n })\n\n ctx.handle('message', (e) =>\n ctx.runWithErrorHandler(async () => {\n const text = ctx.text(e)\n\n if (!cmdPrefix.test(text)) return\n\n if (statusAdminOnly && !ctx.hasRight(e)) return\n\n if (text.replace(cmdPrefix, '') === '状态') {\n const status = await statusFormatter(await getMiokiStatus(ctx.bot))\n await e.reply(`〓 🟢 mioki 状态 〓\\n${status}`.trim())\n return\n }\n\n if (!ctx.isOwner(e)) return\n\n const { cmd, params, ..._options } = ctx.createCmd(text)\n\n if (!cmd) return\n\n const [subCmd, target, ..._subParams] = params\n\n switch (cmd?.replace(/\\s+/g, '')) {\n case '帮助': {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 💡 mioki 帮助 〓\n ${displayPrefix}插件 👉 框架插件管理\n ${displayPrefix}状态 👉 显示框架状态\n ${displayPrefix}设置 👉 框架设置管理\n ${displayPrefix}帮助 👉 显示帮助信息\n ${displayPrefix}退出 👉 退出框架进程\n `,\n )\n .trim(),\n )\n break\n }\n\n case '插件': {\n if (corePlugins.includes(target)) {\n await e.reply('内置插件无法操作', true)\n return\n }\n\n switch (subCmd) {\n case '列表': {\n const localPlugins = await findLocalPlugins()\n\n const plugins = ctx\n .unique([...localPlugins.map((e) => e.name), ...runtimePlugins.keys()])\n .map((name) => {\n const isEnable = runtimePlugins.get(name)\n const tag = isEnable ? '🟢' : '🔴'\n const type = isEnable && isEnable?.type === 'builtin' ? '[内置]' : '[用户]'\n return `${tag} ${type} ${name}`\n })\n .toSorted((pre, next) => {\n function weight(str: string) {\n let w = 0\n if (str.includes('🟢')) w += 10\n if (str.includes('[内置]')) w += 1\n return w\n }\n\n const preWeight = weight(pre)\n const nextWeight = weight(next)\n\n return nextWeight - preWeight || pre.localeCompare(next)\n })\n\n await e.reply(\n ctx\n .dedent(\n `\n 〓 插件列表 〓\n ${plugins.join('\\n')}\n 共 ${plugins.length} 个,启用 ${runtimePlugins.size} 个\n `,\n )\n .trim(),\n )\n\n break\n }\n case '启用': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n if (runtimePlugins.has(target)) {\n await e.reply(`插件 ${target} 已经是启用状态`, true)\n return\n }\n\n const pluginPath = ctx.path.join(getAbsPluginDir(), target)\n\n if (!ctx.fs.existsSync(pluginPath)) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n try {\n const plugin = (await ctx.jiti.import(pluginPath, { default: true })) as MiokiPlugin\n\n if (plugin.name !== target) {\n const tip = `[插件目录名称: ${target}] 和插件代码中设置的 [name: ${plugin.name}] 不一致,可能导致重载异常,请修改后重启。`\n ctx.bot.logger.warn(tip)\n ctx.noticeMainOwner(tip)\n }\n\n await enablePlugin(ctx.bot, plugin)\n } catch (err: any) {\n await e.reply(`插件 ${target} 启用失败:${err?.message || '未知错误'}`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = [...ctx.botConfig.plugins, target]))\n\n await e.reply(`插件 ${target} 启用成功`, true)\n\n break\n }\n\n case '禁用': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n const plugin = runtimePlugins.get(target)\n\n if (!plugin) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n try {\n await plugin.disable()\n } catch (err: any) {\n await e.reply(err?.message, true)\n break\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = ctx.botConfig.plugins.filter((name) => name !== target)))\n\n ctx.bot.logger.info(`禁用插件 => ${target}`)\n\n await e.reply(`插件 ${target} 已禁用`, true)\n\n break\n }\n\n case '重载': {\n if (!target) {\n await e.reply('请指定插件 ID', true)\n return\n }\n\n let isOff = false\n const plugin = runtimePlugins.get(target)\n\n try {\n if (plugin) {\n await plugin.disable()\n }\n\n const pluginPath = ctx.path.join(getAbsPluginDir(), target)\n\n if (!ctx.fs.existsSync(pluginPath)) {\n await e.reply(`插件 ${target} 不存在`, true)\n return\n }\n\n if (!plugin) {\n isOff = true\n // await e.reply(`插件 ${target} 还未启用,尝试直接启用...`, true)\n }\n\n const importedPlugin = (await ctx.jiti.import(pluginPath, { default: true })) as MiokiPlugin\n\n if (importedPlugin.name !== target) {\n const tip = `插件目录名称: ${target} 和插件代码中设置的 name: ${importedPlugin.name} 不一致,可能导致重载异常,请修改后重启。`\n ctx.bot.logger.warn(tip)\n ctx.noticeMainOwner(tip)\n }\n\n await enablePlugin(ctx.bot, importedPlugin)\n } catch (err: any) {\n await e.reply(err?.message, true)\n await ctx.updateBotConfig((c) => (c.plugins = c.plugins.filter((name) => name !== target)))\n break\n }\n\n await ctx.updateBotConfig((c) => (c.plugins = [...c.plugins, target]))\n\n await e.reply(`插件 ${target} 已${isOff ? '直接启用' : '重载'}`, true)\n\n break\n }\n default: {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 🧩 mioki 插件 〓\n ${displayPrefix}插件 列表\n ${displayPrefix}插件 启用 <插件 ID>\n ${displayPrefix}插件 禁用 <插件 ID>\n ${displayPrefix}插件 重载 <插件 ID>\n `,\n )\n .trim(),\n )\n break\n }\n }\n break\n }\n\n case '设置': {\n switch (subCmd) {\n case '详情': {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 设置详情 〓\n 主人: ${ctx.botConfig.owners.join(', ')}\n 管理: ${ctx.botConfig.admins.join(', ').trim()}\n 启用插件: ${ctx.botConfig.plugins.join(', ').trim()}\n `,\n )\n .trim(),\n )\n break\n }\n\n case '加主人':\n case '添加主人': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定主人 QQ/AT', true)\n return\n }\n\n if (ctx.botConfig.owners.includes(uid)) {\n await e.reply(`主人 ${uid} 已存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.owners = [...c.owners, uid]))\n\n await e.reply(`已添加主人 ${uid}`, true)\n\n break\n }\n\n case '删主人':\n case '删除主人': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定主人 QQ/AT', true)\n return\n }\n\n if (uid === ctx.botConfig.admins[0]) {\n await e.reply('不能删除第一主人', true)\n return\n }\n\n const idx = ctx.botConfig.owners.indexOf(uid)\n\n if (idx === -1) {\n await e.reply(`主人 ${uid} 不存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => c.owners.splice(idx, 1))\n\n await e.reply(`已删除主人 ${uid}`, true)\n\n break\n }\n case '加管理':\n case '添加管理': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定管理 QQ/AT', true)\n return\n }\n\n if (ctx.botConfig.admins.includes(uid)) {\n await e.reply(`管理 ${uid} 已存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => (c.admins = [...c.admins, uid]))\n\n await e.reply(`已添加管理 ${uid}`, true)\n\n break\n }\n case '删管理':\n case '删除管理': {\n const inputUid = Number.parseInt(target)\n const uid = Number.isNaN(inputUid) ? +(e.message.find((e) => e.type === 'at')?.qq || 0) : inputUid || 0\n\n if (!uid || Number.isNaN(uid)) {\n await e.reply('请指定管理 QQ/AT', true)\n return\n }\n\n const idx = ctx.botConfig.admins.indexOf(uid)\n\n if (idx === -1) {\n await e.reply(`管理 ${uid} 不存在`, true)\n return\n }\n\n await ctx.updateBotConfig((c) => c.admins.splice(idx, 1))\n\n await e.reply(`已删除管理 ${uid}`, true)\n\n break\n }\n default: {\n await e.reply(\n ctx\n .dedent(\n `\n 〓 ⚙️ mioki 设置 〓\n ${displayPrefix}设置 详情\n ${displayPrefix}设置 [加/删]主人 <QQ/AT>\n ${displayPrefix}设置 [加/删]管理 <QQ/AT>\n `,\n )\n .trim(),\n )\n break\n }\n }\n break\n }\n\n case '退出': {\n await e.reply('またね~', true)\n ctx.bot.logger.info('接收到退出指令,即将退出... 如需自动重启,请使用 pm2 部署。')\n process.exit(0)\n }\n }\n }, e),\n )\n },\n})\n\nexport default core\n","import core from './core'\n\nimport type { MiokiPlugin } from '../plugin'\n\nexport const BUILTIN_PLUGINS: MiokiPlugin[] = [core]\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { hrtime } from 'node:process'\nimport * as cfg from './config'\nimport { NapCat } from 'napcat-sdk'\nimport { version } from '../package.json'\nimport * as utils from './utils'\nimport * as actions from './actions'\nimport { logger } from './logger'\nimport { colors } from 'consola/utils'\nimport { BUILTIN_PLUGINS } from './builtins'\nimport { enablePlugin, ensurePluginDir, getAbsPluginDir, runtimePlugins } from './plugin'\n\nimport type { MiokiPlugin } from './plugin'\nexport interface StartOptions {\n cwd?: string\n}\n\nexport async function start(options: StartOptions = {}): Promise<void> {\n const { cwd = process.cwd() } = options\n\n if (cwd !== cfg.BOT_CWD.value) {\n cfg.updateBotCWD(path.resolve(cwd))\n }\n\n process.title = `mioki v${version}`\n\n const plugin_dir = getAbsPluginDir()\n\n logger.info(colors.dim('='.repeat(40)))\n logger.info(`欢迎使用 ${colors.bold(colors.redBright('mioki'))} 💓 ${colors.bold(colors.cyan(`v${version}`))}`)\n logger.info(colors.yellow(colors.underline(`一个基于 NapCat 的插件式 QQ 机器人框架`)))\n logger.info(colors.cyan(`轻量 * 跨平台 * 插件式 * 热重载 * 注重开发体验`))\n logger.info(colors.dim('='.repeat(40)))\n logger.info(colors.dim(colors.italic(`作者: Viki <hi@viki.moe> (https://github.com/vikiboss)`)))\n logger.info(colors.dim(colors.italic(`仓库: https://github.com/vikiboss/mioki`)))\n logger.info(colors.dim(colors.italic(`文档: https://mioki.viki.moe`)))\n logger.info(colors.dim('='.repeat(40)))\n logger.info(`${colors.dim('工作目录: ')}${colors.blue(cfg.BOT_CWD.value)}`)\n logger.info(`${colors.dim('插件目录: ')}${colors.blue(plugin_dir)}`)\n logger.info(`${colors.dim('配置文件: ')}${colors.blue(`${cfg.BOT_CWD.value}/package.json`)}`)\n logger.info(colors.dim('='.repeat(40)))\n\n const { protocol = 'ws', port = 3001, host = 'localhost', token = '' } = cfg.botConfig.napcat || {}\n const wsUrl = colors.green(`${protocol}://${host}:${port}${token ? '?access_token=***' : ''}`)\n\n logger.info(`>>> 正在连接 NapCat 实例: ${wsUrl}`)\n\n const napcat = new NapCat({ token, protocol, host, port, logger })\n\n napcat.on('ws.close', () => {\n logger.error('WS 连接失败,请确保 token 配置正确且 NapCat 实例正常运行')\n process.exit(1)\n })\n\n napcat.on('napcat.connected', async ({ user_id, nickname, app_name, app_version }) => {\n logger.info(`已连接到 NapCat 实例: ${colors.green(`${app_name}-v${app_version} ${nickname}(${user_id})`)}`)\n\n process.title = `mioki v${version} ${app_name}-v${app_version}-${user_id}`\n\n let lastNoticeTime = 0\n\n process.on('uncaughtException', async (err: any) => {\n const msg = utils.stringifyError(err)\n napcat.logger.error(`uncaughtException, 出错了: ${msg}`)\n\n if (cfg.botConfig.error_push) {\n if (Date.now() - lastNoticeTime < 1_000) return\n lastNoticeTime = Date.now()\n await actions.noticeMainOwner(napcat, `mioki 发生未捕获异常:\\n\\n${msg}`).catch(() => {\n napcat.logger.error('发送未捕获异常通知失败')\n })\n }\n })\n\n process.on('unhandledRejection', async (err: any) => {\n const msg = utils.stringifyError(err)\n napcat.logger.error(`unhandledRejection, 出错了: ${msg}`)\n\n if (cfg.botConfig.error_push) {\n if (Date.now() - lastNoticeTime < 1_000) return\n lastNoticeTime = Date.now()\n const date = new Date().toLocaleString()\n\n await actions.noticeMainOwner(napcat, `【${date}】\\n\\nmioki 发生未处理异常:\\n\\n${msg}`).catch(() => {\n napcat.logger.error('发送未处理异常通知失败')\n })\n }\n })\n\n ensurePluginDir()\n\n const plugins = cfg.botConfig.plugins\n .map((p) => ({ dirName: p, absPath: path.resolve(plugin_dir, p) }))\n .filter((p) => {\n if (!fs.existsSync(p.absPath)) {\n napcat.logger.warn(`插件 ${colors.red(p.dirName)} 不存在,已忽略`)\n return false\n }\n\n return true\n })\n\n const failedImportPlugins: [string, string][] = []\n\n const promises = plugins.map(async ({ absPath, dirName }) => {\n try {\n const plugin = (await utils.jiti.import(absPath, { default: true })) as MiokiPlugin\n\n if (plugin.name !== dirName) {\n const tip = `插件目录名 [${colors.yellow(dirName)}] 和插件声明的 name [${colors.yellow(plugin.name)}] 不一致,可能导致重载异常,请修改一致后重启。`\n napcat.logger.warn(tip)\n actions.noticeMainOwner(napcat, tip)\n }\n return plugin\n } catch (e) {\n const err = utils.stringifyError(e)\n failedImportPlugins.push([dirName, err])\n return null\n }\n })\n\n const start = hrtime.bigint()\n const userPlugins = (await Promise.all(promises)).filter(Boolean) as MiokiPlugin[]\n const sortedUserPlugins = userPlugins.toSorted((prev, next) => (prev.priority ?? 100) - (next.priority ?? 100))\n\n if (failedImportPlugins.length) {\n const tip = `${colors.red(failedImportPlugins.length)} 个插件加载失败: \\n\\n${failedImportPlugins.map(([dirName, err]) => `${dirName}: ${err}`).join('\\n\\n')}`\n napcat.logger.warn(tip)\n actions.noticeMainOwner(napcat, tip)\n }\n\n // 按 priority 分组\n const pluginGroups = new Map<number, MiokiPlugin[]>()\n for (const plugin of sortedUserPlugins) {\n const priority = plugin.priority ?? 100\n if (!pluginGroups.has(priority)) {\n pluginGroups.set(priority, [])\n }\n pluginGroups.get(priority)!.push(plugin)\n }\n\n // 按 priority 排序分组\n const sortedGroups = Array.from(pluginGroups.entries()).toSorted(([a], [b]) => a - b)\n\n const failedEnablePlugins: [string, string][] = []\n\n try {\n // 加载内置插件\n napcat.logger.info(`>>> 加载内置插件: ${BUILTIN_PLUGINS.map((p) => colors.cyan(p.name)).join(', ')}`)\n await Promise.all(BUILTIN_PLUGINS.map((p) => enablePlugin(napcat, p, 'builtin')))\n\n // 按优先级分组并行加载用户插件,相同优先级的插件可以并行加载\n napcat.logger.info(\n `>>> 加载用户插件: ${sortedGroups.map(([priority, plugins]) => `优先级 ${colors.yellow(priority)} (${plugins.map((p) => colors.cyan(p.name)).join(', ')})`).join(',')}`,\n )\n for (const [_, plugins] of sortedGroups) {\n await Promise.all(\n plugins.map(async (p) => {\n try {\n await enablePlugin(napcat, p, 'external')\n } catch (e) {\n failedEnablePlugins.push([p.name, utils.stringifyError(e)])\n }\n }),\n )\n }\n } catch (e: any) {\n napcat.logger.error(e?.message)\n await actions.noticeMainOwner(napcat, e?.message).catch(() => {\n napcat.logger.error('发送插件启用失败通知失败')\n })\n }\n\n const end = hrtime.bigint()\n const costTime = Math.round(Number(end - start)) / 1_000_000\n const failedCount = failedImportPlugins.length + failedEnablePlugins.length\n\n const failedInfo =\n failedCount > 0\n ? `${colors.red(failedCount)} 个失败 (导入 ${colors.red(failedImportPlugins.length)},启用 ${colors.red(failedEnablePlugins.length)})`\n : ''\n\n napcat.logger.info(\n `成功加载了 ${colors.green(runtimePlugins.size)} 个插件,${failedInfo ? failedInfo : ''}总耗时 ${colors.green(costTime.toFixed(2))} 毫秒`,\n )\n\n napcat.logger.info(\n colors.green(\n `mioki v${version} 启动完成,向机器人发送「${colors.magentaBright(`${cfg.botConfig.prefix}帮助`)}」查看消息指令`,\n ),\n )\n\n if (cfg.botConfig.online_push) {\n await actions.noticeMainOwner(napcat, `✅ mioki v${version} 已就绪`).catch((err) => {\n napcat.logger.error(`发送就绪通知失败: ${utils.stringifyError(err)}`)\n })\n }\n })\n\n await napcat.run()\n}\n"],"mappings":"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"}