@corca-org/ceal-host-linux-arm64 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.
@@ -3,7 +3,7 @@ import { createRequire as __cealCreateRequire } from "node:module";
3
3
  const require = __cealCreateRequire(import.meta.url);
4
4
 
5
5
  // host/producer-service.ts
6
- import { posix as posix3, win32 as win323 } from "node:path";
6
+ import { posix as posix3, win32 as win324 } from "node:path";
7
7
 
8
8
  // host/runtime-source-paths.ts
9
9
  import { createHash } from "node:crypto";
@@ -29,22 +29,17 @@ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platfor
29
29
  const sourceRoot = path.join(sourcesRoot, sourceId);
30
30
  const runtimeRoot = path.join(stateRoot, "run");
31
31
  const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
32
- assertHostRuntimeIpcLength(endpoint, platform);
33
32
  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 };
34
33
  }
35
- function assertHostRuntimeIpcLength(endpoint, platform) {
36
- if (platform === "win32") return;
37
- const maximum = platform === "linux" ? 107 : 103;
38
- 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" });
39
- }
40
34
  function assertHostProducerSourcePaths(stateRoot, config, producer, platform = process.platform) {
41
35
  const paths = hostRuntimeSourcePaths(stateRoot, config.host_source_ref, platform);
42
- 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.");
36
+ 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.");
37
+ return paths.endpoint;
43
38
  }
44
39
 
45
40
  // host/producer-service.ts
46
- import { constants } from "node:fs";
47
- import { lstat, open } from "node:fs/promises";
41
+ import { constants as constants2 } from "node:fs";
42
+ import { lstat as lstat2 } from "node:fs/promises";
48
43
 
49
44
  // packages/ceal-client-protocol/src/canonical-json.ts
50
45
  function cealCanonicalJson(value) {
@@ -73,16 +68,34 @@ function isPlainRecord(value) {
73
68
  return prototype === Object.prototype || prototype === null;
74
69
  }
75
70
 
71
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
72
+ import { createHash as createHash2 } from "node:crypto";
73
+
76
74
  // packages/ceal-client-protocol/client-wire-contract.json
77
75
  var client_wire_contract_default = {
78
76
  schema_version: "ceal.client_wire_contract.v1",
77
+ doctor: {
78
+ schema_version: "ceal.doctor.v1"
79
+ },
80
+ client_commands: {
81
+ doctor: ["doctor"],
82
+ version: ["version"],
83
+ access_group_list: ["access-group", "list"]
84
+ },
85
+ client_environment: {
86
+ environment_prefix: "CEAL",
87
+ context_override_suffixes: ["GATEWAY_ORIGIN", "GATEWAY_TRANSPORT_ORIGIN", "ACCESS_TOKEN", "CONTEXT_STORE_PATH"]
88
+ },
79
89
  canonical_json: {
80
90
  ordering: "utf16_code_unit_ascending"
81
91
  },
82
92
  artifact_descriptor: {
83
- operation_contract_bundle_schema_version: "ceal.operation_contract_bundle.v1",
84
- schema_version: "ceal.verified_artifact_descriptor.v1",
85
- binding_schema_version: "ceal.verified_artifact_binding.v1",
93
+ operation_contract_bundle_schema_name: "ceal.operation_contract_bundle",
94
+ operation_contract_bundle_fields: ["schema_version", "catalog_revision", "operations", "failure_guidance"],
95
+ schema_name: "ceal.verified_artifact_descriptor",
96
+ fields: ["schema_version", "kind", "media_type", "byte_count", "sha256", "binding"],
97
+ binding_schema_name: "ceal.verified_artifact_binding",
98
+ binding_fields: ["schema_version", "kind", "catalog_revision"],
86
99
  kind: "verified_artifact",
87
100
  binding_kind: "catalog",
88
101
  media_type: "application/json",
@@ -98,14 +111,16 @@ var client_wire_contract_default = {
98
111
  length: 72,
99
112
  pattern: "^catalog:[a-f0-9]{64}$"
100
113
  },
101
- envelope_max_bytes: 389
114
+ envelope_max_bytes: 407
102
115
  },
103
116
  command_request: {
104
- schema_version: "ceal.command_request.v1",
117
+ schema_name: "ceal.command_request",
118
+ fields: ["schema_version", "argv", "operation", "client_nonce", "context_token"],
105
119
  absolute_transport_max_bytes: 65536
106
120
  },
107
121
  command_resolution: {
108
- schema_version: "ceal.gateway_command_resolution.v1",
122
+ schema_name: "ceal.gateway_command_resolution",
123
+ 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"],
109
124
  authority: {
110
125
  anonymous: {
111
126
  state: "anonymous",
@@ -145,7 +160,8 @@ var client_wire_contract_default = {
145
160
  }
146
161
  },
147
162
  command_response: {
148
- schema_version: "ceal.command_response.v1",
163
+ schema_name: "ceal.command_response",
164
+ fields: ["schema_version", "exit_code", "document", "operation_id", "visible_output_max_bytes", "local_delivery", "verified_artifact"],
149
165
  descriptor_field: "verified_artifact",
150
166
  required_fields: [
151
167
  "schema_version",
@@ -169,29 +185,41 @@ var client_wire_contract_default = {
169
185
  "required_action_sequence",
170
186
  "withheld"
171
187
  ],
172
- prompt_field: "prompt",
173
- prompt_schema_version: "ceal.prompt.v1",
174
- focused_prompt_document_fields: [
175
- "catalog_revision",
176
- "prompt"
177
- ],
178
- focused_prompt_continuation_document_fields: [
179
- "catalog_revision",
180
- "remaining_work",
181
- "prompt"
182
- ],
183
188
  discovery_command: "discovery",
184
- discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
189
+ discovery_manifest_schema_name: "ceal.discovery_manifest",
190
+ discovery_manifest_fields: ["schema_version", "skill", "authority_scope", "connector_kinds", "personal_connector_kinds", "guide_markdown", "renderer_version", "digest"],
185
191
  discovery_manifest_document_fields: [
186
192
  "discovery_manifest"
187
193
  ],
188
194
  exit_code_max: 125,
189
195
  bare_document_max_bytes: 65536,
190
- complete_max_bytes: 66019
196
+ complete_max_bytes: 66046
197
+ },
198
+ host_invocation_authentication: {
199
+ request_schema_name: "ceal.host_invocation_authentication_request",
200
+ request_fields: [
201
+ "schema_version",
202
+ "client_nonce"
203
+ ],
204
+ result_schema_name: "ceal.host_invocation_authentication_result",
205
+ result_fields: [
206
+ "schema_version",
207
+ "context_token",
208
+ "expires_at"
209
+ ],
210
+ client_nonce: {
211
+ character_class_source: "A-Za-z0-9_-",
212
+ encoded_characters: 43
213
+ }
214
+ },
215
+ gateway_host_invocation_context_request: {
216
+ schema_name: "ceal.gateway_host_invocation_context_request",
217
+ fields: ["schema_version", "client_nonce", "context_expires_at", "request_work_context", "current_prompt", "visible_output_max_bytes"]
191
218
  },
192
219
  resource_stream: {
193
220
  path: "/api/ceal/v2/resources",
194
- request_schema_version: "ceal.resource_stream_request.v1",
221
+ request_schema_name: "ceal.resource_stream_request",
222
+ request_fields: ["schema_version", "resource_ref", "client_nonce", "context_token"],
195
223
  ref_pattern: "^resource:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
196
224
  media_type_pattern: "^[a-z0-9][a-z0-9!#$&^_.+-]{0,63}/[a-z0-9][a-z0-9!#$&^_.+-]{0,63}$",
197
225
  filename_max_bytes: 512,
@@ -208,88 +236,6 @@ var client_wire_contract_default = {
208
236
  }
209
237
  };
210
238
 
211
- // packages/ceal-client-protocol/src/client-wire-contract.ts
212
- var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
213
- var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
214
- var commandResolutionAuthority = commandResolution.authority;
215
- var commandResolutionSemanticOptions = commandResolution.semantic_options;
216
- var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = commandResolution.schema_version;
217
- var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
218
- var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
219
- var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
220
- var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
221
- var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = artifact.operation_contract_bundle_schema_version;
222
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = artifact.schema_version;
223
- var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = artifact.binding_schema_version;
224
- var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
225
- var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
226
- var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
227
- var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
228
- var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
229
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
230
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
231
- var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
232
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
233
- var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
234
- var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
235
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
236
- var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
237
- var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
238
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
239
- var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
240
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
241
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
242
- var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
243
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
244
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
245
-
246
- // packages/ceal-client-protocol/src/vocabulary.ts
247
- function vocabulary(words) {
248
- return Object.freeze(words);
249
- }
250
-
251
- // packages/ceal-client-protocol/src/gateway-response-types.ts
252
- var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
253
- var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
254
- var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
255
- var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
256
- 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"]);
257
- var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
258
- var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
259
- var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
260
- var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
261
- var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
262
- var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
263
- var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
264
- var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
265
- var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
266
- var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
267
- var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
268
- var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
269
- var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
270
- var CEAL_PROTOCOL_VERSION = "1.4.0";
271
- var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
272
- var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
273
- var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
274
- "audited_call_pending",
275
- "continuation_read_pending",
276
- "continuation_write_pending",
277
- "provider_pacing_pending",
278
- "corpus_replay_pending",
279
- "corpus_append_pending",
280
- "corpus_fence_pending",
281
- "corpus_content_pending",
282
- "corpus_transaction_pending"
283
- ]);
284
- var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
285
- var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
286
- var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
287
- var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
288
- "connector_ref",
289
- "connector_revision",
290
- "policy_decision_revision"
291
- ]);
292
-
293
239
  // packages/ceal-client-protocol/src/operation-next-actions.ts
294
240
  var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
295
241
  var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
@@ -356,7 +302,10 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
356
302
  "follow_required_action_sequence",
357
303
  // The command needs caller-owned local materialization (for example an
358
304
  // @path file) before the Gateway can receive the argument.
359
- "materialize_local_argument"
305
+ "materialize_local_argument",
306
+ // A peer's derived schema identifier changed with its field set; install or
307
+ // upgrade the CLI and Host Relay to the Gateway's release before retrying.
308
+ "upgrade_ceal_client"
360
309
  ];
361
310
  var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
362
311
  var NON_REMEDY_NEXT_ACTION_VALUES = [
@@ -469,47 +418,53 @@ var CEAL_OPERATION_WITHHELD_NEXT_ACTIONS = Object.freeze({
469
418
  personal_authorization_required: "connect_personal_account"
470
419
  });
471
420
 
472
- // packages/ceal-client-protocol/src/operation-withheld-cause.ts
473
- var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
421
+ // packages/ceal-client-protocol/src/vocabulary.ts
422
+ function vocabulary(words) {
423
+ return Object.freeze(words);
424
+ }
474
425
 
475
- // packages/ceal-client-protocol/src/operation-contract-types.ts
476
- var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
477
- var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
478
- var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
479
- var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
480
- var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
481
- var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
482
- var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
483
- var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
484
- var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
485
- var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
486
- var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
487
- var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
488
- var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
489
- var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
490
- var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
491
- var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
492
- var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
493
- var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
494
- var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
495
- var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
496
- var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
497
- var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
498
- var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
499
- var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
500
- var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
501
- var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
502
- var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
503
- var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
504
- var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
505
- var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
506
- var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
507
- "approval_not_required_by_policy",
508
- "interactive_pending",
509
- "interactive_granted",
510
- "interactive_denied",
511
- "interactive_expired",
512
- "interactive_unavailable"
426
+ // packages/ceal-client-protocol/src/gateway-response-types.ts
427
+ var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
428
+ var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
429
+ var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
430
+ var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
431
+ 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"]);
432
+ var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
433
+ var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
434
+ var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
435
+ var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
436
+ var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
437
+ var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
438
+ var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
439
+ var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
440
+ var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
441
+ var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
442
+ var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
443
+ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
444
+ var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
445
+ var CEAL_PROTOCOL_VERSION = "1.4.0";
446
+ var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
447
+ var CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION = "ceal.gateway_call_result.v1";
448
+ var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
449
+ var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
450
+ "audited_call_pending",
451
+ "continuation_read_pending",
452
+ "continuation_write_pending",
453
+ "provider_pacing_pending",
454
+ "corpus_replay_pending",
455
+ "corpus_append_pending",
456
+ "corpus_fence_pending",
457
+ "corpus_content_pending",
458
+ "corpus_transaction_pending"
459
+ ]);
460
+ var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
461
+ var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
462
+ var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
463
+ var CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION = "ceal.gateway_audit_call_detail.v1";
464
+ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
465
+ "connector_ref",
466
+ "connector_revision",
467
+ "policy_decision_revision"
513
468
  ]);
514
469
 
515
470
  // packages/ceal-client-protocol/src/gateway-validation-primitives.ts
@@ -551,10 +506,10 @@ function assertSafeJsonArray(value, options, depth, count) {
551
506
  if (value.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
552
507
  for (const item of value) assertSafeJsonValue(item, options, depth + 1, count);
553
508
  }
554
- function assertSafeJsonRecord(record3, options, depth, count) {
555
- const entries = Object.entries(record3);
509
+ function assertSafeJsonRecord(record, options, depth, count) {
510
+ const entries = Object.entries(record);
556
511
  if (entries.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
557
- const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record3.fields) : null;
512
+ const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record.fields) : null;
558
513
  for (const [key, child] of entries) {
559
514
  if (key === "credential_material_included" && child !== false) invalidByContext(options);
560
515
  if (!isSafeNegativeMaterialAssertion(key, child)) assertSafeJsonKey(key, options);
@@ -723,51 +678,6 @@ function cut(text) {
723
678
  return text.length <= REFUSAL_VALUE_MAX_CHARS ? text : `${text.slice(0, REFUSAL_VALUE_MAX_CHARS)}...(+${text.length - REFUSAL_VALUE_MAX_CHARS} chars)`;
724
679
  }
725
680
 
726
- // packages/ceal-client-protocol/src/operation-access-class.ts
727
- var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
728
-
729
- // packages/ceal-client-protocol/src/domain-vocabulary.ts
730
- var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
731
- var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
732
- var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
733
- var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
734
- var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
735
- var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
736
- var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
737
- var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
738
- var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
739
- var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
740
- var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
741
- var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
742
-
743
- // packages/ceal-client-protocol/src/safe-json-budget.ts
744
- var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
745
- function safeJsonNodeBudgetForBytes(maxBytes) {
746
- if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
747
- throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
748
- }
749
- return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
750
- }
751
-
752
- // packages/ceal-client-protocol/src/protocol-bounds.ts
753
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
754
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
755
- var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
756
- var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
757
- max_depth: 8,
758
- max_properties: 96,
759
- max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
760
- max_alternatives: 8,
761
- max_enum_values: 64,
762
- max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
763
- /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
764
- max_description_characters: 1024,
765
- /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
766
- max_pattern_characters: 256,
767
- /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
768
- max_literal_nodes: 512
769
- });
770
-
771
681
  // packages/ceal-client-protocol/src/operation-validation-primitives.ts
772
682
  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;
773
683
  var CEAL_CALENDAR_DATE_PATTERN_SOURCE = "^\\d{4}-\\d{2}-\\d{2}$";
@@ -835,6 +745,317 @@ function requireIsoTimestamp(value, message) {
835
745
  if (!isCealIsoTimestamp(value)) throw new TypeError(message);
836
746
  }
837
747
 
