agent-embassy 1.4.0 → 1.5.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 (82) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/CONTRIBUTING.md +61 -6
  3. package/README.md +6 -5
  4. package/README.zh-CN.md +4 -4
  5. package/SECURITY.md +128 -24
  6. package/dist/src/gateway/claude-peer.d.ts +8 -5
  7. package/dist/src/gateway/claude-peer.js +81 -36
  8. package/dist/src/gateway/claude-peer.js.map +1 -1
  9. package/dist/src/gateway/claude-runtime.d.ts +4 -0
  10. package/dist/src/gateway/claude-runtime.js +50 -39
  11. package/dist/src/gateway/claude-runtime.js.map +1 -1
  12. package/dist/src/gateway/cli-copy.d.ts +1 -1
  13. package/dist/src/gateway/cli-copy.en.d.ts +1 -1
  14. package/dist/src/gateway/cli-copy.en.js +1 -1
  15. package/dist/src/gateway/cli-copy.en.js.map +1 -1
  16. package/dist/src/gateway/cli-copy.js +1 -1
  17. package/dist/src/gateway/cli-copy.js.map +1 -1
  18. package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
  19. package/dist/src/gateway/cli-copy.zh-CN.js +1 -1
  20. package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
  21. package/dist/src/gateway/cli.d.ts +1 -1
  22. package/dist/src/gateway/cli.js +3 -7
  23. package/dist/src/gateway/cli.js.map +1 -1
  24. package/dist/src/gateway/codex-app-server.d.ts +2 -1
  25. package/dist/src/gateway/codex-app-server.js +1 -1
  26. package/dist/src/gateway/codex-app-server.js.map +1 -1
  27. package/dist/src/gateway/codex-local-transport.d.ts +10 -6
  28. package/dist/src/gateway/codex-local-transport.js +101 -56
  29. package/dist/src/gateway/codex-local-transport.js.map +1 -1
  30. package/dist/src/gateway/compatibility.d.ts +11 -0
  31. package/dist/src/gateway/compatibility.js +104 -22
  32. package/dist/src/gateway/compatibility.js.map +1 -1
  33. package/dist/src/gateway/control.js +28 -30
  34. package/dist/src/gateway/control.js.map +1 -1
  35. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  36. package/dist/src/gateway/dashboard-copy.en.d.ts +36 -17
  37. package/dist/src/gateway/dashboard-copy.en.js +50 -31
  38. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  39. package/dist/src/gateway/dashboard-copy.js +36 -17
  40. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  41. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +36 -17
  42. package/dist/src/gateway/dashboard-copy.zh-CN.js +50 -31
  43. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  44. package/dist/src/gateway/dashboard-model.d.ts +176 -8
  45. package/dist/src/gateway/dashboard-model.js +420 -70
  46. package/dist/src/gateway/dashboard-model.js.map +1 -1
  47. package/dist/src/gateway/dashboard.js +48 -135
  48. package/dist/src/gateway/dashboard.js.map +1 -1
  49. package/dist/src/gateway/live-dashboard-app/app.js +148 -247
  50. package/dist/src/gateway/live-dashboard-assets.js +2 -1
  51. package/dist/src/gateway/live-dashboard-assets.js.map +1 -1
  52. package/dist/src/gateway/live-dashboard-stream.d.ts +2 -2
  53. package/dist/src/gateway/live-dashboard-stream.js +2 -2
  54. package/dist/src/gateway/live-dashboard-stream.js.map +1 -1
  55. package/dist/src/gateway/progress-watch-machine.d.ts +50 -64
  56. package/dist/src/gateway/progress-watch-machine.js +42 -133
  57. package/dist/src/gateway/progress-watch-machine.js.map +1 -1
  58. package/dist/src/gateway/provenance-envelope.d.ts +2 -0
  59. package/dist/src/gateway/provenance-envelope.js +13 -3
  60. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  61. package/dist/src/gateway/providers.d.ts +69 -15
  62. package/dist/src/gateway/providers.js +456 -109
  63. package/dist/src/gateway/providers.js.map +1 -1
  64. package/dist/src/gateway/server.d.ts +8 -5
  65. package/dist/src/gateway/server.js +94 -13
  66. package/dist/src/gateway/server.js.map +1 -1
  67. package/dist/src/gateway/service.d.ts +25 -1
  68. package/dist/src/gateway/service.js +252 -69
  69. package/dist/src/gateway/service.js.map +1 -1
  70. package/dist/src/gateway/store.d.ts +23 -28
  71. package/dist/src/gateway/store.js +479 -467
  72. package/dist/src/gateway/store.js.map +1 -1
  73. package/dist/src/gateway/types.d.ts +38 -11
  74. package/dist/src/gateway/types.js +141 -3
  75. package/dist/src/gateway/types.js.map +1 -1
  76. package/docs/CONFIGURATION.md +8 -8
  77. package/docs/CONFIGURATION.zh-CN.md +8 -8
  78. package/docs/DASHBOARD.md +29 -6
  79. package/docs/DASHBOARD.zh-CN.md +1 -1
  80. package/docs/GATEWAY-ARCHITECTURE.md +143 -57
  81. package/package.json +1 -1
  82. package/skills/embassy-peer/SKILL.md +2 -2
@@ -91,203 +91,94 @@ var Embassy;
91
91
  "inert",
92
92
  "unknown",
93
93
  ];
