feat(terminal): switch terminal transport to pure websocket with fallback (#762)

* feat(terminal): add resumable websocket transport

Unify terminal input and stream traffic on `/api/terminal/ws` with a v2 control-frame protocol and advertised transport capabilities.

Buffer recent PTY output on the server so rebinding clients can replay missed chunks after reconnects or startup races, while keeping SSE as a fallback stream path.

Update the web terminal client and store to negotiate the new transport, track tab lifecycle, and avoid reopening exited sessions when restoring tabs.

* fix(terminal): retry rehydrated websocket reconnects

* fix(terminal): keep reconnect retries silent

* fix(terminal): wire ws stream output and replay in runtime

* fix(web): enable ws proxy for /api in dev

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Yifan
2026-04-01 19:31:21 +03:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent d68bec491c
commit 2b70ec6f3a
14 changed files with 1012 additions and 462 deletions
+27 -8
View File
@@ -1,12 +1,31 @@
export {
TERMINAL_INPUT_WS_PATH,
TERMINAL_INPUT_WS_CONTROL_TAG_JSON,
TERMINAL_INPUT_WS_MAX_PAYLOAD_BYTES,
TERMINAL_WS_PATH,
TERMINAL_WS_CONTROL_TAG_JSON,
TERMINAL_WS_MAX_PAYLOAD_BYTES,
isTerminalWsPathname,
parseRequestPathname,
normalizeTerminalInputWsMessageToBuffer,
normalizeTerminalInputWsMessageToText,
readTerminalInputWsControlFrame,
createTerminalInputWsControlFrame,
normalizeTerminalWsMessageToBuffer,
normalizeTerminalWsMessageToText,
readTerminalWsControlFrame,
createTerminalWsControlFrame,
pruneRebindTimestamps,
isRebindRateLimited,
} from './input-ws-protocol.js';
} from './terminal-ws-protocol.js';
export {
TERMINAL_WS_PATH as TERMINAL_INPUT_WS_PATH,
TERMINAL_WS_CONTROL_TAG_JSON as TERMINAL_INPUT_WS_CONTROL_TAG_JSON,
TERMINAL_WS_MAX_PAYLOAD_BYTES as TERMINAL_INPUT_WS_MAX_PAYLOAD_BYTES,
normalizeTerminalWsMessageToBuffer as normalizeTerminalInputWsMessageToBuffer,
normalizeTerminalWsMessageToText as normalizeTerminalInputWsMessageToText,
readTerminalWsControlFrame as readTerminalInputWsControlFrame,
createTerminalWsControlFrame as createTerminalInputWsControlFrame,
} from './terminal-ws-protocol.js';
export {
TERMINAL_OUTPUT_REPLAY_MAX_BYTES,
createTerminalOutputReplayBuffer,
appendTerminalOutputReplayChunk,
listTerminalOutputReplayChunksSince,
getLatestTerminalOutputReplayChunkId,
} from './output-replay-buffer.js';