748
+ // packages/ceal-client-protocol/src/failure-guidance-table.ts
749
+ var CEAL_FAILURE_REDACTION_CLASSES = vocabulary(["model_safe", "withheld"]);
750
+ var CEAL_GATEWAY_STARTING_FAILURE_CODE = "gateway_starting";
751
+ var CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE = "bootstrap_absent";
752
+ var CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE = "bootstrap_unavailable";
753
+ var LOCAL_COMMAND_INVALID = "The local command or argument is invalid.";
754
+ var LOCAL_TRANSPORT_INCOMPLETE = "The local Ceal transport could not complete; report this as a gap.";
755
+ var GATEWAY_TRANSPORT_UNAVAILABLE = "The Gateway transport is unavailable; ask an administrator to restore Gateway availability.";
756
+ var HOST_AUTHENTICATION_UNAVAILABLE = "The Host could not authenticate this invocation; report this as a gap.";
757
+ var SESSION_CONTEXT_UNAVAILABLE = "The local Gateway session context is unavailable.";
758
+ function guidance(message, next_action, http_status, retryable = false, redaction_class = "model_safe") {
759
+ return Object.freeze({ message, next_action, http_status, retryable, redaction_class });
760
+ }
761
+ var CEAL_FAILURE_GUIDANCE_TABLE = Object.freeze({
762
+ invalid_command: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
763
+ invalid_argument: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
764
+ command_not_found: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 404),
765
+ 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),
766
+ local_route_unavailable: guidance("The requested local route is unavailable or its descriptor is invalid; report this as a gap.", "answer_with_gap", 404),
767
+ local_route_ambiguous: guidance("The requested local route is ambiguous; no local executable was selected. Report this as a gap.", "answer_with_gap", 400),
768
+ local_execution_unavailable: guidance("The selected local route executable is unavailable; report this as a gap.", "answer_with_gap", 500),
769
+ local_pickup_failed: guidance("The Host Request pickup failed; the Gateway command was not sent. Report this as a gap.", "answer_with_gap", 502),
770
+ invocation_authentication_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
771
+ 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),
772
+ gateway_origin_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
773
+ access_token_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
774
+ context_pair_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
775
+ context_not_selected: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
776
+ context_store_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
777
+ context_store_conflict: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
778
+ refresh_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
779
+ refresh_expired: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
780
+ refresh_replayed: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
781
+ refresh_revoked: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
782
+ refresh_recovery_unavailable: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
783
+ refresh_custody_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
784
+ 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),
785
+ local_output_exists: guidance("The selected local output path already exists; nothing was written to it.", "choose_new_output_path", 400),
786
+ 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),
787
+ 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),
788
+ 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),
789
+ 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),
790
+ 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),
791
+ response_encoding_failed: guidance("The local response could not be encoded; report this as a gap.", "answer_with_gap", 500),
792
+ request_timeout: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 504),
793
+ request_failed: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 502),
794
+ gateway_unavailable: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 503, true),
795
+ 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),
796
+ // `gateway_starting` is the one retryable envelope the serving gate answers on every route while starting
797
+ // (`cli/internal/client/gateway_startup_wait.go` re-drives it); the sentence is the client default that renders
798
+ // when the wait ends still unserved, moved from the `localFailureText` default branch.
799
+ [CEAL_GATEWAY_STARTING_FAILURE_CODE]: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503, true),
800
+ gateway_internal_error: guidance("The Gateway failed without exposing internal state; report this as a gap.", "answer_with_gap", 500),
801
+ // The serving gate emits this code with no message; the sentence is the owner-normalized form of the
802
+ // `gateway_internal_error` guidance (decided with the operator 2026-10-13).
803
+ internal_error: guidance("The Gateway failed without exposing internal state.", "answer_with_gap", 500),
804
+ // Owned by the Gateway canonical adapter (`gateway/core/src/gateway-canonical-operation-http-adapter.ts`):
805
+ // the client variant of this sentence in `localFailureText` was retired when the client started reading this table.
806
+ request_body_too_large: guidance("The Gateway request body exceeds its bounded limit.", "reduce_request_size", 413),
807
+ // Restored verbatim from the retired `localFailureText` `unknown_outcome`
808
+ // case: the outcome is unknown, so a read may be retried while a write
809
+ // must receipt-check first. Collapsing both to "do not repeat the call"
810
+ // forbids the safe read retry the sentence exists to allow.
811
+ 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),
812
+ // Restored verbatim from the retired `localFailureText`
813
+ // `refresh_unknown_outcome` case: a refresh that ends unknown leaves the
814
+ // session context unavailable, so the caller repairs or adopts the
815
+ // session instead of reporting a transport gap.
816
+ refresh_unknown_outcome: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
817
+ request_cancelled: guidance("The caller cancelled the request before it completed.", "retry", 400, true),
818
+ 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),
819
+ denied: guidance("An administrator denied this device's activation request; ask an administrator whether to reconsider it.", "ask_admin", 403),
820
+ 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),
821
+ 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),
822
+ 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),
823
+ recovery_required: guidance("The Gateway could not safely complete the activation transaction automatically; ask an administrator to recover this transaction.", "ask_admin", 500),
824
+ 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),
825
+ // Activation commit codes rendered through the `localFailureText` default before phase 2b; `retryable` is moved from the
826
+ // emitting sites in `cli/internal/client/gateway_installation_activation.go` and `activation.go:483`.
827
+ activation_state_commit_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500, true),
828
+ activation_response_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502, true),
829
+ activation_rejected: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
830
+ activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
831
+ activation_binding: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
832
+ activation_crypto: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
833
+ activation_state_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
834
+ // Long-tail local codes rendered through the `localFailureText` default before phase 2b; sentences moved from that branch.
835
+ invalid_response: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
836
+ invalid_configuration: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
837
+ activation_state_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
838
+ activation_code_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
839
+ activation_code_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
840
+ activation_code_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 404),
841
+ bootstrap_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
842
+ bootstrap_not_active: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
843
+ bootstrap_unauthorized: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
844
+ // The Gateway owner-bootstrap store file was never created, so the Gateway
845
+ // holds no owner bootstrap to exchange (`gateway/src/host/owner-bootstrap-http-composition.ts`
846
+ // `absent`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:162`);
847
+ // the sentence is the owner-normalized form of that store error. Non-retryable:
848
+ // repeating the exchange cannot create the store; only an administrator
849
+ // placing a bootstrap (fresh gateway setup) changes the outcome.
850
+ [CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE]: guidance("The Gateway holds no owner bootstrap to exchange; report this as a gap.", "answer_with_gap", 503),
851
+ // The Gateway owner-bootstrap store file exists but cannot be read, so the
852
+ // exchange cannot proceed (`gateway/src/host/owner-bootstrap-http-composition.ts`
853
+ // `unavailable`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:163`);
854
+ // the sentence is the owner-normalized form of that store error. Retryable:
855
+ // unlike `absent`, a later exchange may succeed once the store is readable.
856
+ [CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE]: guidance("The Gateway owner bootstrap store is unavailable; retry the exchange.", "retry", 503, true),
857
+ context_selection_ambiguous: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
858
+ session_authority_unverified: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
859
+ session_authority_mismatch: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
860
+ local_credential_lost: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
861
+ local_capability_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
862
+ host_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
863
+ host_activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
864
+ doctor_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
865
+ admin_sign_in_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
866
+ // `invalid_request` renders through the client default today (local encode/path faults); Gateway-answered
867
+ // envelopes carry the Gateway message verbatim and never read this sentence.
868
+ invalid_request: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
869
+ // Gateway canonical-route codes, sentences moved from their minting adapters; statuses moved from the
870
+ // `valid*Failure` decoder maps in `cli/internal/client/gateway_api.go` and `transport.go`.
871
+ invalid_json: guidance("The Gateway request body must be valid JSON.", "answer_with_gap", 400),
872
+ // Per-route variants name their route; the table holds the one stable guidance and the route's `allow`
873
+ // header stays the measured fact (decided with the operator 2026-10-13).
874
+ method_not_allowed: guidance("The HTTP method is not allowed for this Gateway route.", "answer_with_gap", 405),
875
+ request_target_too_large: guidance("The Gateway request target exceeds its bounded limit.", "reduce_request_size", 414),
876
+ route_not_found: guidance("The Gateway route is not present.", "answer_with_gap", 404),
877
+ artifact_unavailable: guidance("The Gateway artifact is unavailable.", "answer_with_gap", 503),
878
+ discovery_unavailable: guidance("The Gateway discovery manifest is unavailable.", "answer_with_gap", 503),
879
+ serialization_failed: guidance("The Gateway response could not be serialized.", "answer_with_gap", 500),
880
+ request_header_too_large: guidance("A consumed Gateway request header exceeds its bounded limit.", "answer_with_gap", 431),
881
+ request_work_context_missing: guidance("The Gateway command requires a Request work context.", "answer_with_gap", 400),
882
+ request_work_context_invalid: guidance("The Gateway Request work context encoding is invalid.", "answer_with_gap", 400),
883
+ request_work_context_refused: guidance("The Host-only discovery manifest takes no Request work context.", "answer_with_gap", 400),
884
+ // Moved from `gateway/src/operations/http-composition.ts` (`unauthorized`) and `command-runtime.ts:827`
885
+ // (`artifact_stale`); both travel with Gateway messages verbatim online, so these sentences are the
886
+ // owner fallback guidance. `unauthorized` re-authenticates through the session, hence its action.
887
+ unauthorized: guidance("Unauthorized.", "repair_or_adopt_session", 401),
888
+ artifact_stale: guidance("The requested contract artifact is not the current catalog artifact.", "answer_with_gap", 409),
889
+ // Host mint classifications. The CLI emits `invocation_authentication_unavailable` with the classification
890
+ // in its detail fact; rows without their own sentence share that code's moved sentence, while `next_action`
891
+ // is moved from `canonicalHostAuthenticationNextActions` (generated from `CEAL_HOST_AUTHENTICATION_POLICY`)
892
+ // and `retryable` from `hostAuthenticationFailureForCause` (`failure.nextAction == "retry"`). The three rows
893
+ // with their own sentences carry the retired policy remedies as Gateway-owned guidance. Statuses are the
894
+ // Gateway-owned mapping decided with the operator 2026-10-13. This covers every wire cause the maps at
895
+ // `host/invocation-authentication-command.ts:217-242` emit, through their policy classifications.
896
+ host_arguments_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 400),
897
+ host_configuration_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
898
+ host_session_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
899
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
900
+ // missing exact-turn fact names the fresh Host turn, not a reinstall.
901
+ 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),
902
+ host_invocation_context_stale: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
903
+ host_invocation_context_expired: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
904
+ host_source_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 403),
905
+ host_registration_credential_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 403),
906
+ host_mint_gateway_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 503),
907
+ host_mint_gateway_rate_limited: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 429),
908
+ host_mint_gateway_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
909
+ host_mint_gateway_response_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
910
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
911
+ // producer-frame fault names the administrator repair step.
912
+ host_producer_frame_invalid: guidance("Ask an administrator to inspect and repair the producer frame, then start a fresh Host turn.", "ask_admin", 400),
913
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
914
+ // sandboxed Relay socket names the run-alone retry.
915
+ 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),
916
+ host_relay_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 503),
917
+ host_mint_transient_retryable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 503, true),
918
+ host_mint_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
919
+ host_relay_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
920
+ host_refusal_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500)
921
+ });
922
+ var FAILURE_GUIDANCE_ENTRY_KEYS = Object.freeze(["message", "next_action", "http_status", "retryable", "redaction_class"]);
923
+
924
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
925
+ var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
926
+ var CEAL_CLIENT_DOCTOR_SCHEMA_VERSION = CEAL_CLIENT_WIRE_CONTRACT.doctor.schema_version;
927
+ var clientCommands = CEAL_CLIENT_WIRE_CONTRACT.client_commands;
928
+ var CEAL_CLIENT_DOCTOR_COMMAND = Object.freeze([...clientCommands.doctor]);
929
+ var CEAL_CLIENT_VERSION_COMMAND = Object.freeze([...clientCommands.version]);
930
+ var CEAL_CLIENT_ACCESS_GROUP_LIST_COMMAND = Object.freeze([...clientCommands.access_group_list]);
931
+ function deriveCealClientWireSchemaVersion(schema) {
932
+ 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))) {
933
+ throw new TypeError("Client wire schema name or field set is invalid.");
934
+ }
935
+ const fields = schema.fields.filter((field) => field !== "schema_version").sort();
936
+ const hash8 = createHash2("sha256").update(cealCanonicalJson(fields), "utf8").digest("hex").slice(0, 8);
937
+ return `${schema.schema_name}.v1.${hash8}`;
938
+ }
939
+ var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
940
+ var commandResolutionAuthority = commandResolution.authority;
941
+ var commandResolutionSemanticOptions = commandResolution.semantic_options;
942
+ var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(commandResolution);
943
+ var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
944
+ var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
945
+ var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
946
+ var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
947
+ var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.operation_contract_bundle_schema_name, fields: artifact.operation_contract_bundle_fields });
948
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(artifact);
949
+ var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.binding_schema_name, fields: artifact.binding_fields });
950
+ var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
951
+ var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
952
+ var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
953
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
954
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
955
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
956
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
957
+ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
958
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
959
+ var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(request);
960
+ var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
961
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
962
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
963
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
964
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: response.discovery_manifest_schema_name, fields: response.discovery_manifest_fields });
965
+ var CEAL_COMMAND_RESPONSE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(response);
966
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
967
+ 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 });
968
+ var CEAL_RESOURCE_STREAM_REQUEST_FIELDS = Object.freeze([...CEAL_CLIENT_WIRE_CONTRACT.resource_stream.request_fields]);
969
+
970
+ // packages/ceal-client-protocol/src/operation-withheld-cause.ts
971
+ var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
972
+
973
+ // packages/ceal-client-protocol/src/operation-contract-types.ts
974
+ var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
975
+ var CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION = "ceal.operation_descriptor.v1";
976
+ var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
977
+ var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
978
+ var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
979
+ var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
980
+ var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
981
+ var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
982
+ var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
983
+ var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
984
+ var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
985
+ var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
986
+ var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
987
+ var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
988
+ var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
989
+ var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
990
+ var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
991
+ var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
992
+ var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
993
+ var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
994
+ var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
995
+ var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
996
+ var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
997
+ var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
998
+ var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
999
+ var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
1000
+ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
1001
+ var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
1002
+ var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
1003
+ var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
1004
+ var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
1005
+ var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
1006
+ "approval_not_required_by_policy",
1007
+ "interactive_pending",
1008
+ "interactive_granted",
1009
+ "interactive_denied",
1010
+ "interactive_expired",
1011
+ "interactive_unavailable"
1012
+ ]);
1013
+
1014
+ // packages/ceal-client-protocol/src/operation-access-class.ts
1015
+ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
1016
+
1017
+ // packages/ceal-client-protocol/src/domain-vocabulary.ts
1018
+ var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
1019
+ var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
1020
+ var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
1021
+ var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
1022
+ var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
1023
+ var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
1024
+ var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
1025
+ var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
1026
+ var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
1027
+ var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
1028
+ var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
1029
+ var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
1030
+
1031
+ // packages/ceal-client-protocol/src/safe-json-budget.ts
1032
+ var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
1033
+ function safeJsonNodeBudgetForBytes(maxBytes) {
1034
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
1035
+ throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
1036
+ }
1037
+ return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
1038
+ }
1039
+
1040
+ // packages/ceal-client-protocol/src/protocol-bounds.ts
1041
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
1042
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
1043
+ var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
1044
+ var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
1045
+ max_depth: 8,
1046
+ max_properties: 96,
1047
+ max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
1048
+ max_alternatives: 8,
1049
+ max_enum_values: 64,
1050
+ max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
1051
+ /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
1052
+ max_description_characters: 1024,
1053
+ /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
1054
+ max_pattern_characters: 256,
1055
+ /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
1056
+ max_literal_nodes: 512
1057
+ });
1058
+
838
1059
  // packages/ceal-client-protocol/src/operation-json-schema.ts
839
1060
  var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
840
1061
 
