codex-to-im 1.0.60 → 1.0.62

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/daemon.mjs CHANGED
@@ -324,9 +324,9 @@ __export(codex_provider_exports, {
324
324
  CodexProvider: () => CodexProvider,
325
325
  mapCodexUsage: () => mapCodexUsage
326
326
  });
327
- import fs15 from "node:fs";
327
+ import fs17 from "node:fs";
328
328
  import os4 from "node:os";
329
- import path17 from "node:path";
329
+ import path18 from "node:path";
330
330
  function isRecord(value) {
331
331
  return typeof value === "object" && value !== null && !Array.isArray(value);
332
332
  }
@@ -543,13 +543,13 @@ var init_codex_provider = __esm({
543
543
  { type: "text", text: params.prompt }
544
544
  ];
545
545
  for (const file of imageFiles) {
546
- if (file.filePath && fs15.existsSync(file.filePath)) {
546
+ if (file.filePath && fs17.existsSync(file.filePath)) {
547
547
  parts.push({ type: "local_image", path: file.filePath });
548
548
  continue;
549
549
  }
550
550
  const ext = MIME_EXT[file.type] || ".png";
551
- const tmpPath = path17.join(os4.tmpdir(), `cti-img-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
552
- fs15.writeFileSync(tmpPath, Buffer.from(file.data, "base64"));
551
+ const tmpPath = path18.join(os4.tmpdir(), `cti-img-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
552
+ fs17.writeFileSync(tmpPath, Buffer.from(file.data, "base64"));
553
553
  tempFiles.push(tmpPath);
554
554
  parts.push({ type: "local_image", path: tmpPath });
555
555
  }
@@ -715,7 +715,7 @@ var init_codex_provider = __esm({
715
715
  } finally {
716
716
  for (const tmp of tempFiles) {
717
717
  try {
718
- fs15.unlinkSync(tmp);
718
+ fs17.unlinkSync(tmp);
719
719
  } catch {
720
720
  }
721
721
  }
@@ -845,9 +845,9 @@ var init_codex_provider = __esm({
845
845
  });
846
846
 
847
847
  // src/main.ts
848
- import fs16 from "node:fs";
849
- import path18 from "node:path";
850
- import crypto10 from "node:crypto";
848
+ import fs18 from "node:fs";
849
+ import path19 from "node:path";
850
+ import crypto11 from "node:crypto";
851
851
 
852
852
  // src/lib/bridge/context.ts
853
853
  var CONTEXT_KEY = "__bridge_context__";
@@ -3286,20 +3286,20 @@ ${trimmedResponse}`;
3286
3286
  buffer = Buffer.concat(chunks);
3287
3287
  } catch (streamErr) {
3288
3288
  console.warn("[feishu-adapter] Stream read failed, falling back to writeFile:", streamErr instanceof Error ? streamErr.message : streamErr);
3289
- const fs17 = await import("fs");
3289
+ const fs19 = await import("fs");
3290
3290
  const os5 = await import("os");
3291
- const path19 = await import("path");
3292
- const tmpPath = path19.join(os5.tmpdir(), `feishu-dl-${crypto3.randomUUID()}`);
3291
+ const path20 = await import("path");
3292
+ const tmpPath = path20.join(os5.tmpdir(), `feishu-dl-${crypto3.randomUUID()}`);
3293
3293
  try {
3294
3294
  await res.writeFile(tmpPath);
3295
- buffer = fs17.readFileSync(tmpPath);
3295
+ buffer = fs19.readFileSync(tmpPath);
3296
3296
  if (buffer.length > MAX_FILE_SIZE) {
3297
3297
  console.warn(`[feishu-adapter] Resource too large (>${MAX_FILE_SIZE} bytes), key: ${fileKey}`);
3298
3298
  return null;
3299
3299
  }
3300
3300
  } finally {
3301
3301
  try {
3302
- fs17.unlinkSync(tmpPath);
3302
+ fs19.unlinkSync(tmpPath);
3303
3303
  } catch {
3304
3304
  }
3305
3305
  }
@@ -10837,8 +10837,10 @@ var IGNORED_RESPONSE_ITEM_TYPES = /* @__PURE__ */ new Set([
10837
10837
  "web_search_call"
10838
10838
  ]);
10839
10839
  var IGNORED_TOP_LEVEL_TYPES = /* @__PURE__ */ new Set([
10840
+ "compacted",
10840
10841
  "session_meta",
10841
- "turn_context"
10842
+ "turn_context",
10843
+ "world_state"
10842
10844
  ]);
10843
10845
  var TERMINAL_COMPLETION_EVENT_TYPES = /* @__PURE__ */ new Set([
10844
10846
  "task_complete",
@@ -10865,6 +10867,10 @@ function extractTerminalCompletionText(payload) {
10865
10867
  }
10866
10868
  return "";
10867
10869
  }
10870
+ function isSyntheticDesktopUserContext(text2) {
10871
+ const normalized = text2.trim();
10872
+ return normalized.startsWith("<environment_context>") && normalized.endsWith("</environment_context>");
10873
+ }
10868
10874
  function isIgnoredMirrorLineKind(line) {
10869
10875
  if (isSessionEventLine(line)) {
10870
10876
  const payloadType = typeof line.payload?.type === "string" ? line.payload.type.trim() : "";
@@ -11177,7 +11183,7 @@ function pushDesktopMirrorEventRecord(records, parsed, rawLine, activeTurnId) {
11177
11183
  }
11178
11184
  if (parsed.payload?.type === "user_message") {
11179
11185
  const text2 = extractNormalizedStructuredText(parsed.payload.message);
11180
- if (!text2) return true;
11186
+ if (!text2 || isSyntheticDesktopUserContext(text2)) return true;
11181
11187
  records.push({
11182
11188
  signature,
11183
11189
  type: "message",
@@ -11234,7 +11240,7 @@ function pushDesktopMirrorResponseRecord(records, parsed, rawLine, activeTurnId,
11234
11240
  }
11235
11241
  if (parsed.payload?.type === "message" && parsed.payload.role === "user") {
11236
11242
  const text2 = extractDesktopMessageText(parsed);
11237
- if (!text2) return true;
11243
+ if (!text2 || isSyntheticDesktopUserContext(text2)) return true;
11238
11244
  const previous = records.at(-1);
11239
11245
  if (previous?.type === "message" && previous.role === "user" && previous.content === text2 && previous.turnId === (activeTurnId || void 0)) {
11240
11246
  return true;
@@ -11249,6 +11255,9 @@ function pushDesktopMirrorResponseRecord(records, parsed, rawLine, activeTurnId,
11249
11255
  });
11250
11256
  return true;
11251
11257
  }
11258
+ if (parsed.payload?.type === "message") {
11259
+ return true;
11260
+ }
11252
11261
  if (parsed.payload?.type === "tool_search_call") {
11253
11262
  const toolId = extractNormalizedFreeText(parsed.payload.call_id) || signature;
11254
11263
  records.push({
@@ -13165,6 +13174,10 @@ function filterSuppressedMirrorRecords(store, sessionId, records, config2, nowMs
13165
13174
  break;
13166
13175
  }
13167
13176
  if (record.type === "message" && record.role === "user") {
13177
+ if (isSyntheticDesktopUserContext(record.content || "")) {
13178
+ handled = true;
13179
+ break;
13180
+ }
13168
13181
  if (suppression.promptText && normalizedContent === suppression.promptText) {
13169
13182
  suppression.awaitingPromptMatch = false;
13170
13183
  suppression.droppingTurn = true;
@@ -16676,7 +16689,47 @@ async function runMirrorReconcileBatch(deps) {
16676
16689
  }
16677
16690
 
16678
16691
  // src/lib/bridge/mirror-runtime.ts
16692
+ var MIRROR_ORPHAN_PROCESS_PROBE_INTERVAL_MS = 6e4;
16679
16693
  function createMirrorRuntime(getState2, options, deps) {
16694
+ const orphanProbeAt = /* @__PURE__ */ new Map();
16695
+ function isAtOrBefore(timestamp, boundary) {
16696
+ if (!timestamp) return true;
16697
+ const timestampMs = Date.parse(timestamp);
16698
+ const boundaryMs = Date.parse(boundary);
16699
+ if (Number.isFinite(timestampMs) && Number.isFinite(boundaryMs)) {
16700
+ return timestampMs <= boundaryMs;
16701
+ }
16702
+ return timestamp <= boundary;
16703
+ }
16704
+ function discardClaimedMirrorTurn(subscription, routeResult) {
16705
+ if (!routeResult.terminalClaimed) return;
16706
+ const claimedTurnId = routeResult.claimedTurnId;
16707
+ if (claimedTurnId) {
16708
+ const claimedStreamKey = buildMirrorStreamKey(subscription.sessionId, claimedTurnId, "");
16709
+ subscription.bufferedRecords = subscription.bufferedRecords.filter(
16710
+ (record) => record.turnId !== claimedTurnId
16711
+ );
16712
+ subscription.pendingDeliveries = subscription.pendingDeliveries.filter(
16713
+ (turn) => turn.streamKey !== claimedStreamKey
16714
+ );
16715
+ if (subscription.pendingTurn?.turnId === claimedTurnId) {
16716
+ deps.stopMirrorStreaming(subscription, "interrupted");
16717
+ subscription.pendingTurn = null;
16718
+ }
16719
+ }
16720
+ const claimedAt = routeResult.claimedAt;
16721
+ if (!claimedAt) return;
16722
+ const retainedAtOrBeforeClaim = [
16723
+ ...subscription.bufferedRecords.map((record) => record.timestamp),
16724
+ ...subscription.pendingDeliveries.map((turn) => turn.timestamp),
16725
+ ...routeResult.unclaimed.map((record) => record.timestamp),
16726
+ ...subscription.pendingTurn ? [subscription.pendingTurn.lastActivityAt] : []
16727
+ ].some((timestamp) => isAtOrBefore(timestamp, claimedAt));
16728
+ if (retainedAtOrBeforeClaim) return;
16729
+ if (!subscription.lastDeliveredAt || !isAtOrBefore(claimedAt, subscription.lastDeliveredAt)) {
16730
+ subscription.lastDeliveredAt = claimedAt;
16731
+ }
16732
+ }
16680
16733
  function closeMirrorWatcher(subscription) {
16681
16734
  if (subscription.watcher) {
16682
16735
  try {
@@ -16725,8 +16778,35 @@ function createMirrorRuntime(getState2, options, deps) {
16725
16778
  deps.stopMirrorStreaming(existing);
16726
16779
  closeMirrorWatcher(existing);
16727
16780
  state.mirrorSubscriptions.delete(bindingId);
16781
+ orphanProbeAt.delete(bindingId);
16728
16782
  deps.syncMirrorSessionStateSafe(existing.sessionId, "mirror subscription removal");
16729
16783
  }
16784
+ async function finalizeOrphanedMirrorStream(subscription, snapshot, blocked, runtimeBusy, nowMs) {
16785
+ const pendingTurn = subscription.pendingTurn;
16786
+ if (!pendingTurn?.streamStarted || blocked || runtimeBusy) return null;
16787
+ const timeoutMs = options.streamOrphanTimeoutMs;
16788
+ const lastActivityMs = Date.parse(pendingTurn.lastActivityAt);
16789
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || !Number.isFinite(lastActivityMs)) {
16790
+ return null;
16791
+ }
16792
+ const sourceActivityMs = Math.max(lastActivityMs, snapshot.mtimeMs);
16793
+ if (nowMs - sourceActivityMs < timeoutMs) return null;
16794
+ const lastProbeAt = orphanProbeAt.get(subscription.bindingId);
16795
+ if (typeof lastProbeAt === "number" && nowMs - lastProbeAt < MIRROR_ORPHAN_PROCESS_PROBE_INTERVAL_MS) {
16796
+ return null;
16797
+ }
16798
+ orphanProbeAt.set(subscription.bindingId, nowMs);
16799
+ if (!await deps.isThreadProcessDefinitelyGone(subscription.threadId)) return null;
16800
+ const finalized = flushTimedOutMirrorTurn(subscription, timeoutMs, nowMs);
16801
+ if (!finalized) return null;
16802
+ orphanProbeAt.delete(subscription.bindingId);
16803
+ const detail = "\u684C\u9762\u7EBF\u7A0B\u957F\u65F6\u95F4\u6CA1\u6709\u65B0\u8BB0\u5F55\uFF0C\u4E14\u672C\u673A\u672A\u627E\u5230\u5BF9\u5E94\u8FDB\u7A0B\uFF1B\u5DF2\u7ED3\u675F\u5B64\u7ACB\u7684\u6D41\u5F0F\u540C\u6B65\u3002";
16804
+ deps.recordOrphanedMirrorTurn(subscription.sessionId, detail);
16805
+ console.warn(
16806
+ `[bridge-manager] Finalized orphaned mirror turn ${pendingTurn.turnId || pendingTurn.streamKey} for thread ${subscription.threadId}`
16807
+ );
16808
+ return finalized;
16809
+ }
16730
16810
  function clearDanglingMirrorThread(subscription, reason) {
16731
16811
  const { store } = getBridgeContext();
16732
16812
  const session = store.getSession(subscription.sessionId);
@@ -16784,6 +16864,7 @@ function createMirrorRuntime(getState2, options, deps) {
16784
16864
  });
16785
16865
  if (threadChanged || filePathChanged) {
16786
16866
  deps.stopMirrorStreaming(existing);
16867
+ orphanProbeAt.delete(existing.bindingId);
16787
16868
  }
16788
16869
  watchMirrorFile(existing, filePath);
16789
16870
  if (previousSessionId !== binding.codepilotSessionId) {
@@ -16864,7 +16945,14 @@ function createMirrorRuntime(getState2, options, deps) {
16864
16945
  `[bridge-manager] Unhandled desktop mirror event for thread ${subscription.threadId}: ${kind}`
16865
16946
  );
16866
16947
  }
16867
- const routeResult = deliverableRecords.length > 0 && deps.routeDesktopRecords ? await deps.routeDesktopRecords(subscription.sessionId, subscription.threadId, deliverableRecords) : { claimed: [], unclaimed: deliverableRecords, terminalClaimed: false };
16948
+ const routeResult = deliverableRecords.length > 0 && deps.routeDesktopRecords ? await deps.routeDesktopRecords(subscription.sessionId, subscription.threadId, deliverableRecords) : {
16949
+ claimed: [],
16950
+ unclaimed: deliverableRecords,
16951
+ terminalClaimed: false,
16952
+ claimedTurnId: null,
16953
+ claimedAt: null
16954
+ };
16955
+ discardClaimedMirrorTurn(subscription, routeResult);
16868
16956
  const mirrorRecords = routeResult.unclaimed;
16869
16957
  if (mirrorRecords.length > 0) {
16870
16958
  deps.observeSessionHealthRecords(subscription.sessionId, subscription.threadId, mirrorRecords);
@@ -16876,6 +16964,20 @@ function createMirrorRuntime(getState2, options, deps) {
16876
16964
  flushTimedOutTurn: (currentSubscription) => deps.flushTimedOutMirrorTurn(currentSubscription),
16877
16965
  consumeBufferedTurns: (currentSubscription) => deps.consumeBufferedMirrorTurns(currentSubscription)
16878
16966
  });
16967
+ const runtimeBusy = session.runtime_status === "running" || session.runtime_status === "queued";
16968
+ const orphanedTurn = await finalizeOrphanedMirrorStream(
16969
+ subscription,
16970
+ snapshot,
16971
+ blocked,
16972
+ runtimeBusy,
16973
+ Date.now()
16974
+ );
16975
+ if (orphanedTurn) {
16976
+ deliveryPlan.finalizedTurns.push(orphanedTurn);
16977
+ deliveryPlan.syncReason = "mirror reconcile delivered turns";
16978
+ } else if (!subscription.pendingTurn?.streamStarted) {
16979
+ orphanProbeAt.delete(subscription.bindingId);
16980
+ }
16879
16981
  if (deliveryPlan.finalizedTurns.length > 0) {
16880
16982
  enqueuePendingMirrorDeliveries(subscription, deliveryPlan.finalizedTurns);
16881
16983
  }
@@ -17298,6 +17400,12 @@ async function probeCodexThreadProcess(threadId) {
17298
17400
  };
17299
17401
  }
17300
17402
  }
17403
+ async function isCodexThreadProcessDefinitelyGone(threadId, probe = probeCodexThreadProcess) {
17404
+ const threadProbe = await probe(threadId);
17405
+ if (threadProbe.status !== "not_found") return false;
17406
+ const hostProbe = await probe("app-server");
17407
+ return hostProbe.status === "not_found";
17408
+ }
17301
17409
 
17302
17410
  // src/lib/bridge/session-health-reducer.ts
17303
17411
  var HEALTH_RECENT_PROGRESS_MS = 10 * 60 * 1e3;
@@ -17437,7 +17545,9 @@ function computeBaseDiagnosis(session, nowMs) {
17437
17545
  const sdkSessionId = trimOrNull(session.sdk_session_id);
17438
17546
  const lastProgressMs = parseIsoMs(lastProgressAt || void 0);
17439
17547
  const previousStatus = session.health_status || "idle";
17440
- if (!isRunningRuntimeStatus(runtimeStatus) && isRunningHealthStatus(previousStatus)) {
17548
+ const terminalHealth = previousStatus === "completed" || previousStatus === "failed" || previousStatus === "aborted";
17549
+ const activeDesktopMirror = session.thread_origin === "desktop" && session.mirror_status === "watching" && isRunningHealthStatus(previousStatus);
17550
+ if (!isRunningRuntimeStatus(runtimeStatus) && !terminalHealth && !activeDesktopMirror) {
17441
17551
  return {
17442
17552
  sessionId: session.id,
17443
17553
  checkedAt: null,
@@ -17525,6 +17635,12 @@ function applyProcessProbeDiagnosis(diagnosis, processProbe) {
17525
17635
  processProbe: null
17526
17636
  };
17527
17637
  }
17638
+ if (!isRunningHealthStatus(diagnosis.healthStatus)) {
17639
+ return {
17640
+ ...diagnosis,
17641
+ processProbe
17642
+ };
17643
+ }
17528
17644
  if (processProbe.status === "alive") {
17529
17645
  const healthStatus = diagnosis.activeToolName ? "waiting_tool" : "slow_observed";
17530
17646
  const healthReason = diagnosis.activeToolName ? "\u68C0\u6D4B\u5230\u672C\u673A\u7EBF\u7A0B\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u5F53\u524D\u66F4\u50CF\u662F\u957F\u65F6\u5DE5\u5177\u6267\u884C\u3002" : "\u68C0\u6D4B\u5230\u672C\u673A\u7EBF\u7A0B\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u5F53\u524D\u66F4\u50CF\u662F\u957F\u65F6\u4EFB\u52A1\u3002";
@@ -17930,7 +18046,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
17930
18046
  return {
17931
18047
  claimed: [],
17932
18048
  unclaimed: records,
17933
- terminalClaimed: false
18049
+ terminalClaimed: false,
18050
+ claimedTurnId: null,
18051
+ claimedAt: null
17934
18052
  };
17935
18053
  }
17936
18054
  const claim = await coordinator.claimDesktopTerminal(
@@ -17940,7 +18058,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
17940
18058
  return {
17941
18059
  claimed: [],
17942
18060
  unclaimed: records,
17943
- terminalClaimed: false
18061
+ terminalClaimed: false,
18062
+ claimedTurnId: null,
18063
+ claimedAt: null
17944
18064
  };
17945
18065
  }
17946
18066
  const claimedTurnId = terminalRecord.turnId;
@@ -17949,7 +18069,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
17949
18069
  return {
17950
18070
  claimed,
17951
18071
  unclaimed: records.filter((record) => !claimedSet.has(record.signature)),
17952
- terminalClaimed: true
18072
+ terminalClaimed: true,
18073
+ claimedTurnId: claimedTurnId || null,
18074
+ claimedAt: terminalRecord.timestamp || null
17953
18075
  };
17954
18076
  }
17955
18077
 
@@ -18012,6 +18134,7 @@ var MIRROR_PROMPT_MATCH_GRACE_MS = 12e4;
18012
18134
  var DESKTOP_TERMINAL_FINALIZATION_TIMEOUT_MS = 3e4;
18013
18135
  var MIRROR_STREAM_STATUS_IDLE_START_MS = 18e4;
18014
18136
  var MIRROR_STREAM_STATUS_HEARTBEAT_MS = 1e4;
18137
+ var MIRROR_STREAM_ORPHAN_TIMEOUT_MS = 30 * 6e4;
18015
18138
  var MIRROR_TURN_BUFFER_TIMEOUT_MS = 10 * 6e4;
18016
18139
  function describeUnknownError(error) {
18017
18140
  if (error instanceof Error) {
@@ -18241,7 +18364,8 @@ var MIRROR_RUNTIME = createMirrorRuntime(getState, {
18241
18364
  watchDebounceMs: MIRROR_WATCH_DEBOUNCE_MS,
18242
18365
  danglingThreadRetryLimit: DANGLING_MIRROR_THREAD_RETRY_LIMIT,
18243
18366
  failureSuspendThreshold: MIRROR_FAILURE_SUSPEND_THRESHOLD,
18244
- failureSuspendMs: MIRROR_FAILURE_SUSPEND_MS
18367
+ failureSuspendMs: MIRROR_FAILURE_SUSPEND_MS,
18368
+ streamOrphanTimeoutMs: MIRROR_STREAM_ORPHAN_TIMEOUT_MS
18245
18369
  }, {
18246
18370
  nowIso: nowIso3,
18247
18371
  describeUnknownError,
@@ -18251,6 +18375,10 @@ var MIRROR_RUNTIME = createMirrorRuntime(getState, {
18251
18375
  observeSessionHealthRecords: (sessionId, threadId, records) => {
18252
18376
  SESSION_HEALTH_RUNTIME.observeDesktopMirrorRecords(sessionId, threadId, records);
18253
18377
  },
18378
+ recordOrphanedMirrorTurn: (sessionId, detail) => {
18379
+ SESSION_HEALTH_RUNTIME.recordInteractiveEnd(sessionId, "aborted", detail);
18380
+ },
18381
+ isThreadProcessDefinitelyGone: isCodexThreadProcessDefinitelyGone,
18254
18382
  routeDesktopRecords: (sessionId, threadId, records) => routeDesktopRecords(
18255
18383
  sessionId,
18256
18384
  threadId,
@@ -18579,40 +18707,76 @@ function persistSdkSessionUpdate(sessionId, sdkSessionId, hasError) {
18579
18707
  }
18580
18708
 
18581
18709
  // src/store.ts
18710
+ import fs13 from "node:fs";
18711
+ import path15 from "node:path";
18712
+ import crypto10 from "node:crypto";
18713
+
18714
+ // src/atomic-file.ts
18715
+ import crypto9 from "node:crypto";
18582
18716
  import fs12 from "node:fs";
18583
18717
  import path14 from "node:path";
18584
- import crypto9 from "node:crypto";
18585
- var DATA_DIR2 = path14.join(CTI_HOME, "data");
18586
- var MESSAGES_DIR = path14.join(DATA_DIR2, "messages");
18587
- var SESSIONS_PATH = path14.join(DATA_DIR2, "sessions.json");
18588
- var BINDINGS_PATH = path14.join(DATA_DIR2, "bindings.json");
18589
- var PERMISSIONS_PATH = path14.join(DATA_DIR2, "permissions.json");
18590
- var OFFSETS_PATH = path14.join(DATA_DIR2, "offsets.json");
18591
- var DEDUP_PATH = path14.join(DATA_DIR2, "dedup.json");
18592
- var AUDIT_PATH = path14.join(DATA_DIR2, "audit.json");
18593
- var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
18594
- var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
18595
- function ensureDir2(dir) {
18596
- fs12.mkdirSync(dir, { recursive: true });
18718
+ var RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
18719
+ var WAIT_ARRAY2 = new Int32Array(new SharedArrayBuffer(4));
18720
+ function defaultSleepSync(delayMs) {
18721
+ Atomics.wait(WAIT_ARRAY2, 0, 0, Math.max(1, delayMs));
18722
+ }
18723
+ function isRetryableRenameError(error) {
18724
+ return RETRYABLE_RENAME_CODES.has(error?.code || "");
18725
+ }
18726
+ function renameFileWithRetrySync(source, destination, options = {}) {
18727
+ const maxAttempts = Math.max(1, options.maxAttempts ?? 8);
18728
+ const baseDelayMs = Math.max(1, options.baseDelayMs ?? 15);
18729
+ const renameSync = options.renameSync ?? fs12.renameSync;
18730
+ const sleepSync2 = options.sleepSync ?? defaultSleepSync;
18731
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
18732
+ try {
18733
+ renameSync(source, destination);
18734
+ return;
18735
+ } catch (error) {
18736
+ if (!isRetryableRenameError(error) || attempt === maxAttempts - 1) {
18737
+ throw error;
18738
+ }
18739
+ sleepSync2(Math.min(250, baseDelayMs * 2 ** attempt));
18740
+ }
18741
+ }
18597
18742
  }
18598
- function atomicWrite2(filePath, data) {
18599
- const tmp = `${filePath}.${process.pid}.${crypto9.randomUUID()}.tmp`;
18743
+ function atomicWriteFileSync(filePath, data) {
18744
+ fs12.mkdirSync(path14.dirname(filePath), { recursive: true });
18745
+ const tmpPath = `${filePath}.${process.pid}.${crypto9.randomUUID()}.tmp`;
18600
18746
  try {
18601
- fs12.writeFileSync(tmp, data, "utf-8");
18602
- fs12.renameSync(tmp, filePath);
18747
+ fs12.writeFileSync(tmpPath, data, "utf-8");
18748
+ renameFileWithRetrySync(tmpPath, filePath);
18603
18749
  } finally {
18604
18750
  try {
18605
- fs12.rmSync(tmp, { force: true });
18751
+ fs12.rmSync(tmpPath, { force: true });
18606
18752
  } catch {
18607
18753
  }
18608
18754
  }
18609
18755
  }
18756
+
18757
+ // src/store.ts
18758
+ var DATA_DIR2 = path15.join(CTI_HOME, "data");
18759
+ var MESSAGES_DIR = path15.join(DATA_DIR2, "messages");
18760
+ var SESSIONS_PATH = path15.join(DATA_DIR2, "sessions.json");
18761
+ var BINDINGS_PATH = path15.join(DATA_DIR2, "bindings.json");
18762
+ var PERMISSIONS_PATH = path15.join(DATA_DIR2, "permissions.json");
18763
+ var OFFSETS_PATH = path15.join(DATA_DIR2, "offsets.json");
18764
+ var DEDUP_PATH = path15.join(DATA_DIR2, "dedup.json");
18765
+ var AUDIT_PATH = path15.join(DATA_DIR2, "audit.json");
18766
+ var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
18767
+ var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
18768
+ function ensureDir2(dir) {
18769
+ fs13.mkdirSync(dir, { recursive: true });
18770
+ }
18771
+ function atomicWrite2(filePath, data) {
18772
+ atomicWriteFileSync(filePath, data);
18773
+ }
18610
18774
  function dedupTtlMs(key) {
18611
18775
  return key.startsWith("inbound:") ? INBOUND_DEDUP_TTL_MS : DEFAULT_DEDUP_TTL_MS;
18612
18776
  }
18613
18777
  function readJson2(filePath, fallback) {
18614
18778
  try {
18615
- const raw = fs12.readFileSync(filePath, "utf-8");
18779
+ const raw = fs13.readFileSync(filePath, "utf-8");
18616
18780
  return JSON.parse(raw);
18617
18781
  } catch (error) {
18618
18782
  if (error.code === "ENOENT") return fallback;
@@ -18623,7 +18787,7 @@ function writeJson(filePath, data) {
18623
18787
  atomicWrite2(filePath, JSON.stringify(data, null, 2));
18624
18788
  }
18625
18789
  function uuid() {
18626
- return crypto9.randomUUID();
18790
+ return crypto10.randomUUID();
18627
18791
  }
18628
18792
  function now() {
18629
18793
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -18786,14 +18950,14 @@ var JsonFileStore = class {
18786
18950
  }
18787
18951
  persistMessages(sessionId) {
18788
18952
  const msgs = this.messages.get(sessionId) || [];
18789
- writeJson(path14.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
18953
+ writeJson(path15.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
18790
18954
  }
18791
18955
  loadMessages(sessionId) {
18792
18956
  if (this.messages.has(sessionId)) {
18793
18957
  return this.messages.get(sessionId);
18794
18958
  }
18795
18959
  const msgs = readJson2(
18796
- path14.join(MESSAGES_DIR, `${sessionId}.json`),
18960
+ path15.join(MESSAGES_DIR, `${sessionId}.json`),
18797
18961
  []
18798
18962
  );
18799
18963
  this.messages.set(sessionId, msgs);
@@ -18816,7 +18980,7 @@ var JsonFileStore = class {
18816
18980
  });
18817
18981
  }
18818
18982
  mutateMessages(sessionId, mutation) {
18819
- const messagePath = path14.join(MESSAGES_DIR, `${sessionId}.json`);
18983
+ const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
18820
18984
  return withFileLock(messagePath, () => {
18821
18985
  const messages = readJson2(messagePath, []);
18822
18986
  this.messages.set(sessionId, messages);
@@ -18975,7 +19139,7 @@ var JsonFileStore = class {
18975
19139
  });
18976
19140
  }
18977
19141
  deleteSession(sessionId) {
18978
- const messagePath = path14.join(MESSAGES_DIR, `${sessionId}.json`);
19142
+ const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
18979
19143
  withFileLocks([SESSIONS_PATH, BINDINGS_PATH, messagePath], () => {
18980
19144
  this.reloadSessions();
18981
19145
  this.reloadBindings();
@@ -18987,7 +19151,7 @@ var JsonFileStore = class {
18987
19151
  }
18988
19152
  this.messages.delete(sessionId);
18989
19153
  try {
18990
- fs12.rmSync(messagePath, { force: true });
19154
+ fs13.rmSync(messagePath, { force: true });
18991
19155
  } catch {
18992
19156
  }
18993
19157
  this.persistSessions();
@@ -19001,7 +19165,7 @@ var JsonFileStore = class {
19001
19165
  });
19002
19166
  }
19003
19167
  getMessages(sessionId, opts) {
19004
- const messagePath = path14.join(MESSAGES_DIR, `${sessionId}.json`);
19168
+ const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
19005
19169
  const msgs = readJson2(messagePath, []);
19006
19170
  this.messages.set(sessionId, msgs);
19007
19171
  if (opts?.limit && opts.limit > 0) {
@@ -19242,8 +19406,8 @@ var PendingPermissions = class {
19242
19406
  };
19243
19407
 
19244
19408
  // src/logger.ts
19245
- import fs13 from "node:fs";
19246
- import path15 from "node:path";
19409
+ import fs14 from "node:fs";
19410
+ import path16 from "node:path";
19247
19411
  import { inspect as inspect2 } from "node:util";
19248
19412
  var MASK_PATTERNS = [
19249
19413
  /(?:token|secret|password|api_key)["']?\s*[:=]\s*["']?([^\s"',]+)/gi,
@@ -19261,8 +19425,8 @@ function maskSecrets(text2) {
19261
19425
  }
19262
19426
  return result;
19263
19427
  }
19264
- var LOG_DIR = path15.join(CTI_HOME, "logs");
19265
- var LOG_PATH = path15.join(LOG_DIR, "bridge.log");
19428
+ var LOG_DIR = path16.join(CTI_HOME, "logs");
19429
+ var LOG_PATH = path16.join(LOG_DIR, "bridge.log");
19266
19430
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
19267
19431
  var MAX_ROTATED = 3;
19268
19432
  var logStream = null;
@@ -19283,11 +19447,11 @@ function formatLogArg(value) {
19283
19447
  return String(value);
19284
19448
  }
19285
19449
  function openLogStream() {
19286
- return fs13.createWriteStream(LOG_PATH, { flags: "a" });
19450
+ return fs14.createWriteStream(LOG_PATH, { flags: "a" });
19287
19451
  }
19288
19452
  function rotateIfNeeded() {
19289
19453
  try {
19290
- const stat = fs13.statSync(LOG_PATH);
19454
+ const stat = fs14.statSync(LOG_PATH);
19291
19455
  if (stat.size < MAX_LOG_SIZE) return;
19292
19456
  } catch {
19293
19457
  return;
@@ -19297,17 +19461,17 @@ function rotateIfNeeded() {
19297
19461
  logStream = null;
19298
19462
  }
19299
19463
  const path32 = `${LOG_PATH}.${MAX_ROTATED}`;
19300
- if (fs13.existsSync(path32)) fs13.unlinkSync(path32);
19464
+ if (fs14.existsSync(path32)) fs14.unlinkSync(path32);
19301
19465
  for (let i = MAX_ROTATED - 1; i >= 1; i--) {
19302
19466
  const src = `${LOG_PATH}.${i}`;
19303
19467
  const dst = `${LOG_PATH}.${i + 1}`;
19304
- if (fs13.existsSync(src)) fs13.renameSync(src, dst);
19468
+ if (fs14.existsSync(src)) fs14.renameSync(src, dst);
19305
19469
  }
19306
- fs13.renameSync(LOG_PATH, `${LOG_PATH}.1`);
19470
+ fs14.renameSync(LOG_PATH, `${LOG_PATH}.1`);
19307
19471
  logStream = openLogStream();
19308
19472
  }
19309
19473
  function setupLogger() {
19310
- fs13.mkdirSync(LOG_DIR, { recursive: true });
19474
+ fs14.mkdirSync(LOG_DIR, { recursive: true });
19311
19475
  logStream = openLogStream();
19312
19476
  const write = (level, args) => {
19313
19477
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -19323,13 +19487,13 @@ function setupLogger() {
19323
19487
  }
19324
19488
 
19325
19489
  // src/bridge-instance-lock.ts
19326
- import fs14 from "node:fs";
19327
- import path16 from "node:path";
19328
- var runtimeDir = path16.join(CTI_HOME, "runtime");
19329
- var bridgeInstanceLockFile = path16.join(runtimeDir, "bridge.instance.lock");
19490
+ import fs15 from "node:fs";
19491
+ import path17 from "node:path";
19492
+ var runtimeDir = path17.join(CTI_HOME, "runtime");
19493
+ var bridgeInstanceLockFile = path17.join(runtimeDir, "bridge.instance.lock");
19330
19494
  function readJsonFile(filePath, fallback) {
19331
19495
  try {
19332
- return JSON.parse(fs14.readFileSync(filePath, "utf-8"));
19496
+ return JSON.parse(fs15.readFileSync(filePath, "utf-8"));
19333
19497
  } catch {
19334
19498
  return fallback;
19335
19499
  }
@@ -19361,8 +19525,8 @@ function tryAcquireBridgeInstanceLock(options = {}) {
19361
19525
  };
19362
19526
  for (let attempt = 0; attempt < 2; attempt += 1) {
19363
19527
  try {
19364
- fs14.mkdirSync(path16.dirname(filePath), { recursive: true });
19365
- fs14.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
19528
+ fs15.mkdirSync(path17.dirname(filePath), { recursive: true });
19529
+ fs15.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
19366
19530
  return { acquired: true };
19367
19531
  } catch (error) {
19368
19532
  const code2 = error.code;
@@ -19372,7 +19536,7 @@ function tryAcquireBridgeInstanceLock(options = {}) {
19372
19536
  return { acquired: false, holderPid: existing2.pid };
19373
19537
  }
19374
19538
  try {
19375
- fs14.unlinkSync(filePath);
19539
+ fs15.unlinkSync(filePath);
19376
19540
  } catch {
19377
19541
  }
19378
19542
  }
@@ -19387,37 +19551,46 @@ function releaseBridgeInstanceLock(filePath = bridgeInstanceLockFile, ownerPid =
19387
19551
  const existing = readBridgeInstanceLock(filePath);
19388
19552
  if (!existing) {
19389
19553
  try {
19390
- fs14.unlinkSync(filePath);
19554
+ fs15.unlinkSync(filePath);
19391
19555
  } catch {
19392
19556
  }
19393
19557
  return;
19394
19558
  }
19395
19559
  if (existing.pid !== ownerPid) return;
19396
19560
  try {
19397
- fs14.unlinkSync(filePath);
19561
+ fs15.unlinkSync(filePath);
19398
19562
  } catch {
19399
19563
  }
19400
19564
  }
19401
19565
 
19402
- // src/main.ts
19403
- var RUNTIME_DIR = path18.join(CTI_HOME, "runtime");
19404
- var STATUS_FILE = path18.join(RUNTIME_DIR, "status.json");
19405
- var PID_FILE = path18.join(RUNTIME_DIR, "bridge.pid");
19406
- async function resolveProvider() {
19407
- const { CodexProvider: CodexProvider2 } = await Promise.resolve().then(() => (init_codex_provider(), codex_provider_exports));
19408
- return new CodexProvider2();
19409
- }
19410
- function writeStatus(info) {
19411
- fs16.mkdirSync(RUNTIME_DIR, { recursive: true });
19566
+ // src/runtime-status.ts
19567
+ import fs16 from "node:fs";
19568
+ function writeRuntimeStatus(filePath, info, options = {}) {
19412
19569
  let existing = {};
19413
19570
  try {
19414
- existing = JSON.parse(fs16.readFileSync(STATUS_FILE, "utf-8"));
19571
+ existing = JSON.parse(fs16.readFileSync(filePath, "utf-8"));
19415
19572
  } catch {
19416
19573
  }
19574
+ const existingRunId = typeof existing.runId === "string" ? existing.runId : "";
19575
+ if (options.expectedRunId && existingRunId && existingRunId !== options.expectedRunId && options.allowRunIdTakeover !== true) {
19576
+ return false;
19577
+ }
19417
19578
  const merged = { ...existing, ...info };
19418
- const tmp = STATUS_FILE + ".tmp";
19419
- fs16.writeFileSync(tmp, JSON.stringify(merged, null, 2), "utf-8");
19420
- fs16.renameSync(tmp, STATUS_FILE);
19579
+ atomicWriteFileSync(filePath, JSON.stringify(merged, null, 2));
19580
+ return true;
19581
+ }
19582
+
19583
+ // src/main.ts
19584
+ var RUNTIME_DIR = path19.join(CTI_HOME, "runtime");
19585
+ var STATUS_FILE = path19.join(RUNTIME_DIR, "status.json");
19586
+ var PID_FILE = path19.join(RUNTIME_DIR, "bridge.pid");
19587
+ var runId = crypto11.randomUUID();
19588
+ async function resolveProvider() {
19589
+ const { CodexProvider: CodexProvider2 } = await Promise.resolve().then(() => (init_codex_provider(), codex_provider_exports));
19590
+ return new CodexProvider2();
19591
+ }
19592
+ function writeStatus(info, options = {}) {
19593
+ return writeRuntimeStatus(STATUS_FILE, info, options);
19421
19594
  }
19422
19595
  function getRunningChannels() {
19423
19596
  return getStatus().adapters.map((adapter) => adapter.channelType).sort();
@@ -19429,10 +19602,6 @@ async function main() {
19429
19602
  const lockState = tryAcquireBridgeInstanceLock();
19430
19603
  if (!lockState.acquired) {
19431
19604
  const holderPid = lockState.holderPid;
19432
- writeStatus({
19433
- running: true,
19434
- ...Number.isFinite(holderPid) && holderPid ? { pid: holderPid } : {}
19435
- });
19436
19605
  console.log(
19437
19606
  `[codex-to-im] Another bridge daemon is already running${holderPid ? ` (PID: ${holderPid})` : ""}. Exiting duplicate launcher.`
19438
19607
  );
@@ -19444,9 +19613,15 @@ async function main() {
19444
19613
  releaseBridgeInstanceLock(void 0, process.pid);
19445
19614
  instanceLockHeld = false;
19446
19615
  };
19616
+ writeStatus({
19617
+ running: false,
19618
+ pid: process.pid,
19619
+ runId,
19620
+ channels: [],
19621
+ adapters: []
19622
+ }, { expectedRunId: runId, allowRunIdTakeover: true });
19447
19623
  const config2 = loadConfig();
19448
19624
  setupLogger();
19449
- const runId = crypto10.randomUUID();
19450
19625
  console.log(`[codex-to-im] Starting bridge (run_id: ${runId})`);
19451
19626
  const settings = configToSettings(config2);
19452
19627
  const store = new JsonFileStore(settings, { dynamicSettings: true });
@@ -19462,8 +19637,8 @@ async function main() {
19462
19637
  permissions: gateway,
19463
19638
  lifecycle: {
19464
19639
  onBridgeStart: () => {
19465
- fs16.mkdirSync(RUNTIME_DIR, { recursive: true });
19466
- fs16.writeFileSync(PID_FILE, String(process.pid), "utf-8");
19640
+ fs18.mkdirSync(RUNTIME_DIR, { recursive: true });
19641
+ fs18.writeFileSync(PID_FILE, String(process.pid), "utf-8");
19467
19642
  const channels = getRunningChannels();
19468
19643
  writeStatus({
19469
19644
  running: true,
@@ -19472,7 +19647,7 @@ async function main() {
19472
19647
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
19473
19648
  channels,
19474
19649
  adapters: getAdapterStatuses()
19475
- });
19650
+ }, { expectedRunId: runId });
19476
19651
  console.log(`[codex-to-im] Bridge started (PID: ${process.pid}, channels: ${channels.join(", ")})`);
19477
19652
  },
19478
19653
  onBridgeAdaptersChanged: (channels) => {
@@ -19482,41 +19657,60 @@ async function main() {
19482
19657
  runId,
19483
19658
  channels,
19484
19659
  adapters: getAdapterStatuses()
19485
- });
19660
+ }, { expectedRunId: runId });
19486
19661
  console.log(`[codex-to-im] Active channels updated: ${channels.join(", ") || "none"}`);
19487
19662
  },
19488
19663
  onBridgeStop: () => {
19489
19664
  releaseInstanceLock();
19490
- writeStatus({ running: false, channels: [], adapters: [] });
19665
+ writeStatus({ running: false, channels: [], adapters: [] }, { expectedRunId: runId });
19491
19666
  console.log("[codex-to-im] Bridge stopped");
19492
19667
  }
19493
19668
  }
19494
19669
  });
19495
19670
  await start();
19496
19671
  let shuttingDown = false;
19497
- const shutdown = async (signal) => {
19672
+ const shutdown = async (reason, exitCode = 0) => {
19498
19673
  if (shuttingDown) return;
19499
19674
  shuttingDown = true;
19500
- const reason = signal ? `signal: ${signal}` : "shutdown requested";
19501
19675
  console.log(`[codex-to-im] Shutting down (${reason})...`);
19502
19676
  pendingPerms.denyAll();
19503
- await stop();
19504
- releaseInstanceLock();
19505
- writeStatus({ running: false, lastExitReason: reason });
19506
- process.exit(0);
19677
+ try {
19678
+ await stop();
19679
+ } catch (error) {
19680
+ console.error("[codex-to-im] Graceful bridge stop failed:", error instanceof Error ? error.stack || error.message : error);
19681
+ } finally {
19682
+ releaseInstanceLock();
19683
+ try {
19684
+ writeStatus({ running: false, lastExitReason: reason }, { expectedRunId: runId });
19685
+ } catch (error) {
19686
+ console.error("[codex-to-im] Failed to write final runtime status:", error instanceof Error ? error.message : error);
19687
+ }
19688
+ process.exit(exitCode);
19689
+ }
19507
19690
  };
19508
- process.on("SIGTERM", () => shutdown("SIGTERM"));
19509
- process.on("SIGINT", () => shutdown("SIGINT"));
19510
- process.on("SIGHUP", () => shutdown("SIGHUP"));
19691
+ process.on("SIGTERM", () => {
19692
+ void shutdown("signal: SIGTERM");
19693
+ });
19694
+ process.on("SIGINT", () => {
19695
+ void shutdown("signal: SIGINT");
19696
+ });
19697
+ process.on("SIGHUP", () => {
19698
+ void shutdown("signal: SIGHUP");
19699
+ });
19511
19700
  process.on("unhandledRejection", (reason) => {
19512
19701
  console.error("[codex-to-im] unhandledRejection:", reason instanceof Error ? reason.stack || reason.message : reason);
19513
- writeStatus({ running: false, lastExitReason: `unhandledRejection: ${reason instanceof Error ? reason.message : String(reason)}` });
19702
+ writeStatus({
19703
+ running: true,
19704
+ pid: process.pid,
19705
+ runId,
19706
+ channels: getRunningChannels(),
19707
+ adapters: getAdapterStatuses(),
19708
+ lastExitReason: `unhandledRejection: ${reason instanceof Error ? reason.message : String(reason)}`
19709
+ }, { expectedRunId: runId });
19514
19710
  });
19515
19711
  process.on("uncaughtException", (err) => {
19516
19712
  console.error("[codex-to-im] uncaughtException:", err.stack || err.message);
19517
- releaseInstanceLock();
19518
- writeStatus({ running: false, lastExitReason: `uncaughtException: ${err.message}` });
19519
- process.exit(1);
19713
+ void shutdown(`uncaughtException: ${err.message}`, 1);
19520
19714
  });
19521
19715
  process.on("beforeExit", (code2) => {
19522
19716
  console.log(`[codex-to-im] beforeExit (code: ${code2})`);
@@ -19532,7 +19726,10 @@ main().catch((err) => {
19532
19726
  console.error("[codex-to-im] Fatal error:", err instanceof Error ? err.stack || err.message : err);
19533
19727
  releaseBridgeInstanceLock(void 0, process.pid);
19534
19728
  try {
19535
- writeStatus({ running: false, lastExitReason: `fatal: ${err instanceof Error ? err.message : String(err)}` });
19729
+ writeStatus(
19730
+ { running: false, lastExitReason: `fatal: ${err instanceof Error ? err.message : String(err)}` },
19731
+ { expectedRunId: runId }
19732
+ );
19536
19733
  } catch {
19537
19734
  }
19538
19735
  process.exit(1);
@@ -1572,10 +1572,10 @@ var require_segments = __commonJS({
1572
1572
  const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
1573
1573
  const nodes = buildNodes(segs);
1574
1574
  const graph = buildGraph(nodes, version);
1575
- const path10 = dijkstra.find_path(graph.map, "start", "end");
1575
+ const path11 = dijkstra.find_path(graph.map, "start", "end");
1576
1576
  const optimizedSegs = [];
1577
- for (let i = 1; i < path10.length - 1; i++) {
1578
- optimizedSegs.push(graph.table[path10[i]].node);
1577
+ for (let i = 1; i < path11.length - 1; i++) {
1578
+ optimizedSegs.push(graph.table[path11[i]].node);
1579
1579
  }
1580
1580
  return exports.fromArray(mergeSegments(optimizedSegs));
1581
1581
  };
@@ -4011,7 +4011,7 @@ var require_utils2 = __commonJS({
4011
4011
  // node_modules/qrcode/lib/renderer/png.js
4012
4012
  var require_png2 = __commonJS({
4013
4013
  "node_modules/qrcode/lib/renderer/png.js"(exports) {
4014
- var fs10 = __require("fs");
4014
+ var fs11 = __require("fs");
4015
4015
  var PNG = require_png().PNG;
4016
4016
  var Utils = require_utils2();
4017
4017
  exports.render = function render(qrData, options) {
@@ -4052,7 +4052,7 @@ var require_png2 = __commonJS({
4052
4052
  });
4053
4053
  png.pack();
4054
4054
  };
4055
- exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4055
+ exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
4056
4056
  if (typeof cb === "undefined") {
4057
4057
  cb = options;
4058
4058
  options = void 0;
@@ -4063,7 +4063,7 @@ var require_png2 = __commonJS({
4063
4063
  called = true;
4064
4064
  cb.apply(null, args);
4065
4065
  };
4066
- const stream = fs10.createWriteStream(path10);
4066
+ const stream = fs11.createWriteStream(path11);
4067
4067
  stream.on("error", done);
4068
4068
  stream.on("close", done);
4069
4069
  exports.renderToFileStream(stream, qrData, options);
@@ -4125,14 +4125,14 @@ var require_utf8 = __commonJS({
4125
4125
  }
4126
4126
  return output;
4127
4127
  };
4128
- exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4128
+ exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
4129
4129
  if (typeof cb === "undefined") {
4130
4130
  cb = options;
4131
4131
  options = void 0;
4132
4132
  }
4133
- const fs10 = __require("fs");
4133
+ const fs11 = __require("fs");
4134
4134
  const utf8 = exports.render(qrData, options);
4135
- fs10.writeFile(path10, utf8, cb);
4135
+ fs11.writeFile(path11, utf8, cb);
4136
4136
  };
4137
4137
  }
4138
4138
  });
@@ -4253,7 +4253,7 @@ var require_svg_tag = __commonJS({
4253
4253
  return str;
4254
4254
  }
4255
4255
  function qrToPath(data, size, margin) {
4256
- let path10 = "";
4256
+ let path11 = "";
4257
4257
  let moveBy = 0;
4258
4258
  let newRow = false;
4259
4259
  let lineLength = 0;
@@ -4264,19 +4264,19 @@ var require_svg_tag = __commonJS({
4264
4264
  if (data[i]) {
4265
4265
  lineLength++;
4266
4266
  if (!(i > 0 && col > 0 && data[i - 1])) {
4267
- path10 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4267
+ path11 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
4268
4268
  moveBy = 0;
4269
4269
  newRow = false;
4270
4270
  }
4271
4271
  if (!(col + 1 < size && data[i + 1])) {
4272
- path10 += svgCmd("h", lineLength);
4272
+ path11 += svgCmd("h", lineLength);
4273
4273
  lineLength = 0;
4274
4274
  }
4275
4275
  } else {
4276
4276
  moveBy++;
4277
4277
  }
4278
4278
  }
4279
- return path10;
4279
+ return path11;
4280
4280
  }
4281
4281
  exports.render = function render(qrData, options, cb) {
4282
4282
  const opts = Utils.getOptions(options);
@@ -4284,10 +4284,10 @@ var require_svg_tag = __commonJS({
4284
4284
  const data = qrData.modules.data;
4285
4285
  const qrcodesize = size + opts.margin * 2;
4286
4286
  const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
4287
- const path10 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4287
+ const path11 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
4288
4288
  const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
4289
4289
  const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
4290
- const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path10 + "</svg>\n";
4290
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path11 + "</svg>\n";
4291
4291
  if (typeof cb === "function") {
4292
4292
  cb(null, svgTag);
4293
4293
  }
@@ -4301,15 +4301,15 @@ var require_svg = __commonJS({
4301
4301
  "node_modules/qrcode/lib/renderer/svg.js"(exports) {
4302
4302
  var svgTagRenderer = require_svg_tag();
4303
4303
  exports.render = svgTagRenderer.render;
4304
- exports.renderToFile = function renderToFile(path10, qrData, options, cb) {
4304
+ exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
4305
4305
  if (typeof cb === "undefined") {
4306
4306
  cb = options;
4307
4307
  options = void 0;
4308
4308
  }
4309
- const fs10 = __require("fs");
4309
+ const fs11 = __require("fs");
4310
4310
  const svgTag = exports.render(qrData, options);
4311
4311
  const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
4312
- fs10.writeFile(path10, xmlStr, cb);
4312
+ fs11.writeFile(path11, xmlStr, cb);
4313
4313
  };
4314
4314
  }
4315
4315
  });
@@ -4467,8 +4467,8 @@ var require_server = __commonJS({
4467
4467
  cb
4468
4468
  };
4469
4469
  }
4470
- function getTypeFromFilename(path10) {
4471
- return path10.slice((path10.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4470
+ function getTypeFromFilename(path11) {
4471
+ return path11.slice((path11.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
4472
4472
  }
4473
4473
  function getRendererFromType(type) {
4474
4474
  switch (type) {
@@ -4532,17 +4532,17 @@ var require_server = __commonJS({
4532
4532
  const renderer = getRendererFromType(params.opts.type);
4533
4533
  return render(renderer.renderToBuffer, text2, params);
4534
4534
  };
4535
- exports.toFile = function toFile(path10, text2, opts, cb) {
4536
- if (typeof path10 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4535
+ exports.toFile = function toFile(path11, text2, opts, cb) {
4536
+ if (typeof path11 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
4537
4537
  throw new Error("Invalid argument");
4538
4538
  }
4539
4539
  if (arguments.length < 3 && !canPromise()) {
4540
4540
  throw new Error("Too few arguments provided");
4541
4541
  }
4542
4542
  const params = checkParams(text2, opts, cb);
4543
- const type = params.opts.type || getTypeFromFilename(path10);
4543
+ const type = params.opts.type || getTypeFromFilename(path11);
4544
4544
  const renderer = getRendererFromType(type);
4545
- const renderToFile = renderer.renderToFile.bind(null, path10);
4545
+ const renderToFile = renderer.renderToFile.bind(null, path11);
4546
4546
  return render(renderToFile, text2, params);
4547
4547
  };
4548
4548
  exports.toFileStream = function toFileStream(stream, text2, opts) {
@@ -4566,7 +4566,7 @@ var require_lib = __commonJS({
4566
4566
 
4567
4567
  // src/ui-server.ts
4568
4568
  import http from "node:http";
4569
- import crypto8 from "node:crypto";
4569
+ import crypto9 from "node:crypto";
4570
4570
  import net from "node:net";
4571
4571
  import os5 from "node:os";
4572
4572
 
@@ -6438,40 +6438,76 @@ function isCodexIntegrationInstalled() {
6438
6438
  }
6439
6439
 
6440
6440
  // src/store.ts
6441
+ import fs7 from "node:fs";
6442
+ import path7 from "node:path";
6443
+ import crypto5 from "node:crypto";
6444
+
6445
+ // src/atomic-file.ts
6446
+ import crypto4 from "node:crypto";
6441
6447
  import fs6 from "node:fs";
6442
6448
  import path6 from "node:path";
6443
- import crypto4 from "node:crypto";
6444
- var DATA_DIR = path6.join(CTI_HOME, "data");
6445
- var MESSAGES_DIR = path6.join(DATA_DIR, "messages");
6446
- var SESSIONS_PATH = path6.join(DATA_DIR, "sessions.json");
6447
- var BINDINGS_PATH = path6.join(DATA_DIR, "bindings.json");
6448
- var PERMISSIONS_PATH = path6.join(DATA_DIR, "permissions.json");
6449
- var OFFSETS_PATH = path6.join(DATA_DIR, "offsets.json");
6450
- var DEDUP_PATH = path6.join(DATA_DIR, "dedup.json");
6451
- var AUDIT_PATH = path6.join(DATA_DIR, "audit.json");
6452
- var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
6453
- var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
6454
- function ensureDir(dir) {
6455
- fs6.mkdirSync(dir, { recursive: true });
6449
+ var RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
6450
+ var WAIT_ARRAY2 = new Int32Array(new SharedArrayBuffer(4));
6451
+ function defaultSleepSync(delayMs) {
6452
+ Atomics.wait(WAIT_ARRAY2, 0, 0, Math.max(1, delayMs));
6453
+ }
6454
+ function isRetryableRenameError(error) {
6455
+ return RETRYABLE_RENAME_CODES.has(error?.code || "");
6456
+ }
6457
+ function renameFileWithRetrySync(source, destination, options = {}) {
6458
+ const maxAttempts = Math.max(1, options.maxAttempts ?? 8);
6459
+ const baseDelayMs = Math.max(1, options.baseDelayMs ?? 15);
6460
+ const renameSync = options.renameSync ?? fs6.renameSync;
6461
+ const sleepSync2 = options.sleepSync ?? defaultSleepSync;
6462
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
6463
+ try {
6464
+ renameSync(source, destination);
6465
+ return;
6466
+ } catch (error) {
6467
+ if (!isRetryableRenameError(error) || attempt === maxAttempts - 1) {
6468
+ throw error;
6469
+ }
6470
+ sleepSync2(Math.min(250, baseDelayMs * 2 ** attempt));
6471
+ }
6472
+ }
6456
6473
  }
6457
- function atomicWrite(filePath, data) {
6458
- const tmp = `${filePath}.${process.pid}.${crypto4.randomUUID()}.tmp`;
6474
+ function atomicWriteFileSync(filePath, data) {
6475
+ fs6.mkdirSync(path6.dirname(filePath), { recursive: true });
6476
+ const tmpPath = `${filePath}.${process.pid}.${crypto4.randomUUID()}.tmp`;
6459
6477
  try {
6460
- fs6.writeFileSync(tmp, data, "utf-8");
6461
- fs6.renameSync(tmp, filePath);
6478
+ fs6.writeFileSync(tmpPath, data, "utf-8");
6479
+ renameFileWithRetrySync(tmpPath, filePath);
6462
6480
  } finally {
6463
6481
  try {
6464
- fs6.rmSync(tmp, { force: true });
6482
+ fs6.rmSync(tmpPath, { force: true });
6465
6483
  } catch {
6466
6484
  }
6467
6485
  }
6468
6486
  }
6487
+
6488
+ // src/store.ts
6489
+ var DATA_DIR = path7.join(CTI_HOME, "data");
6490
+ var MESSAGES_DIR = path7.join(DATA_DIR, "messages");
6491
+ var SESSIONS_PATH = path7.join(DATA_DIR, "sessions.json");
6492
+ var BINDINGS_PATH = path7.join(DATA_DIR, "bindings.json");
6493
+ var PERMISSIONS_PATH = path7.join(DATA_DIR, "permissions.json");
6494
+ var OFFSETS_PATH = path7.join(DATA_DIR, "offsets.json");
6495
+ var DEDUP_PATH = path7.join(DATA_DIR, "dedup.json");
6496
+ var AUDIT_PATH = path7.join(DATA_DIR, "audit.json");
6497
+ var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
6498
+ var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
6499
+ function ensureDir(dir) {
6500
+ fs7.mkdirSync(dir, { recursive: true });
6501
+ }
6502
+ function atomicWrite(filePath, data) {
6503
+ atomicWriteFileSync(filePath, data);
6504
+ }
6469
6505
  function dedupTtlMs(key) {
6470
6506
  return key.startsWith("inbound:") ? INBOUND_DEDUP_TTL_MS : DEFAULT_DEDUP_TTL_MS;
6471
6507
  }
6472
6508
  function readJson(filePath, fallback) {
6473
6509
  try {
6474
- const raw = fs6.readFileSync(filePath, "utf-8");
6510
+ const raw = fs7.readFileSync(filePath, "utf-8");
6475
6511
  return JSON.parse(raw);
6476
6512
  } catch (error) {
6477
6513
  if (error.code === "ENOENT") return fallback;
@@ -6482,7 +6518,7 @@ function writeJson(filePath, data) {
6482
6518
  atomicWrite(filePath, JSON.stringify(data, null, 2));
6483
6519
  }
6484
6520
  function uuid() {
6485
- return crypto4.randomUUID();
6521
+ return crypto5.randomUUID();
6486
6522
  }
6487
6523
  function now() {
6488
6524
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -6645,14 +6681,14 @@ var JsonFileStore = class {
6645
6681
  }
6646
6682
  persistMessages(sessionId) {
6647
6683
  const msgs = this.messages.get(sessionId) || [];
6648
- writeJson(path6.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6684
+ writeJson(path7.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
6649
6685
  }
6650
6686
  loadMessages(sessionId) {
6651
6687
  if (this.messages.has(sessionId)) {
6652
6688
  return this.messages.get(sessionId);
6653
6689
  }
6654
6690
  const msgs = readJson(
6655
- path6.join(MESSAGES_DIR, `${sessionId}.json`),
6691
+ path7.join(MESSAGES_DIR, `${sessionId}.json`),
6656
6692
  []
6657
6693
  );
6658
6694
  this.messages.set(sessionId, msgs);
@@ -6675,7 +6711,7 @@ var JsonFileStore = class {
6675
6711
  });
6676
6712
  }
6677
6713
  mutateMessages(sessionId, mutation) {
6678
- const messagePath = path6.join(MESSAGES_DIR, `${sessionId}.json`);
6714
+ const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
6679
6715
  return withFileLock(messagePath, () => {
6680
6716
  const messages = readJson(messagePath, []);
6681
6717
  this.messages.set(sessionId, messages);
@@ -6834,7 +6870,7 @@ var JsonFileStore = class {
6834
6870
  });
6835
6871
  }
6836
6872
  deleteSession(sessionId) {
6837
- const messagePath = path6.join(MESSAGES_DIR, `${sessionId}.json`);
6873
+ const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
6838
6874
  withFileLocks([SESSIONS_PATH, BINDINGS_PATH, messagePath], () => {
6839
6875
  this.reloadSessions();
6840
6876
  this.reloadBindings();
@@ -6846,7 +6882,7 @@ var JsonFileStore = class {
6846
6882
  }
6847
6883
  this.messages.delete(sessionId);
6848
6884
  try {
6849
- fs6.rmSync(messagePath, { force: true });
6885
+ fs7.rmSync(messagePath, { force: true });
6850
6886
  } catch {
6851
6887
  }
6852
6888
  this.persistSessions();
@@ -6860,7 +6896,7 @@ var JsonFileStore = class {
6860
6896
  });
6861
6897
  }
6862
6898
  getMessages(sessionId, opts) {
6863
- const messagePath = path6.join(MESSAGES_DIR, `${sessionId}.json`);
6899
+ const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
6864
6900
  const msgs = readJson(messagePath, []);
6865
6901
  this.messages.set(sessionId, msgs);
6866
6902
  if (opts?.limit && opts.limit > 0) {
@@ -7064,13 +7100,13 @@ var JsonFileStore = class {
7064
7100
 
7065
7101
  // src/weixin-login.ts
7066
7102
  var import_qrcode = __toESM(require_lib(), 1);
7067
- import fs8 from "node:fs";
7068
- import path8 from "node:path";
7069
- import crypto7 from "node:crypto";
7103
+ import fs9 from "node:fs";
7104
+ import path9 from "node:path";
7105
+ import crypto8 from "node:crypto";
7070
7106
  import { spawn as spawn2 } from "node:child_process";
7071
7107
 
7072
7108
  // src/adapters/weixin/weixin-api.ts
7073
- import crypto5 from "node:crypto";
7109
+ import crypto6 from "node:crypto";
7074
7110
 
7075
7111
  // src/adapters/weixin/weixin-types.ts
7076
7112
  var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
@@ -7119,32 +7155,32 @@ async function pollLoginQrStatus(qrcode, baseUrl) {
7119
7155
  }
7120
7156
 
7121
7157
  // src/weixin-store.ts
7122
- import fs7 from "node:fs";
7123
- import crypto6 from "node:crypto";
7124
- import path7 from "node:path";
7125
- var DATA_DIR2 = path7.join(CTI_HOME, "data");
7126
- var ACCOUNTS_PATH = path7.join(DATA_DIR2, "weixin-accounts.json");
7127
- var CONTEXT_TOKENS_PATH = path7.join(DATA_DIR2, "weixin-context-tokens.json");
7158
+ import fs8 from "node:fs";
7159
+ import crypto7 from "node:crypto";
7160
+ import path8 from "node:path";
7161
+ var DATA_DIR2 = path8.join(CTI_HOME, "data");
7162
+ var ACCOUNTS_PATH = path8.join(DATA_DIR2, "weixin-accounts.json");
7163
+ var CONTEXT_TOKENS_PATH = path8.join(DATA_DIR2, "weixin-context-tokens.json");
7128
7164
  var DEFAULT_BASE_URL2 = "https://ilinkai.weixin.qq.com";
7129
7165
  var DEFAULT_CDN_BASE_URL2 = "https://novac2c.cdn.weixin.qq.com/c2c";
7130
7166
  function ensureDir2(dir) {
7131
- fs7.mkdirSync(dir, { recursive: true });
7167
+ fs8.mkdirSync(dir, { recursive: true });
7132
7168
  }
7133
7169
  function atomicWrite2(filePath, data) {
7134
- const tmpPath = `${filePath}.${process.pid}.${crypto6.randomUUID()}.tmp`;
7170
+ const tmpPath = `${filePath}.${process.pid}.${crypto7.randomUUID()}.tmp`;
7135
7171
  try {
7136
- fs7.writeFileSync(tmpPath, data, "utf-8");
7137
- fs7.renameSync(tmpPath, filePath);
7172
+ fs8.writeFileSync(tmpPath, data, "utf-8");
7173
+ fs8.renameSync(tmpPath, filePath);
7138
7174
  } finally {
7139
7175
  try {
7140
- fs7.rmSync(tmpPath, { force: true });
7176
+ fs8.rmSync(tmpPath, { force: true });
7141
7177
  } catch {
7142
7178
  }
7143
7179
  }
7144
7180
  }
7145
7181
  function readJson2(filePath, fallback) {
7146
7182
  try {
7147
- const raw = fs7.readFileSync(filePath, "utf-8");
7183
+ const raw = fs8.readFileSync(filePath, "utf-8");
7148
7184
  return JSON.parse(raw);
7149
7185
  } catch (error) {
7150
7186
  if (error.code === "ENOENT") return fallback;
@@ -7236,11 +7272,11 @@ var MAX_REFRESHES = 3;
7236
7272
  var QR_TTL_MS = 5 * 6e4;
7237
7273
  var POLL_INTERVAL_MS = 3e3;
7238
7274
  var WEB_SESSION_TTL_MS = 15 * 6e4;
7239
- var RUNTIME_DIR = path8.join(CTI_HOME, "runtime");
7240
- var HTML_PATH = path8.join(RUNTIME_DIR, "weixin-login.html");
7275
+ var RUNTIME_DIR = path9.join(CTI_HOME, "runtime");
7276
+ var HTML_PATH = path9.join(RUNTIME_DIR, "weixin-login.html");
7241
7277
  var webLoginSessions = /* @__PURE__ */ new Map();
7242
7278
  function ensureRuntimeDir() {
7243
- fs8.mkdirSync(RUNTIME_DIR, { recursive: true });
7279
+ fs9.mkdirSync(RUNTIME_DIR, { recursive: true });
7244
7280
  }
7245
7281
  function escapeHtml(text2) {
7246
7282
  return text2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
@@ -7553,7 +7589,7 @@ function buildWeixinLoginPopupHtml(sessionId) {
7553
7589
  async function writeQrHtml(session) {
7554
7590
  ensureRuntimeDir();
7555
7591
  const qrSvg = await buildQrSvg(session.qrImageUrl);
7556
- fs8.writeFileSync(HTML_PATH, buildQrHtml(qrSvg), "utf-8");
7592
+ fs9.writeFileSync(HTML_PATH, buildQrHtml(qrSvg), "utf-8");
7557
7593
  }
7558
7594
  function openQrHtml() {
7559
7595
  try {
@@ -7742,7 +7778,7 @@ async function startWeixinLoginWebSession(options = {}) {
7742
7778
  ensureRuntimeDir();
7743
7779
  const config = options.config || {};
7744
7780
  const seed = await createSession(0, config.baseUrl);
7745
- const sessionId = crypto7.randomUUID();
7781
+ const sessionId = crypto8.randomUUID();
7746
7782
  const qrSvg = await buildQrSvg(seed.qrImageUrl);
7747
7783
  const session = {
7748
7784
  id: sessionId,
@@ -7814,7 +7850,7 @@ async function runWeixinLogin(config = {}) {
7814
7850
  }
7815
7851
  var isMainModule = (() => {
7816
7852
  const entry = process.argv[1];
7817
- return !!entry && path8.resolve(entry) === path8.resolve(new URL(import.meta.url).pathname);
7853
+ return !!entry && path9.resolve(entry) === path9.resolve(new URL(import.meta.url).pathname);
7818
7854
  })();
7819
7855
  if (isMainModule) {
7820
7856
  runWeixinLogin().catch((err) => {
@@ -7824,11 +7860,11 @@ if (isMainModule) {
7824
7860
  }
7825
7861
 
7826
7862
  // src/codex-models.ts
7827
- import fs9 from "node:fs";
7863
+ import fs10 from "node:fs";
7828
7864
  import os4 from "node:os";
7829
- import path9 from "node:path";
7830
- var DEFAULT_CODEX_CONFIG_PATH = path9.join(os4.homedir(), ".codex", "config.toml");
7831
- var DEFAULT_CODEX_MODELS_CACHE_PATH = path9.join(os4.homedir(), ".codex", "models_cache.json");
7865
+ import path10 from "node:path";
7866
+ var DEFAULT_CODEX_CONFIG_PATH = path10.join(os4.homedir(), ".codex", "config.toml");
7867
+ var DEFAULT_CODEX_MODELS_CACHE_PATH = path10.join(os4.homedir(), ".codex", "models_cache.json");
7832
7868
  var REASONING_LEVEL_DESCRIPTIONS = {
7833
7869
  low: "Fast responses with lighter reasoning",
7834
7870
  medium: "Balances speed and reasoning depth for everyday tasks",
@@ -7877,7 +7913,7 @@ var KNOWN_CODEX_MODEL_FALLBACKS = [
7877
7913
  ];
7878
7914
  function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
7879
7915
  try {
7880
- const raw = fs9.readFileSync(configPath, "utf-8");
7916
+ const raw = fs10.readFileSync(configPath, "utf-8");
7881
7917
  let inSection = false;
7882
7918
  for (const line of raw.split(/\r?\n/)) {
7883
7919
  const trimmed = line.trim();
@@ -7921,7 +7957,7 @@ function parseSupportedReasoningLevels(value) {
7921
7957
  }
7922
7958
  function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
7923
7959
  try {
7924
- const raw = fs9.readFileSync(cachePath, "utf-8");
7960
+ const raw = fs10.readFileSync(cachePath, "utf-8");
7925
7961
  const parsed = JSON.parse(raw);
7926
7962
  if (!Array.isArray(parsed.models)) return [];
7927
7963
  const seen = /* @__PURE__ */ new Set();
@@ -8220,14 +8256,14 @@ function channelToPayload(channel) {
8220
8256
  };
8221
8257
  }
8222
8258
  function generateAccessToken() {
8223
- return crypto8.randomBytes(18).toString("base64url");
8259
+ return crypto9.randomBytes(18).toString("base64url");
8224
8260
  }
8225
8261
  function timingSafeMatch(left, right) {
8226
8262
  if (!left || !right) return false;
8227
8263
  const leftBuffer = Buffer.from(left);
8228
8264
  const rightBuffer = Buffer.from(right);
8229
8265
  if (leftBuffer.length !== rightBuffer.length) return false;
8230
- return crypto8.timingSafeEqual(leftBuffer, rightBuffer);
8266
+ return crypto9.timingSafeEqual(leftBuffer, rightBuffer);
8231
8267
  }
8232
8268
  function parseCookies(request) {
8233
8269
  const header = request.headers.cookie;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-to-im",
3
- "version": "1.0.60",
3
+ "version": "1.0.62",
4
4
  "description": "Installable Codex-to-IM bridge with local setup UI and background service",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/zhangle1987/codex-to-im#readme",