Skip to content

feat(terminal): natural drag-select + scheme-less clickable links over claude's TUI (v0.190.0)#320

Merged
vikasprogrammer merged 1 commit into
mainfrom
feat/terminal-natural
Jul 14, 2026
Merged

feat(terminal): natural drag-select + scheme-less clickable links over claude's TUI (v0.190.0)#320
vikasprogrammer merged 1 commit into
mainfrom
feat/terminal-natural

Conversation

@vikasprogrammer

Copy link
Copy Markdown
Owner

What & why

The browser terminal's selection and links were unnatural: text could only be selected with Option+drag, and links didn't click at all — especially rendered links without a full https://.

Root cause: claude's fullscreen TUI turns on mouse tracking. The moment xterm sees a tracking mode it disables its own selection service and forwards click/drag to the app — hence Option-drag was the only escape, and link clicks got eaten. But claude only ever uses the wheel (it runs with DISABLE_MOUSE_CLICKS); it discards clicks/drags. The old test bed ran plain bash, which never enables mouse tracking, so it never reproduced this.

The rework (web-only — no server/MCP restart)

  • stripMouseTracking filters the app's mouse-tracking DECSET modes (1000–1003) out of the PTY output stream before xterm sees them — so xterm stays in its normal, no-mouse state (plain drag selects, links are clickable like a web page). Everything else (SGR encoding, focus, alt-screen, bracketed paste, …) passes through untouched; split-across-frame sequences are carried. Only the wheel is re-supplied to claude as SGR events (via attachCustomWheelEventHandler) so its conversation still scrolls. Documented xterm API only — no internals, survives xterm upgrades.
  • makeLinkProvider replaces the stock WebLinksAddon (full https://… only) with custom providers matching bare domains (example.com), subdomains, www.…, localhost:PORT/127.0.0.1:PORT, and OSC-8 hyperlinks — opening the right target in a new tab, while deliberately not underlining file.tsx:42-style tokens.

Reproducing + validation

  • New scripts/mouse-tui.mjs reproduces claude's mouse-reporting condition; TERMBED_CMD='node …/mouse-tui.mjs' node scripts/termbed.mjs points the test bed at it.
  • Verified end-to-end with Playwright driving the harness under real mouse mode — 7/7:
    • ✓ native drag-select (no Option) selected example.com
    • ✓ bare domain → https://example.com; ✓ localhost:5199http://…; ✓ www.google.comhttps://…; ✓ full URL passes through
    • Component.tsx:42 is not a link
    • ✓ wheel forwarded to the app (counter ticked)
  • npm run typecheck, cd web && npm run build, and npm run test:governance (68/68) all green.

🤖 Generated with Claude Code

…r claude's mouse-reporting TUI (v0.192.0)

The first-party <Xterm> client strips the app's mouse-*tracking* DECSET modes
(1000–1003) out of the PTY output stream before xterm sees them, so a plain drag
selects and links are clickable like a web page — no Option-drag. Only the wheel
is forwarded back to claude (as SGR events) so its conversation still scrolls.
Replaces WebLinksAddon with custom link providers that match bare domains,
localhost:port, www, and OSC-8 links (not file.tsx:42). Adds scripts/mouse-tui.mjs
+ TERMBED_CMD so the test bed can reproduce claude's mouse mode. Verified end-to-end
with Playwright against the harness: drag-select, link-click, and wheel all pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vikasprogrammer vikasprogrammer force-pushed the feat/terminal-natural branch from ef3f8b4 to 6d4a1f8 Compare July 14, 2026 10:34
@vikasprogrammer vikasprogrammer merged commit 96c7223 into main Jul 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant