@openai-lite/codex-feishu 0.1.2 → 0.1.4

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.2",
3
+ "version": "0.1.4",
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 };
@@ -183,8 +194,8 @@ export async function restartDaemonDetached() {
183
194
  await removePidFile();
184
195
 
185
196
  const entry = process.argv[1];
186
- const stableCliEntry = fileURLToPath(new URL("../cli.js", import.meta.url));
187
- const candidateEntries = [...new Set([stableCliEntry, entry].filter(Boolean))];
197
+ const stableBinEntry = fileURLToPath(new URL("../../bin/codex-feishu.js", import.meta.url));
198
+ const candidateEntries = [...new Set([stableBinEntry, entry].filter(Boolean))];
188
199
  const attempts = [];
189
200
  if (process.platform === "win32") {
190
201
  for (const cliEntry of candidateEntries) {
@@ -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,