codex-to-im 1.0.28 → 1.0.30

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
@@ -4255,6 +4255,7 @@ function getRegisteredTypes() {
4255
4255
  // src/lib/bridge/bridge-manager.ts
4256
4256
  import fs8 from "node:fs";
4257
4257
  import path11 from "node:path";
4258
+ import { inspect } from "node:util";
4258
4259
 
4259
4260
  // src/lib/bridge/adapters/telegram-adapter.ts
4260
4261
  import crypto from "crypto";
@@ -7817,11 +7818,8 @@ function readJson(filePath, fallback) {
7817
7818
  function getAccountRecency(account) {
7818
7819
  return account.lastLoginAt ?? account.updatedAt ?? account.createdAt;
7819
7820
  }
7820
- function normalizeAccounts(accounts) {
7821
- if (accounts.length <= 1) {
7822
- return { accounts, removedAccountIds: [] };
7823
- }
7824
- const sorted = [...accounts].sort((a, b) => {
7821
+ function sortAccountsByRecency(accounts) {
7822
+ return [...accounts].sort((a, b) => {
7825
7823
  const recencyDiff = getAccountRecency(b).localeCompare(getAccountRecency(a));
7826
7824
  if (recencyDiff !== 0) return recencyDiff;
7827
7825
  const updatedDiff = b.updatedAt.localeCompare(a.updatedAt);
@@ -7830,16 +7828,14 @@ function normalizeAccounts(accounts) {
7830
7828
  if (createdDiff !== 0) return createdDiff;
7831
7829
  return 0;
7832
7830
  });
7833
- const kept = sorted[0];
7834
- const removedAccountIds = [
7835
- ...new Set(
7836
- sorted.slice(1).map((account) => account.accountId).filter((accountId) => accountId !== kept.accountId)
7837
- )
7838
- ];
7839
- return {
7840
- accounts: [kept],
7841
- removedAccountIds
7842
- };
7831
+ }
7832
+ function normalizeAccounts(accounts) {
7833
+ const deduped = /* @__PURE__ */ new Map();
7834
+ for (const account of sortAccountsByRecency(accounts)) {
7835
+ if (!account?.accountId || deduped.has(account.accountId)) continue;
7836
+ deduped.set(account.accountId, account);
7837
+ }
7838
+ return Array.from(deduped.values());
7843
7839
  }
7844
7840
  function readStoredAccounts() {
7845
7841
  ensureDir(DATA_DIR);
@@ -7847,7 +7843,7 @@ function readStoredAccounts() {
7847
7843
  return Array.isArray(raw) ? raw : [];
7848
7844
  }
7849
7845
  function readAccounts() {
7850
- return normalizeAccounts(readStoredAccounts()).accounts;
7846
+ return normalizeAccounts(readStoredAccounts());
7851
7847
  }
7852
7848
  function readContextTokens() {
7853
7849
  ensureDir(DATA_DIR);
@@ -7861,7 +7857,7 @@ function contextKey(accountId, peerUserId) {
7861
7857
  return `${accountId}::${peerUserId}`;
7862
7858
  }
7863
7859
  function listWeixinAccounts() {
7864
- return readAccounts().sort((a, b) => b.createdAt.localeCompare(a.createdAt));
7860
+ return sortAccountsByRecency(readAccounts());
7865
7861
  }
7866
7862
  function getWeixinAccount(accountId) {
7867
7863
  return readAccounts().find((account) => account.accountId === accountId);
@@ -14233,11 +14229,21 @@ var WeixinAdapter = class extends BaseChannelAdapter {
14233
14229
  }
14234
14230
  }
14235
14231
  validateConfig() {
14236
- const linkedAccounts = this.filterConfiguredAccounts(
14237
- listWeixinAccounts().filter((account) => account.enabled && account.token)
14238
- );
14239
- if (linkedAccounts.length === 0) {
14240
- return "No linked WeChat account. Run the WeChat QR login helper first.";
14232
+ const configuredAccountId = this.configuredAccountId;
14233
+ const accounts = listWeixinAccounts();
14234
+ const enabledAccounts = accounts.filter((account) => account.enabled && account.token);
14235
+ if (configuredAccountId) {
14236
+ const configured = getWeixinAccount(configuredAccountId);
14237
+ if (!configured) {
14238
+ return `Linked WeChat account ${configuredAccountId} not found`;
14239
+ }
14240
+ if (!configured.enabled || !configured.token) {
14241
+ return `Linked WeChat account ${configuredAccountId} is disabled or missing token`;
14242
+ }
14243
+ return null;
14244
+ }
14245
+ if (enabledAccounts.length > 1) {
14246
+ return "Multiple linked WeChat accounts detected. Please select a WeChat account for this channel.";
14241
14247
  }
14242
14248
  return null;
14243
14249
  }
@@ -15375,7 +15381,7 @@ function bindStoreToSdkSession(store, channelType, chatId, sdkSessionId, opts) {
15375
15381
  import fs5 from "node:fs";
15376
15382
  import path6 from "node:path";
15377
15383
  var DRAFT_TTL_MS = 24 * 60 * 60 * 1e3;
15378
- var MAX_HIDDEN_DRAFT_SESSIONS = 20;
15384
+ var MAX_HIDDEN_DRAFT_SESSIONS = 64;
15379
15385
  var INTERNAL_SESSION_ROOT = path6.join(CTI_HOME, "runtime", "internal-sessions");
15380
15386
  var DRAFT_SESSION_PREFIX = "Draft";
15381
15387
  var HISTORY_SESSION_PREFIX = "History Summary";
@@ -17018,6 +17024,9 @@ var MODE_OPTIONS_TEXT = "\u53EF\u9009\uFF1A`code`\uFF08\u76F4\u63A5\u6267\u884C\
17018
17024
  var REASONING_OPTIONS_TEXT = "\u53EF\u9009\uFF1A`1=minimal` `2=low` `3=medium` `4=high` `5=xhigh`";
17019
17025
  var DEFAULT_DESKTOP_THREAD_LIST_LIMIT = 10;
17020
17026
  var MAX_DESKTOP_THREAD_LIST_LIMIT = 200;
17027
+ var DANGLING_MIRROR_THREAD_RETRY_LIMIT = 3;
17028
+ var MIRROR_FAILURE_SUSPEND_MS = 6e4;
17029
+ var MIRROR_FAILURE_SUSPEND_THRESHOLD = 3;
17021
17030
  var MIRROR_POLL_INTERVAL_MS = 2500;
17022
17031
  var MIRROR_WATCH_DEBOUNCE_MS = 350;
17023
17032
  var MIRROR_EVENT_BATCH_LIMIT = 8;
@@ -17027,6 +17036,7 @@ var INTERACTIVE_IDLE_REMINDER_MS = 6e5;
17027
17036
  var MIRROR_IDLE_TIMEOUT_MS = 6e5;
17028
17037
  var AVAILABLE_CODEX_MODELS = listSelectableCodexModels();
17029
17038
  var AVAILABLE_CODEX_MODEL_MAP = new Map(AVAILABLE_CODEX_MODELS.map((model) => [model.slug, model]));
17039
+ var INVALID_ADAPTER_WARNING_CACHE = /* @__PURE__ */ new Map();
17030
17040
  function generateDraftId() {
17031
17041
  return Math.floor(Math.random() * 2147483646) + 1;
17032
17042
  }
@@ -17109,8 +17119,41 @@ function resolveByIndexOrPrefix(raw, items, getId) {
17109
17119
  }
17110
17120
  return { match: null, ambiguous: false };
17111
17121
  }
17122
+ function describeUnknownError(error) {
17123
+ if (error instanceof Error) {
17124
+ return error.stack || `${error.name}: ${error.message}`;
17125
+ }
17126
+ if (error === null) return "null";
17127
+ if (typeof error === "undefined") return "undefined";
17128
+ if (typeof error === "object") {
17129
+ const ctor = error?.constructor?.name;
17130
+ const rendered = inspect(error, {
17131
+ depth: 4,
17132
+ breakLength: Infinity,
17133
+ compact: true
17134
+ });
17135
+ return ctor && ctor !== "Object" ? `${ctor} ${rendered}` : rendered;
17136
+ }
17137
+ return String(error);
17138
+ }
17112
17139
  function getDisplayedDesktopThreads(limit = DEFAULT_DESKTOP_THREAD_LIST_LIMIT) {
17113
- return listDesktopSessions(limit);
17140
+ try {
17141
+ return listDesktopSessions(limit);
17142
+ } catch (error) {
17143
+ console.error("[bridge-manager] Failed to list desktop sessions:", error);
17144
+ return null;
17145
+ }
17146
+ }
17147
+ function getDesktopSessionByThreadIdSafe(threadId, context) {
17148
+ try {
17149
+ return getDesktopSessionByThreadId(threadId);
17150
+ } catch (error) {
17151
+ console.error(
17152
+ `[bridge-manager] Failed to load desktop thread ${threadId} during ${context}:`,
17153
+ error
17154
+ );
17155
+ return null;
17156
+ }
17114
17157
  }
17115
17158
  function parseDesktopThreadListArgs(args) {
17116
17159
  const trimmed = args.trim().toLowerCase();
@@ -17522,7 +17565,7 @@ async function summarizeHistory(currentBinding) {
17522
17565
  }
17523
17566
  function getDesktopThreadTitle(threadId) {
17524
17567
  if (!threadId) return null;
17525
- return getDesktopSessionByThreadId(threadId)?.title || null;
17568
+ return getDesktopSessionByThreadIdSafe(threadId, "status lookup")?.title || null;
17526
17569
  }
17527
17570
  function formatCommandPath(cwd) {
17528
17571
  return cwd?.trim() || "~";
@@ -17684,6 +17727,7 @@ function getState() {
17684
17727
  g[GLOBAL_KEY] = {
17685
17728
  adapters: /* @__PURE__ */ new Map(),
17686
17729
  adapterMeta: /* @__PURE__ */ new Map(),
17730
+ invalidAdapters: /* @__PURE__ */ new Map(),
17687
17731
  running: false,
17688
17732
  startedAt: null,
17689
17733
  loopAborts: /* @__PURE__ */ new Map(),
@@ -17706,6 +17750,9 @@ function getState() {
17706
17750
  if (!g[GLOBAL_KEY].mirrorSubscriptions) {
17707
17751
  g[GLOBAL_KEY].mirrorSubscriptions = /* @__PURE__ */ new Map();
17708
17752
  }
17753
+ if (!g[GLOBAL_KEY].invalidAdapters) {
17754
+ g[GLOBAL_KEY].invalidAdapters = /* @__PURE__ */ new Map();
17755
+ }
17709
17756
  if (!g[GLOBAL_KEY].queuedCounts) {
17710
17757
  g[GLOBAL_KEY].queuedCounts = /* @__PURE__ */ new Map();
17711
17758
  }
@@ -18065,7 +18112,9 @@ function scheduleMirrorWake(delayMs = MIRROR_WATCH_DEBOUNCE_MS) {
18065
18112
  if (state.mirrorWakeTimer) return;
18066
18113
  state.mirrorWakeTimer = setTimeout(() => {
18067
18114
  state.mirrorWakeTimer = null;
18068
- void reconcileMirrorSubscriptions();
18115
+ void reconcileMirrorSubscriptions().catch((err) => {
18116
+ console.error("[bridge-manager] Mirror wake reconcile failed:", describeUnknownError(err));
18117
+ });
18069
18118
  }, delayMs);
18070
18119
  }
18071
18120
  function watchMirrorFile(subscription, filePath) {
@@ -18103,6 +18152,16 @@ function syncMirrorSessionState(sessionId) {
18103
18152
  mirror_last_event_at: deliveredAt
18104
18153
  });
18105
18154
  }
18155
+ function syncMirrorSessionStateSafe(sessionId, context) {
18156
+ try {
18157
+ syncMirrorSessionState(sessionId);
18158
+ } catch (error) {
18159
+ console.error(
18160
+ `[bridge-manager] Failed to sync mirror session state for ${sessionId} during ${context}:`,
18161
+ describeUnknownError(error)
18162
+ );
18163
+ }
18164
+ }
18106
18165
  function getMirrorAssistantRuntimeLabel() {
18107
18166
  const { store } = getBridgeContext();
18108
18167
  const runtime = (store.getSetting("bridge_runtime") || "codex").trim().toLowerCase();
@@ -18368,7 +18427,6 @@ function consumeMirrorRecords(subscription, records) {
18368
18427
  subscription.pendingTurn.lastActivityAt = record.timestamp;
18369
18428
  }
18370
18429
  }
18371
- startMirrorStreaming(subscription, subscription.pendingTurn);
18372
18430
  continue;
18373
18431
  }
18374
18432
  if (record.type === "task_complete") {
@@ -18467,7 +18525,17 @@ function removeMirrorSubscription(bindingId) {
18467
18525
  stopMirrorStreaming(existing);
18468
18526
  closeMirrorWatcher(existing);
18469
18527
  state.mirrorSubscriptions.delete(bindingId);
18470
- syncMirrorSessionState(existing.sessionId);
18528
+ syncMirrorSessionStateSafe(existing.sessionId, "mirror subscription removal");
18529
+ }
18530
+ function clearDanglingMirrorThread(subscription, reason) {
18531
+ const { store } = getBridgeContext();
18532
+ const session = store.getSession(subscription.sessionId);
18533
+ const currentThreadId = session?.sdk_session_id || subscription.threadId;
18534
+ console.warn(
18535
+ `[bridge-manager] Clearing dangling desktop thread ${currentThreadId} for session ${subscription.sessionId}: ${reason}`
18536
+ );
18537
+ store.updateSdkSessionId(subscription.sessionId, "");
18538
+ removeMirrorSubscription(subscription.bindingId);
18471
18539
  }
18472
18540
  function upsertMirrorSubscription(binding) {
18473
18541
  const { store } = getBridgeContext();
@@ -18482,7 +18550,7 @@ function upsertMirrorSubscription(binding) {
18482
18550
  removeMirrorSubscription(binding.id);
18483
18551
  return;
18484
18552
  }
18485
- const desktopSession = getDesktopSessionByThreadId(threadId);
18553
+ const desktopSession = getDesktopSessionByThreadIdSafe(threadId, "mirror subscription sync");
18486
18554
  const filePath = desktopSession?.filePath || null;
18487
18555
  const existing = state.mirrorSubscriptions.get(binding.id);
18488
18556
  if (!existing) {
@@ -18507,11 +18575,14 @@ function upsertMirrorSubscription(binding) {
18507
18575
  trailingText: "",
18508
18576
  activeMirrorTurnId: null,
18509
18577
  bufferedRecords: [],
18510
- pendingTurn: null
18578
+ pendingTurn: null,
18579
+ missingThreadPolls: 0,
18580
+ consecutiveFailures: 0,
18581
+ suspendedUntil: null
18511
18582
  };
18512
18583
  watchMirrorFile(created, filePath);
18513
18584
  state.mirrorSubscriptions.set(binding.id, created);
18514
- syncMirrorSessionState(binding.codepilotSessionId);
18585
+ syncMirrorSessionStateSafe(binding.codepilotSessionId, "mirror subscription create");
18515
18586
  return;
18516
18587
  }
18517
18588
  const previousSessionId = existing.sessionId;
@@ -18529,18 +18600,23 @@ function upsertMirrorSubscription(binding) {
18529
18600
  existing.lastDeliveredAt = session.mirror_last_event_at || null;
18530
18601
  existing.dirty = true;
18531
18602
  existing.pendingTurn = null;
18603
+ existing.missingThreadPolls = 0;
18604
+ existing.consecutiveFailures = 0;
18605
+ existing.suspendedUntil = null;
18532
18606
  resetMirrorReadState(existing);
18533
18607
  } else if (filePathChanged) {
18534
18608
  stopMirrorStreaming(existing);
18535
18609
  existing.dirty = true;
18536
18610
  existing.pendingTurn = null;
18611
+ existing.consecutiveFailures = 0;
18612
+ existing.suspendedUntil = null;
18537
18613
  resetMirrorReadState(existing);
18538
18614
  }
18539
18615
  watchMirrorFile(existing, filePath);
18540
18616
  if (previousSessionId !== binding.codepilotSessionId) {
18541
- syncMirrorSessionState(previousSessionId);
18617
+ syncMirrorSessionStateSafe(previousSessionId, "mirror subscription rebind previous session");
18542
18618
  }
18543
- syncMirrorSessionState(binding.codepilotSessionId);
18619
+ syncMirrorSessionStateSafe(binding.codepilotSessionId, "mirror subscription upsert");
18544
18620
  }
18545
18621
  function syncMirrorSubscriptionSet() {
18546
18622
  const { store } = getBridgeContext();
@@ -18554,7 +18630,14 @@ function syncMirrorSubscriptionSet() {
18554
18630
  const desiredIds = /* @__PURE__ */ new Set();
18555
18631
  for (const binding of desiredBindings) {
18556
18632
  desiredIds.add(binding.id);
18557
- upsertMirrorSubscription(binding);
18633
+ try {
18634
+ upsertMirrorSubscription(binding);
18635
+ } catch (error) {
18636
+ console.error(
18637
+ `[bridge-manager] Failed to sync mirror subscription for binding ${binding.id}:`,
18638
+ error
18639
+ );
18640
+ }
18558
18641
  }
18559
18642
  for (const bindingId of Array.from(state.mirrorSubscriptions.keys())) {
18560
18643
  if (!desiredIds.has(bindingId)) {
@@ -18569,7 +18652,29 @@ async function reconcileMirrorSubscription(subscription) {
18569
18652
  removeMirrorSubscription(subscription.bindingId);
18570
18653
  return;
18571
18654
  }
18572
- const desktopSession = getDesktopSessionByThreadId(subscription.threadId);
18655
+ if (subscription.suspendedUntil && Date.now() < subscription.suspendedUntil) {
18656
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror suspension");
18657
+ return;
18658
+ }
18659
+ if (subscription.suspendedUntil) {
18660
+ subscription.suspendedUntil = null;
18661
+ }
18662
+ const desktopSession = getDesktopSessionByThreadIdSafe(
18663
+ subscription.threadId,
18664
+ "mirror reconcile"
18665
+ );
18666
+ if (!desktopSession) {
18667
+ subscription.missingThreadPolls += 1;
18668
+ if (subscription.missingThreadPolls >= DANGLING_MIRROR_THREAD_RETRY_LIMIT) {
18669
+ clearDanglingMirrorThread(
18670
+ subscription,
18671
+ "desktop thread no longer exists locally"
18672
+ );
18673
+ return;
18674
+ }
18675
+ } else {
18676
+ subscription.missingThreadPolls = 0;
18677
+ }
18573
18678
  const filePathChanged = subscription.filePath !== (desktopSession?.filePath || null);
18574
18679
  subscription.filePath = desktopSession?.filePath || null;
18575
18680
  subscription.status = subscription.filePath ? "watching" : "stale";
@@ -18580,7 +18685,7 @@ async function reconcileMirrorSubscription(subscription) {
18580
18685
  watchMirrorFile(subscription, subscription.filePath);
18581
18686
  subscription.lastReconciledAt = nowIso2();
18582
18687
  if (!subscription.filePath) {
18583
- syncMirrorSessionState(subscription.sessionId);
18688
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile without file");
18584
18689
  return;
18585
18690
  }
18586
18691
  const snapshot = statMirrorFile(subscription.filePath);
@@ -18588,12 +18693,12 @@ async function reconcileMirrorSubscription(subscription) {
18588
18693
  subscription.status = "stale";
18589
18694
  subscription.dirty = true;
18590
18695
  resetMirrorReadState(subscription);
18591
- syncMirrorSessionState(subscription.sessionId);
18696
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile missing snapshot");
18592
18697
  return;
18593
18698
  }
18594
18699
  const unchanged = !subscription.dirty && subscription.fileIdentity === snapshot.identity && subscription.fileSize === snapshot.size && subscription.fileMtimeMs === snapshot.mtimeMs;
18595
18700
  if (unchanged && !hasPendingMirrorWork(subscription)) {
18596
- syncMirrorSessionState(subscription.sessionId);
18701
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile unchanged snapshot");
18597
18702
  return;
18598
18703
  }
18599
18704
  let deliverableRecords = [];
@@ -18648,13 +18753,13 @@ async function reconcileMirrorSubscription(subscription) {
18648
18753
  console.warn("[bridge-manager] Mirror delivery failed:", error instanceof Error ? error.message : error);
18649
18754
  }
18650
18755
  }
18651
- syncMirrorSessionState(subscription.sessionId);
18756
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile active task");
18652
18757
  return;
18653
18758
  }
18654
18759
  const finalizedTurns = timedOutTurn ? [timedOutTurn] : [];
18655
18760
  finalizedTurns.push(...consumeBufferedMirrorTurns(subscription));
18656
18761
  if (finalizedTurns.length === 0) {
18657
- syncMirrorSessionState(subscription.sessionId);
18762
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile no finalized turns");
18658
18763
  return;
18659
18764
  }
18660
18765
  try {
@@ -18663,29 +18768,66 @@ async function reconcileMirrorSubscription(subscription) {
18663
18768
  subscription.dirty = true;
18664
18769
  console.warn("[bridge-manager] Mirror delivery failed:", error instanceof Error ? error.message : error);
18665
18770
  }
18666
- syncMirrorSessionState(subscription.sessionId);
18771
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile delivered turns");
18667
18772
  }
18668
18773
  async function reconcileMirrorSubscriptions() {
18669
18774
  const state = getState();
18670
18775
  if (!state.running || state.mirrorSyncInFlight) return;
18671
18776
  state.mirrorSyncInFlight = true;
18777
+ let stage = "sync-start";
18672
18778
  try {
18673
- syncMirrorSubscriptionSet();
18674
- for (const subscription of state.mirrorSubscriptions.values()) {
18779
+ try {
18780
+ stage = "sync-subscription-set";
18781
+ syncMirrorSubscriptionSet();
18782
+ } catch (error) {
18783
+ console.error("[bridge-manager] Mirror subscription set reconcile failed:", error);
18784
+ return;
18785
+ }
18786
+ stage = "snapshot-subscriptions";
18787
+ const subscriptions = Array.from(state.mirrorSubscriptions.values());
18788
+ for (const subscription of subscriptions) {
18789
+ stage = `subscription:${subscription.bindingId}`;
18675
18790
  try {
18676
18791
  await reconcileMirrorSubscription(subscription);
18792
+ subscription.consecutiveFailures = 0;
18793
+ subscription.suspendedUntil = null;
18677
18794
  } catch (error) {
18678
- stopMirrorStreaming(subscription, "interrupted");
18679
- resetMirrorReadState(subscription);
18680
- subscription.status = "stale";
18681
- subscription.dirty = false;
18682
- console.error(
18683
- `[bridge-manager] Mirror reconcile failed for thread ${subscription.threadId}:`,
18684
- error instanceof Error ? error.stack || error.message : error
18685
- );
18686
- syncMirrorSessionState(subscription.sessionId);
18795
+ try {
18796
+ stopMirrorStreaming(subscription, "interrupted");
18797
+ subscription.pendingTurn = null;
18798
+ subscription.bufferedRecords = [];
18799
+ subscription.status = "stale";
18800
+ subscription.dirty = false;
18801
+ subscription.consecutiveFailures += 1;
18802
+ if (subscription.consecutiveFailures >= MIRROR_FAILURE_SUSPEND_THRESHOLD) {
18803
+ subscription.suspendedUntil = Date.now() + MIRROR_FAILURE_SUSPEND_MS;
18804
+ console.warn(
18805
+ `[bridge-manager] Mirror subscription for thread ${subscription.threadId} is suspended for ${Math.round(MIRROR_FAILURE_SUSPEND_MS / 1e3)}s after ${subscription.consecutiveFailures} consecutive failures`
18806
+ );
18807
+ }
18808
+ console.error(
18809
+ `[bridge-manager] Mirror reconcile failed for thread ${subscription.threadId}:`,
18810
+ describeUnknownError(error)
18811
+ );
18812
+ syncMirrorSessionStateSafe(subscription.sessionId, "mirror reconcile failure");
18813
+ } catch (recoveryError) {
18814
+ console.error(
18815
+ `[bridge-manager] Mirror reconcile recovery failed for thread ${subscription.threadId}:`,
18816
+ describeUnknownError(recoveryError)
18817
+ );
18818
+ console.error(
18819
+ `[bridge-manager] Original mirror reconcile error for thread ${subscription.threadId}:`,
18820
+ describeUnknownError(error)
18821
+ );
18822
+ }
18687
18823
  }
18688
18824
  }
18825
+ stage = "sync-complete";
18826
+ } catch (error) {
18827
+ console.error(
18828
+ `[bridge-manager] Mirror reconcile failed during ${stage}:`,
18829
+ describeUnknownError(error)
18830
+ );
18689
18831
  } finally {
18690
18832
  state.mirrorSyncInFlight = false;
18691
18833
  }
@@ -18774,6 +18916,8 @@ function listEnabledAdapterInstances() {
18774
18916
  async function stopAdapterInstance(channelType) {
18775
18917
  const state = getState();
18776
18918
  const adapter = state.adapters.get(channelType);
18919
+ state.invalidAdapters.delete(channelType);
18920
+ INVALID_ADAPTER_WARNING_CACHE.delete(channelType);
18777
18921
  if (!adapter) return;
18778
18922
  state.loopAborts.get(channelType)?.abort();
18779
18923
  state.loopAborts.delete(channelType);
@@ -18799,6 +18943,14 @@ async function syncConfiguredAdapters(options) {
18799
18943
  await stopAdapterInstance(existingKey);
18800
18944
  changed = true;
18801
18945
  }
18946
+ for (const invalidKey of Array.from(state.invalidAdapters.keys())) {
18947
+ if (desiredKeys.has(invalidKey)) continue;
18948
+ state.invalidAdapters.delete(invalidKey);
18949
+ }
18950
+ for (const invalidKey of Array.from(INVALID_ADAPTER_WARNING_CACHE.keys())) {
18951
+ if (desiredKeys.has(invalidKey)) continue;
18952
+ INVALID_ADAPTER_WARNING_CACHE.delete(invalidKey);
18953
+ }
18802
18954
  for (const instance of desiredInstances) {
18803
18955
  const existing = state.adapters.get(instance.id);
18804
18956
  const desiredFingerprint = desiredFingerprints.get(instance.id) || "";
@@ -18812,9 +18964,16 @@ async function syncConfiguredAdapters(options) {
18812
18964
  if (!adapter) continue;
18813
18965
  const configError = adapter.validateConfig();
18814
18966
  if (configError) {
18815
- console.warn(`[bridge-manager] ${instance.id} adapter not valid:`, configError);
18967
+ const invalidSignature = `${desiredFingerprint}:${configError}`;
18968
+ if (INVALID_ADAPTER_WARNING_CACHE.get(instance.id) !== invalidSignature) {
18969
+ console.warn(`[bridge-manager] ${instance.id} adapter not valid:`, configError);
18970
+ INVALID_ADAPTER_WARNING_CACHE.set(instance.id, invalidSignature);
18971
+ state.invalidAdapters.set(instance.id, invalidSignature);
18972
+ }
18816
18973
  continue;
18817
18974
  }
18975
+ state.invalidAdapters.delete(instance.id);
18976
+ INVALID_ADAPTER_WARNING_CACHE.delete(instance.id);
18818
18977
  try {
18819
18978
  state.adapters.set(instance.id, adapter);
18820
18979
  state.adapterMeta.set(instance.id, {
@@ -18874,11 +19033,11 @@ async function start() {
18874
19033
  }, 5e3);
18875
19034
  state.mirrorPollTimer = setInterval(() => {
18876
19035
  void reconcileMirrorSubscriptions().catch((err) => {
18877
- console.error("[bridge-manager] Mirror reconcile failed:", err);
19036
+ console.error("[bridge-manager] Mirror reconcile failed:", describeUnknownError(err));
18878
19037
  });
18879
19038
  }, MIRROR_POLL_INTERVAL_MS);
18880
19039
  void reconcileMirrorSubscriptions().catch((err) => {
18881
- console.error("[bridge-manager] Initial mirror reconcile failed:", err);
19040
+ console.error("[bridge-manager] Initial mirror reconcile failed:", describeUnknownError(err));
18882
19041
  });
18883
19042
  console.log(`[bridge-manager] Bridge started with ${startedCount} adapter(s)`);
18884
19043
  }
@@ -18911,6 +19070,8 @@ async function stop() {
18911
19070
  state.mirrorSuppressUntil.clear();
18912
19071
  state.mirrorIgnoredTurnIds.clear();
18913
19072
  state.queuedCounts.clear();
19073
+ state.invalidAdapters.clear();
19074
+ INVALID_ADAPTER_WARNING_CACHE.clear();
18914
19075
  for (const sessionId of activeSessionIds) {
18915
19076
  syncSessionRuntimeState(sessionId);
18916
19077
  }
@@ -19403,6 +19564,10 @@ async function handleCommand(adapter, msg, text2) {
19403
19564
  }
19404
19565
  if (args === "all") {
19405
19566
  const desktopSessions = getDisplayedDesktopThreads(MAX_DESKTOP_THREAD_LIST_LIMIT);
19567
+ if (!desktopSessions) {
19568
+ response = "\u8BFB\u53D6\u684C\u9762\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
19569
+ break;
19570
+ }
19406
19571
  if (desktopSessions.length === 0) {
19407
19572
  response = "\u6CA1\u6709\u627E\u5230\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002";
19408
19573
  break;
@@ -19415,6 +19580,10 @@ async function handleCommand(adapter, msg, text2) {
19415
19580
  break;
19416
19581
  }
19417
19582
  const displayedThreads = getDisplayedDesktopThreads(MAX_DESKTOP_THREAD_LIST_LIMIT);
19583
+ if (!displayedThreads) {
19584
+ response = "\u8BFB\u53D6\u684C\u9762\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
19585
+ break;
19586
+ }
19418
19587
  const threadPick = resolveByIndexOrPrefix(args, displayedThreads, (session) => session.threadId);
19419
19588
  if (threadPick.ambiguous) {
19420
19589
  response = "\u5339\u914D\u5230\u591A\u4E2A\u684C\u9762\u4F1A\u8BDD\uFF0C\u8BF7\u5148\u53D1\u9001 `/t` \u67E5\u770B\u5217\u8868\uFF0C\u518D\u7528 `/t 1` \u8FD9\u79CD\u5E8F\u53F7\u5207\u6362\u3002";
@@ -19422,7 +19591,7 @@ async function handleCommand(adapter, msg, text2) {
19422
19591
  }
19423
19592
  if (!threadPick.match) {
19424
19593
  if (validateSessionId(args)) {
19425
- const desktop = getDesktopSessionByThreadId(args);
19594
+ const desktop = getDesktopSessionByThreadIdSafe(args, "thread switch");
19426
19595
  let binding2;
19427
19596
  try {
19428
19597
  binding2 = bindToSdkSession(msg.address, args, desktop ? {
@@ -19481,6 +19650,10 @@ async function handleCommand(adapter, msg, text2) {
19481
19650
  }
19482
19651
  const { showAll, limit } = listArgs;
19483
19652
  const desktopSessions = getDisplayedDesktopThreads(limit);
19653
+ if (!desktopSessions) {
19654
+ response = "\u8BFB\u53D6\u684C\u9762\u4F1A\u8BDD\u5217\u8868\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002";
19655
+ break;
19656
+ }
19484
19657
  if (desktopSessions.length === 0) {
19485
19658
  response = showAll ? "\u6CA1\u6709\u627E\u5230\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002" : "\u6CA1\u6709\u627E\u5230\u6700\u8FD1\u684C\u9762\u4F1A\u8BDD\u3002\u5148\u5728 Codex Desktop App \u4E2D\u6253\u5F00\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u518D\u56DE\u6765\u8BD5\u4E00\u6B21\u3002";
19486
19659
  break;
@@ -20887,6 +21060,7 @@ var PendingPermissions = class {
20887
21060
  // src/logger.ts
20888
21061
  import fs11 from "node:fs";
20889
21062
  import path13 from "node:path";
21063
+ import { inspect as inspect2 } from "node:util";
20890
21064
  var MASK_PATTERNS = [
20891
21065
  /(?:token|secret|password|api_key)["']?\s*[:=]\s*["']?([^\s"',]+)/gi,
20892
21066
  /bot\d+:[A-Za-z0-9_-]{35}/g,
@@ -20908,6 +21082,22 @@ var LOG_PATH = path13.join(LOG_DIR, "bridge.log");
20908
21082
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
20909
21083
  var MAX_ROTATED = 3;
20910
21084
  var logStream = null;
21085
+ function formatLogArg(value) {
21086
+ if (typeof value === "string") return value;
21087
+ if (value instanceof Error) {
21088
+ return value.stack || `${value.name}: ${value.message}`;
21089
+ }
21090
+ if (value === null) return "null";
21091
+ if (typeof value === "undefined") return "undefined";
21092
+ if (typeof value === "object") {
21093
+ return inspect2(value, {
21094
+ depth: 4,
21095
+ breakLength: Infinity,
21096
+ compact: true
21097
+ });
21098
+ }
21099
+ return String(value);
21100
+ }
20911
21101
  function openLogStream() {
20912
21102
  return fs11.createWriteStream(LOG_PATH, { flags: "a" });
20913
21103
  }
@@ -20937,7 +21127,7 @@ function setupLogger() {
20937
21127
  logStream = openLogStream();
20938
21128
  const write = (level, args) => {
20939
21129
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
20940
- const message = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
21130
+ const message = args.map((a) => formatLogArg(a)).join(" ");
20941
21131
  const formatted = `[${timestamp}] [${level}] ${message}`;
20942
21132
  const masked = maskSecrets(formatted);
20943
21133
  rotateIfNeeded();