mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-31 00:10:04 +08:00
Add event emitters for workspace folder and worktree changes (#312288)
* Add event emitters for workspace folder and worktree changes; improve cache management Co-authored-by: Copilot <copilot@github.com> * Update extensions/copilot/src/extension/chatSessions/common/chatSessionWorktreeService.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update extensions/copilot/src/extension/chatSessions/vscode-node/copilotCLIChatSessions.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Enhance chat session item handling by eagerly including changes for refreshed sessions to improve UX Co-authored-by: Copilot <copilot@github.com> * Change defaults * Fixes Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4677,7 +4677,7 @@
|
||||
},
|
||||
"github.copilot.chat.cli.lazyLoadSessionItem.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"default": true,
|
||||
"markdownDescription": "%github.copilot.config.cli.lazyLoadSessionItem.enabled%",
|
||||
"tags": [
|
||||
"advanced"
|
||||
|
||||
@@ -17,6 +17,10 @@ export const IChatSessionWorkspaceFolderService = createServiceIdentifier<IChatS
|
||||
*/
|
||||
export interface IChatSessionWorkspaceFolderService {
|
||||
readonly _serviceBrand: undefined;
|
||||
/**
|
||||
* Triggered when the set of changes in a session workspace folder has changed.
|
||||
*/
|
||||
onDidChangeWorkspaceFolderChanges: vscode.Event<{ sessionId: string }>;
|
||||
deleteTrackedWorkspaceFolder(sessionId: string): Promise<void>;
|
||||
/**
|
||||
* Track workspace folder selection for a session (for folders without git repos in multi-root workspaces)
|
||||
|
||||
@@ -59,6 +59,13 @@ export const IChatSessionWorktreeService = createServiceIdentifier<IChatSessionW
|
||||
|
||||
export interface IChatSessionWorktreeService {
|
||||
readonly _serviceBrand: undefined;
|
||||
/**
|
||||
* Triggered when cached worktree changes for a session are invalidated and should be refreshed.
|
||||
*
|
||||
* This event does not guarantee that the underlying set of changes was updated directly; callers
|
||||
* should re-query {@link getWorktreeChanges} when it fires.
|
||||
*/
|
||||
onDidChangeWorktreeChanges: vscode.Event<{ sessionId: string }>;
|
||||
|
||||
createWorktree(repositoryPath: vscode.Uri, stream?: vscode.ChatResponseStream, baseBranch?: string, branchName?: string): Promise<ChatSessionWorktreeProperties | undefined>;
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ export class ChatSessionRepositoryTracker extends Disposable {
|
||||
private readonly repositories = new DisposableResourceMap();
|
||||
|
||||
constructor(
|
||||
private readonly sessionItemProvider: ICopilotCLIChatSessionItemProvider,
|
||||
// This is only required in non-controller code paths.
|
||||
private readonly sessionItemProvider: ICopilotCLIChatSessionItemProvider | undefined,
|
||||
@IChatSessionWorktreeService private readonly worktreeService: IChatSessionWorktreeService,
|
||||
@IChatSessionWorkspaceFolderService private readonly workspaceFolderService: IChatSessionWorkspaceFolderService,
|
||||
@IGitService private readonly gitService: IGitService,
|
||||
@@ -69,23 +70,7 @@ export class ChatSessionRepositoryTracker extends Disposable {
|
||||
}
|
||||
|
||||
private async onDidChangeRepositoryState(uri: vscode.Uri): Promise<void> {
|
||||
this.logService.trace(`[ChatSessionRepositoryTracker][onDidChangeRepositoryState] Repository state changed for ${uri.toString()}. Updating session properties.`);
|
||||
|
||||
const sessionIds = await this.metadataStore.getSessionIdsForFolder(uri);
|
||||
const workspaceSessionIds = this.workspaceFolderService.clearWorkspaceChanges(uri);
|
||||
sessionIds.push(...workspaceSessionIds);
|
||||
await Promise.all(Array.from(new Set(sessionIds)).map(async sessionId => {
|
||||
// Worktree
|
||||
const worktreeProperties = await this.worktreeService.getWorktreeProperties(sessionId);
|
||||
if (worktreeProperties) {
|
||||
await this.worktreeService.setWorktreeProperties(sessionId, {
|
||||
...worktreeProperties,
|
||||
changes: undefined
|
||||
});
|
||||
}
|
||||
}));
|
||||
await this.sessionItemProvider.refreshSession({ reason: 'update', sessionIds });
|
||||
this.logService.trace(`[ChatSessionRepositoryTracker][onDidChangeRepositoryState] Updated session properties for worktree ${uri.toString()}.`);
|
||||
await clearChangesCacheForAffectedSessions(uri, [], this.logService, this.metadataStore, this.workspaceFolderService, this.worktreeService, this.sessionItemProvider);
|
||||
}
|
||||
|
||||
private disposeRepositoryWatcher(uri: vscode.Uri): void {
|
||||
@@ -102,3 +87,32 @@ export class ChatSessionRepositoryTracker extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the cache for sessions affected by a repository change, and triggers a refresh of those sessions.
|
||||
* You can optionally provide a list of sessions that should not be refreshed.
|
||||
* E.g. if you know that those sessions are not affected or are already up to date, you can exclude them from the refresh to avoid unnecessary work.
|
||||
*/
|
||||
export async function clearChangesCacheForAffectedSessions(folder: vscode.Uri, sessionsToIgnore: string[], logService: ILogService, metadataStore: IChatSessionMetadataStore, workspaceFolderService: IChatSessionWorkspaceFolderService, worktreeService: IChatSessionWorktreeService, sessionItemProvider?: ICopilotCLIChatSessionItemProvider): Promise<void> {
|
||||
logService.trace(`[ChatSessionRepositoryTracker][onDidChangeRepositoryState] Repository state changed for ${folder.toString()}. Updating session properties.`);
|
||||
|
||||
const sessionIds = metadataStore.getSessionIdsForFolder(folder).filter(id => !sessionsToIgnore.includes(id));
|
||||
const workspaceSessionIds = workspaceFolderService.clearWorkspaceChanges(folder).filter(id => !sessionsToIgnore.includes(id));
|
||||
sessionIds.forEach(id => workspaceFolderService.clearWorkspaceChanges(id));
|
||||
sessionIds.push(...workspaceSessionIds);
|
||||
await Promise.all(Array.from(new Set(sessionIds)).map(async sessionId => {
|
||||
// Worktree
|
||||
const worktreeProperties = await worktreeService.getWorktreeProperties(sessionId);
|
||||
if (worktreeProperties) {
|
||||
await worktreeService.setWorktreeProperties(sessionId, {
|
||||
...worktreeProperties,
|
||||
changes: undefined
|
||||
});
|
||||
}
|
||||
}));
|
||||
// Will be passed in non-controller code paths.
|
||||
if (sessionItemProvider) {
|
||||
await sessionItemProvider.refreshSession({ reason: 'update', sessionIds });
|
||||
}
|
||||
logService.trace(`[ChatSessionRepositoryTracker][onDidChangeRepositoryState] Updated session properties for worktree ${folder.toString()}.`);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ export class ChatSessionWorkspaceFolderService extends Disposable implements ICh
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private static readonly EMPTY_TREE_OBJECT = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
||||
private readonly _onDidChangeWorkspaceFolderChanges = this._register(new vscode.EventEmitter<{ sessionId: string }>());
|
||||
readonly onDidChangeWorkspaceFolderChanges = this._onDidChangeWorkspaceFolderChanges.event;
|
||||
|
||||
private readonly workspaceState = new Map<string, WorkspaceFolderEntry>();
|
||||
private readonly sessionRepoKeys = new Map<string, string>();
|
||||
@@ -311,6 +313,7 @@ export class ChatSessionWorkspaceFolderService extends Disposable implements ICh
|
||||
if (repoKey) {
|
||||
this.workspaceFolderChanges.delete(repoKey);
|
||||
}
|
||||
this._onDidChangeWorkspaceFolderChanges.fire({ sessionId });
|
||||
}
|
||||
|
||||
getAssociatedSessions(folderUri: vscode.Uri): string[] {
|
||||
|
||||
@@ -29,7 +29,8 @@ export class ChatSessionWorktreeService extends Disposable implements IChatSessi
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private _sessionWorktrees: Map<string, string | ChatSessionWorktreeProperties> = new Map();
|
||||
|
||||
private readonly _onDidChangeWorktreeChanges = this._register(new vscode.EventEmitter<{ sessionId: string }>());
|
||||
readonly onDidChangeWorktreeChanges = this._onDidChangeWorktreeChanges.event;
|
||||
constructor(
|
||||
@IAgentSessionsWorkspace private readonly agentSessionsWorkspace: IAgentSessionsWorkspace,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@@ -189,6 +190,10 @@ export class ChatSessionWorktreeService extends Disposable implements IChatSessi
|
||||
async setWorktreeProperties(sessionId: string, properties: ChatSessionWorktreeProperties): Promise<void> {
|
||||
this._sessionWorktrees.set(sessionId, properties);
|
||||
await this.metadataStore.storeWorktreeInfo(sessionId, properties);
|
||||
// If we're explicitly clearing the changes.
|
||||
if ('changes' in properties && !properties.changes) {
|
||||
this._onDidChangeWorktreeChanges.fire({ sessionId });
|
||||
}
|
||||
}
|
||||
|
||||
async getWorktreeRepository(sessionId: string): Promise<RepoContext | undefined> {
|
||||
|
||||
@@ -198,7 +198,7 @@ export class ChatSessionsContrib extends Disposable implements IExtensionContrib
|
||||
));
|
||||
|
||||
const copilotcliChatSessionContentProvider = copilotcliAgentInstaService.createInstance(CopilotCLIChatSessionContentProvider);
|
||||
this._register(copilotcliAgentInstaService.createInstance(ChatSessionRepositoryTracker, copilotcliChatSessionContentProvider));
|
||||
this._register(copilotcliAgentInstaService.createInstance(ChatSessionRepositoryTracker, undefined));
|
||||
const promptResolver = copilotcliAgentInstaService.createInstance(CopilotCLIPromptResolver);
|
||||
const gitService = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(IGitService));
|
||||
const sessionTracker = copilotcliAgentInstaService.invokeFunction(accessor => accessor.get(ICopilotCLISessionTracker));
|
||||
|
||||
@@ -145,6 +145,7 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
@IChatSessionWorkspaceFolderService private readonly _workspaceFolderService: IChatSessionWorkspaceFolderService,
|
||||
@IChatSessionMetadataStore private readonly _metadataStore: IChatSessionMetadataStore,
|
||||
@IWorkspaceService private readonly _workspaceService: IWorkspaceService,
|
||||
@IChatSessionWorktreeService chatSessionWorktreeService: IChatSessionWorktreeService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -180,6 +181,12 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
void refreshSessions();
|
||||
}
|
||||
}));
|
||||
this._register(this._workspaceFolderService.onDidChangeWorkspaceFolderChanges(e => {
|
||||
this.refreshSession({ reason: 'update', sessionId: e.sessionId });
|
||||
}));
|
||||
this._register(chatSessionWorktreeService.onDidChangeWorktreeChanges(e => {
|
||||
this.refreshSession({ reason: 'update', sessionId: e.sessionId });
|
||||
}));
|
||||
controller.newChatSessionItemHandler = async (context) => {
|
||||
const sessionId = this.sessionService.createNewSessionId();
|
||||
const resource = SessionIdForCLI.getResource(sessionId);
|
||||
@@ -217,7 +224,7 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
controller.resolveChatSessionItem = async (item, token) => {
|
||||
const sessionId = SessionIdForCLI.parse(item.resource);
|
||||
const session = await this.sessionService.getSessionItem(sessionId, token);
|
||||
if (!session || token.isCancellationRequested || Array.isArray(item.changes)) {
|
||||
if (!session || token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
const updatedItem = await this.toChatSessionItem(session, { includeChanges: true }, token);
|
||||
@@ -228,7 +235,10 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
controller.items.delete(SessionIdForCLI.getResource(e));
|
||||
}));
|
||||
this._register(this.sessionService.onDidChangeSession(async (e) => {
|
||||
const item = await this.toChatSessionItem(e);
|
||||
// Push path: VS Code uses the item we provide as source of truth and does not
|
||||
// re-invoke `resolveChatSessionItem` for already-visible rows. Include changes
|
||||
// eagerly so the visible row reflects the latest diff info.
|
||||
const item = await this.toChatSessionItem(e, { includeChanges: true });
|
||||
controller.items.add(item);
|
||||
}));
|
||||
this._register(this.sessionService.onDidCreateSession(async (e) => {
|
||||
@@ -236,7 +246,7 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
if (controller.items.get(resource)) {
|
||||
return;
|
||||
}
|
||||
const item = await this.toChatSessionItem(e);
|
||||
const item = await this.toChatSessionItem(e, { includeChanges: true });
|
||||
controller.items.add(item);
|
||||
}));
|
||||
|
||||
@@ -323,14 +333,16 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
await Promise.allSettled(refreshOptions.sessionIds.map(async sessionId => {
|
||||
const item = await this.sessionService.getSessionItem(sessionId, CancellationToken.None);
|
||||
if (item) {
|
||||
const chatSessionItem = await this.toChatSessionItem(item);
|
||||
// Push path — include changes eagerly (see `onDidChangeSession`).
|
||||
const chatSessionItem = await this.toChatSessionItem(item, { includeChanges: true });
|
||||
this.controller.items.add(chatSessionItem);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
const item = await this.sessionService.getSessionItem(refreshOptions.sessionId, CancellationToken.None);
|
||||
if (item) {
|
||||
const chatSessionItem = await this.toChatSessionItem(item);
|
||||
// Push path — include changes eagerly (see `onDidChangeSession`).
|
||||
const chatSessionItem = await this.toChatSessionItem(item, { includeChanges: true });
|
||||
this.controller.items.add(chatSessionItem);
|
||||
}
|
||||
}
|
||||
@@ -359,7 +371,6 @@ export class CopilotCLIChatSessionContentProvider extends Disposable implements
|
||||
if (token.isCancellationRequested) {
|
||||
return item;
|
||||
}
|
||||
|
||||
// We need to get an updated version of worktree properties here because when the
|
||||
// changes are being computed, the worktree properties are also updated with the
|
||||
// repository state which we are passing along through the metadata
|
||||
|
||||
@@ -55,6 +55,7 @@ import { ICopilotCLIChatSessionItemProvider } from './copilotCLIChatSessions';
|
||||
import { ICopilotCLITerminalIntegration, TerminalOpenLocation } from './copilotCLITerminalIntegration';
|
||||
import { CopilotCloudSessionsProvider } from './copilotCloudSessionsProvider';
|
||||
import { convertReferenceToVariable } from '../copilotcli/vscode-node/copilotCLIPromptReferences';
|
||||
import { clearChangesCacheForAffectedSessions } from './chatSessionRepositoryTracker';
|
||||
|
||||
const REPOSITORY_OPTION_ID = 'repository';
|
||||
|
||||
@@ -170,6 +171,14 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
|
||||
|
||||
private readonly _onDidCommitChatSessionItem = this._register(new Emitter<{ original: vscode.ChatSessionItem; modified: vscode.ChatSessionItem }>());
|
||||
public readonly onDidCommitChatSessionItem: Event<{ original: vscode.ChatSessionItem; modified: vscode.ChatSessionItem }> = this._onDidCommitChatSessionItem.event;
|
||||
/**
|
||||
* Session ids that were targeted by an explicit `refreshSession(...)` call and have not yet been
|
||||
* re-provided. The next `provideChatSessionItems` pass eagerly includes `changes` for these
|
||||
* sessions so the visible row reflects the latest diff info — VS Code uses the items returned
|
||||
* from `provideChatSessionItems` as source of truth and does not re-invoke `resolveChatSessionItem`
|
||||
* for already-visible rows. The set is cleared after each `provideChatSessionItems` call.
|
||||
*/
|
||||
private readonly pendingChangeIncludeIds = new Set<string>();
|
||||
|
||||
public resolveChatSessionItem?: (item: vscode.ChatSessionItem, token: vscode.CancellationToken) => Promise<vscode.ChatSessionItem | undefined>;
|
||||
|
||||
@@ -199,7 +208,7 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
|
||||
this.resolveChatSessionItem = async (item: vscode.ChatSessionItem, token: vscode.CancellationToken): Promise<vscode.ChatSessionItem | undefined> => {
|
||||
const sessionId = SessionIdForCLI.parse(item.resource);
|
||||
const session = await this.copilotcliSessionService.getSessionItem(sessionId, token);
|
||||
if (!session || token.isCancellationRequested || Array.isArray(item.changes)) {
|
||||
if (!session || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
return this.toChatSessionItem(session, { includeChanges: true }, token);
|
||||
@@ -237,6 +246,17 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
|
||||
|
||||
public async refreshSession(refreshOptions: { reason: 'update'; sessionId: string } | { reason: 'update'; sessionIds: string[] } | { reason: 'delete'; sessionId: string }): Promise<void> {
|
||||
await this.chatSessionMetadataStore.refresh().catch(() => { /* logged inside */ });
|
||||
if (refreshOptions.reason === 'update') {
|
||||
// Mark the targeted sessions so the next `provideChatSessionItems` pass includes
|
||||
// fresh `changes` for them (push path equivalent — see `pendingChangeIncludeIds`).
|
||||
if ('sessionIds' in refreshOptions) {
|
||||
for (const id of refreshOptions.sessionIds) {
|
||||
this.pendingChangeIncludeIds.add(id);
|
||||
}
|
||||
} else {
|
||||
this.pendingChangeIncludeIds.add(refreshOptions.sessionId);
|
||||
}
|
||||
}
|
||||
this._onDidChangeChatSessionItems.fire();
|
||||
}
|
||||
|
||||
@@ -247,7 +267,15 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
|
||||
public async provideChatSessionItems(token: vscode.CancellationToken): Promise<vscode.ChatSessionItem[]> {
|
||||
const stopwatch = new StopWatch();
|
||||
const sessions = await this.copilotcliSessionService.getAllSessions(token);
|
||||
const diskSessions = await Promise.all(sessions.map(async session => this.toChatSessionItem(session)));
|
||||
// Drain the pending set: sessions that were explicitly refreshed get `changes` populated
|
||||
// eagerly so the visible row reflects the latest diff info on this re-provide pass.
|
||||
const pendingIds = new Set(this.pendingChangeIncludeIds);
|
||||
this.pendingChangeIncludeIds.clear();
|
||||
const diskSessions = await Promise.all(sessions.map(async session => this.toChatSessionItem(
|
||||
session,
|
||||
pendingIds.has(session.id) ? { includeChanges: true } : undefined,
|
||||
token,
|
||||
)));
|
||||
|
||||
const count = diskSessions.length;
|
||||
void this.commandExecutionService.executeCommand('setContext', 'github.copilot.chat.cliSessionsEmpty', count === 0);
|
||||
@@ -302,7 +330,6 @@ export class CopilotCLIChatSessionItemProvider extends Disposable implements vsc
|
||||
let changes: vscode.ChatSessionChangedFile[] | undefined;
|
||||
if (!token.isCancellationRequested && (options?.includeChanges || (await this.hasCachedChanges(session.id, worktreeProperties)))) {
|
||||
changes = await this.buildChanges(session.id, worktreeProperties, workingDirectory, token);
|
||||
|
||||
// We need to get an updated version of worktree properties here because when the
|
||||
// changes are being computed, the worktree properties are also updated with the
|
||||
// repository state which we are passing along through the metadata
|
||||
@@ -1656,6 +1683,9 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
|
||||
// is used if worktree isolation is enabled, and auto-commit is disabled or workspace
|
||||
// isolation is enabled.
|
||||
await this.copilotCLIWorktreeCheckpointService.handleRequestCompleted(session.sessionId, request.id);
|
||||
if (workingDirectory) {
|
||||
void clearChangesCacheForAffectedSessions(workingDirectory, [session.sessionId], this.logService, this.chatSessionMetadataStore, this.workspaceFolderService, this.copilotCLIWorktreeManagerService, this.sessionItemProvider).catch(ex => this.logService.error(ex, 'Failed to clear changes cache after request completion'));
|
||||
}
|
||||
}
|
||||
|
||||
void this.handlePullRequestCreated(session).catch(ex => this.logService.error(ex, 'Failed to handle pull request creation'));
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IChatSessionWorktreeCheckpointService } from '../common/chatSessionWork
|
||||
import { IChatSessionWorktreeService } from '../common/chatSessionWorktreeService';
|
||||
import { getWorkingDirectory, isIsolationEnabled, IWorkspaceInfo } from '../common/workspaceInfo';
|
||||
import { IPullRequestDetectionService } from './pullRequestDetectionService';
|
||||
import { clearChangesCacheForAffectedSessions } from './chatSessionRepositoryTracker';
|
||||
|
||||
export interface ISessionRequestLifecycle {
|
||||
readonly _serviceBrand: undefined;
|
||||
@@ -133,6 +134,11 @@ export class SessionRequestLifecycle extends Disposable implements ISessionReque
|
||||
// is used if worktree isolation is enabled, and auto-commit is disabled or workspace
|
||||
// isolation is enabled.
|
||||
await this.checkpointService.handleRequestCompleted(sessionId, request.id);
|
||||
|
||||
// Clear the changes (diff) cache for sessions associated with the same folder.
|
||||
if (workingDirectory) {
|
||||
void clearChangesCacheForAffectedSessions(workingDirectory, [sessionId], this.logService, this.metadataStore, this.workspaceFolderService, this.worktreeService).catch(ex => this.logService.error(ex, 'Failed to clear changes cache after request completion'));
|
||||
}
|
||||
}
|
||||
|
||||
this.prDetectionService.handlePullRequestCreated(sessionId, session.createdPullRequestUrl);
|
||||
|
||||
@@ -92,11 +92,15 @@ class TestWorktreeService extends mock<IChatSessionWorktreeService>() {
|
||||
override getWorktreeProperties = vi.fn(async (_sessionId: string | vscode.Uri): Promise<ChatSessionWorktreeProperties | undefined> => undefined);
|
||||
override setWorktreeProperties = vi.fn(async () => { });
|
||||
override getWorktreeChanges = vi.fn(async () => []);
|
||||
override hasCachedChanges = vi.fn(async () => false);
|
||||
override onDidChangeWorktreeChanges = Event.None;
|
||||
}
|
||||
|
||||
class TestWorkspaceFolderService extends mock<IChatSessionWorkspaceFolderService>() {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
override getWorkspaceChanges = vi.fn(async () => []);
|
||||
override hasCachedChanges = vi.fn(async () => false);
|
||||
override onDidChangeWorkspaceFolderChanges = Event.None;
|
||||
}
|
||||
|
||||
class TestFolderRepositoryManager extends mock<IFolderRepositoryManager>() {
|
||||
@@ -206,6 +210,7 @@ function createProvider() {
|
||||
workspaceFolderService,
|
||||
metadataStore,
|
||||
new NullWorkspaceService(),
|
||||
worktreeService,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -614,7 +614,7 @@ export namespace ConfigKey {
|
||||
export const CLIPlanExitModeEnabled = defineSetting<boolean>('chat.cli.planExitMode.enabled', ConfigType.Simple, true);
|
||||
export const CLIAutoModelEnabled = defineSetting<boolean>('chat.cli.autoModel.enabled', ConfigType.Simple, true);
|
||||
export const CLIPlanCommandEnabled = defineSetting<boolean>('chat.cli.planCommand.enabled', ConfigType.Simple, true);
|
||||
export const CLIChatLazyLoadSessionItem = defineSetting<boolean>('chat.cli.lazyLoadSessionItem.enabled', ConfigType.Simple, false);
|
||||
export const CLIChatLazyLoadSessionItem = defineSetting<boolean>('chat.cli.lazyLoadSessionItem.enabled', ConfigType.Simple, true);
|
||||
export const CLIAIGenerateBranchNames = defineSetting<boolean>('chat.cli.aiGenerateBranchNames.enabled', ConfigType.Simple, true);
|
||||
export const CLIForkSessionsEnabled = defineSetting<boolean>('chat.cli.forkSessions.enabled', ConfigType.Simple, true);
|
||||
export const CLIMCPServerEnabled = defineAndMigrateSetting<boolean | undefined>('chat.advanced.cli.mcp.enabled', 'chat.cli.mcp.enabled', true);
|
||||
|
||||
@@ -282,6 +282,7 @@ async function registerChatServices(testingServiceCollection: TestingServiceColl
|
||||
async getWorkspaceChanges() { return undefined; },
|
||||
async hasCachedChanges() { return false; },
|
||||
clearWorkspaceChanges() { return []; },
|
||||
onDidChangeWorkspaceFolderChanges: () => ({ dispose() { } }),
|
||||
} as IChatSessionWorkspaceFolderService);
|
||||
testingServiceCollection.define(IChatSessionWorktreeService, {
|
||||
_serviceBrand: undefined,
|
||||
@@ -300,6 +301,7 @@ async function registerChatServices(testingServiceCollection: TestingServiceColl
|
||||
async cleanupWorktreeOnArchive() { return { cleaned: false }; },
|
||||
async recreateWorktreeOnUnarchive() { return { recreated: false }; },
|
||||
async hasCachedChanges() { return false; },
|
||||
onDidChangeWorktreeChanges: () => ({ dispose() { } }),
|
||||
} as IChatSessionWorktreeService);
|
||||
testingServiceCollection.define(IPromptVariablesService, new SyncDescriptor(NullPromptVariablesService));
|
||||
testingServiceCollection.define(IChatDebugFileLoggerService, new NullChatDebugFileLoggerService());
|
||||
|
||||
Reference in New Issue
Block a user