ca TUI: fix the railway harness launch hang, ⇧esc release, and the shift+enter newline - #1079
Merged
Conversation
Launching the railway harness left a pane holding nothing but the relay's banner. `railway-agent-tui` opens by writing its whole startup burst in one go — bracketed paste, focus reporting, the kitty keyboard query, DA1, then the cursor-position query — and then waits. crossterm uses DA1 as the sentinel in `supports_keyboard_enhancement`: it writes the kitty query and `ESC[c` immediately after, then reads until one of them answers, because a terminal too old to know the kitty query will still answer DA1. Answering the kitty query while ignoring DA1 is therefore the one combination that hangs outright — the harness is told the protocol exists and then waits on a reply that never comes, never reaching the cursor query the pane was already answering. Before the pane learned `ESC[?u` it answered neither, crossterm's two-second timeout expired, and the harness drew; adding half the handshake turned a slow launch into a stuck one. So answer DA1 too. Measured against the real binary under a pty: no DA1 reply and it emits 23 bytes and stops forever; with one it draws in full in 0.07s, which also retires the two-second timeout that was there before any of this.
⌥esc stopped releasing the session pane because macOS cannot send it. Option is a compose key unless the terminal maps it to Meta, and the other ⌥ chords survive that by arriving as the character they compose to — ⌥f as `ƒ`, ⌥[ as a curly quote, which `alt_chord` already matches. Escape composes to nothing, so ⌥esc arrives as a bare Escape with no modifier left to tell it apart from the one meant for the agent. Shift is never composed and the kitty protocol reports a shifted Escape as `CSI 27;2u`, so ⇧esc is taken alongside it and is what the hints now name. ⌥esc, `^]` and `^o` all keep working. Modified Enter falls back to `ESC CR` rather than a bare `\r` when the remote side has not pushed the kitty protocol. A bare `\r` submits the half-written prompt, which is the one outcome shift+enter exists to prevent; `ESC CR` is the legacy newline chord harnesses have always taken, and the exact bytes Claude Code's own `/terminal-setup` binds shift+enter to. Worth recording why the CSI-u path alone was not enough: the kitty protocol exempts Enter, Tab and Backspace from disambiguate mode by design, so a stock terminal reports shift+enter as a bare `\r` with no modifier on it and there is nothing for `encode_key_for` to act on. Lifting that needs REPORT_ALL_KEYS_AS_ESCAPE_CODES, which crossterm cannot yet pair with the associated text those events carry — composed ⌥ characters, dead keys and IMEs would all break — so reporting shift+enter stays the terminal's to opt into.
codyde
force-pushed
the
railway/ca-answer-da1-query
branch
from
August 11, 2026 07:55
67b9694 to
0aa2c1e
Compare
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.
Three fixes in the
railway casession pane. All three are the pane failing to speak the terminal's side of a protocol.1. Fix: railway harness hung on launch — pane showed only the relay banner
railway-agent-tuiwrites its startup burst in one write — bracketed paste, focus reporting,ESC[?u,ESC[c,ESC[6n— then waits.ESC[c) as the sentinel insupports_keyboard_enhancement. The pane answeredESC[?ubut never DA1, so the harness waited on a reply that never came and never reached the cursor query the pane already answered.ESC[?62;22c.2. Fix: ⌥esc no longer released the session pane
ƒ, ⌥[ as a curly quote — whichalt_chordalready matches.CSI 27;3u); it is dead where Option composes, which is the default in Ghostty and Terminal.app.railway cato drive them #1013 shipped this chord as ⇧esc, TUI: replace the wizard-replay ⌥s with a proper settings card #1069 swapped it to ⌥esc.CSI 27;2u. ⌥esc,^]and^oare untouched, so terminals where ⌥esc already worked are unaffected. Hints read⌥/⇧esc / ^].3. Partial fix: shift+enter did not insert a newline in the harness
\rwith no modifier on it. There was nothing forencode_key_forto act on — the CSI-u encoding added earlier could never fire.ESC CRinstead of a bare\rwhen the remote has not pushed the kitty protocol. A bare\rsubmits the half-written prompt;ESC CRis the legacy newline chord, and the bytes Claude Code's/terminal-setupbinds shift+enter to./terminal-setup(or an equivalent keybind sendingESC CR), or Option-as-Meta plus ⌥enter, which already worked.REPORT_ALL_KEYS_AS_ESCAPE_CODESwould lift the exemption, but crossterm cannot pair it with the associated text those events carry — composed ⌥ characters, dead keys and IMEs would all break. Recorded in a comment onsetup_terminal.Tests
ESC[?62;22creplies or otherc-terminated sequences, and the real startup burst gets all three answers in the order asked.3 pre-existing
auth_simfailures on master, unrelated to this branch.