Files
2026Technology-Competition/docs/superpowers/specs/implementation-steps/15-phase5.1-commands-extension.md
T
范智鹏 a734cdf009 refactor: 品牌重命名 + maxTokens 支持 + 设置面板简化
- 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
2026-07-20 20:24:40 +08:00

8.2 KiB
Raw Blame History

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

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 通过