@corca-org/ceal-host-win32-x64 1.0.20 → 1.0.21

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.
@@ -5,7 +5,7 @@ const require = __cealCreateRequire(import.meta.url);
5
5
  // host/codex/src/codex-adapter.ts
6
6
  import { randomUUID } from "node:crypto";
7
7
  import { homedir } from "node:os";
8
- import { isAbsolute as isAbsolute3, join as join4, relative, resolve as resolve2 } from "node:path";
8
+ import { isAbsolute as isAbsolute3, relative, resolve as resolve2 } from "node:path";
9
9
 
10
10
  // packages/ceal-client-protocol/src/canonical-json.ts
11
11
  function cealCanonicalJson(value) {
@@ -34,16 +34,34 @@ function isPlainRecord(value) {
34
34
  return prototype === Object.prototype || prototype === null;
35
35
  }
36
36
 
37
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
38
+ import { createHash } from "node:crypto";
39
+
37
40
  // packages/ceal-client-protocol/client-wire-contract.json
38
41
  var client_wire_contract_default = {
39
42
  schema_version: "ceal.client_wire_contract.v1",
43
+ doctor: {
44
+ schema_version: "ceal.doctor.v1"
45
+ },
46
+ client_commands: {
47
+ doctor: ["doctor"],
48
+ version: ["version"],
49
+ access_group_list: ["access-group", "list"]
50
+ },
51
+ client_environment: {
52
+ environment_prefix: "CEAL",
53
+ context_override_suffixes: ["GATEWAY_ORIGIN", "GATEWAY_TRANSPORT_ORIGIN", "ACCESS_TOKEN", "CONTEXT_STORE_PATH"]
54
+ },
40
55
  canonical_json: {
41
56
  ordering: "utf16_code_unit_ascending"
42
57
  },
43
58
  artifact_descriptor: {
44
- operation_contract_bundle_schema_version: "ceal.operation_contract_bundle.v1",
45
- schema_version: "ceal.verified_artifact_descriptor.v1",
46
- binding_schema_version: "ceal.verified_artifact_binding.v1",
59
+ operation_contract_bundle_schema_name: "ceal.operation_contract_bundle",
60
+ operation_contract_bundle_fields: ["schema_version", "catalog_revision", "operations", "failure_guidance"],
61
+ schema_name: "ceal.verified_artifact_descriptor",
62
+ fields: ["schema_version", "kind", "media_type", "byte_count", "sha256", "binding"],
63
+ binding_schema_name: "ceal.verified_artifact_binding",
64
+ binding_fields: ["schema_version", "kind", "catalog_revision"],
47
65
  kind: "verified_artifact",
48
66
  binding_kind: "catalog",
49
67
  media_type: "application/json",
@@ -59,14 +77,16 @@ var client_wire_contract_default = {
59
77
  length: 72,
60
78
  pattern: "^catalog:[a-f0-9]{64}$"
61
79
  },
62
- envelope_max_bytes: 389
80
+ envelope_max_bytes: 407
63
81
  },
64
82
  command_request: {
65
- schema_version: "ceal.command_request.v1",
83
+ schema_name: "ceal.command_request",
84
+ fields: ["schema_version", "argv", "operation", "client_nonce", "context_token"],
66
85
  absolute_transport_max_bytes: 65536
67
86
  },
68
87
  command_resolution: {
69
- schema_version: "ceal.gateway_command_resolution.v1",
88
+ schema_name: "ceal.gateway_command_resolution",
89
+ fields: ["schema_version", "kind", "ok", "execution_started", "program", "route", "authority", "routes", "operations", "required_action_sequence", "semantic_options", "result_delivery", "operation", "invocation", "entrypoints", "common_concepts", "withheld", "catalog_revision", "operation_id", "input", "transport", "output", "unresolved_inputs", "unresolved_refusal", "attempted_route", "did_you_mean", "error"],
70
90
  authority: {
71
91
  anonymous: {
72
92
  state: "anonymous",
@@ -106,7 +126,8 @@ var client_wire_contract_default = {
106
126
  }
107
127
  },
108
128
  command_response: {
109
- schema_version: "ceal.command_response.v1",
129
+ schema_name: "ceal.command_response",
130
+ fields: ["schema_version", "exit_code", "document", "operation_id", "visible_output_max_bytes", "local_delivery", "verified_artifact"],
110
131
  descriptor_field: "verified_artifact",
111
132
  required_fields: [
112
133
  "schema_version",
@@ -130,29 +151,41 @@ var client_wire_contract_default = {
130
151
  "required_action_sequence",
131
152
  "withheld"
132
153
  ],
133
- prompt_field: "prompt",
134
- prompt_schema_version: "ceal.prompt.v1",
135
- focused_prompt_document_fields: [
136
- "catalog_revision",
137
- "prompt"
138
- ],
139
- focused_prompt_continuation_document_fields: [
140
- "catalog_revision",
141
- "remaining_work",
142
- "prompt"
143
- ],
144
154
  discovery_command: "discovery",
145
- discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
155
+ discovery_manifest_schema_name: "ceal.discovery_manifest",
156
+ discovery_manifest_fields: ["schema_version", "skill", "authority_scope", "connector_kinds", "personal_connector_kinds", "guide_markdown", "renderer_version", "digest"],
146
157
  discovery_manifest_document_fields: [
147
158
  "discovery_manifest"
148
159
  ],
149
160
  exit_code_max: 125,
150
161
  bare_document_max_bytes: 65536,
151
- complete_max_bytes: 66019
162
+ complete_max_bytes: 66046
163
+ },
164
+ host_invocation_authentication: {
165
+ request_schema_name: "ceal.host_invocation_authentication_request",
166
+ request_fields: [
167
+ "schema_version",
168
+ "client_nonce"
169
+ ],
170
+ result_schema_name: "ceal.host_invocation_authentication_result",
171
+ result_fields: [
172
+ "schema_version",
173
+ "context_token",
174
+ "expires_at"
175
+ ],
176
+ client_nonce: {
177
+ character_class_source: "A-Za-z0-9_-",
178
+ encoded_characters: 43
179
+ }
180
+ },
181
+ gateway_host_invocation_context_request: {
182
+ schema_name: "ceal.gateway_host_invocation_context_request",
183
+ fields: ["schema_version", "client_nonce", "context_expires_at", "request_work_context", "current_prompt", "visible_output_max_bytes"]
152
184
  },
153
185
  resource_stream: {
154
186
  path: "/api/ceal/v2/resources",
155
- request_schema_version: "ceal.resource_stream_request.v1",
187
+ request_schema_name: "ceal.resource_stream_request",
188
+ request_fields: ["schema_version", "resource_ref", "client_nonce", "context_token"],
156
189
  ref_pattern: "^resource:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
157
190
  media_type_pattern: "^[a-z0-9][a-z0-9!#$&^_.+-]{0,63}/[a-z0-9][a-z0-9!#$&^_.+-]{0,63}$",
158
191
  filename_max_bytes: 512,
@@ -169,88 +202,6 @@ var client_wire_contract_default = {
169
202
  }
170
203
  };
171
204
 
172
- // packages/ceal-client-protocol/src/client-wire-contract.ts
173
- var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
174
- var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
175
- var commandResolutionAuthority = commandResolution.authority;
176
- var commandResolutionSemanticOptions = commandResolution.semantic_options;
177
- var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = commandResolution.schema_version;
178
- var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
179
- var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
180
- var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
181
- var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
182
- var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = artifact.operation_contract_bundle_schema_version;
183
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = artifact.schema_version;
184
- var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = artifact.binding_schema_version;
185
- var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
186
- var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
187
- var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
188
- var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
189
- var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
190
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
191
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
192
- var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
193
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
194
- var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
195
- var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
196
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
197
- var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
198
- var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
199
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
200
- var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
201
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
202
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
203
- var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
204
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
205
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
206
-
207
- // packages/ceal-client-protocol/src/vocabulary.ts
208
- function vocabulary(words) {
209
- return Object.freeze(words);
210
- }
211
-
212
- // packages/ceal-client-protocol/src/gateway-response-types.ts
213
- var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
214
- var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
215
- var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
216
- var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
217
- 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"]);
218
- var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
219
- var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
220
- var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
221
- var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
222
- var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
223
- var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
224
- var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
225
- var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
226
- var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
227
- var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
228
- var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
229
- var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
230
- var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
231
- var CEAL_PROTOCOL_VERSION = "1.4.0";
232
- var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
233
- var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
234
- var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
235
- "audited_call_pending",
236
- "continuation_read_pending",
237
- "continuation_write_pending",
238
- "provider_pacing_pending",
239
- "corpus_replay_pending",
240
- "corpus_append_pending",
241
- "corpus_fence_pending",
242
- "corpus_content_pending",
243
- "corpus_transaction_pending"
244
- ]);
245
- var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
246
- var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
247
- var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
248
- var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
249
- "connector_ref",
250
- "connector_revision",
251
- "policy_decision_revision"
252
- ]);
253
-
254
205
  // packages/ceal-client-protocol/src/operation-next-actions.ts
255
206
  var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
256
207
  var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
@@ -317,7 +268,10 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
317
268
  "follow_required_action_sequence",
318
269
  // The command needs caller-owned local materialization (for example an
319
270
  // @path file) before the Gateway can receive the argument.
320
- "materialize_local_argument"
271
+ "materialize_local_argument",
272
+ // A peer's derived schema identifier changed with its field set; install or
273
+ // upgrade the CLI and Host Relay to the Gateway's release before retrying.
274
+ "upgrade_ceal_client"
321
275
  ];
322
276
  var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
323
277
  var NON_REMEDY_NEXT_ACTION_VALUES = [
@@ -430,47 +384,53 @@ var CEAL_OPERATION_WITHHELD_NEXT_ACTIONS = Object.freeze({
430
384
  personal_authorization_required: "connect_personal_account"
431
385
  });
432
386
 
433
- // packages/ceal-client-protocol/src/operation-withheld-cause.ts
434
- var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
387
+ // packages/ceal-client-protocol/src/vocabulary.ts
388
+ function vocabulary(words) {
389
+ return Object.freeze(words);
390
+ }
435
391
 
436
- // packages/ceal-client-protocol/src/operation-contract-types.ts
437
- var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
438
- var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
439
- var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
440
- var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
441
- var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
442
- var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
443
- var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
444
- var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
445
- var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
446
- var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
447
- var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
448
- var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
449
- var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
450
- var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
451
- var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
452
- var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
453
- var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
454
- var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
455
- var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
456
- var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
457
- var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
458
- var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
459
- var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
460
- var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
461
- var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
462
- var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
463
- var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
464
- var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
465
- var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
466
- var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
467
- var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
468
- "approval_not_required_by_policy",
469
- "interactive_pending",
470
- "interactive_granted",
471
- "interactive_denied",
472
- "interactive_expired",
473
- "interactive_unavailable"
392
+ // packages/ceal-client-protocol/src/gateway-response-types.ts
393
+ var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
394
+ var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
395
+ var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
396
+ var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
397
+ 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"]);
398
+ var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
399
+ var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
400
+ var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
401
+ var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
402
+ var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
403
+ var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
404
+ var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
405
+ var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
406
+ var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
407
+ var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
408
+ var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
409
+ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
410
+ var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
411
+ var CEAL_PROTOCOL_VERSION = "1.4.0";
412
+ var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
413
+ var CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION = "ceal.gateway_call_result.v1";
414
+ var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
415
+ var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
416
+ "audited_call_pending",
417
+ "continuation_read_pending",
418
+ "continuation_write_pending",
419
+ "provider_pacing_pending",
420
+ "corpus_replay_pending",
421
+ "corpus_append_pending",
422
+ "corpus_fence_pending",
423
+ "corpus_content_pending",
424
+ "corpus_transaction_pending"
425
+ ]);
426
+ var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
427
+ var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
428
+ var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
429
+ var CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION = "ceal.gateway_audit_call_detail.v1";
430
+ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
431
+ "connector_ref",
432
+ "connector_revision",
433
+ "policy_decision_revision"
474
434
  ]);
475
435
 
476
436
  // packages/ceal-client-protocol/src/gateway-validation-primitives.ts
@@ -512,10 +472,10 @@ function assertSafeJsonArray(value, options, depth, count) {
512
472
  if (value.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
513
473
  for (const item of value) assertSafeJsonValue(item, options, depth + 1, count);
514
474
  }
515
- function assertSafeJsonRecord(record3, options, depth, count) {
516
- const entries = Object.entries(record3);
475
+ function assertSafeJsonRecord(record, options, depth, count) {
476
+ const entries = Object.entries(record);
517
477
  if (entries.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
518
- const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record3.fields) : null;
478
+ const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record.fields) : null;
519
479
  for (const [key, child] of entries) {
520
480
  if (key === "credential_material_included" && child !== false) invalidByContext(options);
521
481
  if (!isSafeNegativeMaterialAssertion(key, child)) assertSafeJsonKey(key, options);
@@ -684,51 +644,6 @@ function cut(text) {
684
644
  return text.length <= REFUSAL_VALUE_MAX_CHARS ? text : `${text.slice(0, REFUSAL_VALUE_MAX_CHARS)}...(+${text.length - REFUSAL_VALUE_MAX_CHARS} chars)`;
685
645
  }
686
646
 
687
- // packages/ceal-client-protocol/src/operation-access-class.ts
688
- var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
689
-
690
- // packages/ceal-client-protocol/src/domain-vocabulary.ts
691
- var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
692
- var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
693
- var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
694
- var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
695
- var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
696
- var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
697
- var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
698
- var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
699
- var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
700
- var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
701
- var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
702
- var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
703
-
704
- // packages/ceal-client-protocol/src/safe-json-budget.ts
705
- var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
706
- function safeJsonNodeBudgetForBytes(maxBytes) {
707
- if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
708
- throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
709
- }
710
- return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
711
- }
712
-
713
- // packages/ceal-client-protocol/src/protocol-bounds.ts
714
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
715
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
716
- var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
717
- var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
718
- max_depth: 8,
719
- max_properties: 96,
720
- max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
721
- max_alternatives: 8,
722
- max_enum_values: 64,
723
- max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
724
- /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
725
- max_description_characters: 1024,
726
- /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
727
- max_pattern_characters: 256,
728
- /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
729
- max_literal_nodes: 512
730
- });
731
-
732
647
  // packages/ceal-client-protocol/src/operation-validation-primitives.ts
733
648
  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;
734
649
  var CEAL_CALENDAR_DATE_PATTERN_SOURCE = "^\\d{4}-\\d{2}-\\d{2}$";
@@ -796,6 +711,317 @@ function requireIsoTimestamp(value, message) {
796
711
  if (!isCealIsoTimestamp(value)) throw new TypeError(message);
797
712
  }
798
713
 
714
+ // packages/ceal-client-protocol/src/failure-guidance-table.ts
715
+ var CEAL_FAILURE_REDACTION_CLASSES = vocabulary(["model_safe", "withheld"]);
716
+ var CEAL_GATEWAY_STARTING_FAILURE_CODE = "gateway_starting";
717
+ var CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE = "bootstrap_absent";
718
+ var CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE = "bootstrap_unavailable";
719
+ var LOCAL_COMMAND_INVALID = "The local command or argument is invalid.";
720
+ var LOCAL_TRANSPORT_INCOMPLETE = "The local Ceal transport could not complete; report this as a gap.";
721
+ var GATEWAY_TRANSPORT_UNAVAILABLE = "The Gateway transport is unavailable; ask an administrator to restore Gateway availability.";
722
+ var HOST_AUTHENTICATION_UNAVAILABLE = "The Host could not authenticate this invocation; report this as a gap.";
723
+ var SESSION_CONTEXT_UNAVAILABLE = "The local Gateway session context is unavailable.";
724
+ function guidance(message, next_action, http_status, retryable = false, redaction_class = "model_safe") {
725
+ return Object.freeze({ message, next_action, http_status, retryable, redaction_class });
726
+ }
727
+ var CEAL_FAILURE_GUIDANCE_TABLE = Object.freeze({
728
+ invalid_command: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
729
+ invalid_argument: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
730
+ command_not_found: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 404),
731
+ unknown_operation: guidance("The requested Operation is absent from the current verified catalog; report this as a gap unless a catalog suggestion names a replacement.", "answer_with_gap", 404),
732
+ local_route_unavailable: guidance("The requested local route is unavailable or its descriptor is invalid; report this as a gap.", "answer_with_gap", 404),
733
+ local_route_ambiguous: guidance("The requested local route is ambiguous; no local executable was selected. Report this as a gap.", "answer_with_gap", 400),
734
+ local_execution_unavailable: guidance("The selected local route executable is unavailable; report this as a gap.", "answer_with_gap", 500),
735
+ local_pickup_failed: guidance("The Host Request pickup failed; the Gateway command was not sent. Report this as a gap.", "answer_with_gap", 502),
736
+ invocation_authentication_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
737
+ local_execution_cancellation_unknown: guidance("The selected local route cancellation outcome is unknown; a retry can repeat an effect the cancelled route already completed. Report this as a gap and do not retry.", "answer_with_gap", 409),
738
+ gateway_origin_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
739
+ access_token_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
740
+ context_pair_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
741
+ context_not_selected: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
742
+ context_store_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
743
+ context_store_conflict: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
744
+ refresh_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
745
+ refresh_expired: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
746
+ refresh_replayed: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
747
+ refresh_revoked: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
748
+ refresh_recovery_unavailable: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
749
+ refresh_custody_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
750
+ session_store_unwritable: guidance("The Ceal client could not write its local session store; the operating system refused the write (EACCES, EPERM, or EROFS). rerun_outside_agent_sandbox reruns it with escalated execution.", "rerun_outside_agent_sandbox", 500),
751
+ local_output_exists: guidance("The selected local output path already exists; nothing was written to it.", "choose_new_output_path", 400),
752
+ local_output_outside_result_root: guidance("The selected local output path lies outside this run's result root; only a path inside the result root named here is writable.", "choose_new_output_path", 400),
753
+ local_output_unwritable: guidance("The Ceal client could not write the result file at its local path; the operating system refused the write. When that step followed the Gateway call, the call may already have completed a write effect that a rerun repeats. rerun_outside_agent_sandbox reruns it with escalated execution.", "rerun_outside_agent_sandbox", 500),
754
+ local_output_unavailable: guidance("The Gateway result could not be materialized at the selected local path; report this as a gap.", "answer_with_gap", 500),
755
+ local_materialization_required: guidance("The Gateway result could not be materialized at the selected local path; report this as a gap.", "answer_with_gap", 500),
756
+ contract_artifact_cache_invalid: guidance("The verified contract artifact could not be stored in the private local cache; report this as a gap.", "answer_with_gap", 500),
757
+ response_encoding_failed: guidance("The local response could not be encoded; report this as a gap.", "answer_with_gap", 500),
758
+ request_timeout: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 504),
759
+ request_failed: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 502),
760
+ gateway_unavailable: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 503, true),
761
+ contract_mismatch: guidance("Install or upgrade the Ceal CLI and Host Relay to the same release as the Gateway, then retry.", "upgrade_ceal_client", 409),
762
+ // `gateway_starting` is the one retryable envelope the serving gate answers on every route while starting
763
+ // (`cli/internal/client/gateway_startup_wait.go` re-drives it); the sentence is the client default that renders
764
+ // when the wait ends still unserved, moved from the `localFailureText` default branch.
765
+ [CEAL_GATEWAY_STARTING_FAILURE_CODE]: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503, true),
766
+ gateway_internal_error: guidance("The Gateway failed without exposing internal state; report this as a gap.", "answer_with_gap", 500),
767
+ // The serving gate emits this code with no message; the sentence is the owner-normalized form of the
768
+ // `gateway_internal_error` guidance (decided with the operator 2026-10-13).
769
+ internal_error: guidance("The Gateway failed without exposing internal state.", "answer_with_gap", 500),
770
+ // Owned by the Gateway canonical adapter (`gateway/core/src/gateway-canonical-operation-http-adapter.ts`):
771
+ // the client variant of this sentence in `localFailureText` was retired when the client started reading this table.
772
+ request_body_too_large: guidance("The Gateway request body exceeds its bounded limit.", "reduce_request_size", 413),
773
+ // Restored verbatim from the retired `localFailureText` `unknown_outcome`
774
+ // case: the outcome is unknown, so a read may be retried while a write
775
+ // must receipt-check first. Collapsing both to "do not repeat the call"
776
+ // forbids the safe read retry the sentence exists to allow.
777
+ unknown_outcome: guidance("The transport outcome is unknown: a read may be retried; for a write, check write_receipt.get before repeating.", "answer_with_gap", 500),
778
+ // Restored verbatim from the retired `localFailureText`
779
+ // `refresh_unknown_outcome` case: a refresh that ends unknown leaves the
780
+ // session context unavailable, so the caller repairs or adopts the
781
+ // session instead of reporting a transport gap.
782
+ refresh_unknown_outcome: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
783
+ request_cancelled: guidance("The caller cancelled the request before it completed.", "retry", 400, true),
784
+ expired: guidance("The activation transaction or its administrator approval request expired before completion; repeat the original activation arguments to start a new transaction.", "repeat_original_arguments", 410, true),
785
+ denied: guidance("An administrator denied this device's activation request; ask an administrator whether to reconsider it.", "ask_admin", 403),
786
+ device_approval_pending_limit: guidance("Device approval requests are already waiting for an administrator decision; ask an administrator to decide a pending request before adding another device.", "ask_admin", 429),
787
+ session_already_adopted: guidance("The requested enrollment was not started because this machine already has a live session with the Gateway. Report this as a gap if that local session needs replacement.", "answer_with_gap", 409),
788
+ pending_adoption_limit: guidance("This device's pending activation file is full; another activation is refused while an administrator decision is pending. Report this as a gap.", "answer_with_gap", 429),
789
+ recovery_required: guidance("The Gateway could not safely complete the activation transaction automatically; ask an administrator to recover this transaction.", "ask_admin", 500),
790
+ unsupported_feature: guidance("This Ceal client does not support the Gateway's required activation protocol; ask an administrator to update the client.", "ask_admin", 501),
791
+ // Activation commit codes rendered through the `localFailureText` default before phase 2b; `retryable` is moved from the
792
+ // emitting sites in `cli/internal/client/gateway_installation_activation.go` and `activation.go:483`.
793
+ activation_state_commit_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500, true),
794
+ activation_response_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502, true),
795
+ activation_rejected: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
796
+ activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
797
+ activation_binding: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
798
+ activation_crypto: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
799
+ activation_state_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
800
+ // Long-tail local codes rendered through the `localFailureText` default before phase 2b; sentences moved from that branch.
801
+ invalid_response: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
802
+ invalid_configuration: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
803
+ activation_state_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
804
+ activation_code_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
805
+ activation_code_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
806
+ activation_code_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 404),
807
+ bootstrap_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
808
+ bootstrap_not_active: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
809
+ bootstrap_unauthorized: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
810
+ // The Gateway owner-bootstrap store file was never created, so the Gateway
811
+ // holds no owner bootstrap to exchange (`gateway/src/host/owner-bootstrap-http-composition.ts`
812
+ // `absent`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:162`);
813
+ // the sentence is the owner-normalized form of that store error. Non-retryable:
814
+ // repeating the exchange cannot create the store; only an administrator
815
+ // placing a bootstrap (fresh gateway setup) changes the outcome.
816
+ [CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE]: guidance("The Gateway holds no owner bootstrap to exchange; report this as a gap.", "answer_with_gap", 503),
817
+ // The Gateway owner-bootstrap store file exists but cannot be read, so the
818
+ // exchange cannot proceed (`gateway/src/host/owner-bootstrap-http-composition.ts`
819
+ // `unavailable`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:163`);
820
+ // the sentence is the owner-normalized form of that store error. Retryable:
821
+ // unlike `absent`, a later exchange may succeed once the store is readable.
822
+ [CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE]: guidance("The Gateway owner bootstrap store is unavailable; retry the exchange.", "retry", 503, true),
823
+ context_selection_ambiguous: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
824
+ session_authority_unverified: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
825
+ session_authority_mismatch: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
826
+ local_credential_lost: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
827
+ local_capability_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
828
+ host_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
829
+ host_activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
830
+ doctor_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
831
+ admin_sign_in_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
832
+ // `invalid_request` renders through the client default today (local encode/path faults); Gateway-answered
833
+ // envelopes carry the Gateway message verbatim and never read this sentence.
834
+ invalid_request: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
835
+ // Gateway canonical-route codes, sentences moved from their minting adapters; statuses moved from the
836
+ // `valid*Failure` decoder maps in `cli/internal/client/gateway_api.go` and `transport.go`.
837
+ invalid_json: guidance("The Gateway request body must be valid JSON.", "answer_with_gap", 400),
838
+ // Per-route variants name their route; the table holds the one stable guidance and the route's `allow`
839
+ // header stays the measured fact (decided with the operator 2026-10-13).
840
+ method_not_allowed: guidance("The HTTP method is not allowed for this Gateway route.", "answer_with_gap", 405),
841
+ request_target_too_large: guidance("The Gateway request target exceeds its bounded limit.", "reduce_request_size", 414),
842
+ route_not_found: guidance("The Gateway route is not present.", "answer_with_gap", 404),
843
+ artifact_unavailable: guidance("The Gateway artifact is unavailable.", "answer_with_gap", 503),
844
+ discovery_unavailable: guidance("The Gateway discovery manifest is unavailable.", "answer_with_gap", 503),
845
+ serialization_failed: guidance("The Gateway response could not be serialized.", "answer_with_gap", 500),
846
+ request_header_too_large: guidance("A consumed Gateway request header exceeds its bounded limit.", "answer_with_gap", 431),
847
+ request_work_context_missing: guidance("The Gateway command requires a Request work context.", "answer_with_gap", 400),
848
+ request_work_context_invalid: guidance("The Gateway Request work context encoding is invalid.", "answer_with_gap", 400),
849
+ request_work_context_refused: guidance("The Host-only discovery manifest takes no Request work context.", "answer_with_gap", 400),
850
+ // Moved from `gateway/src/operations/http-composition.ts` (`unauthorized`) and `command-runtime.ts:827`
851
+ // (`artifact_stale`); both travel with Gateway messages verbatim online, so these sentences are the
852
+ // owner fallback guidance. `unauthorized` re-authenticates through the session, hence its action.
853
+ unauthorized: guidance("Unauthorized.", "repair_or_adopt_session", 401),
854
+ artifact_stale: guidance("The requested contract artifact is not the current catalog artifact.", "answer_with_gap", 409),
855
+ // Host mint classifications. The CLI emits `invocation_authentication_unavailable` with the classification
856
+ // in its detail fact; rows without their own sentence share that code's moved sentence, while `next_action`
857
+ // is moved from `canonicalHostAuthenticationNextActions` (generated from `CEAL_HOST_AUTHENTICATION_POLICY`)
858
+ // and `retryable` from `hostAuthenticationFailureForCause` (`failure.nextAction == "retry"`). The three rows
859
+ // with their own sentences carry the retired policy remedies as Gateway-owned guidance. Statuses are the
860
+ // Gateway-owned mapping decided with the operator 2026-10-13. This covers every wire cause the maps at
861
+ // `host/invocation-authentication-command.ts:217-242` emit, through their policy classifications.
862
+ host_arguments_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 400),
863
+ host_configuration_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
864
+ host_session_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
865
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
866
+ // missing exact-turn fact names the fresh Host turn, not a reinstall.
867
+ host_context_unavailable: guidance("The Host has not activated an invocation context for this session yet. Wait for the Host turn hook to register the session, then retry this command.", "retry", 401, true),
868
+ host_invocation_context_stale: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
869
+ host_invocation_context_expired: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
870
+ host_source_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 403),
871
+ host_registration_credential_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 403),
872
+ host_mint_gateway_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 503),
873
+ host_mint_gateway_rate_limited: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 429),
874
+ host_mint_gateway_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
875
+ host_mint_gateway_response_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
876
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
877
+ // producer-frame fault names the administrator repair step.
878
+ host_producer_frame_invalid: guidance("Ask an administrator to inspect and repair the producer frame, then start a fresh Host turn.", "ask_admin", 400),
879
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
880
+ // sandboxed Relay socket names the run-alone retry.
881
+ host_relay_permission_denied: guidance("An agent sandbox denied the Host Relay socket; run `ceal` as the only command, with no pipe, redirect, or `&&`, so the Host allow rule runs it outside the sandbox.", "rerun_outside_agent_sandbox", 403),
882
+ host_relay_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 503),
883
+ host_mint_transient_retryable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 503, true),
884
+ host_mint_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
885
+ host_relay_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
886
+ host_refusal_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500)
887
+ });
888
+ var FAILURE_GUIDANCE_ENTRY_KEYS = Object.freeze(["message", "next_action", "http_status", "retryable", "redaction_class"]);
889
+
890
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
891
+ var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
892
+ var CEAL_CLIENT_DOCTOR_SCHEMA_VERSION = CEAL_CLIENT_WIRE_CONTRACT.doctor.schema_version;
893
+ var clientCommands = CEAL_CLIENT_WIRE_CONTRACT.client_commands;
894
+ var CEAL_CLIENT_DOCTOR_COMMAND = Object.freeze([...clientCommands.doctor]);
895
+ var CEAL_CLIENT_VERSION_COMMAND = Object.freeze([...clientCommands.version]);
896
+ var CEAL_CLIENT_ACCESS_GROUP_LIST_COMMAND = Object.freeze([...clientCommands.access_group_list]);
897
+ function deriveCealClientWireSchemaVersion(schema) {
898
+ if (!/^ceal\.[a-z][a-z0-9_]*$/u.test(schema.schema_name) || !schema.fields.includes("schema_version") || new Set(schema.fields).size !== schema.fields.length || schema.fields.some((field) => typeof field !== "string" || !/^[a-z][a-z0-9_]*$/u.test(field))) {
899
+ throw new TypeError("Client wire schema name or field set is invalid.");
900
+ }
901
+ const fields = schema.fields.filter((field) => field !== "schema_version").sort();
902
+ const hash8 = createHash("sha256").update(cealCanonicalJson(fields), "utf8").digest("hex").slice(0, 8);
903
+ return `${schema.schema_name}.v1.${hash8}`;
904
+ }
905
+ var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
906
+ var commandResolutionAuthority = commandResolution.authority;
907
+ var commandResolutionSemanticOptions = commandResolution.semantic_options;
908
+ var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(commandResolution);
909
+ var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
910
+ var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
911
+ var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
912
+ var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
913
+ var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.operation_contract_bundle_schema_name, fields: artifact.operation_contract_bundle_fields });
914
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(artifact);
915
+ var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.binding_schema_name, fields: artifact.binding_fields });
916
+ var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
917
+ var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
918
+ var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
919
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
920
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
921
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
922
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
923
+ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
924
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
925
+ var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(request);
926
+ var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
927
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
928
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
929
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
930
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: response.discovery_manifest_schema_name, fields: response.discovery_manifest_fields });
931
+ var CEAL_COMMAND_RESPONSE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(response);
932
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
933
+ var CEAL_RESOURCE_STREAM_REQUEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: CEAL_CLIENT_WIRE_CONTRACT.resource_stream.request_schema_name, fields: CEAL_CLIENT_WIRE_CONTRACT.resource_stream.request_fields });
934
+ var CEAL_RESOURCE_STREAM_REQUEST_FIELDS = Object.freeze([...CEAL_CLIENT_WIRE_CONTRACT.resource_stream.request_fields]);
935
+
936
+ // packages/ceal-client-protocol/src/operation-withheld-cause.ts
937
+ var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
938
+
939
+ // packages/ceal-client-protocol/src/operation-contract-types.ts
940
+ var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
941
+ var CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION = "ceal.operation_descriptor.v1";
942
+ var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
943
+ var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
944
+ var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
945
+ var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
946
+ var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
947
+ var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
948
+ var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
949
+ var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
950
+ var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
951
+ var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
952
+ var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
953
+ var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
954
+ var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
955
+ var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
956
+ var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
957
+ var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
958
+ var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
959
+ var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
960
+ var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
961
+ var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
962
+ var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
963
+ var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
964
+ var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
965
+ var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
966
+ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
967
+ var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
968
+ var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
969
+ var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
970
+ var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
971
+ var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
972
+ "approval_not_required_by_policy",
973
+ "interactive_pending",
974
+ "interactive_granted",
975
+ "interactive_denied",
976
+ "interactive_expired",
977
+ "interactive_unavailable"
978
+ ]);
979
+
980
+ // packages/ceal-client-protocol/src/operation-access-class.ts
981
+ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
982
+
983
+ // packages/ceal-client-protocol/src/domain-vocabulary.ts
984
+ var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
985
+ var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
986
+ var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
987
+ var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
988
+ var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
989
+ var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
990
+ var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
991
+ var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
992
+ var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
993
+ var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
994
+ var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
995
+ var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
996
+
997
+ // packages/ceal-client-protocol/src/safe-json-budget.ts
998
+ var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
999
+ function safeJsonNodeBudgetForBytes(maxBytes) {
1000
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
1001
+ throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
1002
+ }
1003
+ return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
1004
+ }
1005
+
1006
+ // packages/ceal-client-protocol/src/protocol-bounds.ts
1007
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
1008
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
1009
+ var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
1010
+ var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
1011
+ max_depth: 8,
1012
+ max_properties: 96,
1013
+ max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
1014
+ max_alternatives: 8,
1015
+ max_enum_values: 64,
1016
+ max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
1017
+ /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
1018
+ max_description_characters: 1024,
1019
+ /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
1020
+ max_pattern_characters: 256,
1021
+ /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
1022
+ max_literal_nodes: 512
1023
+ });
1024
+
799
1025
  // packages/ceal-client-protocol/src/operation-json-schema.ts
