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.
- package/CHANGELOG.md +31 -0
- package/README.md +9 -9
- package/README.zh-CN.md +9 -9
- package/SECURITY.md +34 -77
- package/dist/src/gateway/acp-client.d.ts +117 -0
- package/dist/src/gateway/acp-client.js +382 -0
- package/dist/src/gateway/acp-client.js.map +1 -0
- package/dist/src/gateway/acp-provider.d.ts +65 -0
- package/dist/src/gateway/acp-provider.js +163 -0
- package/dist/src/gateway/acp-provider.js.map +1 -0
- package/dist/src/gateway/claude-helper-protocol.d.ts +3 -1
- package/dist/src/gateway/claude-helper-protocol.js +15 -5
- package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
- package/dist/src/gateway/claude-helper-supervisor.d.ts +3 -1
- package/dist/src/gateway/claude-helper-supervisor.js +16 -2
- package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
- package/dist/src/gateway/claude-helper.js +4 -3
- package/dist/src/gateway/claude-helper.js.map +1 -1
- package/dist/src/gateway/claude-peer.d.ts +1 -1
- package/dist/src/gateway/claude-peer.js +11 -13
- package/dist/src/gateway/claude-peer.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +0 -20
- package/dist/src/gateway/claude-runtime.js +6 -127
- package/dist/src/gateway/claude-runtime.js.map +1 -1
- package/dist/src/gateway/cli-copy.en.d.ts +1 -1
- package/dist/src/gateway/cli-copy.en.js +2 -2
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.js +2 -2
- package/dist/src/gateway/cli.d.ts +1 -1
- package/dist/src/gateway/cli.js +26 -5
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +5 -74
- package/dist/src/gateway/codex-app-server.js +9 -597
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-local-transport.d.ts +8 -26
- package/dist/src/gateway/codex-local-transport.js +26 -76
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/compatibility.d.ts +6 -66
- package/dist/src/gateway/compatibility.js +14 -296
- package/dist/src/gateway/compatibility.js.map +1 -1
- package/dist/src/gateway/config.d.ts +9 -0
- package/dist/src/gateway/config.js +6 -2
- package/dist/src/gateway/config.js.map +1 -1
- package/dist/src/gateway/control.d.ts +16 -1
- package/dist/src/gateway/control.js +89 -57
- 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 +14 -44
- package/dist/src/gateway/dashboard-copy.en.js +37 -67
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +14 -44
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +14 -44
- package/dist/src/gateway/dashboard-copy.zh-CN.js +37 -67
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +38 -76
- package/dist/src/gateway/dashboard-model.js +158 -256
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.d.ts +0 -3
- package/dist/src/gateway/dashboard.js +75 -76
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/deepseek-detect.d.ts +7 -6
- package/dist/src/gateway/deepseek-detect.js +31 -115
- package/dist/src/gateway/deepseek-detect.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +166 -621
- package/dist/src/gateway/live-dashboard-command.js +2 -4
- package/dist/src/gateway/live-dashboard-command.js.map +1 -1
- package/dist/src/gateway/live-dashboard-http.d.ts +1 -2
- package/dist/src/gateway/live-dashboard-http.js +14 -15
- package/dist/src/gateway/live-dashboard-http.js.map +1 -1
- package/dist/src/gateway/progress-watch-machine.d.ts +1 -4
- package/dist/src/gateway/progress-watch-machine.js.map +1 -1
- package/dist/src/gateway/provenance-envelope.d.ts +3 -2
- package/dist/src/gateway/provenance-envelope.js +44 -11
- package/dist/src/gateway/provenance-envelope.js.map +1 -1
- package/dist/src/gateway/providers.d.ts +12 -84
- package/dist/src/gateway/providers.js +69 -806
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.d.ts +8 -9
- package/dist/src/gateway/server.js +51 -99
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +22 -49
- package/dist/src/gateway/service.js +196 -432
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/store.d.ts +20 -29
- package/dist/src/gateway/store.js +281 -827
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +55 -55
- package/dist/src/gateway/types.js +49 -91
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/CONFIGURATION.md +11 -10
- package/docs/CONFIGURATION.zh-CN.md +10 -9
- package/docs/DASHBOARD.md +4 -38
- package/docs/DASHBOARD.zh-CN.md +4 -2
- package/docs/GATEWAY-ARCHITECTURE.md +61 -119
- package/package.json +1 -1
- package/skills/embassy-peer/SKILL.md +6 -6
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { arePublicAvailablePeerSnapshots,
|
|
2
|
-
import { compatibilitySurfaceDefinitions, } from "./compatibility.js";
|
|
1
|
+
import { arePublicAvailablePeerSnapshots, gatewayProviders, isPublicRegistryObservationSnapshot, parseDirection, } from "./types.js";
|
|
3
2
|
export const DASHBOARD_MODEL_LIMITS = Object.freeze({
|
|
4
3
|
connectors: 16,
|
|
5
4
|
availablePeers: 64,
|
|
6
5
|
routes: 128,
|
|
7
|
-
|
|
6
|
+
consentEdges: 64,
|
|
8
7
|
messages: 50,
|
|
9
8
|
messageEvents: 60,
|
|
10
9
|
progressWatches: 64,
|
|
@@ -35,7 +34,6 @@ const statePresentation = {
|
|
|
35
34
|
busy: { tone: "info", chip: "active" },
|
|
36
35
|
awaiting_approval: { tone: "warning", chip: "warning" },
|
|
37
36
|
offline: { tone: "danger", chip: "failure" },
|
|
38
|
-
incompatible: { tone: "danger", chip: "failure" },
|
|
39
37
|
disabled: { tone: "quiet", chip: "inert" },
|
|
40
38
|
}),
|
|
41
39
|
peer: presentation({
|
|
@@ -43,20 +41,12 @@ const statePresentation = {
|
|
|
43
41
|
busy: { tone: "info", chip: "active" },
|
|
44
42
|
awaiting_approval: { tone: "warning", chip: "warning" },
|
|
45
43
|
offline: { tone: "danger", chip: "inert" },
|
|
46
|
-
incompatible: { tone: "danger", chip: "failure" },
|
|
47
44
|
}),
|
|
48
45
|
health: presentation({
|
|
49
46
|
healthy: { tone: "good", chip: "positive" },
|
|
50
47
|
connecting: { tone: "info", chip: "progress" },
|
|
51
48
|
degraded: { tone: "warning", chip: "warning" },
|
|
52
49
|
offline: { tone: "danger", chip: "failure" },
|
|
53
|
-
incompatible: { tone: "danger", chip: "failure" },
|
|
54
|
-
}),
|
|
55
|
-
compatibility: presentation({
|
|
56
|
-
compatible: { tone: "good", chip: "positive" },
|
|
57
|
-
unknown: { tone: "quiet", chip: "inert" },
|
|
58
|
-
expired: { tone: "warning", chip: "warning" },
|
|
59
|
-
incompatible: { tone: "danger", chip: "failure" },
|
|
60
50
|
}),
|
|
61
51
|
overall: presentation({
|
|
62
52
|
ready: { tone: "good", chip: "positive" },
|
|
@@ -104,7 +94,6 @@ const guidanceCopyKeys = {
|
|
|
104
94
|
progress_watch: "progressWatch",
|
|
105
95
|
registry_empty: "registryEmpty",
|
|
106
96
|
registry_rejected: "registryRejected",
|
|
107
|
-
provider_incompatible: "providerIncompatible",
|
|
108
97
|
generic: "generic",
|
|
109
98
|
};
|
|
110
99
|
const nextActionCopyKeys = {
|
|
@@ -115,7 +104,6 @@ const nextActionCopyKeys = {
|
|
|
115
104
|
repair_claude_inventory: "next.repairClaude",
|
|
116
105
|
register_codex: "next.registerCodex",
|
|
117
106
|
restore_codex: "next.restoreCodex",
|
|
118
|
-
review_compatibility: "next.reviewCompatibility",
|
|
119
107
|
none: "next.none",
|
|
120
108
|
};
|
|
121
109
|
const attentionCommands = {
|
|
@@ -137,7 +125,6 @@ const attentionCommands = {
|
|
|
137
125
|
progress_watch: "embassy status",
|
|
138
126
|
registry_empty: "embassy refresh-dashboard",
|
|
139
127
|
registry_rejected: "embassy status",
|
|
140
|
-
provider_incompatible: "embassy refresh-dashboard",
|
|
141
128
|
generic: "embassy status",
|
|
142
129
|
};
|
|
143
130
|
const deliveryMeaningKeys = {
|
|
@@ -158,8 +145,8 @@ const deliveryMeaningKeys = {
|
|
|
158
145
|
/** JSON-safe semantics embedded once in the live dashboard boot payload. */
|
|
159
146
|
export const DASHBOARD_SEMANTICS = Object.freeze({
|
|
160
147
|
statePresentation,
|
|
161
|
-
|
|
162
|
-
delivered: {
|
|
148
|
+
deliveryChipByTargetProvider: {
|
|
149
|
+
delivered: { claude: "qualified" },
|
|
163
150
|
},
|
|
164
151
|
deliveryChipBySafeErrorCode: {
|
|
165
152
|
rejected: { SENDER_NOT_PAIRED: "inert" },
|
|
@@ -175,9 +162,11 @@ export const DASHBOARD_SEMANTICS = Object.freeze({
|
|
|
175
162
|
codex_succession_recovery: "<old>",
|
|
176
163
|
},
|
|
177
164
|
deliveryMeaningKeys,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
165
|
+
deliveryMeaningByTargetProvider: {
|
|
166
|
+
claude: "activity.meaning.delivered.toClaude",
|
|
167
|
+
codex: "activity.meaning.delivered.toCodex",
|
|
168
|
+
deepseek: "activity.meaning.delivered.toDeepSeek",
|
|
169
|
+
grok: "activity.meaning.delivered.toGrok",
|
|
181
170
|
},
|
|
182
171
|
deliveryMeaningBySafeErrorCode: {
|
|
183
172
|
SENDER_NOT_PAIRED: "activity.meaning.senderNotPaired",
|
|
@@ -196,14 +185,15 @@ function semanticPresentation(domain, state) {
|
|
|
196
185
|
export function dashboardChipKind(domain, state, direction, safeErrorCode) {
|
|
197
186
|
if (domain === "delivery") {
|
|
198
187
|
const byCode = DASHBOARD_SEMANTICS.deliveryChipBySafeErrorCode;
|
|
199
|
-
const
|
|
188
|
+
const byTarget = DASHBOARD_SEMANTICS.deliveryChipByTargetProvider;
|
|
200
189
|
if (safeErrorCode !== undefined) {
|
|
201
190
|
const override = byCode[state]?.[safeErrorCode];
|
|
202
191
|
if (override !== undefined)
|
|
203
192
|
return override;
|
|
204
193
|
}
|
|
205
194
|
if (direction !== undefined) {
|
|
206
|
-
const
|
|
195
|
+
const target = parseDirection(direction)?.targetProvider;
|
|
196
|
+
const override = target === undefined ? undefined : byTarget[state]?.[target];
|
|
207
197
|
if (override !== undefined)
|
|
208
198
|
return override;
|
|
209
199
|
}
|
|
@@ -224,7 +214,10 @@ export function deliveryMeaningKey(state, direction, safeErrorCode) {
|
|
|
224
214
|
return DASHBOARD_SEMANTICS.deliveryMeaningBySafeErrorCode.SENDER_NOT_PAIRED;
|
|
225
215
|
}
|
|
226
216
|
if (state === "delivered" && direction !== undefined) {
|
|
227
|
-
|
|
217
|
+
const target = parseDirection(direction)?.targetProvider;
|
|
218
|
+
if (target !== undefined) {
|
|
219
|
+
return DASHBOARD_SEMANTICS.deliveryMeaningByTargetProvider[target];
|
|
220
|
+
}
|
|
228
221
|
}
|
|
229
222
|
if (state === "abandoned" && safeErrorCode !== undefined) {
|
|
230
223
|
const byCode = DASHBOARD_SEMANTICS.deliveryMeaningBySafeErrorCode;
|
|
@@ -300,16 +293,14 @@ function normalizedCounters(counters) {
|
|
|
300
293
|
bytesAccepted: normalizedInteger(counters?.bytesAccepted) ?? 0,
|
|
301
294
|
};
|
|
302
295
|
}
|
|
303
|
-
export function buildDashboardViewModel(snapshot
|
|
304
|
-
return buildProjectedDashboardViewModel(snapshot, false
|
|
296
|
+
export function buildDashboardViewModel(snapshot) {
|
|
297
|
+
return buildProjectedDashboardViewModel(snapshot, false);
|
|
305
298
|
}
|
|
306
|
-
export function buildLiveDashboardViewModel(snapshot
|
|
307
|
-
return buildProjectedDashboardViewModel(snapshot, true
|
|
299
|
+
export function buildLiveDashboardViewModel(snapshot) {
|
|
300
|
+
return buildProjectedDashboardViewModel(snapshot, true);
|
|
308
301
|
}
|
|
309
302
|
function routeIsReady(route) {
|
|
310
303
|
return (route.enabled &&
|
|
311
|
-
route.safeErrorCode !== "CODEX_WRITES_DISABLED" &&
|
|
312
|
-
route.compatibility === "compatible" &&
|
|
313
304
|
(route.state === "idle" || route.state === "busy"));
|
|
314
305
|
}
|
|
315
306
|
function peerSelectionGuidance(peer) {
|
|
@@ -322,11 +313,6 @@ function peerSelectionGuidance(peer) {
|
|
|
322
313
|
}
|
|
323
314
|
if (peer.state === "offline")
|
|
324
315
|
return "offline";
|
|
325
|
-
if (peer.state === "incompatible" ||
|
|
326
|
-
peer.compatibility !== "compatible" ||
|
|
327
|
-
peer.safeErrorCode !== undefined) {
|
|
328
|
-
return "incompatible";
|
|
329
|
-
}
|
|
330
316
|
return undefined;
|
|
331
317
|
}
|
|
332
318
|
function peerIsSelectable(peer) {
|
|
@@ -343,10 +329,10 @@ function partyStatus(routes, ready) {
|
|
|
343
329
|
return routes.some((route) => route.state === "busy") ? "busy" : "ready";
|
|
344
330
|
}
|
|
345
331
|
function routePriority(route) {
|
|
346
|
-
if (!route.enabled || route.state === "offline"
|
|
332
|
+
if (!route.enabled || route.state === "offline") {
|
|
347
333
|
return 0;
|
|
348
334
|
}
|
|
349
|
-
if (route.state === "stale"
|
|
335
|
+
if (route.state === "stale")
|
|
350
336
|
return 1;
|
|
351
337
|
if (route.state === "awaiting_approval")
|
|
352
338
|
return 2;
|
|
@@ -367,8 +353,7 @@ function needsCodexAppReconnect(route, connectors, generatedAt) {
|
|
|
367
353
|
}
|
|
368
354
|
return connectors.some((connector) => connector.provider === "codex" &&
|
|
369
355
|
connector.host === route.host &&
|
|
370
|
-
connector.health === "healthy"
|
|
371
|
-
connector.compatibility === "compatible");
|
|
356
|
+
connector.health === "healthy");
|
|
372
357
|
}
|
|
373
358
|
function alertPriority(severity) {
|
|
374
359
|
return severity === "error" ? 0 : severity === "warning" ? 1 : 2;
|
|
@@ -405,14 +390,6 @@ function guidanceFor(code, provider) {
|
|
|
405
390
|
case "ADAPTER_DEGRADED":
|
|
406
391
|
case "ROUTE_DEGRADED":
|
|
407
392
|
return "degraded";
|
|
408
|
-
case "CLAUDE_PEER_VERSION_UNSUPPORTED":
|
|
409
|
-
case "CLAUDE_VERSION_UNPARSEABLE":
|
|
410
|
-
case "CLAUDE_VERSION_CHECK_FAILED":
|
|
411
|
-
case "CLAUDE_VERSION_EVIDENCE_CONFLICT":
|
|
412
|
-
case "CLAUDE_VERSION_EVIDENCE_TOO_LARGE":
|
|
413
|
-
case "CODEX_APP_SERVER_VERSION_UNSUPPORTED":
|
|
414
|
-
case "CODEX_APP_SERVER_VERSION_UNPARSEABLE":
|
|
415
|
-
return "provider_incompatible";
|
|
416
393
|
default:
|
|
417
394
|
return "generic";
|
|
418
395
|
}
|
|
@@ -574,35 +551,17 @@ function buildMessageGroups(messages, includeBodies) {
|
|
|
574
551
|
activeGroups: all.filter((message) => ["queued", "dispatching", "transport_written", "held"].includes(message.state)).length,
|
|
575
552
|
};
|
|
576
553
|
}
|
|
577
|
-
function buildProjectedDashboardViewModel(snapshot, includeBodies
|
|
578
|
-
const surfaceDefinitions = options.compatibilitySurfaceDefinitions ?? compatibilitySurfaceDefinitions;
|
|
554
|
+
function buildProjectedDashboardViewModel(snapshot, includeBodies) {
|
|
579
555
|
const generatedAt = normalizedTimestamp(snapshot.generatedAt);
|
|
580
556
|
const inboundMode = snapshot.inboundMode === "open" ? "open" : "paired";
|
|
581
557
|
const validPeers = arePublicAvailablePeerSnapshots(snapshot.availablePeers)
|
|
582
558
|
? snapshot.availablePeers
|
|
583
559
|
: [];
|
|
584
|
-
const writesCoveredProviders = new Set((Array.isArray(snapshot.compatibilityChecks)
|
|
585
|
-
? snapshot.compatibilityChecks.filter(isPublicCompatibilityCheckSnapshot)
|
|
586
|
-
: []).filter((check) => check.writesCovered).map((check) => check.surface));
|
|
587
|
-
const quarantinedProviders = new Set([
|
|
588
|
-
...snapshot.connectors
|
|
589
|
-
.filter((connector) => connector.compatibility === "incompatible")
|
|
590
|
-
.map((connector) => connector.provider),
|
|
591
|
-
...(Array.isArray(snapshot.compatibilityChecks)
|
|
592
|
-
? snapshot.compatibilityChecks
|
|
593
|
-
.filter(isPublicCompatibilityCheckSnapshot)
|
|
594
|
-
.filter((check) => check.tier === "incompatible")
|
|
595
|
-
.flatMap((check) => check.surface === "claude" || check.surface === "codex"
|
|
596
|
-
? [check.surface]
|
|
597
|
-
: [])
|
|
598
|
-
: []),
|
|
599
|
-
]);
|
|
600
560
|
const peers = validPeers
|
|
601
561
|
.map((peer) => ({
|
|
602
562
|
alias: boundedText(peer.alias),
|
|
603
563
|
host: boundedText(peer.host),
|
|
604
564
|
state: peer.state,
|
|
605
|
-
compatibility: peer.compatibility,
|
|
606
565
|
validated: peer.validated,
|
|
607
566
|
selected: peer.selected,
|
|
608
567
|
selectable: peerIsSelectable(peer),
|
|
@@ -654,7 +613,6 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
654
613
|
host: boundedText(route.host),
|
|
655
614
|
enabled: Boolean(route.enabled),
|
|
656
615
|
state: route.state,
|
|
657
|
-
compatibility: route.compatibility,
|
|
658
616
|
queueDepth: depth,
|
|
659
617
|
...(oldestQueuedAt === undefined ? {} : { oldestQueuedAt }),
|
|
660
618
|
...(age === undefined ? {} : { queueAgeMs: age }),
|
|
@@ -671,33 +629,32 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
671
629
|
.sort((left, right) => routePriority(left) - routePriority(right) ||
|
|
672
630
|
compareText(left.alias, right.alias))
|
|
673
631
|
.slice(0, DASHBOARD_MODEL_LIMITS.routes);
|
|
674
|
-
const
|
|
675
|
-
const
|
|
676
|
-
.map((
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
const
|
|
632
|
+
const routeByEndpoint = new Map(allRoutes.map((route) => [`${route.provider}\0${route.alias}`, route]));
|
|
633
|
+
const allConsentEdges = snapshot.consentEdges
|
|
634
|
+
.map((edge) => {
|
|
635
|
+
const endpoints = edge.endpoints.map((endpoint) => ({
|
|
636
|
+
alias: boundedText(endpoint.alias),
|
|
637
|
+
provider: endpoint.provider,
|
|
638
|
+
}));
|
|
639
|
+
const routes = endpoints.map((endpoint) => routeByEndpoint.get(`${endpoint.provider}\0${endpoint.alias}`));
|
|
640
|
+
const bothPresent = routes.every((route) => route !== undefined);
|
|
682
641
|
return {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
host: boundedText(pair.host),
|
|
642
|
+
endpoints,
|
|
643
|
+
host: boundedText(edge.host),
|
|
686
644
|
state: bothPresent &&
|
|
687
|
-
|
|
688
|
-
!quarantinedProviders.has("codex") &&
|
|
689
|
-
routeIsReady(claudeRoute) &&
|
|
690
|
-
routeIsReady(codexRoute)
|
|
645
|
+
routes.every((route) => route !== undefined && routeIsReady(route))
|
|
691
646
|
? "ready"
|
|
692
647
|
: bothPresent
|
|
693
648
|
? "degraded"
|
|
694
649
|
: "unavailable",
|
|
695
|
-
counters: normalizedCounters(
|
|
650
|
+
counters: normalizedCounters(edge.counters),
|
|
696
651
|
};
|
|
697
652
|
})
|
|
698
|
-
.sort((left, right) => compareText(left.
|
|
699
|
-
compareText(left.
|
|
700
|
-
|
|
653
|
+
.sort((left, right) => compareText(left.endpoints[0].provider, right.endpoints[0].provider) ||
|
|
654
|
+
compareText(left.endpoints[0].alias, right.endpoints[0].alias) ||
|
|
655
|
+
compareText(left.endpoints[1].provider, right.endpoints[1].provider) ||
|
|
656
|
+
compareText(left.endpoints[1].alias, right.endpoints[1].alias));
|
|
657
|
+
const consentEdges = allConsentEdges.slice(0, DASHBOARD_MODEL_LIMITS.consentEdges);
|
|
701
658
|
const allWatches = (snapshot.progressWatches ?? [])
|
|
702
659
|
.flatMap((watch) => {
|
|
703
660
|
const lastActivityAt = normalizedTimestamp(watch.lastActivityAt);
|
|
@@ -763,7 +720,6 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
763
720
|
provider: connector.provider,
|
|
764
721
|
host: boundedText(connector.host),
|
|
765
722
|
health: connector.health,
|
|
766
|
-
compatibility: connector.compatibility,
|
|
767
723
|
...(safeProtocol(connector.protocol) === undefined
|
|
768
724
|
? {}
|
|
769
725
|
: { protocol: safeProtocol(connector.protocol) }),
|
|
@@ -791,38 +747,6 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
791
747
|
})
|
|
792
748
|
.sort((left, right) => compareText(`${left.provider}\0${left.host}`, `${right.provider}\0${right.host}`))
|
|
793
749
|
.slice(0, DASHBOARD_MODEL_LIMITS.connectors);
|
|
794
|
-
const detectedCompatibilityChecks = (Array.isArray(snapshot.compatibilityChecks)
|
|
795
|
-
? snapshot.compatibilityChecks.filter(isPublicCompatibilityCheckSnapshot)
|
|
796
|
-
: [])
|
|
797
|
-
.map((attestation) => {
|
|
798
|
-
const failed = attestation.probes.find((probe) => probe.outcome === "fail");
|
|
799
|
-
const issue = safeCode(attestation.safeErrorCode);
|
|
800
|
-
return {
|
|
801
|
-
surface: attestation.surface,
|
|
802
|
-
version: boundedText(attestation.version),
|
|
803
|
-
...(attestation.testedVersion === undefined
|
|
804
|
-
? {}
|
|
805
|
-
: { testedVersion: boundedText(attestation.testedVersion) }),
|
|
806
|
-
...(attestation.supportedMajor === undefined
|
|
807
|
-
? {}
|
|
808
|
-
: { supportedMajor: boundedText(attestation.supportedMajor) }),
|
|
809
|
-
tier: attestation.tier,
|
|
810
|
-
writesCovered: attestation.writesCovered,
|
|
811
|
-
checkedAt: attestation.checkedAt,
|
|
812
|
-
...(failed === undefined ? {} : { failure: failed.name }),
|
|
813
|
-
...(issue === undefined ? {} : { safeErrorCode: issue }),
|
|
814
|
-
};
|
|
815
|
-
})
|
|
816
|
-
.sort((left, right) => compareText(left.surface, right.surface));
|
|
817
|
-
const detectedSurfaces = new Set(detectedCompatibilityChecks.map(({ surface }) => surface));
|
|
818
|
-
const compatibilityChecks = [
|
|
819
|
-
...detectedCompatibilityChecks,
|
|
820
|
-
...surfaceDefinitions
|
|
821
|
-
.filter(({ required, surface }) => !required && !detectedSurfaces.has(surface))
|
|
822
|
-
.map(({ surface }) => ({ surface, notDetected: true })),
|
|
823
|
-
]
|
|
824
|
-
.sort((left, right) => compareText(left.surface, right.surface))
|
|
825
|
-
.slice(0, surfaceDefinitions.length);
|
|
826
750
|
const messages = buildMessageGroups(snapshot.messages, includeBodies);
|
|
827
751
|
const queuedMessages = allRoutes.reduce((total, route) => boundedAdd(total, route.queueDepth), 0);
|
|
828
752
|
const queuedWithAge = allRoutes
|
|
@@ -830,69 +754,109 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
830
754
|
.sort((left, right) => right.queueAgeMs - left.queueAgeMs);
|
|
831
755
|
const oldest = queuedWithAge[0];
|
|
832
756
|
const activeDeliveries = messages.activeGroups;
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
const
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
const
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
757
|
+
const routesByProvider = Object.fromEntries(gatewayProviders.map((provider) => [
|
|
758
|
+
provider,
|
|
759
|
+
allRoutes.filter((route) => route.provider === provider),
|
|
760
|
+
]));
|
|
761
|
+
const readyByProvider = Object.fromEntries(gatewayProviders.map((provider) => [
|
|
762
|
+
provider,
|
|
763
|
+
routesByProvider[provider].filter(routeIsReady).length,
|
|
764
|
+
]));
|
|
765
|
+
const pairedAliasesByProvider = Object.fromEntries(gatewayProviders.map((provider) => [provider, new Set()]));
|
|
766
|
+
for (const edge of allConsentEdges) {
|
|
767
|
+
for (const endpoint of edge.endpoints) {
|
|
768
|
+
pairedAliasesByProvider[endpoint.provider].add(endpoint.alias);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
const readyConsentEdges = allConsentEdges.filter((edge) => edge.state === "ready");
|
|
772
|
+
const consentEdgeCountIsLowerBound = (normalizedInteger(snapshot.truncation.consentEdges) ?? 0) > 0;
|
|
773
|
+
const hasConsentEvidence = allConsentEdges.length > 0 || consentEdgeCountIsLowerBound;
|
|
846
774
|
const graph = {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
775
|
+
consentEdgeCount: allConsentEdges.length,
|
|
776
|
+
readyConsentEdgeCount: readyConsentEdges.length,
|
|
777
|
+
consentEdgeCountIsLowerBound,
|
|
778
|
+
unpairedReadyByProvider: Object.fromEntries(gatewayProviders.map((provider) => [
|
|
779
|
+
provider,
|
|
780
|
+
routesByProvider[provider].filter((route) => routeIsReady(route) &&
|
|
781
|
+
!pairedAliasesByProvider[provider].has(route.alias)).length,
|
|
782
|
+
])),
|
|
852
783
|
};
|
|
853
784
|
const selectedPeers = validPeers.filter((peer) => peer.selected && peerIsSelectable(peer));
|
|
854
785
|
const selectablePeers = validPeers.filter(peerIsSelectable);
|
|
855
|
-
const selectedClaudeCount =
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
(
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const codexNextAction =
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
786
|
+
const selectedClaudeCount = Math.max(selectedPeers.filter((peer) => peer.provider === "claude").length, readyByProvider.claude);
|
|
787
|
+
const readyPairedByProvider = Object.fromEntries(gatewayProviders.map((provider) => [
|
|
788
|
+
provider,
|
|
789
|
+
routesByProvider[provider].some((route) => routeIsReady(route) &&
|
|
790
|
+
pairedAliasesByProvider[provider].has(route.alias)),
|
|
791
|
+
]));
|
|
792
|
+
const claudeNextAction = selectedClaudeCount > 0 &&
|
|
793
|
+
(readyPairedByProvider.claude ||
|
|
794
|
+
(consentEdgeCountIsLowerBound && readyByProvider.claude > 0))
|
|
795
|
+
? "none"
|
|
796
|
+
: readyByProvider.claude > 0
|
|
797
|
+
? "pair_routes"
|
|
798
|
+
: validPeers.length === 0
|
|
799
|
+
? "discover_claude"
|
|
800
|
+
: selectablePeers.length > 0
|
|
801
|
+
? !hasConsentEvidence
|
|
802
|
+
? "pair_routes"
|
|
803
|
+
: "restore_claude"
|
|
804
|
+
: selectedPeers.length > 0
|
|
805
|
+
? "restore_claude"
|
|
806
|
+
: "repair_claude_inventory";
|
|
807
|
+
const codexNextAction = readyPairedByProvider.codex ||
|
|
808
|
+
(consentEdgeCountIsLowerBound && readyByProvider.codex > 0)
|
|
809
|
+
? "none"
|
|
810
|
+
: readyByProvider.codex > 0
|
|
811
|
+
? "pair_routes"
|
|
812
|
+
: routesByProvider.codex.length === 0
|
|
813
|
+
? "register_codex"
|
|
814
|
+
: "restore_codex";
|
|
815
|
+
const parties = gatewayProviders.map((provider) => {
|
|
816
|
+
const providerPeers = validPeers.filter((peer) => peer.provider === provider);
|
|
817
|
+
const providerRoutes = routesByProvider[provider];
|
|
818
|
+
const ready = provider === "claude"
|
|
819
|
+
? selectedClaudeCount
|
|
820
|
+
: readyByProvider[provider];
|
|
821
|
+
const nextAction = provider === "claude"
|
|
822
|
+
? claudeNextAction
|
|
823
|
+
: provider === "codex"
|
|
824
|
+
? codexNextAction
|
|
825
|
+
: readyPairedByProvider[provider]
|
|
826
|
+
? "none"
|
|
827
|
+
: ready > 0
|
|
828
|
+
? "pair_routes"
|
|
829
|
+
: "none";
|
|
830
|
+
return {
|
|
831
|
+
kind: provider,
|
|
832
|
+
status: provider === "claude" && ready > 0 && partyStatus(providerRoutes, ready) === "missing"
|
|
833
|
+
? "attention"
|
|
834
|
+
: partyStatus(providerRoutes, ready),
|
|
835
|
+
total: provider === "claude" ? providerPeers.length : providerRoutes.length,
|
|
836
|
+
ready,
|
|
837
|
+
...(provider === "claude"
|
|
838
|
+
? { selectable: selectablePeers.filter((peer) => peer.provider === provider).length }
|
|
839
|
+
: {}),
|
|
840
|
+
countIsLowerBound: (normalizedInteger(snapshot.truncation.routes) ?? 0) > 0 ||
|
|
841
|
+
(provider === "claude" &&
|
|
842
|
+
(normalizedInteger(snapshot.truncation.availablePeers) ?? 0) > 0),
|
|
843
|
+
...(providerPeers.find((peer) => peer.selected)?.alias === undefined
|
|
844
|
+
? providerRoutes[0]?.alias === undefined
|
|
845
|
+
? {}
|
|
846
|
+
: { primaryAlias: boundedText(providerRoutes[0].alias) }
|
|
847
|
+
: { primaryAlias: boundedText(providerPeers.find((peer) => peer.selected).alias) }),
|
|
848
|
+
nextAction,
|
|
849
|
+
};
|
|
850
|
+
});
|
|
885
851
|
const explicitAlerts = coalesceCodexReactivationAlerts(snapshot.alerts
|
|
886
|
-
.filter((alert) => alert.code !== "COMPATIBILITY_CERTIFICATION_FAILED")
|
|
887
852
|
.map((alert) => {
|
|
888
853
|
const code = safeCode(alert.code);
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
? routeByAlias.get(alert.alias)
|
|
854
|
+
const route = code === "QUEUE_STALLED" && typeof alert.alias === "string" &&
|
|
855
|
+
alert.provider !== undefined
|
|
856
|
+
? routeByEndpoint.get(`${alert.provider}\0${alert.alias}`)
|
|
893
857
|
: undefined;
|
|
894
|
-
const alertRoute = typeof alert.alias === "string"
|
|
895
|
-
?
|
|
858
|
+
const alertRoute = typeof alert.alias === "string" && alert.provider !== undefined
|
|
859
|
+
? routeByEndpoint.get(`${alert.provider}\0${alert.alias}`)
|
|
896
860
|
: undefined;
|
|
897
861
|
return {
|
|
898
862
|
kind: "alert",
|
|
@@ -905,9 +869,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
905
869
|
...(normalizedTimestamp(alert.timestamp) === undefined
|
|
906
870
|
? {}
|
|
907
871
|
: { timestamp: normalizedTimestamp(alert.timestamp) }),
|
|
908
|
-
...(alert.provider ===
|
|
909
|
-
? { provider: alert.provider }
|
|
910
|
-
: {}),
|
|
872
|
+
...(alert.provider === undefined ? {} : { provider: alert.provider }),
|
|
911
873
|
...(typeof alert.alias === "string"
|
|
912
874
|
? { alias: boundedText(alert.alias) }
|
|
913
875
|
: {}),
|
|
@@ -926,29 +888,19 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
926
888
|
guidance: alertRoute !== undefined &&
|
|
927
889
|
needsCodexAppReconnect(alertRoute, connectors, generatedAt)
|
|
928
890
|
? "codex_app_reconnect_required"
|
|
929
|
-
:
|
|
930
|
-
alert.provider !== undefined &&
|
|
931
|
-
quarantinedProviders.has(alert.provider)
|
|
932
|
-
? "provider_incompatible"
|
|
933
|
-
: providerWritesCovered &&
|
|
934
|
-
guidanceFor(code, alert.provider) === "provider_incompatible"
|
|
935
|
-
? "degraded"
|
|
936
|
-
: guidanceFor(code, alert.provider),
|
|
891
|
+
: guidanceFor(code, alert.provider),
|
|
937
892
|
};
|
|
938
893
|
}), allRoutes).sort((left, right) => alertPriority(left.severity) - alertPriority(right.severity) ||
|
|
939
894
|
compareText(right.timestamp ?? "", left.timestamp ?? ""));
|
|
940
895
|
const attentionCandidates = [...explicitAlerts];
|
|
941
896
|
const unavailableConsentEdgeScopes = new Set();
|
|
942
|
-
for (const
|
|
943
|
-
if (
|
|
897
|
+
for (const edge of allConsentEdges) {
|
|
898
|
+
if (edge.state !== "unavailable")
|
|
944
899
|
continue;
|
|
945
|
-
for (const endpoint of
|
|
946
|
-
{
|
|
947
|
-
{ provider: "codex", alias: pair.codexAlias },
|
|
948
|
-
]) {
|
|
949
|
-
if (routeByAlias.has(endpoint.alias))
|
|
900
|
+
for (const endpoint of edge.endpoints) {
|
|
901
|
+
if (routeByEndpoint.has(`${endpoint.provider}\0${endpoint.alias}`))
|
|
950
902
|
continue;
|
|
951
|
-
const scope = `${endpoint.provider}\0${endpoint.alias}\0${
|
|
903
|
+
const scope = `${endpoint.provider}\0${endpoint.alias}\0${edge.host}`;
|
|
952
904
|
if (unavailableConsentEdgeScopes.has(scope))
|
|
953
905
|
continue;
|
|
954
906
|
unavailableConsentEdgeScopes.add(scope);
|
|
@@ -957,13 +909,13 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
957
909
|
severity: "warning",
|
|
958
910
|
provider: endpoint.provider,
|
|
959
911
|
alias: endpoint.alias,
|
|
960
|
-
host:
|
|
912
|
+
host: edge.host,
|
|
961
913
|
guidance: "consent_edge_unavailable",
|
|
962
914
|
});
|
|
963
915
|
}
|
|
964
916
|
}
|
|
965
917
|
for (const route of allRoutes) {
|
|
966
|
-
const writes = messages.groups.filter(({ direction, targetAlias, state, timestamp }) => direction === "
|
|
918
|
+
const writes = messages.groups.filter(({ direction, targetAlias, state, timestamp }) => parseDirection(direction)?.targetProvider === "claude" &&
|
|
967
919
|
targetAlias === route.alias && state === "delivered" &&
|
|
968
920
|
timestamp !== undefined);
|
|
969
921
|
// Groups arrive newest-first. The oldest unconsumed write owns the notice:
|
|
@@ -1008,9 +960,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1008
960
|
}
|
|
1009
961
|
const representedScopes = new Set(attentionCandidates.map((item) => `${item.provider ?? ""}\0${item.alias ?? ""}\0${item.host ?? ""}`));
|
|
1010
962
|
for (const route of allRoutes) {
|
|
1011
|
-
if (routeIsReady(route)
|
|
1012
|
-
quarantinedProviders.has(route.provider) ||
|
|
1013
|
-
route.safeErrorCode === "CODEX_WRITES_DISABLED") {
|
|
963
|
+
if (routeIsReady(route)) {
|
|
1014
964
|
continue;
|
|
1015
965
|
}
|
|
1016
966
|
const scope = `${route.provider}\0${route.alias}\0${route.host}`;
|
|
@@ -1019,9 +969,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1019
969
|
attentionCandidates.push({
|
|
1020
970
|
kind: "route",
|
|
1021
971
|
...(route.safeErrorCode === undefined ? {} : { code: route.safeErrorCode }),
|
|
1022
|
-
severity: route.state === "offline"
|
|
1023
|
-
? "error"
|
|
1024
|
-
: "warning",
|
|
972
|
+
severity: route.state === "offline" ? "error" : "warning",
|
|
1025
973
|
...(route.lastSeenAt === undefined ? {} : { timestamp: route.lastSeenAt }),
|
|
1026
974
|
provider: route.provider,
|
|
1027
975
|
alias: route.alias,
|
|
@@ -1039,10 +987,8 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1039
987
|
representedScopes.add(scope);
|
|
1040
988
|
}
|
|
1041
989
|
for (const connector of connectors) {
|
|
1042
|
-
if (
|
|
1043
|
-
connector.compatibility === "compatible")) {
|
|
990
|
+
if (connector.health === "healthy")
|
|
1044
991
|
continue;
|
|
1045
|
-
}
|
|
1046
992
|
const scope = `${connector.provider}\0\0${connector.host}`;
|
|
1047
993
|
if (representedScopes.has(scope))
|
|
1048
994
|
continue;
|
|
@@ -1059,17 +1005,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1059
1005
|
host: connector.host,
|
|
1060
1006
|
guidance: connector.health === "offline"
|
|
1061
1007
|
? "connector_offline"
|
|
1062
|
-
:
|
|
1063
|
-
(quarantinedProviders.has(connector.provider) ||
|
|
1064
|
-
connector.safeErrorCode === "CLAUDE_PEER_VERSION_UNSUPPORTED" ||
|
|
1065
|
-
connector.safeErrorCode === "CLAUDE_VERSION_UNPARSEABLE" ||
|
|
1066
|
-
connector.safeErrorCode === "CLAUDE_VERSION_CHECK_FAILED" ||
|
|
1067
|
-
connector.safeErrorCode === "CLAUDE_VERSION_EVIDENCE_CONFLICT" ||
|
|
1068
|
-
connector.safeErrorCode === "CLAUDE_VERSION_EVIDENCE_TOO_LARGE" ||
|
|
1069
|
-
connector.safeErrorCode === "CODEX_APP_SERVER_VERSION_UNSUPPORTED" ||
|
|
1070
|
-
connector.safeErrorCode === "CODEX_APP_SERVER_VERSION_UNPARSEABLE")
|
|
1071
|
-
? "provider_incompatible"
|
|
1072
|
-
: "degraded",
|
|
1008
|
+
: "degraded",
|
|
1073
1009
|
});
|
|
1074
1010
|
representedScopes.add(scope);
|
|
1075
1011
|
}
|
|
@@ -1112,10 +1048,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1112
1048
|
guidance: "registry_empty",
|
|
1113
1049
|
});
|
|
1114
1050
|
}
|
|
1115
|
-
if ((snapshot.health === "degraded" ||
|
|
1116
|
-
snapshot.health === "offline" ||
|
|
1117
|
-
snapshot.health === "incompatible") &&
|
|
1118
|
-
!(snapshot.health === "degraded" && quarantinedProviders.size > 0) &&
|
|
1051
|
+
if ((snapshot.health === "degraded" || snapshot.health === "offline") &&
|
|
1119
1052
|
!attentionCandidates.some((item) => item.kind === "broker")) {
|
|
1120
1053
|
attentionCandidates.push({
|
|
1121
1054
|
kind: "broker",
|
|
@@ -1124,11 +1057,11 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1124
1057
|
});
|
|
1125
1058
|
}
|
|
1126
1059
|
const attention = attentionCandidates.slice(0, DASHBOARD_MODEL_LIMITS.alerts);
|
|
1127
|
-
const setupComplete =
|
|
1128
|
-
const
|
|
1060
|
+
const setupComplete = hasConsentEvidence;
|
|
1061
|
+
const hasDegradedConsentEdge = allConsentEdges.some((edge) => edge.state !== "ready");
|
|
1129
1062
|
const overall = attentionCandidates.length > 0 ||
|
|
1130
1063
|
(normalizedInteger(snapshot.truncation.alerts) ?? 0) > 0 ||
|
|
1131
|
-
|
|
1064
|
+
hasDegradedConsentEdge
|
|
1132
1065
|
? "attention"
|
|
1133
1066
|
: setupComplete
|
|
1134
1067
|
? "ready"
|
|
@@ -1137,7 +1070,7 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1137
1070
|
connectors: boundedAdd(normalizedInteger(snapshot.truncation.connectors) ?? 0, Math.max(0, snapshot.connectors.length - DASHBOARD_MODEL_LIMITS.connectors)),
|
|
1138
1071
|
availablePeers: boundedAdd(normalizedInteger(snapshot.truncation.availablePeers) ?? 0, Math.max(0, validPeers.length - DASHBOARD_MODEL_LIMITS.availablePeers)),
|
|
1139
1072
|
routes: boundedAdd(normalizedInteger(snapshot.truncation.routes) ?? 0, Math.max(0, allRoutes.length - DASHBOARD_MODEL_LIMITS.routes)),
|
|
1140
|
-
|
|
1073
|
+
consentEdges: boundedAdd(normalizedInteger(snapshot.truncation.consentEdges) ?? 0, Math.max(0, allConsentEdges.length - DASHBOARD_MODEL_LIMITS.consentEdges)),
|
|
1141
1074
|
progressWatches: boundedAdd(normalizedInteger(snapshot.truncation.progressWatches) ?? 0, Math.max(0, allWatches.length - DASHBOARD_MODEL_LIMITS.progressWatches)),
|
|
1142
1075
|
upstreamProgressWatchEvents: normalizedInteger(snapshot.truncation.progressWatchEvents) ?? 0,
|
|
1143
1076
|
progressWatchEvents: Math.max(0, allWatchEvents.length - DASHBOARD_MODEL_LIMITS.progressWatchEvents),
|
|
@@ -1150,43 +1083,13 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1150
1083
|
activityEvents: Math.max(0, allBrokerActivity.length - DASHBOARD_MODEL_LIMITS.activityEvents),
|
|
1151
1084
|
};
|
|
1152
1085
|
return {
|
|
1153
|
-
schemaVersion:
|
|
1086
|
+
schemaVersion: 2,
|
|
1154
1087
|
...(generatedAt === undefined ? {} : { generatedAt }),
|
|
1155
1088
|
inboundMode,
|
|
1156
1089
|
health: snapshot.health,
|
|
1157
1090
|
overall,
|
|
1158
1091
|
exchange: {
|
|
1159
|
-
|
|
1160
|
-
kind: "claude",
|
|
1161
|
-
status: selectedClaudeCount > 0 && claudeStatus === "missing"
|
|
1162
|
-
? "attention"
|
|
1163
|
-
: claudeStatus,
|
|
1164
|
-
total: validPeers.length,
|
|
1165
|
-
ready: selectedClaudeCount,
|
|
1166
|
-
selectable: selectablePeers.length,
|
|
1167
|
-
countIsLowerBound: (normalizedInteger(snapshot.truncation.availablePeers) ?? 0) > 0 ||
|
|
1168
|
-
(normalizedInteger(snapshot.truncation.routes) ?? 0) > 0,
|
|
1169
|
-
...(selectedPeers[0]?.alias === undefined
|
|
1170
|
-
? claudeRoutes[0]?.alias === undefined
|
|
1171
|
-
? {}
|
|
1172
|
-
: { primaryAlias: boundedText(claudeRoutes[0].alias) }
|
|
1173
|
-
: { primaryAlias: boundedText(selectedPeers[0].alias) }),
|
|
1174
|
-
nextAction: claudeNextAction,
|
|
1175
|
-
},
|
|
1176
|
-
codex: {
|
|
1177
|
-
kind: "codex",
|
|
1178
|
-
status: codexStatus,
|
|
1179
|
-
total: codexRoutes.length,
|
|
1180
|
-
ready: readyCodex,
|
|
1181
|
-
...(monitorOnlyCodexRoutes.length === 0
|
|
1182
|
-
? {}
|
|
1183
|
-
: { monitorOnly: monitorOnlyCodexRoutes.length }),
|
|
1184
|
-
countIsLowerBound: (normalizedInteger(snapshot.truncation.routes) ?? 0) > 0,
|
|
1185
|
-
...(codexRoutes[0]?.alias === undefined
|
|
1186
|
-
? {}
|
|
1187
|
-
: { primaryAlias: codexRoutes[0].alias }),
|
|
1188
|
-
nextAction: codexNextAction,
|
|
1189
|
-
},
|
|
1092
|
+
parties,
|
|
1190
1093
|
queuedMessages,
|
|
1191
1094
|
queueCountIsLowerBound: (normalizedInteger(snapshot.truncation.routes) ?? 0) > 0,
|
|
1192
1095
|
...(oldest === undefined
|
|
@@ -1213,12 +1116,11 @@ function buildProjectedDashboardViewModel(snapshot, includeBodies, options) {
|
|
|
1213
1116
|
brokerActivity,
|
|
1214
1117
|
peers,
|
|
1215
1118
|
routes,
|
|
1216
|
-
|
|
1119
|
+
consentEdges,
|
|
1217
1120
|
watches,
|
|
1218
1121
|
watchEvents,
|
|
1219
1122
|
graph,
|
|
1220
1123
|
connectors,
|
|
1221
|
-
compatibilityChecks,
|
|
1222
1124
|
accounting: {
|
|
1223
1125
|
accepted: normalizedInteger(snapshot.accounting.accepted) ?? 0,
|
|
1224
1126
|
duplicates: normalizedInteger(snapshot.accounting.duplicates) ?? 0,
|