From b6e83f0f2db71c705d48ef14b499a513c1506f4d Mon Sep 17 00:00:00 2001 From: Seth Date: Sat, 5 Sep 2026 19:47:05 -0400 Subject: [PATCH] feat(tui): open local file links --- packages/tui/.changes/local-file-links.md | 1 + packages/tui/src/tui.ts | 2 +- packages/tui/test/fullscreen.test.ts | 10 +++++++--- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 packages/tui/.changes/local-file-links.md diff --git a/packages/tui/.changes/local-file-links.md b/packages/tui/.changes/local-file-links.md new file mode 100644 index 0000000000..c6f3817d55 --- /dev/null +++ b/packages/tui/.changes/local-file-links.md @@ -0,0 +1 @@ +- Added support for opening file links from the fullscreen terminal UI. diff --git a/packages/tui/src/tui.ts b/packages/tui/src/tui.ts index 318513c824..1877da3298 100644 --- a/packages/tui/src/tui.ts +++ b/packages/tui/src/tui.ts @@ -768,7 +768,7 @@ export class TUI extends Container { let href: string; try { const parsed = new URL(url); - if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return; + if (parsed.protocol !== "http:" && parsed.protocol !== "https:" && parsed.protocol !== "file:") return; href = parsed.href; } catch { return; diff --git a/packages/tui/test/fullscreen.test.ts b/packages/tui/test/fullscreen.test.ts index 3166b47003..99b5e89440 100644 --- a/packages/tui/test/fullscreen.test.ts +++ b/packages/tui/test/fullscreen.test.ts @@ -1066,9 +1066,11 @@ describe("TUI fullscreen mode", () => { tui.stop(); }); - it("ignores clicked hyperlinks with non-http schemes", async () => { + it("opens file hyperlinks and ignores unsupported schemes", async () => { const transcript = lines(20); - transcript[12] = "\x1b]8;;file:///etc/passwd\x1b\\secrets\x1b]8;;\x1b\\"; + transcript[12] = + "\x1b]8;;file:///tmp/example%20file.txt\x1b\\file\x1b]8;;\x1b\\ " + + "\x1b]8;;ssh://example.com\x1b\\remote\x1b]8;;\x1b\\"; const { terminal, tui, chat, dock } = setup(transcript); const opened: string[] = []; tui.onOpenUrl = (url) => opened.push(url); @@ -1077,8 +1079,10 @@ describe("TUI fullscreen mode", () => { terminal.sendInput("\x1b[<0;3;1M"); terminal.sendInput("\x1b[<0;3;1m"); + terminal.sendInput("\x1b[<0;7;1M"); + terminal.sendInput("\x1b[<0;7;1m"); await terminal.waitForRender(); - assert.deepStrictEqual(opened, []); + assert.deepStrictEqual(opened, ["file:///tmp/example%20file.txt"]); tui.stop(); });