Files
claude-code/docs/superpowers/specs/2026-04-07-vscode-ide-bridge-design.md
2026-04-09 01:26:18 +08:00

351 lines
8.7 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.
# VSCode IDE Bridge 设计文档
**日期:** 2026-04-07
## 1. 背景
当前仓库已经具备一套较完整的 IDE 接入链路:
- CLI 能发现 `ws-ide` / `sse-ide` 类型的 IDE 连接
- CLI 能接收 `selection_changed` 并将其注入为 `<ide_selection>` 上下文
- CLI 能调用 `openDiff``close_tab``closeAllDiffTabs` 等 IDE RPC
- `/ide`、diff 预览、选区提示、已打开文件提示都依赖这套链路
但当前仓库中没有可直接使用的 VSCode 扩展实现,导致本地 VSCode 无法真正把这些能力提供给 CLI。目标不是重做一个聊天面板而是补齐一个兼容现有 CLI 协议的 VSCode 扩展,让 CLI “像连接到原生 IDE 扩展一样”工作。
## 2. 目标
构建一个独立的 VSCode 扩展,在本地暴露一个与当前 CLI 兼容的 `ws-ide` 服务,完成以下能力:
1. 让 CLI 能自动发现 VSCode
2. 让 VSCode 当前文件和选区变化能进入 CLI 的 IDE 上下文链路
3. 让 CLI 发起的 diff 预览能在 VSCode 中打开和关闭
4. 保持实现最小、可调试、可逐步扩展
## 3. 非目标
第一版明确不做以下内容:
- 不实现 VSCode 聊天面板
- 不接入远程工作区、Codespaces、Dev Container、SSH Remote
- 不兼容多台机器之间的桥接
- 不实现复杂的会话恢复或扩展端持久化缓存
- 不覆盖官方扩展的所有功能
## 4. 总体方案
采用“独立 sidecar 扩展 + 本地 WebSocket IDE Bridge”的方式。
### 4.1 连接模型
VSCode 扩展启动后:
1.`127.0.0.1` 上启动一个随机可用端口的 WebSocket 服务
2. 生成与 CLI 现有 IDE 发现逻辑兼容的 lockfile
3. 等待 CLI 以 `ws-ide` MCP 客户端身份连接
4. 扩展在该 WebSocket 连接上暴露 MCP Server负责把 IDE 事件推送给 CLI并响应 CLI 发来的 MCP tool 调用
### 4.2 复用现有 CLI 能力
扩展尽量不改 CLI 的上层交互,只复用现有协议:
- VSCode -> CLI`selection_changed``ide_connected` 通知
- CLI -> VSCode通过 MCP tool 调用 `openDiff``close_tab``closeAllDiffTabs`
这样可以最大化复用:
- `src/hooks/useIdeSelection.ts`
- `src/utils/attachments.ts`
- `src/utils/messages.ts`
- `src/hooks/useDiffInIDE.ts`
- `/ide` 命令及 IDE 状态展示
## 5. 协议设计
### 5.1 Lockfile
扩展写出的 lockfile 需要满足 CLI 的 IDE 自动发现逻辑。内容至少包含:
- `workspaceFolders`
- `pid`
- `ideName`
- `transport: "ws"`
- `runningInWindows`
- `authToken`
文件名使用端口号,例如 `<port>.lock`
### 5.2 鉴权
扩展启动时生成一次随机 `authToken`
- 写入 lockfile
- CLI 连接 `ws-ide` 时通过 `X-Claude-Code-Ide-Authorization` 头带上
- 扩展端校验成功后才允许建立 MCP/WebSocket 会话
第一版只允许本地回环地址,不暴露到公网。
### 5.3 VSCode -> CLI 通知
#### `selection_changed`
在下列事件触发后发送:
- `window.onDidChangeTextEditorSelection`
- `window.onDidChangeActiveTextEditor`
- 扩展激活完成后的初始同步
消息字段包含:
- `selection.start.line`
- `selection.start.character`
- `selection.end.line`
- `selection.end.character`
- `text`
- `filePath`
若当前没有活动选区:
- `selection` 允许为 `null`
- 仍尽量发送 `filePath`
这样 CLI 至少可以知道“用户当前打开的是哪个文件”。
### 5.4 CLI -> VSCode MCP tools
#### `openDiff`
入参:
- `old_file_path`
- `new_file_path`
- `new_file_contents`
- `tab_name`
行为:
- 读取当前磁盘文件内容作为左侧内容
- 使用临时文档或内存文档构造右侧内容
- 在 VSCode 中打开 diff 视图
- 记录 `tab_name -> 资源引用` 映射
#### `close_tab`
入参:
- `tab_name`
行为:
- 根据映射关闭对应 diff 视图
- 清理映射与临时资源
#### `closeAllDiffTabs`
行为:
- 关闭所有由本扩展打开的 diff 标签
- 清理内部状态
## 6. 扩展内部结构
建议新增独立包:`packages/vscode-ide-bridge`
目录结构如下:
```text
packages/vscode-ide-bridge/
package.json
tsconfig.json
src/
extension.ts
server/
bridgeServer.ts
lockfile.ts
workspaceInfo.ts
selectionPublisher.ts
diffController.ts
protocol.ts
util/
randomToken.ts
disposables.ts
test/
selectionPublisher.test.ts
lockfile.test.ts
bridgeServer.test.ts
diffController.test.ts
```
各模块职责如下:
- `extension.ts`
VSCode 扩展入口,负责激活、停用、启动 bridge、注册命令。
- `bridgeServer.ts`
本地 WebSocket 服务与消息路由层,负责握手、鉴权、连接管理,以及把单个 WebSocket 连接桥接为 MCP transport。
- `lockfile.ts`
负责写 lockfile、更新 lockfile、删除 lockfile。
- `workspaceInfo.ts`
负责采集工作区目录、平台信息、活动编辑器文件路径。
- `selectionPublisher.ts`
监听 VSCode 编辑器事件,并把选区信息转换为 `selection_changed`
- `diffController.ts`
处理 `openDiff` / `close_tab` / `closeAllDiffTabs` 这三个 MCP tools维护临时资源和 tab 映射。
- `protocol.ts`
统一定义扩展端需要识别和发送的消息结构,避免字符串散落。
## 7. 命令与可观察性
虽然主流程是自动连接,但第一版仍建议提供两个调试命令:
- `Claude Code Bridge: Restart`
- `Claude Code Bridge: Show Status`
状态信息至少包含:
- 当前监听端口
- lockfile 路径
- 是否有 CLI 已连接
- 当前工作区数量
- 最近一次选区推送时间
另外建议注册一个 output channel
- `Claude Code IDE Bridge`
用于输出:
- 启动日志
- 鉴权失败
- lockfile 写入失败
- diff 打开失败
- 连接断开原因
## 8. 错误处理策略
### 8.1 端口占用
- 自动尝试新的随机端口
- 更新 lockfile
- 在 output channel 中记录端口变化
### 8.2 lockfile 写入失败
- bridge 不进入 ready 状态
- 弹出 VSCode 错误通知
- output channel 记录完整错误
### 8.3 WebSocket 鉴权失败
- 拒绝连接
- 记录远端地址和失败原因
### 8.4 活动编辑器为空
- 发送空选区状态或仅跳过通知
- 不抛异常、不打断 bridge 生命周期
### 8.5 diff 打开失败
- 返回明确错误结果给 CLI
- 不留下半开的临时资源
### 8.6 扩展退出
- 关闭 WebSocket server
- 删除 lockfile
- 释放临时文档资源
- 清空 tab 映射
## 9. 测试方案
### 9.1 单元测试
覆盖以下逻辑:
- lockfile 内容生成与路径选择
- 选区对象到协议消息的转换
- tab 映射和关闭逻辑
- 鉴权令牌校验
### 9.2 集成测试
通过 Node/WebSocket 客户端模拟 CLI
- 连接本地 bridge server
- 验证鉴权成功与失败
- 验证 `selection_changed` 是否按预期发送
- 验证 `openDiff` / `close_tab` 是否触发预期行为
### 9.3 手工验证
手工验证路径:
1. 启动 VSCode 扩展
2. 启动 `claude-code-best`
3. 执行 `/ide`
4. 确认 CLI 能识别到 VSCode
5. 在 VSCode 中选中一段代码并提问
6. 确认 CLI 能注入 `<ide_selection>`
7. 触发一次 IDE diff
8. 确认 diff 标签可打开、保存、关闭
## 10. 风险与取舍
### 10.1 MCP 完整兼容风险
仓库当前 CLI 连接 `ws-ide` 时使用的是 MCP 客户端通路,因此扩展端若实现过薄,可能在握手或工具注册阶段与 CLI 预期不一致。
**取舍:**
第一版只实现 CLI 当前实际会调用到的最小工具与通知,不尝试泛化为完整 MCP server但协议层要留出扩展空间。
### 10.2 VSCode diff 资源回收
VSCode diff 视图不是纯命名 tab直接按 `tab_name` 定位关闭可能和实际标签生命周期有偏差。
**取舍:**
扩展内部维护显式映射,以资源 URI 为主、`tab_name` 为辅,不依赖 UI 文本匹配。
### 10.3 多工作区与路径兼容
Windows、WSL、单根工作区、多根工作区在路径表示上会不同。
**取舍:**
第一版先以本机本地工作区为主路径统一走绝对路径WSL/Windows 转换尽量复用 CLI 现有约定,不在扩展端重新发明路径映射。
## 11. 分阶段交付
### 第一阶段
目标:打通本地 VSCode 与 CLI 的最小闭环。
范围:
- 启动 `ws-ide`
- 写 lockfile
- 发送 `selection_changed`
- 实现 `openDiff`
- 实现 `close_tab`
- 实现 `closeAllDiffTabs`
- 提供状态命令和日志输出
### 第二阶段
目标:增强稳定性和调试能力。
范围:
- 更细的错误提示
- 更稳定的 tab 生命周期管理
- 更多 IDE 状态信息展示
- 更完整的集成测试
## 12. 结论
推荐按本设计实现独立的 VSCode IDE Bridge 扩展,并让它完全对齐当前 CLI 已有的 `ws-ide` 连接与 IDE 上下文/差异视图协议。这样能在不大改 CLI 上层逻辑的前提下,把 VSCode 选区、当前文件和 diff 预览能力真正打通。