💻 OpenClaw VS Code 扩展开发指南

凌晨2点17分,我第37次按下了Ctrl+Space。代码补全弹出的那一刻,我突然想:如果这背后是我的OpenClaw呢?

VS Code + OpenClaw = 你的专属AI编程助手

把OpenClaw接入VS Code,实现智能代码补全、重构建议、Bug修复、文档生成。不需要依赖GitHub Copilot,完全自托管,代码不上云。

🎯 方案选择

🛠️ 方案A:CLI集成(5分钟搞定)

Step 1: 配置VS Code任务

// .vscode/tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "OpenClaw: 解释代码",
      "type": "shell",
      "command": "openclaw",
      "args": [
        "chat",
        "--message",
        "解释这段代码:${selectedText}",
        "--output",
        "markdown"
      ],
      "group": "none",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared"
      }
    },
    {
      "label": "OpenClaw: 重构代码",
      "type": "shell",
      "command": "openclaw",
      "args": [
        "chat",
        "--message",
        "重构这段代码,提高可读性:${selectedText}"
      ]
    }
  ]
}

Step 2: 添加快捷键

// .vscode/keybindings.json
[
  {
    "key": "ctrl+shift+e",
    "command": "workbench.action.tasks.runTask",
    "args": "OpenClaw: 解释代码",
    "when": "editorHasSelection"
  },
  {
    "key": "ctrl+shift+r",
    "command": "workbench.action.tasks.runTask",
    "args": "OpenClaw: 重构代码",
    "when": "editorHasSelection"
  }
]

Step 3: 使用

选中代码 → 按 Ctrl+Shift+E → 看OpenClaw解释代码

🚀 方案B:开发VS Code扩展

项目结构

openclaw-vscode/
├── package.json          # 扩展配置
├── src/
│   ├── extension.ts      # 入口文件
│   ├── openclawClient.ts # API客户端
│   └── providers/        # 各种Provider
│       ├── completionProvider.ts
│       ├── hoverProvider.ts
│       └── codeActionProvider.ts
└── README.md

package.json配置

{
  "name": "openclaw-vscode",
  "displayName": "OpenClaw AI Assistant",
  "version": "1.0.0",
  "engines": {
    "vscode": "^1.74.0"
  },
  "categories": ["Machine Learning", "Snippets"],
  "activationEvents": ["onLanguage:python", "onLanguage:javascript"],
  "main": "./out/extension.js",
  "contributes": {
    "configuration": {
      "title": "OpenClaw",
      "properties": {
        "openclaw.apiUrl": {
          "type": "string",
          "default": "http://localhost:3000",
          "description": "OpenClaw API地址"
        },
        "openclaw.apiKey": {
          "type": "string",
          "default": "",
          "description": "API密钥"
        }
      }
    },
    "commands": [
      {
        "command": "openclaw.explain",
        "title": "用OpenClaw解释代码",
        "category": "OpenClaw"
      },
      {
        "command": "openclaw.generateDoc",
        "title": "生成文档注释",
        "category": "OpenClaw"
      }
    ],
    "menus": {
      "editor/context": [
        {
          "command": "openclaw.explain",
          "group": "9_cutcopypaste@5",
          "when": "editorHasSelection"
        }
      ]
    }
  }
}

核心代码:extension.ts

import * as vscode from 'vscode';
import { OpenClawClient } from './openclawClient';

export function activate(context: vscode.ExtensionContext) {
    const config = vscode.workspace.getConfiguration('openclaw');
    const client = new OpenClawClient(
        config.get('apiUrl') || 'http://localhost:3000',
        config.get('apiKey') || ''
    );

    // 注册:解释代码命令
    let explainDisposable = vscode.commands.registerCommand(
        'openclaw.explain',
        async () => {
            const editor = vscode.window.activeTextEditor;
            if (!editor) return;

            const selectedText = editor.document.getText(editor.selection);
            if (!selectedText) {
                vscode.window.showWarningMessage('请先选中代码');
                return;
            }

            // 显示进度
            await vscode.window.withProgress({
                location: vscode.ProgressLocation.Notification,
                title: "OpenClaw正在分析代码...",
                cancellable: false
            }, async () => {
                try {
                    const explanation = await client.explainCode(selectedText);
                    
                    // 在输出通道显示结果
                    const outputChannel = vscode.window.createOutputChannel('OpenClaw');
                    outputChannel.clear();
                    outputChannel.appendLine('=== 代码解释 ===');
                    outputChannel.appendLine(explanation);
                    outputChannel.show();
                } catch (error) {
                    vscode.window.showErrorMessage(`OpenClaw错误: ${error}`);
                }
            });
        }
    );

    context.subscriptions.push(explainDisposable);
}

