@corca-org/ceal-host-linux-arm64 1.0.10 → 1.0.12

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.
@@ -61,6 +61,46 @@ var client_wire_contract_default = {
61
61
  schema_version: "ceal.command_request.v1",
62
62
  absolute_transport_max_bytes: 65536
63
63
  },
64
+ command_resolution: {
65
+ schema_version: "ceal.gateway_command_resolution.v1",
66
+ authority: {
67
+ anonymous: {
68
+ state: "anonymous",
69
+ fields: [
70
+ "state"
71
+ ]
72
+ },
73
+ authenticated: {
74
+ state: "authenticated",
75
+ fields: [
76
+ "state",
77
+ "principal_kind",
78
+ "organization_ref",
79
+ "instance_ref",
80
+ "access_group_ref",
81
+ "principal_ref",
82
+ "authority_revision_ref"
83
+ ]
84
+ }
85
+ },
86
+ semantic_options: {
87
+ inspection: {
88
+ values: [
89
+ "default",
90
+ "full"
91
+ ]
92
+ },
93
+ cache_mode: {
94
+ values: [
95
+ "default",
96
+ "bypass"
97
+ ]
98
+ },
99
+ compact: {
100
+ type: "boolean"
101
+ }
102
+ }
103
+ },
64
104
  command_response: {
65
105
  schema_version: "ceal.command_response.v1",
66
106
  descriptor_field: "verified_artifact",
@@ -74,12 +114,15 @@ var client_wire_contract_default = {
74
114
  ],
75
115
  bare_document_fields: [
76
116
  "invocation",
77
- "required_action_sequence",
78
117
  "entrypoints",
79
118
  "common_concepts",
80
119
  "operations",
81
120
  "catalog_revision"
82
121
  ],
122
+ bare_document_optional_fields: [
123
+ "required_action_sequence",
124
+ "withheld"
125
+ ],
83
126
  prompt_field: "prompt",
84
127
  prompt_schema_version: "ceal.prompt.v1",
85
128
  focused_prompt_document_fields: [
@@ -92,7 +135,7 @@ var client_wire_contract_default = {
92
135
  "prompt"
93
136
  ],
94
137
  discovery_command: "discovery",
95
- discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
138
+ discovery_manifest_schema_version: "ceal.discovery_manifest.v2",
96
139
  discovery_manifest_document_fields: [
97
140
  "discovery_manifest"
98
141
  ],
@@ -100,11 +143,29 @@ var client_wire_contract_default = {
100
143
  bare_document_max_bytes: 65536,
101
144
  complete_max_bytes: 66019,
102
145
  absolute_transport_max_bytes: 4194304
146
+ },
147
+ resource_stream: {
148
+ path: "/api/ceal/v2/resources",
149
+ request_schema_version: "ceal.resource_stream_request.v1",
150
+ ref_pattern: "^resource:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
151
+ media_type_pattern: "^[a-z0-9][a-z0-9!#$&^_.+-]{0,63}/[a-z0-9][a-z0-9!#$&^_.+-]{0,63}$",
152
+ filename_max_bytes: 512,
153
+ max_bytes: 9007199254740991,
154
+ deadline_ms: 6e5,
155
+ fetch_argv: [
156
+ "resource",
157
+ "fetch"
158
+ ],
159
+ ref_flag: "--ref"
103
160
  }
104
161
  };
105
162
 
106
163
  // packages/ceal-client-protocol/src/client-wire-contract.ts
107
164
  var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
165
+ var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
166
+ var commandResolutionAuthority = commandResolution.authority;
167
+ var commandResolutionSemanticOptions = commandResolution.semantic_options;
168
+ var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = commandResolution.schema_version;
108
169
  var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
109
170
  var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
110
171
  var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
@@ -125,6 +186,7 @@ var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
125
186
  var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
126
187
  var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
127
188
  var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
189
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
128
190
  var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
129
191
  var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
130
192
  var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
@@ -138,9 +200,50 @@ function vocabulary(words) {
138
200
  return Object.freeze(words);
139
201
  }
140
202
 
203
+ // packages/ceal-client-protocol/src/gateway-response-types.ts
204
+ var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
205
+ var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
206
+ var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
207
+ var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
208
+ var CEAL_GATEWAY_READ_REUSE_DISPOSITIONS = vocabulary(["response_cache_hit", "corpus_hit", "corpus_hit_after_revalidation", "corpus_partial_provider_supplement", "provider_direct", "provider_continuation", "reuse_unavailable"]);
209
+ var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
210
+ var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
211
+ var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
212
+ var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
213
+ var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "agent_lease_admission", "provider_authenticated_event"]);
214
+ var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
215
+ var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
216
+ var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
217
+ var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
218
+ var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
219
+ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
220
+ var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
221
+ var CEAL_PROTOCOL_VERSION = "1.4.0";
222
+ var CEAL_GATEWAY_ANNOUNCEMENT_SCOPE_STATEMENTS = Object.freeze({
223
+ github_app_installation_repositories: "Repositories in the installed GitHub App installation.",
224
+ slack_public_app_member_channels_only: "Public channels where the installed Slack app is a member, plus direct and multi-person direct messages the requester is a member of, as Slack reports that membership; private channels the administrator has not approved are not declared by this connector.",
225
+ notion_connected_logical_area: "Connected Notion logical area under provider-enforced sharing; descendant inventory is not declared.",
226
+ google_workspace_calendar_read_only: "Approved Calendar availability and event reads only; Calendar mutation is not declared.",
227
+ google_workspace_admitted_drive_target_metadata: "Metadata search for files in the shared drives and directly shared files the Connector reaches and the Organization admits as Targets; file-content read and mutation are not declared.",
228
+ google_workspace_admitted_drive_target_sheet_ranges: "Bounded values reads from Google Sheets in the shared drives and directly shared files the Connector reaches and the Organization admits as Targets; file mutation is not declared.",
229
+ google_workspace_admitted_drive_target_sheet_tabs: "Bounded tab metadata and grid extents from Google Sheets in the shared drives and directly shared files the Connector reaches and the Organization admits as Targets; cell contents and file mutation are not declared.",
230
+ google_workspace_admitted_drive_target_editable_sheet_ranges: "Bounded values updates and clears in editable Google Sheets in the shared drives and directly shared files the Connector reaches and the Organization admits as Targets; Docs, Slides, and other Drive file mutation are not declared."
231
+ });
232
+ var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
233
+ var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
234
+ var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
235
+ var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
236
+ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
237
+ "connector_ref",
238
+ "connector_revision",
239
+ "policy_decision_revision"
240
+ ]);
241
+
141
242
  // packages/ceal-client-protocol/src/operation-contract-types.ts
142
243
  var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
143
244
  var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
245
+ var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
246
+ var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
144
247
  var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
145
248
  var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
146
249
  var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
@@ -176,27 +279,6 @@ var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
176
279
  "interactive_unavailable"
177
280
  ]);
178
281
 
179
- // packages/ceal-client-protocol/src/gateway-response-types.ts
180
- var CEAL_CAPABILITY_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
181
- var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
182
- var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
183
- var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
184
- var CEAL_GATEWAY_READ_REUSE_DISPOSITIONS = vocabulary(["response_cache_hit", "corpus_hit", "corpus_hit_after_revalidation", "corpus_partial_provider_supplement", "provider_direct", "provider_continuation", "reuse_unavailable"]);
185
- var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
186
- var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
187
- var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
188
- var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
189
- var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "agent_lease_admission", "provider_authenticated_event"]);
190
- var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
191
- var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
192
- var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
193
- var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
194
- var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
195
- var CEAL_PROTOCOL_VERSION = "1.4.0";
196
- var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
197
- var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
198
- var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
199
-
200
282
  // packages/ceal-client-protocol/src/gateway-validation-primitives.ts
