Browse Source

feat: Make shell configurable via config file (#23)

Ed Zynda 9 months ago
parent
commit
4a444e9c9b
3 changed files with 60 additions and 4 deletions
  1. 33 0
      README.md
  2. 7 0
      internal/config/config.go
  3. 20 4
      internal/llm/tools/shell/shell.go

+ 33 - 0
README.md

@@ -136,6 +136,10 @@ You can configure OpenCode using environment variables:
       "command": "gopls"
       "command": "gopls"
     }
     }
   },
   },
+  "shell": {
+    "path": "/bin/zsh",
+    "args": ["-l"]
+  },
   "debug": false,
   "debug": false,
   "debugLSP": false
   "debugLSP": false
 }
 }
@@ -411,6 +415,35 @@ You can define any of the following color keys in your `customTheme`:
 
 
 You don't need to define all colors. Any undefined colors will fall back to the default "opencode" theme colors.
 You don't need to define all colors. Any undefined colors will fall back to the default "opencode" theme colors.
 
 
+### Shell Configuration
+
+OpenCode allows you to configure the shell used by the `bash` tool. By default, it uses:
+1. The shell specified in the config file (if provided)
+2. The shell from the `$SHELL` environment variable (if available)
+3. Falls back to `/bin/bash` if neither of the above is available
+
+To configure a custom shell, add a `shell` section to your `.opencode.json` configuration file:
+
+```json
+{
+  "shell": {
+    "path": "/bin/zsh",
+    "args": ["-l"]
+  }
+}
+```
+
+You can specify any shell executable and custom arguments:
+
+```json
+{
+  "shell": {
+    "path": "/usr/bin/fish",
+    "args": []
+  }
+}
+```
+
 ## Architecture
 ## Architecture
 
 
 OpenCode is built with a modular architecture:
 OpenCode is built with a modular architecture:

+ 7 - 0
internal/config/config.go

@@ -73,6 +73,12 @@ type TUIConfig struct {
 	CustomTheme map[string]any `json:"customTheme,omitempty"`
 	CustomTheme map[string]any `json:"customTheme,omitempty"`
 }
 }
 
 
+// ShellConfig defines the configuration for the shell used by the bash tool.
+type ShellConfig struct {
+	Path string   `json:"path,omitempty"`
+	Args []string `json:"args,omitempty"`
+}
+
 // Config is the main configuration structure for the application.
 // Config is the main configuration structure for the application.
 type Config struct {
 type Config struct {
 	Data         Data                              `json:"data"`
 	Data         Data                              `json:"data"`
@@ -85,6 +91,7 @@ type Config struct {
 	DebugLSP     bool                              `json:"debugLSP,omitempty"`
 	DebugLSP     bool                              `json:"debugLSP,omitempty"`
 	ContextPaths []string                          `json:"contextPaths,omitempty"`
 	ContextPaths []string                          `json:"contextPaths,omitempty"`
 	TUI          TUIConfig                         `json:"tui"`
 	TUI          TUIConfig                         `json:"tui"`
+	Shell        ShellConfig                       `json:"shell,omitempty"`
 }
 }
 
 
 // Application constants
 // Application constants

+ 20 - 4
internal/llm/tools/shell/shell.go

@@ -12,6 +12,7 @@ import (
 	"syscall"
 	"syscall"
 	"time"
 	"time"
 
 
+	"github.com/sst/opencode/internal/config"
 	"github.com/sst/opencode/internal/status"
 	"github.com/sst/opencode/internal/status"
 )
 )
 
 
@@ -59,12 +60,27 @@ func GetPersistentShell(workingDir string) *PersistentShell {
 }
 }
 
 
 func newPersistentShell(cwd string) *PersistentShell {
 func newPersistentShell(cwd string) *PersistentShell {
-	shellPath := os.Getenv("SHELL")
-	if shellPath == "" {
-		shellPath = "/bin/bash"
+	cfg := config.Get()
+	
+	// Use shell from config if specified
+	shellPath := ""
+	shellArgs := []string{"-l"}
+	
+	if cfg != nil && cfg.Shell.Path != "" {
+		shellPath = cfg.Shell.Path
+		if len(cfg.Shell.Args) > 0 {
+			shellArgs = cfg.Shell.Args
+		}
+	} else {
+		// Fall back to environment variable
+		shellPath = os.Getenv("SHELL")
+		if shellPath == "" {
+			// Default to bash if neither config nor environment variable is set
+			shellPath = "/bin/bash"
+		}
 	}
 	}
 
 
-	cmd := exec.Command(shellPath, "-l")
+	cmd := exec.Command(shellPath, shellArgs...)
 	cmd.Dir = cwd
 	cmd.Dir = cwd
 
 
 	stdinPipe, err := cmd.StdinPipe()
 	stdinPipe, err := cmd.StdinPipe()