From 2af8a42f5fcbc44aa8829d7ec31332e065f930c9 Mon Sep 17 00:00:00 2001 From: "robopipi[bot]" <336283572+robopipi[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2026 09:26:27 +0100 Subject: [PATCH] fix(tui): detect Alacritty for OSC 8 hyperlinks without TERM_PROGRAM (#11777) Hyperlink detection recognised Alacritty only through `TERM_PROGRAM=alacritty`, and Alacritty never sets `TERM_PROGRAM`. So in a default Alacritty setup, pi fell back to `hyperlinks: false` and rendered Markdown links as `label (url)` instead of clickable OSC 8 links. Alacritty does set two other variables, which this change now checks: - `TERM=alacritty` when its terminfo entry is installed (otherwise `TERM=xterm-256color`); - `ALACRITTY_WINDOW_ID` for the shell on Unix and macOS. This covers the common macOS case where the terminfo entry is missing. The tmux and screen checks still run first, so behaviour inside multiplexers is unchanged. **Testing** - Added a `detectCapabilities` test covering `TERM=alacritty` and `TERM=xterm-256color` with `ALACRITTY_WINDOW_ID`. It fails without the change and passes with it. - `node --test test/*.test.ts` in `packages/tui`: 1121 passing tests. - `npm run check` passes. - Checked `detectCapabilities()` with clean environments: - Before: `TERM=alacritty` and `ALACRITTY_WINDOW_ID=123` both gave `hyperlinks: false`. - After: both give `hyperlinks: true`. - Plain `xterm-256color` and tmux with `ALACRITTY_WINDOW_ID` still give `false`. Fixes #11767 Requested by @badlogic Co-authored-by: triagent --- packages/tui/src/terminal-image.ts | 5 ++++- packages/tui/test/terminal-image.test.ts | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/tui/src/terminal-image.ts b/packages/tui/src/terminal-image.ts index 64703bf48..c1f682dff 100644 --- a/packages/tui/src/terminal-image.ts +++ b/packages/tui/src/terminal-image.ts @@ -128,7 +128,10 @@ function detectCapabilitiesFromEnvironment(tmuxForwardsHyperlink: () => boolean) return { images: null, trueColor: true, hyperlinks: true }; } - if (termProgram === "alacritty" || termProgram === "vscode" || termProgram === "zed") { + // Alacritty does not set TERM_PROGRAM. It sets TERM=alacritty when its terminfo entry is + // installed (otherwise xterm-256color) and ALACRITTY_WINDOW_ID on Unix and macOS. + const isAlacritty = termProgram === "alacritty" || term.startsWith("alacritty") || process.env.ALACRITTY_WINDOW_ID; + if (isAlacritty || termProgram === "vscode" || termProgram === "zed") { return { images: null, trueColor: true, hyperlinks: true }; } diff --git a/packages/tui/test/terminal-image.test.ts b/packages/tui/test/terminal-image.test.ts index 0ae5bd8b4..2a96f78d2 100644 --- a/packages/tui/test/terminal-image.test.ts +++ b/packages/tui/test/terminal-image.test.ts @@ -43,6 +43,7 @@ const ENV_KEYS = [ "WEZTERM_PANE", "ITERM_SESSION_ID", "WT_SESSION", + "ALACRITTY_WINDOW_ID", "CMUX_WORKSPACE_ID", "WARP_SESSION_ID", "WARP_TERMINAL_SESSION_UUID", @@ -445,6 +446,15 @@ describe("detectCapabilities", () => { }); }); + it("enables hyperlinks for Alacritty without TERM_PROGRAM", () => { + withEnv({ TERM: "alacritty", COLORTERM: "truecolor" }, () => { + assert.deepStrictEqual(detectCapabilities(), { images: null, trueColor: true, hyperlinks: true }); + }); + withEnv({ TERM: "xterm-256color", COLORTERM: "truecolor", ALACRITTY_WINDOW_ID: "1" }, () => { + assert.deepStrictEqual(detectCapabilities(), { images: null, trueColor: true, hyperlinks: true }); + }); + }); + it("enables Alacritty capabilities for Zed", () => { withEnv({ TERM_PROGRAM: "zed" }, () => { assert.deepStrictEqual(detectCapabilities(), { images: null, trueColor: true, hyperlinks: true });