Разработка AI-расширения для VS Code
VS Code Extension — TypeScript/JavaScript приложение, интегрирующееся в редактор через Extension API. AI-расширение может добавлять: inline suggestions, chat panel, code actions (рефакторинг, объяснение кода), hover tooltips с AI-объяснениями.
Структура расширения
// package.json
{
"name": "ai-dev-assistant",
"displayName": "AI Dev Assistant",
"engines": { "vscode": "^1.85.0" },
"activationEvents": ["onStartupFinished"],
"contributes": {
"commands": [
{ "command": "aiAssistant.explainCode", "title": "AI: Explain Code" },
{ "command": "aiAssistant.refactor", "title": "AI: Refactor Selection" },
{ "command": "aiAssistant.generateTests", "title": "AI: Generate Tests" },
{ "command": "aiAssistant.openChat", "title": "AI: Open Chat" }
],
"keybindings": [
{ "command": "aiAssistant.explainCode", "key": "ctrl+shift+e", "when": "editorTextFocus" }
],
"configuration": {
"title": "AI Assistant",
"properties": {
"aiAssistant.apiKey": {
"type": "string",
"description": "Anthropic API Key"
},
"aiAssistant.model": {
"type": "string",
"default": "claude-haiku-4-5",
"enum": ["claude-haiku-4-5", "claude-sonnet-4-5"]
}
}
}
},
"main": "./out/extension.js"
}
Основной файл расширения
// src/extension.ts
import * as vscode from 'vscode';
import Anthropic from '@anthropic-ai/sdk';
let client: Anthropic;
export function activate(context: vscode.ExtensionContext) {
const config = vscode.workspace.getConfiguration('aiAssistant');
client = new Anthropic({ apiKey: config.get('apiKey') || '' });
// Команда объяснения кода
context.subscriptions.push(
vscode.commands.registerCommand('aiAssistant.explainCode', explainSelectedCode)
);
// Команда рефакторинга
context.subscriptions.push(
vscode.commands.registerCommand('aiAssistant.refactor', refactorCode)
);
// Генерация тестов
context.subscriptions.push(
vscode.commands.registerCommand('aiAssistant.generateTests', generateTests)
);
// Chat panel
context.subscriptions.push(
vscode.commands.registerCommand('aiAssistant.openChat', () => {
ChatPanel.createOrShow(context.extensionUri);
})
);
// Code Actions Provider (лампочка в редакторе)
context.subscriptions.push(
vscode.languages.registerCodeActionsProvider(
{ scheme: 'file', language: 'python' },
new AICodeActionProvider(),
)
);
}
async function explainSelectedCode() {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
const selection = editor.selection;
const selectedText = editor.document.getText(selection);
if (!selectedText) {
vscode.window.showWarningMessage('Выберите код для объяснения');
return;
}
// Показываем прогресс
await vscode.window.withProgress(
{ location: vscode.ProgressLocation.Notification, title: 'AI анализирует код...' },
async () => {
const response = await client.messages.create({
model: 'claude-haiku-4-5',
max_tokens: 1024,
messages: [{
role: 'user',
content: `Объясни этот код кратко и понятно:\n\`\`\`\n${selectedText}\n\`\`\``
}]
});
const explanation = response.content[0].type === 'text' ? response.content[0].text : '';
// Показываем в Output Channel
const outputChannel = vscode.window.createOutputChannel('AI Assistant');
outputChannel.appendLine('=== AI Объяснение ===');
outputChannel.appendLine(explanation);
outputChannel.show();
}
);
}
Chat Panel (WebviewPanel)
class ChatPanel {
private static currentPanel?: ChatPanel;
private readonly panel: vscode.WebviewPanel;
static createOrShow(extensionUri: vscode.Uri) {
if (ChatPanel.currentPanel) {
ChatPanel.currentPanel.panel.reveal();
return;
}
const panel = vscode.window.createWebviewPanel(
'aiChat', 'AI Chat', vscode.ViewColumn.Beside,
{ enableScripts: true }
);
ChatPanel.currentPanel = new ChatPanel(panel, extensionUri);
}
constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this.panel = panel;
this.panel.webview.html = this.getWebviewContent();
this.panel.webview.onDidReceiveMessage(async message => {
if (message.type === 'chat') {
// Streaming response
const stream = await client.messages.stream({
model: 'claude-sonnet-4-5',
max_tokens: 2048,
messages: message.history,
});
for await (const chunk of stream.textStream) {
this.panel.webview.postMessage({ type: 'token', text: chunk });
}
this.panel.webview.postMessage({ type: 'done' });
}
});
}
private getWebviewContent(): string {
return `<!DOCTYPE html>
<html>
<head><style>/* styles */</style></head>
<body>
<div id="messages"></div>
<input type="text" id="input" placeholder="Задайте вопрос..." />
<button onclick="sendMessage()">Отправить</button>
<script>
const vscode = acquireVsCodeApi();
const history = [];
function sendMessage() {
const input = document.getElementById('input');
history.push({ role: 'user', content: input.value });
vscode.postMessage({ type: 'chat', history });
input.value = '';
}
window.addEventListener('message', event => {
const msg = event.data;
if (msg.type === 'token') {
// Append token to current message
}
});
</script>
</body>
</html>`;
}
}
Code Actions Provider
class AICodeActionProvider implements vscode.CodeActionProvider {
provideCodeActions(
document: vscode.TextDocument,
range: vscode.Range,
): vscode.CodeAction[] {
const actions: vscode.CodeAction[] = [];
const selectedText = document.getText(range);
if (!selectedText) return actions;
// Добавляем AI действия в контекстное меню
const explainAction = new vscode.CodeAction('AI: Объяснить', vscode.CodeActionKind.RefactorRewrite);
explainAction.command = { command: 'aiAssistant.explainCode', title: 'Объяснить' };
actions.push(explainAction);
return actions;
}
}
Сроки
- Базовые команды (explain, refactor): 3–5 дней
- Chat panel с WebView: 1 неделя
- Inline completion provider: 1–2 недели
- Публикация в VS Code Marketplace: 1–2 дня







