@chibitek/chibi 0.1.154 → 0.1.155

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.
Files changed (79) hide show
  1. package/dist/assets/{abnfDiagram-O67JEVCF-CbIXKQpc.js → abnfDiagram-O67JEVCF-B8LdsCr1.js} +1 -1
  2. package/dist/assets/{arc-D1xLD8SN.js → arc-DU5fSmKU.js} +1 -1
  3. package/dist/assets/{architectureDiagram-NJMV4G6O-xZe7iJ9y.js → architectureDiagram-NJMV4G6O-DdQSIFKv.js} +1 -1
  4. package/dist/assets/{blockDiagram-BEXU5L5S-Cq35uL03.js → blockDiagram-BEXU5L5S-CaPcGYSS.js} +1 -1
  5. package/dist/assets/{c4Diagram-YGBWAQC7-DjlN_-0r.js → c4Diagram-YGBWAQC7-unt0ePgO.js} +1 -1
  6. package/dist/assets/channel-GBaPOaz-.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-BQpywZWX.js → chunk-2Q5K7J3B-Babg5Fzu.js} +1 -1
  8. package/dist/assets/{chunk-3FUC2YCW-BajOpOBu.js → chunk-3FUC2YCW-D1-dWVHo.js} +2 -2
  9. package/dist/assets/{chunk-5VM5RSS4-DuZpQtDE.js → chunk-5VM5RSS4-DU7nSMbT.js} +1 -1
  10. package/dist/assets/{chunk-GTNCS2PH-Dn8xlUsI.js → chunk-GTNCS2PH-QIjCJIhV.js} +1 -1
  11. package/dist/assets/{chunk-GWA4HPMP-Xrus5lAx.js → chunk-GWA4HPMP-pSByUE5R.js} +1 -1
  12. package/dist/assets/{chunk-JWPE2WC7-Dhf8RCqM.js → chunk-JWPE2WC7-Dj2AaR1b.js} +1 -1
  13. package/dist/assets/{chunk-NETBCI7D-BQXmOQMl.js → chunk-NETBCI7D-pZbN0-FP.js} +1 -1
  14. package/dist/assets/{chunk-WEXAMYUT-BeraxyW-.js → chunk-WEXAMYUT-Bqarwe4D.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-BsKuu9tP.js → chunk-XXDRQBXY-WV8lm3aa.js} +1 -1
  16. package/dist/assets/{classDiagram-v2-NBCMYWYE-CcR0y3zf.js → classDiagram-v2-NBCMYWYE-BANBtky1.js} +1 -1
  17. package/dist/assets/{cose-bilkent-JH36ORCC-Dd2y43ln.js → cose-bilkent-JH36ORCC-CtrktgBC.js} +1 -1
  18. package/dist/assets/{cynefin-OW5HDTMX-DL4Zf255.js → cynefin-OW5HDTMX-DnhVVfba.js} +1 -1
  19. package/dist/assets/{cynefinDiagram-VND7K2PF-CvfZKzI5.js → cynefinDiagram-VND7K2PF-B42SRR6x.js} +1 -1
  20. package/dist/assets/{dagre-6A5THRUB-CZfm2BmL.js → dagre-6A5THRUB-DM--vFMK.js} +1 -1
  21. package/dist/assets/{diagram-22UHCM2B-DEEoufNr.js → diagram-22UHCM2B-ZBupBrPU.js} +1 -1
  22. package/dist/assets/{diagram-3UASUU5V-C1R6O8j1.js → diagram-3UASUU5V-BPQzNIOd.js} +1 -1
  23. package/dist/assets/{diagram-ATOU4E4O-D9dPGToa.js → diagram-ATOU4E4O-5kO8vf8Z.js} +1 -1
  24. package/dist/assets/{diagram-CDSNMT55-BHy3uSmJ.js → diagram-CDSNMT55-DtxogB86.js} +1 -1
  25. package/dist/assets/{diagram-MLGK6HIB-CEo2WbRd.js → diagram-MLGK6HIB-Co9-nYw_.js} +1 -1
  26. package/dist/assets/{diagram-MPIPVDR6-BrZrCrGC.js → diagram-MPIPVDR6-DWRuMh5y.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-ZINNZB2B-CtChmI9r.js → ebnfDiagram-ZINNZB2B-DU_nmoG9.js} +1 -1
  28. package/dist/assets/{elk-276RUBZZ-C-qEle2N.js → elk-276RUBZZ-Bcje7S94.js} +1 -1
  29. package/dist/assets/{erDiagram-OPXOYQCR-BEdc5DT9.js → erDiagram-OPXOYQCR-9aCo_2CI.js} +1 -1
  30. package/dist/assets/{flowDiagram-KWPJA3E3-CT-fOp9_.js → flowDiagram-KWPJA3E3-D4FYFyc5.js} +1 -1
  31. package/dist/assets/{ganttDiagram-FUAMR5RP-LWgFxnGJ.js → ganttDiagram-FUAMR5RP-WQHX5rbx.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-X574FWY7-xHSa3-lE.js → gitGraphDiagram-X574FWY7-DRyzBdiV.js} +1 -1
  33. package/dist/assets/{index-Dy25lFJN.js → index-CG1OvRgO.js} +1 -1
  34. package/dist/assets/{index-BpHS2C5J.js → index-D_8SD_0K.js} +3 -3
  35. package/dist/assets/{infoDiagram-VRGFBTTK-BOyODyhP.js → infoDiagram-VRGFBTTK-D7SOmp4n.js} +1 -1
  36. package/dist/assets/{ishikawaDiagram-OU5B5YK6-D3F47TMU.js → ishikawaDiagram-OU5B5YK6-CdxOnDVX.js} +1 -1
  37. package/dist/assets/{journeyDiagram-ZHPQQLJL-B8h_aacv.js → journeyDiagram-ZHPQQLJL-CH7477Oa.js} +1 -1
  38. package/dist/assets/{kanban-definition-PNTS6WVX-nqNasrdQ.js → kanban-definition-PNTS6WVX-BdpVvkHd.js} +1 -1
  39. package/dist/assets/{linear-CDofN9-p.js → linear-DTGq6qn5.js} +1 -1
  40. package/dist/assets/{mermaid.core-k18eNV07.js → mermaid.core-Sn2sv0Ti.js} +5 -5
  41. package/dist/assets/{mindmap-definition-NLK3R4M7-BYNmNDXA.js → mindmap-definition-NLK3R4M7-koCmkYuq.js} +1 -1
  42. package/dist/assets/{pegDiagram-GJSIUBJH-44c5V9Pa.js → pegDiagram-GJSIUBJH-C3sqhm8e.js} +1 -1
  43. package/dist/assets/{pieDiagram-5QR66LMP-BDvznIYT.js → pieDiagram-5QR66LMP-BELBK122.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-O4NWA36T-BWrzS8SI.js → quadrantDiagram-O4NWA36T-Cksi5LSm.js} +1 -1
  45. package/dist/assets/{railroadDiagram-XR7U4H2S-H_3uxTrq.js → railroadDiagram-XR7U4H2S-f1av_EZW.js} +1 -1
  46. package/dist/assets/{requirementDiagram-PLB6GJNP-BiyKTF3R.js → requirementDiagram-PLB6GJNP-CW4O5nER.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-IPEJSGJF-43RmpN9N.js → sankeyDiagram-IPEJSGJF-Dz8ADHNY.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-PO4LG4MO-B0OUYqhV.js → sequenceDiagram-PO4LG4MO-Cc3HE0iZ.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-xiXiEFtk.js → sizeCapture-INFHLROL-gdaZNHnK.js} +1 -1
  50. package/dist/assets/{stateDiagram-v2-GCMORJYK-C4-l5TZJ.js → stateDiagram-v2-GCMORJYK--u8LCnab.js} +1 -1
  51. package/dist/assets/{swimlanes-2SLR337P-B58p5Kvz.js → swimlanes-2SLR337P-4MAw4kdO.js} +1 -1
  52. package/dist/assets/swimlanesDiagram-TC7HE7FX-CamSa0NE.js +8 -0
  53. package/dist/assets/{timeline-definition-EJHVYXUP-DUgR2Qsq.js → timeline-definition-EJHVYXUP-CL89YkCT.js} +1 -1
  54. package/dist/assets/{usecaseDiagram-POWQR4AR-DcicVGBU.js → usecaseDiagram-POWQR4AR-C92l7YQe.js} +1 -1
  55. package/dist/assets/{vennDiagram-UO4OBE2U-9pThMhQ1.js → vennDiagram-UO4OBE2U-17siYhSj.js} +1 -1
  56. package/dist/assets/{wardleyDiagram-VNRHLVJA-CStNs1Wv.js → wardleyDiagram-VNRHLVJA-CNwa9VmN.js} +1 -1
  57. package/dist/assets/{xychartDiagram-PMCCYNJV-JmQMXi-y.js → xychartDiagram-PMCCYNJV-Dnu6Xzih.js} +1 -1
  58. package/dist/index.html +1 -1
  59. package/dist-server/connector-proxy.js +205 -0
  60. package/dist-server/index.js +93 -38
  61. package/dist-server/mcp-gate.js +7 -4
  62. package/dist-server/openmausbot.js +16 -22
  63. package/dist-server/pair-cli.js +16 -22
  64. package/dist-server/server/composio.js +1051 -0
  65. package/dist-server/server/connector-proxy.js +249 -0
  66. package/dist-server/server/drivers/codex.js +18 -23
  67. package/dist-server/server/incidents.js +8 -4
  68. package/dist-server/server/index.js +14 -16
  69. package/dist-server/server/mcp-auth-signal.js +2 -1
  70. package/dist-server/server/mcp-gate-config.js +1 -0
  71. package/dist-server/server/mcp-gate.js +7 -4
  72. package/dist-server/server/mcp-health.js +14 -4
  73. package/dist-server/server/mcp-public-registry.js +325 -0
  74. package/dist-server/server/mcp-turn.js +26 -0
  75. package/dist-server/server/system-prompt.js +14 -6
  76. package/dist-server/shared/connector-availability.js +12 -0
  77. package/package.json +1 -1
  78. package/dist/assets/channel-Bm-MISs3.js +0 -1
  79. package/dist/assets/swimlanesDiagram-TC7HE7FX-CPlL77A3.js +0 -8
