From 5aa5ea7d140820429b7d1e054d83c8008aade9ea Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Wed, 12 Nov 2025 09:01:39 -0800 Subject: [PATCH 01/14] try adding options.remoteAuthority field for profile --- .../contrib/terminal/browser/terminalProfileResolverService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 0bc0700b6fd81..e669ed41e62e5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -232,7 +232,7 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl // Try select an existing profile to fallback to, based on the default system shell, only do // this when it is NOT a local terminal in a remote window where the front and back end OS // differs (eg. Windows -> WSL, Mac -> Linux) - if (options.os === OS) { + if (options.os === OS && options.remoteAuthority) { let existingProfile = this._terminalProfileService.availableProfiles.find(e => path.parse(e.path).name === path.parse(executable).name); if (existingProfile) { if (options.allowAutomationShell) { From a11048f3fc62b15a2482232df63e6a412c5f2e70 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 17 Nov 2025 08:19:36 -0800 Subject: [PATCH 02/14] try explicit remoteAuthority undefined when local --- .../electron-browser/terminalRemote.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index 1a11a3fa56ac2..4cfb1c6540447 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -9,8 +9,9 @@ import { localize2 } from '../../../../nls.js'; import { INativeEnvironmentService } from '../../../../platform/environment/common/environment.js'; import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; import { registerTerminalAction } from '../browser/terminalActions.js'; -import { TerminalCommandId } from '../common/terminal.js'; +import { TerminalCommandId, ITerminalProfileResolverService } from '../common/terminal.js'; import { IHistoryService } from '../../../services/history/common/history.js'; +import { OS } from '../../../../base/common/platform.js'; export function registerRemoteContributions() { registerTerminalAction({ @@ -20,6 +21,8 @@ export function registerRemoteContributions() { const historyService = accessor.get(IHistoryService); const remoteAuthorityResolverService = accessor.get(IRemoteAuthorityResolverService); const nativeEnvironmentService = accessor.get(INativeEnvironmentService); + const terminalProfileResolverService = accessor.get(ITerminalProfileResolverService); + let cwd: URI | undefined; try { const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.vscodeRemote); @@ -33,7 +36,19 @@ export function registerRemoteContributions() { if (!cwd) { cwd = nativeEnvironmentService.userHome; } - const instance = await c.service.createTerminal({ cwd }); + + // Fix: Explicitly get the local default profile to ensure we use the correct local shell + // instead of accidentally using remote shell profiles when in a remote workspace + const localProfile = await terminalProfileResolverService.getDefaultProfile({ + remoteAuthority: undefined, // Force local backend + os: OS // Use the actual local OS + }); + + // Create terminal with explicit local profile configuration + const instance = await c.service.createTerminal({ + cwd, + config: localProfile + }); if (!instance) { return Promise.resolve(undefined); } From 31bbae2468c4eb5e2cbeb8029b82a0653d58b677 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 17 Nov 2025 09:46:01 -0800 Subject: [PATCH 03/14] Dont touch terminalProfileResolverService.ts --- .../contrib/terminal/browser/terminalProfileResolverService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index e669ed41e62e5..0bc0700b6fd81 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -232,7 +232,7 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl // Try select an existing profile to fallback to, based on the default system shell, only do // this when it is NOT a local terminal in a remote window where the front and back end OS // differs (eg. Windows -> WSL, Mac -> Linux) - if (options.os === OS && options.remoteAuthority) { + if (options.os === OS) { let existingProfile = this._terminalProfileService.availableProfiles.find(e => path.parse(e.path).name === path.parse(executable).name); if (existingProfile) { if (options.allowAutomationShell) { From 4f5b582db9c084cb42c46743000c74b3f4dda775 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 17 Nov 2025 10:34:13 -0800 Subject: [PATCH 04/14] Better comments to explicitly get local default profile in remote --- .../contrib/terminal/electron-browser/terminalRemote.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index 4cfb1c6540447..397972c7e2e57 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -37,11 +37,10 @@ export function registerRemoteContributions() { cwd = nativeEnvironmentService.userHome; } - // Fix: Explicitly get the local default profile to ensure we use the correct local shell - // instead of accidentally using remote shell profiles when in a remote workspace + // Make sure to explicitly get the local default profile const localProfile = await terminalProfileResolverService.getDefaultProfile({ - remoteAuthority: undefined, // Force local backend - os: OS // Use the actual local OS + remoteAuthority: undefined, + os: OS }); // Create terminal with explicit local profile configuration From e590c629bcb52e4d32d83c9525ff2c9f6ebbad49 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 17 Nov 2025 13:39:30 -0800 Subject: [PATCH 05/14] Try to handle mac -> linux scenario --- .../terminal/browser/terminalProfileResolverService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 0bc0700b6fd81..bf6086b4d122d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -232,7 +232,10 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl // Try select an existing profile to fallback to, based on the default system shell, only do // this when it is NOT a local terminal in a remote window where the front and back end OS // differs (eg. Windows -> WSL, Mac -> Linux) - if (options.os === OS) { + // When remoteAuthority is undefined but we have a remote connection, we're creating a local + // terminal in a remote window - skip profile matching as availableProfiles contains remote profiles + const isLocalTerminalInRemoteWindow = options.remoteAuthority === undefined && this._remoteAgentService.getConnection()?.remoteAuthority !== undefined; + if (options.os === OS && !isLocalTerminalInRemoteWindow) { let existingProfile = this._terminalProfileService.availableProfiles.find(e => path.parse(e.path).name === path.parse(executable).name); if (existingProfile) { if (options.allowAutomationShell) { From f43a28343e36d4865f5d0725f7e9523bf293ad10 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 17 Nov 2025 14:43:19 -0800 Subject: [PATCH 06/14] see if caching is problem --- src/vs/base/node/shell.ts | 55 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/vs/base/node/shell.ts b/src/vs/base/node/shell.ts index ab2c0d1c693f2..46db36f97bb31 100644 --- a/src/vs/base/node/shell.ts +++ b/src/vs/base/node/shell.ts @@ -25,40 +25,49 @@ export async function getSystemShell(os: platform.OperatingSystem, env: platform return getSystemShellUnixLike(os, env); } -let _TERMINAL_DEFAULT_SHELL_UNIX_LIKE: string | null = null; +const _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE = new Map(); function getSystemShellUnixLike(os: platform.OperatingSystem, env: platform.IProcessEnvironment): string { // Only use $SHELL for the current OS if (platform.isLinux && os === platform.OperatingSystem.Macintosh || platform.isMacintosh && os === platform.OperatingSystem.Linux) { return '/bin/bash'; } - if (!_TERMINAL_DEFAULT_SHELL_UNIX_LIKE) { - let unixLikeTerminal: string | undefined | null; - if (platform.isWindows) { - unixLikeTerminal = '/bin/bash'; // for WSL - } else { - unixLikeTerminal = env['SHELL']; + // Create a cache key based on the OS and the SHELL environment variable to handle + // cases where different environments (local vs remote) have different shells + const shellEnv = env['SHELL'] || ''; + const cacheKey = `${os}-${shellEnv}`; + + const cached = _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE.get(cacheKey); + if (cached) { + return cached; + } - if (!unixLikeTerminal) { - try { - // It's possible for $SHELL to be unset, this API reads /etc/passwd. See https://github.com/github/codespaces/issues/1639 - // Node docs: "Throws a SystemError if a user has no username or homedir." - unixLikeTerminal = userInfo().shell; - } catch (err) { } - } + let unixLikeTerminal: string | undefined | null; + if (platform.isWindows) { + unixLikeTerminal = '/bin/bash'; // for WSL + } else { + unixLikeTerminal = env['SHELL']; - if (!unixLikeTerminal) { - unixLikeTerminal = 'sh'; - } + if (!unixLikeTerminal) { + try { + // It's possible for $SHELL to be unset, this API reads /etc/passwd. See https://github.com/github/codespaces/issues/1639 + // Node docs: "Throws a SystemError if a user has no username or homedir." + unixLikeTerminal = userInfo().shell; + } catch (err) { } + } - // Some systems have $SHELL set to /bin/false which breaks the terminal - if (unixLikeTerminal === '/bin/false') { - unixLikeTerminal = '/bin/bash'; - } + if (!unixLikeTerminal) { + unixLikeTerminal = 'sh'; + } + + // Some systems have $SHELL set to /bin/false which breaks the terminal + if (unixLikeTerminal === '/bin/false') { + unixLikeTerminal = '/bin/bash'; } - _TERMINAL_DEFAULT_SHELL_UNIX_LIKE = unixLikeTerminal; } - return _TERMINAL_DEFAULT_SHELL_UNIX_LIKE; + + _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE.set(cacheKey, unixLikeTerminal); + return unixLikeTerminal; } let _TERMINAL_DEFAULT_SHELL_WINDOWS: string | null = null; From 183b5e58af68cc48d2b681a73b189ab2cdc05004 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 17 Nov 2025 14:58:52 -0800 Subject: [PATCH 07/14] Dont mix up profile and skip list when creating local terminal in remote --- .../browser/terminalProfileResolverService.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index bf6086b4d122d..0671f73025258 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -200,12 +200,18 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl } } + // When creating a local terminal in a remote window, skip looking up profiles from + // terminalProfileService as it contains remote profiles, not local ones + const isLocalTerminalInRemoteWindow = options.remoteAuthority === undefined && this._remoteAgentService.getConnection()?.remoteAuthority !== undefined; + // Return the real default profile if it exists and is valid, wait for profiles to be ready // if the window just opened - await this._terminalProfileService.profilesReady; - const defaultProfile = this._getUnresolvedRealDefaultProfile(options.os); - if (defaultProfile) { - return this._setIconForAutomation(options, defaultProfile); + if (!isLocalTerminalInRemoteWindow) { + await this._terminalProfileService.profilesReady; + const defaultProfile = this._getUnresolvedRealDefaultProfile(options.os); + if (defaultProfile) { + return this._setIconForAutomation(options, defaultProfile); + } } // If there is no real default profile, create a fallback default profile based on the shell From 9d167f0840d95b0f67122e4d26c72ba0fbe3f72c Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 17 Nov 2025 16:25:04 -0800 Subject: [PATCH 08/14] Just handle wsl in this PR to make life simpler --- src/vs/base/node/shell.ts | 55 ++++++++----------- .../browser/terminalProfileResolverService.ts | 19 ++----- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/src/vs/base/node/shell.ts b/src/vs/base/node/shell.ts index 46db36f97bb31..ab2c0d1c693f2 100644 --- a/src/vs/base/node/shell.ts +++ b/src/vs/base/node/shell.ts @@ -25,49 +25,40 @@ export async function getSystemShell(os: platform.OperatingSystem, env: platform return getSystemShellUnixLike(os, env); } -const _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE = new Map(); +let _TERMINAL_DEFAULT_SHELL_UNIX_LIKE: string | null = null; function getSystemShellUnixLike(os: platform.OperatingSystem, env: platform.IProcessEnvironment): string { // Only use $SHELL for the current OS if (platform.isLinux && os === platform.OperatingSystem.Macintosh || platform.isMacintosh && os === platform.OperatingSystem.Linux) { return '/bin/bash'; } - // Create a cache key based on the OS and the SHELL environment variable to handle - // cases where different environments (local vs remote) have different shells - const shellEnv = env['SHELL'] || ''; - const cacheKey = `${os}-${shellEnv}`; - - const cached = _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE.get(cacheKey); - if (cached) { - return cached; - } + if (!_TERMINAL_DEFAULT_SHELL_UNIX_LIKE) { + let unixLikeTerminal: string | undefined | null; + if (platform.isWindows) { + unixLikeTerminal = '/bin/bash'; // for WSL + } else { + unixLikeTerminal = env['SHELL']; - let unixLikeTerminal: string | undefined | null; - if (platform.isWindows) { - unixLikeTerminal = '/bin/bash'; // for WSL - } else { - unixLikeTerminal = env['SHELL']; + if (!unixLikeTerminal) { + try { + // It's possible for $SHELL to be unset, this API reads /etc/passwd. See https://github.com/github/codespaces/issues/1639 + // Node docs: "Throws a SystemError if a user has no username or homedir." + unixLikeTerminal = userInfo().shell; + } catch (err) { } + } - if (!unixLikeTerminal) { - try { - // It's possible for $SHELL to be unset, this API reads /etc/passwd. See https://github.com/github/codespaces/issues/1639 - // Node docs: "Throws a SystemError if a user has no username or homedir." - unixLikeTerminal = userInfo().shell; - } catch (err) { } - } + if (!unixLikeTerminal) { + unixLikeTerminal = 'sh'; + } - if (!unixLikeTerminal) { - unixLikeTerminal = 'sh'; - } - - // Some systems have $SHELL set to /bin/false which breaks the terminal - if (unixLikeTerminal === '/bin/false') { - unixLikeTerminal = '/bin/bash'; + // Some systems have $SHELL set to /bin/false which breaks the terminal + if (unixLikeTerminal === '/bin/false') { + unixLikeTerminal = '/bin/bash'; + } } + _TERMINAL_DEFAULT_SHELL_UNIX_LIKE = unixLikeTerminal; } - - _TERMINAL_DEFAULT_SHELL_UNIX_LIKE_CACHE.set(cacheKey, unixLikeTerminal); - return unixLikeTerminal; + return _TERMINAL_DEFAULT_SHELL_UNIX_LIKE; } let _TERMINAL_DEFAULT_SHELL_WINDOWS: string | null = null; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 0671f73025258..0bc0700b6fd81 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -200,18 +200,12 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl } } - // When creating a local terminal in a remote window, skip looking up profiles from - // terminalProfileService as it contains remote profiles, not local ones - const isLocalTerminalInRemoteWindow = options.remoteAuthority === undefined && this._remoteAgentService.getConnection()?.remoteAuthority !== undefined; - // Return the real default profile if it exists and is valid, wait for profiles to be ready // if the window just opened - if (!isLocalTerminalInRemoteWindow) { - await this._terminalProfileService.profilesReady; - const defaultProfile = this._getUnresolvedRealDefaultProfile(options.os); - if (defaultProfile) { - return this._setIconForAutomation(options, defaultProfile); - } + await this._terminalProfileService.profilesReady; + const defaultProfile = this._getUnresolvedRealDefaultProfile(options.os); + if (defaultProfile) { + return this._setIconForAutomation(options, defaultProfile); } // If there is no real default profile, create a fallback default profile based on the shell @@ -238,10 +232,7 @@ export abstract class BaseTerminalProfileResolverService extends Disposable impl // Try select an existing profile to fallback to, based on the default system shell, only do // this when it is NOT a local terminal in a remote window where the front and back end OS // differs (eg. Windows -> WSL, Mac -> Linux) - // When remoteAuthority is undefined but we have a remote connection, we're creating a local - // terminal in a remote window - skip profile matching as availableProfiles contains remote profiles - const isLocalTerminalInRemoteWindow = options.remoteAuthority === undefined && this._remoteAgentService.getConnection()?.remoteAuthority !== undefined; - if (options.os === OS && !isLocalTerminalInRemoteWindow) { + if (options.os === OS) { let existingProfile = this._terminalProfileService.availableProfiles.find(e => path.parse(e.path).name === path.parse(executable).name); if (existingProfile) { if (options.allowAutomationShell) { From 44e725f075223c783c6bb5ee36dad436aa91e7f1 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 17 Nov 2025 16:30:41 -0800 Subject: [PATCH 09/14] Logs for debugging --- .../contrib/terminal/electron-browser/terminalRemote.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index 397972c7e2e57..a318237becd40 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -10,6 +10,7 @@ import { INativeEnvironmentService } from '../../../../platform/environment/comm import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; import { registerTerminalAction } from '../browser/terminalActions.js'; import { TerminalCommandId, ITerminalProfileResolverService } from '../common/terminal.js'; +import { ITerminalLogService } from '../../../../platform/terminal/common/terminal.js'; import { IHistoryService } from '../../../services/history/common/history.js'; import { OS } from '../../../../base/common/platform.js'; @@ -22,6 +23,7 @@ export function registerRemoteContributions() { const remoteAuthorityResolverService = accessor.get(IRemoteAuthorityResolverService); const nativeEnvironmentService = accessor.get(INativeEnvironmentService); const terminalProfileResolverService = accessor.get(ITerminalProfileResolverService); + const terminalLogService = accessor.get(ITerminalLogService); let cwd: URI | undefined; try { @@ -42,6 +44,11 @@ export function registerRemoteContributions() { remoteAuthority: undefined, os: OS }); + terminalLogService.trace('terminalRemote#newLocal resolved profile', { + os: OS, + profileName: localProfile?.profileName, + isAutoDetected: localProfile?.isAutoDetected ?? false + }); // Create terminal with explicit local profile configuration const instance = await c.service.createTerminal({ From 9fb14cce8aa57954468bcb1454fc3ddaba4fc38d Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 18 Nov 2025 15:02:10 -0800 Subject: [PATCH 10/14] Allow local to get backend by checking from createTerminal in terminalService.ts --- .../terminal/browser/terminalService.ts | 16 ++++++++++-- .../electron-browser/terminalRemote.ts | 25 ++----------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 2a89cf343a798..3b2324c3092f5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -967,9 +967,9 @@ export class TerminalService extends Disposable implements ITerminalService { // Await the initialization of available profiles as long as this is not a pty terminal or a // local terminal in a remote workspace as profile won't be used in those cases and these // terminals need to be launched before remote connections are established. + const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; if (this._terminalProfileService.availableProfiles.length === 0) { const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config; - const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; if (!isPtyTerminal && !isLocalInRemoteTerminal) { if (this._connectionState === TerminalConnectionState.Connecting) { mark(`code/terminal/willGetProfiles`); @@ -981,7 +981,19 @@ export class TerminalService extends Disposable implements ITerminalService { } } - const config = options?.config || this._terminalProfileService.getDefaultProfile(); + let config = options?.config; + if (!config && isLocalInRemoteTerminal) { + const backend = await this._terminalInstanceService.getBackend(undefined); + const executable = await backend?.getDefaultSystemShell(); + if (executable) { + config = { executable }; + } + } + + if (!config) { + config = this._terminalProfileService.getDefaultProfile(); + } + const shellLaunchConfig = config && 'extensionIdentifier' in config ? {} : this._terminalInstanceService.convertProfileToShellLaunchConfig(config || {}); // Get the contributed profile if it was provided diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts index a318237becd40..1a11a3fa56ac2 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts @@ -9,10 +9,8 @@ import { localize2 } from '../../../../nls.js'; import { INativeEnvironmentService } from '../../../../platform/environment/common/environment.js'; import { IRemoteAuthorityResolverService } from '../../../../platform/remote/common/remoteAuthorityResolver.js'; import { registerTerminalAction } from '../browser/terminalActions.js'; -import { TerminalCommandId, ITerminalProfileResolverService } from '../common/terminal.js'; -import { ITerminalLogService } from '../../../../platform/terminal/common/terminal.js'; +import { TerminalCommandId } from '../common/terminal.js'; import { IHistoryService } from '../../../services/history/common/history.js'; -import { OS } from '../../../../base/common/platform.js'; export function registerRemoteContributions() { registerTerminalAction({ @@ -22,9 +20,6 @@ export function registerRemoteContributions() { const historyService = accessor.get(IHistoryService); const remoteAuthorityResolverService = accessor.get(IRemoteAuthorityResolverService); const nativeEnvironmentService = accessor.get(INativeEnvironmentService); - const terminalProfileResolverService = accessor.get(ITerminalProfileResolverService); - const terminalLogService = accessor.get(ITerminalLogService); - let cwd: URI | undefined; try { const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.vscodeRemote); @@ -38,23 +33,7 @@ export function registerRemoteContributions() { if (!cwd) { cwd = nativeEnvironmentService.userHome; } - - // Make sure to explicitly get the local default profile - const localProfile = await terminalProfileResolverService.getDefaultProfile({ - remoteAuthority: undefined, - os: OS - }); - terminalLogService.trace('terminalRemote#newLocal resolved profile', { - os: OS, - profileName: localProfile?.profileName, - isAutoDetected: localProfile?.isAutoDetected ?? false - }); - - // Create terminal with explicit local profile configuration - const instance = await c.service.createTerminal({ - cwd, - config: localProfile - }); + const instance = await c.service.createTerminal({ cwd }); if (!instance) { return Promise.resolve(undefined); } From 1b762fc6ca5743b863267aa24fdbf9d2cdcff0af Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 18 Nov 2025 22:41:01 -0800 Subject: [PATCH 11/14] leave logs to debug, code doesnt work after prev commit --- .../contrib/terminal/browser/terminalService.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 3b2324c3092f5..94532a249b057 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -968,9 +968,12 @@ export class TerminalService extends Disposable implements ITerminalService { // local terminal in a remote workspace as profile won't be used in those cases and these // terminals need to be launched before remote connections are established. const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; + this._logService.debug(`#terminalService#createTerminal: Value of isLocalInRemoteTerminal is: ${isLocalInRemoteTerminal}`); if (this._terminalProfileService.availableProfiles.length === 0) { + this._logService.debug(`#terminalService#createTerminal: available profile length is zero`); const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config; if (!isPtyTerminal && !isLocalInRemoteTerminal) { + this._logService.debug(`#terminalService#createTerminal: !isPtyTerminal and !isLocalInRemoteTerminal`); if (this._connectionState === TerminalConnectionState.Connecting) { mark(`code/terminal/willGetProfiles`); } @@ -982,20 +985,25 @@ export class TerminalService extends Disposable implements ITerminalService { } let config = options?.config; + this._logService.debug(`#terminalService#createTerminal: config ${config}`); if (!config && isLocalInRemoteTerminal) { + this._logService.debug(`#terminalService#createTerminal: !config and isLocalInRemoteTerminal`); const backend = await this._terminalInstanceService.getBackend(undefined); const executable = await backend?.getDefaultSystemShell(); + this._logService.debug(`#terminalService#createTerminal: backend is: ${backend} and executable is: ${executable}`); if (executable) { config = { executable }; + this._logService.debug(`#terminalService#createTerminal: setting current config ${config} to ${executable}`); } } if (!config) { config = this._terminalProfileService.getDefaultProfile(); + this._logService.debug(`#terminalService#createTerminal: !config, so set it to new value: ${config}`); } const shellLaunchConfig = config && 'extensionIdentifier' in config ? {} : this._terminalInstanceService.convertProfileToShellLaunchConfig(config || {}); - + this._logService.debug(`#terminalService#createTerminal: shellLaunchConfig is ${shellLaunchConfig}`); // Get the contributed profile if it was provided const contributedProfile = options?.skipContributedProfileCheck ? undefined : await this._getContributedProfile(shellLaunchConfig, options); From 3e214053fc48c5a057d51d2644173fee586f816c Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Wed, 19 Nov 2025 00:01:20 -0800 Subject: [PATCH 12/14] stringify for better logs. isLocalRemoteTerminal value is still false --- .../contrib/terminal/browser/terminalService.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 94532a249b057..2877d0505966b 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -969,6 +969,8 @@ export class TerminalService extends Disposable implements ITerminalService { // terminals need to be launched before remote connections are established. const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; this._logService.debug(`#terminalService#createTerminal: Value of isLocalInRemoteTerminal is: ${isLocalInRemoteTerminal}`); + this._logService.debug(`$terminalService#createTerminal: options are: ${JSON.stringify(options)}`); + this._logService.debug(`#terminalService#createTerminal: available profile length is: ${this._terminalProfileService.availableProfiles.length}`); if (this._terminalProfileService.availableProfiles.length === 0) { this._logService.debug(`#terminalService#createTerminal: available profile length is zero`); const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config; @@ -985,7 +987,7 @@ export class TerminalService extends Disposable implements ITerminalService { } let config = options?.config; - this._logService.debug(`#terminalService#createTerminal: config ${config}`); + this._logService.debug(`#terminalService#createTerminal: config ${JSON.stringify(config)}`); if (!config && isLocalInRemoteTerminal) { this._logService.debug(`#terminalService#createTerminal: !config and isLocalInRemoteTerminal`); const backend = await this._terminalInstanceService.getBackend(undefined); @@ -993,17 +995,17 @@ export class TerminalService extends Disposable implements ITerminalService { this._logService.debug(`#terminalService#createTerminal: backend is: ${backend} and executable is: ${executable}`); if (executable) { config = { executable }; - this._logService.debug(`#terminalService#createTerminal: setting current config ${config} to ${executable}`); + this._logService.debug(`#terminalService#createTerminal: setting current config ${JSON.stringify(config)} to ${executable}`); } } if (!config) { config = this._terminalProfileService.getDefaultProfile(); - this._logService.debug(`#terminalService#createTerminal: !config, so set it to new value: ${config}`); + this._logService.debug(`#terminalService#createTerminal: !config, so set it to new value: ${JSON.stringify(config)}`); } const shellLaunchConfig = config && 'extensionIdentifier' in config ? {} : this._terminalInstanceService.convertProfileToShellLaunchConfig(config || {}); - this._logService.debug(`#terminalService#createTerminal: shellLaunchConfig is ${shellLaunchConfig}`); + this._logService.debug(`#terminalService#createTerminal: shellLaunchConfig is ${JSON.stringify(shellLaunchConfig)}`); // Get the contributed profile if it was provided const contributedProfile = options?.skipContributedProfileCheck ? undefined : await this._getContributedProfile(shellLaunchConfig, options); From d9844565f35373a3c7744a45c53b4fe02059bd68 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Wed, 19 Nov 2025 08:55:37 -0800 Subject: [PATCH 13/14] more and more logs --- .../workbench/contrib/terminal/browser/terminalService.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 2877d0505966b..1a7ae13e5125e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -969,7 +969,11 @@ export class TerminalService extends Disposable implements ITerminalService { // terminals need to be launched before remote connections are established. const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; this._logService.debug(`#terminalService#createTerminal: Value of isLocalInRemoteTerminal is: ${isLocalInRemoteTerminal}`); - this._logService.debug(`$terminalService#createTerminal: options are: ${JSON.stringify(options)}`); + this._logService.debug(`#terminalService#createTerminal: options are: ${JSON.stringify(options)}`); + this._logService.debug(`terminalService#createTerminal: Value of this._remoteAgentService.getConnection() is: ${this._remoteAgentService.getConnection()}`); + this._logService.debug(`#terminalService#createTerminal: Value of options?.cwd is: ${options?.cwd}`); + this._logService.debug(`#terminalService#createTerminal: Value of URI.isUri:: ${URI.isUri(options?.cwd)} and scheme is: ${options?.cwd && URI.isUri(options.cwd) ? options.cwd.scheme : 'N/A'}`); + this._logService.debug(`#terminalService#createTerminal: options?.cwd.scheme === Schemas.vscodeFileResource is: ${options?.cwd && URI.isUri(options.cwd) ? options.cwd.scheme === Schemas.vscodeFileResource : 'N/A'}`); this._logService.debug(`#terminalService#createTerminal: available profile length is: ${this._terminalProfileService.availableProfiles.length}`); if (this._terminalProfileService.availableProfiles.length === 0) { this._logService.debug(`#terminalService#createTerminal: available profile length is zero`); From 15178bf549761f3ae23fa744c81d4ccd3a4852c8 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Wed, 19 Nov 2025 10:23:59 -0800 Subject: [PATCH 14/14] Bug fixed) Use Schemas.file instead of Shemas.vscodeFileResource --- .../terminal/browser/terminalService.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 1a7ae13e5125e..1e7a11057dd23 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -967,19 +967,10 @@ export class TerminalService extends Disposable implements ITerminalService { // Await the initialization of available profiles as long as this is not a pty terminal or a // local terminal in a remote workspace as profile won't be used in those cases and these // terminals need to be launched before remote connections are established. - const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.vscodeFileResource; - this._logService.debug(`#terminalService#createTerminal: Value of isLocalInRemoteTerminal is: ${isLocalInRemoteTerminal}`); - this._logService.debug(`#terminalService#createTerminal: options are: ${JSON.stringify(options)}`); - this._logService.debug(`terminalService#createTerminal: Value of this._remoteAgentService.getConnection() is: ${this._remoteAgentService.getConnection()}`); - this._logService.debug(`#terminalService#createTerminal: Value of options?.cwd is: ${options?.cwd}`); - this._logService.debug(`#terminalService#createTerminal: Value of URI.isUri:: ${URI.isUri(options?.cwd)} and scheme is: ${options?.cwd && URI.isUri(options.cwd) ? options.cwd.scheme : 'N/A'}`); - this._logService.debug(`#terminalService#createTerminal: options?.cwd.scheme === Schemas.vscodeFileResource is: ${options?.cwd && URI.isUri(options.cwd) ? options.cwd.scheme === Schemas.vscodeFileResource : 'N/A'}`); - this._logService.debug(`#terminalService#createTerminal: available profile length is: ${this._terminalProfileService.availableProfiles.length}`); + const isLocalInRemoteTerminal = this._remoteAgentService.getConnection() && URI.isUri(options?.cwd) && options?.cwd.scheme === Schemas.file; if (this._terminalProfileService.availableProfiles.length === 0) { - this._logService.debug(`#terminalService#createTerminal: available profile length is zero`); const isPtyTerminal = options?.config && 'customPtyImplementation' in options.config; if (!isPtyTerminal && !isLocalInRemoteTerminal) { - this._logService.debug(`#terminalService#createTerminal: !isPtyTerminal and !isLocalInRemoteTerminal`); if (this._connectionState === TerminalConnectionState.Connecting) { mark(`code/terminal/willGetProfiles`); } @@ -991,25 +982,20 @@ export class TerminalService extends Disposable implements ITerminalService { } let config = options?.config; - this._logService.debug(`#terminalService#createTerminal: config ${JSON.stringify(config)}`); if (!config && isLocalInRemoteTerminal) { - this._logService.debug(`#terminalService#createTerminal: !config and isLocalInRemoteTerminal`); const backend = await this._terminalInstanceService.getBackend(undefined); const executable = await backend?.getDefaultSystemShell(); - this._logService.debug(`#terminalService#createTerminal: backend is: ${backend} and executable is: ${executable}`); if (executable) { config = { executable }; - this._logService.debug(`#terminalService#createTerminal: setting current config ${JSON.stringify(config)} to ${executable}`); } } if (!config) { config = this._terminalProfileService.getDefaultProfile(); - this._logService.debug(`#terminalService#createTerminal: !config, so set it to new value: ${JSON.stringify(config)}`); } const shellLaunchConfig = config && 'extensionIdentifier' in config ? {} : this._terminalInstanceService.convertProfileToShellLaunchConfig(config || {}); - this._logService.debug(`#terminalService#createTerminal: shellLaunchConfig is ${JSON.stringify(shellLaunchConfig)}`); + // Get the contributed profile if it was provided const contributedProfile = options?.skipContributedProfileCheck ? undefined : await this._getContributedProfile(shellLaunchConfig, options);