1. 从零写一个 VSCode 插件,为什么我建议顺手把模型调用也接进去
VSCode 插件开发这件事,说难不难,说简单也容易踩坑。它本质上是往编辑器里塞一段 Node.js 代码,通过package.json声明「我能干什么」,再通过extension.ts里的activate函数告诉 VSCode「什么时候把我叫起来」。你不需要懂 Electron 底层,也不用改 VSCode 源码,只要会写 TypeScript,就能做出一个能选中代码、右键转换、快捷键触发的实用工具。
但真正让插件「有灵魂」的,是它能调用外部能力。比如你写一个命名转换插件,选中user_name想转成userName,本地正则当然能做;可如果你想让它理解语义、按团队规范重命名、甚至生成一段注释,那就得调用大模型。问题来了:每接一个模型就配一套 Key、改一次环境变量,插件里散落一堆密钥,既难维护又不安全。
这篇就按「从 extension.ts 到 vsce 发布」的完整链路走一遍,并且演示怎么在插件里通过统一 Key / API 通道调用模型。你跟着做,能拿到一个可 F5 调试、可vsce package打包、可发布到市场的插件骨架。适合已经会一点 TypeScript、想把自己重复劳动工具化的开发者。下面所有配置我都实测跑过,命令可以直接复制。
2. 前置准备:环境、脚手架与 TaoToken 统一 Key
2.1 先把 Node 和脚手架装好
插件开发依赖 Node.js 和 Git,建议 Node 18 以上。装完执行:
npm install -g yo generator-code @vscode/vscegenerator-code是官方脚手架,@vscode/vsce是后面打包发布用的命令行工具。装好后运行yo code,选择New Extension (TypeScript),按提示填插件名,比如name-transform。脚手架会生成一整套目录,核心就两个文件:package.json和src/extension.ts。
2.2 为什么用统一 Key 而不是每个模型一套
插件里调用模型,最怕两件事:一是密钥硬编码进代码,打包发布后等于公开;二是换模型要改代码。统一 Key 的思路是:插件只认一个 API 地址和一个 Key,具体路由到哪个模型由服务端决定。这样插件代码干净,密钥放配置里,换模型不动插件。
TaoToken 就提供这种统一通道,官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。你需要在控制台创建一个 Key,后面插件通过Authorization: Bearer <你的Key>调用。Key 的创建入口在控制台的 API Keys 页面,接入细节可以对照官方文档,模型对话能力可以在模型对话页先试跑通再写进插件。
注意:Key 不要写进
extension.ts,也不要提交到 Git。正确做法是让用户在 VSCode 设置里填,插件通过vscode.workspace.getConfiguration读取。
3. 可复制的 package.json 与 extension.ts 骨架
3.1 package.json:声明命令、菜单、快捷键和配置项
package.json是插件的「说明书」,VSCode 靠它知道你的插件提供哪些命令、在哪儿显示、有哪些设置。下面这份可以直接改名字用:
{ "name": "name-transform", "displayName": "Name Transform", "description": "选中代码,一键转换命名风格,并可通过统一 Key 调用模型生成规范命名", "version": "0.0.1", "engines": { "vscode": "^1.85.0" }, "categories": ["Other"], "activationEvents": [], "main": "./out/extension.js", "contributes": { "commands": [ { "command": "nameTransform.toCamel", "title": "转换为小驼峰" }, { "command": "nameTransform.toSnake", "title": "转换为下划线" }, { "command": "nameTransform.aiRename", "title": "AI 智能重命名" } ], "menus": { "editor/context": [ { "command": "nameTransform.toCamel", "group": "navigation@1" }, { "command": "nameTransform.toSnake", "group": "navigation@2" }, { "command": "nameTransform.aiRename", "group": "navigation@3" } ] }, "keybindings": [ { "command": "nameTransform.toCamel", "key": "ctrl+alt+c", "mac": "cmd+alt+c", "when": "editorTextFocus" } ], "configuration": { "title": "Name Transform", "properties": { "nameTransform.apiKey": { "type": "string", "default": "", "description": "TaoToken 统一 Key,用于 AI 重命名" }, "nameTransform.apiBase": { "type": "string", "default": "https://taotoken.net/api", "description": "统一 API 地址" }, "nameTransform.model": { "type": "string", "default": "claude-sonnet-4-5", "description": "调用的模型名称" } } } }, "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./" }, "devDependencies": { "@types/vscode": "^1.85.0", "@types/node": "^20.0.0", "typescript": "^5.4.0" } }几个关键点:activationEvents在新版本里可以留空,VSCode 会根据contributes.commands自动推断激活时机;menus.editor/context让命令出现在右键菜单;keybindings绑定快捷键;configuration暴露三个设置项,用户可以在设置里填 Key、改地址、换模型。
3.2 extension.ts:激活入口与命令注册
extension.ts是入口,activate在插件被激活时执行,deactivate在卸载时清理。下面这份骨架包含本地转换和 AI 调用两部分:
import * as vscode from 'vscode'; const COMMANDS = { toCamel: 'nameTransform.toCamel', toSnake: 'nameTransform.toSnake', aiRename: 'nameTransform.aiRename' }; export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand(COMMANDS.toCamel, () => transformLocal('camel')), vscode.commands.registerCommand(COMMANDS.toSnake, () => transformLocal('snake')), vscode.commands.registerCommand(COMMANDS.aiRename, () => aiRename()) ); } function getSelectedText(): { editor: vscode.TextEditor; text: string } | undefined { const editor = vscode.window.activeTextEditor; if (!editor) return undefined; const text = editor.document.getText(editor.selection); if (!text) { vscode.window.showWarningMessage('请先选中一段文本'); return undefined; } return { editor, text }; } function transformLocal(style: 'camel' | 'snake') { const sel = getSelectedText(); if (!sel) return; const words = sel.text.split(/[_\-\s]+/).filter(Boolean); const result = style === 'camel' ? words.map((w, i) => i === 0 ? w.toLowerCase() : w[0].toUpperCase() + w.slice(1).toLowerCase()).join('') : words.map(w => w.toLowerCase()).join('_'); sel.editor.edit(e => e.replace(sel.editor.selection, result)); } async function aiRename() { const sel = getSelectedText(); if (!sel) return; const cfg = vscode.workspace.getConfiguration('nameTransform'); const apiKey = cfg.get<string>('apiKey'); const apiBase = cfg.get<string>('apiBase'); const model = cfg.get<string>('model'); if (!apiKey) { vscode.window.showErrorMessage('请先在设置中配置 nameTransform.apiKey'); return; } const prompt = `请把下面的标识符按团队规范重命名,只返回新名字,不要解释:\n${sel.text}`; try { const res = await fetch(`${apiBase}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }], temperature: 0.2 }) }); if (!res.ok) { throw new Error(`HTTP ${res.status}: ${await res.text()}`); } const data: any = await res.json(); const newName = data.choices?.[0]?.message?.content?.trim(); if (!newName) throw new Error('模型返回为空'); sel.editor.edit(e => e.replace(sel.editor.selection, newName)); vscode.window.showInformationMessage(`已重命名为 ${newName}`); } catch (err: any) { vscode.window.showErrorMessage(`AI 重命名失败:${err.message}`); } } export function deactivate() {}这里用 Node 18 自带的fetch,不用额外装 axios。aiRename从配置读 Key 和地址,拼一个标准的 chat completions 请求,把选中文本作为 prompt 发出去,拿到结果后替换选区。整个流程没有硬编码密钥,用户换模型只改设置。
4. 本地 F5 调试与 vsce package 验证
4.1 F5 启动扩展开发宿主
先开一个终端跑编译监听:
npm run watch然后在 VSCode 左侧点「运行和调试」图标,按 F5,会弹出一个新窗口,标题带「扩展开发宿主」。这个新窗口里你的插件是生效的。打开任意文件,选中一段user_name,按Ctrl+Alt+C,应该变成userName;右键菜单里也能看到三个命令。
注意:调试前一定要先跑
npm run watch,否则改了extension.ts不重新编译,调试窗口里命令不生效,这是新手最常见的坑。
4.2 配置 Key 并验证 AI 调用
在调试窗口里按Ctrl+,打开设置,搜索nameTransform,把apiKey填成你在控制台创建的 Key,apiBase保持https://taotoken.net/api,model填你要用的模型名。然后选中一段命名混乱的代码,右键选「AI 智能重命名」,如果配置正确,选区会被替换成模型返回的新名字,右下角弹出提示。
如果这一步想先单独验证 Key 和模型是否通,可以先用模型对话页发一条消息确认通道正常,再回到插件里调。长期做编码类插件、需要频繁调用模型的,可以了解 Coding Plan,它更适合持续性的编码场景。
4.3 vsce package 打包验证
功能没问题后,先编译再打包:
npm run compile vsce package成功的话会在根目录生成name-transform-0.0.1.vsix。这个文件可以直接在 VSCode 里「从 VSIX 安装」验证,也可以上传到市场。打包前记得检查.vscodeignore,把src、node_modules里不必要的东西排除,否则包会很大。如果vsce package报缺少repository字段,在package.json里补一个repository地址即可。
5. 本篇常见错误排查
5.1 命令不生效、右键菜单没有
八成是没跑npm run watch,或者package.json里contributes.commands的command值和extension.ts里registerCommand的字符串不一致。两者必须完全对应,大小写都不能错。改完package.json要重启调试窗口,因为它只在激活时读一次。
5.2 AI 调用返回 401 或 404
401 一般是 Key 没填、填错,或者Authorization头格式不对,正确格式是Bearer <Key>,中间一个空格。404 多半是apiBase拼错了,注意不要重复拼/v1,代码里已经带了/v1/chat/completions,所以apiBase只写到https://taotoken.net/api。如果返回模型不存在,检查model字段是不是当前通道支持的模型名。
5.3 打包报错或安装后不工作
vsce package常见报错是Missing publisher,在package.json里加"publisher": "你的发布者ID"。安装后不工作,先看main字段指向的./out/extension.js是否真的存在,也就是有没有先npm run compile。另外engines.vscode版本别写太高,否则低版本 VSCode 装不上。
6. 把 Key 管好,把插件发出去
走到这里,你已经有了一个能调试、能打包、能调用模型的插件。最后强调两件事:一是 Key 永远走设置项,不要写死;二是发布前用vsce package生成的 vsix 在干净环境里再装一次,确认没有依赖本地路径。
发布到市场需要微软账号和发布者 ID,vsce publish前先vsce login填个人访问令牌。如果你只是想团队内部用,直接把 vsix 发给同事安装就够了,不必走市场审核。插件里调用模型的 Key 管理、接入文档和模型列表,都可以在 https://taotoken.net/api 对应的控制台和文档里找到,先把通道跑通,再把它封装成你顺手的小工具,这才是插件开发最舒服的节奏。