From ecf6cc095341c55f77eabf914f1cbba94dfb8e8f Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Fri, 9 Jan 2026 10:18:26 -0800 Subject: [PATCH 1/4] Clear prompt input value when onDidEndShellExecution --- .../commandDetection/promptInputModel.ts | 14 ++++++++++++++ .../browser/mainThreadTerminalShellIntegration.ts | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts index 328f5f941ef82..7d2e18714019d 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts @@ -42,6 +42,12 @@ export interface IPromptInputModel extends IPromptInputModelState { getCombinedString(emptyStringWhenEmpty?: boolean): string; setShellType(shellType?: TerminalShellType): void; + + /** + * Clears the prompt input value. This should be called when the command has finished + * and the value is no longer relevant as editable prompt input. + */ + clearValue(): void; } export interface IPromptInputModelState { @@ -261,6 +267,14 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { this._onDidChangeInput.fire(event); } + /** + * Clears the prompt input value. This should be called when the command has finished + * and the value is no longer relevant as editable prompt input. + */ + clearValue(): void { + this._value = ''; + } + @throttle(0) private _sync() { try { diff --git a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts index 4a46691ae5682..19b17b1880112 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts @@ -98,6 +98,9 @@ export class MainThreadTerminalShellIntegration extends Disposable implements Ma currentCommand = undefined; const instanceId = e.instance.instanceId; instanceDataListeners.get(instanceId)?.dispose(); + // Clear the prompt input value before sending the event to the extension host + // so that subsequent executeCommand calls don't see stale input + e.instance.capabilities.get(TerminalCapability.CommandDetection)?.promptInputModel.clearValue(); // Shell integration C (executed) and D (command finished) sequences should always be in // their own events, so send this immediately. This means that the D sequence will not // be included as it's currently being parsed when the command finished event fires. From f6a4ea1889d6144e1e53a98c2f782c43353246b0 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Fri, 9 Jan 2026 11:44:06 -0800 Subject: [PATCH 2/4] logs to capture manually --- .../capabilities/commandDetection/promptInputModel.ts | 2 ++ .../api/browser/mainThreadTerminalShellIntegration.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts index 7d2e18714019d..28bb1cd86c230 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts @@ -245,8 +245,10 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { private _handleCommandExecuted() { if (this._state === PromptInputState.Execute) { + this._logService.trace('PromptInputModel#_handleCommandExecuted: already in Execute state'); return; } + this._logService.trace('PromptInputModel#_handleCommandExecuted: Inside _handleCommandExecuted but not PromptInputState.Execute yet'); this._cursorIndex = -1; diff --git a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts index 19b17b1880112..cf7782fcebd52 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts @@ -7,6 +7,7 @@ import { Event } from '../../../base/common/event.js'; import { Disposable, toDisposable, type IDisposable } from '../../../base/common/lifecycle.js'; import { TerminalCapability, type ITerminalCommand } from '../../../platform/terminal/common/capabilities/capabilities.js'; import { ExtHostContext, MainContext, type ExtHostTerminalShellIntegrationShape, type MainThreadTerminalShellIntegrationShape } from '../common/extHost.protocol.js'; +import { ILogService } from '../../../platform/log/common/log.js'; import { ITerminalService, type ITerminalInstance } from '../../contrib/terminal/browser/terminal.js'; import { IWorkbenchEnvironmentService } from '../../services/environment/common/environmentService.js'; import { extHostNamedCustomer, type IExtHostContext } from '../../services/extensions/common/extHostCustomers.js'; @@ -21,7 +22,8 @@ export class MainThreadTerminalShellIntegration extends Disposable implements Ma extHostContext: IExtHostContext, @ITerminalService private readonly _terminalService: ITerminalService, @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, - @IExtensionService private readonly _extensionService: IExtensionService + @IExtensionService private readonly _extensionService: IExtensionService, + @ILogService private readonly _logService: ILogService ) { super(); @@ -100,11 +102,13 @@ export class MainThreadTerminalShellIntegration extends Disposable implements Ma instanceDataListeners.get(instanceId)?.dispose(); // Clear the prompt input value before sending the event to the extension host // so that subsequent executeCommand calls don't see stale input - e.instance.capabilities.get(TerminalCapability.CommandDetection)?.promptInputModel.clearValue(); + // e.instance.capabilities.get(TerminalCapability.CommandDetection)?.promptInputModel.clearValue(); + this._logService.trace(`PromptInputModel#_onDidEndTerminalShellExecution# state of promptInputModel is : ${e.instance.capabilities.get(TerminalCapability.CommandDetection)?.promptInputModel.state}`); // Shell integration C (executed) and D (command finished) sequences should always be in // their own events, so send this immediately. This means that the D sequence will not // be included as it's currently being parsed when the command finished event fires. this._proxy.$shellExecutionEnd(instanceId, e.data.command, convertToExtHostCommandLineConfidence(e.data), e.data.isTrusted, e.data.exitCode); + this._logService.trace(`PromptInputModel#_onDidEndTerminalShellExecution# state of promptInputModel after shellExecutionEnd is : ${e.instance.capabilities.get(TerminalCapability.CommandDetection)?.promptInputModel.state}`); })); // Clean up after dispose From 868cbac2a25721f23ead9e0d449935e73a4bd95a Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Fri, 9 Jan 2026 11:56:32 -0800 Subject: [PATCH 3/4] more logs for testing --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index ce934e637ac01..454c45124696d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1008,6 +1008,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Determine whether to send ETX (ctrl+c) before running the command. Only do this when the // command will be executed immediately or when command detection shows the prompt contains text. if (shouldExecute && (!commandDetection || commandDetection.promptInputModel.value.length > 0)) { + this._logService.trace(`PromptInputModel#runCommand: Sending ETX (ctrl+c) before running command`); + this._logService.trace(`PromptInputModel#runCommand: state of promptinputmodel before sending ETX: ${commandDetection ? commandDetection.promptInputModel.state : 'no command detection'}`); + this._logService.trace(`PromptInputModel#runCommand: value of promptinputmodel before sending ETX: ${commandDetection ? commandDetection.promptInputModel.value : 'no command detection'}`); + await this.sendText('\x03', false); // Wait a little before running the command to avoid the sequences being echoed while the ^C // is being evaluated From 10bce4e8050d6e041217d45cbbd9637634f444e9 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Fri, 9 Jan 2026 12:39:58 -0800 Subject: [PATCH 4/4] Use terminal log instead --- .../api/browser/mainThreadTerminalShellIntegration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts index cf7782fcebd52..c4c0fd07ed794 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts @@ -7,12 +7,12 @@ import { Event } from '../../../base/common/event.js'; import { Disposable, toDisposable, type IDisposable } from '../../../base/common/lifecycle.js'; import { TerminalCapability, type ITerminalCommand } from '../../../platform/terminal/common/capabilities/capabilities.js'; import { ExtHostContext, MainContext, type ExtHostTerminalShellIntegrationShape, type MainThreadTerminalShellIntegrationShape } from '../common/extHost.protocol.js'; -import { ILogService } from '../../../platform/log/common/log.js'; import { ITerminalService, type ITerminalInstance } from '../../contrib/terminal/browser/terminal.js'; import { IWorkbenchEnvironmentService } from '../../services/environment/common/environmentService.js'; import { extHostNamedCustomer, type IExtHostContext } from '../../services/extensions/common/extHostCustomers.js'; import { TerminalShellExecutionCommandLineConfidence } from '../common/extHostTypes.js'; import { IExtensionService } from '../../services/extensions/common/extensions.js'; +import { ITerminalLogService } from '../../../platform/terminal/common/terminal.js'; @extHostNamedCustomer(MainContext.MainThreadTerminalShellIntegration) export class MainThreadTerminalShellIntegration extends Disposable implements MainThreadTerminalShellIntegrationShape { @@ -23,7 +23,7 @@ export class MainThreadTerminalShellIntegration extends Disposable implements Ma @ITerminalService private readonly _terminalService: ITerminalService, @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, @IExtensionService private readonly _extensionService: IExtensionService, - @ILogService private readonly _logService: ILogService + @ITerminalLogService private readonly _logService: ITerminalLogService ) { super();