800
1026
  var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
801
1027
 
@@ -837,12 +1063,12 @@ var CEAL_SCHEMA_LITERALS = [
837
1063
  "ceal.enrollment_result.v1",
838
1064
  "ceal.first_activation_causal_join.v1",
839
1065
  "ceal.gateway_announcement_policy.v1",
840
- "ceal.gateway_audit_call_detail.v1",
1066
+ CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION,
841
1067
  "ceal.gateway_audit_event.v1",
842
1068
  "ceal.gateway_audit_readback.v1",
843
1069
  "ceal.gateway_authorization_snapshot.v1",
844
1070
  "ceal.gateway_cache_origin.v1",
845
- "ceal.gateway_call_result.v1",
1071
+ CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION,
846
1072
  CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION,
847
1073
  "ceal.gateway_connector_route_failure.v1",
848
1074
  "ceal.gateway_discovery.v1",
@@ -867,7 +1093,7 @@ var CEAL_SCHEMA_LITERALS = [
867
1093
  "ceal.host_observation.v1",
868
1094
  "ceal.host_registration_request.v1",
869
1095
  "ceal.host_registration_result.v1",
870
- "ceal.operation_descriptor.v1",
1096
+ CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION,
871
1097
  "ceal.operation_error.v1",
872
1098
  "ceal.operation_failure.v1",
873
1099
  "ceal.operation_failure.compact.v1",
@@ -972,10 +1198,20 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
972
1198
  var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
973
1199
  var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
974
1200
 
1201
+ // packages/ceal-client-protocol/src/client-environment-generated.ts
1202
+ var CEAL_CLIENT_CONTEXT_OVERRIDE_ENVIRONMENTS = Object.freeze(["CEAL_GATEWAY_ORIGIN", "CEAL_GATEWAY_TRANSPORT_ORIGIN", "CEAL_ACCESS_TOKEN", "CEAL_CONTEXT_STORE_PATH"]);
1203
+
1204
+ // packages/ceal-client-protocol/src/client-process-contract.ts
1205
+ var CEAL_CLIENT_VERSION_SCHEMA_SUFFIX = ".version.v1";
1206
+ var CEAL_CLIENT_VERSION_SCHEMA_VERSION = `ceal${CEAL_CLIENT_VERSION_SCHEMA_SUFFIX}`;
1207
+
975
1208
  // packages/ceal-client-protocol/src/bare-document.ts
976
1209
  var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_fields;
977
1210
  var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
978
1211
 
1212
+ // packages/ceal-client-protocol/src/actor-kind.ts
1213
+ var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
1214
+
979
1215
  // packages/ceal-client-protocol/src/resource-row.ts
980
1216
  var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
981
1217
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
@@ -990,6 +1226,8 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
990
1226
  "resource_created",
991
1227
  "review_submitted",
992
1228
  "comment_created",
1229
+ "reaction_created",
1230
+ "ceal_write_completed",
993
1231
  "event_start",
994
1232
  "all_day_start",
995
1233
  "file_created",
@@ -1024,6 +1262,10 @@ var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
1024
1262
  "github.review.submitted",
1025
1263
  "github.issue_comment.created",
1026
1264
  "github.review_comment.created",
1265
+ "github.reaction.created",
1266
+ "github.reaction.deleted",
1267
+ "github.pull_request.review_requested",
1268
+ "github.pull_request.review_request_removed",
1027
1269
  "calendar.organized",
1028
1270
  "calendar.accepted_invite",
1029
1271
  "calendar.recorded",
@@ -1045,6 +1287,10 @@ var CEAL_ACTIVITY_EVENT_TIMESTAMP_BASIS_MAP = Object.freeze({
1045
1287
  "github.pull_request.opened": "resource_created",
1046
1288
  "github.issue.edited": "resource_modified",
1047
1289
  "github.pull_request.edited": "resource_modified",
1290
+ "github.reaction.created": "reaction_created",
1291
+ "github.reaction.deleted": "ceal_write_completed",
1292
+ "github.pull_request.review_requested": "ceal_write_completed",
1293
+ "github.pull_request.review_request_removed": "ceal_write_completed",
1048
1294
  "calendar.organized": "resource_created",
1049
1295
  "drive.file.created": "file_created",
1050
1296
  "drive.file.modified": "file_modified_by_me",
@@ -1068,6 +1314,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1068
1314
  source_url: { required: false, timestamp: false },
1069
1315
  source: { required: true, timestamp: false },
1070
1316
  owner: { required: false, timestamp: false },
1317
+ actor_kind: { required: false, timestamp: false },
1071
1318
  counterparts: { required: false, timestamp: false },
1072
1319
  attachments: { required: false, timestamp: false },
1073
1320
  created_at: { required: false, timestamp: true },
@@ -1075,9 +1322,18 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1075
1322
  modified_at: { required: false, timestamp: true },
1076
1323
  modified_at_local: { required: false, timestamp: true },
1077
1324
  viewed_by_me_at: { required: false, timestamp: true },
1325
+ modified_by_me_at: { required: false, timestamp: true },
1078
1326
  own_ceal_write: { required: false, timestamp: false },
1079
1327
  owned_by_me: { required: false, timestamp: false },
1328
+ mime_type: { required: false, timestamp: false },
1329
+ size_bytes: { required: false, timestamp: false },
1330
+ version: { required: false, timestamp: false },
1331
+ trashed: { required: false, timestamp: false },
1080
1332
  visibility: { required: false, timestamp: false },
1333
+ archived: { required: false, timestamp: false },
1334
+ tag: { required: false, timestamp: false },
1335
+ labels: { required: false, timestamp: false },
1336
+ labels_incomplete: { required: false, timestamp: false },
1081
1337
  start: { required: false, timestamp: false },
1082
1338
  end: { required: false, timestamp: false },
1083
1339
  status: { required: false, timestamp: false },
@@ -1150,18 +1406,29 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1150
1406
  // The serving gate answers this while the Gateway is still starting and the
1151
1407
  // refresh was never attempted; the same attempt stays retryable. It is never
1152
1408
  // stored by the session owner, only answered at the serving edge.
1153
- "gateway_starting"
1409
+ CEAL_GATEWAY_STARTING_FAILURE_CODE
1410
+ ]);
1411
+ var CEAL_CLIENT_REVOKE_FAILURE_CODES = vocabulary([
1412
+ "refresh_invalid",
1413
+ "refresh_expired",
1414
+ "refresh_replayed",
1415
+ "refresh_revoked"
1154
1416
  ]);
1417
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX = "ceal_personal_";
1418
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX = "ceal_refresh_";
1419
+ var PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN = "[A-Za-z0-9_-]{43}";
1420
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
1421
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
1155
1422
 
1156
1423
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
1157
- import { createHash } from "node:crypto";
1424
+ import { createHash as createHash2 } from "node:crypto";
1158
1425
  var DIGEST = /^[a-f0-9]{64}$/u;
1159
1426
  var CEAL_SHA256_DIGEST_PATTERN = DIGEST.source;
1160
1427
  function isCealDigest(value) {
1161
1428
  return typeof value === "string" && DIGEST.test(value);
1162
1429
  }
1163
1430
  function cealRequestSha256(value) {
1164
- return createHash("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
1431
+ return createHash2("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
1165
1432
  }
1166
1433
  function operationRecord(value, message) {
1167
1434
  requireOperationRecord(value, message);
@@ -1177,40 +1444,71 @@ function requirePrefixedRef(value, prefix, message) {
1177
1444
  // packages/ceal-client-protocol/src/request-authority.ts
1178
1445
  var CEAL_REQUEST_SCHEMA_VERSION = "ceal.request.v1";
1179
1446
  var CEAL_REQUEST_ARTIFACT_OWNERS = vocabulary(["gateway", "host", "connector"]);
1180
- var CEAL_REQUEST_HOST_BINDING_KEYS = vocabulary(["prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
1447
+ var CEAL_HOST_INVOCATION_IDENTITY_KEYS = vocabulary(["host_session_ref", "host_turn_ref", "host_source_ref"]);
1181
1448
  var CEAL_REQUEST_ARTIFACT_RETENTION_CLASSES = vocabulary(["request", "source", "result"]);
1182
1449
  var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
1183
- 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"]);
1450
+ var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority"]);
1451
+ var CEAL_REQUEST_COMMON_PROPERTIES = Object.freeze({
1452
+ schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
1453
+ ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
1454
+ created_at: { type: "string", minLength: 1, maxLength: 64 },
1455
+ authority: {
1456
+ type: "object",
1457
+ maxProperties: 5,
1458
+ additionalProperties: false,
1459
+ properties: {
1460
+ instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1461
+ access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1462
+ principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1463
+ execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1464
+ authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1465
+ },
1466
+ required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
1467
+ }
1468
+ });
1469
+ var CEAL_REQUEST_HOST_PROPERTIES = Object.freeze({
1470
+ prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1471
+ host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1472
+ host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1473
+ host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1474
+ host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1475
+ });
1476
+ var CEAL_REQUEST_CALLER_PROPERTIES = Object.freeze({
1477
+ caller_call_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Gateway-minted call-group identity for a non-Host caller." },
1478
+ caller_call_input_sha256: { type: "string", minLength: 64, maxLength: 64, pattern: "^[a-f0-9]{64}$", description: "Commitment to the exact input for active non-Host identity-reuse checks; a migrated legacy call group commits to its legacy group key because the original input may no longer exist." }
1479
+ });
1480
+ var CEAL_REQUEST_OPTIONAL_PROPERTIES = Object.freeze({
1481
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1482
+ device_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Device that submitted this Request through its client session, including Host turns when the authenticated Host registration carries the device; absent for older records." }
1483
+ });
1484
+ var CEAL_REQUEST_HOST_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, ...CEAL_HOST_INVOCATION_IDENTITY_KEYS, "prompt_ref"]);
1485
+ var CEAL_REQUEST_CALLER_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, "caller_call_group_ref", "caller_call_input_sha256"]);
1184
1486
  var CEAL_REQUEST_JSON_SCHEMA = {
1185
1487
  type: "object",
1186
- maxProperties: 11,
1488
+ description: "A Request has exactly one creation identity: the complete Host tuple and prompt reference, or a caller call-group identity. Caller Requests retain no prompt reference or prompt body.",
1489
+ maxProperties: 13,
1187
1490
  additionalProperties: false,
1188
1491
  properties: {
1189
- schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
1190
- ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
1191
- created_at: { type: "string", minLength: 1, maxLength: 64 },
1192
- authority: {
1492
+ ...CEAL_REQUEST_COMMON_PROPERTIES,
1493
+ ...CEAL_REQUEST_HOST_PROPERTIES,
1494
+ ...CEAL_REQUEST_CALLER_PROPERTIES,
1495
+ ...CEAL_REQUEST_OPTIONAL_PROPERTIES
1496
+ },
1497
+ required: CEAL_REQUEST_KEYS,
1498
+ anyOf: [
1499
+ {
1193
1500
  type: "object",
1194
- maxProperties: 5,
1195
- additionalProperties: false,
1196
- properties: {
1197
- instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1198
- access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1199
- principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1200
- execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1201
- authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1202
- },
1203
- required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
1501
+ required: CEAL_REQUEST_HOST_REQUIRED_KEYS,
1502
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_HOST_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
1503
+ additionalProperties: false
1204
1504
  },
1205
- prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1206
- host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1207
- host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1208
- host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1209
- host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1210
- requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1211
- device_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Device that submitted this Request through its client session; absent for Host turns and older records." }
1212
- },
1213
- required: CEAL_REQUEST_KEYS
1505
+ {
1506
+ type: "object",
1507
+ required: CEAL_REQUEST_CALLER_REQUIRED_KEYS,
1508
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_CALLER_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
1509
+ additionalProperties: false
1510
+ }
1511
+ ]
1214
1512
  };
1215
1513
 
1216
1514
  // packages/ceal-client-protocol/src/request-operands.ts
@@ -1321,10 +1619,6 @@ var CEAL_REQUEST_RUN_BATCH_JSON_SCHEMA = {
1321
1619
  };
1322
1620
 
1323
1621
  // packages/ceal-client-protocol/src/host-observation.ts
1324
- var CEAL_HOST_INPUT_KINDS = vocabulary(["human", "host_automatic"]);
1325
- function isCealHostInputKind(value) {
1326
- return typeof value === "string" && CEAL_HOST_INPUT_KINDS.some((kind) => kind === value);
1327
- }
1328
1622
  var CEAL_HOST_OBSERVATION_REF_PREFIX = "host-observation:";
1329
1623
  var HOST_OBSERVATION_PRODUCER = /^[a-z][a-z0-9]{0,31}$/u;
1330
1624
  var HOST_OBSERVATION_DIGEST = /^[a-f0-9]{8,64}$/u;
@@ -1370,14 +1664,14 @@ function safeCount(value) {
1370
1664
  return Number.isSafeInteger(value) && Number(value) >= 0;
1371
1665
  }
1372
1666
  function validateCealHostObservationDraft(value) {
1373
- const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
1374
- requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
1375
- requireClosedValue(record3.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
1376
- requireIsoTimestamp(record3.observed_at, "Ceal Host observation time is invalid.");
1377
- assertHostObservationValue(record3.value, record3.observation_kind);
1667
+ const record = operationRecord(value, "Ceal Host observation draft is invalid.");
1668
+ requirePrefixedRef(record.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
1669
+ requireClosedValue(record.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
1670
+ requireIsoTimestamp(record.observed_at, "Ceal Host observation time is invalid.");
1671
+ assertHostObservationValue(record.value, record.observation_kind);
1378
1672
  }
1379
1673
  var CEAL_REQUEST_MAX_OBSERVATION_VALUE_BYTES = 64 * 1024;
1380
- var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "cost", "timing"]);
1674
+ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "timing"]);
1381
1675
  function isCealHostPromptObservationValue(value) {
1382
1676
  return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
1383
1677
  }
@@ -1500,16 +1794,41 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
1500
1794
  };
1501
1795
 
1502
1796
  // packages/ceal-client-protocol/src/host-invocation-authentication.ts
1503
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = "ceal.host_invocation_authentication_result.v1";
1504
- var CEAL_HOST_NONCE_ENCODED_CHARACTERS = 43;
1505
- var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
1506
- var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(`^ceal_context_[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
1507
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = new TextEncoder().encode(`${JSON.stringify({
1508
- schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA,
1509
- context_token: `ceal_context_${"A".repeat(CEAL_HOST_NONCE_ENCODED_CHARACTERS)}`,
1510
- expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
1511
- })}
1797
+ var hostInvocationAuthenticationContract = CEAL_CLIENT_WIRE_CONTRACT.host_invocation_authentication;
1798
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.request_schema_name, fields: hostInvocationAuthenticationContract.request_fields });
1799
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.request_fields]);
1800
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.result_schema_name, fields: hostInvocationAuthenticationContract.result_fields });
1801
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.result_fields]);
1802
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE = "^(?:0|[1-9][0-9]{0,8})$";
1803
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN = new RegExp(CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE, "u");
1804
+ var CEAL_HOST_INVOCATION_CONTEXT_REQUEST_MAX_BYTES = 16 * 1024;
1805
+ var CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_BYTES = 2 * 1024;
1806
+ var CEAL_HOST_CONTEXT_TOKEN_PREFIX = "ceal_context_";
1807
+ function deriveCealHostInvocationNonceContract(contract = CEAL_CLIENT_WIRE_CONTRACT) {
1808
+ const clientNonce = contract.host_invocation_authentication.client_nonce;
1809
+ return {
1810
+ encoded_characters: clientNonce.encoded_characters,
1811
+ client_nonce_pattern_source: `^[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`,
1812
+ context_token_pattern_source: `^${CEAL_HOST_CONTEXT_TOKEN_PREFIX}[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`
1813
+ };
1814
+ }
1815
+ var hostNonceContract = deriveCealHostInvocationNonceContract();
1816
+ var CEAL_HOST_NONCE_ENCODED_CHARACTERS = hostNonceContract.encoded_characters;
1817
+ var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(hostNonceContract.client_nonce_pattern_source, "u");
1818
+ var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(hostNonceContract.context_token_pattern_source, "u");
1819
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = deriveCealHostInvocationAuthenticationResultMaxBytes();
1820
+ function deriveCealHostInvocationAuthenticationResultMaxBytes(contract = CEAL_CLIENT_WIRE_CONTRACT) {
1821
+ const hostAuthentication = contract.host_invocation_authentication;
1822
+ const values = {
1823
+ schema_version: deriveCealClientWireSchemaVersion({ schema_name: hostAuthentication.result_schema_name, fields: hostAuthentication.result_fields }),
1824
+ context_token: `${CEAL_HOST_CONTEXT_TOKEN_PREFIX}${"A".repeat(hostAuthentication.client_nonce.encoded_characters)}`,
1825
+ expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
1826
+ };
1827
+ const fields = hostAuthentication.result_fields;
1828
+ if (fields.some((field) => !Object.hasOwn(values, field))) throw new TypeError("Host invocation result fields have no bounded sample value.");
1829
+ return new TextEncoder().encode(`${JSON.stringify(Object.fromEntries(fields.map((field) => [field, values[field]])))}
1512
1830
  `).byteLength;
1831
+ }
1513
1832
  var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
