diff --git a/docs/ide-companion-spec.md b/docs/ide-companion-spec.md index 75ec327e34..dcc6dc4f8b 100644 --- a/docs/ide-companion-spec.md +++ b/docs/ide-companion-spec.md @@ -1,16 +1,16 @@ -# Gemini CLI Companion Extension: Interface Specification +# Gemini CLI Companion Plugin: Interface Specification > Last Updated: September 15, 2025 -This document defines the contract for building a companion extension to enable Gemini CLI's IDE mode. For VS Code, these features (native diffing, context awareness) are provided by the official extension ([marketplace](https://marketplace.visualstudio.com/items?itemName=Google.gemini-cli-vscode-ide-companion)). This specification is for contributors who wish to bring similar functionality to other editors like JetBrains IDEs, Sublime Text, etc. +This document defines the contract for building a companion plugin to enable Gemini CLI's IDE mode. For VS Code, these features (native diffing, context awareness) are provided by the official extension ([marketplace](https://marketplace.visualstudio.com/items?itemName=Google.gemini-cli-vscode-ide-companion)). This specification is for contributors who wish to bring similar functionality to other editors like JetBrains IDEs, Sublime Text, etc. ## I. The Communication Interface -Gemini CLI and the IDE extension communicate through a local communication channel. +Gemini CLI and the IDE plugin communicate through a local communication channel. ### 1. Transport Layer: MCP over HTTP -The extension **MUST** run a local HTTP server that implements the **Model Context Protocol (MCP)**. +The plugin **MUST** run a local HTTP server that implements the **Model Context Protocol (MCP)**. - **Protocol:** The server must be a valid MCP server. We recommend using an existing MCP SDK for your language of choice if available. - **Endpoint:** The server should expose a single endpoint (e.g., `/mcp`) for all MCP communication. @@ -18,13 +18,13 @@ The extension **MUST** run a local HTTP server that implements the **Model Conte ### 2. Discovery Mechanism: The Port File -For Gemini CLI to connect, it needs to discover which IDE instance it's running in and what port your server is using. The extension **MUST** facilitate this by creating a "discovery file." +For Gemini CLI to connect, it needs to discover which IDE instance it's running in and what port your server is using. The plugin **MUST** facilitate this by creating a "discovery file." - **How the CLI Finds the File:** The CLI determines the Process ID (PID) of the IDE it's running in by traversing the process tree. It then looks for a discovery file that contains this PID in its name. -- **File Location:** The file must be created in a specific directory: `os.tmpdir()/gemini/ide/`. Your extension must create this directory if it doesn't exist. +- **File Location:** The file must be created in a specific directory: `os.tmpdir()/gemini/ide/`. Your plugin must create this directory if it doesn't exist. - **File Naming Convention:** The filename is critical and **MUST** follow the pattern: `gemini-ide-server-${PID}-${PORT}.json` - - `${PID}`: The process ID of the parent IDE process. Your extension must determine this PID and include it in the filename. + - `${PID}`: The process ID of the parent IDE process. Your plugin must determine this PID and include it in the filename. - `${PORT}`: The port your MCP server is listening on. - **File Content & Workspace Validation:** The file **MUST** contain a JSON object with the following structure: @@ -40,22 +40,22 @@ For Gemini CLI to connect, it needs to discover which IDE instance it's running } ``` - `port` (number, required): The port of the MCP server. - - `workspacePath` (string, required): A list of all open workspace root paths, delimited by the OS-specific path separator (`:` for Linux/macOS, `;` for Windows). The CLI uses this path to ensure it's running in the same project folder that's open in the IDE. If the CLI's current working directory is not a sub-directory of `workspacePath`, the connection will be rejected. Your extension **MUST** provide the correct, absolute path(s) to the root of the open workspace(s). + - `workspacePath` (string, required): A list of all open workspace root paths, delimited by the OS-specific path separator (`:` for Linux/macOS, `;` for Windows). The CLI uses this path to ensure it's running in the same project folder that's open in the IDE. If the CLI's current working directory is not a sub-directory of `workspacePath`, the connection will be rejected. Your plugin **MUST** provide the correct, absolute path(s) to the root of the open workspace(s). - `authToken` (string, required): A secret token for securing the connection. The CLI will include this token in an `Authorization: Bearer ` header on all requests. - `ideInfo` (object, required): Information about the IDE. - `name` (string, required): A short, lowercase identifier for the IDE (e.g., `vscode`, `jetbrains`). - `displayName` (string, required): A user-friendly name for the IDE (e.g., `VS Code`, `JetBrains IDE`). -- **Authentication:** To secure the connection, the extension **MUST** generate a unique, secret token and include it in the discovery file. The CLI will then include this token in the `Authorization` header for all requests to the MCP server (e.g., `Authorization: Bearer a-very-secret-token`). Your server **MUST** validate this token on every request and reject any that are unauthorized. -- **Tie-Breaking with Environment Variables (Recommended):** For the most reliable experience, your extension **SHOULD** both create the discovery file and set the `GEMINI_CLI_IDE_SERVER_PORT` environment variable in the integrated terminal. The file serves as the primary discovery mechanism, but the environment variable is crucial for tie-breaking. If a user has multiple IDE windows open for the same workspace, the CLI uses the `GEMINI_CLI_IDE_SERVER_PORT` variable to identify and connect to the correct window's server. +- **Authentication:** To secure the connection, the plugin **MUST** generate a unique, secret token and include it in the discovery file. The CLI will then include this token in the `Authorization` header for all requests to the MCP server (e.g., `Authorization: Bearer a-very-secret-token`). Your server **MUST** validate this token on every request and reject any that are unauthorized. +- **Tie-Breaking with Environment Variables (Recommended):** For the most reliable experience, your plugin **SHOULD** both create the discovery file and set the `GEMINI_CLI_IDE_SERVER_PORT` environment variable in the integrated terminal. The file serves as the primary discovery mechanism, but the environment variable is crucial for tie-breaking. If a user has multiple IDE windows open for the same workspace, the CLI uses the `GEMINI_CLI_IDE_SERVER_PORT` variable to identify and connect to the correct window's server. ## II. The Context Interface -To enable context awareness, the extension **MAY** provide the CLI with real-time information about the user's activity in the IDE. +To enable context awareness, the plugin **MAY** provide the CLI with real-time information about the user's activity in the IDE. ### `ide/contextUpdate` Notification -The extension **MAY** send an `ide/contextUpdate` [notification](https://modelcontextprotocol.io/specification/2025-06-18/basic/index#notifications) to the CLI whenever the user's context changes. +The plugin **MAY** send an `ide/contextUpdate` [notification](https://modelcontextprotocol.io/specification/2025-06-18/basic/index#notifications) to the CLI whenever the user's context changes. - **Triggering Events:** This notification should be sent (with a recommended debounce of 50ms) when: - A file is opened, closed, or focused. @@ -94,19 +94,19 @@ The extension **MAY** send an `ide/contextUpdate` [notification](https://modelco After receiving the `IdeContext` object, the CLI performs several normalization and truncation steps before sending the information to the model. -- **File Ordering:** The CLI uses the `timestamp` field to determine the most recently used files. It sorts the `openFiles` list based on this value. Therefore, your extension **MUST** provide an accurate Unix timestamp for when a file was last focused. -- **Active File:** The CLI considers only the most recent file (after sorting) to be the "active" file. It will ignore the `isActive` flag on all other files and clear their `cursor` and `selectedText` fields. Your extension should focus on setting `isActive: true` and providing cursor/selection details only for the currently focused file. +- **File Ordering:** The CLI uses the `timestamp` field to determine the most recently used files. It sorts the `openFiles` list based on this value. Therefore, your plugin **MUST** provide an accurate Unix timestamp for when a file was last focused. +- **Active File:** The CLI considers only the most recent file (after sorting) to be the "active" file. It will ignore the `isActive` flag on all other files and clear their `cursor` and `selectedText` fields. Your plugin should focus on setting `isActive: true` and providing cursor/selection details only for the currently focused file. - **Truncation:** To manage token limits, the CLI truncates both the file list (to 10 files) and the `selectedText` (to 16KB). -While the CLI handles the final truncation, it is highly recommended that your extension also limits the amount of context it sends. +While the CLI handles the final truncation, it is highly recommended that your plugin also limits the amount of context it sends. ## III. The Diffing Interface -To enable interactive code modifications, the extension **MAY** expose a diffing interface. This allows the CLI to request that the IDE open a diff view, showing proposed changes to a file. The user can then review, edit, and ultimately accept or reject these changes directly within the IDE. +To enable interactive code modifications, the plugin **MAY** expose a diffing interface. This allows the CLI to request that the IDE open a diff view, showing proposed changes to a file. The user can then review, edit, and ultimately accept or reject these changes directly within the IDE. ### `openDiff` Tool -The extension **MUST** register an `openDiff` tool on its MCP server. +The plugin **MUST** register an `openDiff` tool on its MCP server. - **Description:** This tool instructs the IDE to open a modifiable diff view for a specific file. - **Request (`OpenDiffRequest`):** The tool is invoked via a `tools/call` request. The `arguments` field within the request's `params` **MUST** be an `OpenDiffRequest` object. @@ -128,7 +128,7 @@ The extension **MUST** register an `openDiff` tool on its MCP server. ### `closeDiff` Tool -The extension **MUST** register a `closeDiff` tool on its MCP server. +The plugin **MUST** register a `closeDiff` tool on its MCP server. - **Description:** This tool instructs the IDE to close an open diff view for a specific file. - **Request (`CloseDiffRequest`):** The tool is invoked via a `tools/call` request. The `arguments` field within the request's `params` **MUST** be an `CloseDiffRequest` object. @@ -146,7 +146,7 @@ The extension **MUST** register a `closeDiff` tool on its MCP server. ### `ide/diffAccepted` Notification -When the user accepts the changes in a diff view (e.g., by clicking an "Apply" or "Save" button), the extension **MUST** send an `ide/diffAccepted` notification to the CLI. +When the user accepts the changes in a diff view (e.g., by clicking an "Apply" or "Save" button), the plugin **MUST** send an `ide/diffAccepted` notification to the CLI. - **Payload:** The notification parameters **MUST** include the file path and the final content of the file. The content may differ from the original `newContent` if the user made manual edits in the diff view. @@ -161,7 +161,7 @@ When the user accepts the changes in a diff view (e.g., by clicking an "Apply" o ### `ide/diffRejected` Notification -When the user rejects the changes (e.g., by closing the diff view without accepting), the extension **MUST** send an `ide/diffRejected` notification to the CLI. +When the user rejects the changes (e.g., by closing the diff view without accepting), the plugin **MUST** send an `ide/diffRejected` notification to the CLI. - **Payload:** The notification parameters **MUST** include the file path of the rejected diff. @@ -174,11 +174,11 @@ When the user rejects the changes (e.g., by closing the diff view without accept ## IV. The Lifecycle Interface -The extension **MUST** manage its resources and the discovery file correctly based on the IDE's lifecycle. +The plugin **MUST** manage its resources and the discovery file correctly based on the IDE's lifecycle. -- **On Activation (IDE startup/extension enabled):** +- **On Activation (IDE startup/plugin enabled):** 1. Start the MCP server. 2. Create the discovery file. -- **On Deactivation (IDE shutdown/extension disabled):** +- **On Deactivation (IDE shutdown/plugin disabled):** 1. Stop the MCP server. 2. Delete the discovery file.