@@ -27615,7 +27615,8 @@ function gateServer(input) {
27615
27615
  OMB_GATE_UPSTREAM: JSON.stringify({ command: spec.command, args: spec.args ?? [], env: spec.env ?? {} }),
27616
27616
  OMB_GATE_SPILL_DIR: spillDir(input.threadId),
27617
27617
  OMB_GATE_BUDGET: String(budget),
27618
- OMB_GATE_AUTH_DIR: mcpAuthSignalDir()
27618
+ OMB_GATE_AUTH_DIR: mcpAuthSignalDir(),
27619
+ OMB_GATE_THREAD: input.threadId
27619
27620
  }
27620
27621
  };
27621
27622
  }
@@ -52466,12 +52467,13 @@ var McpHealthStore = class {
52466
52467
  * once. */
52467
52468
  noteFailed(name2, spec, kind, at2 = this.now()) {
52468
52469
  const entry = this.entry(name2, spec);
52469
- if (entry && at2 < entry.retryAt) return;
52470
+ if (entry && at2 < entry.retryAt) return false;
52470
52471
  const failures = (entry?.failures ?? 0) + 1;
52471
52472
  const wait2 = MCP_FAILURE_BACKOFF_MS[Math.min(failures, MCP_FAILURE_BACKOFF_MS.length) - 1];
52472
52473
  const retryAt = at2 + wait2;
52473
52474
  this.servers.set(name2, { fingerprint: mcpServerFingerprint(spec), kind, failures, lastFailureAt: at2, retryAt });
52474
52475
  this.log(`[mcp] "${name2}" ${kind === "crashed" ? "stopped during a turn" : "would not start"}; turns run without it until ${formatTime(retryAt)}`);
52476
+ return true;
52475
52477
  }
52476
52478
  /** The server answered: whatever was wrong is over. An answer from a start
52477
52479
  * that began before a later failure does not clear that failure. */
@@ -52489,15 +52491,24 @@ var McpHealthStore = class {
52489
52491
  const when = this.now() >= entry.retryAt ? "Atomic tries it again on the next turn." : `Atomic tries it again at ${formatTime(entry.retryAt)}.`;
52490
52492
  return `This server ${what}, so bots are working without it for now. ${when} Check its command and settings if this keeps happening.`;
52491
52493
  }
52494
+ /** Why a server is left out of turns right now, or undefined when it mounts. */
52495
+ unavailableKind(name2, spec) {
52496
+ const entry = this.entry(name2, spec);
52497
+ return entry && this.now() < entry.retryAt ? entry.kind : void 0;
52498
+ }
52492
52499
  /** Apply what gates and the chat runtime reported, in order. `specs` are
52493
- * the servers as configured now; a signal for a removed server is dropped. */
52500
+ * the servers as configured now; a signal for a removed server is dropped.
52501
+ * Returns the signals that recorded a new failure (a repeat inside the
52502
+ * backoff window is not one), so the harness can raise one incident each. */
52494
52503
  ingest(signals, specs) {
52504
+ const fresh = [];
52495
52505
  for (const signal of signals) {
52496
52506
  const spec = specs[signal.name];
52497
52507
  if (!spec) continue;
52498
52508
  if (signal.kind === "ok") this.noteOk(signal.name, signal.at);
52499
- else if (signal.kind === "start-failed" || signal.kind === "crashed") this.noteFailed(signal.name, spec, signal.kind, signal.at);
52509
+ else if ((signal.kind === "start-failed" || signal.kind === "crashed") && this.noteFailed(signal.name, spec, signal.kind, signal.at)) fresh.push(signal);
52500
52510
  }
52511
+ return fresh;
52501
52512
  }
52502
52513
  };
