fix(terminal): bun-safe exec attach, box self-heal, surfaced errors
The workspace terminal died everywhere: bun's node:http client never
emits the client 'upgrade' event (it surfaces the 101 as a plain
response), so docker-modem's exec.start({hijack:true}) waited forever —
a connected WebSocket with no bytes flowing (prod), or an instant close
when the socket was unreachable (dev). The pre-Phase-1 bridge avoided
dockerode attach for exactly this reason; the real-TTY-resize rewrite
reintroduced it.
- runtime/exec-stream.ts: speak the exec-start HTTP upgrade over a raw
net socket (docker and podman both answer 101 UPGRADED). Works under
bun and node; honors the modem's socketPath/host:port. The stream is
returned paused so the first screen paint can't race the caller's
data handler. Exec create/resize stay on dockerode (plain POSTs).
- user-container.ts: acquireUserBox re-ensures the container on every
acquire instead of trusting a cached "initialized" flag, so a box
removed behind the worker's back (manual rm, another instance's
reaper) is recreated instead of bricking terminals and agent turns
until restart.
- terminal.ts: bridge failures are logged and close the WebSocket with
a clamped human-readable reason instead of a silent catch;
xterm-session.tsx displays that reason instead of a mute
"Session ended". Also roomier terminal line spacing (1.2 -> 1.35).
This commit is contained in:
@@ -189,7 +189,7 @@ export const XtermSession = ({
|
||||
const term = new Terminal({
|
||||
fontFamily: TERMINAL_FONT,
|
||||
fontSize: 13,
|
||||
lineHeight: 1.2,
|
||||
lineHeight: 1.35,
|
||||
cursorBlink: true,
|
||||
theme: themeIsLight ? lightTheme : darkTheme,
|
||||
allowProposedApi: true,
|
||||
@@ -257,8 +257,13 @@ export const XtermSession = ({
|
||||
if (typeof event.data === 'string') term.write(event.data);
|
||||
else term.write(new Uint8Array(event.data));
|
||||
};
|
||||
ws.onclose = () => {
|
||||
if (!isAborted()) setStatus('closed');
|
||||
ws.onclose = (event: CloseEvent) => {
|
||||
if (isAborted()) return;
|
||||
setStatus('closed');
|
||||
// The worker attaches a human-readable reason when the bridge fails
|
||||
// (e.g. container runtime unreachable) — show it instead of a mute
|
||||
// "Session ended".
|
||||
if (event.reason) setErrorText(event.reason);
|
||||
};
|
||||
ws.onerror = () => {
|
||||
if (!isAborted()) setStatus('error');
|
||||
@@ -323,7 +328,9 @@ export const XtermSession = ({
|
||||
{status === 'connected'
|
||||
? `Connected · ${label}`
|
||||
: status === 'idle'
|
||||
? (waitingLabel ? 'Waiting…' : 'Idle')
|
||||
? waitingLabel
|
||||
? 'Waiting…'
|
||||
: 'Idle'
|
||||
: status === 'connecting'
|
||||
? 'Connecting…'
|
||||
: status === 'closed'
|
||||
|
||||
Reference in New Issue
Block a user