94
- function tableLookup(table, state) {
95
- return Object.prototype.hasOwnProperty.call(table, state)
96
- ? table[state]
97
- : "unknown";
98
- }
99
- const DELIVERY_CHIP_KINDS = {
100
- queued: "progress",
101
- dispatching: "progress",
102
- transport_written: "progress",
103
- held: "progress",
104
- duplicate: "inert",
105
- delivered: "positive",
106
- unconfirmed: "indeterminate",
107
- ambiguous: "indeterminate",
108
- failed: "failure",
109
- expired: "failure",
110
- rejected: "warning",
111
- cancelled: "inert",
112
- abandoned: "inert",
113
- };
114
- const ROUTE_CHIP_KINDS = {
115
- idle: "progress",
116
- busy: "active",
117
- awaiting_approval: "warning",
118
- stale: "failure",
119
- offline: "failure",
120
- incompatible: "failure",
121
- disabled: "inert",
122
- };
123
- const PEER_CHIP_KINDS = {
124
- idle: "progress",
125
- busy: "active",
126
- awaiting_approval: "warning",
127
- offline: "inert",
128
- incompatible: "failure",
129
- };
130
- const HEALTH_CHIP_KINDS = {
131
- healthy: "positive",
132
- connecting: "progress",
133
- degraded: "warning",
134
- offline: "failure",
135
- incompatible: "failure",
136
- };
137
- const COMPATIBILITY_CHIP_KINDS = {
138
- compatible: "positive",
139
- unknown: "inert",
140
- expired: "warning",
141
- incompatible: "failure",
142
- };
143
- const OVERALL_CHIP_KINDS = {
144
- ready: "positive",
145
- setup: "progress",
146
- attention: "failure",
147
- };
148
- const PARTY_CHIP_KINDS = {
149
- ready: "positive",
150
- busy: "active",
151
- waiting: "warning",
152
- missing: "inert",
153
- attention: "failure",
154
- };
155
- const SEVERITY_CHIP_KINDS = {
156
- info: "active",
157
- warning: "warning",
158
- error: "failure",
159
- };
160
- const CONNECTION_CHIP_KINDS = {
161
- connected: "positive",
162
- connecting: "progress",
163
- paused: "inert",
164
- unavailable: "warning",
165
- capacity: "warning",
166
- disconnected: "warning",
167
- stopped: "warning",
168
- };
94
+ function tableValue(table, key) {
95
+ return Object.prototype.hasOwnProperty.call(table, key)
96
+ ? table[key]
97
+ : undefined;
98
+ }
99
+ function presentation(domain, state) {
100
+ const table = window.EMBASSY_BOOT.semantics.statePresentation[domain];
101
+ return tableValue(table, state)?.chip ?? "unknown";
102
+ }
103
+ function deliveryOverride(table, state, discriminator) {
104
+ if (discriminator === undefined)
105
+ return undefined;
106
+ const byState = tableValue(table, state);
107
+ return byState === undefined
108
+ ? undefined
109
+ : tableValue(byState, discriminator);
110
+ }
169
111
  function chipKindFor(state, direction, safeErrorCode) {
170
- if (state === "rejected" && safeErrorCode === "SENDER_NOT_PAIRED") {
171
- return "inert";
172
- }
173
- if (state === "delivered" && direction === "codex_to_claude") {
174
- return "qualified";
175
- }
176
- return tableLookup(DELIVERY_CHIP_KINDS, state);
112
+ const semantics = window.EMBASSY_BOOT.semantics;
113
+ return (deliveryOverride(semantics.deliveryChipBySafeErrorCode, state, safeErrorCode) ??
114
+ deliveryOverride(semantics.deliveryChipByDirection, state, direction) ??
115
+ presentation("delivery", state));
177
116
  }
178
117
  Embassy.chipKindFor = chipKindFor;
179
118
  function routeChipKind(state) {
180
- return tableLookup(ROUTE_CHIP_KINDS, state);
119
+ return presentation("route", state);
181
120
  }
182
121
  Embassy.routeChipKind = routeChipKind;
183
122
  function peerChipKind(state) {
184
- return tableLookup(PEER_CHIP_KINDS, state);
123
+ return presentation("peer", state);
185
124
  }
186
125
  Embassy.peerChipKind = peerChipKind;
187
126
  function healthChipKind(state) {
188
- return tableLookup(HEALTH_CHIP_KINDS, state);
127
+ return presentation("health", state);
189
128
  }
190
129
  Embassy.healthChipKind = healthChipKind;
191
130
  function compatibilityChipKind(state) {
192
- return tableLookup(COMPATIBILITY_CHIP_KINDS, state);
131
+ return presentation("compatibility", state);
193
132
  }
194
133
  Embassy.compatibilityChipKind = compatibilityChipKind;
195
134
  function overallChipKind(state) {
196
- return tableLookup(OVERALL_CHIP_KINDS, state);
135
+ return presentation("overall", state);
197
136
  }
198
137
  Embassy.overallChipKind = overallChipKind;
199
138
  function partyChipKind(state) {
200
- return tableLookup(PARTY_CHIP_KINDS, state);
139
+ return presentation("party", state);
201
140
  }
202
141
  Embassy.partyChipKind = partyChipKind;
203
142
  function severityChipKind(state) {
204
- return tableLookup(SEVERITY_CHIP_KINDS, state);
143
+ return presentation("severity", state);
205
144
  }
206
145
  Embassy.severityChipKind = severityChipKind;
