|
1 | 1 | #!/usr/bin/env bun |
| 2 | +import { execFileSync } from "node:child_process"; |
2 | 3 | import { restoreNativeCodex } from "./codex-inject"; |
3 | 4 | import { loadConfig, readPid, removePid, writePid } from "./config"; |
4 | 5 | import { serviceCommand } from "./service"; |
@@ -88,32 +89,59 @@ function handleStart() { |
88 | 89 | } |
89 | 90 |
|
90 | 91 | function killProxy(pid: number): void { |
| 92 | + if (!isProcessAlive(pid)) return; |
91 | 93 | if (process.platform === "win32") { |
| 94 | + const taskkill = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\taskkill.exe`; |
92 | 95 | try { |
93 | | - (require("node:child_process") as typeof import("node:child_process")) |
94 | | - .execSync(`taskkill /PID ${pid} /T /F`, { stdio: "pipe" }); |
95 | | - } catch { /* process already gone */ } |
| 96 | + execFileSync(taskkill, ["/PID", String(pid), "/T", "/F"], { stdio: "pipe" }); |
| 97 | + } catch (err) { |
| 98 | + if (isProcessAlive(pid)) throw err; |
| 99 | + } |
96 | 100 | } else { |
97 | 101 | process.kill(pid, "SIGTERM"); |
| 102 | + if (!waitForExit(pid, 5000)) process.kill(pid, "SIGKILL"); |
| 103 | + } |
| 104 | + if (!waitForExit(pid, 5000)) throw new Error(`process ${pid} did not exit`); |
| 105 | +} |
| 106 | + |
| 107 | +function isProcessAlive(pid: number): boolean { |
| 108 | + try { |
| 109 | + process.kill(pid, 0); |
| 110 | + return true; |
| 111 | + } catch { |
| 112 | + return false; |
98 | 113 | } |
99 | 114 | } |
100 | 115 |
|
| 116 | +function waitForExit(pid: number, timeoutMs: number): boolean { |
| 117 | + const deadline = Date.now() + timeoutMs; |
| 118 | + const marker = new Int32Array(new SharedArrayBuffer(4)); |
| 119 | + while (Date.now() < deadline) { |
| 120 | + if (!isProcessAlive(pid)) return true; |
| 121 | + Atomics.wait(marker, 0, 0, 50); |
| 122 | + } |
| 123 | + return !isProcessAlive(pid); |
| 124 | +} |
| 125 | + |
101 | 126 | function handleStop() { |
102 | 127 | const pid = readPid(); |
| 128 | + let stopFailed = false; |
103 | 129 | if (pid) { |
104 | 130 | try { |
105 | 131 | killProxy(pid); |
106 | 132 | console.log(`✅ Proxy (PID ${pid}) stopped.`); |
| 133 | + removePid(); |
107 | 134 | } catch { |
108 | | - console.log("Proxy process not found."); |
| 135 | + stopFailed = true; |
| 136 | + console.error(`❌ Failed to stop proxy (PID ${pid}).`); |
109 | 137 | } |
110 | | - removePid(); |
111 | 138 | } else { |
112 | 139 | console.log("No running proxy found."); |
113 | 140 | } |
114 | 141 | // Recover native Codex so plain `codex` keeps working while the proxy is down. |
115 | 142 | const r = restoreNativeCodex(); |
116 | 143 | console.log(`↩️ ${r.message}`); |
| 144 | + if (stopFailed) process.exit(1); |
117 | 145 | } |
118 | 146 |
|
119 | 147 | function handleStatus() { |
|
0 commit comments