diff --git a/README.md b/README.md index 074b063..5337509 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,15 @@ - 生成任务收尾包:把状态、验证计划、可选验证执行、全局 review 和历史清理收成一份结果。 - 生成页面测试用例:内置“先写用例、可视化证据、事不过三”的测试闭环。 - 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。 -- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、Web/Playground 回跳。 +- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。 - 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。 - 生成远程只读健康检查和数据库同步安全向导:覆盖飞牛 NAS 服务探测、GTID、备份和行数校验。 -- 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、Knife4jSwagger 的防踩坑清单和验证点。 +- 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger 的防踩坑清单和验证点。 - 生成验证进程清理计划:按项目路径和端口给出 PowerShell 检查命令,不直接杀进程。 - 清理历史产物:统一治理 `.kt-workspace` 下的测试/验证产物,按目录最近修改时间只保留最近 3 轮,模板目录永久保留。 - 检查 env 策略和变更风险:区分后端真实 env 与前端客户端 `.env*`,提醒锁文件、核心表格组件、部署链路和 Vue TSX 插槽写法等高风险改动。 -- 全局 CodeReview 只读扫描:汇总全部 KT 子仓库的 Git 状态、敏感文件跟踪、冲突标记、运行时调试输出、疑似凭据字面量、根目录生成产物和当前变更风险;任何文件改动后都要跑一遍。 -- 生成或写入 `TASKS.md` 改动记录:默认 `dryRun=true`,确认后再落盘。 +- 全局 CodeReview 只读扫描:汇总全部 KT 子仓库的 Git 状态、敏感文件跟踪、冲突标记、运行时调试输出、疑似凭据字面量、根目录生成产物和当前变更风险;默认只对变更文件做内容扫描,避免历史误报污染上下文;任何文件改动后都要跑一遍。 +- 生成或写入 `TASKS.md` 最近记录:默认 `dryRun=true`,确认后再落盘。 - 生成提交前检查清单:校验 KT commit message 约定。 ## 安装 @@ -74,15 +74,15 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `kt_cleanup_process_plan` | 生成验证进程清理检查命令 | | `kt_env_policy` | 检查 env 文件现状和提交策略 | | `kt_risk_scan` | 扫描当前或传入变更文件的偏差风险 | -| `kt_global_code_review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描 | +| `kt_global_code_review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,默认仅深扫变更文件 | | `kt_finish_task` | 生成任务收尾包,可选执行验证和历史清理 | | `kt_commit_plan` | 生成多仓库提交计划、建议 commit message 和检查项 | | `kt_push_plan` | 生成多仓库推送计划和远程异常提醒 | -| `kt_business_test_plan` | 生成固化业务链路测试计划 | +| `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 | | `kt_remote_health_check` | 生成或执行远程只读健康检查命令 | | `kt_db_sync_plan` | 生成数据库同步安全向导 | | `kt_component_workflow` | 输出专项组件/链路防踩坑工作流 | -| `kt_append_task_record` | 预览或写入 `TASKS.md` 改动记录 | +| `kt_append_task_record` | 预览或写入 `TASKS.md` 最近记录 | | `kt_commit_checklist` | 生成提交前检查清单并校验 commit message | ## 可复用脚本 @@ -90,7 +90,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | 脚本 | 用途 | | --- | --- | | `pnpm run admin-login` | 使用可见 Edge 打开 Admin 登录页,填写账号密码,拖动滑块,保存登录态和截图。默认账号来自初始化数据 `admin/123456`,生产或个人账号用 `KT_ADMIN_USERNAME` / `KT_ADMIN_PASSWORD` 或 CLI 参数覆盖。 | -| `pnpm run global-review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,输出 JSON 复审报告。 | +| `pnpm run global-review` | 对 KT 全部子仓库做只读全局 CodeReview 扫描,默认仅对变更文件做内容深扫,输出 JSON 复审报告。 | ## 项目别名 @@ -122,10 +122,10 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login - 要收尾时调用 `kt_finish_task`,默认只生成计划和 review;需要执行验证时显式传 `runValidation=true`。 - 文件改动完成并验证后调用 `kt_global_code_review`,或运行 `pnpm run global-review`;它只读扫描,不删除文件、不提交代码。 - 要提交或推送时先调用 `kt_commit_plan` / `kt_push_plan`,按仓库分组确认范围。 -- 要测真实业务链路时调用 `kt_business_test_plan`,选择 `admin-login`、`qqbot-auto-reply` 等 flow。 +- 要测真实业务链路时调用 `kt_business_test_plan`,选择 `admin-login`、`qqbot-auto-reply`、`qqbot-login-sse`、`fflogs-command`、`system-log-visualization` 等 flow。 - 远程服务排查先调用 `kt_remote_health_check`,默认只生成只读命令;需要执行时显式传 `execute=true`。 - 数据库同步前调用 `kt_db_sync_plan`,先确认源库、目标库、备份库和校验点。 -- 改 KtTable、BlogArgon、AdminAuth、QQBot、Knife4jSwagger 前调用 `kt_component_workflow`,先看专项禁区。 +- 改 KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger 前调用 `kt_component_workflow`,先看专项禁区。 - 不确定任务边界时调用 `kt_guardrails`,先拿到“能做什么、不能做什么、怎么验证”。 - 验证前调用 `kt_suggest_verification`,避免盲跑全量构建。 - 页面测试前调用 `kt_create_page_test_case`,再执行 Playwright/浏览器测试。 diff --git a/package.json b/package.json index 2acf896..076ecc8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kt/mcp-kt-workflow", - "version": "0.5.0", + "version": "0.6.0", "private": true, "type": "module", "description": "Reusable MCP workflow tools for the KT workspace.", diff --git a/src/registerTools.ts b/src/registerTools.ts index fe9d663..9872a7d 100644 --- a/src/registerTools.ts +++ b/src/registerTools.ts @@ -205,8 +205,9 @@ export function registerTools(server: McpServer): void { server.registerTool( 'kt_global_code_review', { - description: '对 KT 已知子仓库做只读全局 CodeReview 扫描:Git 状态、tracked env/deploy/secrets、冲突标记、调试输出、疑似凭据字面量和当前变更风险。', + description: '对 KT 已知子仓库做只读全局 CodeReview 扫描:Git 状态、tracked env/deploy/secrets、冲突标记、调试输出、疑似凭据字面量和当前变更风险。默认只对变更文件做内容扫描,避免历史误报污染上下文。', inputSchema: { + contentScanMode: z.enum(['changed', 'all']).default('changed'), includeContentScan: z.boolean().default(true), includeRootScan: z.boolean().default(true), maxFindingsPerProject: z.number().int().min(1).max(200).default(20), @@ -224,6 +225,7 @@ export function registerTools(server: McpServer): void { inputSchema: { changeType: z.enum(taskTypeValues).default('general'), cleanupHistory: z.boolean().default(false), + contentScanMode: z.enum(['changed', 'all']).default('changed'), includeRootScan: z.boolean().default(true), keepHistory: z.number().int().min(0).max(50).default(3), maxFindingsPerProject: z.number().int().min(1).max(200).default(20), @@ -274,8 +276,11 @@ export function registerTools(server: McpServer): void { .enum([ 'admin-login', 'blog-crud', + 'fflogs-command', 'qqbot-account-scan', 'qqbot-auto-reply', + 'qqbot-login-sse', + 'system-log-visualization', 'web-playground-auth', 'all', ]) @@ -319,10 +324,19 @@ export function registerTools(server: McpServer): void { server.registerTool( 'kt_component_workflow', { - description: '按 KT 专项组件/链路输出防踩坑工作流:KtTable、BlogArgon、AdminAuth、QQBot、Knife4jSwagger。', + description: '按 KT 专项组件/链路输出防踩坑工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger。', inputSchema: { target: z - .enum(['AdminAuth', 'BlogArgon', 'Knife4jSwagger', 'KtTable', 'QQBot']) + .enum([ + 'AdminAuth', + 'BlogArgon', + 'FF14Plugin', + 'Knife4jSwagger', + 'KtTable', + 'NapCatLogin', + 'QQBot', + 'SystemLog', + ]) .default('KtTable'), }, title: 'KT Component Workflow', diff --git a/src/selfTest.ts b/src/selfTest.ts index 9a9f215..3cca7dc 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -38,13 +38,13 @@ export async function runSelfTest(): Promise { projects: ['mcp'], }), businessTestPlan: buildBusinessTestPlan({ - flow: 'qqbot-auto-reply', + flow: 'system-log-visualization', }), commitPlan: await buildCommitPlan({ projects: ['mcp'], }), componentWorkflow: buildComponentWorkflow({ - target: 'Knife4jSwagger', + target: 'SystemLog', }), dbSyncPlan: buildDbSyncPlan({}), finishTask: await buildFinishTask({ diff --git a/src/tools/envRisk.ts b/src/tools/envRisk.ts index 45b24d3..3725549 100644 --- a/src/tools/envRisk.ts +++ b/src/tools/envRisk.ts @@ -127,6 +127,51 @@ export async function scanTaskRisk(input: RiskScanInput): Promise>, + input: Required< + Pick + >, ): Promise { const project = resolveProject(projectKey); const repoType = detectRepoType(project.path); @@ -284,6 +293,14 @@ async function reviewProject( : { ok: false, stderr: '', stdout: '' }; const changedFiles = status.ok ? parseGitStatusFiles(status.stdout) : []; const trackedFiles = repoType === 'git' ? await listGitTrackedFiles(project.path) : []; + const trackedFileSet = new Set(trackedFiles); + const contentScannedFiles = + input.contentScanMode === 'all' + ? trackedFiles + : changedFiles + .map((file) => file.replaceAll('\\', '/')) + .filter((file) => shouldReadReviewFile(file)) + .filter((file) => trackedFileSet.has(file) || existsSync(path.join(project.path, file))); const trackedSensitiveFiles = trackedFiles.filter( (file) => sensitiveTrackedFilePattern.test(file) && @@ -291,7 +308,7 @@ async function reviewProject( ); const contentFindings = collectProjectContentFindings( project, - trackedFiles, + contentScannedFiles, input.includeContentScan, input.maxFindingsPerProject, ); @@ -308,6 +325,7 @@ async function reviewProject( return { changedFiles, + contentScannedFiles, credentialHints: contentFindings.credentialHints, debugFindings: contentFindings.debugFindings, findings: [...trackedSensitiveFindings, ...contentFindings.findings], @@ -330,6 +348,7 @@ export async function buildGlobalCodeReview( ? input.projects! : [...defaultReviewProjects]; const includeContentScan = input.includeContentScan ?? true; + const contentScanMode = input.contentScanMode ?? 'changed'; const maxFindingsPerProject = Math.max( 1, Math.min(input.maxFindingsPerProject ?? 20, 200), @@ -337,6 +356,7 @@ export async function buildGlobalCodeReview( const projectResults = await Promise.all( projects.map((project) => reviewProject(project, { + contentScanMode, includeContentScan, maxFindingsPerProject, }), @@ -377,11 +397,13 @@ export async function buildGlobalCodeReview( notes: [ '本工具只读扫描,不会修改文件、删除文件或提交代码。', 'P1 优先处理:冲突标记、被跟踪的真实 env/部署凭据文件。', + '默认 contentScanMode=changed,只对当前变更文件做 P2/P3 内容扫描,避免历史误报污染上下文;需要全仓库深扫时传 all。', 'P2 需要人工确认:疑似凭据字面量、旧部署文件、调试断点。', 'P3 为清洁度问题:运行时 console.log 等。', ], projects: projectResults.map((item) => ({ changedFiles: item.changedFiles, + contentScannedFileCount: item.contentScannedFiles.length, credentialHintCount: item.credentialHints.length, debugFindingCount: item.debugFindings.length, findingCount: item.findings.length, @@ -394,6 +416,7 @@ export async function buildGlobalCodeReview( summary: { changedProjectCount: projectResults.filter((item) => item.changedFiles.length > 0) .length, + contentScanMode, findingCount: allFindings.length, p1: allFindings.filter((item) => item.level === 'P1').length, p2: allFindings.filter((item) => item.level === 'P2').length, diff --git a/src/tools/task.ts b/src/tools/task.ts index f058d16..e630a1a 100644 --- a/src/tools/task.ts +++ b/src/tools/task.ts @@ -38,7 +38,7 @@ export async function prepareTask(input: PrepareTaskInput): Promise 0 ? input.scope!.join('、') : '待补充'; const content = input.content || '待补充'; - const testCase = input.testCase || '本次无页面测试或待补充。'; const verification = input.verification || '待补充。'; - return `### ${date}:${input.title}\n\n- 范围:${scope}\n- 内容:${content}\n- 页面测试用例:${testCase}\n- 验证:${verification}\n`; + const optionalTestCase = input.testCase ? `- 页面测试用例:${input.testCase}\n` : ''; + + return `### ${date}:${input.title}\n\n- 范围:${scope}\n- 关键词:${content}\n${optionalTestCase}- 验证:${verification}\n`; } export function appendTaskRecord(input: TaskRecordInput): Record { const record = buildTaskRecord(input); const tasksPath = resolveInsideRoot('TASKS.md'); const current = readFileSync(tasksPath, 'utf8'); - const marker = '## 改动记录'; + const marker = current.includes('## 最近记录') ? '## 最近记录' : '## 改动记录'; const markerIndex = current.indexOf(marker); if (markerIndex === -1) { - throw new Error('TASKS.md does not contain ## 改动记录'); + throw new Error('TASKS.md does not contain ## 最近记录 or ## 改动记录'); } const insertAt = current.indexOf('\n', markerIndex); diff --git a/src/tools/testing.ts b/src/tools/testing.ts index 8ca8baf..261294e 100644 --- a/src/tools/testing.ts +++ b/src/tools/testing.ts @@ -102,6 +102,17 @@ export function buildBusinessTestPlan(input: BusinessTestPlanInput = {}): Record projects: ['api', 'admin', 'blog'], steps: ['登录 Admin', '新增分类/标签', '新增文章并绑定分类标签', '编辑后查询列表', '清理 KT_TEST_ 数据'], }, + 'fflogs-command': { + assertions: [ + '命令注册表和在线命令表都能看到 FFLogs 查询命令。', + '中文任务名可查询,回显使用本地化任务名和字段名。', + '最近 10 次 logs 返回颜色、输出评分、治疗评分、dps、adps、rdps、ndps、hps。', + 'FF14 查价和 FFLogs 映射优先来自字典表,不在插件代码硬编码。', + ], + preflight: ['API 可达', 'FFLogs client id/secret 由环境变量注入', '字典表存在 FFLogs/FF14Market 映射项', 'QQBot 测试账号在线'], + projects: ['api', 'admin'], + steps: ['确认字典映射', '执行 /logs 角色 服务器 中文高难任务', '查询命令日志', '确认失败场景返回可读中文错误'], + }, 'qqbot-account-scan': { assertions: [ '扫码创建返回 qrcode/containerName/webuiPort。', @@ -112,6 +123,17 @@ export function buildBusinessTestPlan(input: BusinessTestPlanInput = {}): Record projects: ['api', 'admin'], steps: ['打开账号连接页', '点击扫码新增账号', '轮询二维码状态', '确认账号回填', '测试删除联动容器'], }, + 'qqbot-login-sse': { + assertions: [ + '更新登录接口快速返回 pending session,不被前端 HTTP 超时截断。', + 'scan/events SSE 能看到重置登录态、生成二维码、等待扫码、成功或错误等步骤。', + '账号被其他终端踢下线后,更新登录不复用旧二维码或旧 isLogin 状态。', + '手动刷新二维码不超时,且不会无意义重启容器。', + ], + preflight: ['API 可达', 'NapCat 容器可达', '账号处于离线或可重置状态', 'Admin QQBot 账号页面可访问'], + projects: ['api', 'admin'], + steps: ['触发更新登录', '订阅 scan/events', '观察二维码刷新', '扫码或等待过期', '核对账号状态和容器状态'], + }, 'qqbot-auto-reply': { assertions: [ '消息日志能看到 OneBot 收到的私聊/群聊/频道消息。', @@ -122,6 +144,17 @@ export function buildBusinessTestPlan(input: BusinessTestPlanInput = {}): Record projects: ['api', 'admin'], steps: ['创建 KT_TEST_ 自动回复规则', '发送私聊测试消息', '查询消息日志', '查询发送日志', '清理测试规则'], }, + 'system-log-visualization': { + assertions: [ + 'API pino 日志能写入 Loki 或在 Loki 不可用时不阻塞业务。', + '/system/logs、/system/logs/summary、/system/logs/status 返回 Vben 兼容结构。', + 'Admin 系统日志页面能查询、筛选、刷新,控制台无 error。', + '时间字段统一显示为 YYYY-MM-DD HH:mm:ss。', + ], + preflight: ['API 可达', 'Loki /ready 返回 200 或降级状态明确', 'Admin 系统日志菜单可见', 'K8s Secret/Jenkins env 已注入 LOKI_*'], + projects: ['api', 'admin'], + steps: ['触发一条 API 日志', '查询 Loki query_range', '打开 Admin #/system/logs', '执行筛选刷新', '核对 summary/status'], + }, 'web-playground-auth': { assertions: [ '无 token 时不主动 refresh,不产生登录循环。', diff --git a/src/tools/workflow.ts b/src/tools/workflow.ts index a02b503..3113e13 100644 --- a/src/tools/workflow.ts +++ b/src/tools/workflow.ts @@ -95,6 +95,7 @@ export async function buildFinishTask(input: FinishTaskInput = {}): Promise { @@ -313,10 +314,28 @@ export function buildComponentWorkflow(input: ComponentWorkflowInput = {}): Reco verification: ['横向滚动性能', '纵向滚动表头对齐', '列宽/行高 resize', 'summary 固定底部', '宽屏无无意义横向滚动条'], }, QQBot: { - antiPatterns: ['把 NapCat token 写进仓库', '删除账号不清理专属容器', '白名单/黑名单只做前端过滤', '远程服务不可达时伪装成业务成功'], + antiPatterns: ['把 NapCat token 写进仓库', '删除账号不清理专属容器', '白名单/黑名单只做前端过滤', '远程服务不可达时伪装成业务成功', '更新登录时用旧 isLogin 状态短路'], files: ['Node/kt-template-online-api/src/qqbot', 'Vue/kt-template-admin/apps/web-antdv-next/src/views/qqbot', 'ci/fnos-k8s/deploy-qqbot-runtime.ps1'], - guardrails: ['OneBot 反向 WS token 校验', '权限名单底层先走 QQ号过滤', '群/频道精确 QQ 过滤由开关控制', '扫码取消/过期/失败清理未绑定容器'], - verification: ['账号在线', '扫码新增/更新登录', '自动回复规则命中', '权限名单三类过滤', '消息日志和发送日志闭环'], + guardrails: ['OneBot 反向 WS token 校验', '权限名单底层先走 QQ号过滤', '群/频道精确 QQ 过滤由开关控制', '扫码取消/过期/失败清理未绑定容器', '更新登录走 SSE 进度,后台重置登录态后再生成二维码'], + verification: ['账号在线', '扫码新增/更新登录', 'scan/events 每步进度', '自动回复规则命中', '权限名单三类过滤', '消息日志和发送日志闭环'], + }, + FF14Plugin: { + antiPatterns: ['把 boss/服务器/职业映射硬编码到插件里', 'FFLogs 英文任务名直接回显给中文用户', '外部 API 失败时吞掉错误上下文', '字典缺失时返回空白结果'], + files: ['Node/kt-template-online-api/src/qqbot/plugins/ff14Market', 'Node/kt-template-online-api/src/qqbot/plugins/fflogs', 'Node/kt-template-online-api/src/admin/dict', 'Vue/kt-template-admin/apps/web-antdv-next/src/views/system/dict'], + guardrails: ['FF14 查价和 FFLogs 映射优先走字典表维护', '中文任务名查询和回显都要经过字典', '命令注册表和在线命令列表同步验证', '保留最近 logs 的颜色/评分/dps/adps/rdps/ndps/hps 字段语义'], + verification: ['/logs 角色 服务器 高难任务中文名', '/logs 角色 服务器 最近10次', 'FF14 查价中文物品名', '字典管理页面可维护映射'], + }, + NapCatLogin: { + antiPatterns: ['更新登录复用已过期二维码 URL', '前端等待长接口导致超时', '手动刷新每次重启容器', '后端拿旧 login state 判断成功'], + files: ['Node/kt-template-online-api/src/qqbot/account', 'Node/kt-template-online-api/src/qqbot/napcat', 'Vue/kt-template-admin/apps/web-antdv-next/src/views/qqbot'], + guardrails: ['创建账号和更新登录共用同一套二维码生成事实源', '更新登录先 reset runtime login state', 'SSE 返回 step/status/qrcode/error', '容器重启只在必要时触发,优先直接通信 NapCat API'], + verification: ['账号被踢下线后点击更新登录', 'scan/events 能看到重置/生成二维码/等待扫码/成功或失败', '手动刷新不超时', '过期二维码不再复用'], + }, + SystemLog: { + antiPatterns: ['把真实 Loki 凭据写入仓库', '只改 Dockerfile 不校验线上 env/Secret', '日志时间格式前后端不一致', 'global-review 把历史脱敏占位符当作真实凭据输出'], + files: ['Node/kt-template-online-api/src/common/logger', 'Node/kt-template-online-api/src/admin/system-log', 'Vue/kt-template-admin/apps/web-antdv-next/src/views/system/log', 'mcp/ktWorkflow/src/tools/review.ts'], + guardrails: ['pino + Loki env 走 Jenkins 私有 env 或 K8s Secret', '后端时间字段经 DTO/Entity 装饰器统一 YYYY-MM-DD HH:mm:ss', '系统日志页面走 /system/logs 系列接口', 'review 默认只对变更文件做 P2/P3 内容扫描'], + verification: ['API typecheck/lint/test', 'Loki /ready 和 query_range', 'Admin #/system/logs 无 console error', 'global-review findings 不含已知脱敏占位符误报'], }, } satisfies Record>; diff --git a/src/types.ts b/src/types.ts index aef81db..b822376 100644 --- a/src/types.ts +++ b/src/types.ts @@ -128,6 +128,7 @@ export interface RiskScanInput { } export interface GlobalCodeReviewInput { + contentScanMode?: 'all' | 'changed'; includeContentScan?: boolean; includeRootScan?: boolean; maxFindingsPerProject?: number; @@ -137,6 +138,7 @@ export interface GlobalCodeReviewInput { export interface FinishTaskInput { changeType?: TaskType; cleanupHistory?: boolean; + contentScanMode?: 'all' | 'changed'; includeRootScan?: boolean; keepHistory?: number; maxFindingsPerProject?: number; @@ -159,8 +161,11 @@ export interface PushPlanInput { export type BusinessFlow = | 'admin-login' | 'blog-crud' + | 'fflogs-command' | 'qqbot-account-scan' | 'qqbot-auto-reply' + | 'qqbot-login-sse' + | 'system-log-visualization' | 'web-playground-auth'; export interface BusinessTestPlanInput { @@ -184,7 +189,15 @@ export interface DbSyncPlanInput { } export interface ComponentWorkflowInput { - target?: 'AdminAuth' | 'BlogArgon' | 'Knife4jSwagger' | 'KtTable' | 'QQBot'; + target?: + | 'AdminAuth' + | 'BlogArgon' + | 'FF14Plugin' + | 'Knife4jSwagger' + | 'KtTable' + | 'NapCatLogin' + | 'QQBot' + | 'SystemLog'; } export interface PrepareTaskInput extends GuardrailsInput {