diff --git a/src/config/config.ts b/src/config/config.ts index 31565a6..b33128f 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -21,6 +21,32 @@ export const PRIVILEGELEVELMAP = { "user": 0, "blacklist": -30 } +export const HELPMAP = { + "ID": `: +【QQ:1234567890】 私聊窗口 +【QQ-Group:1234】 群聊窗口 +【now】当前窗口`, + "会话权限": `<会话权限>:任意数字,越大权限越高`, + "指令": `<指令>:指令名称和参数,多个指令用-连接,如ai-sb`, + "权限限制": `<权限限制>:数字0-数字1-数字2,如0-0-0,含义如下: +0: 会话所需权限, 1: 会话检查通过后用户所需权限, 2: 强行触发指令用户所需权限, 进行检查时若通过0和1则无需检查2 +【-30】黑名单用户 +【0】普通用户 +【40】邀请者 +【50】群管理员 +【60】群主 +【70】白名单用户 +【100】骰主`, + "参数": `<参数>: +【c】计数器模式,接收消息数达到后触发 +单位/条,默认10条 +【t】计时器模式,最后一条消息后达到时限触发 +单位/秒,默认60秒 +【p】概率模式,每条消息按概率触发 +单位/%,默认10% +【a】活跃时间段和活跃次数 +格式为"开始时间-结束时间-活跃次数"(如"09:00-18:00-5")` +} export class ConfigManager { static ext: seal.ExtInfo; diff --git a/src/index.ts b/src/index.ts index 5dce60f..af937fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { AIManager } from "./AI/AI"; import { Image, ImageManager } from "./AI/image"; import { ToolManager } from "./tool/tool"; -import { ConfigManager, CQTYPESALLOW } from "./config/config"; +import { ConfigManager, CQTYPESALLOW, HELPMAP } from "./config/config"; import { buildSystemMessage } from "./utils/utils_message"; import { triggerConditionMap } from "./tool/tool_trigger"; import { logger } from "./logger"; @@ -11,6 +11,7 @@ import { get_chart_url } from "./service"; import { TimerManager } from "./timer"; import { createMsg } from "./utils/utils_seal"; import { PrivilegeManager } from "./privilege"; +import { aliasToCmd } from "./utils/utils"; function main() { ConfigManager.registerConfig(); @@ -23,18 +24,18 @@ function main() { const ext = ConfigManager.ext; const cmdAI = seal.ext.newCmdItemInfo(); - cmdAI.name = 'ai'; // 指令名字,可用中文 + cmdAI.name = 'ai'; cmdAI.help = `帮助: 【.ai priv】权限相关 【.ai prompt】查看system prompt 【.ai status】查看当前AI状态 【.ai ctxn】查看上下文里的名字 -【.ai timer】查看当前聊天定时器 +【.ai timer】定时器相关 【.ai on】开启AI -【.ai sb】开启待机模式,此时AI将记忆聊天内容 -【.ai off】关闭AI,此时仍能用关键词触发 +【.ai sb】开启待机模式,此时AI将记录聊天内容 +【.ai off】关闭AI,此时仍能用正则匹配触发 【.ai fgt】遗忘上下文 -【.ai role】选择角色设定 +【.ai role】角色设定相关 【.ai memo】AI的记忆相关 【.ai tool】AI的工具相关 【.ai ign】AI的忽略名单相关 @@ -50,31 +51,26 @@ function main() { const ret = seal.ext.newCmdExecuteResult(true); const ai = AIManager.getAI(id); - if (!PrivilegeManager.checkPriv(ctx, cmdArgs, ai)) { - seal.replyToSender(ctx, msg, "权限不足或指令不存在"); + const { success, exist } = PrivilegeManager.checkPriv(ctx, cmdArgs, ai); + if (!success) { + seal.replyToSender(ctx, msg, exist ? '权限不足' : '命令不存在'); return ret; } - switch (val) { - case 'priv': { + switch (aliasToCmd(val)) { + case 'privilege': { const val2 = cmdArgs.getArgN(2); - switch (val2) { - case 's': + switch (aliasToCmd(val2)) { case 'session': { const val3 = cmdArgs.getArgN(3); - switch (val3) { - case 'st': { + switch (aliasToCmd(val3)) { + case 'set': { const val4 = cmdArgs.getArgN(4); if (!val4 || val4 == 'help') { seal.replyToSender(ctx, msg, `帮助: -【.ai priv s st <会话权限>】修改会话权限 - -: -【QQ:1234567890】 私聊窗口 -【QQ-Group:1234】 群聊窗口 -【now】当前窗口 - -<会话权限>:任意数字,越大权限越高`); +【.ai priv ses st <会话权限>】修改会话权限 +${HELPMAP["ID"]} +${HELPMAP["会话权限"]}`); return ret; } @@ -94,71 +90,45 @@ function main() { AIManager.saveAI(id2); return ret; } - case 'ck': { + case 'check': { const val4 = cmdArgs.getArgN(4); if (!val4 || val4 == 'help') { seal.replyToSender(ctx, msg, `帮助: -【.ai priv s ck 】检查会话权限 - -: -【QQ:1234567890】 私聊窗口 -【QQ-Group:1234】 群聊窗口 -【now】当前窗口`); +【.ai priv ses ck 】检查会话权限 +${HELPMAP["ID"]}`); return ret; } const id2 = val4 === 'now' ? id : val4; const ai2 = AIManager.getAI(id2); - - const setting = ai2.setting; - - const counter = setting.counter > -1 ? `${setting.counter}条` : '关闭'; - const timer = setting.timer > -1 ? `${setting.timer}秒` : '关闭'; - const prob = setting.prob > -1 ? `${setting.prob}%` : '关闭'; - const standby = setting.standby ? '开启' : '关闭'; - const s = `${id2}\n权限限制:${setting.priv}\n计数器模式(c):${counter}\n计时器模式(t):${timer}\n概率模式(p):${prob}\n待机模式:${standby}`; - seal.replyToSender(ctx, msg, s); + seal.replyToSender(ctx, msg, `${id2}\n会话权限:${ai2.setting.priv}`); return ret; } default: { seal.replyToSender(ctx, msg, `帮助: -【.ai priv s st <会话权限>】修改会话权限 -【.ai priv s ck 】检查会话权限 - -: -【QQ:1234567890】 私聊窗口 -【QQ-Group:1234】 群聊窗口 -【now】当前窗口 - -<会话权限>:任意数字,越大权限越高`); +【.ai priv ses st <会话权限>】修改会话权限 +【.ai priv ses ck 】检查会话权限 +${HELPMAP["ID"]} +${HELPMAP["会话权限"]}`); return ret; } } } - case 'st': { + case 'set': { const val3 = cmdArgs.getArgN(3); if (!val3 || val3 == 'help') { seal.replyToSender(ctx, msg, `帮助: 【.ai priv st <指令> <权限限制>】修改指令权限 - -<指令>:指令名称和参数,多个指令用-连接,如ai-sb -<权限限制>:数字0-数字1-数字2,如0-0-0,含义如下: -0: 会话所需权限, 1: 会话检查通过后用户所需权限, 2: 强行触发指令用户所需权限, 进行检查时若通过0和1则无需检查2 -【-30】黑名单用户 -【0】普通用户 -【40】邀请者 -【50】群管理员 -【60】群主 -【70】白名单用户 -【100】骰主`); +${HELPMAP["指令"]} +${HELPMAP["权限限制"]}`); return ret; } - const cmdChain = val3.split('-'); - if (cmdChain?.[1] === 'priv') { + const cmdChain = val3.split('-').map(cmd => aliasToCmd(cmd)); + if (cmdChain?.[1] === 'privilege') { seal.replyToSender(ctx, msg, `你不能修改priv指令的权限`); return ret; } - const cpi = PrivilegeManager.getCmdPriv(cmdChain); + const cpi = PrivilegeManager.getCmdPrivInfo(cmdChain); if (!cpi) { seal.replyToSender(ctx, msg, `指令${val3}不存在`); return ret; @@ -185,12 +155,11 @@ function main() { if (!val3 || val3 == 'help') { seal.replyToSender(ctx, msg, `帮助: 【.ai priv show <指令>】检查指令权限 - -<指令>:指令名称和参数,多个指令用-连接,如ai-sb`); +${HELPMAP["指令"]}`); return ret; } const cmdChain = val3.split('-'); - const cpi = PrivilegeManager.getCmdPriv(cmdChain); + const cpi = PrivilegeManager.getCmdPrivInfo(cmdChain); if (!cpi) { seal.replyToSender(ctx, msg, `指令${val3}不存在`); return ret; @@ -205,28 +174,15 @@ function main() { } default: { seal.replyToSender(ctx, msg, `帮助: -【.ai priv s st <会话权限>】修改会话权限 -【.ai priv s ck 】检查会话权限 +【.ai priv ses st <会话权限>】修改会话权限 +【.ai priv ses ck 】检查会话权限 【.ai priv st <指令> <权限限制>】修改指令权限 【.ai priv show <指令>】检查指令权限 【.ai priv reset】重置指令权限 - -: -【QQ:1234567890】 私聊窗口 -【QQ-Group:1234】 群聊窗口 -【now】当前窗口 - -<会话权限>:任意数字,越大权限越高 -<指令>:指令名称和参数,多个指令用-连接,如ai-sb -<权限限制>:数字0-数字1-数字2,如0-0-0,含义如下: -0: 会话所需权限, 1: 会话检查通过后用户所需权限, 2: 强行触发指令用户所需权限, 进行检查时若通过0和1则无需检查2 -【-30】黑名单用户 -【0】普通用户 -【40】邀请者 -【50】群管理员 -【60】群主 -【70】白名单用户 -【100】骰主`); +${HELPMAP["ID"]} +${HELPMAP["会话权限"]} +${HELPMAP["指令"]} +${HELPMAP["权限限制"]}`); return ret; } } @@ -260,20 +216,8 @@ function main() { } case 'timer': { const val2 = cmdArgs.getArgN(2); - switch (val2) { - case 'clr': { - TimerManager.removeTimers(id, '', [], []); - seal.replyToSender(ctx, msg, '所有定时器已清除'); - return ret; - } - case 'help': { - seal.replyToSender(ctx, msg, `帮助: -【.ai timer】查看当前定时器 -【.ai timer clr】清除所有定时器`); - return ret; - } - case '': - default: { + switch (aliasToCmd(val2)) { + case 'list': { const timers = TimerManager.getTimers(id, '', []); if (timers.length === 0) { @@ -306,6 +250,17 @@ function main() { seal.replyToSender(ctx, msg, s); return ret; } + case 'clear': { + TimerManager.removeTimers(id, '', [], []); + seal.replyToSender(ctx, msg, '所有定时器已清除'); + return ret; + } + default: { + seal.replyToSender(ctx, msg, `帮助: +【.ai timer lst】查看当前聊天定时器 +【.ai timer clr】清除当前聊天定时器`); + return ret; + } } } case 'on': { @@ -420,7 +375,7 @@ function main() { AIManager.saveAI(id); return ret; } - case 'sb': { + case 'standby': { const setting = ai.setting; ai.resetState(); @@ -507,13 +462,11 @@ function main() { AIManager.saveAI(id); return ret; } - case 'f': - case 'fgt': { + case 'forget': { ai.resetState(); const val2 = cmdArgs.getArgN(2); - switch (val2) { - case 'ass': + switch (aliasToCmd(val2)) { case 'assistant': { ai.context.clearMessages('assistant', 'tool'); seal.replyToSender(ctx, msg, 'ai上下文已清除'); @@ -538,18 +491,16 @@ function main() { const { roleSettingTemplate } = ConfigManager.message; const val2 = cmdArgs.getArgN(2); - switch (val2) { - case '': - case 'help': { + switch (aliasToCmd(val2)) { + case 'show': { const [roleSettingIndex, _] = seal.vars.intGet(ctx, "$gSYSPROMPT"); - seal.replyToSender(ctx, msg, `帮助: -【.ai role <序号>】切换角色设定,当前角色设定序号为${roleSettingIndex},序号范围为0-${roleSettingTemplate.length - 1}`); + seal.replyToSender(ctx, msg, `当前角色设定序号为${roleSettingIndex},序号范围为0-${roleSettingTemplate.length - 1}`); return ret; } default: { const index = parseInt(val2); if (isNaN(index) || index < 0 || index >= roleSettingTemplate.length) { - seal.replyToSender(ctx, msg, `角色设定序号错误,序号范围为0-${roleSettingTemplate.length - 1}`); + seal.replyToSender(ctx, msg, `【.ai role <序号>】切换角色设定\n角色设定序号错误,序号范围为0-${roleSettingTemplate.length - 1}`); return ret; } @@ -559,13 +510,13 @@ function main() { } } } - case 'memo': { + case 'memory': { const mctx = seal.getCtxProxyFirst(ctx, cmdArgs); const muid = mctx.player.userId; const ai2 = AIManager.getAI(muid); const val2 = cmdArgs.getArgN(2); - switch (val2) { + switch (aliasToCmd(val2)) { case 'status': { let ai3 = ai; if (cmdArgs.at.length > 0 && (cmdArgs.at.length !== 1 || cmdArgs.at[0].userId !== ctx.endPoint.userId)) { @@ -587,18 +538,17 @@ function main() { 短期记忆条数: ${ai3.memory.shortMemoryList.length}`); return ret; } - case 'p': case 'private': { const val3 = cmdArgs.getArgN(3); - switch (val3) { - case 'st': { + switch (aliasToCmd(val3)) { + case 'set': { const s = cmdArgs.getRestArgsFrom(4); - switch (s) { + switch (aliasToCmd(s)) { case '': { seal.replyToSender(ctx, msg, '参数缺失,【.ai memo p st <内容>】设置个人设定,【.ai memo p st clr】清除个人设定'); return ret; } - case 'clr': { + case 'clear': { ai2.memory.persona = '无'; seal.replyToSender(ctx, msg, '设定已清除'); AIManager.saveAI(muid); @@ -616,7 +566,7 @@ function main() { } } } - case 'del': { + case 'delete': { const idList = cmdArgs.args.slice(3); const kw = cmdArgs.kwargs.map(item => item.name); if (idList.length === 0 && kw.length === 0) { @@ -634,19 +584,23 @@ function main() { seal.replyToSender(ctx, msg, s || '无'); return ret; } - case 'clr': { + case 'clear': { ai2.memory.clearMemory(); seal.replyToSender(ctx, msg, '个人记忆已清除'); AIManager.saveAI(muid); return ret; } default: { - seal.replyToSender(ctx, msg, '参数缺失,【.ai memo p show】展示个人记忆,【.ai memo p clr】清除个人记忆'); + seal.replyToSender(ctx, msg, `参数缺失: +【.ai memo p st <内容>】设置个人设定 +【.ai memo p st clr】清除个人设定 +【.ai memo p del --关键词1 --关键词2】删除个人记忆 +【.ai memo p show】展示个人记忆 +【.ai memo p clr】清除个人记忆`); return ret; } } } - case 'g': case 'group': { if (ctx.isPrivate) { seal.replyToSender(ctx, msg, '群聊记忆仅在群聊可用'); @@ -654,15 +608,15 @@ function main() { } const val3 = cmdArgs.getArgN(3); - switch (val3) { - case 'st': { + switch (aliasToCmd(val3)) { + case 'set': { const s = cmdArgs.getRestArgsFrom(4); - switch (s) { + switch (aliasToCmd(s)) { case '': { seal.replyToSender(ctx, msg, '参数缺失,【.ai memo g st <内容>】设置群聊设定,【.ai memo g st clr】清除群聊设定'); return ret; } - case 'clr': { + case 'clear': { ai.memory.persona = '无'; seal.replyToSender(ctx, msg, '设定已清除'); AIManager.saveAI(id); @@ -680,7 +634,7 @@ function main() { } } } - case 'del': { + case 'delete': { const idList = cmdArgs.args.slice(3); const kw = cmdArgs.kwargs.map(item => item.name); if (idList.length === 0 && kw.length === 0) { @@ -698,22 +652,26 @@ function main() { seal.replyToSender(ctx, msg, s || '无'); return ret; } - case 'clr': { + case 'clear': { ai.memory.clearMemory(); seal.replyToSender(ctx, msg, '群聊记忆已清除'); AIManager.saveAI(id); return ret; } default: { - seal.replyToSender(ctx, msg, '参数缺失,【.ai memo g show】展示群聊记忆,【.ai memo g clr】清除群聊记忆'); + seal.replyToSender(ctx, msg, `参数缺失: +【.ai memo g st <内容>】设置群聊设定 +【.ai memo g st clr】清除群聊设定 +【.ai memo g del --关键词1 --关键词2】删除群聊记忆 +【.ai memo g show】展示群聊记忆 +【.ai memo g clr】清除群聊记忆`); return ret; } } } - case 's': case 'short': { const val3 = cmdArgs.getArgN(3); - switch (val3) { + switch (aliasToCmd(val3)) { case 'on': { ai.memory.useShortMemory = true; seal.replyToSender(ctx, msg, '短期记忆已开启'); @@ -731,14 +689,17 @@ function main() { seal.replyToSender(ctx, msg, s || '无'); return ret; } - case 'clr': { + case 'clear': { ai.memory.clearShortMemory(); seal.replyToSender(ctx, msg, '短期记忆已清除'); AIManager.saveAI(id); return ret; } default: { - seal.replyToSender(ctx, msg, '参数缺失,【.ai memo s show】展示短期记忆,【.ai memo s clr】清除短期记忆'); + seal.replyToSender(ctx, msg, `参数缺失 +【.ai memo short show】展示短期记忆 +【.ai memo short clr】清除短期记忆 +【.ai memo short [on/off]】开启/关闭短期记忆`); return ret; } } @@ -758,9 +719,9 @@ function main() { 【.ai memo [p/g] st <内容>】设置个人/群聊设定 【.ai memo [p/g] st clr】清除个人/群聊设定 【.ai memo [p/g] del --关键词1 --关键词2】删除个人/群聊记忆 -【.ai memo [p/g/s] show】展示个人/群聊/短期记忆 -【.ai memo [p/g/s] clr】清除个人/群聊/短期记忆 -【.ai memo s [on/off]】开启/关闭短期记忆 +【.ai memo [p/g/short] show】展示个人/群聊/短期记忆 +【.ai memo [p/g/short] clr】清除个人/群聊/短期记忆 +【.ai memo short [on/off]】开启/关闭短期记忆 【.ai memo sum】立即总结一次短期记忆`); return ret; } @@ -768,18 +729,42 @@ function main() { } case 'tool': { const val2 = cmdArgs.getArgN(2); - switch (val2) { - case '': { - const toolStatus = ai.tool.toolStatus; - - let i = 1; - let s = '工具函数如下:'; - Object.keys(toolStatus).forEach(key => { - const status = toolStatus[key] ? '开' : '关'; - s += `\n${i++}. ${key}[${status}]`; - }); + switch (aliasToCmd(val2)) { + case 'on': { + const val3 = cmdArgs.getArgN(3); + if (val3) { + const toolsNotAllow = ConfigManager.tool.toolsNotAllow; + if (toolsNotAllow.includes(val3)) { + seal.replyToSender(ctx, msg, `工具函数 ${val3} 不被允许开启`); + return ret; + } - seal.replyToSender(ctx, msg, s); + ai.tool.toolStatus[val3] = true; + seal.replyToSender(ctx, msg, `已开启工具函数 ${val3}`); + AIManager.saveAI(id); + return ret; + } + const toolsNotAllow = ConfigManager.tool.toolsNotAllow; + for (const key in ai.tool.toolStatus) { + ai.tool.toolStatus[key] = toolsNotAllow.includes(key) ? false : true; + } + seal.replyToSender(ctx, msg, '已开启全部工具函数'); + AIManager.saveAI(id); + return ret; + } + case 'off': { + const val3 = cmdArgs.getArgN(3); + if (val3) { + ai.tool.toolStatus[val3] = false; + seal.replyToSender(ctx, msg, `已关闭工具函数 ${val3}`); + AIManager.saveAI(id); + return ret; + } + for (const key in ai.tool.toolStatus) { + ai.tool.toolStatus[key] = false; + } + seal.replyToSender(ctx, msg, '已关闭全部工具函数'); + AIManager.saveAI(id); return ret; } case 'help': { @@ -787,10 +772,9 @@ function main() { if (!val3) { seal.replyToSender(ctx, msg, `帮助: 【.ai tool】列出所有工具 +【.ai tool [on/off] <函数名>】开启或关闭工具函数 【.ai tool help <函数名>】查看工具详情 -【.ai tool [on/off]】开启或关闭全部工具函数 -【.ai tool <函数名> [on/off]】开启或关闭工具函数 -【.ai tool <函数名> --参数名=具体参数】试用工具函数`); +【.ai tool call <函数名> --参数名=具体参数】试用工具函数`); return ret; } @@ -803,102 +787,71 @@ function main() { const s = `${tool.info.function.name} 描述:${tool.info.function.description} -参数: -${Object.keys(tool.info.function.parameters.properties).map(key => { - const property = tool.info.function.parameters.properties[key]; - return `【${key}】${property.description}`; - }).join('\n')} +参数信息: +${JSON.stringify(tool.info.function.parameters.properties, null, 2)} 必需参数:${tool.info.function.parameters.required.join(',')}`; seal.replyToSender(ctx, msg, s); return ret; } - case 'on': { - const toolsNotAllow = ConfigManager.tool.toolsNotAllow; - for (const key in ai.tool.toolStatus) { - ai.tool.toolStatus[key] = toolsNotAllow.includes(key) ? false : true; - } - seal.replyToSender(ctx, msg, '已开启全部工具函数'); - AIManager.saveAI(id); - return ret; - } - case 'off': { - for (const key in ai.tool.toolStatus) { - ai.tool.toolStatus[key] = false; - } - seal.replyToSender(ctx, msg, '已关闭全部工具函数'); - AIManager.saveAI(id); - return ret; - } - default: { - if (!ToolManager.toolMap.hasOwnProperty(val2)) { - seal.replyToSender(ctx, msg, '没有这个工具函数'); + case 'call': { + if (ToolManager.cmdArgs == null) { + seal.replyToSender(ctx, msg, `暂时无法调用函数,请先使用 .r 指令`); return ret; } - // 开启或关闭工具函数 const val3 = cmdArgs.getArgN(3); - switch (val3) { - case 'on': { - const toolsNotAllow = ConfigManager.tool.toolsNotAllow; - if (toolsNotAllow.includes(val2)) { - seal.replyToSender(ctx, msg, `工具函数 ${val2} 不被允许开启`); - return ret; - } - - ai.tool.toolStatus[val2] = true; - seal.replyToSender(ctx, msg, `已开启工具函数 ${val2}`); - AIManager.saveAI(id); - return ret; - } - case 'off': { - ai.tool.toolStatus[val2] = false; - seal.replyToSender(ctx, msg, `已关闭工具函数 ${val2}`); - AIManager.saveAI(id); - return ret; - } - default: { - if (ToolManager.cmdArgs == null) { - seal.replyToSender(ctx, msg, `暂时无法调用函数,请先使用 .r 指令`); - return ret; - } - - const tool = ToolManager.toolMap[val2]; + if (!val3) { + seal.replyToSender(ctx, msg, `调用函数缺少工具函数名`); + return ret; + } + const tool = ToolManager.toolMap[val3]; + try { + const args = cmdArgs.kwargs.reduce((acc, kwarg) => { + const valueString = kwarg.value; try { - const args = cmdArgs.kwargs.reduce((acc, kwarg) => { - const valueString = kwarg.value; - try { - acc[kwarg.name] = JSON.parse(`[${valueString}]`)[0]; - } catch (e) { - acc[kwarg.name] = valueString; - } - return acc; - }, {}); - - for (const key of tool.info.function.parameters.required) { - if (!args.hasOwnProperty(key)) { - logger.warning(`调用函数失败:缺少必需参数 ${key}`); - seal.replyToSender(ctx, msg, `调用函数失败:缺少必需参数 ${key}`); - return ret; - } - } - - tool.solve(ctx, msg, ai, args) - .then(({ content }) => seal.replyToSender(ctx, msg, content)); - return ret; + acc[kwarg.name] = JSON.parse(`[${valueString}]`)[0]; } catch (e) { - const s = `调用函数 (${val2}) 失败:${e.message}`; - seal.replyToSender(ctx, msg, s); + acc[kwarg.name] = valueString; + } + return acc; + }, {}); + + for (const key of tool.info.function.parameters.required) { + if (!args.hasOwnProperty(key)) { + logger.warning(`调用函数失败:缺少必需参数 ${key}`); + seal.replyToSender(ctx, msg, `调用函数失败:缺少必需参数 ${key}`); return ret; } } + + tool.solve(ctx, msg, ai, args) + .then(({ content }) => seal.replyToSender(ctx, msg, content)); + return ret; + } catch (e) { + const s = `调用函数 (${val3}) 失败:${e.message}`; + seal.replyToSender(ctx, msg, s); + return ret; } } + default: { + const toolStatus = ai.tool.toolStatus; + + let i = 1; + let s = '工具函数如下:'; + Object.keys(toolStatus).forEach(key => { + const status = toolStatus[key] ? '开' : '关'; + s += `\n${i++}. ${key}[${status}]`; + }); + + seal.replyToSender(ctx, msg, s); + return ret; + } } } - case 'ign': { + case 'ignore': { if (ctx.isPrivate) { seal.replyToSender(ctx, msg, '忽略名单仅在群聊可用'); return ret; @@ -909,7 +862,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { const muid = cmdArgs.amIBeMentionedFirst ? epId : mctx.player.userId; const val2 = cmdArgs.getArgN(2); - switch (val2) { + switch (aliasToCmd(val2)) { case 'add': { if (cmdArgs.at.length === 0) { seal.replyToSender(ctx, msg, '参数缺失,【.ai ign add @xxx】添加忽略名单'); @@ -924,7 +877,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { AIManager.saveAI(id); return ret; } - case 'rm': { + case 'remove': { if (cmdArgs.at.length === 0) { seal.replyToSender(ctx, msg, '参数缺失,【.ai ign rm @xxx】移除忽略名单'); return ret; @@ -947,17 +900,17 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `帮助: 【.ai ign add @xxx】添加忽略名单 【.ai ign rm @xxx】移除忽略名单 -【.ai ign list】列出忽略名单 +【.ai ign lst】列出忽略名单 忽略名单中的对象仍能正常对话,但无法被选中QQ号`); return ret; } } } - case 'tk': { + case 'token': { const val2 = cmdArgs.getArgN(2); - switch (val2) { - case 'lst': { + switch (aliasToCmd(val2)) { + case 'list': { const s = Object.keys(AIManager.usageMap).join('\n'); seal.replyToSender(ctx, msg, `有使用记录的模型:\n${s}`); return ret; @@ -1007,7 +960,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `全部使用记录如下:\n${s}`); return ret; } - case 'y': { + case 'year': { const obj: { [key: string]: { prompt_tokens: number; @@ -1073,7 +1026,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `最近12个月使用记录如下:\n${s}`); return ret; } - case 'm': { + case 'month': { const obj: { [key: string]: { prompt_tokens: number; @@ -1135,7 +1088,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `最近31天使用记录如下:\n${s}`); return ret; } - case 'clr': { + case 'clear': { const val3 = cmdArgs.getArgN(3); if (!val3) { AIManager.clearUsageMap(); @@ -1174,8 +1127,8 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { } const val3 = cmdArgs.getArgN(3); - switch (val3) { - case 'y': { + switch (aliasToCmd(val3)) { + case 'year': { const obj: { [key: string]: { prompt_tokens: number; @@ -1241,7 +1194,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `最近12个月使用记录如下:\n${s}`); return ret; } - case 'm': { + case 'month': { const obj: { [key: string]: { prompt_tokens: number; @@ -1362,16 +1315,16 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { const ret = seal.ext.newCmdExecuteResult(true); const ai = AIManager.getAI(id); - if (!PrivilegeManager.checkPriv(ctx, cmdArgs, ai)) { - seal.replyToSender(ctx, msg, "权限不足或指令不存在"); + const { success, exist } = PrivilegeManager.checkPriv(ctx, cmdArgs, ai); + if (!success) { + seal.replyToSender(ctx, msg, exist ? '权限不足' : '命令不存在'); return ret; } - switch (val) { + switch (aliasToCmd(val)) { case 'draw': { const type = cmdArgs.getArgN(2); - switch (type) { - case 'lcl': + switch (aliasToCmd(type)) { case 'local': { const file = ai.imageManager.drawLocalImageFile(); if (!file) { @@ -1381,8 +1334,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `[CQ:image,file=${file}]`); return ret; } - case 'stl': - case 'stolen': { + case 'steal': { ai.imageManager.drawStolenImageFile() .then(file => seal.replyToSender(ctx, msg, file ? `[CQ:image,file=${file}]` : '暂无偷取图片')); return ret; @@ -1406,10 +1358,9 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { } } } - case 'stl': case 'steal': { const op = cmdArgs.getArgN(2); - switch (op) { + switch (aliasToCmd(op)) { case 'on': { ai.imageManager.stealStatus = true; seal.replyToSender(ctx, msg, `图片偷取已开启,当前偷取数量:${ai.imageManager.stolenImages.filter(img => img.isUrl).length}`); @@ -1428,13 +1379,10 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { } } } - case 'f': - case 'fgt': case 'forget': { const type = cmdArgs.getArgN(2); - switch (type) { - case 'stl': - case 'stolen': { + switch (aliasToCmd(type)) { + case 'steal': { ai.imageManager.stolenImages = []; seal.replyToSender(ctx, msg, '偷取图片已遗忘'); AIManager.saveAI(id); @@ -1466,33 +1414,37 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { return ret; } - if (val2 == 'ran') { - ai.imageManager.drawStolenImageFile() - .then(url => { - if (!url) { - seal.replyToSender(ctx, msg, '图片偷取为空'); - return; - } - const text = cmdArgs.getRestArgsFrom(3); - ImageManager.imageToText(url, text) - .then(s => seal.replyToSender(ctx, msg, `[CQ:image,file=${url}]\n` + s)); - }); - } else { - const messageItem0 = transformTextToArray(val2)?.[0]; - const url = messageItem0?.data?.url || messageItem0?.data?.file; - if (messageItem0?.type !== 'image' || !url) { - seal.replyToSender(ctx, msg, '请附带图片'); + switch (aliasToCmd(val2)) { + case 'random': { + ai.imageManager.drawStolenImageFile() + .then(url => { + if (!url) { + seal.replyToSender(ctx, msg, '图片偷取为空'); + return; + } + const text = cmdArgs.getRestArgsFrom(3); + ImageManager.imageToText(url, text) + .then(s => seal.replyToSender(ctx, msg, `[CQ:image,file=${url}]\n` + s)); + }); return ret; } - const text = cmdArgs.getRestArgsFrom(3); - ImageManager.imageToText(url, text) - .then(s => seal.replyToSender(ctx, msg, `[CQ:image,file=${url}]\n` + s)); + default: { + const messageItem0 = transformTextToArray(val2)?.[0]; + const url = messageItem0?.data?.url || messageItem0?.data?.file; + if (messageItem0?.type !== 'image' || !url) { + seal.replyToSender(ctx, msg, '请附带图片'); + return ret; + } + const text = cmdArgs.getRestArgsFrom(3); + ImageManager.imageToText(url, text) + .then(s => seal.replyToSender(ctx, msg, `[CQ:image,file=${url}]\n` + s)); + } + return ret; } - return ret; } case 'save': { const val2 = cmdArgs.getArgN(2); - switch (val2) { + switch (aliasToCmd(val2)) { case '': { seal.replyToSender(ctx, msg, '参数缺失,【.img save 名称 场景1,场景2,... 图片】保存图片,【.img save show】展示保存的图片,【.img save clr】清除所有保存的图片,【.img save del <图片名称1> <图片名称2> ...】删除指定名称的保存图片'); return ret; @@ -1511,13 +1463,13 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { seal.replyToSender(ctx, msg, `保存的图片列表:\n${imageList}`); return ret; } - case 'clr': { + case 'clear': { ai.imageManager.clearSavedImages(); seal.replyToSender(ctx, msg, '已清除所有保存的图片'); AIManager.saveAI(id); return ret; } - case 'del': { + case 'delete': { const nameList = cmdArgs.args.slice(2); if (nameList.length === 0) { seal.replyToSender(ctx, msg, '参数缺失,【.img del <图片名称1> <图片名称2> ...】删除指定名称的保存图片'); diff --git a/src/privilege.ts b/src/privilege.ts index 0391e50..af586fb 100644 --- a/src/privilege.ts +++ b/src/privilege.ts @@ -1,178 +1,192 @@ import { AI } from "./AI/AI"; import { logger } from "./logger"; -import { ConfigManager } from "./config/config"; +import { ConfigManager, PRIVILEGELEVELMAP } from "./config/config"; +import { aliasToCmd } from "./utils/utils"; + export interface CmdPrivInfo { - cmd: string[]; priv: [number, number, number], // 0: 会话所需权限, 1: 会话检查通过后用户所需权限, 2: 强行触发指令用户所需权限, 进行检查时若通过0和1则无需检查2 - args?: CmdPrivInfo[]; // 需通过前一级检查才可检查子命令 + args?: CmdPriv; // 需通过前一级检查才可检查子命令 } -const defaultCmdPriv: CmdPrivInfo[] = [ - { - cmd: ["ai", "AI"], priv: [0, 0, 0], args: [ - { - cmd: ["priv"], priv: [0, 100, 100], args: [ - { - cmd: ["s", "session"], priv: [0, 0, 0], args: [ - { cmd: ["st"], priv: [0, 0, 0] }, - { cmd: ["ck"], priv: [0, 0, 0] }, - ] +export interface CmdPriv { [key: string]: CmdPrivInfo }; + +const U: [number, number, number] = [0, PRIVILEGELEVELMAP.user, PRIVILEGELEVELMAP.user]; // user +const M: [number, number, number] = [0, PRIVILEGELEVELMAP.master, PRIVILEGELEVELMAP.master]; // master +const I: [number, number, number] = [0, PRIVILEGELEVELMAP.inviter, PRIVILEGELEVELMAP.inviter]; // inviter +const S: [number, number, number] = [1, PRIVILEGELEVELMAP.inviter, PRIVILEGELEVELMAP.master]; // spesial,会话所需权限为1,是才能被邀请者使用,否则需为骰主 + +export const defaultCmdPriv: CmdPriv = { + ai: { + priv: U, args: { + privilege: { + priv: M, args: { + session: { + priv: U, args: { + set: { priv: U }, + check: { priv: U } + } }, - { cmd: ["st"], priv: [0, 0, 0] }, - { cmd: ["show"], priv: [0, 0, 0] }, - { cmd: ["reset"], priv: [0, 0, 0] }, - ] + set: { priv: U }, + show: { priv: U }, + reset: { priv: U } + } }, - { cmd: ["prompt"], priv: [0, 100, 100] }, - { cmd: ["status"], priv: [0, 0, 0] }, - { cmd: ["ctxn"], priv: [0, 0, 0] }, - { - cmd: ["timer"], priv: [0, 0, 0], args: [ - { cmd: ["clr"], priv: [0, 40, 40] } - ] + prompt: { priv: M }, + status: { priv: U }, + ctxn: { priv: U }, + timer: { + priv: U, args: { + list: { priv: U }, + clear: { priv: I } + } + }, + on: { priv: S }, + standby: { priv: I }, + off: { priv: I }, + forget: { + priv: I, args: { + assistant: { priv: U }, + user: { priv: U } + } }, - { cmd: ["on"], priv: [1, 40, 100] }, - { cmd: ["sb"], priv: [0, 40, 40] }, - { cmd: ["off"], priv: [0, 40, 40] }, - { - cmd: ["f", "fgt"], priv: [0, 40, 40], args: [ - { cmd: ["ass", "assistant"], priv: [0, 0, 0] }, - { cmd: ["user"], priv: [0, 0, 0] } - ] + role: { + priv: S, args: { + show: { priv: U }, + "*": { priv: U }, + } }, - { cmd: ["role"], priv: [1, 40, 40] }, - { - cmd: ["memo"], priv: [0, 0, 0], args: [ - { cmd: ["status"], priv: [0, 0, 0] }, - { - cmd: ["p", "private"], priv: [0, 0, 0], args: [ - { - cmd: ["st"], priv: [0, 0, 0], args: [ - { cmd: ["clr"], priv: [0, 0, 0] }, - { cmd: ["*"], priv: [0, 0, 0] } - ] + memory: { + priv: U, args: { + status: { priv: U }, + private: { + priv: U, args: { + set: { + priv: U, args: { + clear: { priv: U }, + "*": { priv: U } + } }, - { cmd: ["del"], priv: [0, 0, 0] }, - { cmd: ["show"], priv: [0, 0, 0] }, - { cmd: ["clr"], priv: [0, 0, 0] } - ] + delete: { priv: U }, + show: { priv: U }, + clear: { priv: U } + } }, - { - cmd: ["g", "group"], priv: [0, 40, 40], args: [ - { - cmd: ["st"], priv: [0, 0, 0], args: [ - { cmd: ["clr"], priv: [0, 0, 0] }, - { cmd: ["*"], priv: [0, 0, 0] } - ] + group: { + priv: I, args: { + set: { + priv: U, args: { + clear: { priv: U }, + "*": { priv: U } + } }, - { cmd: ["del"], priv: [0, 0, 0] }, - { cmd: ["show"], priv: [0, 0, 0] }, - { cmd: ["clr"], priv: [0, 0, 0] } - ] + delete: { priv: U }, + show: { priv: U }, + clear: { priv: U } + } }, - { - cmd: ["s", "short"], priv: [1, 40, 100], args: [ - { cmd: ["show"], priv: [0, 0, 0] }, - { cmd: ["clr"], priv: [0, 0, 0] }, - { cmd: ["on"], priv: [0, 0, 0] }, - { cmd: ["off"], priv: [0, 0, 0] } - ] + short: { + priv: S, args: { + show: { priv: U }, + clear: { priv: U }, + on: { priv: U }, + off: { priv: U } + } }, - { cmd: ["sum"], priv: [1, 40, 100] } - ] + sum: { priv: U } + } }, - { - cmd: ["tool"], priv: [0, 40, 40], args: [ - { cmd: ["help"], priv: [0, 0, 0] }, - { cmd: ["on"], priv: [0, 0, 0] }, - { cmd: ["off"], priv: [0, 0, 0] }, - { - cmd: ["*"], priv: [1, 100, 100], args: [ - { cmd: ["on"], priv: [0, 0, 0] }, - { cmd: ["off"], priv: [0, 0, 0] } - ] - } - ] + tool: { + priv: U, args: { + on: { priv: I }, + off: { priv: I }, + help: { priv: U }, + call: { priv: M }, + "*": { priv: U } + } }, - { - cmd: ["ign"], priv: [0, 0, 0], args: [ - { cmd: ["add"], priv: [0, 0, 0] }, - { cmd: ["rm"], priv: [0, 0, 0] }, - { cmd: ["list"], priv: [0, 0, 0] } - ] + ignore: { + priv: U, args: { + add: { priv: U }, + remove: { priv: U }, + list: { priv: U } + } }, - { - cmd: ["tk"], priv: [1, 40, 100], args: [ - { cmd: ["lst"], priv: [0, 0, 0] }, - { cmd: ["sum"], priv: [0, 0, 0] }, - { cmd: ["all"], priv: [0, 0, 0] }, - { - cmd: ["y"], priv: [0, 0, 0], args: [ - { cmd: ["chart"], priv: [0, 0, 0] } - ] + token: { + priv: S, args: { + list: { priv: U }, + sum: { priv: U }, + all: { priv: U }, + year: { + priv: U, args: { + chart: { priv: U } + } }, - { - cmd: ["m"], priv: [0, 0, 0], args: [ - { cmd: ["chart"], priv: [0, 0, 0] } - ] + month: { + priv: U, args: { + chart: { priv: U } + } }, - { cmd: ["clr"], priv: [0, 0, 0] } - ] + clear: { priv: U }, + help: { priv: U }, + "*": { priv: U } + } }, - { cmd: ["shut"], priv: [0, 0, 0] } - ] + shut: { priv: U } + } }, - { - cmd: ["img"], priv: [0, 0, 0], args: [ - { - cmd: ["draw"], priv: [0, 0, 0], args: [ - { cmd: ["lcl", "local"], priv: [0, 0, 0] }, - { cmd: ["stl", "stolen"], priv: [0, 0, 0] }, - { cmd: ["save"], priv: [0, 0, 0] }, - { cmd: ["all"], priv: [0, 0, 0] } - ] + img: { + priv: U, args: { + draw: { + priv: U, args: { + local: { priv: U }, + steal: { priv: U }, + save: { priv: U }, + all: { priv: U } + } }, - { - cmd: ["stl", "steal"], priv: [0, 40, 40], args: [ - { cmd: ["on"], priv: [0, 0, 0] }, - { cmd: ["off"], priv: [0, 0, 0] } - ] + steal: { + priv: I, args: { + on: { priv: U }, + off: { priv: U } + } }, - { - cmd: ["f", "fgt", "forget"], priv: [0, 40, 40], args: [ - { cmd: ["stl", "stolen"], priv: [0, 0, 0] }, - { cmd: ["save"], priv: [0, 0, 0] }, - { cmd: ["all"], priv: [0, 0, 0] } - ] + forget: { + priv: I, args: { + steal: { priv: U }, + save: { priv: U }, + all: { priv: U } + } }, - { - cmd: ["itt"], priv: [1, 100, 100], args: [ - { cmd: ["ran"], priv: [0, 0, 0] }, - { cmd: ["*"], priv: [0, 0, 0] } - ] + itt: { + priv: M, args: { + random: { priv: U }, + "*": { priv: U } + } }, - { - cmd: ["save"], priv: [0, 40, 40], args: [ - { cmd: ["show"], priv: [0, 0, 0] }, - { cmd: ["clr"], priv: [0, 0, 0] }, - { cmd: ["del"], priv: [0, 0, 0] }, - { cmd: ["*"], priv: [1, 100, 100] } - ] + save: { + priv: I, args: { + show: { priv: U }, + clear: { priv: U }, + delete: { priv: U }, + "*": { priv: M } + } } - ] - }, -]; + } + } +}; export class PrivilegeManager { - static cmdPriv: CmdPrivInfo[] = defaultCmdPriv; + static cmdPriv: CmdPriv = defaultCmdPriv; static reviveCmdPriv() { try { - const cmdPriv = JSON.parse(ConfigManager.ext.storageGet('cmdPriv') || '[]'); - if (cmdPriv.length > 0) { - this.cmdPriv = this.updateCmdPriv(cmdPriv, defaultCmdPriv); + const cmdPriv = JSON.parse(ConfigManager.ext.storageGet('cmdPriv') || '{}'); + if (typeof cmdPriv === 'object' && !Array.isArray(cmdPriv)) { + this.cmdPriv = this.updateCmdPriv(cmdPriv, JSON.parse(JSON.stringify(defaultCmdPriv))); this.saveCmdPriv(); + } else { + this.resetCmdPriv(); } } catch (error) { logger.error(`从数据库中获取cmdPriv失败:`, error); @@ -183,79 +197,79 @@ export class PrivilegeManager { ConfigManager.ext.storageSet('cmdPriv', JSON.stringify(this.cmdPriv)); } - static updateCmdPriv(cp: CmdPrivInfo[], defaultCp: CmdPrivInfo[]): CmdPrivInfo[] { - const newCp: CmdPrivInfo[] = []; - for (const defaultCpi of defaultCp) { - const cpi = cp.find(cpi => defaultCpi.cmd.some(c => cpi.cmd.includes(c))); - if (!cpi) { - newCp.push(defaultCpi); + static updateCmdPriv(cp: CmdPriv, defaultCp: CmdPriv): CmdPriv { + const newCp: CmdPriv = {}; + for (const cmd in defaultCp) { + const defaultCpi = defaultCp[cmd]; + if (!cp.hasOwnProperty(cmd)) { + newCp[cmd] = defaultCpi; } else { - if (defaultCpi.args) { - cpi.cmd = defaultCpi.cmd; - if (cpi.args) { + const cpi = cp[cmd]; + if (defaultCpi.hasOwnProperty('args')) { + if (cpi.hasOwnProperty('args')) { cpi.args = this.updateCmdPriv(cpi.args, defaultCpi.args); } else { cpi.args = defaultCpi.args; } - } else if (cpi.args) { + } else if (cpi.hasOwnProperty('args')) { delete cpi.args; } - newCp.push(cpi); + newCp[cmd] = cpi; } } return newCp; } static resetCmdPriv() { - this.cmdPriv = defaultCmdPriv; + this.cmdPriv = JSON.parse(JSON.stringify(defaultCmdPriv)); this.saveCmdPriv(); } - static getCmdPriv(cmdChain: string[], cp: CmdPrivInfo[] = this.cmdPriv): CmdPrivInfo | null { + static getCmdPrivInfo(cmdChain: string[], cp: CmdPriv = this.cmdPriv): CmdPrivInfo | null { if (cmdChain.length === 0) { return null; } - const cpi = cp.find(cpi => cpi.cmd.includes(cmdChain[0])); - if (!cpi) { + const cmd = aliasToCmd(cmdChain[0]); + if (!cp.hasOwnProperty(cmd)) { return null; } + const cpi = cp[cmd]; if (cpi.args && cmdChain.length > 1) { - return this.getCmdPriv(cmdChain.slice(1), cpi.args); + return this.getCmdPrivInfo(cmdChain.slice(1), cpi.args); } return cpi; } - static checkPriv(ctx: seal.MsgContext, cmdArgs: seal.CmdArgs, ai: AI): boolean { + static checkPriv(ctx: seal.MsgContext, cmdArgs: seal.CmdArgs, ai: AI): { success: boolean, exist: boolean } { const sessionPriv = ai.setting.priv; const userPriv = ctx.privilegeLevel; - const cmdChain = [cmdArgs.command, ...cmdArgs.args]; + const cmdChain = [cmdArgs.command, ...cmdArgs.args].map(cmd => aliasToCmd(cmd)); - function checkCmdPriv(cp: CmdPrivInfo[], i: number): boolean { + function checkCmdPriv(cp: CmdPriv, i: number): { success: boolean, exist: boolean } { if (i >= cmdChain.length) { - return true; + return { success: true, exist: true }; } - for (const cpi of cp) { - if (!cpi.cmd.includes(cmdChain[i]) && !cpi.cmd.includes("*")) { - continue; - } + const cmd = cmdChain[i]; + if (!cp.hasOwnProperty(cmd) && !cp.hasOwnProperty("*")) { + logger.warning(`权限检查失败,命令:[${cmdChain.join(' ')}],未在权限列表中找到匹配项`); + return { success: false, exist: false }; + } - if (sessionPriv >= cpi.priv[0] && userPriv >= cpi.priv[1]) { - return cpi.args ? checkCmdPriv(cpi.args, i + 1) : true; - } + const cpi = cp[cmd] || cp["*"]; - if (userPriv >= cpi.priv[2]) { - return cpi.args ? checkCmdPriv(cpi.args, i + 1) : true; - } + if (sessionPriv >= cpi.priv[0] && userPriv >= cpi.priv[1]) { + return cpi.args ? checkCmdPriv(cpi.args, i + 1) : { success: true, exist: true }; + } - return false; + if (userPriv >= cpi.priv[2]) { + return cpi.args ? checkCmdPriv(cpi.args, i + 1) : { success: true, exist: true }; } - logger.warning(`权限检查失败,命令:${cmdChain.join(' ')},未在权限列表中找到匹配项`); - return false; + return { success: false, exist: true }; } return checkCmdPriv(this.cmdPriv, 0); diff --git a/src/tool/tool_qq_list.ts b/src/tool/tool_qq_list.ts index df649de..026293c 100644 --- a/src/tool/tool_qq_list.ts +++ b/src/tool/tool_qq_list.ts @@ -232,7 +232,7 @@ export function registerQQList() { name: { type: 'string', description: '用户名称' + (ConfigManager.message.showNumber ? '或纯数字QQ号' : '') - }, + } }, required: ["name"] } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 912a7ee..b9a7cb8 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -129,4 +129,34 @@ export function revive(constructor: { new(): T, validKeys: (keyof T)[] }, val } return obj; +} + +export function aliasToCmd(val: string) { + // 命令别名映射表,别名:原始命令 + const aliasMap = { + "AI": "ai", + "priv": "privilege", + "ses": "session", + "st": "set", + "ck": "check", + "clr": "clear", + "sb": "standby", + "fgt": "forget", + "f": "forget", + "ass": "assistant", + "memo": "memory", + "p": "private", + "g": "group", + "del": "delete", + "ign": "ignore", + "rm": "remove", + "lst": "list", + "tk": "token", + "y": "year", + "m": "month", + "lcl": "local", + "stl": "steal", + "ran": "random", + } + return aliasMap[val] || val; } \ No newline at end of file