feat: Support custom git bash path (#11813)

* feat: allow custom Git Bash path for Claude Code

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* format code

* format code

* update i18n

* fix: correct Git Bash invalid path translation key

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* test: cover null inputs for validateGitBashPath

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* refactor: rely on findGitBash for env override check

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* fix: validate env override for Git Bash path

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* chore: align Git Bash path getter with platform guard

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* test: cover env override behavior in findGitBash

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* refactor: unify Git Bash path detection logic

- Add customPath parameter to findGitBash() for config-based paths
- Simplify checkGitBash IPC handler by delegating to findGitBash
- Change validateGitBashPath success log level from info to debug
- Only show success Alert when custom path is configured
- Add tests for customPath parameter priority handling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
beyondkmp 2025-12-11 15:04:04 +08:00 committed by GitHub
parent 8cd4b1b747
commit ed695a8620
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 438 additions and 12 deletions

View File

@ -241,6 +241,8 @@ export enum IpcChannel {
System_GetHostname = 'system:getHostname',
System_GetCpuName = 'system:getCpuName',
System_CheckGitBash = 'system:checkGitBash',
System_GetGitBashPath = 'system:getGitBashPath',
System_SetGitBashPath = 'system:setGitBashPath',
// DevTools
System_ToggleDevTools = 'system:toggleDevTools',

View File

@ -6,7 +6,7 @@ import { loggerService } from '@logger'
import { isLinux, isMac, isPortable, isWin } from '@main/constant'
import { generateSignature } from '@main/integration/cherryai'
import anthropicService from '@main/services/AnthropicService'
import { findGitBash, getBinaryPath, isBinaryExists, runInstallScript } from '@main/utils/process'
import { findGitBash, getBinaryPath, isBinaryExists, runInstallScript, validateGitBashPath } from '@main/utils/process'
import { handleZoomFactor } from '@main/utils/zoom'
import type { SpanEntity, TokenUsage } from '@mcp-trace/trace-core'
import type { UpgradeChannel } from '@shared/config/constant'
@ -35,7 +35,7 @@ import appService from './services/AppService'
import AppUpdater from './services/AppUpdater'
import BackupManager from './services/BackupManager'
import { codeToolsService } from './services/CodeToolsService'
import { configManager } from './services/ConfigManager'
import { ConfigKeys, configManager } from './services/ConfigManager'
import CopilotService from './services/CopilotService'
import DxtService from './services/DxtService'
import { ExportService } from './services/ExportService'
@ -499,7 +499,8 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
}
try {
const bashPath = findGitBash()
const customPath = configManager.get(ConfigKeys.GitBashPath) as string | undefined
const bashPath = findGitBash(customPath)
if (bashPath) {
logger.info('Git Bash is available', { path: bashPath })
@ -513,6 +514,35 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
return false
}
})
ipcMain.handle(IpcChannel.System_GetGitBashPath, () => {
if (!isWin) {
return null
}
const customPath = configManager.get(ConfigKeys.GitBashPath) as string | undefined
return customPath ?? null
})
ipcMain.handle(IpcChannel.System_SetGitBashPath, (_, newPath: string | null) => {
if (!isWin) {
return false
}
if (!newPath) {
configManager.set(ConfigKeys.GitBashPath, null)
return true
}
const validated = validateGitBashPath(newPath)
if (!validated) {
return false
}
configManager.set(ConfigKeys.GitBashPath, validated)
return true
})
ipcMain.handle(IpcChannel.System_ToggleDevTools, (e) => {
const win = BrowserWindow.fromWebContents(e.sender)
win && win.webContents.toggleDevTools()

View File

@ -31,7 +31,8 @@ export enum ConfigKeys {
DisableHardwareAcceleration = 'disableHardwareAcceleration',
Proxy = 'proxy',
EnableDeveloperMode = 'enableDeveloperMode',
ClientId = 'clientId'
ClientId = 'clientId',
GitBashPath = 'gitBashPath'
}
export class ConfigManager {

View File

@ -15,6 +15,8 @@ import { query } from '@anthropic-ai/claude-agent-sdk'
import { loggerService } from '@logger'
import { config as apiConfigService } from '@main/apiServer/config'
import { validateModelId } from '@main/apiServer/utils'
import { ConfigKeys, configManager } from '@main/services/ConfigManager'
import { validateGitBashPath } from '@main/utils/process'
import getLoginShellEnvironment from '@main/utils/shell-env'
import { app } from 'electron'
@ -107,6 +109,8 @@ class ClaudeCodeService implements AgentServiceInterface {
Object.entries(loginShellEnv).filter(([key]) => !key.toLowerCase().endsWith('_proxy'))
) as Record<string, string>
const customGitBashPath = validateGitBashPath(configManager.get(ConfigKeys.GitBashPath) as string | undefined)
const env = {
...loginShellEnvWithoutProxies,
// TODO: fix the proxy api server
@ -126,7 +130,8 @@ class ClaudeCodeService implements AgentServiceInterface {
// Set CLAUDE_CONFIG_DIR to app's userData directory to avoid path encoding issues
// on Windows when the username contains non-ASCII characters (e.g., Chinese characters)
// This prevents the SDK from using the user's home directory which may have encoding problems
CLAUDE_CONFIG_DIR: path.join(app.getPath('userData'), '.claude')
CLAUDE_CONFIG_DIR: path.join(app.getPath('userData'), '.claude'),
...(customGitBashPath ? { CLAUDE_CODE_GIT_BASH_PATH: customGitBashPath } : {})
}
const errorChunks: string[] = []

View File

@ -3,7 +3,7 @@ import fs from 'fs'
import path from 'path'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { findExecutable, findGitBash } from '../process'
import { findExecutable, findGitBash, validateGitBashPath } from '../process'
// Mock dependencies
vi.mock('child_process')
@ -289,7 +289,133 @@ describe.skipIf(process.platform !== 'win32')('process utilities', () => {
})
})
describe('validateGitBashPath', () => {
it('returns null when path is null', () => {
const result = validateGitBashPath(null)
expect(result).toBeNull()
})
it('returns null when path is undefined', () => {
const result = validateGitBashPath(undefined)
expect(result).toBeNull()
})
it('returns normalized path when valid bash.exe exists', () => {
const customPath = 'C:\\PortableGit\\bin\\bash.exe'
vi.mocked(fs.existsSync).mockImplementation((p) => p === 'C:\\PortableGit\\bin\\bash.exe')
const result = validateGitBashPath(customPath)
expect(result).toBe('C:\\PortableGit\\bin\\bash.exe')
})
it('returns null when file does not exist', () => {
vi.mocked(fs.existsSync).mockReturnValue(false)
const result = validateGitBashPath('C:\\missing\\bash.exe')
expect(result).toBeNull()
})
it('returns null when path is not bash.exe', () => {
const customPath = 'C:\\PortableGit\\bin\\git.exe'
vi.mocked(fs.existsSync).mockReturnValue(true)
const result = validateGitBashPath(customPath)
expect(result).toBeNull()
})
})
describe('findGitBash', () => {
describe('customPath parameter', () => {
beforeEach(() => {
delete process.env.CLAUDE_CODE_GIT_BASH_PATH
})
it('uses customPath when valid', () => {
const customPath = 'C:\\CustomGit\\bin\\bash.exe'
vi.mocked(fs.existsSync).mockImplementation((p) => p === customPath)
const result = findGitBash(customPath)
expect(result).toBe(customPath)
expect(execFileSync).not.toHaveBeenCalled()
})
it('falls back when customPath is invalid', () => {
const customPath = 'C:\\Invalid\\bash.exe'
const gitPath = 'C:\\Program Files\\Git\\cmd\\git.exe'
const bashPath = 'C:\\Program Files\\Git\\bin\\bash.exe'
vi.mocked(fs.existsSync).mockImplementation((p) => {
if (p === customPath) return false
if (p === gitPath) return true
if (p === bashPath) return true
return false
})
vi.mocked(execFileSync).mockReturnValue(gitPath)
const result = findGitBash(customPath)
expect(result).toBe(bashPath)
})
it('prioritizes customPath over env override', () => {
const customPath = 'C:\\CustomGit\\bin\\bash.exe'
const envPath = 'C:\\EnvGit\\bin\\bash.exe'
process.env.CLAUDE_CODE_GIT_BASH_PATH = envPath
vi.mocked(fs.existsSync).mockImplementation((p) => p === customPath || p === envPath)
const result = findGitBash(customPath)
expect(result).toBe(customPath)
})
})
describe('env override', () => {
beforeEach(() => {
delete process.env.CLAUDE_CODE_GIT_BASH_PATH
})
it('uses CLAUDE_CODE_GIT_BASH_PATH when valid', () => {
const envPath = 'C:\\OverrideGit\\bin\\bash.exe'
process.env.CLAUDE_CODE_GIT_BASH_PATH = envPath
vi.mocked(fs.existsSync).mockImplementation((p) => p === envPath)
const result = findGitBash()
expect(result).toBe(envPath)
expect(execFileSync).not.toHaveBeenCalled()
})
it('falls back when CLAUDE_CODE_GIT_BASH_PATH is invalid', () => {
const envPath = 'C:\\Invalid\\bash.exe'
const gitPath = 'C:\\Program Files\\Git\\cmd\\git.exe'
const bashPath = 'C:\\Program Files\\Git\\bin\\bash.exe'
process.env.CLAUDE_CODE_GIT_BASH_PATH = envPath
vi.mocked(fs.existsSync).mockImplementation((p) => {
if (p === envPath) return false
if (p === gitPath) return true
if (p === bashPath) return true
return false
})
vi.mocked(execFileSync).mockReturnValue(gitPath)
const result = findGitBash()
expect(result).toBe(bashPath)
})
})
describe('git.exe path derivation', () => {
it('should derive bash.exe from standard Git installation (Git/cmd/git.exe)', () => {
const gitPath = 'C:\\Program Files\\Git\\cmd\\git.exe'

View File

@ -131,15 +131,37 @@ export function findExecutable(name: string): string | null {
/**
* Find Git Bash executable on Windows
* @param customPath - Optional custom path from config
* @returns Full path to bash.exe or null if not found
*/
export function findGitBash(): string | null {
export function findGitBash(customPath?: string | null): string | null {
// Git Bash is Windows-only
if (!isWin) {
return null
}
// 1. Find git.exe and derive bash.exe path
// 1. Check custom path from config first
if (customPath) {
const validated = validateGitBashPath(customPath)
if (validated) {
logger.debug('Using custom Git Bash path from config', { path: validated })
return validated
}
logger.warn('Custom Git Bash path provided but invalid', { path: customPath })
}
// 2. Check environment variable override
const envOverride = process.env.CLAUDE_CODE_GIT_BASH_PATH
if (envOverride) {
const validated = validateGitBashPath(envOverride)
if (validated) {
logger.debug('Using CLAUDE_CODE_GIT_BASH_PATH override for bash.exe', { path: validated })
return validated
}
logger.warn('CLAUDE_CODE_GIT_BASH_PATH provided but path is invalid', { path: envOverride })
}
// 3. Find git.exe and derive bash.exe path
const gitPath = findExecutable('git')
if (gitPath) {
// Try multiple possible locations for bash.exe relative to git.exe
@ -164,7 +186,7 @@ export function findGitBash(): string | null {
})
}
// 2. Fallback: check common Git Bash paths directly
// 4. Fallback: check common Git Bash paths directly
const commonBashPaths = [
path.join(process.env.ProgramFiles || 'C:\\Program Files', 'Git', 'bin', 'bash.exe'),
path.join(process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)', 'Git', 'bin', 'bash.exe'),
@ -181,3 +203,25 @@ export function findGitBash(): string | null {
logger.debug('Git Bash not found - checked git derivation and common paths')
return null
}
export function validateGitBashPath(customPath?: string | null): string | null {
if (!customPath) {
return null
}
const resolved = path.resolve(customPath)
if (!fs.existsSync(resolved)) {
logger.warn('Custom Git Bash path does not exist', { path: resolved })
return null
}
const isExe = resolved.toLowerCase().endsWith('bash.exe')
if (!isExe) {
logger.warn('Custom Git Bash path is not bash.exe', { path: resolved })
return null
}
logger.debug('Validated custom Git Bash path', { path: resolved })
return resolved
}

View File

@ -124,7 +124,10 @@ const api = {
getDeviceType: () => ipcRenderer.invoke(IpcChannel.System_GetDeviceType),
getHostname: () => ipcRenderer.invoke(IpcChannel.System_GetHostname),
getCpuName: () => ipcRenderer.invoke(IpcChannel.System_GetCpuName),
checkGitBash: (): Promise<boolean> => ipcRenderer.invoke(IpcChannel.System_CheckGitBash)
checkGitBash: (): Promise<boolean> => ipcRenderer.invoke(IpcChannel.System_CheckGitBash),
getGitBashPath: (): Promise<string | null> => ipcRenderer.invoke(IpcChannel.System_GetGitBashPath),
setGitBashPath: (newPath: string | null): Promise<boolean> =>
ipcRenderer.invoke(IpcChannel.System_SetGitBashPath, newPath)
},
devTools: {
toggle: () => ipcRenderer.invoke(IpcChannel.System_ToggleDevTools)

View File

@ -60,6 +60,7 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
const [hasGitBash, setHasGitBash] = useState<boolean>(true)
const [customGitBashPath, setCustomGitBashPath] = useState<string>('')
useEffect(() => {
if (open) {
@ -70,7 +71,11 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
const checkGitBash = useCallback(
async (showToast = false) => {
try {
const gitBashInstalled = await window.api.system.checkGitBash()
const [gitBashInstalled, savedPath] = await Promise.all([
window.api.system.checkGitBash(),
window.api.system.getGitBashPath().catch(() => null)
])
setCustomGitBashPath(savedPath ?? '')
setHasGitBash(gitBashInstalled)
if (showToast) {
if (gitBashInstalled) {
@ -93,6 +98,46 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
const selectedPermissionMode = form.configuration?.permission_mode ?? 'default'
const handlePickGitBash = useCallback(async () => {
try {
const selected = await window.api.file.select({
title: t('agent.gitBash.pick.title', 'Select Git Bash executable'),
filters: [{ name: 'Executable', extensions: ['exe'] }],
properties: ['openFile']
})
if (!selected || selected.length === 0) {
return
}
const pickedPath = selected[0].path
const ok = await window.api.system.setGitBashPath(pickedPath)
if (!ok) {
window.toast.error(
t('agent.gitBash.pick.invalidPath', 'Selected file is not a valid Git Bash executable (bash.exe).')
)
return
}
setCustomGitBashPath(pickedPath)
await checkGitBash(true)
} catch (error) {
logger.error('Failed to pick Git Bash path', error as Error)
window.toast.error(t('agent.gitBash.pick.failed', 'Failed to set Git Bash path'))
}
}, [checkGitBash, t])
const handleClearGitBash = useCallback(async () => {
try {
await window.api.system.setGitBashPath(null)
setCustomGitBashPath('')
await checkGitBash(true)
} catch (error) {
logger.error('Failed to clear Git Bash path', error as Error)
window.toast.error(t('agent.gitBash.pick.failed', 'Failed to set Git Bash path'))
}
}, [checkGitBash, t])
const onPermissionModeChange = useCallback((value: PermissionMode) => {
setForm((prev) => {
const parsedConfiguration = AgentConfigurationSchema.parse(prev.configuration ?? {})
@ -324,6 +369,9 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
<Button size="small" onClick={() => checkGitBash(true)}>
{t('agent.gitBash.error.recheck', 'Recheck Git Bash Installation')}
</Button>
<Button size="small" style={{ marginLeft: 8 }} onClick={handlePickGitBash}>
{t('agent.gitBash.pick.button', 'Select Git Bash Path')}
</Button>
</div>
}
type="error"
@ -331,6 +379,33 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
style={{ marginBottom: 16 }}
/>
)}
{hasGitBash && customGitBashPath && (
<Alert
message={t('agent.gitBash.found.title', 'Git Bash configured')}
description={
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<div>
{t('agent.gitBash.customPath', {
defaultValue: 'Using custom path: {{path}}',
path: customGitBashPath
})}
</div>
<div style={{ display: 'flex', gap: 8 }}>
<Button size="small" onClick={handlePickGitBash}>
{t('agent.gitBash.pick.button', 'Select Git Bash Path')}
</Button>
<Button size="small" onClick={handleClearGitBash}>
{t('agent.gitBash.clear.button', 'Clear custom path')}
</Button>
</div>
</div>
}
type="success"
showIcon
style={{ marginBottom: 16 }}
/>
)}
<FormRow>
<FormItem style={{ flex: 1 }}>
<Label>

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Using auto-detected Git Bash",
"clear": {
"button": "Clear custom path"
},
"customPath": "Using custom path: {{path}}",
"error": {
"description": "Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "Recheck Git Bash Installation",
"title": "Git Bash Required"
},
"found": {
"title": "Git Bash configured"
},
"notFound": "Git Bash not found. Please install it first.",
"pick": {
"button": "Select Git Bash Path",
"failed": "Failed to set Git Bash path",
"invalidPath": "Selected file is not a valid Git Bash executable (bash.exe).",
"title": "Select Git Bash executable"
},
"success": "Git Bash detected successfully!"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "使用自动检测的 Git Bash",
"clear": {
"button": "清除自定义路径"
},
"customPath": "使用自定义路径:{{path}}",
"error": {
"description": "在 Windows 上运行智能体需要 Git Bash。没有它智能体无法运行。请从以下地址安装 Git for Windows",
"recheck": "重新检测 Git Bash 安装",
"title": "需要 Git Bash"
},
"found": {
"title": "已配置 Git Bash"
},
"notFound": "未找到 Git Bash。请先安装。",
"pick": {
"button": "选择 Git Bash 路径",
"failed": "设置 Git Bash 路径失败",
"invalidPath": "选择的文件不是有效的 Git Bash 可执行文件bash.exe。",
"title": "选择 Git Bash 可执行文件"
},
"success": "成功检测到 Git Bash"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "使用自動偵測的 Git Bash",
"clear": {
"button": "清除自訂路徑"
},
"customPath": "使用自訂路徑:{{path}}",
"error": {
"description": "在 Windows 上執行代理程式需要 Git Bash。沒有它代理程式無法運作。請從以下地址安裝 Git for Windows",
"recheck": "重新檢測 Git Bash 安裝",
"title": "需要 Git Bash"
},
"found": {
"title": "已配置 Git Bash"
},
"notFound": "找不到 Git Bash。請先安裝。",
"pick": {
"button": "選擇 Git Bash 路徑",
"failed": "設定 Git Bash 路徑失敗",
"invalidPath": "選擇的檔案不是有效的 Git Bash 可執行檔bash.exe。",
"title": "選擇 Git Bash 可執行檔"
},
"success": "成功偵測到 Git Bash"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Automatisch ermitteltes Git Bash wird verwendet",
"clear": {
"button": "Benutzerdefinierten Pfad löschen"
},
"customPath": "Benutzerdefinierter Pfad: {{path}}",
"error": {
"description": "Git Bash ist erforderlich, um Agents unter Windows auszuführen. Der Agent kann ohne es nicht funktionieren. Bitte installieren Sie Git für Windows von",
"recheck": "Überprüfe die Git Bash-Installation erneut",
"title": "Git Bash erforderlich"
},
"found": {
"title": "Git Bash konfiguriert"
},
"notFound": "Git Bash nicht gefunden. Bitte installieren Sie es zuerst.",
"pick": {
"button": "Git Bash Pfad auswählen",
"failed": "Git Bash Pfad konnte nicht gesetzt werden",
"invalidPath": "Die ausgewählte Datei ist keine gültige Git Bash ausführbare Datei (bash.exe).",
"title": "Git Bash ausführbare Datei auswählen"
},
"success": "Git Bash erfolgreich erkannt!"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "[to be translated]:Using auto-detected Git Bash",
"clear": {
"button": "[to be translated]:Clear custom path"
},
"customPath": "[to be translated]:Using custom path: {{path}}",
"error": {
"description": "Το Git Bash απαιτείται για την εκτέλεση πρακτόρων στα Windows. Ο πράκτορας δεν μπορεί να λειτουργήσει χωρίς αυτό. Παρακαλούμε εγκαταστήστε το Git για Windows από",
"recheck": "Επανέλεγχος Εγκατάστασης του Git Bash",
"title": "Απαιτείται Git Bash"
},
"found": {
"title": "[to be translated]:Git Bash configured"
},
"notFound": "Το Git Bash δεν βρέθηκε. Παρακαλώ εγκαταστήστε το πρώτα.",
"pick": {
"button": "[to be translated]:Select Git Bash Path",
"failed": "[to be translated]:Failed to set Git Bash path",
"invalidPath": "[to be translated]:Selected file is not a valid Git Bash executable (bash.exe).",
"title": "[to be translated]:Select Git Bash executable"
},
"success": "Το Git Bash εντοπίστηκε με επιτυχία!"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Usando Git Bash detectado automáticamente",
"clear": {
"button": "Borrar ruta personalizada"
},
"customPath": "Usando ruta personalizada: {{path}}",
"error": {
"description": "Se requiere Git Bash para ejecutar agentes en Windows. El agente no puede funcionar sin él. Instale Git para Windows desde",
"recheck": "Volver a verificar la instalación de Git Bash",
"title": "Git Bash Requerido"
},
"found": {
"title": "Git Bash configurado"
},
"notFound": "Git Bash no encontrado. Por favor, instálalo primero.",
"pick": {
"button": "Seleccionar ruta de Git Bash",
"failed": "No se pudo configurar la ruta de Git Bash",
"invalidPath": "El archivo seleccionado no es un ejecutable válido de Git Bash (bash.exe).",
"title": "Seleccionar ejecutable de Git Bash"
},
"success": "¡Git Bash detectado con éxito!"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Utilisation de Git Bash détecté automatiquement",
"clear": {
"button": "Effacer le chemin personnalisé"
},
"customPath": "Utilisation du chemin personnalisé : {{path}}",
"error": {
"description": "Git Bash est requis pour exécuter des agents sur Windows. L'agent ne peut pas fonctionner sans. Veuillez installer Git pour Windows depuis",
"recheck": "Revérifier l'installation de Git Bash",
"title": "Git Bash requis"
},
"notFound": "Git Bash introuvable. Veuillez linstaller dabord.",
"found": {
"title": "Git Bash configuré"
},
"notFound": "Git Bash non trouvé. Veuillez l'installer d'abord.",
"pick": {
"button": "Sélectionner le chemin Git Bash",
"failed": "Échec de la configuration du chemin Git Bash",
"invalidPath": "Le fichier sélectionné n'est pas un exécutable Git Bash valide (bash.exe).",
"title": "Sélectionner l'exécutable Git Bash"
},
"success": "Git Bash détecté avec succès !"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "[to be translated]:Using auto-detected Git Bash",
"clear": {
"button": "[to be translated]:Clear custom path"
},
"customPath": "[to be translated]:Using custom path: {{path}}",
"error": {
"description": "Windowsでエージェントを実行するにはGit Bashが必要です。これがないとエージェントは動作しません。以下からGit for Windowsをインストールしてください。",
"recheck": "Git Bashのインストールを再確認してください",
"title": "Git Bashが必要です"
},
"found": {
"title": "[to be translated]:Git Bash configured"
},
"notFound": "Git Bash が見つかりません。先にインストールしてください。",
"pick": {
"button": "[to be translated]:Select Git Bash Path",
"failed": "[to be translated]:Failed to set Git Bash path",
"invalidPath": "[to be translated]:Selected file is not a valid Git Bash executable (bash.exe).",
"title": "[to be translated]:Select Git Bash executable"
},
"success": "Git Bashが正常に検出されました"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Usando Git Bash detectado automaticamente",
"clear": {
"button": "Limpar caminho personalizado"
},
"customPath": "Usando caminho personalizado: {{path}}",
"error": {
"description": "O Git Bash é necessário para executar agentes no Windows. O agente não pode funcionar sem ele. Por favor, instale o Git para Windows a partir de",
"recheck": "Reverificar a Instalação do Git Bash",
"title": "Git Bash Necessário"
},
"found": {
"title": "Git Bash configurado"
},
"notFound": "Git Bash não encontrado. Por favor, instale-o primeiro.",
"pick": {
"button": "Selecionar caminho do Git Bash",
"failed": "Falha ao configurar o caminho do Git Bash",
"invalidPath": "O arquivo selecionado não é um executável válido do Git Bash (bash.exe).",
"title": "Selecionar executável do Git Bash"
},
"success": "Git Bash detectado com sucesso!"
},
"input": {

View File

@ -31,12 +31,26 @@
}
},
"gitBash": {
"autoDetected": "Используется автоматически обнаруженный Git Bash",
"clear": {
"button": "Очистить пользовательский путь"
},
"customPath": "Используется пользовательский путь: {{path}}",
"error": {
"description": "Для запуска агентов в Windows требуется Git Bash. Без него агент не может работать. Пожалуйста, установите Git для Windows с",
"recheck": "Повторная проверка установки Git Bash",
"title": "Требуется Git Bash"
},
"found": {
"title": "Git Bash настроен"
},
"notFound": "Git Bash не найден. Пожалуйста, сначала установите его.",
"pick": {
"button": "Выбрать путь Git Bash",
"failed": "Не удалось настроить путь Git Bash",
"invalidPath": "Выбранный файл не является допустимым исполняемым файлом Git Bash (bash.exe).",
"title": "Выберите исполняемый файл Git Bash"
},
"success": "Git Bash успешно обнаружен!"
},
"input": {