201
283
  var CealProtocolValidationError = class extends Error {
202
284
  name = "CealProtocolValidationError";
@@ -213,6 +295,7 @@ var SAFE_CONNECTOR_KIND = new RegExp(`^[a-z][a-z0-9-]{0,${MAX_SAFE_TOKEN_LENGTH
213
295
  var FORBIDDEN_SECRET_KEY = /^(?:[a-z0-9_]*(?:token|secret|password|credential(?:s)?|private_?key)|api_?key|authorization|bearer|raw_?provider_?payload|provider_?payload)$/iu;
214
296
  var FORBIDDEN_AUTHORITY_KEY = /^(?:actor_?ref|owner_?ref|registration_?ref|runner_?ref|auth_?decision|policy_?decision|host_?decision)$/iu;
215
297
  var TEXT_ENCODER = new TextEncoder();
298
+ var CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS = 128;
216
299
  var CEAL_WIRE_SAFE_TEXT_MAX_BYTES = 8 * 1024;
217
300
  function assertSafeJsonValue(value, options, depth = 0, count = { value: 0 }) {
218
301
  count.value += 1;
@@ -232,12 +315,12 @@ function assertSafeJsonString(value, options) {
232
315
  if (byteLength(value) > CEAL_WIRE_SAFE_TEXT_MAX_BYTES || firstDisallowedControl(value, "multi_line") !== null) invalidByContext(options);
233
316
  }
234
317
  function assertSafeJsonArray(value, options, depth, count) {
235
- if (value.length > 128) invalidByContext(options);
318
+ if (value.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
236
319
  for (const item of value) assertSafeJsonValue(item, options, depth + 1, count);
237
320
  }
238
321
  function assertSafeJsonRecord(record6, options, depth, count) {
239
322
  const entries = Object.entries(record6);
240
- if (entries.length > 128) invalidByContext(options);
323
+ if (entries.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
241
324
  const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record6.fields) : null;
242
325
  for (const [key, child] of entries) {
243
326
  if (key === "credential_material_included" && child !== false) invalidByContext(options);
@@ -263,9 +346,9 @@ function compactSourceUrlColumn(fields) {
263
346
  return index < 0 ? null : index;
264
347
  }
265
348
  function assertSafeJsonCompactRows(value, sourceUrlColumn, options, depth, count) {
266
- if (!Array.isArray(value) || value.length > 128) invalidByContext(options);
349
+ if (!Array.isArray(value) || value.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
267
350
  for (const row of value) {
268
- if (!Array.isArray(row) || row.length > 128) invalidByContext(options);
351
+ if (!Array.isArray(row) || row.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
269
352
  for (const [index, cell] of row.entries()) {
270
353
  if (index === sourceUrlColumn && (cell === null || isSafeExternalHttpsUrl(cell))) continue;
271
354
  assertSafeJsonValue(cell, options, depth + 2, count);
@@ -298,6 +381,7 @@ function isSafeResultContent(value, key) {
298
381
  const maximum = key === "text" ? 8192 : 1024;
299
382
  return typeof value === "string" && byteLength(value) <= maximum && firstDisallowedControl(value, "multi_line") === null;
300
383
  }
384
+ var CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES = 512;
301
385
  function normalizeCealSingleLineText(value) {
302
386
  return value.split("").map((character) => hasControlCharacter(character) ? " " : character).join("").trim();
303
387
  }
@@ -406,6 +490,28 @@ function cut(text) {
406
490
  return text.length <= REFUSAL_VALUE_MAX_CHARS ? text : `${text.slice(0, REFUSAL_VALUE_MAX_CHARS)}...(+${text.length - REFUSAL_VALUE_MAX_CHARS} chars)`;
407
491
  }
408
492
 
493
+ // packages/ceal-client-protocol/src/operation-access-class.ts
494
+ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
495
+
496
+ // packages/ceal-client-protocol/src/domain-vocabulary.ts
497
+ var CEAL_INTEGRATION_KINDS = vocabulary(["github", "google-workspace", "notion", "slack"]);
498
+ var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
499
+ var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
500
+ var CEAL_PROVIDER_BOUNDARY_KINDS = vocabulary([
501
+ "github_account",
502
+ "github_organization",
503
+ "google_workspace_domain",
504
+ "notion_workspace",
505
+ "slack_workspace"
506
+ ]);
507
+ var CEAL_PROVIDER_BOUNDARY_EVIDENCE = vocabulary(["provider_readback", "operator_stated"]);
508
+ var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
509
+ var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
510
+ var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
511
+ var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
512
+ var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
513
+ var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
514
+
409
515
  // packages/ceal-client-protocol/src/safe-json-budget.ts
410
516
  var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
411
517
  function safeJsonNodeBudgetForBytes(maxBytes) {
@@ -435,7 +541,9 @@ var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
435
541
  });
436
542
 
437
543
  // packages/ceal-client-protocol/src/operation-validation-primitives.ts
438
- var ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/u;
544
+ var ISO_TIMESTAMP = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?([Zz]|([+-])(\d{2}):(\d{2}))$/u;
545
+ var CEAL_CALENDAR_DATE_PATTERN_SOURCE = "^\\d{4}-\\d{2}-\\d{2}$";
546
+ var CEAL_CALENDAR_DATE = new RegExp(CEAL_CALENDAR_DATE_PATTERN_SOURCE, "u");
439
547
  function isOperationRecord(value) {
440
548
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
441
549
  const prototype = Object.getPrototypeOf(value);
@@ -447,8 +555,56 @@ function requireOperationRecord(value, message) {
447
555
  function requireClosedValue(value, members, message) {
448
556
  if (typeof value !== "string" || !members.includes(value)) throw new TypeError(message);
449
557
  }
558
+ function isCealIsoTimestamp(value) {
559
+ return typeof value === "string" && parseCealIsoTimestamp(value) !== null;
560
+ }
561
+ function parseCealIsoTimestamp(value) {
562
+ const fields = parseCealIsoTimestampFields(value);
563
+ if (fields === null || !validCalendarDate(fields) || !validClockTime(fields) || !validUtcOffset(fields)) return null;
564
+ const epochMilliseconds = cealFieldsEpochMilliseconds(fields);
565
+ if (!Number.isFinite(epochMilliseconds)) return null;
566
+ return {
567
+ epochNanoseconds: BigInt(epochMilliseconds) * 1000000n + BigInt(fields.fraction.padEnd(9, "0") || "0")
568
+ };
569
+ }
570
+ function parseCealIsoTimestampFields(value) {
571
+ const match = ISO_TIMESTAMP.exec(value);
572
+ if (match === null) return null;
573
+ return {
574
+ year: Number(match[1]),
575
+ month: Number(match[2]),
576
+ day: Number(match[3]),
577
+ hour: Number(match[4]),
578
+ minute: Number(match[5]),
579
+ second: Number(match[6]),
580
+ fraction: match[7] ?? "",
581
+ offsetSign: match[9] === void 0 ? 0 : match[9] === "+" ? 1 : -1,
582
+ offsetHour: Number(match[10] ?? 0),
583
+ offsetMinute: Number(match[11] ?? 0)
584
+ };
585
+ }
586
+ function validCalendarDate({ year, month, day }) {
587
+ return month >= 1 && month <= 12 && day >= 1 && day <= daysInMonth(year, month);
588
+ }
589
+ function validClockTime({ hour, minute, second }) {
590
+ return hour <= 23 && minute <= 59 && second <= 59;
591
+ }
592
+ function validUtcOffset({ offsetHour, offsetMinute }) {
593
+ return offsetHour <= 23 && offsetMinute <= 59;
594
+ }
595
+ function cealFieldsEpochMilliseconds(fields) {
596
+ const shiftedYear = fields.year < 100 ? fields.year + 400 : fields.year;
597
+ const cycleMilliseconds = fields.year < 100 ? (400 * 365 + 97) * 24 * 60 * 60 * 1e3 : 0;
598
+ const localMilliseconds = Date.UTC(shiftedYear, fields.month - 1, fields.day, fields.hour, fields.minute, fields.second, 0) - cycleMilliseconds;
599
+ const offsetMilliseconds = fields.offsetSign * (fields.offsetHour * 60 + fields.offsetMinute) * 6e4;
600
+ return localMilliseconds - offsetMilliseconds;
601
+ }
602
+ function daysInMonth(year, month) {
603
+ const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
604
+ return [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1] ?? 0;
605
+ }
450
606
  function requireIsoTimestamp(value, message) {
451
- if (typeof value !== "string" || !ISO_TIMESTAMP.test(value) || !Number.isFinite(Date.parse(value))) throw new TypeError(message);
607
+ if (!isCealIsoTimestamp(value)) throw new TypeError(message);
452
608
  }
453
609
 
454
610
  // packages/ceal-client-protocol/src/operation-json-schema.ts
@@ -470,7 +626,7 @@ var CLIENT_AUDIENCE_SET = new Set(CLIENT_AUDIENCES);
470
626
  // packages/ceal-client-protocol/src/schema-literals.ts
471
627
  var CEAL_SCHEMA_LITERALS = [
472
628
  "ceal.activation_transport.v1",
473
- "ceal.capability_access.v1",
629
+ CEAL_OPERATION_ACCESS_SCHEMA_VERSION,
474
630
  CEAL_OPERATION_CATALOG_SCHEMA_VERSION,
475
631
  "ceal.client_refresh_request.v2",
476
632
  "ceal.client_refresh_result.v2",
@@ -493,7 +649,6 @@ var CEAL_SCHEMA_LITERALS = [
493
649
  "ceal.enrollment_exchange.v1",
494
650
  "ceal.enrollment_result.v1",
495
651
  "ceal.first_activation_causal_join.v1",
496
- "ceal.gateway_aggregate_authorization_snapshot.v2",
497
652
  "ceal.gateway_announcement_policy.v1",
498
653
  "ceal.gateway_audit_call_detail.v1",
499
654
  "ceal.gateway_audit_event.v1",
@@ -501,7 +656,7 @@ var CEAL_SCHEMA_LITERALS = [
501
656
  "ceal.gateway_authorization_snapshot.v1",
502
657
  "ceal.gateway_cache_origin.v1",
503
658
  "ceal.gateway_call_result.v1",
504
- "ceal.gateway_command_resolution.v1",
659
+ CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION,
505
660
  "ceal.gateway_connector_route_failure.v1",
506
661
  "ceal.gateway_discovery.v3",
507
662
  "ceal.gateway_handshake.v1",
@@ -536,7 +691,7 @@ var CEAL_SCHEMA_LITERALS = [
536
691
  "ceal.operation_receipt.v1",
537
692
  "ceal.operation_result.v1",
538
693
  "ceal.operation_result.compact.v1",
539
- "ceal.local_result_materialization.v1",
694
+ "ceal.local_result_materialization.v2",
540
695
  "ceal.local_result_root.v1",
541
696
  "ceal.owner_bootstrap_exchange_request.v1",
542
697
  "ceal.owner_bootstrap_exchange_result.v1",
@@ -546,7 +701,8 @@ var CEAL_SCHEMA_LITERALS = [
546
701
  "ceal.request_cancellation.v1",
547
702
  "ceal.request_graph_revision.v1",
548
703
  "ceal.request_occurrence_correlation.v1",
549
- "ceal.request_projection.v1"
704
+ "ceal.request_projection.v1",
705
+ "ceal.write_safety_finding.v1"
550
706
  ];
551
707
  var CEAL_SCHEMA_LITERAL_SET = new Set(CEAL_SCHEMA_LITERALS);
552
708
 
@@ -561,21 +717,14 @@ var CEAL_BOUNDED_SERIES_CATALOG = Object.freeze({
561
717
  thread_run_events: (root) => join(root, "run-events.jsonl"),
562
718
  bounded_store_sidecar: (root) => `${root}.jsonl`,
563
719
  gateway_audit_archive: (root) => `${root}.jsonl`,
564
- gateway_capability_audit: (root) => join(root, "capability-audit.jsonl"),
565
- gateway_retrieval_waste_partition: (root) => `${root}.jsonl`,
566
- gateway_access_policy_publication: (root) => join(root, "access-policy-publications.jsonl"),
567
720
  gateway_access_group_connector_control_audit: (root) => `${root}.audit.jsonl`,
568
721
  gateway_access_group_connector_scope_audit: (root) => join(root, "profile-connector-scope-audit.jsonl"),
569
722
  gateway_access_group_connector_activity_scope_audit: (root) => join(root, "profile-connector-activity-scope-audit.jsonl"),
723
+ gateway_access_group_connector_calendar_scope_audit: (root) => join(root, "profile-connector-calendar-scope-audit.jsonl"),
570
724
  gateway_access_group_connector_readiness_audit: (root) => join(root, "profile-connector-readiness.audit.jsonl"),
571
725
  gateway_organization_audit_ledger: (root) => join(root, "organization-ledger.jsonl"),
572
726
  gateway_personal_client_audit: (root) => join(root, "audit.jsonl"),
573
- gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl"),
574
- gateway_admin_enrollment: (root) => join(root, "enrollments.jsonl"),
575
- gateway_admin_login: (root) => join(root, "logins.jsonl"),
576
- gateway_admin_family: (root) => join(root, "families.jsonl"),
577
- gateway_admin_refresh_token: (root) => join(root, "refresh-tokens.jsonl"),
578
- gateway_admin_access_token: (root) => join(root, "access-tokens.jsonl")
727
+ gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl")
579
728
  });
580
729
 
581
730
  // packages/ceal-client-protocol/src/gateway-installation-activation.ts
@@ -583,8 +732,21 @@ var CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_DATA_CHARACTERS = 32;
583
732
  var CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_CHECK_CHARACTERS = 8;
584
733
  var CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_COMPACT_CHARACTERS = CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_DATA_CHARACTERS + CEAL_GATEWAY_INSTALLATION_ACTIVATION_CODE_CHECK_CHARACTERS;
585
734
 
735
+ // packages/ceal-client-protocol/src/gateway-entrypoint-commands.ts
736
+ var GATEWAY_ENTRYPOINT_COMMANDS = Object.freeze([
737
+ Object.freeze({ id: "controlPlane", path: Object.freeze(["control-plane"]) }),
738
+ Object.freeze({ id: "originShow", path: Object.freeze(["origin", "show"]) }),
739
+ Object.freeze({ id: "credentialsImport", path: Object.freeze(["credentials", "import"]) }),
740
+ Object.freeze({ id: "initialize", path: Object.freeze(["init"]) })
741
+ ]);
742
+
586
743
  // packages/ceal-client-protocol/src/host-registration.ts
587
744
  var CEAL_HOST_REGISTRATION_RESULT_KEYS = Object.freeze(["credential_generation", "host_access_token", "host_installation_ref", "host_source_ref", "ok", "registration_attempt_ref", "schema_version", "status"]);
745
+ var CEAL_LOWERCASE_UUID_PATTERN = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
746
+ var CEAL_HOST_REGISTRATION_ATTEMPT_REF_PATTERN = new RegExp(`^host-registration-attempt:${CEAL_LOWERCASE_UUID_PATTERN}$`, "u");
747
+ var CEAL_HOST_INSTALLATION_REF_PATTERN = new RegExp(`^host-installation:${CEAL_LOWERCASE_UUID_PATTERN}$`, "u");
748
+ var CEAL_HOST_SOURCE_REF_PATTERN = new RegExp(`^host-source:${CEAL_LOWERCASE_UUID_PATTERN}$`, "u");
749
+ var CEAL_HOST_ACCESS_TOKEN_PATTERN = /^ceal_host_[A-Za-z0-9_-]{43}$/u;
588
750
 
589
751
  // packages/ceal-client-protocol/src/agent-session-handoff.ts
590
752
  var CEAL_AGENT_ADMISSION_PHASES = vocabulary([
@@ -616,12 +778,19 @@ var CEAL_AGENT_SERVICE_SESSION_RECORD_KEYS = vocabulary([
616
778
  var CEAL_AGENT_SESSION_COMMIT_KEYS = vocabulary(["attempt_ref", "expected_session_revision", "session_revision"]);
617
779
 
618
780
  // packages/ceal-client-protocol/src/operation-next-actions.ts
781
+ var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
782
+ var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
619
783
  var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
620
784
  "select_did_you_mean",
621
785
  "choose_new_output_path",
622
786
  "choose_new_idempotency_key",
623
787
  "restart_search",
624
788
  "repeat_original_arguments",
789
+ // The occurrence this call addressed is settled and cannot move again -- a
790
+ // denied effect approval, an expired continuation -- so the caller runs the
791
+ // same call again as a new request. The refusal names the re-request; this
792
+ // word is the re-request.
793
+ CEAL_REPEAT_REQUEST_NEXT_ACTION,
625
794
  "choose_new_request_identity",
626
795
  // A refusal that names the argument (invalid_argument with `property`) tells the caller exactly what to change.
627
796
  "correct_argument",
@@ -640,10 +809,35 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
640
809
  "use_original_input",
641
810
  // The same mismatch on the Request binding rather than the input: the
642
811
  // occurrence was admitted under one binding and the replay presents another.
643
- "use_original_request_binding"
812
+ "use_original_request_binding",
813
+ // The client's own filesystem write was refused -- EACCES, EPERM, or a
814
+ // read-only mount -- which is how an agent sandbox fences writes outside its
815
+ // workspace. The caller reruns the same command with unsandboxed or escalated
816
+ // execution; re-adopting the session cannot help, because the sandbox refuses
817
+ // that write too.
818
+ "rerun_outside_agent_sandbox",
819
+ // The refusal names the one Operation to read next in `describe_command`:
820
+ // an absent Operation id with a sole catalog-ranked candidate, or a known
821
+ // Operation invoked without its input. Describing only reads the verified
822
+ // contract and dispatches nothing, and the caller then retries with the
823
+ // named Operation or input, so it is guidance the scorer counts.
824
+ "describe_operation",
825
+ // The refusal names the caller's own personal connect Operation in
826
+ // `required_action_sequence`: the Operation asked for, or the credential
827
+ // the call ran on, needs a personal connection the caller does not hold
828
+ // (never connected, revoked, or expired). The caller runs that exact
829
+ // Operation, completes the consent it hands back, and retries the same call.
830
+ "connect_personal_account",
831
+ // The provider or Gateway named a bounded wait; the caller waits that long
832
+ // and submits the same read again.
833
+ "retry_after"
644
834
  ];
645
835
  var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
646
836
  var NON_REMEDY_NEXT_ACTION_VALUES = [
837
+ // Only an administrator can take the named step -- approving a place for an
838
+ // Operation, granting a withheld capability -- so a non-administrator asks
839
+ // one. The refusal names the administrator step; this word is the ask.
840
+ "ask_admin",
647
841
  "await_pending_approval",
648
842
  "check_gateway",
649
843
  "inspect_context_store",
@@ -658,9 +852,13 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
658
852
  "inspect_local_command",
659
853
  "inspect_local_output",
660
854
  "inspect_local_route",
661
- "inspect_receipt",
855
+ CEAL_INSPECT_RECEIPT_NEXT_ACTION,
662
856
  "inspect_request",
663
857
  "none",
858
+ // The provider refused because of its own configuration -- an API not
859
+ // enabled, an app scope missing -- which an operator changes in that
860
+ // provider's console. No caller edit and no retry fixes it.
861
+ "operator_action",
664
862
  "recover",
665
863
  "reconcile",
666
864
  // Reconciliation of one named occurrence, not of the deployment: a legacy
@@ -668,6 +866,10 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
668
866
  // no edit to the call changes that. `reconcile` is the deployment-wide word.
669
867
  "reconcile_occurrence",
670
868
  "reduce_request_size",
869
+ // The Host's invocation context for this turn is stale or expired at the
870
+ // Gateway. The Host's next turn rebinds it and the same call then succeeds;
871
+ // nothing in the call changes, so it is not a remedy the scorer may count.
872
+ "refresh_host_invocation_context",
671
873
  "repair_or_adopt_session",
672
874
  "retry",
673
875
  // The owner -- a correlation hook, an approval hook -- is not serving right
@@ -681,10 +883,23 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
681
883
  var CEAL_NON_REMEDY_NEXT_ACTIONS = Object.freeze(NON_REMEDY_NEXT_ACTION_VALUES);
682
884
  var DECLARED = /* @__PURE__ */ new Set([...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS, ...CEAL_NON_REMEDY_NEXT_ACTIONS]);
683
885
  var RECOVERABLE = new Set(CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS);
886
+ var CEAL_OPERATION_WITHHELD_NEXT_ACTIONS = Object.freeze({
887
+ provider_permission: "ask_admin",
888
+ access_level: "ask_admin",
889
+ personal_authorization_required: "connect_personal_account"
890
+ });
684
891
 
685
892
  // packages/ceal-client-protocol/src/operation-contract-artifact.ts
686
893
  var CATALOG_REVISION = new RegExp(CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN, "u");
687
894
  var SHA256 = new RegExp(CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN, "u");
895
+ var CEAL_OPERATION_INVOKE_COMMAND = "invoke";
896
+ var CEAL_OPERATION_INPUT_FLAG = "--input";
897
+ var CEAL_OPERATION_ID_PLACEHOLDER = "<operation-id>";
898
+ var CEAL_OPERATION_INPUT_PLACEHOLDER = "<json-object>";
899
+ var CEAL_MODEL_INVOCATION_ARGUMENTS = [CEAL_OPERATION_INVOKE_COMMAND, CEAL_OPERATION_ID_PLACEHOLDER, CEAL_OPERATION_INPUT_FLAG, shellSingleQuoted(CEAL_OPERATION_INPUT_PLACEHOLDER)].join(" ");
900
+ function shellSingleQuoted(value) {
901
+ return `'${value.replaceAll("'", "'\\''")}'`;
902
+ }
688
903
  var CEAL_OPERATION_CONTRACT_REQUIRED_FIELDS = Object.freeze(["input_schema", "result_schema"]);
689
904
  var CEAL_OPERATION_CONTRACT_OPTIONAL_FIELDS = Object.freeze(["summary", "input_resolution"]);
690
905
  var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
@@ -713,9 +928,178 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
713
928
  }
714
929
  });
715
930
 
931
+ // packages/ceal-client-protocol/src/bare-document.ts
932
+ var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_fields;
933
+ var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
934
+
935
+ // packages/ceal-client-protocol/src/leased-consumer-vocabulary.ts
936
+ var CEAL_TERMINAL_DISPOSITIONS = vocabulary(["completed", "failed", "cancelled"]);
937
+ var CEAL_LEASE_DISPOSITIONS = vocabulary([...CEAL_TERMINAL_DISPOSITIONS, "deferred"]);
938
+ var CEAL_AUTOMATIC_FEEDBACK_INTENTS = vocabulary(["initial"]);
939
+ var CEAL_LEASED_MESSAGE_DELIVERY_OPERATION_IDS = vocabulary(["message.send", "message.update", "message.delete"]);
940
+ var CEAL_REPOSITORY_VISIBILITIES = vocabulary(["public", "private", "internal"]);
941
+ var CEAL_RESULT_DELIVERY_OFFERS = vocabulary(["pending", "offered", "transport_lost"]);
942
+ var CEAL_RESULT_DELIVERY_STATES = vocabulary(["unavailable", ...CEAL_RESULT_DELIVERY_OFFERS]);
943
+ var CEAL_PROVIDER_OUTCOMES = vocabulary(["not_attempted", "outcome_unknown", "verified"]);
944
+ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
945
+ "provider_page_budget",
946
+ "call_deadline",
947
+ "related_item_budget",
948
+ "provider_cursor_unavailable",
949
+ "malformed_provider_page",
950
+ "visibility_incomplete",
951
+ "unsupported_event_kind"
952
+ ]);
953
+ var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
954
+ var CEAL_ACTIVITY_COVERAGE_STATUSES = vocabulary(["complete_for_target", "continuation_required", "blocked"]);
955
+ var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
956
+ "slack.message",
957
+ "slack.reply",
958
+ "slack.direct_message",
959
+ "github.commit.authored",
960
+ "github.issue.opened",
961
+ "github.pull_request.opened",
962
+ "github.review.submitted",
963
+ "github.issue_comment.created",
964
+ "github.review_comment.created",
965
+ "calendar.organized",
966
+ "calendar.accepted_invite",
967
+ "calendar.recorded",
968
+ "drive.file.created",
969
+ "drive.file.modified",
970
+ "drive.file.viewed",
971
+ "notion.page.created",
972
+ "notion.page.edited"
973
+ ]);
974
+ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
975
+ "message_created",
976
+ "commit_authored",
977
+ "resource_created",
978
+ "review_submitted",
979
+ "comment_created",
980
+ "event_start",
981
+ "all_day_start",
982
+ "file_created",
983
+ "file_modified",
984
+ "file_modified_by_me",
985
+ "file_viewed_by_me",
986
+ "page_created",
987
+ "page_last_edited",
988
+ "resource_modified"
989
+ ]);
990
+ var CEAL_ACTIVITY_V3_KINDS = vocabulary(["authored", "edited", "messaged", "responded"]);
991
+ var CEAL_RESOURCE_TIME_BASES = vocabulary(["created", "modified", "viewed"]);
992
+ var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
993
+ var CEAL_RESOURCE_SEARCH_DIRECTIONS = vocabulary(["ascending", "descending"]);
994
+ var CEAL_RESOURCE_SEARCH_FILTERS = vocabulary(["query", "modified_since", "kinds", "container_ref", "addressed_to_me", "unread"]);
995
+ var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
996
+ var CEAL_READ_ITEM_KINDS = vocabulary(["conversation", "identity", "usergroup", "message", "file", "document"]);
997
+ var CEAL_LEASED_MESSAGE_SEARCH_COMPLETENESS = vocabulary(["complete", "continuation_available", "truncated"]);
998
+ var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "object"]);
999
+ var CEAL_WRITE_OBJECT_KINDS = vocabulary(["document", "comment", "cell_range"]);
1000
+ var CEAL_CONVERSATION_KINDS = vocabulary(["channel", "dm", "group"]);
1001
+ var CEAL_FILE_TYPE_FAMILIES = vocabulary(["all", "image", "pdf"]);
1002
+ var CEAL_GITHUB_ISSUE_STATES = vocabulary(["open", "closed", "all"]);
1003
+ var CEAL_NOTION_UPDATABLE_BLOCK_TYPES = vocabulary([
1004
+ "paragraph",
1005
+ "heading_1",
1006
+ "heading_2",
1007
+ "heading_3",
1008
+ "bulleted_list_item",
1009
+ "numbered_list_item",
1010
+ "to_do",
1011
+ "code"
1012
+ ]);
1013
+ var CEAL_NOTION_NEUTRAL_TYPES = vocabulary([
1014
+ "text",
1015
+ "number",
1016
+ "boolean",
1017
+ "date",
1018
+ "select",
1019
+ "multi_select",
1020
+ "people",
1021
+ "url",
1022
+ "email",
1023
+ "phone",
1024
+ "unsupported"
1025
+ ]);
1026
+ var CEAL_NOTION_IDENTITY_GAP_REASONS = vocabulary([
1027
+ "identity_unavailable",
1028
+ "identity_stale",
1029
+ "identity_ambiguous",
1030
+ "identity_revoked",
1031
+ "identity_unlinked"
1032
+ ]);
1033
+ var CEAL_NOTION_STRING_VALUE_TYPES = vocabulary(["text", "select", "url", "email", "phone"]);
1034
+ var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
1035
+ var CEAL_PLAN_ITEM_STATUSES = vocabulary(["pending", "active", "completed"]);
1036
+ var CEAL_FINAL_PRESENTATION_INTENTS = vocabulary(["final", "stop", "transient_notice"]);
1037
+ var CEAL_PRESENTATION_INTENTS = vocabulary(["progress", ...CEAL_FINAL_PRESENTATION_INTENTS]);
1038
+
1039
+ // packages/ceal-client-protocol/src/resource-row.ts
1040
+ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1041
+ schema_version: { required: true, timestamp: false },
1042
+ ref: { required: true, timestamp: false },
1043
+ next: { required: true, timestamp: false },
1044
+ kind: { required: true, timestamp: false },
1045
+ title: { required: true, timestamp: false },
1046
+ container_label: { required: true, timestamp: false },
1047
+ container_ref: { required: false, timestamp: false },
1048
+ source: { required: true, timestamp: false },
1049
+ owner: { required: false, timestamp: false },
1050
+ counterparts: { required: false, timestamp: false },
1051
+ created_at: { required: false, timestamp: true },
1052
+ created_at_local: { required: false, timestamp: true },
1053
+ modified_at: { required: false, timestamp: true },
1054
+ modified_at_local: { required: false, timestamp: true },
1055
+ viewed_by_me_at: { required: false, timestamp: true },
1056
+ visibility: { required: false, timestamp: false },
1057
+ start: { required: false, timestamp: false },
1058
+ end: { required: false, timestamp: false },
1059
+ status: { required: false, timestamp: false },
1060
+ snippet: { required: false, timestamp: false },
1061
+ state: { required: true, timestamp: false },
1062
+ timestamp_basis: { required: true, timestamp: false }
1063
+ });
1064
+ var RESOURCE_ROW_REQUIRED_KEYS = Object.entries(RESOURCE_ROW_KEY_RULES).flatMap(([key, rule]) => rule.required ? [key] : []);
1065
+ var RESOURCE_ROW_KEYS = new Set(Object.keys(RESOURCE_ROW_KEY_RULES));
1066
+ var RESOURCE_ROW_TIMESTAMP_KEYS = Object.entries(RESOURCE_ROW_KEY_RULES).flatMap(([key, rule]) => rule.timestamp ? [key] : []);
1067
+
1068
+ // packages/ceal-client-protocol/src/resource-read-result.ts
1069
+ var CEAL_RESOURCE_GET_COVERAGE_NEXT_ACTIONS = vocabulary(["reduce_request_size", "read_resource_again"]);
1070
+
1071
+ // packages/ceal-client-protocol/src/excluded-target-coverage-contract.ts
1072
+ var CEAL_EXCLUDED_TARGET_REASONS = vocabulary(["audience_narrower_than_place", "visibility_unknown"]);
1073
+
1074
+ // packages/ceal-client-protocol/src/excluded-target-coverage.ts
1075
+ var CEAL_EXCLUDED_TARGET_COVERAGE_MAX_ENTRIES = 64;
1076
+ function cealExcludedTargetCoverageJsonSchema() {
1077
+ const target = {
1078
+ target_ref: { type: "string", minLength: 8, maxLength: 134, pattern: "^target:[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
1079
+ connector_kind: { type: "string", minLength: 1, maxLength: 64, pattern: "^[a-z][a-z0-9-]{0,63}$" },
1080
+ label: { type: "string", minLength: 1, maxLength: CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES },
1081
+ reason: { type: "string", enum: [...CEAL_EXCLUDED_TARGET_REASONS] }
1082
+ };
1083
+ return {
1084
+ type: "array",
1085
+ minItems: 1,
1086
+ maxItems: CEAL_EXCLUDED_TARGET_COVERAGE_MAX_ENTRIES,
1087
+ items: { type: "object", additionalProperties: false, maxProperties: 4, properties: target, required: ["target_ref", "reason"] }
1088
+ };
1089
+ }
1090
+
1091
+ // packages/ceal-client-protocol/src/write-safety-finding.ts
1092
+ var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
1093
+ var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
1094
+ var CEAL_WRITE_SAFETY_REFERENCE_REASONS = vocabulary(["not_published_to_audience", "audience_access_unknown"]);
1095
+ var CEAL_WRITE_SAFETY_UNCHECKED_REASONS = vocabulary(["authority_unavailable"]);
1096
+
716
1097
  // packages/ceal-client-protocol/src/operation-occurrence.ts
717
1098
  var MAX_RECEIPT_REVISION = Number.MAX_SAFE_INTEGER - 1;
718
1099
 
1100
+ // packages/ceal-client-protocol/src/leased-artifact-contract.ts
1101
+ var CEAL_LEASED_CONSUMER_ARTIFACT_CHUNK_MAX_BYTES = 12 * 1024;
1102
+
719
1103
  // packages/ceal-client-protocol/src/leased-resource-stream.ts
720
1104
  var CEAL_LEASED_CONSUMER_ATTACHMENT_STREAM_MAGIC = new Uint8Array([67, 69, 65, 76, 82, 83, 50, 0]);
721
1105
  var CEAL_LEASED_CONSUMER_ATTACHMENT_STREAM_RECORD_PREFIX_BYTES = 8;
@@ -727,6 +1111,7 @@ var CEAL_ATTACHMENT_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_
727
1111
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
728
1112
  import { createHash } from "node:crypto";
729
1113
  var DIGEST = /^[a-f0-9]{64}$/u;
1114
+ var CEAL_SHA256_DIGEST_PATTERN = DIGEST.source;
730
1115
  function isCealDigest(value) {
731
1116
  return typeof value === "string" && DIGEST.test(value);
732
1117
  }
@@ -753,7 +1138,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
753
1138
  var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority", "prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
754
1139
  var CEAL_REQUEST_JSON_SCHEMA = {
755
1140
  type: "object",
756
- maxProperties: 9,
1141
+ maxProperties: 10,
757
1142
  additionalProperties: false,
758
1143
  properties: {
759
1144
  schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
@@ -776,7 +1161,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
776
1161
  host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
777
1162
  host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
778
1163
  host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
779
- host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1164
+ host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1165
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." }
780
1166
  },
781
1167
  required: CEAL_REQUEST_KEYS
782
1168
  };
@@ -826,21 +1212,26 @@ var REQUEST_NODE_STANDING_OCCURRENCE_SCHEMA = {
826
1212
  },
827
1213
  required: ["schema_version", "node_ref", "operation_id", "correlation_ref", "occurrence_ref", "graph_revision", "graph_revision_digest", "admitted_input_sha256", "reason"]
828
1214
  };
1215
+ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
1216
+ schema_version: { type: "string", const: CEAL_OPERATION_ERROR_SCHEMA_VERSION, maxLength: 64 },
1217
+ code: REQUEST_ACTION_SAFE_REF_SCHEMA,
1218
+ message: { type: "string", minLength: 1, maxLength: 2048 },
1219
+ property: { type: "string", minLength: 1, maxLength: 256 },
1220
+ next_action: REQUEST_ACTION_SAFE_REF_SCHEMA,
1221
+ retryable: { type: "boolean" },
1222
+ source: { type: "string", enum: ["provider", "gateway"] },
1223
+ retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
1224
+ excluded_targets: cealExcludedTargetCoverageJsonSchema(),
1225
+ repaired_input: {},
1226
+ unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
1227
+ provider_handoff: { type: "string", const: "not_offered", maxLength: 32 },
1228
+ cause: { type: "string", enum: [...CEAL_OPERATION_WITHHELD_CAUSES] }
1229
+ };
829
1230
  var REQUEST_EXECUTION_PREPARE_REFUSAL_SCHEMA = {
830
1231
  type: "object",
831
1232
  additionalProperties: false,
832
- maxProperties: 9,
833
- properties: {
834
- schema_version: { type: "string", const: CEAL_OPERATION_ERROR_SCHEMA_VERSION, maxLength: 64 },
835
- code: REQUEST_ACTION_SAFE_REF_SCHEMA,
836
- message: { type: "string", minLength: 1, maxLength: 2048 },
837
- property: { type: "string", minLength: 1, maxLength: 256 },
838
- next_action: REQUEST_ACTION_SAFE_REF_SCHEMA,
839
- retryable: { type: "boolean" },
840
- repaired_input: {},
841
- unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
842
- provider_handoff: { type: "string", const: "not_offered", maxLength: 32 }
843
- },
1233
+ maxProperties: Object.keys(REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES).length,
1234
+ properties: REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES,
844
1235
  required: ["schema_version", "code", "message", "next_action", "retryable"]
845
1236
  };
846
1237
  var CEAL_REQUEST_EXECUTION_ORDERS = vocabulary(["graph_dependency", "caller"]);
@@ -1023,6 +1414,7 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
1023
1414
  // packages/ceal-client-protocol/src/host-invocation-authentication.ts
1024
1415
  var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = "ceal.host_invocation_authentication_result.v1";
1025
1416
  var CEAL_HOST_INVOCATION_CONTEXT_PATH = "/api/ceal/v2/host-invocation-context";
1417
+ var CEAL_HOST_INGRESS_PATH = "/api/ceal/v2/host-ingress";
1026
1418
  var CEAL_HOST_CLIENT_NONCE_PATTERN = /^[A-Za-z0-9_-]{43}$/u;
1027
1419
  var CEAL_HOST_CONTEXT_TOKEN_PATTERN = /^ceal_context_[A-Za-z0-9_-]{43}$/u;
1028
1420
  function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__ */ new Date()) {
@@ -1041,16 +1433,14 @@ function exactKeys(value, expected) {
1041
1433
  }
1042
1434
 
1043
1435
  // packages/ceal-client-protocol/src/client-result-materialization.ts
1044
- var REQUIRED_FIELDS = Object.freeze(["schema_version", "operation_id", "local_path", "content_json_pointer", "size_bytes", "sha256", "read_argv"]);
1045
- var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS, "local_result_root", "model_disclosure"]);
1436
+ var CEAL_MODEL_VISIBLE_COMMAND_OUTPUT_MAX_BYTES = 32 * 1024;
1437
+ var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "read_argv"]);
1438
+ var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "local_result_root"]);
1046
1439
 
1047
1440
  // packages/ceal-client-protocol/src/session-start-affordance.ts
1048
1441
  var CEAL_SESSION_ENTRY_INVOCATION = "ceal";
1049
1442
  var CEAL_LINK_RESOURCE_PRECEDENCE = `When the user asks to use Ceal or provides a link to information that may be available through installed organizational capabilities, run bare \`${CEAL_SESSION_ENTRY_INVOCATION}\`. The Host supplies the current user prompt without exposing it to the client command, and the Gateway returns the applicable entry in that one response. Treat a supplied link as a candidate Ceal resource rather than a public web-search target. Reach for a generic web fetch or web search only when the Gateway offered nothing.`;
1050
1443
 
1051
- // packages/ceal-client-protocol/src/discovery-manifest.ts
1052
- var CEAL_DISCOVERY_MANIFEST_CONNECTOR_KINDS = vocabulary(["github", "google-workspace", "notion", "slack"]);
1053
-
1054
1444
  // packages/ceal-client-protocol/src/conversation-contracts.ts
1055
1445
  var CEAL_APPROVAL_POLICY_KINDS = vocabulary(["requester_only", "named_users", "role_based"]);
1056
1446
  var CEAL_APPROVAL_TARGET_KINDS = vocabulary([
@@ -1093,38 +1483,18 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
1093
1483
 
1094
1484
  // packages/ceal-client-protocol/src/gateway-discovery-response-validation.ts
1095
1485
  var ANNOUNCEMENT_POLICY_CAPABILITY_BINDINGS = Object.freeze({
1096
- "github.repository.get": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1097
- "collection.search": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1098
- "github.issue.get": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1099
- "github.pull_request.get": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1486
+ "repository.get": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1487
+ "resource.search": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1100
1488
  "github.workflow_run.get": [{ effect: "read", scopeStatementKind: "github_app_installation_repositories", providerAuthorityKind: "github_app" }],
1101
1489
  "message.search": [{ effect: "read", scopeStatementKind: "slack_public_app_member_channels_only", providerAuthorityKind: "slack_app" }],
1102
- "message.get": [{ effect: "read", scopeStatementKind: "slack_public_app_member_channels_only", providerAuthorityKind: "slack_app" }],
1103
- "resource.resolve": [
1104
- { effect: "read", scopeStatementKind: "slack_public_app_member_channels_only", providerAuthorityKind: "slack_app" },
1105
- { effect: "read", scopeStatementKind: "notion_connected_logical_area", providerAuthorityKind: "notion_integration" }
1106
- ],
1107
- "conversation.thread.get": [{ effect: "read", scopeStatementKind: "slack_public_app_member_channels_only", providerAuthorityKind: "slack_app" }],
1108
1490
  "notion.search": [{ effect: "read", scopeStatementKind: "notion_connected_logical_area", providerAuthorityKind: "notion_integration" }],
1109
- "notion.page.get": [{ effect: "read", scopeStatementKind: "notion_connected_logical_area", providerAuthorityKind: "notion_integration" }],
1110
- "calendar.availability": [{ effect: "read", scopeStatementKind: "google_workspace_calendar_read_only", providerAuthorityKind: "google_service_account" }],
1111
- "calendar.event.search": [{ effect: "read", scopeStatementKind: "google_workspace_calendar_read_only", providerAuthorityKind: "google_service_account" }],
1112
- "calendar.event.get": [{ effect: "read", scopeStatementKind: "google_workspace_calendar_read_only", providerAuthorityKind: "google_service_account" }],
1113
- "file.search": [{ effect: "read", scopeStatementKind: "google_workspace_ceal_drive_or_direct_share_metadata", providerAuthorityKind: "google_service_account" }],
1114
- "sheets.values.read": [{ effect: "read", scopeStatementKind: "google_workspace_ceal_drive_or_direct_share_sheet_ranges", providerAuthorityKind: "google_service_account" }],
1115
- "sheets.tabs.list": [{ effect: "read", scopeStatementKind: "google_workspace_ceal_drive_or_direct_share_sheet_tabs", providerAuthorityKind: "google_service_account" }],
1116
- "sheets.values.update": [{ effect: "write", scopeStatementKind: "google_workspace_ceal_drive_or_direct_share_editable_sheet_ranges", providerAuthorityKind: "google_service_account" }],
1117
- "sheets.values.clear": [{ effect: "write", scopeStatementKind: "google_workspace_ceal_drive_or_direct_share_editable_sheet_clear_ranges", providerAuthorityKind: "google_service_account" }]
1118
- });
1119
- var ANNOUNCEMENT_SCOPE_STATEMENTS = Object.freeze({
1120
- github_app_installation_repositories: "Repositories in the installed GitHub App installation.",
1121
- slack_public_app_member_channels_only: "Public channels where the installed Slack app is a member; private channels, direct messages, multi-person direct messages, and requester membership are not declared by this connector.",
1122
- notion_connected_logical_area: "Connected Notion logical area under provider-enforced sharing; descendant inventory is not declared.",
1123
- google_workspace_calendar_read_only: "Approved Calendar availability and event reads only; Calendar mutation is not declared.",
1124
- google_workspace_ceal_drive_or_direct_share_metadata: "Metadata search for files in the organization shared drive named Ceal Drive and files directly shared with the provider application; file-content read and mutation are not declared.",
1125
- google_workspace_ceal_drive_or_direct_share_sheet_ranges: "Bounded values reads from governed Google Sheets in the organization shared drive named Ceal Drive and directly shared files; file mutation is not declared.",
1126
- google_workspace_ceal_drive_or_direct_share_editable_sheet_ranges: "Bounded values updates in governed editable Google Sheets in the organization shared drive named Ceal Drive and directly shared files; Docs, Slides, and other Drive file mutation are not declared.",
1127
- google_workspace_ceal_drive_or_direct_share_editable_sheet_clear_ranges: "Bounded values clears in governed editable Google Sheets in the organization shared drive named Ceal Drive and directly shared files; Docs, Slides, and other Drive file mutation are not declared."
1491
+ "resource.get": [{ effect: "read", scopeStatementKind: "notion_connected_logical_area", providerAuthorityKind: "notion_integration" }],
1492
+ "availability.get": [{ effect: "read", scopeStatementKind: "google_workspace_calendar_read_only", providerAuthorityKind: "google_service_account" }],
1493
+ "event.search": [{ effect: "read", scopeStatementKind: "google_workspace_calendar_read_only", providerAuthorityKind: "google_service_account" }],
1494
+ "file.search": [{ effect: "read", scopeStatementKind: "google_workspace_admitted_drive_target_metadata", providerAuthorityKind: "google_service_account" }],
1495
+ "cell_range.get": [{ effect: "read", scopeStatementKind: "google_workspace_admitted_drive_target_sheet_ranges", providerAuthorityKind: "google_service_account" }],
1496
+ "sheet.list": [{ effect: "read", scopeStatementKind: "google_workspace_admitted_drive_target_sheet_tabs", providerAuthorityKind: "google_service_account" }],
1497
+ "cell_range.update": [{ effect: "write", scopeStatementKind: "google_workspace_admitted_drive_target_editable_sheet_ranges", providerAuthorityKind: "google_service_account" }]
1128
1498
  });
1129
1499
 
1130
1500
  // packages/ceal-client-protocol/src/gateway-write-identity.ts
@@ -1181,113 +1551,29 @@ var ADMIN_LINEAGE_NODE_KINDS = vocabulary(["source_read", "synthesis_preview", "
1181
1551
  // packages/ceal-client-protocol/src/actor-kind.ts
1182
1552
  var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
1183
1553
 
1184
- // packages/ceal-client-protocol/src/leased-consumer-vocabulary.ts
1185
- var CEAL_TERMINAL_DISPOSITIONS = vocabulary(["completed", "failed", "cancelled"]);
1186
- var CEAL_LEASE_DISPOSITIONS = vocabulary([...CEAL_TERMINAL_DISPOSITIONS, "deferred"]);
1187
- var CEAL_AUTOMATIC_FEEDBACK_INTENTS = vocabulary(["initial"]);
1188
- var CEAL_LEASED_MESSAGE_DELIVERY_CAPABILITY_IDS = vocabulary(["message.create", "message.update", "message.delete"]);
1189
- var CEAL_REPOSITORY_VISIBILITIES = vocabulary(["public", "private", "internal"]);
1190
- var CEAL_RESULT_DELIVERY_OFFERS = vocabulary(["pending", "offered", "transport_lost"]);
1191
- var CEAL_RESULT_DELIVERY_STATES = vocabulary(["unavailable", ...CEAL_RESULT_DELIVERY_OFFERS]);
1192
- var CEAL_PROVIDER_OUTCOMES = vocabulary(["not_attempted", "outcome_unknown", "verified"]);
1193
- var CEAL_ACTIVITY_GAP_CODES = vocabulary([
1194
- "provider_page_budget",
1195
- "related_item_budget",
1196
- "provider_cursor_unavailable",
1197
- "malformed_provider_page",
1198
- "visibility_incomplete",
1199
- "unsupported_event_kind"
1200
- ]);
1201
- var CEAL_ACTIVITY_COVERAGE_STATUSES = vocabulary(["complete_for_target", "continuation_required", "blocked"]);
1202
- var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
1203
- "slack.message",
1204
- "slack.reply",
1205
- "github.commit.authored",
1206
- "github.issue.opened",
1207
- "github.pull_request.opened",
1208
- "github.review.submitted",
1209
- "github.issue_comment.created",
1210
- "github.review_comment.created",
1211
- "calendar.organized",
1212
- "calendar.accepted_invite",
1213
- "calendar.recorded"
1214
- ]);
1215
- var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
1216
- "message_created",
1217
- "commit_authored",
1218
- "resource_created",
1219
- "review_submitted",
1220
- "comment_created",
1221
- "event_start",
1222
- "all_day_start"
1554
+ // packages/ceal-client-protocol/src/personal-client-vocabulary.ts
1555
+ var CEAL_PERSONAL_CLIENT_BINDING_KEYS = vocabulary([
1556
+ "access_group_ref",
1557
+ "membership_ref",
1558
+ "registration_ref",
1559
+ "client_ref",
1560
+ "subject_ref",
1561
+ "instance_ref"
1223
1562
  ]);
1224
- var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
1225
- var CEAL_READ_ITEM_KINDS = vocabulary(["conversation", "identity", "usergroup", "message", "file", "document"]);
1226
- var CEAL_RESOURCE_RESOLVE_KINDS = vocabulary(["conversation", "identity", "usergroup", "permalink"]);
1227
- var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "object"]);
1228
- var CEAL_WRITE_OBJECT_KINDS = vocabulary(["document", "comment", "cell_range"]);
1229
- var CEAL_CONVERSATION_KINDS = vocabulary(["channel", "dm", "group"]);
1230
- var CEAL_FILE_TYPE_FAMILIES = vocabulary(["all", "image", "pdf"]);
1231
- var CEAL_GITHUB_ISSUE_STATES = vocabulary(["open", "closed", "all"]);
1232
- var CEAL_NOTION_UPDATABLE_BLOCK_TYPES = vocabulary([
1233
- "paragraph",
1234
- "heading_1",
1235
- "heading_2",
1236
- "heading_3",
1237
- "bulleted_list_item",
1238
- "numbered_list_item",
1239
- "to_do",
1240
- "code"
1241
- ]);
1242
- var CEAL_NOTION_NEUTRAL_TYPES = vocabulary([
1243
- "text",
1244
- "number",
1245
- "boolean",
1246
- "date",
1247
- "select",
1248
- "multi_select",
1249
- "people",
1250
- "url",
1251
- "email",
1252
- "phone",
1253
- "unsupported"
1254
- ]);
1255
- var CEAL_NOTION_IDENTITY_GAP_REASONS = vocabulary([
1256
- "identity_unavailable",
1257
- "identity_stale",
1258
- "identity_ambiguous",
1259
- "identity_revoked",
1260
- "identity_unlinked"
1261
- ]);
1262
- var CEAL_NOTION_STRING_VALUE_TYPES = vocabulary(["text", "select", "url", "email", "phone"]);
1263
- var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
1264
- var CEAL_PLAN_ITEM_STATUSES = vocabulary(["pending", "active", "completed"]);
1265
- var CEAL_FINAL_PRESENTATION_INTENTS = vocabulary(["final", "stop", "transient_notice"]);
1266
- var CEAL_PRESENTATION_INTENTS = vocabulary(["progress", ...CEAL_FINAL_PRESENTATION_INTENTS]);
1267
-
1268
- // packages/ceal-client-protocol/src/personal-client-vocabulary.ts
1269
- var CEAL_PERSONAL_CLIENT_BINDING_KEYS = vocabulary([
1270
- "access_group_ref",
1271
- "membership_ref",
1272
- "registration_ref",
1273
- "client_ref",
1274
- "subject_ref",
1275
- "instance_ref"
1276
- ]);
1277
- var CEAL_ENROLLMENT_FAILURE_CODES = vocabulary(["enrollment_invalid", "enrollment_expired", "enrollment_used"]);
1278
- var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1279
- "refresh_invalid",
1280
- "refresh_expired",
1281
- "refresh_inactive",
1282
- "refresh_replayed",
1283
- "refresh_revoked",
1284
- "authority_replaced",
1285
- "refresh_recovery_unavailable",
1286
- "refresh_recovery_expired"
1563
+ var CEAL_ENROLLMENT_FAILURE_CODES = vocabulary(["enrollment_invalid", "enrollment_expired", "enrollment_used"]);
1564
+ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1565
+ "refresh_invalid",
1566
+ "refresh_expired",
1567
+ "refresh_inactive",
1568
+ "refresh_replayed",
1569
+ "refresh_revoked",
1570
+ "authority_replaced",
1571
+ "refresh_recovery_unavailable",
1572
+ "refresh_recovery_expired"
1287
1573
  ]);