@@ -876,12 +1097,12 @@ var CEAL_SCHEMA_LITERALS = [
876
1097
  "ceal.enrollment_result.v1",
877
1098
  "ceal.first_activation_causal_join.v1",
878
1099
  "ceal.gateway_announcement_policy.v1",
879
- "ceal.gateway_audit_call_detail.v1",
1100
+ CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION,
880
1101
  "ceal.gateway_audit_event.v1",
881
1102
  "ceal.gateway_audit_readback.v1",
882
1103
  "ceal.gateway_authorization_snapshot.v1",
883
1104
  "ceal.gateway_cache_origin.v1",
884
- "ceal.gateway_call_result.v1",
1105
+ CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION,
885
1106
  CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION,
886
1107
  "ceal.gateway_connector_route_failure.v1",
887
1108
  "ceal.gateway_discovery.v1",
@@ -906,7 +1127,7 @@ var CEAL_SCHEMA_LITERALS = [
906
1127
  "ceal.host_observation.v1",
907
1128
  "ceal.host_registration_request.v1",
908
1129
  "ceal.host_registration_result.v1",
909
- "ceal.operation_descriptor.v1",
1130
+ CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION,
910
1131
  "ceal.operation_error.v1",
911
1132
  "ceal.operation_failure.v1",
912
1133
  "ceal.operation_failure.compact.v1",
@@ -1011,10 +1232,20 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
1011
1232
  var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
1012
1233
  var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
1013
1234
 
1235
+ // packages/ceal-client-protocol/src/client-environment-generated.ts
1236
+ var CEAL_CLIENT_CONTEXT_OVERRIDE_ENVIRONMENTS = Object.freeze(["CEAL_GATEWAY_ORIGIN", "CEAL_GATEWAY_TRANSPORT_ORIGIN", "CEAL_ACCESS_TOKEN", "CEAL_CONTEXT_STORE_PATH"]);
1237
+
1238
+ // packages/ceal-client-protocol/src/client-process-contract.ts
1239
+ var CEAL_CLIENT_VERSION_SCHEMA_SUFFIX = ".version.v1";
1240
+ var CEAL_CLIENT_VERSION_SCHEMA_VERSION = `ceal${CEAL_CLIENT_VERSION_SCHEMA_SUFFIX}`;
1241
+
1014
1242
  // packages/ceal-client-protocol/src/bare-document.ts
1015
1243
  var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_fields;
1016
1244
  var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
1017
1245
 
1246
+ // packages/ceal-client-protocol/src/actor-kind.ts
1247
+ var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
1248
+
1018
1249
  // packages/ceal-client-protocol/src/resource-row.ts
1019
1250
  var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
1020
1251
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
@@ -1029,6 +1260,8 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
1029
1260
  "resource_created",
1030
1261
  "review_submitted",
1031
1262
  "comment_created",
1263
+ "reaction_created",
1264
+ "ceal_write_completed",
1032
1265
  "event_start",
1033
1266
  "all_day_start",
1034
1267
  "file_created",
@@ -1063,6 +1296,10 @@ var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
1063
1296
  "github.review.submitted",
1064
1297
  "github.issue_comment.created",
1065
1298
  "github.review_comment.created",
1299
+ "github.reaction.created",
1300
+ "github.reaction.deleted",
1301
+ "github.pull_request.review_requested",
1302
+ "github.pull_request.review_request_removed",
1066
1303
  "calendar.organized",
1067
1304
  "calendar.accepted_invite",
1068
1305
  "calendar.recorded",
@@ -1084,6 +1321,10 @@ var CEAL_ACTIVITY_EVENT_TIMESTAMP_BASIS_MAP = Object.freeze({
1084
1321
  "github.pull_request.opened": "resource_created",
1085
1322
  "github.issue.edited": "resource_modified",
1086
1323
  "github.pull_request.edited": "resource_modified",
1324
+ "github.reaction.created": "reaction_created",
1325
+ "github.reaction.deleted": "ceal_write_completed",
1326
+ "github.pull_request.review_requested": "ceal_write_completed",
1327
+ "github.pull_request.review_request_removed": "ceal_write_completed",
1087
1328
  "calendar.organized": "resource_created",
1088
1329
  "drive.file.created": "file_created",
1089
1330
  "drive.file.modified": "file_modified_by_me",
@@ -1107,6 +1348,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1107
1348
  source_url: { required: false, timestamp: false },
1108
1349
  source: { required: true, timestamp: false },
1109
1350
  owner: { required: false, timestamp: false },
1351
+ actor_kind: { required: false, timestamp: false },
1110
1352
  counterparts: { required: false, timestamp: false },
1111
1353
  attachments: { required: false, timestamp: false },
1112
1354
  created_at: { required: false, timestamp: true },
@@ -1114,9 +1356,18 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1114
1356
  modified_at: { required: false, timestamp: true },
1115
1357
  modified_at_local: { required: false, timestamp: true },
1116
1358
  viewed_by_me_at: { required: false, timestamp: true },
1359
+ modified_by_me_at: { required: false, timestamp: true },
1117
1360
  own_ceal_write: { required: false, timestamp: false },
1118
1361
  owned_by_me: { required: false, timestamp: false },
1362
+ mime_type: { required: false, timestamp: false },
1363
+ size_bytes: { required: false, timestamp: false },
1364
+ version: { required: false, timestamp: false },
1365
+ trashed: { required: false, timestamp: false },
1119
1366
  visibility: { required: false, timestamp: false },
1367
+ archived: { required: false, timestamp: false },
1368
+ tag: { required: false, timestamp: false },
1369
+ labels: { required: false, timestamp: false },
1370
+ labels_incomplete: { required: false, timestamp: false },
1120
1371
  start: { required: false, timestamp: false },
1121
1372
  end: { required: false, timestamp: false },
1122
1373
  status: { required: false, timestamp: false },
@@ -1189,18 +1440,29 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1189
1440
  // The serving gate answers this while the Gateway is still starting and the
1190
1441
  // refresh was never attempted; the same attempt stays retryable. It is never
1191
1442
  // stored by the session owner, only answered at the serving edge.
1192
- "gateway_starting"
1443
+ CEAL_GATEWAY_STARTING_FAILURE_CODE
1444
+ ]);
1445
+ var CEAL_CLIENT_REVOKE_FAILURE_CODES = vocabulary([
1446
+ "refresh_invalid",
1447
+ "refresh_expired",
1448
+ "refresh_replayed",
1449
+ "refresh_revoked"
1193
1450
  ]);
1451
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX = "ceal_personal_";
1452
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX = "ceal_refresh_";
1453
+ var PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN = "[A-Za-z0-9_-]{43}";
1454
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
1455
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
1194
1456
 
1195
1457
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
1196
- import { createHash as createHash2 } from "node:crypto";
1458
+ import { createHash as createHash3 } from "node:crypto";
1197
1459
  var DIGEST = /^[a-f0-9]{64}$/u;
1198
1460
  var CEAL_SHA256_DIGEST_PATTERN = DIGEST.source;
1199
1461
  function isCealDigest(value) {
1200
1462
  return typeof value === "string" && DIGEST.test(value);
1201
1463
  }
1202
1464
  function cealRequestSha256(value) {
1203
- return createHash2("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
1465
+ return createHash3("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
1204
1466
  }
1205
1467
  function operationRecord(value, message) {
1206
1468
  requireOperationRecord(value, message);
@@ -1216,40 +1478,71 @@ function requirePrefixedRef(value, prefix, message) {
1216
1478
  // packages/ceal-client-protocol/src/request-authority.ts
1217
1479
  var CEAL_REQUEST_SCHEMA_VERSION = "ceal.request.v1";
1218
1480
  var CEAL_REQUEST_ARTIFACT_OWNERS = vocabulary(["gateway", "host", "connector"]);
1219
- var CEAL_REQUEST_HOST_BINDING_KEYS = vocabulary(["prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
1481
+ var CEAL_HOST_INVOCATION_IDENTITY_KEYS = vocabulary(["host_session_ref", "host_turn_ref", "host_source_ref"]);
1220
1482
  var CEAL_REQUEST_ARTIFACT_RETENTION_CLASSES = vocabulary(["request", "source", "result"]);
1221
1483
  var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
1222
- 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"]);
1484
+ var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority"]);
1485
+ var CEAL_REQUEST_COMMON_PROPERTIES = Object.freeze({
1486
+ schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
1487
+ ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
1488
+ created_at: { type: "string", minLength: 1, maxLength: 64 },
1489
+ authority: {
1490
+ type: "object",
1491
+ maxProperties: 5,
1492
+ additionalProperties: false,
1493
+ properties: {
1494
+ instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1495
+ access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1496
+ principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1497
+ execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1498
+ authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1499
+ },
1500
+ required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
1501
+ }
1502
+ });
1503
+ var CEAL_REQUEST_HOST_PROPERTIES = Object.freeze({
1504
+ prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1505
+ host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1506
+ host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1507
+ host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1508
+ host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1509
+ });
1510
+ var CEAL_REQUEST_CALLER_PROPERTIES = Object.freeze({
1511
+ 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." },
1512
+ 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." }
1513
+ });
1514
+ var CEAL_REQUEST_OPTIONAL_PROPERTIES = Object.freeze({
1515
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1516
+ 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." }
1517
+ });
1518
+ var CEAL_REQUEST_HOST_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, ...CEAL_HOST_INVOCATION_IDENTITY_KEYS, "prompt_ref"]);
1519
+ var CEAL_REQUEST_CALLER_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, "caller_call_group_ref", "caller_call_input_sha256"]);
1223
1520
  var CEAL_REQUEST_JSON_SCHEMA = {
1224
1521
  type: "object",
1225
- maxProperties: 11,
1522
+ 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.",
1523
+ maxProperties: 13,
1226
1524
  additionalProperties: false,
1227
1525
  properties: {
1228
- schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
1229
- ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
1230
- created_at: { type: "string", minLength: 1, maxLength: 64 },
1231
- authority: {
1526
+ ...CEAL_REQUEST_COMMON_PROPERTIES,
1527
+ ...CEAL_REQUEST_HOST_PROPERTIES,
1528
+ ...CEAL_REQUEST_CALLER_PROPERTIES,
1529
+ ...CEAL_REQUEST_OPTIONAL_PROPERTIES
1530
+ },
1531
+ required: CEAL_REQUEST_KEYS,
1532
+ anyOf: [
1533
+ {
1232
1534
  type: "object",
1233
- maxProperties: 5,
1234
- additionalProperties: false,
1235
- properties: {
1236
- instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1237
- access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1238
- principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1239
- execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1240
- authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
1241
- },
1242
- required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
1535
+ required: CEAL_REQUEST_HOST_REQUIRED_KEYS,
1536
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_HOST_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
1537
+ additionalProperties: false
1243
1538
  },
1244
- prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1245
- host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1246
- host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1247
- host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1248
- host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1249
- requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1250
- 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." }
1251
- },
1252
- required: CEAL_REQUEST_KEYS
1539
+ {
1540
+ type: "object",
1541
+ required: CEAL_REQUEST_CALLER_REQUIRED_KEYS,
1542
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_CALLER_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
1543
+ additionalProperties: false
1544
+ }
1545
+ ]
1253
1546
  };
1254
1547
 
1255
1548
  // packages/ceal-client-protocol/src/request-operands.ts
@@ -1360,10 +1653,6 @@ var CEAL_REQUEST_RUN_BATCH_JSON_SCHEMA = {
1360
1653
  };
1361
1654
 
1362
1655
  // packages/ceal-client-protocol/src/host-observation.ts
1363
- var CEAL_HOST_INPUT_KINDS = vocabulary(["human", "host_automatic"]);
1364
- function isCealHostInputKind(value) {
1365
- return typeof value === "string" && CEAL_HOST_INPUT_KINDS.some((kind) => kind === value);
1366
- }
1367
1656
  var CEAL_HOST_OBSERVATION_REF_PREFIX = "host-observation:";
1368
1657
  var HOST_OBSERVATION_PRODUCER = /^[a-z][a-z0-9]{0,31}$/u;
1369
1658
  var HOST_OBSERVATION_DIGEST = /^[a-f0-9]{8,64}$/u;
@@ -1409,14 +1698,14 @@ function safeCount(value) {
1409
1698
  return Number.isSafeInteger(value) && Number(value) >= 0;
1410
1699
  }
1411
1700
  function validateCealHostObservationDraft(value) {
1412
- const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
1413
- requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
1414
- requireClosedValue(record3.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
1415
- requireIsoTimestamp(record3.observed_at, "Ceal Host observation time is invalid.");
1416
- assertHostObservationValue(record3.value, record3.observation_kind);
1701
+ const record = operationRecord(value, "Ceal Host observation draft is invalid.");
1702
+ requirePrefixedRef(record.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
1703
+ requireClosedValue(record.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
1704
+ requireIsoTimestamp(record.observed_at, "Ceal Host observation time is invalid.");
1705
+ assertHostObservationValue(record.value, record.observation_kind);
1417
1706
  }
1418
1707
  var CEAL_REQUEST_MAX_OBSERVATION_VALUE_BYTES = 64 * 1024;
1419
- var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "cost", "timing"]);
1708
+ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "timing"]);
1420
1709
  function isCealHostPromptObservationValue(value) {
1421
1710
  return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
1422
1711
  }
@@ -1539,16 +1828,41 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
1539
1828
  };
1540
1829
 
1541
1830
  // packages/ceal-client-protocol/src/host-invocation-authentication.ts
1542
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = "ceal.host_invocation_authentication_result.v1";
1543
- var CEAL_HOST_NONCE_ENCODED_CHARACTERS = 43;
1544
- var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
1545
- var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(`^ceal_context_[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
1546
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = new TextEncoder().encode(`${JSON.stringify({
1547
- schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA,
1548
- context_token: `ceal_context_${"A".repeat(CEAL_HOST_NONCE_ENCODED_CHARACTERS)}`,
1549
- expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
1550
- })}
1831
+ var hostInvocationAuthenticationContract = CEAL_CLIENT_WIRE_CONTRACT.host_invocation_authentication;
1832
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.request_schema_name, fields: hostInvocationAuthenticationContract.request_fields });
1833
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.request_fields]);
1834
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.result_schema_name, fields: hostInvocationAuthenticationContract.result_fields });
1835
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.result_fields]);
1836
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE = "^(?:0|[1-9][0-9]{0,8})$";
1837
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN = new RegExp(CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE, "u");
1838
+ var CEAL_HOST_INVOCATION_CONTEXT_REQUEST_MAX_BYTES = 16 * 1024;
1839
+ var CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_BYTES = 2 * 1024;
1840
+ var CEAL_HOST_CONTEXT_TOKEN_PREFIX = "ceal_context_";
1841
+ function deriveCealHostInvocationNonceContract(contract = CEAL_CLIENT_WIRE_CONTRACT) {
1842
+ const clientNonce = contract.host_invocation_authentication.client_nonce;
1843
+ return {
1844
+ encoded_characters: clientNonce.encoded_characters,
1845
+ client_nonce_pattern_source: `^[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`,
1846
+ context_token_pattern_source: `^${CEAL_HOST_CONTEXT_TOKEN_PREFIX}[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`
1847
+ };
1848
+ }
1849
+ var hostNonceContract = deriveCealHostInvocationNonceContract();
1850
+ var CEAL_HOST_NONCE_ENCODED_CHARACTERS = hostNonceContract.encoded_characters;
1851
+ var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(hostNonceContract.client_nonce_pattern_source, "u");
1852
+ var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(hostNonceContract.context_token_pattern_source, "u");
1853
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = deriveCealHostInvocationAuthenticationResultMaxBytes();
1854
+ function deriveCealHostInvocationAuthenticationResultMaxBytes(contract = CEAL_CLIENT_WIRE_CONTRACT) {
1855
+ const hostAuthentication = contract.host_invocation_authentication;
1856
+ const values = {
1857
+ schema_version: deriveCealClientWireSchemaVersion({ schema_name: hostAuthentication.result_schema_name, fields: hostAuthentication.result_fields }),
1858
+ context_token: `${CEAL_HOST_CONTEXT_TOKEN_PREFIX}${"A".repeat(hostAuthentication.client_nonce.encoded_characters)}`,
1859
+ expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
1860
+ };
1861
+ const fields = hostAuthentication.result_fields;
1862
+ if (fields.some((field) => !Object.hasOwn(values, field))) throw new TypeError("Host invocation result fields have no bounded sample value.");
1863
+ return new TextEncoder().encode(`${JSON.stringify(Object.fromEntries(fields.map((field) => [field, values[field]])))}
1551
1864
  `).byteLength;
1865
+ }
1552
1866
  var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
1553
1867
  "request_authority_unavailable",
1554
1868
  "request_missing",
@@ -1572,6 +1886,7 @@ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
1572
1886
  "host_credential_refused",
1573
1887
  "gateway_unavailable",
1574
1888
  "gateway_rate_limited",
1889
+ "contract_mismatch",
1575
1890
  "gateway_refused",
1576
1891
  "gateway_response_invalid",
1577
1892
  "producer_frame_invalid",
@@ -1586,19 +1901,23 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
1586
1901
  invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
1587
1902
  options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
1588
1903
  session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1589
- 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)" }),
1590
- context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1591
- no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
1592
- context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1593
- context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
1904
+ context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "retry" }),
1905
+ context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
1906
+ // `no_binding` now means the producer has no real current Host session. The
1907
+ // Host Relay never uses it for an uncreated Gateway Request; there is no
1908
+ // useful retry until the consumer is running inside a Host session.
1909
+ no_binding: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1910
+ context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
1911
+ context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "retry" }),
1594
1912
  host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
1595
1913
  host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
1596
1914
  gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
1597
1915
  gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
1916
+ contract_mismatch: Object.freeze({ classification: "contract_mismatch", next_action: "upgrade_ceal_client" }),
1598
1917
  gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
1599
1918
  gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
1600
- 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" }),
1601
- 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" }),
1919
+ producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin" }),
1920
+ relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox" }),
1602
1921
  relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
1603
1922
  transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
1604
1923
  mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
@@ -1613,10 +1932,6 @@ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
1613
1932
  "hook_invoked",
1614
1933
  "registration_written",
1615
1934
  "hook_failed",
1616
- "watcher_turn_observed",
1617
- "current_prompt_registered",
1618
- "current_prompt_registration_failed",
1619
- "current_prompt_capacity_exhausted",
1620
1935
  "activation_recorded",
1621
1936
  "activation_failed",
1622
1937
  "watcher_scan_failed",
@@ -1639,6 +1954,9 @@ var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "un
1639
1954
  var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
1640
1955
  var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
1641
1956
 
1957
+ // packages/ceal-client-protocol/src/discovery-manifest.ts
1958
+ var DISCOVERY_MANIFEST_KEYS = CEAL_CLIENT_WIRE_CONTRACT.command_response.discovery_manifest_fields;
1959
+
1642
1960
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
1643
1961
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
1644
1962
 
@@ -1697,6 +2015,7 @@ var ADMIN_UNAVAILABLE_REASONS = vocabulary([
1697
2015
  "legacy",
1698
2016
  "invalid_observation",
1699
2017
  "redacted",
2018
+ "organization_setting_disabled",
1700
2019
  "owner_unavailable",
1701
2020
  "unit_unknown",
1702
2021
  "retention_gap",
@@ -1726,15 +2045,13 @@ var ADMIN_APPROVAL_DISPOSITIONS = CEAL_OPERATION_APPROVAL_DISPOSITIONS;
1726
2045
  var ADMIN_APPROVAL_POSTURES = vocabulary([...ADMIN_APPROVAL_DISPOSITIONS, "not_applicable"]);
1727
2046
  var ADMIN_LINEAGE_NODE_KINDS = vocabulary(["source_read", "synthesis_preview", "approval", "effect", "readback"]);
1728
2047
 
1729
- // packages/ceal-client-protocol/src/actor-kind.ts
1730
- var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
1731
-
1732
2048
  // packages/ceal-client-protocol/src/device-enrollment.ts
1733
2049
  var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired", "denied"]);
1734
2050
  var POLL_RESULT_KEYS = Object.freeze(["retry_after_ms", "schema_version", "status"]);
1735
2051
 
1736
2052
  // packages/ceal-client-protocol/src/personal-client-session.ts
1737
2053
  var REFRESH_FAILURE_CODES = new Set(CEAL_REFRESH_FAILURE_CODES);
2054
+ var REVOKE_FAILURE_CODES = new Set(CEAL_CLIENT_REVOKE_FAILURE_CODES);
1738
2055
 
1739
2056
  // packages/ceal-client-protocol/src/index.ts
1740
2057
  var MAX_REQUEST_BYTES = 32 * 1024;
@@ -1757,6 +2074,125 @@ function waitForAbort(signal, milliseconds) {
1757
2074
  });
1758
2075
  }
1759
2076
 