1514
1833
  "request_authority_unavailable",
1515
1834
  "request_missing",
@@ -1533,6 +1852,7 @@ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
1533
1852
  "host_credential_refused",
1534
1853
  "gateway_unavailable",
1535
1854
  "gateway_rate_limited",
1855
+ "contract_mismatch",
1536
1856
  "gateway_refused",
1537
1857
  "gateway_response_invalid",
1538
1858
  "producer_frame_invalid",
@@ -1547,19 +1867,23 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
1547
1867
  invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
1548
1868
  options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
1549
1869
  session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1550
- context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "refresh_host_invocation_context", remedy: "the Host has no invocation context from the current transcript turn; send a new message to start a fresh Host turn, then retry this command on that turn (run `ceal-host install` only if the Host hook registration is missing or drifted)" }),
1551
- context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1552
- no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
1553
- context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1554
- context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
1870
+ context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "retry" }),
1871
+ context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
1872
+ // `no_binding` now means the producer has no real current Host session. The
1873
+ // Host Relay never uses it for an uncreated Gateway Request; there is no
1874
+ // useful retry until the consumer is running inside a Host session.
1875
+ no_binding: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1876
+ context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
1877
+ context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "retry" }),
1555
1878
  host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
1556
1879
  host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
1557
1880
  gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
1558
1881
  gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
1882
+ contract_mismatch: Object.freeze({ classification: "contract_mismatch", next_action: "upgrade_ceal_client" }),
1559
1883
  gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
1560
1884
  gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
1561
- producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin", remedy: "ask an administrator to inspect and repair the producer frame, then start a fresh Host turn" }),
1562
- relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox", remedy: "an agent sandbox denied the Host Relay socket; run `ceal` as the only command, with no pipe, redirect, or `&&`, so the Host allow rule runs it outside the sandbox" }),
1885
+ producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin" }),
1886
+ relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox" }),
1563
1887
  relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
1564
1888
  transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
1565
1889
  mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
@@ -1574,10 +1898,6 @@ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
1574
1898
  "hook_invoked",
1575
1899
  "registration_written",
1576
1900
  "hook_failed",
1577
- "watcher_turn_observed",
1578
- "current_prompt_registered",
1579
- "current_prompt_registration_failed",
1580
- "current_prompt_capacity_exhausted",
1581
1901
  "activation_recorded",
1582
1902
  "activation_failed",
1583
1903
  "watcher_scan_failed",
@@ -1600,6 +1920,9 @@ var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "un
1600
1920
  var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
1601
1921
  var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
1602
1922
 
1923
+ // packages/ceal-client-protocol/src/discovery-manifest.ts
1924
+ var DISCOVERY_MANIFEST_KEYS = CEAL_CLIENT_WIRE_CONTRACT.command_response.discovery_manifest_fields;
1925
+
1603
1926
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
1604
1927
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
1605
1928
 