1288
1574
 
1289
1575
  // packages/ceal-client-protocol/src/device-enrollment.ts
1290
- var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired"]);
1576
+ var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired", "denied"]);
1291
1577
  var POLL_RESULT_KEYS = Object.freeze(["retry_after_ms", "schema_version", "status"]);
1292
1578
 
1293
1579
  // packages/ceal-client-protocol/src/personal-client-session.ts
@@ -1299,7 +1585,6 @@ var MAX_ARGUMENT_BYTES = 16 * 1024;
1299
1585
  var HANDSHAKE_IDENTITY_KEYS = Object.freeze(["membership_ref", "registration_ref", "client_ref", "subject_ref", "instance_ref"]);
1300
1586
  var AUDIT_IDENTITY_KEYS = Object.freeze(["event_ref", "membership_ref", "registration_ref", "client_ref", "subject_ref", "instance_ref"]);
1301
1587
  var FAILURE_RESPONSE_KEYS = Object.freeze(["error", "ok", "proof_ref_or_unavailable", "protocol_version", "request_id"]);
1302
- var MAX_RECOVERY_RETRY_AFTER_MS = 60 * 60 * 1e3;
1303
1588
 
1304
1589
  // host/invocation-authentication-client-command.ts
1305
1590
  var MAX_DETAIL_CHARACTERS = 240;
