feat(CodeTools): add environment variable support for CLI tools; update UI to manage environment variables and enhance localization for related strings

This commit is contained in:
kangfenmao 2025-08-19 16:39:50 +08:00
parent 29d4e37f6b
commit 2265ecab21
10 changed files with 94 additions and 12 deletions

View File

@ -283,12 +283,11 @@ class CodeToolsService {
}
// Build command to execute
let baseCommand: string
let baseCommand = `${bunPath} "${executablePath}"`
const bunInstallPath = path.join(os.homedir(), '.cherrystudio')
if (isInstalled) {
// If already installed, run executable directly (with optional update message)
baseCommand = `"${executablePath}"`
if (updateMessage) {
baseCommand = `echo "Checking ${cliTool} version..."${updateMessage} && ${baseCommand}`
}
@ -301,7 +300,7 @@ class CodeToolsService {
: `export BUN_INSTALL="${bunInstallPath}" && export NPM_CONFIG_REGISTRY="${registryUrl}" &&`
const installCommand = `${installEnvPrefix} "${bunPath}" install -g ${packageName}`
baseCommand = `echo "Installing ${packageName}..." && ${installCommand} && echo "Installation complete, starting ${cliTool}..." && "${executablePath}"`
baseCommand = `echo "Installing ${packageName}..." && ${installCommand} && echo "Installation complete, starting ${cliTool}..." && "${baseCommand}"`
}
switch (platform) {

View File

@ -6,6 +6,7 @@ import {
removeDirectory,
resetCodeTools,
setCurrentDirectory,
setEnvironmentVariables,
setSelectedCliTool,
setSelectedModel
} from '@renderer/store/codeTools'
@ -33,6 +34,14 @@ export const useCodeTools = () => {
[dispatch]
)
// 设置环境变量
const setEnvVars = useCallback(
(envVars: string) => {
dispatch(setEnvironmentVariables(envVars))
},
[dispatch]
)
// 添加目录
const addDir = useCallback(
(directory: string) => {
@ -85,6 +94,9 @@ export const useCodeTools = () => {
// 获取当前CLI工具选择的模型
const selectedModel = codeToolsState.selectedModels[codeToolsState.selectedCliTool] || null
// 获取当前CLI工具的环境变量
const environmentVariables = codeToolsState?.environmentVariables?.[codeToolsState.selectedCliTool] || ''
// 检查是否可以启动(所有必需字段都已填写)
const canLaunch = Boolean(codeToolsState.selectedCliTool && selectedModel && codeToolsState.currentDirectory)
@ -92,6 +104,7 @@ export const useCodeTools = () => {
// 状态
selectedCliTool: codeToolsState.selectedCliTool,
selectedModel: selectedModel,
environmentVariables: environmentVariables,
directories: codeToolsState.directories,
currentDirectory: codeToolsState.currentDirectory,
canLaunch,
@ -99,6 +112,7 @@ export const useCodeTools = () => {
// 操作函数
setCliTool,
setModel,
setEnvVars,
addDir,
removeDir,
setCurrentDir,

View File

@ -654,6 +654,8 @@
"cli_tool": "CLI Tool",
"cli_tool_placeholder": "Select the CLI tool to use",
"description": "Quickly launch multiple code CLI tools to improve development efficiency",
"env_vars_help": "Enter custom environment variables (one per line, format: KEY=value)",
"environment_variables": "Environment Variables",
"folder_placeholder": "Select working directory",
"install_bun": "Install Bun",
"installing_bun": "Installing...",

View File

@ -654,6 +654,8 @@
"cli_tool": "CLI ツール",
"cli_tool_placeholder": "使用する CLI ツールを選択してください",
"description": "開発効率を向上させるために、複数のコード CLI ツールを迅速に起動します",
"env_vars_help": "環境変数を設定して、CLI ツールの実行時に使用します。各変数は 1 行ごとに設定してください。",
"environment_variables": "環境変数",
"folder_placeholder": "作業ディレクトリを選択してください",
"install_bun": "Bun をインストール",
"installing_bun": "インストール中...",

View File

@ -654,6 +654,8 @@
"cli_tool": "Инструмент",
"cli_tool_placeholder": "Выберите CLI-инструмент для использования",
"description": "Быстро запускает несколько CLI-инструментов для кода, повышая эффективность разработки",
"env_vars_help": "Установите переменные окружения для использования при запуске CLI-инструментов. Каждая переменная должна быть на отдельной строке в формате KEY=value",
"environment_variables": "Переменные окружения",
"folder_placeholder": "Выберите рабочую директорию",
"install_bun": "Установить Bun",
"installing_bun": "Установка...",

View File

@ -654,6 +654,8 @@
"cli_tool": "CLI 工具",
"cli_tool_placeholder": "选择要使用的 CLI 工具",
"description": "快速启动多个代码 CLI 工具,提高开发效率",
"env_vars_help": "输入自定义环境变量每行一个格式KEY=value",
"environment_variables": "环境变量",
"folder_placeholder": "选择工作目录",
"install_bun": "安装 Bun",
"installing_bun": "安装中...",

View File

@ -654,6 +654,8 @@
"cli_tool": "CLI 工具",
"cli_tool_placeholder": "選擇要使用的 CLI 工具",
"description": "快速啟動多個程式碼 CLI 工具,提高開發效率",
"env_vars_help": "輸入自定義環境變數每行一個格式KEY=value",
"environment_variables": "環境變數",
"folder_placeholder": "選擇工作目錄",
"install_bun": "安裝 Bun",
"installing_bun": "安裝中...",

View File

@ -10,7 +10,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { setIsBunInstalled } from '@renderer/store/mcp'
import { Model } from '@renderer/types'
import { Alert, Button, Checkbox, Select, Space } from 'antd'
import { Alert, Button, Checkbox, Input, Select, Space } from 'antd'
import { Download, Terminal, X } from 'lucide-react'
import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -35,11 +35,13 @@ const CodeToolsPage: FC = () => {
const {
selectedCliTool,
selectedModel,
environmentVariables,
directories,
currentDirectory,
canLaunch,
setCliTool,
setModel,
setEnvVars,
setCurrentDir,
removeDir,
selectFolder
@ -100,6 +102,11 @@ const CodeToolsPage: FC = () => {
}
}
// 处理环境变量更改
const handleEnvVarsChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setEnvVars(e.target.value)
}
// 处理文件夹选择
const handleFolderSelect = async () => {
try {
@ -214,6 +221,22 @@ const CodeToolsPage: FC = () => {
}
}
// 解析用户自定义的环境变量
if (environmentVariables) {
const lines = environmentVariables.split('\n')
for (const line of lines) {
const trimmedLine = line.trim()
if (trimmedLine && trimmedLine.includes('=')) {
const [key, ...valueParts] = trimmedLine.split('=')
const trimmedKey = key.trim()
const value = valueParts.join('=').trim()
if (trimmedKey) {
env[trimmedKey] = value
}
}
}
}
try {
// 这里可以添加实际的启动逻辑
logger.info('启动配置:', {
@ -340,6 +363,18 @@ const CodeToolsPage: FC = () => {
</Space.Compact>
</SettingsItem>
<SettingsItem>
<div className="settings-label">{t('code.environment_variables')}</div>
<Input.TextArea
placeholder={`KEY1=value1\nKEY2=value2`}
value={environmentVariables}
onChange={handleEnvVarsChange}
rows={2}
style={{ fontFamily: 'monospace' }}
/>
<div style={{ fontSize: 12, color: 'var(--color-text-3)', marginTop: 4 }}>{t('code.env_vars_help')}</div>
</SettingsItem>
<SettingsItem>
<div className="settings-label">{t('code.update_options')}</div>
<Checkbox checked={autoUpdateToLatest} onChange={(e) => setAutoUpdateToLatest(e.target.checked)}>

View File

@ -9,6 +9,8 @@ export interface CodeToolsState {
selectedCliTool: string
// 为每个 CLI 工具单独保存选择的模型
selectedModels: Record<string, Model | null>
// 为每个 CLI 工具单独保存环境变量
environmentVariables: Record<string, string>
// 记录用户选择过的所有目录,支持增删
directories: string[]
// 当前选择的目录
@ -22,6 +24,11 @@ export const initialState: CodeToolsState = {
'claude-code': null,
'gemini-cli': null
},
environmentVariables: {
'qwen-code': '',
'claude-code': '',
'gemini-cli': ''
},
directories: [],
currentDirectory: ''
}
@ -40,6 +47,18 @@ const codeToolsSlice = createSlice({
state.selectedModels[state.selectedCliTool] = action.payload
},
// 设置环境变量(为当前 CLI 工具设置)
setEnvironmentVariables: (state, action: PayloadAction<string>) => {
if (!state.environmentVariables) {
state.environmentVariables = {
'qwen-code': '',
'claude-code': '',
'gemini-cli': ''
}
}
state.environmentVariables[state.selectedCliTool] = action.payload
},
// 添加目录到列表中
addDirectory: (state, action: PayloadAction<string>) => {
const directory = action.payload
@ -87,14 +106,11 @@ const codeToolsSlice = createSlice({
// 重置所有设置
resetCodeTools: (state) => {
state.selectedCliTool = 'qwen-code'
state.selectedModels = {
'qwen-code': null,
'claude-code': null,
'gemini-cli': null
}
state.directories = []
state.currentDirectory = ''
state.selectedCliTool = initialState.selectedCliTool
state.selectedModels = initialState.selectedModels
state.environmentVariables = initialState.environmentVariables
state.directories = initialState.directories
state.currentDirectory = initialState.currentDirectory
}
}
})
@ -102,6 +118,7 @@ const codeToolsSlice = createSlice({
export const {
setSelectedCliTool,
setSelectedModel,
setEnvironmentVariables,
addDirectory,
removeDirectory,
setCurrentDirectory,

View File

@ -2123,6 +2123,13 @@ const migrateConfig = {
'133': (state: RootState) => {
try {
state.settings.sidebarIcons.visible.push('code_tools')
if (state.codeTools) {
state.codeTools.environmentVariables = {
'qwen-code': '',
'claude-code': '',
'gemini-cli': ''
}
}
return state
} catch (error) {
logger.error('migrate 133 error', error as Error)