You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(tui): modified authorization-link clicks open duplicate tabs #51756
A modified click on a TUI authorization link can open two browser tabs: the terminal follows the native OSC 8 hyperlink and the TUI also calls its browser opener. Expected: one tab.
Root cause: the Link component's mouse-up handler opens the URL without checking mouse-button/modifier state.
Plugins
No plugin is required; this is the built-in Link component.
OpenCode version
2.0.15 (V2)
Steps to reproduce
Open an authorization link in the TUI in a terminal with native OSC 8 hyperlink support.
Use the terminal's link-opening modifier and click the link (Ctrl/Cmd/Shift/Alt, depending on the terminal).
When the terminal also reports the modified mouse event to the TUI, two browser tabs open instead of one.
Operating System
macOS and Linux.
Terminal
Terminals with native OSC 8 hyperlinks that also forward modified mouse events. The relevant behavior is terminal-specific; not every modifier reproduces it in every terminal.
Thanks! #44442 concerns Markdown links not opening under mouse capture; this report concerns authorization links opening twice when both the terminal and TUI handle a modified click. #51757 fixes the duplicate opener, not Markdown link capture.
Thanks for the clear report. I could reproduce this on 2.0.15, and it still happens on the latest dev (86ce19d).
How I tested it:
Opened /pair, which shows connect/authorization links rendered with the shared Link component.
Clicked a link six ways: plain left click, Ctrl+click, Shift+click, Alt+click, middle click and right click.
Logged every browser launch the TUI makes, using a stub xdg-open.
Result: every one of the six clicks made the TUI open the browser. The link is also emitted as an OSC 8 hyperlink, so in a terminal that opens it on a modified click and also forwards the mouse event, that open from the TUI is the duplicate tab. The clickedLink() helper used for transcript links already leaves modified clicks to the terminal; Link's mouse-up handler doesn't check the button or modifiers.
The script below reproduces it. The recording shows the dialog and the clicks, but the browser launches go to a log file, not the screen. I couldn't simulate the terminal's own OSC 8 open here, only the TUI's.
Related: #51757 (your fix PR), #53903 (added the modifier-aware clickedLink for transcript links), #52754, #56062.
recording.mp4Reproduction script (drive.ts)
// Reproduces #51756: a modified (Ctrl/Shift/Alt) click on an authorization Link in the TUI// still makes the TUI open the browser itself, on top of the terminal's own OSC 8 handling.// A fake `xdg-open` is put first on PATH so every browser open the TUI itself performs is logged// (the terminal's own OSC 8 handling is outside the TUI and not simulated here).// Run: opencode-drive run ./drive.ts (set OC_DEV=<checkout> to run a source checkout instead)import{Effect}from"effect"import{readFileSync,existsSync,writeFileSync,mkdirSync,chmodSync}from"node:fs"import{OpenCodeDriver}from"opencode-drive"constDIR="/tmp/opencode/link-repro"constLOG=`${DIR}/opened.log`mkdirSync(`${DIR}/bin`,{recursive: true})writeFileSync(`${DIR}/bin/xdg-open`,`#!/bin/sh\necho "$(date -u +%T) TUI opened browser: $*" >> ${LOG}\n`)chmodSync(`${DIR}/bin/xdg-open`,0o755)process.env.PATH=`${DIR}/bin:${process.env.PATH}`process.env.BROWSER=`${DIR}/bin/xdg-open`deleteprocess.env.DISPLAYdeleteprocess.env.WAYLAND_DISPLAYconstopened=()=>(existsSync(LOG) ? readFileSync(LOG,"utf8").trim().split("\n").filter(Boolean).length : 0)exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true,pointerOverlay: true,keypressOverlay: true},},({ ui })=>Effect.gen(function*(){writeFileSync(LOG,"")yield*ui.submit("/pair")yield*ui.waitFor("http://localhost")// Locate the first authorization link on screen from the captured frame.constframe: any=yield*ui.capture()letx=-1,y=-1frame.lines.forEach((line: any,row: number)=>{consttext=line.spans.map((s: any)=>s.text).join("")constcol=text.indexOf("http://localhost")if(y<0&&col>=0){y=row;x=col+5}})yield*Effect.log(`link at x=${x} y=${y}`)yield*ui.screenshot("pair-dialog")constresults: string[]=[]for(constmodsof[{plain: false}asany,{ctrl: true},{shift: true},{alt: true}]){constbefore=opened()yield*ui.mouse({action: "move", x, y })yield*ui.mouse({action: "down", x, y,button: "left", ...mods}asany)yield*ui.mouse({action: "up", x, y,button: "left", ...mods}asany)yield*Effect.sleep("1500 millis")results.push(`${Object.keys(mods)[0]}+click -> TUI browser opens: ${opened()-before}`)}for(constbuttonof["middle","right"]asconst){constbefore=opened()yield*ui.mouse({action: "down", x, y, button })yield*ui.mouse({action: "up", x, y, button })yield*Effect.sleep("1500 millis")results.push(`${button}-click -> TUI browser opens: ${opened()-before}`)}yield*ui.screenshot("after-clicks")yield*Effect.log(results.join("\n"))yield*Effect.log(`opened.log:\n${readFileSync(LOG,"utf8")}`)}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
github-actions commentedon Sep 28, 2026
This issue might overlap with an existing report. Please check:
For keybind-related issues, please also check our pinned keybinds documentation: #4997
gszep commentedon Sep 28, 2026
Thanks! #44442 concerns Markdown links not opening under mouse capture; this report concerns authorization links opening twice when both the terminal and TUI handle a modified click. #51757 fixes the duplicate opener, not Markdown link capture.
opencodejr commentedon Oct 28, 2026
Thanks for the clear report. I could reproduce this on 2.0.15, and it still happens on the latest
dev(86ce19d).How I tested it:
/pair, which shows connect/authorization links rendered with the sharedLinkcomponent.xdg-open.Result: every one of the six clicks made the TUI open the browser. The link is also emitted as an OSC 8 hyperlink, so in a terminal that opens it on a modified click and also forwards the mouse event, that open from the TUI is the duplicate tab. The
clickedLink()helper used for transcript links already leaves modified clicks to the terminal;Link's mouse-up handler doesn't check the button or modifiers.The script below reproduces it. The recording shows the dialog and the clicks, but the browser launches go to a log file, not the screen. I couldn't simulate the terminal's own OSC 8 open here, only the TUI's.
Related: #51757 (your fix PR), #53903 (added the modifier-aware
clickedLinkfor transcript links), #52754, #56062.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.