diff --git a/src/main/git/runner.test.ts b/src/main/git/runner.test.ts index 57b04831acc..a5ba0e8b607 100644 --- a/src/main/git/runner.test.ts +++ b/src/main/git/runner.test.ts @@ -218,3 +218,44 @@ describe('nonInteractiveGitEnv credential-interactivity disable (STA-1292)', () expect(env.GIT_SSH_COMMAND).toBe('ssh -o BatchMode=yes') }) }) + +describe('guard-env WSLENV forwarding (#7652)', () => { + it('registers the guard vars in WSLENV on Windows so WSL-routed git imports them', () => { + const env = promptGuardGitEnv({ PATH: '/usr/bin' }, 'win32') + const keys = (env.WSLENV ?? '').split(':') + expect(keys).toContain('GIT_TERMINAL_PROMPT') + expect(keys).toContain('GCM_INTERACTIVE') + expect(keys).toContain('GIT_CONFIG_COUNT') + expect(keys).toContain('GIT_CONFIG_KEY_0') + expect(keys).toContain('GIT_CONFIG_VALUE_0') + expect(keys).toContain('GIT_CONFIG_KEY_1') + expect(keys).toContain('GIT_CONFIG_VALUE_1') + // Windows askpass paths are meaningless inside a distro. + expect(keys).not.toContain('GIT_ASKPASS') + expect(keys).not.toContain('SSH_ASKPASS') + }) + + it('preserves a caller-set WSLENV instead of clobbering it', () => { + const env = promptGuardGitEnv({ PATH: '/usr/bin', WSLENV: 'MY_VAR/p' }, 'win32') + const keys = (env.WSLENV ?? '').split(':') + expect(keys[0]).toBe('MY_VAR/p') + expect(keys).toContain('GIT_TERMINAL_PROMPT') + }) + + it('does not touch WSLENV on non-Windows hosts', () => { + const env = promptGuardGitEnv({ PATH: '/usr/bin' }, 'darwin') + expect(env.WSLENV).toBeUndefined() + }) + + it('forwards GIT_SSH_COMMAND only when nonInteractiveGitEnv set the default itself', () => { + const defaulted = nonInteractiveGitEnv({ PATH: '/usr/bin' }, 'win32') + expect((defaulted.WSLENV ?? '').split(':')).toContain('GIT_SSH_COMMAND') + + // A caller's Windows-specific ssh command must not leak into the distro. + const callerSet = nonInteractiveGitEnv( + { PATH: '/usr/bin', GIT_SSH_COMMAND: 'C:\\ssh\\ssh.exe' }, + 'win32' + ) + expect((callerSet.WSLENV ?? '').split(':')).not.toContain('GIT_SSH_COMMAND') + }) +}) diff --git a/src/main/git/runner.ts b/src/main/git/runner.ts index c9009845369..3dfec80d7fb 100644 --- a/src/main/git/runner.ts +++ b/src/main/git/runner.ts @@ -29,6 +29,7 @@ import { notifyGhPrimaryRateLimit } from './gh-rate-limit-breaker' import { getDefaultWslDistro, parseWslPath, toWindowsWslPath, type WslPathInfo } from '../wsl' +import { addWslEnvKeys } from '../wsl-env' import { getSpawnArgsForWindows, isWindowsBatchScript, resolveWindowsCommand } from '../win32-utils' import { buildWslLoginShellCommand, @@ -560,8 +561,13 @@ export function appendGitConfigEnv( return next } -export function promptGuardGitEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv { - return appendGitConfigEnv( +const GIT_CONFIG_WSLENV_KEY_RE = /^GIT_CONFIG_(?:COUNT|KEY_\d+|VALUE_\d+)$/ + +export function promptGuardGitEnv( + env: NodeJS.ProcessEnv = process.env, + platform: NodeJS.Platform = process.platform +): NodeJS.ProcessEnv { + const next = appendGitConfigEnv( { ...env, GIT_TERMINAL_PROMPT: '0', @@ -580,6 +586,19 @@ export function promptGuardGitEnv(env: NodeJS.ProcessEnv = process.env): NodeJS. ['credential.guiPrompt', 'false'] ] ) + if (platform === 'win32') { + // Why: wsl.exe only imports env vars named in WSLENV, so WSL-routed git + // would never see the guard — and WSL setups commonly use the Windows + // credential manager as git's helper, which pops the same OAuth window + // (issue #7652). Askpass vars are deliberately not forwarded: a Windows + // askpass path is meaningless inside the distro. + addWslEnvKeys(next, [ + 'GIT_TERMINAL_PROMPT', + 'GCM_INTERACTIVE', + ...Object.keys(next).filter((key) => GIT_CONFIG_WSLENV_KEY_RE.test(key)) + ]) + } + return next } /** @@ -597,10 +616,19 @@ export function promptGuardGitEnv(env: NodeJS.ProcessEnv = process.env): NodeJS. * (an unknown host still errors, it just won't hang). Only added when the * caller hasn't set its own GIT_SSH_COMMAND. */ -export function nonInteractiveGitEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv { - const next = promptGuardGitEnv(env) +export function nonInteractiveGitEnv( + env: NodeJS.ProcessEnv = process.env, + platform: NodeJS.Platform = process.platform +): NodeJS.ProcessEnv { + const next = promptGuardGitEnv(env, platform) if (!next.GIT_SSH_COMMAND) { next.GIT_SSH_COMMAND = 'ssh -o BatchMode=yes' + if (platform === 'win32') { + // Why: forward across the WSL boundary only when we set the value — + // plain `ssh` resolves inside the distro, whereas a caller's + // Windows-specific GIT_SSH_COMMAND must not leak into Linux git. + addWslEnvKeys(next, ['GIT_SSH_COMMAND']) + } } return next } diff --git a/src/main/ipc/pty.ts b/src/main/ipc/pty.ts index 38519a621dd..9576308e2ba 100644 --- a/src/main/ipc/pty.ts +++ b/src/main/ipc/pty.ts @@ -511,9 +511,10 @@ export type BuildPtyHostEnvOptions = { isWsl?: boolean agentStatusHooksEnabled: boolean networkProxySettings?: NetworkProxySettings - /** When true (the default at the call sites), a user terminal's git cannot - * pop the OS credential helper's interactive OAuth window (issue #7652). - * Agent terminals are always guarded regardless of this flag. */ + /** When true (the default at the call sites), a user terminal's git on a + * Windows host cannot pop Git Credential Manager's interactive OAuth window + * (issue #7652). No effect on non-Windows hosts; agent terminals are always + * guarded on every platform regardless of this flag. */ suppressUserTerminalGitCredentialPrompt?: boolean } diff --git a/src/main/ipc/terminal-git-credential-guard.test.ts b/src/main/ipc/terminal-git-credential-guard.test.ts index d25c8155846..280d3b8d521 100644 --- a/src/main/ipc/terminal-git-credential-guard.test.ts +++ b/src/main/ipc/terminal-git-credential-guard.test.ts @@ -7,32 +7,67 @@ function isGuarded(env: Record): boolean { } describe('applyTerminalGitCredentialPromptGuard', () => { - it('guards an agent terminal even when user-terminal suppression is off', () => { - const env: Record = { PATH: '/usr/bin' } - applyTerminalGitCredentialPromptGuard(env, { - launchCommand: 'claude', - suppressUserTerminalPrompt: false - }) - expect(isGuarded(env)).toBe(true) - // Never empties the credential helper — cached auth must keep working. - expect(env.GIT_CONFIG_COUNT).toBeDefined() - expect(Object.values(env)).not.toContain('credential.helper') + it('guards an agent terminal on every platform, even when user-terminal suppression is off', () => { + for (const platform of ['win32', 'darwin', 'linux'] as const) { + const env: Record = { PATH: '/usr/bin' } + applyTerminalGitCredentialPromptGuard(env, { + launchCommand: 'claude', + suppressUserTerminalPrompt: false, + platform + }) + expect(isGuarded(env), platform).toBe(true) + // Never empties the credential helper — cached auth must keep working. + expect(env.GIT_CONFIG_COUNT).toBeDefined() + expect(Object.values(env)).not.toContain('credential.helper') + } }) - it('guards a plain user terminal by default (suppression on)', () => { + it('guards a plain user terminal by default on a Windows host', () => { const env: Record = { PATH: '/usr/bin' } applyTerminalGitCredentialPromptGuard(env, { launchCommand: undefined, - suppressUserTerminalPrompt: true + suppressUserTerminalPrompt: true, + platform: 'win32' }) expect(isGuarded(env)).toBe(true) }) - it('leaves a plain user terminal untouched when the user opts out', () => { + it('registers the guard in WSLENV on Windows so WSL-routed git sees it too', () => { + const env: Record = { PATH: '/usr/bin' } + applyTerminalGitCredentialPromptGuard(env, { + launchCommand: undefined, + suppressUserTerminalPrompt: true, + platform: 'win32' + }) + const wslenvKeys = (env.WSLENV ?? '').split(':') + expect(wslenvKeys).toContain('GIT_TERMINAL_PROMPT') + expect(wslenvKeys).toContain('GCM_INTERACTIVE') + expect(wslenvKeys).toContain('GIT_CONFIG_COUNT') + expect(wslenvKeys).toContain('GIT_CONFIG_KEY_0') + expect(wslenvKeys).toContain('GIT_CONFIG_VALUE_0') + // Windows askpass paths are meaningless inside a distro. + expect(wslenvKeys).not.toContain('GIT_ASKPASS') + expect(wslenvKeys).not.toContain('SSH_ASKPASS') + }) + + it('leaves a user terminal untouched on non-Windows hosts — no popup exists there, only working tty prompts', () => { + for (const platform of ['darwin', 'linux'] as const) { + const env: Record = { PATH: '/usr/bin' } + applyTerminalGitCredentialPromptGuard(env, { + launchCommand: '/bin/zsh', + suppressUserTerminalPrompt: true, + platform + }) + expect(env, platform).toEqual({ PATH: '/usr/bin' }) + } + }) + + it('leaves a Windows user terminal untouched when the user opts out', () => { const env: Record = { PATH: '/usr/bin' } applyTerminalGitCredentialPromptGuard(env, { launchCommand: '/bin/zsh', - suppressUserTerminalPrompt: false + suppressUserTerminalPrompt: false, + platform: 'win32' }) expect(env.GIT_TERMINAL_PROMPT).toBeUndefined() expect(env.GCM_INTERACTIVE).toBeUndefined() diff --git a/src/main/ipc/terminal-git-credential-guard.ts b/src/main/ipc/terminal-git-credential-guard.ts index 1c3df7ac6bf..1e069d8e200 100644 --- a/src/main/ipc/terminal-git-credential-guard.ts +++ b/src/main/ipc/terminal-git-credential-guard.ts @@ -10,20 +10,29 @@ import { recognizeAgentProcessFromCommandLine } from '../../shared/agent-process * * The credential *helper* is kept, so cached-token auth still works; only the * interactive fallback prompt is suppressed. Agent terminals are always guarded - * (they can't dismiss a GUI popup); user terminals are guarded unless the user - * opted out via settings. + * on every platform (an agent can't answer a prompt, so failing fast beats + * hanging). User terminals are only guarded on Windows terminal hosts — the + * popup is a Windows credential-manager behavior, and on other platforms the + * guard would only take working tty prompts away from an interactive user — + * and the user can opt out via settings. * * Mutates `env` in place to match how the PTY host assembles its environment. */ export function applyTerminalGitCredentialPromptGuard( env: Record, - opts: { launchCommand?: string | null; suppressUserTerminalPrompt: boolean } + opts: { + launchCommand?: string | null + suppressUserTerminalPrompt: boolean + /** Injectable for tests; defaults to the spawning host's platform. */ + platform?: NodeJS.Platform + } ): void { const isAgentTerminal = Boolean(recognizeAgentProcessFromCommandLine(opts.launchCommand)) - if (!isAgentTerminal && !opts.suppressUserTerminalPrompt) { + const platform = opts.platform ?? process.platform + if (!isAgentTerminal && (!opts.suppressUserTerminalPrompt || platform !== 'win32')) { return } - for (const [key, value] of Object.entries(promptGuardGitEnv(env))) { + for (const [key, value] of Object.entries(promptGuardGitEnv(env, platform))) { if (typeof value === 'string') { env[key] = value } diff --git a/src/renderer/src/components/settings/TerminalAdvancedSection.test.tsx b/src/renderer/src/components/settings/TerminalAdvancedSection.test.tsx index a9f361d7ce3..c775df0a9aa 100644 --- a/src/renderer/src/components/settings/TerminalAdvancedSection.test.tsx +++ b/src/renderer/src/components/settings/TerminalAdvancedSection.test.tsx @@ -36,6 +36,7 @@ describe('TerminalAdvancedSection scrollback rows', () => { setScrollbackMode={vi.fn()} searchQuery="" showWindowsPowerShellImplementation={false} + showWindowsGitCredentialGuard={false} isMac={false} /> ) diff --git a/src/renderer/src/components/settings/TerminalAdvancedSection.tsx b/src/renderer/src/components/settings/TerminalAdvancedSection.tsx index 27d29ed4241..fb89e440863 100644 --- a/src/renderer/src/components/settings/TerminalAdvancedSection.tsx +++ b/src/renderer/src/components/settings/TerminalAdvancedSection.tsx @@ -10,12 +10,16 @@ import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group' import { SettingsRow, SettingsSegmentedControl, - SettingsSubsectionHeader + SettingsSubsectionHeader, + SettingsSwitchRow } from './SettingsFormControls' import { SCROLLBACK_PRESETS_ROWS } from './SettingsConstants' import { SearchableSetting } from './SearchableSetting' import { matchesSettingsSearch } from './settings-search' -import { getTerminalWindowsPowershellImplementationSearchEntry } from './terminal-windows-search' +import { + getTerminalGitCredentialPopupSearchEntry, + getTerminalWindowsPowershellImplementationSearchEntry +} from './terminal-windows-search' import { TerminalMacKeyboardSection } from './TerminalMacKeyboardSection' import { translate } from '@/i18n/i18n' @@ -26,6 +30,9 @@ type TerminalAdvancedSectionProps = { setScrollbackMode: (mode: 'preset' | 'custom') => void searchQuery: string showWindowsPowerShellImplementation: boolean + /** Windows terminal hosts only — the popup this guards against is a Windows + * credential-manager behavior (issue #7652). */ + showWindowsGitCredentialGuard: boolean pwshAvailable?: boolean isMac: boolean } @@ -41,6 +48,7 @@ export function TerminalAdvancedSection({ setScrollbackMode, searchQuery, showWindowsPowerShellImplementation, + showWindowsGitCredentialGuard, pwshAvailable, isMac }: TerminalAdvancedSectionProps): React.JSX.Element { @@ -296,6 +304,40 @@ export function TerminalAdvancedSection({ ) : null} + {showWindowsGitCredentialGuard && + matchesSettingsSearch(searchQuery, getTerminalGitCredentialPopupSearchEntry()) ? ( + + + updateSettings({ + terminalSuppressGitCredentialPrompt: !( + settings.terminalSuppressGitCredentialPrompt ?? true + ) + }) + } + /> + + ) : null} + {isMac ? ( ) : null} diff --git a/src/renderer/src/components/settings/TerminalPane.tsx b/src/renderer/src/components/settings/TerminalPane.tsx index 679589846b6..1ae40eabe26 100644 --- a/src/renderer/src/components/settings/TerminalPane.tsx +++ b/src/renderer/src/components/settings/TerminalPane.tsx @@ -13,6 +13,7 @@ import { getTerminalSetupScriptSearchEntries } from './terminal-search' import { + getTerminalGitCredentialPopupSearchEntry, getTerminalRightClickToPasteSearchEntry, getTerminalWindowsPowershellImplementationSearchEntry, getTerminalWindowsShellSearchEntry @@ -104,6 +105,8 @@ export function TerminalPane({ searchQuery, getTerminalWindowsPowershellImplementationSearchEntry() )) || + (showWindowsHostSettings && + matchesSettingsSearch(searchQuery, getTerminalGitCredentialPopupSearchEntry())) || (isMac && (matchesSettingsSearch(searchQuery, getTerminalMacOptionSearchEntries()) || matchesSettingsSearch(searchQuery, getTerminalMacYenSearchEntries()))) ? ( @@ -115,6 +118,7 @@ export function TerminalPane({ setScrollbackMode={setScrollbackMode} searchQuery={searchQuery} showWindowsPowerShellImplementation={showWindowsPowerShellImplementation} + showWindowsGitCredentialGuard={showWindowsHostSettings} pwshAvailable={pwshAvailable} isMac={isMac} /> diff --git a/src/renderer/src/components/settings/terminal-windows-search.ts b/src/renderer/src/components/settings/terminal-windows-search.ts index fae8b6fca9f..2acf9996577 100644 --- a/src/renderer/src/components/settings/terminal-windows-search.ts +++ b/src/renderer/src/components/settings/terminal-windows-search.ts @@ -140,8 +140,68 @@ export const getTerminalRightClickToPasteSearchEntry = createLocalizedCatalog(() } ]) +export const getTerminalGitCredentialPopupSearchEntry = createLocalizedCatalog(() => [ + { + title: translate( + 'auto.components.settings.terminal.windows.search.8630676830', + 'Block Git Credential Popups' + ), + description: translate( + 'auto.components.settings.terminal.windows.search.9d8b09bc09', + 'Stop git in terminals from opening Git Credential Manager sign-in windows.' + ), + keywords: [ + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.e7d2793b03', + 'terminal' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.28ff08ed35', + 'windows' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.ba9f11ecc3', + 'git' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.7c7c74ef60', + 'credential' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.8eff361700', + 'popup' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.7c82e855b0', + 'oauth' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.bf215181b5', + 'github' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.b19a25c6a0', + 'sign in' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.ef5acdb939', + 'gcm' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.4ae35dbb42', + 'prompt' + ), + ...translateSearchKeyword( + 'auto.components.settings.terminal.windows.search.27e4a4878d', + 'credential manager' + ) + ] + } +]) + export const getTerminalWindowsSearchEntries = createLocalizedCatalog((): SettingsSearchEntry[] => [ ...getTerminalWindowsShellSearchEntry(), ...getTerminalWindowsPowershellImplementationSearchEntry(), - ...getTerminalRightClickToPasteSearchEntry() + ...getTerminalRightClickToPasteSearchEntry(), + ...getTerminalGitCredentialPopupSearchEntry() ]) diff --git a/src/renderer/src/i18n/locales/en.json b/src/renderer/src/i18n/locales/en.json index 570c20c6c54..cc9694bdca6 100644 --- a/src/renderer/src/i18n/locales/en.json +++ b/src/renderer/src/i18n/locales/en.json @@ -6678,7 +6678,8 @@ "fastDescription": "Extra multiplier while scrolling with a modifier key.", "tui": "TUI", "tuiDescription": "Discrete wheel reports for full-screen terminal apps." - } + }, + "3fab0f2239": "Stop git in user terminals from opening Git Credential Manager sign-in windows. Saved credentials still work; git fails fast instead of prompting. Applies to new terminals." }, "TerminalSettingsPreview": { "a63953a48a": "Preview {{value0}} theme", @@ -8397,7 +8398,9 @@ "6cd20b9e64": "cmd", "7c7056940a": "shell", "713c4a2f92": "Choose the default shell for new terminal panes on Windows.", - "13715f9d23": "Default Shell" + "13715f9d23": "Default Shell", + "8630676830": "Block Git Credential Popups", + "9d8b09bc09": "Stop git in terminals from opening Git Credential Manager sign-in windows." } } }, diff --git a/src/renderer/src/i18n/locales/es.json b/src/renderer/src/i18n/locales/es.json index 2543c3ce6d3..e1047ba9fc3 100644 --- a/src/renderer/src/i18n/locales/es.json +++ b/src/renderer/src/i18n/locales/es.json @@ -6641,7 +6641,8 @@ "fastDescription": "Multiplicador adicional al desplazarse con una tecla modificadora.", "tui": "TUI", "tuiDescription": "Eventos discretos de rueda para apps de terminal de pantalla completa." - } + }, + "3fab0f2239": "Stop git in user terminals from opening Git Credential Manager sign-in windows. Saved credentials still work; git fails fast instead of prompting. Applies to new terminals." }, "TerminalSettingsPreview": { "a63953a48a": "Vista previa del tema {{value0}}", @@ -8360,7 +8361,9 @@ "6cd20b9e64": "cmd", "7c7056940a": "shell", "713c4a2f92": "Elija el shell predeterminado para los nuevos paneles de terminal en Windows.", - "13715f9d23": "Shell predeterminado" + "13715f9d23": "Shell predeterminado", + "8630676830": "Block Git Credential Popups", + "9d8b09bc09": "Stop git in terminals from opening Git Credential Manager sign-in windows." } } }, diff --git a/src/renderer/src/i18n/locales/ja.json b/src/renderer/src/i18n/locales/ja.json index 9727ae4adc4..f3615777ae3 100644 --- a/src/renderer/src/i18n/locales/ja.json +++ b/src/renderer/src/i18n/locales/ja.json @@ -6663,7 +6663,8 @@ "fastDescription": "修飾キーを押しながらスクロールするときの追加倍率。", "tui": "TUI", "tuiDescription": "全画面ターミナルアプリ向けの離散的なホイール通知。" - } + }, + "3fab0f2239": "Stop git in user terminals from opening Git Credential Manager sign-in windows. Saved credentials still work; git fails fast instead of prompting. Applies to new terminals." }, "TerminalSettingsPreview": { "a63953a48a": "{{value0}} テーマのプレビュー", @@ -8382,7 +8383,9 @@ "6cd20b9e64": "cmd", "7c7056940a": "シェル", "713c4a2f92": "Windows 上の新規 terminal ペインのデフォルト シェルを選択します。", - "13715f9d23": "デフォルトのシェル" + "13715f9d23": "デフォルトのシェル", + "8630676830": "Block Git Credential Popups", + "9d8b09bc09": "Stop git in terminals from opening Git Credential Manager sign-in windows." } } }, diff --git a/src/renderer/src/i18n/locales/ko.json b/src/renderer/src/i18n/locales/ko.json index bff86bf9af6..383d25ac14a 100644 --- a/src/renderer/src/i18n/locales/ko.json +++ b/src/renderer/src/i18n/locales/ko.json @@ -6626,7 +6626,8 @@ "fastDescription": "수정 키로 스크롤할 때 적용되는 추가 배율.", "tui": "TUI", "tuiDescription": "전체 화면 터미널 앱을 위한 개별 휠 보고." - } + }, + "3fab0f2239": "Stop git in user terminals from opening Git Credential Manager sign-in windows. Saved credentials still work; git fails fast instead of prompting. Applies to new terminals." }, "TerminalSettingsPreview": { "a63953a48a": "{{value0}} 테마 미리보기", @@ -8345,7 +8346,9 @@ "6cd20b9e64": "cmd", "7c7056940a": "셸", "713c4a2f92": "Windows의 새 terminal 패널에 대한 기본 셸을 선택합니다.", - "13715f9d23": "기본 쉘" + "13715f9d23": "기본 쉘", + "8630676830": "Block Git Credential Popups", + "9d8b09bc09": "Stop git in terminals from opening Git Credential Manager sign-in windows." } } }, diff --git a/src/renderer/src/i18n/locales/zh.json b/src/renderer/src/i18n/locales/zh.json index a0b21163a78..89835a36ee3 100644 --- a/src/renderer/src/i18n/locales/zh.json +++ b/src/renderer/src/i18n/locales/zh.json @@ -6626,7 +6626,8 @@ "fastDescription": "按住修饰键滚动时的额外倍数。", "tui": "TUI", "tuiDescription": "面向全屏终端应用的离散滚轮报告。" - } + }, + "3fab0f2239": "Stop git in user terminals from opening Git Credential Manager sign-in windows. Saved credentials still work; git fails fast instead of prompting. Applies to new terminals." }, "TerminalSettingsPreview": { "a63953a48a": "预览 {{value0}} 主题", @@ -8345,7 +8346,9 @@ "6cd20b9e64": "指令", "7c7056940a": "shell", "713c4a2f92": "为 Windows 上的新终端窗格选择默认 Shell。", - "13715f9d23": "默认 Shell" + "13715f9d23": "默认 Shell", + "8630676830": "Block Git Credential Popups", + "9d8b09bc09": "Stop git in terminals from opening Git Credential Manager sign-in windows." } } }, diff --git a/src/shared/constants.ts b/src/shared/constants.ts index a443bd22388..65e6ada2492 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -252,9 +252,9 @@ export function getDefaultSettings(homedir: string): GlobalSettings { // is installed, with a safe fallback to the inbox Windows PowerShell. terminalWindowsPowerShellImplementation: 'auto', terminalMouseHideWhileTyping: false, - // Default on: suppress the OS credential helper's interactive OAuth popup - // for git in user terminals (issue #7652). Agent/automated contexts are - // guarded regardless of this setting. + // Default on: suppress Git Credential Manager's interactive OAuth popup + // for git in user terminals on Windows hosts (issue #7652). No effect on + // other platforms; agent/automated contexts are guarded regardless. terminalSuppressGitCredentialPrompt: true, terminalQuickCommands: getDefaultTerminalQuickCommands(), // Default false: opt-in only (matches Ghostty's default). Existing users diff --git a/src/shared/types.ts b/src/shared/types.ts index 3d87ef79d68..33779fa821b 100644 --- a/src/shared/types.ts +++ b/src/shared/types.ts @@ -2554,12 +2554,14 @@ export type GlobalSettings = { terminalPaddingX?: number terminalPaddingY?: number terminalMouseHideWhileTyping?: boolean - /** When on (default), git run in a user terminal cannot pop the OS credential - * helper's interactive OAuth window (e.g. Git Credential Manager's "Connect - * to GitHub" popup) — it uses cached credentials or fails fast instead of - * looping in network-restricted environments (issue #7652). Agent terminals - * and Orca-run setup scripts are always guarded regardless of this setting. - * Turn off to let your interactive terminal prompt via the OS helper. */ + /** When on (default), git run in a user terminal on a Windows terminal host + * cannot pop Git Credential Manager's interactive OAuth window ("Connect to + * GitHub") — it uses cached credentials or fails fast instead of looping in + * network-restricted environments (issue #7652). Only applies on Windows + * hosts: the popup is a Windows credential-manager behavior, and elsewhere + * the guard would only remove working tty prompts. Agent terminals and + * Orca-run setup scripts are always guarded on every platform regardless of + * this setting. Turn off to let your terminal prompt via the OS helper. */ terminalSuppressGitCredentialPrompt?: boolean terminalWordSeparator?: string terminalCursorOpacity?: number