From c3d9028cec516f2ab20d5cf3577c52b283026fe4 Mon Sep 17 00:00:00 2001 From: Bruce MacDonald Date: Wed, 4 Mar 2026 14:14:51 -0800 Subject: [PATCH] tui: fix signin on headless Linux systems Defensively handle environments without a display server to ensure signin remains usable on headless VMs and SSH sessions. - Skip calling xdg-open when neither DISPLAY nor WAYLAND_DISPLAY is set, preventing silent failures or unexpected browser handlers - Render the signin URL as plain text instead of wrapping it in OSC 8 hyperlink escape sequences, which can be garbled or hidden by terminals that don't support them --- cmd/config/integrations.go | 4 ++++ cmd/tui/signin.go | 5 +---- cmd/tui/signin_test.go | 16 ---------------- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/cmd/config/integrations.go b/cmd/config/integrations.go index acf458abe..c23def989 100644 --- a/cmd/config/integrations.go +++ b/cmd/config/integrations.go @@ -629,6 +629,10 @@ func OpenBrowser(url string) { case "darwin": _ = exec.Command("open", url).Start() case "linux": + // Skip on headless systems where no display server is available + if os.Getenv("DISPLAY") == "" && os.Getenv("WAYLAND_DISPLAY") == "" { + return + } _ = exec.Command("xdg-open", url).Start() case "windows": _ = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() diff --git a/cmd/tui/signin.go b/cmd/tui/signin.go index 118dbdf1c..895cf48fd 100644 --- a/cmd/tui/signin.go +++ b/cmd/tui/signin.go @@ -88,11 +88,8 @@ func renderSignIn(modelName, signInURL string, spinner, width int) string { fmt.Fprintf(&s, "To use %s, please sign in.\n\n", selectorSelectedItemStyle.Render(modelName)) - // Wrap in OSC 8 hyperlink so the entire URL is clickable even when wrapped. - // Padding is outside the hyperlink so spaces don't get underlined. - link := fmt.Sprintf("\033]8;;%s\033\\%s\033]8;;\033\\", signInURL, urlColor.Render(signInURL)) s.WriteString("Navigate to:\n") - s.WriteString(urlWrap.Render(link)) + s.WriteString(urlWrap.Render(urlColor.Render(signInURL))) s.WriteString("\n\n") s.WriteString(lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "242", Dark: "246"}).Render( diff --git a/cmd/tui/signin_test.go b/cmd/tui/signin_test.go index 0af9ddc6e..b25771831 100644 --- a/cmd/tui/signin_test.go +++ b/cmd/tui/signin_test.go @@ -25,22 +25,6 @@ func TestRenderSignIn_ContainsURL(t *testing.T) { } } -func TestRenderSignIn_OSC8Hyperlink(t *testing.T) { - url := "https://ollama.com/connect?key=abc123" - got := renderSignIn("test:cloud", url, 0, 120) - - // Should contain OSC 8 open sequence with the URL - osc8Open := "\033]8;;" + url + "\033\\" - if !strings.Contains(got, osc8Open) { - t.Error("should contain OSC 8 open sequence with URL") - } - - // Should contain OSC 8 close sequence - osc8Close := "\033]8;;\033\\" - if !strings.Contains(got, osc8Close) { - t.Error("should contain OSC 8 close sequence") - } -} func TestRenderSignIn_ContainsSpinner(t *testing.T) { got := renderSignIn("test:cloud", "https://example.com", 0, 80)