fix: retire kitty ctrl+v interception (XWayland breaks router tmux detection)#2
Merged
Merged
Conversation
…etection Under XWayland kitty, `kitten @ ls` reports is_focused=false for every OS window and empty foreground_processes, so kitty-paste-router.sh's focused_window_is_tmux() can never succeed. Every Ctrl+V took the slow fallthrough (background launch, seconds late under load) and the late second fire landed outside the daemon's 2.5s dedup window — journal shows identical 162-byte text pastes 4s apart (pane %23, 15:14:50 + 15:14:54). Fix: kitty must not bind ctrl+v at all. tmux's own `bind -n C-v` is the single handler (~5ms, pane id from the pressing client — also kills the wrong-pane hazard of the router's target-less `tmux display-message`). Non-tmux kitty windows: raw 0x16 reaches Claude Code, which reads the clipboard itself via the wl-paste shim; plain shells use ctrl+shift+v. - keybindings.canonical: kitty ctrl+v -> UNBOUND (new keyword) - flashpaste-keybindings-check.sh: support UNBOUND (binding must not exist) - kitty-paste-router.sh: retired-status header + clip-pipeline-log tracing (it was the only paste path with zero logging) - tests/keybindings-check.test.sh: cover UNBOUND pass/violation + keep positive-rule and literal-+ coverage via fixture canonicals
NagyVikt
commented
Jun 10, 2026
NagyVikt
left a comment
Collaborator
Author
There was a problem hiding this comment.
AI review (independent fresh-context agent): APPROVE — 0 CRITICAL, 0 HIGH, 0 MEDIUM, 3 LOW.
- UNBOUND keyword logic verified: surface-dispatch → UNBOUND check →
continueflow is correct; literal+escaping covered by tests. clogtracing guard matches the established pipeline pattern; noset -utraps; no injection surface (quoted args to aprintf >>logger).- Tests 6/6 pass;
bash -nclean; manual shellcheck analysis of new lines against the CI gate (-S warning -e SC1090,SC2034,SC2155) finds no new warnings.
LOW (non-blocking): missing-conf file silently satisfies UNBOUND (pre-existing gap shared with positive rules); pre-existing hardcoded paste_image.sh default path; no fixture for UNBOUND-with-absent-conf. Full artifact: .claude/reviews/pr-2-review.md.
shellcheck -S warning (CI gate) parses $key_re[[:space:]] as an array expansion and errors. Introduced with the checker in PR #1; this was the shellcheck regression that turned main's Lint job red. Braces quiet it with no behavior change (tests 6/6, live check consistent).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
PR #1 widened the daemon dedup window to 2.5s and fixed the router's socket resolution — but double-pastes persisted. Root cause found today: the kitty→XWayland switch breaks the router's entire detection premise.
kitten @ lsreportsis_focused=falsefor every OS window and emptyforeground_processes, sofocused_window_is_tmux()can never return true. Every Ctrl+V in kitty took the slow fallthrough (backgroundlaunchspawn, seconds late under load), and the late second fire landed outside any reasonable dedup window — the journal shows identical 162-byte text pastes 4s apart (pane %23 at 15:14:50 and 15:14:54).What
config/keybindings.canonical: kittyctrl+v→UNBOUND— kitty must NOT intercept Ctrl+V. tmux'sbind -n C-vbecomes the single handler: ~5ms via flashpaste-trigger, and the pane id comes from the pressing client (also killing the wrong-pane hazard of the router's target-lesstmux display-message). Non-tmux kitty windows: the raw0x16reaches Claude Code, which reads the clipboard itself via the wl-paste shim; plain shells use kitty-nativectrl+shift+v.bin/flashpaste-keybindings-check.sh: newUNBOUNDkeyword — asserts a key must not be bound on a surface (checker previously only supported positive substring rules).bin/kitty-paste-router.sh: retired-status header + tracing to the shared clipboard-pipeline log (it was the only paste path that wrote no logs — which is why this regression was invisible).tests/keybindings-check.test.sh: covers UNBOUND pass/violation, keeps positive-rule and literal-+coverage via fixture canonicals.Test plan
bash tests/keybindings-check.test.sh— 6/6 passbash tests/kitty-focused-is-tmux.test.sh,tests/wl-paste-guard.test.sh— passbash bin/flashpaste-keybindings-check.shagainst live configs — consistentctrl+vmap removed from kitty.conf +kitten @ load-configreload; tmux-bind path verified single-paste end-to-end (sentinel viakitten @ send-key→ one daemon request, one paste, 38 bytes)🤖 Generated with Claude Code