agent-embassy 1.6.0 → 1.7.0

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 (97) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +9 -9
  3. package/README.zh-CN.md +9 -9
  4. package/SECURITY.md +34 -77
  5. package/dist/src/gateway/acp-client.d.ts +117 -0
  6. package/dist/src/gateway/acp-client.js +382 -0
  7. package/dist/src/gateway/acp-client.js.map +1 -0
  8. package/dist/src/gateway/acp-provider.d.ts +65 -0
  9. package/dist/src/gateway/acp-provider.js +163 -0
  10. package/dist/src/gateway/acp-provider.js.map +1 -0
  11. package/dist/src/gateway/claude-helper-protocol.d.ts +3 -1
  12. package/dist/src/gateway/claude-helper-protocol.js +15 -5
  13. package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
  14. package/dist/src/gateway/claude-helper-supervisor.d.ts +3 -1
  15. package/dist/src/gateway/claude-helper-supervisor.js +16 -2
  16. package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
  17. package/dist/src/gateway/claude-helper.js +4 -3
  18. package/dist/src/gateway/claude-helper.js.map +1 -1
  19. package/dist/src/gateway/claude-peer.d.ts +1 -1
  20. package/dist/src/gateway/claude-peer.js +11 -13
  21. package/dist/src/gateway/claude-peer.js.map +1 -1
  22. package/dist/src/gateway/claude-runtime.d.ts +0 -20
  23. package/dist/src/gateway/claude-runtime.js +6 -127
  24. package/dist/src/gateway/claude-runtime.js.map +1 -1
  25. package/dist/src/gateway/cli-copy.en.d.ts +1 -1
  26. package/dist/src/gateway/cli-copy.en.js +2 -2
  27. package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
  28. package/dist/src/gateway/cli-copy.zh-CN.js +2 -2
  29. package/dist/src/gateway/cli.d.ts +1 -1
  30. package/dist/src/gateway/cli.js +26 -5
  31. package/dist/src/gateway/cli.js.map +1 -1
  32. package/dist/src/gateway/codex-app-server.d.ts +5 -74
  33. package/dist/src/gateway/codex-app-server.js +9 -597
  34. package/dist/src/gateway/codex-app-server.js.map +1 -1
  35. package/dist/src/gateway/codex-local-transport.d.ts +8 -26
  36. package/dist/src/gateway/codex-local-transport.js +26 -76
  37. package/dist/src/gateway/codex-local-transport.js.map +1 -1
  38. package/dist/src/gateway/compatibility.d.ts +6 -66
  39. package/dist/src/gateway/compatibility.js +14 -296
  40. package/dist/src/gateway/compatibility.js.map +1 -1
  41. package/dist/src/gateway/config.d.ts +9 -0
  42. package/dist/src/gateway/config.js +6 -2
  43. package/dist/src/gateway/config.js.map +1 -1
  44. package/dist/src/gateway/control.d.ts +16 -1
  45. package/dist/src/gateway/control.js +89 -57
  46. package/dist/src/gateway/control.js.map +1 -1
  47. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  48. package/dist/src/gateway/dashboard-copy.en.d.ts +14 -44
  49. package/dist/src/gateway/dashboard-copy.en.js +37 -67
  50. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  51. package/dist/src/gateway/dashboard-copy.js +14 -44
  52. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  53. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +14 -44
  54. package/dist/src/gateway/dashboard-copy.zh-CN.js +37 -67
  55. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  56. package/dist/src/gateway/dashboard-model.d.ts +38 -76
  57. package/dist/src/gateway/dashboard-model.js +158 -256
  58. package/dist/src/gateway/dashboard-model.js.map +1 -1
  59. package/dist/src/gateway/dashboard.d.ts +0 -3
  60. package/dist/src/gateway/dashboard.js +75 -76
  61. package/dist/src/gateway/dashboard.js.map +1 -1
  62. package/dist/src/gateway/deepseek-detect.d.ts +7 -6
  63. package/dist/src/gateway/deepseek-detect.js +31 -115
  64. package/dist/src/gateway/deepseek-detect.js.map +1 -1
  65. package/dist/src/gateway/live-dashboard-app/app.js +166 -621
  66. package/dist/src/gateway/live-dashboard-command.js +2 -4
  67. package/dist/src/gateway/live-dashboard-command.js.map +1 -1
  68. package/dist/src/gateway/live-dashboard-http.d.ts +1 -2
  69. package/dist/src/gateway/live-dashboard-http.js +14 -15
  70. package/dist/src/gateway/live-dashboard-http.js.map +1 -1
  71. package/dist/src/gateway/progress-watch-machine.d.ts +1 -4
  72. package/dist/src/gateway/progress-watch-machine.js.map +1 -1
  73. package/dist/src/gateway/provenance-envelope.d.ts +3 -2
  74. package/dist/src/gateway/provenance-envelope.js +44 -11
  75. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  76. package/dist/src/gateway/providers.d.ts +12 -84
  77. package/dist/src/gateway/providers.js +69 -806
  78. package/dist/src/gateway/providers.js.map +1 -1
  79. package/dist/src/gateway/server.d.ts +8 -9
  80. package/dist/src/gateway/server.js +51 -99
  81. package/dist/src/gateway/server.js.map +1 -1
  82. package/dist/src/gateway/service.d.ts +22 -49
  83. package/dist/src/gateway/service.js +196 -432
  84. package/dist/src/gateway/service.js.map +1 -1
  85. package/dist/src/gateway/store.d.ts +20 -29
  86. package/dist/src/gateway/store.js +281 -827
  87. package/dist/src/gateway/store.js.map +1 -1
  88. package/dist/src/gateway/types.d.ts +55 -55
  89. package/dist/src/gateway/types.js +49 -91
  90. package/dist/src/gateway/types.js.map +1 -1
  91. package/docs/CONFIGURATION.md +11 -10
  92. package/docs/CONFIGURATION.zh-CN.md +10 -9
  93. package/docs/DASHBOARD.md +4 -38
  94. package/docs/DASHBOARD.zh-CN.md +4 -2
  95. package/docs/GATEWAY-ARCHITECTURE.md +61 -119
  96. package/package.json +1 -1
  97. package/skills/embassy-peer/SKILL.md +6 -6
@@ -111,7 +111,9 @@ var Embassy;
111
111
  function chipKindFor(state, direction, safeErrorCode) {
112
112
  const semantics = window.EMBASSY_BOOT.semantics;
113
113
  return (deliveryOverride(semantics.deliveryChipBySafeErrorCode, state, safeErrorCode) ??
114
- deliveryOverride(semantics.deliveryChipByDirection, state, direction) ??
114
+ deliveryOverride(semantics.deliveryChipByTargetProvider, state, direction === undefined
115
+ ? undefined
116
+ : Embassy.parseDirection(direction)?.targetProvider) ??
115
117
  presentation("delivery", state));
116
118
  }
117
119
  Embassy.chipKindFor = chipKindFor;
@@ -127,10 +129,6 @@ var Embassy;
127
129
  return presentation("health", state);
128
130
  }
129
131
  Embassy.healthChipKind = healthChipKind;
130
- function compatibilityChipKind(state) {
131
- return presentation("compatibility", state);
132
- }
133
- Embassy.compatibilityChipKind = compatibilityChipKind;
134
132
  function overallChipKind(state) {
135
133
  return presentation("overall", state);
136
134
  }
@@ -163,7 +161,10 @@ var Embassy;
163
161
  return semantics.deliveryMeaningBySafeErrorCode.SENDER_NOT_PAIRED;
164
162
  }
165
163
  if (state === "delivered" && direction !== undefined) {
166
- return semantics.deliveryMeaningByDirection[direction];
164
+ const target = Embassy.parseDirection(direction)?.targetProvider;
165
+ if (target !== undefined) {
166
+ return semantics.deliveryMeaningByTargetProvider[target];
167
+ }
167
168
  }
168
169
  if (state === "abandoned" && safeErrorCode !== undefined) {
169
170
  const byCode = semantics.deliveryMeaningBySafeErrorCode;
@@ -185,8 +186,6 @@ var Embassy;
185
186
  return `peer.meaning.${camelCaseToken(state)}`;
186
187
  case "health":
187
188
  return `health.meaning.${camelCaseToken(state)}`;
188
- case "compatibility":
189
- return `compatibility.meaning.${camelCaseToken(state)}`;
190
189
  case "overall":
191
190
  return `overall.${camelCaseToken(state)}`;
192
191
  case "party":
@@ -244,6 +243,24 @@ var Embassy;
244
243
  })(Embassy || (Embassy = {}));
245
244
  var Embassy;
