refactor: update chat transfer service methods for workspace trust management (#245265)

This commit is contained in:
Bhavya U
2025-04-01 17:39:11 -07:00
committed by GitHub
parent 6e2cad6fcf
commit 18c72eee2b
7 changed files with 42 additions and 21 deletions
@@ -14,6 +14,6 @@ export class ChatTransferContribution extends Disposable implements IWorkbenchCo
@IChatTransferService chatTransferService: IChatTransferService,
) {
super();
chatTransferService.checkAndSetWorkspaceTrust();
chatTransferService.checkAndSetTransferredWorkspaceTrust();
}
}
@@ -631,6 +631,7 @@ registerChatToolActions();
registerEditorFeature(ChatPasteProvidersFeature);
registerSingleton(IChatTransferService, ChatTransferService, InstantiationType.Delayed);
registerSingleton(IChatService, ChatService, InstantiationType.Delayed);
registerSingleton(IChatWidgetService, ChatWidgetService, InstantiationType.Delayed);
registerSingleton(IQuickChatService, QuickChatService, InstantiationType.Delayed);
@@ -651,6 +652,5 @@ registerSingleton(IChatMarkdownAnchorService, ChatMarkdownAnchorService, Instant
registerSingleton(ILanguageModelIgnoredFilesService, LanguageModelIgnoredFilesService, InstantiationType.Delayed);
registerSingleton(IChatEntitlementService, ChatEntitlementService, InstantiationType.Delayed);
registerSingleton(IPromptsService, PromptsService, InstantiationType.Delayed);
registerSingleton(IChatTransferService, ChatTransferService, InstantiationType.Delayed);
registerWorkbenchContribution2(ChatEditingNotebookFileSystemProviderContrib.ID, ChatEditingNotebookFileSystemProviderContrib, WorkbenchPhase.BlockStartup);
@@ -34,6 +34,7 @@ import { IChatCompleteResponse, IChatDetail, IChatFollowup, IChatProgress, IChat
import { ChatServiceTelemetry } from './chatServiceTelemetry.js';
import { ChatSessionStore, IChatTransfer2 } from './chatSessionStore.js';
import { IChatSlashCommandService } from './chatSlashCommands.js';
import { IChatTransferService } from './chatTransferService.js';
import { IChatVariablesService } from './chatVariables.js';
import { ChatAgentLocation, ChatConfiguration, ChatMode } from './constants.js';
import { ChatMessageRole, IChatMessage } from './languageModels.js';
@@ -158,6 +159,7 @@ export class ChatService extends Disposable implements IChatService {
@IChatAgentService private readonly chatAgentService: IChatAgentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService,
@IChatTransferService private readonly chatTransferService: IChatTransferService,
) {
super();
@@ -1128,6 +1130,7 @@ export class ChatService extends Disposable implements IChatService {
});
this.storageService.store(globalChatKey, JSON.stringify(existingRaw), StorageScope.PROFILE, StorageTarget.MACHINE);
this.chatTransferService.addWorkspaceToTransferred(toWorkspace);
this.trace('transferChatSession', `Transferred session ${model.sessionId} to workspace ${toWorkspace.toString()}`);
}
@@ -3,18 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
import { IStorageService } from '../../../../platform/storage/common/storage.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IFileService } from '../../../../platform/files/common/files.js';
import { IWorkspaceTrustManagementService } from '../../../../platform/workspace/common/workspaceTrust.js';
import { isChatTransferredWorkspace, areWorkspaceFoldersEmpty } from '../../../services/workspaces/common/workspaceUtils.js';
import { areWorkspaceFoldersEmpty } from '../../../services/workspaces/common/workspaceUtils.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { URI } from '../../../../base/common/uri.js';
export const IChatTransferService = createDecorator<IChatTransferService>('chatTransferService');
const transferredWorkspacesKey = 'chat.transferedWorkspaces';
export interface IChatTransferService {
readonly _serviceBrand: undefined;
checkAndSetWorkspaceTrust(): Promise<void>;
checkAndSetTransferredWorkspaceTrust(): Promise<void>;
addWorkspaceToTransferred(workspace: URI): void;
}
export class ChatTransferService implements IChatTransferService {
@@ -27,10 +30,35 @@ export class ChatTransferService implements IChatTransferService {
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService
) { }
async checkAndSetWorkspaceTrust(): Promise<void> {
deleteWorkspaceFromTransferredList(workspace: URI): void {
const transferredWorkspaces = this.storageService.getObject<string[]>(transferredWorkspacesKey, StorageScope.PROFILE, []);
const updatedWorkspaces = transferredWorkspaces.filter(uri => uri !== workspace.toString());
this.storageService.store(transferredWorkspacesKey, updatedWorkspaces, StorageScope.PROFILE, StorageTarget.MACHINE);
}
addWorkspaceToTransferred(workspace: URI): void {
const transferredWorkspaces = this.storageService.getObject<string[]>(transferredWorkspacesKey, StorageScope.PROFILE, []);
transferredWorkspaces.push(workspace.toString());
this.storageService.store(transferredWorkspacesKey, transferredWorkspaces, StorageScope.PROFILE, StorageTarget.MACHINE);
}
async checkAndSetTransferredWorkspaceTrust(): Promise<void> {
const workspace = this.workspaceService.getWorkspace();
if (isChatTransferredWorkspace(workspace, this.storageService) && await areWorkspaceFoldersEmpty(workspace, this.fileService)) {
const currentWorkspaceUri = workspace.folders[0]?.uri;
if (!currentWorkspaceUri) {
return;
}
if (this.isChatTransferredWorkspace(currentWorkspaceUri, this.storageService) && await areWorkspaceFoldersEmpty(workspace, this.fileService)) {
await this.workspaceTrustManagementService.setWorkspaceTrust(true);
this.deleteWorkspaceFromTransferredList(currentWorkspaceUri);
}
}
isChatTransferredWorkspace(workspace: URI, storageService: IStorageService): boolean {
if (!workspace) {
return false;
}
const chatWorkspaceTransfer: URI[] = storageService.getObject(transferredWorkspacesKey, StorageScope.PROFILE, []);
return chatWorkspaceTransfer.some(item => item.toString() === workspace.toString());
}
}
@@ -33,6 +33,7 @@ import { INotebookService } from '../../../notebook/common/notebookService.js';
import { Range } from '../../../../../editor/common/core/range.js';
import { ChatAgentLocation } from '../../common/constants.js';
import { NotebookTextModel } from '../../../notebook/common/model/notebookTextModel.js';
import { ChatTransferService, IChatTransferService } from '../../common/chatTransferService.js';
function getAgentData(id: string) {
return {
@@ -62,6 +63,7 @@ suite('ChatEditingService', function () {
collection.set(IChatAgentService, new SyncDescriptor(ChatAgentService));
collection.set(IChatVariablesService, new MockChatVariablesService());
collection.set(IChatSlashCommandService, new class extends mock<IChatSlashCommandService>() { });
collection.set(IChatTransferService, new SyncDescriptor(ChatTransferService));
collection.set(IChatEditingService, new SyncDescriptor(ChatEditingService));
collection.set(IChatService, new SyncDescriptor(ChatService));
collection.set(IMultiDiffSourceResolverService, new class extends mock<IMultiDiffSourceResolverService>() {
@@ -63,6 +63,7 @@ import { assertSnapshot } from '../../../../../base/test/common/snapshot.js';
import { IObservable, constObservable } from '../../../../../base/common/observable.js';
import { IChatEditingService, IChatEditingSession } from '../../../chat/common/chatEditingService.js';
import { ChatAgentLocation } from '../../../chat/common/constants.js';
import { ChatTransferService, IChatTransferService } from '../../../chat/common/chatTransferService.js';
suite('InlineChatSession', function () {
@@ -89,6 +90,7 @@ suite('InlineChatSession', function () {
[IChatWidgetHistoryService, new SyncDescriptor(ChatWidgetHistoryService)],
[IChatWidgetService, new SyncDescriptor(ChatWidgetService)],
[IChatSlashCommandService, new SyncDescriptor(ChatSlashCommandService)],
[IChatTransferService, new SyncDescriptor(ChatTransferService)],
[IChatService, new SyncDescriptor(ChatService)],
[IEditorWorkerService, new SyncDescriptor(TestWorkerService)],
[IChatAgentService, new SyncDescriptor(ChatAgentService)],
@@ -2,22 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from '../../../../base/common/uri.js';
import { IWorkspace } from '../../../../platform/workspace/common/workspace.js';
import { IFileService } from '../../../../platform/files/common/files.js';
import { IStorageService, StorageScope } from '../../../../platform/storage/common/storage.js';
export function isChatTransferredWorkspace(workspace: IWorkspace, storageService: IStorageService): boolean {
const workspaceUri = workspace.folders[0]?.uri;
if (!workspaceUri) {
return false;
}
const chatWorkspaceTransfer = storageService.getObject('chat.workspaceTransfer', StorageScope.PROFILE, []);
const toWorkspace: { toWorkspace: URI }[] = chatWorkspaceTransfer.map((item: any) => {
return { toWorkspace: URI.from(item.toWorkspace) };
});
return toWorkspace.some(item => item.toWorkspace.toString() === workspaceUri.toString());
}
export async function areWorkspaceFoldersEmpty(workspace: IWorkspace, fileService: IFileService): Promise<boolean> {
for (const folder of workspace.folders) {