Secret Scan / scan (push) Successful in 4s
Build App (Preview) / compute-version (pull_request) Successful in 3s
Secret Scan / scan (pull_request) Successful in 7s
Build App (Preview) / create-release (pull_request) Successful in 4s
Build App (Preview) / build-macos (pull_request) Successful in 2m42s
Build App (Preview) / build-linux (pull_request) Successful in 6m39s
Build App (Preview) / build-windows (pull_request) Successful in 5m0s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Re-review found the gate did not cover the gesture users actually make. xterm's `Linkifier._handleMouseUp` has no click-count check, no distance threshold and no timestamp, so it activates on the mouseup that *ends a selection* as readily as on a click. Double-clicking a word or dragging across a few characters inside an OSC 8 link therefore opened the browser. Worse with a program holding the mouse: the only way to select text there is Shift/Option+drag, which is byte-identical to the gesture the gate accepted as a deliberate request to open. A container wrapping each output row in a link would have harvested every legitimate copy. `term.hasSelection()` is the load-bearing check: a drag is one press and one release, so its click count is 1 and `detail` cannot see it. `detail > 1` is belt-and-braces for the case where the selection came out empty, and for not depending on the selection model being written before the Linkifier's listener runs -- it is, but the check costs nothing. Drag distance was rejected rather than forgotten: xterm hands `activate` only the mouseup, so measuring it means binding our own listener and keeping a second source of truth about one gesture. The hover card's promise is now sticky. The hint was computed once at hover while the gate re-read the mode at mouseup, so a card reading "Shift+click to open" could be on screen while a bare click opened the link. The gate now requires the modifier if either the card asked for it or the live mode does. The same gate is applied to the WebLinksAddon branch, which had none. That also closes a real bypass: `OscLinkProvider` drops non-http(s) OSC 8 targets before `linkHandler` sees them, so a `javascript:` target with an `https://evil.tld` label fell through to WebLinks and opened ungated. What is not closed, and is now recorded rather than papered over: the mouse mode is a permission the container grants itself. It can drop tracking before the pointer arrives and hold it off through the click. The selection and click-count checks hold either way, so the mass-harvest variant is gone, but the real fix needs a signal the container cannot write and this pane does not have one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>