From 74ee4877badc12ca20c71b42cb8759ba664345cd Mon Sep 17 00:00:00 2001 From: sunlei Date: Sun, 7 Jun 2026 03:23:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9B=BA=E5=8C=96=E5=8D=A1=E7=82=B9?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++ src/core/constants.ts | 1 + src/registerTools.ts | 21 ++++++++++++ src/selfTest.ts | 8 +++++ src/tools/blocker.ts | 74 +++++++++++++++++++++++++++++++++++++++++++ src/types.ts | 12 +++++++ 6 files changed, 119 insertions(+) create mode 100644 src/tools/blocker.ts diff --git a/README.md b/README.md index a18add4..4a0fa74 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - 生成页面测试用例:内置“先写用例、可视化证据、事不过三”的测试闭环。 - 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。 - 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。 +- 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。 - 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。 - 生成远程只读健康检查和数据库同步安全向导:覆盖飞牛 NAS 服务探测、GTID、备份和行数校验。 - 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s 的防踩坑清单和验证点。 @@ -79,6 +80,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `kt_commit_plan` | 生成多仓库提交计划、建议 commit message 和检查项 | | `kt_push_plan` | 生成多仓库推送计划和远程异常提醒 | | `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 | +| `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 | | `kt_remote_health_check` | 生成或执行远程只读健康检查命令 | | `kt_db_sync_plan` | 生成数据库同步安全向导 | | `kt_component_workflow` | 输出专项组件/链路防踩坑工作流,包含 FnosK8s | @@ -124,6 +126,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login - 文件改动完成并验证后调用 `kt_global_code_review`,或运行 `pnpm run global-review`;它只读扫描,不删除文件、不提交代码。`findings` 先判定真实风险或工具误报,真实风险修业务代码,误报修 `mcp/ktWorkflow/src/tools/review.ts` 并复跑。 - 要提交或推送时先调用 `kt_commit_plan` / `kt_push_plan`,按仓库分组确认范围。 - 要测真实业务链路时调用 `kt_business_test_plan`,选择 `admin-login`、`qqbot-auto-reply`、`qqbot-login-sse`、`fflogs-command`、`system-log-visualization` 等 flow。 +- 遇到同一命令或同一远程步骤重复卡住时调用 `kt_blocker_resolution`;第二次仍失败时先写入 `TASKS.md` 或补成脚本,再继续。 - 远程服务排查先调用 `kt_remote_health_check`,默认只生成只读命令;需要执行时显式传 `execute=true`。 - 数据库同步前调用 `kt_db_sync_plan`,先确认源库、目标库、备份库和校验点。 - 改 KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s 前调用 `kt_component_workflow`,先看专项禁区。 diff --git a/src/core/constants.ts b/src/core/constants.ts index e32ccc2..770ffb9 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -56,6 +56,7 @@ export const registeredToolNames = [ 'kt_commit_plan', 'kt_push_plan', 'kt_business_test_plan', + 'kt_blocker_resolution', 'kt_remote_health_check', 'kt_db_sync_plan', 'kt_component_workflow', diff --git a/src/registerTools.ts b/src/registerTools.ts index 4d1b2b7..d9f3e92 100644 --- a/src/registerTools.ts +++ b/src/registerTools.ts @@ -2,6 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import type { McpTextResponse } from './types.js'; +import { buildBlockerResolution } from './tools/blocker.js'; import { defaultHistoryRoots, taskTypeValues } from './core/constants.js'; import { createCleanupProcessPlan, cleanupHistoryArtifacts } from './tools/cleanup.js'; import { buildEnvPolicy, scanTaskRisk } from './tools/envRisk.js'; @@ -291,6 +292,26 @@ export function registerTools(server: McpServer): void { async (input) => response(buildBusinessTestPlan(input)), ); + server.registerTool( + 'kt_blocker_resolution', + { + description: '生成或写入卡点固化记录:问题点、稳定解法、后续入口、验证证据,并给出停止原样重试的下一步动作。', + inputSchema: { + attempts: z.number().int().min(0).max(20).default(1), + command: z.string().optional(), + dryRun: z.boolean().default(true), + evidence: z.string().optional(), + nextEntry: z.string().optional(), + problem: z.string().optional(), + project: z.string().default('root'), + solution: z.string().optional(), + title: z.string().optional(), + }, + title: 'KT Blocker Resolution', + }, + async (input) => response(buildBlockerResolution(input)), + ); + server.registerTool( 'kt_remote_health_check', { diff --git a/src/selfTest.ts b/src/selfTest.ts index 1b52d23..1a567f1 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -3,6 +3,7 @@ import path from 'node:path'; import { parseGlobalReviewCliArgs } from './core/cli.js'; import { registeredToolNames } from './core/constants.js'; +import { buildBlockerResolution } from './tools/blocker.js'; import { resolveInsideRoot } from './core/workspace.js'; import { buildGuardrails } from './tools/guardrails.js'; import { cleanupHistoryArtifacts } from './tools/cleanup.js'; @@ -77,6 +78,13 @@ export async function runSelfTest(): Promise { businessTestPlan: buildBusinessTestPlan({ flow: 'system-log-visualization', }), + blockerResolution: buildBlockerResolution({ + attempts: 2, + evidence: 'self-test', + problem: '重复超时', + project: 'mcp', + solution: '改用固定脚本和 timeout 后再验证', + }), commitPlan: await buildCommitPlan({ projects: ['mcp'], }), diff --git a/src/tools/blocker.ts b/src/tools/blocker.ts new file mode 100644 index 0000000..f5316b1 --- /dev/null +++ b/src/tools/blocker.ts @@ -0,0 +1,74 @@ +import { appendTaskRecord, buildTaskRecord } from './task.js'; +import { resolveProject } from '../core/workspace.js'; +import type { BlockerResolutionInput } from '../types.js'; + +function formatRecord( + input: Required> & + Pick, +): string { + const evidence = input.evidence || '待补充'; + + return `问题点:${input.problem};稳定解法:${input.solution};后续入口:${input.nextEntry};验证证据:${evidence}`; +} + +export function buildBlockerResolution(input: BlockerResolutionInput = {}): Record { + const attempts = input.attempts ?? 1; + const project = resolveProject(input.project || 'root'); + const problem = input.problem || '待填写卡住的命令、接口、进程或远程阶段'; + const solution = input.solution || '待填写已经验证或下一轮要验证的稳定解法'; + const nextEntry = input.nextEntry || 'TASKS.md 或 docs/kt-testing-workflows.md'; + const record = formatRecord({ + evidence: input.evidence, + nextEntry, + problem, + solution, + }); + const title = input.title || '卡点固化记录'; + const taskRecord = buildTaskRecord({ + content: record, + scope: [project.relativePath], + title, + verification: input.evidence || '待补充。', + }); + const shouldStopBlindRetry = attempts >= 2; + const nextActions = shouldStopBlindRetry + ? [ + '停止原样重复执行同一条命令。', + '把问题点、稳定解法、后续入口和证据写入 TASKS.md、docs 或脚本。', + '下一轮只能改变一个可验证变量,例如缩短范围、增加 timeout、拆分 Pod 内外步骤或改用固定脚本。', + ] + : [ + '先采集命令、输入、PID 或 Pod、最后有效日志和已生成产物。', + '只清理本轮启动的进程、临时目录或 Pod 文件。', + '第二次尝试前必须改变一个可验证变量,不能原样等待。', + ]; + + const writeResult = + input.dryRun === false + ? appendTaskRecord({ + content: record, + dryRun: false, + scope: [project.relativePath], + title, + verification: input.evidence || '待补充。', + }) + : null; + + return { + command: input.command || '', + dryRun: input.dryRun !== false, + nextActions, + project, + record, + safeCommandRules: [ + '本地或远程长命令必须有外层 timeout 或固定脚本内置超时。', + '远程 here-doc、awk、kubectl jsonpath 和 Node 片段不能直接塞进双引号 ssh 命令。', + "PowerShell 多行 Node 片段使用单引号 here-string:@' ... '@ | node -。", + '同一卡点最多两次原样尝试;第二次仍卡住先固化再继续。', + '只清理本轮启动的进程或临时文件,不批量杀未知进程。', + ], + shouldStopBlindRetry, + taskRecord, + writeResult, + }; +} diff --git a/src/types.ts b/src/types.ts index ef2a64a..878ca4f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -176,6 +176,18 @@ export interface BusinessTestPlanInput { flow?: BusinessFlow | 'all'; } +export interface BlockerResolutionInput { + attempts?: number; + command?: string; + dryRun?: boolean; + evidence?: string; + nextEntry?: string; + problem?: string; + project?: string; + solution?: string; + title?: string; +} + export interface RemoteHealthCheckInput { execute?: boolean; host?: string;