Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/vs/sessions/common/agentHostSessionWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export function agentHostSessionWorkspaceKey(workspace: ISessionWorkspace | unde
const repo = folder.gitRepository;
return [
workspace.label,
extUri.getComparisonKey(folder.uri),
extUri.getComparisonKey(folder.root),
folder.workingDirectory ? extUri.getComparisonKey(folder.workingDirectory) : '',
repo?.branchName ?? '',
repo?.baseBranchName ?? '',
Expand Down Expand Up @@ -113,7 +113,7 @@ export function buildAgentHostSessionWorkspace(project: IAgentHostSessionProject
icon: Codicon.repo,
group: options.group,
folders: [{
uri: project.uri,
root: project.uri,
workingDirectory: workingDirectory ?? project.uri,
name: project.displayName,
description: options.description,
Expand All @@ -136,7 +136,7 @@ export function buildAgentHostSessionWorkspace(project: IAgentHostSessionProject
icon: options.fallbackIcon,
group: options.group,
folders: [{
uri: workingDirectory,
root: workingDirectory,
workingDirectory,
name: folderName,
description: options.description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ class NewSession extends Disposable {

constructor(ctx: INewSessionConstructionContext) {
super();
const workspaceUri = ctx.workspace.folders[0]?.uri;
const workspaceUri = ctx.workspace.folders[0]?.root;
if (!workspaceUri) {
throw new Error('Workspace has no repository URI');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export class LocalAgentHostSessionsProvider extends BaseAgentHostSessionsProvide
group: SESSION_WORKSPACE_GROUP_LOCAL,
icon: Codicon.folder,
folders: [{
uri: repositoryUri,
root: repositoryUri,
workingDirectory: repositoryUri,
name: folderName,
description: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ suite('LocalAgentHostSessionsProvider', () => {
assert.ok(ws, 'resolveWorkspace should resolve file:// URIs');
assert.strictEqual(ws.label, 'project [Local]');
assert.strictEqual(ws.folders.length, 1);
assert.strictEqual(ws.folders[0].uri.toString(), uri.toString());
assert.strictEqual(ws.folders[0].root.toString(), uri.toString());
assert.strictEqual(ws.requiresWorkspaceTrust, true);
});

Expand Down Expand Up @@ -555,7 +555,7 @@ suite('LocalAgentHostSessionsProvider', () => {
const workspace = provider.getSessions()[0].workspace.get();
assert.deepStrictEqual({
label: workspace?.label,
repository: workspace?.folders[0]?.uri.toString(),
repository: workspace?.folders[0]?.root.toString(),
workingDirectory: workspace?.folders[0]?.workingDirectory?.toString(),
}, {
label: 'vscode [Local]',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class ApplyChangesToParentRepoAction extends Action2 {
}

const worktreeRoot = folder.gitRepository.workTreeUri;
const repoRoot = folder.uri;
const repoRoot = folder.root;

const openFolderAction = toAction({
id: 'applyChangesToParentRepo.openFolder',
Expand Down
4 changes: 2 additions & 2 deletions src/vs/sessions/contrib/changes/browser/changesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ export class ChangesViewPane extends ViewPane {
const activeSession = this.sessionManagementService.activeSession.get();
const folder = activeSession?.workspace.get()?.folders[0];
const workspaceFolderUri = folder?.workingDirectory;
if (!folder?.uri || !workspaceFolderUri) {
if (!folder?.root || !workspaceFolderUri) {
return undefined;
}

Expand Down Expand Up @@ -998,7 +998,7 @@ export class ChangesViewPane extends ViewPane {
// Pass in the tree root to be used to compute the label description
const activeSession = this.sessionManagementService.activeSession.get();
const folder = activeSession?.workspace.get()?.folders[0];
return folder?.uri.scheme === GITHUB_REMOTE_FILE_SCHEME
return folder?.root.scheme === GITHUB_REMOTE_FILE_SCHEME
? URI.from({ scheme: Schemas.copilotPr, path: '/' })
: folder?.workingDirectory;
})],
Expand Down
103 changes: 25 additions & 78 deletions src/vs/sessions/contrib/changes/browser/changesViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import { isWeb } from '../../../../base/common/platform.js';
import { isEqual } from '../../../../base/common/resources.js';
import { URI } from '../../../../base/common/uri.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js';
import { IChatSessionFileChange2, IChatSessionItemMetadata } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
import { IChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
import { GitDiffChange, IGitService } from '../../../../workbench/contrib/git/common/gitService.js';
import { COPILOT_CLOUD_SESSION_TYPE, gitHubInfoEqual, IGitHubInfo, ISessionFileChange } from '../../../services/sessions/common/session.js';
import { ISessionsManagementService } from '../../../services/sessions/common/sessionsManagement.js';
Expand Down Expand Up @@ -90,7 +89,6 @@ export class ChangesViewModel extends Disposable {
readonly activeSessionStateObs: IObservable<ActiveSessionState | undefined>;
readonly activeSessionIsLoadingObs: IObservable<boolean>;

private _activeSessionMetadataObs!: IObservable<IChatSessionItemMetadata | undefined>;
private _activeSessionAllChangesPromiseObs!: IObservableWithChange<IObservable<IChatSessionFileChange2[] | undefined>>;
private _activeSessionLastTurnChangesPromiseObs!: IObservableWithChange<IObservable<IChatSessionFileChange2[] | undefined>>;
private _activeSessionUncommittedChangesPromiseObs!: IObservableWithChange<IObservable<IChatSessionFileChange2[] | undefined>>;
Expand All @@ -114,7 +112,6 @@ export class ChangesViewModel extends Disposable {

constructor(
@IAgentFeedbackService private readonly agentFeedbackService: IAgentFeedbackService,
@IAgentSessionsService private readonly agentSessionsService: IAgentSessionsService,
@ICodeReviewService private readonly codeReviewService: ICodeReviewService,
@IGitHubService private readonly gitHubService: IGitHubService,
@IGitService private readonly gitService: IGitService,
Expand All @@ -140,27 +137,16 @@ export class ChangesViewModel extends Disposable {
return activeSession?.isArchived.read(reader) === true;
});

// Active session metadata
this._activeSessionMetadataObs = this._getActiveSessionMetadata();

// Active session has git repository
this.activeSessionHasGitRepositoryObs = derived(reader => {
const sessionType = this.activeSessionTypeObs.read(reader);
const metadata = this._activeSessionMetadataObs.read(reader);
if (sessionType === COPILOT_CLOUD_SESSION_TYPE || metadata?.repositoryPath !== undefined) {
if (sessionType === COPILOT_CLOUD_SESSION_TYPE) {
return true;
}

// Fall back to reading details from repo on the session management service session
const activeSession = this.sessionManagementService.activeSession.read(reader);
const workspace = activeSession?.workspace.read(reader);
const folder = workspace?.folders[0];
return folder !== undefined && (
folder.gitRepository?.uncommittedChanges !== undefined ||
folder.gitRepository?.incomingChanges !== undefined ||
folder.gitRepository?.outgoingChanges !== undefined ||
folder.gitRepository?.upstreamBranchName !== undefined
);
return workspace?.folders[0].gitRepository !== undefined;
});
Comment thread
lszomoru marked this conversation as resolved.

// Active session first checkpoint ref
Expand Down Expand Up @@ -230,33 +216,6 @@ export class ChangesViewModel extends Disposable {
this.viewModeObs = observableValue<ChangesViewMode>(this, initialMode);
}

private _getActiveSessionMetadata(): IObservable<IChatSessionItemMetadata | undefined> {
const sessionsChangedSignal = observableSignalFromEvent(this,
this.sessionManagementService.onDidChangeSessions);

const sessionMetadata = derivedObservableWithCache<IChatSessionItemMetadata | undefined>(this, (reader, lastValue) => {
const sessionResource = this.activeSessionResourceObs.read(reader);
if (!sessionResource) {
return undefined;
}

sessionsChangedSignal.read(reader);
const model = this.agentSessionsService.getSession(sessionResource);
if (model === undefined) {
// This occurs when the untitled session is committed. In order
// to avoid flickering of the toolbar, we keep the old metadata
// until the new metadata is available.
return lastValue;
}

return model.metadata;
});

return derivedOpts<IChatSessionItemMetadata | undefined>({ equalsFn: structuralEquals }, reader => {
return sessionMetadata.read(reader);
});
}

private _getActiveSessionChanges(): IObservable<readonly ISessionFileChange[]> {
const gitHubInfoObs = derivedOpts<IGitHubInfo | undefined>(
{ equalsFn: gitHubInfoEqual },
Expand All @@ -275,24 +234,16 @@ export class ChangesViewModel extends Disposable {
});

const activeSessionRepositoryPathObs = derived(reader => {
const metadata = this._activeSessionMetadataObs.read(reader);
const repositoryPath = metadata?.repositoryPath as string | undefined;
const worktreePath = metadata?.worktreePath as string | undefined;
const workingDirectoryPath = metadata?.workingDirectoryPath as string | undefined;

return worktreePath ?? repositoryPath ?? workingDirectoryPath;
const activeSession = this.sessionManagementService.activeSession.read(reader);
const gitRepository = activeSession?.workspace.read(reader)?.folders[0].gitRepository;
return gitRepository?.workTreeUri ?? gitRepository?.uri;
});

// Uncommitted changes
const activeSessionUncommittedChangesCountObs = derived(reader => {
const sessionMetadata = this._activeSessionMetadataObs.read(reader);
const uncommittedChanges = sessionMetadata?.uncommittedChanges as number | undefined;

const activeSession = this.sessionManagementService.activeSession.read(reader);
const workspace = activeSession?.workspace.read(reader);
const workspaceFolder = workspace?.folders[0];

return uncommittedChanges ?? workspaceFolder?.gitRepository?.uncommittedChanges;
const gitRepository = activeSession?.workspace.read(reader)?.folders[0].gitRepository;
return gitRepository?.uncommittedChanges ?? 0;
});

this._activeSessionUncommittedChangesPromiseObs = derived(reader => {
Expand Down Expand Up @@ -433,42 +384,38 @@ export class ChangesViewModel extends Disposable {
return lastValue;
}

const sessionMetadata = this._activeSessionMetadataObs.read(reader);
const activeSession = this.sessionManagementService.activeSession.read(reader);
const activeSessionChanges = activeSession?.changes.read(reader) ?? [];
const workspace = activeSession?.workspace.read(reader);

// Session state
const workspaceFolder = workspace?.folders[0];
const gitRepo = workspaceFolder?.gitRepository;
const gitRepository = workspaceFolder?.gitRepository;
const hasGitRepository = this.activeSessionHasGitRepositoryObs.read(reader);
const branchName = gitRepo?.branchName ??
(sessionMetadata?.branchName ?? sessionMetadata?.branch) as string | undefined;
const baseBranchName = gitRepo?.baseBranchName
?? (sessionMetadata?.baseBranchName ?? sessionMetadata?.baseBranch) as string | undefined;

// Fall back to reading details from repo on the session management service session
const isMergeBaseBranchProtected = gitRepo?.baseBranchProtected
?? (sessionMetadata?.baseBranchProtected as boolean | undefined);
const isolationMode = gitRepo?.workTreeUri === undefined

const branchName = gitRepository?.branchName;
const baseBranchName = gitRepository?.baseBranchName;

const isMergeBaseBranchProtected = gitRepository?.baseBranchProtected;
const isolationMode = gitRepository?.workTreeUri === undefined
? IsolationMode.Workspace
: IsolationMode.Worktree;

// Pull request state
const gitHubInfo = gitRepo?.gitHubInfo.read(reader);
const gitHubInfo = gitRepository?.gitHubInfo.read(reader);
const hasPullRequest = gitHubInfo?.pullRequest?.uri !== undefined;
const hasOpenPullRequest = hasPullRequest &&
(gitHubInfo.pullRequest.icon?.id === Codicon.gitPullRequestDraft.id ||
gitHubInfo.pullRequest.icon?.id === Codicon.gitPullRequest.id);

// Fall back to reading details from repo on the session management service session
const hasGitHubRemote = gitRepo?.hasGitHubRemote ?? (sessionMetadata?.hasGitHubRemote as boolean | undefined) ?? false;
const upstreamBranchName = gitRepo?.upstreamBranchName ?? (sessionMetadata?.upstreamBranchName as string | undefined);
const incomingChanges = gitRepo?.incomingChanges ?? (sessionMetadata?.incomingChanges as number | undefined) ?? 0;
const outgoingChanges = gitRepo?.outgoingChanges ?? (sessionMetadata?.outgoingChanges as number | undefined) ?? 0;
const uncommittedChanges = gitRepo?.uncommittedChanges ?? (sessionMetadata?.uncommittedChanges as number | undefined) ?? 0;
// Repository state
const hasGitHubRemote = gitRepository?.hasGitHubRemote ?? false;
const upstreamBranchName = gitRepository?.upstreamBranchName;
const incomingChanges = gitRepository?.incomingChanges ?? 0;
const outgoingChanges = gitRepository?.outgoingChanges ?? 0;
const uncommittedChanges = gitRepository?.uncommittedChanges ?? 0;
const hasBranchChanges = activeSessionChanges.length > 0;
const hasGitOperationInProgress = gitRepo?.hasGitOperationInProgress ?? (sessionMetadata?.hasGitOperationInProgress as boolean | undefined) ?? false;
const hasGitOperationInProgress = gitRepository?.hasGitOperationInProgress ?? false;

return {
isolationMode,
Expand Down Expand Up @@ -555,8 +502,8 @@ export class ChangesViewModel extends Disposable {
});
}

private async _getRepositoryChanges(repositoryPath: string, firstCheckpointRef: string, lastCheckpointRef: string | undefined): Promise<IChatSessionFileChange2[] | undefined> {
const repository = await this.gitService.openRepository(URI.file(repositoryPath));
private async _getRepositoryChanges(uri: URI, firstCheckpointRef: string, lastCheckpointRef: string | undefined): Promise<IChatSessionFileChange2[] | undefined> {
const repository = await this.gitService.openRepository(uri);
const ref = lastCheckpointRef
? `${firstCheckpointRef}..${lastCheckpointRef}`
: firstCheckpointRef;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ export class SessionsAICustomizationWorkspaceService implements IAICustomization
async commitFiles(_projectRoot: URI, fileUris: URI[]): Promise<void> {
const session = this.sessionsService.activeSession.get();
const folder = session?.workspace.get()?.folders[0];
if (!folder?.uri) {
if (!folder?.root) {
return;
}

for (const fileUri of fileUris) {
await this.commitFileToRepos(fileUri, folder.uri, folder.workingDirectory);
await this.commitFileToRepos(fileUri, folder.root, folder.workingDirectory);
}
}

Expand All @@ -140,12 +140,12 @@ export class SessionsAICustomizationWorkspaceService implements IAICustomization
async deleteFiles(_projectRoot: URI, fileUris: URI[]): Promise<void> {
const session = this.sessionsService.activeSession.get();
const folder = session?.workspace.get()?.folders[0];
if (!folder?.uri) {
if (!folder?.root) {
return;
}

for (const fileUri of fileUris) {
await this.commitDeletionToRepos(fileUri, folder.uri, folder.workingDirectory);
await this.commitDeletionToRepos(fileUri, folder.root, folder.workingDirectory);
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/vs/sessions/contrib/chat/browser/newChatViewPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class NewChatWidget extends Disposable {
this._register(this._workspacePicker.onDidSelectWorkspace(async workspace => {
if (workspace) {
const selectedSessionType = this._newChatInput.sessionTypePicker.selectedType;
const validSessionTypes = this.sessionsProvidersService.getProvider(workspace.providerId)?.getSessionTypes(workspace.workspace.folders[0].uri);
const validSessionTypes = this.sessionsProvidersService.getProvider(workspace.providerId)?.getSessionTypes(workspace.workspace.folders[0].root);
const validSessionType = selectedSessionType ? validSessionTypes?.find(type => type.id === selectedSessionType) : validSessionTypes?.[0];
await this._onWorkspaceSelected(workspace, validSessionType?.id);
} else {
Expand Down Expand Up @@ -171,7 +171,7 @@ class NewChatWidget extends Disposable {

private _createNewSession(selection: IWorkspaceSelection, sessionTypeId: string | undefined): void {
const provider = this.sessionsProvidersService.getProviders().find(p => p.id === selection.providerId);
const repoUri = selection.workspace.folders[0].uri;
const repoUri = selection.workspace.folders[0].root;

// Drop the carried-over sessionTypeId if it doesn't apply to this provider —
// happens when the picker upgrades to a different provider after restore and
Expand Down Expand Up @@ -212,7 +212,7 @@ class NewChatWidget extends Disposable {
* Returns the workspace URI for the context picker based on the current workspace selection.
*/
private _getContextFolderUri(): URI | undefined {
return this._workspacePicker.selectedProject?.workspace.folders[0]?.uri;
return this._workspacePicker.selectedProject?.workspace.folders[0]?.root;
}

private _renderWorkspacePicker(container: HTMLElement): IDisposable {
Expand Down Expand Up @@ -379,7 +379,7 @@ class NewChatWidget extends Disposable {
}

if (selection.workspace.requiresWorkspaceTrust) {
const workspaceUri = selection.workspace.folders[0]?.uri;
const workspaceUri = selection.workspace.folders[0]?.root;
if (workspaceUri && !await this._requestFolderTrust(workspaceUri)) {
return;
}
Expand Down
Loading
Loading