82 lines
2.9 KiB
Go

package windsurf
import (
"fmt"
"os/exec"
"runtime"
"strings"
)
// Platform identifies a (OS, architecture) pair that Windsurf may support.
// OS values match runtime.GOOS ("linux", "darwin", "windows"), and Arch
// values match runtime.GOARCH ("amd64", "arm64").
type Platform struct {
OS string
Arch string
}
// String renders the platform as "os/arch" (e.g. "darwin/arm64").
func (p Platform) String() string { return p.OS + "/" + p.Arch }
// procTranslatedProbe reports whether the current process is running under
// Rosetta 2 translation (an amd64 Go binary on Apple Silicon). It is mocked
// by tests.
var procTranslatedProbe = defaultProcTranslatedProbe
// defaultProcTranslatedProbe runs `sysctl sysctl.proc_translated` on darwin
// and returns true when the value is "1". On non-darwin platforms it always
// returns false. The sysctl key is only defined on darwin, so we skip the
// exec on every other OS to avoid spurious errors.
func defaultProcTranslatedProbe() bool {
if runtime.GOOS != "darwin" {
return false
}
out, err := exec.Command("sysctl", "-n", "sysctl.proc_translated").Output()
if err != nil {
return false
}
return strings.TrimSpace(string(out)) == "1"
}
// DetectPlatform returns the platform for which we should load the LS binary.
// It accounts for Rosetta translation: an amd64 Go binary running on Apple
// Silicon should load the arm64 LS, not the x64 one, because the native
// Mac arm64 binary performs better and the x64 build may not exist.
func DetectPlatform() Platform {
return detectPlatformFor(runtime.GOOS, runtime.GOARCH, procTranslatedProbe())
}
func detectPlatformFor(goos, goarch string, rosetta bool) Platform {
p := Platform{OS: goos, Arch: goarch}
if p.OS == "darwin" && p.Arch == "amd64" && rosetta {
p.Arch = "arm64"
}
return p
}
// ErrUnsupportedPlatform is returned when no Windsurf LS binary exists for
// the current platform. Callers should fall back to ls_mode=docker.
var ErrUnsupportedPlatform = fmt.Errorf("windsurf: no language server binary for this platform")
// BinaryFilename returns the official Windsurf LS binary filename for the
// given platform, matching the mapping used by the Windsurf VS Code
// extension (extracted from extension.js PlatformArch enum).
func BinaryFilename(p Platform) (string, error) {
switch {
case p.OS == "linux" && p.Arch == "amd64":
return "language_server_linux_x64", nil
case p.OS == "linux" && p.Arch == "arm64":
return "language_server_linux_arm", nil
case p.OS == "darwin" && p.Arch == "arm64":
return "language_server_macos_arm", nil
case p.OS == "darwin" && p.Arch == "amd64":
return "language_server_macos_x64", nil
case p.OS == "windows" && p.Arch == "amd64":
return "language_server_windows_x64.exe", nil
case p.OS == "windows" && p.Arch == "arm64":
return "language_server_windows_arm.exe", nil
default:
return "", fmt.Errorf("%w: %s — use ls_mode=docker to run the Linux LS in a container", ErrUnsupportedPlatform, p)
}
}