From cae186c9f85686383baa272b379c14e725c35576 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 26 Mar 2026 17:10:25 +0100 Subject: [PATCH] fixes to sessions (#305205) * fixes to sessions * copilot feedback --- src/vs/sessions/SESSIONS_PROVIDER.md | 2 +- .../contrib/chat/browser/newChatViewPane.ts | 13 +++- .../chat/browser/sessionWorkspacePicker.ts | 2 +- .../sessionsConfigurationService.test.ts | 4 +- .../browser/copilotChatSessionsActions.ts | 14 +++- .../browser/copilotChatSessionsProvider.ts | 74 +++++++++---------- .../remoteAgentHostSessionsProvider.ts | 15 ++-- .../contrib/sessions/browser/sessionTypes.ts | 29 ++++++++ .../browser/sessionsManagementService.ts | 2 +- .../sessions/browser/sessionsProvider.ts | 2 - .../sessions/browser/views/sessionsList.ts | 6 +- .../browser/views/sessionsViewActions.ts | 8 +- .../contrib/sessions/common/sessionData.ts | 18 ++++- .../sessionsTerminalContribution.test.ts | 10 +-- .../browser/workspaceFolderManagement.ts | 1 + 15 files changed, 120 insertions(+), 80 deletions(-) create mode 100644 src/vs/sessions/contrib/sessions/browser/sessionTypes.ts diff --git a/src/vs/sessions/SESSIONS_PROVIDER.md b/src/vs/sessions/SESSIONS_PROVIDER.md index 596803cd782..3292867ed5d 100644 --- a/src/vs/sessions/SESSIONS_PROVIDER.md +++ b/src/vs/sessions/SESSIONS_PROVIDER.md @@ -67,7 +67,7 @@ The common session interface exposed by all providers. It is a self-contained fa | `isRead` | `IObservable` | Read/unread state | | `description` | `IObservable` | Status description (e.g., current agent action) | | `lastTurnEnd` | `IObservable` | When the last agent turn ended | -| `pullRequestUri` | `IObservable` | Associated pull request URI | +| `pullRequest` | `IObservable` | Associated pull request | #### Supporting Types diff --git a/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts b/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts index 923f3fe7d42..ac50eacefc0 100644 --- a/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts +++ b/src/vs/sessions/contrib/chat/browser/newChatViewPane.ts @@ -645,10 +645,7 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { * Requests folder trust if needed and creates a new session. */ private async _onWorkspaceSelected(selection: IWorkspaceSelection): Promise { - // Check if the provider's session type requires workspace trust - const sessionTypes = this.sessionsProvidersService.getSessionTypesForProvider(selection.providerId); - const requiresTrust = sessionTypes.some(t => t.requiresWorkspaceTrust); - if (requiresTrust) { + if (selection.workspace.requiresWorkspaceTrust) { const workspaceUri = selection.workspace.repositories[0]?.uri; if (workspaceUri && !await this._requestFolderTrust(workspaceUri)) { return; @@ -677,6 +674,10 @@ class NewChatWidget extends Disposable implements IHistoryNavigationWidget { this._send(); } } + + selectWorkspace(workspace: IWorkspaceSelection): void { + this._workspacePicker.setSelectedWorkspace(workspace); + } } // #endregion @@ -736,6 +737,10 @@ export class NewChatViewPane extends ViewPane { this._widget?.sendQuery(text); } + selectWorkspace(workspace: IWorkspaceSelection): void { + this._widget?.selectWorkspace(workspace); + } + override setVisible(visible: boolean): void { super.setVisible(visible); if (visible) { diff --git a/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts b/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts index d23a2d5c8f5..c70e5fd750a 100644 --- a/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts +++ b/src/vs/sessions/contrib/chat/browser/sessionWorkspacePicker.ts @@ -189,7 +189,7 @@ export class WorkspacePicker extends Disposable { * Programmatically set the selected project. * @param fireEvent Whether to fire the onDidSelectWorkspace event. Defaults to true. */ - setSelectedProject(project: IWorkspaceSelection, fireEvent = true): void { + setSelectedWorkspace(project: IWorkspaceSelection, fireEvent = true): void { this._selectProject(project, fireEvent); } diff --git a/src/vs/sessions/contrib/chat/test/browser/sessionsConfigurationService.test.ts b/src/vs/sessions/contrib/chat/test/browser/sessionsConfigurationService.test.ts index 591594e6d58..876fd749002 100644 --- a/src/vs/sessions/contrib/chat/test/browser/sessionsConfigurationService.test.ts +++ b/src/vs/sessions/contrib/chat/test/browser/sessionsConfigurationService.test.ts @@ -33,6 +33,7 @@ function makeSession(opts: { repository?: URI; worktree?: URI } = {}): ISessionD detail: undefined, baseBranchProtected: undefined, }], + requiresWorkspaceTrust: false, } : undefined; return { sessionId: 'test:session', @@ -53,8 +54,7 @@ function makeSession(opts: { repository?: URI; worktree?: URI } = {}): ISessionD isRead: observableValue('isRead', true), lastTurnEnd: observableValue('lastTurnEnd', undefined), description: observableValue('description', undefined), - pullRequestUri: observableValue('pullRequestUri', undefined), - pullRequestStateIcon: observableValue('pullRequestStateIcon', undefined), + pullRequest: observableValue('pullRequest', undefined), }; } diff --git a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts index 3987b6579a8..90e130963ca 100644 --- a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts +++ b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsActions.ts @@ -20,13 +20,15 @@ import { IChatInputPickerOptions } from '../../../../workbench/contrib/chat/brow import { EnhancedModelPickerActionItem } from '../../../../workbench/contrib/chat/browser/widget/input/modelPickerActionItem2.js'; import { HoverPosition } from '../../../../base/browser/ui/hover/hoverWidget.js'; import { IContextKeyService, ContextKeyExpr, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { Menus } from '../../../browser/menus.js'; import { ISessionsManagementService } from '../../sessions/browser/sessionsManagementService.js'; import { ISessionsProvidersService } from '../../sessions/browser/sessionsProvidersService.js'; import { SessionItemContextMenuId } from '../../sessions/browser/views/sessionsList.js'; import { ISessionData } from '../../sessions/common/sessionData.js'; import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js'; -import { CopilotCLISession, COPILOT_PROVIDER_ID, COPILOT_CLI_SESSION_TYPE, COPILOT_CLOUD_SESSION_TYPE } from './copilotChatSessionsProvider.js'; +import { CopilotCLISession, COPILOT_PROVIDER_ID } from './copilotChatSessionsProvider.js'; +import { COPILOT_CLI_SESSION_TYPE, COPILOT_CLOUD_SESSION_TYPE } from '../../sessions/browser/sessionTypes.js'; import { IsolationPicker } from './isolationPicker.js'; import { BranchPicker } from './branchPicker.js'; import { ModePicker } from './modePicker.js'; @@ -181,6 +183,7 @@ class CopilotPickerActionViewItemContribution extends Disposable implements IWor @ILanguageModelsService languageModelsService: ILanguageModelsService, @ISessionsManagementService sessionsManagementService: ISessionsManagementService, @ISessionsProvidersService sessionsProvidersService: ISessionsProvidersService, + @IStorageService storageService: IStorageService, ) { super(); @@ -213,6 +216,7 @@ class CopilotPickerActionViewItemContribution extends Disposable implements IWor currentModel, setModel: (model: ILanguageModelChatMetadataAndIdentifier) => { currentModel.set(model, undefined); + storageService.store('sessions.localModelPicker.selectedModelId', model.identifier, StorageScope.PROFILE, StorageTarget.MACHINE); const session = sessionsManagementService.activeSession.get(); if (session) { const provider = sessionsProvidersService.getProviders().find(p => p.id === session.providerId); @@ -232,12 +236,14 @@ class CopilotPickerActionViewItemContribution extends Disposable implements IWor const action = { id: 'sessions.modelPicker', label: '', enabled: true, class: undefined, tooltip: '', run: () => { } }; const modelPicker = instantiationService.createInstance(EnhancedModelPickerActionItem, action, delegate, pickerOptions); - // Initialize with first available model, or wait for models to load + // Initialize with remembered model or first available model + const rememberedModelId = storageService.get('sessions.localModelPicker.selectedModelId', StorageScope.PROFILE); const initModel = () => { const models = getAvailableModels(languageModelsService); modelPicker.setEnabled(models.length > 0); - if (!currentModel.get() && models[0]) { - currentModel.set(models[0], undefined); + if (!currentModel.get() && models.length > 0) { + const remembered = rememberedModelId ? models.find(m => m.identifier === rememberedModelId) : undefined; + currentModel.set(remembered ?? models[0], undefined); } }; initModel(); diff --git a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsProvider.ts b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsProvider.ts index 7a6eec2f3f8..db4d0379855 100644 --- a/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsProvider.ts +++ b/src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsProvider.ts @@ -18,10 +18,11 @@ import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browse import { AgentSessionProviders, AgentSessionTarget } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessions.js'; import { IChatService, IChatSendRequestOptions } from '../../../../workbench/contrib/chat/common/chatService/chatService.js'; import { ChatSessionStatus, IChatSessionFileChange, IChatSessionsService, IChatSessionProviderOptionGroup, IChatSessionProviderOptionItem } from '../../../../workbench/contrib/chat/common/chatSessionsService.js'; -import { ISessionData, ISessionRepository, ISessionWorkspace, SessionStatus, GITHUB_REMOTE_FILE_SCHEME } from '../../sessions/common/sessionData.js'; +import { ISessionData, ISessionPullRequest, ISessionRepository, ISessionWorkspace, SessionStatus, GITHUB_REMOTE_FILE_SCHEME } from '../../sessions/common/sessionData.js'; import { ChatAgentLocation, ChatModeKind, ChatPermissionLevel } from '../../../../workbench/contrib/chat/common/constants.js'; import { basename } from '../../../../base/common/resources.js'; import { ISendRequestOptions, ISessionsBrowseAction, ISessionsChangeEvent, ISessionsProvider, ISessionType } from '../../sessions/browser/sessionsProvider.js'; +import { CopilotCLISessionType, CopilotCloudSessionType } from '../../sessions/browser/sessionTypes.js'; import { ISessionOptionGroup } from '../../chat/browser/newSession.js'; import { IsolationMode } from './isolationPicker.js'; import { ChatViewPaneTarget, IChatWidgetService } from '../../../../workbench/contrib/chat/browser/chat.js'; @@ -41,22 +42,6 @@ const OPEN_REPO_COMMAND = 'github.copilot.chat.cloudSessions.openRepository'; /** Provider ID for the Copilot Chat Sessions provider. */ export const COPILOT_PROVIDER_ID = 'default-copilot'; -/** Session type ID for local Copilot CLI sessions. */ -export const COPILOT_CLI_SESSION_TYPE = AgentSessionProviders.Background; -export const COPILOT_CLOUD_SESSION_TYPE = AgentSessionProviders.Cloud; - -const CopilotCLISessionType: ISessionType = { - id: COPILOT_CLI_SESSION_TYPE, - label: localize('copilotCLI', "Copilot"), - icon: Codicon.copilot, - requiresWorkspaceTrust: true, -}; - -const CopilotCloudSessionType: ISessionType = { - id: COPILOT_CLOUD_SESSION_TYPE, - label: localize('copilotCloud', "Cloud"), - icon: Codicon.cloud, -}; const REPOSITORY_OPTION_ID = 'repository'; const BRANCH_OPTION_ID = 'branch'; @@ -126,8 +111,7 @@ export class CopilotCLISession extends Disposable implements ISessionData { readonly isRead: IObservable = observableValue(this, true); readonly description: IObservable = observableValue(this, undefined); readonly lastTurnEnd: IObservable = observableValue(this, undefined); - readonly pullRequestUri: IObservable = observableValue(this, undefined); - readonly pullRequestStateIcon: IObservable = observableValue(this, undefined); + readonly pullRequest: IObservable = observableValue(this, undefined); private _gitRepository: IGitRepository | undefined; private readonly _loadBranchesCts = this._register(new MutableDisposable()); @@ -312,6 +296,10 @@ export class CopilotCLISession extends Disposable implements ISessionData { } this.chatSessionsService.setSessionOption(this.resource, optionId, value); } + + update(session: ISessionData): void { + this._workspaceData.set(session.workspace.get(), undefined); + } } function isModelOptionGroup(group: IChatSessionProviderOptionGroup): boolean { @@ -369,8 +357,7 @@ export class RemoteNewSession extends Disposable implements ISessionData { readonly isRead: IObservable = observableValue(this, true); readonly description: IObservable = observableValue(this, undefined); readonly lastTurnEnd: IObservable = observableValue(this, undefined); - readonly pullRequestUri: IObservable = observableValue(this, undefined); - readonly pullRequestStateIcon: IObservable = observableValue(this, undefined); + readonly pullRequest: IObservable = observableValue(this, undefined); readonly _hasGitRepo = observableValue(this, false); readonly hasGitRepo: IObservable = this._hasGitRepo; @@ -545,6 +532,8 @@ export class RemoteNewSession extends Disposable implements ISessionData { // Default to first item marked as default, or first item return group.items.find(i => i.default === true) ?? group.items[0]; } + + update(session: ISessionData): void { } } /** @@ -606,11 +595,8 @@ class AgentSessionAdapter implements ISessionData { private readonly _lastTurnEnd: ReturnType>; readonly lastTurnEnd: IObservable; - private readonly _pullRequestUri: ReturnType>; - readonly pullRequestUri: IObservable; - - private readonly _pullRequestStateIcon: ReturnType>; - readonly pullRequestStateIcon: IObservable; + private readonly _pullRequest: ReturnType>; + readonly pullRequest: IObservable; constructor( session: IAgentSession, @@ -650,10 +636,8 @@ class AgentSessionAdapter implements ISessionData { this.description = this._description; this._lastTurnEnd = observableValue(this, session.timing.lastRequestEnded ? new Date(session.timing.lastRequestEnded) : undefined); this.lastTurnEnd = this._lastTurnEnd; - this._pullRequestUri = observableValue(this, this._extractPullRequestUri(session)); - this.pullRequestUri = this._pullRequestUri; - this._pullRequestStateIcon = observableValue(this, this._extractPullRequestStateIcon(session)); - this.pullRequestStateIcon = this._pullRequestStateIcon; + this._pullRequest = observableValue(this, this._extractPullRequest(session)); + this.pullRequest = this._pullRequest; } /** @@ -670,8 +654,7 @@ class AgentSessionAdapter implements ISessionData { this._isRead.set(session.isRead(), tx); this._description.set(this._extractDescription(session), tx); this._lastTurnEnd.set(session.timing.lastRequestEnded ? new Date(session.timing.lastRequestEnded) : undefined, tx); - this._pullRequestUri.set(this._extractPullRequestUri(session), tx); - this._pullRequestStateIcon.set(this._extractPullRequestStateIcon(session), tx); + this._pullRequest.set(this._extractPullRequest(session), tx); }); } @@ -682,6 +665,15 @@ class AgentSessionAdapter implements ISessionData { return typeof session.description === 'string' ? session.description : session.description.value; } + private _extractPullRequest(session: IAgentSession): ISessionPullRequest | undefined { + const uri = this._extractPullRequestUri(session); + if (!uri) { + return undefined; + } + const icon = this._extractPullRequestStateIcon(session); + return { uri, icon: icon }; + } + private _extractPullRequestStateIcon(session: IAgentSession): ThemeIcon | undefined { const metadata = session.metadata; const state = metadata?.pullRequestState; @@ -748,12 +740,6 @@ class AgentSessionAdapter implements ISessionData { } private _buildWorkspace(session: IAgentSession): ISessionWorkspace | undefined { - // Use the same repository name extraction as the old agent sessions view - const label = getRepositoryName(session); - if (!label) { - return undefined; - } - const [repoUri, worktreeUri, branchName, baseBranchProtected] = this._extractRepositoryFromMetadata(session); const repository: ISessionRepository = { @@ -764,9 +750,10 @@ class AgentSessionAdapter implements ISessionData { }; return { - label, + label: getRepositoryName(session) ?? basename(repository.uri), icon: repoUri?.scheme === GITHUB_REMOTE_FILE_SCHEME ? Codicon.repo : Codicon.folder, repositories: [repository], + requiresWorkspaceTrust: session.providerType !== AgentSessionProviders.Cloud, }; } @@ -1047,7 +1034,10 @@ export class CopilotChatSessionsProvider extends Disposable implements ISessions } // Wait for the agent session to appear - return this._waitForNewAgentSession(session.target, existingSessions); + const createdSession = await this._waitForNewAgentSession(session.target, existingSessions); + this._currentNewSession?.dispose(); + this._currentNewSession = undefined; + return createdSession; } private async _waitForNewAgentSession(target: AgentSessionTarget, existingSessions: ResourceSet): Promise { @@ -1080,6 +1070,7 @@ export class CopilotChatSessionsProvider extends Disposable implements ISessions label: this._labelFromUri(uri), icon: this._iconFromUri(uri), repositories: [{ uri, workingDirectory: undefined, detail: undefined, baseBranchProtected: undefined }], + requiresWorkspaceTrust: true }; } return undefined; @@ -1093,6 +1084,7 @@ export class CopilotChatSessionsProvider extends Disposable implements ISessions label: this._labelFromUri(uri), icon: this._iconFromUri(uri), repositories: [{ uri, workingDirectory: undefined, detail: undefined, baseBranchProtected: undefined }], + requiresWorkspaceTrust: false, }; } return undefined; @@ -1103,6 +1095,7 @@ export class CopilotChatSessionsProvider extends Disposable implements ISessions label: this._labelFromUri(repositoryUri), icon: this._iconFromUri(repositoryUri), repositories: [{ uri: repositoryUri, workingDirectory: undefined, detail: undefined, baseBranchProtected: undefined }], + requiresWorkspaceTrust: repositoryUri.scheme !== GITHUB_REMOTE_FILE_SCHEME }; } @@ -1134,6 +1127,7 @@ export class CopilotChatSessionsProvider extends Disposable implements ISessions for (const session of this.agentSessionsService.model.sessions) { if (session.resource.toString() === this._currentNewSession?.resource.toString()) { + this._currentNewSession.update(new AgentSessionAdapter(session, this.id)); continue; } diff --git a/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts b/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts index 460140c5ee6..e964d6a41d3 100644 --- a/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts +++ b/src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts @@ -14,17 +14,10 @@ import { localize } from '../../../../nls.js'; import { IFileDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { ISessionData, ISessionWorkspace, SessionStatus } from '../../sessions/common/sessionData.js'; import { ISendRequestOptions, ISessionsBrowseAction, ISessionsChangeEvent, ISessionsProvider, ISessionType } from '../../sessions/browser/sessionsProvider.js'; +import { CopilotCLISessionType } from '../../sessions/browser/sessionTypes.js'; import { IChatSessionFileChange } from '../../../../workbench/contrib/chat/common/chatSessionsService.js'; import { agentHostUri } from '../../../../platform/agentHost/common/agentHostFileSystemProvider.js'; import { AGENT_HOST_SCHEME, agentHostAuthority } from '../../../../platform/agentHost/common/agentHostUri.js'; -import { AgentSessionProviders } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessions.js'; - -const CopilotCLISessionType: ISessionType = { - id: AgentSessionProviders.AgentHostCopilot, - label: localize('copilotCLI', "Copilot"), - icon: Codicon.copilot, - requiresWorkspaceTrust: true, -}; /** * A sessions provider for a single agent on a remote agent host connection. @@ -73,6 +66,7 @@ export class RemoteAgentHostSessionsProvider extends Disposable implements ISess label: repositoryUri.path.split('/').pop() || repositoryUri.path, icon: Codicon.remote, repositories: [{ uri: repositoryUri, workingDirectory: undefined, detail: this.label, baseBranchProtected: undefined }], + requiresWorkspaceTrust: true }; } @@ -108,6 +102,7 @@ export class RemoteAgentHostSessionsProvider extends Disposable implements ISess label: workspaceUri.path.split('/').pop() || workspaceUri.path, icon: Codicon.remote, repositories: [{ uri: workspaceUri, workingDirectory: undefined, detail: this.label, baseBranchProtected: undefined }], + requiresWorkspaceTrust: true }), title: observableValue(this, ''), updatedAt: observableValue(this, new Date()), @@ -120,8 +115,7 @@ export class RemoteAgentHostSessionsProvider extends Disposable implements ISess isRead: observableValue(this, true), description: observableValue(this, undefined), lastTurnEnd: observableValue(this, undefined), - pullRequestUri: observableValue(this, undefined), - pullRequestStateIcon: observableValue(this, undefined), + pullRequest: observableValue(this, undefined), }; } @@ -183,6 +177,7 @@ export class RemoteAgentHostSessionsProvider extends Disposable implements ISess label, icon: Codicon.remote, repositories: [{ uri, workingDirectory: undefined, detail: this.label, baseBranchProtected: undefined }], + requiresWorkspaceTrust: true }; } } catch { diff --git a/src/vs/sessions/contrib/sessions/browser/sessionTypes.ts b/src/vs/sessions/contrib/sessions/browser/sessionTypes.ts new file mode 100644 index 00000000000..fd421679546 --- /dev/null +++ b/src/vs/sessions/contrib/sessions/browser/sessionTypes.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Codicon } from '../../../../base/common/codicons.js'; +import { localize } from '../../../../nls.js'; +import { AgentSessionProviders } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessions.js'; +import { ISessionType } from './sessionsProvider.js'; + +/** Session type ID for local Copilot CLI sessions. */ +export const COPILOT_CLI_SESSION_TYPE = AgentSessionProviders.Background; + +/** Session type ID for Copilot Cloud sessions. */ +export const COPILOT_CLOUD_SESSION_TYPE = AgentSessionProviders.Cloud; + +/** Copilot CLI session type — local background agent running in a Git worktree. */ +export const CopilotCLISessionType: ISessionType = { + id: COPILOT_CLI_SESSION_TYPE, + label: localize('copilotCLI', "Copilot CLI"), + icon: Codicon.copilot, +}; + +/** Copilot Cloud session type - cloud-hosted agent. */ +export const CopilotCloudSessionType: ISessionType = { + id: COPILOT_CLOUD_SESSION_TYPE, + label: localize('copilotCloud', "Cloud"), + icon: Codicon.cloud, +}; diff --git a/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.ts b/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.ts index d1bc410b55c..670b3b8cfcb 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessionsManagementService.ts @@ -558,7 +558,7 @@ export class SessionsManagementService extends Disposable implements ISessionsMa } private _parsePRNumberFromSession(session: ISessionData): number | undefined { - const prUri = session.pullRequestUri.get(); + const prUri = session.pullRequest.get()?.uri; if (prUri) { const match = /\/pull\/(\d+)/.exec(prUri.path); if (match) { diff --git a/src/vs/sessions/contrib/sessions/browser/sessionsProvider.ts b/src/vs/sessions/contrib/sessions/browser/sessionsProvider.ts index 7a06db1a2cd..6bbf24b9ad3 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessionsProvider.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessionsProvider.ts @@ -20,8 +20,6 @@ export interface ISessionType { readonly label: string; /** Icon for this session type. */ readonly icon: ThemeIcon; - /** Whether this session type requires workspace trust before creating a session. */ - readonly requiresWorkspaceTrust?: boolean; } /** diff --git a/src/vs/sessions/contrib/sessions/browser/views/sessionsList.ts b/src/vs/sessions/contrib/sessions/browser/views/sessionsList.ts index 7591980eaa9..8388ea8a43c 100644 --- a/src/vs/sessions/contrib/sessions/browser/views/sessionsList.ts +++ b/src/vs/sessions/contrib/sessions/browser/views/sessionsList.ts @@ -225,10 +225,10 @@ class SessionItemRenderer implements ITreeRenderer(NewChatViewId, true); + const workspace = context.sessions[0].workspace.get(); + if (view && workspace) { + view.selectWorkspace({ providerId: context.sessions[0].providerId, workspace }); + } } }); diff --git a/src/vs/sessions/contrib/sessions/common/sessionData.ts b/src/vs/sessions/contrib/sessions/common/sessionData.ts index 1be8e1bb0dd..4e004be8638 100644 --- a/src/vs/sessions/contrib/sessions/common/sessionData.ts +++ b/src/vs/sessions/contrib/sessions/common/sessionData.ts @@ -50,6 +50,18 @@ export interface ISessionWorkspace { readonly icon: ThemeIcon; /** Repositories in this workspace. */ readonly repositories: ISessionRepository[]; + /** Whether the session requires workspace trust to operate. */ + readonly requiresWorkspaceTrust: boolean; +} + +/** + * Pull request information associated with a session. + */ +export interface ISessionPullRequest { + /** URI of the pull request. */ + readonly uri: URI; + /** Icon reflecting the PR state. */ + readonly icon?: ThemeIcon; } /** @@ -97,8 +109,6 @@ export interface ISessionData { readonly description: IObservable; /** Timestamp of when the last agent turn ended, if any. */ readonly lastTurnEnd: IObservable; - /** URI of the pull request associated with this session, if any. */ - readonly pullRequestUri: IObservable; - /** Icon reflecting the PR state */ - readonly pullRequestStateIcon: IObservable; + /** Pull request associated with this session, if any. */ + readonly pullRequest: IObservable; } diff --git a/src/vs/sessions/contrib/terminal/test/browser/sessionsTerminalContribution.test.ts b/src/vs/sessions/contrib/terminal/test/browser/sessionsTerminalContribution.test.ts index 1529bc9e486..a408b138ecb 100644 --- a/src/vs/sessions/contrib/terminal/test/browser/sessionsTerminalContribution.test.ts +++ b/src/vs/sessions/contrib/terminal/test/browser/sessionsTerminalContribution.test.ts @@ -61,7 +61,7 @@ function makeAgentSession(opts: { sessionType: opts.providerType ?? AgentSessionProviders.Local, icon: Codicon.copilot, createdAt: new Date(), - workspace: observableValue('test.workspace', repo ? { label: 'test', icon: Codicon.repo, repositories: [repo] } : undefined), + workspace: observableValue('test.workspace', repo ? { label: 'test', icon: Codicon.repo, repositories: [repo], requiresWorkspaceTrust: false, } : undefined), title: observableValue('test.title', 'Test Session'), updatedAt: observableValue('test.updatedAt', new Date()), status: observableValue('test.status', 0), @@ -73,8 +73,7 @@ function makeAgentSession(opts: { isRead: observableValue('test.isRead', true), lastTurnEnd: observableValue('test.lastTurnEnd', undefined), description: observableValue('test.description', undefined), - pullRequestUri: observableValue('test.pullRequestUri', undefined), - pullRequestStateIcon: observableValue('test.pullRequestStateIcon', undefined), + pullRequest: observableValue('test.pullRequest', undefined), }; } @@ -92,7 +91,7 @@ function makeNonAgentSession(opts: { repository?: URI; worktree?: URI; providerT sessionType: opts.providerType ?? AgentSessionProviders.Local, icon: Codicon.copilot, createdAt: new Date(), - workspace: observableValue('test.workspace', repo ? { label: 'test', icon: Codicon.repo, repositories: [repo] } : undefined), + workspace: observableValue('test.workspace', repo ? { label: 'test', icon: Codicon.repo, repositories: [repo], requiresWorkspaceTrust: false, } : undefined), title: observableValue('test.title', 'Test Session'), updatedAt: observableValue('test.updatedAt', new Date()), status: observableValue('test.status', 0), @@ -104,8 +103,7 @@ function makeNonAgentSession(opts: { repository?: URI; worktree?: URI; providerT isRead: observableValue('test.isRead', true), lastTurnEnd: observableValue('test.lastTurnEnd', undefined), description: observableValue('test.description', undefined), - pullRequestUri: observableValue('test.pullRequestUri', undefined), - pullRequestStateIcon: observableValue('test.pullRequestStateIcon', undefined), + pullRequest: observableValue('test.pullRequest', undefined), }; } diff --git a/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts b/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts index d0918fa9729..9f1083cef72 100644 --- a/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts +++ b/src/vs/sessions/contrib/workspace/browser/workspaceFolderManagement.ts @@ -34,6 +34,7 @@ export class WorkspaceFolderManagementContribution extends Disposable implements super(); this._register(autorun(reader => { const activeSession = this.sessionManagementService.activeSession.read(reader); + activeSession?.workspace.read(reader); this.queue.queue(() => this.updateWorkspaceFoldersForSession(activeSession)); })); }