246
245
  (function (Embassy) {
246
+ Embassy.GATEWAY_PROVIDERS = ["claude", "codex", "deepseek", "grok"];
247
+ function parseDirection(direction) {
248
+ const separator = direction.indexOf("_to_");
249
+ if (separator < 1 || separator !== direction.lastIndexOf("_to_")) {
250
+ return undefined;
251
+ }
252
+ const sourceProvider = direction.slice(0, separator);
253
+ const targetProvider = direction.slice(separator + 4);
254
+ const providers = Embassy.GATEWAY_PROVIDERS;
255
+ if (sourceProvider === targetProvider || !providers.includes(sourceProvider) ||
256
+ !providers.includes(targetProvider))
257
+ return undefined;
258
+ return {
259
+ sourceProvider: sourceProvider,
260
+ targetProvider: targetProvider,
261
+ };
262
+ }
263
+ Embassy.parseDirection = parseDirection;
247
264
  Embassy.TERMINAL_DELIVERY_STATES = [
248
265
  "delivered",
249
266
  "unconfirmed",
@@ -258,17 +275,10 @@ var Embassy;
258
275
  Embassy.PULSE_WINDOW_MS = 3_600_000;
259
276
  const HEALTH_WORST_FIRST = [
260
277
  "offline",
261
- "incompatible",
262
278
  "degraded",
263
279
  "connecting",
264
280
  "healthy",
265
281
  ];
266
- const COMPATIBILITY_WORST_FIRST = [
267
- "incompatible",
268
- "expired",
269
- "unknown",
270
- "compatible",
271
- ];
272
282
  function compareText(left, right) {
273
283
  return left < right ? -1 : left > right ? 1 : 0;
274
284
  }
@@ -334,18 +344,6 @@ var Embassy;
334
344
  return worst;
335
345
  }
336
346
  Embassy.worstConnectorHealth = worstConnectorHealth;
337
- function worstCompatibility(model) {
338
- let worst;
339
- for (const connector of model.connectors) {
340
- if (worst === undefined ||
341
- COMPATIBILITY_WORST_FIRST.indexOf(connector.compatibility) <
342
- COMPATIBILITY_WORST_FIRST.indexOf(worst)) {
343
- worst = connector.compatibility;
344
- }
345
- }
346
- return worst;
347
- }
348
- Embassy.worstCompatibility = worstCompatibility;
349
347
  function pulse(model) {
350
348
  const generatedMs = parseTimestampMs(model.generatedAt);
351
349
  const cutoffMs = generatedMs === undefined ? undefined : generatedMs - Embassy.PULSE_WINDOW_MS;
@@ -369,10 +367,6 @@ var Embassy;
369
367
  };
370
368
  }
371
369
  Embassy.pulse = pulse;
372
- function isMonitorOnly(route) {
373
- return route.safeErrorCode === "CODEX_WRITES_DISABLED";
374
- }
375
- Embassy.isMonitorOnly = isMonitorOnly;
376
370
  function hasLifecycleTruncation(group) {
377
371
  for (let index = 1; index < group.events.length; index += 1) {
378
372
  const previous = group.events[index - 1];
@@ -436,24 +430,22 @@ var Embassy;
436
430
  }
437
431
  Embassy.extractSuccessions = extractSuccessions;
438
432
  function overviewProps(model, nowMs) {
439
- const nonReadyPairCount = model.graph.pairCount - model.graph.readyPairCount;
433
+ const nonReadyConsentEdgeCount = model.graph.consentEdgeCount - model.graph.readyConsentEdgeCount;
440
434
  return {
441
435
  generatedAt: model.generatedAt,
442
436
  inboundMode: model.inboundMode,
443
437
  overall: model.overall,
444
438
  statusStrip: {
445
439
  broker: model.health,
446
- claudeConnector: worstConnectorHealth(model, "claude"),
447
- codexConnector: worstConnectorHealth(model, "codex"),
448
- compatibility: worstCompatibility(model),
440
+ providers: Embassy.GATEWAY_PROVIDERS.map((provider) => ({ provider, health: worstConnectorHealth(model, provider) })),
449
441
  },
450
442
  exchange: model.exchange,
451
- queueClaudeToCodex: queueSplit(model, "codex", nowMs),
452
- queueCodexToClaude: queueSplit(model, "claude", nowMs),
443
+ providerQueues: Embassy.GATEWAY_PROVIDERS.map((provider) => ({ provider, queue: queueSplit(model, provider, nowMs) })),
453
444
  graph: model.graph,
454
- degradedPairCopyKey: nonReadyPairCount <= 0
445
+ degradedConsentEdgeCopyKey: nonReadyConsentEdgeCount <= 0
455
446
  ? undefined
456
- : nonReadyPairCount === 1 && !model.graph.pairCountIsLowerBound
447
+ : nonReadyConsentEdgeCount === 1 &&
448
+ !model.graph.consentEdgeCountIsLowerBound
457
449
  ? "app.overview.degradedEdge"
458
450
  : "app.overview.degradedEdges",
459
451
  attention: attentionViews(model),
@@ -463,30 +455,40 @@ var Embassy;
463
455
  }
464
456
  Embassy.overviewProps = overviewProps;
465
457
  function deliveriesGroups(model) {
466
- return model.activity.map((group) => ({
467
- key: deliveryGroupKey(group),
468
- group,
469
- routePair: `${group.sourceAlias} → ${group.targetAlias}`,
470
- eventsTruncated: hasLifecycleTruncation(group),
471
- }));
458
+ return model.activity.map((group) => {
459
+ const parsed = parseDirection(group.direction);
460
+ if (parsed === undefined)
461
+ throw new Error("INVALID_MESSAGE_DIRECTION");
462
+ return {
463
+ key: deliveryGroupKey(group),
464
+ group,
465
+ routePair: `${group.sourceAlias} → ${group.targetAlias}`,
466
+ sourceProvider: parsed.sourceProvider,
467
+ targetProvider: parsed.targetProvider,
468
+ eventsTruncated: hasLifecycleTruncation(group),
469
+ };
470
+ });
472
471
  }
473
472
  Embassy.deliveriesGroups = deliveriesGroups;
473
+ function matchesProviderFilters(view, from, to) {
474
+ const parsed = parseDirection(view.group.direction);
475
+ return parsed !== undefined && (from === "all" || parsed.sourceProvider === from) &&
476
+ (to === "all" || parsed.targetProvider === to);
477
+ }
478
+ Embassy.matchesProviderFilters = matchesProviderFilters;
474
479
  function routesProps(model, nowMs) {
475
- const codexRoutes = model.routes
476
- .filter((route) => route.provider === "codex")
477
- .map((route) => ({
480
+ const routes = model.routes.map((route) => ({
478
481
  route,
479
- monitorOnly: isMonitorOnly(route),
480
482
  oldestAgeMs: routeOldestAgeMs(route, nowMs),
481
483
  }));
482
484
  return {
483
485
  inboundMode: model.inboundMode,
484
486
  peers: model.peers,
485
487
  peersOmitted: model.omissions.availablePeers,
486
- codexRoutes,
488
+ routes,
487
489
  routesOmitted: model.omissions.routes,
488
- pairs: model.pairs,
489
- pairsOmitted: model.omissions.pairs,
490
+ consentEdges: model.consentEdges,
491
+ consentEdgesOmitted: model.omissions.consentEdges,
490
492
  graph: model.graph,
491
493
  successions: extractSuccessions(model),
492
494
  };
@@ -527,7 +529,6 @@ var Embassy;
527
529
  return {
528
530
  connectors: model.connectors,
529
531
  connectorsOmitted: model.omissions.connectors,
530
- compatibilityChecks: model.compatibilityChecks ?? [],
531
532
  expiredCount: model.accounting.expired,
532
533
  ...(model.deadlinePressure === undefined
533
534
  ? {}
@@ -542,6 +543,7 @@ var Embassy;
542
543
  Embassy.adapter = {
543
544
  overviewProps,
544
545
  deliveriesGroups,
546
+ matchesProviderFilters,
545
547
  routesProps,
546
548
  activityRows,
547
549
  diagnosticsProps,
@@ -549,9 +551,7 @@ var Embassy;
549
551
  routeOldestAgeMs,
550
552
  pulse,
551
553
  worstConnectorHealth,
552
- worstCompatibility,
553
554
  extractSuccessions,
554
- isMonitorOnly,
555
555
  hasLifecycleTruncation,
556
556
  deliveriesTruncated,
557
557
  deliveryGroupKey,
@@ -935,14 +935,6 @@ var Embassy;
935
935
  }
936
936
  return (React.createElement(StatusCard, { label: props.label, detail: t(`health.meaning.${Embassy.camelCaseToken(health)}`), chip: React.createElement(Embassy.StateChip, { domain: "health", state: health, small: true }) }));
937
937
  }
938
- function CompatStatusCard(props) {
939
- const t = Embassy.useT();
940
- const compatibility = props.compatibility;
941
- if (compatibility === undefined) {
942
- return (React.createElement(StatusCard, { label: t("app.overview.compat"), detail: undefined, chip: React.createElement("span", { className: "chip chip--small", "data-kind": "inert" }, t("app.overview.connectorMissing")) }));
943
- }
944
- return (React.createElement(StatusCard, { label: t("app.overview.compat"), detail: t(`compatibility.meaning.${Embassy.camelCaseToken(compatibility)}`), chip: React.createElement(Embassy.StateChip, { domain: "compatibility", state: compatibility, small: true }) }));
945
- }
946
938
  function ExchangeNode(props) {
947
939
  const party = props.party;
948
940
  return (React.createElement("div", { className: "exchange-node" },
@@ -980,7 +972,7 @@ var Embassy;
980
972
  function attentionScopeParts(item, t) {
981
973
  const parts = [];
982
974
  if (item.provider !== undefined) {
983
- parts.push(item.provider === "claude" ? t("provider.claude") : t("provider.codex"));
975
+ parts.push(t(`provider.${item.provider}`));
984
976
  }
985
977
  if (item.alias !== undefined)
986
978
  parts.push(item.alias);
@@ -1032,25 +1024,9 @@ var Embassy;
1032
1024
  function OverviewTab(props) {
1033
1025
  const t = Embassy.useT();
1034
1026
  const { data, onViewDeliveries } = props;
1035
- const strip = data.statusStrip;
1036
- const queueOut = data.queueClaudeToCodex;
1037
- const queueIn = data.queueCodexToClaude;
1038
1027
  const openInbound = data.inboundMode === "open";
1039
- const hasPair = data.graph.pairCount > 0 || data.graph.pairCountIsLowerBound;
1040
- const showEdges = hasPair || queueOut.depth > 0 || queueIn.depth > 0;
1041
- const nextActionLine = (who, action) => action === "none"
1042
- ? null
1043
- : `${t("next.label")} · ${who}: ${t(window.EMBASSY_BOOT.semantics.nextActionCopyKeys[action])}`;
1044
- const boardNotes = [
1045
- !openInbound && !hasPair && showEdges
1046
- ? `${t("app.overview.noPair.title")} — ${t("app.overview.noPair.body")}`
1047
- : null,
1048
- data.degradedPairCopyKey === undefined
1049
- ? null
1050
- : t(data.degradedPairCopyKey),
1051
- nextActionLine(t("provider.claude"), data.exchange.claude.nextAction),
1052
- nextActionLine(t("provider.codex"), data.exchange.codex.nextAction),
1053
- ].filter((line) => line !== null);
1028
+ const hasConsentEdge = data.graph.consentEdgeCount > 0 ||
1029
+ data.graph.consentEdgeCountIsLowerBound;
1054
1030
  const showAttention = data.attention.length > 0 || data.attentionOmitted > 0;
1055
1031
  const maxPulse = data.pulse.bars.reduce((largest, bar) => Math.max(largest, bar.count), 1);
1056
1032
  const selectPulseState = React.useCallback((state) => {
@@ -1065,10 +1041,8 @@ var Embassy;
1065
1041
  React.createElement("section", { className: "section", "aria-labelledby": stripId },
1066
1042
  React.createElement("h2", { className: "mono-label section-label", id: stripId }, t("app.overview.statusStrip")),
1067
1043
  React.createElement("div", { className: "status-strip" },
1068
- React.createElement(HealthStatusCard, { label: t("app.overview.broker"), health: strip.broker }),
1069
- React.createElement(HealthStatusCard, { label: t("app.overview.claudeConn"), health: strip.claudeConnector }),
1070
- React.createElement(HealthStatusCard, { label: t("app.overview.codexConn"), health: strip.codexConnector }),
1071
- React.createElement(CompatStatusCard, { compatibility: strip.compatibility }))),
1044
+ React.createElement(HealthStatusCard, { label: t("app.overview.broker"), health: data.statusStrip.broker }),
1045
+ data.statusStrip.providers.map(({ provider, health }) => (React.createElement(HealthStatusCard, { key: provider, label: t(`provider.${provider}`), health: health }))))),
1072
1046
  React.createElement("section", { className: "section", "aria-labelledby": exchangeId },
1073
1047
  React.createElement("div", { className: "row section-label section-head" },
1074
1048
  React.createElement("h2", { className: "mono-label", id: exchangeId }, t("exchange.eyebrow")),
@@ -1080,30 +1054,12 @@ var Embassy;
1080
1054
  : "inbound.paired.badge")),
1081
1055
  React.createElement("p", null, t(openInbound
1082
1056
  ? "inbound.open.body"
1083
- : hasPair
1057
+ : hasConsentEdge
1084
1058
  ? "inbound.paired.body"
1085
1059
  : "inbound.noPair.body"))),
1086
- React.createElement("div", { className: "exchange-board" },
1087
- React.createElement(ExchangeNode, { title: t("app.overview.node.claude.title"), sub: t("app.overview.node.claude.sub"), party: data.exchange.claude, countLine: t("exchange.count.claude", {
1088
- ready: data.exchange.claude.ready,
1089
- selectable: data.exchange.claude.selectable ?? "—",
1090
- total: data.exchange.claude.total,
1091
- }) }),
1092
- showEdges ? (React.createElement("div", { className: "exchange-edges" },
1093
- React.createElement(ExchangeEdge, { direction: "out", label: t("app.overview.queueC2x"), queue: queueOut }),
1094
- React.createElement(ExchangeEdge, { direction: "in", label: t("app.overview.queueX2c"), queue: queueIn }))) : (React.createElement("div", { className: "no-pair" },
1095
- React.createElement("span", { className: "no-pair__label" }, t(openInbound
1096
- ? "inbound.open.badge"
1097
- : "app.overview.noPair.title")),
1098
- React.createElement("span", { className: "no-pair__body" }, t(openInbound
1099
- ? "inbound.open.body"
1100
- : "app.overview.noPair.body")))),
1101
- React.createElement(ExchangeNode, { title: t("app.overview.node.codex.title"), sub: t("app.overview.node.codex.sub"), party: data.exchange.codex, countLine: t("app.overview.count.codex", {
1102
- ready: data.exchange.codex.ready,
1103
- total: data.exchange.codex.total,
1104
- monitorOnly: data.exchange.codex.monitorOnly ?? 0,
1105
- }) })),
1106
- boardNotes.length === 0 ? null : (React.createElement("div", { className: "exchange-notes stack-sm" }, boardNotes.map((line) => (React.createElement("p", { className: "text-xs text-body-muted", key: line }, line)))))),
1060
+ React.createElement("div", { className: "exchange-board" }, data.exchange.parties.map((party) => (React.createElement(ExchangeNode, { key: party.kind, title: t(`provider.${party.kind}`), sub: party.kind, party: party, countLine: `${party.ready}/${party.total}` })))),
1061
+ React.createElement("div", { className: "exchange-edges" }, data.providerQueues.map(({ provider, queue }) => (React.createElement(ExchangeEdge, { key: provider, direction: "in", label: t(`provider.${provider}`), queue: queue })))),
1062
+ data.degradedConsentEdgeCopyKey === undefined ? null : (React.createElement("p", { className: "text-xs text-body-muted" }, t(data.degradedConsentEdgeCopyKey)))),
1107
1063
  showAttention ? (React.createElement("section", { className: "section", "aria-labelledby": attentionId },
1108
1064
  React.createElement("div", { className: "row section-label section-head" },
1109
1065
  React.createElement("h2", { className: "mono-label", id: attentionId }, t("attention.eyebrow")),
@@ -1139,18 +1095,6 @@ var Embassy;
1139
1095
  "abandoned",
1140
1096
  ];
1141
1097
  const DELIVERY_STATE_FILTERS_COVER_THE_UNION = true;
1142
- const DIRECTION_FILTERS = [
1143
- "claude_to_codex",
1144
- "codex_to_claude",
1145
- ];
1146
- const DIRECTION_COPY_KEYS = {
1147
- claude_to_codex: "direction.claudeToCodex",
1148
- codex_to_claude: "direction.codexToClaude",
1149
- };
1150
- const DIRECTION_PILL_COPY_KEYS = {
1151
- claude_to_codex: "direction.claudeToCodex",
1152
- codex_to_claude: "app.deliveries.dir.codexToClaude",
1153
- };
1154
1098
  const SEND_TO_CODEX_CMD = "embassy send-to-codex --from <alias> --to <alias>";
1155
1099
  const countFormatters = new Map();
1156
1100
  function fmtCount(locale, value) {
@@ -1273,7 +1217,9 @@ var Embassy;
1273
1217
  React.createElement("div", { className: "detail-pane__sub" },
1274
1218
  props.view.routePair,
1275
1219
  " \u00B7 ",
1276
- t(DIRECTION_COPY_KEYS[group.direction]))),
1220
+ t(`provider.${props.view.sourceProvider}`),
1221
+ " \u2192 ",
1222
+ t(`provider.${props.view.targetProvider}`))),
1277
1223
  React.createElement("div", null,
1278
1224
  React.createElement(Embassy.MonoLabel, { className: "section-label section-label--lifecycle" }, t("app.deliveries.lifecycle")),
1279
1225
  React.createElement(DeliveryLifecycle, { group: group }),
@@ -1326,8 +1272,6 @@ var Embassy;
1326
1272
  pair_removed: "watches.reason.pairRemoved",
1327
1273
  endpoint_retired: "watches.reason.endpointRetired",
1328
1274
  tracking_disabled: "watches.reason.trackingDisabled",
1329
- legacy_upgrade: "watches.reason.legacyUpgrade",
1330
- legacy_done: "watches.reason.legacyDone",
1331
1275
  };
1332
1276
  function ProgressWatchRegister(props) {
1333
1277
  const t = Embassy.useT();
@@ -1385,7 +1329,8 @@ var Embassy;
1385
1329
  const [locale] = Embassy.useLocale();
1386
1330
  const captionId = React.useId();
1387
1331
  const searchId = React.useId();
1388
- const [directionFilter, setDirectionFilter] = React.useState("all");
1332
+ const [fromProvider, setFromProvider] = React.useState("all");
1333
+ const [toProvider, setToProvider] = React.useState("all");
1389
1334
  const [stateFilter, setStateFilter] = React.useState("all");
1390
1335
  const [viewMode, setViewMode] = React.useState("byRoute");
1391
1336
  const [query, setQuery] = React.useState("");
@@ -1409,10 +1354,9 @@ var Embassy;
1409
1354
  clearPreset?.();
1410
1355
  }, [preset]);
1411
1356
  const needle = query.trim().toLowerCase();
1412
- const filtered = React.useMemo(() => groups.filter((view) => (directionFilter === "all" ||
1413
- view.group.direction === directionFilter) &&
1357
+ const filtered = React.useMemo(() => groups.filter((view) => Embassy.adapter.matchesProviderFilters(view, fromProvider, toProvider) &&
1414
1358
  (stateFilter === "all" || view.group.state === stateFilter) &&
1415
- matchesQuery(view, needle)), [groups, directionFilter, stateFilter, needle]);
1359
+ matchesQuery(view, needle)), [groups, fromProvider, toProvider, stateFilter, needle]);
1416
1360
  const pairs = React.useMemo(() => groupByRoutePair(filtered), [filtered]);
1417
1361
  const ordered = React.useMemo(() => (viewMode === "flat" ? filtered : pairs.flatMap((pair) => pair.rows)), [viewMode, filtered, pairs]);
1418
1362
  const selectedView = ordered.find((view) => view.key === selectedKey);
@@ -1483,14 +1427,19 @@ var Embassy;
1483
1427
  }))) : null),
1484
1428
  React.createElement("div", { className: "filters" },
1485
1429
  React.createElement("div", { className: "filter-group" },
1486
- React.createElement(Embassy.MonoLabel, null, t("app.deliveries.dir.label")),
1487
- React.createElement("div", { className: "pill-row", role: "group", "aria-label": t("app.deliveries.dir.label") },
1488
- React.createElement(Embassy.FilterPill, { active: directionFilter === "all", onClick: () => {
1489
- setDirectionFilter("all");
1490
- } }, t("app.deliveries.dir.all")),
1491
- DIRECTION_FILTERS.map((direction) => (React.createElement(Embassy.FilterPill, { key: direction, active: directionFilter === direction, onClick: () => {
1492
- setDirectionFilter(direction);
1493
- } }, t(DIRECTION_PILL_COPY_KEYS[direction])))))),
1430
+ React.createElement(Embassy.MonoLabel, null, t("app.deliveries.fromProvider")),
1431
+ React.createElement("div", { className: "pill-row", role: "group", "aria-label": t("app.deliveries.fromProvider") },
1432
+ React.createElement(Embassy.FilterPill, { active: fromProvider === "all", onClick: () => {
1433
+ setFromProvider("all");
1434
+ } }, t("app.deliveries.providerAll")),
1435
+ Embassy.GATEWAY_PROVIDERS.map((provider) => (React.createElement(Embassy.FilterPill, { key: provider, active: fromProvider === provider, onClick: () => {
1436
+ setFromProvider(provider);
1437
+ } }, t(`provider.${provider}`)))))),
1438
+ React.createElement("div", { className: "filter-group" },
1439
+ React.createElement(Embassy.MonoLabel, null, t("app.deliveries.toProvider")),
1440
+ React.createElement("div", { className: "pill-row", role: "group", "aria-label": t("app.deliveries.toProvider") },
1441
+ React.createElement(Embassy.FilterPill, { active: toProvider === "all", onClick: () => { setToProvider("all"); } }, t("app.deliveries.providerAll")),
1442
+ Embassy.GATEWAY_PROVIDERS.map((provider) => (React.createElement(Embassy.FilterPill, { key: provider, active: toProvider === provider, onClick: () => { setToProvider(provider); } }, t(`provider.${provider}`)))))),
1494
1443
  React.createElement("div", { className: "filter-group" },
1495
1444
  React.createElement(Embassy.MonoLabel, null, t("app.deliveries.view.label")),
1496
1445
  React.createElement("div", { className: "pill-row", role: "group", "aria-label": t("app.deliveries.view.label") },
@@ -1528,464 +1477,92 @@ var Embassy;
1528
1477
  })(Embassy || (Embassy = {}));
1529
1478
  var Embassy;
1530
1479
  (function (Embassy) {
1531
- const TOPOLOGY_ROW_HEIGHT_PX = 64;
1532
- const TOPOLOGY_PADDING_PX = 18;
1533
- const TOPOLOGY_EDGE_WIDTH_PX = 220;
1534
- const SELECT_CLAUDE_COMMAND = "embassy select-claude --alias <alias>";
1535
- const REGISTER_CODEX_COMMAND = "embassy register-codex --alias codex-<name>@<host>";
1536
- const SUCCEEDS_COMMAND = "embassy register-codex --alias <new> --succeeds <old>";
1537
- const ROUTE_COUNTER_ROWS = [
1538
- ["accepted", "diagnostics.accepted"],
1539
- ["delivered", "diagnostics.delivered"],
1540
- ["unconfirmed", "diagnostics.unconfirmed"],
1541
- ["failed", "diagnostics.failed"],
1542
- ["ambiguous", "diagnostics.ambiguous"],
1543
- ["expired", "diagnostics.expired"],
1544
- ["cancelled", "diagnostics.cancelled"],
1545
- ["abandoned", "diagnostics.abandoned"],
1546
- ["rejected", "diagnostics.rejected"],
1547
- ["bytesAccepted", "diagnostics.bytesAccepted"],
1548
- ];
1549
- const countFormatters = new Map();
1550
- function formatCount(value, locale) {
1551
- const existing = countFormatters.get(locale);
1552
- if (existing !== undefined)
1553
- return existing.format(value);
1554
- const formatter = new Intl.NumberFormat(locale);
1555
- countFormatters.set(locale, formatter);
1556
- return formatter.format(value);
1557
- }
1558
- function isReadyCodexRoute(route) {
1559
- return (route.enabled &&
1560
- route.compatibility === "compatible" &&
1561
- (route.state === "idle" || route.state === "busy"));
1562
- }
1563
- function rowIdentity(alias, host) {
1564
- return `${alias}\u0000${host}`;
1565
- }
1566
1480
  function canRequestStaleCodexRegistrationRemoval(route) {
1567
1481
  return route.provider === "codex" && route.state === "stale";
1568
1482
  }
1569
1483
  Embassy.canRequestStaleCodexRegistrationRemoval = canRequestStaleCodexRegistrationRemoval;
1570
- function topologyRowCenterY(index) {
1571
- return (TOPOLOGY_PADDING_PX +
1572
- index * TOPOLOGY_ROW_HEIGHT_PX +
1573
- TOPOLOGY_ROW_HEIGHT_PX / 2);
1574
- }
1575
- function topologyEdges(data) {
1576
- const claudeIndices = new Map(data.peers.map((peer, index) => [peer.alias, index]));
1577
- const codexIndices = new Map(data.codexRoutes.map((view, index) => [view.route.alias, index]));
1578
- const edges = [];
1579
- for (const pair of data.pairs) {
1580
- const claudeIndex = claudeIndices.get(pair.claudeAlias);
1581
- const codexIndex = codexIndices.get(pair.codexAlias);
1582
- if (claudeIndex === undefined || codexIndex === undefined)
1583
- continue;
1584
- edges.push({
1585
- claudeIndex,
1586
- codexIndex,
1587
- claudeAlias: pair.claudeAlias,
1588
- codexAlias: pair.codexAlias,
1589
- state: pair.state,
1590
- });
1591
- }
1592
- return edges;
1593
- }
1594
- function isEdgeEndpoint(edge, side, index) {
1595
- return side === "claude"
1596
- ? index === edge.claudeIndex
1597
- : index === edge.codexIndex;
1598
- }
1599
- function chipHighlight(focus, edges, side, index) {
1600
- if (focus === undefined)
1601
- return undefined;
1602
- if (focus.side === side && focus.index === index)
1603
- return "on";
1604
- if (focus.side !== side &&
1605
- edges.some((edge) => isEdgeEndpoint(edge, focus.side, focus.index) &&
1606
- isEdgeEndpoint(edge, side, index))) {
1607
- return "on";
1608
- }
1609
- return "off";
1610
- }
1611
- function edgeHighlight(focus, edge) {
1612
- if (focus === undefined)
1613
- return undefined;
1614
- return isEdgeEndpoint(edge, focus.side, focus.index) ? "on" : "off";
1615
- }
1616
- function TopologyColumn(props) {
1617
- const { side, highlightAt, onFocusChange } = props;
1618
- if (props.items.length === 0) {
1619
- return (React.createElement("div", { className: "topology__col" },
1620
- React.createElement("p", { className: "topology__empty" }, props.emptyText)));
1621
- }
1622
- return (React.createElement("div", { className: "topology__col" },
1623
- React.createElement("div", { role: "list", "aria-label": props.listLabel }, props.items.map((item, index) => (React.createElement("div", { key: item.key, role: "listitem", className: side === "claude"
1624
- ? "topo-row topo-row--left"
1625
- : "topo-row topo-row--right", onMouseEnter: () => {
1626
- onFocusChange({ side, index });
1627
- }, onMouseLeave: () => {
1628
- onFocusChange(undefined);
1629
- } },
1630
- React.createElement("span", { className: "topo-chip", "data-side": side, "data-candidate": item.candidate ? "true" : undefined, "data-highlight": highlightAt(side, index), tabIndex: 0, onFocus: () => {
1631
- onFocusChange({ side, index });
1632
- }, onBlur: () => {
1633
- onFocusChange(undefined);
1634
- } }, item.alias),
1635
- React.createElement("span", { className: "sr-only" }, item.srLabel)))))));
1636
- }
1637
- function TopologyEdgeSvg(props) {
1638
- const height = TOPOLOGY_PADDING_PX * 2 + props.rows * TOPOLOGY_ROW_HEIGHT_PX;
1639
- return (React.createElement("svg", { className: "topology__svg", width: TOPOLOGY_EDGE_WIDTH_PX, height: height, viewBox: `0 0 ${TOPOLOGY_EDGE_WIDTH_PX} ${height}`, "aria-hidden": "true", focusable: "false" }, props.edges.map((edge) => {
1640
- const highlight = edgeHighlight(props.focus, edge);
1641
- const stroke = highlight === "on"
1642
- ? props.focusSide === "codex"
1643
- ? "var(--action-blue)"
1644
- : "var(--coral-accent, var(--coral))"
1645
- : edge.state === "ready"
1646
- ? "var(--hairline)"
1647
- : "var(--warning)";
1648
- return (React.createElement("path", { key: `${edge.claudeAlias}\0${edge.codexAlias}`, fill: "none", d: `M 0 ${topologyRowCenterY(edge.claudeIndex)} C 80 ${topologyRowCenterY(edge.claudeIndex)} 140 ${topologyRowCenterY(edge.codexIndex)} ${TOPOLOGY_EDGE_WIDTH_PX} ${topologyRowCenterY(edge.codexIndex)}`, style: {
1649
- stroke,
1650
- strokeDasharray: edge.state === "ready" ? undefined : "5 4",
1651
- strokeWidth: highlight === "on" ? 2 : 1.25,
1652
- opacity: highlight === "off" ? 0.2 : 1,
1653
- } }));
1654
- })));
1655
- }
1656
- function DetailRow(props) {
1657
- return (React.createElement("p", { className: "detail-row" },
1658
- React.createElement("span", { className: "detail-label" },
1659
- props.label,
1660
- ": "),
1661
- props.children));
1662
- }
1663
- function AbsentDetail(props) {
1664
- const t = Embassy.useT();
1665
- return (React.createElement("p", { className: "detail-row" },
1666
- React.createElement("span", { className: "detail-value detail-value--mono" }, props.fields.join(" · ")),
1667
- React.createElement("span", { className: "detail-label" },
1668
- " \u2014 ",
1669
- t("app.routes.detail.absent"))));
1484
+ Embassy.canOfferConsentEdgeCandidate = (route) => route.enabled && (route.state === "idle" || route.state === "busy" || route.state === "awaiting_approval");
1485
+ function sameEdge(edge, aliases) {
1486
+ const actual = edge.endpoints.map(({ alias }) => alias);
1487
+ return aliases.every((alias) => actual.includes(alias));
1670
1488
  }
1671
- function LowerBoundBadge(props) {
1672
- const t = Embassy.useT();
1673
- return (React.createElement("span", { className: "lower-bound" }, t("app.lowerBound", { count: props.count })));
1674
- }
1675
- function AccordionRow(props) {
1676
- const t = Embassy.useT();
1677
- const baseId = React.useId();
1678
- const buttonId = `${baseId}-summary`;
1679
- const panelId = `${baseId}-panel`;
1680
- return (React.createElement("div", { className: "accordion" },
1681
- React.createElement("button", { type: "button", id: buttonId, className: "accordion__row", "aria-label": t(props.open
1682
- ? "app.routes.collapseDetails"
1683
- : "app.routes.expandDetails", { alias: props.alias }), "aria-expanded": props.open, "aria-controls": props.open ? panelId : undefined, onClick: props.onToggle },
1684
- React.createElement("span", { className: "accordion__alias" }, props.alias),
1685
- props.head,
1686
- React.createElement("span", { className: "accordion__marker", "aria-hidden": "true" }, props.open ? "−" : "+")),
1687
- props.open ? (React.createElement("div", { className: "accordion__panel", id: panelId, role: "region", "aria-labelledby": buttonId },
1688
- React.createElement("div", { className: "detail-list" }, props.children))) : null));
1689
- }
1690
- function PeerAccordionRow(props) {
1691
- const t = Embassy.useT();
1692
- const peer = props.peer;
1693
- const selectionLabel = peer.selected
1694
- ? t("status.selected")
1695
- : peer.selectable
1696
- ? t("status.available")
1697
- : t("status.notSelectable");
1698
- return (React.createElement(AccordionRow, { alias: peer.alias, open: props.open, onToggle: props.onToggle, head: React.createElement(React.Fragment, null,
1699
- peer.selected ? (React.createElement("span", { className: "status-dot", title: t("status.selected"), "aria-hidden": "true" })) : null,
1700
- React.createElement(Embassy.StateChip, { domain: "peer", state: peer.state, small: true }),
1701
- peer.selected ? (React.createElement("span", { className: "chip chip--small", "data-kind": "positive" }, selectionLabel)) : null) },
1702
- React.createElement(DetailRow, { label: t("column.state") },
1703
- React.createElement(Embassy.StateChip, { domain: "peer", state: peer.state, small: true })),
1704
- React.createElement(DetailRow, { label: t("column.compatibility") },
1705
- React.createElement(Embassy.StateChip, { domain: "compatibility", state: peer.compatibility, small: true })),
1706
- React.createElement(DetailRow, { label: t("column.validation") },
1707
- React.createElement("span", { className: "chip chip--small", "data-kind": peer.validated ? "positive" : "warning" }, t(peer.validated
1708
- ? "status.validated"
1709
- : "status.validationRejected"))),
1710
- React.createElement(DetailRow, { label: t("column.selection") },
1711
- React.createElement("span", { className: "chip chip--small", "data-kind": peer.selected ? "positive" : "inert" }, selectionLabel)),
1712
- peer.selectionGuidance === undefined ? null : (React.createElement("p", { className: "detail-row" }, t(`peer.reason.${Embassy.camelCaseToken(peer.selectionGuidance)}`))),
1713
- React.createElement(DetailRow, { label: t("column.host") },
1714
- React.createElement("span", { className: "detail-value detail-value--mono" }, peer.host)),
1715
- React.createElement(DetailRow, { label: t("column.observed") }, peer.lastSeenAt === undefined ? (t("time.unavailable")) : (React.createElement(Embassy.TimeAgo, { iso: peer.lastSeenAt }))),
1716
- peer.safeErrorCode === undefined ? null : (React.createElement(DetailRow, { label: t("column.issue") },
1717
- React.createElement("span", { className: "detail-value detail-value--mono" }, peer.safeErrorCode))),
1718
- React.createElement(AbsentDetail, { fields: ["binding", "renames", "discovery"] }),
1719
- peer.selected || peer.selectable
1720
- ? props.codexRoutes.map((view) => {
1721
- const codexAlias = view.route.alias;
1722
- const paired = props.pairs.some((pair) => pair.claudeAlias === peer.alias &&
1723
- pair.codexAlias === codexAlias);
1724
- return (React.createElement(ActionControl, { key: codexAlias, action: {
1725
- action: paired ? "unpair" : "pair",
1726
- claudeAlias: peer.alias,
1727
- codexAlias,
1728
- }, consequence: t(paired
1729
- ? "app.routes.unpairCmd.consequence"
1730
- : "app.routes.pairCmd.consequence", { claude: peer.alias, codex: codexAlias }), enabled: props.actionsEnabled, onAction: props.onAction }));
1731
- })
1732
- : null));
1733
- }
1734
- function RouteCountersTable(props) {
1735
- const t = Embassy.useT();
1736
- const [locale] = Embassy.useLocale();
1737
- return (React.createElement("details", { className: "details-block" },
1738
- React.createElement("summary", null, t("app.routes.counters")),
1739
- React.createElement("div", { className: "details-block__content" },
1740
- React.createElement("div", { className: "table-wrap" },
1741
- React.createElement("table", { className: "data-table" },
1742
- React.createElement("caption", { className: "table-caption" }, `${t("app.routes.counters")} — ${props.alias}`),
1743
- React.createElement("tbody", null, ROUTE_COUNTER_ROWS.map(([field, copyKey]) => (React.createElement("tr", { key: field },
1744
- React.createElement("th", { scope: "row" }, t(copyKey)),
1745
- React.createElement("td", { className: "cell-mono" }, formatCount(props.counters[field], locale)))))))))));
1746
- }
1747
- function CodexAccordionRow(props) {
1748
- const t = Embassy.useT();
1749
- const [locale] = Embassy.useLocale();
1750
- const route = props.view.route;
1751
- return (React.createElement(AccordionRow, { alias: route.alias, open: props.open, onToggle: props.onToggle, head: React.createElement(React.Fragment, null,
1752
- React.createElement("span", { className: "status-dot", title: t("app.routes.registered"), "aria-hidden": "true" }),
1753
- React.createElement(Embassy.StateChip, { domain: "route", state: route.state, small: true }),
1754
- props.view.monitorOnly ? (React.createElement("span", { className: "chip chip--small", "data-kind": "warning" }, t("app.routes.monitorOnly"))) : null) },
1755
- React.createElement(DetailRow, { label: t("column.state") },
1756
- React.createElement(Embassy.StateChip, { domain: "route", state: route.state, small: true })),
1757
- React.createElement(DetailRow, { label: t("column.compatibility") },
1758
- React.createElement(Embassy.StateChip, { domain: "compatibility", state: route.compatibility, small: true })),
1759
- React.createElement(DetailRow, { label: t("column.selection") },
1760
- React.createElement("span", { className: "chip chip--small", "data-kind": route.enabled ? "positive" : "inert" }, route.enabled ? t("status.enabled") : t("status.disabled"))),
1761
- React.createElement(DetailRow, { label: t("app.routes.queueDepth") },
1762
- React.createElement("span", { className: "detail-value detail-value--mono" }, formatCount(route.queueDepth, locale))),
1763
- props.view.oldestAgeMs === undefined ? null : (React.createElement(DetailRow, { label: t("app.overview.oldest") },
1764
- React.createElement("span", { className: "detail-value detail-value--mono" }, Embassy.fmtAge(props.view.oldestAgeMs)))),
1765
- props.view.monitorOnly ? (React.createElement("p", { className: "detail-row" }, t("app.routes.monitorOnlyReason"))) : null,
1766
- React.createElement(DetailRow, { label: t("column.host") },
1767
- React.createElement("span", { className: "detail-value detail-value--mono" }, route.host)),
1768
- React.createElement(DetailRow, { label: t("column.observed") }, route.lastSeenAt === undefined ? (t("time.unavailable")) : (React.createElement(Embassy.TimeAgo, { iso: route.lastSeenAt }))),
1769
- route.safeErrorCode === undefined ? null : (React.createElement(DetailRow, { label: t("column.issue") },
1770
- React.createElement("span", { className: "detail-value detail-value--mono" }, route.safeErrorCode))),
1771
- React.createElement(AbsentDetail, { fields: ["policy", "identity lock", "registered"] }),
1772
- React.createElement(RouteCountersTable, { alias: route.alias, counters: route.counters }),
1773
- canRequestStaleCodexRegistrationRemoval(route) ? (React.createElement(ActionControl, { action: {
1774
- action: "remove_stale_codex_registration",
1775
- alias: route.alias,
1776
- }, consequence: t("app.routes.removeStaleCodex.consequence", {
1777
- alias: route.alias,
1778
- }), enabled: props.actionsEnabled, onAction: props.onAction })) : null));
1779
- }
1780
- function successionScope(item, t) {
1781
- const parts = [];
1782
- if (item.provider !== undefined)
1783
- parts.push(t(`provider.${item.provider}`));
1784
- if (item.alias !== undefined)
1785
- parts.push(item.alias);
1786
- if (item.host !== undefined)
1787
- parts.push(item.host);
1788
- if (item.code !== undefined)
1789
- parts.push(item.code);
1790
- return parts.join(" · ");
1791
- }
1792
- function SuccessionCard(props) {
1793
- const t = Embassy.useT();
1794
- const item = props.view.item;
1795
- const scope = successionScope(item, t);
1796
- return (React.createElement("article", { className: "succession-card" },
1797
- React.createElement("div", { className: "succession-card__head" },
1798
- React.createElement("div", { className: "chip-row" },
1799
- React.createElement(Embassy.MonoLabel, null, "succession"),
1800
- React.createElement(Embassy.StateChip, { domain: "severity", state: item.severity, small: true })),
1801
- item.timestamp === undefined ? null : (React.createElement(Embassy.TimeAgo, { iso: item.timestamp }))),
1802
- React.createElement("h3", { className: "card__title succession-card__title" }, t(`guidance.${props.view.guidanceKey}.title`)),
1803
- React.createElement("p", { className: "card__body" }, t(`guidance.${props.view.guidanceKey}.body`)),
1804
- scope === "" ? null : (React.createElement("p", { className: "attention-item__scope" },
1805
- t("attention.scope"),
1806
- ": ",
1807
- scope)),
1808
- React.createElement("p", { className: "card__body" }, t(`guidance.${props.view.guidanceKey}.action`)),
1809
- React.createElement(AbsentDetail, { fields: ["predecessor", "successor", "drain outcome"] }),
1810
- React.createElement("p", { className: "succession-note" }, t("app.routes.successions.note")),
1811
- React.createElement(Embassy.CopyCmd, { cmd: props.view.command })));
1812
- }
1813
- function actionLabelKey(action) {
1814
- switch (action.action) {
1815
- case "pair":
1816
- return "live.action.pair";
1817
- case "unpair":
1818
- return "live.action.unpair";
1819
- case "remove_stale_codex_registration":
1820
- return "live.action.removeStaleCodexRegistration";
1821
- case "refresh_dashboard":
1822
- return "live.action.refresh";
1823
- }
1824
- }
1825
- function ActionControl(props) {
1489
+ function ActionButton(props) {
1826
1490
  const t = Embassy.useT();
1827
1491
  const [confirming, setConfirming] = React.useState(false);
1828
1492
  const [pending, setPending] = React.useState(false);
1829
- const [result, setResult] = React.useState(undefined);
1830
- const actionIdentity = (() => {
1831
- switch (props.action.action) {
1832
- case "refresh_dashboard":
1833
- return props.action.action;
1834
- case "remove_stale_codex_registration":
1835
- return `${props.action.action}:${props.action.alias}`;
1836
- case "pair":
1837
- case "unpair":
1838
- return `${props.action.action}:${props.action.claudeAlias}:${props.action.codexAlias}`;
1839
- }
1840
- })();
1841
- React.useEffect(() => {
1842
- setConfirming(false);
1843
- setPending(false);
1844
- setResult(undefined);
1845
- }, [actionIdentity]);
1846
- const baseLabel = t(actionLabelKey(props.action));
1847
- const label = (() => {
1848
- switch (props.action.action) {
1849
- case "refresh_dashboard":
1850
- return baseLabel;
1851
- case "remove_stale_codex_registration":
1852
- return `${baseLabel}: ${props.action.alias}`;
1853
- case "pair":
1854
- case "unpair":
1855
- return `${baseLabel}: ${props.action.claudeAlias} ↔ ${props.action.codexAlias}`;
1856
- }
1857
- })();
1858
- const confirm = async () => {
1859
- if (!props.enabled || pending)
1860
- return;
1493
+ const [result, setResult] = React.useState();
1494
+ const run = () => {
1861
1495
  setPending(true);
1862
- setResult(undefined);
1863
- const next = await props.onAction(props.action);
1864
- setPending(false);
1865
- setConfirming(false);
1866
- setResult(next);
1496
+ props.onAction(props.action).then((next) => {
1497
+ setResult(next);
1498
+ setPending(false);
1499
+ setConfirming(false);
1500
+ });
1867
1501
  };
1868
- return (React.createElement("section", { className: "action-card", "aria-label": label },
1869
- React.createElement("h3", { className: "action-card__title" }, label),
1870
- React.createElement("p", { className: "action-card__consequence" }, props.consequence),
1871
- !props.enabled ? (React.createElement("p", { className: "action-card__status", role: "status" }, t("live.action.requiresConnected"))) : null,
1872
- result === undefined ? null : (React.createElement("p", { className: "action-card__status", "data-action-result": result.ok ? "success" : "failure", role: "status" }, t(result.ok ? "live.action.succeeded" : "live.action.failed", {
1873
- code: result.code,
1874
- }))),
1875
- confirming ? (React.createElement("div", { className: "action-card__buttons", role: "group", "aria-label": label },
1876
- React.createElement("button", { type: "button", className: "btn btn--primary", disabled: !props.enabled || pending, onClick: () => {
1877
- void confirm();
1878
- } }, pending ? t("live.action.pending") : t("live.action.confirm")),
1879
- React.createElement("button", { type: "button", className: "btn btn--ghost", disabled: pending, onClick: () => {
1880
- setConfirming(false);
1881
- } }, t("live.action.cancel")))) : (React.createElement("button", { type: "button", className: "btn btn--ghost", disabled: !props.enabled, onClick: () => {
1882
- setResult(undefined);
1883
- setConfirming(true);
1884
- } }, label))));
1502
+ if (confirming)
1503
+ return React.createElement("span", { className: "row-baseline" },
1504
+ React.createElement("button", { type: "button", disabled: pending, onClick: run }, pending ? t("live.action.pending") : t("live.action.confirm")),
1505
+ React.createElement("button", { type: "button", disabled: pending, onClick: () => { setConfirming(false); } }, t("live.action.cancel")));
1506
+ return React.createElement("span", { className: "stack-sm" },
1507
+ React.createElement("button", { type: "button", disabled: !props.enabled, onClick: () => { setResult(undefined); setConfirming(true); } }, props.label),
1508
+ result === undefined ? null : React.createElement("span", { className: "footnote" }, t(result.ok ? "live.action.succeeded" : "live.action.failed", { code: result.code })));
1509
+ }
1510
+ function edgeLabel(edge, t) {
1511
+ const labels = edge.endpoints.map(({ provider, alias }) => t("app.routes.consentEndpoint", { provider: t(`provider.${provider}`), alias }));
1512
+ return t("app.routes.consentEdge", { left: labels[0] ?? "", right: labels[1] ?? "" });
1885
1513
  }
1886
1514
  function RoutesTab(props) {
1887
1515
  const t = Embassy.useT();
1888
- const data = props.data;
1889
- const openInbound = data.inboundMode === "open";
1890
- const [focus, setFocus] = React.useState(undefined);
1891
- const [openPeer, setOpenPeer] = React.useState(undefined);
1892
- const [openRoute, setOpenRoute] = React.useState(undefined);
1893
- const edges = topologyEdges(data);
1894
- const hasPair = data.graph.pairCount > 0 || data.graph.pairCountIsLowerBound;
1895
- const highlightAt = (side, index) => chipHighlight(focus, edges, side, index);
1896
- const claudeItems = data.peers.map((peer, index) => ({
1897
- key: `${rowIdentity(peer.alias, peer.host)}|${index}`,
1898
- alias: peer.alias,
1899
- candidate: !data.pairs.some((pair) => pair.claudeAlias === peer.alias),
1900
- srLabel: data.pairs.some((pair) => pair.claudeAlias === peer.alias)
1901
- ? t("status.selected")
1902
- : peer.selectable
1903
- ? t("status.available")
1904
- : t("status.notSelectable"),
1905
- }));
1906
- const codexItems = data.codexRoutes.map((view, index) => ({
1907
- key: `${rowIdentity(view.route.alias, view.route.host)}|${index}`,
1908
- alias: view.route.alias,
1909
- candidate: !data.pairs.some((pair) => pair.codexAlias === view.route.alias),
1910
- srLabel: t(`route.${Embassy.camelCaseToken(view.route.state)}`),
1911
- }));
1912
- return (React.createElement("div", { className: "tab-panel" },
1913
- React.createElement("section", { className: "section", "aria-label": t("app.routes.topology") },
1914
- React.createElement(Embassy.MonoLabel, { className: "section-label" }, t("app.routes.topology")),
1915
- React.createElement("div", { className: "inbound-policy", "data-inbound-mode": data.inboundMode },
1916
- React.createElement("span", { className: "chip chip--small", "data-kind": openInbound ? "warning" : "inert" }, t(openInbound
1917
- ? "inbound.open.badge"
1918
- : "inbound.paired.badge")),
1919
- React.createElement("p", null, t(openInbound
1920
- ? "inbound.open.body"
1921
- : hasPair
1922
- ? "inbound.paired.body"
1923
- : "inbound.noPair.body"))),
1924
- React.createElement("div", { className: "topology" },
1925
- React.createElement("div", { className: "topology__heads" },
1926
- React.createElement(Embassy.MonoLabel, { className: "topology__head--claude" }, t("provider.claude")),
1927
- React.createElement(Embassy.MonoLabel, { className: "topology__head--codex" }, t("provider.codex"))),
1928
- React.createElement("div", { className: "topology__cols" },
1929
- React.createElement(TopologyColumn, { side: "claude", items: claudeItems, listLabel: t("app.routes.candidates"), emptyText: t("app.routes.noPeers"), highlightAt: highlightAt, onFocusChange: setFocus }),
1930
- React.createElement(TopologyEdgeSvg, { rows: Math.max(claudeItems.length, codexItems.length), edges: edges, focus: focus, focusSide: focus === undefined ? undefined : focus.side }),
1931
- React.createElement(TopologyColumn, { side: "codex", items: codexItems, listLabel: t("app.routes.codexRoutes"), emptyText: t("app.routes.noCodex"), highlightAt: highlightAt, onFocusChange: setFocus })),
1932
- !hasPair ? (React.createElement("p", { className: "topology__empty" }, t(openInbound
1933
- ? "inbound.open.body"
1934
- : "app.routes.noPairInline"))) : (React.createElement("ul", { className: "topology__edge-list", "aria-label": t("app.routes.pairs") }, data.pairs.map((pair) => (React.createElement("li", { key: `${pair.claudeAlias}\0${pair.codexAlias}` },
1935
- t("app.routes.pairDescription", {
1936
- claude: pair.claudeAlias,
1937
- codex: pair.codexAlias,
1938
- }),
1516
+ const { data } = props;
1517
+ const candidates = [];
1518
+ for (let left = 0; left < data.routes.length; left += 1) {
1519
+ for (let right = left + 1; right < data.routes.length; right += 1) {
1520
+ const a = data.routes[left]?.route;
1521
+ const b = data.routes[right]?.route;
1522
+ if (a === undefined || b === undefined || !Embassy.canOfferConsentEdgeCandidate(a) || !Embassy.canOfferConsentEdgeCandidate(b) || a.provider === b.provider || a.host !== b.host)
1523
+ continue;
1524
+ if (!data.consentEdges.some((edge) => sameEdge(edge, [a.alias, b.alias])))
1525
+ candidates.push([a, b]);
1526
+ }
1527
+ }
1528
+ return React.createElement("div", { className: "tab-panel" },
1529
+ React.createElement("section", { className: "section" },
1530
+ React.createElement("h2", { className: "mono-label section-label" }, t("app.routes.topology")),
1531
+ React.createElement("p", null, t("app.routes.pairSummary", { ready: data.graph.readyConsentEdgeCount, total: data.graph.consentEdgeCount })),
1532
+ React.createElement("ul", { className: "pair-list" }, data.consentEdges.map((edge) => {
1533
+ const aliases = edge.endpoints.map(({ alias }) => alias);
1534
+ return React.createElement("li", { key: aliases.join("\0") },
1535
+ React.createElement("code", null, edgeLabel(edge, t)),
1939
1536
  " ",
1940
- React.createElement(Embassy.StateChip, { domain: "route", state: pair.state === "ready" ? "idle" : "stale", label: pair.state === "ready"
1941
- ? t("status.ready")
1942
- : t(pair.state === "degraded"
1943
- ? "app.routes.pairState.degraded"
1944
- : "app.routes.pairState.unavailable"), small: true }),
1945
- pair.state === "ready" ? null : (React.createElement("span", { className: "text-body-muted" }, t(pair.state === "degraded"
1946
- ? "app.routes.pairDegradedReason"
1947
- : "app.routes.pairUnavailableReason")))))))),
1948
- data.pairsOmitted > 0 ? (React.createElement("p", { className: "topology__empty" }, t("app.omitted.pairs", { count: data.pairsOmitted }))) : null),
1949
- React.createElement("section", { className: "section section__sub", "aria-label": t("live.action.sectionTitle") },
1950
- React.createElement("div", { className: "row-baseline section-label" },
1951
- React.createElement(Embassy.MonoLabel, null, t("live.action.sectionTitle"))),
1952
- React.createElement("p", { className: "section-teaching" }, t("live.action.scope")),
1953
- React.createElement("div", { className: "action-panel" },
1954
- React.createElement(ActionControl, { action: { action: "refresh_dashboard" }, consequence: t("app.routes.refreshCmd"), enabled: props.actionsEnabled, onAction: props.onAction })))),
1955
- React.createElement("section", { className: "section", "aria-label": t("app.routes.claudeSessions") },
1956
- React.createElement("div", { className: "row-baseline row-baseline--split section-label" },
1957
- React.createElement(Embassy.MonoLabel, null, t("app.routes.claudeSessions")),
1958
- data.peersOmitted > 0 ? (React.createElement(LowerBoundBadge, { count: data.peers.length })) : null),
1959
- data.peers.length === 0 ? (React.createElement("div", { className: "empty-state" },
1960
- React.createElement("p", { className: "empty-state__text" }, t("app.routes.noPeers")),
1961
- React.createElement(Embassy.CopyCmd, { cmd: SELECT_CLAUDE_COMMAND }))) : (React.createElement("div", null, data.peers.map((peer, index) => {
1962
- const identity = rowIdentity(peer.alias, peer.host);
1963
- return (React.createElement(PeerAccordionRow, { key: `${identity}|${index}`, peer: peer, open: openPeer === identity, pairs: data.pairs, codexRoutes: data.codexRoutes, actionsEnabled: props.actionsEnabled, onAction: props.onAction, onToggle: () => {
1964
- setOpenPeer(openPeer === identity ? undefined : identity);
1965
- } }));
1966
- }))),
1967
- React.createElement(Embassy.Rule, null)),
1968
- React.createElement("section", { className: "section", "aria-label": t("app.routes.codexRoutes") },
1969
- React.createElement("div", { className: "row-baseline row-baseline--split section-label" },
1970
- React.createElement(Embassy.MonoLabel, null, t("app.routes.codexRoutes")),
1971
- data.routesOmitted > 0 ? (React.createElement(LowerBoundBadge, { count: data.codexRoutes.length })) : null),
1972
- data.codexRoutes.length === 0 ? (React.createElement("div", { className: "empty-state" },
1973
- React.createElement("p", { className: "empty-state__text" }, t("app.routes.noCodex")))) : (React.createElement("div", null, data.codexRoutes.map((view, index) => {
1974
- const identity = rowIdentity(view.route.alias, view.route.host);
1975
- return (React.createElement(CodexAccordionRow, { key: `${identity}|${index}`, view: view, open: openRoute === identity, actionsEnabled: props.actionsEnabled, onAction: props.onAction, onToggle: () => {
1976
- setOpenRoute(openRoute === identity ? undefined : identity);
1977
- } }));
1978
- }))),
1979
- React.createElement(Embassy.Rule, null),
1980
- React.createElement("div", { className: "stack routes-register" },
1981
- React.createElement("p", { className: "text-xs text-body-muted" }, t("app.routes.registerHint")),
1982
- React.createElement(Embassy.CopyCmd, { cmd: REGISTER_CODEX_COMMAND }))),
1983
- React.createElement("section", { className: "section", "aria-label": t("app.routes.successions") },
1984
- React.createElement(Embassy.MonoLabel, { className: "section-label" }, t("app.routes.successions")),
1985
- data.successions.length === 0 ? (React.createElement("div", { className: "empty-state" },
1986
- React.createElement("p", { className: "empty-state__text" }, t("app.routes.successions.empty")),
1987
- React.createElement("p", { className: "succession-note" }, t("app.routes.successions.note")),
1988
- React.createElement(Embassy.CopyCmd, { cmd: SUCCEEDS_COMMAND }))) : (React.createElement("div", { className: "stack-lg" }, data.successions.map((view, index) => (React.createElement(SuccessionCard, { key: `${view.guidanceKey}|${view.item.alias ?? ""}|${index}`, view: view }))))))));
1537
+ React.createElement(Embassy.StateChip, { domain: "route", state: edge.state === "ready" ? "idle" : "stale", small: true }),
1538
+ React.createElement(ActionButton, { action: { action: "unpair", aliases }, label: t("live.action.unpair"), enabled: props.actionsEnabled, onAction: props.onAction }));
1539
+ })),
1540
+ data.consentEdgesOmitted > 0 ? React.createElement("p", { className: "footnote" }, t("app.omitted.pairs", { count: data.consentEdgesOmitted })) : null),
1541
+ Embassy.GATEWAY_PROVIDERS.map((provider) => {
1542
+ const routes = data.routes.filter((view) => view.route.provider === provider);
1543
+ return React.createElement("section", { className: "section", key: provider, "aria-label": t(`provider.${provider}`) },
1544
+ React.createElement("h2", { className: "mono-label section-label" }, t(`provider.${provider}`)),
1545
+ React.createElement("ul", null, routes.map(({ route, oldestAgeMs }) => React.createElement("li", { key: `${route.alias}\0${route.host}` },
1546
+ React.createElement("code", null, route.alias),
1547
+ " \u00B7 ",
1548
+ React.createElement(Embassy.StateChip, { domain: "route", state: route.state, small: true }),
1549
+ " \u00B7 ",
1550
+ t("app.routes.queueDepth"),
1551
+ ": ",
1552
+ route.queueDepth,
1553
+ oldestAgeMs === undefined ? "" : ` · ${Embassy.fmtAge(oldestAgeMs)}`,
1554
+ canRequestStaleCodexRegistrationRemoval(route) ? React.createElement(ActionButton, { action: { action: "remove_stale_codex_registration", alias: route.alias }, label: t("live.action.removeStaleCodexRegistration"), enabled: props.actionsEnabled, onAction: props.onAction }) : null))),
1555
+ React.createElement("p", { className: "footnote" }, t("app.routes.unpairedProvider", { provider: t(`provider.${provider}`), count: data.graph.unpairedReadyByProvider[provider] })));
1556
+ }),
1557
+ React.createElement("section", { className: "section" },
1558
+ React.createElement("h2", { className: "mono-label section-label" }, t("app.routes.candidates")),
1559
+ React.createElement("ul", null, candidates.map(([left, right]) => React.createElement("li", { key: `${left.alias}\0${right.alias}` },
1560
+ React.createElement("code", null,
1561
+ left.alias,
1562
+ " \u2194 ",
1563
+ right.alias),
1564
+ React.createElement(ActionButton, { action: { action: "pair", aliases: [left.alias, right.alias] }, label: t("live.action.pair"), enabled: props.actionsEnabled, onAction: props.onAction })))),
1565
+ React.createElement(ActionButton, { action: { action: "refresh_dashboard" }, label: t("live.action.refresh"), enabled: props.actionsEnabled, onAction: props.onAction })));
1989
1566
  }
1990
1567
  Embassy.RoutesTab = RoutesTab;
1991
1568
  })(Embassy || (Embassy = {}));
@@ -2078,7 +1655,7 @@ var Embassy;
2078
1655
  function alertScope(item, t) {
2079
1656
  const parts = [];
2080
1657
  if (item.provider !== undefined) {
2081
- parts.push(t(item.provider === "claude" ? "provider.claude" : "provider.codex"));
1658
+ parts.push(t(`provider.${item.provider}`));
2082
1659
  }
2083
1660
  if (item.alias !== undefined)
2084
1661
  parts.push(item.alias);
@@ -2188,7 +1765,7 @@ var Embassy;
2188
1765
  var Embassy;
2189
1766
  (function (Embassy) {
2190
1767
  const DIAGNOSTICS_ABSENT_FIELD = "—";
2191
- const DIAGNOSTICS_CONNECTOR_COLUMNS = 8;
1768
+ const DIAGNOSTICS_CONNECTOR_COLUMNS = 7;
2192
1769
  const diagnosticsNumberFormatters = new Map();
2193
1770
  function diagnosticsNumberFormatter(locale) {
2194
1771
  const existing = diagnosticsNumberFormatters.get(locale);
@@ -2235,7 +1812,6 @@ var Embassy;
2235
1812
  React.createElement("th", { scope: "col" }, t("app.diag.col.protocol")),
2236
1813
  React.createElement("th", { scope: "col" }, t("app.diag.col.version")),
2237
1814
  React.createElement("th", { scope: "col" }, t("diagnostics.health")),
2238
- React.createElement("th", { scope: "col" }, t("app.diag.col.compat")),
2239
1815
  React.createElement("th", { scope: "col" }, t("diagnostics.registry.title")),
2240
1816
  React.createElement("th", { scope: "col" }, t("column.issue")))),
2241
1817
  React.createElement("tbody", null, connectors.length === 0 ? (React.createElement("tr", null,
@@ -2249,16 +1825,12 @@ var Embassy;
2249
1825
  ? "diagnostics.registry.state.emptySinceBoot"
2250
1826
  : "diagnostics.registry.state.noParseableRecordSinceBoot";
2251
1827
  return (React.createElement("tr", { key: `${connector.provider}|${connector.host}|${index}` },
2252
- React.createElement("th", { scope: "row" }, connector.provider === "claude"
2253
- ? t("provider.claude")
2254
- : t("provider.codex")),
1828
+ React.createElement("th", { scope: "row" }, t(`provider.${connector.provider}`)),
2255
1829
  React.createElement("td", { className: "cell-mono" }, connector.host),
2256
1830
  React.createElement("td", { className: "cell-mono" }, connector.protocol ?? DIAGNOSTICS_ABSENT_FIELD),
2257
1831
  React.createElement("td", { className: "cell-mono" }, connector.protocolVersion ?? DIAGNOSTICS_ABSENT_FIELD),
2258
1832
  React.createElement("td", null,
2259
1833
  React.createElement(Embassy.StateChip, { domain: "health", state: connector.health, small: true })),
2260
- React.createElement("td", null,
2261
- React.createElement(Embassy.StateChip, { domain: "compatibility", state: connector.compatibility, small: true })),
2262
1834
  React.createElement("td", null, observation === undefined || stateKey === undefined ? (DIAGNOSTICS_ABSENT_FIELD) : (React.createElement("div", { className: "stack-sm" },
2263
1835
  React.createElement("span", null, t(stateKey)),
2264
1836
  React.createElement("span", { className: "cell-note" },
@@ -2285,36 +1857,6 @@ var Embassy;
2285
1857
  React.createElement("td", { className: "cell-mono" }, connector.safeErrorCode ?? DIAGNOSTICS_ABSENT_FIELD)));
2286
1858
  }))))));
2287
1859
  }
2288
- function DiagnosticsCompatibilityTable(props) {
2289
- const t = Embassy.useT();
2290
- return (React.createElement("div", { className: "table-wrap" },
2291
- React.createElement("table", { className: "data-table" },
2292
- React.createElement("caption", { className: "sr-only" }, t("diagnostics.compatibilityChecks.caption")),
2293
- React.createElement("thead", null,
2294
- React.createElement("tr", null,
2295
- React.createElement("th", { scope: "col" }, t("app.diag.col.provider")),
2296
- React.createElement("th", { scope: "col" }, t("diagnostics.version")),
2297
- React.createElement("th", { scope: "col" }, t("diagnostics.testedVersion")),
2298
- React.createElement("th", { scope: "col" }, t("diagnostics.supportedMajor")),
2299
- React.createElement("th", { scope: "col" }, t("diagnostics.tier")),
2300
- React.createElement("th", { scope: "col" }, t("diagnostics.checkedAt")),
2301
- React.createElement("th", { scope: "col" }, t("diagnostics.failure")),
2302
- React.createElement("th", { scope: "col" }, t("column.issue")))),
2303
- React.createElement("tbody", null, props.checks.length === 0 ? (React.createElement("tr", null,
2304
- React.createElement("td", { colSpan: 8 }, t("diagnostics.compatibilityChecks.empty")))) : (props.checks.map((check) => (React.createElement("tr", { key: check.surface },
2305
- React.createElement("th", { scope: "row" }, t(`provider.${check.surface}`)),
2306
- "notDetected" in check ? (React.createElement("td", { colSpan: 7 }, t("compatibilityTier.notDetected"))) : (React.createElement(React.Fragment, null,
2307
- React.createElement("td", { className: "cell-mono" }, check.version),
2308
- React.createElement("td", { className: "cell-mono" }, check.testedVersion ?? DIAGNOSTICS_ABSENT_FIELD),
2309
- React.createElement("td", { className: "cell-mono" }, check.supportedMajor ?? DIAGNOSTICS_ABSENT_FIELD),
2310
- React.createElement("td", null, t(check.tier === "schema_attested" && check.writesCovered
2311
- ? "compatibilityTier.schema_attested.writesCovered"
2312
- : `compatibilityTier.${check.tier}`)),
2313
- React.createElement("td", null,
2314
- React.createElement(Embassy.TimeAgo, { iso: check.checkedAt })),
2315
- React.createElement("td", { className: "cell-mono" }, check.failure ?? DIAGNOSTICS_ABSENT_FIELD),
2316
- React.createElement("td", { className: "cell-mono" }, check.safeErrorCode ?? DIAGNOSTICS_ABSENT_FIELD)))))))))));
2317
- }
2318
1860
  function DiagnosticsCounterTable(props) {
2319
1861
  return (React.createElement("div", { className: "table-wrap counters-list" },
2320
1862
  React.createElement("table", { className: "data-table data-table--counters" },
@@ -2457,6 +1999,12 @@ var Embassy;
2457
1999
  count: formatDiagnosticsCount(omissions.routes, locale),
2458
2000
  }),
2459
2001
  },
2002
+ {
2003
+ field: "consentEdges",
2004
+ text: t("diagnostics.omissions.consentEdges", {
2005
+ count: formatDiagnosticsCount(omissions.consentEdges, locale),
2006
+ }),
2007
+ },
2460
2008
  {
2461
2009
  field: "upstreamMessageEvents",
2462
2010
  text: t("diagnostics.omissions.upstreamMessageEvents", {
@@ -2491,6 +2039,7 @@ var Embassy;
2491
2039
  const nothingOmitted = omissions.connectors === 0 &&
2492
2040
  omissions.availablePeers === 0 &&
2493
2041
  omissions.routes === 0 &&
2042
+ omissions.consentEdges === 0 &&
2494
2043
  omissions.upstreamMessageEvents === 0 &&
2495
2044
  omissions.messageGroups === 0 &&
2496
2045
  omissions.messageEvents === 0 &&
@@ -2577,10 +2126,6 @@ var Embassy;
2577
2126
  React.createElement(DiagnosticsConnectorTable, { connectors: data.connectors }),
2578
2127
  React.createElement("p", { className: "footnote" }, t("app.diag.versions.rangeAbsent")))),
2579
2128
  React.createElement("div", { className: "grid-2" },
2580
- React.createElement("section", { className: "card", "aria-labelledby": "provider-compatibility-title" },
2581
- React.createElement("div", { className: "card__head" },
2582
- React.createElement("h3", { className: "card__title", id: "provider-compatibility-title" }, t("app.diag.providerCompatibility.title"))),
2583
- React.createElement(DiagnosticsCompatibilityTable, { checks: data.compatibilityChecks })),
2584
2129
  React.createElement(Embassy.AbsentFeature, { title: t("app.diag.lease.title"), body: t("app.diag.lease.absent"), cmd: "embassy status" })),
2585
2130
  React.createElement("section", { className: "section", "aria-labelledby": limitsHeadingId },
2586
2131
  React.createElement("h2", { className: "mono-label section-label", id: limitsHeadingId }, t("app.diag.limits")),