@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 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
 
@@ -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`. */id: GatewayClientId; /** Human-readable label for diagnostics; not used for policy decisions. */
61
- displayName?: string; /** Client app or package version reported by the connecting process. */
62
- version: string; /** Exact immutable artifact identity when the client can report one. */
63
- buildId?: string; /** Runtime platform string, such as `darwin`, `ios`, `android`, or `web`. */
64
- platform: string; /** Optional device family used by native clients for display and routing hints. */
65
- deviceFamily?: string; /** Native hardware/model identifier when available. */
66
- modelIdentifier?: string; /** Coarse category from `GATEWAY_CLIENT_MODES` for policy and diagnostics. */
67
- mode: GatewayClientMode; /** Per-installation or per-process id used to distinguish same-product clients. */
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];
@@ -1,4 +1,4 @@
1
- import { i as normalizeOptionalProtocolString } from "./protocol-value-normalization-Bexl3yr1.mjs";
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 { i as normalizeOptionalProtocolString } from "./protocol-value-normalization-Bexl3yr1.mjs";
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 (!details || typeof details !== "object" || Array.isArray(details)) return null;
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
- if (readConnectErrorDetailCode(details) !== ConnectErrorDetailCodes.CONTROL_UI_BUILD_MISMATCH) return null;
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 (!details || typeof details !== "object" || Array.isArray(details)) return {};
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 (!details || typeof details !== "object" || Array.isArray(details)) return null;
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");
@@ -1,5 +1,4 @@
1
- import { a as EventFrame, c as GatewayFrame, f as RequestFrame, m as ResponseFrame, r as ErrorShape, t as ConnectParams, u as HelloOk } from "./frames-B9De7i2H.mjs";
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;
@@ -1,20 +1,21 @@
1
- import { n as isNonEmptyProtocolString, r as isProtocolRecord } from "./protocol-value-normalization-Bexl3yr1.mjs";
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 (!isProtocolRecord(value)) return false;
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 (!isProtocolRecord(value) || value.type !== "event" || !isNonEmptyProtocolString(value.event)) return false;
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 (!isProtocolRecord(value) || value.type !== "res" || !isNonEmptyProtocolString(value.id) || typeof value.ok !== "boolean") return false;
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>>; /** Additive Computer Use declaration; the owning core contract validates its bounded shape. */
43
- computerUse: Type.TOptional<Type.TUnknown>; /** Additive node-local worker build identity; presence advertises session hosting. */
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 { ShutdownEventSchema as _, EventFrame as a, GatewayFrame as c, HelloOkSchema as d, RequestFrame as f, ShutdownEvent as g, ResponseFrameSchema as h, ErrorShapeSchema as i, GatewayFrameSchema as l, ResponseFrame as m, ConnectParamsSchema as n, EventFrameSchema as o, RequestFrameSchema as p, ErrorShape as r, GATEWAY_SERVER_CAPS as s, ConnectParams as t, HelloOk as u, TickEvent as v, TickEventSchema as y };
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 McpAppViewExpiredErrorDetails, c as ProjectCloneFailureCause, d as WizardNotFoundErrorDetails, f as isMcpAppViewExpiredError, i as GatewayErrorDetails, l as UnknownAgentIdErrorDetails, m as readMissingScopeErrorDetails, n as ErrorCodes, o as MissingScopeErrorDetails, p as readMissingScopeError, r as GatewayErrorDetailCodes, s as ProjectCloneErrorDetails, t as ErrorCode, u as UserPrefsLimitExceededErrorDetails } from "./gateway-error-details-BXoMHq1i.mjs";
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 asProtocolRecord } from "./protocol-value-normalization-Bexl3yr1.mjs";
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 = asProtocolRecord(details);
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 asProtocolRecord(asProtocolRecord(error)?.details)?.code === GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
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 = asProtocolRecord(error);
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 };