207
146
  function connectionChipKind(state) {
208
- return tableLookup(CONNECTION_CHIP_KINDS, state);
147
+ return presentation("connection", state);
209
148
  }
210
149
  Embassy.connectionChipKind = connectionChipKind;
211
150
  function chipKindByDomain(domain, state, direction) {
212
- switch (domain) {
213
- case "delivery":
214
- return chipKindFor(state, direction);
215
- case "route":
216
- return routeChipKind(state);
217
- case "peer":
218
- return peerChipKind(state);
219
- case "health":
220
- return healthChipKind(state);
221
- case "compatibility":
222
- return compatibilityChipKind(state);
223
- case "overall":
224
- return overallChipKind(state);
225
- case "party":
226
- return partyChipKind(state);
227
- case "severity":
228
- return severityChipKind(state);
229
- case "connection":
230
- return connectionChipKind(state);
231
- }
151
+ return domain === "delivery"
152
+ ? chipKindFor(state, direction)
153
+ : presentation(domain, state);
232
154
  }
233
155
  Embassy.chipKindByDomain = chipKindByDomain;
234
156
  function camelCaseToken(token) {
235
157
  return token.replace(/_([a-z])/g, (_match, character) => character.toUpperCase());
236
158
  }
237
159
  Embassy.camelCaseToken = camelCaseToken;
