feat(workflow): 升级KT工作流上下文
This commit is contained in:
parent
0c2131a26d
commit
300a34d33e
14
README.md
14
README.md
@ -1,6 +1,6 @@
|
||||
# KT Workflow MCP
|
||||
|
||||
`ktWorkflow` 是 KT 工作区的可复用 MCP 能力包,用 TypeScript 封装工具入参、项目别名和返回结构,用来把根目录 `AGENTS.md` 的硬规则、`SKILLS.md` 的工作流索引、`TASKS.md` 的上下文记录和 `docs/` 的详细流程变成可调用工具。
|
||||
`ktWorkflow` 是 KT 工作区的可复用 MCP 能力包,用 TypeScript 封装工具入参、项目别名和返回结构,用来把根目录 `AGENTS.md` 的硬规则、`SKILLS.md` 的工作流索引、`TASKS.md` 的上下文记录和 `docs/` 的详细流程变成可调用工具。当前版本:`0.6.1`。
|
||||
|
||||
## 能力边界
|
||||
|
||||
@ -15,11 +15,11 @@
|
||||
- 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。
|
||||
- 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。
|
||||
- 生成远程只读健康检查和数据库同步安全向导:覆盖飞牛 NAS 服务探测、GTID、备份和行数校验。
|
||||
- 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger 的防踩坑清单和验证点。
|
||||
- 生成专项组件工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s 的防踩坑清单和验证点。
|
||||
- 生成验证进程清理计划:按项目路径和端口给出 PowerShell 检查命令,不直接杀进程。
|
||||
- 清理历史产物:统一治理 `.kt-workspace` 下的测试/验证产物,按目录最近修改时间只保留最近 3 轮,模板目录永久保留。
|
||||
- 检查 env 策略和变更风险:区分后端真实 env 与前端客户端 `.env*`,提醒锁文件、核心表格组件、部署链路和 Vue TSX 插槽写法等高风险改动。
|
||||
- 全局 CodeReview 只读扫描:汇总全部 KT 子仓库的 Git 状态、敏感文件跟踪、冲突标记、运行时调试输出、疑似凭据字面量、根目录生成产物和当前变更风险;默认只对变更文件做内容扫描,避免历史误报污染上下文;任何文件改动后都要跑一遍。
|
||||
- 全局 CodeReview 只读扫描:汇总全部 KT 子仓库的 Git 状态、敏感文件跟踪、冲突标记、运行时调试输出、疑似凭据字面量、根目录生成产物和当前变更风险;默认只对变更文件做内容扫描,并放过短中文显示标签,避免历史误报污染上下文;任何文件改动后都要跑一遍。
|
||||
- 生成或写入 `TASKS.md` 最近记录:默认 `dryRun=true`,确认后再落盘。
|
||||
- 生成提交前检查清单:校验 KT commit message 约定。
|
||||
|
||||
@ -81,7 +81,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
||||
| `kt_business_test_plan` | 生成固化业务链路测试计划,包含 QQBot SSE、FFLogs 和系统日志 |
|
||||
| `kt_remote_health_check` | 生成或执行远程只读健康检查命令 |
|
||||
| `kt_db_sync_plan` | 生成数据库同步安全向导 |
|
||||
| `kt_component_workflow` | 输出专项组件/链路防踩坑工作流 |
|
||||
| `kt_component_workflow` | 输出专项组件/链路防踩坑工作流,包含 FnosK8s |
|
||||
| `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 复审报告;确认误报时优先升级 `src/tools/review.ts`,不要把误报沉积到上下文。 |
|
||||
|
||||
## 项目别名
|
||||
|
||||
@ -121,12 +121,12 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login
|
||||
- 写代码前先调用 `kt_prepare_task`;只需要单项信息时再调用 `kt_read_context` 或 `kt_inspect_project`。`kt_read_context` 默认紧凑输出,只有确实需要完整 `TASKS.md` 时再传 `includeFullDocs=true`。
|
||||
- 多项目联动时先调用 `kt_inspect_all_projects`。
|
||||
- 要收尾时调用 `kt_finish_task`,默认只生成计划和 review;需要执行验证时显式传 `runValidation=true`。
|
||||
- 文件改动完成并验证后调用 `kt_global_code_review`,或运行 `pnpm run global-review`;它只读扫描,不删除文件、不提交代码。
|
||||
- 文件改动完成并验证后调用 `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_remote_health_check`,默认只生成只读命令;需要执行时显式传 `execute=true`。
|
||||
- 数据库同步前调用 `kt_db_sync_plan`,先确认源库、目标库、备份库和校验点。
|
||||
- 改 KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger 前调用 `kt_component_workflow`,先看专项禁区。
|
||||
- 改 KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s 前调用 `kt_component_workflow`,先看专项禁区。
|
||||
- 不确定任务边界时调用 `kt_guardrails`,先拿到“能做什么、不能做什么、怎么验证”。
|
||||
- 验证前调用 `kt_suggest_verification`,避免盲跑全量构建。
|
||||
- 页面测试前调用 `kt_create_page_test_case`,再执行 Playwright/浏览器测试。
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kt/mcp-kt-workflow",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Reusable MCP workflow tools for the KT workspace.",
|
||||
|
||||
@ -324,13 +324,14 @@ export function registerTools(server: McpServer): void {
|
||||
server.registerTool(
|
||||
'kt_component_workflow',
|
||||
{
|
||||
description: '按 KT 专项组件/链路输出防踩坑工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger。',
|
||||
description: '按 KT 专项组件/链路输出防踩坑工作流:KtTable、BlogArgon、AdminAuth、QQBot、FF14Plugin、NapCatLogin、SystemLog、Knife4jSwagger、FnosK8s。',
|
||||
inputSchema: {
|
||||
target: z
|
||||
.enum([
|
||||
'AdminAuth',
|
||||
'BlogArgon',
|
||||
'FF14Plugin',
|
||||
'FnosK8s',
|
||||
'Knife4jSwagger',
|
||||
'KtTable',
|
||||
'NapCatLogin',
|
||||
|
||||
@ -7,11 +7,19 @@ import { buildGuardrails } from './tools/guardrails.js';
|
||||
import { cleanupHistoryArtifacts } from './tools/cleanup.js';
|
||||
import { inspectProject } from './tools/inspect.js';
|
||||
import { prepareTask, readWorkflowContext } from './tools/task.js';
|
||||
import { buildGlobalCodeReview } from './tools/review.js';
|
||||
import { buildGlobalCodeReview, isBenignCredentialReviewValue } from './tools/review.js';
|
||||
import { buildBusinessTestPlan } from './tools/testing.js';
|
||||
import { buildVerificationPlan } from './tools/verification.js';
|
||||
import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js';
|
||||
export async function runSelfTest(): Promise<void> {
|
||||
const reviewClassifier = {
|
||||
localizedSecretLabelAllowed: isBenignCredentialReviewValue('密钥'),
|
||||
realTokenRejected: !isBenignCredentialReviewValue('eqc2Sbp8ufP2AcS6I2YReLqxnu3XJKC6D7C6PUcx'),
|
||||
};
|
||||
if (!reviewClassifier.localizedSecretLabelAllowed || !reviewClassifier.realTokenRejected) {
|
||||
throw new Error('review credential classifier self-check failed');
|
||||
}
|
||||
|
||||
const data = {
|
||||
context: readWorkflowContext({ taskRecordCount: 2 }),
|
||||
guardrails: buildGuardrails({
|
||||
@ -37,6 +45,7 @@ export async function runSelfTest(): Promise<void> {
|
||||
maxFindingsPerProject: 10,
|
||||
projects: ['mcp'],
|
||||
}),
|
||||
reviewClassifier,
|
||||
businessTestPlan: buildBusinessTestPlan({
|
||||
flow: 'system-log-visualization',
|
||||
}),
|
||||
|
||||
@ -25,7 +25,7 @@ if (process.argv.includes('--cleanup-history')) {
|
||||
} else {
|
||||
const server = new McpServer({
|
||||
name: 'kt-workflow',
|
||||
version: '0.4.0',
|
||||
version: '0.6.1',
|
||||
});
|
||||
registerTools(server);
|
||||
await server.connect(new StdioServerTransport());
|
||||
|
||||
@ -39,7 +39,7 @@ export function buildGuardrails(input: GuardrailsInput): GuardrailsResult {
|
||||
}
|
||||
|
||||
guardrails.verification.notes.push(
|
||||
'改动后的 review 是硬步骤,优先用 kt_global_code_review 或 pnpm run global-review。',
|
||||
'改动后的 review 是硬步骤,优先用 kt_global_code_review 或 pnpm run global-review;findings 先判定真实风险或误报,误报应修 ktWorkflow 规则。',
|
||||
);
|
||||
|
||||
if (taskType === 'page' || input.includePageTest) {
|
||||
|
||||
@ -112,6 +112,7 @@ function isBenignCredentialValue(value: string): boolean {
|
||||
if (normalized.startsWith('$') || normalized.startsWith('${')) return true;
|
||||
if (normalized.startsWith('<') || normalized.includes('example')) return true;
|
||||
if (/^\*+$/.test(normalized)) return true;
|
||||
if (isLocalizedDisplayLabelValue(normalized)) return true;
|
||||
return [
|
||||
'false',
|
||||
'hidden',
|
||||
@ -129,6 +130,18 @@ function isBenignCredentialValue(value: string): boolean {
|
||||
].includes(normalized);
|
||||
}
|
||||
|
||||
export function isBenignCredentialReviewValue(value: string): boolean {
|
||||
return isBenignCredentialValue(value);
|
||||
}
|
||||
|
||||
function isLocalizedDisplayLabelValue(value: string): boolean {
|
||||
return (
|
||||
value.length <= 24 &&
|
||||
/[\u3400-\u9fff]/.test(value) &&
|
||||
!/[a-z0-9_$./\\:=]/i.test(value)
|
||||
);
|
||||
}
|
||||
|
||||
function isRuntimeDebugAllowed(projectAlias: ProjectAlias | null, file: string): boolean {
|
||||
const normalized = file.replaceAll('\\', '/');
|
||||
if (/^(README|skills\/|.*\.md$)/.test(normalized)) return true;
|
||||
@ -401,7 +414,7 @@ export async function buildGlobalCodeReview(
|
||||
notes: [
|
||||
'本工具只读扫描,不会修改文件、删除文件或提交代码。',
|
||||
'P1 优先处理:冲突标记、被跟踪的真实 env/部署凭据文件。',
|
||||
'默认 contentScanMode=changed,只对当前变更文件做 P2/P3 内容扫描,避免历史误报污染上下文;需要全仓库深扫时传 all。',
|
||||
'默认 contentScanMode=changed,只对当前变更文件做 P2/P3 内容扫描,并放过短中文显示标签,避免历史误报污染上下文;需要全仓库深扫时传 all。',
|
||||
'P2 需要人工确认:疑似凭据字面量、旧部署文件、调试断点。',
|
||||
'P3 为清洁度问题:运行时 console.log 等。',
|
||||
],
|
||||
|
||||
@ -38,7 +38,7 @@ export async function prepareTask(input: PrepareTaskInput): Promise<Record<strin
|
||||
'按最小范围修改。',
|
||||
'按 verification.commands 和 notes 做轻量验证。',
|
||||
'有文件改动时更新 TASKS.md。',
|
||||
'最终回复或提交前跑全局 review;默认只深扫变更文件,真实 findings 先处理。',
|
||||
'最终回复或提交前跑全局 review;默认只深扫变更文件,findings 先判定真实风险或工具误报,误报要沉淀到 ktWorkflow。',
|
||||
],
|
||||
pageTestCase,
|
||||
project,
|
||||
@ -114,7 +114,7 @@ export async function createCommitChecklist(input: CommitChecklistInput): Promis
|
||||
checks: [
|
||||
'确认只包含本次任务相关文件。',
|
||||
'先运行对应轻量验证命令。',
|
||||
'提交前已跑全局 review,且 findings 已修复或明确记录为非阻塞风险。',
|
||||
'提交前已跑全局 review,且 findings 已修复;确认误报时优先修 ktWorkflow 过滤规则,避免污染后续上下文。',
|
||||
'每个独立 Git 仓库单独 commit。',
|
||||
'没有用户明确要求时不 push。',
|
||||
],
|
||||
|
||||
@ -12,7 +12,7 @@ export function buildVerificationPlan(input: VerificationPlanInput): Verificatio
|
||||
const notes = [
|
||||
'先确认仓库类型,再确认包管理器和 Node 版本。',
|
||||
'只跑当前变更所需的最轻验证,不默认全量 build。',
|
||||
'只要产生文件改动,最终回复或提交前必须走一次 review;有 findings 先修复再复跑。',
|
||||
'只要产生文件改动,最终回复或提交前必须走一次 review;有 findings 先判定真实风险或工具误报,真实风险先修复,误报优先收敛到 ktWorkflow 规则后复跑。',
|
||||
];
|
||||
|
||||
const typecheck = getTypecheckCommand(project, packageManager, scripts);
|
||||
@ -54,7 +54,7 @@ export function buildVerificationPlan(input: VerificationPlanInput): Verificatio
|
||||
|
||||
if (project.alias === 'mcp') {
|
||||
if (scripts['self-test']) commands.push(`${packageManager} run self-test`);
|
||||
notes.push('MCP 变更需要用真实 SDK Client 做 listTools/callTool smoke test。');
|
||||
notes.push('MCP 工具注册或协议变更需要用真实 SDK Client 做 listTools/callTool smoke test;纯扫描规则变更至少跑 self-test 和 global-review。');
|
||||
}
|
||||
|
||||
if (project.alias === 'knife4j') {
|
||||
|
||||
@ -117,7 +117,7 @@ export async function buildFinishTask(input: FinishTaskInput = {}): Promise<Reco
|
||||
review,
|
||||
snapshots,
|
||||
stopConditions: [
|
||||
'review.findings 存在真实 P1/P2 时先修复,再复跑 kt_global_code_review。',
|
||||
'review.findings 存在 P1/P2 时先判定真实风险或工具误报;真实风险修代码,工具误报修 ktWorkflow,再复跑 kt_global_code_review。',
|
||||
'validationRuns 中任一 result.ok=false 时先处理失败命令。',
|
||||
'发现真实 env、生产 Secret 或非本次范围文件时停止提交。',
|
||||
],
|
||||
@ -139,6 +139,7 @@ export async function buildCommitPlan(input: CommitPlanInput = {}): Promise<Reco
|
||||
checks: [
|
||||
'每个独立 Git 仓库单独提交。',
|
||||
'提交前先跑对应轻量验证和 kt_global_code_review。',
|
||||
'kt_global_code_review findings 必须为 0;确认误报时先修 ktWorkflow 规则,不把误报当作长期上下文。',
|
||||
'后端真实 .env.development/.env.production 不提交;前端 env 可提交但只能包含客户端公开配置。',
|
||||
'KT 根目录是本地治理仓库;如没有 remote,只本地提交并在最终回复说明。',
|
||||
],
|
||||
@ -177,7 +178,7 @@ export async function buildPushPlan(input: PushPlanInput = {}): Promise<Record<s
|
||||
return {
|
||||
checks: [
|
||||
'推送前工作区应干净;如仍有改动,先提交或说明为什么暂不提交。',
|
||||
'推送前复跑 kt_global_code_review,findings 必须为 0 或明确非阻塞。',
|
||||
'推送前复跑 kt_global_code_review,findings 必须为 0;如出现误报先升级 ktWorkflow 规则。',
|
||||
'如果 Jenkins/Gitea host key、mirror、hooks 异常,先修远程仓库状态再重试。',
|
||||
],
|
||||
projects: snapshots
|
||||
@ -325,6 +326,12 @@ export function buildComponentWorkflow(input: ComponentWorkflowInput = {}): Reco
|
||||
guardrails: ['FF14 查价和 FFLogs 映射优先走字典表维护', '中文任务名查询和回显都要经过字典', '命令注册表和在线命令列表同步验证', '保留最近 logs 的颜色/评分/dps/adps/rdps/ndps/hps 字段语义'],
|
||||
verification: ['/logs 角色 服务器 高难任务中文名', '/logs 角色 服务器 最近10次', 'FF14 查价中文物品名', '字典管理页面可维护映射'],
|
||||
},
|
||||
FnosK8s: {
|
||||
antiPatterns: ['把 fnOS 原生面板改成 Docker 应用', '在 ui/config 显式配置公网端口', '提交 _build/_dist 打包产物', '只测桌面视口不测 fnOS 内嵌窗口和窄屏', '用非官方或旧缓存图标替代 Kubernetes 官方图标'],
|
||||
files: ['Plugins/fnos-k8s-dashboard-fpk/src/server.ts', 'Plugins/fnos-k8s-dashboard-fpk/src/ui', 'Plugins/fnos-k8s-dashboard-fpk/apps/kt-k8s-dashboard/fnos', 'Plugins/fnos-k8s-dashboard-fpk/scripts'],
|
||||
guardrails: ['保持非 Docker .fpk 形态', 'Web 面板源码只放 src/ui,由打包脚本复制进 app.tgz', 'fnOS 桌面入口使用 ui/config iframe 和 /kt-k8s-dashboard/ 代理路径', '应用标题与图标保持 Kubernetes 官方语义', '集群配置文件只作为运行时数据,不提交真实 kubeconfig'],
|
||||
verification: ['bun run typecheck', 'bun run build:fpk', 'bun run verify:fpk', '本地 /api/health 和首页请求', 'Playwright 桌面与 390px 窄屏截图', '线上应用中心/桌面入口只在用户允许远程测试时验证'],
|
||||
},
|
||||
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'],
|
||||
@ -332,10 +339,10 @@ export function buildComponentWorkflow(input: ComponentWorkflowInput = {}): Reco
|
||||
verification: ['账号被踢下线后点击更新登录', 'scan/events 能看到重置/生成二维码/等待扫码/成功或失败', '手动刷新不超时', '过期二维码不再复用'],
|
||||
},
|
||||
SystemLog: {
|
||||
antiPatterns: ['把真实 Loki 凭据写入仓库', '只改 Dockerfile 不校验线上 env/Secret', '日志时间格式前后端不一致', 'global-review 把历史脱敏占位符当作真实凭据输出'],
|
||||
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 不含已知脱敏占位符误报'],
|
||||
guardrails: ['pino + Loki env 走 Jenkins 私有 env 或 K8s Secret', '后端时间字段经 DTO/Entity 装饰器统一 YYYY-MM-DD HH:mm:ss', '系统日志页面走 /system/logs 系列接口', 'review 默认只对变更文件做 P2/P3 内容扫描,确认误报要沉淀到 review.ts'],
|
||||
verification: ['API typecheck/lint/test', 'Loki /ready 和 query_range', 'Admin #/system/logs 无 console error', 'global-review findings 不含已知脱敏占位符或中文显示标签误报'],
|
||||
},
|
||||
} satisfies Record<string, Record<string, unknown>>;
|
||||
|
||||
|
||||
@ -194,6 +194,7 @@ export interface ComponentWorkflowInput {
|
||||
| 'AdminAuth'
|
||||
| 'BlogArgon'
|
||||
| 'FF14Plugin'
|
||||
| 'FnosK8s'
|
||||
| 'Knife4jSwagger'
|
||||
| 'KtTable'
|
||||
| 'NapCatLogin'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user