codex-endpoint-switcher 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-endpoint-switcher",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "用于切换 Codex URL 和 Key 的本地网页控制台与 npm CLI",
5
5
  "main": "src/main/main.js",
6
6
  "bin": {
@@ -1,6 +1,9 @@
1
1
  const fs = require("node:fs/promises");
2
2
  const { spawn } = require("node:child_process");
3
3
 
4
+ const WAIT_PARENT_EXIT_TIMEOUT_MS = 20000;
5
+ const WAIT_PARENT_POLL_MS = 400;
6
+
4
7
  function sleep(timeoutMs) {
5
8
  return new Promise((resolve) => {
6
9
  setTimeout(resolve, timeoutMs);
@@ -53,6 +56,55 @@ function runProcess(command, args, options = {}) {
53
56
  });
54
57
  }
55
58
 
59
+ function isProcessAlive(pid) {
60
+ try {
61
+ process.kill(pid, 0);
62
+ return true;
63
+ } catch {
64
+ return false;
65
+ }
66
+ }
67
+
68
+ async function forceTerminateProcess(pid) {
69
+ if (!pid || pid <= 0) {
70
+ return;
71
+ }
72
+
73
+ if (process.platform === "win32") {
74
+ await runProcess("cmd.exe", ["/d", "/s", "/c", `taskkill /PID ${pid} /F`]);
75
+ return;
76
+ }
77
+
78
+ try {
79
+ process.kill(pid, "SIGTERM");
80
+ } catch {
81
+ // 进程已结束时忽略。
82
+ }
83
+ }
84
+
85
+ async function waitForProcessExit(pid, logPath) {
86
+ if (!pid || pid <= 0) {
87
+ return;
88
+ }
89
+
90
+ const startedAt = Date.now();
91
+ while (Date.now() - startedAt < WAIT_PARENT_EXIT_TIMEOUT_MS) {
92
+ if (!isProcessAlive(pid)) {
93
+ await appendLog(logPath, `[${new Date().toISOString()}] 旧进程已退出:${pid}\n`);
94
+ return;
95
+ }
96
+
97
+ await sleep(WAIT_PARENT_POLL_MS);
98
+ }
99
+
100
+ await appendLog(
101
+ logPath,
102
+ `[${new Date().toISOString()}] 旧进程超时未退出,开始强制结束:${pid}\n`,
103
+ );
104
+ await forceTerminateProcess(pid);
105
+ await sleep(1200);
106
+ }
107
+
56
108
  async function reopenConsole(payload) {
57
109
  return runProcess(
58
110
  payload.nodePath,
@@ -91,6 +143,7 @@ async function main() {
91
143
  });
92
144
 
93
145
  await sleep(Number(payload.waitSeconds || 3) * 1000);
146
+ await waitForProcessExit(Number(payload.parentPid || 0), payload.logPath);
94
147
 
95
148
  const installResult = await runProcess(
96
149
  payload.nodePath,
@@ -205,6 +205,7 @@ function scheduleAutoUpdate(options = {}) {
205
205
  JSON.stringify({
206
206
  packageName: packageInfo.name,
207
207
  currentVersion: packageInfo.version,
208
+ parentPid: process.pid,
208
209
  waitSeconds: AUTO_UPDATE_WAIT_SECONDS,
209
210
  logPath,
210
211
  statePath,
@@ -836,7 +836,8 @@ async function handleAutoUpdate() {
836
836
  summary.textContent = `正在自动更新到 ${update.latestVersion}...`;
837
837
  }
838
838
  if (detail) {
839
- detail.textContent = "程序会先关闭,再自动安装最新 npm 包并重新打开控制台。";
839
+ detail.textContent =
840
+ "程序会先关闭,再自动安装最新 npm 包并重新打开控制台。若 10 秒内没有自动关闭,请查看本地更新日志。";
840
841
  }
841
842
  if (checkButton) {
842
843
  checkButton.disabled = true;
package/src/web/server.js CHANGED
@@ -312,7 +312,14 @@ function startServer(options = {}) {
312
312
 
313
313
  process.removeAllListeners("codex-switcher:shutdown");
314
314
  process.on("codex-switcher:shutdown", () => {
315
+ const forceExitTimer = setTimeout(() => {
316
+ webServer.closeAllConnections?.();
317
+ proxyServer.closeAllConnections?.();
318
+ process.exit(0);
319
+ }, 2500);
320
+
315
321
  controller.close(() => {
322
+ clearTimeout(forceExitTimer);
316
323
  process.exit(0);
317
324
  });
318
325
  });