diff --git a/packages/vscode-ide-companion/src/extension.ts b/packages/vscode-ide-companion/src/extension.ts index 912b9b8f..74bcaf89 100644 --- a/packages/vscode-ide-companion/src/extension.ts +++ b/packages/vscode-ide-companion/src/extension.ts @@ -15,7 +15,6 @@ let log: (message: string) => void = () => {}; export async function activate(context: vscode.ExtensionContext) { logger = vscode.window.createOutputChannel('Gemini CLI IDE Companion'); log = createLogger(context, logger); - log('Extension activated'); ideServer = new IDEServer(log); try { diff --git a/packages/vscode-ide-companion/src/ide-server.ts b/packages/vscode-ide-companion/src/ide-server.ts index 75828485..aad86a08 100644 --- a/packages/vscode-ide-companion/src/ide-server.ts +++ b/packages/vscode-ide-companion/src/ide-server.ts @@ -18,6 +18,7 @@ import { RecentFilesManager } from './recent-files-manager.js'; const MCP_SESSION_ID_HEADER = 'mcp-session-id'; const IDE_SERVER_PORT_ENV_VAR = 'GEMINI_CLI_IDE_SERVER_PORT'; +const MAX_SELECTED_TEXT_LENGTH = 16384; // 16 KiB limit function sendOpenFilesChangedNotification( transport: StreamableHTTPServerTransport, @@ -29,6 +30,19 @@ function sendOpenFilesChangedNotification( editor && editor.document.uri.scheme === 'file' ? editor.document.uri.fsPath : ''; + const selection = editor?.selection; + const cursor = selection + ? { + // This value is a zero-based index, but the vscode IDE is one-based. + line: selection.active.line + 1, + character: selection.active.character, + } + : undefined; + let selectedText = editor?.document.getText(selection) ?? undefined; + if (selectedText && selectedText.length > MAX_SELECTED_TEXT_LENGTH) { + selectedText = + selectedText.substring(0, MAX_SELECTED_TEXT_LENGTH) + '... [TRUNCATED]'; + } const notification: JSONRPCNotification = { jsonrpc: '2.0', method: 'ide/openFilesChanged', @@ -37,6 +51,8 @@ function sendOpenFilesChangedNotification( recentOpenFiles: recentFilesManager.recentFiles.filter( (file) => file.filePath !== filePath, ), + cursor, + selectedText, }, }; log( @@ -69,7 +85,7 @@ export class IDEServer { const mcpServer = createMcpServer(); const recentFilesManager = new RecentFilesManager(context); - const disposable = recentFilesManager.onDidChange(() => { + const onDidChangeSubscription = recentFilesManager.onDidChange(() => { for (const transport of Object.values(transports)) { sendOpenFilesChangedNotification( transport, @@ -78,7 +94,7 @@ export class IDEServer { ); } }); - context.subscriptions.push(disposable); + context.subscriptions.push(onDidChangeSubscription); app.post('/mcp', async (req: Request, res: Response) => { const sessionId = req.headers[MCP_SESSION_ID_HEADER] as diff --git a/packages/vscode-ide-companion/src/recent-files-manager.test.ts b/packages/vscode-ide-companion/src/recent-files-manager.test.ts index 97f19f30..9d56a10d 100644 --- a/packages/vscode-ide-companion/src/recent-files-manager.test.ts +++ b/packages/vscode-ide-companion/src/recent-files-manager.test.ts @@ -28,6 +28,7 @@ vi.mock('vscode', () => ({ }), window: { onDidChangeActiveTextEditor: vi.fn(), + onDidChangeTextEditorSelection: vi.fn(), }, workspace: { onDidDeleteFiles: vi.fn(), diff --git a/packages/vscode-ide-companion/src/recent-files-manager.ts b/packages/vscode-ide-companion/src/recent-files-manager.ts index cbe7e9a9..317cc903 100644 --- a/packages/vscode-ide-companion/src/recent-files-manager.ts +++ b/packages/vscode-ide-companion/src/recent-files-manager.ts @@ -47,11 +47,19 @@ export class RecentFilesManager { this.add(newUri); } }); + + const selectionWatcher = vscode.window.onDidChangeTextEditorSelection( + () => { + this.fireWithDebounce(); + }, + ); + context.subscriptions.push( editorWatcher, deleteWatcher, closeWatcher, renameWatcher, + selectionWatcher, ); }