From 9a795ccbb09d99a420dcbedf6d6fcfc2e663434f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 06:35:09 +0000 Subject: [PATCH 1/2] Initial plan From cd474c488f431aa6e1afea0d6b029c472dc7d75c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 06:43:39 +0000 Subject: [PATCH 2/2] Move event handlers from registerTerminalInstanceWithToolSession to constructor to avoid duplicate listeners Co-authored-by: osortega <48293249+osortega@users.noreply.github.com> --- .../chat/browser/terminalChatService.ts | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts index 6e176da9fd62d..5785eb2b13c58 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts @@ -66,6 +66,30 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ this._hasHiddenToolTerminalContext = TerminalChatContextKeys.hasHiddenChatTerminals.bindTo(this._contextKeyService); this._restoreFromStorage(); + + // Register session disposal listener once in constructor to avoid duplicate listeners + this._register(this._chatService.onDidDisposeSession(e => { + for (const resource of e.sessionResource) { + const sessionId = LocalChatSessionUri.parseLocalSessionId(resource); + if (sessionId) { + // Clean up session auto approval state + this._sessionAutoApprovalEnabled.delete(sessionId); + + // Clean up terminal instance mappings if the session ID matches a tool session + const instance = this._terminalInstancesByToolSessionId.get(sessionId); + if (instance) { + this._terminalInstancesByToolSessionId.delete(sessionId); + this._toolSessionIdByTerminalInstance.delete(instance); + this._terminalInstanceListenersByToolSessionId.deleteAndDispose(sessionId); + this._persistToStorage(); + this._updateHasToolTerminalContextKeys(); + } + } + } + })); + + // Update context keys when terminal instances change (registered once) + this._register(this._terminalService.onDidChangeInstances(() => this._updateHasToolTerminalContextKeys())); } registerTerminalInstanceWithToolSession(terminalToolSessionId: string | undefined, instance: ITerminalInstance): void { @@ -84,26 +108,6 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ this._updateHasToolTerminalContextKeys(); })); - this._register(this._chatService.onDidDisposeSession(e => { - for (const resource of e.sessionResource) { - if (LocalChatSessionUri.parseLocalSessionId(resource) === terminalToolSessionId) { - this._terminalInstancesByToolSessionId.delete(terminalToolSessionId); - this._toolSessionIdByTerminalInstance.delete(instance); - this._terminalInstanceListenersByToolSessionId.deleteAndDispose(terminalToolSessionId); - // Clean up session auto approval state - const sessionId = LocalChatSessionUri.parseLocalSessionId(resource); - if (sessionId) { - this._sessionAutoApprovalEnabled.delete(sessionId); - } - this._persistToStorage(); - this._updateHasToolTerminalContextKeys(); - } - } - })); - - // Update context keys when terminal instances change (including when terminals are created, disposed, revealed, or hidden) - this._register(this._terminalService.onDidChangeInstances(() => this._updateHasToolTerminalContextKeys())); - if (isNumber(instance.shellLaunchConfig?.attachPersistentProcess?.id) || isNumber(instance.persistentProcessId)) { this._persistToStorage(); }