MCPcopy
hub / github.com/codeaashu/claude-code / forceExit

Function forceExit

src/utils/gracefulShutdown.ts:193–232  ·  view source on GitHub ↗

* Force process exit, handling the case where the terminal is gone. * When the terminal/PTY is closed (e.g., SIGHUP), process.exit() can throw * EIO errors because Bun tries to flush stdout to a dead file descriptor. * In that case, fall back to SIGKILL which always works.

(exitCode: number)

Source from the content-addressed store, hash-verified

191 * In that case, fall back to SIGKILL which always works.
192 */
193function forceExit(exitCode: number): never {
194 // Clear failsafe timer since we're exiting now
195 if (failsafeTimer !== undefined) {
196 clearTimeout(failsafeTimer)
197 failsafeTimer = undefined
198 }
199 // Drain stdin LAST, right before exit. cleanupTerminalModes() sent
200 // DISABLE_MOUSE_TRACKING early, but the terminal round-trip plus any
201 // events already in flight means bytes can arrive during the seconds
202 // of async cleanup between then and now. Draining here catches them.
203 // Use the Ink class method (not the standalone drainStdin()) so we
204 // drain the instance's stdin — when process.stdin is piped,
205 // getStdinOverride() opens /dev/tty as the real input stream and the
206 // class method knows about it; the standalone function defaults to
207 // process.stdin which would early-return on isTTY=false.
208 try {
209 instances.get(process.stdout)?.drainStdin()
210 } catch {
211 // Terminal may be gone (SIGHUP). Ignore — we are about to exit.
212 }
213 try {
214 process.exit(exitCode)
215 } catch (e) {
216 // process.exit() threw. In tests, it's mocked to throw - re-throw so test sees it.
217 // In production, it's likely EIO from dead terminal - use SIGKILL.
218 if ((process.env.NODE_ENV as string) === 'test') {
219 throw e
220 }
221 // Fall back to SIGKILL which doesn't try to flush anything.
222 process.kill(process.pid, 'SIGKILL')
223 }
224 // In tests, process.exit may be mocked to return instead of exiting.
225 // In production, we should never reach here.
226 if ((process.env.NODE_ENV as string) !== 'test') {
227 throw new Error('unreachable')
228 }
229 // TypeScript trick: cast to never since we know this only happens in tests
230 // where the mock returns instead of exiting
231 return undefined as never
232}
233
234/**
235 * Set up global signal handlers for graceful shutdown

Callers 2

gracefulShutdownSyncFunction · 0.85
gracefulShutdownFunction · 0.85

Calls 3

drainStdinMethod · 0.80
getMethod · 0.65
killMethod · 0.45

Tested by

no test coverage detected