Description
OpenTUI sends response-generating terminal capability probes through tmux DCS passthrough during startup. If the user switches panes before the outer terminal replies, tmux can deliver those replies to the newly active pane instead of the pane that sent the query.
The receiving shell then displays or executes fragments such as:
1+r4D73=...
2027;1$y
2031;1$y
1004;1$y
2004;1$y
2026;1$y
Gi=31337;OK
62;22;52c
These correspond to OpenTUI's XTGETTCAP Ms, DECRQM, Kitty graphics, and primary device attributes startup probes.
This is different from #334: #415 fixed the framing that caused the Kitty graphics query itself to affect the pane title, but DCS passthrough does not associate a later terminal reply with the pane that originated the query.
Reproduction
Environment used:
- Ghostty 1.3.1
- tmux 3.7c
- OpenCode 1.18.23
- macOS
- Enable tmux passthrough with
tmux set -g allow-passthrough on.
- Create two tmux panes, A and B.
- Start OpenCode, or another OpenTUI application, in pane A.
- Immediately switch to pane B while startup capability detection is running.
- Press a key in pane B.
- Observe terminal response fragments in pane B's shell input or output.
The race is timing-sensitive with a local terminal. It can be made deterministic by delaying the outer terminal's replies until after select-pane.
Root cause
Terminal.queryTerminalSend() emits capabilityQueriesTmux, kittyGraphicsQueryTmux, and primaryDeviceAttrsTmux. The wrapper transports each query from pane A to the outer terminal, but the corresponding response has no tmux pane identity:
pane A -> tmux passthrough -> outer terminal
|
pane B <- tmux client input <-----+
OpenTUI already documents this constraint in queryThemeColors():
DCS passthrough replies are not routed back to the pane that asked.
The same constraint applies to the other response-generating startup probes.
Proposed behavior
When running inside tmux:
- Do not send response-generating capability probes through DCS passthrough.
- Send probes that tmux can answer directly without wrapping.
- Skip the outer Kitty graphics probe, falling back conservatively when the complete OpenTUI -> tmux -> terminal path cannot be detected safely.
- Do not retry the probes through passthrough after late XTVERSION-based tmux detection.
One-way passthrough operations are outside this issue.
I can submit a focused PR with native regression tests if this direction is acceptable.
Expected behavior
Starting an OpenTUI application in one tmux pane must not inject terminal response bytes into another pane after focus changes.
Description
OpenTUI sends response-generating terminal capability probes through tmux DCS passthrough during startup. If the user switches panes before the outer terminal replies, tmux can deliver those replies to the newly active pane instead of the pane that sent the query.
The receiving shell then displays or executes fragments such as:
These correspond to OpenTUI's XTGETTCAP
Ms, DECRQM, Kitty graphics, and primary device attributes startup probes.This is different from #334: #415 fixed the framing that caused the Kitty graphics query itself to affect the pane title, but DCS passthrough does not associate a later terminal reply with the pane that originated the query.
Reproduction
Environment used:
tmux set -g allow-passthrough on.The race is timing-sensitive with a local terminal. It can be made deterministic by delaying the outer terminal's replies until after
select-pane.Root cause
Terminal.queryTerminalSend()emitscapabilityQueriesTmux,kittyGraphicsQueryTmux, andprimaryDeviceAttrsTmux. The wrapper transports each query from pane A to the outer terminal, but the corresponding response has no tmux pane identity:OpenTUI already documents this constraint in
queryThemeColors():The same constraint applies to the other response-generating startup probes.
Proposed behavior
When running inside tmux:
One-way passthrough operations are outside this issue.
I can submit a focused PR with native regression tests if this direction is acceptable.
Expected behavior
Starting an OpenTUI application in one tmux pane must not inject terminal response bytes into another pane after focus changes.