Files
orca/src/main/window/window-close-decision.ts
T
Brennan Benson bded1fb2c0 fix(app): bound the wake/quit paths implicated in the phone-session-ended freeze (#9447) (#9853)
* fix(app): bound the wake/quit paths implicated in the phone-session-ended freeze (#9447)

- relay-transport: waitForClose now times out (5s) so a half-open post-sleep
  socket can't wedge runtimeRpc.stop()
- will-quit: race teardown against a 20s deadline so app.quit() always runs
  (Force Quit was the only escape when any teardown member never settled)
- terminal-fit-restore: local restoreTerminalFit invoke gets the same 15s
  bound as the remote path so the held-fit modal buttons can't pin disabled

* fix(app): close wake recovery timeout gaps

* fix(relay): drop late frames after forced teardown

* fix(relay): fence detached socket callbacks

* fix(app): close timeout resource gaps

* fix(relay): detach retired mobile transports

* fix(types): exclude absent stat overloads

* fix(runtime): expire wedged terminal restore dedupe

* fix(runtime): keep restore retries on one reclaim

* chore(skills): refresh bundled skill manifests

* fix(window): fence quit acknowledgements by request

* fix(relay): bound revoked device socket cleanup
2026-07-23 18:03:43 -07:00

35 lines
1.5 KiB
TypeScript

export type WindowCloseAction = 'allow-confirmed' | 'bypass-gone' | 'request-confirmation'
export type WindowCloseState = {
/** The renderer already replied to window:close-requested and called close(). */
windowCloseConfirmed: boolean
/** webContents emitted render-process-gone (the process is truly gone). */
rendererProcessGone: boolean
/** Electron reports the webContents as crashed (isCrashed()). */
isRendererCrashed: boolean
}
/**
* Decides how a native 'close' event should be handled.
*
* Why: a force-killed HUNG renderer must not be treated like a true crash. The
* renderer-owned confirmation (dirty-file save, running-process, multi-session
* guard) is only safe to bypass when the renderer is genuinely gone/crashed and
* therefore cannot answer — bypassing it for a merely-unresponsive renderer is
* what silently destroyed other sessions in #5787. An unresponsive-but-alive
* renderer (rendererProcessGone=false, isRendererCrashed=false) still resolves
* to 'request-confirmation' so the save guard runs. App-wide quit separately
* bounds failure to acknowledge that request; ordinary window close does not.
* A genuinely gone renderer still bypasses so the window stays closable
* (#5144/#5314).
*/
export function resolveWindowCloseAction(state: WindowCloseState): WindowCloseAction {
if (state.windowCloseConfirmed) {
return 'allow-confirmed'
}
if (state.rendererProcessGone || state.isRendererCrashed) {
return 'bypass-gone'
}
return 'request-confirmation'
}