@@ -1327,10 +1612,56 @@ function errorCode(error) {
1327
1612
  return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
1328
1613
  }
1329
1614
 
1330
- // host/relay/src/host-relay-runtime.ts
1331
- import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
1332
- import { lstat as lstat4, open as open4 } from "node:fs/promises";
1333
- import { dirname as dirname3, join as join6 } from "node:path";
1615
+ // host/service-log.ts
1616
+ import { copyFile, open, stat, truncate } from "node:fs/promises";
1617
+ import { isAbsolute } from "node:path";
1618
+ var HOST_SERVICE_LOG_ENVIRONMENT = "CEAL_HOST_SERVICE_LOG";
1619
+ var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
1620
+ var HOST_SERVICE_LOG_CHECK_INTERVAL_MS = 6e4;
1621
+ function hostServiceLogPreviousPath(path) {
1622
+ return `${path}.1`;
1623
+ }
1624
+ async function rotateHostServiceLog(path, maxBytes = HOST_SERVICE_LOG_MAX_BYTES) {
1625
+ let size;
1626
+ try {
1627
+ size = (await stat(path)).size;
1628
+ } catch (error) {
1629
+ if (isNotFound(error)) return false;
1630
+ throw error;
1631
+ }
1632
+ if (size <= maxBytes) return false;
1633
+ await copyFile(path, hostServiceLogPreviousPath(path));
1634
+ await truncate(path, 0);
1635
+ return true;
1636
+ }
1637
+ function boundHostServiceLog(environment = process.env) {
1638
+ const path = environment[HOST_SERVICE_LOG_ENVIRONMENT];
1639
+ if (path === void 0 || !isAbsolute(path)) return () => void 0;
1640
+ let reported = false;
1641
+ const check = () => {
1642
+ rotateHostServiceLog(path).catch((error) => {
1643
+ if (reported) return;
1644
+ reported = true;
1645
+ process.stderr.write(`[host-service-log] rotation_failed code=${errorCode2(error)}
1646
+ `);
1647
+ });
1648
+ };
1649
+ check();
1650
+ const timer = setInterval(check, HOST_SERVICE_LOG_CHECK_INTERVAL_MS);
1651
+ timer.unref();
1652
+ return () => clearInterval(timer);
1653
+ }
1654
+ var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
1655
+ function isNotFound(error) {
1656
+ return errorCode2(error) === "ENOENT";
1657
+ }
1658
+ function errorCode2(error) {
1659
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "unknown";
1660
+ }
1661
+
1662
+ // host/runtime-source-paths.ts
1663
+ import { createHash as createHash2 } from "node:crypto";
1664
+ import { posix as posix2, win32 as win322 } from "node:path";
1334
1665
 
1335
1666
  // host/absolute-path.ts
1336
1667
  import { posix, win32 } from "node:path";
@@ -1339,6 +1670,37 @@ function isAbsoluteNormalizedNonRootPath(value, flavor = process.platform, allow
1339
1670
  return typeof value === "string" && value.length <= 4096 && !value.includes("\0") && pathApi.isAbsolute(value) && pathApi.normalize(value) === value && (allowRoot || pathApi.parse(value).root !== value);
1340
1671
  }
1341
1672
 
