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

@@ -169,7 +169,99 @@ scripts/run_tests.sh
- 💬 [Discord](https://discord.gg/NousResearch)
- 📚 [Skills Hub](https://agentskills.io)
- 🐛 [Issues](https://github.com/NousResearch/hermes-agent/issues)
- 🔌 [HermesClaw](https://github.com/AaronWong1999/hermesclaw) — Community WeChat bridge: Run Hermes Agent and OpenClaw on the same WeChat account.
- 🔌 [HermesClaw](https://github.com/AaronWong1999/hermesclaw) — Community WeChat bridge: Run Hermes Agent and OpenClaw on the same WeChat account.
---
## Clipboard Troubleshooting
Hermes TUI (standalone) and dashboard both support copying via `Ctrl+C` / `Cmd+C`. This requires either:
- A terminal with **OSC 52** support enabled, **or**
- Native clipboard utilities (`pbcopy`, `wl-copy`, `xclip`, `xsel`, `clip.exe`) available in PATH **and** a running display server (X11 or Wayland).
If the UI says "copied" but the text is not in your system clipboard, follow these steps.
### Standalone TUI (`hermes --tui`)
#### Verify OSC 52 support
Run this in the same terminal you use for Hermes:
```bash
printf '\e]52;c;%s\a' "$(echo -n 'test-osc52' | base64)" && echo
```
Then paste (Cmd+V / Ctrl+Shift+V). If you see `test-osc52`, OSC 52 works.
If it fails, enable OSC 52 in your terminal:
| Terminal | Setting |
|--------------|-------------------------------------------------------------------------|
| iTerm2 | Preferences → General → Selection → check "Copy to pasteboard" |
| Kitty | `allow_remote_control yes` (default: on) |
| WezTerm | `enable_osc52_copy = true` |
| VS Code | Usually works; if blocked, check DevTools console for permission error |
| GNOME | Enabled by default |
#### tmux users
tmux absorbs OSC 52 unless explicitly configured. Add to `~/.tmux.conf`:
```tmux
set -g set-clipboard on
set -g allow-passthrough on
```
Then reload: `tmux source-file ~/.tmux.conf`.
#### Docker/headless environments
Inside a Docker container, `$DISPLAY` and `$WAYLAND_DISPLAY` are typically unset, so native clipboard tools fail immediately. OSC 52 is the only path — it must be supported by your local terminal emulator (the one connected to the container's PTY). If your terminal doesn't support OSC 52, consider:
- Using `ssh -X` / `ssh -Y` to forward X11 and run `xclip` on the host via SSH
- Running Hermes on the host directly, not inside a container
- Writing copied text to a file: `/copy` saves to `~/.hermes/clipboard.txt` (fallback)
#### Force OSC 52 emission
If your terminal supports OSC 52 but Hermes isn't emitting it (e.g., inside SSH where native tools are skipped), set:
```bash
export HERMES_TUI_CLIPBOARD_OSC52=1
hermes --tui
```
#### Debug mode
To see exactly which clipboard path Hermes takes:
```bash
export HERMES_TUI_DEBUG_CLIPBOARD=1
hermes --tui
```
Then attempt a copy and watch stderr for messages like:
```
[clipboard] [native] Linux: no DISPLAY or WAYLAND_DISPLAY — native clipboard unavailable
[clipboard] [native] Linux: clipboard probe complete → xclip
[clipboard] [osc52] no sequence emitted — native clipboard or tmux buffer path in use
```
### Dashboard (`hermes dashboard` → /chat)
The dashboard uses the browser's Clipboard API. There are two copy paths:
1. **Ctrl/Cmd+Shift+C** — direct copy from xterm's selection (most reliable)
2. **Ink's Ctrl+C** — emits OSC 52 → xterm OSC 52 handler → Clipboard API; this is more fragile because the Clipboard API requires a **user gesture**. In some browsers the OSC 52 response is processed outside the original key event's activation window, causing a silent failure.
If copy doesn't work in the dashboard:
- Use `Ctrl+Shift+C` (Linux/Windows) or `Cmd+Shift+C` (macOS) instead
- Check the browser console (F12) for warnings like `[dashboard clipboard] OSC 52 write failed`
- Ensure the page has clipboard permissions (browser may ask on first use)
Clicking the "copy last response" button also sends `/copy` over the WebSocket, which suffers from the same OSC 52 timing issue.
### When all else fails: file-based fallback
You can save copied text to a file manually:
```bash
hermes --tui # inside TUI, use /copy which includes a file fallback in future versions
```
Or implement a custom skill that writes the last assistant message to disk.
---