From 068323b32f0ccbb4ee7a41da7511b02ce6f479be Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 24 Nov 2025 14:52:22 -0800 Subject: [PATCH 01/13] Debug wsl cwd regression 3 --- .../common/xterm/shellIntegrationAddon.ts | 3 +++ .../terminal/browser/terminalInstance.ts | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index bfc85875cf7ab..0badf3a620c25 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -638,6 +638,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati } private _updateCwd(value: string) { + this._logService.debug(`MYLOG ShellIntegrationAddon#_updateCwd: updating cwd to "${value}"`); value = sanitizeCwd(value); this._createOrGetCwdDetection().updateCwd(value); const commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); @@ -739,10 +740,12 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati if (!this._terminal) { throw new Error('Cannot restore commands before addon is activated'); } + this._logService.debug(`MYLOG ShellIntegrationAddon#deserialize: deserializing command detection capability`); const commandDetection = this._createOrGetCommandDetection(this._terminal); commandDetection.deserialize(serialized); if (commandDetection.cwd) { // Cwd gets set when the command is deserialized, so we need to update it here + this._logService.debug(`MYLOG ShellIntegrationAddon#deserialize: updating cwd from deserialized commandDetection.cwd="${commandDetection.cwd}"`); this._updateCwd(commandDetection.cwd); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 5256233446fb7..a02720b9c9b0c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -470,6 +470,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { switch (e.id) { case TerminalCapability.CwdDetection: { capabilityListeners.set(e.id, e.capability.onDidChangeCwd(e => { + this._logService.debug(`MYLOG TerminalInstance#onDidChangeCwd: cwd changed to "${e}", hasRemoteAuthority=${this.hasRemoteAuthority}, remoteAuthority=${this.remoteAuthority}`); this._cwd = e; this._setTitle(this.title, TitleEventSource.Config); })); @@ -556,6 +557,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Re-establish the title after reconnect if (this.shellLaunchConfig.attachPersistentProcess) { + this._logService.debug(`MYLOG TerminalInstance: Setting cwd from attachPersistentProcess.cwd="${this.shellLaunchConfig.attachPersistentProcess.cwd}", previous _cwd="${this._cwd}"`); this._cwd = this.shellLaunchConfig.attachPersistentProcess.cwd; this._setTitle(this.shellLaunchConfig.attachPersistentProcess.title, this.shellLaunchConfig.attachPersistentProcess.titleSource); this.setShellType(this.shellType); @@ -876,7 +878,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } xterm.raw.options.windowsPty = processTraits.windowsPty; })); - this._register(this._processManager.onRestoreCommands(e => this.xterm?.shellIntegration.deserialize(e))); + this._register(this._processManager.onRestoreCommands(e => { + this._logService.debug(`MYLOG TerminalInstance#onRestoreCommands: Restoring commands, current _cwd="${this._cwd}", hasRemoteAuthority=${this.hasRemoteAuthority}`); + this.xterm?.shellIntegration.deserialize(e); + this._logService.debug(`MYLOG TerminalInstance#onRestoreCommands: After deserialize, _cwd="${this._cwd}"`); + })); this._register(this._viewDescriptorService.onDidChangeLocation(({ views }) => { if (views.some(v => v.id === TERMINAL_VIEW_ID)) { @@ -908,10 +914,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } if (this.xterm?.shellIntegration) { + this._logService.debug(`MYLOG TerminalInstance#_createXterm: Adding shell integration capabilities, hasRemoteAuthority=${this.hasRemoteAuthority}, current _cwd="${this._cwd}"`); this.capabilities.add(this.xterm.shellIntegration.capabilities); + this._logService.debug(`MYLOG TerminalInstance#_createXterm: After adding shell integration capabilities, _cwd="${this._cwd}"`); } this._pathService.userHome().then(userHome => { + this._logService.debug(`MYLOG TerminalInstance#_createXterm: userHome resolved to "${userHome.fsPath}", current _cwd="${this._cwd}"`); this._userHome = userHome.fsPath; }); @@ -1530,13 +1539,16 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this.isDisposed) { return; } + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Starting process creation, _cwd="${this._cwd}", _userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, remoteAuthority=${this.remoteAuthority}`); const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); + this._logService.debug(`MYLOG TerminalInstance#_createProcess: activeWorkspaceRootUri=${activeWorkspaceRootUri?.toString()}`); if (activeWorkspaceRootUri) { const trusted = await this._trust(); if (!trusted) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}`); // something strange is going on if cwd is not userHome in an empty workspace this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) @@ -1548,6 +1560,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm?.resize(this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows); } const originalIcon = this.shellLaunchConfig.icon; + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Creating process with shellLaunchConfig=${JSON.stringify(this._shellLaunchConfig)}, _cols=${this._cols}, _rows=${this._rows}`); await this._processManager.createProcess(this._shellLaunchConfig, this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows).then(result => { if (result) { if (hasKey(result, { message: true })) { @@ -1558,9 +1571,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } }); if (this.isDisposed) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Disposed during process creation, skipping icon update`); return; } if (originalIcon !== this.shellLaunchConfig.icon || this.shellLaunchConfig.color) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Updating icon from originalIcon=${originalIcon} to icon=${this._shellLaunchConfig.attachPersistentProcess?.icon || this._shellLaunchConfig.icon}`); this._icon = this._shellLaunchConfig.attachPersistentProcess?.icon || this._shellLaunchConfig.icon; this._onIconChanged.fire({ instance: this, userInitiated: false }); } From b62f671bfad76f309a5bf5937b1da1e2f6b7c347 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 24 Nov 2025 23:29:44 -0800 Subject: [PATCH 02/13] skip trust check if remote or has explicit shellLaunchConfig.cwd --- .../terminal/browser/terminalInstance.ts | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a02720b9c9b0c..51f4fc18cb3f4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1548,11 +1548,24 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}`); - // something strange is going on if cwd is not userHome in an empty workspace - this._onProcessExit({ - message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) - }); + // For the trust check in empty workspaces, we need to be careful about comparing + // paths from different filesystem contexts. In remote scenarios (like WSL), the + // cwd may be a remote path (e.g., /mnt/c/...) while userHome is from a different + // context. Additionally, if the shellLaunchConfig has an explicit cwd, this is + // a legitimate task/terminal request that should be allowed. + const hasExplicitCwd = !!this._shellLaunchConfig.cwd; + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, hasExplicitCwd=${hasExplicitCwd}`); + + // Skip trust check if: + // 1. This is a remote terminal (cwd and userHome are in different filesystem contexts) + // 2. The shellLaunchConfig explicitly specifies a cwd (legitimate task/terminal request) + if (!this.hasRemoteAuthority && !hasExplicitCwd) { + // something strange is going on if cwd is not userHome in an empty workspace + // and no explicit cwd was requested and this is not a remote terminal + this._onProcessExit({ + message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) + }); + } } // Re-evaluate dimensions if the container has been set since the xterm instance was created if (this._container && this._cols === 0 && this._rows === 0) { From acffcd967742f78e5cf81f21ce13faf0e6d818a1 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 00:44:28 -0800 Subject: [PATCH 03/13] TODO: remove logs --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 51f4fc18cb3f4..bafe5b21445d9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1548,11 +1548,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { - // For the trust check in empty workspaces, we need to be careful about comparing - // paths from different filesystem contexts. In remote scenarios (like WSL), the - // cwd may be a remote path (e.g., /mnt/c/...) while userHome is from a different - // context. Additionally, if the shellLaunchConfig has an explicit cwd, this is - // a legitimate task/terminal request that should be allowed. const hasExplicitCwd = !!this._shellLaunchConfig.cwd; this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, hasExplicitCwd=${hasExplicitCwd}`); From 95747dd4984b9435a8196efc243bd8aa75a89d4a Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 00:46:32 -0800 Subject: [PATCH 04/13] comments --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index bafe5b21445d9..8dab68c8141a2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1556,7 +1556,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // 2. The shellLaunchConfig explicitly specifies a cwd (legitimate task/terminal request) if (!this.hasRemoteAuthority && !hasExplicitCwd) { // something strange is going on if cwd is not userHome in an empty workspace - // and no explicit cwd was requested and this is not a remote terminal this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) }); From d5a5ecee57704d0718efb5cce441c9b0a10928dc Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 08:27:51 -0800 Subject: [PATCH 05/13] More logs to show better debugging --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 8dab68c8141a2..94607660bf3bf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1543,8 +1543,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); this._logService.debug(`MYLOG TerminalInstance#_createProcess: activeWorkspaceRootUri=${activeWorkspaceRootUri?.toString()}`); if (activeWorkspaceRootUri) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Active Workspace at: ${activeWorkspaceRootUri.toString()}`); const trusted = await this._trust(); + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace trust for active workspace is ${trusted}`); if (!trusted) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace is not trusted - terminating process creation`); this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { From 0f4908af2b7113f653730f4724a1ffe8c7319f6a Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 08:53:54 -0800 Subject: [PATCH 06/13] Debug getLastActiveWorkspaceRoot --- .../services/history/browser/historyService.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/services/history/browser/historyService.ts b/src/vs/workbench/services/history/browser/historyService.ts index 1032eaa007867..7f0b969642e30 100644 --- a/src/vs/workbench/services/history/browser/historyService.ts +++ b/src/vs/workbench/services/history/browser/historyService.ts @@ -1133,22 +1133,29 @@ export class HistoryService extends Disposable implements IHistoryService { // No Folder: return early const folders = this.contextService.getWorkspace().folders; + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: workspace folders=${folders.length}, schemeFilter=${schemeFilter}, authorityFilter=${authorityFilter}`); + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot Folders: ${folders.map(f => f.uri.toString()).join(', ')}`); if (folders.length === 0) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: no workspace folders found`); return undefined; } // Single Folder: return early if (folders.length === 1) { const resource = folders[0].uri; + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: 1 workspace folder found: ${resource.toString()}`); if ((!schemeFilter || resource.scheme === schemeFilter) && (!authorityFilter || resource.authority === authorityFilter)) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: returning the single workspace folder`); + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: Value of schemeFilter: ${schemeFilter}, authorityFilter: ${authorityFilter}, resource.scheme: ${resource.scheme}, resource.authority: ${resource.authority}`); return resource; } - + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: single workspace folder did not match filters, returning undefined`); return undefined; } // Multiple folders: find the last active one for (const input of this.getHistory()) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: checking history entry: ${isEditorInput(input) ? 'editor input' : input.resource.toString()}`); if (isEditorInput(input)) { continue; } @@ -1163,18 +1170,22 @@ export class HistoryService extends Disposable implements IHistoryService { const resourceWorkspace = this.contextService.getWorkspaceFolder(input.resource); if (resourceWorkspace) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: found matching workspace folder from history: ${resourceWorkspace.uri.toString()}`); return resourceWorkspace.uri; } } // Fallback to first workspace matching scheme filter if any for (const folder of folders) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: checking workspace folder: ${folder.uri.toString()}`); const resource = folder.uri; if ((!schemeFilter || resource.scheme === schemeFilter) && (!authorityFilter || resource.authority === authorityFilter)) { + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: Returning resource: ${resource} value of schemeFilter: ${schemeFilter}, authorityFilter: ${authorityFilter}, resource.scheme: ${resource.scheme}, resource.authority: ${resource.authority}`); return resource; } } + this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: no matching workspace folder found at all, returning undefined`); return undefined; } From 062ffb2c64d705fb10cb2f0c05067f46e3428397 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 12:14:47 -0800 Subject: [PATCH 07/13] Remove .getLastActiveWorkspaceRoot(Schemas.file); --- .../terminal/browser/terminalInstance.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 94607660bf3bf..c88e47043c198 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1540,17 +1540,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this._logService.debug(`MYLOG TerminalInstance#_createProcess: Starting process creation, _cwd="${this._cwd}", _userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, remoteAuthority=${this.remoteAuthority}`); - const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file); - this._logService.debug(`MYLOG TerminalInstance#_createProcess: activeWorkspaceRootUri=${activeWorkspaceRootUri?.toString()}`); - if (activeWorkspaceRootUri) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Active Workspace at: ${activeWorkspaceRootUri.toString()}`); - const trusted = await this._trust(); - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace trust for active workspace is ${trusted}`); - if (!trusted) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace is not trusted - terminating process creation`); - this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); - } - } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { + + const trusted = await this._trust(); + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace trust for active workspace is ${trusted}`); + if (!trusted) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace is not trusted - terminating process creation`); + this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); + } + if (this._cwd && this._userHome && this._cwd !== this._userHome) { const hasExplicitCwd = !!this._shellLaunchConfig.cwd; this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, hasExplicitCwd=${hasExplicitCwd}`); From 6a8f6f31e81794566817cac79ceb9c32bebaccde Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 13:09:50 -0800 Subject: [PATCH 08/13] Clean up all logs, remove --- .../common/xterm/shellIntegrationAddon.ts | 3 -- .../terminal/browser/terminalInstance.ts | 37 +++---------------- .../history/browser/historyService.ts | 13 +------ 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index 0badf3a620c25..bfc85875cf7ab 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -638,7 +638,6 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati } private _updateCwd(value: string) { - this._logService.debug(`MYLOG ShellIntegrationAddon#_updateCwd: updating cwd to "${value}"`); value = sanitizeCwd(value); this._createOrGetCwdDetection().updateCwd(value); const commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); @@ -740,12 +739,10 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati if (!this._terminal) { throw new Error('Cannot restore commands before addon is activated'); } - this._logService.debug(`MYLOG ShellIntegrationAddon#deserialize: deserializing command detection capability`); const commandDetection = this._createOrGetCommandDetection(this._terminal); commandDetection.deserialize(serialized); if (commandDetection.cwd) { // Cwd gets set when the command is deserialized, so we need to update it here - this._logService.debug(`MYLOG ShellIntegrationAddon#deserialize: updating cwd from deserialized commandDetection.cwd="${commandDetection.cwd}"`); this._updateCwd(commandDetection.cwd); } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index c88e47043c198..af14b7a7cbc94 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -470,7 +470,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { switch (e.id) { case TerminalCapability.CwdDetection: { capabilityListeners.set(e.id, e.capability.onDidChangeCwd(e => { - this._logService.debug(`MYLOG TerminalInstance#onDidChangeCwd: cwd changed to "${e}", hasRemoteAuthority=${this.hasRemoteAuthority}, remoteAuthority=${this.remoteAuthority}`); this._cwd = e; this._setTitle(this.title, TitleEventSource.Config); })); @@ -557,7 +556,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Re-establish the title after reconnect if (this.shellLaunchConfig.attachPersistentProcess) { - this._logService.debug(`MYLOG TerminalInstance: Setting cwd from attachPersistentProcess.cwd="${this.shellLaunchConfig.attachPersistentProcess.cwd}", previous _cwd="${this._cwd}"`); this._cwd = this.shellLaunchConfig.attachPersistentProcess.cwd; this._setTitle(this.shellLaunchConfig.attachPersistentProcess.title, this.shellLaunchConfig.attachPersistentProcess.titleSource); this.setShellType(this.shellType); @@ -878,11 +876,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } xterm.raw.options.windowsPty = processTraits.windowsPty; })); - this._register(this._processManager.onRestoreCommands(e => { - this._logService.debug(`MYLOG TerminalInstance#onRestoreCommands: Restoring commands, current _cwd="${this._cwd}", hasRemoteAuthority=${this.hasRemoteAuthority}`); - this.xterm?.shellIntegration.deserialize(e); - this._logService.debug(`MYLOG TerminalInstance#onRestoreCommands: After deserialize, _cwd="${this._cwd}"`); - })); + this._register(this._processManager.onRestoreCommands(e => this.xterm?.shellIntegration.deserialize(e))); this._register(this._viewDescriptorService.onDidChangeLocation(({ views }) => { if (views.some(v => v.id === TERMINAL_VIEW_ID)) { @@ -914,13 +908,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } if (this.xterm?.shellIntegration) { - this._logService.debug(`MYLOG TerminalInstance#_createXterm: Adding shell integration capabilities, hasRemoteAuthority=${this.hasRemoteAuthority}, current _cwd="${this._cwd}"`); this.capabilities.add(this.xterm.shellIntegration.capabilities); - this._logService.debug(`MYLOG TerminalInstance#_createXterm: After adding shell integration capabilities, _cwd="${this._cwd}"`); } this._pathService.userHome().then(userHome => { - this._logService.debug(`MYLOG TerminalInstance#_createXterm: userHome resolved to "${userHome.fsPath}", current _cwd="${this._cwd}"`); this._userHome = userHome.fsPath; }); @@ -1539,27 +1530,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this.isDisposed) { return; } - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Starting process creation, _cwd="${this._cwd}", _userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, remoteAuthority=${this.remoteAuthority}`); - const trusted = await this._trust(); - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace trust for active workspace is ${trusted}`); if (!trusted) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Workspace is not trusted - terminating process creation`); this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); - } - if (this._cwd && this._userHome && this._cwd !== this._userHome) { - const hasExplicitCwd = !!this._shellLaunchConfig.cwd; - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Empty workspace cwd mismatch detected - cwd="${this._cwd}", userHome="${this._userHome}", hasRemoteAuthority=${this.hasRemoteAuthority}, hasExplicitCwd=${hasExplicitCwd}`); - - // Skip trust check if: - // 1. This is a remote terminal (cwd and userHome are in different filesystem contexts) - // 2. The shellLaunchConfig explicitly specifies a cwd (legitimate task/terminal request) - if (!this.hasRemoteAuthority && !hasExplicitCwd) { - // something strange is going on if cwd is not userHome in an empty workspace - this._onProcessExit({ - message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) - }); - } + } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { + // something strange is going on if cwd is not userHome in an empty workspace + this._onProcessExit({ + message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) + }); } // Re-evaluate dimensions if the container has been set since the xterm instance was created if (this._container && this._cols === 0 && this._rows === 0) { @@ -1567,7 +1545,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this.xterm?.resize(this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows); } const originalIcon = this.shellLaunchConfig.icon; - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Creating process with shellLaunchConfig=${JSON.stringify(this._shellLaunchConfig)}, _cols=${this._cols}, _rows=${this._rows}`); await this._processManager.createProcess(this._shellLaunchConfig, this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows).then(result => { if (result) { if (hasKey(result, { message: true })) { @@ -1578,11 +1555,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } }); if (this.isDisposed) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Disposed during process creation, skipping icon update`); return; } if (originalIcon !== this.shellLaunchConfig.icon || this.shellLaunchConfig.color) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess: Updating icon from originalIcon=${originalIcon} to icon=${this._shellLaunchConfig.attachPersistentProcess?.icon || this._shellLaunchConfig.icon}`); this._icon = this._shellLaunchConfig.attachPersistentProcess?.icon || this._shellLaunchConfig.icon; this._onIconChanged.fire({ instance: this, userInitiated: false }); } diff --git a/src/vs/workbench/services/history/browser/historyService.ts b/src/vs/workbench/services/history/browser/historyService.ts index 7f0b969642e30..1032eaa007867 100644 --- a/src/vs/workbench/services/history/browser/historyService.ts +++ b/src/vs/workbench/services/history/browser/historyService.ts @@ -1133,29 +1133,22 @@ export class HistoryService extends Disposable implements IHistoryService { // No Folder: return early const folders = this.contextService.getWorkspace().folders; - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: workspace folders=${folders.length}, schemeFilter=${schemeFilter}, authorityFilter=${authorityFilter}`); - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot Folders: ${folders.map(f => f.uri.toString()).join(', ')}`); if (folders.length === 0) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: no workspace folders found`); return undefined; } // Single Folder: return early if (folders.length === 1) { const resource = folders[0].uri; - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: 1 workspace folder found: ${resource.toString()}`); if ((!schemeFilter || resource.scheme === schemeFilter) && (!authorityFilter || resource.authority === authorityFilter)) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: returning the single workspace folder`); - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: Value of schemeFilter: ${schemeFilter}, authorityFilter: ${authorityFilter}, resource.scheme: ${resource.scheme}, resource.authority: ${resource.authority}`); return resource; } - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: single workspace folder did not match filters, returning undefined`); + return undefined; } // Multiple folders: find the last active one for (const input of this.getHistory()) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: checking history entry: ${isEditorInput(input) ? 'editor input' : input.resource.toString()}`); if (isEditorInput(input)) { continue; } @@ -1170,22 +1163,18 @@ export class HistoryService extends Disposable implements IHistoryService { const resourceWorkspace = this.contextService.getWorkspaceFolder(input.resource); if (resourceWorkspace) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: found matching workspace folder from history: ${resourceWorkspace.uri.toString()}`); return resourceWorkspace.uri; } } // Fallback to first workspace matching scheme filter if any for (const folder of folders) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: checking workspace folder: ${folder.uri.toString()}`); const resource = folder.uri; if ((!schemeFilter || resource.scheme === schemeFilter) && (!authorityFilter || resource.authority === authorityFilter)) { - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: Returning resource: ${resource} value of schemeFilter: ${schemeFilter}, authorityFilter: ${authorityFilter}, resource.scheme: ${resource.scheme}, resource.authority: ${resource.authority}`); return resource; } } - this.logService.debug(`MYLOG getLastActiveWorkspaceRoot: no matching workspace folder found at all, returning undefined`); return undefined; } From 6b1505e576059a4bc48a9f197134b4304499be7c Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 13:20:03 -0800 Subject: [PATCH 09/13] One last debug before final cleanup --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index af14b7a7cbc94..07bbcaf82eba2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1531,9 +1531,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } const trusted = await this._trust(); + this._logService.debug(`MYLOG TerminalInstance#_createProcess (instanceId: ${this.instanceId}, trusted: ${trusted})`); if (!trusted) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { + this._logService.debug(`MYLOG TerminalInstance#_createProcess This should only happen for empty workspace, cwd: ${this._cwd}, userHome: ${this._userHome}`); // something strange is going on if cwd is not userHome in an empty workspace this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) From e9ea74a5a3aded8edd29230fdcb884634a80c167 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 15:31:42 -0800 Subject: [PATCH 10/13] Only go into second process exit when workspace is empty --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 07bbcaf82eba2..39c60fb640caf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1534,7 +1534,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._logService.debug(`MYLOG TerminalInstance#_createProcess (instanceId: ${this.instanceId}, trusted: ${trusted})`); if (!trusted) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); - } else if (this._cwd && this._userHome && this._cwd !== this._userHome) { + } else if (this._workspaceContextService.getWorkspace().folders.length === 0 && this._cwd && this._userHome && this._cwd !== this._userHome) { this._logService.debug(`MYLOG TerminalInstance#_createProcess This should only happen for empty workspace, cwd: ${this._cwd}, userHome: ${this._userHome}`); // something strange is going on if cwd is not userHome in an empty workspace this._onProcessExit({ From 889a9f55a94c7cad03abc3c3f3f10dbebb40a0f9 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 18:37:05 -0800 Subject: [PATCH 11/13] Clean up the debugging logs, not needed anymore --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 39c60fb640caf..a9188ddcaeefa 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1531,11 +1531,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } const trusted = await this._trust(); - this._logService.debug(`MYLOG TerminalInstance#_createProcess (instanceId: ${this.instanceId}, trusted: ${trusted})`); if (!trusted) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } else if (this._workspaceContextService.getWorkspace().folders.length === 0 && this._cwd && this._userHome && this._cwd !== this._userHome) { - this._logService.debug(`MYLOG TerminalInstance#_createProcess This should only happen for empty workspace, cwd: ${this._cwd}, userHome: ${this._userHome}`); // something strange is going on if cwd is not userHome in an empty workspace this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminalCwd', "Cannot launch a terminal process in an untrusted workspace with cwd {0} and userHome {1}", this._cwd, this._userHome) From 355a6375f57e56f1a3cee07e075e6378512706d7 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 19:01:19 -0800 Subject: [PATCH 12/13] Only ban terminal when untristed and NOT remote --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a9188ddcaeefa..f5281684c4dc4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1531,7 +1531,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } const trusted = await this._trust(); - if (!trusted) { + if (!trusted && !this.remoteAuthority) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } else if (this._workspaceContextService.getWorkspace().folders.length === 0 && this._cwd && this._userHome && this._cwd !== this._userHome) { // something strange is going on if cwd is not userHome in an empty workspace From 2c403146ea7d6383f71394f1d4a34101aa584c7a Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 25 Nov 2025 21:39:25 -0800 Subject: [PATCH 13/13] Try to get local from remote to create terminal in untrusted remote workspace --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index f5281684c4dc4..4a51c8603b9e8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -384,7 +384,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @IProductService private readonly _productService: IProductService, @IQuickInputService private readonly _quickInputService: IQuickInputService, - @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IWorkbenchEnvironmentService private readonly _workbenchEnvironmentService: IWorkbenchEnvironmentService, @IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService, @IEditorService private readonly _editorService: IEditorService, @IWorkspaceTrustRequestService private readonly _workspaceTrustRequestService: IWorkspaceTrustRequestService, @@ -509,7 +509,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // which would result in the wrong profile being selected and the wrong icon being // permanently attached to the terminal. This also doesn't work when the default profile // setting is set to null, that's handled after the process is created. - if (!this.shellLaunchConfig.executable && !workbenchEnvironmentService.remoteAuthority) { + if (!this.shellLaunchConfig.executable && !this._workbenchEnvironmentService.remoteAuthority) { this._terminalProfileResolverService.resolveIcon(this._shellLaunchConfig, OS); } this._icon = _shellLaunchConfig.attachPersistentProcess?.icon || _shellLaunchConfig.icon; @@ -1531,7 +1531,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } const trusted = await this._trust(); - if (!trusted && !this.remoteAuthority) { + // Allow remote and local terminals from remote to be created in untrusted remote workspace + if (!trusted && !this.remoteAuthority && !this._workbenchEnvironmentService.remoteAuthority) { this._onProcessExit({ message: nls.localize('workspaceNotTrustedCreateTerminal', "Cannot launch a terminal process in an untrusted workspace") }); } else if (this._workspaceContextService.getWorkspace().folders.length === 0 && this._cwd && this._userHome && this._cwd !== this._userHome) { // something strange is going on if cwd is not userHome in an empty workspace