@openai-lite/codex-feishu 0.1.3 → 0.1.5

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": "@openai-lite/codex-feishu",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Feishu bridge for Codex with dual-end synchronized conversations.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,8 @@ import fs from "node:fs";
2
2
  import { spawn, spawnSync } from "node:child_process";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { ensureDir, readTextIfExists, writeText } from "./fs_utils.js";
5
- import { getDaemonLogPath, getDaemonPidPath, getRunDir } from "./paths.js";
5
+ import { getBridgeRpcEndpoint, getDaemonLogPath, getDaemonPidPath, getRunDir } from "./paths.js";
6
+ import { callJsonRpc } from "./uds_rpc.js";
6
7
 
7
8
  function sleep(ms) {
8
9
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -45,6 +46,16 @@ async function removePidFile() {
45
46
  }
46
47
  }
47
48
 
49
+ async function isDaemonRpcResponsive(timeoutMs = 1000) {
50
+ try {
51
+ const endpoint = getBridgeRpcEndpoint();
52
+ const pong = await callJsonRpc(endpoint, "ping", {}, { timeoutMs });
53
+ return Boolean(pong?.ok);
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
48
59
  async function stopByPid(pid, timeoutMs = 3000) {
49
60
  if (!isPidAlive(pid)) {
50
61
  return { action: "already_stopped", pid };
@@ -206,6 +217,20 @@ export async function restartDaemonDetached() {
206
217
  if (startResult.ok) {
207
218
  break;
208
219
  }
220
+ // On Windows, daemon may already be alive (port occupied by existing daemon)
221
+ // while a new detached process exits early. In that case, treat as healthy.
222
+ // eslint-disable-next-line no-await-in-loop
223
+ const responsive = await isDaemonRpcResponsive(1200);
224
+ if (responsive) {
225
+ // eslint-disable-next-line no-await-in-loop
226
+ const current = await readPidFile();
227
+ startResult = {
228
+ ok: true,
229
+ pid: current.pid ?? null,
230
+ reused: true,
231
+ };
232
+ break;
233
+ }
209
234
  failedAttempts.push(`${cmd} ${args.join(" ")} => ${startResult.error}`);
210
235
  }
211
236
  if (!startResult.ok) {
@@ -213,7 +238,9 @@ export async function restartDaemonDetached() {
213
238
  throw new Error(`failed to start daemon in background: ${startResult.error}${details}`);
214
239
  }
215
240
 
216
- await writeText(pidPath, `${startResult.pid}\n`);
241
+ if (startResult.pid) {
242
+ await writeText(pidPath, `${startResult.pid}\n`);
243
+ }
217
244
  return {
218
245
  pidPath,
219
246
  logPath,