Skip to content

Gemini CLI 伴侣插件:接口规范

最后更新:2025 年 9 月 15 日

本文档定义了构建伴侣插件以启用 Gemini CLI IDE 模式的契约。对于 VS Code,这些功能(原生差异对比、上下文感知)由官方扩展提供(市场)。此规范适用于希望将类似功能带到其他编辑器(如 JetBrains IDE、Sublime Text 等)的贡献者。

I. 通信接口

Gemini CLI 和 IDE 插件通过本地通信通道进行通信。

1. 传输层:基于 HTTP 的 MCP

插件必须运行一个实现 Model Context Protocol (MCP) 的本地 HTTP 服务器。

  • 协议: 服务器必须是有效的 MCP 服务器。如果可用,我们建议使用你选择语言的现有 MCP SDK。
  • 端点: 服务器应为所有 MCP 通信公开单个端点(例如 /mcp)。
  • 端口: 服务器必须监听动态分配的端口(即监听端口 0)。

2. 发现机制:端口文件

为了让 Gemini CLI 连接,它需要发现它正在运行的 IDE 实例以及你的服务器使用的端口。插件必须通过创建"发现文件"来促进这一点。

  • CLI 如何找到文件: CLI 通过遍历进程树确定它正在运行的 IDE 的进程 ID (PID)。然后它查找名称中包含此 PID 的发现文件。

  • 文件位置: 文件必须在特定目录中创建:os.tmpdir()/gemini/ide/。如果此目录不存在,你的插件必须创建它。

  • 文件命名约定: 文件名至关重要,必须遵循模式:gemini-ide-server-${PID}-${PORT}.json

    • ${PID}:父 IDE 进程的进程 ID。你的插件必须确定此 PID 并将其包含在文件名中。
    • ${PORT}:你的 MCP 服务器正在监听的端口。
  • 文件内容和工作区验证: 文件必须包含具有以下结构的 JSON 对象:

    json
    {
      "port": 12345,
      "workspacePath": "/path/to/project1:/path/to/project2",
      "authToken": "a-very-secret-token",
      "ideInfo": {
        "name": "vscode",
        "displayName": "VS Code"
      }
    }
    • port(数字,必需):MCP 服务器的端口。
    • workspacePath(字符串,必需):所有打开的工作区根路径列表,由操作系统特定的路径分隔符分隔(Linux/macOS 为 :,Windows 为 ;)。CLI 使用此路径确保它运行在 IDE 中打开的同一项目文件夹中。如果 CLI 的当前工作目录不是 workspacePath 的子目录,连接将被拒绝。你的插件必须提供打开工作区根目录的正确绝对路径。
    • authToken(字符串,必需):用于保护连接的密钥令牌。CLI 将在所有请求的 Authorization: Bearer <token> 头中包含此令牌。
    • ideInfo(对象,必需):关于 IDE 的信息。
      • name(字符串,必需):IDE 的简短小写标识符(例如 vscodejetbrains)。
      • displayName(字符串,必需):IDE 的用户友好名称(例如 VS CodeJetBrains IDE)。
  • 认证: 为保护连接,插件必须生成唯一的密钥令牌并将其包含在发现文件中。然后 CLI 将在对 MCP 服务器的所有请求的 Authorization 头中包含此令牌(例如 Authorization: Bearer a-very-secret-token)。你的服务器必须在每个请求上验证此令牌并拒绝任何未授权的请求。

  • 使用环境变量进行决胜(推荐): 为获得最可靠的体验,你的插件应该同时创建发现文件并在集成终端中设置 GEMINI_CLI_IDE_SERVER_PORT 环境变量。文件作为主要发现机制,但环境变量对于决胜至关重要。如果用户为同一工作区打开了多个 IDE 窗口,CLI 使用 GEMINI_CLI_IDE_SERVER_PORT 变量来识别并连接到正确窗口的服务器。

II. 上下文接口

为启用上下文感知,插件可以向 CLI 提供关于用户在 IDE 中活动的实时信息。

ide/contextUpdate 通知

插件可以在用户上下文更改时向 CLI 发送 ide/contextUpdate 通知

  • 触发事件: 此通知应在以下情况下发送(建议 50ms 防抖):

    • 文件被打开、关闭或聚焦。
    • 用户在活动文件中的光标位置或文本选择更改。
  • 负载(IdeContext): 通知参数必须IdeContext 对象:

    typescript
    interface IdeContext {
      workspaceState?: {
        openFiles?: File[];
        isTrusted?: boolean;
      };
    }
    
    interface File {
      // 文件的绝对路径
      path: string;
      // 最后聚焦的 Unix 时间戳(用于排序)
      timestamp: number;
      // 如果这是当前聚焦的文件则为 true
      isActive?: boolean;
      cursor?: {
        // 基于 1 的行号
        line: number;
        // 基于 1 的字符号
        character: number;
      };
      // 用户当前选择的文本
      selectedText?: string;
    }

    注意: openFiles 列表应只包含磁盘上存在的文件。虚拟文件(例如没有路径的未保存文件、编辑器设置页面)必须被排除。

