codex-to-im 1.0.59 → 1.0.60

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/dist/cli.mjs CHANGED
@@ -5,14 +5,15 @@ import { createRequire } from 'module'; const require = createRequire(import.met
5
5
  import { stdin as input, stdout as output } from "node:process";
6
6
 
7
7
  // src/service-manager.ts
8
- import fs3 from "node:fs";
8
+ import fs4 from "node:fs";
9
9
  import os2 from "node:os";
10
10
  import path3 from "node:path";
11
11
  import { spawn } from "node:child_process";
12
12
  import { fileURLToPath } from "node:url";
13
13
 
14
14
  // src/config.ts
15
- import fs from "node:fs";
15
+ import fs2 from "node:fs";
16
+ import crypto2 from "node:crypto";
16
17
  import os from "node:os";
17
18
  import path from "node:path";
18
19
 
@@ -39,10 +40,101 @@ function normalizeChannelId(value) {
39
40
  return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "channel";
40
41
  }
41
42
 
43
+ // src/file-lock.ts
44
+ import crypto from "node:crypto";
45
+ import fs from "node:fs";
46
+ var DEFAULT_LOCK_TIMEOUT_MS = 5e3;
47
+ var DEFAULT_STALE_LOCK_MS = 3e4;
48
+ var LOCK_RETRY_INTERVAL_MS = 25;
49
+ var WAIT_ARRAY = new Int32Array(new SharedArrayBuffer(4));
50
+ var ACTIVE_LOCKS = /* @__PURE__ */ new Map();
51
+ function sleepSync(ms) {
52
+ Atomics.wait(WAIT_ARRAY, 0, 0, Math.max(1, ms));
53
+ }
54
+ function isProcessAlive(pid) {
55
+ if (!Number.isInteger(pid) || pid <= 0) return false;
56
+ try {
57
+ process.kill(pid, 0);
58
+ return true;
59
+ } catch (error) {
60
+ return error.code === "EPERM";
61
+ }
62
+ }
63
+ function removeStaleLock(lockPath, staleAfterMs) {
64
+ try {
65
+ const stat = fs.statSync(lockPath);
66
+ if (Date.now() - stat.mtimeMs < staleAfterMs) return false;
67
+ let ownerPid = 0;
68
+ try {
69
+ const parsed = JSON.parse(fs.readFileSync(lockPath, "utf8"));
70
+ ownerPid = typeof parsed.pid === "number" ? parsed.pid : 0;
71
+ } catch {
72
+ }
73
+ if (ownerPid && isProcessAlive(ownerPid)) return false;
74
+ fs.rmSync(lockPath, { force: true });
75
+ return true;
76
+ } catch (error) {
77
+ return error.code === "ENOENT";
78
+ }
79
+ }
80
+ function withFileLock(targetPath, operation, options) {
81
+ const lockPath = `${targetPath}.lock`;
82
+ const activeDepth = ACTIVE_LOCKS.get(lockPath) || 0;
83
+ if (activeDepth > 0) {
84
+ ACTIVE_LOCKS.set(lockPath, activeDepth + 1);
85
+ try {
86
+ return operation();
87
+ } finally {
88
+ const nextDepth = (ACTIVE_LOCKS.get(lockPath) || 1) - 1;
89
+ if (nextDepth > 0) ACTIVE_LOCKS.set(lockPath, nextDepth);
90
+ else ACTIVE_LOCKS.delete(lockPath);
91
+ }
92
+ }
93
+ const timeoutMs = Math.max(0, options?.timeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS);
94
+ const staleAfterMs = Math.max(timeoutMs, options?.staleAfterMs ?? DEFAULT_STALE_LOCK_MS);
95
+ const deadline = Date.now() + timeoutMs;
96
+ const record = {
97
+ token: crypto.randomUUID(),
98
+ pid: process.pid,
99
+ createdAt: Date.now()
100
+ };
101
+ let handle = null;
102
+ while (handle === null) {
103
+ try {
104
+ handle = fs.openSync(lockPath, "wx", 384);
105
+ fs.writeFileSync(handle, JSON.stringify(record), "utf8");
106
+ } catch (error) {
107
+ const code = error.code;
108
+ if (code !== "EEXIST") throw error;
109
+ if (removeStaleLock(lockPath, staleAfterMs)) continue;
110
+ if (Date.now() >= deadline) {
111
+ throw new Error(`Timed out waiting for file lock: ${lockPath}`);
112
+ }
113
+ sleepSync(Math.min(LOCK_RETRY_INTERVAL_MS, Math.max(1, deadline - Date.now())));
114
+ }
115
+ }
116
+ try {
117
+ ACTIVE_LOCKS.set(lockPath, 1);
118
+ return operation();
119
+ } finally {
120
+ ACTIVE_LOCKS.delete(lockPath);
121
+ try {
122
+ fs.closeSync(handle);
123
+ } catch {
124
+ }
125
+ try {
126
+ const current = JSON.parse(fs.readFileSync(lockPath, "utf8"));
127
+ if (current.token === record.token) fs.rmSync(lockPath, { force: true });
128
+ } catch {
129
+ }
130
+ }
131
+ }
132
+
42
133
  // src/config.ts
43
134
  function isSupportedChannelProvider(value) {
44
135
  return value === "feishu" || value === "weixin";
45
136
  }
137
+ var RAW_CHANNELS = Symbol("rawConfigV2Channels");
46
138
  var DEFAULT_CTI_HOME = path.join(os.homedir(), ".codex-to-im");
47
139
  var DEFAULT_WORKSPACE_ROOT = path.join(os.homedir(), "cx2im");
48
140
  var CTI_HOME = process.env.CTI_HOME || DEFAULT_CTI_HOME;
@@ -76,7 +168,7 @@ function parseEnvFile(content) {
76
168
  }
77
169
  function loadRawConfigEnv() {
78
170
  try {
79
- return parseEnvFile(fs.readFileSync(CONFIG_PATH, "utf-8"));
171
+ return parseEnvFile(fs2.readFileSync(CONFIG_PATH, "utf-8"));
80
172
  } catch {
81
173
  return /* @__PURE__ */ new Map();
82
174
  }
@@ -103,26 +195,66 @@ function nowIso() {
103
195
  return (/* @__PURE__ */ new Date()).toISOString();
104
196
  }
105
197
  function ensureConfigDir() {
106
- fs.mkdirSync(CTI_HOME, { recursive: true });
198
+ fs2.mkdirSync(CTI_HOME, { recursive: true });
107
199
  }
108
200
  function readConfigV2File() {
201
+ if (!fs2.existsSync(CONFIG_V2_PATH)) return null;
202
+ let content;
203
+ try {
204
+ content = fs2.readFileSync(CONFIG_V2_PATH, "utf-8");
205
+ } catch (error) {
206
+ throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6 ${CONFIG_V2_PATH}: ${error instanceof Error ? error.message : String(error)}`);
207
+ }
208
+ let raw;
109
209
  try {
110
- const parsed = JSON.parse(fs.readFileSync(CONFIG_V2_PATH, "utf-8"));
111
- if (parsed && parsed.schemaVersion === 2 && parsed.runtime && Array.isArray(parsed.channels)) {
112
- parsed.runtime.provider = normalizeRuntimeProvider(parsed.runtime.provider);
113
- parsed.channels = normalizeChannelInstances(parsed.channels);
114
- return parsed;
210
+ raw = JSON.parse(content);
211
+ } catch (error) {
212
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${CONFIG_V2_PATH} \u4E0D\u662F\u6709\u6548 JSON\uFF0C\u5DF2\u62D2\u7EDD\u8986\u76D6: ${error instanceof Error ? error.message : String(error)}`);
213
+ }
214
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
215
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${CONFIG_V2_PATH} \u7684\u6839\u8282\u70B9\u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u5DF2\u62D2\u7EDD\u8986\u76D6\u3002`);
216
+ }
217
+ if (raw.schemaVersion !== 2) {
218
+ throw new Error(`\u4E0D\u652F\u6301\u914D\u7F6E schemaVersion=${String(raw.schemaVersion)}\uFF0C\u5DF2\u62D2\u7EDD\u7528\u5F53\u524D\u7248\u672C\u8986\u76D6\u3002`);
219
+ }
220
+ if (!raw.runtime || typeof raw.runtime !== "object" || Array.isArray(raw.runtime)) {
221
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${CONFIG_V2_PATH} \u7F3A\u5C11\u6709\u6548\u7684 runtime \u5BF9\u8C61\uFF0C\u5DF2\u62D2\u7EDD\u8986\u76D6\u3002`);
222
+ }
223
+ if (!Array.isArray(raw.channels)) {
224
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6 ${CONFIG_V2_PATH} \u7F3A\u5C11 channels \u6570\u7EC4\uFF0C\u5DF2\u62D2\u7EDD\u8986\u76D6\u3002`);
225
+ }
226
+ const rawChannels = raw.channels;
227
+ const parsed = {
228
+ ...raw,
229
+ schemaVersion: 2,
230
+ runtime: {
231
+ ...raw.runtime,
232
+ provider: normalizeRuntimeProvider(raw.runtime.provider)
233
+ },
234
+ channels: normalizeChannelInstances(rawChannels)
235
+ };
236
+ Object.defineProperty(parsed, RAW_CHANNELS, { value: rawChannels, enumerable: false });
237
+ return parsed;
238
+ }
239
+ function atomicWriteFile(filePath, content) {
240
+ ensureConfigDir();
241
+ const tmpPath = `${filePath}.${process.pid}.${crypto2.randomUUID()}.tmp`;
242
+ try {
243
+ fs2.writeFileSync(tmpPath, content, { mode: 384 });
244
+ fs2.renameSync(tmpPath, filePath);
245
+ } finally {
246
+ try {
247
+ fs2.rmSync(tmpPath, { force: true });
248
+ } catch {
115
249
  }
116
- return null;
117
- } catch {
118
- return null;
119
250
  }
120
251
  }
121
252
  function writeConfigV2File(config) {
122
- ensureConfigDir();
123
- const tmpPath = CONFIG_V2_PATH + ".tmp";
124
- fs.writeFileSync(tmpPath, JSON.stringify(config, null, 2), { mode: 384 });
125
- fs.renameSync(tmpPath, CONFIG_V2_PATH);
253
+ const serialized = {
254
+ ...config,
255
+ channels: config[RAW_CHANNELS] || config.channels
256
+ };
257
+ atomicWriteFile(CONFIG_V2_PATH, JSON.stringify(serialized, null, 2));
126
258
  }
127
259
  function defaultAliasForProvider(provider) {
128
260
  return provider === "feishu" ? "\u98DE\u4E66" : "\u5FAE\u4FE1";
@@ -143,6 +275,7 @@ function normalizeChannelInstances(value) {
143
275
  const config = record.config && typeof record.config === "object" ? record.config : {};
144
276
  const timestamp = nowIso();
145
277
  return [{
278
+ ...record,
146
279
  id: normalizeChannelId(
147
280
  typeof record.id === "string" && record.id.trim() ? record.id : buildDefaultChannelId(provider)
148
281
  ),
@@ -242,44 +375,48 @@ function expandConfig(v2) {
242
375
  function loadConfig() {
243
376
  const current = readConfigV2File();
244
377
  if (current) return expandConfig(current);
245
- const legacyEnv = loadRawConfigEnv();
246
- if (legacyEnv.size > 0) {
247
- const migrated = migrateLegacyEnvToV2(legacyEnv);
248
- writeConfigV2File(migrated);
249
- return expandConfig(migrated);
250
- }
251
- const empty = {
252
- schemaVersion: 2,
253
- runtime: {
254
- provider: "codex",
255
- defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
256
- defaultMode: "code",
257
- historyMessageLimit: 8,
258
- streamStatusIdleStartSeconds: DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
259
- streamStatusCheckIntervalSeconds: DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
260
- codexSkipGitRepoCheck: true,
261
- codexSandboxMode: "workspace-write",
262
- codexReasoningEffort: "medium",
263
- uiAllowLan: false
264
- },
265
- channels: []
266
- };
267
- return expandConfig(empty);
378
+ return withFileLock(CONFIG_V2_PATH, () => {
379
+ const concurrentlyCreated = readConfigV2File();
380
+ if (concurrentlyCreated) return expandConfig(concurrentlyCreated);
381
+ const legacyEnv = loadRawConfigEnv();
382
+ if (legacyEnv.size > 0) {
383
+ const migrated = migrateLegacyEnvToV2(legacyEnv);
384
+ writeConfigV2File(migrated);
385
+ return expandConfig(migrated);
386
+ }
387
+ const empty = {
388
+ schemaVersion: 2,
389
+ runtime: {
390
+ provider: "codex",
391
+ defaultWorkspaceRoot: DEFAULT_WORKSPACE_ROOT,
392
+ defaultMode: "code",
393
+ historyMessageLimit: 8,
394
+ streamStatusIdleStartSeconds: DEFAULT_STREAM_STATUS_IDLE_START_SECONDS,
395
+ streamStatusCheckIntervalSeconds: DEFAULT_STREAM_STATUS_CHECK_INTERVAL_SECONDS,
396
+ codexSkipGitRepoCheck: true,
397
+ codexSandboxMode: "workspace-write",
398
+ codexReasoningEffort: "medium",
399
+ uiAllowLan: false
400
+ },
401
+ channels: []
402
+ };
403
+ return expandConfig(empty);
404
+ });
268
405
  }
269
406
 
270
407
  // src/bridge-instance-lock.ts
271
- import fs2 from "node:fs";
408
+ import fs3 from "node:fs";
272
409
  import path2 from "node:path";
273
410
  var runtimeDir = path2.join(CTI_HOME, "runtime");
274
411
  var bridgeInstanceLockFile = path2.join(runtimeDir, "bridge.instance.lock");
275
412
  function readJsonFile(filePath, fallback) {
276
413
  try {
277
- return JSON.parse(fs2.readFileSync(filePath, "utf-8"));
414
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
278
415
  } catch {
279
416
  return fallback;
280
417
  }
281
418
  }
282
- function isProcessAlive(pid) {
419
+ function isProcessAlive2(pid) {
283
420
  if (!pid) return false;
284
421
  try {
285
422
  process.kill(pid, 0);
@@ -295,11 +432,11 @@ function readBridgeInstanceLock(filePath = bridgeInstanceLockFile) {
295
432
  if (!Number.isFinite(pid) || pid <= 0 || !createdAt) return null;
296
433
  return { pid, createdAt };
297
434
  }
298
- function clearStaleBridgeInstanceLock(filePath = bridgeInstanceLockFile, isAlive = isProcessAlive) {
435
+ function clearStaleBridgeInstanceLock(filePath = bridgeInstanceLockFile, isAlive = isProcessAlive2) {
299
436
  const existing = readBridgeInstanceLock(filePath);
300
437
  if (existing && isAlive(existing.pid)) return;
301
438
  try {
302
- fs2.unlinkSync(filePath);
439
+ fs3.unlinkSync(filePath);
303
440
  } catch {
304
441
  }
305
442
  }
@@ -320,26 +457,26 @@ var npmUninstallLogFile = path3.join(runtimeDir2, "npm-uninstall.log");
320
457
  var WINDOWS_HIDE = process.platform === "win32" ? { windowsHide: true } : {};
321
458
  var BRIDGE_START_LOCK_STALE_MS = 3e4;
322
459
  function ensureDirs() {
323
- fs3.mkdirSync(runtimeDir2, { recursive: true });
324
- fs3.mkdirSync(logsDir, { recursive: true });
460
+ fs4.mkdirSync(runtimeDir2, { recursive: true });
461
+ fs4.mkdirSync(logsDir, { recursive: true });
325
462
  }
326
463
  function readJsonFile2(filePath, fallback) {
327
464
  try {
328
- return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
465
+ return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
329
466
  } catch {
330
467
  return fallback;
331
468
  }
332
469
  }
333
470
  function readPid(filePath) {
334
471
  try {
335
- const raw = fs3.readFileSync(filePath, "utf-8").trim();
472
+ const raw = fs4.readFileSync(filePath, "utf-8").trim();
336
473
  const pid = Number(raw);
337
474
  return Number.isFinite(pid) ? pid : void 0;
338
475
  } catch {
339
476
  return void 0;
340
477
  }
341
478
  }
342
- function isProcessAlive2(pid) {
479
+ function isProcessAlive3(pid) {
343
480
  if (!pid) return false;
344
481
  try {
345
482
  process.kill(pid, 0);
@@ -357,7 +494,7 @@ function collectTrackedBridgePids(bridgePid, statusPid, instanceLockPid) {
357
494
  }
358
495
  return [...unique];
359
496
  }
360
- function resolveTrackedBridgePid(bridgePid, statusPid, instanceLockPid, isAlive = isProcessAlive2) {
497
+ function resolveTrackedBridgePid(bridgePid, statusPid, instanceLockPid, isAlive = isProcessAlive3) {
361
498
  if (isAlive(bridgePid)) return bridgePid;
362
499
  if (isAlive(statusPid)) return statusPid;
363
500
  if (isAlive(instanceLockPid)) return instanceLockPid;
@@ -373,7 +510,7 @@ function getTrackedBridgePids(status) {
373
510
  }
374
511
  function clearBridgePidFile() {
375
512
  try {
376
- fs3.unlinkSync(bridgePidFile);
513
+ fs4.unlinkSync(bridgePidFile);
377
514
  } catch {
378
515
  }
379
516
  }
@@ -388,7 +525,7 @@ function isBridgeStartLockStale(lock, options = {}) {
388
525
  if (!lock) return true;
389
526
  const nowMs = options.nowMs ?? Date.now();
390
527
  const staleMs = options.staleMs ?? BRIDGE_START_LOCK_STALE_MS;
391
- const isAlive = options.isAlive ?? isProcessAlive2;
528
+ const isAlive = options.isAlive ?? isProcessAlive3;
392
529
  const createdAtMs = Date.parse(lock.createdAt);
393
530
  if (!Number.isFinite(createdAtMs)) return true;
394
531
  if (!isAlive(lock.pid)) return true;
@@ -404,7 +541,7 @@ function tryAcquireBridgeStartLock(options = {}) {
404
541
  };
405
542
  for (let attempt = 0; attempt < 2; attempt += 1) {
406
543
  try {
407
- fs3.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
544
+ fs4.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
408
545
  return { acquired: true };
409
546
  } catch (error) {
410
547
  const code = error.code;
@@ -418,7 +555,7 @@ function tryAcquireBridgeStartLock(options = {}) {
418
555
  return { acquired: false, holderPid: existing2?.pid };
419
556
  }
420
557
  try {
421
- fs3.unlinkSync(filePath);
558
+ fs4.unlinkSync(filePath);
422
559
  } catch {
423
560
  }
424
561
  }
@@ -430,14 +567,14 @@ function releaseBridgeStartLock(filePath = bridgeStartLockFile, ownerPid = proce
430
567
  const existing = readBridgeStartLock(filePath);
431
568
  if (!existing) {
432
569
  try {
433
- fs3.unlinkSync(filePath);
570
+ fs4.unlinkSync(filePath);
434
571
  } catch {
435
572
  }
436
573
  return;
437
574
  }
438
575
  if (existing.pid !== ownerPid) return;
439
576
  try {
440
- fs3.unlinkSync(filePath);
577
+ fs4.unlinkSync(filePath);
441
578
  } catch {
442
579
  }
443
580
  }
@@ -523,7 +660,7 @@ function ensureBridgeAutostartLauncher() {
523
660
  "exit $LASTEXITCODE",
524
661
  ""
525
662
  ].join("\r\n");
526
- fs3.writeFileSync(bridgeAutostartLauncherFile, content, "utf-8");
663
+ fs4.writeFileSync(bridgeAutostartLauncherFile, content, "utf-8");
527
664
  return bridgeAutostartLauncherFile;
528
665
  }
529
666
  function parsePowerShellJson(raw) {
@@ -567,7 +704,7 @@ function buildDeferredGlobalNpmUninstallLaunch(options = {}) {
567
704
  async function launchDeferredGlobalNpmUninstall() {
568
705
  ensureDirs();
569
706
  const launch = buildDeferredGlobalNpmUninstallLaunch();
570
- fs3.writeFileSync(
707
+ fs4.writeFileSync(
571
708
  launch.logPath,
572
709
  [
573
710
  `[${(/* @__PURE__ */ new Date()).toISOString()}] Scheduling global uninstall.`,
@@ -606,7 +743,7 @@ function getBridgeStatus() {
606
743
  status.pid,
607
744
  readBridgeInstanceLock()?.pid
608
745
  );
609
- if (!isProcessAlive2(pid)) {
746
+ if (!isProcessAlive3(pid)) {
610
747
  return {
611
748
  ...status,
612
749
  pid,
@@ -621,7 +758,7 @@ function getBridgeStatus() {
621
758
  }
622
759
  function getUiServerStatus() {
623
760
  const status = readJsonFile2(uiStatusFile, { running: false, port: uiPort });
624
- if (!isProcessAlive2(status.pid)) {
761
+ if (!isProcessAlive3(status.pid)) {
625
762
  return {
626
763
  ...status,
627
764
  running: false,
@@ -706,7 +843,7 @@ async function waitForUiServer(timeoutMs = 15e3) {
706
843
  async function startBridge() {
707
844
  ensureDirs();
708
845
  const current = getBridgeStatus();
709
- const extraAlivePids = getTrackedBridgePids(current).filter((pid) => pid !== current.pid && isProcessAlive2(pid));
846
+ const extraAlivePids = getTrackedBridgePids(current).filter((pid) => pid !== current.pid && isProcessAlive3(pid));
710
847
  if (current.running && extraAlivePids.length === 0) return current;
711
848
  if (current.running && extraAlivePids.length > 0) {
712
849
  await stopBridge();
@@ -731,17 +868,17 @@ async function startBridge() {
731
868
  startLockHeld = true;
732
869
  try {
733
870
  const currentAfterLock = getBridgeStatus();
734
- const extraAlivePidsAfterLock = getTrackedBridgePids(currentAfterLock).filter((pid) => pid !== currentAfterLock.pid && isProcessAlive2(pid));
871
+ const extraAlivePidsAfterLock = getTrackedBridgePids(currentAfterLock).filter((pid) => pid !== currentAfterLock.pid && isProcessAlive3(pid));
735
872
  if (currentAfterLock.running && extraAlivePidsAfterLock.length === 0) return currentAfterLock;
736
873
  if (currentAfterLock.running && extraAlivePidsAfterLock.length > 0) {
737
874
  await stopBridge();
738
875
  }
739
876
  const daemonEntry = path3.join(packageRoot, "dist", "daemon.mjs");
740
- if (!fs3.existsSync(daemonEntry)) {
877
+ if (!fs4.existsSync(daemonEntry)) {
741
878
  throw new Error(`Daemon bundle not found at ${daemonEntry}. Run npm run build first.`);
742
879
  }
743
- const stdoutFd = fs3.openSync(path3.join(logsDir, "bridge-launcher.out.log"), "a");
744
- const stderrFd = fs3.openSync(path3.join(logsDir, "bridge-launcher.err.log"), "a");
880
+ const stdoutFd = fs4.openSync(path3.join(logsDir, "bridge-launcher.out.log"), "a");
881
+ const stderrFd = fs4.openSync(path3.join(logsDir, "bridge-launcher.err.log"), "a");
745
882
  const child = spawn(process.execPath, [daemonEntry], {
746
883
  cwd: packageRoot,
747
884
  detached: true,
@@ -765,7 +902,7 @@ async function startBridge() {
765
902
  }
766
903
  async function stopBridge() {
767
904
  const status = readJsonFile2(bridgeStatusFile, { running: false });
768
- const pids = getTrackedBridgePids(status).filter((pid) => isProcessAlive2(pid));
905
+ const pids = getTrackedBridgePids(status).filter((pid) => isProcessAlive3(pid));
769
906
  if (pids.length === 0) {
770
907
  clearBridgePidFile();
771
908
  clearStaleBridgeInstanceLock();
@@ -790,7 +927,7 @@ async function stopBridge() {
790
927
  }
791
928
  const startedAt = Date.now();
792
929
  while (Date.now() - startedAt < 1e4) {
793
- if (pids.every((pid) => !isProcessAlive2(pid))) {
930
+ if (pids.every((pid) => !isProcessAlive3(pid))) {
794
931
  clearBridgePidFile();
795
932
  clearStaleBridgeInstanceLock();
796
933
  return getBridgeStatus();
@@ -887,8 +1024,8 @@ async function uninstallBridgeAutostart() {
887
1024
  ].join("; ");
888
1025
  await runPowerShell(script);
889
1026
  try {
890
- if (fs3.existsSync(bridgeAutostartLauncherFile)) {
891
- fs3.unlinkSync(bridgeAutostartLauncherFile);
1027
+ if (fs4.existsSync(bridgeAutostartLauncherFile)) {
1028
+ fs4.unlinkSync(bridgeAutostartLauncherFile);
892
1029
  }
893
1030
  } catch {
894
1031
  }
@@ -920,11 +1057,11 @@ async function ensureUiServerRunning() {
920
1057
  const current = getUiServerStatus();
921
1058
  if (current.running) return current;
922
1059
  const serverEntry = path3.join(packageRoot, "dist", "ui-server.mjs");
923
- if (!fs3.existsSync(serverEntry)) {
1060
+ if (!fs4.existsSync(serverEntry)) {
924
1061
  throw new Error(`UI server bundle not found at ${serverEntry}. Run npm run build first.`);
925
1062
  }
926
- const stdoutFd = fs3.openSync(path3.join(logsDir, "ui-server.out.log"), "a");
927
- const stderrFd = fs3.openSync(path3.join(logsDir, "ui-server.err.log"), "a");
1063
+ const stdoutFd = fs4.openSync(path3.join(logsDir, "ui-server.out.log"), "a");
1064
+ const stderrFd = fs4.openSync(path3.join(logsDir, "ui-server.err.log"), "a");
928
1065
  const child = spawn(process.execPath, [serverEntry], {
929
1066
  cwd: packageRoot,
930
1067
  detached: true,
@@ -944,7 +1081,7 @@ async function ensureUiServerRunning() {
944
1081
  }
945
1082
  async function stopUiServer() {
946
1083
  const status = getUiServerStatus();
947
- if (!status.pid || !isProcessAlive2(status.pid)) {
1084
+ if (!status.pid || !isProcessAlive3(status.pid)) {
948
1085
  const next2 = { ...status, running: false };
949
1086
  writeUiServerStatus(next2);
950
1087
  return next2;
@@ -981,7 +1118,7 @@ async function stopUiServer() {
981
1118
  }
982
1119
  function writeUiServerStatus(status) {
983
1120
  ensureDirs();
984
- fs3.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
1121
+ fs4.writeFileSync(uiStatusFile, JSON.stringify(status, null, 2), "utf-8");
985
1122
  }
986
1123
  function openBrowser(url) {
987
1124
  if (process.platform === "win32") {