- CodeGuard → Code Purifier / 净码特工(displayName、命令、配置标题) - 新增 ai.maxTokens 配置项,所有 Provider 及 fixer 传入 maxTokens - AI 引擎增强:repairJsonEscapes + JSON 解析 fallback + 详细错误信息 - 设置面板规则管理改为文件级(list/delete .yaml),addRule 改为 AI 从 Markdown 生成 YAML - yaml-parser 简化:移除 config.yaml 的 enable/disable 过滤逻辑 - 审查报告面板:errorBanner 优先显示具体错误、lint 诊断显示 suggestion、移除 translatedDiagnostics 独立渲染 - merger 中 translatedDiagnostics 覆盖原始 lint 诊断 message/suggestion - HTML linter 配置项、测试用例重写、typescript-eslint 移入 dependencies
8.2 KiB
8.2 KiB
Step 15 — Phase 5.1: 命令注册 + extension.ts 更新
依赖: Step 08, 14(Orchestrator + 报告导出),Step 13(Fixer 可选)
参考设计: §6
目标
注册 8 个命令,更新 package.json 贡献点,更新 extension.ts 入口串联所有模块。
文件变更
| # | 文件 | 操作 | 说明 |
|---|---|---|---|
| 1 | src/activation/commands.ts |
新建 | 所有命令处理函数注册 |
| 2 | src/extension.ts |
修改 | 替换 helloWorld 为正式入口 |
| 3 | package.json |
修改 | 添加 commands、viewsContainers、views、menus、configuration |
1. src/activation/commands.ts
import * as vscode from 'vscode';
import { Orchestrator } from '../orchestrator/orchestrator';
import { runAIReview } from '../ai/engine';
import { loadActiveRules } from '../rules/yaml-parser';
import { mergeResults } from '../merger/merger';
import { reportToMarkdown } from '../utils/report';
import { getApiKey } from '../config';
export function registerCommands(context: vscode.ExtensionContext, orchestrator: Orchestrator): void {
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.review', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showWarningMessage('请先打开一个文件');
return;
}
const document = editor.document;
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
const workingDir = workspaceRoot || vscode.Uri.joinPath(document.uri, '..').fsPath;
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: '正在审查...',
cancellable: false,
}, async (progress) => {
progress.report({ message: '运行静态分析...' });
const startTime = Date.now();
const staticResult = await orchestrator.runStaticAnalysis(document, workingDir);
progress.report({ message: '运行 AI 审查...' });
const customRules = loadActiveRules(workspaceRoot);
const code = document.getText();
const aiResult = await runAIReview(context, code, staticResult.diagnostics, customRules);
const report = mergeResults({
staticDiagnostics: staticResult.diagnostics,
customRuleResults: aiResult.customRuleResults,
translatedDiagnostics: aiResult.translatedDiagnostics,
aiFindings: aiResult.findings,
errors: [...staticResult.errors, ...(aiResult.error ? [aiResult.error] : [])],
degraded: aiResult.degraded,
startTime,
filePath: document.uri.fsPath,
language: document.languageId,
adapterIds: staticResult.adapterIds,
});
// TODO: Phase 5.3 — 推送报告到审查面板
vscode.window.showInformationMessage(
`审查完成: ${report.linterCount + report.customRuleCount + report.aiCount} 个问题`
);
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.reviewSelection', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) { return; }
const selection = editor.selection;
if (selection.isEmpty) {
vscode.window.showWarningMessage('请先选中要审查的代码');
return;
}
const code = editor.document.getText(selection);
const apiKey = await getApiKey(context);
if (!apiKey) {
vscode.window.showWarningMessage('请先在设置面板中配置 API Key');
return;
}
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
const customRules = loadActiveRules(workspaceRoot);
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: '审查选中代码...',
cancellable: false,
}, async () => {
const aiResult = await runAIReview(context, code, [], customRules);
vscode.window.showInformationMessage(
`选中代码审查完成: ${aiResult.customRuleResults.length + aiResult.findings.length} 个问题`
);
});
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.openPanel', () => {
// TODO: Phase 5.3 — 打开审查面板
vscode.window.showInformationMessage('审查面板功能开发中');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.exportReport', async () => {
// TODO: 与审查面板集成后获取最新 report
vscode.window.showInformationMessage('请先运行完整审查生成报告');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.addCustomRule', () => {
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
if (!workspaceRoot) {
vscode.window.showWarningMessage('请先打开工作区');
return;
}
// TODO: 打开规则向导,保存到 .code-review/rules/
vscode.window.showInformationMessage('添加自定义规则功能开发中');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.fixIssue', () => {
// TODO: Phase 4.5 — 单条修复(与审查面板交互)
vscode.window.showInformationMessage('单条修复功能开发中');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.fixAll', () => {
// TODO: Phase 4.5 — 批量修复
vscode.window.showInformationMessage('批量修复功能开发中');
})
);
context.subscriptions.push(
vscode.commands.registerCommand('codeReviewer.openSetup', () => {
vscode.commands.executeCommand('workbench.view.extension.code-reviewer');
})
);
}
2. src/extension.ts 修改
import * as vscode from 'vscode';
import { Orchestrator } from './orchestrator/orchestrator';
import { registerCommands } from './activation/commands';
let orchestrator: Orchestrator;
export function activate(context: vscode.ExtensionContext) {
console.log('净码特工 · Code Purifier 已激活');
orchestrator = new Orchestrator();
registerCommands(context, orchestrator);
const debounceTimers = new Map<string, NodeJS.Timeout>();
context.subscriptions.push(
vscode.workspace.onDidSaveTextDocument((document) => {
const key = document.uri.toString();
const existing = debounceTimers.get(key);
if (existing) { clearTimeout(existing); }
const timer = setTimeout(() => {
debounceTimers.delete(key);
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
const workingDir = workspaceRoot || vscode.Uri.joinPath(document.uri, '..').fsPath;
orchestrator.runStaticAnalysis(document, workingDir);
}, 500);
debounceTimers.set(key, timer);
})
);
}
export function deactivate() {
orchestrator = undefined!;
}
3. package.json 修改
将 configuration 部分替换为完整的命令、视图容器、菜单和配置项。
commands:
{
"commands": [
{ "command": "codeReviewer.review", "title": "净码特工: 运行代码审查" },
{ "command": "codeReviewer.reviewSelection", "title": "净码特工: 审查选中代码" },
{ "command": "codeReviewer.openPanel", "title": "净码特工: 打开审查面板" },
{ "command": "codeReviewer.exportReport", "title": "净码特工: 导出报告" },
{ "command": "codeReviewer.addCustomRule", "title": "净码特工: 添加自定义规则" },
{ "command": "codeReviewer.fixIssue", "title": "净码特工: 修复此问题" },
{ "command": "codeReviewer.fixAll", "title": "净码特工: 批量修复" },
{ "command": "codeReviewer.openSetup", "title": "净码特工: 打开设置面板" }
]
}
keybindings:
{
"keybindings": [
{
"command": "codeReviewer.review",
"key": "ctrl+shift+r",
"when": "editorTextFocus"
}
]
}
viewsContainers + views + menus + configuration: 见设计 §6.2-6.4
验收
- 3 个文件变更完成
Ctrl+Shift+R可触发审查- 保存文件后 500ms 自动运行静态分析
- 命令面板显示 8 个命令
npm run compile通过npm run lint通过