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.

Evict stale PTY sessions and clean up on close

+29 -1
+11 -1
apps/api/src/pty/index.ts
··· 39 39 }); 40 40 41 41 async function getSession(ctx: Context, id: string) { 42 - if (ctx.sessions.has(id)) return ctx.sessions.get(id)!; 42 + if (ctx.sessions.has(id)) { 43 + const existing = ctx.sessions.get(id)!; 44 + // If the underlying pty-tunnel socket is closed, evict and recreate. 45 + const sock = existing.socket as { readyState?: number }; 46 + if (sock.readyState !== undefined && sock.readyState !== 1 /* OPEN */) { 47 + consola.info("PTY session stale, recreating", { id }); 48 + ctx.sessions.delete(id); 49 + } else { 50 + return existing; 51 + } 52 + } 43 53 44 54 const [record] = await ctx.db 45 55 .select({
+9
apps/api/src/pty/modal/index.ts
··· 187 187 } 188 188 }); 189 189 190 + socket.addEventListener("close", () => { 191 + ctx.sessions.delete(id); 192 + for (const ws of session.wsClients) { 193 + if (ws.readyState === ws.OPEN) ws.close(1000, "exit"); 194 + } 195 + session.clients.clear(); 196 + session.wsClients.clear(); 197 + }); 198 + 190 199 consola.info("Modal: waiting for pty-tunnel socket to open", chalk.greenBright(id)); 191 200 await socket.waitForOpen(); 192 201 consola.info("Modal: pty-tunnel socket open, sending ready", chalk.greenBright(id));
+9
apps/api/src/pty/vercel/index.ts
··· 179 179 } 180 180 }); 181 181 182 + socket.addEventListener("close", () => { 183 + ctx.sessions.delete(id); 184 + for (const ws of session.wsClients) { 185 + if (ws.readyState === ws.OPEN) ws.close(1000, "exit"); 186 + } 187 + session.clients.clear(); 188 + session.wsClients.clear(); 189 + }); 190 + 182 191 await socket.waitForOpen(); 183 192 socket.sendMessage({ type: "ready" }); 184 193