Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/contribution.ts
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as vscode from 'vscode';6import { ILogger, ILogService } from '../../../../platform/log/common/logService';7import { Disposable } from '../../../../util/vs/base/common/lifecycle';8import { ServiceCollection } from '../../../../util/vs/platform/instantiation/common/serviceCollection';9import { registerAddFileReferenceCommand, registerAddSelectionCommand, registerDiffCommands } from './commands';10import { registerCommandContext } from './commands/context';11import { CopilotCLISessionTracker, ICopilotCLISessionTracker } from './copilotCLISessionTracker';12import { DiffStateManager } from './diffState';13import { InProcHttpServer } from './inProcHttpServer';14import { cleanupStaleLockFiles, createLockFile } from './lockFile';15import { ReadonlyContentProvider } from './readonlyContentProvider';16import { registerTools, SelectionState } from './tools';17import { registerDiagnosticsChangedNotification, registerSelectionChangedNotification } from './tools/push';1819export function getServices(): ConstructorParameters<typeof ServiceCollection> {20return [21[ICopilotCLISessionTracker, new CopilotCLISessionTracker()]22];23}24export class CopilotCLIContrib extends Disposable {2526constructor(27@ICopilotCLISessionTracker private readonly sessionTracker: ICopilotCLISessionTracker,28@ILogService private readonly logService: ILogService,29) {30super();3132const logger = this.logService.createSubLogger('CopilotCLI');3334// Create shared instances35const diffState = new DiffStateManager(logger);36const httpServer = this._register(new InProcHttpServer(logger, this.sessionTracker));37const selectionState = new SelectionState();38const contentProvider = new ReadonlyContentProvider();3940this._register(registerCommandContext(httpServer));4142// Register commands43this._register(registerAddFileReferenceCommand(logger, httpServer, this.sessionTracker));44this._register(registerAddSelectionCommand(logger, httpServer, this.sessionTracker));45for (const d of registerDiffCommands(logger, diffState)) {46this._register(d);47}48for (const d of diffState.setupContextTracking()) {49this._register(d);50}51this._register(contentProvider.register());52this._register(httpServer.onDidClientDisconnect(sessionId => {53diffState.closeAllForSession(sessionId);54}));5556// Clean up any stale lockfiles from previous sessions57cleanupStaleLockFiles(logger).then(cleanedCount => {58if (cleanedCount > 0) {59logger.info(`Cleaned up ${cleanedCount} stale lock file(s).`);60}61}).catch(err => {62logger.error(err, 'Failed to clean up stale lock files');63});6465// Start the MCP server66this._startMcpServer(logger, httpServer, diffState, selectionState, contentProvider);67}68private async _startMcpServer(logger: ILogger, httpServer: InProcHttpServer, diffState: DiffStateManager, selectionState: SelectionState, contentProvider: ReadonlyContentProvider): Promise<void> {69try {70const { serverUri, headers } = await httpServer.start({71id: 'vscode-copilot-cli',72serverLabel: 'VS Code Copilot CLI',73serverVersion: '0.0.1',74registerTools: (server, sessionId) => {75registerTools(server, logger, diffState, selectionState, contentProvider, this.sessionTracker, sessionId);76},77registerPushNotifications: () => {78for (const d of registerSelectionChangedNotification(logger, httpServer, selectionState)) {79this._register(d);80}81for (const d of registerDiagnosticsChangedNotification(logger, httpServer)) {82this._register(d);83}84},85});8687const lockFile = await createLockFile(serverUri, headers, logger);88logger.info(`MCP server started. Lock file: ${lockFile.path}`);89logger.info(`Server URI: ${serverUri.toString()}`);9091// Update lock file when workspace folders change92this._register(vscode.workspace.onDidChangeWorkspaceFolders(() => {93void lockFile.update();94logger.info('Workspace folders changed, lock file updated.');95}));9697// Update lock file when workspace trust is granted98this._register(vscode.workspace.onDidGrantWorkspaceTrust(() => {99void lockFile.update();100}));101102this._register({ dispose: () => { void lockFile.remove(); } });103} catch (err) {104const errMsg = err instanceof Error ? err.message : String(err);105logger.error(`Failed to start MCP server: ${errMsg}`);106}107}108}109110111