feat: add Git Bash detection and requirement check for Windows agents (#11388)

* feat: add Git Bash detection and requirement check for Windows agents

- Add System_CheckGitBash IPC channel for detecting Git Bash installation
- Implement detection logic checking common installation paths and PATH environment
- Display non-closable error alert in AgentModal when Git Bash is not found
- Disable agent creation/edit button until Git Bash is installed
- Add recheck functionality to verify installation without restarting app

Git Bash is required for agents to function properly on Windows systems.

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

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

* i18n: add Git Bash requirement translations for agent modal

- Add English translations for Git Bash detection warnings
- Add Simplified Chinese (zh-cn) translations
- Add Traditional Chinese (zh-tw) translations

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

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

* format code

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
beyondkmp 2025-11-21 21:32:53 +08:00 committed by GitHub
parent eee49d1580
commit 852192dce6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 188 additions and 3 deletions

View File

@ -235,6 +235,7 @@ export enum IpcChannel {
System_GetDeviceType = 'system:getDeviceType',
System_GetHostname = 'system:getHostname',
System_GetCpuName = 'system:getCpuName',
System_CheckGitBash = 'system:checkGitBash',
// DevTools
System_ToggleDevTools = 'system:toggleDevTools',

View File

@ -493,6 +493,44 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
ipcMain.handle(IpcChannel.System_GetDeviceType, () => (isMac ? 'mac' : isWin ? 'windows' : 'linux'))
ipcMain.handle(IpcChannel.System_GetHostname, () => require('os').hostname())
ipcMain.handle(IpcChannel.System_GetCpuName, () => require('os').cpus()[0].model)
ipcMain.handle(IpcChannel.System_CheckGitBash, () => {
if (!isWin) {
return true // Non-Windows systems don't need Git Bash
}
try {
// Check common Git Bash installation paths
const commonPaths = [
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'),
path.join(process.env.LOCALAPPDATA || '', 'Programs', 'Git', 'bin', 'bash.exe')
]
// Check if any of the common paths exist
for (const bashPath of commonPaths) {
if (fs.existsSync(bashPath)) {
logger.debug('Git Bash found', { path: bashPath })
return true
}
}
// Check if git is in PATH
const { execSync } = require('child_process')
try {
execSync('git --version', { stdio: 'ignore' })
logger.debug('Git found in PATH')
return true
} catch {
// Git not in PATH
}
logger.debug('Git Bash not found on Windows system')
return false
} catch (error) {
logger.error('Error checking Git Bash', error as Error)
return false
}
})
ipcMain.handle(IpcChannel.System_ToggleDevTools, (e) => {
const win = BrowserWindow.fromWebContents(e.sender)
win && win.webContents.toggleDevTools()

View File

@ -122,7 +122,8 @@ const api = {
system: {
getDeviceType: () => ipcRenderer.invoke(IpcChannel.System_GetDeviceType),
getHostname: () => ipcRenderer.invoke(IpcChannel.System_GetHostname),
getCpuName: () => ipcRenderer.invoke(IpcChannel.System_GetCpuName)
getCpuName: () => ipcRenderer.invoke(IpcChannel.System_GetCpuName),
checkGitBash: (): Promise<boolean> => ipcRenderer.invoke(IpcChannel.System_CheckGitBash)
},
devTools: {
toggle: () => ipcRenderer.invoke(IpcChannel.System_ToggleDevTools)

View File

@ -15,7 +15,7 @@ import type {
UpdateAgentForm
} from '@renderer/types'
import { AgentConfigurationSchema, isAgentType } from '@renderer/types'
import { Button, Input, Modal, Select } from 'antd'
import { Alert, Button, Input, Modal, Select } from 'antd'
import { AlertTriangleIcon } from 'lucide-react'
import type { ChangeEvent, FormEvent } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
@ -58,6 +58,7 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
const isEditing = (agent?: AgentWithTools) => agent !== undefined
const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
const [hasGitBash, setHasGitBash] = useState<boolean>(true)
useEffect(() => {
if (open) {
@ -65,6 +66,30 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
}
}, [agent, open])
const checkGitBash = useCallback(
async (showToast = false) => {
try {
const gitBashInstalled = await window.api.system.checkGitBash()
setHasGitBash(gitBashInstalled)
if (showToast) {
if (gitBashInstalled) {
window.toast.success(t('agent.gitBash.success', 'Git Bash detected successfully!'))
} else {
window.toast.error(t('agent.gitBash.notFound', 'Git Bash not found. Please install it first.'))
}
}
} catch (error) {
logger.error('Failed to check Git Bash:', error as Error)
setHasGitBash(true) // Default to true on error to avoid false warnings
}
},
[t]
)
useEffect(() => {
checkGitBash()
}, [checkGitBash])
const selectedPermissionMode = form.configuration?.permission_mode ?? 'default'
const onPermissionModeChange = useCallback((value: PermissionMode) => {
@ -275,6 +300,36 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
footer={null}>
<StyledForm onSubmit={onSubmit}>
<FormContent>
{!hasGitBash && (
<Alert
message={t('agent.gitBash.error.title', 'Git Bash Required')}
description={
<div>
<div style={{ marginBottom: 8 }}>
{t(
'agent.gitBash.error.description',
'Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from'
)}{' '}
<a
href="https://git-scm.com/download/win"
onClick={(e) => {
e.preventDefault()
window.api.openWebsite('https://git-scm.com/download/win')
}}
style={{ textDecoration: 'underline' }}>
git-scm.com
</a>
</div>
<Button size="small" onClick={() => checkGitBash(true)}>
{t('agent.gitBash.error.recheck', 'Recheck Git Bash Installation')}
</Button>
</div>
}
type="error"
showIcon
style={{ marginBottom: 16 }}
/>
)}
<FormRow>
<FormItem style={{ flex: 1 }}>
<Label>
@ -377,7 +432,7 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
<FormFooter>
<Button onClick={onCancel}>{t('common.close')}</Button>
<Button type="primary" htmlType="submit" loading={loadingRef.current}>
<Button type="primary" htmlType="submit" loading={loadingRef.current} disabled={!hasGitBash}>
{isEditing(agent) ? t('common.confirm') : t('common.add')}
</Button>
</FormFooter>

View File

@ -27,6 +27,15 @@
"null_id": "Agent ID is null."
}
},
"gitBash": {
"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"
},
"notFound": "Git Bash not found. Please install it first.",
"success": "Git Bash detected successfully!"
},
"input": {
"placeholder": "Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "智能体 ID 为空。"
}
},
"gitBash": {
"error": {
"description": "在 Windows 上运行智能体需要 Git Bash。没有它智能体无法运行。请从以下地址安装 Git for Windows",
"recheck": "重新检测 Git Bash 安装",
"title": "需要 Git Bash"
},
"notFound": "未找到 Git Bash。请先安装。",
"success": "成功检测到 Git Bash"
},
"input": {
"placeholder": "在这里输入消息,按 {{key}} 发送 - @ 选择路径, / 选择命令"
},

View File

@ -27,6 +27,15 @@
"null_id": "代理程式 ID 為空。"
}
},
"gitBash": {
"error": {
"description": "在 Windows 上執行代理程式需要 Git Bash。沒有它代理程式無法運作。請從以下地址安裝 Git for Windows",
"recheck": "重新檢測 Git Bash 安裝",
"title": "需要 Git Bash"
},
"notFound": "找不到 Git Bash。請先安裝。",
"success": "成功偵測到 Git Bash"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "Agent ID ist leer."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "Το ID του πράκτορα είναι null."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "El ID del agente es nulo."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "L'ID de l'agent est nul."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "エージェント ID が null です。"
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "O ID do agente é nulo."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},

View File

@ -27,6 +27,15 @@
"null_id": "ID агента равен null."
}
},
"gitBash": {
"error": {
"description": "[to be translated]:Git Bash is required to run agents on Windows. The agent cannot function without it. Please install Git for Windows from",
"recheck": "[to be translated]:Recheck Git Bash Installation",
"title": "[to be translated]:Git Bash Required"
},
"notFound": "[to be translated]:Git Bash not found. Please install it first.",
"success": "[to be translated]:Git Bash detected successfully!"
},
"input": {
"placeholder": "[to be translated]:Enter your message here, send with {{key}} - @ select path, / select command"
},