(
child: ChildProcess,
options?: { sigkillAfterMs?: number }
)
| 85 | const SIGKILL_GRACE_PERIOD_MS = 5000; |
| 86 | |
| 87 | function createGracefulTerminator( |
| 88 | child: ChildProcess, |
| 89 | options?: { sigkillAfterMs?: number } |
| 90 | ): { |
| 91 | terminate: () => void; |
| 92 | cleanup: () => void; |
| 93 | } { |
| 94 | const sigkillAfterMs = options?.sigkillAfterMs ?? SIGKILL_GRACE_PERIOD_MS; |
| 95 | let sigkillTimer: ReturnType<typeof setTimeout> | null = null; |
| 96 | |
| 97 | const scheduleSigkill = () => { |
| 98 | if (sigkillTimer) return; |
| 99 | sigkillTimer = setTimeout(() => { |
| 100 | sigkillTimer = null; |
| 101 | // Only attempt SIGKILL if the process still appears to be running. |
| 102 | if (child.exitCode === null && child.signalCode === null) { |
| 103 | try { |
| 104 | child.kill("SIGKILL"); |
| 105 | } catch { |
| 106 | // ignore |
| 107 | } |
| 108 | } |
| 109 | }, sigkillAfterMs); |
| 110 | }; |
| 111 | |
| 112 | const terminate = () => { |
| 113 | try { |
| 114 | child.kill("SIGTERM"); |
| 115 | } catch { |
| 116 | // ignore |
| 117 | } |
| 118 | scheduleSigkill(); |
| 119 | }; |
| 120 | |
| 121 | const cleanup = () => { |
| 122 | if (sigkillTimer) { |
| 123 | clearTimeout(sigkillTimer); |
| 124 | sigkillTimer = null; |
| 125 | } |
| 126 | }; |
| 127 | |
| 128 | return { terminate, cleanup }; |
| 129 | } |
| 130 | |
| 131 | /** |
| 132 | * Stream output from a coder CLI command line by line. |
no outgoing calls
no test coverage detected