2077
+ // host/secure-file.ts
2078
+ import { execFile } from "node:child_process";
2079
+ import { constants } from "node:fs";
2080
+ import { lstat, open } from "node:fs/promises";
2081
+ import { dirname, win32 as win323 } from "node:path";
2082
+ import { fileURLToPath } from "node:url";
2083
+ var SecureFileCustodyError = class extends Error {
2084
+ name = "SecureFileCustodyError";
2085
+ reason;
2086
+ constructor(reason, message) {
2087
+ super(message);
2088
+ this.reason = reason;
2089
+ }
2090
+ get code() {
2091
+ if (this.reason === "reparse_point") return "ELOOP";
2092
+ if (this.reason === "not_found") return "ENOENT";
2093
+ if (this.reason === "too_large") return "secure_file_too_large";
2094
+ if (this.reason === "already_exists") return "EEXIST";
2095
+ return this.reason === "not_private" ? "secure_file_not_private" : "secure_file_unavailable";
2096
+ }
2097
+ };
2098
+ var WINDOWS_SECUREFS_REFUSAL_SCHEMA = "ceal.host_securefs_refusal.v1";
2099
+ var WINDOWS_SECUREFS_TIMEOUT_MS = 1e4;
2100
+ var WINDOWS_SECUREFS_DIAGNOSTIC_BYTES = 4096;
2101
+ function secureOpenFlags(flags, platform) {
2102
+ if (platform === "win32") return flags;
2103
+ const nofollow = constants.O_NOFOLLOW;
2104
+ if (typeof nofollow === "number" && nofollow !== 0) return flags | nofollow;
2105
+ throw new Error("Secure file reads require O_NOFOLLOW on this platform.");
2106
+ }
2107
+ async function openNoFollow(path, flags = constants.O_RDONLY, mode, platform = process.platform, _custody = {}) {
2108
+ if (platform !== "win32") return await open(path, secureOpenFlags(flags, platform), mode);
2109
+ return await openWindowsIdentityScreened(path, flags, mode);
2110
+ }
2111
+ async function openWindowsIdentityScreened(path, flags, mode) {
2112
+ const handle = await open(path, flags, mode);
2113
+ try {
2114
+ const first = await handle.stat();
2115
+ if (!first.isFile()) throw new SecureFileCustodyError("not_private", "The Windows Host file is not a regular file.");
2116
+ await assertWindowsLinkFree(path, first);
2117
+ await assertWindowsIdentityStable(handle, first, path);
2118
+ return handle;
2119
+ } catch (error) {
2120
+ await handle.close();
2121
+ throw error;
2122
+ }
2123
+ }
2124
+ async function assertWindowsLinkFree(path, first) {
2125
+ const entry = await lstat(path);
2126
+ if (entry.isSymbolicLink() || entry.dev !== first.dev || entry.ino !== first.ino) {
2127
+ throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
2128
+ }
2129
+ }
2130
+ async function assertWindowsIdentityStable(handle, first, path) {
2131
+ const second = await handle.stat();
2132
+ if (second.dev !== first.dev || second.ino !== first.ino || second.size !== first.size || second.mtimeMs !== first.mtimeMs) {
2133
+ throw new SecureFileCustodyError("unavailable", "The Windows Host file changed while its identity was checked.");
2134
+ }
2135
+ const entry = await lstat(path);
2136
+ if (entry.isSymbolicLink()) throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
2137
+ if (entry.dev !== second.dev || entry.ino !== second.ino) throw new SecureFileCustodyError("unavailable", "The Windows Host file path no longer names the opened file.");
2138
+ }
2139
+ async function readPrivateFileWithSecurefs(path, maxBytes, custody = {}) {
2140
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new TypeError("The securefs read bound must be a positive safe integer.");
2141
+ const result = await runWindowsSecurefs(["internal", "securefs", "read-private-file", path, String(maxBytes)], maxBytes, custody);
2142
+ if (result.exit_code === 0 && result.stderr.length === 0 && result.stdout.length <= maxBytes) return result.stdout;
2143
+ if (result.stdout.length !== 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned bytes with a refusal.");
2144
+ if (result.exit_code === 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command exceeded its output contract.");
2145
+ throw securefsRefusal(result.stderr);
2146
+ }
2147
+ async function runWindowsSecurefs(args, maxBytes, custody) {
2148
+ if (custody.run_securefs_command !== void 0) return await custody.run_securefs_command(args);
2149
+ const executable = custody.securefs_executable ?? resolveInstalledHostExecutable();
2150
+ const processArgs = [...custody.securefs_args_prefix ?? [], ...args];
2151
+ return await new Promise((resolve, reject2) => {
2152
+ execFile(executable, processArgs, { encoding: "buffer", timeout: WINDOWS_SECUREFS_TIMEOUT_MS, maxBuffer: maxBytes + WINDOWS_SECUREFS_DIAGNOSTIC_BYTES }, (error, stdout, stderr) => {
2153
+ const exitCode = error === null ? 0 : typeof error.code === "number" ? error.code : null;
2154
+ if (exitCode === null) {
2155
+ reject2(new SecureFileCustodyError("unavailable", "The installed Windows Host securefs command could not run."));
2156
+ return;
2157
+ }
2158
+ resolve({ exit_code: exitCode, stdout: Buffer.from(stdout), stderr: Buffer.from(stderr) });
2159
+ });
2160
+ });
2161
+ }
2162
+ function securefsRefusal(stderr) {
2163
+ let value;
2164
+ try {
2165
+ value = JSON.parse(stderr.toString("utf8"));
2166
+ } catch {
2167
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned an unreadable refusal.");
2168
+ }
2169
+ if (!isRecord(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.");
2170
+ if (value.code === "reparse_point") return new SecureFileCustodyError("reparse_point", "The Windows Host securefs file is a reparse point.");
2171
+ if (value.code === "not_found") return new SecureFileCustodyError("not_found", "The Windows Host securefs file was not found.");
2172
+ if (value.code === "too_large") return new SecureFileCustodyError("too_large", "The Windows Host securefs file exceeds its read bound.");
2173
+ if (value.code === "already_exists") return new SecureFileCustodyError("already_exists", "The Windows Host securefs target already exists.");
2174
+ if (value.code === "not_private") return new SecureFileCustodyError("not_private", "The Windows Host securefs file is not private to the current user.");
2175
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command refused the file read.");
2176
+ }
2177
+ function resolveInstalledHostExecutable() {
2178
+ const privateRuntimeRoot = dirname(fileURLToPath(import.meta.url));
2179
+ return win323.join(privateRuntimeRoot, "..", "..", "bin", "ceal-host.exe");
2180
+ }
2181
+ function isRecord(value) {
2182
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2183
+ }
2184
+ function isOwnedBy(uid, expectedUid) {
2185
+ return Number.isSafeInteger(uid) && Number.isSafeInteger(expectedUid) && uid === expectedUid;
2186
+ }
2187
+ function isSelfOwned(uid, platform = process.platform, _handle) {
2188
+ if (platform === "win32" || typeof process.geteuid !== "function") return false;
2189
+ return isOwnedBy(uid, process.geteuid());
2190
+ }
2191
+ function isPrivateFileMode(mode, platform = process.platform, _handle) {
2192
+ if (platform === "win32") return false;
2193
+ return (mode & 63) === 0;
2194
+ }
2195
+
1760
2196
  // host/producer-service.ts
1761
2197
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1762
2198
  var HOST_PRODUCER_SERVE_COMMAND_PREFIX = ["serve", "--config"];
@@ -1769,18 +2205,19 @@ var HostProducerServiceError = class extends Error {
1769
2205
  }
1770
2206
  };
1771
2207
  var HOST_PRODUCER_CONFIG_KEYS = ["schema_version", "host_source_ref", "producer_installation_ref", "producer_epoch", "outbox_dir", "relay_endpoint"];
2208
+ var HOST_PRODUCER_CONFIG_ENDPOINT_KEY = "relay_endpoint";
1772
2209
  var HOST_PRODUCER_TIMING_DEFAULTS = Object.freeze({ reconcile_interval_ms: 250, retry_backoff_ms: 1e3, ipc_timeout_ms: 5e3 });
1773
2210
  function hostProducerExtraPath(extras, key) {
1774
2211
  const value = extras[key];
1775
- if (value === void 0) throw hostProducerError("invalid_config");
2212
+ if (value === void 0) throw hostProducerError("invalid_config", refusalFact(key, "missing", "an absolute path"));
1776
2213
  return value;
1777
2214
  }
1778
2215
  function parseHostProducerServeArgs(args, platform = process.platform) {
1779
2216
  return parseProducerServeArgs(args, platform, hostProducerError);
1780
2217
  }
1781
- async function readHostProducerConfig(descriptor, configPath, platform = process.platform) {
1782
- const config = decodeHostProducerConfigText(descriptor, await readProducerConfigText(configPath, platform, hostProducerError), platform);
1783
- const path = platform === "win32" ? win323 : posix3;
2218
+ async function readHostProducerConfig(descriptor, configPath, platform = process.platform, custody = {}) {
2219
+ const config = decodeHostProducerConfigText(descriptor, await readProducerConfigText(configPath, platform, hostProducerError, custody), platform);
2220
+ const path = platform === "win32" ? win324 : posix3;
1784
2221
  const root = path.resolve(config.outbox_dir, "../../../../..");
1785
2222
  try {
1786
2223
  assertHostProducerSourcePaths(root, config, descriptor.producer_id, platform);
@@ -1809,15 +2246,31 @@ function parseProducerServeArgs(args, platform, error) {
1809
2246
  assertProducerAbsolutePath(args[2], platform, "config", error);
1810
2247
  return args[2];
1811
2248
  }
1812
- async function readProducerConfigText(configPath, platform, error) {
1813
- assertProducerAbsolutePath(configPath, platform, "config", error);
2249
+ async function readProducerConfigText(configPath, platform, error, custody) {
2250
+ assertProducerAbsolutePath(configPath, process.platform, "config", error);
2251
+ if (platform === "win32") {
2252
+ let bytes;
2253
+ try {
2254
+ bytes = await readPrivateFileWithSecurefs(configPath, CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES, custody);
2255
+ } catch (cause) {
2256
+ if (cause instanceof SecureFileCustodyError && cause.reason === "not_private") throw error("config_not_private");
2257
+ 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}`));
2258
+ if (cause instanceof SecureFileCustodyError && cause.reason === "reparse_point") throw error("invalid_config");
2259
+ throw error("config_unavailable");
2260
+ }
2261
+ if (bytes.byteLength === 0) throw error("invalid_config", refusalFact("config_bytes", 0, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
2262
+ try {
2263
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
2264
+ } catch {
2265
+ throw error("invalid_config");
2266
+ }
2267
+ }
1814
2268
  const pathStat = await configPathStat(configPath, error);
1815
2269
  validateConfigFile(pathStat, platform, error);
1816
- const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
1817
- const handle = await openConfigFile(configPath, constants.O_RDONLY | noFollow, error);
2270
+ const handle = await openConfigFile(configPath, platform, error, custody);
1818
2271
  try {
1819
2272
  const opened = await handle.stat();
1820
- validateConfigFile(opened, platform, error);
2273
+ validateConfigFile(opened, platform, error, handle);
1821
2274
  validateOpenedFile(opened, pathStat, platform, error);
1822
2275
  return await readBoundedConfig(handle, opened.size, error);
1823
2276
  } finally {
@@ -1825,8 +2278,9 @@ async function readProducerConfigText(configPath, platform, error) {
1825
2278
  }
1826
2279
  }
1827
2280
  function decodeProducerConfigCore(text, options) {
2281
+ const ownership = producerConfigKeyOwnership(options.keys, options.platform);
1828
2282
  const value = parseCanonicalJson(text, options.error);
1829
- if (!isRecord(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
2283
+ if (!isRecord2(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 })));
1830
2284
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
1831
2285
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
1832
2286
  const producerEpoch = validateIdentity(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -1844,7 +2298,7 @@ function decodeProducerConfigCore(text, options) {
1844
2298
  producer_installation_ref: installationRef,
1845
2299
  producer_epoch: producerEpoch,
1846
2300
  outbox_dir: value.outbox_dir,
1847
- relay_endpoint: value.relay_endpoint,
2301
+ relay_endpoint: producerConfigEndpoint(value),
1848
2302
  reconcile_interval_ms: intervals[0],
1849
2303
  retry_backoff_ms: intervals[1],
1850
2304
  ipc_timeout_ms: intervals[2]
@@ -1861,8 +2315,15 @@ async function serveProducer(runtimeOptions, timing, signal, drain, wait = (mill
1861
2315
  if (!signal.aborted) await wait(delay, signal);
1862
2316
  }
1863
2317
  }
2318
+ function producerConfigKeyOwnership(keys, platform) {
2319
+ if (platform !== "win32") return { required: keys, tolerated: [] };
2320
+ return { required: keys.filter((key) => key !== HOST_PRODUCER_CONFIG_ENDPOINT_KEY), tolerated: [HOST_PRODUCER_CONFIG_ENDPOINT_KEY] };
2321
+ }
2322
+ function producerConfigEndpoint(value) {
2323
+ return typeof value.relay_endpoint === "string" ? value.relay_endpoint : "";
2324
+ }
1864
2325
  function assertProducerRelayEndpoint(value, platform, error) {
1865
- if (platform === "win32" && typeof value === "string" && /^\\\\\.\\pipe\\[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)) return;
2326
+ if (platform === "win32") return;
1866
2327
  assertProducerAbsolutePath(value, platform, "runtime", error);
1867
2328
  }
1868
2329
  function assertProducerAbsolutePath(value, platform, kind, error) {
@@ -1870,26 +2331,27 @@ function assertProducerAbsolutePath(value, platform, kind, error) {
1870
2331
  }
1871
2332
  async function configPathStat(configPath, error) {
1872
2333
  try {
1873
- return await lstat(configPath);
2334
+ return await lstat2(configPath);
1874
2335
  } catch {
1875
2336
  throw error("config_unavailable");
1876
2337
  }
1877
2338
  }
1878
- function validateConfigFile(value, platform, error) {
2339
+ function validateConfigFile(value, platform, error, handle) {
1879
2340
  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" }]));
1880
2341
  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}`));
1881
- 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" }]));
2342
+ 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" }]));
1882
2343
  }
1883
- async function openConfigFile(configPath, flags, error) {
2344
+ async function openConfigFile(configPath, platform, error, custody) {
1884
2345
  try {
1885
- return await open(configPath, flags);
1886
- } catch {
2346
+ return await openNoFollow(configPath, constants2.O_RDONLY, void 0, platform, custody);
2347
+ } catch (error_) {
2348
+ if (error_ instanceof SecureFileCustodyError) throw error(error_.reason === "not_private" ? "config_not_private" : "invalid_config");
1887
2349
  throw error("config_unavailable");
1888
2350
  }
1889
2351
  }
1890
2352
  function validateOpenedFile(opened, pathStat, platform, error) {
1891
2353
  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" }]));
1892
- 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) }]));
2354
+ 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) }]));
1893
2355
  }
1894
2356
  async function readBoundedConfig(handle, expectedBytes, error) {
1895
2357
  const buffer = Buffer.allocUnsafe(expectedBytes + 1);
@@ -1921,18 +2383,43 @@ function firstDifferenceIndex(left, right) {
1921
2383
  for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
1922
2384
  return shared;
1923
2385
  }
2386
+ function producerShapeFacts(value, options) {
2387
+ if (!isRecord2(value)) return [{ name: "config", value: "wrong_type", expected: "a record" }];
2388
+ const tolerated = options.tolerated ?? [];
2389
+ const allowed = [...options.keys, ...tolerated, ...Object.keys(HOST_PRODUCER_TIMING_DEFAULTS)];
2390
+ const facts = [
2391
+ ...Object.keys(value).filter((key) => !allowed.includes(key)).map((key) => ({ name: key, value: "unknown", expected: `one of ${[...options.keys, ...tolerated].join(", ")}` })),
2392
+ ...options.keys.filter((key) => !Object.hasOwn(value, key)).map((key) => ({ name: key, value: "missing", expected: "present" }))
2393
+ ];
2394
+ if (Object.hasOwn(value, "schema_version") && value.schema_version !== options.schema) facts.push({ name: "schema_version", value: "wrong_type", expected: options.schema });
2395
+ return facts;
2396
+ }
1924
2397
  function validateIdentity(sourceRef, installationRef, epoch, error) {
1925
- if (!SAFE_REF2.test(sourceRef) || !SAFE_REF2.test(installationRef) || !positive(epoch, 2147483647)) throw error("invalid_config");
2398
+ if (!SAFE_REF2.test(sourceRef) || !SAFE_REF2.test(installationRef) || !positive(epoch, 2147483647)) throw error("invalid_config", refusalFacts(producerIdentityFacts(sourceRef, installationRef, epoch)));
1926
2399
  return epoch;
1927
2400
  }
2401
+ function producerIdentityFacts(sourceRef, installationRef, epoch) {
2402
+ const facts = [];
2403
+ if (!SAFE_REF2.test(sourceRef)) facts.push({ name: "host_source_ref", value: "wrong_type", expected: "a safe reference" });
2404
+ if (!SAFE_REF2.test(installationRef)) facts.push({ name: "producer_installation_ref", value: "wrong_type", expected: "a safe reference" });
2405
+ if (!positive(epoch, 2147483647)) facts.push({ name: "producer_epoch", value: "wrong_type", expected: "a positive integer" });
2406
+ return facts;
2407
+ }
1928
2408
  function validateIntervals(reconcile, retry, timeout, error) {
1929
- if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
2409
+ if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config", refusalFacts(producerIntervalFacts(reconcile, retry, timeout)));
1930
2410
  return [reconcile, retry, timeout];
1931
2411
  }
1932
- function hasConfigKeys(value, required) {
1933
- return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
2412
+ function producerIntervalFacts(reconcile, retry, timeout) {
2413
+ const facts = [];
2414
+ if (!boundedMilliseconds(reconcile)) facts.push({ name: "reconcile_interval_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
2415
+ if (!boundedMilliseconds(retry)) facts.push({ name: "retry_backoff_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
2416
+ if (!boundedMilliseconds(timeout)) facts.push({ name: "ipc_timeout_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
2417
+ return facts;
1934
2418
  }
1935
- function isRecord(value) {
2419
+ function hasConfigKeys(value, required, tolerated = []) {
2420
+ 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));
2421
+ }
2422
+ function isRecord2(value) {
1936
2423
  return value !== null && typeof value === "object" && !Array.isArray(value);
1937
2424
  }
1938
2425
  function positive(value, maximum) {
@@ -1942,183 +2429,27 @@ function boundedMilliseconds(value) {
1942
2429
  return positive(value, 6e4) && Number(value) >= 25;
1943
2430
  }
1944
2431
 
1945
- // host/relay/src/producer-frame.ts
1946
- var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1947
- var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1948
- var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
1949
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1950
- var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
1951
- var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
1952
- var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
1953
- function isHostProducerFrameKind(value) {
1954
- return typeof value === "string" && FRAME_KINDS.has(value);
1955
- }
1956
- var HOST_PRODUCER_FRAME_ERROR_CODES = [
1957
- "invalid_frame_encoding",
1958
- "invalid_frame_length",
1959
- "frame_truncated",
1960
- "unsupported_frame_schema",
1961
- "invalid_frame_shape",
1962
- "invalid_producer_identity",
1963
- "frame_too_large"
1964
- ];
1965
- var HostProducerFrameError = class extends Error {
1966
- code;
1967
- constructor(code, message = code) {
1968
- super(message);
1969
- this.code = code;
1970
- }
1971
- };
1972
- function encodeHostProducerFrame(frame) {
1973
- validateFrame(frame);
1974
- const json = Buffer.from(JSON.stringify(frame), "utf8");
1975
- 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}`)}`);
1976
- const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
1977
- result.writeUInt32BE(json.byteLength, 0);
1978
- json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
1979
- return result;
1980
- }
1981
- function decodeHostProducerFrame(input) {
1982
- 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}`)}`);
1983
- const length = input.readUInt32BE(0);
1984
- 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}`)}`);
1985
- if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
1986
- 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");
1987
- const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
1988
- const text = new TextDecoder("utf-8", { fatal: true });
1989
- let value;
1990
- try {
1991
- value = JSON.parse(text.decode(bytes));
1992
- } catch (error) {
1993
- if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
1994
- throw new HostProducerFrameError("frame_truncated");
1995
- }
1996
- validateFrame(value);
1997
- return value;
1998
- }
1999
- function isHostSafeRef(value) {
2000
- return safeRef(value);
2001
- }
2002
- function validateFrame(value) {
2003
- if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
2004
- 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)}`);
2005
- if (!exactKeys(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
2006
- if (!PRODUCERS.has(String(value.producer_id)) || !safeRef(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
2007
- if (!positive2(value.producer_epoch) || !positive2(value.sequence) || !hostProducerFrameKind(value.frame_kind) || !timestamp(value.occurred_at) || !record(value.payload)) throw new HostProducerFrameError("invalid_frame_shape");
2008
- validatePayload(value.frame_kind, value.payload);
2009
- }
2010
- function validatePayload(kind, value) {
2011
- const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
2012
- if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
2013
- }
2014
- function validSession(value) {
2015
- return exactOptional(value, ["local_session_ref", "working_directory_ref"], ["model", "host_version", "observations"]) && safeRef(value.local_session_ref) && safeRef(value.working_directory_ref) && optionalText(value.model, 256) && optionalText(value.host_version, 256) && validObservations(value.observations);
2016
- }
2017
- function validTurn(value) {
2018
- return exactOptional(value, ["local_session_ref", "local_turn_ref"], ["model", "observations"]) && safeRef(value.local_session_ref) && safeRef(value.local_turn_ref) && optionalText(value.model, 256) && validObservations(value.observations);
2019
- }
2020
- function validInput(value) {
2021
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "local_input_ref", "input_kind", "origin_input", "observations"], ["local_turn_aliases", "context_expires_at"]) && safeRef(value.local_session_ref) && safeRef(value.local_turn_ref) && safeRef(value.local_input_ref) && validInputObservations(value.observations) && isCealHostInputKind(value.input_kind) && typeof value.origin_input === "boolean" && validInputOptionals(value);
2022
- }
2023
- function validInputObservations(value) {
2024
- return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
2025
- }
2026
- function validInputOptionals(value) {
2027
- return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp(value.context_expires_at));
2028
- }
2029
- function validTerminal(value) {
2030
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "terminal_state"], ["abort_reason", "duration_ms", "time_to_first_token_ms", "usage", "observations"]) && safeRef(value.local_session_ref) && safeRef(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);
2031
- }
2032
- function validTerminalDisposition(state, reason) {
2033
- return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef(reason));
2034
- }
2035
- function validStatus(value) {
2036
- return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef(value.reason_code) && optionalText(value.detail, 4096);
2037
- }
2038
- function optionalText(value, maxLength) {
2039
- return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
2040
- }
2041
- function optionalNonNegative(value) {
2042
- return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
2043
- }
2044
- function optionalRefs(value) {
2045
- return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef);
2046
- }
2047
- function validObservations(value) {
2048
- if (value === void 0) return true;
2049
- if (!Array.isArray(value) || value.length > 32) return false;
2050
- return value.every((item) => {
2051
- try {
2052
- validateCealHostObservationDraft(item);
2053
- return true;
2054
- } catch {
2055
- return false;
2056
- }
2057
- });
2058
- }
2059
- function jsonValue(value, depth = 0) {
2060
- if (depth > 16) return false;
2061
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2062
- if (typeof value === "number") return Number.isFinite(value);
2063
- if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
2064
- return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
2065
- }
2066
- function record(value) {
2067
- return value !== null && typeof value === "object" && !Array.isArray(value);
2068
- }
2069
- function safeRef(value) {
2070
- return typeof value === "string" && SAFE_REF3.test(value);
2071
- }
2072
- function positive2(value) {
2073
- return Number.isSafeInteger(value) && Number(value) > 0;
2074
- }
2075
- function timestamp(value) {
2076
- return typeof value === "string" && Number.isFinite(Date.parse(value));
2077
- }
2078
- function hostProducerFrameKind(value) {
2079
- return isHostProducerFrameKind(value);
2080
- }
2081
- function exactKeys(value, keys) {
2082
- return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
2083
- }
2084
- function exactOptional(value, required, optional) {
2085
- const keys = Object.keys(value);
2086
- return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2087
- }
2088
-
2089
- // host/relay/src/host-producer-core.ts
2090
- import { createHash as createHash3 } from "node:crypto";
2091
- import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
2092
- import { mkdir as mkdir2, open as open4, readFile, rename as rename2, writeFile } from "node:fs/promises";
2093
- import { join as join2 } from "node:path";
2094
-
2095
- // host/relay/src/relay-ipc.ts
2096
- import { createConnection, createServer } from "node:net";
2097
-
2098
- // host/relay/src/durable-atomic-replacement.ts
2099
- import { O_RDONLY } from "node:constants";
2100
- import { lstat as lstat2, mkdir, open as open2, rename, unlink } from "node:fs/promises";
2101
- var DEFAULT_PORT = {
2102
- platform: process.platform,
2103
- mkdir: (path, options) => mkdir(path, options),
2104
- lstat: (path) => lstat2(path),
2105
- open_file: (path) => open2(path, "wx", 384),
2106
- rename,
2107
- unlink,
2108
- open_directory: (path) => open2(path, O_RDONLY),
2109
- unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2110
- };
2111
-
2112
- // host/relay/src/relay-request-binding-store.ts
2113
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
2114
-
2115
- // host/relay/src/current-prompt-custody.ts
2116
- var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2117
-
2118
2432
  // host/service-log.ts
2119
- import { copyFile, open as open3, stat, truncate } from "node:fs/promises";
2120
- import { isAbsolute } from "node:path";
2433
+ import { copyFile, mkdir, stat, truncate, appendFile } from "node:fs/promises";
2434
+ import { dirname as dirname2, isAbsolute, posix as posix4, win32 as win325 } from "node:path";
2121
2435
  var HOST_SERVICE_LOG_ENVIRONMENT = "CEAL_HOST_SERVICE_LOG";
2436
+ var HOST_SERVICE_LOG_ARGUMENT = "--ceal-host-service-log";
2437
+ var HostServiceLogArgumentError = class extends Error {
2438
+ constructor() {
2439
+ super("The Host service log argument must occur once with an absolute normalized path.");
2440
+ this.name = "HostServiceLogArgumentError";
2441
+ }
2442
+ };
2443
+ function consumeHostServiceLogArgument(args, platform = process.platform) {
2444
+ const indexes = args.flatMap((value, index2) => value === HOST_SERVICE_LOG_ARGUMENT ? [index2] : []);
2445
+ if (indexes.length === 0) return { args: [...args] };
2446
+ const index = indexes[0];
2447
+ if (index === void 0) throw new HostServiceLogArgumentError();
2448
+ const path = args[index + 1];
2449
+ const pathApi = platform === "win32" ? win325 : posix4;
2450
+ if (indexes.length !== 1 || path === void 0 || !pathApi.isAbsolute(path) || pathApi.normalize(path) !== path) throw new HostServiceLogArgumentError();
2451
+ return { args: [...args.slice(0, index), ...args.slice(index + 2)], path };
2452
+ }
2122
2453
  function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
2123
2454
  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 } : {} })}
2124
2455
  `;
@@ -2128,6 +2459,7 @@ function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sin
2128
2459
  }