238
- function deliveryMeaningKey(state, safeErrorCode, direction) {
239
- switch (state) {
240
- case "queued":
241
- return "activity.meaning.queued";
242
- case "dispatching":
243
- return "activity.meaning.dispatching";
244
- case "transport_written":
245
- return "activity.meaning.transportWritten";
246
- case "held":
247
- return "activity.meaning.held";
248
- case "duplicate":
249
- return "activity.meaning.duplicate";
250
- case "delivered":
251
- return direction === "codex_to_claude"
252
- ? "activity.meaning.delivered.codexToClaude"
253
- : direction === "claude_to_codex"
254
- ? "activity.meaning.delivered.claudeToCodex"
255
- : "activity.meaning.delivered";
256
- case "unconfirmed":
257
- return "activity.meaning.unconfirmed";
258
- case "ambiguous":
259
- return "activity.meaning.ambiguous";
260
- case "failed":
261
- return "activity.meaning.failed";
262
- case "expired":
263
- return "activity.meaning.expired";
264
- case "rejected":
265
- return safeErrorCode === "SENDER_NOT_PAIRED"
266
- ? "activity.meaning.senderNotPaired"
267
- : "activity.meaning.rejected";
268
- case "cancelled":
269
- return "activity.meaning.cancelled";
270
- case "abandoned":
271
- switch (safeErrorCode) {
272
- case "CONTROLLER_RESTARTED":
273
- return "activity.meaning.abandoned.controllerRestarted";
274
- case "TRANSIENT_BODY_UNAVAILABLE":
275
- return "activity.meaning.abandoned.transientBody";
276
- case "ROUTE_UNREGISTERED":
277
- case "MESSAGE_EXPIRED":
278
- return "activity.meaning.abandoned.routeTerminated";
279
- default:
280
- return "activity.meaning.abandoned.generic";
281
- }
282
- default:
283
- return "activity.meaning.other";
160
+ function deliveryMeaningKey(state, direction, safeErrorCode) {
161
+ const semantics = window.EMBASSY_BOOT.semantics;
162
+ if (state === "rejected" && safeErrorCode === "SENDER_NOT_PAIRED") {
163
+ return semantics.deliveryMeaningBySafeErrorCode.SENDER_NOT_PAIRED;
164
+ }
165
+ if (state === "delivered" && direction !== undefined) {
166
+ return semantics.deliveryMeaningByDirection[direction];
167
+ }
168
+ if (state === "abandoned" && safeErrorCode !== undefined) {
169
+ const byCode = semantics.deliveryMeaningBySafeErrorCode;
170
+ return tableValue(byCode, safeErrorCode) ??
171
+ semantics.deliveryMeaningKeys.abandoned;
284
172
  }
173
+ const byState = semantics.deliveryMeaningKeys;
174
+ return tableValue(byState, state) ?? "activity.meaning.other";
285
175
  }
286
176
  Embassy.deliveryMeaningKey = deliveryMeaningKey;
287
177
  function meaningKeyFor(domain, state, safeErrorCode, direction) {
178
+ if (domain === "delivery") {
179
+ return deliveryMeaningKey(state, direction, safeErrorCode);
180
+ }
288
181
  switch (domain) {
289
- case "delivery":
290
- return deliveryMeaningKey(state, safeErrorCode, direction);
291
182
  case "route":
292
183
  return `route.meaning.${camelCaseToken(state)}`;
293
184
  case "peer":
@@ -505,45 +396,14 @@ var Embassy;
505
396
  return `${group.direction}|${group.sourceAlias}|${group.targetAlias}|${suffix}`;
506
397
  }
507
398
  Embassy.deliveryGroupKey = deliveryGroupKey;
508
- const GUIDANCE_COPY_KEYS = {
509
- reobserve_claude: "reobserveClaude",
510
- reobserve_codex: "reobserveCodex",
511
- codex_reactivation_required: "codexReactivationRequired",
512
- consent_edge_unavailable: "consentEdgeUnavailable",
513
- claude_not_observed: "claudeNotObserved",
514
- codex_stale: "codexStale",
515
- connector_offline: "connectorOffline",
516
- route_stale: "routeStale",
517
- queue_stalled: "queueStalled",
518
- recipient_waiting_input: "recipientWaitingInput",
519
- unconfirmed: "unconfirmed",
520
- degraded: "degraded",
521
- codex_succession_busy: "codexSuccessionBusy",
522
- codex_succession_recovery: "codexSuccessionRecovery",
523
- progress_watch: "progressWatch",
524
- generic: "generic",
525
- };
526
399
  function guidanceCopyKey(guidance) {
527
- return GUIDANCE_COPY_KEYS[guidance];
400
+ return window.EMBASSY_BOOT.semantics.guidanceCopyKeys[guidance];
528
401
  }
529
402
  Embassy.guidanceCopyKey = guidanceCopyKey;
530
403
  function attentionCommand(item) {
531
- switch (item.guidance) {
532
- case "reobserve_claude":
533
- case "claude_not_observed":
534
- return `embassy select-claude --alias ${item.alias ?? "<alias>"}`;
535
- case "reobserve_codex":
536
- case "codex_stale":
537
- case "codex_reactivation_required":
538
- return `embassy register-codex --alias ${item.alias ?? "<alias>"}`;
539
- case "consent_edge_unavailable":
540
- return "embassy refresh-dashboard";
541
- case "codex_succession_busy":
542
- case "codex_succession_recovery":
543
- return `embassy register-codex --alias <new> --succeeds ${item.alias ?? "<old>"}`;
544
- default:
545
- return "embassy status";
546
- }
404
+ const semantics = window.EMBASSY_BOOT.semantics;
405
+ const fallbacks = semantics.attentionCommandFallbacks;
406
+ return semantics.attentionCommands[item.guidance].replaceAll("{alias}", item.alias ?? fallbacks[item.guidance] ?? "<alias>");
547
407
  }
548
408
  Embassy.attentionCommand = attentionCommand;
549
409
  function attentionViews(model) {
@@ -587,13 +447,7 @@ var Embassy;
587
447
  codexConnector: worstConnectorHealth(model, "codex"),
588
448
  compatibility: worstCompatibility(model),
589
449
  },
590
- exchange: {
591
- ...model.exchange,
592
- codex: {
593
- ...model.exchange.codex,
594
- monitorOnly: model.routes.filter((route) => route.provider === "codex" && isMonitorOnly(route)).length,
595
- },
596
- },
450
+ exchange: model.exchange,
597
451
  queueClaudeToCodex: queueSplit(model, "codex", nowMs),
598
452
  queueCodexToClaude: queueSplit(model, "claude", nowMs),
599
453
  graph: model.graph,
@@ -1059,16 +913,6 @@ var Embassy;
1059
913
  const PULSE_BAR_BASE_PX = 6;
1060
914
  const PULSE_BAR_RANGE_PX = 38;
1061
915
  const QUEUE_DEPTH_COMMAND = "EMBASSY_MAX_QUEUE_MESSAGES=<n> embassy serve";
1062
- const NEXT_ACTION_COPY_KEYS = {
1063
- discover_claude: "next.discoverClaude",
1064
- select_claude: "next.selectClaude",
1065
- pair_routes: "next.pairRoutes",
1066
- restore_claude: "next.restoreClaude",
1067
- repair_claude_inventory: "next.repairClaude",
1068
- register_codex: "next.registerCodex",
1069
- restore_codex: "next.restoreCodex",
1070
- none: "next.none",
1071
- };
1072
916
  function LowerBound(props) {
1073
917
  const t = Embassy.useT();
1074
918
  const sentence = t("app.lowerBound", { count: props.count });
@@ -1146,10 +990,18 @@ var Embassy;
1146
990
  parts.push(item.code);
1147
991
  return parts;
1148
992
  }
993
+ function attentionQueueDepthLine(item, t, locale) {
994
+ return item.queueDepth === undefined
995
+ ? undefined
996
+ : `${t("app.routes.queueDepth")}: ${item.queueDepth.toLocaleString(locale)}`;
997
+ }
998
+ Embassy.attentionQueueDepthLine = attentionQueueDepthLine;
1149
999
  function AttentionItem(props) {
1150
1000
  const t = Embassy.useT();
1001
+ const [locale] = Embassy.useLocale();
1151
1002
  const { item, guidanceKey, command } = props.view;
1152
1003
  const scope = attentionScopeParts(item, t).join(" · ");
1004
+ const queueDepthLine = attentionQueueDepthLine(item, t, locale);
1153
1005
  return (React.createElement("div", { className: "attention-item" },
1154
1006
  React.createElement("div", { className: "attention-item__head" },
1155
1007
  React.createElement(Embassy.StateChip, { domain: "severity", state: item.severity, small: true }),
@@ -1159,6 +1011,7 @@ var Embassy;
1159
1011
  React.createElement("p", { className: "attention-item__body" }, t(`guidance.${guidanceKey}.action`, {
1160
1012
  alias: item.alias ?? "<alias>",
1161
1013
  })),
1014
+ queueDepthLine === undefined ? null : (React.createElement("p", { className: "attention-item__body" }, queueDepthLine)),
1162
1015
  scope === "" ? null : (React.createElement("div", { className: "attention-item__scope" }, `${t("attention.scope")}: ${scope}`)),
1163
1016
  React.createElement("div", { className: "attention-item__action" },
1164
1017
  React.createElement(Embassy.CopyCmd, { cmd: command })),
@@ -1187,7 +1040,7 @@ var Embassy;
1187
1040
  const showEdges = hasPair || queueOut.depth > 0 || queueIn.depth > 0;
1188
1041
  const nextActionLine = (who, action) => action === "none"
1189
1042
  ? null
1190
- : `${t("next.label")} · ${who}: ${t(NEXT_ACTION_COPY_KEYS[action])}`;
1043
+ : `${t("next.label")} · ${who}: ${t(window.EMBASSY_BOOT.semantics.nextActionCopyKeys[action])}`;
1191
1044
  const boardNotes = [
1192
1045
  !openInbound && !hasPair && showEdges
1193
1046
  ? `${t("app.overview.noPair.title")} — ${t("app.overview.noPair.body")}`
@@ -1397,7 +1250,7 @@ var Embassy;
1397
1250
  React.createElement(Embassy.TimeAgo, { iso: event.timestamp }),
1398
1251
  React.createElement("span", { className: "lifecycle-abs" }, Embassy.fmtAbs(event.timestamp, locale))))),
1399
1252
  noteParts.length === 0 ? null : (React.createElement("div", { className: "lifecycle-note" }, noteParts.join(" · "))),
1400
- React.createElement("div", { className: "lifecycle-meaning" }, t(Embassy.deliveryMeaningKey(event.state, event.safeErrorCode, props.group.direction))))));
1253
+ React.createElement("div", { className: "lifecycle-meaning" }, t(Embassy.deliveryMeaningKey(event.state, props.group.direction, event.safeErrorCode))))));
1401
1254
  })));
