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.
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +61 -6
- package/README.md +6 -5
- package/README.zh-CN.md +4 -4
- package/SECURITY.md +128 -24
- package/dist/src/gateway/claude-peer.d.ts +8 -5
- package/dist/src/gateway/claude-peer.js +81 -36
- package/dist/src/gateway/claude-peer.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +4 -0
- package/dist/src/gateway/claude-runtime.js +50 -39
- package/dist/src/gateway/claude-runtime.js.map +1 -1
- package/dist/src/gateway/cli-copy.d.ts +1 -1
- package/dist/src/gateway/cli-copy.en.d.ts +1 -1
- package/dist/src/gateway/cli-copy.en.js +1 -1
- package/dist/src/gateway/cli-copy.en.js.map +1 -1
- package/dist/src/gateway/cli-copy.js +1 -1
- package/dist/src/gateway/cli-copy.js.map +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.js +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/cli.d.ts +1 -1
- package/dist/src/gateway/cli.js +3 -7
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +2 -1
- package/dist/src/gateway/codex-app-server.js +1 -1
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-local-transport.d.ts +10 -6
- package/dist/src/gateway/codex-local-transport.js +101 -56
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/compatibility.d.ts +11 -0
- package/dist/src/gateway/compatibility.js +104 -22
- package/dist/src/gateway/compatibility.js.map +1 -1
- package/dist/src/gateway/control.js +28 -30
- package/dist/src/gateway/control.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.d.ts +1 -1
- package/dist/src/gateway/dashboard-copy.en.d.ts +36 -17
- package/dist/src/gateway/dashboard-copy.en.js +50 -31
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +36 -17
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +36 -17
- package/dist/src/gateway/dashboard-copy.zh-CN.js +50 -31
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +176 -8
- package/dist/src/gateway/dashboard-model.js +420 -70
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.js +48 -135
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +148 -247
- package/dist/src/gateway/live-dashboard-assets.js +2 -1
- package/dist/src/gateway/live-dashboard-assets.js.map +1 -1
- package/dist/src/gateway/live-dashboard-stream.d.ts +2 -2
- package/dist/src/gateway/live-dashboard-stream.js +2 -2
- package/dist/src/gateway/live-dashboard-stream.js.map +1 -1
- package/dist/src/gateway/progress-watch-machine.d.ts +50 -64
- package/dist/src/gateway/progress-watch-machine.js +42 -133
- package/dist/src/gateway/progress-watch-machine.js.map +1 -1
- package/dist/src/gateway/provenance-envelope.d.ts +2 -0
- package/dist/src/gateway/provenance-envelope.js +13 -3
- package/dist/src/gateway/provenance-envelope.js.map +1 -1
- package/dist/src/gateway/providers.d.ts +69 -15
- package/dist/src/gateway/providers.js +456 -109
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.d.ts +8 -5
- package/dist/src/gateway/server.js +94 -13
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +25 -1
- package/dist/src/gateway/service.js +252 -69
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/store.d.ts +23 -28
- package/dist/src/gateway/store.js +479 -467
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +38 -11
- package/dist/src/gateway/types.js +141 -3
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/CONFIGURATION.md +8 -8
- package/docs/CONFIGURATION.zh-CN.md +8 -8
- package/docs/DASHBOARD.md +29 -6
- package/docs/DASHBOARD.zh-CN.md +1 -1
- package/docs/GATEWAY-ARCHITECTURE.md +143 -57
- package/package.json +1 -1
- package/skills/embassy-peer/SKILL.md +2 -2
|
@@ -91,203 +91,94 @@ var Embassy;
|
|
|
91
91
|
"inert",
|
|
92
92
|
"unknown",
|
|
93
93
|
];
|
|
94
|
-
function
|
|
95
|
-
return Object.prototype.hasOwnProperty.call(table,
|
|
96
|
-
? table[
|
|
97
|
-
:
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
|
119
|
+
return presentation("route", state);
|
|
181
120
|
}
|
|
182
121
|
Embassy.routeChipKind = routeChipKind;
|
|
183
122
|
function peerChipKind(state) {
|
|
184
|
-
return
|
|
123
|
+
return presentation("peer", state);
|
|
185
124
|
}
|
|
186
125
|
Embassy.peerChipKind = peerChipKind;
|
|
187
126
|
function healthChipKind(state) {
|
|
188
|
-
return
|
|
127
|
+
return presentation("health", state);
|
|
189
128
|
}
|
|
190
129
|
Embassy.healthChipKind = healthChipKind;
|
|
191
130
|
function compatibilityChipKind(state) {
|
|
192
|
-
return
|
|
131
|
+
return presentation("compatibility", state);
|
|
193
132
|
}
|
|
194
133
|
Embassy.compatibilityChipKind = compatibilityChipKind;
|
|
195
134
|
function overallChipKind(state) {
|
|
196
|
-
return
|
|
135
|
+
return presentation("overall", state);
|
|
197
136
|
}
|
|
198
137
|
Embassy.overallChipKind = overallChipKind;
|
|
199
138
|
function partyChipKind(state) {
|
|
200
|
-
return
|
|
139
|
+
return presentation("party", state);
|
|
201
140
|
}
|
|
202
141
|
Embassy.partyChipKind = partyChipKind;
|
|
203
142
|
function severityChipKind(state) {
|
|
204
|
-
return
|
|
143
|
+
return presentation("severity", state);
|
|
205
144
|
}
|
|
206
145
|
Embassy.severityChipKind = severityChipKind;
|
|
207
146
|
function connectionChipKind(state) {
|
|
208
|
-
return
|
|
147
|
+
return presentation("connection", state);
|
|
209
148
|
}
|
|
210
149
|
Embassy.connectionChipKind = connectionChipKind;
|
|
211
150
|
function chipKindByDomain(domain, state, direction) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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,
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
|
400
|
+
return window.EMBASSY_BOOT.semantics.guidanceCopyKeys[guidance];
|
|
528
401
|
}
|
|
529
402
|
Embassy.guidanceCopyKey = guidanceCopyKey;
|
|
530
403
|
function attentionCommand(item) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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(
|
|
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,
|
|
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
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
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",
|
|
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.
|
|
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 =
|
|
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) =>
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
React.createElement("
|
|
2388
|
-
React.createElement(
|
|
2389
|
-
|
|
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:
|
|
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;
|
|
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
|
|
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:
|
|
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 {
|
|
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 =
|
|
138
|
+
const model = buildLiveDashboardViewModel(observed.snapshot);
|
|
139
139
|
const nextFingerprint = fingerprint(model);
|
|
140
140
|
const changed = latest?.fingerprint !== nextFingerprint;
|
|
141
141
|
const reset = observerUnavailable ||
|