2129
2460
  }
2130
2461
  function defaultHostServiceDiagnosticSink(line) {
2462
+ writeHostServiceLogLine(line);
2131
2463
  process.stderr.write(line);
2132
2464
  }
2133
2465
  var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
@@ -2152,8 +2484,9 @@ function boundHostServiceLog(environment = process.env) {
2152
2484
  const path = environment[HOST_SERVICE_LOG_ENVIRONMENT];
2153
2485
  if (path === void 0 || !isAbsolute(path)) return () => void 0;
2154
2486
  let reported = false;
2487
+ const ready = ensureHostServiceLogDirectory(path);
2155
2488
  const check = () => {
2156
- rotateHostServiceLog(path).catch((error) => {
2489
+ ready.then(() => rotateHostServiceLog(path)).catch((error) => {
2157
2490
  if (reported) return;
2158
2491
  reported = true;
2159
2492
  process.stderr.write(`[host-service-log] rotation_failed code=${errorCode(error)}
@@ -2165,7 +2498,30 @@ function boundHostServiceLog(environment = process.env) {
2165
2498
  timer.unref();
2166
2499
  return () => clearInterval(timer);
2167
2500
  }
2501
+ function writeHostServiceLogLine(line, environment = process.env) {
2502
+ if (process.platform !== "win32") return;
2503
+ const path = environment[HOST_SERVICE_LOG_ENVIRONMENT];
2504
+ if (path === void 0 || !win325.isAbsolute(path) || win325.normalize(path) !== path) return;
2505
+ void appendHostServiceLogLine(path, line).catch(() => void 0);
2506
+ }
2507
+ async function appendHostServiceLogLine(path, line) {
2508
+ if (!isAbsolute(path)) return;
2509
+ await ensureHostServiceLogDirectory(path);
2510
+ await appendFile(path, line);
2511
+ }
2168
2512
  var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
2513
+ var hostServiceLogDirectories = /* @__PURE__ */ new Map();
2514
+ function ensureHostServiceLogDirectory(path) {
2515
+ const directory = dirname2(path);
2516
+ const existing = hostServiceLogDirectories.get(directory);
2517
+ if (existing !== void 0) return existing;
2518
+ const pending = mkdir(directory, { recursive: true, mode: 448 }).then(() => void 0).catch((error) => {
2519
+ hostServiceLogDirectories.delete(directory);
2520
+ throw error;
2521
+ });
2522
+ hostServiceLogDirectories.set(directory, pending);
2523
+ return pending;
2524
+ }
2169
2525
  function isNotFound(error) {
2170
2526
  return errorCode(error) === "ENOENT";
2171
2527
  }
@@ -2173,255 +2529,15 @@ function errorCode(error) {
2173
2529
  return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "unknown";
2174
2530
  }
2175
2531
 
2176
- // host/relay/src/relay-ipc.ts
2177
- var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
2178
- "schema_version",
2179
- "producer_id",
2180
- "producer_installation_ref",
2181
- "local_session_ref",
2182
- "local_turn_ref",
2183
- "local_turn_aliases",
2184
- "prompt_ref",
2185
- "request_ref",
2186
- "bound_at",
2187
- "host_source_ref",
2188
- "host_session_ref",
2189
- "host_turn_ref",
2190
- "host_input_ref"
2191
- ]);
2192
- var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
2193
- var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2194
- var HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA = "ceal.host_relay_current_prompt_release.v1";
2195
- var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2196
- var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2197
- var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
2198
- var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
2199
- "context_stale",
2200
- "context_expired",
2201
- "host_source_refused",
2202
- "host_credential_refused",
2203
- "gateway_unavailable",
2204
- "gateway_refused",
2205
- "gateway_response_invalid",
2206
- "gateway_rate_limited",
2207
- "producer_frame_invalid",
2208
- "deadline",
2209
- "cancelled",
2210
- "mint_failed",
2211
- "relay_failed",
2212
- "request_authority_unavailable",
2213
- "request_missing",
2214
- "authority_mismatch",
2215
- "host_source_mismatch",
2216
- "host_session_mismatch",
2217
- "host_turn_mismatch",
2218
- "host_input_mismatch",
2219
- "host_prompt_mismatch"
2220
- ]);
2221
- var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
2222
- "context_stale",
2223
- "context_expired",
2224
- "host_source_refused",
2225
- "host_credential_refused",
2226
- "gateway_unavailable",
2227
- "gateway_rate_limited",
2228
- "gateway_refused",
2229
- "gateway_response_invalid",
2230
- "producer_frame_invalid"
2231
- ]);
2232
- var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
2233
- var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2234
- "permission_denied",
2235
- "socket_missing",
2236
- "connection_refused",
2237
- "closed_early",
2238
- "response_invalid",
2239
- "timed_out",
2240
- "cancelled",
2241
- "unavailable"
2242
- ]);
2243
- var HostRelayIpcError = class extends Error {
2244
- code;
2245
- /** Set only when the client-side socket exchange itself failed. */
2246
- failure;
2247
- constructor(code, message = code, failure) {
2248
- super(message);
2249
- this.code = code;
2250
- this.failure = failure;
2251
- }
2252
- };
2253
- var HostRelayCurrentPromptCapacityRefusal = class extends Error {
2254
- constructor() {
2255
- super("current_prompt_capacity_exhausted");
2256
- this.name = "HostRelayCurrentPromptCapacityRefusal";
2257
- }
2258
- };
2259
- function hostRelayExchangeFailure(error) {
2260
- return error instanceof HostRelayIpcError ? error.failure : void 0;
2261
- }
2262
- function socketErrorFailure(error) {
2263
- switch (errorCode2(error)) {
2264
- case "EACCES":
2265
- case "EPERM":
2266
- return "permission_denied";
2267
- case "ENOENT":
2268
- return "socket_missing";
2269
- case "ECONNREFUSED":
2270
- return "connection_refused";
2271
- default:
2272
- return "unavailable";
2273
- }
2274
- }
2275
- var HostRelayIpcAdmissionPort = class {
2276
- endpoint;
2277
- timeout_ms;
2278
- constructor(endpoint, timeoutMs = 5e3) {
2279
- this.endpoint = endpoint;
2280
- this.timeout_ms = timeoutMs;
2281
- }
2282
- async admit(frame) {
2283
- const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
2284
- if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
2285
- return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
2286
- }
2287
- };
2288
- var HostRelayCurrentPromptPort = class {
2289
- endpoint;
2290
- timeout_ms;
2291
- constructor(endpoint, timeoutMs = 5e3) {
2292
- this.endpoint = endpoint;
2293
- this.timeout_ms = timeoutMs;
2294
- }
2295
- async register(input) {
2296
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
2297
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2298
- if (response2.status === "capacity_exhausted") throw new HostRelayCurrentPromptCapacityRefusal();
2299
- if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
2300
- }
2301
- async release(identity) {
2302
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA, ...identity };
2303
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2304
- if (response2.status !== "released") throw new HostRelayIpcError("relay_unavailable", response2.status, "response_invalid");
2305
- }
2306
- };
2307
- function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
2308
- return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
2309
- }
2310
- function exchange(endpoint, encoded, timeoutMs, decode, signal) {
2311
- return new Promise((resolve, reject2) => {
2312
- const socket = createConnection(endpoint);
2313
- let buffer = Buffer.alloc(0);
2314
- let settled = false;
2315
- const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
2316
- const finish = (error, response2) => {
2317
- if (settled) return;
2318
- settled = true;
2319
- signal?.removeEventListener("abort", aborted);
2320
- socket.destroy();
2321
- if (error !== null) reject2(error);
2322
- else if (response2 !== void 0) resolve(response2);
2323
- };
2324
- if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
2325
- if (signal?.aborted === true) {
2326
- aborted();
2327
- return;
2328
- }
2329
- signal?.addEventListener("abort", aborted, { once: true });
2330
- socket.once("error", (error) => {
2331
- const failure = socketErrorFailure(error);
2332
- finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure}.`, failure));
2333
- });
2334
- socket.once("connect", () => socket.write(encoded));
2335
- socket.on("data", (chunk) => {
2336
- try {
2337
- buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
2338
- const decoded = decode(buffer);
2339
- if (decoded !== null) finish(null, decoded);
2340
- } catch (error) {
2341
- finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
2342
- }
2343
- });
2344
- socket.once("end", () => {
2345
- if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
2346
- });
2347
- });
2348
- }
2349
- function decodeHostRelayIpcResponse(input) {
2350
- 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}`)}.`);
2351
- const length = input.readUInt32BE(0);
2352
- 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}` }])}.`);
2353
- let value;
2354
- try {
2355
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2356
- } catch {
2357
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
2358
- }
2359
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
2360
- return value;
2361
- }
2362
- function relayAdmissionCode(value) {
2363
- 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";
2364
- }
2365
- function validResponse(value) {
2366
- 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;
2367
- }
2368
- function hostRelayIpcCode(value) {
2369
- 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);
2370
- }
2371
- function nonnegative(value) {
2372
- return Number.isSafeInteger(value) && Number(value) >= 0;
2373
- }
2374
- function record2(value) {
2375
- return value !== null && typeof value === "object" && !Array.isArray(value);
2376
- }
2377
- function decodeResponseBuffer(buffer) {
2378
- if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2379
- const length = buffer.readUInt32BE(0);
2380
- 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}`)}.`);
2381
- if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2382
- 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}` }])}.`);
2383
- return decodeHostRelayIpcResponse(buffer);
2384
- }
2385
- function decodeCurrentPromptResponseBuffer(buffer) {
2386
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
2387
- if (value === null) return null;
2388
- if (!record2(value) || !exactKeys2(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");
2389
- return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
2390
- }
2391
- function decodeLengthPrefixedJson(input, maximum) {
2392
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2393
- const length = input.readUInt32BE(0);
2394
- 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}`)}.`);
2395
- if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2396
- 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}` }])}.`);
2397
- try {
2398
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2399
- } catch {
2400
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
2401
- }
2402
- }
2403
- function encodeLengthPrefixed(value) {
2404
- const body = Buffer.from(JSON.stringify(value), "utf8");
2405
- const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
2406
- output.writeUInt32BE(body.length, 0);
2407
- body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
2408
- return output;
2409
- }
2410
- function exactKeys2(value, required, optional = []) {
2411
- const keys = Object.keys(value);
2412
- return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2413
- }
2414
- function errorCode2(error) {
2415
- return record2(error) && typeof error.code === "string" ? error.code : null;
2416
- }
2417
-
2418
2532
  // host/relay/src/host-producer-core.ts
2533
+ import { createHash as createHash4 } from "node:crypto";
2419
2534
  var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
2420
2535
  function isHostTranscriptCursorReason(value) {
2421
2536
  return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
2422
2537
  }
2423
2538
  var TRANSCRIPT_MISSING_REASON = "transcript_missing";
2424
2539
  var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
2540
+ var HOST_INVOCATION_TRANSCRIPT_TAIL_MAX_BYTES = 1024 * 1024;
2425
2541
  function transcriptScanFailureKind(error, adapterFailureKind) {
2426
2542
  if (transcriptErrorCode(error) === "ELOOP") return "symlink";
2427
2543
  const adapter = adapterFailureKind(error);
@@ -2431,16 +2547,6 @@ function transcriptScanFailureKind(error, adapterFailureKind) {
2431
2547
  if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
2432
2548
  return "other";
2433
2549
  }
2434
- async function registerHostCurrentPromptDiagnosed(register, diagnostic) {
2435
- try {
2436
- await register();
2437
- diagnostic("current_prompt_registered");
2438
- return true;
2439
- } catch (error) {
2440
- if (!(error instanceof HostRelayCurrentPromptCapacityRefusal)) diagnostic("current_prompt_registration_failed");
2441
- throw error;
2442
- }
2443
- }
2444
2550
  function transcriptErrorCode(error) {
2445
2551
  return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
2446
2552
  }
@@ -2488,10 +2594,10 @@ async function transcriptCursorBoundsReason(handle, cursor, size) {
2488
2594
  return null;
2489
2595
  }
2490
2596
  function transcriptSha256(value) {
2491
- return createHash3("sha256").update(value).digest("hex");
2597
+ return createHash4("sha256").update(value).digest("hex");
2492
2598
  }
2493
2599
  function transcriptObjectSha256(value) {
2494
- return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2600
+ return createHash4("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2495
2601
  }
2496
2602
  function isTranscriptRecord(value) {
2497
2603
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -2552,24 +2658,18 @@ var HostTranscriptWatcher = class {
2552
2658
  return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
2553
2659
  }
2554
2660
  async scanRegistration(registration) {
2555
- try {
2556
- return await this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2557
- missing: () => this.retireMissing(registration),
2558
- failed: (handle, error) => this.scanFailed(handle, registration, error)
2559
- });
2560
- } catch (error) {
2561
- if (error instanceof HostRelayCurrentPromptCapacityRefusal) return { records: 0, enqueued: 0, quarantined: false };
2562
- throw error;
2563
- }
2661
+ return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2662
+ missing: () => this.retireMissing(registration),
2663
+ failed: (handle, error) => this.scanFailed(handle, registration, error)
2664
+ });
2564
2665
  }
2565
2666
  async openTranscript(registration, scan, handlers) {
2566
2667
  let handle;
2567
2668
  try {
2568
- handle = await open4(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
2669
+ handle = await openNoFollow(this.transcriptPathOf(registration));
2569
2670
  return await scan(handle);
2570
2671
  } catch (error) {
2571
2672
  if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
2572
- if (hostRelayExchangeFailure(error) !== void 0 || error instanceof HostRelayCurrentPromptCapacityRefusal) throw error;
2573
2673
  return handlers.failed(handle, error);
2574
2674
  } finally {
2575
2675
  await handle?.close();
@@ -2615,29 +2715,12 @@ var HostTranscriptWatcher = class {
2615
2715
  return transcriptCursorBoundsReason(handle, cursor, size);
2616
2716
  }
2617
2717
  };
2618
- var HOST_PRODUCER_STATE_IDENTITY = {
2619
- codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
2620
- claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
2621
- };
2622
2718
  var HostProducerDrainCore = class {
2623
2719
  host;
2624
- relay;
2625
- statePath;
2626
- stateSchema;
2627
- installationRef;
2628
- epoch;
2629
2720
  now;
2630
2721
  tail = Promise.resolve();
2631
2722
  constructor(host, runtime) {
2632
- if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
2633
- const epoch = runtime.producer_epoch ?? 1;
2634
- if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
2635
2723
  this.host = host;
2636
- this.relay = runtime.relay;
2637
- this.statePath = join2(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
2638
- this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
2639
- this.installationRef = runtime.producer_installation_ref;
2640
- this.epoch = epoch;
2641
2724
  this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
2642
2725
  }
2643
2726
  drainOutbox() {
@@ -2647,145 +2730,29 @@ var HostProducerDrainCore = class {
2647
2730
  }
2648
2731
  async drainLocked() {
2649
2732
  const read = await this.host.listEnvelopes();
2650
- let admitted = 0;
2733
+ let removed = 0;
2651
2734
  let expired = 0;
2652
- let retained = 0;
2653
2735
  for (const envelope of read.entries) {
2654
- const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
2655
- if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
2656
- await this.host.removeEnvelope(envelope);
2657
- expired += 1;
2658
- continue;
2659
- }
2660
- const frames = await this.reserve(envelope);
2661
- let complete = true;
2662
- for (const frame of frames) {
2663
- const outcome = await this.relay.admit(frame);
2664
- if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
2665
- complete = false;
2666
- break;
2667
- }
2668
- }
2669
- if (!complete) {
2670
- retained += 1;
2671
- break;
2672
- }
2736
+ if (Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) expired += 1;
2737
+ else removed += 1;
2673
2738
  await this.host.removeEnvelope(envelope);
2674
- await this.release(this.host.submissionRefOf(envelope));
2675
- admitted += 1;
2676
- }
2677
- return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
2678
- }
2679
- async hasReservation(submissionRef) {
2680
- return (await this.readState()).pending[submissionRef] !== void 0;
2681
- }
2682
- async reserve(envelope) {
2683
- const state = await this.readState();
2684
- const submissionRef = this.host.submissionRefOf(envelope);
2685
- const existing = state.pending[submissionRef];
2686
- if (existing !== void 0) return existing;
2687
- const drafts = await this.host.mapEnvelope(envelope);
2688
- const frames = drafts.map((draft, offset) => ({
2689
- schema_version: "ceal.host_producer_frame.v1",
2690
- producer_id: this.host.producer_id,
2691
- producer_installation_ref: this.installationRef,
2692
- producer_epoch: this.epoch,
2693
- sequence: state.next_sequence + offset,
2694
- frame_kind: draft.frame_kind,
2695
- occurred_at: this.host.createdAtOf(envelope),
2696
- payload: draft.payload
2697
- }));
2698
- await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
2699
- return frames;
2700
- }
2701
- async release(submissionRef) {
2702
- const state = await this.readState();
2703
- if (state.pending[submissionRef] === void 0) return;
2704
- const pending = { ...state.pending };
2705
- delete pending[submissionRef];
2706
- await this.writeState({ ...state, pending });
2707
- }
2708
- async readState() {
2709
- try {
2710
- const value = JSON.parse(await readFile(this.statePath, "utf8"));
2711
- return this.decodeState(value);
2712
- } catch (error) {
2713
- if (errorCode3(error) !== "ENOENT") throw error;
2714
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
2715
- }
2716
- }
2717
- async writeState(state) {
2718
- await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
2719
- const temporary = `${this.statePath}.${process.pid}.new`;
2720
- await writeFile(temporary, JSON.stringify(state), { mode: 384 });
2721
- await rename2(temporary, this.statePath);
2722
- }
2723
- decodeState(value) {
2724
- const label = this.host.producer_label;
2725
- const fail = (code, message) => this.host.fail(code, message);
2726
- if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
2727
- throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
2728
- { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
2729
- { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
2730
- ])}).`);
2731
2739
  }
2732
- 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}`)}).`);
2733
- const pending = {};
2734
- const storedEpoch = Number(value.producer_epoch);
2735
- for (const [submissionRef, frames] of Object.entries(value.pending)) {
2736
- if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
2737
- pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
2738
- }
2739
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
2740
- }
2741
- decodeStoredFrame(value, storedEpoch) {
2742
- const label = this.host.producer_label;
2743
- const json = Buffer.from(JSON.stringify(value), "utf8");
2744
- const encoded = Buffer.allocUnsafe(json.length + 4);
2745
- encoded.writeUInt32BE(json.length, 0);
2746
- json.copy(encoded, 4);
2747
- const frame = decodeHostProducerFrame(encoded);
2748
- 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([
2749
- { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
2750
- { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
2751
- { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
2752
- ])}).`);
2753
- return frame;
2740
+ return { removed, expired, malformed: read.malformed };
2754
2741
  }
2755
2742
  };
2756
- function isDrainStateHeader(value, schema, installationRef) {
2757
- 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);
2758
- }
2759
- function errorCode3(error) {
2760
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
2761
- }
2762
-
2763
- // host/relay/src/relay-quarantine-store.ts
2764
- var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
2765
- var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
2766
- var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
2767
-
2768
- // host/relay/src/relay-admission-store.ts
2769
- var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
2770
- var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
2771
- var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
2772
-
2773
- // host/codex/src/codex-producer.ts
2774
- import { createHash as createHash4 } from "node:crypto";
2775
2743
 
2776
2744
  // host/codex/src/codex-outbox.ts