@@ -1658,6 +1981,7 @@ var ADMIN_UNAVAILABLE_REASONS = vocabulary([
1658
1981
  "legacy",
1659
1982
  "invalid_observation",
1660
1983
  "redacted",
1984
+ "organization_setting_disabled",
1661
1985
  "owner_unavailable",
1662
1986
  "unit_unknown",
1663
1987
  "retention_gap",
@@ -1687,15 +2011,13 @@ var ADMIN_APPROVAL_DISPOSITIONS = CEAL_OPERATION_APPROVAL_DISPOSITIONS;
1687
2011
  var ADMIN_APPROVAL_POSTURES = vocabulary([...ADMIN_APPROVAL_DISPOSITIONS, "not_applicable"]);
1688
2012
  var ADMIN_LINEAGE_NODE_KINDS = vocabulary(["source_read", "synthesis_preview", "approval", "effect", "readback"]);
1689
2013
 
1690
- // packages/ceal-client-protocol/src/actor-kind.ts
1691
- var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
1692
-
1693
2014
  // packages/ceal-client-protocol/src/device-enrollment.ts
1694
2015
  var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired", "denied"]);
1695
2016
  var POLL_RESULT_KEYS = Object.freeze(["retry_after_ms", "schema_version", "status"]);
1696
2017
 
1697
2018
  // packages/ceal-client-protocol/src/personal-client-session.ts
1698
2019
  var REFRESH_FAILURE_CODES = new Set(CEAL_REFRESH_FAILURE_CODES);
2020
+ var REVOKE_FAILURE_CODES = new Set(CEAL_CLIENT_REVOKE_FAILURE_CODES);
1699
2021
 
1700
2022
  // packages/ceal-client-protocol/src/index.ts
1701
2023
  var MAX_REQUEST_BYTES = 32 * 1024;
@@ -1705,12 +2027,11 @@ var AUDIT_IDENTITY_KEYS = Object.freeze(["event_ref", "membership_ref", "registr
1705
2027
  var FAILURE_RESPONSE_KEYS = Object.freeze(["error", "ok", "proof_ref_or_unavailable", "protocol_version", "request_id"]);
1706
2028
 
1707
2029
  // host/codex/src/codex-decoder.ts
1708
- import { createHash as createHash2 } from "node:crypto";
2030
+ import { createHash as createHash3 } from "node:crypto";
1709
2031
  import { isAbsolute, resolve } from "node:path";
1710
2032
 
1711
2033
  // host/codex/src/codex-types.ts
1712
2034
  var CODEX_OUTBOX_SCHEMA_VERSION = "ceal.codex_observation_outbox.v1";
1713
- var CODEX_TURN_BINDING_SCHEMA_VERSION = "ceal.codex_turn_binding.v1";
1714
2035
  var CODEX_SESSION_SCHEMA_VERSION = "ceal.codex_session.v1";
1715
2036
  var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1";
1716
2037
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
@@ -1738,8 +2059,8 @@ function decodeCodexHookPayload(event, raw) {
1738
2059
  if (event === "SessionStart") return decodeSession(input, event);
1739
2060
  return decodeUserPromptSubmit(input, event);
1740
2061
  }
1741
- function observationRef(event, identity, value) {
1742
- return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
2062
+ function observationRef(hostSourceRef, event, identity, value) {
2063
+ return cealHostObservationRef("codex", shortDigest({ host_source_ref: hostSourceRef, event, identity, value }));
1743
2064
  }
1744
2065
  function hostSessionReference(sourceRef, sessionId) {
1745
2066
  return `codex-session:${shortDigest({ source_ref: sourceRef, session_id: sessionId })}`;
@@ -1834,7 +2155,7 @@ function isRecord(value) {
1834
2155
  return value !== null && typeof value === "object" && !Array.isArray(value);
1835
2156
  }
1836
2157
  function sha256(value) {
1837
- return createHash2("sha256").update(value, "utf8").digest("hex");
2158
+ return createHash3("sha256").update(value, "utf8").digest("hex");
1838
2159
  }
1839
2160
  function shortDigest(value) {
1840
2161
  return cealRequestSha256(value);
@@ -1844,18 +2165,17 @@ function reject(message) {
1844
2165
  }
1845
2166
 
1846
2167
  // host/codex/src/codex-outbox.ts
1847
- import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
1848
- import { lstat as lstat2, mkdir as mkdir3, open as open3, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
1849
- import { dirname, isAbsolute as isAbsolute2, join as join3 } from "node:path";
2168
+ import { mkdir as mkdir2, open as open3, readdir, rename as rename2, stat, unlink as unlink2 } from "node:fs/promises";
2169
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2 } from "node:path";
1850
2170
 
1851
2171
  // host/invocation-context.ts
1852
- var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
2172
+ var HOST_INVOCATION_TURN_SELECTION_SCHEMA = "ceal.host_invocation_turn_selection.v1";
1853
2173
  var HOST_INVOCATION_CONTEXT_REQUIRED_KEYS = ["schema_version", "identity", "prompt_ref", "expires_at"];
1854
2174
  function invocationContextKey(identity) {
1855
2175
  return cealRequestSha256({ host_source_ref: identity.host_source_ref, host_session_ref: identity.host_session_ref });
1856
2176
  }
1857
2177
  function hasHostInvocationIdentityKeys(value) {
1858
- return exactKeys2(value, HOST_INVOCATION_IDENTITY_KEYS);
2178
+ return exactKeys2(value, CEAL_HOST_INVOCATION_IDENTITY_KEYS);
1859
2179
  }
1860
2180
  function hasHostInvocationContextKeys(value, optional = []) {
1861
2181
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
@@ -1880,456 +2200,159 @@ function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
1880
2200
  descriptor.validate(context);
1881
2201
  return Object.freeze(context);
1882
2202
  }
1883
- function isHostInvocationTurnSelection(value) {
1884
- return isRecord2(value) && Object.keys(value).length === 5 && value.schema_version === "ceal.host_invocation_turn_selection.v1" && ["host_source_ref", "host_session_ref", "prompt_ref", "turn_generation_ref"].every((key) => safeRef(value[key]));
1885
- }
1886
- function invocationTurnSelectionMatches(context, selection) {
1887
- return selection === null || context !== null && selection.host_source_ref === context.identity.host_source_ref && selection.host_session_ref === context.identity.host_session_ref && selection.prompt_ref === context.prompt_ref && selection.turn_generation_ref === context.turn_generation_ref;
1888
- }
1889
- function exactKeys2(value, keys) {
1890
- const actual = Object.keys(value);
1891
- return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
1892
- }
1893
- function requiredKeys(value, required, optional) {
1894
- const actual = Object.keys(value);
1895
- const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
1896
- return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
1897
- }
1898
- function isRecord2(value) {
1899
- return value !== null && typeof value === "object" && !Array.isArray(value);
1900
- }
1901
- function safeRef(value) {
1902
- return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
1903
- }
1904
-
1905
- // host/relay/src/producer-frame.ts
1906
- var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1907
- var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1908
- var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
1909
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1910
- var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
1911
- var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
1912
- var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
1913
- function isHostProducerFrameKind(value) {
1914
- return typeof value === "string" && FRAME_KINDS.has(value);
1915
- }
1916
- var HOST_PRODUCER_FRAME_ERROR_CODES = [
1917
- "invalid_frame_encoding",
1918
- "invalid_frame_length",
1919
- "frame_truncated",
1920
- "unsupported_frame_schema",
1921
- "invalid_frame_shape",
1922
- "invalid_producer_identity",
1923
- "frame_too_large"
1924
- ];
1925
- var HostProducerFrameError = class extends Error {
1926
- code;
1927
- constructor(code, message = code) {
1928
- super(message);
1929
- this.code = code;
1930
- }
1931
- };
1932
- function encodeHostProducerFrame(frame) {
1933
- validateFrame(frame);
1934
- const json = Buffer.from(JSON.stringify(frame), "utf8");
1935
- if (json.byteLength > HOST_PRODUCER_MAX_JSON_BYTES) throw new HostProducerFrameError("frame_too_large", `frame_too_large: ${refusalFact("frame_bytes", json.byteLength, `at most ${HOST_PRODUCER_MAX_JSON_BYTES}`)}`);
1936
- const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
1937
- result.writeUInt32BE(json.byteLength, 0);
1938
- json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
1939
- return result;
1940
- }
1941
- function decodeHostProducerFrame(input) {
1942
- if (input.byteLength < HOST_PRODUCER_FRAME_LENGTH_BYTES) throw new HostProducerFrameError("frame_truncated", `frame_truncated: ${refusalFact("frame_bytes", input.byteLength, `at least ${HOST_PRODUCER_FRAME_LENGTH_BYTES}`)}`);
1943
- const length = input.readUInt32BE(0);
1944
- if (length > HOST_PRODUCER_MAX_JSON_BYTES) throw new HostProducerFrameError("frame_too_large", `frame_too_large: ${refusalFact("declared_bytes", length, `at most ${HOST_PRODUCER_MAX_JSON_BYTES}`)}`);
1945
- if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
1946
- if (input.byteLength !== length + HOST_PRODUCER_FRAME_LENGTH_BYTES) throw new HostProducerFrameError(input.byteLength < length + HOST_PRODUCER_FRAME_LENGTH_BYTES ? "frame_truncated" : "invalid_frame_length");
1947
- const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
1948
- const text = new TextDecoder("utf-8", { fatal: true });
1949
- let value;
1950
- try {
1951
- value = JSON.parse(text.decode(bytes));
1952
- } catch (error) {
1953
- if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
1954
- throw new HostProducerFrameError("frame_truncated");
1955
- }
1956
- validateFrame(value);
1957
- return value;
1958
- }
1959
- function isHostSafeRef(value) {
1960
- return safeRef2(value);
1961
- }
1962
- function validateFrame(value) {
1963
- if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
1964
- if (value.schema_version !== HOST_PRODUCER_FRAME_SCHEMA) throw new HostProducerFrameError("unsupported_frame_schema", `unsupported_frame_schema: ${refusalFact("schema_version", value.schema_version, HOST_PRODUCER_FRAME_SCHEMA)}`);
1965
- if (!exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
1966
- if (!PRODUCERS.has(String(value.producer_id)) || !safeRef2(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
1967
- if (!positive(value.producer_epoch) || !positive(value.sequence) || !hostProducerFrameKind(value.frame_kind) || !timestamp(value.occurred_at) || !record(value.payload)) throw new HostProducerFrameError("invalid_frame_shape");
1968
- validatePayload(value.frame_kind, value.payload);
1969
- }
1970
- function validatePayload(kind, value) {
1971
- const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
1972
- if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
1973
- }
1974
- function validSession(value) {
1975
- return exactOptional(value, ["local_session_ref", "working_directory_ref"], ["model", "host_version", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.working_directory_ref) && optionalText(value.model, 256) && optionalText(value.host_version, 256) && validObservations(value.observations);
1976
- }
1977
- function validTurn(value) {
1978
- return exactOptional(value, ["local_session_ref", "local_turn_ref"], ["model", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && optionalText(value.model, 256) && validObservations(value.observations);
1979
- }
1980
- function validInput(value) {
1981
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "local_input_ref", "input_kind", "origin_input", "observations"], ["local_turn_aliases", "context_expires_at"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && safeRef2(value.local_input_ref) && validInputObservations(value.observations) && isCealHostInputKind(value.input_kind) && typeof value.origin_input === "boolean" && validInputOptionals(value);
1982
- }
1983
- function validInputObservations(value) {
1984
- return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
1985
- }
1986
- function validInputOptionals(value) {
1987
- return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp(value.context_expires_at));
1988
- }
1989
- function validTerminal(value) {
1990
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "terminal_state"], ["abort_reason", "duration_ms", "time_to_first_token_ms", "usage", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && validTerminalDisposition(value.terminal_state, value.abort_reason) && optionalNonNegative(value.duration_ms) && optionalNonNegative(value.time_to_first_token_ms) && (value.usage === void 0 || jsonValue(value.usage)) && validObservations(value.observations);
1991
- }
1992
- function validTerminalDisposition(state, reason) {
1993
- return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef2(reason));
1994
- }
1995
- function validStatus(value) {
1996
- return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef2(value.reason_code) && optionalText(value.detail, 4096);
1997
- }
1998
- function optionalText(value, maxLength) {
1999
- return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
2000
- }
2001
- function optionalNonNegative(value) {
2002
- return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
2003
- }
2004
- function optionalRefs(value) {
2005
- return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef2);
2006
- }
2007
- function validObservations(value) {
2008
- if (value === void 0) return true;
2009
- if (!Array.isArray(value) || value.length > 32) return false;
2010
- return value.every((item) => {
2011
- try {
2012
- validateCealHostObservationDraft(item);
2013
- return true;
2014
- } catch {
2015
- return false;
2016
- }
2017
- });
2018
- }
2019
- function jsonValue(value, depth = 0) {
2020
- if (depth > 16) return false;
2021
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2022
- if (typeof value === "number") return Number.isFinite(value);
2023
- if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
2024
- return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
2025
- }
2026
- function record(value) {
2027
- return value !== null && typeof value === "object" && !Array.isArray(value);
2028
- }
2029
- function safeRef2(value) {
2030
- return typeof value === "string" && SAFE_REF3.test(value);
2031
- }
2032
- function positive(value) {
2033
- return Number.isSafeInteger(value) && Number(value) > 0;
2034
- }
2035
- function timestamp(value) {
2036
- return typeof value === "string" && Number.isFinite(Date.parse(value));
2037
- }
2038
- function hostProducerFrameKind(value) {
2039
- return isHostProducerFrameKind(value);
2040
- }
2041
- function exactKeys3(value, keys) {
2042
- return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
2043
- }
2044
- function exactOptional(value, required, optional) {
2045
- const keys = Object.keys(value);
2046
- return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2047
- }
2048
-
2049
- // host/relay/src/host-producer-core.ts
2050
- import { createHash as createHash3 } from "node:crypto";
2051
- import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
2052
- import { mkdir as mkdir2, open as open2, readFile, rename as rename2, writeFile } from "node:fs/promises";
2053
- import { join as join2 } from "node:path";
2054
-
2055
- // host/relay/src/relay-ipc.ts
2056
- import { createConnection, createServer } from "node:net";
2057
-
2058
- // host/relay/src/durable-atomic-replacement.ts
2059
- import { O_RDONLY } from "node:constants";
2060
- import { lstat, mkdir, open, rename, unlink } from "node:fs/promises";
2061
- var DEFAULT_PORT = {
2062
- platform: process.platform,
2063
- mkdir: (path, options) => mkdir(path, options),
2064
- lstat: (path) => lstat(path),
2065
- open_file: (path) => open(path, "wx", 384),
2066
- rename,
2067
- unlink,
2068
- open_directory: (path) => open(path, O_RDONLY),
2069
- unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2070
- };
2071
-
2072
- // host/relay/src/relay-request-binding-store.ts
2073
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
2074
-
2075
- // host/relay/src/current-prompt-custody.ts
2076
- var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2077
-
2078
- // host/service-log.ts
2079
- function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
2080
- const line = `${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {}, ...event === "watcher_scan_failed" && cause !== void 0 ? { cause } : {} })}
2081
- `;
2082
- try {
2083
- (sink ?? defaultHostServiceDiagnosticSink)(line);
2084
- } catch {
2085
- }
2086
- }
2087
- function defaultHostServiceDiagnosticSink(line) {
2088
- process.stderr.write(line);
2089
- }
2090
- var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
2091
- var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
2092
-
2093
- // host/relay/src/relay-ipc.ts
2094
- var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
2095
- "schema_version",
2096
- "producer_id",
2097
- "producer_installation_ref",
2098
- "local_session_ref",
2099
- "local_turn_ref",
2100
- "local_turn_aliases",
2101
- "prompt_ref",
2102
- "request_ref",
2103
- "bound_at",
2104
- "host_source_ref",
2105
- "host_session_ref",
2106
- "host_turn_ref",
2107
- "host_input_ref"
2108
- ]);
2109
- var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
2110
- var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2111
- var HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA = "ceal.host_relay_current_prompt_release.v1";
2112
- var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2113
- var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2114
- var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
2115
- var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
2116
- "context_stale",
2117
- "context_expired",
2118
- "host_source_refused",
2119
- "host_credential_refused",
2120
- "gateway_unavailable",
2121
- "gateway_refused",
2122
- "gateway_response_invalid",
2123
- "gateway_rate_limited",
2124
- "producer_frame_invalid",
2125
- "deadline",
2126
- "cancelled",
2127
- "mint_failed",
2128
- "relay_failed",
2129
- "request_authority_unavailable",
2130
- "request_missing",
2131
- "authority_mismatch",
2132
- "host_source_mismatch",
2133
- "host_session_mismatch",
2134
- "host_turn_mismatch",
2135
- "host_input_mismatch",
2136
- "host_prompt_mismatch"
2137
- ]);
2138
- var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
2139
- "context_stale",
2140
- "context_expired",
2141
- "host_source_refused",
2142
- "host_credential_refused",
2143
- "gateway_unavailable",
2144
- "gateway_rate_limited",
2145
- "gateway_refused",
2146
- "gateway_response_invalid",
2147
- "producer_frame_invalid"
2148
- ]);
2149
- var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
2150
- var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2151
- "permission_denied",
2152
- "socket_missing",
2153
- "connection_refused",
2154
- "closed_early",
2155
- "response_invalid",
2156
- "timed_out",
2157
- "cancelled",
2158
- "unavailable"
2159
- ]);
2160
- var HostRelayIpcError = class extends Error {
2161
- code;
2162
- /** Set only when the client-side socket exchange itself failed. */
2163
- failure;
2164
- constructor(code, message = code, failure) {
2203
+ function isHostInvocationTurnSelection(value) {
2204
+ return isRecord2(value) && Object.keys(value).length === 5 && value.schema_version === HOST_INVOCATION_TURN_SELECTION_SCHEMA && ["host_source_ref", "host_session_ref", "prompt_ref", "turn_generation_ref"].every((key) => safeRef(value[key]));
2205
+ }
2206
+ function exactKeys2(value, keys) {
2207
+ const actual = Object.keys(value);
2208
+ return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
2209
+ }
2210
+ function requiredKeys(value, required, optional) {
2211
+ const actual = Object.keys(value);
2212
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
2213
+ return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
2214
+ }
2215
+ function isRecord2(value) {
2216
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2217
+ }
2218
+ function safeRef(value) {
2219
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2220
+ }
2221
+
2222
+ // host/relay/src/producer-frame.ts
2223
+ var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2224
+ var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "turn_terminal", "producer_status"];
2225
+ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
2226
+ var HOST_PRODUCER_FRAME_ERROR_CODES = [
2227
+ "invalid_frame_encoding",
2228
+ "invalid_frame_length",
2229
+ "frame_truncated",
2230
+ "unsupported_frame_schema",
2231
+ "invalid_frame_shape",
2232
+ "invalid_producer_identity",
2233
+ "frame_too_large"
2234
+ ];
2235
+
2236
+ // host/relay/src/host-producer-core.ts
2237
+ import { createHash as createHash4 } from "node:crypto";
2238
+
2239
+ // host/secure-file.ts
2240
+ import { execFile } from "node:child_process";
2241
+ import { constants } from "node:fs";
2242
+ import { lstat, open } from "node:fs/promises";
2243
+ import { dirname, win32 } from "node:path";
2244
+ import { fileURLToPath } from "node:url";
2245
+ var SecureFileCustodyError = class extends Error {
2246
+ name = "SecureFileCustodyError";
2247
+ reason;
2248
+ constructor(reason, message) {
2165
2249
  super(message);
2166
- this.code = code;
2167
- this.failure = failure;
2250
+ this.reason = reason;
2168
2251
  }
2169
- };
2170
- var HostRelayCurrentPromptCapacityRefusal = class extends Error {
2171
- constructor() {
2172
- super("current_prompt_capacity_exhausted");
2173
- this.name = "HostRelayCurrentPromptCapacityRefusal";
2174
- }
2175
- };
2176
- function hostRelayExchangeFailure(error) {
2177
- return error instanceof HostRelayIpcError ? error.failure : void 0;
2178
- }
2179
- function socketErrorFailure(error) {
2180
- switch (errorCode(error)) {
2181
- case "EACCES":
2182
- case "EPERM":
2183
- return "permission_denied";
2184
- case "ENOENT":
2185
- return "socket_missing";
2186
- case "ECONNREFUSED":
2187
- return "connection_refused";
2188
- default:
2189
- return "unavailable";
2190
- }
2191
- }
2192
- var HostRelayIpcAdmissionPort = class {
2193
- endpoint;
2194
- timeout_ms;
2195
- constructor(endpoint, timeoutMs = 5e3) {
2196
- this.endpoint = endpoint;
2197
- this.timeout_ms = timeoutMs;
2198
- }
2199
- async admit(frame) {
2200
- const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
2201
- if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
2202
- return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
2252
+ get code() {
2253
+ if (this.reason === "reparse_point") return "ELOOP";
2254
+ if (this.reason === "not_found") return "ENOENT";
2255
+ if (this.reason === "too_large") return "secure_file_too_large";
2256
+ if (this.reason === "already_exists") return "EEXIST";
2257
+ return this.reason === "not_private" ? "secure_file_not_private" : "secure_file_unavailable";
2203
2258
  }
2204
2259
  };
2205
- var HostRelayCurrentPromptPort = class {
2206
- endpoint;
2207
- timeout_ms;
2208
- constructor(endpoint, timeoutMs = 5e3) {
2209
- this.endpoint = endpoint;
2210
- this.timeout_ms = timeoutMs;
2211
- }
2212
- async register(input) {
2213
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
2214
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2215
- if (response2.status === "capacity_exhausted") throw new HostRelayCurrentPromptCapacityRefusal();
2216
- if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
2217
- }
2218
- async release(identity) {
2219
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA, ...identity };
2220
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2221
- if (response2.status !== "released") throw new HostRelayIpcError("relay_unavailable", response2.status, "response_invalid");
2260
+ var WINDOWS_SECUREFS_REFUSAL_SCHEMA = "ceal.host_securefs_refusal.v1";
2261
+ var WINDOWS_SECUREFS_TIMEOUT_MS = 1e4;
2262
+ var WINDOWS_SECUREFS_DIAGNOSTIC_BYTES = 4096;
2263
+ function secureOpenFlags(flags, platform) {
2264
+ if (platform === "win32") return flags;
2265
+ const nofollow = constants.O_NOFOLLOW;
2266
+ if (typeof nofollow === "number" && nofollow !== 0) return flags | nofollow;
2267
+ throw new Error("Secure file reads require O_NOFOLLOW on this platform.");
2268
+ }
2269
+ async function openNoFollow(path, flags = constants.O_RDONLY, mode, platform = process.platform, _custody = {}) {
2270
+ if (platform !== "win32") return await open(path, secureOpenFlags(flags, platform), mode);
2271
+ return await openWindowsIdentityScreened(path, flags, mode);
2272
+ }
2273
+ async function openWindowsIdentityScreened(path, flags, mode) {
2274
+ const handle = await open(path, flags, mode);
2275
+ try {
2276
+ const first = await handle.stat();
2277
+ if (!first.isFile()) throw new SecureFileCustodyError("not_private", "The Windows Host file is not a regular file.");
2278
+ await assertWindowsLinkFree(path, first);
2279
+ await assertWindowsIdentityStable(handle, first, path);
2280
+ return handle;
2281
+ } catch (error) {
2282
+ await handle.close();
2283
+ throw error;
2222
2284
  }
2223
- };
2224
- function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
2225
- return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
2226
- }
2227
- function exchange(endpoint, encoded, timeoutMs, decode, signal) {
2228
- return new Promise((resolve3, reject3) => {
2229
- const socket = createConnection(endpoint);
2230
- let buffer = Buffer.alloc(0);
2231
- let settled = false;
2232
- const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
2233
- const finish = (error, response2) => {
2234
- if (settled) return;
2235
- settled = true;
2236
- signal?.removeEventListener("abort", aborted);
2237
- socket.destroy();
2238
- if (error !== null) reject3(error);
2239
- else if (response2 !== void 0) resolve3(response2);
2240
- };
2241
- if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
2242
- if (signal?.aborted === true) {
2243
- aborted();
2244
- return;
2245
- }
2246
- signal?.addEventListener("abort", aborted, { once: true });
2247
- socket.once("error", (error) => {
2248
- const failure = socketErrorFailure(error);
2249
- finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure}.`, failure));
2250
- });
2251
- socket.once("connect", () => socket.write(encoded));
2252
- socket.on("data", (chunk) => {
2253
- try {
2254
- buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
2255
- const decoded = decode(buffer);
2256
- if (decoded !== null) finish(null, decoded);
2257
- } catch (error) {
2258
- finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
2285
+ }
2286
+ async function assertWindowsLinkFree(path, first) {
2287
+ const entry = await lstat(path);
2288
+ if (entry.isSymbolicLink() || entry.dev !== first.dev || entry.ino !== first.ino) {
2289
+ throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
2290
+ }
2291
+ }
2292
+ async function assertWindowsIdentityStable(handle, first, path) {
2293
+ const second = await handle.stat();
2294
+ if (second.dev !== first.dev || second.ino !== first.ino || second.size !== first.size || second.mtimeMs !== first.mtimeMs) {
2295
+ throw new SecureFileCustodyError("unavailable", "The Windows Host file changed while its identity was checked.");
2296
+ }
2297
+ const entry = await lstat(path);
2298
+ if (entry.isSymbolicLink()) throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
2299
+ if (entry.dev !== second.dev || entry.ino !== second.ino) throw new SecureFileCustodyError("unavailable", "The Windows Host file path no longer names the opened file.");
2300
+ }
2301
+ async function readPrivateFileWithSecurefs(path, maxBytes, custody = {}) {
2302
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new TypeError("The securefs read bound must be a positive safe integer.");
2303
+ const result = await runWindowsSecurefs(["internal", "securefs", "read-private-file", path, String(maxBytes)], maxBytes, custody);
2304
+ if (result.exit_code === 0 && result.stderr.length === 0 && result.stdout.length <= maxBytes) return result.stdout;
2305
+ if (result.stdout.length !== 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned bytes with a refusal.");
2306
+ if (result.exit_code === 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command exceeded its output contract.");
2307
+ throw securefsRefusal(result.stderr);
2308
+ }
2309
+ async function runWindowsSecurefs(args, maxBytes, custody) {
2310
+ if (custody.run_securefs_command !== void 0) return await custody.run_securefs_command(args);
2311
+ const executable = custody.securefs_executable ?? resolveInstalledHostExecutable();
2312
+ const processArgs = [...custody.securefs_args_prefix ?? [], ...args];
2313
+ return await new Promise((resolve3, reject3) => {
2314
+ execFile(executable, processArgs, { encoding: "buffer", timeout: WINDOWS_SECUREFS_TIMEOUT_MS, maxBuffer: maxBytes + WINDOWS_SECUREFS_DIAGNOSTIC_BYTES }, (error, stdout, stderr) => {
2315
+ const exitCode = error === null ? 0 : typeof error.code === "number" ? error.code : null;
2316
+ if (exitCode === null) {
2317
+ reject3(new SecureFileCustodyError("unavailable", "The installed Windows Host securefs command could not run."));
2318
+ return;
2259
2319
  }
2260
- });
2261
- socket.once("end", () => {
2262
- if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
2320
+ resolve3({ exit_code: exitCode, stdout: Buffer.from(stdout), stderr: Buffer.from(stderr) });
2263
2321
  });
2264
2322
  });
2265
2323
  }
2266
- function decodeHostRelayIpcResponse(input) {
2267
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response is truncated: ${refusalFact("response_bytes", input.byteLength, `at least ${HOST_RELAY_IPC_LENGTH_BYTES}`)}.`);
2268
- const length = input.readUInt32BE(0);
2269
- if (length === 0 || length > HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES || input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response length is invalid: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `between 1 and ${HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2324
+ function securefsRefusal(stderr) {
2270
2325
  let value;
2271
2326
  try {
2272
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2327
+ value = JSON.parse(stderr.toString("utf8"));
2273
2328
  } catch {
2274
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
2329
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned an unreadable refusal.");
2275
2330
  }
2276
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
2277
- return value;
2331
+ if (!isRecord3(value) || value.schema_version !== WINDOWS_SECUREFS_REFUSAL_SCHEMA || typeof value.code !== "string") return new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned an unreadable refusal.");
2332
+ if (value.code === "reparse_point") return new SecureFileCustodyError("reparse_point", "The Windows Host securefs file is a reparse point.");
2333
+ if (value.code === "not_found") return new SecureFileCustodyError("not_found", "The Windows Host securefs file was not found.");
2334
+ if (value.code === "too_large") return new SecureFileCustodyError("too_large", "The Windows Host securefs file exceeds its read bound.");
2335
+ if (value.code === "already_exists") return new SecureFileCustodyError("already_exists", "The Windows Host securefs target already exists.");
2336
+ if (value.code === "not_private") return new SecureFileCustodyError("not_private", "The Windows Host securefs file is not private to the current user.");
2337
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command refused the file read.");
2278
2338
  }
2279
- function relayAdmissionCode(value) {
2280
- return value === "admitted" || value === "already_admitted" || value === "producer_epoch_stale" || value === "sequence_gap" || value === "frame_identity_conflict" || value === "producer_queue_full" || value === "relay_queue_full" || value === "producer_already_connected" || value === "invalid_producer_identity";
2281
- }
2282
- function validResponse(value) {
2283
- return record2(value) && value.schema_version === HOST_RELAY_IPC_RESPONSE_SCHEMA && hostRelayIpcCode(value.code) && nonnegative(value.admitted_through_sequence) && nonnegative(value.delivered_through_sequence) && Object.keys(value).length === 4;
2284
- }
2285
- function hostRelayIpcCode(value) {
2286
- return typeof value === "string" && ["admitted", "already_admitted", "producer_epoch_stale", "sequence_gap", "frame_identity_conflict", "producer_queue_full", "relay_queue_full", "invalid_frame_encoding", "invalid_frame_length", "frame_truncated", "unsupported_frame_schema", "invalid_frame_shape", "invalid_producer_identity", "frame_too_large", "producer_already_connected", "relay_unavailable"].includes(value);
2287
- }
2288
- function nonnegative(value) {
2289
- return Number.isSafeInteger(value) && Number(value) >= 0;
2339
+ function resolveInstalledHostExecutable() {
2340
+ const privateRuntimeRoot = dirname(fileURLToPath(import.meta.url));
2341
+ return win32.join(privateRuntimeRoot, "..", "..", "bin", "ceal-host.exe");
2290
2342
  }
2291
- function record2(value) {
2343
+ function isRecord3(value) {
2292
2344
  return value !== null && typeof value === "object" && !Array.isArray(value);
2293
2345
  }
2294
- function decodeResponseBuffer(buffer) {
2295
- if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2296
- const length = buffer.readUInt32BE(0);
2297
- if (length === 0 || length > HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES}`)}.`);
2298
- if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2299
- if (buffer.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC returned trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: buffer.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2300
- return decodeHostRelayIpcResponse(buffer);
2301
- }
2302
- function decodeCurrentPromptResponseBuffer(buffer) {
2303
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
2304
- if (value === null) return null;
2305
- if (!record2(value) || !exactKeys4(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "capacity_exhausted" && value.status !== "current_prompt_unavailable" && value.status !== "released") throw new HostRelayIpcError("relay_unavailable", "Host Relay current-prompt response is invalid.", "response_invalid");
2306
- return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
2307
- }
2308
- function decodeLengthPrefixedJson(input, maximum) {
2309
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2310
- const length = input.readUInt32BE(0);
2311
- if (length === 0 || length > maximum) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${maximum}`)}.`);
2312
- if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2313
- if (input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message has trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2314
- try {
2315
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2316
- } catch {
2317
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
2318
- }
2319
- }
2320
- function encodeLengthPrefixed(value) {
2321
- const body = Buffer.from(JSON.stringify(value), "utf8");
2322
- const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
2323
- output.writeUInt32BE(body.length, 0);
2324
- body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
2325
- return output;
2346
+ function isOwnedBy(uid, expectedUid) {
2347
+ return Number.isSafeInteger(uid) && Number.isSafeInteger(expectedUid) && uid === expectedUid;
2326
2348
  }
2327
- function exactKeys4(value, required, optional = []) {
2328
- const keys = Object.keys(value);
2329
- return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2349
+ function isSelfOwned(uid, platform = process.platform, _handle) {
2350
+ if (platform === "win32" || typeof process.geteuid !== "function") return false;
2351
+ return isOwnedBy(uid, process.geteuid());
2330
2352
  }
2331
- function errorCode(error) {
2332
- return record2(error) && typeof error.code === "string" ? error.code : null;
2353
+ function isPrivateFileMode(mode, platform = process.platform, _handle) {
2354
+ if (platform === "win32") return false;
2355
+ return (mode & 63) === 0;
2333
2356
  }
2334
2357
 
2335
2358
  // host/relay/src/host-producer-core.ts
@@ -2339,6 +2362,7 @@ function isHostTranscriptCursorReason(value) {
2339
2362
  }
2340
2363
  var TRANSCRIPT_MISSING_REASON = "transcript_missing";
2341
2364
  var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
2365
+ var HOST_INVOCATION_TRANSCRIPT_TAIL_MAX_BYTES = 1024 * 1024;
2342
2366
  function transcriptScanFailureKind(error, adapterFailureKind) {
2343
2367
  if (transcriptErrorCode(error) === "ELOOP") return "symlink";
2344
2368
  const adapter = adapterFailureKind(error);
@@ -2348,16 +2372,6 @@ function transcriptScanFailureKind(error, adapterFailureKind) {
2348
2372
  if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
2349
2373
  return "other";
2350
2374
  }
2351
- async function registerHostCurrentPromptDiagnosed(register, diagnostic) {
2352
- try {
2353
- await register();
2354
- diagnostic("current_prompt_registered");
2355
- return true;
2356
- } catch (error) {
2357
- if (!(error instanceof HostRelayCurrentPromptCapacityRefusal)) diagnostic("current_prompt_registration_failed");
2358
- throw error;
2359
- }
2360
- }
2361
2375
  function transcriptErrorCode(error) {
2362
2376
  return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
2363
2377
  }
@@ -2405,10 +2419,10 @@ async function transcriptCursorBoundsReason(handle, cursor, size) {
2405
2419
  return null;
2406
2420
  }
2407
2421
  function transcriptSha256(value) {
2408
- return createHash3("sha256").update(value).digest("hex");
2422
+ return createHash4("sha256").update(value).digest("hex");
2409
2423
  }
2410
2424
  function transcriptObjectSha256(value) {
2411
- return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2425
+ return createHash4("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2412
2426
  }
2413
2427
  function isTranscriptRecord(value) {
2414
2428
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -2469,24 +2483,18 @@ var HostTranscriptWatcher = class {
2469
2483
  return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
2470
2484
  }
2471
2485
  async scanRegistration(registration) {
2472
- try {
2473
- return await this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2474
- missing: () => this.retireMissing(registration),
2475
- failed: (handle, error) => this.scanFailed(handle, registration, error)
2476
- });
2477
- } catch (error) {
2478
- if (error instanceof HostRelayCurrentPromptCapacityRefusal) return { records: 0, enqueued: 0, quarantined: false };
2479
- throw error;
2480
- }
2486
+ return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2487
+ missing: () => this.retireMissing(registration),
2488
+ failed: (handle, error) => this.scanFailed(handle, registration, error)
2489
+ });
2481
2490
  }
2482
2491
  async openTranscript(registration, scan, handlers) {
2483
2492
  let handle;
2484
2493
  try {
2485
- handle = await open2(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
2494
+ handle = await openNoFollow(this.transcriptPathOf(registration));
2486
2495
  return await scan(handle);
2487
2496
  } catch (error) {
2488
2497
  if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
2489
- if (hostRelayExchangeFailure(error) !== void 0 || error instanceof HostRelayCurrentPromptCapacityRefusal) throw error;
2490
2498
  return handlers.failed(handle, error);
2491
2499
  } finally {
2492
2500
  await handle?.close();
@@ -2532,29 +2540,12 @@ var HostTranscriptWatcher = class {
2532
2540
  return transcriptCursorBoundsReason(handle, cursor, size);
2533
2541
  }
2534
2542
  };
2535
- var HOST_PRODUCER_STATE_IDENTITY = {
2536
- codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
2537
- claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
2538
- };
2539
2543
  var HostProducerDrainCore = class {
2540
2544
  host;
2541
- relay;
2542
- statePath;
2543
- stateSchema;
2544
- installationRef;
2545
- epoch;
2546
2545
  now;
2547
2546
  tail = Promise.resolve();
2548
2547
  constructor(host, runtime) {
2549
- if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
2550
- const epoch = runtime.producer_epoch ?? 1;
2551
- if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
2552
2548
  this.host = host;
2553
- this.relay = runtime.relay;
2554
- this.statePath = join2(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
2555
- this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
2556
- this.installationRef = runtime.producer_installation_ref;
2557
- this.epoch = epoch;
2558
2549
  this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
2559
2550
  }
2560
2551
  drainOutbox() {
@@ -2564,118 +2555,29 @@ var HostProducerDrainCore = class {
2564
2555
  }
2565
2556
  async drainLocked() {
2566
2557
  const read = await this.host.listEnvelopes();
2567
- let admitted = 0;
2558
+ let removed = 0;
2568
2559
  let expired = 0;
2569
- let retained = 0;
2570
2560
  for (const envelope of read.entries) {
2571
- const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
2572
- if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
2573
- await this.host.removeEnvelope(envelope);
2574
- expired += 1;
2575
- continue;
2576
- }
2577
- const frames = await this.reserve(envelope);
2578
- let complete = true;
2579
- for (const frame of frames) {
2580
- const outcome = await this.relay.admit(frame);
2581
- if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
2582
- complete = false;
2583
- break;
2584
- }
2585
- }
2586
- if (!complete) {
2587
- retained += 1;
2588
- break;
2589
- }
2561
+ if (Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) expired += 1;
2562
+ else removed += 1;
2590
2563
  await this.host.removeEnvelope(envelope);
2591
- await this.release(this.host.submissionRefOf(envelope));
2592
- admitted += 1;
2593
- }
2594
- return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
2595
- }
2596
- async hasReservation(submissionRef) {
2597
- return (await this.readState()).pending[submissionRef] !== void 0;
2598
- }
2599
- async reserve(envelope) {
2600
- const state = await this.readState();
2601
- const submissionRef = this.host.submissionRefOf(envelope);
2602
- const existing = state.pending[submissionRef];
2603
- if (existing !== void 0) return existing;
2604
- const drafts = await this.host.mapEnvelope(envelope);
2605
- const frames = drafts.map((draft, offset) => ({
2606
- schema_version: "ceal.host_producer_frame.v1",
2607
- producer_id: this.host.producer_id,
2608
- producer_installation_ref: this.installationRef,
2609
- producer_epoch: this.epoch,
2610
- sequence: state.next_sequence + offset,
2611
- frame_kind: draft.frame_kind,
2612
- occurred_at: this.host.createdAtOf(envelope),
2613
- payload: draft.payload
2614
- }));
2615
- await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
2616
- return frames;
2617
- }
2618
- async release(submissionRef) {
2619
- const state = await this.readState();
2620
- if (state.pending[submissionRef] === void 0) return;
2621
- const pending = { ...state.pending };
2622
- delete pending[submissionRef];
2623
- await this.writeState({ ...state, pending });
2624
- }
2625
- async readState() {
2626
- try {
2627
- const value = JSON.parse(await readFile(this.statePath, "utf8"));
2628
- return this.decodeState(value);
2629
- } catch (error) {
2630
- if (errorCode2(error) !== "ENOENT") throw error;
2631
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
2632
- }
2633
- }
2634
- async writeState(state) {
2635
- await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
2636
- const temporary = `${this.statePath}.${process.pid}.new`;
2637
- await writeFile(temporary, JSON.stringify(state), { mode: 384 });
2638
- await rename2(temporary, this.statePath);
2639
- }
2640
- decodeState(value) {
2641
- const label = this.host.producer_label;
2642
- const fail = (code, message) => this.host.fail(code, message);
2643
- if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
2644
- throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
2645
- { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
2646
- { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
2647
- ])}).`);
2648
- }
2649
- if (Number(value.producer_epoch) > this.epoch) throw fail("storage", `${label} producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${this.epoch}`)}).`);
2650
- const pending = {};
2651
- const storedEpoch = Number(value.producer_epoch);
2652
- for (const [submissionRef, frames] of Object.entries(value.pending)) {
2653
- if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
2654
- pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
2655
2564
  }
2656
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
2657
- }
2658
- decodeStoredFrame(value, storedEpoch) {
2659
- const label = this.host.producer_label;
2660
- const json = Buffer.from(JSON.stringify(value), "utf8");
2661
- const encoded = Buffer.allocUnsafe(json.length + 4);
2662
- encoded.writeUInt32BE(json.length, 0);
2663
- json.copy(encoded, 4);
2664
- const frame = decodeHostProducerFrame(encoded);
2665
- if (frame.producer_id !== this.host.producer_id || frame.producer_installation_ref !== this.installationRef || frame.producer_epoch > storedEpoch) throw this.host.fail("storage", `${label} producer pending frame identity is malformed (${refusalFacts([
2666
- { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
2667
- { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
2668
- { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
2669
- ])}).`);
2670
- return frame;
2565
+ return { removed, expired, malformed: read.malformed };
2671
2566
  }
2672
2567
  };
2673
- function isDrainStateHeader(value, schema, installationRef) {
2674
- return isTranscriptRecord(value) && value.schema_version === schema && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isTranscriptRecord(value.pending);
2675
- }
2676
- function errorCode2(error) {
2677
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
2678
- }
2568
+
2569
+ // host/relay/src/durable-atomic-replacement.ts
2570
+ import { lstat as lstat2, mkdir, open as open2, rename, unlink } from "node:fs/promises";
2571
+ var DEFAULT_PORT = {
2572
+ platform: process.platform,
2573
+ mkdir: (path, options) => mkdir(path, options),
2574
+ lstat: (path) => lstat2(path),
2575
+ open_file: (path) => open2(path, "wx", 384),
2576
+ rename,
2577
+ unlink,
2578
+ open_directory: (path) => open2(path),
2579
+ unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2580
+ };
2679
2581
 
2680
2582
  // host/relay/src/relay-quarantine-store.ts
2681
2583
  var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
@@ -2687,11 +2589,21 @@ var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, produ
2687
2589
  var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
2688
2590
  var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
2689
2591
 
2690
- // host/relay/src/relay-gateway-bridge.ts
2691
- var HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS = ["created", "adopted", "replayed", "approval_approved", "approval_denied", "approval_replayed"];
2692
- function isHostGatewayAcknowledgementDisposition(value) {
2693
- return typeof value === "string" && HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS.some((disposition) => disposition === value);
2694
- }
2592
+ // host/relay/src/relay-pipe-handshake.ts
2593
+ var RELAY_PIPE_FRAME_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2594
+
2595
+ // host/relay/src/relay-ipc.ts
2596
+ var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2597
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2598
+ "permission_denied",
2599
+ "socket_missing",
2600
+ "connection_refused",
2601
+ "closed_early",
2602
+ "response_invalid",
2603
+ "timed_out",
2604
+ "cancelled",
2605
+ "unavailable"
2606
+ ]);
2695
2607
 
2696
2608
  // host/codex/src/codex-invocation-context.ts
2697
2609
  function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
@@ -2705,59 +2617,40 @@ function validateCodexHostInvocationContext(value) {
2705
2617
  validateContextReferences(value);
2706
2618
  validateContextTimes(value);
2707
2619
  }
2708
- function invocationContextFromBinding(binding, turnGenerationRef) {
2709
- const context = {
2710
- schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
2711
- identity: binding.identity,
2712
- prompt_ref: binding.prompt_ref,
2713
- request_ref: binding.request_ref,
2714
- bound_at: binding.bound_at,
2715
- expires_at: binding.expires_at,
2716
- ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
2717
- };
2718
- validateCodexHostInvocationContext(context);
2719
- return Object.freeze(context);
2720
- }
2721
2620
  function validateIdentity(value) {
2722
- if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
2621
+ if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef2)) {
2723
2622
  throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
2724
2623
  }
2725
2624
  }
2726
2625
  function isContextShape(value) {
2727
- return isRecord3(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2626
+ return isRecord4(value) && hasHostInvocationContextKeys(value, ["turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2728
2627
  }
2729
2628
  function validateContextReferences(value) {
2730
- if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2629
+ if (!safeRef2(value.prompt_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2731
2630
  }
2732
2631
  function validateContextTimes(value) {
2733
2632
  const expiresAt = value.expires_at;
2734
- const boundAt = value.bound_at;
2735
- if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2736
- if (typeof boundAt === "string" && Date.parse(boundAt) > Date.parse(expiresAt)) throw new CodexHostAdapterError("storage", `Codex Host invocation context has invalid binding time (${refusalFact("bound_at", boundAt, `at or before ${expiresAt}`)}).`);
2633
+ if (!timestamp(expiresAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2737
2634
  }
2738
2635
  function optionalSafeRef(value) {
2739
- return value === void 0 || safeRef3(value);
2740
- }
2741
- function optionalTimestamp(value) {
2742
- return value === void 0 || timestamp2(value);
2636
+ return value === void 0 || safeRef2(value);
2743
2637
  }
2744
- function safeRef3(value) {
2638
+ function safeRef2(value) {
2745
2639
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2746
2640
  }
2747
- function timestamp2(value) {
2641
+ function timestamp(value) {
2748
2642
  return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
2749
2643
  }
2750
- function isRecord3(value) {
2644
+ function isRecord4(value) {
2751
2645
  return value !== null && typeof value === "object" && !Array.isArray(value);
2752
2646
  }
2753
2647
 
2754
2648
  // host/codex/src/codex-outbox.ts
2755
- var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2649
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2756
2650
  var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
2757
2651
  var CodexOutboxStore = class {
2758
2652
  directory;
2759
2653
  entriesDirectory;
2760
- bindingsDirectory;
2761
2654
  sessionsDirectory;
2762
2655
  activeContextsDirectory;
2763
2656
  turnSelectionsDirectory;
@@ -2766,17 +2659,16 @@ var CodexOutboxStore = class {
2766
2659
  constructor(directory) {
2767
2660
  if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
2768
2661
  this.directory = directory;
2769
- this.entriesDirectory = join3(directory, "entries");
2770
- this.bindingsDirectory = join3(directory, "bindings");
2771
- this.sessionsDirectory = join3(directory, "sessions");
2772
- this.activeContextsDirectory = join3(directory, "active-contexts");
2773
- this.turnSelectionsDirectory = join3(directory, "turn-selections");
2774
- this.registrationsDirectory = join3(directory, "transcript-registrations");
2775
- this.cursorsDirectory = join3(directory, "transcript-cursors");
2662
+ this.entriesDirectory = join2(directory, "entries");
2663
+ this.sessionsDirectory = join2(directory, "sessions");
2664
+ this.activeContextsDirectory = join2(directory, "active-contexts");
2665
+ this.turnSelectionsDirectory = join2(directory, "turn-selections");
2666
+ this.registrationsDirectory = join2(directory, "transcript-registrations");
2667
+ this.cursorsDirectory = join2(directory, "transcript-cursors");
2776
2668
  }
2777
2669
  async prepare() {
2778
- for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2779
- await ensurePrivateOwnerDirectory(path);
2670
+ for (const path of [this.directory, this.entriesDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2671
+ await ensureOwnerDirectory(path);
2780
2672
  }
2781
2673
  }
2782
2674
  async put(entry) {
@@ -2791,7 +2683,7 @@ var CodexOutboxStore = class {
2791
2683
  for (const name of await readdir(this.entriesDirectory)) {
2792
2684
  if (!name.endsWith(".json")) continue;
2793
2685
  try {
2794
- const value = JSON.parse(await readPrivateFile(join3(this.entriesDirectory, name)));
2686
+ const value = JSON.parse(await readOwnerStateFile(join2(this.entriesDirectory, name)));
2795
2687
  validateEnvelope(value);
2796
2688
  entries.push(value);
2797
2689
  } catch {
@@ -2809,11 +2701,6 @@ var CodexOutboxStore = class {
2809
2701
  if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
2810
2702
  }
2811
2703
  }
2812
- async writeBinding(binding) {
2813
- validateBinding(binding);
2814
- await this.prepare();
2815
- await writeAtomicJson(this.bindingPath(binding.identity), binding);
2816
- }
2817
2704
  /**
2818
2705
  * Select the exact Host turn that model-reachable commands may use. A new
2819
2706
  * prompt replaces this projection, so it cannot inherit the prior turn's
@@ -2840,7 +2727,7 @@ var CodexOutboxStore = class {
2840
2727
  await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
2841
2728
  }
2842
2729
  async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
2843
- if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
2730
+ if (!SAFE_REF3.test(hostSourceRef) || !SAFE_REF3.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
2844
2731
  await this.prepare();
2845
2732
  return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
2846
2733
  }
@@ -2853,23 +2740,11 @@ var CodexOutboxStore = class {
2853
2740
  await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
2854
2741
  return true;
2855
2742
  }
2856
- /**
2857
- * Publish a Request reference only while the acknowledged binding is still
2858
- * the active turn. A delayed relay response therefore cannot overwrite a
2859
- * newer prompt's context.
2860
- */
2861
- async bindInvocationContext(binding, now = /* @__PURE__ */ new Date()) {
2862
- validateBinding(binding);
2863
- const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
2864
- if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
2865
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
2866
- return true;
2867
- }
2868
2743
  /** Return only the live session projection; never fall back to another turn. */
2869
2744
  async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
2870
2745
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
2871
2746
  const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
2872
- return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
2747
+ return isLiveSessionProjection(context, now) ? context : null;
2873
2748
  }
2874
2749
  /**
2875
2750
  * The latest Codex session projection even when past expiry, so the
@@ -2877,10 +2752,10 @@ var CodexOutboxStore = class {
2877
2752
  * a missing one. Every other caller keeps the fail-closed read above.
2878
2753
  */
2879
2754
  async readRawInvocationContext(hostSourceRef, hostSessionRef) {
2880
- if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
2755
+ if (!SAFE_REF3.test(hostSourceRef) || !SAFE_REF3.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
2881
2756
  await this.prepare();
2882
2757
  const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
2883
- return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
2758
+ return context;
2884
2759
  }
2885
2760
  /** Clear the projection only if the caller still owns its exact active turn. */
2886
2761
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -2894,11 +2769,6 @@ var CodexOutboxStore = class {
2894
2769
  }
2895
2770
  return true;
2896
2771
  }
2897
- async readBinding(identity) {
2898
- validateIdentity2(identity);
2899
- await this.prepare();
2900
- return readOptionalJson(this.bindingPath(identity), validateBinding);
2901
- }
2902
2772
  async saveSession(snapshot) {
2903
2773
  validateSession(snapshot);
2904
2774
  await this.prepare();
@@ -2906,7 +2776,7 @@ var CodexOutboxStore = class {
2906
2776
  }
2907
2777
  async readSession(sourceRef, sessionRef) {
2908
2778
  const identity = { host_source_ref: sourceRef, host_session_ref: sessionRef };
2909
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
2779
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
2910
2780
  await this.prepare();
2911
2781
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
2912
2782
  }
@@ -2939,7 +2809,7 @@ var CodexOutboxStore = class {
2939
2809
  for (const name of await readdir(this.registrationsDirectory)) {
2940
2810
  if (!name.endsWith(".json")) continue;
2941
2811
  try {
2942
- const value = JSON.parse(await readPrivateFile(join3(this.registrationsDirectory, name)));
2812
+ const value = JSON.parse(await readOwnerStateFile(join2(this.registrationsDirectory, name)));
2943
2813
  validateRegistration(value);
2944
2814
  registrations.push(value);
2945
2815
  } catch {
@@ -2958,48 +2828,37 @@ var CodexOutboxStore = class {
2958
2828
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
2959
2829
  }
2960
2830
  async findByAlias(sourceRef, sessionRef, alias) {
2961
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef) || !SAFE_REF4.test(alias)) return null;
2831
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef) || !SAFE_REF3.test(alias)) return null;
2962
2832
  const read = await this.list();
2963
2833
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
2964
2834
  if (envelope !== null) return envelopeMatch(envelope);
2965
2835
  await this.prepare();
2966
- const binding = await findBindingByAlias(this.bindingsDirectory, sourceRef, sessionRef, alias);
2967
- if (binding !== null) return bindingMatch(binding);
2968
2836
  return null;
2969
2837
  }
2970
2838
  async hasPriorTurn(sourceRef, sessionRef) {
2971
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) return false;
2839
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) return false;
2972
2840
  const read = await this.list();
2973
2841
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
2974
- await this.prepare();
2975
- for (const name of await readdir(this.bindingsDirectory)) {
2976
- if (!name.endsWith(".json")) continue;
2977
- const binding = await readBindingCandidate(this.bindingsDirectory, name);
2978
- if (binding?.identity.host_source_ref === sourceRef && binding.identity.host_session_ref === sessionRef) return true;
2979
- }
2980
2842
  return false;
2981
2843
  }
2982
2844
  entryPath(submissionRef) {
2983
- if (!SAFE_REF4.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
2984
- return join3(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
2985
- }
2986
- bindingPath(identity) {
2987
- return join3(this.bindingsDirectory, `${identityKey(identity)}.json`);
2845
+ if (!SAFE_REF3.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
2846
+ return join2(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
2988
2847
  }
2989
2848
  sessionPath(sourceRef, sessionRef) {
2990
- return join3(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
2849
+ return join2(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
2991
2850
  }
2992
2851
  activeContextPath(identity) {
2993
- return join3(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2852
+ return join2(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2994
2853
  }
2995
2854
  turnSelectionPath(sourceRef, sessionRef) {
2996
- return join3(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
2855
+ return join2(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
2997
2856
  }
2998
2857
  registrationPath(sourceRef, sessionRef) {
2999
- return join3(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
2858
+ return join2(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3000
2859
  }
3001
2860
  cursorPath(sourceRef, sessionRef) {
3002
- return join3(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
2861
+ return join2(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3003
2862
  }
3004
2863
  };
3005
2864
  async function removeOwnerState(path, what) {
@@ -3010,14 +2869,11 @@ async function removeOwnerState(path, what) {
3010
2869
  }
3011
2870
  }
3012
2871
  function sessionStateKey(sourceRef, sessionRef) {
3013
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
2872
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
3014
2873
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
3015
2874
  }
3016
2875
  function envelopeMatch(envelope) {
3017
- return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, ...envelope.request_ref === void 0 ? {} : { request_ref: envelope.request_ref }, envelope };
3018
- }
3019
- function bindingMatch(binding) {
3020
- return { identity: binding.identity, prompt_ref: binding.prompt_ref, request_ref: binding.request_ref, binding };
2876
+ return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, envelope };
3021
2877
  }
3022
2878
  function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
3023
2879
  for (const envelope of entries) {
@@ -3026,24 +2882,6 @@ function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
3026
2882
  }
3027
2883
  return null;
3028
2884
  }
3029
- async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
3030
- for (const name of await readdir(directory)) {
3031
- if (!name.endsWith(".json")) continue;
3032
- const binding = await readBindingCandidate(directory, name);
3033
- if (binding === null || binding.identity.host_source_ref !== sourceRef || binding.identity.host_session_ref !== sessionRef) continue;
3034
- if (binding.codex_turn_ids.includes(alias)) return binding;
3035
- }
3036
- return null;
3037
- }
3038
- async function readBindingCandidate(directory, name) {
3039
- try {
3040
- const value = JSON.parse(await readPrivateFile(join3(directory, name)));
3041
- validateBinding(value);
3042
- return value;
3043
- } catch {
3044
- return null;
3045
- }
3046
- }
3047
2885
  function identityKey(identity) {
3048
2886
  validateIdentity2(identity);
3049
2887
  return cealRequestSha256(identity);
@@ -3056,15 +2894,15 @@ async function writeAtomicJson(path, value) {
3056
2894
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
3057
2895
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
3058
2896
  try {
3059
- const handle = await open3(temp, "wx", 384);
2897
+ const handle = await open3(temp, "wx");
3060
2898
  try {
3061
2899
  await handle.writeFile(text, "utf8");
3062
2900
  await handle.sync();
3063
2901
  } finally {
3064
2902
  await handle.close();
3065
2903
  }
3066
- await rename3(temp, path);
3067
- await syncDirectory(dirname(path));
2904
+ await rename2(temp, path);
2905
+ await syncDirectory(dirname2(path));
3068
2906
  } catch (error) {
3069
2907
  try {
3070
2908
  await unlink2(temp);
@@ -3087,7 +2925,7 @@ async function syncDirectory(path) {
3087
2925
  }
3088
2926
  async function readOptionalJson(path, validate) {
3089
2927
  try {
3090
- const value = JSON.parse(await readPrivateFile(path));
2928
+ const value = JSON.parse(await readOwnerStateFile(path));
3091
2929
  validate(value);
3092
2930
  return value;
3093
2931
  } catch (error) {
@@ -3096,36 +2934,30 @@ async function readOptionalJson(path, validate) {
3096
2934
  throw storageError("Codex owner state is malformed.");
3097
2935
  }
3098
2936
  }
3099
- async function ensurePrivateOwnerDirectory(path) {
2937
+ async function ensureOwnerDirectory(path) {
3100
2938
  try {
3101
- await lstat2(path);
2939
+ await stat(path);
3102
2940
  } catch (error) {
3103
2941
  if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
3104
- await mkdir3(path, { recursive: true, mode: 448 });
2942
+ await mkdir2(path, { recursive: true });
3105
2943
  }
3106
- const stats = await lstat2(path);
3107
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3108
- if (!stats.isDirectory() || stats.isSymbolicLink()) throw storageError(`Codex owner state path is not a directory (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a directory mode (0o40xxx)")}).`);
3109
- if ((stats.mode & 63) !== 0) throw storageError(`Codex owner state directory is readable beyond its owner (${refusalFact("permission_bits", `0o${(stats.mode & 511).toString(8)}`, "no group or other bits")}).`);
3110
- if (stats.uid !== uid) throw storageError(`Codex owner state directory is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
2944
+ const stats = await stat(path);
2945
+ if (!stats.isDirectory()) throw storageError("Codex owner state path is not a directory.");
3111
2946
  }
3112
- async function readPrivateFile(path) {
2947
+ async function readOwnerStateFile(path) {
3113
2948
  let handle;
3114
2949
  try {
3115
- handle = await open3(path, O_RDONLY3 | O_NOFOLLOW2);
2950
+ handle = await open3(path);
3116
2951
  const stats = await handle.stat();
3117
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3118
- if (!stats.isFile()) throw storageError(`Codex owner state path is not a regular file (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a regular-file mode (0o100xxx)")}).`);
3119
- if ((stats.mode & 63) !== 0) throw storageError(`Codex owner state file is readable beyond its owner (${refusalFact("permission_bits", `0o${(stats.mode & 511).toString(8)}`, "no group or other bits")}).`);
3120
- if (stats.uid !== uid) throw storageError(`Codex owner state file is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
2952
+ if (!stats.isFile()) throw storageError("Codex owner state path is not a regular file.");
3121
2953
  return await handle.readFile("utf8");
3122
2954
  } finally {
3123
2955
  await handle?.close();
3124
2956
  }
3125
2957
  }
3126
2958
  function validateEnvelope(value) {
3127
- if (!isRecord4(value)) throw storageError("Codex outbox entry is malformed.");
3128
- if (!sameKeys(value, ["schema_version", "identity", "host_input_ref", "input_kind", "prompt_ref", "observations", "origin_input", "submission_ref", "created_at", "expires_at"], ["request_ref", "codex_turn_id"])) throw storageError(`Codex outbox entry key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the outbox entry key set")}).`);
2959
+ if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
2960
+ if (!sameKeys(value, ["schema_version", "identity", "host_input_ref", "prompt_ref", "observations", "origin_input", "submission_ref", "created_at", "expires_at"], ["codex_turn_id"])) throw storageError(`Codex outbox entry key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the outbox entry key set")}).`);
3129
2961
  if (value.schema_version !== CODEX_OUTBOX_SCHEMA_VERSION) throw storageError(`Codex outbox entry is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_OUTBOX_SCHEMA_VERSION}`)}).`);
3130
2962
  validateIdentity2(value.identity);
3131
2963
  validateEnvelopeReferences(value);
@@ -3133,22 +2965,20 @@ function validateEnvelope(value) {
3133
2965
  validateEnvelopeTimestamps(value);
3134
2966
  }
3135
2967
  function validateEnvelopeReferences(value) {
3136
- if (!SAFE_REF4.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
3137
- if (!isCealHostInputKind(value.input_kind)) throw storageError("Codex outbox input provenance is malformed.");
3138
- if (!SAFE_REF4.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
3139
- if (!SAFE_REF4.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
3140
- if (value.request_ref !== void 0 && !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
3141
- if (value.codex_turn_id !== void 0 && !SAFE_REF4.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
2968
+ if (!SAFE_REF3.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
2969
+ if (!SAFE_REF3.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
2970
+ if (!SAFE_REF3.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
2971
+ if (value.codex_turn_id !== void 0 && !SAFE_REF3.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
3142
2972
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
3143
2973
  }
3144
2974
  function validateRegistration(value) {
3145
- if (!isRecord4(value)) throw storageError("Codex transcript registration is malformed.");
2975
+ if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
3146
2976
  if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "codex_session_id", "transcript_path", "registered_at", "expires_at"], ["cwd"])) throw storageError(`Codex transcript registration key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the registration key set")}).`);
3147
2977
  if (value.schema_version !== CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION) throw storageError(`Codex transcript registration is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION}`)}).`);
3148
2978
  validateRegistrationFields(value);
3149
2979
  }
3150
2980
  function validateRegistrationFields(value) {
3151
- if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate))) throw storageError(`Codex transcript registration references are malformed (${refusalFacts([{ name: "host_source_ref", value: value.host_source_ref }, { name: "host_session_ref", value: value.host_session_ref }, { name: "codex_session_id", value: value.codex_session_id }])}).`);
2981
+ if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate))) throw storageError(`Codex transcript registration references are malformed (${refusalFacts([{ name: "host_source_ref", value: value.host_source_ref }, { name: "host_session_ref", value: value.host_session_ref }, { name: "codex_session_id", value: value.codex_session_id }])}).`);
3152
2982
  if (!validRegistrationCwd(value.cwd)) throw storageError(`Codex transcript registration working directory is malformed (${refusalFact("cwd_characters", typeof value.cwd === "string" ? value.cwd.length : 0, `an absolute path of at most ${CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS} characters`)}).`);
3153
2983
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
3154
2984
  if (value.transcript_path.length === 0 || value.transcript_path.length > CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS) throw storageError(`Codex transcript registration path is malformed (${refusalFact("characters", value.transcript_path.length, `from 1 through ${CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS}`)}).`);
@@ -3158,7 +2988,7 @@ function validRegistrationCwd(value) {
3158
2988
  return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
3159
2989
  }
3160
2990
  function validateCursor(value) {
3161
- if (!isRecord4(value)) throw storageError("Codex transcript cursor is malformed.");
2991
+ if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
3162
2992
  if (!sameKeys(value, ["schema_version", "host_source_ref", "host_session_ref", "transcript_path", "device", "inode", "offset", "last_ordinal", "anchor_start", "anchor_sha256", "header_validated", "status", "updated_at"], ["active_task", "reason"])) throw storageError(`Codex transcript cursor key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the cursor key set")}).`);
3163
2993
  if (value.schema_version !== CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION) throw storageError(`Codex transcript cursor is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION}`)}).`);
3164
2994
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
@@ -3166,7 +2996,7 @@ function validateCursor(value) {
3166
2996
  if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
3167
2997
  }
3168
2998
  function validCursorSource(value) {
3169
- return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
2999
+ return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
3170
3000
  }
3171
3001
  function validCursorPosition(value) {
3172
3002
  return nonNegativeInteger(value.offset) && nonNegativeInteger(value.last_ordinal) && nonNegativeInteger(value.anchor_start) && typeof value.anchor_sha256 === "string" && /^[a-f0-9]{64}$/u.test(value.anchor_sha256) && typeof value.header_validated === "boolean";
@@ -3175,23 +3005,23 @@ function validCursorStatus(value) {
3175
3005
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
3176
3006
  }
3177
3007
  function validActiveTask(value) {
3178
- if (!isRecord4(value) || !sameKeys(value, ["codex_turn_id", "host_turn_ref", "started_at"], ["origin_host_input_ref", "prompt_ref", "model", "token_usage", "last_total_usage", "token_usage_gap_reason"])) return false;
3008
+ if (!isRecord5(value) || !sameKeys(value, ["codex_turn_id", "host_turn_ref", "started_at"], ["origin_host_input_ref", "prompt_ref", "model", "token_usage", "last_total_usage", "token_usage_gap_reason"])) return false;
3179
3009
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
3180
3010
  }
3181
3011
  function validActiveTaskIdentity(value) {
3182
- return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && isTimestamp(value.started_at);
3012
+ return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate)) && isTimestamp(value.started_at);
3183
3013
  }
3184
3014
  function validActiveTaskReferences(value) {
3185
3015
  return optionalSafeRef2(value.origin_host_input_ref) && optionalSafeRef2(value.prompt_ref) && (value.model === void 0 || typeof value.model === "string" && value.model.length > 0 && value.model.length <= 256);
3186
3016
  }
3187
3017
  function optionalSafeRef2(value) {
3188
- return value === void 0 || typeof value === "string" && SAFE_REF4.test(value);
3018
+ return value === void 0 || typeof value === "string" && SAFE_REF3.test(value);
3189
3019
  }
3190
3020
  function validActiveTaskUsage(value) {
3191
3021
  return (value.token_usage === void 0 || validTokenUsage(value.token_usage)) && (value.last_total_usage === void 0 || validTokenUsage(value.last_total_usage)) && (value.token_usage_gap_reason === void 0 || value.token_usage_gap_reason === "token_count_shape_not_attributable");
3192
3022
  }
3193
3023
  function validTokenUsage(value) {
3194
- if (!isRecord4(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
3024
+ if (!isRecord5(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
3195
3025
  if (![value.input_tokens, value.cached_input_tokens, value.cache_write_input_tokens, value.output_tokens, value.reasoning_output_tokens, value.total_tokens].every(nonNegativeInteger)) return false;
3196
3026
  return value.total_tokens === Number(value.input_tokens) + Number(value.output_tokens) && Number(value.cached_input_tokens) + Number(value.cache_write_input_tokens) <= Number(value.input_tokens) && Number(value.reasoning_output_tokens) <= Number(value.output_tokens);
3197
3027
  }
@@ -3201,7 +3031,7 @@ function nonNegativeInteger(value) {
3201
3031
  function validateEnvelopeObservations(value) {
3202
3032
  if (!Array.isArray(value.observations)) throw storageError("Codex outbox observations are malformed.");
3203
3033
  try {
3204
- for (const observation2 of value.observations) validateCealHostObservationDraft(observation2);
3034
+ for (const observation of value.observations) validateCealHostObservationDraft(observation);
3205
3035
  } catch {
3206
3036
  throw storageError("Codex outbox observations are malformed.");
3207
3037
  }
@@ -3210,34 +3040,23 @@ function validateEnvelopeTimestamps(value) {
3210
3040
  if (!isTimestamp(value.created_at)) throw storageError("Codex outbox timestamps are malformed.");
3211
3041
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
3212
3042
  }
3213
- function validateBinding(value) {
3214
- if (!isRecord4(value)) throw storageError("Codex turn binding is malformed.");
3215
- if (!sameKeys(value, ["schema_version", "identity", "prompt_ref", "request_ref", "codex_turn_ids", "bound_at", "expires_at"])) throw storageError(`Codex turn binding key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the turn binding key set")}).`);
3216
- if (value.schema_version !== CODEX_TURN_BINDING_SCHEMA_VERSION) throw storageError(`Codex turn binding is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TURN_BINDING_SCHEMA_VERSION}`)}).`);
3217
- validateIdentity2(value.identity);
3218
- if (!SAFE_REF4.test(String(value.prompt_ref)) || !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
3219
- if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
3220
- }
3221
3043
  function validateSession(value) {
3222
- if (!isRecord4(value)) throw storageError("Codex session snapshot is malformed.");
3044
+ if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
3223
3045
  if (!sameKeys(value, ["schema_version", "host_session_ref", "host_source_ref", "observed_at", "value", "expires_at"])) throw storageError(`Codex session snapshot key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the session snapshot key set")}).`);