1402
1255
  }
1403
1256
  function DeliveryDetail(props) {
@@ -1456,16 +1309,25 @@ var Embassy;
1456
1309
  }
1457
1310
  const WATCH_EVENT_COPY_KEYS = {
1458
1311
  opened: "watches.event.opened",
1459
- nudge: "watches.event.nudge",
1460
- worker_reported_complete: "watches.event.workerReportedComplete",
1461
- capability_degraded: "watches.event.capabilityDegraded",
1462
- conversation_rebound: "watches.event.conversationRebound",
1463
1312
  replaced: "watches.event.replaced",
1464
- done: "watches.event.done",
1465
- unresponsive: "watches.event.unresponsive",
1466
- endpoint_retired: "watches.event.endpointRetired",
1467
- pair_removed: "watches.event.pairRemoved",
1468
- disabled: "watches.event.disabled",
1313
+ settled: "watches.event.settled",
1314
+ };
1315
+ const WATCH_ACTOR_COPY_KEYS = {
1316
+ owner: "watches.actor.owner",
1317
+ worker: "watches.actor.worker",
1318
+ operator: "watches.actor.operator",
1319
+ gateway: "watches.actor.gateway",
1320
+ unknown: "watches.actor.unknown",
1321
+ };
1322
+ const WATCH_REASON_COPY_KEYS = {
1323
+ done: "watches.reason.done",
1324
+ untracked: "watches.reason.untracked",
1325
+ idle_timeout: "watches.reason.idleTimeout",
1326
+ pair_removed: "watches.reason.pairRemoved",
1327
+ endpoint_retired: "watches.reason.endpointRetired",
1328
+ tracking_disabled: "watches.reason.trackingDisabled",
1329
+ legacy_upgrade: "watches.reason.legacyUpgrade",
1330
+ legacy_done: "watches.reason.legacyDone",
1469
1331
  };
1470
1332
  function ProgressWatchRegister(props) {
1471
1333
  const t = Embassy.useT();
@@ -1477,16 +1339,11 @@ var Embassy;
1477
1339
  React.createElement("h2", { id: "watch-register-title" }, t("watches.title"))),
1478
1340
  React.createElement("span", { className: "mono text-muted" }, fmtCount(locale, props.watches.length))),
1479
1341
  React.createElement("p", { className: "footnote" }, t("watches.note")),
