Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/contribution.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { ILogger, ILogService } from '../../../../platform/log/common/logService';
8
import { Disposable } from '../../../../util/vs/base/common/lifecycle';
9
import { ServiceCollection } from '../../../../util/vs/platform/instantiation/common/serviceCollection';
10
import { registerAddFileReferenceCommand, registerAddSelectionCommand, registerDiffCommands } from './commands';
11
import { registerCommandContext } from './commands/context';
12
import { CopilotCLISessionTracker, ICopilotCLISessionTracker } from './copilotCLISessionTracker';
13
import { DiffStateManager } from './diffState';
14
import { InProcHttpServer } from './inProcHttpServer';
15
import { cleanupStaleLockFiles, createLockFile } from './lockFile';
16
import { ReadonlyContentProvider } from './readonlyContentProvider';
17
import { registerTools, SelectionState } from './tools';
18
import { registerDiagnosticsChangedNotification, registerSelectionChangedNotification } from './tools/push';
19
20
export function getServices(): ConstructorParameters<typeof ServiceCollection> {
21
return [
22
[ICopilotCLISessionTracker, new CopilotCLISessionTracker()]
23
];
24
}
25
export class CopilotCLIContrib extends Disposable {
26
27
constructor(
28
@ICopilotCLISessionTracker private readonly sessionTracker: ICopilotCLISessionTracker,
29
@ILogService private readonly logService: ILogService,
30
) {
31
super();
32
33
const logger = this.logService.createSubLogger('CopilotCLI');
34
35
// Create shared instances
36
const diffState = new DiffStateManager(logger);
37
const httpServer = this._register(new InProcHttpServer(logger, this.sessionTracker));
38
const selectionState = new SelectionState();
39
const contentProvider = new ReadonlyContentProvider();
40
41
this._register(registerCommandContext(httpServer));
42
43
// Register commands
44
this._register(registerAddFileReferenceCommand(logger, httpServer, this.sessionTracker));
45
this._register(registerAddSelectionCommand(logger, httpServer, this.sessionTracker));
46
for (const d of registerDiffCommands(logger, diffState)) {
47
this._register(d);
48
}
49
for (const d of diffState.setupContextTracking()) {
50
this._register(d);
51
}
52
this._register(contentProvider.register());
53
this._register(httpServer.onDidClientDisconnect(sessionId => {
54
diffState.closeAllForSession(sessionId);
55
}));
56
57
// Clean up any stale lockfiles from previous sessions
58
cleanupStaleLockFiles(logger).then(cleanedCount => {
59
if (cleanedCount > 0) {
60
logger.info(`Cleaned up ${cleanedCount} stale lock file(s).`);
61
}
62
}).catch(err => {
63
logger.error(err, 'Failed to clean up stale lock files');
64
});
65
66
// Start the MCP server
67
this._startMcpServer(logger, httpServer, diffState, selectionState, contentProvider);
68
}
69
private async _startMcpServer(logger: ILogger, httpServer: InProcHttpServer, diffState: DiffStateManager, selectionState: SelectionState, contentProvider: ReadonlyContentProvider): Promise<void> {
70
try {
71
const { serverUri, headers } = await httpServer.start({
72
id: 'vscode-copilot-cli',
73
serverLabel: 'VS Code Copilot CLI',
74
serverVersion: '0.0.1',
75
registerTools: (server, sessionId) => {
76
registerTools(server, logger, diffState, selectionState, contentProvider, this.sessionTracker, sessionId);
77
},
78
registerPushNotifications: () => {
79
for (const d of registerSelectionChangedNotification(logger, httpServer, selectionState)) {
80
this._register(d);
81
}
82
for (const d of registerDiagnosticsChangedNotification(logger, httpServer)) {
83
this._register(d);
84
}
85
},
86
});
87
88
const lockFile = await createLockFile(serverUri, headers, logger);
89
logger.info(`MCP server started. Lock file: ${lockFile.path}`);
90
logger.info(`Server URI: ${serverUri.toString()}`);
91
92
// Update lock file when workspace folders change
93
this._register(vscode.workspace.onDidChangeWorkspaceFolders(() => {
94
void lockFile.update();
95
logger.info('Workspace folders changed, lock file updated.');
96
}));
97
98
// Update lock file when workspace trust is granted
99
this._register(vscode.workspace.onDidGrantWorkspaceTrust(() => {
100
void lockFile.update();
101
}));
102
103
this._register({ dispose: () => { void lockFile.remove(); } });
104
} catch (err) {
105
const errMsg = err instanceof Error ? err.message : String(err);
106
logger.error(`Failed to start MCP server: ${errMsg}`);
107
}
108
}
109
}
110
111