launch/opencode: detect curl installed opencode at ~/.opencode/bin (#15197)

This commit is contained in:
Eva H
2026-04-08 13:54:51 -07:00
committed by GitHub
parent 4e16f562c0
commit d17f482d50
3 changed files with 62 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"slices"
"strings"
@@ -19,12 +20,34 @@ type OpenCode struct{}
func (o *OpenCode) String() string { return "OpenCode" }
// findOpenCode returns the opencode binary path, checking PATH first then the
// curl installer location (~/.opencode/bin) which may not be on PATH yet.
func findOpenCode() (string, bool) {
if p, err := exec.LookPath("opencode"); err == nil {
return p, true
}
home, err := os.UserHomeDir()
if err != nil {
return "", false
}
name := "opencode"
if runtime.GOOS == "windows" {
name = "opencode.exe"
}
fallback := filepath.Join(home, ".opencode", "bin", name)
if _, err := os.Stat(fallback); err == nil {
return fallback, true
}
return "", false
}
func (o *OpenCode) Run(model string, args []string) error {
if _, err := exec.LookPath("opencode"); err != nil {
opencodePath, ok := findOpenCode()
if !ok {
return fmt.Errorf("opencode is not installed, install from https://opencode.ai")
}
cmd := exec.Command("opencode", args...)
cmd := exec.Command(opencodePath, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

View File

@@ -7,6 +7,7 @@ import (
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"testing"
)
@@ -771,6 +772,40 @@ func TestLookupCloudModelLimit(t *testing.T) {
}
}
func TestFindOpenCode(t *testing.T) {
t.Run("fallback to ~/.opencode/bin", func(t *testing.T) {
tmpDir := t.TempDir()
setTestHome(t, tmpDir)
// Ensure opencode is not on PATH
t.Setenv("PATH", tmpDir)
// Without the fallback binary, findOpenCode should fail
if _, ok := findOpenCode(); ok {
t.Fatal("findOpenCode should fail when binary is not on PATH or in fallback location")
}
// Create a fake binary at the curl install fallback location
binDir := filepath.Join(tmpDir, ".opencode", "bin")
os.MkdirAll(binDir, 0o755)
name := "opencode"
if runtime.GOOS == "windows" {
name = "opencode.exe"
}
fakeBin := filepath.Join(binDir, name)
os.WriteFile(fakeBin, []byte("#!/bin/sh\n"), 0o755)
// Now findOpenCode should succeed via fallback
path, ok := findOpenCode()
if !ok {
t.Fatal("findOpenCode should succeed with fallback binary")
}
if path != fakeBin {
t.Errorf("findOpenCode = %q, want %q", path, fakeBin)
}
})
}
func TestOpenCodeModels_NoConfig(t *testing.T) {
o := &OpenCode{}
tmpDir := t.TempDir()

View File

@@ -92,8 +92,8 @@ var integrationSpecs = []*IntegrationSpec{
Description: "Anomaly's open-source coding agent",
Install: IntegrationInstallSpec{
CheckInstalled: func() bool {
_, err := exec.LookPath("opencode")
return err == nil
_, ok := findOpenCode()
return ok
},
URL: "https://opencode.ai",
},