Path: blob/main/src/vs/sessions/contrib/chat/electron-browser/openInVSCode.contribution.ts
13401 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 { Codicon } from '../../../../base/common/codicons.js';6import { Schemas } from '../../../../base/common/network.js';7import { URI } from '../../../../base/common/uri.js';8import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';9import { localize2 } from '../../../../nls.js';10import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';11import { AGENT_HOST_SCHEME, fromAgentHostUri } from '../../../../platform/agentHost/common/agentHostUri.js';12import { IRemoteAgentHostService } from '../../../../platform/agentHost/common/remoteAgentHostService.js';13import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';14import { INativeHostService } from '../../../../platform/native/common/native.js';15import { IOpenerService } from '../../../../platform/opener/common/opener.js';16import { IProductService } from '../../../../platform/product/common/productService.js';17import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';18import { IsAuxiliaryWindowContext } from '../../../../workbench/common/contextkeys.js';19import { IsPhoneLayoutContext, SessionsWelcomeVisibleContext } from '../../../common/contextkeys.js';20import { logSessionsInteraction } from '../../../common/sessionsTelemetry.js';21import { Menus } from '../../../browser/menus.js';22import { isWorkspaceAgentSessionType } from '../../../services/sessions/common/session.js';23import { ISessionsManagementService } from '../../../services/sessions/common/sessionsManagement.js';24import { ISessionsProvidersService } from '../../../services/sessions/browser/sessionsProvidersService.js';25import { resolveRemoteAuthority } from '../browser/openInVSCodeUtils.js';26import { DebugAgentHostInDevToolsAction } from '../../../../workbench/contrib/chat/electron-browser/actions/debugAgentHostAction.js';27import { isLinux } from '../../../../base/common/platform.js';28import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';2930/**31* Desktop version of the "Open in VS Code" action.32*33* In built builds with a sibling app configured, launches the host VS Code app34* via {@link INativeHostService.launchSiblingApp} (child_process.spawn) with35* direct CLI arguments, bypassing protocol handlers and their OS security36* prompts. In dev builds (no sibling app), falls back to the protocol handler37* approach via {@link IOpenerService}.38*/39registerAction2(class OpenSessionWorktreeInVSCodeAction extends Action2 {40static readonly ID = 'chat.openSessionWorktreeInVSCode';4142constructor() {43super({44id: OpenSessionWorktreeInVSCodeAction.ID,45title: localize2('openInVSCode', 'Open in VS Code'),46icon: Codicon.vscodeInsiders,47precondition: ContextKeyExpr.and(IsAuxiliaryWindowContext.toNegated(), SessionsWelcomeVisibleContext.toNegated()),48menu: [{49id: Menus.TitleBarSessionMenu,50group: 'navigation',51order: 7,52when: ContextKeyExpr.and(IsAuxiliaryWindowContext.toNegated(), SessionsWelcomeVisibleContext.toNegated(), IsPhoneLayoutContext.negate()),53}]54});55}5657override async run(accessor: ServicesAccessor): Promise<void> {58const telemetryService = accessor.get(ITelemetryService);59logSessionsInteraction(telemetryService, 'openInVSCode');6061const productService = accessor.get(IProductService);62const environmentService = accessor.get(IEnvironmentService);63const sessionsManagementService = accessor.get(ISessionsManagementService);64const sessionsProvidersService = accessor.get(ISessionsProvidersService);65const remoteAgentHostService = accessor.get(IRemoteAgentHostService);6667const activeSession = sessionsManagementService.activeSession.get();68const workspace = activeSession?.workspace.get();69const repo = workspace?.repositories[0];70const rawFolderUri = isWorkspaceAgentSessionType(activeSession?.sessionType) ? repo?.workingDirectory ?? repo?.uri : undefined;71const folderUri = rawFolderUri?.scheme === AGENT_HOST_SCHEME ? fromAgentHostUri(rawFolderUri) : rawFolderUri;72const remoteAuthority = activeSession73? resolveRemoteAuthority(activeSession.providerId, sessionsProvidersService, remoteAgentHostService)74: undefined;7576if (environmentService.isBuilt && !isLinux) {77await this.launchViaSiblingApp(accessor, activeSession, folderUri, remoteAuthority);78} else {79await this.launchViaProtocolHandler(accessor, productService, activeSession, folderUri, remoteAuthority);80}81}8283private async launchViaSiblingApp(84accessor: ServicesAccessor,85activeSession: ReturnType<ISessionsManagementService['activeSession']['get']>,86folderUri: URI | undefined,87remoteAuthority: string | undefined,88): Promise<void> {89const nativeHostService = accessor.get(INativeHostService);9091const args: string[] = ['--new-window'];9293if (folderUri) {94if (remoteAuthority) {95args.push('--folder-uri', URI.from({ scheme: Schemas.vscodeRemote, authority: remoteAuthority, path: folderUri.path }).toString());96} else {97args.push('--folder-uri', folderUri.toString());98}99}100101if (activeSession) {102args.push('--open-chat-session', activeSession.resource.toString());103}104105await nativeHostService.launchSiblingApp(args);106}107108private async launchViaProtocolHandler(109accessor: ServicesAccessor,110productService: IProductService,111activeSession: ReturnType<ISessionsManagementService['activeSession']['get']>,112folderUri: URI | undefined,113remoteAuthority: string | undefined,114): Promise<void> {115const openerService = accessor.get(IOpenerService);116117const scheme = productService.quality === 'stable'118? 'vscode'119: productService.quality === 'exploration'120? 'vscode-exploration'121: productService.quality === 'insider'122? 'vscode-insiders'123: productService.urlProtocol;124125const params = new URLSearchParams();126params.set('windowId', '_blank');127128if (!activeSession || !folderUri) {129await openerService.open(URI.from({ scheme, query: params.toString() }), { openExternal: true });130return;131}132133params.set('session', activeSession.resource.toString());134135if (remoteAuthority) {136await openerService.open(URI.from({137scheme,138authority: Schemas.vscodeRemote,139path: `/${remoteAuthority}${folderUri.path}`,140query: params.toString(),141}), { openExternal: true });142} else {143await openerService.open(URI.from({144scheme,145authority: Schemas.file,146path: folderUri.path,147query: params.toString(),148}), { openExternal: true });149}150}151});152153registerAction2(DebugAgentHostInDevToolsAction);154155156