Run the TUI in the web UI as a per-connection console - #1182
Merged
Conversation
The web UI reimplements the TUI surface by surface, and the queue of "web UI reaches parity on X" never empties. This adds a console: the daemon spawns its own client under a PTY and streams it to the browser, so anything the TUI can do is reachable from a browser the day it lands. A console is a client, not a session — never listed, persisted, counted, or resumable, and reaped when its connection drops. It has exactly one viewer, so it needs none of the PTY geometry arbitration sessions do. While the console is open the web UI's own chord keymap stands down. Both surfaces speak the same C-x vocabulary, so leaving it armed meant C-x C-f opened a web dialog over a terminal that never saw the prefix. Desktop only, opt-in from settings; the web client stays the default.
While the console is open the web UI's chord keymap stands down, so any click that moves focus off the terminal — the console bar, the padding around the grid — leaves keystrokes with no consumer at all. Hand focus back on mouseup, unless the click was the close button or left a selection to copy.
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.
Two clients render this fleet and they have never been at parity. Every TUI
capability has had to be ported into the web UI a second time — view modes,
playbook, split panes, session controls, the chord keymap — and the queue does
not empty.
This adds a console: the daemon spawns its own TUI in a PTY and streams it
to an xterm in the browser. Not one session's PTY — the whole client, session
list and all. Anything reachable in the TUI becomes reachable from a browser
the day it lands, which turns parity from a blocker into a preference about
which surface is nicer for a given task.
A console is a client, not a session (
specs/0182).It is never listed, persisted, resumed, or counted; it belongs to exactly one
connection and is reaped when that connection drops. Modeling it as a session
would have been less code — attach, input, resize and reconnect all exist — and
would have been wrong: it would appear in its own list, count itself in its own
token meter, and persist a transcript of nothing.
Because it has exactly one viewer, its geometry is just that viewer's fit. The
ownership arbitration a shared session PTY needs (
0153) does not apply and isdeliberately not introduced.
The keymap has to stand down
The web UI deliberately speaks the TUI's
C-xchord vocabulary (0150).Pointed at a console that becomes two consumers of one vocabulary:
C-x C-fopens a web dialog stacked over a terminal that never saw the prefix. So while
the console is open the web keymap stands down entirely and every key, chord
included, goes to the child.
That leaves a second hole, which the follow-up commit closes: with the web
keymap down, clicking the bar or the padding around the grid takes focus off
the terminal and keystrokes reach neither consumer. Focus is handed straight
back on mouseup, skipping the close button and any live text selection.
Verified
Against the built binary with embedded assets, each keystroke sent exactly once
and no web dialog opening:
C-x\x18C-f\x06C-x o\x18oC-x C-b\x18\x02Corroborated by reading the xterm buffer — the TUI's own harness picker was
open:
New session: 1/11 ↑/↓ C-p/C-n select Enter choose Tab complete Esc cancel.Scope
Desktop viewports only — a full-screen TUI on a phone has no modifier keys and
no room for the grid it wants. The modern web client stays the default surface
(
0144); this is an escape hatch, not a replacement, and not a reason to stopbringing TUI capabilities into the web UI natively.
This is a prototype: it proves the shape end to end rather than polishing it.
Known gaps are the terminal-emulator affordances listed in the spec's
Consequences — background reporting, OSC 52 clipboard, and any chord the
browser reserves for itself.
Try it
crates/daemononly → the binary isconstruct:Run
construct daemon run, open the web UI, click the console button.