@@ -5,12 +5,17 @@ import (
5
5
"encoding/json"
6
6
"fmt"
7
7
"os"
8
+ "os/exec"
8
9
"os/user"
9
10
"path/filepath"
11
+ "regexp"
10
12
"strings"
11
13
)
12
14
13
- const ConfigFileName = "config.json"
15
+ const (
16
+ ConfigFileName = "config.json"
17
+ defaultProgram = "claude"
18
+ )
14
19
15
20
// GetConfigDir returns the path to the application's configuration directory
16
21
func GetConfigDir () (string , error ) {
@@ -35,8 +40,14 @@ type Config struct {
35
40
36
41
// DefaultConfig returns the default configuration
37
42
func DefaultConfig () * Config {
43
+ program , err := GetClaudeCommand ()
44
+ if err != nil {
45
+ log .ErrorLog .Printf ("failed to get claude command: %v" , err )
46
+ program = defaultProgram
47
+ }
48
+
38
49
return & Config {
39
- DefaultProgram : "claude" ,
50
+ DefaultProgram : program ,
40
51
AutoYes : false ,
41
52
DaemonPollInterval : 1000 ,
42
53
BranchPrefix : func () string {
@@ -50,7 +61,54 @@ func DefaultConfig() *Config {
50
61
}
51
62
}
52
63
53
- // LoadConfig loads the configuration from disk. If it cannot be done, we return the default configuration.
64
+ // GetClaudeCommand attempts to find the "claude" command in the user's shell
65
+ // It checks in the following order:
66
+ // 1. Shell alias resolution: using "which" command
67
+ // 2. PATH lookup
68
+ //
69
+ // If both fail, it returns an error.
70
+ func GetClaudeCommand () (string , error ) {
71
+ shell := os .Getenv ("SHELL" )
72
+ if shell == "" {
73
+ shell = "/bin/bash" // Default to bash if SHELL is not set
74
+ }
75
+
76
+ // Force the shell to load the user's profile and then run the command
77
+ // For zsh, source .zshrc; for bash, source .bashrc
78
+ var shellCmd string
79
+ if strings .Contains (shell , "zsh" ) {
80
+ shellCmd = "source ~/.zshrc 2>/dev/null || true; which claude"
81
+ } else if strings .Contains (shell , "bash" ) {
82
+ shellCmd = "source ~/.bashrc 2>/dev/null || true; which claude"
83
+ } else {
84
+ shellCmd = "which claude"
85
+ }
86
+
87
+ cmd := exec .Command (shell , "-c" , shellCmd )
88
+ output , err := cmd .Output ()
89
+ if err == nil && len (output ) > 0 {
90
+ path := strings .TrimSpace (string (output ))
91
+ if path != "" {
92
+ // Check if the output is an alias definition and extract the actual path
93
+ // Handle formats like "claude: aliased to /path/to/claude" or other shell-specific formats
94
+ aliasRegex := regexp .MustCompile (`(?:aliased to|->|=)\s*([^\s]+)` )
95
+ matches := aliasRegex .FindStringSubmatch (path )
96
+ if len (matches ) > 1 {
97
+ path = matches [1 ]
98
+ }
99
+ return path , nil
100
+ }
101
+ }
102
+
103
+ // Otherwise, try to find in PATH directly
104
+ claudePath , err := exec .LookPath ("claude" )
105
+ if err == nil {
106
+ return claudePath , nil
107
+ }
108
+
109
+ return "" , fmt .Errorf ("claude command not found in aliases or PATH" )
110
+ }
111
+
54
112
func LoadConfig () * Config {
55
113
configDir , err := GetConfigDir ()
56
114
if err != nil {
0 commit comments