@openclaw/gateway-protocol 2026.8.1-beta.2 → 2026.9.1-beta.1
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 +1 -0
- package/dist/client-info.d.mts +20 -8
- package/dist/client-info.mjs +3 -2
- package/dist/connect-error-details.d.mts +5 -0
- package/dist/connect-error-details.mjs +37 -5
- package/dist/frame-guards.d.mts +1 -2
- package/dist/frame-guards.mjs +5 -4
- package/dist/{frames-B9De7i2H.d.mts → frames-BmksHL6e.d.mts} +12 -14
- package/dist/gateway-error-details-yO9RdEKe.d.mts +97 -0
- package/dist/gateway-error-details.d.mts +2 -2
- package/dist/gateway-error-details.mjs +39 -5
- package/dist/index.d.mts +970 -38
- package/dist/index.mjs +89 -12
- package/dist/protocol-value-normalization-DcAoxLUs.mjs +12 -0
- package/dist/record-coerce-BKHrZ46I.mjs +11 -0
- package/dist/restart-unavailable.d.mts +9 -0
- package/dist/restart-unavailable.mjs +13 -0
- package/dist/{schema-modules-VhRJPNg7.d.mts → schema-modules-BXS3PPpy.d.mts} +18507 -15299
- package/dist/schema.d.mts +2682 -116
- package/dist/schema.mjs +83 -3
- package/dist/{worktrees-CSLN5mQz.mjs → worktrees-D0vExqr5.mjs} +3241 -2127
- package/package.json +11 -3
- package/protocol.schema.json +19944 -1887
- package/dist/gateway-error-details-BXoMHq1i.d.mts +0 -64
- package/dist/protocol-value-normalization-Bexl3yr1.mjs +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,7 @@ version and the additive schema surface. Dates are authoring dates (2026).
|
|
|
14
14
|
- Slim worker and session-catalog payloads to the active wire contract.
|
|
15
15
|
- Remove dead protocol surfaces and add since-vintage metadata to retained schemas and methods.
|
|
16
16
|
- Add optional `step` on `SystemAgentChatResult` carrying the full awaited wizard step.
|
|
17
|
+
- Project plugin tab `placement` in `hello-ok` so active plugins can target native Control UI routes.
|
|
17
18
|
|
|
18
19
|
## Protocol v4 (current)
|
|
19
20
|
|
package/dist/client-info.d.mts
CHANGED
|
@@ -57,14 +57,25 @@ declare const GATEWAY_CLIENT_MODES: {
|
|
|
57
57
|
type GatewayClientMode = (typeof GATEWAY_CLIENT_MODES)[keyof typeof GATEWAY_CLIENT_MODES];
|
|
58
58
|
/** Client metadata sent during gateway connection setup. */
|
|
59
59
|
type GatewayClientInfo = {
|
|
60
|
-
/** Stable product/client identifier from `GATEWAY_CLIENT_IDS`. */
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
/** Stable product/client identifier from `GATEWAY_CLIENT_IDS`. */
|
|
61
|
+
id: GatewayClientId;
|
|
62
|
+
/** Human-readable label for diagnostics; not used for policy decisions. */
|
|
63
|
+
displayName?: string;
|
|
64
|
+
/** Client app or package version reported by the connecting process. */
|
|
65
|
+
version: string;
|
|
66
|
+
/** Exact immutable artifact identity when the client can report one. */
|
|
67
|
+
buildId?: string;
|
|
68
|
+
/** Runtime platform string, such as `darwin`, `ios`, `android`, or `web`. */
|
|
69
|
+
platform: string;
|
|
70
|
+
/** Optional device family used by native clients for display and routing hints. */
|
|
71
|
+
deviceFamily?: string;
|
|
72
|
+
/** Native hardware/model identifier when available. */
|
|
73
|
+
modelIdentifier?: string;
|
|
74
|
+
/** Self-reported IANA time zone, such as `Europe/Vienna`, for presence display. */
|
|
75
|
+
timeZone?: string;
|
|
76
|
+
/** Coarse category from `GATEWAY_CLIENT_MODES` for policy and diagnostics. */
|
|
77
|
+
mode: GatewayClientMode;
|
|
78
|
+
/** Per-installation or per-process id used to distinguish same-product clients. */
|
|
68
79
|
instanceId?: string;
|
|
69
80
|
};
|
|
70
81
|
/** Capability flags a client may advertise during the gateway handshake. */
|
|
@@ -80,6 +91,7 @@ declare const GATEWAY_CLIENT_CAPS: {
|
|
|
80
91
|
readonly TERMINAL_OFFSET_SEQ: "terminal-offset-seq";
|
|
81
92
|
readonly TOOL_EVENTS: "tool-events";
|
|
82
93
|
readonly UI_COMMANDS: "ui-commands";
|
|
94
|
+
readonly USAGE_REFRESHING: "usage-refreshing";
|
|
83
95
|
};
|
|
84
96
|
/** Optional capability advertised by clients during gateway handshake. */
|
|
85
97
|
type GatewayClientCap = (typeof GATEWAY_CLIENT_CAPS)[keyof typeof GATEWAY_CLIENT_CAPS];
|
package/dist/client-info.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as normalizeOptionalProtocolString } from "./protocol-value-normalization-DcAoxLUs.mjs";
|
|
2
2
|
//#region src/client-info.ts
|
|
3
3
|
/**
|
|
4
4
|
* Shared gateway client identity contract.
|
|
@@ -53,7 +53,8 @@ const GATEWAY_CLIENT_CAPS = {
|
|
|
53
53
|
TASK_SUGGESTIONS: "task-suggestions",
|
|
54
54
|
TERMINAL_OFFSET_SEQ: "terminal-offset-seq",
|
|
55
55
|
TOOL_EVENTS: "tool-events",
|
|
56
|
-
UI_COMMANDS: "ui-commands"
|
|
56
|
+
UI_COMMANDS: "ui-commands",
|
|
57
|
+
USAGE_REFRESHING: "usage-refreshing"
|
|
57
58
|
};
|
|
58
59
|
const GATEWAY_CLIENT_ID_SET = new Set(Object.values(GATEWAY_CLIENT_IDS));
|
|
59
60
|
const GATEWAY_CLIENT_MODE_SET = new Set(Object.values(GATEWAY_CLIENT_MODES));
|
|
@@ -17,6 +17,7 @@ declare const ConnectErrorDetailCodes: {
|
|
|
17
17
|
readonly AUTH_TAILSCALE_PROXY_MISSING: "AUTH_TAILSCALE_PROXY_MISSING";
|
|
18
18
|
readonly AUTH_TAILSCALE_WHOIS_FAILED: "AUTH_TAILSCALE_WHOIS_FAILED";
|
|
19
19
|
readonly AUTH_TAILSCALE_IDENTITY_MISMATCH: "AUTH_TAILSCALE_IDENTITY_MISMATCH";
|
|
20
|
+
readonly AUTH_IDENTITY_HEADER_REQUIRED: "AUTH_IDENTITY_HEADER_REQUIRED";
|
|
20
21
|
readonly CONTROL_UI_BUILD_MISMATCH: "CONTROL_UI_BUILD_MISMATCH";
|
|
21
22
|
readonly CONTROL_UI_ORIGIN_NOT_ALLOWED: "CONTROL_UI_ORIGIN_NOT_ALLOWED";
|
|
22
23
|
readonly PROTOCOL_MISMATCH: "PROTOCOL_MISMATCH";
|
|
@@ -115,6 +116,10 @@ declare function classifyGatewayConnectFailure(input: {
|
|
|
115
116
|
kind: "pairing-required";
|
|
116
117
|
userMessage: string;
|
|
117
118
|
remediation: string;
|
|
119
|
+
} | {
|
|
120
|
+
kind: "identity-proxy";
|
|
121
|
+
userMessage: string;
|
|
122
|
+
remediation: string;
|
|
118
123
|
} | {
|
|
119
124
|
remediation?: string | undefined;
|
|
120
125
|
kind: "device-identity-required" | "scope-mismatch" | "rate-limited" | "auth-rejected" | "gateway-rejected" | "unreachable";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as isRecord } from "./record-coerce-BKHrZ46I.mjs";
|
|
2
|
+
import { n as normalizeOptionalProtocolString } from "./protocol-value-normalization-DcAoxLUs.mjs";
|
|
2
3
|
//#region src/connect-error-details.ts
|
|
3
4
|
/**
|
|
4
5
|
* Shared gateway connect-error detail helpers.
|
|
@@ -29,6 +30,7 @@ const ConnectErrorDetailCodes = {
|
|
|
29
30
|
AUTH_TAILSCALE_PROXY_MISSING: "AUTH_TAILSCALE_PROXY_MISSING",
|
|
30
31
|
AUTH_TAILSCALE_WHOIS_FAILED: "AUTH_TAILSCALE_WHOIS_FAILED",
|
|
31
32
|
AUTH_TAILSCALE_IDENTITY_MISMATCH: "AUTH_TAILSCALE_IDENTITY_MISMATCH",
|
|
33
|
+
AUTH_IDENTITY_HEADER_REQUIRED: "AUTH_IDENTITY_HEADER_REQUIRED",
|
|
32
34
|
CONTROL_UI_BUILD_MISMATCH: "CONTROL_UI_BUILD_MISMATCH",
|
|
33
35
|
CONTROL_UI_ORIGIN_NOT_ALLOWED: "CONTROL_UI_ORIGIN_NOT_ALLOWED",
|
|
34
36
|
PROTOCOL_MISMATCH: "PROTOCOL_MISMATCH",
|
|
@@ -95,6 +97,7 @@ const CONNECT_PAIRING_REQUIRED_MESSAGE_BY_REASON = {
|
|
|
95
97
|
};
|
|
96
98
|
/** Maps internal auth failure reasons to public connect-error detail codes. */
|
|
97
99
|
function resolveAuthConnectErrorDetailCode(reason) {
|
|
100
|
+
if (reason?.startsWith("trusted_proxy_missing_header_")) return ConnectErrorDetailCodes.AUTH_IDENTITY_HEADER_REQUIRED;
|
|
98
101
|
switch (reason) {
|
|
99
102
|
case "token_missing": return ConnectErrorDetailCodes.AUTH_TOKEN_MISSING;
|
|
100
103
|
case "token_mismatch": return ConnectErrorDetailCodes.AUTH_TOKEN_MISMATCH;
|
|
@@ -128,13 +131,14 @@ function resolveDeviceAuthConnectErrorDetailCode(reason) {
|
|
|
128
131
|
}
|
|
129
132
|
/** Reads a non-empty detail code from an untrusted error details payload. */
|
|
130
133
|
function readConnectErrorDetailCode(details) {
|
|
131
|
-
if (!
|
|
134
|
+
if (!isRecord(details)) return null;
|
|
132
135
|
const code = details.code;
|
|
133
136
|
return typeof code === "string" && code.trim().length > 0 ? code.trim() : null;
|
|
134
137
|
}
|
|
135
138
|
/** Read the exact target artifact from an untrusted reload-required rejection. */
|
|
136
139
|
function readControlUiBuildMismatchId(details) {
|
|
137
|
-
|
|
140
|
+
const code = readConnectErrorDetailCode(details);
|
|
141
|
+
if (code !== ConnectErrorDetailCodes.PROTOCOL_MISMATCH && code !== ConnectErrorDetailCodes.CONTROL_UI_BUILD_MISMATCH) return null;
|
|
138
142
|
const raw = details;
|
|
139
143
|
const gatewayBuildId = normalizeOptionalProtocolString(raw.gatewayBuildId);
|
|
140
144
|
if (!gatewayBuildId || gatewayBuildId.length > 96 || raw.reloadRequired !== true) return null;
|
|
@@ -142,7 +146,7 @@ function readControlUiBuildMismatchId(details) {
|
|
|
142
146
|
}
|
|
143
147
|
/** Extracts normalized retry advice from untrusted connect-error details. */
|
|
144
148
|
function readConnectErrorRecoveryAdvice(details) {
|
|
145
|
-
if (!
|
|
149
|
+
if (!isRecord(details)) return {};
|
|
146
150
|
const raw = details;
|
|
147
151
|
const canRetryWithDeviceToken = typeof raw.canRetryWithDeviceToken === "boolean" ? raw.canRetryWithDeviceToken : void 0;
|
|
148
152
|
const normalizedNextStep = normalizeOptionalProtocolString(raw.recommendedNextStep) ?? "";
|
|
@@ -226,7 +230,7 @@ function buildPairingConnectCloseReason(params) {
|
|
|
226
230
|
/** Reads and backfills pairing-required details from an untrusted details object. */
|
|
227
231
|
function readPairingConnectErrorDetails(details) {
|
|
228
232
|
if (readConnectErrorDetailCode(details) !== ConnectErrorDetailCodes.PAIRING_REQUIRED) return null;
|
|
229
|
-
if (!
|
|
233
|
+
if (!isRecord(details)) return null;
|
|
230
234
|
const raw = details;
|
|
231
235
|
const reason = normalizePairingConnectReason(raw.reason);
|
|
232
236
|
const requestId = normalizePairingConnectRequestId(raw.requestId);
|
|
@@ -275,7 +279,29 @@ const DEVICE_TOKEN_REMEDIATION = "Rotate the paired-device token with `openclaw
|
|
|
275
279
|
const SHARED_TOKEN_REMEDIATION = "Verify `gateway.remote.token` matches `gateway.auth.token`. If a paired-device token is stale, rotate it with `openclaw devices rotate --device <deviceId> --role operator`, then reconnect.";
|
|
276
280
|
const SCOPE_MISMATCH_REMEDIATION = "Review approved scopes with `openclaw devices list`; if an upgrade is pending, preview it with `openclaw devices approve --latest`, approve the printed request, then reconnect.";
|
|
277
281
|
const RATE_LIMITED_REMEDIATION = "Wait for the temporary authentication lockout to expire, then retry.";
|
|
282
|
+
const IDENTITY_PROXY_REMEDIATION = "An identity-aware proxy rejected the WebSocket upgrade. Configure gateway.remote.edgeAuth for the configured Gateway origin, then reconnect. See https://docs.openclaw.ai/gateway/remote#gateway-behind-an-identity-aware-proxy.";
|
|
283
|
+
const CLOUDFLARE_ACCESS_REMEDIATION = "Cloudflare Access detected: configure its token header or service-token headers in gateway.remote.edgeAuth.";
|
|
284
|
+
const IDENTITY_PROXY_HTTP_STATUSES = /* @__PURE__ */ new Set([
|
|
285
|
+
301,
|
|
286
|
+
302,
|
|
287
|
+
303,
|
|
288
|
+
307,
|
|
289
|
+
308,
|
|
290
|
+
401,
|
|
291
|
+
403
|
|
292
|
+
]);
|
|
278
293
|
const GATEWAY_CLOSED_MESSAGE_PATTERN = /\bgateway closed \(\d+\):/i;
|
|
294
|
+
function readIdentityProxyRejection(details) {
|
|
295
|
+
if (!isRecord(details)) return null;
|
|
296
|
+
if (details.reason !== "websocket-upgrade-rejected" || typeof details.httpStatus !== "number" || !IDENTITY_PROXY_HTTP_STATUSES.has(details.httpStatus)) return null;
|
|
297
|
+
const location = normalizeOptionalProtocolString(details.location);
|
|
298
|
+
if (!location) return { cloudflareAccess: false };
|
|
299
|
+
try {
|
|
300
|
+
return { cloudflareAccess: new URL(location).hostname.toLowerCase().replace(/\.+$/u, "").endsWith(".cloudflareaccess.com") };
|
|
301
|
+
} catch {
|
|
302
|
+
return { cloudflareAccess: false };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
279
305
|
/** Classifies Gateway connect failures from structured details, with one legacy text fallback. */
|
|
280
306
|
function classifyGatewayConnectFailure(input) {
|
|
281
307
|
const code = readConnectErrorDetailCode(input.details);
|
|
@@ -290,6 +316,12 @@ function classifyGatewayConnectFailure(input) {
|
|
|
290
316
|
userMessage: code === ConnectErrorDetailCodes.PAIRING_REQUIRED ? formatConnectPairingRequiredMessage(input.details) : userMessage ?? "device pairing required",
|
|
291
317
|
remediation: PAIRING_APPROVAL_REMEDIATION
|
|
292
318
|
};
|
|
319
|
+
const identityProxy = readIdentityProxyRejection(input.details);
|
|
320
|
+
if (identityProxy) return {
|
|
321
|
+
kind: "identity-proxy",
|
|
322
|
+
userMessage: userMessage ?? "identity-aware proxy rejected websocket upgrade",
|
|
323
|
+
remediation: identityProxy.cloudflareAccess ? `${IDENTITY_PROXY_REMEDIATION}\n${CLOUDFLARE_ACCESS_REMEDIATION}` : IDENTITY_PROXY_REMEDIATION
|
|
324
|
+
};
|
|
293
325
|
const deviceIdentityRequired = code === ConnectErrorDetailCodes.DEVICE_IDENTITY_REQUIRED || code === ConnectErrorDetailCodes.CONTROL_UI_DEVICE_IDENTITY_REQUIRED || normalized.includes("device identity required");
|
|
294
326
|
const scopeMismatch = code === ConnectErrorDetailCodes.AUTH_SCOPE_MISMATCH || normalized.includes("scope mismatch");
|
|
295
327
|
const rateLimited = code === ConnectErrorDetailCodes.AUTH_RATE_LIMITED || !code && normalized.includes("too many failed authentication attempts");
|
package/dist/frame-guards.d.mts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as EventFrame,
|
|
2
|
-
|
|
1
|
+
import { a as EventFrame, d as RequestFrame, l as HelloOk, p as ResponseFrame, r as ErrorShape, s as GatewayFrame, t as ConnectParams } from "./frames-BmksHL6e.mjs";
|
|
3
2
|
//#region src/frame-guards.d.ts
|
|
4
3
|
declare function isGatewayEventFrame(value: unknown): value is EventFrame;
|
|
5
4
|
declare function isGatewayResponseFrame(value: unknown): value is ResponseFrame;
|
package/dist/frame-guards.mjs
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { n as
|
|
1
|
+
import { n as isRecord } from "./record-coerce-BKHrZ46I.mjs";
|
|
2
|
+
import { t as isNonEmptyProtocolString } from "./protocol-value-normalization-DcAoxLUs.mjs";
|
|
2
3
|
//#region src/frame-guards.ts
|
|
3
4
|
function isNonNegativeInteger(value) {
|
|
4
5
|
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
5
6
|
}
|
|
6
7
|
function isGatewayErrorShape(value) {
|
|
7
|
-
if (!
|
|
8
|
+
if (!isRecord(value)) return false;
|
|
8
9
|
if (!isNonEmptyProtocolString(value.code) || !isNonEmptyProtocolString(value.message)) return false;
|
|
9
10
|
if (value.retryable !== void 0 && typeof value.retryable !== "boolean") return false;
|
|
10
11
|
return value.retryAfterMs === void 0 || isNonNegativeInteger(value.retryAfterMs);
|
|
11
12
|
}
|
|
12
13
|
function isGatewayEventFrame(value) {
|
|
13
|
-
if (!
|
|
14
|
+
if (!isRecord(value) || value.type !== "event" || !isNonEmptyProtocolString(value.event)) return false;
|
|
14
15
|
return value.seq === void 0 || isNonNegativeInteger(value.seq);
|
|
15
16
|
}
|
|
16
17
|
function isGatewayResponseFrame(value) {
|
|
17
|
-
if (!
|
|
18
|
+
if (!isRecord(value) || value.type !== "res" || !isNonEmptyProtocolString(value.id) || typeof value.ok !== "boolean") return false;
|
|
18
19
|
return value.error === void 0 || isGatewayErrorShape(value.error);
|
|
19
20
|
}
|
|
20
21
|
//#endregion
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import { Static, Type } from "typebox";
|
|
2
|
-
|
|
3
2
|
//#region src/schema/frames.d.ts
|
|
4
|
-
declare const GATEWAY_SERVER_CAPS: {
|
|
5
|
-
readonly BOARD_WIDGET_PUT_CANVAS_DOC: "board-widget-put-canvas-doc";
|
|
6
|
-
readonly CHAT_SEND_ROUTING_CONTRACT: "chat-send-routing-contract";
|
|
7
|
-
readonly SYSTEM_AGENT_WIZARD_CANCEL: "openclaw-chat-wizard-cancel";
|
|
8
|
-
readonly SYSTEM_AGENT_SETUP_MODEL_REF: "openclaw-setup-model-ref";
|
|
9
|
-
readonly TASK_SUGGESTIONS_ACCEPT_MODES: "taskSuggestions.acceptModes";
|
|
10
|
-
};
|
|
11
3
|
/**
|
|
12
4
|
* Top-level gateway frame schemas.
|
|
13
5
|
*
|
|
@@ -35,16 +27,21 @@ declare const ConnectParamsSchema: Type.TObject<{
|
|
|
35
27
|
platform: Type.TString;
|
|
36
28
|
deviceFamily: Type.TOptional<Type.TString>;
|
|
37
29
|
modelIdentifier: Type.TOptional<Type.TString>;
|
|
30
|
+
/** Self-reported IANA zone. Bounded because the longest real name is well under this cap. */
|
|
31
|
+
timeZone: Type.TOptional<Type.TString>;
|
|
38
32
|
mode: Type.TEnum<["webchat", "cli", "worker", "test", "probe", "ui", "backend", "node"]>;
|
|
39
33
|
instanceId: Type.TOptional<Type.TString>;
|
|
40
34
|
}>;
|
|
41
35
|
caps: Type.TOptional<Type.TArray<Type.TString>>;
|
|
42
|
-
commands: Type.TOptional<Type.TArray<Type.TString>>;
|
|
43
|
-
|
|
36
|
+
commands: Type.TOptional<Type.TArray<Type.TString>>;
|
|
37
|
+
/** Additive Computer Use declaration; the owning core contract validates its bounded shape. */
|
|
38
|
+
computerUse: Type.TOptional<Type.TUnknown>;
|
|
39
|
+
/** @deprecated Accepted for the shipped v1 node-host envelope; current hosts use runner inventory. */
|
|
44
40
|
workerRuns: Type.TOptional<Type.TObject<{
|
|
45
41
|
bundleHash: Type.TString;
|
|
46
42
|
openclawVersion: Type.TString;
|
|
47
43
|
protocolFeatures: Type.TArray<Type.TString>;
|
|
44
|
+
bundlePrewarm: Type.TOptional<Type.TInteger>;
|
|
48
45
|
}>>;
|
|
49
46
|
permissions: Type.TOptional<Type.TRecord<"^.*$", Type.TBoolean>>;
|
|
50
47
|
pathEnv: Type.TOptional<Type.TString>;
|
|
@@ -75,6 +72,7 @@ declare const HelloOkSchema: Type.TObject<{
|
|
|
75
72
|
server: Type.TObject<{
|
|
76
73
|
version: Type.TString;
|
|
77
74
|
buildId: Type.TOptional<Type.TString>;
|
|
75
|
+
bootId: Type.TOptional<Type.TString>;
|
|
78
76
|
controlUiBuildSource: Type.TOptional<Type.TUnion<[Type.TLiteral<"bundled">, Type.TLiteral<"configured">]>>;
|
|
79
77
|
connId: Type.TString;
|
|
80
78
|
}>;
|
|
@@ -91,6 +89,7 @@ declare const HelloOkSchema: Type.TObject<{
|
|
|
91
89
|
platform: Type.TOptional<Type.TString>;
|
|
92
90
|
deviceFamily: Type.TOptional<Type.TString>;
|
|
93
91
|
modelIdentifier: Type.TOptional<Type.TString>;
|
|
92
|
+
timeZone: Type.TOptional<Type.TString>;
|
|
94
93
|
mode: Type.TOptional<Type.TString>;
|
|
95
94
|
lastInputSeconds: Type.TOptional<Type.TInteger>;
|
|
96
95
|
reason: Type.TOptional<Type.TString>;
|
|
@@ -238,6 +237,7 @@ declare const HelloOkSchema: Type.TObject<{
|
|
|
238
237
|
stateDir: Type.TOptional<Type.TString>;
|
|
239
238
|
sessionDefaults: Type.TOptional<Type.TObject<{
|
|
240
239
|
defaultAgentId: Type.TString;
|
|
240
|
+
modelConfigured: Type.TOptional<Type.TBoolean>;
|
|
241
241
|
ownership: Type.TOptional<Type.TUnion<[Type.TLiteral<"sole">, Type.TLiteral<"legacy">, Type.TLiteral<"explicit">]>>;
|
|
242
242
|
selectionRequired: Type.TOptional<Type.TBoolean>;
|
|
243
243
|
mainKey: Type.TString;
|
|
@@ -322,6 +322,7 @@ declare const HelloOkSchema: Type.TObject<{
|
|
|
322
322
|
description: Type.TOptional<Type.TString>;
|
|
323
323
|
icon: Type.TOptional<Type.TString>;
|
|
324
324
|
path: Type.TOptional<Type.TString>;
|
|
325
|
+
placement: Type.TOptional<Type.TString>;
|
|
325
326
|
requiresGatewayAuth: Type.TOptional<Type.TBoolean>;
|
|
326
327
|
group: Type.TOptional<Type.TUnion<[Type.TLiteral<"control">, Type.TLiteral<"agent">]>>;
|
|
327
328
|
order: Type.TOptional<Type.TNumber>;
|
|
@@ -332,9 +333,6 @@ declare const HelloOkSchema: Type.TObject<{
|
|
|
332
333
|
label: Type.TString;
|
|
333
334
|
}>>>;
|
|
334
335
|
pluginSurfaceUrls: Type.TOptional<Type.TRecord<"^.*$", Type.TString>>;
|
|
335
|
-
deviceAuthMigration: Type.TOptional<Type.TObject<{
|
|
336
|
-
pending: Type.TLiteral<true>;
|
|
337
|
-
}>>;
|
|
338
336
|
auth: Type.TObject<{
|
|
339
337
|
deviceToken: Type.TOptional<Type.TString>;
|
|
340
338
|
recoveryMigrationAllowed: Type.TOptional<Type.TLiteral<true>>;
|
|
@@ -440,4 +438,4 @@ type GatewayFrame = Static<typeof GatewayFrameSchema>;
|
|
|
440
438
|
type TickEvent = Static<typeof TickEventSchema>;
|
|
441
439
|
type ShutdownEvent = Static<typeof ShutdownEventSchema>;
|
|
442
440
|
//#endregion
|
|
443
|
-
export {
|
|
441
|
+
export { TickEvent as _, EventFrame as a, GatewayFrameSchema as c, RequestFrame as d, RequestFrameSchema as f, ShutdownEventSchema as g, ShutdownEvent as h, ErrorShapeSchema as i, HelloOk as l, ResponseFrameSchema as m, ConnectParamsSchema as n, EventFrameSchema as o, ResponseFrame as p, ErrorShape as r, GatewayFrame as s, ConnectParams as t, HelloOkSchema as u, TickEventSchema as v };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//#region src/gateway-error-details.d.ts
|
|
2
|
+
/** Gateway JSON-RPC style error codes shared by clients and server handlers. */
|
|
3
|
+
declare const ErrorCodes: {
|
|
4
|
+
/** @deprecated Retained for source compatibility; no current server emitter. */
|
|
5
|
+
readonly NOT_LINKED: "NOT_LINKED";
|
|
6
|
+
/** Device exists but still needs an explicit pairing approval. */
|
|
7
|
+
readonly NOT_PAIRED: "NOT_PAIRED";
|
|
8
|
+
/** @deprecated Retained for source compatibility; no current server emitter. */
|
|
9
|
+
readonly AGENT_TIMEOUT: "AGENT_TIMEOUT";
|
|
10
|
+
/** Request payload failed protocol validation or method preconditions. */
|
|
11
|
+
readonly INVALID_REQUEST: "INVALID_REQUEST";
|
|
12
|
+
/** Authenticated caller lacks permission for the requested operation. */
|
|
13
|
+
readonly FORBIDDEN: "FORBIDDEN";
|
|
14
|
+
/** Approval resolution referenced a missing or expired approval request. */
|
|
15
|
+
readonly APPROVAL_NOT_FOUND: "APPROVAL_NOT_FOUND";
|
|
16
|
+
/** Gateway service or required backend is temporarily unavailable. */
|
|
17
|
+
readonly UNAVAILABLE: "UNAVAILABLE";
|
|
18
|
+
};
|
|
19
|
+
/** Closed set of canonical gateway error code strings. */
|
|
20
|
+
type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
21
|
+
/** Stable discriminants for structured method-level failures. */
|
|
22
|
+
declare const GatewayErrorDetailCodes: {
|
|
23
|
+
readonly CRON_JOB_NOT_FOUND: "CRON_JOB_NOT_FOUND";
|
|
24
|
+
readonly MISSING_SCOPE: "MISSING_SCOPE";
|
|
25
|
+
readonly MCP_APP_VIEW_EXPIRED: "MCP_APP_VIEW_EXPIRED";
|
|
26
|
+
readonly OUTBOUND_DELIVERY_QUEUED: "OUTBOUND_DELIVERY_QUEUED";
|
|
27
|
+
readonly USER_PREFS_LIMIT_EXCEEDED: "USER_PREFS_LIMIT_EXCEEDED";
|
|
28
|
+
readonly SESSION_COMPANION_BUSY: "SESSION_COMPANION_BUSY";
|
|
29
|
+
readonly SKILL_PROPOSAL_REVISION_CHANGED: "SKILL_PROPOSAL_REVISION_CHANGED";
|
|
30
|
+
readonly PROJECT_CLONE_FAILED: "PROJECT_CLONE_FAILED";
|
|
31
|
+
readonly UNKNOWN_AGENT_ID: "UNKNOWN_AGENT_ID";
|
|
32
|
+
readonly WIZARD_NOT_FOUND: "WIZARD_NOT_FOUND";
|
|
33
|
+
};
|
|
34
|
+
/** Missing cron automation identified by its exact store key. */
|
|
35
|
+
type CronJobNotFoundErrorDetails = {
|
|
36
|
+
code: typeof GatewayErrorDetailCodes.CRON_JOB_NOT_FOUND;
|
|
37
|
+
jobId: string;
|
|
38
|
+
};
|
|
39
|
+
/** Missing operator-scope details shared by WebSocket and HTTP responses. */
|
|
40
|
+
type MissingScopeErrorDetails = {
|
|
41
|
+
code: typeof GatewayErrorDetailCodes.MISSING_SCOPE;
|
|
42
|
+
missingScope: string;
|
|
43
|
+
requiredScopes: string[];
|
|
44
|
+
};
|
|
45
|
+
type McpAppViewExpiredErrorDetails = {
|
|
46
|
+
code: typeof GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
|
|
47
|
+
};
|
|
48
|
+
type OutboundDeliveryQueuedErrorDetails = {
|
|
49
|
+
code: typeof GatewayErrorDetailCodes.OUTBOUND_DELIVERY_QUEUED;
|
|
50
|
+
};
|
|
51
|
+
/** Per-profile preference quota details returned by users.prefs.set. */
|
|
52
|
+
type UserPrefsLimitExceededErrorDetails = {
|
|
53
|
+
code: typeof GatewayErrorDetailCodes.USER_PREFS_LIMIT_EXCEEDED;
|
|
54
|
+
limit: number;
|
|
55
|
+
currentCount: number;
|
|
56
|
+
};
|
|
57
|
+
/** Unknown agent details carried by agent-scoped method validation failures. */
|
|
58
|
+
type UnknownAgentIdErrorDetails = {
|
|
59
|
+
code: typeof GatewayErrorDetailCodes.UNKNOWN_AGENT_ID;
|
|
60
|
+
agentId: string;
|
|
61
|
+
};
|
|
62
|
+
/** Missing or expired process-local setup wizard session. */
|
|
63
|
+
type WizardNotFoundErrorDetails = {
|
|
64
|
+
code: typeof GatewayErrorDetailCodes.WIZARD_NOT_FOUND;
|
|
65
|
+
};
|
|
66
|
+
type ProjectCloneFailureCause = "invalid_url" | "auth_required" | "not_found" | "network" | "target_exists" | "clone_failed";
|
|
67
|
+
type ProjectCloneErrorDetails = {
|
|
68
|
+
code: typeof GatewayErrorDetailCodes.PROJECT_CLONE_FAILED;
|
|
69
|
+
cause: ProjectCloneFailureCause;
|
|
70
|
+
};
|
|
71
|
+
/** Optimistic-concurrency mismatch for an operator-reviewed Skill Workshop draft. */
|
|
72
|
+
type SkillProposalRevisionChangedErrorDetails = {
|
|
73
|
+
code: typeof GatewayErrorDetailCodes.SKILL_PROPOSAL_REVISION_CHANGED;
|
|
74
|
+
expectedRevisionHash: string;
|
|
75
|
+
currentRevisionHash: string;
|
|
76
|
+
};
|
|
77
|
+
/** Structured details emitted by method-level failures. */
|
|
78
|
+
type GatewayErrorDetails = CronJobNotFoundErrorDetails | MissingScopeErrorDetails | McpAppViewExpiredErrorDetails | OutboundDeliveryQueuedErrorDetails | UserPrefsLimitExceededErrorDetails | SkillProposalRevisionChangedErrorDetails | ProjectCloneErrorDetails | UnknownAgentIdErrorDetails | WizardNotFoundErrorDetails;
|
|
79
|
+
/** Reads a typed cron lookup miss without parsing operator-facing prose. */
|
|
80
|
+
declare function readCronJobNotFoundError(error: unknown): CronJobNotFoundErrorDetails | null;
|
|
81
|
+
/** Builds the canonical stale-draft details shared by Skill Workshop RPCs. */
|
|
82
|
+
declare function buildSkillProposalRevisionChangedErrorDetails(params: {
|
|
83
|
+
expectedRevisionHash: string;
|
|
84
|
+
currentRevisionHash: string;
|
|
85
|
+
}): SkillProposalRevisionChangedErrorDetails;
|
|
86
|
+
/** Reads a stale Skill Workshop decision without parsing operator-facing prose. */
|
|
87
|
+
declare function readSkillProposalRevisionChangedError(error: unknown): SkillProposalRevisionChangedErrorDetails | null;
|
|
88
|
+
/** Reads validated missing-scope details from an untrusted protocol payload. */
|
|
89
|
+
declare function readMissingScopeErrorDetails(details: unknown): MissingScopeErrorDetails | null;
|
|
90
|
+
declare function isMcpAppViewExpiredError(error: unknown): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Reads a method-level missing-scope failure, preferring structured details.
|
|
93
|
+
* The message fallback keeps clients compatible with gateways predating structured details.
|
|
94
|
+
*/
|
|
95
|
+
declare function readMissingScopeError(error: unknown): MissingScopeErrorDetails | null;
|
|
96
|
+
//#endregion
|
|
97
|
+
export { readCronJobNotFoundError as _, GatewayErrorDetails as a, readSkillProposalRevisionChangedError as b, OutboundDeliveryQueuedErrorDetails as c, SkillProposalRevisionChangedErrorDetails as d, UnknownAgentIdErrorDetails as f, isMcpAppViewExpiredError as g, buildSkillProposalRevisionChangedErrorDetails as h, GatewayErrorDetailCodes as i, ProjectCloneErrorDetails as l, WizardNotFoundErrorDetails as m, ErrorCode as n, McpAppViewExpiredErrorDetails as o, UserPrefsLimitExceededErrorDetails as p, ErrorCodes as r, MissingScopeErrorDetails as s, CronJobNotFoundErrorDetails as t, ProjectCloneFailureCause as u, readMissingScopeError as v, readMissingScopeErrorDetails as y };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { ErrorCode, ErrorCodes, GatewayErrorDetailCodes, GatewayErrorDetails, McpAppViewExpiredErrorDetails, MissingScopeErrorDetails, ProjectCloneErrorDetails, ProjectCloneFailureCause, UnknownAgentIdErrorDetails, UserPrefsLimitExceededErrorDetails, WizardNotFoundErrorDetails, isMcpAppViewExpiredError, readMissingScopeError, readMissingScopeErrorDetails };
|
|
1
|
+
import { _ as readCronJobNotFoundError, a as GatewayErrorDetails, b as readSkillProposalRevisionChangedError, c as OutboundDeliveryQueuedErrorDetails, d as SkillProposalRevisionChangedErrorDetails, f as UnknownAgentIdErrorDetails, g as isMcpAppViewExpiredError, h as buildSkillProposalRevisionChangedErrorDetails, i as GatewayErrorDetailCodes, l as ProjectCloneErrorDetails, m as WizardNotFoundErrorDetails, n as ErrorCode, o as McpAppViewExpiredErrorDetails, p as UserPrefsLimitExceededErrorDetails, r as ErrorCodes, s as MissingScopeErrorDetails, t as CronJobNotFoundErrorDetails, u as ProjectCloneFailureCause, v as readMissingScopeError, y as readMissingScopeErrorDetails } from "./gateway-error-details-yO9RdEKe.mjs";
|
|
2
|
+
export { CronJobNotFoundErrorDetails, ErrorCode, ErrorCodes, GatewayErrorDetailCodes, GatewayErrorDetails, McpAppViewExpiredErrorDetails, MissingScopeErrorDetails, OutboundDeliveryQueuedErrorDetails, ProjectCloneErrorDetails, ProjectCloneFailureCause, SkillProposalRevisionChangedErrorDetails, UnknownAgentIdErrorDetails, UserPrefsLimitExceededErrorDetails, WizardNotFoundErrorDetails, buildSkillProposalRevisionChangedErrorDetails, isMcpAppViewExpiredError, readCronJobNotFoundError, readMissingScopeError, readMissingScopeErrorDetails, readSkillProposalRevisionChangedError };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as
|
|
1
|
+
import { t as asNullableRecord } from "./record-coerce-BKHrZ46I.mjs";
|
|
2
2
|
//#region src/gateway-error-details.ts
|
|
3
3
|
/** Gateway JSON-RPC style error codes shared by clients and server handlers. */
|
|
4
4
|
const ErrorCodes = {
|
|
@@ -19,18 +19,52 @@ const ErrorCodes = {
|
|
|
19
19
|
};
|
|
20
20
|
/** Stable discriminants for structured method-level failures. */
|
|
21
21
|
const GatewayErrorDetailCodes = {
|
|
22
|
+
CRON_JOB_NOT_FOUND: "CRON_JOB_NOT_FOUND",
|
|
22
23
|
MISSING_SCOPE: "MISSING_SCOPE",
|
|
23
24
|
MCP_APP_VIEW_EXPIRED: "MCP_APP_VIEW_EXPIRED",
|
|
25
|
+
OUTBOUND_DELIVERY_QUEUED: "OUTBOUND_DELIVERY_QUEUED",
|
|
24
26
|
USER_PREFS_LIMIT_EXCEEDED: "USER_PREFS_LIMIT_EXCEEDED",
|
|
25
27
|
SESSION_COMPANION_BUSY: "SESSION_COMPANION_BUSY",
|
|
28
|
+
SKILL_PROPOSAL_REVISION_CHANGED: "SKILL_PROPOSAL_REVISION_CHANGED",
|
|
26
29
|
PROJECT_CLONE_FAILED: "PROJECT_CLONE_FAILED",
|
|
27
30
|
UNKNOWN_AGENT_ID: "UNKNOWN_AGENT_ID",
|
|
28
31
|
WIZARD_NOT_FOUND: "WIZARD_NOT_FOUND"
|
|
29
32
|
};
|
|
30
33
|
const LEGACY_MISSING_SCOPE_PATTERN = /\bmissing scope:\s*([a-z0-9._-]+)/i;
|
|
34
|
+
const SHA256_PATTERN = /^[a-fA-F0-9]{64}$/;
|
|
35
|
+
/** Reads a typed cron lookup miss without parsing operator-facing prose. */
|
|
36
|
+
function readCronJobNotFoundError(error) {
|
|
37
|
+
const details = asNullableRecord(asNullableRecord(error)?.details);
|
|
38
|
+
if (details?.code !== GatewayErrorDetailCodes.CRON_JOB_NOT_FOUND) return null;
|
|
39
|
+
const jobId = typeof details.jobId === "string" ? details.jobId.trim() : "";
|
|
40
|
+
return jobId ? {
|
|
41
|
+
code: GatewayErrorDetailCodes.CRON_JOB_NOT_FOUND,
|
|
42
|
+
jobId
|
|
43
|
+
} : null;
|
|
44
|
+
}
|
|
45
|
+
/** Builds the canonical stale-draft details shared by Skill Workshop RPCs. */
|
|
46
|
+
function buildSkillProposalRevisionChangedErrorDetails(params) {
|
|
47
|
+
return {
|
|
48
|
+
code: GatewayErrorDetailCodes.SKILL_PROPOSAL_REVISION_CHANGED,
|
|
49
|
+
expectedRevisionHash: params.expectedRevisionHash,
|
|
50
|
+
currentRevisionHash: params.currentRevisionHash
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Reads a stale Skill Workshop decision without parsing operator-facing prose. */
|
|
54
|
+
function readSkillProposalRevisionChangedError(error) {
|
|
55
|
+
const details = asNullableRecord(asNullableRecord(error)?.details);
|
|
56
|
+
if (details?.code !== GatewayErrorDetailCodes.SKILL_PROPOSAL_REVISION_CHANGED) return null;
|
|
57
|
+
const expectedRevisionHash = typeof details.expectedRevisionHash === "string" ? details.expectedRevisionHash : "";
|
|
58
|
+
const currentRevisionHash = typeof details.currentRevisionHash === "string" ? details.currentRevisionHash : "";
|
|
59
|
+
if (!SHA256_PATTERN.test(expectedRevisionHash) || !SHA256_PATTERN.test(currentRevisionHash)) return null;
|
|
60
|
+
return buildSkillProposalRevisionChangedErrorDetails({
|
|
61
|
+
expectedRevisionHash,
|
|
62
|
+
currentRevisionHash
|
|
63
|
+
});
|
|
64
|
+
}
|
|
31
65
|
/** Reads validated missing-scope details from an untrusted protocol payload. */
|
|
32
66
|
function readMissingScopeErrorDetails(details) {
|
|
33
|
-
const record =
|
|
67
|
+
const record = asNullableRecord(details);
|
|
34
68
|
if (record?.code !== GatewayErrorDetailCodes.MISSING_SCOPE) return null;
|
|
35
69
|
const missingScope = typeof record.missingScope === "string" ? record.missingScope.trim() : "";
|
|
36
70
|
const requiredScopes = Array.isArray(record.requiredScopes) ? record.requiredScopes.map((scope) => typeof scope === "string" ? scope.trim() : "") : [];
|
|
@@ -42,14 +76,14 @@ function readMissingScopeErrorDetails(details) {
|
|
|
42
76
|
};
|
|
43
77
|
}
|
|
44
78
|
function isMcpAppViewExpiredError(error) {
|
|
45
|
-
return
|
|
79
|
+
return asNullableRecord(asNullableRecord(error)?.details)?.code === GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
|
|
46
80
|
}
|
|
47
81
|
/**
|
|
48
82
|
* Reads a method-level missing-scope failure, preferring structured details.
|
|
49
83
|
* The message fallback keeps clients compatible with gateways predating structured details.
|
|
50
84
|
*/
|
|
51
85
|
function readMissingScopeError(error) {
|
|
52
|
-
const record =
|
|
86
|
+
const record = asNullableRecord(error);
|
|
53
87
|
if (!record) return null;
|
|
54
88
|
const structured = readMissingScopeErrorDetails(record.details);
|
|
55
89
|
if (structured) return structured;
|
|
@@ -64,4 +98,4 @@ function readMissingScopeError(error) {
|
|
|
64
98
|
} : null;
|
|
65
99
|
}
|
|
66
100
|
//#endregion
|
|
67
|
-
export { ErrorCodes, GatewayErrorDetailCodes, isMcpAppViewExpiredError, readMissingScopeError, readMissingScopeErrorDetails };
|
|
101
|
+
export { ErrorCodes, GatewayErrorDetailCodes, buildSkillProposalRevisionChangedErrorDetails, isMcpAppViewExpiredError, readCronJobNotFoundError, readMissingScopeError, readMissingScopeErrorDetails, readSkillProposalRevisionChangedError };
|