Files
2026Technology-Competition/docs/superpowers/specs/implementation-steps/15-phase5.1-commands-extension.md
T

253 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Step 15 — Phase 5.1: 命令注册 + extension.ts 更新
**依赖**: Step 08, 14Orchestrator + 报告导出),Step 13Fixer 可选)
**参考设计**: §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('CodeGuard 代码审查插件已激活');
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**:
```json
{
"commands": [
{ "command": "codeReviewer.review", "title": "CodeGuard: 运行代码审查" },
{ "command": "codeReviewer.reviewSelection", "title": "CodeGuard: 审查选中代码" },
{ "command": "codeReviewer.openPanel", "title": "CodeGuard: 打开审查面板" },
{ "command": "codeReviewer.exportReport", "title": "CodeGuard: 导出报告" },
{ "command": "codeReviewer.addCustomRule", "title": "CodeGuard: 添加自定义规则" },
{ "command": "codeReviewer.fixIssue", "title": "CodeGuard: 修复此问题" },
{ "command": "codeReviewer.fixAll", "title": "CodeGuard: 批量修复" },
{ "command": "codeReviewer.openSetup", "title": "CodeGuard: 打开设置面板" }
]
}
```
**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` 通过