From 2372b682a5f40303a084fd4a2516c45fd3e10b12 Mon Sep 17 00:00:00 2001 From: sunlei Date: Fri, 5 Jun 2026 16:21:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=94=B6=E5=8F=A3KT=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E6=8A=A4=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/cli.ts | 22 ++++++++++++++++++ src/core/constants.ts | 1 + src/selfTest.ts | 28 +++++++++++++++++++++++ src/server.ts | 6 ++--- src/tools/guardrails.ts | 7 ++++++ src/tools/karpathy.ts | 48 +++++++++++++++++++++++++++++++++++++++ src/tools/task.ts | 3 +++ src/tools/verification.ts | 8 +++++-- src/tools/workflow.ts | 4 ++++ src/types.ts | 1 + 10 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 src/core/cli.ts create mode 100644 src/tools/karpathy.ts diff --git a/src/core/cli.ts b/src/core/cli.ts new file mode 100644 index 0000000..6944b89 --- /dev/null +++ b/src/core/cli.ts @@ -0,0 +1,22 @@ +import type { GlobalCodeReviewInput } from '../types.js'; + +function parseContentScanMode(argv: string[]): 'all' | 'changed' { + if (argv.includes('--content-scan-all') || argv.includes('--contentScanMode=all')) { + return 'all'; + } + + const modeIndex = argv.findIndex( + (item) => item === '--contentScanMode' || item === '--content-scan-mode', + ); + return modeIndex >= 0 && argv[modeIndex + 1] === 'all' ? 'all' : 'changed'; +} + +export function parseGlobalReviewCliArgs( + argv: string[], +): Pick { + return { + contentScanMode: parseContentScanMode(argv), + includeContentScan: !argv.includes('--no-content-scan'), + includeRootScan: !argv.includes('--no-root-scan'), + }; +} diff --git a/src/core/constants.ts b/src/core/constants.ts index 3cb3355..e32ccc2 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -34,6 +34,7 @@ export const taskTypeValues = [ 'general', 'mcp', 'page', + 'refactor', 'style', ] as const satisfies readonly TaskType[]; diff --git a/src/selfTest.ts b/src/selfTest.ts index eb07a3c..1b52d23 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -1,6 +1,7 @@ import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { parseGlobalReviewCliArgs } from './core/cli.js'; import { registeredToolNames } from './core/constants.js'; import { resolveInsideRoot } from './core/workspace.js'; import { buildGuardrails } from './tools/guardrails.js'; @@ -20,6 +21,31 @@ export async function runSelfTest(): Promise { throw new Error('review credential classifier self-check failed'); } + const reviewCliParser = { + dashedAll: parseGlobalReviewCliArgs(['node', 'server', '--global-review', '--content-scan-all']).contentScanMode, + keyValueAll: parseGlobalReviewCliArgs(['node', 'server', '--global-review', '--contentScanMode=all']).contentScanMode, + splitAll: parseGlobalReviewCliArgs(['node', 'server', '--global-review', '--content-scan-mode', 'all']).contentScanMode, + }; + if ( + reviewCliParser.dashedAll !== 'all' || + reviewCliParser.keyValueAll !== 'all' || + reviewCliParser.splitAll !== 'all' + ) { + throw new Error('global-review CLI content scan mode parser self-check failed'); + } + + const refactorGuardrails = buildGuardrails({ + project: 'mcp', + taskType: 'refactor', + userRequest: '重构 KT 工作流护栏', + }); + const refactorGuardrailOk = + refactorGuardrails.guardrails.beforeEdit.some((item) => item.includes('重构前写清楚')) && + refactorGuardrails.guardrails.verification.notes.some((item) => item.includes('重构验证必须覆盖原行为')); + if (!refactorGuardrailOk) { + throw new Error('refactor guardrail self-check failed'); + } + const data = { context: readWorkflowContext({ taskRecordCount: 2 }), guardrails: buildGuardrails({ @@ -45,7 +71,9 @@ export async function runSelfTest(): Promise { maxFindingsPerProject: 10, projects: ['mcp'], }), + reviewCliParser, reviewClassifier, + refactorGuardrails, businessTestPlan: buildBusinessTestPlan({ flow: 'system-log-visualization', }), diff --git a/src/server.ts b/src/server.ts index 2d4a13e..add1c0e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -2,6 +2,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { parseGlobalReviewCliArgs } from './core/cli.js'; import { cleanupHistoryArtifacts, parseCliCleanupArgs } from './tools/cleanup.js'; import { buildGlobalCodeReview } from './tools/review.js'; import { registerTools } from './registerTools.js'; @@ -12,10 +13,7 @@ if (process.argv.includes('--cleanup-history')) { } else if (process.argv.includes('--global-review')) { console.log( JSON.stringify( - await buildGlobalCodeReview({ - includeContentScan: !process.argv.includes('--no-content-scan'), - includeRootScan: !process.argv.includes('--no-root-scan'), - }), + await buildGlobalCodeReview(parseGlobalReviewCliArgs(process.argv)), null, 2, ), diff --git a/src/tools/guardrails.ts b/src/tools/guardrails.ts index bc446e9..8839ee7 100644 --- a/src/tools/guardrails.ts +++ b/src/tools/guardrails.ts @@ -1,20 +1,24 @@ import type { GuardrailSet, GuardrailsInput, GuardrailsResult } from '../types.js'; import { resolveProject } from '../core/workspace.js'; +import { buildKarpathyGuardrails } from './karpathy.js'; import { createPageTestCase } from './testing.js'; import { buildVerificationPlan } from './verification.js'; export function buildGuardrails(input: GuardrailsInput): GuardrailsResult { const project = resolveProject(input.project); const taskType = input.taskType || input.changeType || 'general'; const paths = input.paths || []; + const karpathy = buildKarpathyGuardrails(taskType); const guardrails: GuardrailSet = { beforeEdit: [ '先读最近的 AGENTS.md,再读 TASKS.md 和 SKILLS.md。', + ...karpathy.beforeEdit, '先检查目标仓库状态,识别用户已有改动,不覆盖、不回滚无关文件。', '先快速扫现有代码风格和目录结构,再决定改动方式。', '搜索优先用 rg,路径和接口名尽量保持可 grep。', ], duringEdit: [ '改动范围收敛到本次需求相关文件。', + ...karpathy.duringEdit, '复杂度高的地方加简短注释,避免空泛解释。', '后端真实环境配置不写入提交内容;前端 env 只允许客户端公开变量。', '前端实现遵循现有 antdv-next/Vben 约定,不引入无关抽象。', @@ -24,6 +28,7 @@ export function buildGuardrails(input: GuardrailsInput): GuardrailsResult { '不要在用户未要求时自动 push。', '不要把真实密钥、数据库密码、生产 env 写进可提交文件。', '不要为了验证长期保留 Node/Vite/浏览器进程。', + ...karpathy.doNot, ], verification: buildVerificationPlan({ changeType: taskType, @@ -65,6 +70,8 @@ export function buildGuardrails(input: GuardrailsInput): GuardrailsResult { guardrails.verification.notes.push('MCP 变更至少跑 self-test 和真实 SDK Client smoke test。'); } + guardrails.verification.notes.push(...karpathy.verificationNotes); + return { guardrails, paths, diff --git a/src/tools/karpathy.ts b/src/tools/karpathy.ts new file mode 100644 index 0000000..953fdd9 --- /dev/null +++ b/src/tools/karpathy.ts @@ -0,0 +1,48 @@ +import type { TaskType } from '../types.js'; + +export interface KarpathyGuardrailItems { + beforeEdit: string[]; + doNot: string[]; + duringEdit: string[]; + verificationNotes: string[]; +} + +export const karpathyPrepareTaskStep = + '先写清假设、范围边界和可验证成功标准;需求过宽时先审计并收敛目标。'; + +export const karpathyCommitChecklistItem = + '确认改动没有引入无验收标准的整体重构或顺手格式化。'; + +export const karpathyChangedFileChecklistItem = + '提交前确认每个 changed file 都属于本次请求、必要验证修复或 KT 记录维护。'; + +export const karpathyFinishNote = + '按 karpathy-guidelines 审计:没有明确假设、范围和成功证据的整体优化不应生成提交。'; + +export const karpathyStopCondition = + '发现全仓格式化、整文件重写或无验收标准重构时停止提交。'; + +export function buildKarpathyGuardrails(taskType: TaskType): KarpathyGuardrailItems { + const items: KarpathyGuardrailItems = { + beforeEdit: [ + '非平凡编码/评审/重构任务先套用 karpathy-guidelines:明确假设、取最小可行改动、定义可验证成功标准。', + '如果需求是笼统优化或整体重构,先把它收敛成具体行为、风险和验收证据;没有明确目标时只做审计不制造 diff。', + ], + doNot: [ + '不要为了“整体优化”做全仓格式化、整文件重写或无验收标准的重构。', + ], + duringEdit: [ + '每一行改动都应能追溯到用户请求、必要验证修复或 KT 记录维护。', + '不为单次使用新增抽象,不引入未被请求的灵活性或配置项。', + ], + verificationNotes: [], + }; + + if (taskType === 'refactor') { + items.beforeEdit.push('重构前写清楚要保留的行为、要降低的复杂度和不触碰的边界。'); + items.duringEdit.push('只合并真实重复、删除自己造成的孤儿代码,避免顺手重构邻近模块。'); + items.verificationNotes.push('重构验证必须覆盖原行为;没有行为证据时不要声称重构完成。'); + } + + return items; +} diff --git a/src/tools/task.ts b/src/tools/task.ts index 865e87a..70b25d3 100644 --- a/src/tools/task.ts +++ b/src/tools/task.ts @@ -6,6 +6,7 @@ import { detectRepoType } from '../core/project.js'; import { formatDateInShanghai, getRecentTaskRecords, getTaskContextIndex, listWorkspaceSkills, readText, resolveInsideRoot, resolveProject, workspaceRoot } from '../core/workspace.js'; import { buildGuardrails } from './guardrails.js'; import { inspectProject } from './inspect.js'; +import { karpathyCommitChecklistItem, karpathyPrepareTaskStep } from './karpathy.js'; import { scanTaskRisk } from './envRisk.js'; import { createPageTestCase } from './testing.js'; export async function prepareTask(input: PrepareTaskInput): Promise> { @@ -35,6 +36,7 @@ export async function prepareTask(input: PrepareTaskInput): Promise