fix(tui): robust clipboard handling with debug logging and headless detection

Problem: Ctrl+C in Hermes TUI shows 'copied' but clipboard often empty.
Root causes:
- Native Linux tools (xclip, wl-copy) require DISPLAY/WAYLAND_DISPLAY; in
  headless Docker/SSH they fail or hang.
- OSC 52 fallback requires terminal emulator support; when absent, sequence
  is dropped silently.
- Dashboard OSC 52 → Clipboard API path fails due to missing user gesture;
  errors were silently caught.
- User feedback 'copied selection' was shown unconditionally, regardless of
  success.

Solution implemented:
- Short-circuit Linux native clipboard probing when no display server is
  present (no DISPLAY and no WAYLAND_DISPLAY). Avoids futile attempts and
  timeouts.
- Add HERMES_TUI_DEBUG_CLIPBOARD env var (1/true). When set, TUI logs to
  stderr which clipboard path is used, probe results on Linux, and whether
  OSC 52 was emitted. Greatly improves diagnosability.
- Improve dashboard clipboard error handling: replace empty catch blocks
  with console.warn messages for OSC 52 decode/Write failures and direct
  copy/paste errors. Makes browser permission/user-gesture failures visible
  in DevTools.
- Add comprehensive clipboard troubleshooting documentation to README and
  AGENTS, covering OSC 52 verification, tmux config, Docker/headless
  constraints, env vars, dashboard caveats, and fallback strategies.

Technical details:
-  in ui-tui/packages/hermes-ink/src/ink/termio/osc.ts:
  - Early return on Linux if both DISPLAY and WAYLAND_DISPLAY unset.
  - Refactor probe sequence to async  with 500ms timeout,
    caching result; subsequent copies use cached tool immediately.
  - Emit debug logs when HERMES_TUI_DEBUG_CLIPBOARD=1.
-  in ink.tsx: log when OSC 52 not emitted (native
  or tmux path in use) in debug mode.
- : OSC 52 handler and Ctrl+Shift+C handler now
  log warnings to console on Clipboard API rejection with error message.
- Documentation: new 'Clipboard Troubleshooting' section in README; new
  'Clipboard environment variables and pitfalls' subsection in AGENTS.md
  (Known Pitfalls).

Tests: full ui-tui test suite (292 tests) passes; clipboard and OSC tests
unaffected. No breaking changes.

Files changed:
- ui-tui/packages/hermes-ink/src/ink/termio/osc.ts
- ui-tui/packages/hermes-ink/src/ink/ink.tsx
- web/src/pages/ChatPage.tsx
- README.md
- AGENTS.md
- CHANGELOG.md (new)
This commit is contained in:
Harry Riddle
2026-04-26 15:19:16 +07:00
committed by Teknium
parent 855366909f
commit a562420383
6 changed files with 204 additions and 52 deletions

View File

@ -667,6 +667,27 @@ def profile_env(tmp_path, monkeypatch):
return home
```
### Clipboard environment variables and pitfalls
Hermes TUI clipboard handling uses a three-tier strategy:
1. **Native OS tools** (`pbcopy`, `wl-copy`, `xclip`, `xsel`, `clip.exe`) — available **only** when a display server is present (`$DISPLAY` for X11 or `$WAYLAND_DISPLAY` for Wayland). On Linux in headless environments (Docker, remote SSH without X11 forwarding), these tools fail or hang. The code now short-circuits immediately if both variables are unset.
2. **tmux buffer** (`tmux load-buffer`) — when inside a tmux session; requires `set-clipboard on` for system clipboard propagation.
3. **OSC 52 escape** — written to stdout; the terminal emulator must intercept and set the clipboard. Support varies: iTerm2 disables it by default, VS Code may block it behind a permission prompt, and raw PTYs without an emulator drop it silently.
**Environment variables:**
| Variable | Purpose |
|---|---|
| `HERMES_TUI_CLIPBOARD_OSC52` or `HERMES_TUI_COPY_OSC52` | Force OSC 52 emission (`1`/`true`) or disable (`0`/`false`). Ignored when native tools are expected to work (macOS local, or Linux with `$DISPLAY/$WAYLAND_DISPLAY`). |
| `HERMES_TUI_DEBUG_CLIPBOARD` | Set to `1` to log detailed debug information to stderr about which clipboard path is taken, probe results on Linux, and why OSC 52 may be suppressed. |
| `SSH_CONNECTION` | Presence indicates an SSH session; this gates native tool usage (to avoid writing to the remote machine's clipboard) and prefers OSC 52. |
| `TMUX`, `STY` | Used to detect tmux/screen and apply appropriate passthrough or buffer loading. |
**Common false-positive:** The UI message "copied selection" is displayed **unconditionally** after Ctrl+C, even if all clipboard mechanisms fail. If you're in a headless Docker container or a non-OSC52-capable terminal, you'll see the message but nothing is copied. Use `HERMES_TUI_DEBUG_CLIPBOARD=1` to diagnose.
**Dashboard caveat:** The dashboard's `Ctrl+C` path relies on OSC 52 → xterm's handler → browser Clipboard API. Because the Clipboard API requires a user gesture, this can fail if the OSC 52 response arrives outside the key event's activation window. Use `Ctrl+Shift+C` (Cmd+Shift+C on macOS) as a reliable fallback; it calls `navigator.clipboard.writeText()` directly inside the key handler.
---
## Testing