Path: blob/main/extensions/copilot/src/extension/chatSessions/vscode-node/chatSessions.ts
13399 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 l10n from '@vscode/l10n';6import * as vscode from 'vscode';7import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';8import { IEnvService, INativeEnvService } from '../../../platform/env/common/envService';9import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';10import { IGitExtensionService } from '../../../platform/git/common/gitExtensionService';11import { IGitService } from '../../../platform/git/common/gitService';12import { IOctoKitService } from '../../../platform/github/common/githubService';13import { OctoKitService } from '../../../platform/github/common/octoKitServiceImpl';14import { ILogService } from '../../../platform/log/common/logService';15import { Disposable, DisposableStore } from '../../../util/vs/base/common/lifecycle';16import { SyncDescriptor } from '../../../util/vs/platform/instantiation/common/descriptors';17import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';18import { ServiceCollection } from '../../../util/vs/platform/instantiation/common/serviceCollection';19import { ILanguageModelServer, LanguageModelServer } from '../../agents/node/langModelServer';20import { IExtensionContribution } from '../../common/contributions';21import { prExtensionInstalledContextKey } from '../../contextKeys/vscode-node/contextKeys.contribution';22import { GitBranchNameGenerator } from '../../prompt/node/gitBranch';23import { ChatSummarizerProvider } from '../../prompt/node/summarizer';24import { IToolsService } from '../../tools/common/toolsService';25import { IClaudeRuntimeDataService } from '../claude/common/claudeRuntimeDataService';26import { ClaudeSessionUri } from '../claude/common/claudeSessionUri';27import { ClaudeToolPermissionService, IClaudeToolPermissionService } from '../claude/common/claudeToolPermissionService';28import { ClaudeCodeFolderMruService } from '../claude/node/claudeCodeFolderMru';29import { ClaudeAgentManager } from '../claude/node/claudeCodeAgent';30import { ClaudeCodeModels, IClaudeCodeModels } from '../claude/node/claudeCodeModels';31import { ClaudeCodeSdkService, IClaudeCodeSdkService } from '../claude/node/claudeCodeSdkService';32import { ClaudeRuntimeDataService } from '../claude/node/claudeRuntimeDataService';33import { ClaudePluginService, IClaudePluginService } from '../claude/node/claudeSkills';34import { IClaudeSessionStateService } from '../claude/common/claudeSessionStateService';35import { ClaudeSessionStateService } from '../claude/node/claudeSessionStateService';36import { ClaudeCodeSessionService, IClaudeCodeSessionService } from '../claude/node/sessionParser/claudeCodeSessionService';37import { ClaudeSlashCommandService, IClaudeSlashCommandService } from '../claude/vscode-node/claudeSlashCommandService';38import { IAgentSessionsWorkspace } from '../common/agentSessionsWorkspace';39import { IChatSessionMetadataStore } from '../common/chatSessionMetadataStore';40import { IChatSessionWorkspaceFolderService } from '../common/chatSessionWorkspaceFolderService';41import { IClaudeWorkspaceFolderService } from '../common/claudeWorkspaceFolderService';42import { IChatSessionWorktreeCheckpointService } from '../common/chatSessionWorktreeCheckpointService';43import { IChatSessionWorktreeService } from '../common/chatSessionWorktreeService';44import { IChatFolderMruService, IFolderRepositoryManager } from '../common/folderRepositoryManager';45import { ICustomSessionTitleService } from '../copilotcli/common/customSessionTitleService';46import { ChatDelegationSummaryService, IChatDelegationSummaryService } from '../copilotcli/common/delegationSummaryService';47import { SessionIdForCLI } from '../copilotcli/common/utils';48import { CopilotCLIAgents, CopilotCLIModels, CopilotCLISDK, ICopilotCLIAgents, ICopilotCLIModels, ICopilotCLISDK } from '../copilotcli/node/copilotCli';49import { CopilotCLIImageSupport, ICopilotCLIImageSupport } from '../copilotcli/node/copilotCLIImageSupport';50import { CopilotCLIPromptResolver } from '../copilotcli/node/copilotcliPromptResolver';51import { CopilotCLISessionService, ICopilotCLISessionService } from '../copilotcli/node/copilotcliSessionService';52import { CopilotCLISkills, ICopilotCLISkills } from '../copilotcli/node/copilotCLISkills';53import { CopilotCLIMCPHandler, ICopilotCLIMCPHandler } from '../copilotcli/node/mcpHandler';54import { IUserQuestionHandler } from '../copilotcli/node/userInputHelpers';55import { CopilotCLIContrib, getServices } from '../copilotcli/vscode-node/contribution';56import { CopilotCLIFolderMruService } from '../copilotcli/vscode-node/copilotCLIFolderMru';57import { ICopilotCLISessionTracker } from '../copilotcli/vscode-node/copilotCLISessionTracker';58import { CustomSessionTitleService } from '../copilotcli/vscode-node/customSessionTitleServiceImpl';59import { GHPR_EXTENSION_ID } from '../vscode/chatSessionsUriHandler';60import { AgentSessionsWorkspace } from './agentSessionsWorkspace';61import { UserQuestionHandler } from '../copilotcli/vscode-node/askUserQuestionHandler';62import { ChatSessionMetadataStore } from '../copilotcli/vscode-node/chatSessionMetadataStoreImpl';63import { ChatSessionRepositoryTracker } from './chatSessionRepositoryTracker';64import { ChatSessionWorkspaceFolderService } from './chatSessionWorkspaceFolderServiceImpl';65import { ClaudeWorkspaceFolderService } from './claudeWorkspaceFolderServiceImpl';66import { ChatSessionWorktreeCheckpointService } from './chatSessionWorktreeCheckpointServiceImpl';67import { ChatSessionWorktreeService } from './chatSessionWorktreeServiceImpl';68import { ClaudeChatSessionContentProvider } from './claudeChatSessionContentProvider';69import { ClaudeCustomizationProvider } from './claudeCustomizationProvider';70import { CopilotCLIChatSessionInitializer, ICopilotCLIChatSessionInitializer } from '../copilotcli/vscode-node/copilotCLIChatSessionInitializer';71import { CopilotCLIChatSessionContentProvider, CopilotCLIChatSessionParticipant, registerCLIChatCommands } from './copilotCLIChatSessions';72import { CopilotCLIChatSessionContentProvider as CopilotCLIChatSessionContentProviderV1, CopilotCLIChatSessionItemProvider as CopilotCLIChatSessionItemProviderV1, CopilotCLIChatSessionParticipant as CopilotCLIChatSessionParticipantV1, registerCLIChatCommands as registerCLIChatCommandsV1 } from './copilotCLIChatSessionsContribution';73import { CopilotCLICustomizationProvider } from '../copilotcli/vscode-node/copilotCLICustomizationProvider';74import { CopilotCLITerminalIntegration, ICopilotCLITerminalIntegration } from './copilotCLITerminalIntegration';75import { CopilotCloudSessionsProvider } from './copilotCloudSessionsProvider';76import { ClaudeFolderRepositoryManager, CopilotCLIFolderRepositoryManager } from './folderRepositoryManagerImpl';77import { PRContentProvider } from './prContentProvider';78import { IPullRequestDetectionService, PullRequestDetectionService } from './pullRequestDetectionService';79import { IPullRequestFileChangesService, PullRequestFileChangesService } from './pullRequestFileChangesService';80import { ISessionOptionGroupBuilder, SessionOptionGroupBuilder } from './sessionOptionGroupBuilder';81import { ISessionRequestLifecycle, SessionRequestLifecycle } from './sessionRequestLifecycle';828384// https://github.com/microsoft/vscode-pull-request-github/blob/8a5c9a145cd80ee364a3bed9cf616b2bd8ac74c2/src/github/copilotApi.ts#L56-L7185export interface CrossChatSessionWithPR {86pullRequestDetails: {87number: number;88repository: {89owner: {90login: string;91};92name: string;93};94};95}9697const CLOSE_SESSION_PR_CMD = 'github.copilot.cloud.sessions.proxy.closeChatSessionPullRequest';98export class ChatSessionsContrib extends Disposable implements IExtensionContribution {99readonly id = 'chatSessions';100readonly copilotcliSessionType = 'copilotcli';101102private copilotCloudRegistrations: DisposableStore | undefined;103private copilotAgentInstaService: IInstantiationService | undefined;104105constructor(106@IInstantiationService instantiationService: IInstantiationService,107@ILogService private readonly logService: ILogService,108@IOctoKitService private readonly octoKitService: IOctoKitService,109@IEnvService private readonly envService: IEnvService,110) {111super();112// Copilot Cloud Agent - conditionally register based on configuration113const summarizer = instantiationService.createInstance(ChatSummarizerProvider);114const delegationSummary = instantiationService.createInstance(ChatDelegationSummaryService, summarizer);115this._register(vscode.workspace.registerTextDocumentContentProvider(delegationSummary.scheme, {116provideTextDocumentContent: (uri: vscode.Uri): string | undefined => delegationSummary.provideTextDocumentContent(uri)117}));118this.copilotAgentInstaService = instantiationService.createChild(new ServiceCollection(119[IOctoKitService, new SyncDescriptor(OctoKitService)],120[IChatDelegationSummaryService, delegationSummary],121[IPullRequestFileChangesService, new SyncDescriptor(PullRequestFileChangesService)],122));123124const configKey = vscode.workspace.isAgentSessionsWorkspace125? ConfigKey.Advanced.CLISessionControllerForSessionsApp126: ConfigKey.Advanced.CLISessionController;127const useController = instantiationService.invokeFunction(accessor =>128accessor.get(IConfigurationService).getConfig(configKey)129);130const { sessionMetadata } = useController ? this.registerCopilotCLIServices(instantiationService, delegationSummary, logService) : this.registerCopilotCLIServicesV1(instantiationService, delegationSummary, logService);131132// #region Claude Code Chat Sessions133const claudeAgentInstaService = instantiationService.createChild(134new ServiceCollection(135[IAgentSessionsWorkspace, new SyncDescriptor(AgentSessionsWorkspace)],136[IClaudeCodeSessionService, new SyncDescriptor(ClaudeCodeSessionService)],137[IClaudeCodeSdkService, new SyncDescriptor(ClaudeCodeSdkService)],138[IClaudeCodeModels, new SyncDescriptor(ClaudeCodeModels)],139[ILanguageModelServer, new SyncDescriptor(LanguageModelServer)],140[IClaudeToolPermissionService, new SyncDescriptor(ClaudeToolPermissionService)],141[IClaudeSessionStateService, new SyncDescriptor(ClaudeSessionStateService)],142[IClaudeSlashCommandService, new SyncDescriptor(ClaudeSlashCommandService)],143[IChatSessionMetadataStore, sessionMetadata],144[IChatSessionWorktreeService, new SyncDescriptor(ChatSessionWorktreeService)],145[IChatSessionWorktreeCheckpointService, new SyncDescriptor(ChatSessionWorktreeCheckpointService)],146[IChatSessionWorkspaceFolderService, new SyncDescriptor(ChatSessionWorkspaceFolderService)],147[IClaudeWorkspaceFolderService, new SyncDescriptor(ClaudeWorkspaceFolderService)],148[IFolderRepositoryManager, new SyncDescriptor(ClaudeFolderRepositoryManager)],149[IChatFolderMruService, new SyncDescriptor(ClaudeCodeFolderMruService)],150[IClaudeRuntimeDataService, new SyncDescriptor(ClaudeRuntimeDataService)],151[IClaudePluginService, new SyncDescriptor(ClaudePluginService)],152));153const claudeAgentManager = this._register(claudeAgentInstaService.createInstance(ClaudeAgentManager));154const claudeModels = claudeAgentInstaService.invokeFunction(accessor => accessor.get(IClaudeCodeModels));155claudeModels.registerLanguageModelChatProvider(vscode.lm);156const chatSessionContentProvider = this._register(claudeAgentInstaService.createInstance(ClaudeChatSessionContentProvider, claudeAgentManager));157const chatParticipant = vscode.chat.createChatParticipant(ClaudeSessionUri.scheme, chatSessionContentProvider.createHandler());158chatParticipant.iconPath = new vscode.ThemeIcon('claude');159this._register(vscode.chat.registerChatSessionContentProvider(ClaudeSessionUri.scheme, chatSessionContentProvider, chatParticipant));160const claudeCustomizationProvider = this._register(claudeAgentInstaService.createInstance(ClaudeCustomizationProvider));161this._register(vscode.chat.registerChatSessionCustomizationProvider(ClaudeSessionUri.scheme, ClaudeCustomizationProvider.metadata, claudeCustomizationProvider));162163// #endregion164165// #endregion166167}168169private registerCopilotCLIServices(instantiationService: IInstantiationService, delegationSummary: IChatDelegationSummaryService, logService: ILogService) {170const cloudSessionProvider = this.registerCopilotCloudAgent();171const copilotcliAgentInstaService = instantiationService.createChild(172new ServiceCollection(173[IAgentSessionsWorkspace, new SyncDescriptor(AgentSessionsWorkspace)],174[ICopilotCLIImageSupport, new SyncDescriptor(CopilotCLIImageSupport)],175[ICopilotCLISessionService, new SyncDescriptor(CopilotCLISessionService)],176[IChatDelegationSummaryService, delegationSummary],177[ICopilotCLIModels, new SyncDescriptor(CopilotCLIModels)],178[ICopilotCLISDK, new SyncDescriptor(CopilotCLISDK)],179[ICopilotCLIAgents, new SyncDescriptor(CopilotCLIAgents)],180[ILanguageModelServer, new SyncDescriptor(LanguageModelServer)],181[ICopilotCLITerminalIntegration, new SyncDescriptor(CopilotCLITerminalIntegration)],182[IChatSessionWorktreeService, new SyncDescriptor(ChatSessionWorktreeService)],183[IChatSessionWorktreeCheckpointService, new SyncDescriptor(ChatSessionWorktreeCheckpointService)],184[IChatSessionWorkspaceFolderService, new SyncDescriptor(ChatSessionWorkspaceFolderService)],185[ICopilotCLIMCPHandler, new SyncDescriptor(CopilotCLIMCPHandler)],186[IFolderRepositoryManager, new SyncDescriptor(CopilotCLIFolderRepositoryManager)],187[IUserQuestionHandler, new SyncDescriptor(UserQuestionHandler)],188[ICustomSessionTitleService, new SyncDescriptor(CustomSessionTitleService)],189[ICopilotCLISkills, new SyncDescriptor(CopilotCLISkills)],190[IChatSessionMetadataStore, new SyncDescriptor(ChatSessionMetadataStore)],191[IChatFolderMruService, new SyncDescriptor(CopilotCLIFolderMruService)],192[IPullRequestDetectionService, new SyncDescriptor(PullRequestDetectionService)],193[ISessionOptionGroupBuilder, new SyncDescriptor(SessionOptionGroupBuilder)],194[ISessionRequestLifecycle, new SyncDescriptor(SessionRequestLifecycle)],195[ICopilotCLIChatSessionInitializer, new SyncDescriptor(CopilotCLIChatSessionInitializer)],196...getServices()197));198199const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProvider);200this._register(copilotcliAgentInstaService.createInstance(ChatSessionRepositoryTracker, undefined));201const promptResolver = copilotcliAgentInstaService.createInstance(CopilotCLIPromptResolver);202const gitService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitService));203const sessionTracker = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionTracker));204const terminalIntegration = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLITerminalIntegration));205const aiGeneratedBranchNames = instantiationService.invokeFunction(accessor =>206accessor.get(IConfigurationService).getConfig(ConfigKey.Advanced.CLIAIGenerateBranchNames)207);208const branchNameGenerator = aiGeneratedBranchNames ? copilotcliAgentInstaService.createInstance(GitBranchNameGenerator) : undefined;209210const copilotcliChatSessionParticipant = this._register(copilotcliAgentInstaService.createInstance(211CopilotCLIChatSessionParticipant,212copilotcliChatSessionContentProvider,213promptResolver,214cloudSessionProvider,215branchNameGenerator,216));217const copilotCLISessionService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionService));218const copilotCLIWorktreeManagerService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionWorktreeService));219const copilotCLIWorkspaceFolderSessions = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionWorkspaceFolderService));220const folderRepositoryManager = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IFolderRepositoryManager));221const nativeEnvService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(INativeEnvService));222const fileSystemService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IFileSystemService));223const copilotModels = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLIModels));224const copilotCLIFolderMruService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatFolderMruService));225226this._register(copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionTracker)));227this._register(copilotcliAgentInstaService.createInstance(CopilotCLIContrib));228229copilotModels.registerLanguageModelChatProvider(vscode.lm);230231const copilotcliParticipant = vscode.chat.createChatParticipant(this.copilotcliSessionType, copilotcliChatSessionParticipant.createHandler());232this._register(vscode.chat.registerChatSessionContentProvider(this.copilotcliSessionType, copilotcliChatSessionContentProvider, copilotcliParticipant));233const copilotcliCustomizationProvider = this._register(copilotcliAgentInstaService.createInstance(CopilotCLICustomizationProvider));234this._register(vscode.chat.registerChatSessionCustomizationProvider(this.copilotcliSessionType, CopilotCLICustomizationProvider.metadata, copilotcliCustomizationProvider));235this._register(registerCLIChatCommands(copilotCLISessionService, copilotCLIWorktreeManagerService, gitService, copilotCLIWorkspaceFolderSessions, copilotcliChatSessionContentProvider, folderRepositoryManager, copilotCLIFolderMruService, nativeEnvService, fileSystemService, sessionTracker, terminalIntegration, logService));236// #endregion237238const sessionMetadata = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionMetadataStore));239return { sessionMetadata };240}241242private registerCopilotCLIServicesV1(instantiationService: IInstantiationService, delegationSummary: IChatDelegationSummaryService, logService: ILogService) {243const cloudSessionProvider = this.registerCopilotCloudAgent();244const copilotcliAgentInstaService = instantiationService.createChild(245new ServiceCollection(246[IAgentSessionsWorkspace, new SyncDescriptor(AgentSessionsWorkspace)],247[ICopilotCLIImageSupport, new SyncDescriptor(CopilotCLIImageSupport)],248[ICopilotCLISessionService, new SyncDescriptor(CopilotCLISessionService)],249[IChatDelegationSummaryService, delegationSummary],250[ICopilotCLIModels, new SyncDescriptor(CopilotCLIModels)],251[ICopilotCLISDK, new SyncDescriptor(CopilotCLISDK)],252[ICopilotCLIAgents, new SyncDescriptor(CopilotCLIAgents)],253[ILanguageModelServer, new SyncDescriptor(LanguageModelServer)],254[ICopilotCLITerminalIntegration, new SyncDescriptor(CopilotCLITerminalIntegration)],255[IChatSessionWorktreeService, new SyncDescriptor(ChatSessionWorktreeService)],256[IChatSessionWorktreeCheckpointService, new SyncDescriptor(ChatSessionWorktreeCheckpointService)],257[IChatSessionWorkspaceFolderService, new SyncDescriptor(ChatSessionWorkspaceFolderService)],258[ICopilotCLIMCPHandler, new SyncDescriptor(CopilotCLIMCPHandler)],259[IFolderRepositoryManager, new SyncDescriptor(CopilotCLIFolderRepositoryManager)],260[IUserQuestionHandler, new SyncDescriptor(UserQuestionHandler)],261[ICustomSessionTitleService, new SyncDescriptor(CustomSessionTitleService)],262[ICopilotCLISkills, new SyncDescriptor(CopilotCLISkills)],263[IChatSessionMetadataStore, new SyncDescriptor(ChatSessionMetadataStore)],264[IChatFolderMruService, new SyncDescriptor(CopilotCLIFolderMruService)],265...getServices()266));267268const copilotcliSessionItemProvider = this._register(copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionItemProviderV1));269const providerRegistration = vscode.chat.registerChatSessionItemProvider(this.copilotcliSessionType, copilotcliSessionItemProvider);270this._register(providerRegistration);271this._register(copilotcliAgentInstaService.createInstance(ChatSessionRepositoryTracker, copilotcliSessionItemProvider));272const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProviderV1, copilotcliSessionItemProvider);273const promptResolver = copilotcliAgentInstaService.createInstance(CopilotCLIPromptResolver);274const gitService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitService));275const gitExtensionService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitExtensionService));276const toolsService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IToolsService));277const aiGeneratedBranchNamesV1 = instantiationService.invokeFunction(accessor =>278accessor.get(IConfigurationService).getConfig(ConfigKey.Advanced.CLIAIGenerateBranchNames)279);280const branchNameGeneratorV1 = aiGeneratedBranchNamesV1 ? copilotcliAgentInstaService.createInstance(GitBranchNameGenerator) : undefined;281282const copilotcliChatSessionParticipant = this._register(copilotcliAgentInstaService.createInstance(283CopilotCLIChatSessionParticipantV1,284copilotcliChatSessionContentProvider,285promptResolver,286copilotcliSessionItemProvider,287cloudSessionProvider,288branchNameGeneratorV1,289));290const copilotCLISessionService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionService));291const copilotCLIWorktreeManagerService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionWorktreeService));292293// Handle worktree cleanup/recreation when archive state changes294const onDidChangeChatSessionItemState = (providerRegistration as { onDidChangeChatSessionItemState?: vscode.Event<vscode.ChatSessionItem> }).onDidChangeChatSessionItemState;295if (onDidChangeChatSessionItemState) {296this._register(onDidChangeChatSessionItemState(async (item) => {297const sessionId = SessionIdForCLI.parse(item.resource);298if (item.archived) {299try {300const result = await copilotCLIWorktreeManagerService.cleanupWorktreeOnArchive(sessionId);301logService.trace(`[CopilotCLI] Worktree cleanup for session ${sessionId}: ${result.cleaned ? 'cleaned' : result.reason}`);302} catch (error) {303logService.error(`[CopilotCLI] Failed to cleanup worktree for archived session ${sessionId}:`, error);304}305} else {306try {307const result = await copilotCLIWorktreeManagerService.recreateWorktreeOnUnarchive(sessionId);308logService.trace(`[CopilotCLI] Worktree recreation for session ${sessionId}: ${result.recreated ? 'recreated' : result.reason}`);309if (result.recreated) {310copilotcliSessionItemProvider.refreshSession({ reason: 'update', sessionId });311}312} catch (error) {313logService.error(`[CopilotCLI] Failed to recreate worktree for unarchived session ${sessionId}:`, error);314}315}316}));317}318319const copilotCLIWorkspaceFolderSessions = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionWorkspaceFolderService));320const folderRepositoryManager = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IFolderRepositoryManager));321const nativeEnvService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(INativeEnvService));322const fileSystemService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IFileSystemService));323const copilotModels = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLIModels));324const copilotFolderMruService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatFolderMruService));325326this._register(copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionTracker)));327this._register(copilotcliAgentInstaService.createInstance(CopilotCLIContrib));328329copilotModels.registerLanguageModelChatProvider(vscode.lm);330331const copilotcliParticipant = vscode.chat.createChatParticipant(this.copilotcliSessionType, copilotcliChatSessionParticipant.createHandler());332this._register(vscode.chat.registerChatSessionContentProvider(this.copilotcliSessionType, copilotcliChatSessionContentProvider, copilotcliParticipant));333const copilotcliCustomizationProvider = this._register(copilotcliAgentInstaService.createInstance(CopilotCLICustomizationProvider));334this._register(vscode.chat.registerChatSessionCustomizationProvider(this.copilotcliSessionType, CopilotCLICustomizationProvider.metadata, copilotcliCustomizationProvider));335this._register(registerCLIChatCommandsV1(copilotcliSessionItemProvider, copilotCLISessionService, copilotCLIWorktreeManagerService, gitService, gitExtensionService, toolsService, copilotCLIWorkspaceFolderSessions, copilotcliChatSessionContentProvider, folderRepositoryManager, copilotFolderMruService, nativeEnvService, fileSystemService, logService));336// #endregion337338const sessionMetadata = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IChatSessionMetadataStore));339return { sessionMetadata };340}341342private registerCopilotCloudAgent() {343if (!this.copilotAgentInstaService) {344return;345}346if (this.copilotCloudRegistrations) {347this.copilotCloudRegistrations.dispose();348this.copilotCloudRegistrations = undefined;349}350this.copilotCloudRegistrations = new DisposableStore();351this.copilotCloudRegistrations.add(352this.copilotAgentInstaService.createInstance(PRContentProvider)353);354const cloudSessionsProvider = this.copilotCloudRegistrations.add(355this.copilotAgentInstaService.createInstance(CopilotCloudSessionsProvider)356);357this.copilotCloudRegistrations.add(358vscode.chat.registerChatSessionItemProvider(CopilotCloudSessionsProvider.TYPE, cloudSessionsProvider)359);360this.copilotCloudRegistrations.add(361vscode.chat.registerChatSessionContentProvider(362CopilotCloudSessionsProvider.TYPE,363cloudSessionsProvider,364cloudSessionsProvider.chatParticipant,365{ supportsInterruptions: true }366)367);368this.copilotCloudRegistrations.add(369vscode.commands.registerCommand('github.copilot.cloud.resetWorkspaceConfirmations', () => {370cloudSessionsProvider.resetWorkspaceContext();371})372);373this.copilotCloudRegistrations.add(374vscode.commands.registerCommand('github.copilot.cloud.sessions.openInBrowser', async (chatSessionItem: vscode.ChatSessionItem) => {375cloudSessionsProvider.openSessionInBrowser(chatSessionItem);376})377);378this.copilotCloudRegistrations.add(379vscode.commands.registerCommand(CLOSE_SESSION_PR_CMD, async (ctx: CrossChatSessionWithPR) => {380try {381const success = await this.octoKitService.closePullRequest(382ctx.pullRequestDetails.repository.owner.login,383ctx.pullRequestDetails.repository.name,384ctx.pullRequestDetails.number,385{ createIfNone: { detail: l10n.t('Sign in to GitHub to access Copilot cloud sessions.') } });386if (!success) {387this.logService.error(`${CLOSE_SESSION_PR_CMD}: Failed to close PR #${ctx.pullRequestDetails.number}`);388}389cloudSessionsProvider.refresh();390} catch (e) {391this.logService.error(`${CLOSE_SESSION_PR_CMD}: Exception ${e}`);392}393})394);395this.copilotCloudRegistrations.add(396vscode.commands.registerCommand('github.copilot.cloud.sessions.installPRExtension', async () => {397await this.installPullRequestExtension();398})399);400return cloudSessionsProvider;401}402403private isPullRequestExtensionInstalled(): boolean {404return vscode.extensions.getExtension(GHPR_EXTENSION_ID) !== undefined;405}406407private async installPullRequestExtension(): Promise<void> {408if (this.isPullRequestExtensionInstalled()) {409return;410}411try {412const isInsiders = this.envService.getEditorInfo().version.includes('insider');413const installOptions = { enable: true, installPreReleaseVersion: isInsiders, justification: vscode.l10n.t('Enable additional pull request features, such as checking out and applying changes.') };414await vscode.commands.executeCommand('workbench.extensions.installExtension', GHPR_EXTENSION_ID, installOptions);415const maxWaitTime = 10_000; // 10 seconds416const pollInterval = 100; // 100ms417let elapsed = 0;418while (elapsed < maxWaitTime) {419if (this.isPullRequestExtensionInstalled()) {420vscode.window.showInformationMessage(vscode.l10n.t('GitHub Pull Request extension installed successfully.'));421break;422}423await new Promise(resolve => setTimeout(resolve, pollInterval));424elapsed += pollInterval;425}426if (!this.isPullRequestExtensionInstalled()) {427vscode.window.showWarningMessage(vscode.l10n.t('GitHub Pull Request extension is taking longer than expected to install.'));428}429await vscode.commands.executeCommand('setContext', prExtensionInstalledContextKey, true);430} catch (error) {431vscode.window.showErrorMessage(vscode.l10n.t('Failed to install GitHub Pull Request extension: {0}', error instanceof Error ? error.message : String(error)));432}433}434}435436437