2777
- import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
2778
- import { lstat as lstat3, mkdir as mkdir3, open as open5, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
2779
- import { dirname, isAbsolute as isAbsolute2, join as join3 } from "node:path";
2745
+ import { mkdir as mkdir3, open as open3, readdir, rename as rename2, stat as stat2, unlink as unlink2 } from "node:fs/promises";
2746
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join2 } from "node:path";
2780
2747
 
2781
2748
  // host/invocation-context.ts
2782
- var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
2749
+ var HOST_INVOCATION_TURN_SELECTION_SCHEMA = "ceal.host_invocation_turn_selection.v1";
2783
2750
  var HOST_INVOCATION_CONTEXT_REQUIRED_KEYS = ["schema_version", "identity", "prompt_ref", "expires_at"];
2784
2751
  function invocationContextKey(identity) {
2785
2752
  return cealRequestSha256({ host_source_ref: identity.host_source_ref, host_session_ref: identity.host_session_ref });
2786
2753
  }
2787
2754
  function hasHostInvocationIdentityKeys(value) {
2788
- return exactKeys3(value, HOST_INVOCATION_IDENTITY_KEYS);
2755
+ return exactKeys(value, CEAL_HOST_INVOCATION_IDENTITY_KEYS);
2789
2756
  }
2790
2757
  function hasHostInvocationContextKeys(value, optional = []) {
2791
2758
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
@@ -2811,12 +2778,9 @@ function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
2811
2778
  return Object.freeze(context);
2812
2779
  }
2813
2780
  function isHostInvocationTurnSelection(value) {
2814
- 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) => safeRef2(value[key]));
2815
- }
2816
- function invocationTurnSelectionMatches(context, selection) {
2817
- 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;
2781
+ return isRecord3(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]));
2818
2782
  }
2819
- function exactKeys3(value, keys) {
2783
+ function exactKeys(value, keys) {
2820
2784
  const actual = Object.keys(value);
2821
2785
  return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
2822
2786
  }
@@ -2825,16 +2789,68 @@ function requiredKeys(value, required, optional) {
2825
2789
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
2826
2790
  return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
2827
2791
  }
2828
- function isRecord2(value) {
2792
+ function isRecord3(value) {
2829
2793
  return value !== null && typeof value === "object" && !Array.isArray(value);
2830
2794
  }
2831
- function safeRef2(value) {
2795
+ function safeRef(value) {
2832
2796
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2833
2797
  }
2834
2798
 
2799
+ // host/relay/src/producer-frame.ts
2800
+ var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2801
+ var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "turn_terminal", "producer_status"];
2802
+ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
2803
+ var HOST_PRODUCER_FRAME_ERROR_CODES = [
2804
+ "invalid_frame_encoding",
2805
+ "invalid_frame_length",
2806
+ "frame_truncated",
2807
+ "unsupported_frame_schema",
2808
+ "invalid_frame_shape",
2809
+ "invalid_producer_identity",
2810
+ "frame_too_large"
2811
+ ];
2812
+
2813
+ // host/relay/src/durable-atomic-replacement.ts
2814
+ import { lstat as lstat3, mkdir as mkdir2, open as open2, rename, unlink } from "node:fs/promises";
2815
+ var DEFAULT_PORT = {
2816
+ platform: process.platform,
2817
+ mkdir: (path, options) => mkdir2(path, options),
2818
+ lstat: (path) => lstat3(path),
2819
+ open_file: (path) => open2(path, "wx", 384),
2820
+ rename,
2821
+ unlink,
2822
+ open_directory: (path) => open2(path),
2823
+ unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2824
+ };
2825
+
2826
+ // host/relay/src/relay-quarantine-store.ts
2827
+ var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
2828
+ var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
2829
+ var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
2830
+
2831
+ // host/relay/src/relay-admission-store.ts
2832
+ var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
2833
+ var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
2834
+ var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
2835
+
2836
+ // host/relay/src/relay-pipe-handshake.ts
2837
+ var RELAY_PIPE_FRAME_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2838
+
2839
+ // host/relay/src/relay-ipc.ts
2840
+ var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2841
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2842
+ "permission_denied",
2843
+ "socket_missing",
2844
+ "connection_refused",
2845
+ "closed_early",
2846
+ "response_invalid",
2847
+ "timed_out",
2848
+ "cancelled",
2849
+ "unavailable"
2850
+ ]);
2851
+
2835
2852
  // host/codex/src/codex-types.ts
2836
2853
  var CODEX_OUTBOX_SCHEMA_VERSION = "ceal.codex_observation_outbox.v1";
2837
- var CODEX_TURN_BINDING_SCHEMA_VERSION = "ceal.codex_turn_binding.v1";
2838
2854
  var CODEX_SESSION_SCHEMA_VERSION = "ceal.codex_session.v1";
2839
2855
  var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1";
2840
2856
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
@@ -2861,59 +2877,40 @@ function validateCodexHostInvocationContext(value) {
2861
2877
  validateContextReferences(value);
2862
2878
  validateContextTimes(value);
2863
2879
  }
2864
- function invocationContextFromBinding(binding, turnGenerationRef) {
2865
- const context = {
2866
- schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
2867
- identity: binding.identity,
2868
- prompt_ref: binding.prompt_ref,
2869
- request_ref: binding.request_ref,
2870
- bound_at: binding.bound_at,
2871
- expires_at: binding.expires_at,
2872
- ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
2873
- };
2874
- validateCodexHostInvocationContext(context);
2875
- return Object.freeze(context);
2876
- }
2877
2880
  function validateIdentity2(value) {
2878
- if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
2881
+ if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef2)) {
2879
2882
  throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
2880
2883
  }
2881
2884
  }