1480
- props.watches.length === 0 ? (React.createElement("p", { className: "watch-register__empty" }, t("watches.empty"))) : (React.createElement("div", { className: "watch-grid" }, props.watches.map((watch) => (React.createElement("article", { className: "watch-card", "data-phase": watch.phase, key: `${watch.ownerAlias}|${watch.workerAlias}|${watch.conversationIdSuffix}` },
1342
+ props.watches.length === 0 ? (React.createElement("p", { className: "watch-register__empty" }, t("watches.empty"))) : (React.createElement("div", { className: "watch-grid" }, props.watches.map((watch) => (React.createElement("article", { className: "watch-card", key: `${watch.ownerAlias}|${watch.workerAlias}|${watch.conversationIdSuffix}` },
1481
1343
  React.createElement("div", { className: "watch-card__head" },
1482
1344
  React.createElement("code", null,
1483
1345
  "\u2026",
1484
- watch.conversationIdSuffix),
1485
- React.createElement(Embassy.StateChip, { domain: "severity", state: watch.phase === "episode" ? "warning" : "info", label: t(watch.phase === "episode"
1486
- ? "watches.phase.episode"
1487
- : "watches.phase.quiet"), note: t(watch.phase === "episode"
1488
- ? "watches.phase.episode"
1489
- : "watches.phase.quiet") })),
1346
+ watch.conversationIdSuffix)),
1490
1347
  React.createElement("strong", null,
1491
1348
  watch.ownerAlias,
1492
1349
  " \u2192 ",
@@ -1502,10 +1359,7 @@ var Embassy;
1502
1359
  React.createElement(Embassy.TimeAgo, { iso: watch.nextActionAt }))),
1503
1360
  React.createElement("div", null,
1504
1361
  React.createElement("dt", null, t("watches.column.nudges")),
1505
- React.createElement("dd", null, fmtCount(locale, watch.nudgeCount))),
1506
- React.createElement("div", null,
1507
- React.createElement("dt", null, t("watches.column.capability")),
1508
- React.createElement("dd", null, t(watch.capability === "route" ? "watches.capability.route" : "watches.capability.conversation"))))))))),
1362
+ React.createElement("dd", null, fmtCount(locale, watch.nudgeCount))))))))),
1509
1363
  props.events.length === 0 ? null : (React.createElement("details", { className: "watch-history" },
1510
1364
  React.createElement("summary", null, t("watches.history.title")),
1511
1365
  React.createElement("ol", null, props.events.map((event) => (React.createElement("li", { key: event.sequence },
@@ -1515,8 +1369,16 @@ var Embassy;
1515
1369
  "\u2026",
1516
1370
  event.conversationIdSuffix),
1517
1371
  " \u00B7 ",
1372
+ t(WATCH_ACTOR_COPY_KEYS[event.actor]),
1373
+ event.actor === "owner" ? React.createElement(React.Fragment, null,
1374
+ " ",
1375
+ React.createElement("code", null, event.ownerAlias)) : null,
1376
+ event.actor === "worker" ? React.createElement(React.Fragment, null,
1377
+ " ",
1378
+ React.createElement("code", null, event.workerAlias)) : null,
1379
+ " · ",
1518
1380
  t(WATCH_EVENT_COPY_KEYS[event.kind]),
1519
- event.nudgeNumber === undefined ? "" : ` #${event.nudgeNumber}`))))))));
1381
+ event.reason === undefined ? "" : ` · ${t(WATCH_REASON_COPY_KEYS[event.reason])}`))))))));
1520
1382
  }
1521
1383
  function DeliveriesTab(props) {
1522
1384
  const t = Embassy.useT();
@@ -2326,7 +2188,7 @@ var Embassy;
2326
2188
  var Embassy;
2327
2189
  (function (Embassy) {
2328
2190
  const DIAGNOSTICS_ABSENT_FIELD = "—";
2329
- const DIAGNOSTICS_CONNECTOR_COLUMNS = 7;
2191
+ const DIAGNOSTICS_CONNECTOR_COLUMNS = 8;
2330
2192
  const diagnosticsNumberFormatters = new Map();
2331
2193
  function diagnosticsNumberFormatter(locale) {
2332
2194
  const existing = diagnosticsNumberFormatters.get(locale);
@@ -2361,6 +2223,7 @@ var Embassy;
2361
2223
  }
2362
2224
  function DiagnosticsConnectorTable(props) {
2363
2225
  const t = Embassy.useT();
2226
+ const [locale] = Embassy.useLocale();
2364
2227
  const { connectors } = props;
2365
2228
  return (React.createElement("div", { className: "table-wrap" },
2366
2229
  React.createElement("table", { className: "data-table" },
@@ -2373,20 +2236,54 @@ var Embassy;
2373
2236
  React.createElement("th", { scope: "col" }, t("app.diag.col.version")),
2374
2237
  React.createElement("th", { scope: "col" }, t("diagnostics.health")),
2375
2238
  React.createElement("th", { scope: "col" }, t("app.diag.col.compat")),
2239
+ React.createElement("th", { scope: "col" }, t("diagnostics.registry.title")),
2376
2240
  React.createElement("th", { scope: "col" }, t("column.issue")))),
2377
2241
  React.createElement("tbody", null, connectors.length === 0 ? (React.createElement("tr", null,
2378
- React.createElement("td", { colSpan: DIAGNOSTICS_CONNECTOR_COLUMNS }, t("diagnostics.connectors.empty")))) : (connectors.map((connector, index) => (React.createElement("tr", { key: `${connector.provider}|${connector.host}|${index}` },
2379
- React.createElement("th", { scope: "row" }, connector.provider === "claude"
2380
- ? t("provider.claude")
2381
- : t("provider.codex")),
2382
- React.createElement("td", { className: "cell-mono" }, connector.host),
2383
- React.createElement("td", { className: "cell-mono" }, connector.protocol ?? DIAGNOSTICS_ABSENT_FIELD),
2384
- React.createElement("td", { className: "cell-mono" }, connector.protocolVersion ?? DIAGNOSTICS_ABSENT_FIELD),
2385
- React.createElement("td", null,
2386
- React.createElement(Embassy.StateChip, { domain: "health", state: connector.health, small: true })),
2387
- React.createElement("td", null,
2388
- React.createElement(Embassy.StateChip, { domain: "compatibility", state: connector.compatibility, small: true })),
2389
- React.createElement("td", { className: "cell-mono" }, connector.safeErrorCode ?? DIAGNOSTICS_ABSENT_FIELD)))))))));
2242
+ React.createElement("td", { colSpan: DIAGNOSTICS_CONNECTOR_COLUMNS }, t("diagnostics.connectors.empty")))) : (connectors.map((connector, index) => {
2243
+ const observation = connector.registry;
2244
+ const stateKey = observation === undefined
2245
+ ? undefined
2246
+ : observation.parseableRecordSeenSinceBoot
2247
+ ? "diagnostics.registry.state.parseableRecordObserved"
2248
+ : observation.entriesScanned === 0
2249
+ ? "diagnostics.registry.state.emptySinceBoot"
2250
+ : "diagnostics.registry.state.noParseableRecordSinceBoot";
2251
+ 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")),
2255
+ React.createElement("td", { className: "cell-mono" }, connector.host),
2256
+ React.createElement("td", { className: "cell-mono" }, connector.protocol ?? DIAGNOSTICS_ABSENT_FIELD),
2257
+ React.createElement("td", { className: "cell-mono" }, connector.protocolVersion ?? DIAGNOSTICS_ABSENT_FIELD),
2258
+ React.createElement("td", null,
2259
+ 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
+ React.createElement("td", null, observation === undefined || stateKey === undefined ? (DIAGNOSTICS_ABSENT_FIELD) : (React.createElement("div", { className: "stack-sm" },
2263
+ React.createElement("span", null, t(stateKey)),
2264
+ React.createElement("span", { className: "cell-note" },
2265
+ t("diagnostics.registry.entriesScanned"),
2266
+ ": ",
2267
+ formatDiagnosticsCount(observation.entriesScanned, locale),
2268
+ " \u00B7 ",
2269
+ t("diagnostics.registry.parseableRecords"),
2270
+ ": ",
2271
+ formatDiagnosticsCount(observation.parseableRecords, locale)),
2272
+ React.createElement("span", { className: "cell-note" },
2273
+ t("diagnostics.registry.rejected"),
2274
+ ": ",
2275
+ observation.rejected.length === 0
2276
+ ? t("diagnostics.registry.rejectedNone")
2277
+ : observation.rejected.map((row, rejectionIndex) => (React.createElement(React.Fragment, { key: row.safeErrorCode },
2278
+ rejectionIndex === 0 ? null : " · ",
2279
+ React.createElement("code", null, row.safeErrorCode),
2280
+ " \u00D7 ",
2281
+ formatDiagnosticsCount(row.count, locale))))),
2282
+ observation.rejectedCodesOmitted === 0 ? null : (React.createElement("span", { className: "cell-note" }, t("diagnostics.registry.rejectedCodesOmitted", {
2283
+ count: formatDiagnosticsCount(observation.rejectedCodesOmitted, locale),
2284
+ })))))),
2285
+ React.createElement("td", { className: "cell-mono" }, connector.safeErrorCode ?? DIAGNOSTICS_ABSENT_FIELD)));
2286
+ }))))));
2390
2287
  }