CLI 如何使用此上下文

收到 IdeContext 对象后,CLI 在将信息发送给模型之前执行几个规范化和截断步骤。

  • 文件排序: CLI 使用 timestamp 字段确定最近使用的文件。它根据此值对 openFiles 列表进行排序。因此,你的插件必须提供文件最后聚焦时的准确 Unix 时间戳。
  • 活动文件: CLI 只将最近的文件(排序后)视为"活动"文件。它将忽略所有其他文件上的 isActive 标志并清除它们的 cursorselectedText 字段。你的插件应专注于仅为当前聚焦的文件设置 isActive: true 并提供光标/选择详情。
  • 截断: 为管理 token 限制,CLI 截断文件列表(到 10 个文件)和 selectedText(到 16KB)。

虽然 CLI 处理最终截断,但强烈建议你的插件也限制它发送的上下文量。

III. 差异接口

为启用交互式代码修改,插件可以公开差异接口。这允许 CLI 请求 IDE 打开差异视图,显示对文件的建议更改。然后用户可以直接在 IDE 中审查、编辑并最终接受或拒绝这些更改。

openDiff 工具

插件必须在其 MCP 服务器上注册 openDiff 工具。

  • 描述: 此工具指示 IDE 为特定文件打开可修改的差异视图。

  • 请求(OpenDiffRequest): 工具通过 tools/call 请求调用。请求 params 中的 arguments 字段必须OpenDiffRequest 对象。

    typescript
    interface OpenDiffRequest {
      // 要进行差异对比的文件的绝对路径。
      filePath: string;
      // 文件的建议新内容。
      newContent: string;
    }
  • 响应(CallToolResult): 工具必须立即返回 CallToolResult 以确认请求并报告差异视图是否成功打开。

    • 成功时:如果差异视图成功打开,响应必须包含空内容(即 content: [])。
    • 失败时:如果错误阻止差异视图打开,响应必须具有 isError: true 并在 content 数组中包含描述错误的 TextContent 块。

    差异的实际结果(接受或拒绝)通过通知异步传达。

closeDiff 工具

插件必须在其 MCP 服务器上注册 closeDiff 工具。

  • 描述: 此工具指示 IDE 关闭特定文件的打开差异视图。

  • 请求(CloseDiffRequest): 工具通过 tools/call 请求调用。请求 params 中的 arguments 字段必须CloseDiffRequest 对象。

    typescript
    interface CloseDiffRequest {
      // 应关闭其差异视图的文件的绝对路径。
      filePath: string;
    }
  • 响应(CallToolResult): 工具必须返回 CallToolResult

    • 成功时:如果差异视图成功关闭,响应必须在内容数组中包含单个 TextContent 块,其中包含关闭前文件的最终内容。
    • 失败时:如果错误阻止差异视图关闭,响应必须具有 isError: true 并在 content 数组中包含描述错误的 TextContent 块。

ide/diffAccepted 通知

当用户接受差异视图中的更改(例如,通过点击"应用"或"保存"按钮)时,插件必须向 CLI 发送 ide/diffAccepted 通知。

  • 负载: 通知参数必须包含文件路径和文件的最终内容。如果用户在差异视图中进行了手动编辑,内容可能与原始 newContent 不同。

    typescript
    {
      // 进行差异对比的文件的绝对路径。
      filePath: string;
      // 接受后文件的完整内容。
      content: string;
    }

ide/diffRejected 通知

当用户拒绝更改(例如,通过关闭差异视图而不接受)时,插件必须向 CLI 发送 ide/diffRejected 通知。

  • 负载: 通知参数必须包含被拒绝差异的文件路径。

    typescript
    {
      // 进行差异对比的文件的绝对路径。
      filePath: string;
    }

IV. 生命周期接口

插件必须根据 IDE 的生命周期正确管理其资源和发现文件。

  • 激活时(IDE 启动/插件启用):
    1. 启动 MCP 服务器。
    2. 创建发现文件。
  • 停用时(IDE 关闭/插件禁用):
    1. 停止 MCP 服务器。
    2. 删除发现文件。

aicodex 文档网站