3224
3046
  if (value.schema_version !== CODEX_SESSION_SCHEMA_VERSION) throw storageError(`Codex session snapshot is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_SESSION_SCHEMA_VERSION}`)}).`);
3225
- if (!SAFE_REF4.test(String(value.host_session_ref)) || !SAFE_REF4.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
3047
+ if (!SAFE_REF3.test(String(value.host_session_ref)) || !SAFE_REF3.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
3226
3048
  }
3227
3049
  function validateTurnSelection(value) {
3228
3050
  if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
3229
3051
  }
3230
3052
  function validateIdentity2(value) {
3231
- if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate))) throw storageError("Codex Host identity is malformed.");
3053
+ if (!isRecord5(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate))) throw storageError("Codex Host identity is malformed.");
3232
3054
  }
3233
3055
  function isJsonValue(value) {
3234
3056
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
3235
3057
  if (typeof value === "number") return Number.isFinite(value);
3236
3058
  if (Array.isArray(value)) return value.every(isJsonValue);
3237
- return isRecord4(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
3238
- }
3239
- function isStringList(value) {
3240
- return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate));
3059
+ return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
3241
3060
  }
3242
3061
  function isTimestamp(value) {
3243
3062
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -3247,23 +3066,22 @@ function sameKeys(value, required, optional = []) {
3247
3066
  const keys = Object.keys(value);
3248
3067
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
3249
3068
  }
3250
- function isRecord4(value) {
3069
+ function isRecord5(value) {
3251
3070
  return value !== null && typeof value === "object" && !Array.isArray(value);
3252
3071
  }
3253
3072
  function isNotFound(error) {
3254
- return isRecord4(error) && error.code === "ENOENT";
3073
+ return isRecord5(error) && error.code === "ENOENT";
3255
3074
  }
3256
3075
  function storageError(message) {
3257
3076
  return new CodexHostAdapterError("storage", message);
3258
3077
  }
3259
3078
 
3260
3079
  // host/codex/src/codex-transcript-baseline.ts
3261
- import { createHash as createHash4 } from "node:crypto";
3262
- import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
3263
- import { open as open4 } from "node:fs/promises";
3080
+ import { createHash as createHash5 } from "node:crypto";
3081
+ import { constants as constants2 } from "node:fs";
3264
3082
 
3265
3083
  // host/codex/src/codex-transcript-decoder.ts
3266
- var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3084
+ var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3267
3085
  var MAX_PROMPT_BYTES = 64 * 1024;
3268
3086
  function decodeCodexTranscriptLine(line) {
3269
3087
  let value;
@@ -3272,40 +3090,40 @@ function decodeCodexTranscriptLine(line) {
3272
3090
  } catch {
3273
3091
  reject2("Codex transcript record is not valid JSON.");
3274
3092
  }
3275
- if (!isRecord5(value)) reject2("Codex transcript record envelope is malformed.");
3093
+ if (!isRecord6(value)) reject2("Codex transcript record envelope is malformed.");
3276
3094
  const ordinal = safeOrdinal(value.ordinal);
3277
- const timestamp5 = safeTimestamp(value.timestamp);
3278
- if (!isRecord5(value.payload) || typeof value.type !== "string") reject2("Codex transcript record payload is malformed.");
3279
- if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp5);
3280
- if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp5);
3281
- if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp5);
3282
- if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp5);
3283
- return { kind: "ignored", ordinal, timestamp: timestamp5 };
3284
- }
3285
- function decodeTurnContext(payload, ordinal, timestamp5) {
3095
+ const timestamp4 = safeTimestamp(value.timestamp);
3096
+ if (!isRecord6(value.payload) || typeof value.type !== "string") reject2("Codex transcript record payload is malformed.");
3097
+ if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
3098
+ if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
3099
+ if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
3100
+ if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
3101
+ return { kind: "ignored", ordinal, timestamp: timestamp4 };
3102
+ }
3103
+ function decodeTurnContext(payload, ordinal, timestamp4) {
3286
3104
  return {
3287
3105
  kind: "turn_context",
3288
3106
  ordinal,
3289
- timestamp: timestamp5,
3290
- turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
3107
+ timestamp: timestamp4,
3108
+ turn_id: safeRef3(payload.turn_id, "Codex turn context identity is invalid."),
3291
3109
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
3292
3110
  };
3293
3111
  }
3294
- function decodeSessionMeta(payload, ordinal, timestamp5) {
3295
- const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
3112
+ function decodeSessionMeta(payload, ordinal, timestamp4) {
3113
+ const sessionId = safeRef3(payload.id, "Codex transcript session identity is invalid.");
3296
3114
  const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
3297
- return { kind: "session_meta", ordinal, timestamp: timestamp5, session_id: sessionId, cli_version: cliVersion };
3115
+ return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
3298
3116
  }
3299
- function decodeEventMessage(payload, ordinal, timestamp5) {
3117
+ function decodeEventMessage(payload, ordinal, timestamp4) {
3300
3118
  if (payload.type === "task_started") {
3301
- return { kind: "task_started", ordinal, timestamp: timestamp5, turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
3119
+ return { kind: "task_started", ordinal, timestamp: timestamp4, turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
3302
3120
  }
3303
3121
  if (payload.type === "task_complete") {
3304
3122
  return {
3305
3123
  kind: "task_complete",
3306
3124
  ordinal,
3307
- timestamp: timestamp5,
3308
- turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
3125
+ timestamp: timestamp4,
3126
+ turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."),
3309
3127
  started_at: safeNumber(payload.started_at),
3310
3128
  completed_at: safeNumber(payload.completed_at),
3311
3129
  duration_ms: safeNumber(payload.duration_ms),
@@ -3316,20 +3134,20 @@ function decodeEventMessage(payload, ordinal, timestamp5) {
3316
3134
  return {
3317
3135
  kind: "turn_aborted",
3318
3136
  ordinal,
3319
- timestamp: timestamp5,
3320
- turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
3137
+ timestamp: timestamp4,
3138
+ turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."),
3321
3139
  started_at: safeNumber(payload.started_at),
3322
3140
  completed_at: safeNumber(payload.completed_at),
3323
3141
  duration_ms: safeNumber(payload.duration_ms),
3324
3142
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
3325
3143
  };
3326
3144
  }
3327
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp5);
3328
- return { kind: "ignored", ordinal, timestamp: timestamp5 };
3145
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
3146
+ return { kind: "ignored", ordinal, timestamp: timestamp4 };
3329
3147
  }
3330
- function decodeTokenCount(payload, ordinal, timestamp5) {
3331
- if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp5 };
3332
- if (!isRecord5(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp5, usage_gap_reason: "token_count_shape_not_attributable" };
3148
+ function decodeTokenCount(payload, ordinal, timestamp4) {
3149
+ if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
3150
+ if (!isRecord6(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
3333
3151
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
3334
3152
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
3335
3153
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -3337,7 +3155,7 @@ function decodeTokenCount(payload, ordinal, timestamp5) {
3337
3155
  return {
3338
3156
  kind: "token_count",
3339
3157
  ordinal,
3340
- timestamp: timestamp5,
3158
+ timestamp: timestamp4,
3341
3159
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
3342
3160
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
3343
3161
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -3353,7 +3171,7 @@ function optionalTokenUsage(value) {
3353
3171
  }
3354
3172
  }
3355
3173
  function decodeTokenUsage(value) {
3356
- if (!isRecord5(value)) reject2("Codex token usage is malformed.");
3174
+ if (!isRecord6(value)) reject2("Codex token usage is malformed.");
3357
3175
  const usage = {
3358
3176
  input_tokens: safeTokenCount(value.input_tokens),
3359
3177
  cached_input_tokens: safeTokenCount(value.cached_input_tokens),
@@ -3365,35 +3183,33 @@ function decodeTokenUsage(value) {
3365
3183
  if (usage.total_tokens !== usage.input_tokens + usage.output_tokens || usage.cached_input_tokens + usage.cache_write_input_tokens > usage.input_tokens || usage.reasoning_output_tokens > usage.output_tokens) reject2("Codex token usage buckets are inconsistent.");
3366
3184
  return usage;
3367
3185
  }
3368
- function decodeResponseItem(payload, ordinal, timestamp5) {
3369
- if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp5 };
3186
+ function decodeResponseItem(payload, ordinal, timestamp4) {
3187
+ if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
3370
3188
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
3371
- const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
3372
- if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp5 };
3189
+ const contentItemKind = userTextContentKind(metadata.content_item_kinds);
3190
+ if (contentItemKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
3373
3191
  const prompt = userTextContent(payload.content);
3374
3192
  return {
3375
3193
  kind: "user_text",
3376
3194
  ordinal,
3377
- timestamp: timestamp5,
3195
+ timestamp: timestamp4,
3378
3196
  prompt,
3379
- input_kind: inputKind,
3380
- message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
3381
- turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
3197
+ content_item_kind: contentItemKind,
3198
+ message_id: safeRef3(payload.id, "Codex user message identity is invalid."),
3199
+ turn_id: safeRef3(metadata.turn_id, "Codex user message task identity is invalid.")
3382
3200
  };
3383
3201
  }
3384
- function inputKindFromContentItems(kinds) {
3385
- if (kinds.length !== 1) return void 0;
3386
- if (kinds[0] === "user.text") return "human";
3387
- return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
3202
+ function userTextContentKind(kinds) {
3203
+ return kinds.length === 1 && (kinds[0] === "user.text" || kinds[0] === "goal.internal_context") ? kinds[0] : void 0;
3388
3204
  }
3389
3205
  function userMessageMetadata(value) {
3390
- if (!isRecord5(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
3206
+ if (!isRecord6(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
3391
3207
  return { ...value, content_item_kinds: value.content_item_kinds };
3392
3208
  }
3393
3209
  function userTextContent(value) {
3394
3210
  if (!Array.isArray(value)) reject2(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
3395
3211
  if (value.length !== 1) reject2(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
3396
- if (!isRecord5(value[0]) || value[0].type !== "input_text") reject2(`Codex user text content is malformed (${refusalFact("item_type", isRecord5(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
3212
+ if (!isRecord6(value[0]) || value[0].type !== "input_text") reject2(`Codex user text content is malformed (${refusalFact("item_type", isRecord6(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
3397
3213
  return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
3398
3214
  }
3399
3215
  function safeOrdinal(value) {
@@ -3414,8 +3230,8 @@ function safeTimestamp(value) {
3414
3230
  if (!Number.isFinite(Date.parse(value))) reject2(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
3415
3231
  return value;
3416
3232
  }
3417
- function safeRef4(value, message) {
3418
- if (typeof value !== "string" || !SAFE_REF5.test(value)) reject2(message);
3233
+ function safeRef3(value, message) {
3234
+ if (typeof value !== "string" || !SAFE_REF4.test(value)) reject2(message);
3419
3235
  return value;
3420
3236
  }
3421
3237
  function boundedText(value, maximum, message) {
@@ -3429,7 +3245,7 @@ function boundedNonEmptyText(value, maximum, message) {
3429
3245
  if (result.length === 0) reject2(message);
3430
3246
  return result;
3431
3247
  }
3432
- function isRecord5(value) {
3248
+ function isRecord6(value) {
3433
3249
  return value !== null && typeof value === "object" && !Array.isArray(value);
3434
3250
  }
3435
3251
  function reject2(message) {
@@ -3439,11 +3255,11 @@ function reject2(message) {
3439
3255
  // host/codex/src/codex-transcript-baseline.ts
3440
3256
  var BASELINE_READ_CHUNK_BYTES = 256 * 1024;
3441
3257
  var CODEX_TRANSCRIPT_ANCHOR_BYTES = 256;
3442
- async function captureCodexTranscriptBaseline(registration, now = () => /* @__PURE__ */ new Date()) {
3258
+ async function captureCodexTranscriptBaseline(registration, now = () => /* @__PURE__ */ new Date(), platform = process.platform, custody = {}) {
3443
3259
  let handle;
3444
3260
  try {
3445
- handle = await open4(registration.transcript_path, O_RDONLY4 | O_NOFOLLOW3);
3446
- const { size, device, inode } = await ownedCodexTranscriptFile(handle);
3261
+ handle = await openNoFollow(registration.transcript_path, constants2.O_RDONLY, void 0, platform, custody);
3262
+ const { size, device, inode } = await ownedCodexTranscriptFile(handle, platform);
3447
3263
  const empty = codexTranscriptInitialCursor(registration, device, inode, now);
3448
3264
  const headerLine = await firstCompleteLine(handle, size);
3449
3265
  if (headerLine === null) throw new CodexHostAdapterError("payload_rejected", "Codex transcript header is incomplete.");
@@ -3462,7 +3278,7 @@ async function captureCodexTranscriptBaseline(registration, now = () => /* @__PU
3462
3278
  anchor_start: anchorStart,
3463
3279
  anchor_sha256: digest(anchor),
3464
3280
  header_validated: true,
3465
- updated_at: timestamp3(now)
3281
+ updated_at: timestamp2(now)
3466
3282
  };
3467
3283
  } finally {
3468
3284
  await handle?.close();
@@ -3482,23 +3298,19 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
3482
3298
  anchor_sha256: digest(Buffer.alloc(0)),
3483
3299
  header_validated: false,
3484
3300
  status: "active",
3485
- updated_at: timestamp3(now)
3301
+ updated_at: timestamp2(now)
3486
3302
  };
3487
3303
  }
3488
- async function ownedCodexTranscriptFile(handle) {
3304
+ async function ownedCodexTranscriptFile(handle, platform = process.platform) {
3489
3305
  const stats = await handle.stat();
3490
- assertCodexTranscriptOwner(stats);
3306
+ if (!stats.isFile()) throw new CodexHostAdapterError("storage", "Codex transcript source is not a regular file.");
3307
+ if (platform !== "win32" && !isSelfOwned(stats.uid, platform, handle)) throw new CodexHostAdapterError("storage", "Codex transcript source is owned by another user.");
3491
3308
  return { size: stats.size, device: String(stats.dev), inode: String(stats.ino) };
3492
3309
  }
3493
- function assertCodexTranscriptOwner(stats) {
3494
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3495
- if (!stats.isFile()) throw new CodexHostAdapterError("storage", `Codex transcript source is not a regular file (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a regular-file mode (0o100xxx)")}).`);
3496
- if (stats.uid !== uid) throw new CodexHostAdapterError("storage", `Codex transcript source is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
3497
- }
3498
- function assertCodexTranscriptHeader(registration, record3) {
3499
- if (record3.kind !== "session_meta" || record3.session_id !== registration.codex_session_id) throw new CodexHostAdapterError("payload_rejected", `Codex transcript header does not match its SessionStart registration (${refusalFacts([
3500
- { name: "kind", value: record3.kind, expected: "session_meta" },
3501
- { name: "session_id", value: record3.kind === "session_meta" ? record3.session_id : "unavailable", expected: registration.codex_session_id }
3310
+ function assertCodexTranscriptHeader(registration, record) {
3311
+ if (record.kind !== "session_meta" || record.session_id !== registration.codex_session_id) throw new CodexHostAdapterError("payload_rejected", `Codex transcript header does not match its SessionStart registration (${refusalFacts([
3312
+ { name: "kind", value: record.kind, expected: "session_meta" },
3313
+ { name: "session_id", value: record.kind === "session_meta" ? record.session_id : "unavailable", expected: registration.codex_session_id }
3502
3314
  ])}).`);
3503
3315
  }
3504
3316
  async function firstCompleteLine(handle, size) {
@@ -3584,24 +3396,32 @@ async function* completeLinesBackward(handle, end) {
3584
3396
  yield { start: 0, bytes: Buffer.concat(carry) };
3585
3397
  }
3586
3398
  function digest(value) {
3587
- return createHash4("sha256").update(value).digest("hex");
3399
+ return createHash5("sha256").update(value).digest("hex");
3588
3400
  }
3589
- function timestamp3(now) {
3401
+ function timestamp2(now) {
3590
3402
  const value = now();
3591
3403
  if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
3592
3404
  return value.toISOString();
3593
3405
  }
3594
3406
 
3407
+ // host/codex/src/codex-runtime-paths.ts
3408
+ import { join as join3 } from "node:path";
3409
+ var CODEX_HOME_ENVIRONMENT = "CODEX_HOME";
3410
+ var CODEX_HOME_DEFAULT_DIRECTORY = ".codex";
3411
+ var CODEX_SESSIONS_DIRECTORY = "sessions";
3412
+ function resolveCodexHome(environment, home) {
3413
+ return environment[CODEX_HOME_ENVIRONMENT] || join3(home, CODEX_HOME_DEFAULT_DIRECTORY);
3414
+ }
3415
+ function resolveCodexSessionsRoot(environment, home) {
3416
+ return join3(resolveCodexHome(environment, home), CODEX_SESSIONS_DIRECTORY);
3417
+ }
3418
+
3595
3419
  // host/codex/src/codex-adapter.ts
3596
- var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3597
- var DEFAULT_TIMEOUT_MS = 5e3;
3598
- var ORIGIN_DELIVERY_CONCURRENCY = 8;
3599
- var CODEX_RELAY_TIMEOUT_MAX_MS = 1e4;
3420
+ var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3600
3421
  function createCodexHostObservationAdapter(options) {
3601
3422
  validateOptions(options);
3602
3423
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
3603
3424
  const retentionMs = options.retention_ms ?? CODEX_DEFAULT_RETENTION_MS;
3604
- const timeoutMs = options.timeout_ms ?? DEFAULT_TIMEOUT_MS;
3605
3425
  const store = new CodexOutboxStore(options.outbox_dir);
3606
3426
  return Object.freeze({
3607
3427
  handle: async (event, payload) => {
@@ -3610,15 +3430,14 @@ function createCodexHostObservationAdapter(options) {
3610
3430
  } catch (error) {
3611
3431
  return { event, disposition: "rejected", reason: safeReason(error) };
3612
3432
  }
3613
- },
3614
- drainOutbox: (signal) => drainOutbox(options, store, now, timeoutMs, signal)
3433
+ }
3615
3434
  });
3616
3435
  }
3617
3436
  async function registerSession(event, options, store, now, retentionMs) {
3618
- const defaultRoot = join4(process.env.CODEX_HOME || join4(homedir(), ".codex"), "sessions");
3437
+ const defaultRoot = resolveCodexSessionsRoot(process.env, homedir());
3619
3438
  const transcriptPath = sourceBoundTranscriptPath(event.transcript_path, options.codex_sessions_root ?? defaultRoot);
3620
3439
  const hostSessionRef = hostSessionReference(options.host_source_ref, event.session_id);
3621
- const observedAt = timestamp4(now);
3440
+ const observedAt = timestamp3(now);
3622
3441
  const expiresAt = new Date(Date.parse(observedAt) + retentionMs).toISOString();
3623
3442
  const registration = {
3624
3443
  schema_version: "ceal.codex_transcript_registration.v1",
@@ -3664,7 +3483,7 @@ async function selectCurrentTurn(event, options, store, hostSessionRef) {
3664
3483
  turn_generation_ref: options.random_uuid?.() ?? randomUUID()
3665
3484
  };
3666
3485
  await store.writeInvocationTurnSelection({
3667
- schema_version: "ceal.host_invocation_turn_selection.v1",
3486
+ schema_version: HOST_INVOCATION_TURN_SELECTION_SCHEMA,
3668
3487
  host_source_ref: options.host_source_ref,
3669
3488
  host_session_ref: hostSessionRef,
3670
3489
  prompt_ref: currentTurn.prompt_ref,
@@ -3694,164 +3513,47 @@ function sourceBoundTranscriptPath(path, sessionsRoot) {
3694
3513
  }
3695
3514
  return transcript;
3696
3515
  }
3697
- async function drainOutbox(options, store, now, timeoutMs, signal) {
3698
- const read = await store.list();
3699
- const { live, expired } = await liveOutboxEntries(read.entries, store, now, signal);
3700
- const origins = live.filter((entry) => entry.origin_input === true).sort((left, right) => right.created_at.localeCompare(left.created_at));
3701
- const originResult = await deliverOriginEntries(origins, options, store, now, timeoutMs, signal);
3702
- const boundResult = await deliverBoundEntries(live.filter((entry) => entry.origin_input !== true), options, store, now, timeoutMs, signal);
3703
- return { delivered: originResult.delivered + boundResult.delivered, retained: originResult.retained + boundResult.retained, expired, malformed: read.malformed };
3704
- }
3705
- async function liveOutboxEntries(entries, store, now, signal) {
3706
- const live = [];
3707
- let expired = 0;
3708
- for (const entry of entries) {
3709
- if (signal?.aborted === true) break;
3710
- if (Date.parse(entry.expires_at) > now().getTime()) live.push(entry);
3711
- else {
3712
- await store.remove(entry);
3713
- expired += 1;
3714
- }
3715
- }
3716
- return { live, expired };
3717
- }
3718
- async function deliverOriginEntries(entries, options, store, now, timeoutMs, signal) {
3719
- const counts = { delivered: 0, retained: 0 };
3720
- for (let offset = 0; offset < entries.length; offset += ORIGIN_DELIVERY_CONCURRENCY) {
3721
- if (signal?.aborted === true) break;
3722
- const outcomes = await Promise.allSettled(entries.slice(offset, offset + ORIGIN_DELIVERY_CONCURRENCY).map((entry) => deliverPreparedEntry(entry, entry, options, store, now, timeoutMs, signal)));
3723
- for (const outcome of outcomes) {
3724
- if (outcome.status === "rejected") throw outcome.reason;
3725
- incrementDelivery(counts, outcome.value);
3726
- }
3727
- }
3728
- return counts;
3729
- }
3730
- async function deliverBoundEntries(entries, options, store, now, timeoutMs, signal) {
3731
- const counts = { delivered: 0, retained: 0 };
3732
- for (const entry of entries) {
3733
- if (signal?.aborted === true) break;
3734
- const prepared = await prepareForDelivery(entry, store);
3735
- if (prepared === null) {
3736
- counts.retained += 1;
3737
- continue;
3738
- }
3739
- const outcome = await deliverPreparedEntry(entry, prepared, options, store, now, timeoutMs, signal);
3740
- incrementDelivery(counts, outcome);
3741
- }
3742
- return counts;
3743
- }
3744
- function incrementDelivery(counts, outcome) {
3745
- counts[outcome] += 1;
3746
- }
3747
- async function deliverPreparedEntry(entry, prepared, options, store, now, timeoutMs, signal) {
3748
- try {
3749
- const acknowledgement = await submitWithDeadline(options.gateway, gatewaySubmission(prepared), timeoutMs, signal);
3750
- if (prepared.request_ref === void 0) {
3751
- const binding = bindingFor(prepared, acknowledgement, now);
3752
- await store.writeBinding(binding);
3753
- await store.bindInvocationContext(binding, now());
3754
- }
3755
- await store.remove(entry);
3756
- return "delivered";
3757
- } catch (error) {
3758
- if (error instanceof CodexHostAdapterError && error.code === "payload_rejected") throw error;
3759
- return "retained";
3760
- }
3761
- }
3762
- async function prepareForDelivery(entry, store) {
3763
- const binding = await store.readBinding(entry.identity);
3764
- if (!entry.origin_input && binding === null) return null;
3765
- if (binding === null) return entry;
3766
- return { ...entry, prompt_ref: binding.prompt_ref, request_ref: binding.request_ref };
3767
- }
3768
- function gatewaySubmission(envelope) {
3769
- return {
3770
- identity: envelope.identity,
3771
- host_input_ref: envelope.host_input_ref,
3772
- input_kind: envelope.input_kind,
3773
- prompt_ref: envelope.prompt_ref,
3774
- observations: envelope.observations,
3775
- ...envelope.request_ref === void 0 ? {} : { request_ref: envelope.request_ref },
3776
- submission_ref: envelope.submission_ref
3777
- };
3778
- }
3779
- async function submitWithDeadline(gateway, submission, timeoutMs, signal) {
3780
- if (signal?.aborted === true) throw new CodexHostAdapterError("storage", "Codex relay delivery was cancelled.");
3781
- const controller = new AbortController();
3782
- const abort = () => controller.abort();
3783
- signal?.addEventListener("abort", abort, { once: true });
3784
- let timeoutHandle;
3785
- const timeout = new Promise((_resolve, reject3) => {
3786
- timeoutHandle = setTimeout(() => {
3787
- controller.abort();
3788
- reject3(new CodexHostAdapterError("storage", "Codex relay delivery timed out."));
3789
- }, timeoutMs);
3790
- });
3791
- try {
3792
- const acknowledgement = await Promise.race([gateway.submitHostTurn(submission, controller.signal), timeout]);
3793
- if (!isRecord6(acknowledgement) || !SAFE_REF6.test(String(acknowledgement.request_ref)) || !isHostGatewayAcknowledgementDisposition(acknowledgement.disposition)) {
3794
- throw new CodexHostAdapterError("payload_rejected", "Gateway Host acknowledgement is invalid.");
3795
- }
3796
- return acknowledgement;
3797
- } finally {
3798
- if (timeoutHandle !== void 0) clearTimeout(timeoutHandle);
3799
- signal?.removeEventListener("abort", abort);
3800
- }
3801
- }
3802
- function bindingFor(envelope, acknowledgement, now) {
3803
- return {
3804
- schema_version: "ceal.codex_turn_binding.v1",
3805
- identity: envelope.identity,
3806
- prompt_ref: envelope.prompt_ref,
3807
- request_ref: acknowledgement.request_ref,
3808
- codex_turn_ids: envelope.codex_turn_id === void 0 ? [] : [envelope.codex_turn_id],
3809
- bound_at: timestamp4(now),
3810
- expires_at: envelope.expires_at
3811
- };
3812
- }
3813
3516
  function codexSubmissionReference(hostInputRef, event, ordinal) {
3814
- if (!SAFE_REF6.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
3517
+ if (!SAFE_REF5.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
3815
3518
  return `codex-submission:${cealRequestSha256({ host_input_ref: hostInputRef, event, ordinal })}`;
3816
3519
  }
3817
- function timestamp4(now) {
3520
+ function timestamp3(now) {
3818
3521
  const value = now();
3819
3522
  if (!(value instanceof Date) || !Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex adapter clock is invalid.");
3820
3523
  return value.toISOString();
3821
3524
  }
3822
3525
  function validateOptions(options) {
3823
- if (!isRecord6(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
3526
+ if (!isRecord7(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
3824
3527
  validateAdapterOwner(options);
3825
3528
  validateAdapterBehavior(options);
3826
3529
  }
3827
3530
  function validateAdapterOwner(options) {
3828
- if (!SAFE_REF6.test(options.host_source_ref) || options.outbox_dir.length === 0 || !isRecord6(options.gateway) || typeof options.gateway.submitHostTurn !== "function") {
3531
+ if (!SAFE_REF5.test(options.host_source_ref) || options.outbox_dir.length === 0) {
3829
3532
  throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
3830
3533
  }
3831
3534
  if (options.codex_sessions_root !== void 0 && !isAbsolute3(options.codex_sessions_root)) throw new CodexHostAdapterError("configuration", "Codex sessions root is invalid.");
3832
3535
  }
3833
3536
  function validateAdapterBehavior(options) {
3834
- if (options.timeout_ms !== void 0 && (!Number.isSafeInteger(options.timeout_ms) || options.timeout_ms < 1 || options.timeout_ms > CODEX_RELAY_TIMEOUT_MAX_MS)) throw new CodexHostAdapterError("configuration", `Codex relay timeout is invalid (${refusalFact("timeout_ms", options.timeout_ms, `an integer from 1 through ${CODEX_RELAY_TIMEOUT_MAX_MS}`)}).`);
3835
3537
  if (options.retention_ms !== void 0 && (!Number.isSafeInteger(options.retention_ms) || options.retention_ms < 1)) throw new CodexHostAdapterError("configuration", `Codex retention is invalid (${refusalFact("retention_ms", options.retention_ms, "a positive integer")}).`);
3836
3538
  }
3837
3539
  function safeReason(error) {
3838
3540
  return error instanceof CodexHostAdapterError ? error.message.slice(0, 128) : "codex_session_registration_rejected";
3839
3541
  }
3840
- function isRecord6(value) {
3542
+ function isRecord7(value) {
3841
3543
  return value !== null && typeof value === "object" && !Array.isArray(value);
3842
3544
  }
3843
3545
 
3844
3546
  // host/producer-service.ts
3845
- import { posix as posix3, win32 as win323 } from "node:path";
3547
+ import { posix as posix3, win32 as win324 } from "node:path";
3846
3548
 
3847
3549
  // host/runtime-source-paths.ts
3848
- import { createHash as createHash5 } from "node:crypto";
3849
- import { posix as posix2, win32 as win322 } from "node:path";
3550
+ import { createHash as createHash6 } from "node:crypto";
3551
+ import { posix as posix2, win32 as win323 } from "node:path";
3850
3552
 
3851
3553
  // host/absolute-path.ts
3852
- import { posix, win32 } from "node:path";
3554
+ import { posix, win32 as win322 } from "node:path";
3853
3555
  function isAbsoluteNormalizedNonRootPath(value, flavor = process.platform, allowRoot = false) {
3854
- const pathApi = flavor === "win32" || flavor === "windows" ? win32 : posix;
3556
+ const pathApi = flavor === "win32" || flavor === "windows" ? win322 : posix;
3855
3557
  return typeof value === "string" && value.length <= 4096 && !value.includes("\0") && pathApi.isAbsolute(value) && pathApi.normalize(value) === value && (allowRoot || pathApi.parse(value).root !== value);
3856
3558
  }
3857
3559
 
@@ -3863,28 +3565,23 @@ function hostSourceUuid(sourceRef) {
3863
3565
  function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platform) {
3864
3566
  const sourceId = hostSourceUuid(sourceRef);
3865
3567
  if (!isAbsoluteNormalizedNonRootPath(stateRoot, platform) || sourceId === null) throw new TypeError("Host runtime source identity is invalid.");
3866
- const path = platform === "win32" ? win322 : posix2;
3568
+ const path = platform === "win32" ? win323 : posix2;
3867
3569
  const sourcesRoot = path.join(stateRoot, "sources");
3868
3570
  const sourceRoot = path.join(sourcesRoot, sourceId);
3869
3571
  const runtimeRoot = path.join(stateRoot, "run");
3870
- const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash5("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
3871
- assertHostRuntimeIpcLength(endpoint, platform);
3572
+ const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash6("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
3872
3573
  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 };
3873
3574
  }
3874
- function assertHostRuntimeIpcLength(endpoint, platform) {
3875
- if (platform === "win32") return;
3876
- const maximum = platform === "linux" ? 107 : 103;
3877
- 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" });
3878
- }
3879
3575
  function assertHostProducerSourcePaths(stateRoot, config, producer, platform = process.platform) {
3880
3576
  const paths = hostRuntimeSourcePaths(stateRoot, config.host_source_ref, platform);
3881
- if (config.outbox_dir !== (producer === "codex" ? paths.codexOutbox : paths.claudeOutbox) || config.relay_endpoint !== paths.endpoint) throw new TypeError("Host producer outbox and IPC must belong to its configured source.");
3577
+ if (config.outbox_dir !== (producer === "codex" ? paths.codexOutbox : paths.claudeOutbox) || platform !== "win32" && config.relay_endpoint !== paths.endpoint) throw new TypeError("Host producer outbox and IPC must belong to its configured source.");
3578
+ return paths.endpoint;
3882
3579
  }
3883
3580
 
3884
3581
  // host/producer-service.ts
3885
- import { constants } from "node:fs";
3886
- import { lstat as lstat3, open as open5 } from "node:fs/promises";
3887
- var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3582
+ import { constants as constants3 } from "node:fs";
3583
+ import { lstat as lstat3 } from "node:fs/promises";
3584
+ var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3888
3585
  var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
3889
3586
  var HostProducerServiceError = class extends Error {
3890
3587
  code;
@@ -3895,18 +3592,19 @@ var HostProducerServiceError = class extends Error {
3895
3592
  }
3896
3593
  };
3897
3594
  var HOST_PRODUCER_CONFIG_KEYS = ["schema_version", "host_source_ref", "producer_installation_ref", "producer_epoch", "outbox_dir", "relay_endpoint"];
3595
+ var HOST_PRODUCER_CONFIG_ENDPOINT_KEY = "relay_endpoint";
3898
3596
  var HOST_PRODUCER_TIMING_DEFAULTS = Object.freeze({ reconcile_interval_ms: 250, retry_backoff_ms: 1e3, ipc_timeout_ms: 5e3 });
3899
3597
  function hostProducerExtraPath(extras, key) {
3900
3598
  const value = extras[key];
3901
- if (value === void 0) throw hostProducerError("invalid_config");
3599
+ if (value === void 0) throw hostProducerError("invalid_config", refusalFact(key, "missing", "an absolute path"));
3902
3600
  return value;
3903
3601
  }
3904
3602
  function parseHostProducerConfigFlag(args, platform = process.platform) {
3905
3603
  return parseProducerHostConfigFlag(args, HOST_PRODUCER_CONFIG_FLAG, platform, hostProducerError);
3906
3604
  }
3907
- async function readHostProducerConfig(descriptor, configPath, platform = process.platform) {
3908
- const config = decodeHostProducerConfigText(descriptor, await readProducerConfigText(configPath, platform, hostProducerError), platform);
3909
- const path = platform === "win32" ? win323 : posix3;
3605
+ async function readHostProducerConfig(descriptor, configPath, platform = process.platform, custody = {}) {
3606
+ const config = decodeHostProducerConfigText(descriptor, await readProducerConfigText(configPath, platform, hostProducerError, custody), platform);
3607
+ const path = platform === "win32" ? win324 : posix3;
3910
3608
  const root = path.resolve(config.outbox_dir, "../../../../..");
3911
3609
  try {
3912
3610
  assertHostProducerSourcePaths(root, config, descriptor.producer_id, platform);
@@ -3932,15 +3630,31 @@ function parseProducerHostConfigFlag(args, flag, platform, error) {
3932
3630
  assertProducerAbsolutePath(value, platform, "config", error);
3933
3631
  return value;
3934
3632
  }
3935
- async function readProducerConfigText(configPath, platform, error) {
3936
- assertProducerAbsolutePath(configPath, platform, "config", error);
3633
+ async function readProducerConfigText(configPath, platform, error, custody) {
3634
+ assertProducerAbsolutePath(configPath, process.platform, "config", error);
3635
+ if (platform === "win32") {
3636
+ let bytes;
3637
+ try {
3638
+ bytes = await readPrivateFileWithSecurefs(configPath, CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES, custody);
3639
+ } catch (cause) {
3640
+ if (cause instanceof SecureFileCustodyError && cause.reason === "not_private") throw error("config_not_private");
3641
+ if (cause instanceof SecureFileCustodyError && cause.reason === "too_large") throw error("invalid_config", refusalFact("config_bytes", "over_limit", `at most ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
3642
+ if (cause instanceof SecureFileCustodyError && cause.reason === "reparse_point") throw error("invalid_config");
3643
+ throw error("config_unavailable");
3644
+ }
3645
+ if (bytes.byteLength === 0) throw error("invalid_config", refusalFact("config_bytes", 0, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
3646
+ try {
3647
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
3648
+ } catch {
3649
+ throw error("invalid_config");
3650
+ }
3651
+ }
3937
3652
  const pathStat = await configPathStat(configPath, error);
3938
3653
  validateConfigFile(pathStat, platform, error);
3939
- const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
3940
- const handle = await openConfigFile(configPath, constants.O_RDONLY | noFollow, error);
3654
+ const handle = await openConfigFile(configPath, platform, error, custody);
3941
3655
  try {
3942
3656
  const opened = await handle.stat();
3943
- validateConfigFile(opened, platform, error);
3657
+ validateConfigFile(opened, platform, error, handle);
3944
3658
  validateOpenedFile(opened, pathStat, platform, error);
3945
3659
  return await readBoundedConfig(handle, opened.size, error);
3946
3660
  } finally {
@@ -3948,8 +3662,9 @@ async function readProducerConfigText(configPath, platform, error) {
3948
3662
  }
3949
3663
  }
3950
3664
  function decodeProducerConfigCore(text, options) {
3665
+ const ownership = producerConfigKeyOwnership(options.keys, options.platform);
3951
3666
  const value = parseCanonicalJson(text, options.error);
3952
- if (!isRecord7(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
3667
+ if (!isRecord8(value) || !hasConfigKeys(value, ownership.required, ownership.tolerated) || value.schema_version !== options.schema) throw options.error("invalid_config", refusalFacts(producerShapeFacts(value, { schema: options.schema, keys: ownership.required, tolerated: ownership.tolerated })));
3953
3668
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
3954
3669
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
3955
3670
  const producerEpoch = validateIdentity3(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -3967,14 +3682,21 @@ function decodeProducerConfigCore(text, options) {
3967
3682
  producer_installation_ref: installationRef,
3968
3683
  producer_epoch: producerEpoch,
3969
3684
  outbox_dir: value.outbox_dir,
3970
- relay_endpoint: value.relay_endpoint,
3685
+ relay_endpoint: producerConfigEndpoint(value),
3971
3686
  reconcile_interval_ms: intervals[0],
3972
3687
  retry_backoff_ms: intervals[1],
3973
3688
  ipc_timeout_ms: intervals[2]
3974
3689
  };
3975
3690
  }
3691
+ function producerConfigKeyOwnership(keys, platform) {
3692
+ if (platform !== "win32") return { required: keys, tolerated: [] };
3693
+ return { required: keys.filter((key) => key !== HOST_PRODUCER_CONFIG_ENDPOINT_KEY), tolerated: [HOST_PRODUCER_CONFIG_ENDPOINT_KEY] };
3694
+ }
3695
+ function producerConfigEndpoint(value) {
3696
+ return typeof value.relay_endpoint === "string" ? value.relay_endpoint : "";
3697
+ }
3976
3698
  function assertProducerRelayEndpoint(value, platform, error) {
3977
- if (platform === "win32" && typeof value === "string" && /^\\\\\.\\pipe\\[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)) return;
3699
+ if (platform === "win32") return;
3978
3700
  assertProducerAbsolutePath(value, platform, "runtime", error);
3979
3701
  }
3980
3702
  function assertProducerAbsolutePath(value, platform, kind, error) {
@@ -3987,21 +3709,22 @@ async function configPathStat(configPath, error) {
3987
3709
  throw error("config_unavailable");
3988
3710
  }
3989
3711
  }
3990
- function validateConfigFile(value, platform, error) {
3712
+ function validateConfigFile(value, platform, error, handle) {
3991
3713
  if (!value.isFile() || value.isSymbolicLink()) throw error("invalid_config", refusalFacts([{ name: "config_is_file", value: value.isFile(), expected: "true" }, { name: "config_is_symlink", value: value.isSymbolicLink(), expected: "false" }]));
3992
3714
  if (value.size <= 0 || value.size > CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES) throw error("invalid_config", refusalFact("config_bytes", value.size, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
3993
- if (platform !== "win32" && (value.uid !== process.getuid?.() || (value.mode & 63) !== 0)) throw error("config_not_private", refusalFacts([{ name: "platform", value: platform, expected: "win32 or owner-private" }, { name: "config_uid", value: value.uid, expected: "the current user" }, { name: "config_mode", value: value.mode, expected: "owner-private" }]));
3715
+ if (!isSelfOwned(value.uid, platform, handle) || !isPrivateFileMode(value.mode, platform, handle)) throw error("config_not_private", refusalFacts([{ name: "platform", value: platform, expected: "a platform with verifiable owner and private-mode facts" }, { name: "config_uid", value: value.uid, expected: "the current user" }, { name: "config_mode", value: value.mode, expected: "private to its owner" }]));
3994
3716
  }
3995
- async function openConfigFile(configPath, flags, error) {
3717
+ async function openConfigFile(configPath, platform, error, custody) {
3996
3718
  try {
3997
- return await open5(configPath, flags);
3998
- } catch {
3719
+ return await openNoFollow(configPath, constants3.O_RDONLY, void 0, platform, custody);
3720
+ } catch (error_) {
3721
+ if (error_ instanceof SecureFileCustodyError) throw error(error_.reason === "not_private" ? "config_not_private" : "invalid_config");
3999
3722
  throw error("config_unavailable");
4000
3723
  }
4001
3724
  }
4002
3725
  function validateOpenedFile(opened, pathStat, platform, error) {
4003
3726
  if (!opened.isFile()) throw error("config_unavailable", refusalFacts([{ name: "opened_is_file", value: opened.isFile(), expected: "true" }, { name: "opened_mode", value: opened.mode.toString(8), expected: "a regular file mode" }]));
4004
- if (platform !== "win32" && (opened.dev !== pathStat.dev || opened.ino !== pathStat.ino)) throw error("config_unavailable", refusalFacts([{ name: "platform", value: platform, expected: "win32, or the same file the path named" }, { name: "opened_device", value: opened.dev, expected: String(pathStat.dev) }, { name: "opened_inode", value: opened.ino, expected: String(pathStat.ino) }]));
3727
+ if (opened.dev !== pathStat.dev || opened.ino !== pathStat.ino) throw error("config_unavailable", refusalFacts([{ name: "platform", value: platform, expected: "the same file the path named" }, { name: "opened_device", value: opened.dev, expected: String(pathStat.dev) }, { name: "opened_inode", value: opened.ino, expected: String(pathStat.ino) }]));
4005
3728
  }
4006
3729
  async function readBoundedConfig(handle, expectedBytes, error) {
4007
3730
  const buffer = Buffer.allocUnsafe(expectedBytes + 1);
@@ -4033,153 +3756,119 @@ function firstDifferenceIndex(left, right) {
4033
3756
  for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
4034
3757
  return shared;
4035
3758
  }
3759
+ function producerShapeFacts(value, options) {
3760
+ if (!isRecord8(value)) return [{ name: "config", value: "wrong_type", expected: "a record" }];
3761
+ const tolerated = options.tolerated ?? [];
3762
+ const allowed = [...options.keys, ...tolerated, ...Object.keys(HOST_PRODUCER_TIMING_DEFAULTS)];
3763
+ const facts = [
3764
+ ...Object.keys(value).filter((key) => !allowed.includes(key)).map((key) => ({ name: key, value: "unknown", expected: `one of ${[...options.keys, ...tolerated].join(", ")}` })),
3765
+ ...options.keys.filter((key) => !Object.hasOwn(value, key)).map((key) => ({ name: key, value: "missing", expected: "present" }))
3766
+ ];
3767
+ if (Object.hasOwn(value, "schema_version") && value.schema_version !== options.schema) facts.push({ name: "schema_version", value: "wrong_type", expected: options.schema });
3768
+ return facts;
3769
+ }
4036
3770
  function validateIdentity3(sourceRef, installationRef, epoch, error) {
4037
- if (!SAFE_REF7.test(sourceRef) || !SAFE_REF7.test(installationRef) || !positive2(epoch, 2147483647)) throw error("invalid_config");
3771
+ if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(installationRef) || !positive(epoch, 2147483647)) throw error("invalid_config", refusalFacts(producerIdentityFacts(sourceRef, installationRef, epoch)));
4038
3772
  return epoch;
4039
3773
  }
3774
+ function producerIdentityFacts(sourceRef, installationRef, epoch) {
3775
+ const facts = [];
3776
+ if (!SAFE_REF6.test(sourceRef)) facts.push({ name: "host_source_ref", value: "wrong_type", expected: "a safe reference" });
3777
+ if (!SAFE_REF6.test(installationRef)) facts.push({ name: "producer_installation_ref", value: "wrong_type", expected: "a safe reference" });
3778
+ if (!positive(epoch, 2147483647)) facts.push({ name: "producer_epoch", value: "wrong_type", expected: "a positive integer" });
3779
+ return facts;
3780
+ }
4040
3781
  function validateIntervals(reconcile, retry, timeout, error) {
4041
- if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
3782
+ if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config", refusalFacts(producerIntervalFacts(reconcile, retry, timeout)));
4042
3783
  return [reconcile, retry, timeout];
4043
3784
  }
4044
- function hasConfigKeys(value, required) {
4045
- return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
3785
+ function producerIntervalFacts(reconcile, retry, timeout) {
3786
+ const facts = [];
3787
+ if (!boundedMilliseconds(reconcile)) facts.push({ name: "reconcile_interval_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
3788
+ if (!boundedMilliseconds(retry)) facts.push({ name: "retry_backoff_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
3789
+ if (!boundedMilliseconds(timeout)) facts.push({ name: "ipc_timeout_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
3790
+ return facts;
4046
3791
  }
4047
- function isRecord7(value) {
3792
+ function hasConfigKeys(value, required, tolerated = []) {
3793
+ return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || tolerated.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
3794
+ }
3795
+ function isRecord8(value) {
4048
3796
  return value !== null && typeof value === "object" && !Array.isArray(value);
4049
3797
  }
4050
- function positive2(value, maximum) {
3798
+ function positive(value, maximum) {
4051
3799
  return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
4052
3800
  }
4053
3801
  function boundedMilliseconds(value) {
4054
- return positive2(value, 6e4) && Number(value) >= 25;
3802
+ return positive(value, 6e4) && Number(value) >= 25;
3803
+ }
3804
+
3805
+ // host/service-log.ts
3806
+ import { copyFile, mkdir as mkdir3, stat as stat2, truncate, appendFile } from "node:fs/promises";
3807
+ import { dirname as dirname3, isAbsolute as isAbsolute4, posix as posix4, win32 as win325 } from "node:path";
3808
+ var HOST_SERVICE_LOG_ENVIRONMENT = "CEAL_HOST_SERVICE_LOG";
3809
+ function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
3810
+ const line = `${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {}, ...event === "watcher_scan_failed" && cause !== void 0 ? { cause } : {} })}
3811
+ `;
3812
+ try {
3813
+ (sink ?? defaultHostServiceDiagnosticSink)(line);
3814
+ } catch {
3815
+ }
3816
+ }
3817
+ function defaultHostServiceDiagnosticSink(line) {
3818
+ writeHostServiceLogLine(line);
3819
+ process.stderr.write(line);
3820
+ }
3821
+ var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
3822
+ function writeHostServiceLogLine(line, environment = process.env) {
3823
+ if (process.platform !== "win32") return;
3824
+ const path = environment[HOST_SERVICE_LOG_ENVIRONMENT];
3825
+ if (path === void 0 || !win325.isAbsolute(path) || win325.normalize(path) !== path) return;
3826
+ void appendHostServiceLogLine(path, line).catch(() => void 0);
3827
+ }
3828
+ async function appendHostServiceLogLine(path, line) {
3829
+ if (!isAbsolute4(path)) return;
3830
+ await ensureHostServiceLogDirectory(path);
3831
+ await appendFile(path, line);
3832
+ }
3833
+ var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
3834
+ var hostServiceLogDirectories = /* @__PURE__ */ new Map();
3835
+ function ensureHostServiceLogDirectory(path) {
3836
+ const directory = dirname3(path);
3837
+ const existing = hostServiceLogDirectories.get(directory);
3838
+ if (existing !== void 0) return existing;
3839
+ const pending = mkdir3(directory, { recursive: true, mode: 448 }).then(() => void 0).catch((error) => {
3840
+ hostServiceLogDirectories.delete(directory);
3841
+ throw error;
3842
+ });
3843
+ hostServiceLogDirectories.set(directory, pending);
3844
+ return pending;
4055
3845
  }
4056
3846
 
4057
3847
  // host/codex/src/codex-producer.ts
4058
- import { createHash as createHash6 } from "node:crypto";
4059
- var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
4060
3848
  var CodexProducer = class {
4061
- producer_id = "codex";
4062
- producer_label = "Codex";
4063
- outbox_directory;
4064
3849
  store;
4065
3850
  core;
4066
3851
  constructor(options) {
4067
3852
  this.store = new CodexOutboxStore(options.outbox_dir);
4068
- this.outbox_directory = this.store.directory;
4069
3853
  this.core = new HostProducerDrainCore(this, options);
4070
3854
  }
4071
3855
  drainOutbox() {
4072
3856
  return this.core.drainOutbox();
4073
3857
  }
4074
- fail(code, message) {
4075
- return new CodexHostAdapterError(code, message);
4076
- }
4077
3858
  listEnvelopes() {
4078
3859
  return this.store.list();
4079
3860
  }
4080
3861
  removeEnvelope(envelope) {
4081
3862
  return this.store.remove(envelope);
4082
3863
  }
4083
- submissionRefOf(envelope) {
4084
- return envelope.submission_ref;
4085
- }
4086
3864
  expiresAtOf(envelope) {
4087
3865
  return envelope.expires_at;
4088
3866
  }
4089
- createdAtOf(envelope) {
4090
- return envelope.created_at;
4091
- }
4092
- async mapEnvelope(envelope) {
4093
- const prompt = observation(envelope, "prompt");
4094
- if (prompt !== void 0) return this.mapInput(envelope, prompt);
4095
- return [mapTerminal(envelope)];
4096
- }
4097
- async mapInput(envelope, prompt) {
4098
- const drafts = [];
4099
- const session = observation(envelope, "session");
4100
- if (session !== void 0) {
4101
- const registrations = await this.store.listTranscriptRegistrations();
4102
- const registration = registrations.find((item) => item.host_source_ref === envelope.identity.host_source_ref && item.host_session_ref === envelope.identity.host_session_ref);
4103
- const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
4104
- drafts.push({ frame_kind: "session_started", payload: compact({
4105
- local_session_ref: envelope.identity.host_session_ref,
4106
- working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
4107
- model: recordText(session.value, "model"),
4108
- host_version: nestedText(session.value, "host_version"),
4109
- observations: [session]
4110
- }) });
4111
- }
4112
- const turn = observation(envelope, "turn");
4113
- if (turn !== void 0) drafts.push({ frame_kind: "turn_started", payload: compact({
4114
- local_session_ref: envelope.identity.host_session_ref,
4115
- local_turn_ref: localTurnRef(envelope),
4116
- observations: [turn]
4117
- }) });
4118
- if (!isCealHostPromptObservationValue(prompt.value)) throw new CodexHostAdapterError("storage", "Codex prompt observation is malformed.");
4119
- drafts.push({ frame_kind: "user_input", payload: compact({
4120
- local_session_ref: envelope.identity.host_session_ref,
4121
- local_turn_ref: localTurnRef(envelope),
4122
- local_input_ref: envelope.host_input_ref,
4123
- input_kind: envelope.input_kind,
4124
- origin_input: envelope.origin_input,
4125
- observations: [prompt],
4126
- local_turn_aliases: envelope.codex_turn_id === void 0 ? void 0 : [envelope.codex_turn_id],
4127
- context_expires_at: envelope.expires_at
4128
- }) });
4129
- return drafts;
4130
- }
4131
3867
  };
4132
- function mapTerminal(envelope) {
4133
- const timing = observation(envelope, "timing");
4134
- const timingValue = asRecord(timing?.value);
4135
- const aborted = timingValue?.terminal === "aborted";
4136
- const usage = envelope.observations.filter((item) => ["token", "cost", "model"].includes(item.observation_kind));
4137
- return { frame_kind: "turn_terminal", payload: compact({
4138
- local_session_ref: envelope.identity.host_session_ref,
4139
- local_turn_ref: localTurnRef(envelope),
4140
- terminal_state: aborted ? "aborted" : "completed",
4141
- abort_reason: aborted && typeof timingValue?.reason === "string" ? safeReasonRef(timingValue.reason) : void 0,
4142
- duration_ms: nonNegativeNumber(timingValue?.duration_ms),
4143
- time_to_first_token_ms: nonNegativeNumber(timingValue?.time_to_first_token_ms),
4144
- usage: usage.length === 0 ? void 0 : Object.fromEntries(usage.map((item) => [item.observation_kind, item.value])),
4145
- observations: envelope.observations
4146
- }) };
4147
- }
4148
- function observation(envelope, kind) {
4149
- return envelope.observations.find((item) => item.observation_kind === kind);
4150
- }
4151
- function localTurnRef(envelope) {
4152
- return envelope.identity.host_turn_ref;
4153
- }
4154
- function compact(value) {
4155
- return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
4156
- }
4157
- function asRecord(value) {
4158
- return isRecord8(value) ? value : void 0;
4159
- }
4160
- function recordText(value, key) {
4161
- const record3 = asRecord(value);
4162
- return typeof record3?.[key] === "string" ? record3[key] : void 0;
4163
- }
4164
- function nestedText(value, key) {
4165
- const nested = asRecord(asRecord(value)?.[key]);
4166
- return typeof nested?.value === "string" ? nested.value : void 0;
4167
- }
4168
- function nonNegativeNumber(value) {
4169
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
4170
- }
4171
- function safeReasonRef(value) {
4172
- return SAFE_REF8.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
4173
- }
4174
- function isRecord8(value) {
4175
- return value !== null && typeof value === "object" && !Array.isArray(value);
4176
- }
4177
3868
 
4178
3869
  // host/codex/src/codex-transcript-watcher.ts
4179
3870
  var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4180
3871
  store;
4181
- registerCurrentPrompt;
4182
- releaseCurrentPrompt;
4183
3872
  diagnostic;
4184
3873
  constructor(options) {
4185
3874
  super(options, {
@@ -4188,8 +3877,6 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4188
3877
  clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
4189
3878
  });
4190
3879
  this.store = new CodexOutboxStore(options.outbox_dir);
4191
- this.registerCurrentPrompt = options.register_current_prompt;
4192
- this.releaseCurrentPrompt = options.release_current_prompt;
4193
3880
  this.diagnostic = options.diagnostic ?? (() => void 0);
4194
3881
  }
4195
3882
  transcriptPathOf(registration) {
@@ -4212,14 +3899,12 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4212
3899
  return { records: 0, enqueued: 0, quarantined: true };
4213
3900
  }
4214
3901
  async retireMissing(registration) {
4215
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, await this.store.readTranscriptCursor(registration).catch(() => null));
4216
3902
  return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
4217
3903
  }
4218
3904
  async preflight(registration, handle, size, device, inode) {
4219
3905
  const existing = await this.store.readTranscriptCursor(registration);
4220
3906
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
4221
3907
  if (cursor.status === "quarantined") {
4222
- if (cursor.reason !== "transcript_malformed") await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
4223
3908
  return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
4224
3909
  }
4225
3910
  const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
@@ -4233,22 +3918,22 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4233
3918
  let records = 0;
4234
3919
  let enqueued = 0;
4235
3920
  for (const line of complete.toString("utf8").split("\n").filter((value) => value.length > 0)) {
4236
- const record3 = decodeCodexTranscriptLine(line);
4237
- assertRecordSequence(registration, cursor, records, lastOrdinal, record3);
4238
- await this.observeSessionMetadata(registration, record3);
4239
- const outcome = await this.processRecord(registration, activeTask, record3);
3921
+ const record = decodeCodexTranscriptLine(line);
3922
+ assertRecordSequence(registration, cursor, records, lastOrdinal, record);
3923
+ await this.observeSessionMetadata(registration, record);
3924
+ const outcome = await this.processRecord(registration, activeTask, record);
4240
3925
  activeTask = outcome.activeTask;
4241
3926
  enqueued += outcome.enqueued;
4242
- lastOrdinal = record3.ordinal;
3927
+ lastOrdinal = record.ordinal;
4243
3928
  records += 1;
4244
3929
  }
4245
3930
  await this.commitCursor(registration, handle, cursor, complete.length, device, inode, lastOrdinal, activeTask);
4246
3931
  return { records, enqueued, quarantined: false };
4247
3932
  }
4248
- async observeSessionMetadata(registration, record3) {
4249
- if (record3.kind !== "session_meta") return;
3933
+ async observeSessionMetadata(registration, record) {
3934
+ if (record.kind !== "session_meta") return;
4250
3935
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
4251
- if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
3936
+ if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record.cli_version } });
4252
3937
  }
4253
3938
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
4254
3939
  const offset = cursor.offset + consumedBytes;
@@ -4271,56 +3956,54 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4271
3956
  };
4272
3957
  await this.store.writeTranscriptCursor(quarantined);
4273
3958
  }
4274
- async processRecord(registration, activeTask, record3) {
4275
- if (record3.kind === "task_started") return this.processTaskStarted(registration, activeTask, record3);
4276
- if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
4277
- if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
4278
- if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
4279
- if (record3.kind === "task_complete" || record3.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record3);
3959
+ async processRecord(registration, activeTask, record) {
3960
+ if (record.kind === "task_started") return this.processTaskStarted(registration, record);
3961
+ if (record.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record.model } : activeTask }, enqueued: 0 };
3962
+ if (record.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record) }, enqueued: 0 };
3963
+ if (record.kind === "user_text") return this.processUserInput(registration, activeTask, record);
3964
+ if (record.kind === "task_complete" || record.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record);
4280
3965
  return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4281
3966
  }
4282
- async processTaskStarted(registration, activeTask, record3) {
4283
- if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4284
- return { activeTask: { codex_turn_id: record3.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id), started_at: record3.timestamp }, enqueued: 0 };
3967
+ async processTaskStarted(registration, record) {
3968
+ return { activeTask: { codex_turn_id: record.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record.turn_id), started_at: record.timestamp }, enqueued: 0 };
4285
3969
  }
4286
- async processUserInput(registration, activeTask, record3) {
4287
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) {
4288
- const adopted = await this.adoptHookCorrelatedTurn(registration, activeTask, record3);
3970
+ async processUserInput(registration, activeTask, record) {
3971
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record.turn_id) {
3972
+ const adopted = await this.adoptHookCorrelatedTurn(registration, record);
4289
3973
  if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4290
3974
  activeTask = adopted;
4291
3975
  }
4292
- const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
3976
+ const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record.turn_id, record.message_id, record.ordinal, record.prompt);
4293
3977
  const origin = activeTask.origin_host_input_ref === void 0;
4294
- const promptValue = promptObservationValue(record3.prompt);
3978
+ const promptValue = promptObservationValue(record.prompt);
4295
3979
  const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
4296
3980
  const promptRef = activeTask.prompt_ref ?? currentPromptRef;
4297
3981
  const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
4298
3982
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
4299
3983
  const observations = [{
4300
- observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
3984
+ observation_ref: observationRef(registration.host_source_ref, "transcript_user_text", hostInputRef, record.prompt),
4301
3985
  observation_kind: "prompt",
4302
- observed_at: record3.timestamp,
3986
+ observed_at: record.timestamp,
4303
3987
  value: promptValue
4304
3988
  }];
4305
3989
  if (origin) {
4306
- observations.push({ observation_ref: observationRef("transcript_task_started", activeTask.host_turn_ref, record3.turn_id), observation_kind: "turn", observed_at: record3.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "started") });
3990
+ observations.push({ observation_ref: observationRef(registration.host_source_ref, "transcript_task_started", activeTask.host_turn_ref, record.turn_id), observation_kind: "turn", observed_at: record.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "started") });
4307
3991
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
4308
- if (session !== null) observations.push({ observation_ref: observationRef("transcript_session", registration.host_session_ref, session.value), observation_kind: "session", observed_at: record3.timestamp, value: session.value });
3992
+ if (session !== null) observations.push({ observation_ref: observationRef(registration.host_source_ref, "transcript_session", registration.host_session_ref, session.value), observation_kind: "session", observed_at: record.timestamp, value: session.value });
4309
3993
  }
4310
3994
  const envelope = {
4311
3995
  schema_version: "ceal.codex_observation_outbox.v1",
4312
3996
  identity,
4313
3997
  host_input_ref: hostInputRef,
4314
- input_kind: record3.input_kind,
4315
3998
  prompt_ref: promptRef,
4316
3999
  observations,
4317
- codex_turn_id: record3.turn_id,
4000
+ codex_turn_id: record.turn_id,
4318
4001
  origin_input: origin,
4319
- submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
4320
- created_at: record3.timestamp,
4002
+ submission_ref: codexSubmissionReference(hostInputRef, "input", record.ordinal),
4003
+ created_at: record.timestamp,
4321
4004
  expires_at: this.expire(this.outboxRetentionMs)
4322
4005
  };
4323
- const persisted = await this.persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
4006
+ const persisted = await this.persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
4324
4007
  if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
4325
4008
  return persisted;
4326
4009
  }
@@ -4347,40 +4030,21 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4347
4030
  * stay ignored. A stale active task for another turn releases first, the
4348
4031
  * same as a task_started supersession.
4349
4032
  */
4350
- async adoptHookCorrelatedTurn(registration, activeTask, record3) {
4351
- const currentPromptRef = hostProducerPromptRef(promptObservationValue(record3.prompt).body_sha256);
4033
+ async adoptHookCorrelatedTurn(registration, record) {
4034
+ const currentPromptRef = hostProducerPromptRef(promptObservationValue(record.prompt).body_sha256);
4352
4035
  const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
4353
4036
  if (selection?.prompt_ref !== currentPromptRef) return void 0;
4354
- if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) {
4355
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4356
- }
4357
4037
  return {
4358
- codex_turn_id: record3.turn_id,
4359
- host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id),
4360
- started_at: record3.timestamp
4038
+ codex_turn_id: record.turn_id,
4039
+ host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record.turn_id),
4040
+ started_at: record.timestamp
4361
4041
  };
4362
4042
  }
4363
- async persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
4364
- const custodyRegistered = await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
4365
- if (custodyRegistered) this.diagnostic("watcher_turn_observed");
4366
- try {
4367
- await this.store.put(envelope);
4368
- if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
4369
- } catch (error) {
4370
- if (custodyRegistered) await this.releasePrompt(registration.host_session_ref, activeTask, currentPromptRef).catch(() => void 0);
4371
- throw error;
4372
- }
4043
+ async persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
4044
+ await this.store.put(envelope);
4045
+ if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
4373
4046
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
4374
4047
  }
4375
- async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
4376
- if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return false;
4377
- const register = this.registerCurrentPrompt;
4378
- const installationRef = this.producerInstallationRef;
4379
- return registerHostCurrentPromptDiagnosed(
4380
- () => register({ producer_id: "codex", producer_installation_ref: installationRef, local_session_ref: registration.host_session_ref, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef, current_prompt: prompt, context_expires_at: expiresAt }),
4381
- (event) => this.diagnostic(event)
4382
- );
4383
- }
4384
4048
  async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
4385
4049
  try {
4386
4050
  const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
@@ -4392,41 +4056,27 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4392
4056
  throw error;
4393
4057
  }
4394
4058
  }
4395
- async releasePrompt(sessionRef, activeTask, promptRef) {
4396
- if (this.producerInstallationRef === void 0 || this.releaseCurrentPrompt === void 0) return;
4397
- await this.releaseCurrentPrompt({ producer_id: "codex", producer_installation_ref: this.producerInstallationRef, local_session_ref: sessionRef, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef });
4398
- }
4399
- async releaseStoredPromptBestEffort(sessionRef, cursor) {
4400
- await this.releaseActiveTaskBestEffort(sessionRef, cursor?.active_task);
4401
- }
4402
- async releaseActiveTaskBestEffort(sessionRef, activeTask) {
4403
- if (activeTask?.prompt_ref === void 0) return;
4404
- await this.releasePrompt(sessionRef, activeTask, activeTask.prompt_ref).catch(() => void 0);
4405
- }
4406
- async processTerminal(registration, activeTask, record3) {
4407
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id || activeTask.origin_host_input_ref === void 0 || activeTask.prompt_ref === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4059
+ async processTerminal(registration, activeTask, record) {
4060
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record.turn_id || activeTask.origin_host_input_ref === void 0 || activeTask.prompt_ref === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4408
4061
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
4409
- const timing = record3.kind === "task_complete" ? { status: "available", unit: "milliseconds", started_at: record3.started_at, completed_at: record3.completed_at, duration_ms: record3.duration_ms, time_to_first_token_ms: record3.time_to_first_token_ms } : { status: "available", unit: "milliseconds", started_at: record3.started_at, completed_at: record3.completed_at, duration_ms: record3.duration_ms, terminal: "aborted", reason: record3.reason };
4410
- const observations = terminalObservations(registration, activeTask, record3, timing);
4062
+ const timing = record.kind === "task_complete" ? { status: "available", unit: "milliseconds", started_at: record.started_at, completed_at: record.completed_at, duration_ms: record.duration_ms, time_to_first_token_ms: record.time_to_first_token_ms } : { status: "available", unit: "milliseconds", started_at: record.started_at, completed_at: record.completed_at, duration_ms: record.duration_ms, terminal: "aborted", reason: record.reason };
4063
+ const observations = terminalObservations(registration, activeTask, record, timing);
4411
4064
  await this.store.put({
4412
4065
  schema_version: "ceal.codex_observation_outbox.v1",
4413
4066
  identity,
4414
4067
  host_input_ref: activeTask.origin_host_input_ref,
4415
- input_kind: "host_automatic",
4416
4068
  prompt_ref: activeTask.prompt_ref,
4417
4069
  observations,
4418
- codex_turn_id: record3.turn_id,
4070
+ codex_turn_id: record.turn_id,
4419
4071
  origin_input: false,
4420
- submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
4421
- created_at: record3.timestamp,
4072
+ submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record.ordinal),
4073
+ created_at: record.timestamp,
4422
4074
  expires_at: this.expire(this.outboxRetentionMs)
4423
4075
  });
4424
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4425
4076
  await this.store.clearInvocationContext(identity, this.now());
4426
4077
  return { enqueued: 1 };
4427
4078
  }
4428
4079
  async quarantine(registration, cursor, device, inode, reason) {
4429
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
4430
4080
  const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
4431
4081
  await this.store.writeTranscriptCursor(quarantined);
4432
4082
  }
@@ -4439,10 +4089,10 @@ function codexTranscriptScanFailureKind(error) {
4439
4089
  return void 0;
4440
4090
  });
4441
4091
  }
4442
- function accumulateTokenCount(activeTask, record3) {
4443
- if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
4444
- const last = record3.last_usage;
4445
- const total = record3.total_usage;
4092
+ function accumulateTokenCount(activeTask, record) {
4093
+ if (record.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record.usage_gap_reason };
4094
+ const last = record.last_usage;
4095
+ const total = record.total_usage;
4446
4096
  if (last === void 0 || ignoreTokenCount(activeTask.last_total_usage, total, last)) return activeTask;
4447
4097
  const tokenUsage = addUsage(activeTask.token_usage, last);
4448
4098
  return {
@@ -4456,21 +4106,16 @@ function ignoreTokenCount(previous, total, last) {
4456
4106
  if (total === void 0 || previous === void 0) return false;
4457
4107
  return sameUsage(total, previous) || regressedUsage(total, previous) && looksLikeStaleRegression(total, previous, last);
4458
4108
  }
4459
- function terminalObservations(registration, activeTask, record3, timing) {
4109
+ function terminalObservations(registration, activeTask, record, timing) {
4460
4110
  const tokenValue = activeTask.token_usage_gap_reason !== void 0 ? notRecorded(activeTask.token_usage_gap_reason) : activeTask.token_usage === void 0 ? notRecorded("token_count_not_observed_for_active_turn") : tokenObservationValue(activeTask.token_usage);
4461
- const costValue = terminalCostValue();
4462
4111
  const observations = [
4463
- { observation_ref: observationRef("transcript_terminal", activeTask.host_turn_ref, record3), observation_kind: "turn", observed_at: record3.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "stopped") },
4464
- { observation_ref: observationRef("transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record3.timestamp, value: timing },
4465
- { observation_ref: observationRef("transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record3.timestamp, value: tokenValue },
4466
- { observation_ref: observationRef("transcript_cost", activeTask.host_turn_ref, costValue), observation_kind: "cost", observed_at: record3.timestamp, value: costValue }
4112
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_terminal", activeTask.host_turn_ref, record), observation_kind: "turn", observed_at: record.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "stopped") },
4113
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record.timestamp, value: timing },
4114
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record.timestamp, value: tokenValue }
4467
4115
  ];
4468
- if (activeTask.model !== void 0) observations.push({ observation_ref: observationRef("transcript_model", activeTask.host_turn_ref, activeTask.model), observation_kind: "model", observed_at: record3.timestamp, value: { status: "available", value: activeTask.model, source: "turn_context.model" } });
4116
+ if (activeTask.model !== void 0) observations.push({ observation_ref: observationRef(registration.host_source_ref, "transcript_model", activeTask.host_turn_ref, activeTask.model), observation_kind: "model", observed_at: record.timestamp, value: { status: "available", value: activeTask.model, source: "turn_context.model" } });
4469
4117
  return observations;
4470
4118
  }
4471
- function terminalCostValue() {
4472
- return notRecorded("provider_cost_not_observed");
4473
- }
4474
4119
  function notRecorded(reason) {
4475
4120
  return hostObservationNotRecorded(reason);
4476
4121
  }
@@ -4517,25 +4162,21 @@ function looksLikeStaleRegression(current, previous, last) {
4517
4162
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
4518
4163
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
4519
4164
  }
4520
- function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
4521
- if ((cursor.header_validated || records > 0) && record3.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record3.ordinal, `greater than ${lastOrdinal}`)}).`);
4522
- if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
4165
+ function assertRecordSequence(registration, cursor, records, lastOrdinal, record) {
4166
+ if ((cursor.header_validated || records > 0) && record.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record.ordinal, `greater than ${lastOrdinal}`)}).`);
4167
+ if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record);
4523
4168
  }
4524
4169
 
4525
4170
  // host/codex/src/codex-producer-runtime.ts
4526
4171
  async function drainCodexProducerOnce(options) {
4527
- const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
4528
4172
  const scan = await new CodexTranscriptWatcher({
4529
4173
  outbox_dir: options.outbox_dir,
4530
- producer_installation_ref: options.producer_installation_ref,
4531
- register_current_prompt: (input) => promptPort.register(input),
4532
- release_current_prompt: (identity) => promptPort.release(identity),
4533
4174
  diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
4534
4175
  }).scanOnce().catch((error) => {
4535
4176
  writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
4536
4177
  throw error;
4537
4178
  });
4538
- const producer = new CodexProducer({ outbox_dir: options.outbox_dir, producer_installation_ref: options.producer_installation_ref, relay: new HostRelayIpcAdmissionPort(options.relay_endpoint, options.timeout_ms), ...options.producer_epoch === void 0 ? {} : { producer_epoch: options.producer_epoch }, ...options.now === void 0 ? {} : { now: options.now } });
4179
+ const producer = new CodexProducer({ outbox_dir: options.outbox_dir, ...options.now === void 0 ? {} : { now: options.now } });
4539
4180
  return { scanned: scan.enqueued, ...await producer.drainOutbox() };
4540
4181
  }
4541
4182
 
@@ -4548,11 +4189,7 @@ var CODEX_PRODUCER_DESCRIPTOR = {
4548
4189
  extra_paths: [CODEX_SESSIONS_ROOT],
4549
4190
  config: (shared, extras) => ({ ...shared, codex_sessions_root: hostProducerExtraPath(extras, CODEX_SESSIONS_ROOT) }),
4550
4191
  runtime_options: (config) => Object.freeze({
4551
- outbox_dir: config.outbox_dir,
4552
- producer_installation_ref: config.producer_installation_ref,
4553
- producer_epoch: config.producer_epoch,
4554
- relay_endpoint: config.relay_endpoint,
4555
- timeout_ms: config.ipc_timeout_ms
4192
+ outbox_dir: config.outbox_dir
4556
4193
  }),
4557
4194
  drain: drainCodexProducerOnce
4558
4195
  };
@@ -4599,18 +4236,13 @@ async function readStdin(stdin) {
4599
4236
  return Buffer.concat(chunks).toString("utf8");
4600
4237
  }
4601
4238
  async function runCodexHookCli() {
4602
- const unavailableGateway = {
4603
- submitHostTurn: async () => {
4604
- throw new Error("Codex Gateway adapter is not configured");
4605
- }
4606
- };
4607
4239
  const args = process.argv.slice(2);
4608
- const owner = await installedCodexHookRunnerOptions(args, unavailableGateway);
4240
+ const owner = await installedCodexHookRunnerOptions(args);
4609
4241
  return runCodexHookProcess(args, process.stdin, owner);
4610
4242
  }
4611
- async function installedCodexHookRunnerOptions(args, gateway) {
4243
+ async function installedCodexHookRunnerOptions(args) {
4612
4244
  const config = await readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, parseHostProducerConfigFlag(args));
4613
- return { gateway, host_source_ref: config.host_source_ref, outbox_dir: config.outbox_dir, codex_sessions_root: config.codex_sessions_root };
4245
+ return { host_source_ref: config.host_source_ref, outbox_dir: config.outbox_dir, codex_sessions_root: config.codex_sessions_root };
4614
4246
  }
4615
4247
 
4616
4248
  // host/codex/bin/ceal-codex-hook.ts