Skip to content

emulator: answer OSC 10/11/12 colour queries for detached sessions#89

Open
nymph-ai wants to merge 1 commit into
Helvesec:mainfrom
nymph-ai:fix/answer-terminal-queries
Open

emulator: answer OSC 10/11/12 colour queries for detached sessions#89
nymph-ai wants to merge 1 commit into
Helvesec:mainfrom
nymph-ai:fix/answer-terminal-queries

Conversation

@nymph-ai

Copy link
Copy Markdown

Problem

A program inside a detached rmux pane gets no answer when it queries the terminal's colours (OSC 10/11/12 with a ? payload). The emulator already impersonates the attached terminal for DA1/DA2/DSR/DECRQM/XTVERSION (input/dispatch.rs), but the OSC colour commands were parsed and dropped (screen/writer.rs no-op stubs), so there was no reply at all.

Theme-detecting TUIs mis-render as a result: e.g. Claude Code with theme: "auto" queries ESC ]11;? at startup and, receiving nothing, silently falls back to the wrong palette variant (we hit this driving Claude Code inside detached rmux sessions — 256-color salmon instead of its truecolor brand orange).

Change

Answer the queries from the emulator, riding the existing parser reply-buffer → pane reader → pty master write-back path (the same machinery as DA1):

  • ? payload → reply OSC <n>;rgb:RRRR/GGGG/BBBB, terminated like the query (BEL vs ST) — the exact format rmux's own client-side theme parser (src/cli/terminal_theme.rs) produces and consumes.
  • Set payloads are recorded on the parser so later queries round-trip the value, and still reach the ScreenWriter unchanged.
  • OSC 110/111/112 resets restore defaults.
  • Defaults impersonate a conventional dark terminal (rgb:cccc/cccc/cccc on rgb:0000/0000/0000), overridable per daemon via RMUX_DEFAULT_FOREGROUND / RMUX_DEFAULT_BACKGROUND / RMUX_DEFAULT_CURSOR_COLOUR.

Tests

New unit tests beside the existing DA1/XTVERSION reply tests: query replies for all three slots with both terminators, set-then-query round-trip, reset behavior, and writer passthrough for set payloads (RecordingWriter now records the colour calls). cargo test -p rmux-core: 913 passed; cargo test -p rmux-server pane_transcript: 18 passed; clippy/fmt clean.

A program inside a detached rmux pane gets no answer when it queries the
terminal's colours (OSC 10/11/12 with a `?` payload) — there is no
attached terminal to forward the query to, and the emulator (which
already impersonates the terminal for DA1/DA2/DSR/DECRQM/XTVERSION at
dispatch.rs) parsed these OSC commands but never replied. Theme-detecting
TUIs (e.g. Claude Code with theme=auto) silently fall back to the wrong
palette.

Answer the queries from the emulator, riding the existing parser reply
buffer -> pane reader -> pty master write-back path:

- `?` payload replies `OSC <n>;rgb:RRRR/GGGG/BBBB` terminated like the
  query (BEL/ST), matching the format rmux's own client-side theme
  parser (src/cli/terminal_theme.rs) expects.
- set payloads are recorded so later queries round-trip the value, and
  still reach the ScreenWriter as before.
- OSC 110/111/112 resets restore the defaults.
- Defaults impersonate a conventional dark terminal (fg cccc/cccc/cccc,
  bg 0000/0000/0000) and are overridable per daemon via
  RMUX_DEFAULT_FOREGROUND / RMUX_DEFAULT_BACKGROUND /
  RMUX_DEFAULT_CURSOR_COLOUR.

Tests: query replies for 10/11/12 with both terminators, set-then-query
round-trip, 111 reset, writer passthrough for sets (RecordingWriter now
records the colour calls).
shideneyu added a commit that referenced this pull request Jul 12, 2026
…plies

install-windows.ps1 (PR #88 follow-up): force TLS 1.2 so Windows
PowerShell 5.1 can reach GitHub releases, and make Fail throw instead
of exit under irm|iex so a failed install no longer closes the user's
interactive shell. verify-package-windows.ps1: check the installer's
exit code instead of $? so a failing install.ps1 cannot pass the
package gate. Ledger C-D50 (PR #89): record that answering OSC
10/11/12 colour queries from the emulator is an RMUX extension —
probed tmux 3.7b leaves them unanswered in detached sessions.
shideneyu added a commit that referenced this pull request Jul 12, 2026
…ication DoS

The OSC colour-query support (PR #89) stored an application-set colour
verbatim (up to the 1 MiB input-buffer limit) and reflected it to every
subsequent OSC 10/11/12 `?` query. Because the parser reply buffer is
uncapped and drained only once per read batch (up to 4 MiB), a single pane
output stream could set a ~1 MiB colour and then pack the rest of a batch
with 7-byte queries, amplifying the stored value into hundreds of GB of
replies before the buffer drains and OOM-ing the daemon that serves every
session. Unlike the fixed-size DA1/DA2/DSR/XTVERSION replies, this reflected
arbitrary application-controlled unbounded data, so the vector was new.

- input/mod.rs: bound set_osc_colour to a 64-byte colour-spec length; a real
  X11 / rgb: / #rrggbb spec is far shorter, and an oversized value is not a
  colour, so it is left unstored and queries keep answering the prior or
  default value. The set is still forwarded to the writer (outer terminal)
  as before.
- input/tests/osc_dcs_misc.rs: add a regression test asserting a ~1 MiB set
  followed by 100 queries keeps reply_buf under 100 KiB (was ~100 MiB) and
  still answers the default; the legitimate set-then-query round trip stays
  green.
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