# 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` ```typescript 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` 修改 ```typescript 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(); 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**: ```json { "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**: ```json { "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` 通过