diff --git a/cmd/desktop/app.go b/cmd/desktop/app.go
index c2bf7a7..a1fe4c3 100644
--- a/cmd/desktop/app.go
+++ b/cmd/desktop/app.go
@@ -505,8 +505,8 @@ func (a *App) SendUpdateNotification(title, message string) error {
func (a *App) DetectTerminals() string { return a.terminal.DetectTerminals() }
func (a *App) GetTerminalConfig() string { return a.terminal.GetTerminalConfig() }
-func (a *App) SaveTerminalConfig(selectedTerminal string, projectDirs []string) error {
- return a.terminal.SaveTerminalConfig(selectedTerminal, projectDirs)
+func (a *App) SaveTerminalConfig(selectedTerminal string, projectDirs []string, claudeCommand string) error {
+ return a.terminal.SaveTerminalConfig(selectedTerminal, projectDirs, claudeCommand)
}
func (a *App) AddProjectDir(dir string) error { return a.terminal.AddProjectDir(dir) }
func (a *App) RemoveProjectDir(dir string) error { return a.terminal.RemoveProjectDir(dir) }
diff --git a/cmd/desktop/frontend/src/i18n/en.js b/cmd/desktop/frontend/src/i18n/en.js
index db2c9bd..5eba077 100644
--- a/cmd/desktop/frontend/src/i18n/en.js
+++ b/cmd/desktop/frontend/src/i18n/en.js
@@ -446,6 +446,8 @@ export default {
confirmDelete: 'Are you sure you want to delete this project directory?',
addDirFailed: 'Failed to add directory',
dirExists: 'Directory already exists',
+ launcherCommand: 'Launcher Command',
+ launcherCommandHelp: 'Custom CLI command to launch Claude Code, defaults to claude (e.g., hapi)',
// Error messages
errors: {
directory_already_exists: 'Directory already exists'
diff --git a/cmd/desktop/frontend/src/i18n/zh-CN.js b/cmd/desktop/frontend/src/i18n/zh-CN.js
index f3fbca0..fced0a1 100644
--- a/cmd/desktop/frontend/src/i18n/zh-CN.js
+++ b/cmd/desktop/frontend/src/i18n/zh-CN.js
@@ -446,6 +446,8 @@ export default {
confirmDelete: '确定要删除此项目目录吗?',
addDirFailed: '添加目录失败',
dirExists: '目录已存在',
+ launcherCommand: '启动命令',
+ launcherCommandHelp: '自定义 Claude Code 启动命令,默认为 claude(例如:hapi)',
// 错误消息
errors: {
directory_already_exists: '目录已存在'
diff --git a/cmd/desktop/frontend/src/modules/terminal.js b/cmd/desktop/frontend/src/modules/terminal.js
index 7cd3433..10cc44f 100644
--- a/cmd/desktop/frontend/src/modules/terminal.js
+++ b/cmd/desktop/frontend/src/modules/terminal.js
@@ -24,6 +24,7 @@ export function initTerminal() {
window.showTerminalModal = showTerminalModal;
window.closeTerminalModal = closeTerminalModal;
window.onTerminalChange = onTerminalChange;
+ window.onClaudeCommandChange = onClaudeCommandChange;
window.addProjectDir = addProjectDir;
window.removeProjectDir = removeProjectDir;
window.launchTerminal = launchTerminal;
@@ -87,6 +88,11 @@ async function loadTerminalConfig() {
if (select && terminalConfig.selectedTerminal) {
select.value = terminalConfig.selectedTerminal;
}
+ // Update claudeCommand input
+ const cmdInput = document.getElementById('claudeCommandInput');
+ if (cmdInput) {
+ cmdInput.value = terminalConfig.claudeCommand || '';
+ }
} catch (err) {
console.error('Failed to load terminal config:', err);
}
@@ -105,12 +111,22 @@ async function onTerminalChange() {
const select = document.getElementById('terminalSelect');
terminalConfig.selectedTerminal = select.value;
try {
- await SaveTerminalConfig(terminalConfig.selectedTerminal, terminalConfig.projectDirs);
+ await SaveTerminalConfig(terminalConfig.selectedTerminal, terminalConfig.projectDirs, terminalConfig.claudeCommand || '');
} catch (err) {
console.error('Failed to save terminal config:', err);
}
}
+async function onClaudeCommandChange() {
+ const cmdInput = document.getElementById('claudeCommandInput');
+ terminalConfig.claudeCommand = cmdInput ? cmdInput.value.trim() : '';
+ try {
+ await SaveTerminalConfig(terminalConfig.selectedTerminal, terminalConfig.projectDirs, terminalConfig.claudeCommand);
+ } catch (err) {
+ console.error('Failed to save claude command:', err);
+ }
+}
+
function renderProjectDirs() {
const container = document.getElementById('projectDirList');
if (!container) return;
diff --git a/cmd/desktop/frontend/src/modules/ui.js b/cmd/desktop/frontend/src/modules/ui.js
index 6ae70f9..1cfa63c 100644
--- a/cmd/desktop/frontend/src/modules/ui.js
+++ b/cmd/desktop/frontend/src/modules/ui.js
@@ -393,6 +393,12 @@ export function initUI() {
${t('terminal.selectTerminalHelp')}
+
+
+
+ ${t('terminal.launcherCommandHelp')}
+
${t('terminal.projectDirsHelp')}
diff --git a/cmd/desktop/frontend/wailsjs/go/main/App.js b/cmd/desktop/frontend/wailsjs/go/main/App.js
index f546a9f..111233b 100755
--- a/cmd/desktop/frontend/wailsjs/go/main/App.js
+++ b/cmd/desktop/frontend/wailsjs/go/main/App.js
@@ -282,8 +282,8 @@ export function SaveSettings(arg1) {
return window['go']['main']['App']['SaveSettings'](arg1);
}
-export function SaveTerminalConfig(arg1, arg2) {
- return window['go']['main']['App']['SaveTerminalConfig'](arg1, arg2);
+export function SaveTerminalConfig(arg1, arg2, arg3) {
+ return window['go']['main']['App']['SaveTerminalConfig'](arg1, arg2, arg3);
}
export function SelectDirectory() {
diff --git a/internal/config/config.go b/internal/config/config.go
index 29c601f..d99bda0 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -64,6 +64,7 @@ type UpdateConfig struct {
type TerminalConfig struct {
SelectedTerminal string `json:"selectedTerminal"` // Selected terminal ID
ProjectDirs []string `json:"projectDirs"` // Project directories
+ ClaudeCommand string `json:"claudeCommand"` // Custom launcher command, defaults to "claude"
}
// ProxyConfig represents HTTP proxy configuration
@@ -357,6 +358,7 @@ func (c *Config) GetTerminal() *TerminalConfig {
return &TerminalConfig{
SelectedTerminal: "cmd",
ProjectDirs: []string{},
+ ClaudeCommand: "",
}
}
return c.Terminal
@@ -600,6 +602,7 @@ func LoadFromStorage(storage StorageAdapter) (*Config, error) {
config.Terminal = &TerminalConfig{
SelectedTerminal: "cmd",
ProjectDirs: []string{},
+ ClaudeCommand: "",
}
if selectedTerminal, err := storage.GetConfig("terminal_selected"); err == nil && selectedTerminal != "" {
config.Terminal.SelectedTerminal = selectedTerminal
@@ -610,6 +613,9 @@ func LoadFromStorage(storage StorageAdapter) (*Config, error) {
config.Terminal.ProjectDirs = dirs
}
}
+ if claudeCmd, err := storage.GetConfig("terminal_claudeCommand"); err == nil {
+ config.Terminal.ClaudeCommand = claudeCmd
+ }
// Load Proxy config
if proxyURL, err := storage.GetConfig("proxy_url"); err == nil && proxyURL != "" {
@@ -733,6 +739,7 @@ func (c *Config) SaveToStorage(storage StorageAdapter) error {
if dirsJSON, err := json.Marshal(c.Terminal.ProjectDirs); err == nil {
storage.SetConfig("terminal_projectDirs", string(dirsJSON))
}
+ storage.SetConfig("terminal_claudeCommand", c.Terminal.ClaudeCommand)
}
// Save Proxy config
diff --git a/internal/service/terminal.go b/internal/service/terminal.go
index e03a21e..8d6e60a 100644
--- a/internal/service/terminal.go
+++ b/internal/service/terminal.go
@@ -37,10 +37,11 @@ func (t *TerminalService) GetTerminalConfig() string {
}
// SaveTerminalConfig saves the terminal configuration
-func (t *TerminalService) SaveTerminalConfig(selectedTerminal string, projectDirs []string) error {
+func (t *TerminalService) SaveTerminalConfig(selectedTerminal string, projectDirs []string, claudeCommand string) error {
terminalCfg := &config.TerminalConfig{
SelectedTerminal: selectedTerminal,
ProjectDirs: projectDirs,
+ ClaudeCommand: claudeCommand,
}
t.config.UpdateTerminal(terminalCfg)
@@ -51,7 +52,7 @@ func (t *TerminalService) SaveTerminalConfig(selectedTerminal string, projectDir
}
}
- logger.Info("Terminal config saved: terminal=%s, dirs=%d", selectedTerminal, len(projectDirs))
+ logger.Info("Terminal config saved: terminal=%s, dirs=%d, claudeCommand=%s", selectedTerminal, len(projectDirs), claudeCommand)
return nil
}
@@ -107,9 +108,10 @@ func (t *TerminalService) LaunchTerminal(dir string) error {
if terminalID == "" {
terminalID = "cmd"
}
+ customCmd := terminalCfg.ClaudeCommand
- logger.Info("Launching terminal: %s in %s", terminalID, dir)
- return terminal.LaunchTerminal(terminalID, dir)
+ logger.Info("Launching terminal: %s in %s (cmd=%s)", terminalID, dir, customCmd)
+ return terminal.LaunchTerminalWithCustomCmd(terminalID, dir, customCmd)
}
// GetSessions returns all sessions for a project directory
@@ -183,13 +185,14 @@ func (t *TerminalService) LaunchSessionTerminal(dir, sessionID string) error {
if terminalID == "" {
terminalID = "cmd"
}
+ customCmd := terminalCfg.ClaudeCommand
if sessionID != "" {
- logger.Info("Launching terminal with session: %s in %s", sessionID, dir)
+ logger.Info("Launching terminal with session: %s in %s (cmd=%s)", sessionID, dir, customCmd)
} else {
- logger.Info("Launching new terminal in %s", dir)
+ logger.Info("Launching new terminal in %s (cmd=%s)", dir, customCmd)
}
- return terminal.LaunchTerminalWithSession(terminalID, dir, sessionID)
+ return terminal.LaunchSessionTerminalWithCustomCmd(terminalID, dir, sessionID, customCmd)
}
// LaunchCodexTerminal launches a terminal with Codex
diff --git a/internal/terminal/launcher.go b/internal/terminal/launcher.go
index 829dec6..756deeb 100644
--- a/internal/terminal/launcher.go
+++ b/internal/terminal/launcher.go
@@ -16,7 +16,18 @@ func LaunchTerminal(terminalID, dir string) error {
// LaunchTerminalWithSession launches a terminal with optional session resume
func LaunchTerminalWithSession(terminalID, dir, sessionID string) error {
- cliCmd := getClaudeCommand(sessionID)
+ cliCmd := getClaudeCommand(sessionID, "")
+ return launchTerminalWithCli(terminalID, dir, cliCmd)
+}
+
+// LaunchTerminalWithCustomCmd launches a terminal with a custom CLI command
+func LaunchTerminalWithCustomCmd(terminalID, dir, customCmd string) error {
+ return LaunchSessionTerminalWithCustomCmd(terminalID, dir, "", customCmd)
+}
+
+// LaunchSessionTerminalWithCustomCmd launches a terminal with a custom CLI command and optional session
+func LaunchSessionTerminalWithCustomCmd(terminalID, dir, sessionID, customCmd string) error {
+ cliCmd := getClaudeCommand(sessionID, customCmd)
return launchTerminalWithCli(terminalID, dir, cliCmd)
}
@@ -89,10 +100,14 @@ func getShellType(shell string) shellType {
// getClaudeCommand returns the claude command with optional session resume
// On macOS, prepends npm initialization to handle lazy-loaded Node environments (nvm, fnm, etc.)
-func getClaudeCommand(sessionID string) string {
- cmd := "claude"
+func getClaudeCommand(sessionID, customCmd string) string {
+ base := "claude"
+ if customCmd != "" {
+ base = customCmd
+ }
+ cmd := base
if sessionID != "" {
- cmd = fmt.Sprintf("claude -r %s", shellEscape(sessionID))
+ cmd = fmt.Sprintf("%s -r %s", base, shellEscape(sessionID))
}
if runtime.GOOS == "darwin" {
// Trigger npm lazy-loading for nvm/fnm environments
@@ -239,7 +254,7 @@ func buildThirdPartyTerminalCommand(shell, dir, claudeCmd string) string {
}
func buildLaunchCommand(termInfo TerminalInfo, dir, sessionID string) *exec.Cmd {
- claudeCmd := getClaudeCommand(sessionID)
+ claudeCmd := getClaudeCommand(sessionID, "")
return buildLaunchCommandWithCli(termInfo, dir, claudeCmd)
}