agent-embassy 1.0.0 → 1.3.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 +68 -0
- package/CONTRIBUTING.md +25 -7
- package/README.md +66 -13
- package/README.zh-CN.md +41 -13
- package/SECURITY.md +80 -42
- package/assets/live-dashboard/app.css +14 -5
- package/dist/src/gateway/claude-helper-protocol.d.ts +3 -0
- package/dist/src/gateway/claude-helper-protocol.js +15 -1
- package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
- package/dist/src/gateway/claude-helper-supervisor.d.ts +2 -0
- package/dist/src/gateway/claude-helper-supervisor.js +24 -1
- package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
- package/dist/src/gateway/claude-runtime.d.ts +0 -2
- package/dist/src/gateway/claude-runtime.js +6 -17
- 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 +4 -1
- package/dist/src/gateway/cli-copy.en.js +6 -3
- package/dist/src/gateway/cli-copy.en.js.map +1 -1
- package/dist/src/gateway/cli-copy.js +2 -0
- package/dist/src/gateway/cli-copy.js.map +1 -1
- package/dist/src/gateway/cli-copy.zh-CN.d.ts +4 -1
- package/dist/src/gateway/cli-copy.zh-CN.js +6 -3
- package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/cli.d.ts +2 -5
- package/dist/src/gateway/cli.js +49 -73
- package/dist/src/gateway/cli.js.map +1 -1
- package/dist/src/gateway/codex-app-server.d.ts +1 -7
- package/dist/src/gateway/codex-app-server.js +10 -53
- package/dist/src/gateway/codex-app-server.js.map +1 -1
- package/dist/src/gateway/codex-local-transport.d.ts +10 -3
- package/dist/src/gateway/codex-local-transport.js +25 -9
- package/dist/src/gateway/codex-local-transport.js.map +1 -1
- package/dist/src/gateway/compatibility.d.ts +0 -27
- package/dist/src/gateway/compatibility.js +1 -101
- package/dist/src/gateway/compatibility.js.map +1 -1
- package/dist/src/gateway/config.d.ts +0 -3
- package/dist/src/gateway/config.js +4 -12
- package/dist/src/gateway/config.js.map +1 -1
- package/dist/src/gateway/control.d.ts +11 -20
- package/dist/src/gateway/control.js +50 -47
- 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 +12 -7
- package/dist/src/gateway/dashboard-copy.en.js +26 -21
- package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.js +12 -7
- package/dist/src/gateway/dashboard-copy.js.map +1 -1
- package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +12 -7
- package/dist/src/gateway/dashboard-copy.zh-CN.js +26 -21
- package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
- package/dist/src/gateway/dashboard-model.d.ts +7 -9
- package/dist/src/gateway/dashboard-model.js +47 -16
- package/dist/src/gateway/dashboard-model.js.map +1 -1
- package/dist/src/gateway/dashboard.js +10 -10
- package/dist/src/gateway/dashboard.js.map +1 -1
- package/dist/src/gateway/live-dashboard-app/app.js +65 -55
- package/dist/src/gateway/live-dashboard-command.d.ts +5 -1
- package/dist/src/gateway/live-dashboard-command.js +18 -6
- package/dist/src/gateway/live-dashboard-command.js.map +1 -1
- package/dist/src/gateway/live-dashboard-http.d.ts +3 -4
- package/dist/src/gateway/live-dashboard-http.js +32 -93
- package/dist/src/gateway/live-dashboard-http.js.map +1 -1
- package/dist/src/gateway/live-dashboard-protocol.d.ts +1 -5
- package/dist/src/gateway/live-dashboard-protocol.js +0 -42
- package/dist/src/gateway/live-dashboard-protocol.js.map +1 -1
- package/dist/src/gateway/live-dashboard-server.d.ts +2 -2
- package/dist/src/gateway/live-dashboard-server.js +18 -4
- package/dist/src/gateway/live-dashboard-server.js.map +1 -1
- package/dist/src/gateway/live-dashboard-stream.js +26 -25
- package/dist/src/gateway/live-dashboard-stream.js.map +1 -1
- package/dist/src/gateway/live-dashboard.d.ts +3 -6
- package/dist/src/gateway/live-dashboard.js +6 -42
- package/dist/src/gateway/live-dashboard.js.map +1 -1
- package/dist/src/gateway/provenance-envelope.d.ts +16 -0
- package/dist/src/gateway/provenance-envelope.js +80 -0
- package/dist/src/gateway/provenance-envelope.js.map +1 -0
- package/dist/src/gateway/providers.d.ts +40 -33
- package/dist/src/gateway/providers.js +683 -302
- package/dist/src/gateway/providers.js.map +1 -1
- package/dist/src/gateway/server.d.ts +2 -0
- package/dist/src/gateway/server.js +8 -5
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +103 -23
- package/dist/src/gateway/service.js +1346 -272
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/store.d.ts +39 -3
- package/dist/src/gateway/store.js +604 -44
- package/dist/src/gateway/store.js.map +1 -1
- package/dist/src/gateway/types.d.ts +90 -9
- package/dist/src/gateway/types.js +6 -0
- package/dist/src/gateway/types.js.map +1 -1
- package/docs/GATEWAY-ARCHITECTURE.md +155 -56
- package/package.json +3 -2
- package/skills/embassy-peer/SKILL.md +36 -7
- package/dist/src/gateway/claude-compatibility-scratch.d.ts +0 -18
- package/dist/src/gateway/claude-compatibility-scratch.js +0 -158
- package/dist/src/gateway/claude-compatibility-scratch.js.map +0 -1
- package/dist/src/gateway/live-dashboard-bootstrap.d.ts +0 -36
- package/dist/src/gateway/live-dashboard-bootstrap.js +0 -176
- package/dist/src/gateway/live-dashboard-bootstrap.js.map +0 -1
- package/docs/DESIGN.md +0 -134
|
@@ -162,6 +162,7 @@ var Embassy;
|
|
|
162
162
|
connecting: "progress",
|
|
163
163
|
paused: "inert",
|
|
164
164
|
unavailable: "warning",
|
|
165
|
+
capacity: "warning",
|
|
165
166
|
disconnected: "warning",
|
|
166
167
|
stopped: "warning",
|
|
167
168
|
};
|
|
@@ -512,6 +513,7 @@ var Embassy;
|
|
|
512
513
|
connector_offline: "connectorOffline",
|
|
513
514
|
route_stale: "routeStale",
|
|
514
515
|
queue_stalled: "queueStalled",
|
|
516
|
+
recipient_waiting_input: "recipientWaitingInput",
|
|
515
517
|
unconfirmed: "unconfirmed",
|
|
516
518
|
degraded: "degraded",
|
|
517
519
|
codex_succession_busy: "codexSuccessionBusy",
|
|
@@ -702,11 +704,9 @@ var Embassy;
|
|
|
702
704
|
const MAX_AUTO_RECONNECT_ATTEMPTS = 3;
|
|
703
705
|
const MAX_STREAM_BUFFER_LENGTH = 1_048_576;
|
|
704
706
|
function createProtocol(options) {
|
|
705
|
-
const base = location.pathname.endsWith("/
|
|
706
|
-
? location.pathname.slice(0, -
|
|
707
|
-
: location.pathname
|
|
708
|
-
? location.pathname.slice(0, -1)
|
|
709
|
-
: location.pathname;
|
|
707
|
+
const base = location.pathname.endsWith("/")
|
|
708
|
+
? location.pathname.slice(0, -1)
|
|
709
|
+
: location.pathname;
|
|
710
710
|
const api = (name) => base + "/" + name;
|
|
711
711
|
let connectionState = "connecting";
|
|
712
712
|
let controller;
|
|
@@ -718,7 +718,7 @@ var Embassy;
|
|
|
718
718
|
function apiFetch(name, fetchOptions = {}) {
|
|
719
719
|
const init = {
|
|
720
720
|
method: "POST",
|
|
721
|
-
credentials: "
|
|
721
|
+
credentials: "omit",
|
|
722
722
|
cache: "no-store",
|
|
723
723
|
headers: { "X-Embassy-Request": "1", ...(fetchOptions.headers ?? {}) },
|
|
724
724
|
};
|
|
@@ -797,20 +797,6 @@ var Embassy;
|
|
|
797
797
|
}
|
|
798
798
|
}
|
|
799
799
|
}
|
|
800
|
-
async function exchangeCapability() {
|
|
801
|
-
const capability = location.hash.slice(1);
|
|
802
|
-
if (!capability) {
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
history.replaceState(null, "", location.pathname);
|
|
806
|
-
const response = await apiFetch("session", {
|
|
807
|
-
headers: { "Content-Type": "text/plain;charset=UTF-8" },
|
|
808
|
-
body: capability,
|
|
809
|
-
});
|
|
810
|
-
if (!response.ok) {
|
|
811
|
-
throw new Error("session");
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
800
|
function consumeSseBlock(block) {
|
|
815
801
|
let event = "message";
|
|
816
802
|
const data = [];
|
|
@@ -843,6 +829,10 @@ var Embassy;
|
|
|
843
829
|
setConnectionState("connecting");
|
|
844
830
|
try {
|
|
845
831
|
const response = await apiFetch("stream", { signal: current.signal });
|
|
832
|
+
if (response.status === 429) {
|
|
833
|
+
setConnectionState("capacity");
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
846
836
|
if (!response.ok || !response.body) {
|
|
847
837
|
throw new Error("stream");
|
|
848
838
|
}
|
|
@@ -926,13 +916,6 @@ var Embassy;
|
|
|
926
916
|
return result;
|
|
927
917
|
}
|
|
928
918
|
async function start() {
|
|
929
|
-
try {
|
|
930
|
-
await exchangeCapability();
|
|
931
|
-
}
|
|
932
|
-
catch {
|
|
933
|
-
setConnectionState("disconnected");
|
|
934
|
-
return;
|
|
935
|
-
}
|
|
936
919
|
await connect();
|
|
937
920
|
}
|
|
938
921
|
return {
|
|
@@ -1429,7 +1412,7 @@ var Embassy;
|
|
|
1429
1412
|
}))) : null),
|
|
1430
1413
|
React.createElement("div", null,
|
|
1431
1414
|
React.createElement(Embassy.MonoLabel, { className: "section-label section-label--body" }, t("app.deliveries.bodyLabel")),
|
|
1432
|
-
React.createElement("p", { className: "detail-pane__sub" }, t("app.deliveries.bodiesNote"))),
|
|
1415
|
+
group.body === undefined ? (React.createElement("p", { className: "detail-pane__sub" }, t("app.deliveries.bodiesNote"))) : (React.createElement("pre", { className: "detail-pane__message-body" }, group.body))),
|
|
1433
1416
|
React.createElement("div", null,
|
|
1434
1417
|
React.createElement(Embassy.MonoLabel, { className: "section-label section-label--frames" }, t("app.deliveries.frames")),
|
|
1435
1418
|
frames.length === 0 ? (React.createElement("p", { className: "detail-pane__sub" }, t("app.deliveries.noFrames"))) : (React.createElement("div", { className: "frames-list" }, frames.map((event) => (React.createElement("div", { className: "frame-item", key: event.sequence },
|
|
@@ -1699,6 +1682,10 @@ var Embassy;
|
|
|
1699
1682
|
function rowIdentity(alias, host) {
|
|
1700
1683
|
return `${alias}\u0000${host}`;
|
|
1701
1684
|
}
|
|
1685
|
+
function canRequestStaleCodexRegistrationRemoval(route) {
|
|
1686
|
+
return route.provider === "codex" && route.state === "stale";
|
|
1687
|
+
}
|
|
1688
|
+
Embassy.canRequestStaleCodexRegistrationRemoval = canRequestStaleCodexRegistrationRemoval;
|
|
1702
1689
|
function topologyRowCenterY(index) {
|
|
1703
1690
|
return (TOPOLOGY_PADDING_PX +
|
|
1704
1691
|
index * TOPOLOGY_ROW_HEIGHT_PX +
|
|
@@ -1901,7 +1888,13 @@ var Embassy;
|
|
|
1901
1888
|
route.safeErrorCode === undefined ? null : (React.createElement(DetailRow, { label: t("column.issue") },
|
|
1902
1889
|
React.createElement("span", { className: "detail-value detail-value--mono" }, route.safeErrorCode))),
|
|
1903
1890
|
React.createElement(AbsentDetail, { fields: ["policy", "identity lock", "registered"] }),
|
|
1904
|
-
React.createElement(RouteCountersTable, { alias: route.alias, counters: route.counters })
|
|
1891
|
+
React.createElement(RouteCountersTable, { alias: route.alias, counters: route.counters }),
|
|
1892
|
+
canRequestStaleCodexRegistrationRemoval(route) ? (React.createElement(ActionControl, { action: {
|
|
1893
|
+
action: "remove_stale_codex_registration",
|
|
1894
|
+
alias: route.alias,
|
|
1895
|
+
}, consequence: t("app.routes.removeStaleCodex.consequence", {
|
|
1896
|
+
alias: route.alias,
|
|
1897
|
+
}), enabled: props.actionsEnabled, onAction: props.onAction })) : null));
|
|
1905
1898
|
}
|
|
1906
1899
|
function successionScope(item, t) {
|
|
1907
1900
|
const parts = [];
|
|
@@ -1942,6 +1935,8 @@ var Embassy;
|
|
|
1942
1935
|
return "live.action.pair";
|
|
1943
1936
|
case "unpair":
|
|
1944
1937
|
return "live.action.unpair";
|
|
1938
|
+
case "remove_stale_codex_registration":
|
|
1939
|
+
return "live.action.removeStaleCodexRegistration";
|
|
1945
1940
|
case "refresh_dashboard":
|
|
1946
1941
|
return "live.action.refresh";
|
|
1947
1942
|
}
|
|
@@ -1951,18 +1946,34 @@ var Embassy;
|
|
|
1951
1946
|
const [confirming, setConfirming] = React.useState(false);
|
|
1952
1947
|
const [pending, setPending] = React.useState(false);
|
|
1953
1948
|
const [result, setResult] = React.useState(undefined);
|
|
1954
|
-
const actionIdentity =
|
|
1955
|
-
|
|
1956
|
-
|
|
1949
|
+
const actionIdentity = (() => {
|
|
1950
|
+
switch (props.action.action) {
|
|
1951
|
+
case "refresh_dashboard":
|
|
1952
|
+
return props.action.action;
|
|
1953
|
+
case "remove_stale_codex_registration":
|
|
1954
|
+
return `${props.action.action}:${props.action.alias}`;
|
|
1955
|
+
case "pair":
|
|
1956
|
+
case "unpair":
|
|
1957
|
+
return `${props.action.action}:${props.action.claudeAlias}:${props.action.codexAlias}`;
|
|
1958
|
+
}
|
|
1959
|
+
})();
|
|
1957
1960
|
React.useEffect(() => {
|
|
1958
1961
|
setConfirming(false);
|
|
1959
1962
|
setPending(false);
|
|
1960
1963
|
setResult(undefined);
|
|
1961
1964
|
}, [actionIdentity]);
|
|
1962
1965
|
const baseLabel = t(actionLabelKey(props.action));
|
|
1963
|
-
const label =
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
+
const label = (() => {
|
|
1967
|
+
switch (props.action.action) {
|
|
1968
|
+
case "refresh_dashboard":
|
|
1969
|
+
return baseLabel;
|
|
1970
|
+
case "remove_stale_codex_registration":
|
|
1971
|
+
return `${baseLabel}: ${props.action.alias}`;
|
|
1972
|
+
case "pair":
|
|
1973
|
+
case "unpair":
|
|
1974
|
+
return `${baseLabel}: ${props.action.claudeAlias} ↔ ${props.action.codexAlias}`;
|
|
1975
|
+
}
|
|
1976
|
+
})();
|
|
1966
1977
|
const confirm = async () => {
|
|
1967
1978
|
if (!props.enabled || pending)
|
|
1968
1979
|
return;
|
|
@@ -2072,7 +2083,7 @@ var Embassy;
|
|
|
2072
2083
|
data.codexRoutes.length === 0 ? (React.createElement("div", { className: "empty-state" },
|
|
2073
2084
|
React.createElement("p", { className: "empty-state__text" }, t("app.routes.noCodex")))) : (React.createElement("div", null, data.codexRoutes.map((view, index) => {
|
|
2074
2085
|
const identity = rowIdentity(view.route.alias, view.route.host);
|
|
2075
|
-
return (React.createElement(CodexAccordionRow, { key: `${identity}|${index}`, view: view, open: openRoute === identity, onToggle: () => {
|
|
2086
|
+
return (React.createElement(CodexAccordionRow, { key: `${identity}|${index}`, view: view, open: openRoute === identity, actionsEnabled: props.actionsEnabled, onAction: props.onAction, onToggle: () => {
|
|
2076
2087
|
setOpenRoute(openRoute === identity ? undefined : identity);
|
|
2077
2088
|
} }));
|
|
2078
2089
|
}))),
|
|
@@ -2111,9 +2122,15 @@ var Embassy;
|
|
|
2111
2122
|
routes_paired: "app.activity.operation.routesPaired",
|
|
2112
2123
|
routes_unpaired: "app.activity.operation.routesUnpaired",
|
|
2113
2124
|
watch_ended: "app.activity.operation.watchEnded",
|
|
2125
|
+
endpoint_refreshed: "app.activity.operation.endpointRefreshed",
|
|
2126
|
+
codex_orphan_removed: "app.activity.operation.codexOrphanRemoved",
|
|
2114
2127
|
};
|
|
2115
2128
|
const ACTIVITY_EMPTY_COMMAND = "embassy send-to-codex --from <alias> --to <alias>";
|
|
2116
2129
|
const activityCountFormatters = new Map();
|
|
2130
|
+
function activityAuthority(event) {
|
|
2131
|
+
return event.operatorAction ? "operator" : "automatic";
|
|
2132
|
+
}
|
|
2133
|
+
Embassy.activityAuthority = activityAuthority;
|
|
2117
2134
|
function formatCount(count, locale) {
|
|
2118
2135
|
const existing = activityCountFormatters.get(locale);
|
|
2119
2136
|
if (existing !== undefined)
|
|
@@ -2208,8 +2225,12 @@ var Embassy;
|
|
|
2208
2225
|
function OperationEntryText(props) {
|
|
2209
2226
|
const t = Embassy.useT();
|
|
2210
2227
|
const event = props.event;
|
|
2211
|
-
|
|
2228
|
+
const authority = activityAuthority(event);
|
|
2229
|
+
return (React.createElement("div", { className: "activity-text stack-sm", "data-activity-authority": authority },
|
|
2212
2230
|
React.createElement("div", { className: "chip-row" },
|
|
2231
|
+
React.createElement("span", { className: "chip chip--small", "data-kind": "inert" }, t(authority === "operator"
|
|
2232
|
+
? "app.activity.operation.operator"
|
|
2233
|
+
: "app.activity.operation.automatic")),
|
|
2213
2234
|
React.createElement("span", null, t(OPERATION_COPY_KEYS[event.action])),
|
|
2214
2235
|
React.createElement("span", { className: "mono text-muted" }, t(event.outcome === "accepted"
|
|
2215
2236
|
? "app.activity.operation.accepted"
|
|
@@ -2351,12 +2372,10 @@ var Embassy;
|
|
|
2351
2372
|
React.createElement("th", { scope: "col" }, t("diagnostics.version")),
|
|
2352
2373
|
React.createElement("th", { scope: "col" }, t("diagnostics.tier")),
|
|
2353
2374
|
React.createElement("th", { scope: "col" }, t("diagnostics.checkedAt")),
|
|
2354
|
-
React.createElement("th", { scope: "col" }, t("diagnostics.
|
|
2355
|
-
React.createElement("th", { scope: "col" }, t("diagnostics.certifiedAt")),
|
|
2356
|
-
React.createElement("th", { scope: "col" }, t("diagnostics.failedProbe")),
|
|
2375
|
+
React.createElement("th", { scope: "col" }, t("diagnostics.failure")),
|
|
2357
2376
|
React.createElement("th", { scope: "col" }, t("column.issue")))),
|
|
2358
2377
|
React.createElement("tbody", null, props.checks.length === 0 ? (React.createElement("tr", null,
|
|
2359
|
-
React.createElement("td", { colSpan:
|
|
2378
|
+
React.createElement("td", { colSpan: 6 }, t("diagnostics.compatibilityChecks.empty")))) : (props.checks.map((check) => (React.createElement("tr", { key: check.surface },
|
|
2360
2379
|
React.createElement("th", { scope: "row" }, check.surface === "claude"
|
|
2361
2380
|
? t("provider.claude")
|
|
2362
2381
|
: t("provider.codex")),
|
|
@@ -2364,16 +2383,8 @@ var Embassy;
|
|
|
2364
2383
|
React.createElement("td", null, t(`compatibilityTier.${check.tier}`)),
|
|
2365
2384
|
React.createElement("td", null,
|
|
2366
2385
|
React.createElement(Embassy.TimeAgo, { iso: check.checkedAt })),
|
|
2367
|
-
React.createElement("td", { className: "cell-mono" }, check.
|
|
2368
|
-
|
|
2369
|
-
: `${check.certificationOutcome} / ${check.certificationDepth}`),
|
|
2370
|
-
React.createElement("td", null, check.certifiedAt === undefined
|
|
2371
|
-
? DIAGNOSTICS_ABSENT_FIELD
|
|
2372
|
-
: React.createElement(Embassy.TimeAgo, { iso: check.certifiedAt })),
|
|
2373
|
-
React.createElement("td", { className: "cell-mono" }, check.failedProbe ?? DIAGNOSTICS_ABSENT_FIELD),
|
|
2374
|
-
React.createElement("td", { className: "cell-mono" }, check.certificationSafeErrorCode ??
|
|
2375
|
-
check.safeErrorCode ??
|
|
2376
|
-
DIAGNOSTICS_ABSENT_FIELD)))))))));
|
|
2386
|
+
React.createElement("td", { className: "cell-mono" }, check.failure ?? DIAGNOSTICS_ABSENT_FIELD),
|
|
2387
|
+
React.createElement("td", { className: "cell-mono" }, check.safeErrorCode ?? DIAGNOSTICS_ABSENT_FIELD)))))))));
|
|
2377
2388
|
}
|
|
2378
2389
|
function DiagnosticsCounterTable(props) {
|
|
2379
2390
|
return (React.createElement("div", { className: "table-wrap counters-list" },
|
|
@@ -2637,11 +2648,10 @@ var Embassy;
|
|
|
2637
2648
|
React.createElement(DiagnosticsConnectorTable, { connectors: data.connectors }),
|
|
2638
2649
|
React.createElement("p", { className: "footnote" }, t("app.diag.versions.rangeAbsent")))),
|
|
2639
2650
|
React.createElement("div", { className: "grid-2" },
|
|
2640
|
-
React.createElement("section", { className: "card", "aria-labelledby": "compatibility-
|
|
2651
|
+
React.createElement("section", { className: "card", "aria-labelledby": "provider-compatibility-title" },
|
|
2641
2652
|
React.createElement("div", { className: "card__head" },
|
|
2642
|
-
React.createElement("h3", { className: "card__title", id: "compatibility-
|
|
2643
|
-
React.createElement(DiagnosticsCompatibilityTable, { checks: data.compatibilityChecks }),
|
|
2644
|
-
React.createElement(Embassy.CopyCmd, { cmd: "embassy compat-check" })),
|
|
2653
|
+
React.createElement("h3", { className: "card__title", id: "provider-compatibility-title" }, t("app.diag.providerCompatibility.title"))),
|
|
2654
|
+
React.createElement(DiagnosticsCompatibilityTable, { checks: data.compatibilityChecks })),
|
|
2645
2655
|
React.createElement(Embassy.AbsentFeature, { title: t("app.diag.lease.title"), body: t("app.diag.lease.absent"), cmd: "embassy status" })),
|
|
2646
2656
|
React.createElement("section", { className: "section", "aria-labelledby": limitsHeadingId },
|
|
2647
2657
|
React.createElement("h2", { className: "mono-label section-label", id: limitsHeadingId }, t("app.diag.limits")),
|
|
@@ -7,11 +7,13 @@ import type { LiveDashboardObserver } from "./live-dashboard-stream.js";
|
|
|
7
7
|
declare const OPEN_EXECUTABLE = "/usr/bin/open";
|
|
8
8
|
declare const OPEN_TIMEOUT_MS = 10000;
|
|
9
9
|
declare const OPEN_MAX_OUTPUT_BYTES: number;
|
|
10
|
+
export declare const DEFAULT_LIVE_DASHBOARD_PORT = 41961;
|
|
10
11
|
type GatewaySignal = "SIGINT" | "SIGTERM";
|
|
11
12
|
export type LiveDashboardReadyResult = Readonly<{
|
|
12
13
|
status: "ready";
|
|
13
14
|
mode: "live";
|
|
14
15
|
locale: DashboardLocale;
|
|
16
|
+
url: string;
|
|
15
17
|
}>;
|
|
16
18
|
export type LiveDashboardCommandOutcome = Readonly<{
|
|
17
19
|
status: "cancelled";
|
|
@@ -19,6 +21,8 @@ export type LiveDashboardCommandOutcome = Readonly<{
|
|
|
19
21
|
export type LiveDashboardCommandOptions = Readonly<{
|
|
20
22
|
env?: NodeJS.ProcessEnv;
|
|
21
23
|
locale: DashboardLocale;
|
|
24
|
+
/** Explicit CLI-selected port; omitted direct callers receive the default. */
|
|
25
|
+
port?: number;
|
|
22
26
|
signal?: AbortSignal;
|
|
23
27
|
onReady: (result: LiveDashboardReadyResult) => void | Promise<void>;
|
|
24
28
|
loadConfig?: (env: NodeJS.ProcessEnv) => GatewayConfig;
|
|
@@ -47,7 +51,7 @@ export declare function createGatewayLiveDashboardActions(socketPath: string, se
|
|
|
47
51
|
* Run the opt-in live dashboard in the foreground until interrupted.
|
|
48
52
|
*
|
|
49
53
|
* The controller remains the only source of state. This command exposes one
|
|
50
|
-
* observer plus
|
|
54
|
+
* observer plus four closed actions; it has no provider API
|
|
51
55
|
* or generic control-plane escape hatch.
|
|
52
56
|
*/
|
|
53
57
|
export declare function runLiveDashboardCommand(options: LiveDashboardCommandOptions, dependencies?: LiveDashboardCommandDependencies): Promise<LiveDashboardCommandOutcome>;
|
|
@@ -11,6 +11,7 @@ const OPEN_ENVIRONMENT = Object.freeze({
|
|
|
11
11
|
LANG: "C",
|
|
12
12
|
LC_ALL: "C",
|
|
13
13
|
});
|
|
14
|
+
export const DEFAULT_LIVE_DASHBOARD_PORT = 41_961;
|
|
14
15
|
function defaultOpenExecutor(executable, args, options) {
|
|
15
16
|
return new Promise((resolve, reject) => {
|
|
16
17
|
execFile(executable, [...args], options, (error) => {
|
|
@@ -166,6 +167,16 @@ export function createGatewayLiveDashboardActions(socketPath, sendRequest = send
|
|
|
166
167
|
},
|
|
167
168
|
});
|
|
168
169
|
break;
|
|
170
|
+
case "remove_stale_codex_registration":
|
|
171
|
+
response = await sendRequest({
|
|
172
|
+
socketPath,
|
|
173
|
+
request: {
|
|
174
|
+
protocolVersion: GATEWAY_CONTROL_PROTOCOL_VERSION,
|
|
175
|
+
method: "remove_stale_codex_registration",
|
|
176
|
+
params: { alias: action.alias },
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
break;
|
|
169
180
|
case "refresh_dashboard":
|
|
170
181
|
response = await sendRequest({
|
|
171
182
|
socketPath,
|
|
@@ -190,9 +201,9 @@ export function createGatewayLiveDashboardActions(socketPath, sendRequest = send
|
|
|
190
201
|
},
|
|
191
202
|
};
|
|
192
203
|
}
|
|
193
|
-
async function
|
|
204
|
+
async function openLiveDashboard(url, executeOpen, signal) {
|
|
194
205
|
try {
|
|
195
|
-
await executeOpen(OPEN_EXECUTABLE, [
|
|
206
|
+
await executeOpen(OPEN_EXECUTABLE, [url], {
|
|
196
207
|
cwd: "/",
|
|
197
208
|
env: OPEN_ENVIRONMENT,
|
|
198
209
|
shell: false,
|
|
@@ -217,7 +228,7 @@ function ownLateStartup(outcome) {
|
|
|
217
228
|
* Run the opt-in live dashboard in the foreground until interrupted.
|
|
218
229
|
*
|
|
219
230
|
* The controller remains the only source of state. This command exposes one
|
|
220
|
-
* observer plus
|
|
231
|
+
* observer plus four closed actions; it has no provider API
|
|
221
232
|
* or generic control-plane escape hatch.
|
|
222
233
|
*/
|
|
223
234
|
export async function runLiveDashboardCommand(options, dependencies = {}) {
|
|
@@ -243,17 +254,17 @@ export async function runLiveDashboardCommand(options, dependencies = {}) {
|
|
|
243
254
|
latch = createShutdownLatch(options.signal, addSignalListener, removeSignalListener);
|
|
244
255
|
if (!latch.isStopped()) {
|
|
245
256
|
const startup = startDashboard({
|
|
246
|
-
|
|
257
|
+
port: options.port ?? DEFAULT_LIVE_DASHBOARD_PORT,
|
|
247
258
|
observer: createGatewayLiveDashboardObserver(config.controlSocketPath, sendRequest),
|
|
248
259
|
actions: createGatewayLiveDashboardActions(config.controlSocketPath, sendRequest),
|
|
249
260
|
locale: options.locale,
|
|
250
261
|
signal: latch.signal,
|
|
251
262
|
dependencies: {
|
|
252
|
-
|
|
263
|
+
openDashboard: async (url) => {
|
|
253
264
|
if (latch?.isStopped() !== false) {
|
|
254
265
|
throw new Error("LIVE_DASHBOARD_START_CANCELLED");
|
|
255
266
|
}
|
|
256
|
-
await
|
|
267
|
+
await openLiveDashboard(url, executeOpen, latch.signal);
|
|
257
268
|
},
|
|
258
269
|
},
|
|
259
270
|
})
|
|
@@ -287,6 +298,7 @@ export async function runLiveDashboardCommand(options, dependencies = {}) {
|
|
|
287
298
|
status: "ready",
|
|
288
299
|
mode: "live",
|
|
289
300
|
locale: options.locale,
|
|
301
|
+
url: running.url,
|
|
290
302
|
});
|
|
291
303
|
await latch.wait;
|
|
292
304
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-dashboard-command.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAsB,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,gCAAgC,EAChC,yBAAyB,GAI1B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,+BAA+B,EAC/B,kBAAkB,GAGnB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,eAAe,GAAG,eAAe,CAAC;AACxC,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;AACxC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,GAAG;IACT,MAAM,EAAE,GAAG;CACZ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"live-dashboard-command.js","sourceRoot":"","sources":["../../../src/gateway/live-dashboard-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,9 @@ export type LiveDashboardAction = Readonly<{
|
|
|
15
15
|
action: "pair" | "unpair";
|
|
16
16
|
claudeAlias: string;
|
|
17
17
|
codexAlias: string;
|
|
18
|
+
}> | Readonly<{
|
|
19
|
+
action: "remove_stale_codex_registration";
|
|
20
|
+
alias: string;
|
|
18
21
|
}> | Readonly<{
|
|
19
22
|
action: "refresh_dashboard";
|
|
20
23
|
}>;
|
|
@@ -26,12 +29,8 @@ export type LiveDashboardActionExecutor = Readonly<{
|
|
|
26
29
|
execute(action: LiveDashboardAction): Promise<LiveDashboardActionResult>;
|
|
27
30
|
}>;
|
|
28
31
|
export type LiveDashboardRequestHandlerOptions = Readonly<{
|
|
29
|
-
instancePath: string;
|
|
30
32
|
expectedHost: string;
|
|
31
33
|
expectedOrigin: string;
|
|
32
|
-
capability: string;
|
|
33
|
-
sessionSecret: string;
|
|
34
|
-
cookieName: string;
|
|
35
34
|
lang: DashboardLocale;
|
|
36
35
|
assets: LiveDashboardHttpAssets;
|
|
37
36
|
hub: LiveDashboardStreamHub;
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import { isGatewayAlias } from "./control.js";
|
|
2
2
|
import { assertDashboardLocale, getDashboardCopy, } from "./dashboard-copy.js";
|
|
3
|
-
import {
|
|
3
|
+
import { LIVE_DASHBOARD_LIMITS, liveDashboardSecurityHeaders, validateLiveDashboardRequest, } from "./live-dashboard-protocol.js";
|
|
4
4
|
const SHELL_CONTENT_SECURITY_POLICY = "default-src 'none'; script-src 'self'; style-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'";
|
|
5
|
-
function isCanonical256BitBase64Url(value) {
|
|
6
|
-
if (!/^[A-Za-z0-9_-]{43}$/u.test(value))
|
|
7
|
-
return false;
|
|
8
|
-
const decoded = Buffer.from(value, "base64url");
|
|
9
|
-
return decoded.length === 32 && decoded.toString("base64url") === value;
|
|
10
|
-
}
|
|
11
5
|
function assertOptions(options) {
|
|
12
6
|
assertDashboardLocale(options.lang);
|
|
13
|
-
if (!/^\/[A-Za-z0-9_-]{16,128}$/u.test(options.instancePath)) {
|
|
14
|
-
throw new Error("LIVE_DASHBOARD_INSTANCE_PATH_INVALID");
|
|
15
|
-
}
|
|
16
7
|
const hostMatch = /^127\.0\.0\.1:([1-9][0-9]{0,4})$/u.exec(options.expectedHost);
|
|
17
8
|
const port = Number(hostMatch?.[1]);
|
|
18
9
|
if (hostMatch === null ||
|
|
@@ -21,35 +12,27 @@ function assertOptions(options) {
|
|
|
21
12
|
options.expectedOrigin !== `http://${options.expectedHost}`) {
|
|
22
13
|
throw new Error("LIVE_DASHBOARD_ORIGIN_INVALID");
|
|
23
14
|
}
|
|
24
|
-
if (!isCanonical256BitBase64Url(options.capability)) {
|
|
25
|
-
throw new Error("LIVE_DASHBOARD_CAPABILITY_INVALID");
|
|
26
|
-
}
|
|
27
|
-
if (!isCanonical256BitBase64Url(options.sessionSecret)) {
|
|
28
|
-
throw new Error("LIVE_DASHBOARD_SESSION_SECRET_INVALID");
|
|
29
|
-
}
|
|
30
15
|
}
|
|
31
|
-
function routeFor(target
|
|
16
|
+
function routeFor(target) {
|
|
32
17
|
switch (target) {
|
|
33
|
-
case
|
|
34
|
-
return { kind: "navigation", name: "
|
|
35
|
-
case
|
|
18
|
+
case "/":
|
|
19
|
+
return { kind: "navigation", name: "shell" };
|
|
20
|
+
case "/client.js":
|
|
36
21
|
return { kind: "navigation", name: "client" };
|
|
37
|
-
case
|
|
22
|
+
case "/app.css":
|
|
38
23
|
return { kind: "navigation", name: "style" };
|
|
39
|
-
case
|
|
24
|
+
case "/react.js":
|
|
40
25
|
return { kind: "navigation", name: "vendorReact" };
|
|
41
|
-
case
|
|
26
|
+
case "/react-dom.js":
|
|
42
27
|
return { kind: "navigation", name: "vendorReactDom" };
|
|
43
|
-
case
|
|
28
|
+
case "/app.js":
|
|
44
29
|
return { kind: "navigation", name: "app" };
|
|
45
|
-
case
|
|
46
|
-
return { kind: "
|
|
47
|
-
case
|
|
48
|
-
return { kind: "
|
|
49
|
-
case
|
|
50
|
-
return { kind: "
|
|
51
|
-
case `${instancePath}/action`:
|
|
52
|
-
return { kind: "authenticated", name: "action" };
|
|
30
|
+
case "/snapshot":
|
|
31
|
+
return { kind: "api", name: "snapshot" };
|
|
32
|
+
case "/stream":
|
|
33
|
+
return { kind: "api", name: "stream" };
|
|
34
|
+
case "/action":
|
|
35
|
+
return { kind: "api", name: "action" };
|
|
53
36
|
default:
|
|
54
37
|
return undefined;
|
|
55
38
|
}
|
|
@@ -90,14 +73,6 @@ function respond(response, copy, statusCode, body = statusBody(copy, statusCode)
|
|
|
90
73
|
});
|
|
91
74
|
response.end(encoded);
|
|
92
75
|
}
|
|
93
|
-
function respondWithoutBody(response, statusCode, additionalHeaders = {}) {
|
|
94
|
-
response.writeHead(statusCode, {
|
|
95
|
-
...liveDashboardSecurityHeaders(),
|
|
96
|
-
"Content-Length": "0",
|
|
97
|
-
...additionalHeaders,
|
|
98
|
-
});
|
|
99
|
-
response.end();
|
|
100
|
-
}
|
|
101
76
|
function parseContentLength(value) {
|
|
102
77
|
if (value === undefined)
|
|
103
78
|
return undefined;
|
|
@@ -171,10 +146,6 @@ function validateEmptyPostBody(validation) {
|
|
|
171
146
|
}
|
|
172
147
|
return undefined;
|
|
173
148
|
}
|
|
174
|
-
function authenticated(validation, cookieName, sessionSecret) {
|
|
175
|
-
const supplied = readSingleCookie(validation.headers.get("cookie"), cookieName);
|
|
176
|
-
return equalSecret(supplied, sessionSecret);
|
|
177
|
-
}
|
|
178
149
|
function parseAction(body) {
|
|
179
150
|
let value;
|
|
180
151
|
try {
|
|
@@ -193,6 +164,19 @@ function parseAction(body) {
|
|
|
193
164
|
keys[0] === "action") {
|
|
194
165
|
return { action: "refresh_dashboard" };
|
|
195
166
|
}
|
|
167
|
+
if (record.action === "remove_stale_codex_registration" &&
|
|
168
|
+
keys.length === 2 &&
|
|
169
|
+
keys.includes("action") &&
|
|
170
|
+
keys.includes("alias") &&
|
|
171
|
+
typeof record.alias === "string" &&
|
|
172
|
+
record.alias.length <= 128 &&
|
|
173
|
+
isGatewayAlias(record.alias) &&
|
|
174
|
+
record.alias.startsWith("codex-")) {
|
|
175
|
+
return {
|
|
176
|
+
action: "remove_stale_codex_registration",
|
|
177
|
+
alias: record.alias,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
196
180
|
if ((record.action === "pair" || record.action === "unpair") &&
|
|
197
181
|
keys.length === 3 &&
|
|
198
182
|
keys.includes("action") &&
|
|
@@ -249,11 +233,9 @@ function streamWriter(response) {
|
|
|
249
233
|
}
|
|
250
234
|
export function createLiveDashboardRequestHandler(options) {
|
|
251
235
|
assertOptions(options);
|
|
252
|
-
const { actions, assets,
|
|
236
|
+
const { actions, assets, expectedHost, expectedOrigin, hub, lang, } = options;
|
|
253
237
|
const now = options.now ?? Date.now;
|
|
254
238
|
const copy = getDashboardCopy(lang);
|
|
255
|
-
const cookieHeader = sessionCookieHeader(cookieName, sessionSecret, instancePath);
|
|
256
|
-
let remainingCapability = options.capability;
|
|
257
239
|
let actionTokens = LIVE_DASHBOARD_LIMITS.maximumActionsPerMinute;
|
|
258
240
|
let actionRefilledAt = now();
|
|
259
241
|
const consumeActionToken = () => {
|
|
@@ -271,7 +253,7 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
271
253
|
};
|
|
272
254
|
return async (request, response) => {
|
|
273
255
|
try {
|
|
274
|
-
const route = routeFor(request.url
|
|
256
|
+
const route = routeFor(request.url);
|
|
275
257
|
const validation = validateLiveDashboardRequest({
|
|
276
258
|
method: request.method,
|
|
277
259
|
target: request.url,
|
|
@@ -280,7 +262,7 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
280
262
|
expectedHost,
|
|
281
263
|
expectedOrigin,
|
|
282
264
|
kind: route?.kind ??
|
|
283
|
-
(request.method === "GET" ? "navigation" : "
|
|
265
|
+
(request.method === "GET" ? "navigation" : "api"),
|
|
284
266
|
});
|
|
285
267
|
if (!validation.ok) {
|
|
286
268
|
respond(response, copy, validation.statusCode);
|
|
@@ -291,7 +273,7 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
291
273
|
return;
|
|
292
274
|
}
|
|
293
275
|
switch (route.name) {
|
|
294
|
-
case "
|
|
276
|
+
case "shell":
|
|
295
277
|
respond(response, copy, 200, assets.shellHtml, "text/html; charset=utf-8", {}, SHELL_CONTENT_SECURITY_POLICY);
|
|
296
278
|
return;
|
|
297
279
|
case "client":
|
|
@@ -309,47 +291,12 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
309
291
|
case "app":
|
|
310
292
|
respond(response, copy, 200, assets.appJavaScript, "text/javascript; charset=utf-8");
|
|
311
293
|
return;
|
|
312
|
-
case "session": {
|
|
313
|
-
const contentType = validation.headers.get("content-type");
|
|
314
|
-
if (contentType !== "text/plain" &&
|
|
315
|
-
contentType !== "text/plain;charset=UTF-8") {
|
|
316
|
-
respond(response, copy, 415);
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
const contentLength = parseContentLength(validation.headers.get("content-length"));
|
|
320
|
-
if (contentLength === undefined ||
|
|
321
|
-
!Number.isFinite(contentLength) ||
|
|
322
|
-
contentLength < 0) {
|
|
323
|
-
respond(response, copy, 400);
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
if (contentLength > LIVE_DASHBOARD_LIMITS.maximumSessionBodyBytes) {
|
|
327
|
-
respond(response, copy, 413);
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const body = await readBoundedBody(request, contentLength, LIVE_DASHBOARD_LIMITS.maximumSessionBodyBytes);
|
|
331
|
-
if (!body.ok) {
|
|
332
|
-
respond(response, copy, body.statusCode);
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
if (!equalSecret(body.body, remainingCapability)) {
|
|
336
|
-
respond(response, copy, 403);
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
remainingCapability = undefined;
|
|
340
|
-
respondWithoutBody(response, 204, { "Set-Cookie": cookieHeader });
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
294
|
case "snapshot": {
|
|
344
295
|
const bodyError = validateEmptyPostBody(validation);
|
|
345
296
|
if (bodyError !== undefined) {
|
|
346
297
|
respond(response, copy, bodyError);
|
|
347
298
|
return;
|
|
348
299
|
}
|
|
349
|
-
if (!authenticated(validation, cookieName, sessionSecret)) {
|
|
350
|
-
respond(response, copy, 403);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
300
|
const refreshed = await hub.refresh();
|
|
354
301
|
if (refreshed === undefined) {
|
|
355
302
|
respond(response, copy, 503);
|
|
@@ -364,10 +311,6 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
364
311
|
respond(response, copy, bodyError);
|
|
365
312
|
return;
|
|
366
313
|
}
|
|
367
|
-
if (!authenticated(validation, cookieName, sessionSecret)) {
|
|
368
|
-
respond(response, copy, 403);
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
314
|
if (hub.streamCount() >= LIVE_DASHBOARD_LIMITS.maximumStreams) {
|
|
372
315
|
respond(response, copy, 429);
|
|
373
316
|
return;
|
|
@@ -383,10 +326,6 @@ export function createLiveDashboardRequestHandler(options) {
|
|
|
383
326
|
return;
|
|
384
327
|
}
|
|
385
328
|
case "action": {
|
|
386
|
-
if (!authenticated(validation, cookieName, sessionSecret)) {
|
|
387
|
-
respond(response, copy, 403);
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
329
|
if (validation.headers.get("content-type") !== "application/json") {
|
|
391
330
|
respond(response, copy, 415);
|
|
392
331
|
return;
|