Merge pull request #4426 from ofa1/fix/restore-tty-on-uncaught-exception
fix(coding-agent): restore terminal on uncaught exception
This commit is contained in:
@@ -3244,6 +3244,36 @@ export class InteractiveMode {
|
||||
process.exit(129);
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-resort handler for uncaught exceptions. The TUI puts stdin into raw
|
||||
* mode and hides the cursor; without this handler, an uncaught throw from
|
||||
* anywhere (e.g. an extension's async `ChildProcess.on("exit")` callback)
|
||||
* tears down the process while leaving the terminal in raw mode with no
|
||||
* cursor, requiring `stty sane && reset` to recover.
|
||||
*
|
||||
* Unlike emergencyTerminalExit, the terminal is still alive here, so we
|
||||
* call ui.stop() to restore cooked mode, the cursor, and disable bracketed
|
||||
* paste / Kitty / modifyOtherKeys sequences.
|
||||
*/
|
||||
private uncaughtCrash(error: Error): never {
|
||||
if (this.isShuttingDown) {
|
||||
process.exit(1);
|
||||
}
|
||||
this.isShuttingDown = true;
|
||||
try {
|
||||
this.unregisterSignalHandlers();
|
||||
} catch {}
|
||||
try {
|
||||
killTrackedDetachedChildren();
|
||||
} catch {}
|
||||
try {
|
||||
this.ui.stop();
|
||||
} catch {}
|
||||
console.error("pi exiting due to uncaughtException:");
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if shutdown was requested and perform shutdown if so.
|
||||
*/
|
||||
@@ -3282,6 +3312,13 @@ export class InteractiveMode {
|
||||
process.stderr.on("error", terminalErrorHandler);
|
||||
this.signalCleanupHandlers.push(() => process.stdout.off("error", terminalErrorHandler));
|
||||
this.signalCleanupHandlers.push(() => process.stderr.off("error", terminalErrorHandler));
|
||||
|
||||
// Restore the terminal before the process dies on any uncaught throw.
|
||||
// Without this, an unhandled exception from extension code (or anywhere
|
||||
// in pi) leaves the terminal in raw mode with no cursor.
|
||||
const uncaughtExceptionHandler = (error: Error) => this.uncaughtCrash(error);
|
||||
process.prependListener("uncaughtException", uncaughtExceptionHandler);
|
||||
this.signalCleanupHandlers.push(() => process.off("uncaughtException", uncaughtExceptionHandler));
|
||||
}
|
||||
|
||||
private unregisterSignalHandlers(): void {
|
||||
|
||||
Reference in New Issue
Block a user