2882
2885
  function isContextShape(value) {
2883
- return isRecord3(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2886
+ return isRecord4(value) && hasHostInvocationContextKeys(value, ["turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2884
2887
  }
2885
2888
  function validateContextReferences(value) {
2886
- if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2889
+ if (!safeRef2(value.prompt_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2887
2890
  }
2888
2891
  function validateContextTimes(value) {
2889
2892
  const expiresAt = value.expires_at;
2890
- const boundAt = value.bound_at;
2891
- if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2892
- 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}`)}).`);
2893
+ if (!timestamp(expiresAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2893
2894
  }
2894
2895
  function optionalSafeRef(value) {
2895
- return value === void 0 || safeRef3(value);
2896
- }
2897
- function optionalTimestamp(value) {
2898
- return value === void 0 || timestamp2(value);
2896
+ return value === void 0 || safeRef2(value);
2899
2897
  }
2900
- function safeRef3(value) {
2898
+ function safeRef2(value) {
2901
2899
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2902
2900
  }
2903
- function timestamp2(value) {
2901
+ function timestamp(value) {
2904
2902
  return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
2905
2903
  }
2906
- function isRecord3(value) {
2904
+ function isRecord4(value) {
2907
2905
  return value !== null && typeof value === "object" && !Array.isArray(value);
2908
2906
  }
2909
2907
 
2910
2908
  // host/codex/src/codex-outbox.ts
2911
- var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2909
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2912
2910
  var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
2913
2911
  var CodexOutboxStore = class {
2914
2912
  directory;
2915
2913
  entriesDirectory;
2916
- bindingsDirectory;
2917
2914
  sessionsDirectory;
2918
2915
  activeContextsDirectory;
2919
2916
  turnSelectionsDirectory;
@@ -2922,17 +2919,16 @@ var CodexOutboxStore = class {
2922
2919
  constructor(directory) {
2923
2920
  if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
2924
2921
  this.directory = directory;
2925
- this.entriesDirectory = join3(directory, "entries");
2926
- this.bindingsDirectory = join3(directory, "bindings");
2927
- this.sessionsDirectory = join3(directory, "sessions");
2928
- this.activeContextsDirectory = join3(directory, "active-contexts");
2929
- this.turnSelectionsDirectory = join3(directory, "turn-selections");
2930
- this.registrationsDirectory = join3(directory, "transcript-registrations");
2931
- this.cursorsDirectory = join3(directory, "transcript-cursors");
2922
+ this.entriesDirectory = join2(directory, "entries");
2923
+ this.sessionsDirectory = join2(directory, "sessions");
2924
+ this.activeContextsDirectory = join2(directory, "active-contexts");
2925
+ this.turnSelectionsDirectory = join2(directory, "turn-selections");
2926
+ this.registrationsDirectory = join2(directory, "transcript-registrations");
2927
+ this.cursorsDirectory = join2(directory, "transcript-cursors");
2932
2928
  }
2933
2929
  async prepare() {
2934
- for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2935
- await ensurePrivateOwnerDirectory(path);
2930
+ for (const path of [this.directory, this.entriesDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2931
+ await ensureOwnerDirectory(path);
2936
2932
  }
2937
2933
  }
2938
2934
  async put(entry) {
@@ -2947,7 +2943,7 @@ var CodexOutboxStore = class {
2947
2943
  for (const name of await readdir(this.entriesDirectory)) {
2948
2944
  if (!name.endsWith(".json")) continue;
2949
2945
  try {
2950
- const value = JSON.parse(await readPrivateFile(join3(this.entriesDirectory, name)));
2946
+ const value = JSON.parse(await readOwnerStateFile(join2(this.entriesDirectory, name)));
2951
2947
  validateEnvelope(value);
2952
2948
  entries.push(value);
2953
2949
  } catch {
@@ -2965,11 +2961,6 @@ var CodexOutboxStore = class {
2965
2961
  if (!isNotFound2(error)) throw storageError("Unable to remove the Codex outbox entry.");
2966
2962
  }
2967
2963
  }
2968
- async writeBinding(binding) {
2969
- validateBinding(binding);
2970
- await this.prepare();
2971
- await writeAtomicJson(this.bindingPath(binding.identity), binding);
2972
- }
2973
2964
  /**
2974
2965
  * Select the exact Host turn that model-reachable commands may use. A new
2975
2966
  * prompt replaces this projection, so it cannot inherit the prior turn's
@@ -2996,7 +2987,7 @@ var CodexOutboxStore = class {
2996
2987
  await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
2997
2988
  }
2998
2989
  async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
2999
- if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
2990
+ if (!SAFE_REF3.test(hostSourceRef) || !SAFE_REF3.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
3000
2991
  await this.prepare();
3001
2992
  return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
3002
2993
  }
@@ -3009,23 +3000,11 @@ var CodexOutboxStore = class {
3009
3000
  await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
3010
3001
  return true;
3011
3002
  }
3012
- /**
3013
- * Publish a Request reference only while the acknowledged binding is still
3014
- * the active turn. A delayed relay response therefore cannot overwrite a
3015
- * newer prompt's context.
3016
- */
3017
- async bindInvocationContext(binding, now = /* @__PURE__ */ new Date()) {
3018
- validateBinding(binding);
3019
- const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
3020
- if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
3021
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
3022
- return true;
3023
- }
3024
3003
  /** Return only the live session projection; never fall back to another turn. */
3025
3004
  async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
3026
3005
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
3027
3006
  const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
3028
- return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
3007
+ return isLiveSessionProjection(context, now) ? context : null;
3029
3008
  }
3030
3009
  /**
3031
3010
  * The latest Codex session projection even when past expiry, so the
@@ -3033,10 +3012,10 @@ var CodexOutboxStore = class {
3033
3012
  * a missing one. Every other caller keeps the fail-closed read above.
3034
3013
  */
3035
3014
  async readRawInvocationContext(hostSourceRef, hostSessionRef) {
3036
- if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
3015
+ if (!SAFE_REF3.test(hostSourceRef) || !SAFE_REF3.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
3037
3016
  await this.prepare();
3038
3017
  const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
3039
- return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
3018
+ return context;
3040
3019
  }
3041
3020
  /** Clear the projection only if the caller still owns its exact active turn. */
3042
3021
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -3050,11 +3029,6 @@ var CodexOutboxStore = class {
3050
3029
  }
3051
3030
  return true;
3052
3031
  }
3053
- async readBinding(identity) {
3054
- validateIdentity3(identity);
3055
- await this.prepare();
3056
- return readOptionalJson(this.bindingPath(identity), validateBinding);
3057
- }
3058
3032
  async saveSession(snapshot) {
3059
3033
  validateSession(snapshot);
3060
3034
  await this.prepare();
@@ -3062,7 +3036,7 @@ var CodexOutboxStore = class {
3062
3036
  }
3063
3037
  async readSession(sourceRef, sessionRef) {
3064
3038
  const identity = { host_source_ref: sourceRef, host_session_ref: sessionRef };
3065
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
3039
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
3066
3040
  await this.prepare();
3067
3041
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
3068
3042
  }
@@ -3095,7 +3069,7 @@ var CodexOutboxStore = class {
3095
3069
  for (const name of await readdir(this.registrationsDirectory)) {
3096
3070
  if (!name.endsWith(".json")) continue;
3097
3071
  try {
3098
- const value = JSON.parse(await readPrivateFile(join3(this.registrationsDirectory, name)));
3072
+ const value = JSON.parse(await readOwnerStateFile(join2(this.registrationsDirectory, name)));
3099
3073
  validateRegistration(value);
3100
3074
  registrations.push(value);
3101
3075
  } catch {
@@ -3114,48 +3088,37 @@ var CodexOutboxStore = class {
3114
3088
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
3115
3089
  }
3116
3090
  async findByAlias(sourceRef, sessionRef, alias) {
3117
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef) || !SAFE_REF4.test(alias)) return null;
3091
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef) || !SAFE_REF3.test(alias)) return null;
3118
3092
  const read = await this.list();
3119
3093
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
3120
3094
  if (envelope !== null) return envelopeMatch(envelope);
3121
3095
  await this.prepare();
3122
- const binding = await findBindingByAlias(this.bindingsDirectory, sourceRef, sessionRef, alias);
3123
- if (binding !== null) return bindingMatch(binding);
3124
3096
  return null;
3125
3097
  }
3126
3098
  async hasPriorTurn(sourceRef, sessionRef) {
3127
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) return false;
3099
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) return false;
3128
3100
  const read = await this.list();
3129
3101
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
3130
- await this.prepare();
3131
- for (const name of await readdir(this.bindingsDirectory)) {
3132
- if (!name.endsWith(".json")) continue;
3133
- const binding = await readBindingCandidate(this.bindingsDirectory, name);
3134
- if (binding?.identity.host_source_ref === sourceRef && binding.identity.host_session_ref === sessionRef) return true;
3135
- }
3136
3102
  return false;
3137
3103
  }
3138
3104
  entryPath(submissionRef) {
3139
- if (!SAFE_REF4.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
3140
- return join3(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
3141
- }
3142
- bindingPath(identity) {
3143
- return join3(this.bindingsDirectory, `${identityKey(identity)}.json`);
3105
+ if (!SAFE_REF3.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
3106
+ return join2(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
3144
3107
  }
3145
3108
  sessionPath(sourceRef, sessionRef) {
3146
- return join3(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
3109
+ return join2(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
3147
3110
  }
3148
3111
  activeContextPath(identity) {
3149
- return join3(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
3112
+ return join2(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
3150
3113
  }
3151
3114
  turnSelectionPath(sourceRef, sessionRef) {
3152
- return join3(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
3115
+ return join2(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
3153
3116
  }
3154
3117
  registrationPath(sourceRef, sessionRef) {
3155
- return join3(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3118
+ return join2(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3156
3119
  }
3157
3120
  cursorPath(sourceRef, sessionRef) {
3158
- return join3(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3121
+ return join2(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3159
3122
  }
3160
3123
  };
3161
3124
  async function removeOwnerState(path, what) {
@@ -3166,14 +3129,11 @@ async function removeOwnerState(path, what) {
3166
3129
  }
3167
3130
  }
3168
3131
  function sessionStateKey(sourceRef, sessionRef) {
3169
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
3132
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
3170
3133
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
3171
3134
  }
3172
3135
  function envelopeMatch(envelope) {
3173
- return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, ...envelope.request_ref === void 0 ? {} : { request_ref: envelope.request_ref }, envelope };
3174
- }
3175
- function bindingMatch(binding) {
3176
- return { identity: binding.identity, prompt_ref: binding.prompt_ref, request_ref: binding.request_ref, binding };
3136
+ return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, envelope };
3177
3137
  }
3178
3138
  function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
3179
3139
  for (const envelope of entries) {
@@ -3182,24 +3142,6 @@ function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
3182
3142
  }
3183
3143
  return null;
3184
3144
  }
3185
- async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
3186
- for (const name of await readdir(directory)) {
3187
- if (!name.endsWith(".json")) continue;
3188
- const binding = await readBindingCandidate(directory, name);
3189
- if (binding === null || binding.identity.host_source_ref !== sourceRef || binding.identity.host_session_ref !== sessionRef) continue;
3190
- if (binding.codex_turn_ids.includes(alias)) return binding;
3191
- }
3192
- return null;
3193
- }
3194
- async function readBindingCandidate(directory, name) {
3195
- try {
3196
- const value = JSON.parse(await readPrivateFile(join3(directory, name)));
3197
- validateBinding(value);
3198
- return value;
3199
- } catch {
3200
- return null;
3201
- }
3202
- }
3203
3145
  function identityKey(identity) {
3204
3146
  validateIdentity3(identity);
3205
3147
  return cealRequestSha256(identity);
@@ -3212,15 +3154,15 @@ async function writeAtomicJson(path, value) {
3212
3154
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
3213
3155
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
3214
3156
  try {
3215
- const handle = await open5(temp, "wx", 384);
3157
+ const handle = await open3(temp, "wx");
3216
3158
  try {
3217
3159
  await handle.writeFile(text, "utf8");
3218
3160
  await handle.sync();
3219
3161
  } finally {
3220
3162
  await handle.close();
3221
3163
  }
3222
- await rename3(temp, path);
3223
- await syncDirectory(dirname(path));
3164
+ await rename2(temp, path);
3165
+ await syncDirectory(dirname3(path));
3224
3166
  } catch (error) {
3225
3167
  try {
3226
3168
  await unlink2(temp);
@@ -3232,7 +3174,7 @@ async function writeAtomicJson(path, value) {
3232
3174
  }
3233
3175
  async function syncDirectory(path) {
3234
3176
  try {
3235
- const handle = await open5(path, "r");
3177
+ const handle = await open3(path, "r");
3236
3178
  try {
3237
3179
  await handle.sync();
3238
3180
  } finally {
@@ -3243,7 +3185,7 @@ async function syncDirectory(path) {
3243
3185
  }
3244
3186
  async function readOptionalJson(path, validate) {
3245
3187
  try {
3246
- const value = JSON.parse(await readPrivateFile(path));
3188
+ const value = JSON.parse(await readOwnerStateFile(path));
3247
3189
  validate(value);
3248
3190
  return value;
3249
3191
  } catch (error) {
@@ -3252,36 +3194,30 @@ async function readOptionalJson(path, validate) {
3252
3194
  throw storageError("Codex owner state is malformed.");
3253
3195
  }
3254
3196
  }
3255
- async function ensurePrivateOwnerDirectory(path) {
3197
+ async function ensureOwnerDirectory(path) {
3256
3198
  try {
3257
- await lstat3(path);
3199
+ await stat2(path);
3258
3200
  } catch (error) {
3259
3201
  if (!isNotFound2(error)) throw storageError("Codex owner state directory is unavailable.");
3260
- await mkdir3(path, { recursive: true, mode: 448 });
3202
+ await mkdir3(path, { recursive: true });
3261
3203
  }
3262
- const stats = await lstat3(path);
3263
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3264
- 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)")}).`);
3265
- 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")}).`);
3266
- if (stats.uid !== uid) throw storageError(`Codex owner state directory is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
3204
+ const stats = await stat2(path);
3205
+ if (!stats.isDirectory()) throw storageError("Codex owner state path is not a directory.");
3267
3206
  }
3268
- async function readPrivateFile(path) {
3207
+ async function readOwnerStateFile(path) {
3269
3208
  let handle;
3270
3209
  try {
3271
- handle = await open5(path, O_RDONLY3 | O_NOFOLLOW2);
3210
+ handle = await open3(path);
3272
3211
  const stats = await handle.stat();
3273
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3274
- 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)")}).`);
3275
- 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")}).`);
3276
- if (stats.uid !== uid) throw storageError(`Codex owner state file is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
3212
+ if (!stats.isFile()) throw storageError("Codex owner state path is not a regular file.");
3277
3213
  return await handle.readFile("utf8");
3278
3214
  } finally {
3279
3215
  await handle?.close();
3280
3216
  }
3281
3217
  }
3282
3218
  function validateEnvelope(value) {
3283
- if (!isRecord4(value)) throw storageError("Codex outbox entry is malformed.");
3284
- 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")}).`);
3219
+ if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
3220
+ 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")}).`);
3285
3221
  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}`)}).`);
3286
3222
  validateIdentity3(value.identity);
3287
3223
  validateEnvelopeReferences(value);
@@ -3289,22 +3225,20 @@ function validateEnvelope(value) {
3289
3225
  validateEnvelopeTimestamps(value);
3290
3226
  }
3291
3227
  function validateEnvelopeReferences(value) {
3292
- if (!SAFE_REF4.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
3293
- if (!isCealHostInputKind(value.input_kind)) throw storageError("Codex outbox input provenance is malformed.");
3294
- if (!SAFE_REF4.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
3295
- if (!SAFE_REF4.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
3296
- if (value.request_ref !== void 0 && !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
3297
- if (value.codex_turn_id !== void 0 && !SAFE_REF4.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
3228
+ if (!SAFE_REF3.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
3229
+ if (!SAFE_REF3.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
3230
+ if (!SAFE_REF3.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
3231
+ if (value.codex_turn_id !== void 0 && !SAFE_REF3.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
3298
3232
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
3299
3233
  }
3300
3234
  function validateRegistration(value) {
3301
- if (!isRecord4(value)) throw storageError("Codex transcript registration is malformed.");
3235
+ if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
3302
3236
  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")}).`);
3303
3237
  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}`)}).`);
3304
3238
  validateRegistrationFields(value);
3305
3239
  }
3306
3240
  function validateRegistrationFields(value) {
3307
- 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 }])}).`);
3241
+ 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 }])}).`);
3308
3242
  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`)}).`);
3309
3243
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
3310
3244
  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}`)}).`);
@@ -3314,7 +3248,7 @@ function validRegistrationCwd(value) {
3314
3248
  return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
3315
3249
  }
3316
3250
  function validateCursor(value) {
3317
- if (!isRecord4(value)) throw storageError("Codex transcript cursor is malformed.");
3251
+ if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
3318
3252
  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")}).`);
3319
3253
  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}`)}).`);
3320
3254
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
@@ -3322,7 +3256,7 @@ function validateCursor(value) {
3322
3256
  if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
3323
3257
  }
3324
3258
  function validCursorSource(value) {
3325
- 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";
3259
+ 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";
3326
3260
  }
3327
3261
  function validCursorPosition(value) {
3328
3262
  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";
@@ -3331,23 +3265,23 @@ function validCursorStatus(value) {
3331
3265
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
3332
3266
  }
3333
3267
  function validActiveTask(value) {
3334
- 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;
3268
+ 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;
3335
3269
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
3336
3270
  }
3337
3271
  function validActiveTaskIdentity(value) {
3338
- return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && isTimestamp(value.started_at);
3272
+ return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate)) && isTimestamp(value.started_at);
3339
3273
  }
3340
3274
  function validActiveTaskReferences(value) {
3341
3275
  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);
3342
3276
  }
3343
3277
  function optionalSafeRef2(value) {
3344
- return value === void 0 || typeof value === "string" && SAFE_REF4.test(value);
3278
+ return value === void 0 || typeof value === "string" && SAFE_REF3.test(value);
3345
3279
  }
3346
3280
  function validActiveTaskUsage(value) {
3347
3281
  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");
3348
3282
  }
3349
3283
  function validTokenUsage(value) {
3350
- if (!isRecord4(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
3284
+ if (!isRecord5(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
3351
3285
  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;
3352
3286
  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);
3353
3287
  }
@@ -3357,7 +3291,7 @@ function nonNegativeInteger(value) {
3357
3291
  function validateEnvelopeObservations(value) {
3358
3292
  if (!Array.isArray(value.observations)) throw storageError("Codex outbox observations are malformed.");
3359
3293
  try {
3360
- for (const observation2 of value.observations) validateCealHostObservationDraft(observation2);
3294
+ for (const observation of value.observations) validateCealHostObservationDraft(observation);
3361
3295
  } catch {
3362
3296
  throw storageError("Codex outbox observations are malformed.");
3363
3297
  }
@@ -3366,34 +3300,23 @@ function validateEnvelopeTimestamps(value) {
3366
3300
  if (!isTimestamp(value.created_at)) throw storageError("Codex outbox timestamps are malformed.");
3367
3301
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
3368
3302
  }
3369
- function validateBinding(value) {
3370
- if (!isRecord4(value)) throw storageError("Codex turn binding is malformed.");
3371
- 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")}).`);
3372
- 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}`)}).`);
3373
- validateIdentity3(value.identity);
3374
- if (!SAFE_REF4.test(String(value.prompt_ref)) || !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
3375
- if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
3376
- }
3377
3303
  function validateSession(value) {
3378
- if (!isRecord4(value)) throw storageError("Codex session snapshot is malformed.");
3304
+ if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
3379
3305
  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")}).`);
3380
3306
  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}`)}).`);
3381
- 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.");
3307
+ 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.");
3382
3308
  }
3383
3309
  function validateTurnSelection(value) {
3384
3310
  if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
3385
3311
  }
3386
3312
  function validateIdentity3(value) {
3387
- 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.");
3313
+ 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.");
3388
3314
  }
3389
3315
  function isJsonValue(value) {
3390
3316
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
3391
3317
  if (typeof value === "number") return Number.isFinite(value);
3392
3318
  if (Array.isArray(value)) return value.every(isJsonValue);
3393
- return isRecord4(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
3394
- }
3395
- function isStringList(value) {
3396
- return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate));
3319
+ return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
3397
3320
  }
3398
3321
  function isTimestamp(value) {
3399
3322
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -3403,149 +3326,51 @@ function sameKeys(value, required, optional = []) {
3403
3326
  const keys = Object.keys(value);
3404
3327
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
3405
3328
  }
3406
- function isRecord4(value) {
3329
+ function isRecord5(value) {
3407
3330
  return value !== null && typeof value === "object" && !Array.isArray(value);
3408
3331
  }
3409
3332
  function isNotFound2(error) {
3410
- return isRecord4(error) && error.code === "ENOENT";
3333
+ return isRecord5(error) && error.code === "ENOENT";
3411
3334
  }
3412
3335
  function storageError(message) {
3413
3336
  return new CodexHostAdapterError("storage", message);
3414
3337
  }
3415
3338
 
3416
3339
  // host/codex/src/codex-producer.ts
3417
- var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3418
3340
  var CodexProducer = class {
3419
- producer_id = "codex";
3420
- producer_label = "Codex";
3421
- outbox_directory;
3422
3341
  store;
3423
3342
  core;
3424
3343
  constructor(options) {
3425
3344
  this.store = new CodexOutboxStore(options.outbox_dir);
3426
- this.outbox_directory = this.store.directory;
3427
3345
  this.core = new HostProducerDrainCore(this, options);
3428
3346
  }
3429
3347
  drainOutbox() {
3430
3348
  return this.core.drainOutbox();
3431
3349
  }
3432
- fail(code, message) {
3433
- return new CodexHostAdapterError(code, message);
3434
- }
3435
3350
  listEnvelopes() {
3436
3351
  return this.store.list();
3437
3352
  }
3438
3353
  removeEnvelope(envelope) {
3439
3354
  return this.store.remove(envelope);
3440
3355
  }
3441
- submissionRefOf(envelope) {
3442
- return envelope.submission_ref;
3443
- }
3444
3356
  expiresAtOf(envelope) {
3445
3357
  return envelope.expires_at;
3446
3358
  }
3447
- createdAtOf(envelope) {
3448
- return envelope.created_at;
3449
- }
3450
- async mapEnvelope(envelope) {
3451
- const prompt = observation(envelope, "prompt");
3452
- if (prompt !== void 0) return this.mapInput(envelope, prompt);
3453
- return [mapTerminal(envelope)];
3454
- }
3455
- async mapInput(envelope, prompt) {
3456
- const drafts = [];
3457
- const session = observation(envelope, "session");
3458
- if (session !== void 0) {
3459
- const registrations = await this.store.listTranscriptRegistrations();
3460
- const registration = registrations.find((item) => item.host_source_ref === envelope.identity.host_source_ref && item.host_session_ref === envelope.identity.host_session_ref);
3461
- const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
3462
- drafts.push({ frame_kind: "session_started", payload: compact({
3463
- local_session_ref: envelope.identity.host_session_ref,
3464
- working_directory_ref: `workspace:${createHash4("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
3465
- model: recordText(session.value, "model"),
3466
- host_version: nestedText(session.value, "host_version"),
3467
- observations: [session]
3468
- }) });
3469
- }
3470
- const turn = observation(envelope, "turn");
3471
- if (turn !== void 0) drafts.push({ frame_kind: "turn_started", payload: compact({
3472
- local_session_ref: envelope.identity.host_session_ref,
3473
- local_turn_ref: localTurnRef(envelope),
3474
- observations: [turn]
3475
- }) });
3476
- if (!isCealHostPromptObservationValue(prompt.value)) throw new CodexHostAdapterError("storage", "Codex prompt observation is malformed.");
3477
- drafts.push({ frame_kind: "user_input", payload: compact({
3478
- local_session_ref: envelope.identity.host_session_ref,
3479
- local_turn_ref: localTurnRef(envelope),
3480
- local_input_ref: envelope.host_input_ref,
3481
- input_kind: envelope.input_kind,
3482
- origin_input: envelope.origin_input,
3483
- observations: [prompt],
3484
- local_turn_aliases: envelope.codex_turn_id === void 0 ? void 0 : [envelope.codex_turn_id],
3485
- context_expires_at: envelope.expires_at
3486
- }) });
3487
- return drafts;
3488
- }
3489
3359
  };
3490
- function mapTerminal(envelope) {
3491
- const timing = observation(envelope, "timing");
3492
- const timingValue = asRecord(timing?.value);
3493
- const aborted = timingValue?.terminal === "aborted";
3494
- const usage = envelope.observations.filter((item) => ["token", "cost", "model"].includes(item.observation_kind));
3495
- return { frame_kind: "turn_terminal", payload: compact({
3496
- local_session_ref: envelope.identity.host_session_ref,
3497
- local_turn_ref: localTurnRef(envelope),
3498
- terminal_state: aborted ? "aborted" : "completed",
3499
- abort_reason: aborted && typeof timingValue?.reason === "string" ? safeReasonRef(timingValue.reason) : void 0,
3500
- duration_ms: nonNegativeNumber(timingValue?.duration_ms),
3501
- time_to_first_token_ms: nonNegativeNumber(timingValue?.time_to_first_token_ms),
3502
- usage: usage.length === 0 ? void 0 : Object.fromEntries(usage.map((item) => [item.observation_kind, item.value])),
3503
- observations: envelope.observations
3504
- }) };
3505
- }
3506
- function observation(envelope, kind) {
3507
- return envelope.observations.find((item) => item.observation_kind === kind);
3508
- }
3509
- function localTurnRef(envelope) {
3510
- return envelope.identity.host_turn_ref;
3511
- }
3512
- function compact(value) {
3513
- return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
3514
- }
3515
- function asRecord(value) {
3516
- return isRecord5(value) ? value : void 0;
3517
- }
3518
- function recordText(value, key) {
3519
- const record3 = asRecord(value);
3520
- return typeof record3?.[key] === "string" ? record3[key] : void 0;
3521
- }
3522
- function nestedText(value, key) {
3523
- const nested = asRecord(asRecord(value)?.[key]);
3524
- return typeof nested?.value === "string" ? nested.value : void 0;
3525
- }
3526
- function nonNegativeNumber(value) {
3527
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
3528
- }
3529
- function safeReasonRef(value) {
3530
- return SAFE_REF5.test(value) ? value : `reason:${createHash4("sha256").update(value, "utf8").digest("hex")}`;
3531
- }
3532
- function isRecord5(value) {
3533
- return value !== null && typeof value === "object" && !Array.isArray(value);
3534
- }
3535
3360
 
3536
3361
  // host/codex/src/codex-decoder.ts
3537
3362
  import { createHash as createHash5 } from "node:crypto";
3538
- var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3363
+ var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3539
3364
  var MAX_PAYLOAD_BYTES = 512 * 1024;
3540
- function observationRef(event, identity, value) {
3541
- return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
3365
+ function observationRef(hostSourceRef, event, identity, value) {
3366
+ return cealHostObservationRef("codex", shortDigest({ host_source_ref: hostSourceRef, event, identity, value }));
3542
3367
  }
3543
3368
  function hostTurnReference(sourceRef, sessionRef, nativeTurnId) {
3544
- if (![sourceRef, sessionRef, nativeTurnId].every((value) => SAFE_REF6.test(value))) throw new CodexHostAdapterError("invalid_input", "Codex turn identity is invalid.");
3369
+ if (![sourceRef, sessionRef, nativeTurnId].every((value) => SAFE_REF4.test(value))) throw new CodexHostAdapterError("invalid_input", "Codex turn identity is invalid.");
3545
3370
  return `codex-turn:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId })}`;
3546
3371
  }
3547
3372
  function hostInputReference(sourceRef, sessionRef, nativeTurnId, messageId, ordinal, prompt) {
3548
- if (![sourceRef, sessionRef, nativeTurnId, messageId].every((value) => SAFE_REF6.test(value)) || !Number.isSafeInteger(ordinal) || ordinal < 0) {
3373
+ if (![sourceRef, sessionRef, nativeTurnId, messageId].every((value) => SAFE_REF4.test(value)) || !Number.isSafeInteger(ordinal) || ordinal < 0) {
3549
3374
  throw new CodexHostAdapterError("invalid_input", "Codex input identity is invalid.");
3550
3375
  }
3551
3376
  return `codex-input:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId, message_id: messageId, ordinal, prompt_sha256: sha256(prompt) })}`;
@@ -3567,7 +3392,7 @@ function shortDigest(value) {
3567
3392
  import { createHash as createHash6 } from "node:crypto";
3568
3393
 
3569
3394
  // host/codex/src/codex-transcript-decoder.ts
3570
- var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3395
+ var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3571
3396
  var MAX_PROMPT_BYTES = 64 * 1024;
3572
3397
  function decodeCodexTranscriptLine(line) {
3573
3398
  let value;
@@ -3578,38 +3403,38 @@ function decodeCodexTranscriptLine(line) {
3578
3403
  }
3579
3404
  if (!isRecord6(value)) reject("Codex transcript record envelope is malformed.");
3580
3405
  const ordinal = safeOrdinal(value.ordinal);
3581
- const timestamp4 = safeTimestamp(value.timestamp);
3406
+ const timestamp3 = safeTimestamp(value.timestamp);
3582
3407
  if (!isRecord6(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
3583
- if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
3584
- if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
3585
- if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
3586
- if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
3587
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
3408
+ if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp3);
3409
+ if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp3);
3410
+ if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp3);
3411
+ if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp3);
3412
+ return { kind: "ignored", ordinal, timestamp: timestamp3 };
3588
3413
  }
3589
- function decodeTurnContext(payload, ordinal, timestamp4) {
3414
+ function decodeTurnContext(payload, ordinal, timestamp3) {
3590
3415
  return {
3591
3416
  kind: "turn_context",
3592
3417
  ordinal,
3593
- timestamp: timestamp4,
3594
- turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
3418
+ timestamp: timestamp3,
3419
+ turn_id: safeRef3(payload.turn_id, "Codex turn context identity is invalid."),
3595
3420
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
3596
3421
  };
3597
3422
  }
3598
- function decodeSessionMeta(payload, ordinal, timestamp4) {
3599
- const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
3423
+ function decodeSessionMeta(payload, ordinal, timestamp3) {
3424
+ const sessionId = safeRef3(payload.id, "Codex transcript session identity is invalid.");
3600
3425
  const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
3601
- return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
3426
+ return { kind: "session_meta", ordinal, timestamp: timestamp3, session_id: sessionId, cli_version: cliVersion };
3602
3427
  }
3603
- function decodeEventMessage(payload, ordinal, timestamp4) {
3428
+ function decodeEventMessage(payload, ordinal, timestamp3) {
3604
3429
  if (payload.type === "task_started") {
3605
- return { kind: "task_started", ordinal, timestamp: timestamp4, turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
3430
+ return { kind: "task_started", ordinal, timestamp: timestamp3, turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
3606
3431
  }
3607
3432
  if (payload.type === "task_complete") {
3608
3433
  return {
3609
3434
  kind: "task_complete",
3610
3435
  ordinal,
3611
- timestamp: timestamp4,
3612
- turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
3436
+ timestamp: timestamp3,
3437
+ turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."),
3613
3438
  started_at: safeNumber(payload.started_at),
3614
3439
  completed_at: safeNumber(payload.completed_at),
3615
3440
  duration_ms: safeNumber(payload.duration_ms),
@@ -3620,20 +3445,20 @@ function decodeEventMessage(payload, ordinal, timestamp4) {
3620
3445
  return {
3621
3446
  kind: "turn_aborted",
3622
3447
  ordinal,
3623
- timestamp: timestamp4,
3624
- turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
3448
+ timestamp: timestamp3,
3449
+ turn_id: safeRef3(payload.turn_id, "Codex task identity is invalid."),
3625
3450
  started_at: safeNumber(payload.started_at),
3626
3451
  completed_at: safeNumber(payload.completed_at),
3627
3452
  duration_ms: safeNumber(payload.duration_ms),
3628
3453
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
3629
3454
  };
3630
3455
  }
3631
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
3632
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
3456
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp3);
3457
+ return { kind: "ignored", ordinal, timestamp: timestamp3 };
3633
3458
  }
3634
- function decodeTokenCount(payload, ordinal, timestamp4) {
3635
- if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
3636
- if (!isRecord6(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
3459
+ function decodeTokenCount(payload, ordinal, timestamp3) {
3460
+ if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp3 };
3461
+ if (!isRecord6(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp3, usage_gap_reason: "token_count_shape_not_attributable" };
3637
3462
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
3638
3463
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
3639
3464
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -3641,7 +3466,7 @@ function decodeTokenCount(payload, ordinal, timestamp4) {
3641
3466
  return {
3642
3467
  kind: "token_count",
3643
3468
  ordinal,
3644
- timestamp: timestamp4,
3469
+ timestamp: timestamp3,
3645
3470
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
3646
3471
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
3647
3472
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -3669,26 +3494,24 @@ function decodeTokenUsage(value) {
3669
3494
  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) reject("Codex token usage buckets are inconsistent.");
3670
3495
  return usage;
3671
3496
  }
3672
- function decodeResponseItem(payload, ordinal, timestamp4) {
3673
- if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
3497
+ function decodeResponseItem(payload, ordinal, timestamp3) {
3498
+ if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp3 };
3674
3499
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
3675
- const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
3676
- if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
3500
+ const contentItemKind = userTextContentKind(metadata.content_item_kinds);
3501
+ if (contentItemKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp3 };
3677
3502
  const prompt = userTextContent(payload.content);
3678
3503
  return {
3679
3504
  kind: "user_text",
3680
3505
  ordinal,
3681
- timestamp: timestamp4,
3506
+ timestamp: timestamp3,
3682
3507
  prompt,
3683
- input_kind: inputKind,
3684
- message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
3685
- turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
3508
+ content_item_kind: contentItemKind,
3509
+ message_id: safeRef3(payload.id, "Codex user message identity is invalid."),
3510
+ turn_id: safeRef3(metadata.turn_id, "Codex user message task identity is invalid.")
3686
3511
  };
3687
3512
  }
3688
- function inputKindFromContentItems(kinds) {
3689
- if (kinds.length !== 1) return void 0;
3690
- if (kinds[0] === "user.text") return "human";
3691
- return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
3513
+ function userTextContentKind(kinds) {
3514
+ return kinds.length === 1 && (kinds[0] === "user.text" || kinds[0] === "goal.internal_context") ? kinds[0] : void 0;
3692
3515
  }
3693
3516
  function userMessageMetadata(value) {
3694
3517
  if (!isRecord6(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
@@ -3718,8 +3541,8 @@ function safeTimestamp(value) {
3718
3541
  if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
3719
3542
  return value;
3720
3543
  }
3721
- function safeRef4(value, message) {
3722
- if (typeof value !== "string" || !SAFE_REF7.test(value)) reject(message);
3544
+ function safeRef3(value, message) {
3545
+ if (typeof value !== "string" || !SAFE_REF5.test(value)) reject(message);
3723
3546
  return value;
3724
3547
  }
3725
3548
  function boundedText(value, maximum, message) {
@@ -3757,46 +3580,40 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
3757
3580
  anchor_sha256: digest(Buffer.alloc(0)),
3758
3581
  header_validated: false,
3759
3582
  status: "active",
3760
- updated_at: timestamp3(now)
3583
+ updated_at: timestamp2(now)
3761
3584
  };
3762
3585
  }
3763
- async function ownedCodexTranscriptFile(handle) {
3586
+ async function ownedCodexTranscriptFile(handle, platform = process.platform) {
3764
3587
  const stats = await handle.stat();
3765
- assertCodexTranscriptOwner(stats);
3588
+ if (!stats.isFile()) throw new CodexHostAdapterError("storage", "Codex transcript source is not a regular file.");
3589
+ if (platform !== "win32" && !isSelfOwned(stats.uid, platform, handle)) throw new CodexHostAdapterError("storage", "Codex transcript source is owned by another user.");
3766
3590
  return { size: stats.size, device: String(stats.dev), inode: String(stats.ino) };
3767
3591
  }
3768
- function assertCodexTranscriptOwner(stats) {
3769
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
3770
- 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)")}).`);
3771
- if (stats.uid !== uid) throw new CodexHostAdapterError("storage", `Codex transcript source is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
3772
- }
3773
- function assertCodexTranscriptHeader(registration, record3) {
3774
- 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([
3775
- { name: "kind", value: record3.kind, expected: "session_meta" },
3776
- { name: "session_id", value: record3.kind === "session_meta" ? record3.session_id : "unavailable", expected: registration.codex_session_id }
3592
+ function assertCodexTranscriptHeader(registration, record) {
3593
+ 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([
3594
+ { name: "kind", value: record.kind, expected: "session_meta" },
3595
+ { name: "session_id", value: record.kind === "session_meta" ? record.session_id : "unavailable", expected: registration.codex_session_id }
3777
3596
  ])}).`);
3778
3597
  }
3779
3598
  function digest(value) {
3780
3599
  return createHash6("sha256").update(value).digest("hex");
3781
3600
  }
3782
- function timestamp3(now) {
3601
+ function timestamp2(now) {
3783
3602
  const value = now();
3784
3603
  if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
3785
3604
  return value.toISOString();
3786
3605
  }
3787
3606
 
3788
3607
  // host/codex/src/codex-adapter.ts
3789
- var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3608
+ var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3790
3609
  function codexSubmissionReference(hostInputRef, event, ordinal) {
3791
- if (!SAFE_REF8.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
3610
+ if (!SAFE_REF6.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
3792
3611
  return `codex-submission:${cealRequestSha256({ host_input_ref: hostInputRef, event, ordinal })}`;
3793
3612
  }
3794
3613
 
3795
3614
  // host/codex/src/codex-transcript-watcher.ts
3796
3615
  var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3797
3616
  store;
3798
- registerCurrentPrompt;
3799
- releaseCurrentPrompt;
3800
3617
  diagnostic;
3801
3618
  constructor(options) {
3802
3619
  super(options, {
@@ -3805,8 +3622,6 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3805
3622
  clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
3806
3623
  });
3807
3624
  this.store = new CodexOutboxStore(options.outbox_dir);
3808
- this.registerCurrentPrompt = options.register_current_prompt;
3809
- this.releaseCurrentPrompt = options.release_current_prompt;
3810
3625
  this.diagnostic = options.diagnostic ?? (() => void 0);
3811
3626
  }
3812
3627
  transcriptPathOf(registration) {
@@ -3829,14 +3644,12 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3829
3644
  return { records: 0, enqueued: 0, quarantined: true };
3830
3645
  }
3831
3646
  async retireMissing(registration) {
3832
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, await this.store.readTranscriptCursor(registration).catch(() => null));
3833
3647
  return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
3834
3648
  }
3835
3649
  async preflight(registration, handle, size, device, inode) {
3836
3650
  const existing = await this.store.readTranscriptCursor(registration);
3837
3651
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
3838
3652
  if (cursor.status === "quarantined") {
3839
- if (cursor.reason !== "transcript_malformed") await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
3840
3653
  return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
3841
3654
  }
3842
3655
  const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
@@ -3850,22 +3663,22 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3850
3663
  let records = 0;
3851
3664
  let enqueued = 0;
3852
3665
  for (const line of complete.toString("utf8").split("\n").filter((value) => value.length > 0)) {
3853
- const record3 = decodeCodexTranscriptLine(line);
3854
- assertRecordSequence(registration, cursor, records, lastOrdinal, record3);
3855
- await this.observeSessionMetadata(registration, record3);
3856
- const outcome = await this.processRecord(registration, activeTask, record3);
3666
+ const record = decodeCodexTranscriptLine(line);
3667
+ assertRecordSequence(registration, cursor, records, lastOrdinal, record);
3668
+ await this.observeSessionMetadata(registration, record);
3669
+ const outcome = await this.processRecord(registration, activeTask, record);
3857
3670
  activeTask = outcome.activeTask;
3858
3671
  enqueued += outcome.enqueued;
3859
- lastOrdinal = record3.ordinal;
3672
+ lastOrdinal = record.ordinal;
3860
3673
  records += 1;
3861
3674
  }
3862
3675
  await this.commitCursor(registration, handle, cursor, complete.length, device, inode, lastOrdinal, activeTask);
3863
3676
  return { records, enqueued, quarantined: false };
3864
3677
  }
3865
- async observeSessionMetadata(registration, record3) {
3866
- if (record3.kind !== "session_meta") return;
3678
+ async observeSessionMetadata(registration, record) {
3679
+ if (record.kind !== "session_meta") return;
3867
3680
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
3868
- if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
3681
+ if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record.cli_version } });
3869
3682
  }
3870
3683
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
3871
3684
  const offset = cursor.offset + consumedBytes;
@@ -3888,56 +3701,54 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3888
3701
  };
3889
3702
  await this.store.writeTranscriptCursor(quarantined);
3890
3703
  }
3891
- async processRecord(registration, activeTask, record3) {
3892
- if (record3.kind === "task_started") return this.processTaskStarted(registration, activeTask, record3);
3893
- if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
3894
- if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
3895
- if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
3896
- if (record3.kind === "task_complete" || record3.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record3);
3704
+ async processRecord(registration, activeTask, record) {
3705
+ if (record.kind === "task_started") return this.processTaskStarted(registration, record);
3706
+ if (record.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record.model } : activeTask }, enqueued: 0 };
3707
+ if (record.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record) }, enqueued: 0 };
3708
+ if (record.kind === "user_text") return this.processUserInput(registration, activeTask, record);
3709
+ if (record.kind === "task_complete" || record.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record);
3897
3710
  return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
3898
3711
  }
3899
- async processTaskStarted(registration, activeTask, record3) {
3900
- 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);
3901
- 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 };
3712
+ async processTaskStarted(registration, record) {
3713
+ 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 };
3902
3714
  }
3903
- async processUserInput(registration, activeTask, record3) {
3904
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) {
3905
- const adopted = await this.adoptHookCorrelatedTurn(registration, activeTask, record3);
3715
+ async processUserInput(registration, activeTask, record) {
3716
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record.turn_id) {
3717
+ const adopted = await this.adoptHookCorrelatedTurn(registration, record);
3906
3718
  if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
3907
3719
  activeTask = adopted;
3908
3720
  }
3909
- const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
3721
+ const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record.turn_id, record.message_id, record.ordinal, record.prompt);
3910
3722
  const origin = activeTask.origin_host_input_ref === void 0;
3911
- const promptValue = promptObservationValue(record3.prompt);
3723
+ const promptValue = promptObservationValue(record.prompt);
3912
3724
  const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
3913
3725
  const promptRef = activeTask.prompt_ref ?? currentPromptRef;
3914
3726
  const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
3915
3727
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
3916
3728
  const observations = [{
3917
- observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
3729
+ observation_ref: observationRef(registration.host_source_ref, "transcript_user_text", hostInputRef, record.prompt),
3918
3730
  observation_kind: "prompt",
3919
- observed_at: record3.timestamp,
3731
+ observed_at: record.timestamp,
3920
3732
  value: promptValue
3921
3733
  }];
3922
3734
  if (origin) {
3923
- 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") });
3735
+ 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") });
3924
3736
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
3925
- 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 });
3737
+ 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 });
3926
3738
  }
3927
3739
  const envelope = {
3928
3740
  schema_version: "ceal.codex_observation_outbox.v1",
3929
3741
  identity,
3930
3742
  host_input_ref: hostInputRef,
3931
- input_kind: record3.input_kind,
3932
3743
  prompt_ref: promptRef,
3933
3744
  observations,
3934
- codex_turn_id: record3.turn_id,
3745
+ codex_turn_id: record.turn_id,
3935
3746
  origin_input: origin,
3936
- submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
3937
- created_at: record3.timestamp,
3747
+ submission_ref: codexSubmissionReference(hostInputRef, "input", record.ordinal),
3748
+ created_at: record.timestamp,
3938
3749
  expires_at: this.expire(this.outboxRetentionMs)
3939
3750
  };
3940
- const persisted = await this.persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
3751
+ const persisted = await this.persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
3941
3752
  if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
3942
3753
  return persisted;
3943
3754
  }
@@ -3964,40 +3775,21 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3964
3775
  * stay ignored. A stale active task for another turn releases first, the
3965
3776
  * same as a task_started supersession.
3966
3777
  */
3967
- async adoptHookCorrelatedTurn(registration, activeTask, record3) {
3968
- const currentPromptRef = hostProducerPromptRef(promptObservationValue(record3.prompt).body_sha256);
3778
+ async adoptHookCorrelatedTurn(registration, record) {
3779
+ const currentPromptRef = hostProducerPromptRef(promptObservationValue(record.prompt).body_sha256);
3969
3780
  const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
3970
3781
  if (selection?.prompt_ref !== currentPromptRef) return void 0;
3971
- if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) {
3972
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
3973
- }
3974
3782
  return {
3975
- codex_turn_id: record3.turn_id,
3976
- host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id),
3977
- started_at: record3.timestamp
3783
+ codex_turn_id: record.turn_id,
3784
+ host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record.turn_id),
3785
+ started_at: record.timestamp
3978
3786
  };
3979
3787
  }
3980
- async persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
3981
- const custodyRegistered = await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
3982
- if (custodyRegistered) this.diagnostic("watcher_turn_observed");
3983
- try {
3984
- await this.store.put(envelope);
3985
- if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
3986
- } catch (error) {
3987
- if (custodyRegistered) await this.releasePrompt(registration.host_session_ref, activeTask, currentPromptRef).catch(() => void 0);
3988
- throw error;
3989
- }
3788
+ async persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
3789
+ await this.store.put(envelope);
3790
+ if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
3990
3791
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
3991
3792
  }
3992
- async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
3993
- if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return false;
3994
- const register = this.registerCurrentPrompt;
3995
- const installationRef = this.producerInstallationRef;
3996
- return registerHostCurrentPromptDiagnosed(
3997
- () => 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 }),
3998
- (event) => this.diagnostic(event)
3999
- );
4000
- }
4001
3793
  async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
4002
3794
  try {
4003
3795
  const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
@@ -4009,41 +3801,27 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
4009
3801
  throw error;
4010
3802
  }
4011
3803
  }
4012
- async releasePrompt(sessionRef, activeTask, promptRef) {
4013
- if (this.producerInstallationRef === void 0 || this.releaseCurrentPrompt === void 0) return;
4014
- 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 });
4015
- }
4016
- async releaseStoredPromptBestEffort(sessionRef, cursor) {
4017
- await this.releaseActiveTaskBestEffort(sessionRef, cursor?.active_task);
4018
- }
4019
- async releaseActiveTaskBestEffort(sessionRef, activeTask) {
4020
- if (activeTask?.prompt_ref === void 0) return;
4021
- await this.releasePrompt(sessionRef, activeTask, activeTask.prompt_ref).catch(() => void 0);
4022
- }
4023
- async processTerminal(registration, activeTask, record3) {
4024
- 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 };
3804
+ async processTerminal(registration, activeTask, record) {
3805
+ 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 };
4025
3806
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
4026
- 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 };
4027
- const observations = terminalObservations(registration, activeTask, record3, timing);
3807
+ 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 };
3808
+ const observations = terminalObservations(registration, activeTask, record, timing);
4028
3809
  await this.store.put({
4029
3810
  schema_version: "ceal.codex_observation_outbox.v1",
4030
3811
  identity,
4031
3812
  host_input_ref: activeTask.origin_host_input_ref,
4032
- input_kind: "host_automatic",
4033
3813
  prompt_ref: activeTask.prompt_ref,
4034
3814
  observations,
4035
- codex_turn_id: record3.turn_id,
3815
+ codex_turn_id: record.turn_id,
4036
3816
  origin_input: false,
4037
- submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
4038
- created_at: record3.timestamp,
3817
+ submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record.ordinal),
3818
+ created_at: record.timestamp,
4039
3819
  expires_at: this.expire(this.outboxRetentionMs)
4040
3820
  });
4041
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4042
3821
  await this.store.clearInvocationContext(identity, this.now());
4043
3822
  return { enqueued: 1 };
4044
3823
  }
