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);
|
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.
|
* Check if shutdown was requested and perform shutdown if so.
|
||||||
*/
|
*/
|
||||||
@@ -3282,6 +3312,13 @@ export class InteractiveMode {
|
|||||||
process.stderr.on("error", terminalErrorHandler);
|
process.stderr.on("error", terminalErrorHandler);
|
||||||
this.signalCleanupHandlers.push(() => process.stdout.off("error", terminalErrorHandler));
|
this.signalCleanupHandlers.push(() => process.stdout.off("error", terminalErrorHandler));
|
||||||
this.signalCleanupHandlers.push(() => process.stderr.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 {
|
private unregisterSignalHandlers(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user