Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/copilotCLIFolderMru.ts
13405 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 { CancellationToken, Uri } from 'vscode';6import { IGitService } from '../../../../platform/git/common/gitService';7import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';8import { raceTimeout } from '../../../../util/vs/base/common/async';9import { ResourceMap, ResourceSet } from '../../../../util/vs/base/common/map';10import { ChatSessionStatus } from '../../../../vscodeTypes';11import { FolderRepositoryMRUEntry, IChatFolderMruService } from '../../common/folderRepositoryManager';12import { ICopilotCLISessionService } from '../../copilotcli/node/copilotcliSessionService';131415type Mutable<T> = {16-readonly [K in keyof T]: T[K];17};1819export class CopilotCLIFolderMruService implements IChatFolderMruService {20declare _serviceBrand: undefined;21private readonly removedFolders = new ResourceSet();22private cachedEntries: FolderRepositoryMRUEntry[] | undefined = undefined;23constructor(24@ICopilotCLISessionService private readonly sessionService: ICopilotCLISessionService,25@IGitService private readonly gitService: IGitService,26@IWorkspaceService private readonly workspaceService: IWorkspaceService,27) { }2829async getRecentlyUsedFolders(token: CancellationToken): Promise<FolderRepositoryMRUEntry[]> {30const cachedEntries = this.cachedEntries;31const entries = this.getRecentlyUsedFoldersImpl(token).then(entries => {32this.cachedEntries = entries;33return entries;34});3536return (cachedEntries ? cachedEntries : await entries).filter(e => {37if (this.removedFolders.has(e.folder)) {38return false;39}40return true;41});42}4344async getRecentlyUsedFoldersImpl(token: CancellationToken): Promise<FolderRepositoryMRUEntry[]> {45const mruEntries = new ResourceMap<Mutable<FolderRepositoryMRUEntry>>();4647// We're getting MRU, don't delay session retrieve by more than 5s48const sessions = await raceTimeout(this.sessionService.getAllSessions(token), 5_000);4950for (const session of (sessions ?? [])) {51if (!session.workingDirectory) {52continue;53}54if (session.workingDirectory.path.includes('.worktrees/copilot-')) {55continue;56}57const isActive = session.status === ChatSessionStatus.InProgress;58const lastAccessed = session.timing?.lastRequestEnded ?? session.timing?.endTime ?? session.timing?.lastRequestStarted ?? session.timing?.startTime ?? (isActive ? Date.now() : 0);59mruEntries.set(session.workingDirectory, {60folder: session.workingDirectory,61repository: undefined,62lastAccessed,63});64}6566// Add recent git repositories67for (const repo of this.gitService.getRecentRepositories()) {68if (repo.rootUri.path.includes('.worktrees/copilot-')) {69continue;70}71const existingEntry = mruEntries.get(repo.rootUri);72if (existingEntry) {73existingEntry.lastAccessed = Math.max(existingEntry.lastAccessed, repo.lastAccessTime);74existingEntry.repository = repo.rootUri;75continue;76}77mruEntries.set(repo.rootUri, {78folder: repo.rootUri,79repository: repo.rootUri,80lastAccessed: repo.lastAccessTime,81});82}8384// If in mult-root folder add the folders as well, but on top.85for (const folder of this.workspaceService.getWorkspaceFolders()) {86const existingEntry = mruEntries.get(folder);87if (existingEntry) {88continue;89}90mruEntries.set(folder, {91folder: folder,92repository: undefined,93lastAccessed: Date.now(),94});95}9697return Array.from(mruEntries.values())98.sort((a, b) => b.lastAccessed - a.lastAccessed);99}100101async deleteRecentlyUsedFolder(folder: Uri): Promise<void> {102this.removedFolders.add(folder);103}104}105106107