the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Buffer and replay WS messages during session setup

Buffer messages that arrive before async session creation completes and
replay them once the session exists. Also send a newline after attaching
to
trigger a prompt redraw since initial shell output can be lost while
wsClients is empty.

+39 -4
+21 -2
apps/api/src/pty/index.ts
··· 135 135 } 136 136 } 137 137 138 + // The WS upgrade completes immediately but session creation is async. 139 + // Buffer any messages (resize, keystrokes) that arrive before the session 140 + // is ready so they can be replayed once the session exists. 141 + const pendingMessages: Buffer[] = []; 142 + const bufferMessage = (data: Buffer) => pendingMessages.push(data); 143 + ws.on("message", bufferMessage); 144 + 138 145 let session: Awaited<ReturnType<typeof getSession>>; 139 146 try { 140 147 session = await getSession(context.ctx, id); ··· 145 152 } 146 153 147 154 session.wsClients.add(ws); 155 + ws.off("message", bufferMessage); 148 156 149 - ws.on("message", (data) => { 157 + const handleMessage = (data: Buffer) => { 150 158 const text = data.toString("utf-8"); 151 159 try { 152 160 const msg = JSON.parse(text); ··· 166 174 // not JSON — treat as raw input 167 175 } 168 176 session.socket.sendMessage({ type: "message", message: text }); 169 - }); 177 + }; 178 + 179 + // Replay messages buffered during session setup (e.g. the initial resize). 180 + for (const data of pendingMessages) { 181 + handleMessage(data); 182 + } 183 + 184 + ws.on("message", (data) => handleMessage(data as Buffer)); 170 185 171 186 ws.on("close", () => { 172 187 session.wsClients.delete(ws); 173 188 }); 189 + 190 + // The shell's initial prompt was output while wsClients was empty and is 191 + // now lost. Send a newline to trigger a fresh prompt redraw. 192 + session.socket.sendMessage({ type: "message", message: "\n" }); 174 193 }, 175 194 ); 176 195
+18 -2
apps/api/src/tty/index.tsx
··· 398 398 } 399 399 } 400 400 401 + // Buffer messages that arrive before the session is ready. 402 + const pendingMessages: Buffer[] = []; 403 + const bufferMessage = (data: Buffer) => pendingMessages.push(data); 404 + ws.on("message", bufferMessage); 405 + 401 406 let session: Session; 402 407 try { 403 408 session = await getSession(context.ctx, id); ··· 408 413 } 409 414 410 415 session.wsClients.add(ws); 416 + ws.off("message", bufferMessage); 411 417 412 - ws.on("message", (data) => { 418 + const handleMessage = (data: Buffer) => { 413 419 const text = data.toString("utf-8"); 414 420 try { 415 421 const msg = JSON.parse(text); ··· 421 427 // not JSON — treat as raw input 422 428 } 423 429 session.cmd.stdin.write(text); 424 - }); 430 + }; 431 + 432 + // Replay messages buffered during session setup (e.g. the initial resize). 433 + for (const data of pendingMessages) { 434 + handleMessage(data); 435 + } 436 + 437 + ws.on("message", (data) => handleMessage(data as Buffer)); 425 438 426 439 ws.on("close", () => { 427 440 session.wsClients.delete(ws); 428 441 }); 442 + 443 + // Trigger a fresh prompt redraw (initial output was lost while wsClients was empty). 444 + session.cmd.stdin.write("\n"); 429 445 }); 430 446 431 447 return { wss, pathRegex };