export function deactivate() {}

API客户端:openclawClient.ts

import axios from 'axios';

export class OpenClawClient {
    constructor(private baseUrl: string, private apiKey: string) {}

    async explainCode(code: string, language?: string): Promise {
        const response = await axios.post(
            `${this.baseUrl}/api/v1/chat`,
            {
                message: `解释以下${language || ''}代码:\n\n\`\`\`\n${code}\n\`\`\`\n\n请说明:\n1. 这段代码的功能\n2. 关键逻辑\n3. 潜在问题(如有)`,
                context: {
                    temperature: 0.3,
                    max_tokens: 2048
                }
            },
            {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                }
            }
        );
        return response.data.content;
    }

    async generateDoc(code: string): Promise {
        const response = await axios.post(
            `${this.baseUrl}/api/v1/chat`,
            {
                message: `为以下代码生成文档注释:\n\n${code}`,
                context: {
                    temperature: 0.2
                }
            },
            {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`
                }
            }
        );
        return response.data.content;
    }
}

智能补全Provider

import * as vscode from 'vscode';
import { OpenClawClient } from '../openclawClient';

export class OpenClawCompletionProvider implements vscode.CompletionItemProvider {
    constructor(private client: OpenClawClient) {}

    async provideCompletionItems(
        document: vscode.TextDocument,
        position: vscode.Position
    ): Promise {
        // 获取当前行和上下文
        const linePrefix = document.lineAt(position).text.substr(0, position.character);
        
        // 只在特定触发条件下提供AI补全
        if (!linePrefix.includes('// AI:')) {
            return [];
        }

        const codeContext = this.getCodeContext(document, position);
        
        try {
            const suggestion = await this.client.completeCode(codeContext);
            
            const item = new vscode.CompletionItem(
                'AI生成代码',
                vscode.CompletionItemKind.Snippet
            );
            item.insertText = suggestion;
            item.detail = '由OpenClaw生成';
            item.documentation = new vscode.MarkdownString(suggestion);
            
            return [item];
        } catch (error) {
            return [];
        }
    }

    private getCodeContext(document: vscode.TextDocument, position: vscode.Position): string {
        // 获取前后50行作为上下文
        const startLine = Math.max(0, position.line - 50);
        const endLine = Math.min(document.lineCount, position.line + 50);
        
        let context = '';
        for (let i = startLine; i < endLine; i++) {
            context += document.lineAt(i).text + '\n';
        }
        return context;
    }
}

🎯 高级功能

内联聊天(Inline Chat)

// 在编辑器内直接对话
const inlineChat = vscode.languages.registerInlineChatProvider(
    { pattern: '**' },
    {
        provideResponse: async (request, progress, token) => {
            const code = request.doc.getText(request.selection);
            const response = await client.chat(code, request.prompt);
            return { edits: [{ range: request.selection, text: response }] };
        }
    }
);

侧边栏Chat视图

// 创建Webview面板
const panel = vscode.window.createWebviewPanel(
    'openclawChat',
    'OpenClaw Chat',
    vscode.ViewColumn.Beside,
    { enableScripts: true }
);

panel.webview.html = getChatWebviewContent();

💎 最佳实践

🔗 相关资源

最后的代码:
"IDE是程序员的第二大脑,而OpenClaw是这个大脑的外接神经网络。凌晨3点,最后一个bug被修复——不是被我,而是被我的AI副驾驶。"