2391
2288
  function DiagnosticsCompatibilityTable(props) {
2392
2289
  const t = Embassy.useT();
@@ -2397,16 +2294,20 @@ var Embassy;
2397
2294
  React.createElement("tr", null,
2398
2295
  React.createElement("th", { scope: "col" }, t("app.diag.col.provider")),
2399
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")),
2400
2299
  React.createElement("th", { scope: "col" }, t("diagnostics.tier")),
2401
2300
  React.createElement("th", { scope: "col" }, t("diagnostics.checkedAt")),
2402
2301
  React.createElement("th", { scope: "col" }, t("diagnostics.failure")),
2403
2302
  React.createElement("th", { scope: "col" }, t("column.issue")))),
2404
2303
  React.createElement("tbody", null, props.checks.length === 0 ? (React.createElement("tr", null,
2405
- React.createElement("td", { colSpan: 6 }, t("diagnostics.compatibilityChecks.empty")))) : (props.checks.map((check) => (React.createElement("tr", { key: check.surface },
2304
+ React.createElement("td", { colSpan: 8 }, t("diagnostics.compatibilityChecks.empty")))) : (props.checks.map((check) => (React.createElement("tr", { key: check.surface },
2406
2305
  React.createElement("th", { scope: "row" }, check.surface === "claude"
2407
2306
  ? t("provider.claude")
2408
2307
  : t("provider.codex")),
2409
2308
  React.createElement("td", { className: "cell-mono" }, check.version),
2309
+ React.createElement("td", { className: "cell-mono" }, check.testedVersion),
2310
+ React.createElement("td", { className: "cell-mono" }, check.supportedMajor),
2410
2311
  React.createElement("td", null, t(`compatibilityTier.${check.tier}`)),
2411
2312
  React.createElement("td", null,
2412
2313
  React.createElement(Embassy.TimeAgo, { iso: check.checkedAt })),
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { BridgeError } from "../errors.js";
3
3
  import { assertDashboardLocale, getDashboardCopy, } from "./dashboard-copy.js";
4
+ import { DASHBOARD_SEMANTICS } from "./dashboard-model.js";
4
5
  const APP_JAVASCRIPT_CANDIDATES = [
5
6
  "./live-dashboard-app/app.js",
6
7
  "../../dist/src/gateway/live-dashboard-app/app.js",
@@ -56,7 +57,7 @@ function client(locale) {
56
57
  "zh-CN": getDashboardCopy("zh-CN"),
57
58
  };
58
59
  return `"use strict";
59
- window.EMBASSY_BOOT=Object.freeze({locale:${JSON.stringify(locale)},copy:Object.freeze({en:Object.freeze(${JSON.stringify(copies.en)}),"zh-CN":Object.freeze(${JSON.stringify(copies["zh-CN"])})})});
60
+ window.EMBASSY_BOOT=Object.freeze({locale:${JSON.stringify(locale)},copy:Object.freeze({en:Object.freeze(${JSON.stringify(copies.en)}),"zh-CN":Object.freeze(${JSON.stringify(copies["zh-CN"])})}),semantics:Object.freeze(${JSON.stringify(DASHBOARD_SEMANTICS)})});
60
61
  `;
61
62
  }
62
63
  export function renderLiveDashboardAssets(locale) {
@@ -1 +1 @@
1
- {"version":3,"file":"live-dashboard-assets.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAW7B,MAAM,yBAAyB,GAAsB;IACnD,6BAA6B;IAC7B,kDAAkD;CACnD,CAAC;AAEF,MAAM,uBAAuB,GAAsB;IACjD,sDAAsD;IACtD,mDAAmD;CACpD,CAAC;AAEF,MAAM,2BAA2B,GAAsB;IACrD,0DAA0D;IAC1D,uDAAuD;CACxD,CAAC;AAEF,MAAM,sBAAsB,GAAsB;IAChD,wCAAwC;IACxC,qCAAqC;CACtC,CAAC;AAEF,SAAS,gBAAgB,CAAC,UAA6B;IACrD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,WAAW,CACnB,8BAA8B,EAC9B,0DAA0D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CACpH,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,MAAuB;IACpC,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO;cACK,MAAM;;;SAGX,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;;;;;;;YAO3B,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,2BAA2B,CAAC;AACzE,CAAC;AAED,SAAS,MAAM,CAAC,MAAuB;IACrC,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC;QAC1B,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;KACnC,CAAC;IACF,OAAO;4CACmC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,yCAAyC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CAC7L,CAAC;AACF,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAuB;IAEvB,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;QAChC,UAAU,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;QACpD,aAAa,EAAE,gBAAgB,CAAC,yBAAyB,CAAC;QAC1D,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;QAChE,wBAAwB,EAAE,gBAAgB,CAAC,2BAA2B,CAAC;KACxE,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"live-dashboard-assets.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAW3D,MAAM,yBAAyB,GAAsB;IACnD,6BAA6B;IAC7B,kDAAkD;CACnD,CAAC;AAEF,MAAM,uBAAuB,GAAsB;IACjD,sDAAsD;IACtD,mDAAmD;CACpD,CAAC;AAEF,MAAM,2BAA2B,GAAsB;IACrD,0DAA0D;IAC1D,uDAAuD;CACxD,CAAC;AAEF,MAAM,sBAAsB,GAAsB;IAChD,wCAAwC;IACxC,qCAAqC;CACtC,CAAC;AAEF,SAAS,gBAAgB,CAAC,UAA6B;IACrD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,WAAW,CACnB,8BAA8B,EAC9B,0DAA0D,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CACpH,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,KAAK,CAAC,MAAuB;IACpC,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO;cACK,MAAM;;;SAGX,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;;;;;;;YAO3B,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,2BAA2B,CAAC;AACzE,CAAC;AAED,SAAS,MAAM,CAAC,MAAuB;IACrC,MAAM,MAAM,GAAG;QACb,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC;QAC1B,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;KACnC,CAAC;IACF,OAAO;4CACmC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,yCAAyC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,+BAA+B,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC;CAC/P,CAAC;AACF,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAAuB;IAEvB,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC;QAChC,UAAU,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;QACpD,aAAa,EAAE,gBAAgB,CAAC,yBAAyB,CAAC;QAC1D,qBAAqB,EAAE,gBAAgB,CAAC,uBAAuB,CAAC;QAChE,wBAAwB,EAAE,gBAAgB,CAAC,2BAA2B,CAAC;KACxE,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type DashboardViewModel } from "./dashboard-model.js";
1
+ import { type LiveDashboardViewModel } from "./dashboard-model.js";
2
2
  import type { GatewayPublicSnapshot } from "./types.js";
3
3
  export type LiveDashboardSnapshotRevision = string | number;
4
4
  export type LiveDashboardObservation = Readonly<{
@@ -24,7 +24,7 @@ export type LiveDashboardStreamEvent = Readonly<{
24
24
  streamRevision: number;
25
25
  snapshotRevision: LiveDashboardSnapshotRevision;
26
26
  reset: boolean;
27
- model: DashboardViewModel;
27
+ model: LiveDashboardViewModel;
28
28
  }>;
29
29
  export type LiveDashboardStreamHub = Readonly<{
30
30
  add(writer: LiveDashboardStreamWriter): Readonly<{
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { buildDashboardViewModel, } from "./dashboard-model.js";
2
+ import { buildLiveDashboardViewModel, } from "./dashboard-model.js";
3
3
  import { LIVE_DASHBOARD_LIMITS } from "./live-dashboard-protocol.js";
4
4
  export const defaultLiveDashboardClock = {
5
5
  now: Date.now,
@@ -135,7 +135,7 @@ export function createLiveDashboardStreamHub(options) {
135
135
  if (stopped)
136
136
  return undefined;
137
137
  const nextRevision = normalizeRevision(observed.snapshotRevision);
138
- const model = buildDashboardViewModel(observed.snapshot);
138
+ const model = buildLiveDashboardViewModel(observed.snapshot);
139
139
  const nextFingerprint = fingerprint(model);
140
140
  const changed = latest?.fingerprint !== nextFingerprint;
141
141
  const reset = observerUnavailable ||