1673
+ // host/runtime-source-paths.ts
1674
+ var HOST_SOURCE_ID = /^host-source:([0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12})$/u;
1675
+ function hostSourceUuid(sourceRef) {
1676
+ return HOST_SOURCE_ID.exec(sourceRef)?.[1] ?? null;
1677
+ }
1678
+ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platform) {
1679
+ const sourceId = hostSourceUuid(sourceRef);
1680
+ if (!isAbsoluteNormalizedNonRootPath(stateRoot, platform) || sourceId === null) throw new TypeError("Host runtime source identity is invalid.");
1681
+ const path = platform === "win32" ? win322 : posix2;
1682
+ const sourcesRoot = path.join(stateRoot, "sources");
1683
+ const sourceRoot = path.join(sourcesRoot, sourceId);
1684
+ const runtimeRoot = path.join(stateRoot, "run");
1685
+ const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash2("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
1686
+ assertHostRuntimeIpcLength(endpoint, platform);
1687
+ return { sourceId, sourcesRoot, sourceRoot, relayRoot: path.join(sourceRoot, "relay"), codexOutbox: path.join(sourceRoot, "producers", "codex", "outbox"), claudeOutbox: path.join(sourceRoot, "producers", "claude", "outbox"), endpoint, runtimeRoot };
1688
+ }
1689
+ function assertHostRuntimeIpcLength(endpoint, platform) {
1690
+ if (platform === "win32") return;
1691
+ const maximum = platform === "linux" ? 107 : 103;
1692
+ if (Buffer.byteLength(endpoint, "utf8") > maximum) throw Object.assign(new TypeError(`ipc_endpoint_too_long: Host IPC path exceeds ${maximum} bytes; use a shorter Host state root.`), { code: "ipc_endpoint_too_long" });
1693
+ }
1694
+ function assertHostRelaySourcePaths(stateRoot, config, platform = process.platform) {
1695
+ const paths = hostRuntimeSourcePaths(stateRoot, config.host_source_ref, platform);
1696
+ if (config.state_root !== paths.relayRoot || config.ipc_endpoint !== paths.endpoint) throw new TypeError("Host Relay state and IPC must belong to its configured source.");
1697
+ }
1698
+
1699
+ // host/relay/src/host-relay-runtime.ts
1700
+ import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
1701
+ import { lstat as lstat4, open as open5 } from "node:fs/promises";
1702
+ import { dirname as dirname3, join as join6 } from "node:path";
1703
+
1342
1704
  // host/abortable-wait.ts
1343
1705
  function waitForAbort(signal, milliseconds) {
1344
1706
  if (signal.aborted) return Promise.resolve();
@@ -1423,7 +1785,7 @@ function skipWhitespace(text, start) {
1423
1785
  }
1424
1786
 
1425
1787
  // host/relay/src/producer-frame.ts
1426
- import { createHash as createHash2 } from "node:crypto";
1788
+ import { createHash as createHash3 } from "node:crypto";
1427
1789
  var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1428
1790
  var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1429
1791
  var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
@@ -1469,7 +1831,7 @@ function decodeHostProducerFrame(input) {
1469
1831
  return value;
1470
1832
  }
1471
1833
  function hostProducerFrameHash(frame) {
1472
- return createHash2("sha256").update(JSON.stringify(frame), "utf8").digest("hex");
1834
+ return createHash3("sha256").update(JSON.stringify(frame), "utf8").digest("hex");
1473
1835
  }
1474
1836
  function hostProducerIdentityRefs(hostSourceRef, frame, localSessionRef, localTurnRef, localInputRef) {
1475
1837
  if (!opaqueHostSourceRef(hostSourceRef)) throw new TypeError("Gateway host source reference is invalid.");
@@ -1590,20 +1952,20 @@ function exactOptional(value, required, optional) {
1590
1952
 
1591
1953
  // host/relay/src/relay-admission-store.ts
1592
1954
  import { readFile as readFile2 } from "node:fs/promises";
1593
- import { join as join3 } from "node:path";
1955
+ import { join as join4 } from "node:path";
1594
1956
 
1595
1957
  // host/relay/src/durable-atomic-replacement.ts
1596
1958
  import { O_RDONLY } from "node:constants";
1597
- import { lstat, mkdir, open, rename, unlink } from "node:fs/promises";
1959
+ import { lstat, mkdir, open as open2, rename, unlink } from "node:fs/promises";
1598
1960
  import { dirname } from "node:path";
1599
1961
  var DEFAULT_PORT = {
1600
1962
  platform: process.platform,
1601
1963
  mkdir: (path, options) => mkdir(path, options),
1602
1964
  lstat: (path) => lstat(path),
1603
- open_file: (path) => open(path, "wx", 384),
1965
+ open_file: (path) => open2(path, "wx", 384),
1604
1966
  rename,
1605
1967
  unlink,
1606
- open_directory: (path) => open(path, O_RDONLY),
1968
+ open_directory: (path) => open2(path, O_RDONLY),
1607
1969
  unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
1608
1970
  };
1609
1971
  async function durableAtomicReplace(target, data, port = DEFAULT_PORT) {
@@ -1663,7 +2025,7 @@ async function removeTemporary(path, port, failures) {
1663
2025
  try {
1664
2026
  await port.unlink(path);
1665
2027
  } catch (error) {
1666
- if (errorCode2(error) !== "ENOENT") failures.push(error);
2028
+ if (errorCode3(error) !== "ENOENT") failures.push(error);
1667
2029
  }
1668
2030
  }
1669
2031
  function throwFailures(failures) {
@@ -1671,16 +2033,255 @@ function throwFailures(failures) {
1671
2033
  if (failures.length > 1) throw new AggregateError(failures, "Host Relay durable replacement and cleanup failed.");
1672
2034
  }
1673
2035
  function directorySyncUnsupported(error) {
1674
- return ["EINVAL", "ENOSYS", "ENOTSUP"].includes(errorCode2(error) ?? "");
2036
+ return ["EINVAL", "ENOSYS", "ENOTSUP"].includes(errorCode3(error) ?? "");
1675
2037
  }
1676
- function errorCode2(error) {
2038
+ function errorCode3(error) {
1677
2039
  return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
1678
2040
  }
1679
2041
 
2042
+ // host/relay/src/relay-request-binding-store.ts
2043
+ import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
2044
+ import { open as open3 } from "node:fs/promises";
2045
+ import { join as join2 } from "node:path";
2046
+ var HOST_RELAY_REQUEST_BINDING_SCHEMA = "ceal.host_relay_request_binding.v1";
2047
+ var STATE_SCHEMA = "ceal.host_relay_request_binding_state.v1";
2048
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2049
+ var MAX_BINDINGS = 8192;
2050
+ var MAX_STATE_BYTES = 8 * 1024 * 1024;
2051
+ var HostRelayBindingError = class extends TypeError {
2052
+ name = "HostRelayBindingError";
2053
+ code;
2054
+ constructor(code, message) {
2055
+ super(message);
2056
+ this.code = code;
2057
+ }
2058
+ };
2059
+ var RelayRequestBindingStore = class {
2060
+ tail = Promise.resolve();
2061
+ bindingWaiters = /* @__PURE__ */ new Set();
2062
+ root;
2063
+ constructor(root) {
2064
+ if (typeof root !== "string" || root.length === 0) throw new TypeError("Host Relay binding root is invalid.");
2065
+ this.root = root;
2066
+ }
2067
+ bind(input, now = /* @__PURE__ */ new Date()) {
2068
+ const run = this.tail.then(() => this.bindLocked(input, now));
2069
+ this.tail = run.then(() => void 0, () => void 0);
2070
+ return run;
2071
+ }
2072
+ query(input) {
2073
+ const run = this.tail.then(() => this.queryLocked(input));
2074
+ this.tail = run.then(() => void 0, () => void 0);
2075
+ return run;
2076
+ }
2077
+ waitForBinding(input, signal) {
2078
+ validateQuery(input);
2079
+ if (signal.aborted) return Promise.reject(new Error("Host Relay binding wait cancelled."));
2080
+ return new Promise((resolve, reject) => {
2081
+ let settled = false;
2082
+ const finish = (result2, error) => {
2083
+ if (settled) return;
2084
+ settled = true;
2085
+ this.bindingWaiters.delete(waiter);
2086
+ signal.removeEventListener("abort", waiter.abort);
2087
+ if (error !== void 0) reject(error);
2088
+ else if (result2?.status === "ready") resolve(result2);
2089
+ };
2090
+ const abort = () => finish(void 0, new Error("Host Relay binding wait cancelled."));
2091
+ const waiter = { query: input, resolve: (result2) => finish(result2), abort };
2092
+ this.bindingWaiters.add(waiter);
2093
+ signal.addEventListener("abort", abort, { once: true });
2094
+ void this.query(input).then((result2) => {
2095
+ if (result2.status === "ready") finish(result2);
2096
+ }, (error) => finish(void 0, error));
2097
+ });
2098
+ }
2099
+ async bindLocked(input, now) {
2100
+ const candidate = bindingFromGateway(input, now);
2101
+ const state = await this.read();
2102
+ const existing = state.bindings.find((item) => sameCanonicalIdentity(item, candidate));
2103
+ if (existing !== void 0) {
2104
+ if (!sameBinding(existing, candidate)) throw new HostRelayBindingError("canonical_turn_rebound", `Host Relay canonical turn is already bound to another Request: ${refusalFacts([{ name: "candidate_request_ref", value: candidate.request_ref, expected: existing.request_ref }, { name: "candidate_prompt_ref", value: candidate.prompt_ref, expected: existing.prompt_ref }, { name: "candidate_context_expires_at", value: candidate.context_expires_at, expected: String(existing.context_expires_at) }, { name: "candidate_local_turn_aliases", value: candidate.local_turn_aliases, expected: JSON.stringify(existing.local_turn_aliases) }])}.`);
2105
+ return existing;
2106
+ }
2107
+ if (state.bindings.length >= MAX_BINDINGS) throw new HostRelayBindingError("binding_capacity_exhausted", `Host Relay request binding capacity is exhausted: ${refusalFact("binding_count", state.bindings.length, `below ${MAX_BINDINGS}`)}.`);
2108
+ const next = { schema_version: STATE_SCHEMA, bindings: [...state.bindings, candidate] };
2109
+ await this.write(next);
2110
+ this.resolveBindingWaiters(candidate);
2111
+ return structuredClone(candidate);
2112
+ }
2113
+ resolveBindingWaiters(binding) {
2114
+ for (const waiter of this.bindingWaiters) {
2115
+ if (relayRequestBindingMatchesQuery(waiter.query, binding)) waiter.resolve({ status: "ready", binding: structuredClone(binding) });
2116
+ }
2117
+ }
2118
+ async queryLocked(input) {
2119
+ validateQuery(input);
2120
+ const state = await this.read();
2121
+ const matches = state.bindings.filter((binding2) => relayRequestBindingMatchesQuery(input, binding2));
2122
+ if (matches.length === 0) return { status: "no_binding" };
2123
+ const binding = matches[0];
2124
+ if (binding === void 0) throw new TypeError("Host Relay binding query result is invalid.");
2125
+ return { status: "ready", binding: structuredClone(binding) };
2126
+ }
2127
+ async read() {
2128
+ let handle;
2129
+ try {
2130
+ handle = await open3(join2(this.root, "request-bindings.json"), O_RDONLY2 | O_NOFOLLOW);
2131
+ const stats = await handle.stat();
2132
+ if (!stats.isFile() || !ownerPrivate2(stats)) throw new TypeError(`Host Relay binding state is unsafe: ${refusalFacts([{ name: "state_is_file", value: stats.isFile(), expected: "true" }, { name: "state_uid", value: stats.uid, expected: String(process.geteuid?.() ?? stats.uid) }, { name: "state_mode", value: (stats.mode & 511).toString(8), expected: "no group or other permission bits" }])}.`);
2133
+ if (stats.size > MAX_STATE_BYTES) throw new TypeError(`Host Relay binding state is unsafe: ${refusalFact("state_bytes", stats.size, `at most ${MAX_STATE_BYTES}`)}.`);
2134
+ return decodeState(JSON.parse(await handle.readFile("utf8")));
2135
+ } catch (error) {
2136
+ if (errorCode4(error) === "ENOENT") return { schema_version: STATE_SCHEMA, bindings: [] };
2137
+ throw error;
2138
+ } finally {
2139
+ await handle?.close();
2140
+ }
2141
+ }
2142
+ async write(state) {
2143
+ const encoded = JSON.stringify(state);
2144
+ if (Buffer.byteLength(encoded, "utf8") > MAX_STATE_BYTES) throw new TypeError(`Host Relay binding state is too large: ${refusalFact("state_bytes", Buffer.byteLength(encoded, "utf8"), `at most ${MAX_STATE_BYTES}`)}.`);
2145
+ await durableAtomicReplace(join2(this.root, "request-bindings.json"), encoded);
2146
+ }
2147
+ };
2148
+ function relayRequestWorkContextFromBinding(binding) {
2149
+ return createRelayRequestWorkContext({ request_ref: binding.request_ref, host_binding: {
2150
+ host_source_ref: binding.host_source_ref,
2151
+ host_session_ref: binding.host_session_ref,
2152
+ host_turn_ref: binding.host_turn_ref,
2153
+ host_input_ref: binding.host_input_ref,
2154
+ prompt_ref: binding.prompt_ref
2155
+ } });
2156
+ }
2157
+ function createRelayRequestWorkContext(input) {
2158
+ if (!record2(input) || !exactKeys3(input, ["request_ref", "host_binding"]) || !safeRef2(input.request_ref) || !record2(input.host_binding)) {
2159
+ throw new HostRelayBindingError("context_identity_missing", "Host Relay work context does not contain the complete acknowledged Host tuple.");
2160
+ }
2161
+ const hostBinding = input.host_binding;
2162
+ if (!exactKeys3(hostBinding, ["host_source_ref", "host_session_ref", "host_turn_ref", "host_input_ref", "prompt_ref"]) || ![hostBinding.host_source_ref, hostBinding.host_session_ref, hostBinding.host_turn_ref, hostBinding.host_input_ref, hostBinding.prompt_ref].every(safeRef2)) {
2163
+ throw new HostRelayBindingError("context_identity_missing", "Host Relay work context does not contain the complete acknowledged Host tuple.");
2164
+ }
2165
+ const hostSourceRef = requiredRef(hostBinding.host_source_ref);
2166
+ const hostSessionRef = requiredRef(hostBinding.host_session_ref);
2167
+ const hostTurnRef = requiredRef(hostBinding.host_turn_ref);
2168
+ const hostInputRef = requiredRef(hostBinding.host_input_ref);
2169
+ const promptRef = requiredRef(hostBinding.prompt_ref);
2170
+ return Object.freeze({ request_ref: input.request_ref, host_binding: Object.freeze({
2171
+ host_source_ref: hostSourceRef,
2172
+ host_session_ref: hostSessionRef,
2173
+ host_turn_ref: hostTurnRef,
2174
+ host_input_ref: hostInputRef,
2175
+ prompt_ref: promptRef
2176
+ }) });
2177
+ }
2178
+ function bindingFromGateway(input, now) {
2179
+ const payload = input.frame.payload;
2180
+ const candidate = {
2181
+ schema_version: HOST_RELAY_REQUEST_BINDING_SCHEMA,
2182
+ producer_id: input.frame.producer_id,
2183
+ producer_installation_ref: input.frame.producer_installation_ref,
2184
+ local_session_ref: requiredRef(payload.local_session_ref),
2185
+ local_turn_ref: requiredRef(payload.local_turn_ref),
2186
+ local_turn_aliases: optionalRefs2(payload.local_turn_aliases),
2187
+ prompt_ref: requiredRef(input.prompt_ref),
2188
+ request_ref: requiredRef(input.request_ref),
2189
+ bound_at: timestamp2(now.toISOString()),
2190
+ ...payload.context_expires_at === void 0 ? {} : { context_expires_at: timestamp2(payload.context_expires_at) },
2191
+ host_source_ref: requiredRef(input.host_binding.host_source_ref),
2192
+ host_session_ref: requiredRef(input.host_binding.host_session_ref),
2193
+ host_turn_ref: requiredRef(input.host_binding.host_turn_ref),
2194
+ host_input_ref: requiredRef(input.host_binding.host_input_ref)
2195
+ };
2196
+ if (input.host_binding.prompt_ref !== input.prompt_ref) throw new HostRelayBindingError("context_identity_mismatch", "Host Relay binding prompt reference does not match the acknowledged submission.");
2197
+ validateBinding(candidate);
2198
+ return candidate;
2199
+ }
2200
+ function decodeState(value) {
2201
+ if (!record2(value) || !exactKeys3(value, ["schema_version", "bindings"])) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("state_keys", record2(value) ? Object.keys(value) : [], "exactly schema_version and bindings")}.`);
2202
+ if (value.schema_version !== STATE_SCHEMA) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("schema_version", value.schema_version, STATE_SCHEMA)}.`);
2203
+ if (!Array.isArray(value.bindings)) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("bindings", value.bindings, "an array")}.`);
2204
+ const bindings = value.bindings.map((item) => {
2205
+ validateBinding(item);
2206
+ return item;
2207
+ });
2208
+ const keys = bindings.map(bindingKey);
2209
+ if (new Set(keys).size !== keys.length) throw new TypeError("Host Relay binding state contains duplicate canonical turns.");
2210
+ return { schema_version: STATE_SCHEMA, bindings };
2211
+ }
2212
+ function validateBinding(value) {
2213
+ if (!record2(value) || !exactOptionalKeys(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "local_turn_aliases", "prompt_ref", "request_ref", "bound_at", "host_source_ref", "host_session_ref", "host_turn_ref", "host_input_ref"], ["context_expires_at"]) || !validBindingIdentity(value) || !validBindingRequest(value)) throw new TypeError("Host Relay request binding is invalid.");
2214
+ }
2215
+ function validBindingIdentity(value) {
2216
+ return value.schema_version === HOST_RELAY_REQUEST_BINDING_SCHEMA && producer(value.producer_id) && [value.producer_installation_ref, value.local_session_ref, value.local_turn_ref].every(safeRef2) && refList(value.local_turn_aliases);
2217
+ }
2218
+ function validBindingRequest(value) {
2219
+ const tuple = [value.host_source_ref, value.host_session_ref, value.host_turn_ref, value.host_input_ref];
2220
+ return safeRef2(value.prompt_ref) && safeRef2(value.request_ref) && validTimestamp(value.bound_at) && (value.context_expires_at === void 0 || validTimestamp(value.context_expires_at)) && tuple.every(safeRef2);
2221
+ }
2222
+ function validateQuery(value) {
2223
+ if (!record2(value) || !exactKeys3(value, ["producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref"]) || !producer(value.producer_id) || !safeRef2(value.producer_installation_ref) || !safeRef2(value.local_session_ref) || !safeRef2(value.local_turn_ref)) throw new TypeError("Host Relay binding query is invalid.");
2224
+ }
2225
+ function relayRequestBindingMatchesQuery(query, binding) {
2226
+ return query.producer_id === binding.producer_id && query.local_session_ref === binding.local_session_ref && (query.local_turn_ref === binding.local_turn_ref || binding.local_turn_aliases.includes(query.local_turn_ref)) && query.producer_installation_ref === binding.producer_installation_ref;
2227
+ }
2228
+ function sameCanonicalIdentity(left, right) {
2229
+ return bindingKey(left) === bindingKey(right);
2230
+ }
2231
+ function sameBinding(left, right) {
2232
+ return left.request_ref === right.request_ref && left.prompt_ref === right.prompt_ref && left.context_expires_at === right.context_expires_at && left.host_source_ref === right.host_source_ref && left.host_session_ref === right.host_session_ref && left.host_turn_ref === right.host_turn_ref && left.host_input_ref === right.host_input_ref && JSON.stringify(left.local_turn_aliases) === JSON.stringify(right.local_turn_aliases);
2233
+ }
2234
+ function bindingKey(value) {
2235
+ return `${value.producer_id}\0${value.producer_installation_ref}\0${value.local_session_ref}\0${value.local_turn_ref}`;
2236
+ }
2237
+ function requiredRef(value) {
2238
+ if (!safeRef2(value)) throw new TypeError("Host Relay binding reference is invalid.");
2239
+ return value;
2240
+ }
2241
+ function optionalRefs2(value) {
2242
+ if (value === void 0) return [];
2243
+ if (!refList(value)) throw new TypeError("Host Relay binding aliases are invalid.");
2244
+ return [...value];
2245
+ }
2246
+ function timestamp2(value) {
2247
+ if (!validTimestamp(value)) throw new TypeError("Host Relay binding timestamp is invalid.");
2248
+ return value;
2249
+ }
2250
+ function producer(value) {
2251
+ return value === "codex" || value === "claude";
2252
+ }
2253
+ function safeRef2(value) {
2254
+ return typeof value === "string" && SAFE_REF3.test(value);
2255
+ }
2256
+ function refList(value) {
2257
+ return Array.isArray(value) && value.length <= 16 && value.every(safeRef2) && new Set(value).size === value.length;
2258
+ }
2259
+ function validTimestamp(value) {
2260
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
2261
+ }
2262
+ function record2(value) {
2263
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2264
+ }
2265
+ function exactKeys3(value, keys) {
2266
+ return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2267
+ }
2268
+ function exactOptionalKeys(value, required, optional) {
2269
+ const keys = Object.keys(value);
2270
+ return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2271
+ }
2272
+ function errorCode4(error) {
2273
+ return record2(error) && typeof error.code === "string" ? error.code : null;
2274
+ }
2275
+ function ownerPrivate2(stats) {
2276
+ if (process.platform === "win32") return true;
2277
+ const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2278
+ return stats.uid === uid && (stats.mode & 63) === 0;
2279
+ }
2280
+
1680
2281
  // host/relay/src/relay-quarantine-store.ts
1681
- import { createHash as createHash3 } from "node:crypto";
2282
+ import { createHash as createHash4 } from "node:crypto";
1682
2283
  import { readFile } from "node:fs/promises";
1683
- import { join as join2 } from "node:path";
2284
+ import { join as join3 } from "node:path";
1684
2285
  var RELAY_QUARANTINE_SCHEMA = "ceal.host_relay_quarantine_state.v1";
1685
2286
  var RELAY_QUARANTINE_MAX_RECORDS = 512;
1686
2287
  var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
@@ -1721,27 +2322,27 @@ var RelayQuarantineStore = class {
1721
2322
  const raw = Buffer.from(rawFrame).subarray(0, MAX_CAPTURE_BYTES);
1722
2323
  const state = await this.readState();
1723
2324
  const record6 = {
1724
- quarantine_ref: `quarantine:${createHash3("sha256").update(`${producerId}\0${reason}\0${capturedAt}\0`).update(raw).digest("hex")}`,
2325
+ quarantine_ref: `quarantine:${createHash4("sha256").update(`${producerId}\0${reason}\0${capturedAt}\0`).update(raw).digest("hex")}`,
1725
2326
  producer_id: producerId,
1726
2327
  reason,
1727
2328
  captured_at: capturedAt,
1728
- frame_sha256: createHash3("sha256").update(raw).digest("hex"),
2329
+ frame_sha256: createHash4("sha256").update(raw).digest("hex"),
1729
2330
  charged_bytes: raw.byteLength,
1730
2331
  raw_frame_base64: raw.toString("base64")
1731
2332
  };
1732
2333
  const records = state.producers[producerId];
1733
2334
  records.push(record6);
1734
2335
  while (records.length > this.maxRecords || totalBytes(records) > this.maxBytes) records.shift();
1735
- await durableAtomicReplace(join2(this.root, "quarantine.json"), JSON.stringify(state));
2336
+ await durableAtomicReplace(join3(this.root, "quarantine.json"), JSON.stringify(state));
1736
2337
  });
1737
2338
  this.tail = run.then(() => void 0, () => void 0);
1738
2339
  await run;
1739
2340
  }
1740
2341
  async readState() {
1741
2342
  try {
1742
- return decodeState(JSON.parse(await readFile(join2(this.root, "quarantine.json"), "utf8")));
2343
+ return decodeState2(JSON.parse(await readFile(join3(this.root, "quarantine.json"), "utf8")));
1743
2344
  } catch (error) {
1744
- if (errorCode3(error) === "ENOENT") return emptyState();
2345
+ if (errorCode5(error) === "ENOENT") return emptyState();
1745
2346
  throw error;
1746
2347
  }
1747
2348
  }
@@ -1752,9 +2353,9 @@ function emptyState() {
1752
2353
  function totalBytes(records) {
1753
2354
  return records.reduce((total, record6) => total + record6.charged_bytes, 0);
1754
2355
  }
1755
- function decodeState(value) {
1756
- if (!record2(value) || value.schema_version !== RELAY_QUARANTINE_SCHEMA) throw new TypeError(`Host Relay quarantine state is invalid: ${refusalFact("schema_version", record2(value) ? value.schema_version : void 0, RELAY_QUARANTINE_SCHEMA)}.`);
1757
- if (!record2(value.producers)) throw new TypeError(`Host Relay quarantine state is invalid: ${refusalFact("producer_ids", record2(value.producers) ? Object.keys(value.producers) : [], `the ${PRODUCERS2.length} quarantine producer buckets`)}.`);
2356
+ function decodeState2(value) {
2357
+ if (!record3(value) || value.schema_version !== RELAY_QUARANTINE_SCHEMA) throw new TypeError(`Host Relay quarantine state is invalid: ${refusalFact("schema_version", record3(value) ? value.schema_version : void 0, RELAY_QUARANTINE_SCHEMA)}.`);
2358
+ if (!record3(value.producers)) throw new TypeError(`Host Relay quarantine state is invalid: ${refusalFact("producer_ids", record3(value.producers) ? Object.keys(value.producers) : [], `the ${PRODUCERS2.length} quarantine producer buckets`)}.`);
1758
2359
  const state = emptyState();
1759
2360
  for (const producerId of PRODUCERS2) {
1760
2361
  const records = value.producers[producerId];
@@ -1764,7 +2365,7 @@ function decodeState(value) {
1764
2365
  return state;
1765
2366
  }
1766
2367
  function validRecord(value) {
1767
- if (!record2(value) || typeof value.quarantine_ref !== "string" || !quarantineProducer(value.producer_id) || typeof value.reason !== "string" || !Number.isFinite(Date.parse(String(value.captured_at))) || typeof value.frame_sha256 !== "string" || typeof value.charged_bytes !== "number" || !Number.isSafeInteger(value.charged_bytes) || value.charged_bytes < 0 || typeof value.raw_frame_base64 !== "string") return false;
2368
+ if (!record3(value) || typeof value.quarantine_ref !== "string" || !quarantineProducer(value.producer_id) || typeof value.reason !== "string" || !Number.isFinite(Date.parse(String(value.captured_at))) || typeof value.frame_sha256 !== "string" || typeof value.charged_bytes !== "number" || !Number.isSafeInteger(value.charged_bytes) || value.charged_bytes < 0 || typeof value.raw_frame_base64 !== "string") return false;
1768
2369
  return true;
1769
2370
  }
1770
2371
  function quarantineProducer(value) {
@@ -1773,16 +2374,16 @@ function quarantineProducer(value) {
1773
2374
  function inferProducer(rawFrame) {
1774
2375
  try {
1775
2376
  const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(Buffer.from(rawFrame).subarray(4)));
1776
- return record2(value) && (value.producer_id === "codex" || value.producer_id === "claude") ? value.producer_id : "unknown";
2377
+ return record3(value) && (value.producer_id === "codex" || value.producer_id === "claude") ? value.producer_id : "unknown";
1777
2378
  } catch {
1778
2379
  return "unknown";
1779
2380
  }
1780
2381
  }
1781
- function record2(value) {
2382
+ function record3(value) {
1782
2383
  return value !== null && typeof value === "object" && !Array.isArray(value);
1783
2384
  }
1784
- function errorCode3(error) {
1785
- return record2(error) && typeof error.code === "string" ? error.code : null;
2385
+ function errorCode5(error) {
2386
+ return record3(error) && typeof error.code === "string" ? error.code : null;
1786
2387
  }
1787
2388
 
1788
2389
  // host/relay/src/relay-admission-store.ts
@@ -1792,11 +2393,12 @@ var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
1792
2393
  var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
1793
2394
  var RelayAdmissionStore = class {
1794
2395
  tail = Promise.resolve();
2396
+ drainWaiters = /* @__PURE__ */ new Set();
1795
2397
  root;
1796
2398
  quarantine;
1797
2399
  limits;
1798
2400
  faultHooks;
1799
- constructor(root, limits = DEFAULT_LIMITS, faultHooks = {}, quarantine = new RelayQuarantineStore(join3(root, "quarantine"))) {
2401
+ constructor(root, limits = DEFAULT_LIMITS, faultHooks = {}, quarantine = new RelayQuarantineStore(join4(root, "quarantine"))) {
1800
2402
  this.root = root;
1801
2403
  this.quarantine = quarantine;
1802
2404
  this.limits = limits;
@@ -1811,10 +2413,36 @@ var RelayAdmissionStore = class {
1811
2413
  await this.tail;
1812
2414
  return this.read();
1813
2415
  }
2416
+ async hasPendingRequestBinding(query) {
2417
+ const state = await this.read();
2418
+ return state.entries.some((entry2) => pendingFrameMatchesBindingQuery(entry2, query));
2419
+ }
1814
2420
  async drainRound(deliver, options) {
1815
2421
  const run = this.tail.then(() => this.drainLocked(deliver, options));
1816
2422
  this.tail = run.then(() => void 0, () => void 0);
1817
- return run;
2423
+ const result2 = await run;
2424
+ if (result2.delivered.length > 0 || result2.refused.length > 0 || result2.retained.length > 0) this.resolveDrainWaiters();
2425
+ return result2;
2426
+ }
2427
+ waitForDrainChange(signal) {
2428
+ if (signal.aborted) return Promise.reject(new Error("Host Relay admission wait cancelled."));
2429
+ return new Promise((resolve, reject) => {
2430
+ let settled = false;
2431
+ const finish = (error) => {
2432
+ if (settled) return;
2433
+ settled = true;
2434
+ this.drainWaiters.delete(waiter);
2435
+ signal.removeEventListener("abort", waiter.abort);
2436
+ if (error !== void 0) reject(error);
2437
+ else resolve();
2438
+ };
2439
+ const waiter = { resolve: () => finish(), abort: () => finish(new Error("Host Relay admission wait cancelled.")) };
2440
+ this.drainWaiters.add(waiter);
2441
+ signal.addEventListener("abort", waiter.abort, { once: true });
2442
+ });
2443
+ }
2444
+ resolveDrainWaiters() {
2445
+ for (const waiter of this.drainWaiters) waiter.resolve();
1818
2446
  }
1819
2447
  async admitLocked(frame) {
1820
2448
  const state = await this.read();
@@ -1871,308 +2499,109 @@ var RelayAdmissionStore = class {
1871
2499
  if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
1872
2500
  if (outcome.status === "refused" || exhausted) {
1873
2501
  await this.quarantine.retainFrame(head.frame, "gateway_refused");
1874
- installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
1875
- refused.push(input.submission_ref);
1876
- } else {
1877
- await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
1878
- delivered.push(input.submission_ref);
1879
- }
1880
- state.entries.splice(state.entries.indexOf(head), 1);
1881
- installation2.delivered_through_sequence = Math.max(installation2.delivered_through_sequence, head.sequence);
1882
- await this.write(state);
1883
- }
1884
- return { delivered, retained, refused };
1885
- }
1886
- async read() {
1887
- try {
1888
- return decodeState2(JSON.parse(await readFile2(join3(this.root, "admission.json"), "utf8")));
1889
- } catch (error) {
1890
- if (errorCode4(error) === "ENOENT") return { schema_version: "ceal.host_relay_admission_state.v1", installations: {}, entries: [] };
1891
- throw error;
1892
- }
1893
- }
1894
- async write(state) {
1895
- await durableAtomicReplace(join3(this.root, "admission.json"), JSON.stringify(state));
1896
- }
1897
- };
1898
- function installationKey(frame) {
1899
- return `${frame.producer_id}\0${frame.producer_installation_ref}`;
1900
- }
1901
- function replayCode(existing, hash, sequence, installation2) {
1902
- if (existing !== void 0) return existing.hash === hash ? "already_admitted" : "frame_identity_conflict";
1903
- return sequence <= installation2.delivered_through_sequence ? "already_admitted" : null;
1904
- }
1905
- function bytes(entries) {
1906
- return entries.reduce((total, entry2) => total + entry2.charged_bytes, 0);
1907
- }
1908
- function retryExhausted(outcome, entry2) {
1909
- return outcome.status === "retryable" && entry2.retry_attempts >= MAX_RETRYABLE_ATTEMPTS;
1910
- }
1911
- function refusalCause(outcome, entry2) {
1912
- if (outcome.status === "refused") return { code: outcome.code, message: outcome.message };
1913
- const reason = outcome.status === "retryable" ? outcome.reason ?? "no reason reported" : "no reason reported";
1914
- return { code: "retry_exhausted", message: `Gateway delivery stayed retryable through ${entry2.retry_attempts} attempts: ${reason}` };
1915
- }
1916
- function scheduleRetry(entry2, nowMs, reason) {
1917
- if (reason === void 0) delete entry2.retry_reason;
1918
- else entry2.retry_reason = reason;
1919
- entry2.retry_attempts += 1;
1920
- entry2.retry_at_ms = nowMs + 1e3 * (RETRY_SECONDS[Math.min(entry2.retry_attempts - 1, RETRY_SECONDS.length - 1)] ?? 60);
1921
- }
1922
- function result(code, state) {
1923
- return { code, admitted_through_sequence: state.admitted_through_sequence, delivered_through_sequence: state.delivered_through_sequence };
1924
- }
1925
- function errorCode4(error) {
1926
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
1927
- }
1928
- function decodeState2(value) {
1929
- if (!stateRecord(value)) throw new TypeError("Host Relay admission state is invalid.");
1930
- const installations = {};
1931
- for (const [key, item] of Object.entries(value.installations)) {
1932
- if (!installation(item)) throw new TypeError("Host Relay installation state is invalid.");
1933
- installations[key] = item;
1934
- }
1935
- const entries = [];
1936
- for (const item of value.entries) {
1937
- if (!entry(item)) throw new TypeError("Host Relay entry state is invalid.");
1938
- entries.push(item);
1939
- }
1940
- return { schema_version: "ceal.host_relay_admission_state.v1", installations, entries };
1941
- }
1942
- function stateRecord(value) {
1943
- return object(value) && value.schema_version === "ceal.host_relay_admission_state.v1" && object(value.installations) && Array.isArray(value.entries);
1944
- }
1945
- function installation(value) {
1946
- return typeof value === "object" && value !== null && !Array.isArray(value) && "epoch" in value && "admitted_through_sequence" in value && "delivered_through_sequence" in value && [value.epoch, value.admitted_through_sequence, value.delivered_through_sequence].every(Number.isSafeInteger) && (!("last_refusal" in value) || refusalRecord(value.last_refusal));
1947
- }
1948
- function refusalRecord(value) {
1949
- return object(value) && Number.isSafeInteger(value.sequence) && typeof value.submission_ref === "string" && typeof value.code === "string" && typeof value.message === "string" && Number.isSafeInteger(value.refused_at_ms);
1950
- }
1951
- function entry(value) {
1952
- return object(value) && producer(value.producer_id) && typeof value.producer_installation_ref === "string" && Number.isSafeInteger(value.sequence) && typeof value.hash === "string" && Number.isSafeInteger(value.charged_bytes) && object(value.frame) && Number.isSafeInteger(value.retry_attempts) && Number.isSafeInteger(value.retry_at_ms);
1953
- }
1954
- function producer(value) {
1955
- return value === "codex" || value === "claude";
1956
- }
1957
- function object(value) {
1958
- return typeof value === "object" && value !== null && !Array.isArray(value);
1959
- }
1960
-
1961
- // host/relay/src/relay-gateway-bridge.ts
1962
- import { readFile as readFile3 } from "node:fs/promises";
1963
- import { join as join5 } from "node:path";
1964
-
1965
- // host/relay/src/relay-request-binding-store.ts
1966
- import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
1967
- import { open as open2 } from "node:fs/promises";
1968
- import { join as join4 } from "node:path";
1969
- var HOST_RELAY_REQUEST_BINDING_SCHEMA = "ceal.host_relay_request_binding.v1";
1970
- var STATE_SCHEMA = "ceal.host_relay_request_binding_state.v1";
1971
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1972
- var MAX_BINDINGS = 8192;
1973
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
1974
- var HostRelayBindingError = class extends TypeError {
1975
- name = "HostRelayBindingError";
1976
- code;
1977
- constructor(code, message) {
1978
- super(message);
1979
- this.code = code;
1980
- }
1981
- };
1982
- var RelayRequestBindingStore = class {
1983
- tail = Promise.resolve();
1984
- root;
1985
- constructor(root) {
1986
- if (typeof root !== "string" || root.length === 0) throw new TypeError("Host Relay binding root is invalid.");
1987
- this.root = root;
1988
- }
1989
- bind(input, now = /* @__PURE__ */ new Date()) {
1990
- const run = this.tail.then(() => this.bindLocked(input, now));
1991
- this.tail = run.then(() => void 0, () => void 0);
1992
- return run;
1993
- }
1994
- query(input) {
1995
- const run = this.tail.then(() => this.queryLocked(input));
1996
- this.tail = run.then(() => void 0, () => void 0);
1997
- return run;
1998
- }
1999
- async bindLocked(input, now) {
2000
- const candidate = bindingFromGateway(input, now);
2001
- const state = await this.read();
2002
- const existing = state.bindings.find((item) => sameCanonicalIdentity(item, candidate));
2003
- if (existing !== void 0) {
2004
- if (!sameBinding(existing, candidate)) throw new HostRelayBindingError("canonical_turn_rebound", `Host Relay canonical turn is already bound to another Request: ${refusalFacts([{ name: "candidate_request_ref", value: candidate.request_ref, expected: existing.request_ref }, { name: "candidate_prompt_ref", value: candidate.prompt_ref, expected: existing.prompt_ref }, { name: "candidate_context_expires_at", value: candidate.context_expires_at, expected: String(existing.context_expires_at) }, { name: "candidate_local_turn_aliases", value: candidate.local_turn_aliases, expected: JSON.stringify(existing.local_turn_aliases) }])}.`);
2005
- return existing;
2006
- }
2007
- if (state.bindings.length >= MAX_BINDINGS) throw new HostRelayBindingError("binding_capacity_exhausted", `Host Relay request binding capacity is exhausted: ${refusalFact("binding_count", state.bindings.length, `below ${MAX_BINDINGS}`)}.`);
2008
- const next = { schema_version: STATE_SCHEMA, bindings: [...state.bindings, candidate] };
2009
- await this.write(next);
2010
- return structuredClone(candidate);
2011
- }
2012
- async queryLocked(input) {
2013
- validateQuery(input);
2014
- const state = await this.read();
2015
- const matches = state.bindings.filter((binding2) => queryMatches(input, binding2));
2016
- if (matches.length === 0) return { status: "no_binding" };
2017
- const binding = matches[0];
2018
- if (binding === void 0) throw new TypeError("Host Relay binding query result is invalid.");
2019
- return { status: "ready", binding: structuredClone(binding) };
2502
+ installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
2503
+ refused.push(input.submission_ref);
2504
+ } else {
2505
+ await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
2506
+ delivered.push(input.submission_ref);
2507
+ }
2508
+ state.entries.splice(state.entries.indexOf(head), 1);
2509
+ installation2.delivered_through_sequence = Math.max(installation2.delivered_through_sequence, head.sequence);
2510
+ await this.write(state);
2511
+ }
2512
+ return { delivered, retained, refused };
2020
2513
  }
2021
2514
  async read() {
2022
- let handle;
2023
2515
  try {
2024
- handle = await open2(join4(this.root, "request-bindings.json"), O_RDONLY2 | O_NOFOLLOW);
2025
- const stats = await handle.stat();
2026
- if (!stats.isFile() || !ownerPrivate2(stats)) throw new TypeError(`Host Relay binding state is unsafe: ${refusalFacts([{ name: "state_is_file", value: stats.isFile(), expected: "true" }, { name: "state_uid", value: stats.uid, expected: String(process.geteuid?.() ?? stats.uid) }, { name: "state_mode", value: (stats.mode & 511).toString(8), expected: "no group or other permission bits" }])}.`);
2027
- if (stats.size > MAX_STATE_BYTES) throw new TypeError(`Host Relay binding state is unsafe: ${refusalFact("state_bytes", stats.size, `at most ${MAX_STATE_BYTES}`)}.`);
2028
- return decodeState3(JSON.parse(await handle.readFile("utf8")));
2516
+ return decodeState3(JSON.parse(await readFile2(join4(this.root, "admission.json"), "utf8")));
2029
2517
  } catch (error) {
2030
- if (errorCode5(error) === "ENOENT") return { schema_version: STATE_SCHEMA, bindings: [] };
2518
+ if (errorCode6(error) === "ENOENT") return { schema_version: "ceal.host_relay_admission_state.v1", installations: {}, entries: [] };
2031
2519
  throw error;
2032
- } finally {
2033
- await handle?.close();
2034
2520
  }
2035
2521
  }
2036
2522
  async write(state) {
2037
- const encoded = JSON.stringify(state);
2038
- if (Buffer.byteLength(encoded, "utf8") > MAX_STATE_BYTES) throw new TypeError(`Host Relay binding state is too large: ${refusalFact("state_bytes", Buffer.byteLength(encoded, "utf8"), `at most ${MAX_STATE_BYTES}`)}.`);
2039
- await durableAtomicReplace(join4(this.root, "request-bindings.json"), encoded);
2523
+ await durableAtomicReplace(join4(this.root, "admission.json"), JSON.stringify(state));
2040
2524
  }
2041
2525
  };
2042
- function relayRequestWorkContextFromBinding(binding) {
2043
- return createRelayRequestWorkContext({ request_ref: binding.request_ref, host_binding: {
2044
- host_source_ref: binding.host_source_ref,
2045
- host_session_ref: binding.host_session_ref,
2046
- host_turn_ref: binding.host_turn_ref,
2047
- host_input_ref: binding.host_input_ref,
2048
- prompt_ref: binding.prompt_ref
2049
- } });
2050
- }
2051
- function createRelayRequestWorkContext(input) {
2052
- if (!record3(input) || !exactKeys3(input, ["request_ref", "host_binding"]) || !safeRef2(input.request_ref) || !record3(input.host_binding)) {
2053
- throw new HostRelayBindingError("context_identity_missing", "Host Relay work context does not contain the complete acknowledged Host tuple.");
2054
- }
2055
- const hostBinding = input.host_binding;
2056
- if (!exactKeys3(hostBinding, ["host_source_ref", "host_session_ref", "host_turn_ref", "host_input_ref", "prompt_ref"]) || ![hostBinding.host_source_ref, hostBinding.host_session_ref, hostBinding.host_turn_ref, hostBinding.host_input_ref, hostBinding.prompt_ref].every(safeRef2)) {
2057
- throw new HostRelayBindingError("context_identity_missing", "Host Relay work context does not contain the complete acknowledged Host tuple.");
2058
- }
2059
- const hostSourceRef = requiredRef(hostBinding.host_source_ref);
2060
- const hostSessionRef = requiredRef(hostBinding.host_session_ref);
2061
- const hostTurnRef = requiredRef(hostBinding.host_turn_ref);
2062
- const hostInputRef = requiredRef(hostBinding.host_input_ref);
2063
- const promptRef = requiredRef(hostBinding.prompt_ref);
2064
- return Object.freeze({ request_ref: input.request_ref, host_binding: Object.freeze({
2065
- host_source_ref: hostSourceRef,
2066
- host_session_ref: hostSessionRef,
2067
- host_turn_ref: hostTurnRef,
2068
- host_input_ref: hostInputRef,
2069
- prompt_ref: promptRef
2070
- }) });
2071
- }
2072
- function bindingFromGateway(input, now) {
2073
- const payload = input.frame.payload;
2074
- const candidate = {
2075
- schema_version: HOST_RELAY_REQUEST_BINDING_SCHEMA,
2076
- producer_id: input.frame.producer_id,
2077
- producer_installation_ref: input.frame.producer_installation_ref,
2078
- local_session_ref: requiredRef(payload.local_session_ref),
2079
- local_turn_ref: requiredRef(payload.local_turn_ref),
2080
- local_turn_aliases: optionalRefs2(payload.local_turn_aliases),
2081
- prompt_ref: requiredRef(input.prompt_ref),
2082
- request_ref: requiredRef(input.request_ref),
2083
- bound_at: timestamp2(now.toISOString()),
2084
- ...payload.context_expires_at === void 0 ? {} : { context_expires_at: timestamp2(payload.context_expires_at) },
2085
- host_source_ref: requiredRef(input.host_binding.host_source_ref),
2086
- host_session_ref: requiredRef(input.host_binding.host_session_ref),
2087
- host_turn_ref: requiredRef(input.host_binding.host_turn_ref),
2088
- host_input_ref: requiredRef(input.host_binding.host_input_ref)
2089
- };
2090
- if (input.host_binding.prompt_ref !== input.prompt_ref) throw new HostRelayBindingError("context_identity_mismatch", "Host Relay binding prompt reference does not match the acknowledged submission.");
2091
- validateBinding(candidate);
2092
- return candidate;
2526
+ function installationKey(frame) {
2527
+ return `${frame.producer_id}\0${frame.producer_installation_ref}`;
2093
2528
  }
2094
- function decodeState3(value) {
2095
- if (!record3(value) || !exactKeys3(value, ["schema_version", "bindings"])) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("state_keys", record3(value) ? Object.keys(value) : [], "exactly schema_version and bindings")}.`);
2096
- if (value.schema_version !== STATE_SCHEMA) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("schema_version", value.schema_version, STATE_SCHEMA)}.`);
2097
- if (!Array.isArray(value.bindings)) throw new TypeError(`Host Relay binding state is invalid: ${refusalFact("bindings", value.bindings, "an array")}.`);
2098
- const bindings = value.bindings.map((item) => {
2099
- validateBinding(item);
2100
- return item;
2529
+ function pendingFrameMatchesBindingQuery(entry2, query) {
2530
+ if (entry2.frame.frame_kind !== "user_input") return false;
2531
+ const payload = entry2.frame.payload;
2532
+ if (typeof payload.local_session_ref !== "string" || typeof payload.local_turn_ref !== "string") return false;
2533
+ const aliases = Array.isArray(payload.local_turn_aliases) ? payload.local_turn_aliases.filter((value) => typeof value === "string") : [];
2534
+ return relayRequestBindingMatchesQuery(query, {
2535
+ producer_id: entry2.frame.producer_id,
2536
+ producer_installation_ref: entry2.frame.producer_installation_ref,
2537
+ local_session_ref: payload.local_session_ref,
2538
+ local_turn_ref: payload.local_turn_ref,
2539
+ local_turn_aliases: aliases
2101
2540
  });
2102
- const keys = bindings.map(bindingKey);
2103
- if (new Set(keys).size !== keys.length) throw new TypeError("Host Relay binding state contains duplicate canonical turns.");
2104
- return { schema_version: STATE_SCHEMA, bindings };
2105
2541
  }
2106
- function validateBinding(value) {
2107
- if (!record3(value) || !exactOptionalKeys(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "local_turn_aliases", "prompt_ref", "request_ref", "bound_at", "host_source_ref", "host_session_ref", "host_turn_ref", "host_input_ref"], ["context_expires_at"]) || !validBindingIdentity(value) || !validBindingRequest(value)) throw new TypeError("Host Relay request binding is invalid.");
2542
+ function replayCode(existing, hash, sequence, installation2) {
2543
+ if (existing !== void 0) return existing.hash === hash ? "already_admitted" : "frame_identity_conflict";
2544
+ return sequence <= installation2.delivered_through_sequence ? "already_admitted" : null;
2108
2545
  }
2109
- function validBindingIdentity(value) {
2110
- return value.schema_version === HOST_RELAY_REQUEST_BINDING_SCHEMA && producer2(value.producer_id) && [value.producer_installation_ref, value.local_session_ref, value.local_turn_ref].every(safeRef2) && refList(value.local_turn_aliases);
2546
+ function bytes(entries) {
2547
+ return entries.reduce((total, entry2) => total + entry2.charged_bytes, 0);
2111
2548
  }
2112
- function validBindingRequest(value) {
2113
- const tuple = [value.host_source_ref, value.host_session_ref, value.host_turn_ref, value.host_input_ref];
2114
- return safeRef2(value.prompt_ref) && safeRef2(value.request_ref) && validTimestamp(value.bound_at) && (value.context_expires_at === void 0 || validTimestamp(value.context_expires_at)) && tuple.every(safeRef2);
2549
+ function retryExhausted(outcome, entry2) {
2550
+ return outcome.status === "retryable" && entry2.retry_attempts >= MAX_RETRYABLE_ATTEMPTS;
2115
2551
  }
2116
- function validateQuery(value) {
2117
- if (!record3(value) || !exactKeys3(value, ["producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref"]) || !producer2(value.producer_id) || !safeRef2(value.producer_installation_ref) || !safeRef2(value.local_session_ref) || !safeRef2(value.local_turn_ref)) throw new TypeError("Host Relay binding query is invalid.");
2552
+ function refusalCause(outcome, entry2) {
2553
+ if (outcome.status === "refused") return { code: outcome.code, message: outcome.message };
2554
+ const reason = outcome.status === "retryable" ? outcome.reason ?? "no reason reported" : "no reason reported";
2555
+ return { code: "retry_exhausted", message: `Gateway delivery stayed retryable through ${entry2.retry_attempts} attempts: ${reason}` };
2118
2556
  }
2119
- function queryMatches(query, binding) {
2120
- return query.producer_id === binding.producer_id && query.local_session_ref === binding.local_session_ref && (query.local_turn_ref === binding.local_turn_ref || binding.local_turn_aliases.includes(query.local_turn_ref)) && query.producer_installation_ref === binding.producer_installation_ref;
2557
+ function scheduleRetry(entry2, nowMs, reason) {
2558
+ if (reason === void 0) delete entry2.retry_reason;
2559
+ else entry2.retry_reason = reason;
2560
+ entry2.retry_attempts += 1;
2561
+ entry2.retry_at_ms = nowMs + 1e3 * (RETRY_SECONDS[Math.min(entry2.retry_attempts - 1, RETRY_SECONDS.length - 1)] ?? 60);
2121
2562
  }
2122
- function sameCanonicalIdentity(left, right) {
2123
- return bindingKey(left) === bindingKey(right);
2563
+ function result(code, state) {
2564
+ return { code, admitted_through_sequence: state.admitted_through_sequence, delivered_through_sequence: state.delivered_through_sequence };
2124
2565
  }
2125
- function sameBinding(left, right) {
2126
- return left.request_ref === right.request_ref && left.prompt_ref === right.prompt_ref && left.context_expires_at === right.context_expires_at && left.host_source_ref === right.host_source_ref && left.host_session_ref === right.host_session_ref && left.host_turn_ref === right.host_turn_ref && left.host_input_ref === right.host_input_ref && JSON.stringify(left.local_turn_aliases) === JSON.stringify(right.local_turn_aliases);
2566
+ function errorCode6(error) {
2567
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
2127
2568
  }
2128
- function bindingKey(value) {
2129
- return `${value.producer_id}\0${value.producer_installation_ref}\0${value.local_session_ref}\0${value.local_turn_ref}`;
2569
+ function decodeState3(value) {
2570
+ if (!stateRecord(value)) throw new TypeError("Host Relay admission state is invalid.");
2571
+ const installations = {};
2572
+ for (const [key, item] of Object.entries(value.installations)) {
2573
+ if (!installation(item)) throw new TypeError("Host Relay installation state is invalid.");
2574
+ installations[key] = item;
2575
+ }
2576
+ const entries = [];
2577
+ for (const item of value.entries) {
2578
+ if (!entry(item)) throw new TypeError("Host Relay entry state is invalid.");
2579
+ entries.push(item);
2580
+ }
2581
+ return { schema_version: "ceal.host_relay_admission_state.v1", installations, entries };
2130
2582
  }
2131
- function requiredRef(value) {
2132
- if (!safeRef2(value)) throw new TypeError("Host Relay binding reference is invalid.");
2133
- return value;
2583
+ function stateRecord(value) {
2584
+ return object(value) && value.schema_version === "ceal.host_relay_admission_state.v1" && object(value.installations) && Array.isArray(value.entries);
2134
2585
  }
2135
- function optionalRefs2(value) {
2136
- if (value === void 0) return [];
2137
- if (!refList(value)) throw new TypeError("Host Relay binding aliases are invalid.");
2138
- return [...value];
2586
+ function installation(value) {
2587
+ return typeof value === "object" && value !== null && !Array.isArray(value) && "epoch" in value && "admitted_through_sequence" in value && "delivered_through_sequence" in value && [value.epoch, value.admitted_through_sequence, value.delivered_through_sequence].every(Number.isSafeInteger) && (!("last_refusal" in value) || refusalRecord(value.last_refusal));
2139
2588
  }
2140
- function timestamp2(value) {
2141
- if (!validTimestamp(value)) throw new TypeError("Host Relay binding timestamp is invalid.");
2142
- return value;
2589
+ function refusalRecord(value) {
2590
+ return object(value) && Number.isSafeInteger(value.sequence) && typeof value.submission_ref === "string" && typeof value.code === "string" && typeof value.message === "string" && Number.isSafeInteger(value.refused_at_ms);
2591
+ }
2592
+ function entry(value) {
2593
+ return object(value) && producer2(value.producer_id) && typeof value.producer_installation_ref === "string" && Number.isSafeInteger(value.sequence) && typeof value.hash === "string" && Number.isSafeInteger(value.charged_bytes) && object(value.frame) && Number.isSafeInteger(value.retry_attempts) && Number.isSafeInteger(value.retry_at_ms);
2143
2594
  }
2144
2595
  function producer2(value) {
2145
2596
  return value === "codex" || value === "claude";
2146
2597
  }
2147
- function safeRef2(value) {
2148
- return typeof value === "string" && SAFE_REF3.test(value);
2149
- }
2150
- function refList(value) {
2151
- return Array.isArray(value) && value.length <= 16 && value.every(safeRef2) && new Set(value).size === value.length;
2152
- }
2153
- function validTimestamp(value) {
2154
- return typeof value === "string" && Number.isFinite(Date.parse(value));
2155
- }
2156
- function record3(value) {
2157
- return value !== null && typeof value === "object" && !Array.isArray(value);
2158
- }
2159
- function exactKeys3(value, keys) {
2160
- return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2161
- }
2162
- function exactOptionalKeys(value, required, optional) {
2163
- const keys = Object.keys(value);
2164
- return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2165
- }
2166
- function errorCode5(error) {
2167
- return record3(error) && typeof error.code === "string" ? error.code : null;
2168
- }
2169
- function ownerPrivate2(stats) {
2170
- if (process.platform === "win32") return true;
2171
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2172
- return stats.uid === uid && (stats.mode & 63) === 0;
2598
+ function object(value) {
2599
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2173
2600
  }
2174
2601
 
2175
2602
  // host/relay/src/relay-gateway-bridge.ts
2603
+ import { readFile as readFile3 } from "node:fs/promises";
2604
+ import { join as join5 } from "node:path";
2176
2605
  var STATE_SCHEMA2 = "ceal.host_relay_gateway_state.v1";
2177
2606
  var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2178
2607
  var HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS = ["created", "adopted", "replayed", "approval_approved", "approval_denied", "approval_replayed"];
@@ -2292,7 +2721,7 @@ var RelayGatewayBridge = class {
2292
2721
  if (state.host_source_ref !== this.hostSourceRef) throw new TypeError(`Host Relay Gateway source binding changed: ${refusalFacts([{ name: "stored_host_source_ref", value: state.host_source_ref }, { name: "configured_host_source_ref", value: this.hostSourceRef }])}.`);
2293
2722
  return state;
2294
2723
  } catch (error) {
2295
- if (errorCode6(error) === "ENOENT") return { schema_version: STATE_SCHEMA2, host_source_ref: this.hostSourceRef, sessions: {}, turns: {} };
2724
+ if (errorCode7(error) === "ENOENT") return { schema_version: STATE_SCHEMA2, host_source_ref: this.hostSourceRef, sessions: {}, turns: {} };
2296
2725
  throw error;
2297
2726
  }
2298
2727
  }
@@ -2303,7 +2732,7 @@ var RelayGatewayBridge = class {
2303
2732
  var RETRYABLE_HTTP_STATUSES = /* @__PURE__ */ new Set([401, 403, 408, 429]);
2304
2733
  function submissionRefusal(error) {
2305
2734
  const status = isRecord(error) && typeof error.status === "number" ? error.status : void 0;
2306
- const code = errorCode6(error) ?? "gateway_unavailable";
2735
+ const code = errorCode7(error) ?? "gateway_unavailable";
2307
2736
  const definitive = code === "payload_rejected" || status !== void 0 && status >= 400 && status < 500 && !RETRYABLE_HTTP_STATUSES.has(status);
2308
2737
  return { code, message: errorMessage(error), definitive };
2309
2738
  }
@@ -2384,7 +2813,7 @@ function isRecord(value) {
2384
2813
  function validOptionalTimeout(value) {
2385
2814
  return value === void 0 || Number.isSafeInteger(value) && Number(value) >= 1 && Number(value) <= 6e4;
2386
2815
  }
2387
- function errorCode6(error) {
2816
+ function errorCode7(error) {
2388
2817
  return isRecord(error) && typeof error.code === "string" ? error.code : null;
2389
2818
  }
2390
2819
  function decodeState4(value) {
@@ -2428,7 +2857,7 @@ function isInputRefusal(value) {
2428
2857
 
2429
2858
  // host/relay/src/relay-gateway-http.ts
2430
2859
  import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
2431
- import { lstat as lstat2, open as open3 } from "node:fs/promises";
2860
+ import { lstat as lstat2, open as open4 } from "node:fs/promises";
2432
2861
  import { dirname as dirname2 } from "node:path";
2433
2862
 
2434
2863
  // host/gateway-http.ts
@@ -2478,6 +2907,7 @@ async function submitHostIngress(options) {
2478
2907
  }
2479
2908
 
2480
2909
  // host/relay/src/relay-gateway-http.ts
2910
+ var HOST_REGISTRATION_STATE_SCHEMA = "ceal.host_registration_state.v1";
2481
2911
  var HOST_REGISTRATION_STATE_KEYS = Object.freeze([
2482
2912
  "credential_generation",
2483
2913
  "gateway_request_origin",
@@ -2488,19 +2918,30 @@ var HOST_REGISTRATION_STATE_KEYS = Object.freeze([
2488
2918
  "schema_version",
2489
2919
  "status"
2490
2920
  ]);
2491
- var HOST_INGRESS_PATH = "/api/ceal/v2/host-ingress";
2492
2921
  var HOST_REGISTRATION_STATE_MAX_BYTES = 65536;
2493
2922
  var HostRelayGatewayError = class extends Error {
2494
2923
  name = "HostRelayGatewayError";
2495
2924
  code;
2496
2925
  /** HTTP status of a Gateway refusal, when one answered. */
2497
2926
  status;
2498
- constructor(code, message, status) {
2927
+ /** The Gateway's own refusal word, when it named one; a bounded token, never its message. */
2928
+ error_code;
2929
+ constructor(code, message, status, errorCode9) {
2499
2930
  super(message);
2500
2931
  this.code = code;
2501
2932
  if (status !== void 0) this.status = status;
2933
+ if (errorCode9 !== void 0) this.error_code = errorCode9;
2502
2934
  }
2503
2935
  };
2936
+ var GATEWAY_REFUSAL_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
2937
+ async function gatewayRefusalCode(response2) {
2938
+ try {
2939
+ const body = await response2.json();
2940
+ return isCealJsonRecord(body) && typeof body.error_code === "string" && GATEWAY_REFUSAL_CODE_PATTERN.test(body.error_code) ? body.error_code : void 0;
2941
+ } catch {
2942
+ return void 0;
2943
+ }
2944
+ }
2504
2945
  function refusalMessage(status, body) {
2505
2946
  const record6 = isCealJsonRecord(body) ? body : {};
2506
2947
  const code = typeof record6.error_code === "string" ? record6.error_code : "unknown";
@@ -2546,7 +2987,7 @@ function createHostRelayGatewayHttpPort(options) {
2546
2987
  } catch {
2547
2988
  throw new HostRelayGatewayError("gateway_unavailable", "Gateway Host invocation context is unavailable.");
2548
2989
  }
2549
- if (!response2.ok) throw new HostRelayGatewayError(response2.status === 401 ? "credential" : "gateway_refused", `Gateway Host invocation context was refused (${response2.status}).`, response2.status);
2990
+ if (!response2.ok) throw new HostRelayGatewayError(response2.status === 401 ? "credential" : "gateway_refused", `Gateway Host invocation context was refused (${response2.status}).`, response2.status, await gatewayRefusalCode(response2));
2550
2991
  let value;
2551
2992
  try {
2552
2993
  value = await response2.json();
@@ -2562,7 +3003,7 @@ function createHostRelayGatewayHttpPort(options) {
2562
3003
  });
2563
3004
  }
2564
3005
  function hostRelayGatewayEndpoint(value) {
2565
- return hostRelayGatewayRoute(value, HOST_INGRESS_PATH);
3006
+ return hostRelayGatewayRoute(value, CEAL_HOST_INGRESS_PATH);
2566
3007
  }
2567
3008
  function hostRelayGatewayRoute(value, path) {
2568
3009
  let parsed;
@@ -2602,7 +3043,7 @@ async function readHostRegistrationAuthority(path, expectedHostSourceRef) {
2602
3043
  let handle;
2603
3044
  try {
2604
3045
  await assertOwnerPrivateDirectory(dirname2(path));
2605
- handle = await open3(path, O_RDONLY3 | O_NOFOLLOW2);
3046
+ handle = await open4(path, O_RDONLY3 | O_NOFOLLOW2);
2606
3047
  const stats = await handle.stat();
2607
3048
  if (!stats.isFile() || !ownerPrivate3(stats)) throw new HostRelayGatewayError("credential", "Host Relay credential file is not owner-private.");
2608
3049
  const raw = await handle.readFile("utf8");
@@ -2632,13 +3073,13 @@ function decodeHostRegistrationAuthority(value, expectedHostSourceRef) {
2632
3073
  return { gateway_request_origin: value.gateway_request_origin, host_access_token: value.host_access_token };
2633
3074
  }
2634
3075
  function validRegistrationIdentity(value, expectedHostSourceRef) {
2635
- return value.schema_version === "ceal.host_registration_state.v1" && value.status === "active" && value.host_source_ref === expectedHostSourceRef && typeof value.registration_attempt_ref === "string" && /^host-registration-attempt:[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/u.test(value.registration_attempt_ref) && typeof value.host_installation_ref === "string" && /^host-installation:[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/u.test(value.host_installation_ref) && typeof value.host_source_ref === "string" && /^host-source:[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/u.test(value.host_source_ref);
3076
+ return value.schema_version === HOST_REGISTRATION_STATE_SCHEMA && value.status === "active" && value.host_source_ref === expectedHostSourceRef && typeof value.registration_attempt_ref === "string" && CEAL_HOST_REGISTRATION_ATTEMPT_REF_PATTERN.test(value.registration_attempt_ref) && typeof value.host_installation_ref === "string" && CEAL_HOST_INSTALLATION_REF_PATTERN.test(value.host_installation_ref) && typeof value.host_source_ref === "string" && hostSourceUuid(value.host_source_ref) !== null;
2636
3077
  }
2637
3078
  function validRegistrationCredential(value) {
2638
3079
  return Number.isSafeInteger(value.credential_generation) && Number(value.credential_generation) > 0 && validHostAccessToken(value.host_access_token);
2639
3080
  }
2640
3081
  function validHostAccessToken(value) {
2641
- return typeof value === "string" && /^ceal_host_[A-Za-z0-9_-]{43}$/u.test(value);
3082
+ return typeof value === "string" && CEAL_HOST_ACCESS_TOKEN_PATTERN.test(value);
2642
3083
  }
2643
3084
  function validGatewayOrigin(value) {
2644
3085
  try {
@@ -2671,7 +3112,7 @@ import { chmod, lstat as lstat3, unlink as unlink2 } from "node:fs/promises";
2671
3112
  import { createConnection, createServer } from "node:net";
2672
3113
 
2673
3114
  // host/relay/src/current-prompt-custody.ts
2674
- import { createHash as createHash4 } from "node:crypto";
3115
+ import { createHash as createHash5 } from "node:crypto";
2675
3116
  var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2676
3117
  var MAX_CURRENT_PROMPTS = 1024;
2677
3118
  var HostCurrentPromptCustody = class {
@@ -2685,7 +3126,7 @@ var HostCurrentPromptCustody = class {
2685
3126
  const bytes2 = Buffer.byteLength(prompt, "utf8");
2686
3127
  const expiry = Date.parse(expiresAt);
2687
3128
  if (bytes2 === 0 || bytes2 > HOST_CURRENT_PROMPT_MAX_BYTES || !Number.isFinite(expiry) || expiry <= this.#now()) throw new TypeError("current_prompt_unavailable");
2688
- if (hostProducerPromptRef(createHash4("sha256").update(prompt, "utf8").digest("hex")) !== identity.prompt_ref) throw new TypeError("current_prompt_unavailable");
3129
+ if (hostProducerPromptRef(createHash5("sha256").update(prompt, "utf8").digest("hex")) !== identity.prompt_ref) throw new TypeError("current_prompt_unavailable");
2689
3130
  this.#purge();
2690
3131
  const key = promptKey(identity);
2691
3132
  if (this.#consumed.has(key)) return;
@@ -2738,11 +3179,46 @@ var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_co
2738
3179
  var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2739
3180
  var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2740
3181
  var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
3182
+ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
3183
+ "context_stale",
3184
+ "context_expired",
3185
+ "host_source_refused",
3186
+ "host_credential_refused",
3187
+ "gateway_unavailable",
3188
+ "gateway_refused",
3189
+ "gateway_response_invalid",
3190
+ "deadline",
3191
+ "cancelled",
3192
+ "mint_failed",
3193
+ "relay_failed"
3194
+ ]);
3195
+ var HostRelayInvocationMintRefusal = class extends Error {
3196
+ reason;
3197
+ constructor(reason) {
3198
+ super(reason);
3199
+ this.name = "HostRelayInvocationMintRefusal";
3200
+ this.reason = reason;
3201
+ }
3202
+ };
3203
+ var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
3204
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
3205
+ "permission_denied",
3206
+ "socket_missing",
3207
+ "connection_refused",
3208
+ "closed_early",
3209
+ "response_invalid",
3210
+ "timed_out",
3211
+ "cancelled",
3212
+ "unavailable"
3213
+ ]);
2741
3214
  var HostRelayIpcError = class extends Error {
2742
3215
  code;
2743
- constructor(code, message = code) {
3216
+ /** Set only when the client-side socket exchange itself failed. */
3217
+ failure;
3218
+ constructor(code, message = code, failure) {
2744
3219
  super(message);
2745
3220
  this.code = code;
3221
+ this.failure = failure;
2746
3222
  }
2747
3223
  };
2748
3224
  async function startHostRelayIpcServer(options) {
@@ -2751,7 +3227,7 @@ async function startHostRelayIpcServer(options) {
2751
3227
  const sockets = /* @__PURE__ */ new Set();
2752
3228
  const quarantine = options.quarantine ?? options.admission.quarantine;
2753
3229
  const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
2754
- const server = createServer((socket) => serveSocket(socket, options.admission, options.bindings, currentPrompts, options.mintInvocationContext, quarantine, active, sockets));
3230
+ const server = createServer((socket) => serveSocket(socket, options, currentPrompts, quarantine, active, sockets));
2755
3231
  await listen(server, options.endpoint);
2756
3232
  if (process.platform !== "win32") await chmod(options.endpoint, 384);
2757
3233
  return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
@@ -2763,12 +3239,12 @@ function encodeHostRelayIpcResponse(response2) {
2763
3239
  body.copy(result2, HOST_RELAY_IPC_LENGTH_BYTES);
2764
3240
  return result2;
2765
3241
  }
2766
- function serveSocket(socket, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active, sockets) {
3242
+ function serveSocket(socket, options, currentPrompts, quarantine, active, sockets) {
2767
3243
  const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve(), abort: new AbortController() };
2768
3244
  sockets.add(socket);
2769
3245
  socket.on("data", (chunk) => {
2770
3246
  state.buffer = Buffer.concat([state.buffer, Buffer.from(chunk)]);
2771
- state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)).catch(() => {
3247
+ state.tail = state.tail.then(() => drainFrames(socket, state, options, currentPrompts, quarantine, active)).catch(() => {
2772
3248
  writeResponse(socket, errorResponse("relay_unavailable"));
2773
3249
  socket.end();
2774
3250
  });
@@ -2786,11 +3262,11 @@ function serveSocket(socket, admission, bindings, currentPrompts, mintInvocation
2786
3262
  else socket.end();
2787
3263
  });
2788
3264
  }
2789
- async function drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
2790
- while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)) {
3265
+ async function drainFrames(socket, state, options, currentPrompts, quarantine, active) {
3266
+ while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, options, currentPrompts, quarantine, active)) {
2791
3267
  }
2792
3268
  }
2793
- async function processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
3269
+ async function processBufferedRequest(socket, state, options, currentPrompts, quarantine, active) {
2794
3270
  const length = state.buffer.readUInt32BE(0);
2795
3271
  const promptWire = currentPromptWire(state.buffer);
2796
3272
  const maximum = promptWire ? HOST_CURRENT_PROMPT_MAX_BYTES + 4096 : HOST_PRODUCER_MAX_JSON_BYTES;
@@ -2819,8 +3295,13 @@ async function processBufferedRequest(socket, state, admission, bindings, curren
2819
3295
  }
2820
3296
  return true;
2821
3297
  }
2822
- if (await processHostQuery(socket, request2, bindings, currentPrompts, mintInvocationContext2, state.abort.signal)) return true;
2823
- await processProducerRequest(socket, state, request2, encoded, admission, quarantine, active);
3298
+ const answered = await processHostQuery(socket, request2, options, currentPrompts, state.abort.signal);
3299
+ if (answered === "closed") {
3300
+ socket.end();
3301
+ return false;
3302
+ }
3303
+ if (answered === "answered") return true;
3304
+ await processProducerRequest(socket, state, request2, encoded, options.admission, quarantine, active);
2824
3305
  return true;
2825
3306
  }
2826
3307
  async function refuseInvalidBufferedRequest(socket, rawBuffer, length, promptWire, quarantine) {
@@ -2852,16 +3333,29 @@ async function processProducerRequest(socket, state, request2, encoded, admissio
2852
3333
  }
2853
3334
  writeResponse(socket, admissionResponse(await admission.admit(request2)));
2854
3335
  }
2855
- async function processHostQuery(socket, request2, bindings, currentPrompts, mint, signal) {
3336
+ async function processHostQuery(socket, request2, options, currentPrompts, signal) {
2856
3337
  if (request2.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
2857
- writeBindingResponse(socket, await bindings.query(bindingQueryFromRequest(request2)));
2858
- return true;
3338
+ let result2;
3339
+ try {
3340
+ result2 = await options.bindings.query(bindingQueryFromRequest(request2));
3341
+ } catch {
3342
+ return "closed";
3343
+ }
3344
+ writeBindingResponse(socket, result2);
3345
+ return "answered";
2859
3346
  }
2860
3347
  if (request2.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
2861
- writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, currentPrompts, mint, signal));
2862
- return true;
3348
+ let response2;
3349
+ const resolve = (invocationSignal) => resolveInvocationContext(request2, options.admission, options.bindings, currentPrompts, options.mintInvocationContext, invocationSignal);
3350
+ try {
3351
+ response2 = options.invocationMintTimeoutMs === void 0 && options.scheduleInvocationMintDeadline === void 0 && options.observeInvocationMint === void 0 ? await resolve(signal) : await observeInvocationMint(resolve, signal, options.invocationMintTimeoutMs, options.scheduleInvocationMintDeadline, options.observeInvocationMint);
3352
+ } catch {
3353
+ response2 = { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "refused", reason: "relay_failed" };
3354
+ }
3355
+ writeInvocationContextResponse(socket, response2);
3356
+ return "answered";
2863
3357
  }
2864
- return false;
3358
+ return "not_a_query";
2865
3359
  }
2866
3360
  function claimProducer(socket, state, frame, active) {
2867
3361
  const key = producerKey(frame);
@@ -2895,14 +3389,93 @@ function writeInvocationContextResponse(socket, response2) {
2895
3389
  function writeCurrentPromptResponse(socket, status) {
2896
3390
  if (!socket.destroyed) socket.write(encodeLengthPrefixed({ schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status }));
2897
3391
  }
2898
- async function resolveInvocationContext(request2, bindings, currentPrompts, mint, signal) {
3392
+ async function resolveInvocationContext(request2, admission, bindings, currentPrompts, mint, signal) {
2899
3393
  if (mint === void 0) throw new HostRelayIpcError("relay_unavailable");
2900
- const binding = await bindings.query(bindingQueryFromRequest(request2));
2901
- if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, ...binding };
3394
+ const query = bindingQueryFromRequest(request2);
3395
+ const binding = await waitForRequestBinding(query, admission, bindings, signal);
3396
+ if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "no_binding" };
2902
3397
  const currentPrompt = currentPrompts.take({ producer_id: request2.producer_id, producer_installation_ref: request2.producer_installation_ref, local_session_ref: request2.local_session_ref, local_turn_ref: request2.local_turn_ref, prompt_ref: binding.binding.prompt_ref });
2903
- const result2 = await mint({ client_nonce: request2.client_nonce, context_expires_at: binding.binding.context_expires_at ?? binding.binding.bound_at, request_work_context: relayRequestWorkContextFromBinding(binding.binding), ...currentPrompt === void 0 ? {} : { current_prompt: currentPrompt } }, signal);
3398
+ let result2;
3399
+ try {
3400
+ result2 = await mint({ client_nonce: request2.client_nonce, context_expires_at: binding.binding.context_expires_at ?? binding.binding.bound_at, request_work_context: relayRequestWorkContextFromBinding(binding.binding), ...currentPrompt === void 0 ? {} : { current_prompt: currentPrompt } }, signal);
3401
+ } catch (error) {
3402
+ return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "refused", reason: error instanceof HostRelayInvocationMintRefusal ? error.reason : "mint_failed" };
3403
+ }
2904
3404
  return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "ready", result: result2 };
2905
3405
  }
3406
+ async function waitForRequestBinding(query, admission, bindings, signal) {
3407
+ let binding = await bindings.query(query);
3408
+ if (binding.status === "ready") return binding;
3409
+ while (await admission.hasPendingRequestBinding(query)) {
3410
+ const cycle = new AbortController();
3411
+ const cancelCycle = () => cycle.abort(signal.reason);
3412
+ if (signal.aborted) cancelCycle();
3413
+ else signal.addEventListener("abort", cancelCycle, { once: true });
3414
+ try {
3415
+ const changed = Promise.race([
3416
+ bindings.waitForBinding(query, cycle.signal).then((result3) => ({ kind: "bound", result: result3 })),
3417
+ admission.waitForDrainChange(cycle.signal).then(() => ({ kind: "drained" }))
3418
+ ]).then((result3) => result3, (error) => ({ kind: "cancelled", error }));
3419
+ binding = await bindings.query(query);
3420
+ if (binding.status === "ready") return binding;
3421
+ if (!await admission.hasPendingRequestBinding(query)) return await bindings.query(query);
3422
+ const result2 = await changed;
3423
+ if (result2.kind === "cancelled") throw result2.error;
3424
+ } finally {
3425
+ signal.removeEventListener("abort", cancelCycle);
3426
+ cycle.abort("wait_cycle_complete");
3427
+ }
3428
+ binding = await bindings.query(query);
3429
+ if (binding.status === "ready") return binding;
3430
+ }
3431
+ return await bindings.query(query);
3432
+ }
3433
+ async function observeInvocationMint(resolve, callerSignal, timeoutMs, scheduleDeadline, observe) {
3434
+ const started = process.hrtime.bigint();
3435
+ const controller2 = new AbortController();
3436
+ let cancellation = null;
3437
+ let outcome = "failed";
3438
+ let reason;
3439
+ const cancel = (cause) => {
3440
+ if (cancellation === null) {
3441
+ cancellation = cause;
3442
+ controller2.abort(cause);
3443
+ }
3444
+ };
3445
+ const callerCancelled = () => cancel("caller_cancelled");
3446
+ const cancelled = new Promise((_resolve, reject) => controller2.signal.addEventListener("abort", () => reject(new Error("invocation mint cancelled")), { once: true }));
3447
+ const clearDeadline = timeoutMs === void 0 ? () => void 0 : (scheduleDeadline ?? scheduleInvocationMintDeadline)(() => cancel("deadline"), timeoutMs);
3448
+ if (callerSignal.aborted) callerCancelled();
3449
+ else callerSignal.addEventListener("abort", callerCancelled, { once: true });
3450
+ try {
3451
+ const response2 = await Promise.race([resolve(controller2.signal), cancelled]);
3452
+ ({ outcome, reason } = invocationMintObservationForResponse(response2));
3453
+ return response2;
3454
+ } catch {
3455
+ ({ outcome, reason } = invocationMintObservationForCancellation(cancellation));
3456
+ return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "refused", reason: reason ?? "relay_failed" };
3457
+ } finally {
3458
+ clearDeadline();
3459
+ callerSignal.removeEventListener("abort", callerCancelled);
3460
+ observe?.({ outcome, elapsed_ms: Number((process.hrtime.bigint() - started) / 1000000n), ...reason === void 0 ? {} : { reason } });
3461
+ }
3462
+ }
3463
+ function invocationMintObservationForResponse(response2) {
3464
+ if (response2.status === "no_binding") return { outcome: "no_binding" };
3465
+ if (response2.status === "ready") return { outcome: "completed" };
3466
+ if (response2.reason === "deadline") return { outcome: "deadline", reason: "deadline" };
3467
+ if (response2.reason === "cancelled") return { outcome: "caller_cancelled", reason: "cancelled" };
3468
+ return { outcome: "failed", reason: response2.reason };
3469
+ }
3470
+ function invocationMintObservationForCancellation(cancellation) {
3471
+ if (cancellation === "deadline") return { outcome: "deadline", reason: "deadline" };
3472
+ if (cancellation === "caller_cancelled") return { outcome: "caller_cancelled", reason: "cancelled" };
3473
+ return { outcome: "failed", reason: "relay_failed" };
3474
+ }
3475
+ function scheduleInvocationMintDeadline(expire, milliseconds) {
3476
+ const timeout = setTimeout(expire, milliseconds);
3477
+ return () => clearTimeout(timeout);
3478
+ }
2906
3479
  function admissionResponse(result2) {
2907
3480
  return { schema_version: HOST_RELAY_IPC_RESPONSE_SCHEMA, ...result2 };
2908
3481
  }
@@ -2988,7 +3561,7 @@ async function assertEndpointVacant(endpoint) {
2988
3561
  await lstat3(endpoint);
2989
3562
  throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is already present.");
2990
3563
  } catch (error) {
2991
- if (errorCode7(error) !== "ENOENT") throw error;
3564
+ if (errorCode8(error) !== "ENOENT") throw error;
2992
3565
  }
2993
3566
  }
2994
3567
  function listen(server, endpoint) {
@@ -3005,7 +3578,7 @@ async function closeServer(server, sockets, endpoint) {
3005
3578
  await new Promise((resolve) => server.close(() => resolve()));
3006
3579
  if (process.platform !== "win32") await unlink2(endpoint).catch(() => void 0);
3007
3580
  }
3008
- function errorCode7(error) {
3581
+ function errorCode8(error) {
3009
3582
  return record4(error) && typeof error.code === "string" ? error.code : null;
3010
3583
  }
3011
3584
 
@@ -3027,7 +3600,7 @@ async function readHostRelayConfig(path) {
3027
3600
  let handle;
3028
3601
  try {
3029
3602
  await assertOwnerPrivateDirectory2(dirname3(path));
3030
- handle = await open4(path, O_RDONLY4 | O_NOFOLLOW3);
3603
+ handle = await open5(path, O_RDONLY4 | O_NOFOLLOW3);
3031
3604
  const stats = await handle.stat();
3032
3605
  if (!stats.isFile() || !ownerPrivate4(stats)) throw new HostRelayConfigError("config_not_private", "Host Relay config file is not owner-private.");
3033
3606
  if (stats.size < HOST_RELAY_CONFIG_MIN_BYTES || stats.size > HOST_RELAY_CONFIG_MAX_BYTES) throw new HostRelayConfigError("invalid_config", `invalid_config: Host Relay config size is invalid: ${refusalFact("config_bytes", stats.size, `between ${HOST_RELAY_CONFIG_MIN_BYTES} and ${HOST_RELAY_CONFIG_MAX_BYTES}`)}.`);
@@ -3039,7 +3612,9 @@ async function readHostRelayConfig(path) {
3039
3612
  } catch {
3040
3613
  throw new HostRelayConfigError("invalid_json", "Host Relay config is not JSON.");
3041
3614
  }
3042
- return decodeHostRelayConfig(value);
3615
+ const config = decodeHostRelayConfig(value);
3616
+ validateHostRelaySourcePaths(config);
3617
+ return config;
3043
3618
  } catch (error) {
3044
3619
  if (error instanceof HostRelayConfigError) throw error;
3045
3620
  throw new HostRelayConfigError("config_unavailable", "Host Relay config is unavailable.");
@@ -3047,6 +3622,13 @@ async function readHostRelayConfig(path) {
3047
3622
  await handle?.close();
3048
3623
  }
3049
3624
  }
3625
+ function validateHostRelaySourcePaths(config) {
3626
+ try {
3627
+ assertHostRelaySourcePaths(dirname3(config.registration_state_file), config);
3628
+ } catch (error) {
3629
+ throw new HostRelayConfigError("invalid_config", error instanceof Error ? error.message : "Host Relay source tuple is invalid.");
3630
+ }
3631
+ }
3050
3632
  function decodeHostRelayConfig(value) {
3051
3633
  const required = ["schema_version", "registration_state_file", "host_source_ref", "state_root", "ipc_endpoint"];
3052
3634
  const optional = ["drain_interval_ms", "gateway_timeout_ms"];
@@ -3069,6 +3651,8 @@ function validConfigIdentity(value) {
3069
3651
  function validConfigRuntime(value) {
3070
3652
  return isAbsoluteNormalizedNonRootPath(value.state_root, process.platform, true) && isAbsoluteNormalizedNonRootPath(value.ipc_endpoint, process.platform, true) && boundedInteger(value.drain_interval_ms, 50, 3e4, true) && boundedInteger(value.gateway_timeout_ms, 100, 6e4, true);
3071
3653
  }
3654
+ var HOST_RELAY_INVOCATION_MINT_LOG_TAG = "[host-relay-invocation-mint]";
3655
+ var HOST_RELAY_INVOCATION_MINT_LINE = new RegExp(`^${HOST_RELAY_INVOCATION_MINT_LOG_TAG.replace(/[[\]]/gu, "\\$&")} outcome=([a-z_]+)(?: reason=([a-z][a-z0-9_]{0,63}))? elapsed_ms=[0-9]+$`, "u");
3072
3656
  async function serveHostRelay(config, signal, dependencies = {}) {
3073
3657
  const admission = new RelayAdmissionStore(join6(config.state_root, "admission"));
3074
3658
  const bindings = new RelayRequestBindingStore(join6(config.state_root, "bindings"));
@@ -3078,7 +3662,7 @@ async function serveHostRelay(config, signal, dependencies = {}) {
3078
3662
  } });
3079
3663
  let server;
3080
3664
  try {
3081
- server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) => mintInvocationContext(gateway, input, invocationSignal, config.gateway_timeout_ms, dependencies.observeInvocationMint ?? reportInvocationMint, dependencies.scheduleInvocationMintDeadline ?? scheduleInvocationMintDeadline) });
3665
+ server = await startHostRelayRuntimeIpc(config, admission, bindings, gateway, dependencies);
3082
3666
  while (!signal.aborted) {
3083
3667
  const round = await admission.drainRound((input) => bridge.deliver(input), { now_ms: (dependencies.now ?? Date.now)(), host_source_ref: config.host_source_ref });
3084
3668
  if (round.delivered.length === 0 && round.refused.length === 0) await (dependencies.wait ?? ((milliseconds, waitSignal) => waitForAbort(waitSignal, milliseconds)))(config.drain_interval_ms, signal);
@@ -3087,41 +3671,52 @@ async function serveHostRelay(config, signal, dependencies = {}) {
3087
3671
  await server?.close();
3088
3672
  }
3089
3673
  }
3090
- async function mintInvocationContext(gateway, input, callerSignal, timeoutMs, observe, scheduleDeadline) {
3091
- const controller2 = new AbortController();
3092
- const started = process.hrtime.bigint();
3093
- let cancellation = null;
3094
- let outcome = "failed";
3095
- const cancel = (cause) => {
3096
- if (cancellation === null) cancellation = cause;
3097
- controller2.abort();
3098
- };
3099
- const callerCancelled = () => cancel("caller_cancelled");
3100
- const clearDeadline = scheduleDeadline(() => cancel("deadline"), timeoutMs);
3101
- if (callerSignal.aborted) callerCancelled();
3102
- else callerSignal.addEventListener("abort", callerCancelled, { once: true });
3103
- const cancelled = new Promise((_resolve, reject) => controller2.signal.addEventListener("abort", () => reject(new Error("invocation mint cancelled")), { once: true }));
3674
+ async function startHostRelayRuntimeIpc(config, admission, bindings, gateway, dependencies) {
3675
+ return (dependencies.startIpc ?? startHostRelayIpcServer)({
3676
+ endpoint: config.ipc_endpoint,
3677
+ admission,
3678
+ bindings,
3679
+ mintInvocationContext: (input, invocationSignal) => mintInvocationContext(gateway, input, invocationSignal),
3680
+ invocationMintTimeoutMs: config.gateway_timeout_ms,
3681
+ scheduleInvocationMintDeadline: dependencies.scheduleInvocationMintDeadline ?? scheduleInvocationMintDeadline2,
3682
+ observeInvocationMint: dependencies.observeInvocationMint ?? reportInvocationMint
3683
+ });
3684
+ }
3685
+ async function mintInvocationContext(gateway, input, signal) {
3104
3686
  try {
3105
- const result2 = await Promise.race([gateway.mintInvocationContext(input, controller2.signal), cancelled]);
3106
- outcome = "completed";
3107
- return result2;
3687
+ return await gateway.mintInvocationContext(input, signal);
3108
3688
  } catch (error) {
3109
- outcome = cancellation ?? "failed";
3110
- throw error;
3111
- } finally {
3112
- clearDeadline();
3113
- callerSignal.removeEventListener("abort", callerCancelled);
3114
- observe({ outcome, elapsed_ms: Number((process.hrtime.bigint() - started) / 1000000n) });
3115
- }
3116
- }
3117
- function scheduleInvocationMintDeadline(expire, milliseconds) {
3689
+ const cancellation = signal.reason === "deadline" ? "deadline" : signal.reason === "caller_cancelled" ? "caller_cancelled" : null;
3690
+ throw new HostRelayInvocationMintRefusal(invocationMintRefusalReason(error, cancellation));
3691
+ }
3692
+ }
3693
+ function invocationMintRefusalReason(error, cancellation) {
3694
+ if (cancellation === "deadline") return "deadline";
3695
+ if (cancellation === "caller_cancelled") return "cancelled";
3696
+ if (!(error instanceof HostRelayGatewayError)) return "mint_failed";
3697
+ if (error.code === "credential") return "host_credential_refused";
3698
+ if (error.code === "gateway_unavailable") return "gateway_unavailable";
3699
+ if (error.code === "invalid_response") return "gateway_response_invalid";
3700
+ if (error.code !== "gateway_refused") return "mint_failed";
3701
+ return (error.error_code === void 0 ? void 0 : GATEWAY_MINT_REFUSAL_REASONS.get(error.error_code)) ?? "gateway_refused";
3702
+ }
3703
+ var GATEWAY_MINT_REFUSAL_REASONS = /* @__PURE__ */ new Map([
3704
+ ["request_context_refused", "context_stale"],
3705
+ ["context_expired", "context_expired"],
3706
+ ["host_source_refused", "host_source_refused"],
3707
+ ["host_invocation_context_unavailable", "gateway_unavailable"]
3708
+ ]);
3709
+ function scheduleInvocationMintDeadline2(expire, milliseconds) {
3118
3710
  const timeout = setTimeout(expire, milliseconds);
3119
3711
  return () => clearTimeout(timeout);
3120
3712
  }
3121
3713
  function reportInvocationMint(observation) {
3122
- process.stderr.write(`[host-relay-invocation-mint] outcome=${observation.outcome} elapsed_ms=${observation.elapsed_ms}
3714
+ process.stderr.write(`${formatHostRelayInvocationMintLine(observation)}
3123
3715
  `);
3124
3716
  }
3717
+ function formatHostRelayInvocationMintLine(observation) {
3718
+ return `${HOST_RELAY_INVOCATION_MINT_LOG_TAG} outcome=${observation.outcome}${observation.reason === void 0 ? "" : ` reason=${observation.reason}`} elapsed_ms=${observation.elapsed_ms}`;
3719
+ }
3125
3720
  async function runHostRelayCli(args, signal, dependencies = {}) {
3126
3721
  try {
3127
3722
  const configPath = parseServeArgs(args);
@@ -3175,6 +3770,7 @@ var controller = new AbortController();
3175
3770
  var stop = () => controller.abort();
3176
3771
  process.once("SIGINT", stop);
3177
3772
  process.once("SIGTERM", stop);
3773
+ var stopLogBound = boundHostServiceLog();
3178
3774
  void runHostRelayCli(process.argv.slice(2), controller.signal).then((result2) => {
3179
3775
  process.stdout.write(`${JSON.stringify({ schema_version: "ceal.host_relay_command.v1", ...result2 })}
3180
3776
  `);
@@ -3184,6 +3780,7 @@ void runHostRelayCli(process.argv.slice(2), controller.signal).then((result2) =>
3184
3780
  `);
3185
3781
  process.exitCode = 1;
3186
3782
  }).finally(() => {
3783
+ stopLogBound();
3187
3784
  process.removeListener("SIGINT", stop);
3188
3785
  process.removeListener("SIGTERM", stop);
3189
3786
  });