Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ import {
// Tracking bug: https://github.com/microsoft/node-pty/issues/827
process.on('uncaughtException', (error) => {
if (error instanceof Error) {
const message = error.message || '';
const isPtyResizeError =
error.message === 'Cannot resize a pty that has already exited';
const isEbadfError = error.message.includes('EBADF');
message === 'Cannot resize a pty that has already exited';
const isEbadfError =
message.includes('EBADF') ||
(error as { code?: string }).code === 'EBADF';
const isFromNodePty =
error.stack?.includes('node-pty') || error.stack?.includes('PtyResize');

Expand Down
52 changes: 33 additions & 19 deletions packages/core/src/services/shellExecutionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1507,31 +1507,45 @@ export class ShellExecutionService {
}

const activePty = this.activePtys.get(pid);
if (activePty) {
if (!activePty) {
return;
}

// Skip Windows: process.kill(pid, 0) is heavy and native errors are catchable there.
if (process.platform !== 'win32') {
try {
activePty.ptyProcess.resize(cols, rows);
activePty.headlessTerminal.resize(cols, rows);
process.kill(pid, 0);
} catch (e) {
// Ignore errors if the pty has already exited, which can happen
// due to a race condition between the exit event and this call.
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const err = e as { code?: string; message?: string };
const isEsrch = err.code === 'ESRCH';
const isEbadf = err.code === 'EBADF' || err.message?.includes('EBADF');
const isWindowsPtyError = err.message?.includes(
'Cannot resize a pty that has already exited',
);

if (isEsrch || isEbadf || isWindowsPtyError) {
// On Unix, we get an ESRCH or EBADF error.
// On Windows, we get a message-based error.
// In both cases, it's safe to ignore.
} else {
throw e;
// Bail only if the process is explicitly confirmed dead (ESRCH).
if (e instanceof Error && 'code' in e && e.code === 'ESRCH') {
return;
}
}
}

try {
activePty.ptyProcess.resize(cols, rows);
activePty.headlessTerminal.resize(cols, rows);
} catch (e) {
// Ignore errors if the pty has already exited, which can happen
// due to a race condition between the exit event and this call.
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const err = e as { code?: string; message?: string };
Comment thread
scidomino marked this conversation as resolved.
Resolved
const isEsrch = err.code === 'ESRCH';
const isEbadf = err.code === 'EBADF' || err.message?.includes('EBADF');
const isWindowsPtyError = err.message?.includes(
'Cannot resize a pty that has already exited',
);

if (isEsrch || isEbadf || isWindowsPtyError) {
// On Unix, we get an ESRCH or EBADF error.
// On Windows, we get a message-based error.
// In both cases, it's safe to ignore.
} else {
throw e;
}
}

// Force emit the new state after resize
if (activePty) {
const endLine = activePty.headlessTerminal.buffer.active.length;
Expand Down
Loading