4045
3824
  async quarantine(registration, cursor, device, inode, reason) {
4046
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
4047
3825
  const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
4048
3826
  await this.store.writeTranscriptCursor(quarantined);
4049
3827
  }
@@ -4056,10 +3834,10 @@ function codexTranscriptScanFailureKind(error) {
4056
3834
  return void 0;
4057
3835
  });
4058
3836
  }
4059
- function accumulateTokenCount(activeTask, record3) {
4060
- if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
4061
- const last = record3.last_usage;
4062
- const total = record3.total_usage;
3837
+ function accumulateTokenCount(activeTask, record) {
3838
+ if (record.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record.usage_gap_reason };
3839
+ const last = record.last_usage;
3840
+ const total = record.total_usage;
4063
3841
  if (last === void 0 || ignoreTokenCount(activeTask.last_total_usage, total, last)) return activeTask;
4064
3842
  const tokenUsage = addUsage(activeTask.token_usage, last);
4065
3843
  return {
@@ -4073,21 +3851,16 @@ function ignoreTokenCount(previous, total, last) {
4073
3851
  if (total === void 0 || previous === void 0) return false;
4074
3852
  return sameUsage(total, previous) || regressedUsage(total, previous) && looksLikeStaleRegression(total, previous, last);
4075
3853
  }
4076
- function terminalObservations(registration, activeTask, record3, timing) {
3854
+ function terminalObservations(registration, activeTask, record, timing) {
4077
3855
  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);
4078
- const costValue = terminalCostValue();
4079
3856
  const observations = [
4080
- { 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") },
4081
- { observation_ref: observationRef("transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record3.timestamp, value: timing },
4082
- { observation_ref: observationRef("transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record3.timestamp, value: tokenValue },
4083
- { observation_ref: observationRef("transcript_cost", activeTask.host_turn_ref, costValue), observation_kind: "cost", observed_at: record3.timestamp, value: costValue }
3857
+ { 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") },
3858
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record.timestamp, value: timing },
3859
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record.timestamp, value: tokenValue }
4084
3860
  ];
4085
- 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" } });
3861
+ 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" } });
4086
3862
  return observations;
4087
3863
  }
4088
- function terminalCostValue() {
4089
- return notRecorded("provider_cost_not_observed");
4090
- }
4091
3864
  function notRecorded(reason) {
4092
3865
  return hostObservationNotRecorded(reason);
4093
3866
  }
@@ -4134,25 +3907,21 @@ function looksLikeStaleRegression(current, previous, last) {
4134
3907
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
4135
3908
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
4136
3909
  }
4137
- function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
4138
- 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}`)}).`);
4139
- if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
3910
+ function assertRecordSequence(registration, cursor, records, lastOrdinal, record) {
3911
+ 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}`)}).`);
3912
+ if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record);
4140
3913
  }
4141
3914
 
4142
3915
  // host/codex/src/codex-producer-runtime.ts
4143
3916
  async function drainCodexProducerOnce(options) {
4144
- const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
4145
3917
  const scan = await new CodexTranscriptWatcher({
4146
3918
  outbox_dir: options.outbox_dir,
4147
- producer_installation_ref: options.producer_installation_ref,
4148
- register_current_prompt: (input) => promptPort.register(input),
4149
- release_current_prompt: (identity) => promptPort.release(identity),
4150
3919
  diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
4151
3920
  }).scanOnce().catch((error) => {
4152
3921
  writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
4153
3922
  throw error;
4154
3923
  });
4155
- 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 } });
3924
+ const producer = new CodexProducer({ outbox_dir: options.outbox_dir, ...options.now === void 0 ? {} : { now: options.now } });
4156
3925
  return { scanned: scan.enqueued, ...await producer.drainOutbox() };
4157
3926
  }
4158
3927
 
@@ -4165,11 +3934,7 @@ var CODEX_PRODUCER_DESCRIPTOR = {
4165
3934
  extra_paths: [CODEX_SESSIONS_ROOT],
4166
3935
  config: (shared, extras) => ({ ...shared, codex_sessions_root: hostProducerExtraPath(extras, CODEX_SESSIONS_ROOT) }),
4167
3936
  runtime_options: (config) => Object.freeze({
4168
- outbox_dir: config.outbox_dir,
4169
- producer_installation_ref: config.producer_installation_ref,
4170
- producer_epoch: config.producer_epoch,
4171
- relay_endpoint: config.relay_endpoint,
4172
- timeout_ms: config.ipc_timeout_ms
3937
+ outbox_dir: config.outbox_dir
4173
3938
  }),
4174
3939
  drain: drainCodexProducerOnce
4175
3940
  };
@@ -4179,13 +3944,15 @@ function runCodexProducerCli(args, signal, dependencies = {}) {
4179
3944
 
4180
3945
  // host/producer-command.ts
4181
3946
  async function runProducerCommand(schemaVersion, run) {
3947
+ const serviceArguments = consumeHostServiceLogArgument(process.argv.slice(2));
3948
+ if (serviceArguments.path !== void 0) process.env[HOST_SERVICE_LOG_ENVIRONMENT] = serviceArguments.path;
4182
3949
  const controller = new AbortController();
4183
3950
  const stop = () => controller.abort();
4184
3951
  process.once("SIGINT", stop);
4185
3952
  process.once("SIGTERM", stop);
4186
3953
  const stopLogBound = boundHostServiceLog();
4187
3954
  try {
4188
- await run(process.argv.slice(2), controller.signal);
3955
+ await run(serviceArguments.args, controller.signal);
4189
3956
  } catch (error) {
4190
3957
  const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "producer_failed";
4191
3958
  process.stderr.write(`${JSON.stringify({ schema_version: schemaVersion, ok: false, code })}