52503
52514
 
@@ -52532,7 +52543,12 @@ function drainMcpAuthSignals(dir) {
52532
52543
  try {
52533
52544
  const parsed = JSON.parse(readFileSync27(file2, "utf8"));
52534
52545
  if (typeof parsed.name === "string" && MCP_SIGNAL_KINDS.includes(parsed.kind) && typeof parsed.at === "number" && Number.isFinite(parsed.at)) {
52535
- signals.push({ name: parsed.name, kind: parsed.kind, at: parsed.at });
52546
+ signals.push({
52547
+ name: parsed.name,
52548
+ kind: parsed.kind,
52549
+ at: parsed.at,
52550
+ ...typeof parsed.threadId === "string" && parsed.threadId ? { threadId: parsed.threadId } : {}
52551
+ });
52536
52552
  }
52537
52553
  } catch {
52538
52554
  }
@@ -52541,6 +52557,34 @@ function drainMcpAuthSignals(dir) {
52541
52557
  return signals.sort((a, b3) => a.at - b3.at);
52542
52558
  }
52543
52559
 
52560
+ // server/mcp-turn.ts
52561
+ function mcpTurnPolicy(deps) {
52562
+ return {
52563
+ /** Fold in what gates and the chat runtime reported since the last look. */
52564
+ sync() {
52565
+ const signals = drainMcpAuthSignals(deps.signalDir());
52566
+ if (!signals.length) return;
52567
+ const specs = deps.specs();
52568
+ deps.auth.ingest(signals, specs);
52569
+ for (const signal of deps.health.ingest(signals, specs)) {
52570
+ if (signal.threadId) deps.reportUnavailable(signal.threadId, `the "${signal.name}" MCP server ${signal.kind === "crashed" ? "stopped during the turn" : "would not start"}; the turn ran on without its tools`);
52571
+ }
52572
+ },
52573
+ /** The servers one turn starts: `servers` minus any whose sign-in is
52574
+ * backing off or stopped, or that lately would not start or crashed. */
52575
+ mountable(servers) {
52576
+ return Object.fromEntries(Object.entries(servers).filter(([name2, spec]) => deps.auth.mountable(name2, spec) && deps.health.mountable(name2, spec)));
52577
+ },
52578
+ /** The ones left out for being broken, so the model is told in one line. */
52579
+ unavailable(servers) {
52580
+ return Object.entries(servers).flatMap(([name2, spec]) => {
52581
+ const kind = deps.health.unavailableKind(name2, spec);
52582
+ return kind ? [{ name: name2, kind }] : [];
52583
+ });
52584
+ }
52585
+ };
52586
+ }
52587
+
52544
52588
  // server/mcp-import-detect.ts
52545
52589
  import { createHash as createHash12 } from "node:crypto";
52546
52590
  import { readFileSync as readFileSync28 } from "node:fs";
@@ -63052,17 +63096,11 @@ function managedCodexArgs(config2) {
63052
63096
  }
63053
63097
  var QUESTION_TIMEOUT_NOTE2 = "No answer was given \u2014 use your best judgment.";
63054
63098
  var DENY_TIMEOUT_NOTE2 = "Atomic: nobody answered this permission request in time. Skip this action and finish what you can without it.";
63055
- var skippedSseServers = /* @__PURE__ */ new Set();
63056
- var renamedMcpServers = /* @__PURE__ */ new Set();
63057
- function noteRenamedMcpServer(name2, mountName) {
63058
- if (renamedMcpServers.has(name2)) return;
63059
- renamedMcpServers.add(name2);
63060
- console.error(`codex: MCP server ${JSON.stringify(name2)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
63061
- }
63062
- function noteSkippedSseServer(name2) {
63063
- if (skippedSseServers.has(name2)) return;
63064
- skippedSseServers.add(name2);
63065
- console.error(`codex: MCP server ${JSON.stringify(name2)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
63099
+ var notedMcpServers = /* @__PURE__ */ new Set();
63100
+ function noteMcpServerOnce(key4, line2) {
63101
+ if (notedMcpServers.has(key4)) return;
63102
+ notedMcpServers.add(key4);
63103
+ console.error(`codex: MCP server ${line2}`);
63066
63104
  }
63067
63105
  function tomlInlineTable(entries2) {
63068
63106
  return `{ ${Object.entries(entries2).map(([key4, value]) => `${JSON.stringify(key4)} = ${JSON.stringify(value)}`).join(", ")} }`;
@@ -63420,12 +63458,11 @@ var CodexDriver = {
63420
63458
  const stopSignal = new AbortController();
63421
63459
  const { threadId } = turn;
63422
63460
  const approvalMode = turn.approvalMode ?? (config2.fullAuto ? "full" : "ask");
63461
+ const customServers = {};
63423
63462
  for (const [name2, server2] of Object.entries(turn.integrations?.custom ?? {})) {
63424
- if ("url" in server2) continue;
63425
- const reserved = Object.entries(server2.env).find(([key4, value]) => isHarnessOwnedMcpEnvName(key4) && !(key4 === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
63426
- if (reserved) {
63427
- throw new Error(`Custom MCP server \u201C${name2}\u201D cannot set reserved environment variable \u201C${reserved}\u201D`);
63428
- }
63463
+ const reserved = "url" in server2 ? void 0 : Object.entries(server2.env).find(([key4, value]) => isHarnessOwnedMcpEnvName(key4) && !(key4 === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
63464
+ if (reserved) noteMcpServerOnce(`reserved:${name2}`, `${JSON.stringify(name2)} sets reserved environment variable ${JSON.stringify(reserved)} \u2014 left out of this bot's turns until its settings change`);
63465
+ else customServers[name2] = server2;
63429
63466
  }
63430
63467
  let autoAcceptPermissions = approvalMode === "full";
63431
63468
  if (active.has(threadId)) throw new Error("a turn is already running on this thread");
@@ -63451,7 +63488,7 @@ var CodexDriver = {
63451
63488
  mountMcpServer(appServerArgs, env, "browser", turn.integrations.browser);
63452
63489
  }
63453
63490
  const childCwd = turn.cwd ?? homedir17();
63454
- for (const server2 of Object.values(turn.integrations?.custom ?? {})) {
63491
+ for (const server2 of Object.values(customServers)) {
63455
63492
  if (!("url" in server2)) Object.assign(env, server2.env);
63456
63493
  }
63457
63494
  if (turn.integrations?.phone) Object.assign(env, turn.integrations.phone.env);
@@ -63462,13 +63499,13 @@ var CodexDriver = {
63462
63499
  appServerArgs.push(...codexPersonalSetupOffArgs(env, childCwd));
63463
63500
  }
63464
63501
  const customByMountName = /* @__PURE__ */ new Map();
63465
- for (const [name2, server2] of Object.entries(turn.integrations?.custom ?? {})) {
63502
+ for (const [name2, server2] of Object.entries(customServers)) {
63466
63503
  if ("url" in server2 && server2.type === "sse") {
63467
- noteSkippedSseServer(name2);
63504
+ noteMcpServerOnce(`sse:${name2}`, `${JSON.stringify(name2)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
63468
63505
  continue;
63469
63506
  }
63470
63507
  const mountName = mountedMcpServerName(name2, declaredInCodexConfig);
63471
- if (mountName !== name2) noteRenamedMcpServer(name2, mountName);
63508
+ if (mountName !== name2) noteMcpServerOnce(`renamed:${name2}`, `${JSON.stringify(name2)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
63472
63509
  customByMountName.set(mountName, name2);
63473
63510
  mountMcpServer(appServerArgs, env, mountName, server2, false);
63474
63511
  }
@@ -76372,6 +76409,8 @@ function whatHappened(incident) {
76372
76409
  return `${incident.bot.name}'s run ${where} continued on another model because its engine refused the one it was set to${detail}`;
76373
76410
  case "engine-fallback":
76374
76411
  return `${incident.bot.name}'s run ${where} continued on another engine after its selected engine failed${detail}`;
76412
+ case "mcp-unavailable":
76413
+ return `${incident.bot.name}'s run ${where} continued without one of its tool servers${detail}`;
76375
76414
  default:
76376
76415
  return `${incident.bot.name}'s run ${where} failed${detail}`;
76377
76416
  }
@@ -76387,9 +76426,9 @@ function incidentText(incident, count) {
76387
76426
  if (incident.lastRequest) lines.push(`The request there was: "${fold2(incident.lastRequest, 300)}"`);
76388
76427
  if (incident.lastReply) lines.push(`${incident.bot.name} last said: "${fold2(incident.lastReply, 300)}"`);
76389
76428
  if (count.count > 1) lines.push(`This is the ${ordinal(count.count)} incident on that thread within the hour.`);
76390
- if (incident.kind === "model-fallback" || incident.kind === "engine-fallback") {
76429
+ if (incident.kind === "model-fallback" || incident.kind === "engine-fallback" || incident.kind === "mcp-unavailable") {
76391
76430
  lines.push("The run was not interrupted and needs no retry; do not call retry_thread.");
76392
- lines.push(incident.kind === "model-fallback" ? "Tell the person in one or two plain sentences that this engine no longer offers that model and that the bot's or the conversation's model setting should be changed, then stop." : "Use the incident detail to correct the failed engine if action is needed, then report what happened in one or two plain sentences and stop.");
76431
+ lines.push(incident.kind === "model-fallback" ? "Tell the person in one or two plain sentences that this engine no longer offers that model and that the bot's or the conversation's model setting should be changed, then stop." : incident.kind === "mcp-unavailable" ? "Tell the person in one or two plain sentences which tool server is not working, that bots carry on without it until it answers again, and that its command and settings in Settings may need a look, then stop." : "Use the incident detail to correct the failed engine if action is needed, then report what happened in one or two plain sentences and stop.");
76393
76432
  return lines.join("\n");
76394
76433
  }
76395
76434
  lines.push(count.mayRetry ? [
@@ -84731,10 +84770,16 @@ function accountsPrompt(emails) {
84731
84770
  const list3 = emails.map((email3) => `"${email3}"`).join(", ");
84732
84771
  return ` You can use the user's ${emails.length === 1 ? "account" : "accounts"} ${list3} through atomic_accounts (mail, calendar and files). Use list_accounts to check granted permissions. Do not use LLM account connectors for Google or Microsoft services. Pass the email as \`account\` when more than one account of that provider is listed. Save messages as drafts and send only when the user asked you to send.`;
84733
84772
  }
84734
- function customMcpPrompt(names3) {
84735
- if (names3.length === 0) return "";
84736
- const list3 = names3.map((name2) => `"${name2}"`).join(", ");
84737
- return ` The user also added ${names3.length === 1 ? "an MCP server" : "MCP servers"} for you: ${list3}. Use their available tools under the engine's normal approval rules.`;
84773
+ function customMcpPrompt(names3, unavailable2 = []) {
84774
+ const parts = [];
84775
+ if (names3.length > 0) {
84776
+ const list3 = names3.map((name2) => `"${name2}"`).join(", ");
84777
+ parts.push(` The user also added ${names3.length === 1 ? "an MCP server" : "MCP servers"} for you: ${list3}. Use their available tools under the engine's normal approval rules.`);
84778
+ }
84779
+ for (const server2 of unavailable2) {
84780
+ parts.push(` The "${server2.name}" tool server ${server2.kind === "crashed" ? "stopped working during a recent turn" : "would not start"}, so its tools are left out of this turn; Atomic tries it again later. Carry on without them.`);
84781
+ }
84782
+ return parts.join("");
84738
84783
  }
84739
84784
  var CREDENTIAL_PROMPT = " If a supported API key is missing for the service actually needed, use request_credential to create a secure credential request. Before requesting a computer-provider key, inspect the configured targets with select_computer; an existing self-hosted VPS does not need Box credentials. Do not request a different provider's key merely because a task mentions cloud. A freshly QR-paired mobile app or the desktop app can show the secure entry card. Never claim it opened unless the request succeeded, and never ask the user to paste credentials into chat.";
84740
84785
  var THREADS_PROMPT = " A thread is one conversation with its own history and its own run; a bot can have several running at once, and the person sees them as rows under that bot. Use start_thread to open one on yourself for separate work, or on a teammate to hand them a job that should run on its own. Use list_threads to see how the ones you opened are going. When you mention a thread to the person, write its title as #Title so it links. Do not use a ticket comment, a note, or a room post as a stand-in for a thread.";
@@ -126081,6 +126126,7 @@ bus.subscribe((event) => {
126081
126126
  lastReply.delete(event.threadId);
126082
126127
  const turnError = lastTurnError.get(event.threadId);
126083
126128
  lastTurnError.delete(event.threadId);
126129
+ syncMcpAuthState();
126084
126130
  const lazyClaimAlreadyReported = event.stopReason === "exit_before_result" && turnResourceOwners.get(event.threadId)?.lazyClaimFailureReported === true;
126085
126131
  if (!event.ok && event.stopReason !== "interrupted" && !lazyClaimAlreadyReported && !routines?.runForThread(event.threadId)) {
126086
126132
  const broken = bot ?? (speaker2 ? store.bot(speaker2.botId) : void 0);
@@ -126328,8 +126374,8 @@ function incidentContext(threadId) {
126328
126374
  }
126329
126375
  function reportIncident(input) {
126330
126376
  const { bot, threadId } = input;
126331
- const quiet = input.kind === "model-fallback" || input.kind === "engine-fallback";
126332
- if (input.kind !== "routine-failed" && input.kind !== "model-fallback" && input.kind !== "engine-fallback") {
126377
+ const quiet = input.kind === "model-fallback" || input.kind === "engine-fallback" || input.kind === "mcp-unavailable";
126378
+ if (input.kind !== "routine-failed" && input.kind !== "model-fallback" && input.kind !== "engine-fallback" && input.kind !== "mcp-unavailable") {
126333
126379
  primaryBotStore.noteFailure({ botId: bot.id, threadId, kind: input.kind, detail: redactSecretsInText(input.detail).slice(0, 300), at: Date.now() });
126334
126380
  }
126335
126381
  const task2 = store.taskByThread(bot.id, threadId);
@@ -127814,7 +127860,7 @@ async function startTurn(botId, text16, opts) {
127814
127860
  { id: "team-computer", label: "Team computer", text: teamComputerPrompt(teamComputer) },
127815
127861
  { id: "plan", label: "Surface", text: surfacePrompt({ computer: mountedComputer, browser: Boolean(integrations.browser) }, { pinned: plan.pinned, note: plan.note, canSelect: computerSelectionTurns.has(threadId) }) },
127816
127862
  { id: "accounts", label: "Google and Microsoft accounts", text: integrations.accounts ? accountsPrompt(botAccountEmails(bot)) : "" },
127817
- { id: "mcp", label: "MCP servers", text: customMcpPrompt(Object.keys(integrations.custom ?? {})) },
127863
+ { id: "mcp", label: "MCP servers", text: customMcpPrompt(Object.keys(integrations.custom ?? {}), instance.adapter.capabilities.customMcp === true ? mcpTurn.unavailable(engineMcpServers(bot)) : []) },
127818
127864
  { id: "browser", label: "Browser", text: integrations.browser ? BUILT_IN_BROWSER_SYSTEM_PROMPT : "" },
127819
127865
  { id: "coordination", label: "Team", text: coordinationPrompt ? ` ${coordinationPrompt}` : "" },
127820
127866
  { id: "assignment", label: "Teammate task", text: coordinationNode ? `
@@ -129288,7 +129334,7 @@ ${failover.note}` : ""}`;
129288
129334
  { id: "private-bot", label: "Private Bot", text: isPersonalBot(bot) ? privateBotPrompt(false) : "" },
129289
129335
  { id: "files", label: "File locations", text: workspace ? workspaceLocationsPrompt(bot.id, cwd, readyBot.cwd) : "" },
129290
129336
  { id: "repos", label: "Linked repos", text: repoPlan ? repoPromptSection(repoPlan, repoPlace(void 0, roomTeamComputer || roomComputerKind === "box" ? "box" : roomVmMounted ? "vm" : roomComputerKind), cwd) : "" },
129291
- { id: "mcp", label: "MCP servers", text: customMcpPrompt(Object.keys(integrations.custom ?? {})) },
129337
+ { id: "mcp", label: "MCP servers", text: customMcpPrompt(Object.keys(integrations.custom ?? {}), instance.adapter.capabilities.customMcp === true ? mcpTurn.unavailable(engineMcpServers(bot)) : []) },
129292
129338
  { id: "computer", label: "Computer", text: computerPrompt(roomTeamComputer || roomComputerKind === "box" ? instance.driverKind === "boxAgent" ? "box-agent" : instance.adapter.capabilities.cloudComputerMcp ? "box-chat" : "box" : roomVmMounted ? localVmMode(cfg) === "per-bot" ? "vm-private" : "vm-shared" : roomComputerKind) },
129293
129339
  { id: "team-computer", label: "Team computer", text: teamComputerPrompt(roomTeamComputer) },
129294
129340
  { id: "plan", label: "Surface", text: surfacePrompt({ computer: roomTeamComputer ? "cloud" : roomVmMounted ? "vm" : surfaceOfComputerKind(roomComputerKind), browser: Boolean(integrations.browser) }, { note: roomPlan.note }) },
@@ -131127,16 +131173,25 @@ function warmMcpToolHints(custom2) {
131127
131173
  }
131128
131174
  var mcpAuthState = new McpAuthStateStore(join124(DATA_DIR, "mcp-auth-state.json"));
131129
131175
  var mcpHealth = new McpHealthStore();
131176
+ var mcpTurn = mcpTurnPolicy({
131177
+ auth: mcpAuthState,
131178
+ health: mcpHealth,
131179
+ signalDir: mcpAuthSignalDir,
131180
+ specs: () => customMcpServers(cfg),
131181
+ reportUnavailable: (threadId, detail) => {
131182
+ const bot = store.botByThread(threadId);
131183
+ if (bot) reportIncident({ kind: "mcp-unavailable", bot, threadId, detail });
131184
+ }
131185
+ });
131130
131186
  function syncMcpAuthState() {
131131
- const signals = drainMcpAuthSignals(mcpAuthSignalDir());
131132
- if (signals.length) for (const state2 of [mcpAuthState, mcpHealth]) state2.ingest(signals, customMcpServers(cfg));
131187
+ mcpTurn.sync();
131133
131188
  }
131134
131189
  function bridgedMcpServer(spec, allowBrowser) {
131135
131190
  return bridgeMcpRemote(spec, { bridge: resolveMcpRemoteBridge(), execPath: process.execPath, allowBrowser });
131136
131191
  }
131137
131192
  function turnMcpServers2(bot) {
131138
131193
  syncMcpAuthState();
131139
- return Object.fromEntries(Object.entries(engineMcpServers(bot)).filter(([name2, spec]) => mcpAuthState.mountable(name2, spec) && mcpHealth.mountable(name2, spec)));
131194
+ return mcpTurn.mountable(engineMcpServers(bot));
131140
131195
  }
131141
131196
  function engineMcpServers(bot) {
131142
131197
  const requested = bot.mcpServers ?? Object.keys(cfg.mcpServers ?? {});
@@ -812,9 +812,12 @@ var GATE_ENV_KEYS = [
812
812
  "OMB_GATE_UPSTREAM",
813
813
  "OMB_GATE_SPILL_HINT",
814
814
  "OMB_GATE_AUTH_DIR",
815
- "OMB_GATE_START_TIMEOUT_MS"
815
+ "OMB_GATE_START_TIMEOUT_MS",
816
+ "OMB_GATE_THREAD"
816
817
  ];
817
818
  var AUTH_DIR = process.env.OMB_GATE_AUTH_DIR || "";
819
+ var THREAD = process.env.OMB_GATE_THREAD || "";
820
+ var signalHarness = (kind) => writeMcpAuthSignal(AUTH_DIR, { name: NAME, kind, at: Date.now(), ...THREAD ? { threadId: THREAD } : {} });
818
821
  function fail(message) {
819
822
  process.stderr.write(`mcp-gate(${NAME}): ${message}
820
823
  `);
@@ -928,7 +931,7 @@ function goDown(reason, why, signal = true) {
928
931
  if (startTimer) clearTimeout(startTimer);
929
932
  process.stderr.write(`mcp-gate(${NAME}): ${why}; answering as an empty server so the turn carries on without it
930
933
  `);
931
- if (signal) writeMcpAuthSignal(AUTH_DIR, { name: NAME, kind: reason, at: Date.now() });
934
+ if (signal) signalHarness(reason);
932
935
  for (const message of inFlight.values()) answer(strandedResponse(NAME, message));
933
936
  inFlight.clear();
934
937
  pending.clear();
@@ -1002,7 +1005,7 @@ createInterface({ input: child.stdout }).on("line", (line) => {
1002
1005
  if (!reportedOk && id !== void 0 && id === initializeId && message.result !== void 0) {
1003
1006
  reportedOk = true;
1004
1007
  if (startTimer) clearTimeout(startTimer);
1005
- writeMcpAuthSignal(AUTH_DIR, { name: NAME, kind: "ok", at: Date.now() });
1008
+ signalHarness("ok");
1006
1009
  }
1007
1010
  const tool = id === void 0 ? void 0 : pending.get(id);
1008
1011
  if (id !== void 0) pending.delete(id);
@@ -1029,7 +1032,7 @@ child.on("exit", (code, signal) => {
1029
1032
  if (!reportedOk && exitMeansSignInRequired(code, stderrTail)) {
1030
1033
  process.stderr.write(`mcp-gate(${NAME}): sign-in required; not opening a browser from a background start
1031
1034
  `);
1032
- writeMcpAuthSignal(AUTH_DIR, { name: NAME, kind: "sign-in-required", at: Date.now() });
1035
+ signalHarness("sign-in-required");
1033
1036
  if (!clientGone) return goDown("start-failed", "needs a sign-in", false);
1034
1037
  }
1035
1038
  if (clientGone) process.exit(code ?? (signal ? 1 : 0));
@@ -26066,7 +26066,8 @@ function gateServer(input) {
26066
26066
  OMB_GATE_UPSTREAM: JSON.stringify({ command: spec.command, args: spec.args ?? [], env: spec.env ?? {} }),
26067
26067
  OMB_GATE_SPILL_DIR: spillDir(input.threadId),
26068
26068
  OMB_GATE_BUDGET: String(budget),
26069
- OMB_GATE_AUTH_DIR: mcpAuthSignalDir()
26069
+ OMB_GATE_AUTH_DIR: mcpAuthSignalDir(),
26070
+ OMB_GATE_THREAD: input.threadId
26070
26071
  }
26071
26072
  };
26072
26073
  }
@@ -32291,15 +32292,10 @@ function managedCodexArgs(config2) {
32291
32292
  "shell_environment_policy.ignore_default_excludes=false"
32292
32293
  ];
32293
32294
  }
32294
- function noteRenamedMcpServer(name, mountName) {
32295
- if (renamedMcpServers.has(name)) return;
32296
- renamedMcpServers.add(name);
32297
- console.error(`codex: MCP server ${JSON.stringify(name)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
32298
- }
32299
- function noteSkippedSseServer(name) {
32300
- if (skippedSseServers.has(name)) return;
32301
- skippedSseServers.add(name);
32302
- console.error(`codex: MCP server ${JSON.stringify(name)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
32295
+ function noteMcpServerOnce(key, line) {
32296
+ if (notedMcpServers.has(key)) return;
32297
+ notedMcpServers.add(key);
32298
+ console.error(`codex: MCP server ${line}`);
32303
32299
  }
32304
32300
  function tomlInlineTable(entries2) {
32305
32301
  return `{ ${Object.entries(entries2).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`;
@@ -32558,7 +32554,7 @@ function mountMcpServer(appServerArgs, env, name, server, preApproved = true) {
32558
32554
  appServerArgs.push("-c", `${prefix}.default_tools_approval_mode="auto"`);
32559
32555
  }
32560
32556
  }
32561
- var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, skippedSseServers, renamedMcpServers, plainRecord, containsControlCharacter, CodexDriver;
32557
+ var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, notedMcpServers, plainRecord, containsControlCharacter, CodexDriver;
32562
32558
  var init_codex = __esm({
32563
32559
  "server/drivers/codex.ts"() {
32564
32560
  "use strict";
@@ -32597,8 +32593,7 @@ var init_codex = __esm({
32597
32593
  };
32598
32594
  QUESTION_TIMEOUT_NOTE2 = "No answer was given \u2014 use your best judgment.";
32599
32595
  DENY_TIMEOUT_NOTE2 = "Atomic: nobody answered this permission request in time. Skip this action and finish what you can without it.";
32600
- skippedSseServers = /* @__PURE__ */ new Set();
32601
- renamedMcpServers = /* @__PURE__ */ new Set();
32596
+ notedMcpServers = /* @__PURE__ */ new Set();
32602
32597
  plainRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
32603
32598
  containsControlCharacter = (value) => {
32604
32599
  for (const character of value) {
@@ -32698,12 +32693,11 @@ var init_codex = __esm({
32698
32693
  const stopSignal = new AbortController();
32699
32694
  const { threadId } = turn;
32700
32695
  const approvalMode = turn.approvalMode ?? (config2.fullAuto ? "full" : "ask");
32696
+ const customServers = {};
32701
32697
  for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
32702
- if ("url" in server) continue;
32703
- const reserved = Object.entries(server.env).find(([key, value]) => isHarnessOwnedMcpEnvName(key) && !(key === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
32704
- if (reserved) {
32705
- throw new Error(`Custom MCP server \u201C${name}\u201D cannot set reserved environment variable \u201C${reserved}\u201D`);
32706
- }
32698
+ const reserved = "url" in server ? void 0 : Object.entries(server.env).find(([key, value]) => isHarnessOwnedMcpEnvName(key) && !(key === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
32699
+ if (reserved) noteMcpServerOnce(`reserved:${name}`, `${JSON.stringify(name)} sets reserved environment variable ${JSON.stringify(reserved)} \u2014 left out of this bot's turns until its settings change`);
32700
+ else customServers[name] = server;
32707
32701
  }
32708
32702
  let autoAcceptPermissions = approvalMode === "full";
32709
32703
  if (active.has(threadId)) throw new Error("a turn is already running on this thread");
@@ -32729,7 +32723,7 @@ var init_codex = __esm({
32729
32723
  mountMcpServer(appServerArgs, env, "browser", turn.integrations.browser);
32730
32724
  }
32731
32725
  const childCwd = turn.cwd ?? homedir15();
32732
- for (const server of Object.values(turn.integrations?.custom ?? {})) {
32726
+ for (const server of Object.values(customServers)) {
32733
32727
  if (!("url" in server)) Object.assign(env, server.env);
32734
32728
  }
32735
32729
  if (turn.integrations?.phone) Object.assign(env, turn.integrations.phone.env);
@@ -32740,13 +32734,13 @@ var init_codex = __esm({
32740
32734
  appServerArgs.push(...codexPersonalSetupOffArgs(env, childCwd));
32741
32735
  }
32742
32736
  const customByMountName = /* @__PURE__ */ new Map();
32743
- for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
32737
+ for (const [name, server] of Object.entries(customServers)) {
32744
32738
  if ("url" in server && server.type === "sse") {
32745
- noteSkippedSseServer(name);
32739
+ noteMcpServerOnce(`sse:${name}`, `${JSON.stringify(name)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
32746
32740
  continue;
32747
32741
  }
32748
32742
  const mountName = mountedMcpServerName(name, declaredInCodexConfig);
32749
- if (mountName !== name) noteRenamedMcpServer(name, mountName);
32743
+ if (mountName !== name) noteMcpServerOnce(`renamed:${name}`, `${JSON.stringify(name)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
32750
32744
  customByMountName.set(mountName, name);
32751
32745
  mountMcpServer(appServerArgs, env, mountName, server, false);
32752
32746
  }
@@ -26066,7 +26066,8 @@ function gateServer(input) {
26066
26066
  OMB_GATE_UPSTREAM: JSON.stringify({ command: spec.command, args: spec.args ?? [], env: spec.env ?? {} }),
26067
26067
  OMB_GATE_SPILL_DIR: spillDir(input.threadId),
26068
26068
  OMB_GATE_BUDGET: String(budget),
26069
- OMB_GATE_AUTH_DIR: mcpAuthSignalDir()
26069
+ OMB_GATE_AUTH_DIR: mcpAuthSignalDir(),
26070
+ OMB_GATE_THREAD: input.threadId
26070
26071
  }
26071
26072
  };
26072
26073
  }
@@ -32291,15 +32292,10 @@ function managedCodexArgs(config2) {
32291
32292
  "shell_environment_policy.ignore_default_excludes=false"
32292
32293
  ];
32293
32294
  }
32294
- function noteRenamedMcpServer(name, mountName) {
32295
- if (renamedMcpServers.has(name)) return;
32296
- renamedMcpServers.add(name);
32297
- console.error(`codex: MCP server ${JSON.stringify(name)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
32298
- }
32299
- function noteSkippedSseServer(name) {
32300
- if (skippedSseServers.has(name)) return;
32301
- skippedSseServers.add(name);
32302
- console.error(`codex: MCP server ${JSON.stringify(name)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
32295
+ function noteMcpServerOnce(key, line) {
32296
+ if (notedMcpServers.has(key)) return;
32297
+ notedMcpServers.add(key);
32298
+ console.error(`codex: MCP server ${line}`);
32303
32299
  }
32304
32300
  function tomlInlineTable(entries2) {
32305
32301
  return `{ ${Object.entries(entries2).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`;
@@ -32558,7 +32554,7 @@ function mountMcpServer(appServerArgs, env, name, server, preApproved = true) {
32558
32554
  appServerArgs.push("-c", `${prefix}.default_tools_approval_mode="auto"`);
32559
32555
  }
32560
32556
  }
32561
- var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, skippedSseServers, renamedMcpServers, plainRecord, containsControlCharacter, CodexDriver;
32557
+ var DRIVER_KIND3, ASTRA_MODEL_ID, ASTRA_MIN_CODEX_VERSION, CodexRpcError, QUESTION_TIMEOUT_NOTE2, DENY_TIMEOUT_NOTE2, notedMcpServers, plainRecord, containsControlCharacter, CodexDriver;
32562
32558
  var init_codex = __esm({
32563
32559
  "server/drivers/codex.ts"() {
32564
32560
  "use strict";
@@ -32597,8 +32593,7 @@ var init_codex = __esm({
32597
32593
  };
32598
32594
  QUESTION_TIMEOUT_NOTE2 = "No answer was given \u2014 use your best judgment.";
32599
32595
  DENY_TIMEOUT_NOTE2 = "Atomic: nobody answered this permission request in time. Skip this action and finish what you can without it.";
32600
- skippedSseServers = /* @__PURE__ */ new Set();
32601
- renamedMcpServers = /* @__PURE__ */ new Set();
32596
+ notedMcpServers = /* @__PURE__ */ new Set();
32602
32597
  plainRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
32603
32598
  containsControlCharacter = (value) => {
32604
32599
  for (const character of value) {
@@ -32698,12 +32693,11 @@ var init_codex = __esm({
32698
32693
  const stopSignal = new AbortController();
32699
32694
  const { threadId } = turn;
32700
32695
  const approvalMode = turn.approvalMode ?? (config2.fullAuto ? "full" : "ask");
32696
+ const customServers = {};
32701
32697
  for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
32702
- if ("url" in server) continue;
32703
- const reserved = Object.entries(server.env).find(([key, value]) => isHarnessOwnedMcpEnvName(key) && !(key === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
32704
- if (reserved) {
32705
- throw new Error(`Custom MCP server \u201C${name}\u201D cannot set reserved environment variable \u201C${reserved}\u201D`);
32706
- }
32698
+ const reserved = "url" in server ? void 0 : Object.entries(server.env).find(([key, value]) => isHarnessOwnedMcpEnvName(key) && !(key === "ELECTRON_RUN_AS_NODE" && value === "1"))?.[0];
32699
+ if (reserved) noteMcpServerOnce(`reserved:${name}`, `${JSON.stringify(name)} sets reserved environment variable ${JSON.stringify(reserved)} \u2014 left out of this bot's turns until its settings change`);
32700
+ else customServers[name] = server;
32707
32701
  }
32708
32702
  let autoAcceptPermissions = approvalMode === "full";
32709
32703
  if (active.has(threadId)) throw new Error("a turn is already running on this thread");
@@ -32729,7 +32723,7 @@ var init_codex = __esm({
32729
32723
  mountMcpServer(appServerArgs, env, "browser", turn.integrations.browser);
32730
32724
  }
32731
32725
  const childCwd = turn.cwd ?? homedir15();
32732
- for (const server of Object.values(turn.integrations?.custom ?? {})) {
32726
+ for (const server of Object.values(customServers)) {
32733
32727
  if (!("url" in server)) Object.assign(env, server.env);
32734
32728
  }
32735
32729
  if (turn.integrations?.phone) Object.assign(env, turn.integrations.phone.env);
@@ -32740,13 +32734,13 @@ var init_codex = __esm({
32740
32734
  appServerArgs.push(...codexPersonalSetupOffArgs(env, childCwd));
32741
32735
  }
32742
32736
  const customByMountName = /* @__PURE__ */ new Map();
32743
- for (const [name, server] of Object.entries(turn.integrations?.custom ?? {})) {
32737
+ for (const [name, server] of Object.entries(customServers)) {
32744
32738
  if ("url" in server && server.type === "sse") {
32745
- noteSkippedSseServer(name);
32739
+ noteMcpServerOnce(`sse:${name}`, `${JSON.stringify(name)} uses the SSE transport, which codex does not speak \u2014 it is available to Claude bots only`);
32746
32740
  continue;
32747
32741
  }
32748
32742
  const mountName = mountedMcpServerName(name, declaredInCodexConfig);
32749
- if (mountName !== name) noteRenamedMcpServer(name, mountName);
32743
+ if (mountName !== name) noteMcpServerOnce(`renamed:${name}`, `${JSON.stringify(name)} is also declared in Codex's own config.toml \u2014 mounted as ${JSON.stringify(mountName)} for this bot so the two do not merge`);
32750
32744
  customByMountName.set(mountName, name);
32751
32745
  mountMcpServer(appServerArgs, env, mountName, server, false);
32752
32746
  }