openBrowser tries to open url in the user's default browser. It returns an error when no browser can plausibly be launched so the caller can fall back to elicitation. On Linux it treats a headless session (no display server) as unopenable, which is the common case for SSH and containers.
(url string)
| 21 | // to elicitation. On Linux it treats a headless session (no display server) as |
| 22 | // unopenable, which is the common case for SSH and containers. |
| 23 | func openBrowser(url string) error { |
| 24 | var cmd *exec.Cmd |
| 25 | switch runtime.GOOS { |
| 26 | case "linux": |
| 27 | if os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" { |
| 28 | return errNoDisplay |
| 29 | } |
| 30 | cmd = exec.Command("xdg-open", url) |
| 31 | case "darwin": |
| 32 | cmd = exec.Command("open", url) |
| 33 | case "windows": |
| 34 | cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", url) |
| 35 | default: |
| 36 | return fmt.Errorf("unsupported platform: %s", runtime.GOOS) |
| 37 | } |
| 38 | |
| 39 | cmd.Stdout = io.Discard |
| 40 | cmd.Stderr = io.Discard |
| 41 | if err := cmd.Start(); err != nil { |
| 42 | return err |
| 43 | } |
| 44 | // The launcher (xdg-open/open/rundll32) exits as soon as it hands off to the |
| 45 | // browser. Reap it asynchronously so it does not linger as a zombie for the |
| 46 | // lifetime of this long-running server. |
| 47 | go func() { _ = cmd.Wait() }() |
| 48 | return nil |
| 49 | } |
| 50 | |
| 51 | // isRunningInDocker reports whether the process is running inside a Docker (or |
| 52 | // containerd) container. Detection relies on Linux-specific paths and is always |