@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.
@@ -2059,16 +2059,34 @@ function isPlainRecord(value) {
2059
2059
  return prototype === Object.prototype || prototype === null;
2060
2060
  }
2061
2061
 
2062
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
2063
+ import { createHash } from "node:crypto";
2064
+
2062
2065
  // packages/ceal-client-protocol/client-wire-contract.json
2063
2066
  var client_wire_contract_default = {
2064
2067
  schema_version: "ceal.client_wire_contract.v1",
2068
+ doctor: {
2069
+ schema_version: "ceal.doctor.v1"
2070
+ },
2071
+ client_commands: {
2072
+ doctor: ["doctor"],
2073
+ version: ["version"],
2074
+ access_group_list: ["access-group", "list"]
2075
+ },
2076
+ client_environment: {
2077
+ environment_prefix: "CEAL",
2078
+ context_override_suffixes: ["GATEWAY_ORIGIN", "GATEWAY_TRANSPORT_ORIGIN", "ACCESS_TOKEN", "CONTEXT_STORE_PATH"]
2079
+ },
2065
2080
  canonical_json: {
2066
2081
  ordering: "utf16_code_unit_ascending"
2067
2082
  },
2068
2083
  artifact_descriptor: {
2069
- operation_contract_bundle_schema_version: "ceal.operation_contract_bundle.v1",
2070
- schema_version: "ceal.verified_artifact_descriptor.v1",
2071
- binding_schema_version: "ceal.verified_artifact_binding.v1",
2084
+ operation_contract_bundle_schema_name: "ceal.operation_contract_bundle",
2085
+ operation_contract_bundle_fields: ["schema_version", "catalog_revision", "operations", "failure_guidance"],
2086
+ schema_name: "ceal.verified_artifact_descriptor",
2087
+ fields: ["schema_version", "kind", "media_type", "byte_count", "sha256", "binding"],
2088
+ binding_schema_name: "ceal.verified_artifact_binding",
2089
+ binding_fields: ["schema_version", "kind", "catalog_revision"],
2072
2090
  kind: "verified_artifact",
2073
2091
  binding_kind: "catalog",
2074
2092
  media_type: "application/json",
@@ -2084,14 +2102,16 @@ var client_wire_contract_default = {
2084
2102
  length: 72,
2085
2103
  pattern: "^catalog:[a-f0-9]{64}$"
2086
2104
  },
2087
- envelope_max_bytes: 389
2105
+ envelope_max_bytes: 407
2088
2106
  },
2089
2107
  command_request: {
2090
- schema_version: "ceal.command_request.v1",
2108
+ schema_name: "ceal.command_request",
2109
+ fields: ["schema_version", "argv", "operation", "client_nonce", "context_token"],
2091
2110
  absolute_transport_max_bytes: 65536
2092
2111
  },
2093
2112
  command_resolution: {
2094
- schema_version: "ceal.gateway_command_resolution.v1",
2113
+ schema_name: "ceal.gateway_command_resolution",
2114
+ 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"],
2095
2115
  authority: {
2096
2116
  anonymous: {
2097
2117
  state: "anonymous",
@@ -2131,7 +2151,8 @@ var client_wire_contract_default = {
2131
2151
  }
2132
2152
  },
2133
2153
  command_response: {
2134
- schema_version: "ceal.command_response.v1",
2154
+ schema_name: "ceal.command_response",
2155
+ fields: ["schema_version", "exit_code", "document", "operation_id", "visible_output_max_bytes", "local_delivery", "verified_artifact"],
2135
2156
  descriptor_field: "verified_artifact",
2136
2157
  required_fields: [
2137
2158
  "schema_version",
@@ -2155,29 +2176,41 @@ var client_wire_contract_default = {
2155
2176
  "required_action_sequence",
2156
2177
  "withheld"
2157
2178
  ],
2158
- prompt_field: "prompt",
2159
- prompt_schema_version: "ceal.prompt.v1",
2160
- focused_prompt_document_fields: [
2161
- "catalog_revision",
2162
- "prompt"
2163
- ],
2164
- focused_prompt_continuation_document_fields: [
2165
- "catalog_revision",
2166
- "remaining_work",
2167
- "prompt"
2168
- ],
2169
2179
  discovery_command: "discovery",
2170
- discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
2180
+ discovery_manifest_schema_name: "ceal.discovery_manifest",
2181
+ discovery_manifest_fields: ["schema_version", "skill", "authority_scope", "connector_kinds", "personal_connector_kinds", "guide_markdown", "renderer_version", "digest"],
2171
2182
  discovery_manifest_document_fields: [
2172
2183
  "discovery_manifest"
2173
2184
  ],
2174
2185
  exit_code_max: 125,
2175
2186
  bare_document_max_bytes: 65536,
2176
- complete_max_bytes: 66019
2187
+ complete_max_bytes: 66046
2188
+ },
2189
+ host_invocation_authentication: {
2190
+ request_schema_name: "ceal.host_invocation_authentication_request",
2191
+ request_fields: [
2192
+ "schema_version",
2193
+ "client_nonce"
2194
+ ],
2195
+ result_schema_name: "ceal.host_invocation_authentication_result",
2196
+ result_fields: [
2197
+ "schema_version",
2198
+ "context_token",
2199
+ "expires_at"
2200
+ ],
2201
+ client_nonce: {
2202
+ character_class_source: "A-Za-z0-9_-",
2203
+ encoded_characters: 43
2204
+ }
2205
+ },
2206
+ gateway_host_invocation_context_request: {
2207
+ schema_name: "ceal.gateway_host_invocation_context_request",
2208
+ fields: ["schema_version", "client_nonce", "context_expires_at", "request_work_context", "current_prompt", "visible_output_max_bytes"]
2177
2209
  },
2178
2210
  resource_stream: {
2179
2211
  path: "/api/ceal/v2/resources",
2180
- request_schema_version: "ceal.resource_stream_request.v1",
2212
+ request_schema_name: "ceal.resource_stream_request",
2213
+ request_fields: ["schema_version", "resource_ref", "client_nonce", "context_token"],
2181
2214
  ref_pattern: "^resource:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
2182
2215
  media_type_pattern: "^[a-z0-9][a-z0-9!#$&^_.+-]{0,63}/[a-z0-9][a-z0-9!#$&^_.+-]{0,63}$",
2183
2216
  filename_max_bytes: 512,
@@ -2194,92 +2227,6 @@ var client_wire_contract_default = {
2194
2227
  }
2195
2228
  };
2196
2229
 
2197
- // packages/ceal-client-protocol/src/client-wire-contract.ts
2198
- var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
2199
- var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
2200
- var commandResolutionAuthority = commandResolution.authority;
2201
- var commandResolutionSemanticOptions = commandResolution.semantic_options;
2202
- var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = commandResolution.schema_version;
2203
- var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
2204
- var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
2205
- var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
2206
- var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
2207
- var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = artifact.operation_contract_bundle_schema_version;
2208
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = artifact.schema_version;
2209
- var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = artifact.binding_schema_version;
2210
- var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
2211
- var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
2212
- var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
2213
- var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
2214
- var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
2215
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
2216
- var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
2217
- var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
2218
- var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
2219
- var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
2220
- var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
2221
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
2222
- var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
2223
- var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
2224
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
2225
- var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
2226
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
2227
- var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
2228
- var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
2229
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
2230
- var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
2231
- var CEAL_COMMAND_RESPONSE_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
2232
-
2233
- // packages/ceal-client-protocol/src/vocabulary.ts
2234
- function vocabulary(words) {
2235
- return Object.freeze(words);
2236
- }
2237
- function isVocabularyWord(words, value) {
2238
- return words.some((word) => word === value);
2239
- }
2240
-
2241
- // packages/ceal-client-protocol/src/gateway-response-types.ts
2242
- var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
2243
- var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
2244
- var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
2245
- var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
2246
- 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"]);
2247
- var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
2248
- var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
2249
- var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
2250
- var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
2251
- var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
2252
- var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
2253
- var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
2254
- var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
2255
- var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
2256
- var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
2257
- var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
2258
- var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
2259
- var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
2260
- var CEAL_PROTOCOL_VERSION = "1.4.0";
2261
- var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
2262
- var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
2263
- var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
2264
- "audited_call_pending",
2265
- "continuation_read_pending",
2266
- "continuation_write_pending",
2267
- "provider_pacing_pending",
2268
- "corpus_replay_pending",
2269
- "corpus_append_pending",
2270
- "corpus_fence_pending",
2271
- "corpus_content_pending",
2272
- "corpus_transaction_pending"
2273
- ]);
2274
- var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
2275
- var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
2276
- var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
2277
- var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
2278
- "connector_ref",
2279
- "connector_revision",
2280
- "policy_decision_revision"
2281
- ]);
2282
-
2283
2230
  // packages/ceal-client-protocol/src/operation-next-actions.ts
2284
2231
  var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
2285
2232
  var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
@@ -2346,7 +2293,10 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
2346
2293
  "follow_required_action_sequence",
2347
2294
  // The command needs caller-owned local materialization (for example an
2348
2295
  // @path file) before the Gateway can receive the argument.
2349
- "materialize_local_argument"
2296
+ "materialize_local_argument",
2297
+ // A peer's derived schema identifier changed with its field set; install or
2298
+ // upgrade the CLI and Host Relay to the Gateway's release before retrying.
2299
+ "upgrade_ceal_client"
2350
2300
  ];
2351
2301
  var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
2352
2302
  var NON_REMEDY_NEXT_ACTION_VALUES = [
@@ -2459,47 +2409,56 @@ var CEAL_OPERATION_WITHHELD_NEXT_ACTIONS = Object.freeze({
2459
2409
  personal_authorization_required: "connect_personal_account"
2460
2410
  });
2461
2411
 
2462
- // packages/ceal-client-protocol/src/operation-withheld-cause.ts
2463
- var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
2412
+ // packages/ceal-client-protocol/src/vocabulary.ts
2413
+ function vocabulary(words) {
2414
+ return Object.freeze(words);
2415
+ }
2416
+ function isVocabularyWord(words, value) {
2417
+ return words.some((word) => word === value);
2418
+ }
2464
2419
 
2465
- // packages/ceal-client-protocol/src/operation-contract-types.ts
2466
- var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
2467
- var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
2468
- var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
2469
- var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
2470
- var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
2471
- var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
2472
- var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
2473
- var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
2474
- var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
2475
- var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
2476
- var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
2477
- var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
2478
- var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
2479
- var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
2480
- var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
2481
- var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
2482
- var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
2483
- var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
2484
- var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
2485
- var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
2486
- var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
2487
- var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
2488
- var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
2489
- var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
2490
- var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
2491
- var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
2492
- var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
2493
- var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
2494
- var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
2495
- var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
2496
- var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
2497
- "approval_not_required_by_policy",
2498
- "interactive_pending",
2499
- "interactive_granted",
2500
- "interactive_denied",
2501
- "interactive_expired",
2502
- "interactive_unavailable"
2420
+ // packages/ceal-client-protocol/src/gateway-response-types.ts
2421
+ var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
2422
+ var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
2423
+ var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
2424
+ var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
2425
+ 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"]);
2426
+ var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
2427
+ var CEAL_GATEWAY_DERIVED_STORE_FAILURE_CLASSES = vocabulary(["storage_unavailable", "decode_mismatch", "write_conflict", "quota", "store_error"]);
2428
+ var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
2429
+ var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
2430
+ var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
2431
+ var CEAL_WRITE_SOURCE_KINDS = vocabulary(["authenticated_registered_client", "provider_authenticated_event"]);
2432
+ var CEAL_REFRESH_DELIVERIES = vocabulary(["initial", "recovery", "replay", "terminal_failure", "recovery_unavailable"]);
2433
+ var CEAL_CLIENT_OPERATIONS = vocabulary(["handshake", "discover", "call", "readback"]);
2434
+ var CEAL_WRITE_IDEMPOTENCY_POSTURES = vocabulary(["required", "optional", "not_required"]);
2435
+ var CEAL_WRITE_PROVIDER_READBACK_POSTURES = vocabulary(["required", "best_effort", "not_available"]);
2436
+ var CEAL_WRITE_ATTRIBUTIONS = vocabulary(["subject", "requester_event", "connector_integration"]);
2437
+ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verified", "not_dispatched"]);
2438
+ var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
2439
+ var CEAL_PROTOCOL_VERSION = "1.4.0";
2440
+ var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
2441
+ var CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION = "ceal.gateway_call_result.v1";
2442
+ var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
2443
+ var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
2444
+ "audited_call_pending",
2445
+ "continuation_read_pending",
2446
+ "continuation_write_pending",
2447
+ "provider_pacing_pending",
2448
+ "corpus_replay_pending",
2449
+ "corpus_append_pending",
2450
+ "corpus_fence_pending",
2451
+ "corpus_content_pending",
2452
+ "corpus_transaction_pending"
2453
+ ]);
2454
+ var CEAL_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "phase", "schema_version"]);
2455
+ var CEAL_CLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["cause", ...CEAL_CONNECTOR_ROUTE_FAILURE_KEYS]);
2456
+ var CEAL_UNCLASSIFIED_CONNECTOR_ROUTE_FAILURE_KEYS = vocabulary(["connector_kind", "error_class", "phase", "schema_version"]);
2457
+ var CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION = "ceal.gateway_audit_call_detail.v1";
2458
+ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
2459
+ "connector_ref",
2460
+ "connector_revision",
2461
+ "policy_decision_revision"
2503
2462
  ]);
2504
2463
 
2505
2464
  // packages/ceal-client-protocol/src/gateway-validation-primitives.ts
@@ -2541,10 +2500,10 @@ function assertSafeJsonArray(value, options, depth, count) {
2541
2500
  if (value.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
2542
2501
  for (const item of value) assertSafeJsonValue(item, options, depth + 1, count);
2543
2502
  }
2544
- function assertSafeJsonRecord(record3, options, depth, count) {
2545
- const entries = Object.entries(record3);
2503
+ function assertSafeJsonRecord(record2, options, depth, count) {
2504
+ const entries = Object.entries(record2);
2546
2505
  if (entries.length > CEAL_WIRE_SAFE_ARRAY_MAX_ITEMS) invalidByContext(options);
2547
- const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record3.fields) : null;
2506
+ const sourceUrlColumn = options.allowHttpsUrl ? compactSourceUrlColumn(record2.fields) : null;
2548
2507
  for (const [key, child] of entries) {
2549
2508
  if (key === "credential_material_included" && child !== false) invalidByContext(options);
2550
2509
  if (!isSafeNegativeMaterialAssertion(key, child)) assertSafeJsonKey(key, options);
@@ -2639,6 +2598,11 @@ function isCealJsonRecord(value) {
2639
2598
  }
2640
2599
  var CEAL_VALIDATION_STATUSES = vocabulary(["not_applicable", "valid", "invalid"]);
2641
2600
  var CEAL_PARSE_STATUSES = vocabulary(["not_applicable", "parsed", "parse_failed"]);
2601
+ function hasExactKeys(value, expected) {
2602
+ const actual = Object.keys(value).sort();
2603
+ const wanted = [...expected].sort();
2604
+ return actual.length === wanted.length && actual.every((key, index) => key === wanted[index]);
2605
+ }
2642
2606
  function invalidByContext(options) {
2643
2607
  if (options.forbidAuthorityKeys) invalidRequest();
2644
2608
  invalidResponse();
@@ -2713,51 +2677,6 @@ function cut(text) {
2713
2677
  return text.length <= REFUSAL_VALUE_MAX_CHARS ? text : `${text.slice(0, REFUSAL_VALUE_MAX_CHARS)}...(+${text.length - REFUSAL_VALUE_MAX_CHARS} chars)`;
2714
2678
  }
2715
2679
 
2716
- // packages/ceal-client-protocol/src/operation-access-class.ts
2717
- var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
2718
-
2719
- // packages/ceal-client-protocol/src/domain-vocabulary.ts
2720
- var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
2721
- var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
2722
- var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
2723
- var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
2724
- var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
2725
- var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
2726
- var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
2727
- var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
2728
- var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
2729
- var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
2730
- var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
2731
- var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
2732
-
2733
- // packages/ceal-client-protocol/src/safe-json-budget.ts
2734
- var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
2735
- function safeJsonNodeBudgetForBytes(maxBytes) {
2736
- if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
2737
- throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
2738
- }
2739
- return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
2740
- }
2741
-
2742
- // packages/ceal-client-protocol/src/protocol-bounds.ts
2743
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
2744
- var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
2745
- var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
2746
- var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
2747
- max_depth: 8,
2748
- max_properties: 96,
2749
- max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
2750
- max_alternatives: 8,
2751
- max_enum_values: 64,
2752
- max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
2753
- /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
2754
- max_description_characters: 1024,
2755
- /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
2756
- max_pattern_characters: 256,
2757
- /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
2758
- max_literal_nodes: 512
2759
- });
2760
-
2761
2680
  // packages/ceal-client-protocol/src/operation-validation-primitives.ts
2762
2681
  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;
2763
2682
  var CEAL_CALENDAR_DATE_PATTERN_SOURCE = "^\\d{4}-\\d{2}-\\d{2}$";
@@ -2825,38 +2744,366 @@ function requireIsoTimestamp(value, message) {
2825
2744
  if (!isCealIsoTimestamp(value)) throw new TypeError(message);
2826
2745
  }
2827
2746
 
2828
- // packages/ceal-client-protocol/src/operation-json-schema.ts
2829
- var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
2830
-
2831
- // packages/ceal-client-protocol/src/operation-contract-validation.ts
2832
- var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["access_group", "instance_binding", "target", "admission_recheck"]);
2833
- var MAX_OPERATION_INPUT_RESOLVER_BINDINGS = 96;
2834
- var CEAL_OPERATION_DESCRIPTOR_REQUIRED_ENVELOPE_KEYS = Object.freeze(["schema_version", "id", "input_contract", "result_contract", "policy"]);
2835
- var CEAL_OPERATION_DESCRIPTOR_OPTIONAL_ENVELOPE_KEYS = Object.freeze(["input_resolution", "summary"]);
2836
-
2837
- // packages/ceal-client-protocol/src/operation-catalog.ts
2838
- var CEAL_OPERATION_CATALOG_SCHEMA_VERSION = "ceal.catalog.v3";
2839
- var CLIENT_AUDIENCES = Object.freeze(["ceal", "cealctl", "agent"]);
2840
- var CLIENT_AUDIENCE_SET = new Set(CLIENT_AUDIENCES);
2747
+ // packages/ceal-client-protocol/src/failure-guidance-table.ts
2748
+ var CEAL_FAILURE_REDACTION_CLASSES = vocabulary(["model_safe", "withheld"]);
2749
+ var CEAL_GATEWAY_STARTING_FAILURE_CODE = "gateway_starting";
2750
+ var CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE = "bootstrap_absent";
2751
+ var CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE = "bootstrap_unavailable";
2752
+ var LOCAL_COMMAND_INVALID = "The local command or argument is invalid.";
2753
+ var LOCAL_TRANSPORT_INCOMPLETE = "The local Ceal transport could not complete; report this as a gap.";
2754
+ var GATEWAY_TRANSPORT_UNAVAILABLE = "The Gateway transport is unavailable; ask an administrator to restore Gateway availability.";
2755
+ var HOST_AUTHENTICATION_UNAVAILABLE = "The Host could not authenticate this invocation; report this as a gap.";
2756
+ var SESSION_CONTEXT_UNAVAILABLE = "The local Gateway session context is unavailable.";
2757
+ function guidance(message, next_action, http_status, retryable = false, redaction_class = "model_safe") {
2758
+ return Object.freeze({ message, next_action, http_status, retryable, redaction_class });
2759
+ }
2760
+ var CEAL_FAILURE_GUIDANCE_TABLE = Object.freeze({
2761
+ invalid_command: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
2762
+ invalid_argument: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 400),
2763
+ command_not_found: guidance(LOCAL_COMMAND_INVALID, "correct_argument", 404),
2764
+ 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),
2765
+ local_route_unavailable: guidance("The requested local route is unavailable or its descriptor is invalid; report this as a gap.", "answer_with_gap", 404),
2766
+ local_route_ambiguous: guidance("The requested local route is ambiguous; no local executable was selected. Report this as a gap.", "answer_with_gap", 400),
2767
+ local_execution_unavailable: guidance("The selected local route executable is unavailable; report this as a gap.", "answer_with_gap", 500),
2768
+ local_pickup_failed: guidance("The Host Request pickup failed; the Gateway command was not sent. Report this as a gap.", "answer_with_gap", 502),
2769
+ invocation_authentication_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
2770
+ 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),
2771
+ gateway_origin_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2772
+ access_token_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2773
+ context_pair_required: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2774
+ context_not_selected: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2775
+ context_store_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2776
+ context_store_conflict: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2777
+ refresh_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2778
+ refresh_expired: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2779
+ refresh_replayed: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2780
+ refresh_revoked: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2781
+ refresh_recovery_unavailable: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2782
+ refresh_custody_invalid: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2783
+ 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),
2784
+ local_output_exists: guidance("The selected local output path already exists; nothing was written to it.", "choose_new_output_path", 400),
2785
+ 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),
2786
+ 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),
2787
+ 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),
2788
+ 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),
2789
+ 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),
2790
+ response_encoding_failed: guidance("The local response could not be encoded; report this as a gap.", "answer_with_gap", 500),
2791
+ request_timeout: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 504),
2792
+ request_failed: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 502),
2793
+ gateway_unavailable: guidance(GATEWAY_TRANSPORT_UNAVAILABLE, "ask_admin", 503, true),
2794
+ 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),
2795
+ // `gateway_starting` is the one retryable envelope the serving gate answers on every route while starting
2796
+ // (`cli/internal/client/gateway_startup_wait.go` re-drives it); the sentence is the client default that renders
2797
+ // when the wait ends still unserved, moved from the `localFailureText` default branch.
2798
+ [CEAL_GATEWAY_STARTING_FAILURE_CODE]: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503, true),
2799
+ gateway_internal_error: guidance("The Gateway failed without exposing internal state; report this as a gap.", "answer_with_gap", 500),
2800
+ // The serving gate emits this code with no message; the sentence is the owner-normalized form of the
2801
+ // `gateway_internal_error` guidance (decided with the operator 2026-10-13).
2802
+ internal_error: guidance("The Gateway failed without exposing internal state.", "answer_with_gap", 500),
2803
+ // Owned by the Gateway canonical adapter (`gateway/core/src/gateway-canonical-operation-http-adapter.ts`):
2804
+ // the client variant of this sentence in `localFailureText` was retired when the client started reading this table.
2805
+ request_body_too_large: guidance("The Gateway request body exceeds its bounded limit.", "reduce_request_size", 413),
2806
+ // Restored verbatim from the retired `localFailureText` `unknown_outcome`
2807
+ // case: the outcome is unknown, so a read may be retried while a write
2808
+ // must receipt-check first. Collapsing both to "do not repeat the call"
2809
+ // forbids the safe read retry the sentence exists to allow.
2810
+ 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),
2811
+ // Restored verbatim from the retired `localFailureText`
2812
+ // `refresh_unknown_outcome` case: a refresh that ends unknown leaves the
2813
+ // session context unavailable, so the caller repairs or adopts the
2814
+ // session instead of reporting a transport gap.
2815
+ refresh_unknown_outcome: guidance(SESSION_CONTEXT_UNAVAILABLE, "repair_or_adopt_session", 401),
2816
+ request_cancelled: guidance("The caller cancelled the request before it completed.", "retry", 400, true),
2817
+ 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),
2818
+ denied: guidance("An administrator denied this device's activation request; ask an administrator whether to reconsider it.", "ask_admin", 403),
2819
+ 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),
2820
+ 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),
2821
+ 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),
2822
+ recovery_required: guidance("The Gateway could not safely complete the activation transaction automatically; ask an administrator to recover this transaction.", "ask_admin", 500),
2823
+ 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),
2824
+ // Activation commit codes rendered through the `localFailureText` default before phase 2b; `retryable` is moved from the
2825
+ // emitting sites in `cli/internal/client/gateway_installation_activation.go` and `activation.go:483`.
2826
+ activation_state_commit_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500, true),
2827
+ activation_response_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502, true),
2828
+ activation_rejected: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
2829
+ activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2830
+ activation_binding: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2831
+ activation_crypto: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2832
+ activation_state_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2833
+ // Long-tail local codes rendered through the `localFailureText` default before phase 2b; sentences moved from that branch.
2834
+ invalid_response: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2835
+ invalid_configuration: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2836
+ activation_state_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2837
+ activation_code_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2838
+ activation_code_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2839
+ activation_code_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 404),
2840
+ bootstrap_file_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2841
+ bootstrap_not_active: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
2842
+ bootstrap_unauthorized: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
2843
+ // The Gateway owner-bootstrap store file was never created, so the Gateway
2844
+ // holds no owner bootstrap to exchange (`gateway/src/host/owner-bootstrap-http-composition.ts`
2845
+ // `absent`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:162`);
2846
+ // the sentence is the owner-normalized form of that store error. Non-retryable:
2847
+ // repeating the exchange cannot create the store; only an administrator
2848
+ // placing a bootstrap (fresh gateway setup) changes the outcome.
2849
+ [CEAL_OWNER_BOOTSTRAP_ABSENT_FAILURE_CODE]: guidance("The Gateway holds no owner bootstrap to exchange; report this as a gap.", "answer_with_gap", 503),
2850
+ // The Gateway owner-bootstrap store file exists but cannot be read, so the
2851
+ // exchange cannot proceed (`gateway/src/host/owner-bootstrap-http-composition.ts`
2852
+ // `unavailable`, stored at `gateway/src/shared/installation/owner-bootstrap-store.ts:163`);
2853
+ // the sentence is the owner-normalized form of that store error. Retryable:
2854
+ // unlike `absent`, a later exchange may succeed once the store is readable.
2855
+ [CEAL_OWNER_BOOTSTRAP_UNAVAILABLE_FAILURE_CODE]: guidance("The Gateway owner bootstrap store is unavailable; retry the exchange.", "retry", 503, true),
2856
+ context_selection_ambiguous: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2857
+ session_authority_unverified: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
2858
+ session_authority_mismatch: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 409),
2859
+ local_credential_lost: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 401),
2860
+ local_capability_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2861
+ host_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
2862
+ host_activation_failed: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 500),
2863
+ doctor_unavailable: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 503),
2864
+ admin_sign_in_invalid: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 502),
2865
+ // `invalid_request` renders through the client default today (local encode/path faults); Gateway-answered
2866
+ // envelopes carry the Gateway message verbatim and never read this sentence.
2867
+ invalid_request: guidance(LOCAL_TRANSPORT_INCOMPLETE, "answer_with_gap", 400),
2868
+ // Gateway canonical-route codes, sentences moved from their minting adapters; statuses moved from the
2869
+ // `valid*Failure` decoder maps in `cli/internal/client/gateway_api.go` and `transport.go`.
2870
+ invalid_json: guidance("The Gateway request body must be valid JSON.", "answer_with_gap", 400),
2871
+ // Per-route variants name their route; the table holds the one stable guidance and the route's `allow`
2872
+ // header stays the measured fact (decided with the operator 2026-10-13).
2873
+ method_not_allowed: guidance("The HTTP method is not allowed for this Gateway route.", "answer_with_gap", 405),
2874
+ request_target_too_large: guidance("The Gateway request target exceeds its bounded limit.", "reduce_request_size", 414),
2875
+ route_not_found: guidance("The Gateway route is not present.", "answer_with_gap", 404),
2876
+ artifact_unavailable: guidance("The Gateway artifact is unavailable.", "answer_with_gap", 503),
2877
+ discovery_unavailable: guidance("The Gateway discovery manifest is unavailable.", "answer_with_gap", 503),
2878
+ serialization_failed: guidance("The Gateway response could not be serialized.", "answer_with_gap", 500),
2879
+ request_header_too_large: guidance("A consumed Gateway request header exceeds its bounded limit.", "answer_with_gap", 431),
2880
+ request_work_context_missing: guidance("The Gateway command requires a Request work context.", "answer_with_gap", 400),
2881
+ request_work_context_invalid: guidance("The Gateway Request work context encoding is invalid.", "answer_with_gap", 400),
2882
+ request_work_context_refused: guidance("The Host-only discovery manifest takes no Request work context.", "answer_with_gap", 400),
2883
+ // Moved from `gateway/src/operations/http-composition.ts` (`unauthorized`) and `command-runtime.ts:827`
2884
+ // (`artifact_stale`); both travel with Gateway messages verbatim online, so these sentences are the
2885
+ // owner fallback guidance. `unauthorized` re-authenticates through the session, hence its action.
2886
+ unauthorized: guidance("Unauthorized.", "repair_or_adopt_session", 401),
2887
+ artifact_stale: guidance("The requested contract artifact is not the current catalog artifact.", "answer_with_gap", 409),
2888
+ // Host mint classifications. The CLI emits `invocation_authentication_unavailable` with the classification
2889
+ // in its detail fact; rows without their own sentence share that code's moved sentence, while `next_action`
2890
+ // is moved from `canonicalHostAuthenticationNextActions` (generated from `CEAL_HOST_AUTHENTICATION_POLICY`)
2891
+ // and `retryable` from `hostAuthenticationFailureForCause` (`failure.nextAction == "retry"`). The three rows
2892
+ // with their own sentences carry the retired policy remedies as Gateway-owned guidance. Statuses are the
2893
+ // Gateway-owned mapping decided with the operator 2026-10-13. This covers every wire cause the maps at
2894
+ // `host/invocation-authentication-command.ts:217-242` emit, through their policy classifications.
2895
+ host_arguments_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 400),
2896
+ host_configuration_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
2897
+ host_session_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 401),
2898
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
2899
+ // missing exact-turn fact names the fresh Host turn, not a reinstall.
2900
+ 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),
2901
+ host_invocation_context_stale: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
2902
+ host_invocation_context_expired: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 401, true),
2903
+ host_source_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 403),
2904
+ host_registration_credential_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 403),
2905
+ host_mint_gateway_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "ask_admin", 503),
2906
+ host_mint_gateway_rate_limited: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 429),
2907
+ host_mint_gateway_refused: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
2908
+ host_mint_gateway_response_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
2909
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
2910
+ // producer-frame fault names the administrator repair step.
2911
+ host_producer_frame_invalid: guidance("Ask an administrator to inspect and repair the producer frame, then start a fresh Host turn.", "ask_admin", 400),
2912
+ // Moved from the retired `CEAL_HOST_AUTHENTICATION_POLICY` remedy: the
2913
+ // sandboxed Relay socket names the run-alone retry.
2914
+ 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),
2915
+ host_relay_unavailable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 503),
2916
+ host_mint_transient_retryable: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "retry", 503, true),
2917
+ host_mint_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500),
2918
+ host_relay_failed: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 502),
2919
+ host_refusal_invalid: guidance(HOST_AUTHENTICATION_UNAVAILABLE, "answer_with_gap", 500)
2920
+ });
2921
+ function cealFailureGuidanceForCode(code) {
2922
+ const entry = CEAL_FAILURE_GUIDANCE_TABLE[code];
2923
+ if (entry === void 0) throw new TypeError(`Failure guidance code is not guided: ${code}.`);
2924
+ return entry;
2925
+ }
2926
+ var FAILURE_GUIDANCE_ENTRY_KEYS = Object.freeze(["message", "next_action", "http_status", "retryable", "redaction_class"]);
2841
2927
 
2842
- // packages/ceal-client-protocol/src/schema-literals.ts
2843
- var CEAL_SCHEMA_LITERALS = [
2844
- "ceal.activation_transport.v1",
2845
- CEAL_OPERATION_ACCESS_SCHEMA_VERSION,
2846
- CEAL_OPERATION_CATALOG_SCHEMA_VERSION,
2847
- "ceal.client_refresh_request.v1",
2848
- "ceal.client_refresh_result.v1",
2849
- "ceal.client_revoke_request.v1",
2850
- "ceal.client_revoke_result.v1",
2851
- CEAL_COMMAND_REQUEST_SCHEMA_VERSION,
2852
- "ceal.device_enrollment_challenge.v1",
2853
- "ceal.device_enrollment_challenge_request.v1",
2854
- "ceal.device_enrollment_hpke_aad.v1",
2855
- "ceal.device_enrollment_hpke_info.v1",
2856
- "ceal.device_enrollment_poll.v1",
2857
- "ceal.device_enrollment_poll_result.v1",
2858
- "ceal.device_enrollment_proof.v1",
2859
- "ceal.device_enrollment_start.v1",
2928
+ // packages/ceal-client-protocol/src/client-wire-contract.ts
2929
+ var CEAL_CLIENT_WIRE_CONTRACT = Object.freeze(client_wire_contract_default);
2930
+ var CEAL_CLIENT_DOCTOR_SCHEMA_VERSION = CEAL_CLIENT_WIRE_CONTRACT.doctor.schema_version;
2931
+ var clientCommands = CEAL_CLIENT_WIRE_CONTRACT.client_commands;
2932
+ var CEAL_CLIENT_DOCTOR_COMMAND = Object.freeze([...clientCommands.doctor]);
2933
+ var CEAL_CLIENT_VERSION_COMMAND = Object.freeze([...clientCommands.version]);
2934
+ var CEAL_CLIENT_ACCESS_GROUP_LIST_COMMAND = Object.freeze([...clientCommands.access_group_list]);
2935
+ function deriveCealClientWireSchemaVersion(schema) {
2936
+ 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))) {
2937
+ throw new TypeError("Client wire schema name or field set is invalid.");
2938
+ }
2939
+ const fields = schema.fields.filter((field) => field !== "schema_version").sort();
2940
+ const hash8 = createHash("sha256").update(cealCanonicalJson(fields), "utf8").digest("hex").slice(0, 8);
2941
+ return `${schema.schema_name}.v1.${hash8}`;
2942
+ }
2943
+ var CealClientWireContractMismatchError = class extends Error {
2944
+ code = "contract_mismatch";
2945
+ next_action = cealFailureGuidanceForCode("contract_mismatch").next_action;
2946
+ constructor(expected, actual) {
2947
+ super(`The peer wire contract ${actual} does not match this client contract ${expected}.`);
2948
+ this.name = "CealClientWireContractMismatchError";
2949
+ }
2950
+ };
2951
+ function requireCealClientWireSchemaVersion(value, expected) {
2952
+ if (typeof value === "string" && value !== expected) throw new CealClientWireContractMismatchError(expected, value);
2953
+ }
2954
+ var commandResolution = CEAL_CLIENT_WIRE_CONTRACT.command_resolution;
2955
+ var commandResolutionAuthority = commandResolution.authority;
2956
+ var commandResolutionSemanticOptions = commandResolution.semantic_options;
2957
+ var CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(commandResolution);
2958
+ var CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES = CEAL_CLIENT_WIRE_CONTRACT.encoded_json_document.max_bytes;
2959
+ var artifact = CEAL_CLIENT_WIRE_CONTRACT.artifact_descriptor;
2960
+ var request = CEAL_CLIENT_WIRE_CONTRACT.command_request;
2961
+ var response = CEAL_CLIENT_WIRE_CONTRACT.command_response;
2962
+ var CEAL_OPERATION_CONTRACT_BUNDLE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.operation_contract_bundle_schema_name, fields: artifact.operation_contract_bundle_fields });
2963
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(artifact);
2964
+ var CEAL_VERIFIED_ARTIFACT_BINDING_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: artifact.binding_schema_name, fields: artifact.binding_fields });
2965
+ var CEAL_VERIFIED_ARTIFACT_KIND = artifact.kind;
2966
+ var CEAL_VERIFIED_ARTIFACT_BINDING_KIND = artifact.binding_kind;
2967
+ var CEAL_VERIFIED_ARTIFACT_MEDIA_TYPE = artifact.media_type;
2968
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_LENGTH = artifact.digest.length;
2969
+ var CEAL_VERIFIED_ARTIFACT_DIGEST_PATTERN = artifact.digest.pattern;
2970
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_LENGTH = artifact.catalog_revision.length;
2971
+ var CEAL_VERIFIED_ARTIFACT_CATALOG_REVISION_PATTERN = artifact.catalog_revision.pattern;
2972
+ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
2973
+ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
2974
+ var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(request);
2975
+ var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
2976
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
2977
+ var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_OPTIONAL_FIELDS = Object.freeze([...response.bare_document_optional_fields]);
2978
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
2979
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = deriveCealClientWireSchemaVersion({ schema_name: response.discovery_manifest_schema_name, fields: response.discovery_manifest_fields });
2980
+ var CEAL_COMMAND_RESPONSE_SCHEMA_VERSION = deriveCealClientWireSchemaVersion(response);
2981
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
2982
+ var CEAL_COMMAND_RESPONSE_MAX_BYTES = CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES;
2983
+ 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 });
2984
+ var CEAL_RESOURCE_STREAM_REQUEST_FIELDS = Object.freeze([...CEAL_CLIENT_WIRE_CONTRACT.resource_stream.request_fields]);
2985
+
2986
+ // packages/ceal-client-protocol/src/operation-withheld-cause.ts
2987
+ var CEAL_OPERATION_WITHHELD_CAUSES = vocabulary(["provider_permission", "access_level", "personal_authorization_required"]);
2988
+
2989
+ // packages/ceal-client-protocol/src/operation-contract-types.ts
2990
+ var CEAL_JSON_SCHEMA_2020_12 = "https://json-schema.org/draft/2020-12/schema";
2991
+ var CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION = "ceal.operation_descriptor.v1";
2992
+ var CEAL_OPERATION_ERROR_SCHEMA_VERSION = "ceal.operation_error.v1";
2993
+ var CEAL_ARTIFACT_STAGE_TERMINALS = vocabulary(["chunk_accepted", "artifact_ready", "idempotency_replayed"]);
2994
+ var CEAL_RETRY_AFTER_MAX_MS = 60 * 60 * 1e3;
2995
+ var CEAL_JSON_SCHEMA_TYPES = vocabulary(["object", "array", "string", "integer", "number", "boolean", "null"]);
2996
+ var OBSERVATION_POSTURES = vocabulary(["direct_readback", "approved_no_readback", "operator_mediated", "excluded"]);
2997
+ var EFFECT_DOMAINS = vocabulary(["none", "gateway_state", "provider", "external_world"]);
2998
+ var SAFETY_CLASSES = vocabulary(["routine", "sensitive", "high_impact"]);
2999
+ var IDEMPOTENCY_CLASSES = vocabulary(["idempotent", "conditionally_idempotent", "non_idempotent"]);
3000
+ var REVERSIBILITY_CLASSES = vocabulary(["none", "reversible", "compensatable", "irreversible"]);
3001
+ var COMPENSATION_OWNERS = vocabulary(["none", "connector", "operator"]);
3002
+ var CANCELLATION_BOUNDARIES = vocabulary(["before_admission", "before_handoff", "after_handoff_reconcile"]);
3003
+ var HANDOFF_CLASSES = vocabulary(["not_applicable", "submission", "effect"]);
3004
+ var AUTHORITATIVE_READBACK_CLASSES = vocabulary(["required", "unavailable"]);
3005
+ var PROVIDER_READBACK_CLASSES = vocabulary(["required", "not_available", "not_applicable"]);
3006
+ var RECONCILIATION_CLASSES = vocabulary(["none", "automatic", "operator"]);
3007
+ var NO_READBACK_APPROVAL_CLASSES = vocabulary(["not_applicable", "explicit", "operator"]);
3008
+ var REPLAY_PREREQUISITES = vocabulary(["never", "fresh_admission", "reconciled_non_application", "operator_approval"]);
3009
+ var UNKNOWN_OUTCOMES = vocabulary(["reconcile", "operator_action", "excluded"]);
3010
+ var RECOVERY_OWNERS = vocabulary(["gateway", "connector", "operator"]);
3011
+ var CEAL_OPERATION_ADMISSION_STATES = vocabulary(["proposed", "refused", "admitted"]);
3012
+ var CEAL_OPERATION_EXECUTION_STATES = vocabulary(["not_started", "started", "completed"]);
3013
+ var CEAL_OPERATION_PROVIDER_HANDOFF_STATES = vocabulary(["not_offered", "offered", "accepted", "rejected", "unknown"]);
3014
+ var CEAL_OPERATION_EFFECT_STATES = vocabulary(["none", "applied", "failed", "unknown", "compensated"]);
3015
+ var CEAL_OPERATION_OBSERVATION_STATES = vocabulary(["not_started", "not_required", "pending", "observed", "unavailable"]);
3016
+ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate", "operator_action"]);
3017
+ var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
3018
+ var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
3019
+ var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
3020
+ var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
3021
+ var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
3022
+ "approval_not_required_by_policy",
3023
+ "interactive_pending",
3024
+ "interactive_granted",
3025
+ "interactive_denied",
3026
+ "interactive_expired",
3027
+ "interactive_unavailable"
3028
+ ]);
3029
+
3030
+ // packages/ceal-client-protocol/src/operation-access-class.ts
3031
+ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
3032
+
3033
+ // packages/ceal-client-protocol/src/domain-vocabulary.ts
3034
+ var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
3035
+ var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
3036
+ var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
3037
+ var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
3038
+ var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
3039
+ var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
3040
+ var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
3041
+ var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
3042
+ var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
3043
+ var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
3044
+ var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
3045
+ var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
3046
+
3047
+ // packages/ceal-client-protocol/src/safe-json-budget.ts
3048
+ var SAFE_JSON_MIN_BYTES_PER_NODE = 4;
3049
+ function safeJsonNodeBudgetForBytes(maxBytes) {
3050
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < SAFE_JSON_MIN_BYTES_PER_NODE) {
3051
+ throw new RangeError(`safe-JSON byte cap is invalid: ${refusalFact("maxBytes", maxBytes, `at least ${SAFE_JSON_MIN_BYTES_PER_NODE} bytes`)}`);
3052
+ }
3053
+ return Math.floor(maxBytes / SAFE_JSON_MIN_BYTES_PER_NODE);
3054
+ }
3055
+
3056
+ // packages/ceal-client-protocol/src/protocol-bounds.ts
3057
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES = 64 * 1024;
3058
+ var CEAL_PROTOCOL_RESPONSE_VALUE_MAX_NODES = safeJsonNodeBudgetForBytes(CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES);
3059
+ var OPERATION_SCHEMA_LITERAL_MAX_BYTES = CEAL_PROTOCOL_RESPONSE_VALUE_MAX_BYTES / 4;
3060
+ var CEAL_OPERATION_JSON_SCHEMA_BUDGET = Object.freeze({
3061
+ max_depth: 8,
3062
+ max_properties: 96,
3063
+ max_string_length: OPERATION_SCHEMA_LITERAL_MAX_BYTES / 4,
3064
+ max_alternatives: 8,
3065
+ max_enum_values: 64,
3066
+ max_literal_bytes: OPERATION_SCHEMA_LITERAL_MAX_BYTES,
3067
+ /** @basis our_policy -- bounds explanatory schema prose carried in one catalog. */
3068
+ max_description_characters: 1024,
3069
+ /** @basis our_policy -- bounds regular-expression compilation input from one schema. */
3070
+ max_pattern_characters: 256,
3071
+ /** @basis our_policy -- bounds traversal work inside one already byte-bounded schema literal. */
3072
+ max_literal_nodes: 512
3073
+ });
3074
+
3075
+ // packages/ceal-client-protocol/src/operation-json-schema.ts
3076
+ var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
3077
+
3078
+ // packages/ceal-client-protocol/src/operation-contract-validation.ts
3079
+ var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["access_group", "instance_binding", "target", "admission_recheck"]);
3080
+ var MAX_OPERATION_INPUT_RESOLVER_BINDINGS = 96;
3081
+ var CEAL_OPERATION_DESCRIPTOR_REQUIRED_ENVELOPE_KEYS = Object.freeze(["schema_version", "id", "input_contract", "result_contract", "policy"]);
3082
+ var CEAL_OPERATION_DESCRIPTOR_OPTIONAL_ENVELOPE_KEYS = Object.freeze(["input_resolution", "summary"]);
3083
+
3084
+ // packages/ceal-client-protocol/src/operation-catalog.ts
3085
+ var CEAL_OPERATION_CATALOG_SCHEMA_VERSION = "ceal.catalog.v3";
3086
+ var CLIENT_AUDIENCES = Object.freeze(["ceal", "cealctl", "agent"]);
3087
+ var CLIENT_AUDIENCE_SET = new Set(CLIENT_AUDIENCES);
3088
+
3089
+ // packages/ceal-client-protocol/src/schema-literals.ts
3090
+ var CEAL_SCHEMA_LITERALS = [
3091
+ "ceal.activation_transport.v1",
3092
+ CEAL_OPERATION_ACCESS_SCHEMA_VERSION,
3093
+ CEAL_OPERATION_CATALOG_SCHEMA_VERSION,
3094
+ "ceal.client_refresh_request.v1",
3095
+ "ceal.client_refresh_result.v1",
3096
+ "ceal.client_revoke_request.v1",
3097
+ "ceal.client_revoke_result.v1",
3098
+ CEAL_COMMAND_REQUEST_SCHEMA_VERSION,
3099
+ "ceal.device_enrollment_challenge.v1",
3100
+ "ceal.device_enrollment_challenge_request.v1",
3101
+ "ceal.device_enrollment_hpke_aad.v1",
3102
+ "ceal.device_enrollment_hpke_info.v1",
3103
+ "ceal.device_enrollment_poll.v1",
3104
+ "ceal.device_enrollment_poll_result.v1",
3105
+ "ceal.device_enrollment_proof.v1",
3106
+ "ceal.device_enrollment_start.v1",
2860
3107
  "ceal.device_enrollment_start_result.v1",
2861
3108
  "ceal.effect_approval.v1",
2862
3109
  "ceal.effect_approval_confirmation.v1",
@@ -2866,12 +3113,12 @@ var CEAL_SCHEMA_LITERALS = [
2866
3113
  "ceal.enrollment_result.v1",
2867
3114
  "ceal.first_activation_causal_join.v1",
2868
3115
  "ceal.gateway_announcement_policy.v1",
2869
- "ceal.gateway_audit_call_detail.v1",
3116
+ CEAL_GATEWAY_AUDIT_CALL_DETAIL_SCHEMA_VERSION,
2870
3117
  "ceal.gateway_audit_event.v1",
2871
3118
  "ceal.gateway_audit_readback.v1",
2872
3119
  "ceal.gateway_authorization_snapshot.v1",
2873
3120
  "ceal.gateway_cache_origin.v1",
2874
- "ceal.gateway_call_result.v1",
3121
+ CEAL_GATEWAY_CALL_RESULT_SCHEMA_VERSION,
2875
3122
  CEAL_GATEWAY_COMMAND_RESOLUTION_SCHEMA_VERSION,
2876
3123
  "ceal.gateway_connector_route_failure.v1",
2877
3124
  "ceal.gateway_discovery.v1",
@@ -2896,7 +3143,7 @@ var CEAL_SCHEMA_LITERALS = [
2896
3143
  "ceal.host_observation.v1",
2897
3144
  "ceal.host_registration_request.v1",
2898
3145
  "ceal.host_registration_result.v1",
2899
- "ceal.operation_descriptor.v1",
3146
+ CEAL_OPERATION_DESCRIPTOR_SCHEMA_VERSION,
2900
3147
  "ceal.operation_error.v1",
2901
3148
  "ceal.operation_failure.v1",
2902
3149
  "ceal.operation_failure.compact.v1",
@@ -3004,10 +3251,20 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
3004
3251
  var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
3005
3252
  var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
3006
3253
 
3254
+ // packages/ceal-client-protocol/src/client-environment-generated.ts
3255
+ var CEAL_CLIENT_CONTEXT_OVERRIDE_ENVIRONMENTS = Object.freeze(["CEAL_GATEWAY_ORIGIN", "CEAL_GATEWAY_TRANSPORT_ORIGIN", "CEAL_ACCESS_TOKEN", "CEAL_CONTEXT_STORE_PATH"]);
3256
+
3257
+ // packages/ceal-client-protocol/src/client-process-contract.ts
3258
+ var CEAL_CLIENT_VERSION_SCHEMA_SUFFIX = ".version.v1";
3259
+ var CEAL_CLIENT_VERSION_SCHEMA_VERSION = `ceal${CEAL_CLIENT_VERSION_SCHEMA_SUFFIX}`;
3260
+
3007
3261
  // packages/ceal-client-protocol/src/bare-document.ts
3008
3262
  var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_fields;
3009
3263
  var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
3010
3264
 
3265
+ // packages/ceal-client-protocol/src/actor-kind.ts
3266
+ var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
3267
+
3011
3268
  // packages/ceal-client-protocol/src/resource-row.ts
3012
3269
  var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
3013
3270
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
@@ -3022,6 +3279,8 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
3022
3279
  "resource_created",
3023
3280
  "review_submitted",
3024
3281
  "comment_created",
3282
+ "reaction_created",
3283
+ "ceal_write_completed",
3025
3284
  "event_start",
3026
3285
  "all_day_start",
3027
3286
  "file_created",
@@ -3056,6 +3315,10 @@ var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
3056
3315
  "github.review.submitted",
3057
3316
  "github.issue_comment.created",
3058
3317
  "github.review_comment.created",
3318
+ "github.reaction.created",
3319
+ "github.reaction.deleted",
3320
+ "github.pull_request.review_requested",
3321
+ "github.pull_request.review_request_removed",
3059
3322
  "calendar.organized",
3060
3323
  "calendar.accepted_invite",
3061
3324
  "calendar.recorded",
@@ -3077,6 +3340,10 @@ var CEAL_ACTIVITY_EVENT_TIMESTAMP_BASIS_MAP = Object.freeze({
3077
3340
  "github.pull_request.opened": "resource_created",
3078
3341
  "github.issue.edited": "resource_modified",
3079
3342
  "github.pull_request.edited": "resource_modified",
3343
+ "github.reaction.created": "reaction_created",
3344
+ "github.reaction.deleted": "ceal_write_completed",
3345
+ "github.pull_request.review_requested": "ceal_write_completed",
3346
+ "github.pull_request.review_request_removed": "ceal_write_completed",
3080
3347
  "calendar.organized": "resource_created",
3081
3348
  "drive.file.created": "file_created",
3082
3349
  "drive.file.modified": "file_modified_by_me",
@@ -3100,6 +3367,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
3100
3367
  source_url: { required: false, timestamp: false },
3101
3368
  source: { required: true, timestamp: false },
3102
3369
  owner: { required: false, timestamp: false },
3370
+ actor_kind: { required: false, timestamp: false },
3103
3371
  counterparts: { required: false, timestamp: false },
3104
3372
  attachments: { required: false, timestamp: false },
3105
3373
  created_at: { required: false, timestamp: true },
@@ -3107,9 +3375,18 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
3107
3375
  modified_at: { required: false, timestamp: true },
3108
3376
  modified_at_local: { required: false, timestamp: true },
3109
3377
  viewed_by_me_at: { required: false, timestamp: true },
3378
+ modified_by_me_at: { required: false, timestamp: true },
3110
3379
  own_ceal_write: { required: false, timestamp: false },
3111
3380
  owned_by_me: { required: false, timestamp: false },
3381
+ mime_type: { required: false, timestamp: false },
3382
+ size_bytes: { required: false, timestamp: false },
3383
+ version: { required: false, timestamp: false },
3384
+ trashed: { required: false, timestamp: false },
3112
3385
  visibility: { required: false, timestamp: false },
3386
+ archived: { required: false, timestamp: false },
3387
+ tag: { required: false, timestamp: false },
3388
+ labels: { required: false, timestamp: false },
3389
+ labels_incomplete: { required: false, timestamp: false },
3113
3390
  start: { required: false, timestamp: false },
3114
3391
  end: { required: false, timestamp: false },
3115
3392
  status: { required: false, timestamp: false },
@@ -3182,18 +3459,29 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
3182
3459
  // The serving gate answers this while the Gateway is still starting and the
3183
3460
  // refresh was never attempted; the same attempt stays retryable. It is never
3184
3461
  // stored by the session owner, only answered at the serving edge.
3185
- "gateway_starting"
3462
+ CEAL_GATEWAY_STARTING_FAILURE_CODE
3463
+ ]);
3464
+ var CEAL_CLIENT_REVOKE_FAILURE_CODES = vocabulary([
3465
+ "refresh_invalid",
3466
+ "refresh_expired",
3467
+ "refresh_replayed",
3468
+ "refresh_revoked"
3186
3469
  ]);
3470
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX = "ceal_personal_";
3471
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX = "ceal_refresh_";
3472
+ var PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN = "[A-Za-z0-9_-]{43}";
3473
+ var CEAL_PERSONAL_CLIENT_ACCESS_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_ACCESS_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
3474
+ var CEAL_PERSONAL_CLIENT_REFRESH_TOKEN = new RegExp(`^${CEAL_PERSONAL_CLIENT_REFRESH_TOKEN_PREFIX}${PERSONAL_CLIENT_TOKEN_SUFFIX_PATTERN}$`, "u");
3187
3475
 
3188
3476
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
3189
- import { createHash } from "node:crypto";
3477
+ import { createHash as createHash2 } from "node:crypto";
3190
3478
  var DIGEST = /^[a-f0-9]{64}$/u;
3191
3479
  var CEAL_SHA256_DIGEST_PATTERN = DIGEST.source;
3192
3480
  function isCealDigest(value) {
3193
3481
  return typeof value === "string" && DIGEST.test(value);
3194
3482
  }
3195
3483
  function cealRequestSha256(value) {
3196
- return createHash("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
3484
+ return createHash2("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
3197
3485
  }
3198
3486
  function operationRecord(value, message) {
3199
3487
  requireOperationRecord(value, message);
@@ -3209,40 +3497,71 @@ function requirePrefixedRef(value, prefix, message) {
3209
3497
  // packages/ceal-client-protocol/src/request-authority.ts
3210
3498
  var CEAL_REQUEST_SCHEMA_VERSION = "ceal.request.v1";
3211
3499
  var CEAL_REQUEST_ARTIFACT_OWNERS = vocabulary(["gateway", "host", "connector"]);
3212
- var CEAL_REQUEST_HOST_BINDING_KEYS = vocabulary(["prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
3500
+ var CEAL_HOST_INVOCATION_IDENTITY_KEYS = vocabulary(["host_session_ref", "host_turn_ref", "host_source_ref"]);
3213
3501
  var CEAL_REQUEST_ARTIFACT_RETENTION_CLASSES = vocabulary(["request", "source", "result"]);
3214
3502
  var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
3215
- 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"]);
3503
+ var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority"]);
3504
+ var CEAL_REQUEST_COMMON_PROPERTIES = Object.freeze({
3505
+ schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
3506
+ ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
3507
+ created_at: { type: "string", minLength: 1, maxLength: 64 },
3508
+ authority: {
3509
+ type: "object",
3510
+ maxProperties: 5,
3511
+ additionalProperties: false,
3512
+ properties: {
3513
+ instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3514
+ access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3515
+ principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3516
+ execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3517
+ authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
3518
+ },
3519
+ required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
3520
+ }
3521
+ });
3522
+ var CEAL_REQUEST_HOST_PROPERTIES = Object.freeze({
3523
+ prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3524
+ host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3525
+ host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3526
+ host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3527
+ host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
3528
+ });
3529
+ var CEAL_REQUEST_CALLER_PROPERTIES = Object.freeze({
3530
+ 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." },
3531
+ 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." }
3532
+ });
3533
+ var CEAL_REQUEST_OPTIONAL_PROPERTIES = Object.freeze({
3534
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
3535
+ 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." }
3536
+ });
3537
+ var CEAL_REQUEST_HOST_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, ...CEAL_HOST_INVOCATION_IDENTITY_KEYS, "prompt_ref"]);
3538
+ var CEAL_REQUEST_CALLER_REQUIRED_KEYS = Object.freeze([...CEAL_REQUEST_KEYS, "caller_call_group_ref", "caller_call_input_sha256"]);
3216
3539
  var CEAL_REQUEST_JSON_SCHEMA = {
3217
3540
  type: "object",
3218
- maxProperties: 11,
3541
+ 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.",
3542
+ maxProperties: 13,
3219
3543
  additionalProperties: false,
3220
3544
  properties: {
3221
- schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
3222
- ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
3223
- created_at: { type: "string", minLength: 1, maxLength: 64 },
3224
- authority: {
3545
+ ...CEAL_REQUEST_COMMON_PROPERTIES,
3546
+ ...CEAL_REQUEST_HOST_PROPERTIES,
3547
+ ...CEAL_REQUEST_CALLER_PROPERTIES,
3548
+ ...CEAL_REQUEST_OPTIONAL_PROPERTIES
3549
+ },
3550
+ required: CEAL_REQUEST_KEYS,
3551
+ anyOf: [
3552
+ {
3225
3553
  type: "object",
3226
- maxProperties: 5,
3227
- additionalProperties: false,
3228
- properties: {
3229
- instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3230
- access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3231
- principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3232
- execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3233
- authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
3234
- },
3235
- required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
3554
+ required: CEAL_REQUEST_HOST_REQUIRED_KEYS,
3555
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_HOST_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
3556
+ additionalProperties: false
3236
3557
  },
3237
- prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3238
- host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3239
- host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3240
- host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3241
- host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3242
- requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
3243
- 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." }
3244
- },
3245
- required: CEAL_REQUEST_KEYS
3558
+ {
3559
+ type: "object",
3560
+ required: CEAL_REQUEST_CALLER_REQUIRED_KEYS,
3561
+ properties: { ...CEAL_REQUEST_COMMON_PROPERTIES, ...CEAL_REQUEST_CALLER_PROPERTIES, ...CEAL_REQUEST_OPTIONAL_PROPERTIES },
3562
+ additionalProperties: false
3563
+ }
3564
+ ]
3246
3565
  };
3247
3566
 
3248
3567
  // packages/ceal-client-protocol/src/request-operands.ts
@@ -3353,10 +3672,6 @@ var CEAL_REQUEST_RUN_BATCH_JSON_SCHEMA = {
3353
3672
  };
3354
3673
 
3355
3674
  // packages/ceal-client-protocol/src/host-observation.ts
3356
- var CEAL_HOST_INPUT_KINDS = vocabulary(["human", "host_automatic"]);
3357
- function isCealHostInputKind(value) {
3358
- return typeof value === "string" && CEAL_HOST_INPUT_KINDS.some((kind) => kind === value);
3359
- }
3360
3675
  var CEAL_HOST_OBSERVATION_REF_PREFIX = "host-observation:";
3361
3676
  var HOST_OBSERVATION_PRODUCER = /^[a-z][a-z0-9]{0,31}$/u;
3362
3677
  var HOST_OBSERVATION_DIGEST = /^[a-f0-9]{8,64}$/u;
@@ -3402,14 +3717,14 @@ function safeCount(value) {
3402
3717
  return Number.isSafeInteger(value) && Number(value) >= 0;
3403
3718
  }
3404
3719
  function validateCealHostObservationDraft(value) {
3405
- const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
3406
- requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
3407
- requireClosedValue(record3.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
3408
- requireIsoTimestamp(record3.observed_at, "Ceal Host observation time is invalid.");
3409
- assertHostObservationValue(record3.value, record3.observation_kind);
3720
+ const record2 = operationRecord(value, "Ceal Host observation draft is invalid.");
3721
+ requirePrefixedRef(record2.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
3722
+ requireClosedValue(record2.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
3723
+ requireIsoTimestamp(record2.observed_at, "Ceal Host observation time is invalid.");
3724
+ assertHostObservationValue(record2.value, record2.observation_kind);
3410
3725
  }
3411
3726
  var CEAL_REQUEST_MAX_OBSERVATION_VALUE_BYTES = 64 * 1024;
3412
- var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "cost", "timing"]);
3727
+ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "model", "token", "timing"]);
3413
3728
  function isCealHostPromptObservationValue(value) {
3414
3729
  return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
3415
3730
  }
@@ -3532,17 +3847,128 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
3532
3847
  };
3533
3848
 
3534
3849
  // packages/ceal-client-protocol/src/host-invocation-authentication.ts
3535
- var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA = "ceal.host_invocation_authentication_request.v1";
3536
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = "ceal.host_invocation_authentication_result.v1";
3537
- var CEAL_HOST_NONCE_ENCODED_CHARACTERS = 43;
3538
- var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
3539
- var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(`^ceal_context_[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
3540
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = new TextEncoder().encode(`${JSON.stringify({
3541
- schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA,
3542
- context_token: `ceal_context_${"A".repeat(CEAL_HOST_NONCE_ENCODED_CHARACTERS)}`,
3543
- expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
3544
- })}
3850
+ var hostInvocationAuthenticationContract = CEAL_CLIENT_WIRE_CONTRACT.host_invocation_authentication;
3851
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.request_schema_name, fields: hostInvocationAuthenticationContract.request_fields });
3852
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.request_fields]);
3853
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = deriveCealClientWireSchemaVersion({ schema_name: hostInvocationAuthenticationContract.result_schema_name, fields: hostInvocationAuthenticationContract.result_fields });
3854
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_FIELDS = Object.freeze([...hostInvocationAuthenticationContract.result_fields]);
3855
+ var CEAL_HOST_AUTHENTICATION_BUDGET_ENVIRONMENT = "CEAL_HOST_AUTHENTICATION_BUDGET_MS";
3856
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE = "^(?:0|[1-9][0-9]{0,8})$";
3857
+ var CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN = new RegExp(CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN_SOURCE, "u");
3858
+ var CEAL_HOST_INVOCATION_CONTEXT_REQUEST_SCHEMA = "ceal.gateway_host_invocation_context_request.v2";
3859
+ var CEAL_HOST_INVOCATION_CONTEXT_REQUEST_MAX_BYTES = 16 * 1024;
3860
+ var CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_BYTES = 2 * 1024;
3861
+ var CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_MESSAGES = 32;
3862
+ var HOST_CONTEXT_EXPIRY_MAX_CHARS = 64;
3863
+ var CEAL_HOST_INVOCATION_CONTEXT_VISIBLE_OUTPUT_MAX_BYTES = CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
3864
+ var CEAL_HOST_CONTEXT_TOKEN_PREFIX = "ceal_context_";
3865
+ function boundCealHostInvocationHumanMessageWindow(newestFirst, sourceTruncated = false) {
3866
+ const messages = [];
3867
+ let truncated = sourceTruncated || newestFirst.length > CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_MESSAGES;
3868
+ for (const candidate of newestFirst.slice(0, CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_MESSAGES)) {
3869
+ const next = [...messages, candidate];
3870
+ if (new TextEncoder().encode(JSON.stringify(next)).byteLength > CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_BYTES) {
3871
+ truncated = true;
3872
+ break;
3873
+ }
3874
+ messages.push(Object.freeze({ host_turn_ref: candidate.host_turn_ref, host_input_ref: candidate.host_input_ref, text: candidate.text }));
3875
+ }
3876
+ return Object.freeze({ messages: Object.freeze(messages), truncated });
3877
+ }
3878
+ function decodeCealHostInvocationContextRequest(value) {
3879
+ if (!isCealJsonRecord(value)) throw invalidInvocationContextRequest();
3880
+ requireCealClientWireSchemaVersion(value.schema_version, CEAL_HOST_INVOCATION_CONTEXT_REQUEST_SCHEMA);
3881
+ if (!hasInvocationContextRequestKeys(value)) throw invalidInvocationContextRequest();
3882
+ const clientNonce = requireClientNonce(value.client_nonce);
3883
+ const expiresAt = requireContextExpiration(value.context_expires_at);
3884
+ const hostBinding = requireHostBinding(value.host_binding);
3885
+ const messageWindow = requireHumanMessageWindow(value.human_message_window);
3886
+ const lastRequestRef = optionalSafeReference(value.last_seen_request_ref);
3887
+ const visibleOutputMaxBytes = optionalVisibleOutputBudget(value.visible_output_max_bytes);
3888
+ return Object.freeze({
3889
+ schema_version: CEAL_HOST_INVOCATION_CONTEXT_REQUEST_SCHEMA,
3890
+ client_nonce: clientNonce,
3891
+ context_expires_at: expiresAt,
3892
+ host_binding: Object.freeze({ ...hostBinding }),
3893
+ human_message_window: messageWindow,
3894
+ ...lastRequestRef === void 0 ? {} : { last_seen_request_ref: lastRequestRef },
3895
+ ...visibleOutputMaxBytes === void 0 ? {} : { visible_output_max_bytes: visibleOutputMaxBytes }
3896
+ });
3897
+ }
3898
+ function hasInvocationContextRequestKeys(value) {
3899
+ const required = ["schema_version", "client_nonce", "context_expires_at", "host_binding", "human_message_window"];
3900
+ const optional = ["last_seen_request_ref", "visible_output_max_bytes"];
3901
+ const optionalKeys = Object.keys(value).filter((key) => optional.includes(key));
3902
+ return hasExactKeys(value, [...required, ...optionalKeys]) && required.every((key) => Object.hasOwn(value, key)) && value.schema_version === CEAL_HOST_INVOCATION_CONTEXT_REQUEST_SCHEMA;
3903
+ }
3904
+ function requireClientNonce(value) {
3905
+ if (typeof value !== "string" || !CEAL_HOST_CLIENT_NONCE_PATTERN.test(value)) throw invalidInvocationContextRequest();
3906
+ return value;
3907
+ }
3908
+ function requireContextExpiration(value) {
3909
+ if (typeof value !== "string" || value.length > HOST_CONTEXT_EXPIRY_MAX_CHARS || !Number.isFinite(Date.parse(value))) throw invalidInvocationContextRequest();
3910
+ return value;
3911
+ }
3912
+ function requireHostBinding(value) {
3913
+ if (!isCealJsonRecord(value) || !exactOptionalKeys(value, ["host_source_ref", "host_session_ref", "host_turn_ref"], []) || !safeReference(value.host_source_ref) || !safeReference(value.host_session_ref) || !safeReference(value.host_turn_ref)) throw invalidInvocationContextRequest();
3914
+ return { host_source_ref: value.host_source_ref, host_session_ref: value.host_session_ref, host_turn_ref: value.host_turn_ref };
3915
+ }
3916
+ function requireHumanMessageWindow(value) {
3917
+ if (!isCealJsonRecord(value) || !exactOptionalKeys(value, ["messages", "truncated"], []) || !Array.isArray(value.messages) || value.messages.length > CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_MESSAGES || typeof value.truncated !== "boolean") throw invalidInvocationContextRequest();
3918
+ const messages = value.messages.map(decodeHumanMessage);
3919
+ const bytes = new TextEncoder().encode(JSON.stringify(messages)).byteLength;
3920
+ if (bytes > CEAL_HOST_INVOCATION_HUMAN_MESSAGE_WINDOW_MAX_BYTES) throw invalidInvocationContextRequest();
3921
+ return Object.freeze({ messages: Object.freeze(messages), truncated: value.truncated });
3922
+ }
3923
+ function decodeHumanMessage(candidate) {
3924
+ if (!isCealJsonRecord(candidate) || !exactOptionalKeys(candidate, ["host_turn_ref", "host_input_ref", "text"], []) || !safeReference(candidate.host_turn_ref) || !safeReference(candidate.host_input_ref) || typeof candidate.text !== "string") throw invalidInvocationContextRequest();
3925
+ return Object.freeze({ host_turn_ref: candidate.host_turn_ref, host_input_ref: candidate.host_input_ref, text: candidate.text });
3926
+ }
3927
+ function optionalSafeReference(value) {
3928
+ if (value === void 0) return void 0;
3929
+ if (!safeReference(value)) throw invalidInvocationContextRequest();
3930
+ return value;
3931
+ }
3932
+ function safeReference(value) {
3933
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
3934
+ }
3935
+ function exactOptionalKeys(value, required, optional = []) {
3936
+ const keys = Object.keys(value);
3937
+ return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
3938
+ }
3939
+ function optionalVisibleOutputBudget(value) {
3940
+ if (value === void 0) return void 0;
3941
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > CEAL_HOST_INVOCATION_CONTEXT_VISIBLE_OUTPUT_MAX_BYTES) throw invalidInvocationContextRequest();
3942
+ return value;
3943
+ }
3944
+ function invalidInvocationContextRequest() {
3945
+ return new TypeError("The Host invocation context request is invalid.");
3946
+ }
3947
+ function deriveCealHostInvocationNonceContract(contract = CEAL_CLIENT_WIRE_CONTRACT) {
3948
+ const clientNonce = contract.host_invocation_authentication.client_nonce;
3949
+ return {
3950
+ encoded_characters: clientNonce.encoded_characters,
3951
+ client_nonce_pattern_source: `^[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`,
3952
+ context_token_pattern_source: `^${CEAL_HOST_CONTEXT_TOKEN_PREFIX}[${clientNonce.character_class_source}]{${clientNonce.encoded_characters}}$`
3953
+ };
3954
+ }
3955
+ var hostNonceContract = deriveCealHostInvocationNonceContract();
3956
+ var CEAL_HOST_NONCE_ENCODED_CHARACTERS = hostNonceContract.encoded_characters;
3957
+ var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(hostNonceContract.client_nonce_pattern_source, "u");
3958
+ var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(hostNonceContract.context_token_pattern_source, "u");
3959
+ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = deriveCealHostInvocationAuthenticationResultMaxBytes();
3960
+ function deriveCealHostInvocationAuthenticationResultMaxBytes(contract = CEAL_CLIENT_WIRE_CONTRACT) {
3961
+ const hostAuthentication = contract.host_invocation_authentication;
3962
+ const values = {
3963
+ schema_version: deriveCealClientWireSchemaVersion({ schema_name: hostAuthentication.result_schema_name, fields: hostAuthentication.result_fields }),
3964
+ context_token: `${CEAL_HOST_CONTEXT_TOKEN_PREFIX}${"A".repeat(hostAuthentication.client_nonce.encoded_characters)}`,
3965
+ expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
3966
+ };
3967
+ const fields = hostAuthentication.result_fields;
3968
+ if (fields.some((field) => !Object.hasOwn(values, field))) throw new TypeError("Host invocation result fields have no bounded sample value.");
3969
+ return new TextEncoder().encode(`${JSON.stringify(Object.fromEntries(fields.map((field) => [field, values[field]])))}
3545
3970
  `).byteLength;
3971
+ }
3546
3972
  var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
3547
3973
  "request_authority_unavailable",
3548
3974
  "request_missing",
@@ -3566,6 +3992,7 @@ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
3566
3992
  "host_credential_refused",
3567
3993
  "gateway_unavailable",
3568
3994
  "gateway_rate_limited",
3995
+ "contract_mismatch",
3569
3996
  "gateway_refused",
3570
3997
  "gateway_response_invalid",
3571
3998
  "producer_frame_invalid",
@@ -3580,19 +4007,23 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
3580
4007
  invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
3581
4008
  options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
3582
4009
  session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
3583
- 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)" }),
3584
- context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
3585
- no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
3586
- context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
3587
- context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
4010
+ context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "retry" }),
4011
+ context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
4012
+ // `no_binding` now means the producer has no real current Host session. The
4013
+ // Host Relay never uses it for an uncreated Gateway Request; there is no
4014
+ // useful retry until the consumer is running inside a Host session.
4015
+ no_binding: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
4016
+ context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "retry" }),
4017
+ context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "retry" }),
3588
4018
  host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
3589
4019
  host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
3590
4020
  gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
3591
4021
  gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
4022
+ contract_mismatch: Object.freeze({ classification: "contract_mismatch", next_action: "upgrade_ceal_client" }),
3592
4023
  gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
3593
4024
  gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
3594
- 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" }),
3595
- 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" }),
4025
+ producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin" }),
4026
+ relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox" }),
3596
4027
  relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
3597
4028
  transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
3598
4029
  mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
@@ -3602,21 +4033,33 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
3602
4033
  function isCealHostAuthenticationCause(value) {
3603
4034
  return isVocabularyWord(CEAL_HOST_AUTHENTICATION_CAUSES, value);
3604
4035
  }
4036
+ function cealHostAuthenticationCauseForExchangeFailure(failure2) {
4037
+ if (failure2 === "permission_denied") return "relay_permission_denied";
4038
+ if (failure2 === "timed_out") return "transient_retryable";
4039
+ return "relay_unavailable";
4040
+ }
3605
4041
  function decodeCealHostInvocationAuthenticationRequest(value) {
3606
- if (!isCealJsonRecord(value) || !exactKeys(value, ["schema_version", "client_nonce"]) || value.schema_version !== CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA || typeof value.client_nonce !== "string" || !CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce)) {
4042
+ if (!isCealJsonRecord(value)) throw new TypeError("The Host invocation authentication request is invalid.");
4043
+ requireCealClientWireSchemaVersion(value.schema_version, CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA);
4044
+ if (!exactKeys(value, CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_FIELDS) || typeof value.client_nonce !== "string" || !CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce)) {
3607
4045
  throw new TypeError("The Host invocation authentication request is invalid.");
3608
4046
  }
3609
4047
  return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: value.client_nonce });
3610
4048
  }
3611
4049
  function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__ */ new Date()) {
3612
- if (!isCealJsonRecord(value) || !exactKeys(value, ["schema_version", "context_token", "expires_at"]) || value.schema_version !== CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA || typeof value.context_token !== "string" || !CEAL_HOST_CONTEXT_TOKEN_PATTERN.test(value.context_token) || typeof value.expires_at !== "string" || !validFutureTimestamp(value.expires_at, now)) {
4050
+ return decodeHostInvocationAuthenticationResult(value, CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_FIELDS, now);
4051
+ }
4052
+ function decodeHostInvocationAuthenticationResult(value, fields, now) {
4053
+ if (!isCealJsonRecord(value)) throw new TypeError("The Host invocation authentication result is invalid.");
4054
+ requireCealClientWireSchemaVersion(value.schema_version, CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA);
4055
+ if (!exactKeys(value, fields) || typeof value.context_token !== "string" || !CEAL_HOST_CONTEXT_TOKEN_PATTERN.test(value.context_token) || typeof value.expires_at !== "string" || !validFutureTimestamp(value.expires_at, now)) {
3613
4056
  throw new TypeError("The Host invocation authentication result is invalid.");
3614
4057
  }
3615
4058
  return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA, context_token: value.context_token, expires_at: value.expires_at });
3616
4059
  }
3617
4060
  function validFutureTimestamp(value, now) {
3618
- const timestamp4 = Date.parse(value);
3619
- return Number.isFinite(timestamp4) && new Date(timestamp4).toISOString() === value && timestamp4 > now.getTime();
4061
+ const timestamp3 = Date.parse(value);
4062
+ return Number.isFinite(timestamp3) && new Date(timestamp3).toISOString() === value && timestamp3 > now.getTime();
3620
4063
  }
3621
4064
  function exactKeys(value, expected) {
3622
4065
  const keys = Object.keys(value);
@@ -3630,10 +4073,6 @@ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
3630
4073
  "hook_invoked",
3631
4074
  "registration_written",
3632
4075
  "hook_failed",
3633
- "watcher_turn_observed",
3634
- "current_prompt_registered",
3635
- "current_prompt_registration_failed",
3636
- "current_prompt_capacity_exhausted",
3637
4076
  "activation_recorded",
3638
4077
  "activation_failed",
3639
4078
  "watcher_scan_failed",
@@ -3656,6 +4095,9 @@ var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "un
3656
4095
  var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
3657
4096
  var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
3658
4097
 
4098
+ // packages/ceal-client-protocol/src/discovery-manifest.ts
4099
+ var DISCOVERY_MANIFEST_KEYS = CEAL_CLIENT_WIRE_CONTRACT.command_response.discovery_manifest_fields;
4100
+
3659
4101
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
3660
4102
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
3661
4103
 
@@ -3714,6 +4156,7 @@ var ADMIN_UNAVAILABLE_REASONS = vocabulary([
3714
4156
  "legacy",
3715
4157
  "invalid_observation",
3716
4158
  "redacted",
4159
+ "organization_setting_disabled",
3717
4160
  "owner_unavailable",
3718
4161
  "unit_unknown",
3719
4162
  "retention_gap",
@@ -3743,15 +4186,13 @@ var ADMIN_APPROVAL_DISPOSITIONS = CEAL_OPERATION_APPROVAL_DISPOSITIONS;
3743
4186
  var ADMIN_APPROVAL_POSTURES = vocabulary([...ADMIN_APPROVAL_DISPOSITIONS, "not_applicable"]);
3744
4187
  var ADMIN_LINEAGE_NODE_KINDS = vocabulary(["source_read", "synthesis_preview", "approval", "effect", "readback"]);
3745
4188
 
3746
- // packages/ceal-client-protocol/src/actor-kind.ts
3747
- var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
3748
-
3749
4189
  // packages/ceal-client-protocol/src/device-enrollment.ts
3750
4190
  var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired", "denied"]);
3751
4191
  var POLL_RESULT_KEYS = Object.freeze(["retry_after_ms", "schema_version", "status"]);
3752
4192
 
3753
4193
  // packages/ceal-client-protocol/src/personal-client-session.ts
3754
4194
  var REFRESH_FAILURE_CODES = new Set(CEAL_REFRESH_FAILURE_CODES);
4195
+ var REVOKE_FAILURE_CODES = new Set(CEAL_CLIENT_REVOKE_FAILURE_CODES);
3755
4196
 
3756
4197
  // packages/ceal-client-protocol/src/index.ts
3757
4198
  var MAX_REQUEST_BYTES = 32 * 1024;
@@ -3843,16 +4284,59 @@ function hostClientProbeRefusal(probe, subject) {
3843
4284
  }
3844
4285
 
3845
4286
  // host/client-doctor.ts
3846
- import { createHash as createHash2 } from "node:crypto";
4287
+ import { createHash as createHash3 } from "node:crypto";
3847
4288
  import { execFile } from "node:child_process";
3848
4289
  import { access, open, readFile, realpath, stat } from "node:fs/promises";
3849
4290
  import { delimiter, isAbsolute, join as join2 } from "node:path";
3850
4291
  import { promisify } from "node:util";
4292
+
4293
+ // host/command-vector.ts
4294
+ import { win32 } from "node:path";
4295
+ var MAX_COMMAND_BYTES = 4096;
4296
+ function formatHostCommand(vector, platform) {
4297
+ return formatWith(vector, platform === "windows" ? quoteWindowsArgument : quotePosixArgument);
4298
+ }
4299
+ function hostScriptLauncherInvocation(launcherPath, args, platform = process.platform, environment = process.env) {
4300
+ if (/\.(?:cjs|js|mjs)$/iu.test(launcherPath)) return { executable: process.execPath, args: [launcherPath, ...args] };
4301
+ if (platform === "win32" && /\.(?:bat|cmd)$/iu.test(launcherPath)) {
4302
+ return {
4303
+ executable: environment.ComSpec ?? "cmd.exe",
4304
+ args: ["/d", "/s", "/c", `call ${formatHostCommand({ executable: launcherPath, args }, "windows")}`],
4305
+ windowsVerbatimArguments: true
4306
+ };
4307
+ }
4308
+ if (platform === "win32" && /\.ps1$/iu.test(launcherPath)) {
4309
+ return {
4310
+ executable: win32.join(environment.SystemRoot ?? "C:\\Windows", "System32", "WindowsPowerShell", "v1.0", "powershell.exe"),
4311
+ args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-File", launcherPath, ...args]
4312
+ };
4313
+ }
4314
+ return { executable: launcherPath, args };
4315
+ }
4316
+ function formatWith(vector, quote) {
4317
+ const command = [vector.executable, ...vector.args].map(quote).join(" ");
4318
+ const commandBytes = Buffer.byteLength(command, "utf8");
4319
+ if (commandBytes > MAX_COMMAND_BYTES) throw new TypeError(`Host command vector is too large (${refusalFact("bytes", commandBytes, `at most ${MAX_COMMAND_BYTES} UTF-8 bytes`)}).`);
4320
+ return command;
4321
+ }
4322
+ function quotePosixArgument(value) {
4323
+ return `'${value.replaceAll("'", "'\\''")}'`;
4324
+ }
4325
+ function quoteWindowsArgument(value) {
4326
+ if (value.includes("%") || value.includes("!")) throw new TypeError("Host command vector contains unsafe Windows expansion syntax.");
4327
+ return quoteWindowsExecArgument(value);
4328
+ }
4329
+ function quoteWindowsExecArgument(value) {
4330
+ const escaped = value.replace(/(\\*)"/gu, '$1$1\\"').replace(/(\\+)$/gu, "$1$1");
4331
+ return `"${escaped}"`;
4332
+ }
4333
+
4334
+ // host/client-doctor.ts
3851
4335
  var execFileAsync = promisify(execFile);
3852
4336
  var GIT_OID = /^[a-f0-9]{40}$/u;
3853
4337
  var SHA2562 = /^[a-f0-9]{64}$/u;
3854
4338
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3855
- var CEAL_ENVIRONMENT_OVERRIDES = ["CEAL_GATEWAY_ORIGIN", "CEAL_GATEWAY_TRANSPORT_ORIGIN", "CEAL_ACCESS_TOKEN", "CEAL_CONTEXT_STORE_PATH"];
4339
+ var CEAL_ENVIRONMENT_OVERRIDES = CEAL_CLIENT_CONTEXT_OVERRIDE_ENVIRONMENTS;
3856
4340
  async function doctorClient(options = {}, component) {
3857
4341
  const environment = canonicalClientEnvironment(options.environment ?? process.env);
3858
4342
  const run = options.run ?? executeCealCommand;
@@ -3889,7 +4373,7 @@ async function inspectExecutable(options, environment, component) {
3889
4373
  return { ok: true, value: executable };
3890
4374
  }
3891
4375
  async function inspectVersion(options, executable, environment, run, component) {
3892
- const probe = hostClientProbe(await safeRun(run, executable.path, ["version"], environment), (result) => versionIdentity(commandDocument(result)));
4376
+ const probe = hostClientProbe(await safeRun(run, executable.path, CEAL_CLIENT_VERSION_COMMAND, environment), (result) => versionIdentity(commandDocument(result)));
3893
4377
  if (probe.kind !== "value") return probeFailure(probe, "version", component, options);
3894
4378
  if (options.expected_source_commit !== void 0 && probe.value.source_commit !== options.expected_source_commit) return inspectedFailure("ceal_identity_mismatch", `The Ceal executable visible to the ${component} Host did not return the expected source identity (${refusalFact("source_commit", probe.value.source_commit, `expected ${options.expected_source_commit}`)}).`, `Install the exact candidate, restart ${component}, and verify \`ceal version\` from that Host.`);
3895
4379
  return { ok: true, value: probe.value };
@@ -3906,8 +4390,8 @@ function probeCode(code) {
3906
4390
  return "ceal_output_unreadable";
3907
4391
  }
3908
4392
  async function inspectCanonicalContext(options, executable, environment, run, component) {
3909
- const probe = hostClientProbe(await safeRun(run, executable.path, ["access-group", "list"], environment), (result) => selectedContext(commandDocument(result)));
3910
- if (probe.kind === "unreachable") return probeFailure(probe, "access-group list", component, options);
4393
+ const probe = hostClientProbe(await safeRun(run, executable.path, CEAL_CLIENT_ACCESS_GROUP_LIST_COMMAND, environment), (result) => selectedContext(commandDocument(result)));
4394
+ if (probe.kind === "unreachable") return probeFailure(probe, CEAL_CLIENT_ACCESS_GROUP_LIST_COMMAND.join(" "), component, options);
3911
4395
  if (probe.kind !== "value" || options.expected_instance_ref !== void 0 && probe.value.instance_ref !== options.expected_instance_ref) return inspectedFailure("canonical_context_unavailable", `The ${component} Host cannot select the intended authenticated context from Ceal's canonical user configuration (${refusalFacts([{ name: "probe_kind", value: probe.kind, expected: "value" }, { name: "instance_ref", value: probe.kind === "value" ? probe.value.instance_ref : "unavailable", expected: options.expected_instance_ref ?? "a selected context" }])}).`, `Run \`ceal session adopt --email <email>\` without CEAL context overrides, then restart ${component}.`);
3912
4396
  return { ok: true, value: probe.value };
3913
4397
  }
@@ -3928,7 +4412,7 @@ async function resolveCealExecutable(command, environment) {
3928
4412
  const metadata = await stat(path);
3929
4413
  if (!metadata.isFile()) continue;
3930
4414
  if (await isLauncher(path)) return resolveLauncherBinary(path, environment);
3931
- return { path, sha256: createHash2("sha256").update(await readFile(path)).digest("hex") };
4415
+ return { path, sha256: createHash3("sha256").update(await readFile(path)).digest("hex") };
3932
4416
  } catch {
3933
4417
  }
3934
4418
  }
@@ -3947,18 +4431,19 @@ async function isLauncher(path) {
3947
4431
  }
3948
4432
  }
3949
4433
  async function resolveLauncherBinary(launcherPath, environment) {
3950
- const result = await execFileAsync(launcherPath, ["doctor"], { env: environment, timeout: 15e3, encoding: "utf8", windowsHide: false });
4434
+ const invocation = hostScriptLauncherInvocation(launcherPath, CEAL_CLIENT_DOCTOR_COMMAND, process.platform, environment);
4435
+ const result = await execFileAsync(invocation.executable, [...invocation.args], { env: environment, timeout: 15e3, encoding: "utf8", windowsHide: false, ...invocation.windowsVerbatimArguments === void 0 ? {} : { windowsVerbatimArguments: invocation.windowsVerbatimArguments } });
3951
4436
  let parsed;
3952
4437
  try {
3953
4438
  parsed = JSON.parse(result.stdout);
3954
4439
  } catch {
3955
4440
  throw new Error("launcher doctor returned unreadable output");
3956
4441
  }
3957
- if (!isRecord(parsed) || parsed.schema_version !== "ceal.doctor.v1" || parsed.ok !== true || typeof parsed.binary_path !== "string" || parsed.binary_path.length === 0) throw new Error("launcher doctor did not report a binary path");
4442
+ if (!isRecord(parsed) || parsed.schema_version !== CEAL_CLIENT_DOCTOR_SCHEMA_VERSION || parsed.ok !== true || typeof parsed.binary_path !== "string" || parsed.binary_path.length === 0) throw new Error("launcher doctor did not report a binary path");
3958
4443
  const binaryPath = await realpath(parsed.binary_path);
3959
4444
  const metadata = await stat(binaryPath);
3960
4445
  if (!metadata.isFile()) throw new Error("launcher doctor reported a non-file binary path");
3961
- return { path: binaryPath, sha256: createHash2("sha256").update(await readFile(binaryPath)).digest("hex") };
4446
+ return { path: binaryPath, sha256: createHash3("sha256").update(await readFile(binaryPath)).digest("hex") };
3962
4447
  }
3963
4448
  async function executeCealCommand(executable, args, environment) {
3964
4449
  try {
@@ -3993,7 +4478,7 @@ function selectedContextRecord(item) {
3993
4478
  return { name: item.name, instance_ref: item.instance_ref };
3994
4479
  }
3995
4480
  function versionIdentity(value) {
3996
- if (value?.schema_version !== "ceal.version.v1" || value.ok !== true || typeof value.version !== "string" || typeof value.source_commit !== "string" || typeof value.source_tree !== "string") return null;
4481
+ if (value?.schema_version !== CEAL_CLIENT_VERSION_SCHEMA_VERSION || value.ok !== true || typeof value.version !== "string" || typeof value.source_commit !== "string" || typeof value.source_tree !== "string") return null;
3997
4482
  if (value.version.length === 0 || !GIT_OID.test(value.source_commit) || !GIT_OID.test(value.source_tree)) return null;
3998
4483
  return { version: value.version, source_commit: value.source_commit, source_tree: value.source_tree };
3999
4484
  }
@@ -4017,16 +4502,9 @@ async function doctorCodexClient(options = {}) {
4017
4502
  import { performance } from "node:perf_hooks";
4018
4503
 
4019
4504
  // host/relay/src/producer-frame.ts
4020
- var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
4021
- var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
4022
4505
  var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
4023
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
4024
- var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
4025
- var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
4506
+ var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "turn_terminal", "producer_status"];
4026
4507
  var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
4027
- function isHostProducerFrameKind(value) {
4028
- return typeof value === "string" && FRAME_KINDS.has(value);
4029
- }
4030
4508
  var HOST_PRODUCER_FRAME_ERROR_CODES = [
4031
4509
  "invalid_frame_encoding",
4032
4510
  "invalid_frame_length",
@@ -4036,473 +4514,205 @@ var HOST_PRODUCER_FRAME_ERROR_CODES = [
4036
4514
  "invalid_producer_identity",
4037
4515
  "frame_too_large"
4038
4516
  ];
4039
- var HostProducerFrameError = class extends Error {
4040
- code;
4041
- constructor(code, message = code) {
4517
+
4518
+ // host/relay/src/host-producer-core.ts
4519
+ import { createHash as createHash4 } from "node:crypto";
4520
+
4521
+ // host/secure-file.ts
4522
+ import { execFile as execFile2 } from "node:child_process";
4523
+ import { constants } from "node:fs";
4524
+ import { lstat, open as open2 } from "node:fs/promises";
4525
+ import { dirname, win32 as win322 } from "node:path";
4526
+ import { fileURLToPath } from "node:url";
4527
+ var SecureFileCustodyError = class extends Error {
4528
+ name = "SecureFileCustodyError";
4529
+ reason;
4530
+ constructor(reason, message) {
4042
4531
  super(message);
4043
- this.code = code;
4532
+ this.reason = reason;
4533
+ }
4534
+ get code() {
4535
+ if (this.reason === "reparse_point") return "ELOOP";
4536
+ if (this.reason === "not_found") return "ENOENT";
4537
+ if (this.reason === "too_large") return "secure_file_too_large";
4538
+ if (this.reason === "already_exists") return "EEXIST";
4539
+ return this.reason === "not_private" ? "secure_file_not_private" : "secure_file_unavailable";
4044
4540
  }
4045
4541
  };
4046
- function encodeHostProducerFrame(frame) {
4047
- validateFrame(frame);
4048
- const json = Buffer.from(JSON.stringify(frame), "utf8");
4049
- 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}`)}`);
4050
- const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
4051
- result.writeUInt32BE(json.byteLength, 0);
4052
- json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
4053
- return result;
4054
- }
4055
- function decodeHostProducerFrame(input) {
4056
- 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}`)}`);
4057
- const length = input.readUInt32BE(0);
4058
- 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}`)}`);
4059
- if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
4060
- 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");
4061
- const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
4062
- const text = new TextDecoder("utf-8", { fatal: true });
4063
- let value;
4542
+ var WINDOWS_SECUREFS_REFUSAL_SCHEMA = "ceal.host_securefs_refusal.v1";
4543
+ var WINDOWS_SECUREFS_MAX_RANDOM_FILE_BYTES = 4096;
4544
+ var WINDOWS_SECUREFS_TIMEOUT_MS = 1e4;
4545
+ var WINDOWS_SECUREFS_DIAGNOSTIC_BYTES = 4096;
4546
+ function secureOpenFlags(flags, platform) {
4547
+ if (platform === "win32") return flags;
4548
+ const nofollow = constants.O_NOFOLLOW;
4549
+ if (typeof nofollow === "number" && nofollow !== 0) return flags | nofollow;
4550
+ throw new Error("Secure file reads require O_NOFOLLOW on this platform.");
4551
+ }
4552
+ async function openNoFollow(path, flags = constants.O_RDONLY, mode, platform = process.platform, _custody = {}) {
4553
+ if (platform !== "win32") return await open2(path, secureOpenFlags(flags, platform), mode);
4554
+ return await openWindowsIdentityScreened(path, flags, mode);
4555
+ }
4556
+ async function openWindowsIdentityScreened(path, flags, mode) {
4557
+ const handle = await open2(path, flags, mode);
4064
4558
  try {
4065
- value = JSON.parse(text.decode(bytes));
4559
+ const first = await handle.stat();
4560
+ if (!first.isFile()) throw new SecureFileCustodyError("not_private", "The Windows Host file is not a regular file.");
4561
+ await assertWindowsLinkFree(path, first);
4562
+ await assertWindowsIdentityStable(handle, first, path);
4563
+ return handle;
4066
4564
  } catch (error) {
4067
- if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
4068
- throw new HostProducerFrameError("frame_truncated");
4565
+ await handle.close();
4566
+ throw error;
4069
4567
  }
4070
- validateFrame(value);
4071
- return value;
4072
4568
  }
4073
- function isHostSafeRef(value) {
4074
- return safeRef(value);
4075
- }
4076
- function validateFrame(value) {
4077
- if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
4078
- 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)}`);
4079
- if (!exactKeys2(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
4080
- if (!PRODUCERS.has(String(value.producer_id)) || !safeRef(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
4081
- if (!positive(value.producer_epoch) || !positive(value.sequence) || !hostProducerFrameKind(value.frame_kind) || !timestamp(value.occurred_at) || !record(value.payload)) throw new HostProducerFrameError("invalid_frame_shape");
4082
- validatePayload(value.frame_kind, value.payload);
4083
- }
4084
- function validatePayload(kind, value) {
4085
- const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
4086
- if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
4087
- }
4088
- function validSession(value) {
4089
- 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);
4569
+ async function assertWindowsLinkFree(path, first) {
4570
+ const entry = await lstat(path);
4571
+ if (entry.isSymbolicLink() || entry.dev !== first.dev || entry.ino !== first.ino) {
4572
+ throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
4573
+ }
4574
+ }
4575
+ async function assertWindowsIdentityStable(handle, first, path) {
4576
+ const second = await handle.stat();
4577
+ if (second.dev !== first.dev || second.ino !== first.ino || second.size !== first.size || second.mtimeMs !== first.mtimeMs) {
4578
+ throw new SecureFileCustodyError("unavailable", "The Windows Host file changed while its identity was checked.");
4579
+ }
4580
+ const entry = await lstat(path);
4581
+ if (entry.isSymbolicLink()) throw new SecureFileCustodyError("reparse_point", "The Windows Host file path resolves through a reparse point.");
4582
+ if (entry.dev !== second.dev || entry.ino !== second.ino) throw new SecureFileCustodyError("unavailable", "The Windows Host file path no longer names the opened file.");
4583
+ }
4584
+ async function readPrivateFileWithSecurefs(path, maxBytes, custody = {}) {
4585
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new TypeError("The securefs read bound must be a positive safe integer.");
4586
+ const result = await runWindowsSecurefs(["internal", "securefs", "read-private-file", path, String(maxBytes)], maxBytes, custody);
4587
+ if (result.exit_code === 0 && result.stderr.length === 0 && result.stdout.length <= maxBytes) return result.stdout;
4588
+ if (result.stdout.length !== 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned bytes with a refusal.");
4589
+ if (result.exit_code === 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command exceeded its output contract.");
4590
+ throw securefsRefusal(result.stderr);
4591
+ }
4592
+ async function createRandomPrivateFileWithSecurefs(path, byteLength2, custody = {}) {
4593
+ if (!Number.isSafeInteger(byteLength2) || byteLength2 < 1 || byteLength2 > WINDOWS_SECUREFS_MAX_RANDOM_FILE_BYTES) throw new TypeError(`The securefs random-file size must be between 1 and ${WINDOWS_SECUREFS_MAX_RANDOM_FILE_BYTES} bytes.`);
4594
+ const result = await runWindowsSecurefs(["internal", "securefs", "create-random-private-file", path, String(byteLength2)], 0, custody);
4595
+ if (result.exit_code === 0 && result.stdout.length === 0 && result.stderr.length === 0) return;
4596
+ if (result.stdout.length !== 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned unexpected creation bytes.");
4597
+ if (result.exit_code === 0) throw new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned an invalid creation result.");
4598
+ throw securefsRefusal(result.stderr);
4599
+ }
4600
+ async function runWindowsSecurefs(args, maxBytes, custody) {
4601
+ if (custody.run_securefs_command !== void 0) return await custody.run_securefs_command(args);
4602
+ const executable = custody.securefs_executable ?? resolveInstalledHostExecutable();
4603
+ const processArgs = [...custody.securefs_args_prefix ?? [], ...args];
4604
+ return await new Promise((resolve, reject2) => {
4605
+ execFile2(executable, processArgs, { encoding: "buffer", timeout: WINDOWS_SECUREFS_TIMEOUT_MS, maxBuffer: maxBytes + WINDOWS_SECUREFS_DIAGNOSTIC_BYTES }, (error, stdout, stderr) => {
4606
+ const exitCode = error === null ? 0 : typeof error.code === "number" ? error.code : null;
4607
+ if (exitCode === null) {
4608
+ reject2(new SecureFileCustodyError("unavailable", "The installed Windows Host securefs command could not run."));
4609
+ return;
4610
+ }
4611
+ resolve({ exit_code: exitCode, stdout: Buffer.from(stdout), stderr: Buffer.from(stderr) });
4612
+ });
4613
+ });
4090
4614
  }
4091
- function validTurn(value) {
4092
- 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);
4615
+ function securefsRefusal(stderr) {
4616
+ let value;
4617
+ try {
4618
+ value = JSON.parse(stderr.toString("utf8"));
4619
+ } catch {
4620
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command returned an unreadable refusal.");
4621
+ }
4622
+ if (!isRecord2(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.");
4623
+ if (value.code === "reparse_point") return new SecureFileCustodyError("reparse_point", "The Windows Host securefs file is a reparse point.");
4624
+ if (value.code === "not_found") return new SecureFileCustodyError("not_found", "The Windows Host securefs file was not found.");
4625
+ if (value.code === "too_large") return new SecureFileCustodyError("too_large", "The Windows Host securefs file exceeds its read bound.");
4626
+ if (value.code === "already_exists") return new SecureFileCustodyError("already_exists", "The Windows Host securefs target already exists.");
4627
+ if (value.code === "not_private") return new SecureFileCustodyError("not_private", "The Windows Host securefs file is not private to the current user.");
4628
+ return new SecureFileCustodyError("unavailable", "The Windows Host securefs command refused the file read.");
4093
4629
  }
4094
- function validInput(value) {
4095
- 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);
4630
+ function resolveInstalledHostExecutable() {
4631
+ const privateRuntimeRoot = dirname(fileURLToPath(import.meta.url));
4632
+ return win322.join(privateRuntimeRoot, "..", "..", "bin", "ceal-host.exe");
4096
4633
  }
4097
- function validInputObservations(value) {
4098
- return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
4634
+ function isRecord2(value) {
4635
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4099
4636
  }
4100
- function validInputOptionals(value) {
4101
- return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp(value.context_expires_at));
4637
+ function isOwnedBy(uid, expectedUid) {
4638
+ return Number.isSafeInteger(uid) && Number.isSafeInteger(expectedUid) && uid === expectedUid;
4102
4639
  }
4103
- function validTerminal(value) {
4104
- 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);
4640
+ function isSelfOwned(uid, platform = process.platform, _handle) {
4641
+ if (platform === "win32" || typeof process.geteuid !== "function") return false;
4642
+ return isOwnedBy(uid, process.geteuid());
4105
4643
  }
4106
- function validTerminalDisposition(state, reason) {
4107
- return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef(reason));
4108
- }
4109
- function validStatus(value) {
4110
- return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef(value.reason_code) && optionalText(value.detail, 4096);
4111
- }
4112
- function optionalText(value, maxLength) {
4113
- return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
4114
- }
4115
- function optionalNonNegative(value) {
4116
- return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
4117
- }
4118
- function optionalRefs(value) {
4119
- return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef);
4120
- }
4121
- function validObservations(value) {
4122
- if (value === void 0) return true;
4123
- if (!Array.isArray(value) || value.length > 32) return false;
4124
- return value.every((item) => {
4125
- try {
4126
- validateCealHostObservationDraft(item);
4127
- return true;
4128
- } catch {
4129
- return false;
4130
- }
4131
- });
4132
- }
4133
- function jsonValue(value, depth = 0) {
4134
- if (depth > 16) return false;
4135
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
4136
- if (typeof value === "number") return Number.isFinite(value);
4137
- if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
4138
- return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
4139
- }
4140
- function record(value) {
4141
- return value !== null && typeof value === "object" && !Array.isArray(value);
4142
- }
4143
- function safeRef(value) {
4144
- return typeof value === "string" && SAFE_REF3.test(value);
4145
- }
4146
- function positive(value) {
4147
- return Number.isSafeInteger(value) && Number(value) > 0;
4148
- }
4149
- function timestamp(value) {
4150
- return typeof value === "string" && Number.isFinite(Date.parse(value));
4151
- }
4152
- function hostProducerFrameKind(value) {
4153
- return isHostProducerFrameKind(value);
4154
- }
4155
- function exactKeys2(value, keys) {
4156
- return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
4157
- }
4158
- function exactOptional(value, required, optional) {
4159
- const keys = Object.keys(value);
4160
- return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
4644
+ function isPrivateFileMode(mode, platform = process.platform, _handle) {
4645
+ if (platform === "win32") return false;
4646
+ return (mode & 63) === 0;
4161
4647
  }
4162
4648
 
4163
4649
  // host/relay/src/host-producer-core.ts
4164
- import { createHash as createHash3 } from "node:crypto";
4165
- import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
4166
- import { mkdir as mkdir2, open as open3, readFile as readFile2, rename as rename2, writeFile } from "node:fs/promises";
4167
- import { join as join3 } from "node:path";
4168
-
4169
- // host/relay/src/relay-ipc.ts
4170
- import { createConnection, createServer } from "node:net";
4171
-
4172
- // host/relay/src/durable-atomic-replacement.ts
4173
- import { O_RDONLY } from "node:constants";
4174
- import { lstat, mkdir, open as open2, rename, unlink } from "node:fs/promises";
4175
- var DEFAULT_PORT = {
4176
- platform: process.platform,
4177
- mkdir: (path, options) => mkdir(path, options),
4178
- lstat: (path) => lstat(path),
4179
- open_file: (path) => open2(path, "wx", 384),
4180
- rename,
4181
- unlink,
4182
- open_directory: (path) => open2(path, O_RDONLY),
4183
- unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
4184
- };
4185
-
4186
- // host/relay/src/relay-request-binding-store.ts
4187
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
4188
-
4189
- // host/relay/src/current-prompt-custody.ts
4190
- var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
4191
-
4192
- // host/service-log.ts
4193
- function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
4194
- 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 } : {} })}
4195
- `;
4196
- try {
4197
- (sink ?? defaultHostServiceDiagnosticSink)(line);
4198
- } catch {
4199
- }
4200
- }
4201
- function defaultHostServiceDiagnosticSink(line) {
4202
- process.stderr.write(line);
4203
- }
4204
- var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
4205
- var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
4206
-
4207
- // host/relay/src/relay-ipc.ts
4208
- var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
4209
- "schema_version",
4210
- "producer_id",
4211
- "producer_installation_ref",
4212
- "local_session_ref",
4213
- "local_turn_ref",
4214
- "local_turn_aliases",
4215
- "prompt_ref",
4216
- "request_ref",
4217
- "bound_at",
4218
- "host_source_ref",
4219
- "host_session_ref",
4220
- "host_turn_ref",
4221
- "host_input_ref"
4222
- ]);
4223
- var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
4224
- var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
4225
- var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
4226
- var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
4227
- var HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA = "ceal.host_relay_current_prompt_release.v1";
4228
- var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
4229
- var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
4230
- var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
4231
- var HOST_RELAY_QUERY_RESPONSE_MAX_BYTES = 8192;
4232
- var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
4233
- "context_stale",
4234
- "context_expired",
4235
- "host_source_refused",
4236
- "host_credential_refused",
4237
- "gateway_unavailable",
4238
- "gateway_refused",
4239
- "gateway_response_invalid",
4240
- "gateway_rate_limited",
4241
- "producer_frame_invalid",
4242
- "deadline",
4243
- "cancelled",
4244
- "mint_failed",
4245
- "relay_failed",
4246
- "request_authority_unavailable",
4247
- "request_missing",
4248
- "authority_mismatch",
4249
- "host_source_mismatch",
4250
- "host_session_mismatch",
4251
- "host_turn_mismatch",
4252
- "host_input_mismatch",
4253
- "host_prompt_mismatch"
4254
- ]);
4255
- var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
4256
- "context_stale",
4257
- "context_expired",
4258
- "host_source_refused",
4259
- "host_credential_refused",
4260
- "gateway_unavailable",
4261
- "gateway_rate_limited",
4262
- "gateway_refused",
4263
- "gateway_response_invalid",
4264
- "producer_frame_invalid"
4265
- ]);
4266
- var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
4267
- var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
4268
- "permission_denied",
4269
- "socket_missing",
4270
- "connection_refused",
4271
- "closed_early",
4272
- "response_invalid",
4273
- "timed_out",
4274
- "cancelled",
4275
- "unavailable"
4276
- ]);
4277
- var HostRelayIpcError = class extends Error {
4278
- code;
4279
- /** Set only when the client-side socket exchange itself failed. */
4280
- failure;
4281
- constructor(code, message = code, failure2) {
4282
- super(message);
4283
- this.code = code;
4284
- this.failure = failure2;
4285
- }
4286
- };
4287
- var HostRelayCurrentPromptCapacityRefusal = class extends Error {
4288
- constructor() {
4289
- super("current_prompt_capacity_exhausted");
4290
- this.name = "HostRelayCurrentPromptCapacityRefusal";
4291
- }
4292
- };
4293
- function hostRelayExchangeFailure(error) {
4294
- return error instanceof HostRelayIpcError ? error.failure : void 0;
4295
- }
4296
- function socketErrorFailure(error) {
4297
- switch (errorCode2(error)) {
4298
- case "EACCES":
4299
- case "EPERM":
4300
- return "permission_denied";
4301
- case "ENOENT":
4302
- return "socket_missing";
4303
- case "ECONNREFUSED":
4304
- return "connection_refused";
4305
- default:
4306
- return "unavailable";
4307
- }
4308
- }
4309
- var HostRelayInvocationContextPort = class {
4310
- endpoint;
4311
- constructor(endpoint) {
4312
- this.endpoint = endpoint;
4313
- }
4314
- mintInvocationContext(input, signal) {
4315
- return queryHostRelayInvocationContext(this.endpoint, input, signal);
4316
- }
4317
- };
4318
- var HostRelayIpcAdmissionPort = class {
4319
- endpoint;
4320
- timeout_ms;
4321
- constructor(endpoint, timeoutMs = 5e3) {
4322
- this.endpoint = endpoint;
4323
- this.timeout_ms = timeoutMs;
4324
- }
4325
- async admit(frame) {
4326
- const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
4327
- if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
4328
- return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
4329
- }
4330
- };
4331
- var HostRelayCurrentPromptPort = class {
4332
- endpoint;
4333
- timeout_ms;
4334
- constructor(endpoint, timeoutMs = 5e3) {
4335
- this.endpoint = endpoint;
4336
- this.timeout_ms = timeoutMs;
4337
- }
4338
- async register(input) {
4339
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
4340
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
4341
- if (response2.status === "capacity_exhausted") throw new HostRelayCurrentPromptCapacityRefusal();
4342
- if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
4343
- }
4344
- async release(identity) {
4345
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA, ...identity };
4346
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
4347
- if (response2.status !== "released") throw new HostRelayIpcError("relay_unavailable", response2.status, "response_invalid");
4348
- }
4349
- };
4350
- function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
4351
- return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
4352
- }
4353
- function queryHostRelayInvocationContext(endpoint, query, signal) {
4354
- return exchange(endpoint, encodeInvocationContextQuery(query), void 0, decodeInvocationContextResponseBuffer, signal);
4355
- }
4356
- function exchange(endpoint, encoded, timeoutMs, decode, signal) {
4357
- return new Promise((resolve, reject2) => {
4358
- const socket = createConnection(endpoint);
4359
- let buffer = Buffer.alloc(0);
4360
- let settled = false;
4361
- const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
4362
- const finish = (error, response2) => {
4363
- if (settled) return;
4364
- settled = true;
4365
- signal?.removeEventListener("abort", aborted);
4366
- socket.destroy();
4367
- if (error !== null) reject2(error);
4368
- else if (response2 !== void 0) resolve(response2);
4369
- };
4370
- if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
4371
- if (signal?.aborted === true) {
4372
- aborted();
4373
- return;
4374
- }
4375
- signal?.addEventListener("abort", aborted, { once: true });
4376
- socket.once("error", (error) => {
4377
- const failure2 = socketErrorFailure(error);
4378
- finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure2}.`, failure2));
4379
- });
4380
- socket.once("connect", () => socket.write(encoded));
4381
- socket.on("data", (chunk) => {
4382
- try {
4383
- buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
4384
- const decoded = decode(buffer);
4385
- if (decoded !== null) finish(null, decoded);
4386
- } catch (error) {
4387
- finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
4388
- }
4389
- });
4390
- socket.once("end", () => {
4391
- if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
4392
- });
4393
- });
4650
+ var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
4651
+ function isHostTranscriptCursorReason(value) {
4652
+ return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
4394
4653
  }
4395
- function decodeHostRelayIpcResponse(input) {
4396
- 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}`)}.`);
4397
- const length = input.readUInt32BE(0);
4398
- 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}` }])}.`);
4399
- let value;
4654
+ var TRANSCRIPT_MISSING_REASON = "transcript_missing";
4655
+ var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
4656
+ var HOST_INVOCATION_TRANSCRIPT_TAIL_MAX_BYTES = 1024 * 1024;
4657
+ async function readBoundedHostTranscriptTail(path, maximumBytes = HOST_INVOCATION_TRANSCRIPT_TAIL_MAX_BYTES) {
4658
+ if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 1 || maximumBytes > HOST_INVOCATION_TRANSCRIPT_TAIL_MAX_BYTES) throw new TypeError("Host transcript window byte bound is invalid.");
4659
+ const handle = await openNoFollow(path);
4400
4660
  try {
4401
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
4402
- } catch {
4403
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
4661
+ const stats = await handle.stat();
4662
+ if (!stats.isFile() || !isSelfOwned(stats.uid)) throw new TypeError("Host transcript source is not an owner-owned regular file.");
4663
+ const truncated = stats.size > maximumBytes;
4664
+ const start = Math.max(0, stats.size - maximumBytes);
4665
+ const bytes = await readTranscriptBytes(handle, start, stats.size - start);
4666
+ return { bytes: truncated ? dropPartialLeadingTranscriptRecord(bytes) : bytes, truncated };
4667
+ } finally {
4668
+ await handle.close();
4404
4669
  }
4405
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
4406
- return value;
4407
- }
4408
- function relayAdmissionCode(value) {
4409
- 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";
4410
- }
4411
- function validResponse(value) {
4412
- 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;
4413
- }
4414
- function hostRelayIpcCode(value) {
4415
- 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);
4416
- }
4417
- function nonnegative(value) {
4418
- return Number.isSafeInteger(value) && Number(value) >= 0;
4419
- }
4420
- function record2(value) {
4421
- return value !== null && typeof value === "object" && !Array.isArray(value);
4422
- }
4423
- function decodeResponseBuffer(buffer) {
4424
- if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
4425
- const length = buffer.readUInt32BE(0);
4426
- 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}`)}.`);
4427
- if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
4428
- 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}` }])}.`);
4429
- return decodeHostRelayIpcResponse(buffer);
4430
- }
4431
- function decodeInvocationContextResponseBuffer(buffer) {
4432
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_QUERY_RESPONSE_MAX_BYTES);
4433
- if (value === null) return null;
4434
- if (!validInvocationContextResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay invocation context response is invalid.");
4435
- return value;
4436
- }
4437
- function decodeCurrentPromptResponseBuffer(buffer) {
4438
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
4439
- if (value === null) return null;
4440
- if (!record2(value) || !exactKeys3(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");
4441
- return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
4442
- }
4443
- function encodeInvocationContextQuery(query) {
4444
- const value = { schema_version: HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA, ...query };
4445
- if (!validInvocationContextQueryRequest(value)) throw new HostRelayIpcError("invalid_frame_shape");
4446
- return encodeLengthPrefixed(value);
4447
4670
  }
4448
- function validInvocationContextQueryRequest(value) {
4449
- return validQueryIdentity(value, HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) && exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "client_nonce"], ["visible_output_max_bytes"]) && typeof value.client_nonce === "string" && CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce) && (value.visible_output_max_bytes === void 0 || validVisibleOutputBudget(value.visible_output_max_bytes));
4450
- }
4451
- function validQueryIdentity(value, schema) {
4452
- return record2(value) && value.schema_version === schema && (value.producer_id === "codex" || value.producer_id === "claude") && safeRef2(value.producer_installation_ref) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref);
4453
- }
4454
- function validVisibleOutputBudget(value) {
4455
- return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
4456
- }
4457
- function validInvocationContextResponse(value) {
4458
- if (!record2(value) || value.schema_version !== HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA) return false;
4459
- if (value.status === "no_binding") return Object.keys(value).length === 2;
4460
- if (value.status === "refused") return Object.keys(value).length === 3 && isVocabularyWord(HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS, value.reason);
4461
- if (value.status !== "ready" || Object.keys(value).length !== 3) return false;
4462
- try {
4463
- decodeCealHostInvocationAuthenticationResult(value.result);
4464
- return true;
4465
- } catch {
4466
- return false;
4671
+ async function readTranscriptBytes(handle, start, length) {
4672
+ const output = Buffer.alloc(Math.max(0, length));
4673
+ let offset = 0;
4674
+ while (offset < output.length) {
4675
+ const { bytesRead } = await handle.read(output, offset, output.length - offset, start + offset);
4676
+ if (bytesRead === 0) break;
4677
+ offset += bytesRead;
4467
4678
  }
4679
+ return output.subarray(0, offset);
4468
4680
  }
4469
- function decodeLengthPrefixedJson(input, maximum) {
4470
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
4471
- const length = input.readUInt32BE(0);
4472
- 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}`)}.`);
4473
- if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
4474
- 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}` }])}.`);
4681
+ function dropPartialLeadingTranscriptRecord(bytes) {
4682
+ if (bytes.length === 0) return bytes;
4683
+ const newline = bytes.indexOf(10);
4684
+ return newline < 0 ? Buffer.alloc(0) : bytes.subarray(newline + 1);
4685
+ }
4686
+ async function readRegisteredHostInvocationHumanMessageWindow(listRegistrations, identity, decodeLine) {
4475
4687
  try {
4476
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
4688
+ const registration = (await listRegistrations()).find((candidate) => candidate.host_source_ref === identity.host_source_ref && candidate.host_session_ref === identity.host_session_ref && Date.parse(candidate.expires_at) > Date.now());
4689
+ if (registration === void 0) throw new TypeError("context_unavailable");
4690
+ return await readHostInvocationHumanMessageWindow(registration.transcript_path, (line) => decodeLine(line, registration));
4477
4691
  } catch {
4478
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
4692
+ throw new TypeError("context_unavailable");
4693
+ }
4694
+ }
4695
+ async function readHostInvocationHumanMessageWindow(path, decodeLine) {
4696
+ const tail = await readBoundedHostTranscriptTail(path);
4697
+ const lines = new TextDecoder("utf-8", { fatal: true }).decode(tail.bytes).split("\n");
4698
+ const incompleteTail = lines.at(-1) !== "";
4699
+ if (incompleteTail) lines.pop();
4700
+ let truncated = tail.truncated || incompleteTail;
4701
+ const newestFirst = [];
4702
+ const seen = /* @__PURE__ */ new Set();
4703
+ for (const line of lines.reverse()) {
4704
+ if (line.length === 0) continue;
4705
+ const message = decodeLine(line);
4706
+ if (message === "malformed") {
4707
+ truncated = true;
4708
+ continue;
4709
+ }
4710
+ if (message === null || seen.has(message.host_input_ref)) continue;
4711
+ seen.add(message.host_input_ref);
4712
+ newestFirst.push(message);
4479
4713
  }
4714
+ return boundCealHostInvocationHumanMessageWindow(newestFirst, truncated);
4480
4715
  }
4481
- function encodeLengthPrefixed(value) {
4482
- const body = Buffer.from(JSON.stringify(value), "utf8");
4483
- const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
4484
- output.writeUInt32BE(body.length, 0);
4485
- body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
4486
- return output;
4487
- }
4488
- function exactKeys3(value, required, optional = []) {
4489
- const keys = Object.keys(value);
4490
- return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
4491
- }
4492
- function safeRef2(value) {
4493
- return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
4494
- }
4495
- function errorCode2(error) {
4496
- return record2(error) && typeof error.code === "string" ? error.code : null;
4497
- }
4498
-
4499
- // host/relay/src/host-producer-core.ts
4500
- var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
4501
- function isHostTranscriptCursorReason(value) {
4502
- return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
4503
- }
4504
- var TRANSCRIPT_MISSING_REASON = "transcript_missing";
4505
- var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
4506
4716
  function transcriptScanFailureKind(error, adapterFailureKind) {
4507
4717
  if (transcriptErrorCode(error) === "ELOOP") return "symlink";
4508
4718
  const adapter = adapterFailureKind(error);
@@ -4512,16 +4722,6 @@ function transcriptScanFailureKind(error, adapterFailureKind) {
4512
4722
  if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
4513
4723
  return "other";
4514
4724
  }
4515
- async function registerHostCurrentPromptDiagnosed(register, diagnostic) {
4516
- try {
4517
- await register();
4518
- diagnostic("current_prompt_registered");
4519
- return true;
4520
- } catch (error) {
4521
- if (!(error instanceof HostRelayCurrentPromptCapacityRefusal)) diagnostic("current_prompt_registration_failed");
4522
- throw error;
4523
- }
4524
- }
4525
4725
  function transcriptErrorCode(error) {
4526
4726
  return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
4527
4727
  }
@@ -4569,10 +4769,10 @@ async function transcriptCursorBoundsReason(handle, cursor, size) {
4569
4769
  return null;
4570
4770
  }
4571
4771
  function transcriptSha256(value) {
4572
- return createHash3("sha256").update(value).digest("hex");
4772
+ return createHash4("sha256").update(value).digest("hex");
4573
4773
  }
4574
4774
  function transcriptObjectSha256(value) {
4575
- return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
4775
+ return createHash4("sha256").update(JSON.stringify(value), "utf8").digest("hex");
4576
4776
  }
4577
4777
  function isTranscriptRecord(value) {
4578
4778
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -4633,24 +4833,18 @@ var HostTranscriptWatcher = class {
4633
4833
  return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
4634
4834
  }
4635
4835
  async scanRegistration(registration) {
4636
- try {
4637
- return await this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
4638
- missing: () => this.retireMissing(registration),
4639
- failed: (handle, error) => this.scanFailed(handle, registration, error)
4640
- });
4641
- } catch (error) {
4642
- if (error instanceof HostRelayCurrentPromptCapacityRefusal) return { records: 0, enqueued: 0, quarantined: false };
4643
- throw error;
4644
- }
4836
+ return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
4837
+ missing: () => this.retireMissing(registration),
4838
+ failed: (handle, error) => this.scanFailed(handle, registration, error)
4839
+ });
4645
4840
  }
4646
4841
  async openTranscript(registration, scan, handlers) {
4647
4842
  let handle;
4648
4843
  try {
4649
- handle = await open3(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
4844
+ handle = await openNoFollow(this.transcriptPathOf(registration));
4650
4845
  return await scan(handle);
4651
4846
  } catch (error) {
4652
4847
  if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
4653
- if (hostRelayExchangeFailure(error) !== void 0 || error instanceof HostRelayCurrentPromptCapacityRefusal) throw error;
4654
4848
  return handlers.failed(handle, error);
4655
4849
  } finally {
4656
4850
  await handle?.close();
@@ -4696,29 +4890,12 @@ var HostTranscriptWatcher = class {
4696
4890
  return transcriptCursorBoundsReason(handle, cursor, size);
4697
4891
  }
4698
4892
  };
4699
- var HOST_PRODUCER_STATE_IDENTITY = {
4700
- codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
4701
- claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
4702
- };
4703
4893
  var HostProducerDrainCore = class {
4704
4894
  host;
4705
- relay;
4706
- statePath;
4707
- stateSchema;
4708
- installationRef;
4709
- epoch;
4710
4895
  now;
4711
4896
  tail = Promise.resolve();
4712
4897
  constructor(host, runtime) {
4713
- if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
4714
- const epoch = runtime.producer_epoch ?? 1;
4715
- if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
4716
4898
  this.host = host;
4717
- this.relay = runtime.relay;
4718
- this.statePath = join3(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
4719
- this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
4720
- this.installationRef = runtime.producer_installation_ref;
4721
- this.epoch = epoch;
4722
4899
  this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
4723
4900
  }
4724
4901
  drainOutbox() {
@@ -4728,145 +4905,563 @@ var HostProducerDrainCore = class {
4728
4905
  }
4729
4906
  async drainLocked() {
4730
4907
  const read = await this.host.listEnvelopes();
4731
- let admitted = 0;
4908
+ let removed = 0;
4732
4909
  let expired = 0;
4733
- let retained = 0;
4734
4910
  for (const envelope of read.entries) {
4735
- const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
4736
- if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
4737
- await this.host.removeEnvelope(envelope);
4738
- expired += 1;
4739
- continue;
4911
+ if (Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) expired += 1;
4912
+ else removed += 1;
4913
+ await this.host.removeEnvelope(envelope);
4914
+ }
4915
+ return { removed, expired, malformed: read.malformed };
4916
+ }
4917
+ };
4918
+
4919
+ // host/relay/src/durable-atomic-replacement.ts
4920
+ import { lstat as lstat2, mkdir, open as open3, rename, unlink } from "node:fs/promises";
4921
+ var DEFAULT_PORT = {
4922
+ platform: process.platform,
4923
+ mkdir: (path, options) => mkdir(path, options),
4924
+ lstat: (path) => lstat2(path),
4925
+ open_file: (path) => open3(path, "wx", 384),
4926
+ rename,
4927
+ unlink,
4928
+ open_directory: (path) => open3(path),
4929
+ unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
4930
+ };
4931
+
4932
+ // host/relay/src/relay-quarantine-store.ts
4933
+ var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
4934
+ var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
4935
+ var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
4936
+
4937
+ // host/relay/src/relay-admission-store.ts
4938
+ var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
4939
+ var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
4940
+ var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
4941
+
4942
+ // host/relay/src/relay-ipc.ts
4943
+ import { createConnection, createServer } from "node:net";
4944
+
4945
+ // host/relay/src/relay-pipe-handshake.ts
4946
+ import { createHmac, randomBytes } from "node:crypto";
4947
+ import { constants as constants2 } from "node:fs";
4948
+ import { link, unlink as unlink2 } from "node:fs/promises";
4949
+ import { dirname as dirname2, join as join3 } from "node:path";
4950
+ var RELAY_PIPE_HANDSHAKE_TIMEOUT_MS = 5e3;
4951
+ var RELAY_PIPE_KEY_BYTES = 32;
4952
+ var RELAY_PIPE_KEY_FILENAME = "relay-pipe.key";
4953
+ var RELAY_PIPE_NONCE_BYTES = 32;
4954
+ var RELAY_PIPE_NONCE_PATTERN = /^[A-Za-z0-9_-]{43}$/u;
4955
+ var RELAY_PIPE_HELLO_SCHEMA = "ceal.host_relay_pipe_hello.v1";
4956
+ var RELAY_PIPE_CHALLENGE_SCHEMA = "ceal.host_relay_pipe_challenge.v1";
4957
+ var RELAY_PIPE_RESPONSE_SCHEMA = "ceal.host_relay_pipe_response.v1";
4958
+ var RELAY_PIPE_FRAME_BYTES = Uint32Array.BYTES_PER_ELEMENT;
4959
+ var RELAY_PIPE_FRAME_MAX_BYTES = 1024;
4960
+ var RelayPipeHandshakeError = class extends Error {
4961
+ name = "RelayPipeHandshakeError";
4962
+ code;
4963
+ constructor(code, message) {
4964
+ super(message);
4965
+ this.code = code;
4966
+ }
4967
+ };
4968
+ function relayPipeStateRootForOutboxDir(outboxDir) {
4969
+ return join3(dirname2(dirname2(dirname2(outboxDir))), "relay");
4970
+ }
4971
+ function relayPipeKeyPath(relayStateRoot) {
4972
+ return join3(relayStateRoot, RELAY_PIPE_KEY_FILENAME);
4973
+ }
4974
+ async function loadRelayPipeKey(relayStateRoot, platform = process.platform, custody = {}) {
4975
+ const path = relayPipeKeyPath(relayStateRoot);
4976
+ if (platform === "win32") return await loadWindowsRelayPipeKey(path, custody);
4977
+ const existing = await readRelayPipeKey(path, platform, custody);
4978
+ if (existing !== null) return existing;
4979
+ return await createPosixRelayPipeKey(path, platform, custody);
4980
+ }
4981
+ async function loadWindowsRelayPipeKey(path, custody) {
4982
+ const existing = await readRelayPipeKey(path, "win32", custody);
4983
+ if (existing !== null) return existing;
4984
+ try {
4985
+ await createRandomPrivateFileWithSecurefs(path, RELAY_PIPE_KEY_BYTES, custody);
4986
+ } catch (error) {
4987
+ if (errorCode2(error) === "EEXIST") return await readWinnerPipeKey(path, "win32", custody);
4988
+ throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}; delete it and restart the Host Relay.`);
4989
+ }
4990
+ return await readWinnerPipeKey(path, "win32", custody);
4991
+ }
4992
+ async function createPosixRelayPipeKey(path, platform, custody) {
4993
+ const key = randomBytes(RELAY_PIPE_KEY_BYTES);
4994
+ const staging = `${path}.${randomBytes(8).toString("hex")}.tmp`;
4995
+ let handle;
4996
+ try {
4997
+ handle = await openNoFollow(staging, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL, 384);
4998
+ } catch (error) {
4999
+ if (errorCode2(error) !== "EEXIST") throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}.`);
5000
+ return await readWinnerPipeKey(path, platform, custody);
5001
+ }
5002
+ try {
5003
+ const stats = await handle.stat();
5004
+ if (!stats.isFile() || !isSelfOwned(stats.uid) || !isPrivateFileMode(stats.mode)) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key at ${path} is not a private regular file owned by the current user.`);
5005
+ await handle.writeFile(key);
5006
+ await handle.sync();
5007
+ } finally {
5008
+ await handle.close();
5009
+ }
5010
+ try {
5011
+ await link(staging, path);
5012
+ } catch (error) {
5013
+ if (errorCode2(error) !== "EEXIST") throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}.`);
5014
+ return await readWinnerPipeKey(path, platform, custody);
5015
+ } finally {
5016
+ await unlink2(staging).catch(() => void 0);
5017
+ }
5018
+ return Buffer.from(key);
5019
+ }
5020
+ async function readWinnerPipeKey(path, platform, custody) {
5021
+ const winner = await readRelayPipeKey(path, platform, custody);
5022
+ if (winner === null) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}.`);
5023
+ return winner;
5024
+ }
5025
+ async function readRelayPipeKey(path, platform, custody) {
5026
+ if (platform === "win32") return await readWindowsRelayPipeKey(path, custody);
5027
+ return await readPosixRelayPipeKey(path);
5028
+ }
5029
+ async function readWindowsRelayPipeKey(path, custody) {
5030
+ let key;
5031
+ try {
5032
+ key = await readPrivateFileWithSecurefs(path, RELAY_PIPE_KEY_BYTES, custody);
5033
+ } catch (error) {
5034
+ if (errorCode2(error) === "ENOENT" || errorCode2(error) === "ELOOP") return null;
5035
+ throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}; delete it and restart the Host Relay.`);
5036
+ }
5037
+ if (key.byteLength !== RELAY_PIPE_KEY_BYTES) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key at ${path} has ${key.byteLength} bytes; want ${RELAY_PIPE_KEY_BYTES}. Delete the file and restart the Host Relay.`);
5038
+ return Buffer.from(key);
5039
+ }
5040
+ async function readPosixRelayPipeKey(path) {
5041
+ let handle;
5042
+ try {
5043
+ handle = await openNoFollow(path);
5044
+ } catch (error) {
5045
+ if (errorCode2(error) === "ENOENT" || errorCode2(error) === "ELOOP") return null;
5046
+ throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key is unavailable at ${path}.`);
5047
+ }
5048
+ try {
5049
+ const stats = await handle.stat();
5050
+ if (!stats.isFile()) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key at ${path} is not a regular file; delete it and restart the Host Relay.`);
5051
+ if (!isSelfOwned(stats.uid) || !isPrivateFileMode(stats.mode)) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key at ${path} is not a private file owned by the current user; delete it and restart the Host Relay.`);
5052
+ if (stats.size !== RELAY_PIPE_KEY_BYTES) throw new RelayPipeHandshakeError("pipe_key_unavailable", `Host Relay pipe key at ${path} has ${stats.size} bytes; want ${RELAY_PIPE_KEY_BYTES}. Delete the file and restart the Host Relay.`);
5053
+ return await handle.readFile();
5054
+ } finally {
5055
+ await handle.close();
5056
+ }
5057
+ }
5058
+ function createPipeClientNonce() {
5059
+ return randomBytes(RELAY_PIPE_NONCE_BYTES).toString("base64url");
5060
+ }
5061
+ function pipeProof(key, role, firstNonce, secondNonce) {
5062
+ return createHmac("sha256", key).update(`${role}\0${firstNonce}\0${secondNonce}`, "utf8").digest("hex");
5063
+ }
5064
+ function createPipeServerProof(key, clientNonce, serverNonce) {
5065
+ return pipeProof(key, "server", clientNonce, serverNonce);
5066
+ }
5067
+ function createPipeClientProof(key, serverNonce, clientNonce) {
5068
+ return pipeProof(key, "client", serverNonce, clientNonce);
5069
+ }
5070
+ function encodePipeFrame(value) {
5071
+ const body = Buffer.from(JSON.stringify(value), "utf8");
5072
+ const output = Buffer.allocUnsafe(body.length + RELAY_PIPE_FRAME_BYTES);
5073
+ output.writeUInt32BE(body.length, 0);
5074
+ body.copy(output, RELAY_PIPE_FRAME_BYTES);
5075
+ return output;
5076
+ }
5077
+ function decodePipeFrame(buffer) {
5078
+ if (buffer.length < RELAY_PIPE_FRAME_BYTES) return null;
5079
+ const length = buffer.readUInt32BE(0);
5080
+ if (length === 0 || length > RELAY_PIPE_FRAME_MAX_BYTES) throw new RelayPipeHandshakeError("pipe_handshake_invalid", `Host Relay pipe handshake frame declares ${length} bytes; want between 1 and ${RELAY_PIPE_FRAME_MAX_BYTES}.`);
5081
+ if (buffer.length < length + RELAY_PIPE_FRAME_BYTES) return null;
5082
+ let value;
5083
+ try {
5084
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(RELAY_PIPE_FRAME_BYTES, length + RELAY_PIPE_FRAME_BYTES)));
5085
+ } catch {
5086
+ throw new RelayPipeHandshakeError("pipe_handshake_invalid", "Host Relay pipe handshake frame is not JSON.");
5087
+ }
5088
+ return { value, rest: buffer.subarray(length + RELAY_PIPE_FRAME_BYTES) };
5089
+ }
5090
+ function validNonce(value) {
5091
+ return typeof value === "string" && RELAY_PIPE_NONCE_PATTERN.test(value);
5092
+ }
5093
+ function writePipeFrame(socket, frame) {
5094
+ if (socket.write(frame)) return Promise.resolve();
5095
+ return new Promise((resolve, reject2) => {
5096
+ socket.once("drain", resolve);
5097
+ socket.once("error", reject2);
5098
+ socket.once("close", () => reject2(new RelayPipeHandshakeError("pipe_handshake_invalid", "Host Relay pipe handshake connection closed.")));
5099
+ });
5100
+ }
5101
+ function readPipeFrames() {
5102
+ let buffer = Buffer.alloc(0);
5103
+ let pending = null;
5104
+ const feed = (chunk) => {
5105
+ buffer = Buffer.concat([buffer, chunk]);
5106
+ if (pending === null) return;
5107
+ let frame;
5108
+ try {
5109
+ frame = decodePipeFrame(buffer);
5110
+ } catch (error) {
5111
+ const waiting2 = pending;
5112
+ pending = null;
5113
+ waiting2.reject(error instanceof Error ? error : new RelayPipeHandshakeError("pipe_handshake_invalid", "Host Relay pipe handshake frame is invalid."));
5114
+ return;
5115
+ }
5116
+ if (frame === null) return;
5117
+ buffer = frame.rest;
5118
+ const waiting = pending;
5119
+ pending = null;
5120
+ waiting.resolve({ value: frame.value, rest: Buffer.alloc(0) });
5121
+ };
5122
+ const waiter = {
5123
+ wait: () => new Promise((resolve, reject2) => {
5124
+ let frame;
5125
+ try {
5126
+ frame = decodePipeFrame(buffer);
5127
+ } catch (error) {
5128
+ reject2(error instanceof Error ? error : new RelayPipeHandshakeError("pipe_handshake_invalid", "Host Relay pipe handshake frame is invalid."));
5129
+ return;
4740
5130
  }
4741
- const frames = await this.reserve(envelope);
4742
- let complete = true;
4743
- for (const frame of frames) {
4744
- const outcome = await this.relay.admit(frame);
4745
- if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
4746
- complete = false;
4747
- break;
4748
- }
5131
+ if (frame !== null) {
5132
+ buffer = frame.rest;
5133
+ resolve({ value: frame.value, rest: Buffer.alloc(0) });
5134
+ return;
4749
5135
  }
4750
- if (!complete) {
4751
- retained += 1;
4752
- break;
5136
+ pending = { resolve, reject: reject2 };
5137
+ }),
5138
+ cancel: (error) => {
5139
+ if (pending !== null) {
5140
+ const waiting = pending;
5141
+ pending = null;
5142
+ waiting.reject(error);
4753
5143
  }
4754
- await this.host.removeEnvelope(envelope);
4755
- await this.release(this.host.submissionRefOf(envelope));
4756
- admitted += 1;
4757
5144
  }
4758
- return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
4759
- }
4760
- async hasReservation(submissionRef) {
4761
- return (await this.readState()).pending[submissionRef] !== void 0;
4762
- }
4763
- async reserve(envelope) {
4764
- const state = await this.readState();
4765
- const submissionRef = this.host.submissionRefOf(envelope);
4766
- const existing = state.pending[submissionRef];
4767
- if (existing !== void 0) return existing;
4768
- const drafts = await this.host.mapEnvelope(envelope);
4769
- const frames = drafts.map((draft, offset) => ({
4770
- schema_version: "ceal.host_producer_frame.v1",
4771
- producer_id: this.host.producer_id,
4772
- producer_installation_ref: this.installationRef,
4773
- producer_epoch: this.epoch,
4774
- sequence: state.next_sequence + offset,
4775
- frame_kind: draft.frame_kind,
4776
- occurred_at: this.host.createdAtOf(envelope),
4777
- payload: draft.payload
4778
- }));
4779
- await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
4780
- return frames;
5145
+ };
5146
+ return { waiter, feed, remainder: () => buffer };
5147
+ }
5148
+ function attachHandshakeReader(socket, waiter, feed) {
5149
+ const onData = (chunk) => feed(Buffer.from(chunk));
5150
+ const onError = (error) => waiter.cancel(error);
5151
+ const onClose = () => waiter.cancel(new RelayPipeHandshakeError("pipe_handshake_invalid", "Host Relay pipe handshake connection closed."));
5152
+ socket.on("data", onData);
5153
+ socket.once("error", onError);
5154
+ socket.once("close", onClose);
5155
+ return () => {
5156
+ socket.removeListener("data", onData);
5157
+ socket.removeListener("error", onError);
5158
+ socket.removeListener("close", onClose);
5159
+ };
5160
+ }
5161
+ function handshakeTimeout(timeoutMs) {
5162
+ let timer;
5163
+ const done = new Promise((_resolve, reject2) => {
5164
+ timer = setTimeout(() => reject2(new RelayPipeHandshakeError("pipe_handshake_timeout", `Host Relay pipe handshake stalled past ${timeoutMs} ms; dropping the connection.`)), timeoutMs);
5165
+ timer.unref?.();
5166
+ });
5167
+ return { done, clear: () => clearTimeout(timer) };
5168
+ }
5169
+ async function conductPipeClientHandshake(socket, key, timeoutMs = RELAY_PIPE_HANDSHAKE_TIMEOUT_MS) {
5170
+ const bound = handshakeTimeout(timeoutMs);
5171
+ const { waiter, feed } = readPipeFrames();
5172
+ const detach = attachHandshakeReader(socket, waiter, feed);
5173
+ try {
5174
+ const clientNonce = createPipeClientNonce();
5175
+ await Promise.race([writePipeFrame(socket, encodePipeFrame({ schema_version: RELAY_PIPE_HELLO_SCHEMA, client_nonce: clientNonce })), bound.done]);
5176
+ const challenge = await Promise.race([waiter.wait(), bound.done]);
5177
+ if (!isRecord3(challenge.value) || challenge.value.schema_version !== RELAY_PIPE_CHALLENGE_SCHEMA || !validNonce(challenge.value.server_nonce) || typeof challenge.value.server_proof !== "string") {
5178
+ throw new RelayPipeHandshakeError("pipe_server_unproven", "Host Relay pipe server proof is invalid; aborting before sending any request.");
5179
+ }
5180
+ const serverNonce = challenge.value.server_nonce;
5181
+ const expected = createPipeServerProof(key, clientNonce, serverNonce);
5182
+ if (!timingSafeEqualHex(expected, challenge.value.server_proof)) {
5183
+ throw new RelayPipeHandshakeError("pipe_server_unproven", "Host Relay pipe server proof failed; aborting before sending any request.");
5184
+ }
5185
+ const clientProof = createPipeClientProof(key, serverNonce, clientNonce);
5186
+ await Promise.race([writePipeFrame(socket, encodePipeFrame({ schema_version: RELAY_PIPE_RESPONSE_SCHEMA, client_proof: clientProof })), bound.done]);
5187
+ } finally {
5188
+ bound.clear();
5189
+ detach();
4781
5190
  }
4782
- async release(submissionRef) {
4783
- const state = await this.readState();
4784
- if (state.pending[submissionRef] === void 0) return;
4785
- const pending = { ...state.pending };
4786
- delete pending[submissionRef];
4787
- await this.writeState({ ...state, pending });
5191
+ }
5192
+ function timingSafeEqualHex(left, right) {
5193
+ if (left.length !== right.length) return false;
5194
+ let diff = 0;
5195
+ for (let index = 0; index < left.length; index += 1) diff |= left.charCodeAt(index) ^ right.charCodeAt(index);
5196
+ return diff === 0;
5197
+ }
5198
+ function isRecord3(value) {
5199
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5200
+ }
5201
+ function errorCode2(error) {
5202
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
5203
+ }
5204
+
5205
+ // host/relay/src/relay-ipc.ts
5206
+ var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v2";
5207
+ var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v2";
5208
+ var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
5209
+ var HOST_RELAY_QUERY_RESPONSE_MAX_BYTES = 8192;
5210
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
5211
+ "permission_denied",
5212
+ "socket_missing",
5213
+ "connection_refused",
5214
+ "closed_early",
5215
+ "response_invalid",
5216
+ "timed_out",
5217
+ "cancelled",
5218
+ "unavailable"
5219
+ ]);
5220
+ var HostRelayIpcError = class extends Error {
5221
+ code;
5222
+ /** Set only when the client-side socket exchange itself failed. */
5223
+ failure;
5224
+ constructor(code, message = code, failure2) {
5225
+ super(message);
5226
+ this.code = code;
5227
+ this.failure = failure2;
5228
+ }
5229
+ };
5230
+ function hostRelayExchangeFailure(error) {
5231
+ return error instanceof HostRelayIpcError ? error.failure : void 0;
5232
+ }
5233
+ function socketErrorFailure(error) {
5234
+ switch (errorCode3(error)) {
5235
+ case "EACCES":
5236
+ case "EPERM":
5237
+ return "permission_denied";
5238
+ case "ENOENT":
5239
+ return "socket_missing";
5240
+ case "ECONNREFUSED":
5241
+ return "connection_refused";
5242
+ default:
5243
+ return "unavailable";
5244
+ }
5245
+ }
5246
+ var HostRelayInvocationContextPort = class {
5247
+ endpoint;
5248
+ pipe_key;
5249
+ timeout_ms;
5250
+ constructor(endpoint, pipeKey, timeoutMs = 5e3) {
5251
+ this.endpoint = endpoint;
5252
+ this.pipe_key = pipeKey;
5253
+ this.timeout_ms = timeoutMs;
4788
5254
  }
4789
- async readState() {
4790
- try {
4791
- const value = JSON.parse(await readFile2(this.statePath, "utf8"));
4792
- return this.decodeState(value);
4793
- } catch (error) {
4794
- if (errorCode3(error) !== "ENOENT") throw error;
4795
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
4796
- }
5255
+ mintInvocationContext(input, signal) {
5256
+ return queryHostRelayInvocationContext(this.endpoint, input, this.timeout_ms, signal, this.pipe_key);
4797
5257
  }
4798
- async writeState(state) {
4799
- await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
4800
- const temporary = `${this.statePath}.${process.pid}.new`;
4801
- await writeFile(temporary, JSON.stringify(state), { mode: 384 });
4802
- await rename2(temporary, this.statePath);
4803
- }
4804
- decodeState(value) {
4805
- const label = this.host.producer_label;
4806
- const fail = (code, message) => this.host.fail(code, message);
4807
- if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
4808
- throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
4809
- { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
4810
- { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
4811
- ])}).`);
5258
+ };
5259
+ function queryHostRelayInvocationContext(endpoint, query, timeoutMs, signal, pipeKey) {
5260
+ return exchange(endpoint, encodeInvocationContextQuery(query), timeoutMs, decodeInvocationContextResponseBuffer, signal, pipeKey);
5261
+ }
5262
+ function exchange(endpoint, encoded, timeoutMs, decode, signal, pipeKey) {
5263
+ return new Promise((resolve, reject2) => {
5264
+ const socket = createConnection(endpoint);
5265
+ let buffer = Buffer.alloc(0);
5266
+ let settled = false;
5267
+ const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
5268
+ const finish = (error, response2) => {
5269
+ if (settled) return;
5270
+ settled = true;
5271
+ signal?.removeEventListener("abort", aborted);
5272
+ socket.destroy();
5273
+ if (error !== null) reject2(error);
5274
+ else if (response2 !== void 0) resolve(response2);
5275
+ };
5276
+ if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
5277
+ if (signal?.aborted === true) {
5278
+ aborted();
5279
+ return;
4812
5280
  }
4813
- 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}`)}).`);
4814
- const pending = {};
4815
- const storedEpoch = Number(value.producer_epoch);
4816
- for (const [submissionRef, frames] of Object.entries(value.pending)) {
4817
- if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
4818
- pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
5281
+ signal?.addEventListener("abort", aborted, { once: true });
5282
+ socket.once("error", (error) => {
5283
+ const failure2 = socketErrorFailure(error);
5284
+ finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure2}.`, failure2));
5285
+ });
5286
+ socket.once("connect", () => {
5287
+ void beginExchange();
5288
+ });
5289
+ async function beginExchange() {
5290
+ try {
5291
+ if (process.platform === "win32") {
5292
+ if (pipeKey === void 0) throw new HostRelayIpcError("relay_unavailable", "Host Relay pipe key is unavailable; refusing to send any request.");
5293
+ await conductPipeClientHandshake(socket, pipeKey, RELAY_PIPE_HANDSHAKE_TIMEOUT_MS);
5294
+ }
5295
+ } catch (error) {
5296
+ finish(error instanceof HostRelayIpcError ? error : new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay pipe handshake failed.", "closed_early"));
5297
+ return;
5298
+ }
5299
+ if (settled) return;
5300
+ socket.once("error", (error) => {
5301
+ const failure2 = socketErrorFailure(error);
5302
+ finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure2}.`, failure2));
5303
+ });
5304
+ socket.on("data", (chunk) => {
5305
+ try {
5306
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
5307
+ const decoded = decode(buffer);
5308
+ if (decoded !== null) finish(null, decoded);
5309
+ } catch (error) {
5310
+ finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
5311
+ }
5312
+ });
5313
+ socket.once("end", () => {
5314
+ if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
5315
+ });
5316
+ socket.write(encoded);
4819
5317
  }
4820
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
4821
- }
4822
- decodeStoredFrame(value, storedEpoch) {
4823
- const label = this.host.producer_label;
4824
- const json = Buffer.from(JSON.stringify(value), "utf8");
4825
- const encoded = Buffer.allocUnsafe(json.length + 4);
4826
- encoded.writeUInt32BE(json.length, 0);
4827
- json.copy(encoded, 4);
4828
- const frame = decodeHostProducerFrame(encoded);
4829
- 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([
4830
- { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
4831
- { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
4832
- { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
4833
- ])}).`);
4834
- return frame;
5318
+ });
5319
+ }
5320
+ function record(value) {
5321
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5322
+ }
5323
+ function decodeInvocationContextResponseBuffer(buffer) {
5324
+ const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_QUERY_RESPONSE_MAX_BYTES);
5325
+ if (value === null) return null;
5326
+ if (!validInvocationContextResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay invocation context response is invalid.");
5327
+ return value;
5328
+ }
5329
+ function encodeInvocationContextQuery(query) {
5330
+ const value = { schema_version: HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA, ...query };
5331
+ if (!validInvocationContextQueryRequest(value)) throw new HostRelayIpcError("invalid_frame_shape");
5332
+ return encodeLengthPrefixed(value);
5333
+ }
5334
+ function validInvocationContextQueryRequest(value) {
5335
+ if (!validQueryEnvelope(value)) return false;
5336
+ try {
5337
+ decodeCealHostInvocationContextRequest({
5338
+ schema_version: CEAL_HOST_INVOCATION_CONTEXT_REQUEST_SCHEMA,
5339
+ client_nonce: value.client_nonce,
5340
+ context_expires_at: value.context_expires_at,
5341
+ host_binding: value.host_binding,
5342
+ human_message_window: value.human_message_window,
5343
+ ...value.visible_output_max_bytes === void 0 ? {} : { visible_output_max_bytes: value.visible_output_max_bytes }
5344
+ });
5345
+ return true;
5346
+ } catch {
5347
+ return false;
4835
5348
  }
4836
- };
4837
- function isDrainStateHeader(value, schema, installationRef) {
4838
- 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);
5349
+ }
5350
+ function validQueryEnvelope(value) {
5351
+ if (!validQueryIdentity(value, HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) || !exactKeys2(value, ["schema_version", "producer_id", "producer_installation_ref", "client_nonce", "context_expires_at", "host_binding", "human_message_window"], ["visible_output_max_bytes"])) return false;
5352
+ return typeof value.client_nonce === "string" && CEAL_HOST_CLIENT_NONCE_PATTERN.test(value.client_nonce) && typeof value.context_expires_at === "string" && (value.visible_output_max_bytes === void 0 || validVisibleOutputBudget(value.visible_output_max_bytes));
5353
+ }
5354
+ function validQueryIdentity(value, schema) {
5355
+ return record(value) && value.schema_version === schema && (value.producer_id === "codex" || value.producer_id === "claude") && safeRef(value.producer_installation_ref);
5356
+ }
5357
+ function validVisibleOutputBudget(value) {
5358
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
5359
+ }
5360
+ function validInvocationContextResponse(value) {
5361
+ if (!record(value) || value.schema_version !== HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA) return false;
5362
+ return value.status === "refused" ? validInvocationContextRefusal(value) : validReadyInvocationContext(value);
5363
+ }
5364
+ function validInvocationContextRefusal(value) {
5365
+ return exactKeys2(value, ["schema_version", "status", "reason"]) && isCealHostAuthenticationCause(value.reason) && value.reason !== "no_binding";
5366
+ }
5367
+ function validReadyInvocationContext(value) {
5368
+ if (value.status !== "ready" || !exactKeys2(value, ["schema_version", "status", "request_ref", "result"]) || !safeRef(value.request_ref) || !value.request_ref.startsWith("ceal-request:") || !record(value.result)) return false;
5369
+ const result = value.result;
5370
+ return exactKeys2(result, ["schema_version", "context_token", "expires_at"]) && result.schema_version === CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA && typeof result.context_token === "string" && CEAL_HOST_CONTEXT_TOKEN_PATTERN.test(result.context_token) && typeof result.expires_at === "string" && Number.isFinite(Date.parse(result.expires_at));
5371
+ }
5372
+ function decodeLengthPrefixedJson(input, maximum) {
5373
+ if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
5374
+ const length = input.readUInt32BE(0);
5375
+ 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}`)}.`);
5376
+ if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
5377
+ 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}` }])}.`);
5378
+ try {
5379
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
5380
+ } catch {
5381
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
5382
+ }
5383
+ }
5384
+ function encodeLengthPrefixed(value) {
5385
+ const body = Buffer.from(JSON.stringify(value), "utf8");
5386
+ const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
5387
+ output.writeUInt32BE(body.length, 0);
5388
+ body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
5389
+ return output;
5390
+ }
5391
+ function exactKeys2(value, required, optional = []) {
5392
+ const keys = Object.keys(value);
5393
+ return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
5394
+ }
5395
+ function safeRef(value) {
5396
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
4839
5397
  }
4840
5398
  function errorCode3(error) {
4841
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
5399
+ return record(error) && typeof error.code === "string" ? error.code : null;
4842
5400
  }
4843
5401
 
4844
- // host/relay/src/relay-quarantine-store.ts
4845
- var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
4846
- var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
4847
- var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
5402
+ // host/service-log.ts
5403
+ import { copyFile, mkdir as mkdir2, stat as stat2, truncate, appendFile } from "node:fs/promises";
5404
+ import { dirname as dirname3, isAbsolute as isAbsolute2, posix, win32 as win323 } from "node:path";
5405
+ var HOST_SERVICE_LOG_ENVIRONMENT = "CEAL_HOST_SERVICE_LOG";
5406
+ function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
5407
+ 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 } : {} })}
5408
+ `;
5409
+ try {
5410
+ (sink ?? defaultHostServiceDiagnosticSink)(line);
5411
+ } catch {
5412
+ }
5413
+ }
5414
+ function defaultHostServiceDiagnosticSink(line) {
5415
+ writeHostServiceLogLine(line);
5416
+ process.stderr.write(line);
5417
+ }
5418
+ var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
5419
+ function writeHostServiceLogLine(line, environment = process.env) {
5420
+ if (process.platform !== "win32") return;
5421
+ const path = environment[HOST_SERVICE_LOG_ENVIRONMENT];
5422
+ if (path === void 0 || !win323.isAbsolute(path) || win323.normalize(path) !== path) return;
5423
+ void appendHostServiceLogLine(path, line).catch(() => void 0);
5424
+ }
5425
+ async function appendHostServiceLogLine(path, line) {
5426
+ if (!isAbsolute2(path)) return;
5427
+ await ensureHostServiceLogDirectory(path);
5428
+ await appendFile(path, line);
5429
+ }
5430
+ var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
5431
+ var hostServiceLogDirectories = /* @__PURE__ */ new Map();
5432
+ function ensureHostServiceLogDirectory(path) {
5433
+ const directory = dirname3(path);
5434
+ const existing = hostServiceLogDirectories.get(directory);
5435
+ if (existing !== void 0) return existing;
5436
+ const pending = mkdir2(directory, { recursive: true, mode: 448 }).then(() => void 0).catch((error) => {
5437
+ hostServiceLogDirectories.delete(directory);
5438
+ throw error;
5439
+ });
5440
+ hostServiceLogDirectories.set(directory, pending);
5441
+ return pending;
5442
+ }
4848
5443
 
4849
- // host/relay/src/relay-admission-store.ts
4850
- var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
4851
- var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
4852
- var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
5444
+ // host/local-capability-descriptor.ts
5445
+ var HOST_LOCAL_CAPABILITY_AUTHENTICATION_SUFFIX = Object.freeze(["authenticate", "--client-nonce"]);
4853
5446
 
4854
5447
  // host/invocation-authentication-command.ts
4855
- var HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX = ["authenticate", "--client-nonce"];
4856
- var HOST_AUTHENTICATION_BUDGET_ENVIRONMENT = "CEAL_HOST_AUTHENTICATION_BUDGET_MS";
4857
5448
  var HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS = 2e4;
4858
5449
  var CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS = HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
4859
5450
  var HOST_AUTHENTICATION_COMPLETION_RESERVE_MS = 5e3;
4860
5451
  var INVOCATION_CONTEXT_POLL_INTERVAL_MS = 250;
4861
5452
  var REFUSAL_REASON_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
4862
5453
  function installedHostInvocationAuthenticationCommandOptions(config, contextBudgetMs, maxContextWaitMs) {
4863
- const port = new HostRelayInvocationContextPort(config.relay_endpoint);
5454
+ let pipeKey;
5455
+ const loadPipeKey = () => {
5456
+ if (pipeKey === void 0) pipeKey = process.platform === "win32" ? loadRelayPipeKey(relayPipeStateRootForOutboxDir(config.outbox_dir)) : Promise.resolve(void 0);
5457
+ return pipeKey;
5458
+ };
4864
5459
  return {
4865
5460
  host_source_ref: config.host_source_ref,
4866
5461
  outbox_dir: config.outbox_dir,
4867
5462
  producer_installation_ref: config.producer_installation_ref,
4868
5463
  context_activation_wait_ms: boundedContextActivationWait(contextBudgetMs, config.ipc_timeout_ms, maxContextWaitMs),
4869
- mint_invocation_context: (input) => port.mintInvocationContext({ ...input, producer_id: input.producer_id })
5464
+ mint_invocation_context: async (input) => new HostRelayInvocationContextPort(config.relay_endpoint, await loadPipeKey(), config.ipc_timeout_ms).mintInvocationContext(input)
4870
5465
  };
4871
5466
  }
4872
5467
  async function runHostInvocationAuthenticationCommand(descriptor2, args, options) {
@@ -4887,26 +5482,31 @@ function authenticationRefusalReason(error) {
4887
5482
  return isCealHostAuthenticationCause(message) ? message : "host_refusal_invalid";
4888
5483
  }
4889
5484
  async function authenticateHostInvocation(descriptor2, input, options) {
4890
- if (input.length !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX.length + 1 || input[0] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[0] || input[1] !== HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX[1]) throw new TypeError("invalid_arguments");
5485
+ if (input.length !== HOST_LOCAL_CAPABILITY_AUTHENTICATION_SUFFIX.length + 1 || input[0] !== HOST_LOCAL_CAPABILITY_AUTHENTICATION_SUFFIX[0] || input[1] !== HOST_LOCAL_CAPABILITY_AUTHENTICATION_SUFFIX[1]) throw new TypeError("invalid_arguments");
4891
5486
  const request2 = decodeCealHostInvocationAuthenticationRequest({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: input[2] });
4892
5487
  const config = validateOptions(options);
4893
5488
  const now = config.now ?? (() => /* @__PURE__ */ new Date());
4894
5489
  const { store, current } = await currentInvocation(descriptor2, config, now);
4895
5490
  if (config.mint_invocation_context === void 0) throw new TypeError("relay_failed");
4896
- const query = {
4897
- producer_id: descriptor2.producer_id,
4898
- producer_installation_ref: config.producer_installation_ref,
4899
- local_session_ref: current.identity.host_session_ref,
4900
- local_turn_ref: current.identity.host_turn_ref,
4901
- client_nonce: request2.client_nonce,
4902
- ...await visibleOutputBudget(descriptor2)
4903
- };
5491
+ const query = await invocationMintQuery(descriptor2, store, current, request2.client_nonce, config);
4904
5492
  const response2 = await mintedResult(config.mint_invocation_context, query);
4905
5493
  const completedAt = now();
4906
5494
  const rechecked = await store.readInvocationContext(current.identity.host_source_ref, current.identity.host_session_ref, completedAt);
4907
5495
  if (rechecked === null || !sameTurn(current, rechecked)) throw new TypeError("context_replaced");
4908
5496
  return decodeCealHostInvocationAuthenticationResult(response2.result, completedAt);
4909
5497
  }
5498
+ async function invocationMintQuery(descriptor2, store, current, clientNonce, options) {
5499
+ const readWindow = options.read_human_message_window?.(current.identity) ?? descriptor2.read_human_message_window?.({ store, identity: current.identity }) ?? Promise.resolve({ messages: [], truncated: false });
5500
+ return {
5501
+ producer_id: descriptor2.producer_id,
5502
+ producer_installation_ref: options.producer_installation_ref,
5503
+ client_nonce: clientNonce,
5504
+ context_expires_at: current.expires_at,
5505
+ host_binding: { ...current.identity },
5506
+ human_message_window: await readWindow,
5507
+ ...await visibleOutputBudget(descriptor2)
5508
+ };
5509
+ }
4910
5510
  async function visibleOutputBudget(descriptor2) {
4911
5511
  const bytes = await descriptor2.resolve_visible_output_max_bytes?.();
4912
5512
  return bytes === void 0 ? {} : { visible_output_max_bytes: bytes };
@@ -4916,30 +5516,15 @@ async function mintedResult(mint, query) {
4916
5516
  try {
4917
5517
  response2 = await mint(query);
4918
5518
  } catch (error) {
4919
- throw new TypeError(exchangeFailureCause(hostRelayExchangeFailure(error) ?? "unavailable"));
5519
+ throw new TypeError(cealHostAuthenticationCauseForExchangeFailure(hostRelayExchangeFailure(error) ?? "unavailable"));
4920
5520
  }
4921
- if (response2.status === "refused") throw new TypeError(mintRefusalCause(response2.reason));
4922
- if (response2.status !== "ready") throw new TypeError("no_binding");
5521
+ if (response2.status !== "ready") throw new TypeError(isCealHostAuthenticationCause(response2.reason) && response2.reason !== "no_binding" ? response2.reason : "host_refusal_invalid");
4923
5522
  return response2;
4924
5523
  }
4925
- function mintRefusalCause(reason) {
4926
- if (isDirectMintRefusalCause(reason)) return reason;
4927
- if (reason === "deadline" || reason === "cancelled") return "transient_retryable";
4928
- if (reason === "mint_failed" || reason === "relay_failed") return reason;
4929
- return isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, reason) ? "context_stale" : "host_refusal_invalid";
4930
- }
4931
- function isDirectMintRefusalCause(reason) {
4932
- return isVocabularyWord(HOST_RELAY_DIRECT_WIRE_MINT_REASONS, reason);
4933
- }
4934
- function exchangeFailureCause(failure2) {
4935
- if (failure2 === "permission_denied") return "relay_permission_denied";
4936
- if (failure2 === "timed_out") return "transient_retryable";
4937
- return "relay_unavailable";
4938
- }
4939
5524
  async function currentInvocation(descriptor2, config, now) {
4940
5525
  const store = descriptor2.create_store(config.outbox_dir);
4941
5526
  const identity = resolveIdentity(descriptor2, config);
4942
- if (identity.status !== "ready") throw new TypeError(identity.status);
5527
+ if (identity.status === "session_unavailable") throw new TypeError("no_binding");
4943
5528
  const waitBudgetMs = config.context_activation_wait_ms ?? 0;
4944
5529
  const monotonicNow = config.monotonic_now ?? (() => performance.now());
4945
5530
  const deadline = monotonicNow() + waitBudgetMs;
@@ -5003,9 +5588,9 @@ async function resolveOptions(descriptor2, args, options) {
5003
5588
  };
5004
5589
  }
5005
5590
  function authenticationBudgetMsFromEnvironment() {
5006
- const value = process.env[HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
5591
+ const value = process.env[CEAL_HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
5007
5592
  if (value === void 0) return 0;
5008
- if (!/^(?:0|[1-9][0-9]{0,8})$/u.test(value)) throw new TypeError("invalid_arguments");
5593
+ if (!CEAL_HOST_AUTHENTICATION_BUDGET_PATTERN.test(value)) throw new TypeError("invalid_arguments");
5009
5594
  return Number(value);
5010
5595
  }
5011
5596
  function boundedContextActivationWait(contextBudgetMs, relayTimeoutMs, maxContextWaitMs) {
@@ -5042,16 +5627,16 @@ function writeResult(value, sink) {
5042
5627
  }
5043
5628
 
5044
5629
  // host/producer-service.ts
5045
- import { posix as posix3, win32 as win323 } from "node:path";
5630
+ import { posix as posix4, win32 as win326 } from "node:path";
5046
5631
 
5047
5632
  // host/runtime-source-paths.ts
5048
- import { createHash as createHash4 } from "node:crypto";
5049
- import { posix as posix2, win32 as win322 } from "node:path";
5633
+ import { createHash as createHash5 } from "node:crypto";
5634
+ import { posix as posix3, win32 as win325 } from "node:path";
5050
5635
 
5051
5636
  // host/absolute-path.ts
5052
- import { posix, win32 } from "node:path";
5637
+ import { posix as posix2, win32 as win324 } from "node:path";
5053
5638
  function isAbsoluteNormalizedNonRootPath(value, flavor = process.platform, allowRoot = false) {
5054
- const pathApi = flavor === "win32" || flavor === "windows" ? win32 : posix;
5639
+ const pathApi = flavor === "win32" || flavor === "windows" ? win324 : posix2;
5055
5640
  return typeof value === "string" && value.length <= 4096 && !value.includes("\0") && pathApi.isAbsolute(value) && pathApi.normalize(value) === value && (allowRoot || pathApi.parse(value).root !== value);
5056
5641
  }
5057
5642
 
@@ -5063,28 +5648,23 @@ function hostSourceUuid(sourceRef) {
5063
5648
  function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platform) {
5064
5649
  const sourceId = hostSourceUuid(sourceRef);
5065
5650
  if (!isAbsoluteNormalizedNonRootPath(stateRoot, platform) || sourceId === null) throw new TypeError("Host runtime source identity is invalid.");
5066
- const path = platform === "win32" ? win322 : posix2;
5651
+ const path = platform === "win32" ? win325 : posix3;
5067
5652
  const sourcesRoot = path.join(stateRoot, "sources");
5068
5653
  const sourceRoot = path.join(sourcesRoot, sourceId);
5069
5654
  const runtimeRoot = path.join(stateRoot, "run");
5070
- const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash4("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
5071
- assertHostRuntimeIpcLength(endpoint, platform);
5655
+ const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash5("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
5072
5656
  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 };
5073
5657
  }
5074
- function assertHostRuntimeIpcLength(endpoint, platform) {
5075
- if (platform === "win32") return;
5076
- const maximum = platform === "linux" ? 107 : 103;
5077
- 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" });
5078
- }
5079
5658
  function assertHostProducerSourcePaths(stateRoot, config, producer, platform = process.platform) {
5080
5659
  const paths = hostRuntimeSourcePaths(stateRoot, config.host_source_ref, platform);
5081
- 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.");
5660
+ 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.");
5661
+ return paths.endpoint;
5082
5662
  }
5083
5663
 
5084
5664
  // host/producer-service.ts
5085
- import { constants } from "node:fs";
5086
- import { lstat as lstat2, open as open4 } from "node:fs/promises";
5087
- var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5665
+ import { constants as constants3 } from "node:fs";
5666
+ import { lstat as lstat3 } from "node:fs/promises";
5667
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5088
5668
  var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
5089
5669
  var HostProducerServiceError = class extends Error {
5090
5670
  code;
@@ -5095,18 +5675,19 @@ var HostProducerServiceError = class extends Error {
5095
5675
  }
5096
5676
  };
5097
5677
  var HOST_PRODUCER_CONFIG_KEYS = ["schema_version", "host_source_ref", "producer_installation_ref", "producer_epoch", "outbox_dir", "relay_endpoint"];
5678
+ var HOST_PRODUCER_CONFIG_ENDPOINT_KEY = "relay_endpoint";
5098
5679
  var HOST_PRODUCER_TIMING_DEFAULTS = Object.freeze({ reconcile_interval_ms: 250, retry_backoff_ms: 1e3, ipc_timeout_ms: 5e3 });
5099
5680
  function hostProducerExtraPath(extras, key) {
5100
5681
  const value = extras[key];
5101
- if (value === void 0) throw hostProducerError("invalid_config");
5682
+ if (value === void 0) throw hostProducerError("invalid_config", refusalFact(key, "missing", "an absolute path"));
5102
5683
  return value;
5103
5684
  }
5104
5685
  function parseHostProducerConfigFlag(args, platform = process.platform) {
5105
5686
  return parseProducerHostConfigFlag(args, HOST_PRODUCER_CONFIG_FLAG, platform, hostProducerError);
5106
5687
  }
5107
- async function readHostProducerConfig(descriptor2, configPath, platform = process.platform) {
5108
- const config = decodeHostProducerConfigText(descriptor2, await readProducerConfigText(configPath, platform, hostProducerError), platform);
5109
- const path = platform === "win32" ? win323 : posix3;
5688
+ async function readHostProducerConfig(descriptor2, configPath, platform = process.platform, custody = {}) {
5689
+ const config = decodeHostProducerConfigText(descriptor2, await readProducerConfigText(configPath, platform, hostProducerError, custody), platform);
5690
+ const path = platform === "win32" ? win326 : posix4;
5110
5691
  const root = path.resolve(config.outbox_dir, "../../../../..");
5111
5692
  try {
5112
5693
  assertHostProducerSourcePaths(root, config, descriptor2.producer_id, platform);
@@ -5132,15 +5713,31 @@ function parseProducerHostConfigFlag(args, flag, platform, error) {
5132
5713
  assertProducerAbsolutePath(value, platform, "config", error);
5133
5714
  return value;
5134
5715
  }
5135
- async function readProducerConfigText(configPath, platform, error) {
5136
- assertProducerAbsolutePath(configPath, platform, "config", error);
5716
+ async function readProducerConfigText(configPath, platform, error, custody) {
5717
+ assertProducerAbsolutePath(configPath, process.platform, "config", error);
5718
+ if (platform === "win32") {
5719
+ let bytes;
5720
+ try {
5721
+ bytes = await readPrivateFileWithSecurefs(configPath, CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES, custody);
5722
+ } catch (cause) {
5723
+ if (cause instanceof SecureFileCustodyError && cause.reason === "not_private") throw error("config_not_private");
5724
+ 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}`));
5725
+ if (cause instanceof SecureFileCustodyError && cause.reason === "reparse_point") throw error("invalid_config");
5726
+ throw error("config_unavailable");
5727
+ }
5728
+ if (bytes.byteLength === 0) throw error("invalid_config", refusalFact("config_bytes", 0, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
5729
+ try {
5730
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
5731
+ } catch {
5732
+ throw error("invalid_config");
5733
+ }
5734
+ }
5137
5735
  const pathStat = await configPathStat(configPath, error);
5138
5736
  validateConfigFile(pathStat, platform, error);
5139
- const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
5140
- const handle = await openConfigFile(configPath, constants.O_RDONLY | noFollow, error);
5737
+ const handle = await openConfigFile(configPath, platform, error, custody);
5141
5738
  try {
5142
5739
  const opened = await handle.stat();
5143
- validateConfigFile(opened, platform, error);
5740
+ validateConfigFile(opened, platform, error, handle);
5144
5741
  validateOpenedFile(opened, pathStat, platform, error);
5145
5742
  return await readBoundedConfig(handle, opened.size, error);
5146
5743
  } finally {
@@ -5148,8 +5745,9 @@ async function readProducerConfigText(configPath, platform, error) {
5148
5745
  }
5149
5746
  }
5150
5747
  function decodeProducerConfigCore(text, options) {
5748
+ const ownership = producerConfigKeyOwnership(options.keys, options.platform);
5151
5749
  const value = parseCanonicalJson(text, options.error);
5152
- if (!isRecord2(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
5750
+ if (!isRecord4(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 })));
5153
5751
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
5154
5752
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
5155
5753
  const producerEpoch = validateIdentity(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -5167,14 +5765,21 @@ function decodeProducerConfigCore(text, options) {
5167
5765
  producer_installation_ref: installationRef,
5168
5766
  producer_epoch: producerEpoch,
5169
5767
  outbox_dir: value.outbox_dir,
5170
- relay_endpoint: value.relay_endpoint,
5768
+ relay_endpoint: producerConfigEndpoint(value),
5171
5769
  reconcile_interval_ms: intervals[0],
5172
5770
  retry_backoff_ms: intervals[1],
5173
5771
  ipc_timeout_ms: intervals[2]
5174
5772
  };
5175
5773
  }
5774
+ function producerConfigKeyOwnership(keys, platform) {
5775
+ if (platform !== "win32") return { required: keys, tolerated: [] };
5776
+ return { required: keys.filter((key) => key !== HOST_PRODUCER_CONFIG_ENDPOINT_KEY), tolerated: [HOST_PRODUCER_CONFIG_ENDPOINT_KEY] };
5777
+ }
5778
+ function producerConfigEndpoint(value) {
5779
+ return typeof value.relay_endpoint === "string" ? value.relay_endpoint : "";
5780
+ }
5176
5781
  function assertProducerRelayEndpoint(value, platform, error) {
5177
- if (platform === "win32" && typeof value === "string" && /^\\\\\.\\pipe\\[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)) return;
5782
+ if (platform === "win32") return;
5178
5783
  assertProducerAbsolutePath(value, platform, "runtime", error);
5179
5784
  }
5180
5785
  function assertProducerAbsolutePath(value, platform, kind, error) {
@@ -5182,26 +5787,27 @@ function assertProducerAbsolutePath(value, platform, kind, error) {
5182
5787
  }
5183
5788
  async function configPathStat(configPath, error) {
5184
5789
  try {
5185
- return await lstat2(configPath);
5790
+ return await lstat3(configPath);
5186
5791
  } catch {
5187
5792
  throw error("config_unavailable");
5188
5793
  }
5189
5794
  }
5190
- function validateConfigFile(value, platform, error) {
5795
+ function validateConfigFile(value, platform, error, handle) {
5191
5796
  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" }]));
5192
5797
  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}`));
5193
- 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" }]));
5798
+ 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" }]));
5194
5799
  }
5195
- async function openConfigFile(configPath, flags, error) {
5800
+ async function openConfigFile(configPath, platform, error, custody) {
5196
5801
  try {
5197
- return await open4(configPath, flags);
5198
- } catch {
5802
+ return await openNoFollow(configPath, constants3.O_RDONLY, void 0, platform, custody);
5803
+ } catch (error_) {
5804
+ if (error_ instanceof SecureFileCustodyError) throw error(error_.reason === "not_private" ? "config_not_private" : "invalid_config");
5199
5805
  throw error("config_unavailable");
5200
5806
  }
5201
5807
  }
5202
5808
  function validateOpenedFile(opened, pathStat, platform, error) {
5203
5809
  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" }]));
5204
- 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) }]));
5810
+ 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) }]));
5205
5811
  }
5206
5812
  async function readBoundedConfig(handle, expectedBytes, error) {
5207
5813
  const buffer = Buffer.allocUnsafe(expectedBytes + 1);
@@ -5233,34 +5839,58 @@ function firstDifferenceIndex(left, right) {
5233
5839
  for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
5234
5840
  return shared;
5235
5841
  }
5842
+ function producerShapeFacts(value, options) {
5843
+ if (!isRecord4(value)) return [{ name: "config", value: "wrong_type", expected: "a record" }];
5844
+ const tolerated = options.tolerated ?? [];
5845
+ const allowed = [...options.keys, ...tolerated, ...Object.keys(HOST_PRODUCER_TIMING_DEFAULTS)];
5846
+ const facts = [
5847
+ ...Object.keys(value).filter((key) => !allowed.includes(key)).map((key) => ({ name: key, value: "unknown", expected: `one of ${[...options.keys, ...tolerated].join(", ")}` })),
5848
+ ...options.keys.filter((key) => !Object.hasOwn(value, key)).map((key) => ({ name: key, value: "missing", expected: "present" }))
5849
+ ];
5850
+ if (Object.hasOwn(value, "schema_version") && value.schema_version !== options.schema) facts.push({ name: "schema_version", value: "wrong_type", expected: options.schema });
5851
+ return facts;
5852
+ }
5236
5853
  function validateIdentity(sourceRef, installationRef, epoch, error) {
5237
- if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(installationRef) || !positive2(epoch, 2147483647)) throw error("invalid_config");
5854
+ if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(installationRef) || !positive(epoch, 2147483647)) throw error("invalid_config", refusalFacts(producerIdentityFacts(sourceRef, installationRef, epoch)));
5238
5855
  return epoch;
5239
5856
  }
5857
+ function producerIdentityFacts(sourceRef, installationRef, epoch) {
5858
+ const facts = [];
5859
+ if (!SAFE_REF3.test(sourceRef)) facts.push({ name: "host_source_ref", value: "wrong_type", expected: "a safe reference" });
5860
+ if (!SAFE_REF3.test(installationRef)) facts.push({ name: "producer_installation_ref", value: "wrong_type", expected: "a safe reference" });
5861
+ if (!positive(epoch, 2147483647)) facts.push({ name: "producer_epoch", value: "wrong_type", expected: "a positive integer" });
5862
+ return facts;
5863
+ }
5240
5864
  function validateIntervals(reconcile, retry, timeout, error) {
5241
- if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
5865
+ if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config", refusalFacts(producerIntervalFacts(reconcile, retry, timeout)));
5242
5866
  return [reconcile, retry, timeout];
5243
5867
  }
5244
- function hasConfigKeys(value, required) {
5245
- return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
5868
+ function producerIntervalFacts(reconcile, retry, timeout) {
5869
+ const facts = [];
5870
+ if (!boundedMilliseconds(reconcile)) facts.push({ name: "reconcile_interval_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
5871
+ if (!boundedMilliseconds(retry)) facts.push({ name: "retry_backoff_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
5872
+ if (!boundedMilliseconds(timeout)) facts.push({ name: "ipc_timeout_ms", value: "wrong_type", expected: "25..60000 milliseconds" });
5873
+ return facts;
5246
5874
  }
5247
- function isRecord2(value) {
5875
+ function hasConfigKeys(value, required, tolerated = []) {
5876
+ 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));
5877
+ }
5878
+ function isRecord4(value) {
5248
5879
  return value !== null && typeof value === "object" && !Array.isArray(value);
5249
5880
  }
5250
- function positive2(value, maximum) {
5881
+ function positive(value, maximum) {
5251
5882
  return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
5252
5883
  }
5253
5884
  function boundedMilliseconds(value) {
5254
- return positive2(value, 6e4) && Number(value) >= 25;
5885
+ return positive(value, 6e4) && Number(value) >= 25;
5255
5886
  }
5256
5887
 
5257
5888
  // host/codex/src/codex-decoder.ts
5258
- import { createHash as createHash5 } from "node:crypto";
5889
+ import { createHash as createHash6 } from "node:crypto";
5259
5890
 
5260
5891
  // host/codex/src/codex-types.ts
5261
5892
  var CODEX_THREAD_ID_ENVIRONMENT = "CODEX_THREAD_ID";
5262
5893
  var CODEX_OUTBOX_SCHEMA_VERSION = "ceal.codex_observation_outbox.v1";
5263
- var CODEX_TURN_BINDING_SCHEMA_VERSION = "ceal.codex_turn_binding.v1";
5264
5894
  var CODEX_SESSION_SCHEMA_VERSION = "ceal.codex_session.v1";
5265
5895
  var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1";
5266
5896
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
@@ -5276,20 +5906,20 @@ var CodexHostAdapterError = class extends Error {
5276
5906
  };
5277
5907
 
5278
5908
  // host/codex/src/codex-decoder.ts
5279
- var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5909
+ var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5280
5910
  var MAX_PAYLOAD_BYTES = 512 * 1024;
5281
- function observationRef(event, identity, value) {
5282
- return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
5911
+ function observationRef(hostSourceRef, event, identity, value) {
5912
+ return cealHostObservationRef("codex", shortDigest({ host_source_ref: hostSourceRef, event, identity, value }));
5283
5913
  }
5284
5914
  function hostSessionReference(sourceRef, sessionId) {
5285
5915
  return `codex-session:${shortDigest({ source_ref: sourceRef, session_id: sessionId })}`;
5286
5916
  }
5287
5917
  function hostTurnReference(sourceRef, sessionRef, nativeTurnId) {
5288
- if (![sourceRef, sessionRef, nativeTurnId].every((value) => SAFE_REF5.test(value))) throw new CodexHostAdapterError("invalid_input", "Codex turn identity is invalid.");
5918
+ if (![sourceRef, sessionRef, nativeTurnId].every((value) => SAFE_REF4.test(value))) throw new CodexHostAdapterError("invalid_input", "Codex turn identity is invalid.");
5289
5919
  return `codex-turn:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId })}`;
5290
5920
  }
5291
5921
  function hostInputReference(sourceRef, sessionRef, nativeTurnId, messageId, ordinal, prompt) {
5292
- if (![sourceRef, sessionRef, nativeTurnId, messageId].every((value) => SAFE_REF5.test(value)) || !Number.isSafeInteger(ordinal) || ordinal < 0) {
5922
+ if (![sourceRef, sessionRef, nativeTurnId, messageId].every((value) => SAFE_REF4.test(value)) || !Number.isSafeInteger(ordinal) || ordinal < 0) {
5293
5923
  throw new CodexHostAdapterError("invalid_input", "Codex input identity is invalid.");
5294
5924
  }
5295
5925
  return `codex-input:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId, message_id: messageId, ordinal, prompt_sha256: sha256(prompt) })}`;
@@ -5301,25 +5931,24 @@ function turnObservationValue(sessionId, turnRef, status) {
5301
5931
  return { status, host_session_id_sha256: sha256(sessionId), host_turn_ref: turnRef };
5302
5932
  }
5303
5933
  function sha256(value) {
5304
- return createHash5("sha256").update(value, "utf8").digest("hex");
5934
+ return createHash6("sha256").update(value, "utf8").digest("hex");
5305
5935
  }
5306
5936
  function shortDigest(value) {
5307
5937
  return cealRequestSha256(value);
5308
5938
  }
5309
5939
 
5310
5940
  // host/codex/src/codex-outbox.ts
5311
- import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
5312
- import { lstat as lstat3, mkdir as mkdir3, open as open5, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
5313
- import { dirname, isAbsolute as isAbsolute2, join as join4 } from "node:path";
5941
+ import { mkdir as mkdir3, open as open4, readdir, rename as rename2, stat as stat3, unlink as unlink3 } from "node:fs/promises";
5942
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join4 } from "node:path";
5314
5943
 
5315
5944
  // host/invocation-context.ts
5316
- var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
5945
+ var HOST_INVOCATION_TURN_SELECTION_SCHEMA = "ceal.host_invocation_turn_selection.v1";
5317
5946
  var HOST_INVOCATION_CONTEXT_REQUIRED_KEYS = ["schema_version", "identity", "prompt_ref", "expires_at"];
5318
5947
  function invocationContextKey(identity) {
5319
5948
  return cealRequestSha256({ host_source_ref: identity.host_source_ref, host_session_ref: identity.host_session_ref });
5320
5949
  }
5321
5950
  function hasHostInvocationIdentityKeys(value) {
5322
- return exactKeys4(value, HOST_INVOCATION_IDENTITY_KEYS);
5951
+ return exactKeys3(value, CEAL_HOST_INVOCATION_IDENTITY_KEYS);
5323
5952
  }
5324
5953
  function hasHostInvocationContextKeys(value, optional = []) {
5325
5954
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
@@ -5345,12 +5974,9 @@ function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor2)
5345
5974
  return Object.freeze(context);
5346
5975
  }
5347
5976
  function isHostInvocationTurnSelection(value) {
5348
- return isRecord3(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) => safeRef3(value[key]));
5977
+ return isRecord5(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) => safeRef2(value[key]));
5349
5978
  }
5350
- function invocationTurnSelectionMatches(context, selection) {
5351
- 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;
5352
- }
5353
- function exactKeys4(value, keys) {
5979
+ function exactKeys3(value, keys) {
5354
5980
  const actual = Object.keys(value);
5355
5981
  return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
5356
5982
  }
@@ -5359,10 +5985,10 @@ function requiredKeys(value, required, optional) {
5359
5985
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
5360
5986
  return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
5361
5987
  }
5362
- function isRecord3(value) {
5988
+ function isRecord5(value) {
5363
5989
  return value !== null && typeof value === "object" && !Array.isArray(value);
5364
5990
  }
5365
- function safeRef3(value) {
5991
+ function safeRef2(value) {
5366
5992
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
5367
5993
  }
5368
5994
 
@@ -5378,59 +6004,40 @@ function validateCodexHostInvocationContext(value) {
5378
6004
  validateContextReferences(value);
5379
6005
  validateContextTimes(value);
5380
6006
  }
5381
- function invocationContextFromBinding(binding, turnGenerationRef) {
5382
- const context = {
5383
- schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
5384
- identity: binding.identity,
5385
- prompt_ref: binding.prompt_ref,
5386
- request_ref: binding.request_ref,
5387
- bound_at: binding.bound_at,
5388
- expires_at: binding.expires_at,
5389
- ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
5390
- };
5391
- validateCodexHostInvocationContext(context);
5392
- return Object.freeze(context);
5393
- }
5394
6007
  function validateIdentity2(value) {
5395
- if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef4)) {
6008
+ if (!isRecord6(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
5396
6009
  throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
5397
6010
  }
5398
6011
  }
5399
6012
  function isContextShape(value) {
5400
- return isRecord4(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
6013
+ return isRecord6(value) && hasHostInvocationContextKeys(value, ["turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
5401
6014
  }
5402
6015
  function validateContextReferences(value) {
5403
- if (!safeRef4(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
6016
+ if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
5404
6017
  }
5405
6018
  function validateContextTimes(value) {
5406
6019
  const expiresAt = value.expires_at;
5407
- const boundAt = value.bound_at;
5408
- if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
5409
- 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}`)}).`);
6020
+ if (!timestamp(expiresAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
5410
6021
  }
5411
6022
  function optionalSafeRef(value) {
5412
- return value === void 0 || safeRef4(value);
5413
- }
5414
- function optionalTimestamp(value) {
5415
- return value === void 0 || timestamp2(value);
6023
+ return value === void 0 || safeRef3(value);
5416
6024
  }
5417
- function safeRef4(value) {
6025
+ function safeRef3(value) {
5418
6026
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
5419
6027
  }
5420
- function timestamp2(value) {
6028
+ function timestamp(value) {
5421
6029
  return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
5422
6030
  }
5423
- function isRecord4(value) {
6031
+ function isRecord6(value) {
5424
6032
  return value !== null && typeof value === "object" && !Array.isArray(value);
5425
6033
  }
5426
6034
 
5427
6035
  // host/codex/src/codex-outbox.ts
5428
- var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
6036
+ var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5429
6037
  var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
5430
6038
  var CodexOutboxStore = class {
5431
6039
  directory;
5432
6040
  entriesDirectory;
5433
- bindingsDirectory;
5434
6041
  sessionsDirectory;
5435
6042
  activeContextsDirectory;
5436
6043
  turnSelectionsDirectory;
@@ -5440,7 +6047,6 @@ var CodexOutboxStore = class {
5440
6047
  if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
5441
6048
  this.directory = directory;
5442
6049
  this.entriesDirectory = join4(directory, "entries");
5443
- this.bindingsDirectory = join4(directory, "bindings");
5444
6050
  this.sessionsDirectory = join4(directory, "sessions");
5445
6051
  this.activeContextsDirectory = join4(directory, "active-contexts");
5446
6052
  this.turnSelectionsDirectory = join4(directory, "turn-selections");
@@ -5448,8 +6054,8 @@ var CodexOutboxStore = class {
5448
6054
  this.cursorsDirectory = join4(directory, "transcript-cursors");
5449
6055
  }
5450
6056
  async prepare() {
5451
- for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
5452
- await ensurePrivateOwnerDirectory(path);
6057
+ for (const path of [this.directory, this.entriesDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
6058
+ await ensureOwnerDirectory(path);
5453
6059
  }
5454
6060
  }
5455
6061
  async put(entry) {
@@ -5464,7 +6070,7 @@ var CodexOutboxStore = class {
5464
6070
  for (const name of await readdir(this.entriesDirectory)) {
5465
6071
  if (!name.endsWith(".json")) continue;
5466
6072
  try {
5467
- const value = JSON.parse(await readPrivateFile(join4(this.entriesDirectory, name)));
6073
+ const value = JSON.parse(await readOwnerStateFile(join4(this.entriesDirectory, name)));
5468
6074
  validateEnvelope(value);
5469
6075
  entries.push(value);
5470
6076
  } catch {
@@ -5477,16 +6083,11 @@ var CodexOutboxStore = class {
5477
6083
  async remove(entry) {
5478
6084
  validateEnvelope(entry);
5479
6085
  try {
5480
- await unlink2(this.entryPath(entry.submission_ref));
6086
+ await unlink3(this.entryPath(entry.submission_ref));
5481
6087
  } catch (error) {
5482
6088
  if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
5483
6089
  }
5484
6090
  }
5485
- async writeBinding(binding) {
5486
- validateBinding(binding);
5487
- await this.prepare();
5488
- await writeAtomicJson(this.bindingPath(binding.identity), binding);
5489
- }
5490
6091
  /**
5491
6092
  * Select the exact Host turn that model-reachable commands may use. A new
5492
6093
  * prompt replaces this projection, so it cannot inherit the prior turn's
@@ -5500,7 +6101,7 @@ var CodexOutboxStore = class {
5500
6101
  await writeAtomicJson(path, context);
5501
6102
  } catch (error) {
5502
6103
  try {
5503
- await unlink2(path);
6104
+ await unlink3(path);
5504
6105
  } catch (unlinkError) {
5505
6106
  if (!isNotFound(unlinkError)) throw storageError("Unable to clear a failed Codex Host context replacement.");
5506
6107
  }
@@ -5513,7 +6114,7 @@ var CodexOutboxStore = class {
5513
6114
  await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
5514
6115
  }
5515
6116
  async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
5516
- if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
6117
+ if (!SAFE_REF5.test(hostSourceRef) || !SAFE_REF5.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
5517
6118
  await this.prepare();
5518
6119
  return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
5519
6120
  }
@@ -5526,23 +6127,11 @@ var CodexOutboxStore = class {
5526
6127
  await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
5527
6128
  return true;
5528
6129
  }
5529
- /**
5530
- * Publish a Request reference only while the acknowledged binding is still
5531
- * the active turn. A delayed relay response therefore cannot overwrite a
5532
- * newer prompt's context.
5533
- */
5534
- async bindInvocationContext(binding, now = /* @__PURE__ */ new Date()) {
5535
- validateBinding(binding);
5536
- const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
5537
- if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
5538
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
5539
- return true;
5540
- }
5541
6130
  /** Return only the live session projection; never fall back to another turn. */
5542
6131
  async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
5543
6132
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
5544
6133
  const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
5545
- return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
6134
+ return isLiveSessionProjection(context, now) ? context : null;
5546
6135
  }
5547
6136
  /**
5548
6137
  * The latest Codex session projection even when past expiry, so the
@@ -5550,10 +6139,10 @@ var CodexOutboxStore = class {
5550
6139
  * a missing one. Every other caller keeps the fail-closed read above.
5551
6140
  */
5552
6141
  async readRawInvocationContext(hostSourceRef, hostSessionRef) {
5553
- if (!SAFE_REF6.test(hostSourceRef) || !SAFE_REF6.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
6142
+ if (!SAFE_REF5.test(hostSourceRef) || !SAFE_REF5.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
5554
6143
  await this.prepare();
5555
6144
  const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
5556
- return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
6145
+ return context;
5557
6146
  }
5558
6147
  /** Clear the projection only if the caller still owns its exact active turn. */
5559
6148
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -5561,17 +6150,12 @@ var CodexOutboxStore = class {
5561
6150
  const active = await this.readInvocationContext(identity.host_source_ref, identity.host_session_ref, now);
5562
6151
  if (active === null || !sameIdentity(active.identity, identity)) return false;
5563
6152
  try {
5564
- await unlink2(this.activeContextPath(identity));
6153
+ await unlink3(this.activeContextPath(identity));
5565
6154
  } catch (error) {
5566
6155
  if (!isNotFound(error)) throw storageError("Unable to clear the Codex Host invocation context.");
5567
6156
  }
5568
6157
  return true;
5569
6158
  }
5570
- async readBinding(identity) {
5571
- validateIdentity3(identity);
5572
- await this.prepare();
5573
- return readOptionalJson(this.bindingPath(identity), validateBinding);
5574
- }
5575
6159
  async saveSession(snapshot) {
5576
6160
  validateSession(snapshot);
5577
6161
  await this.prepare();
@@ -5579,7 +6163,7 @@ var CodexOutboxStore = class {
5579
6163
  }
5580
6164
  async readSession(sourceRef, sessionRef) {
5581
6165
  const identity = { host_source_ref: sourceRef, host_session_ref: sessionRef };
5582
- if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
6166
+ if (!SAFE_REF5.test(sourceRef) || !SAFE_REF5.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
5583
6167
  await this.prepare();
5584
6168
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
5585
6169
  }
@@ -5612,7 +6196,7 @@ var CodexOutboxStore = class {
5612
6196
  for (const name of await readdir(this.registrationsDirectory)) {
5613
6197
  if (!name.endsWith(".json")) continue;
5614
6198
  try {
5615
- const value = JSON.parse(await readPrivateFile(join4(this.registrationsDirectory, name)));
6199
+ const value = JSON.parse(await readOwnerStateFile(join4(this.registrationsDirectory, name)));
5616
6200
  validateRegistration(value);
5617
6201
  registrations.push(value);
5618
6202
  } catch {
@@ -5631,34 +6215,23 @@ var CodexOutboxStore = class {
5631
6215
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
5632
6216
  }
5633
6217
  async findByAlias(sourceRef, sessionRef, alias) {
5634
- if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(sessionRef) || !SAFE_REF6.test(alias)) return null;
6218
+ if (!SAFE_REF5.test(sourceRef) || !SAFE_REF5.test(sessionRef) || !SAFE_REF5.test(alias)) return null;
5635
6219
  const read = await this.list();
5636
6220
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
5637
6221
  if (envelope !== null) return envelopeMatch(envelope);
5638
6222
  await this.prepare();
5639
- const binding = await findBindingByAlias(this.bindingsDirectory, sourceRef, sessionRef, alias);
5640
- if (binding !== null) return bindingMatch(binding);
5641
6223
  return null;
5642
6224
  }
5643
6225
  async hasPriorTurn(sourceRef, sessionRef) {
5644
- if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(sessionRef)) return false;
6226
+ if (!SAFE_REF5.test(sourceRef) || !SAFE_REF5.test(sessionRef)) return false;
5645
6227
  const read = await this.list();
5646
6228
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
5647
- await this.prepare();
5648
- for (const name of await readdir(this.bindingsDirectory)) {
5649
- if (!name.endsWith(".json")) continue;
5650
- const binding = await readBindingCandidate(this.bindingsDirectory, name);
5651
- if (binding?.identity.host_source_ref === sourceRef && binding.identity.host_session_ref === sessionRef) return true;
5652
- }
5653
6229
  return false;
5654
6230
  }
5655
6231
  entryPath(submissionRef) {
5656
- if (!SAFE_REF6.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
6232
+ if (!SAFE_REF5.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
5657
6233
  return join4(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
5658
6234
  }
5659
- bindingPath(identity) {
5660
- return join4(this.bindingsDirectory, `${identityKey(identity)}.json`);
5661
- }
5662
6235
  sessionPath(sourceRef, sessionRef) {
5663
6236
  return join4(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
5664
6237
  }
@@ -5677,20 +6250,17 @@ var CodexOutboxStore = class {
5677
6250
  };
5678
6251
  async function removeOwnerState(path, what) {
5679
6252
  try {
5680
- await unlink2(path);
6253
+ await unlink3(path);
5681
6254
  } catch (error) {
5682
6255
  if (!isNotFound(error)) throw storageError(`Unable to retire the Codex transcript ${what}.`);
5683
6256
  }
5684
6257
  }
5685
6258
  function sessionStateKey(sourceRef, sessionRef) {
5686
- if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
6259
+ if (!SAFE_REF5.test(sourceRef) || !SAFE_REF5.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
5687
6260
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
5688
6261
  }
5689
6262
  function envelopeMatch(envelope) {
5690
- return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, ...envelope.request_ref === void 0 ? {} : { request_ref: envelope.request_ref }, envelope };
5691
- }
5692
- function bindingMatch(binding) {
5693
- return { identity: binding.identity, prompt_ref: binding.prompt_ref, request_ref: binding.request_ref, binding };
6263
+ return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, envelope };
5694
6264
  }
5695
6265
  function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
5696
6266
  for (const envelope of entries) {
@@ -5699,24 +6269,6 @@ function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
5699
6269
  }
5700
6270
  return null;
5701
6271
  }
5702
- async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
5703
- for (const name of await readdir(directory)) {
5704
- if (!name.endsWith(".json")) continue;
5705
- const binding = await readBindingCandidate(directory, name);
5706
- if (binding === null || binding.identity.host_source_ref !== sourceRef || binding.identity.host_session_ref !== sessionRef) continue;
5707
- if (binding.codex_turn_ids.includes(alias)) return binding;
5708
- }
5709
- return null;
5710
- }
5711
- async function readBindingCandidate(directory, name) {
5712
- try {
5713
- const value = JSON.parse(await readPrivateFile(join4(directory, name)));
5714
- validateBinding(value);
5715
- return value;
5716
- } catch {
5717
- return null;
5718
- }
5719
- }
5720
6272
  function identityKey(identity) {
5721
6273
  validateIdentity3(identity);
5722
6274
  return cealRequestSha256(identity);
@@ -5729,18 +6281,18 @@ async function writeAtomicJson(path, value) {
5729
6281
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
5730
6282
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
5731
6283
  try {
5732
- const handle = await open5(temp, "wx", 384);
6284
+ const handle = await open4(temp, "wx");
5733
6285
  try {
5734
6286
  await handle.writeFile(text, "utf8");
5735
6287
  await handle.sync();
5736
6288
  } finally {
5737
6289
  await handle.close();
5738
6290
  }
5739
- await rename3(temp, path);
5740
- await syncDirectory(dirname(path));
6291
+ await rename2(temp, path);
6292
+ await syncDirectory(dirname4(path));
5741
6293
  } catch (error) {
5742
6294
  try {
5743
- await unlink2(temp);
6295
+ await unlink3(temp);
5744
6296
  } catch {
5745
6297
  }
5746
6298
  if (error instanceof CodexHostAdapterError) throw error;
@@ -5749,7 +6301,7 @@ async function writeAtomicJson(path, value) {
5749
6301
  }
5750
6302
  async function syncDirectory(path) {
5751
6303
  try {
5752
- const handle = await open5(path, "r");
6304
+ const handle = await open4(path, "r");
5753
6305
  try {
5754
6306
  await handle.sync();
5755
6307
  } finally {
@@ -5760,7 +6312,7 @@ async function syncDirectory(path) {
5760
6312
  }
5761
6313
  async function readOptionalJson(path, validate) {
5762
6314
  try {
5763
- const value = JSON.parse(await readPrivateFile(path));
6315
+ const value = JSON.parse(await readOwnerStateFile(path));
5764
6316
  validate(value);
5765
6317
  return value;
5766
6318
  } catch (error) {
@@ -5769,36 +6321,30 @@ async function readOptionalJson(path, validate) {
5769
6321
  throw storageError("Codex owner state is malformed.");
5770
6322
  }
5771
6323
  }
5772
- async function ensurePrivateOwnerDirectory(path) {
6324
+ async function ensureOwnerDirectory(path) {
5773
6325
  try {
5774
- await lstat3(path);
6326
+ await stat3(path);
5775
6327
  } catch (error) {
5776
6328
  if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
5777
- await mkdir3(path, { recursive: true, mode: 448 });
6329
+ await mkdir3(path, { recursive: true });
5778
6330
  }
5779
- const stats = await lstat3(path);
5780
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
5781
- 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)")}).`);
5782
- 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")}).`);
5783
- if (stats.uid !== uid) throw storageError(`Codex owner state directory is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
6331
+ const stats = await stat3(path);
6332
+ if (!stats.isDirectory()) throw storageError("Codex owner state path is not a directory.");
5784
6333
  }
5785
- async function readPrivateFile(path) {
6334
+ async function readOwnerStateFile(path) {
5786
6335
  let handle;
5787
6336
  try {
5788
- handle = await open5(path, O_RDONLY3 | O_NOFOLLOW2);
6337
+ handle = await open4(path);
5789
6338
  const stats = await handle.stat();
5790
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
5791
- 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)")}).`);
5792
- 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")}).`);
5793
- if (stats.uid !== uid) throw storageError(`Codex owner state file is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
6339
+ if (!stats.isFile()) throw storageError("Codex owner state path is not a regular file.");
5794
6340
  return await handle.readFile("utf8");
5795
6341
  } finally {
5796
6342
  await handle?.close();
5797
6343
  }
5798
6344
  }
5799
6345
  function validateEnvelope(value) {
5800
- if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
5801
- 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")}).`);
6346
+ if (!isRecord7(value)) throw storageError("Codex outbox entry is malformed.");
6347
+ 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")}).`);
5802
6348
  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}`)}).`);
5803
6349
  validateIdentity3(value.identity);
5804
6350
  validateEnvelopeReferences(value);
@@ -5806,32 +6352,30 @@ function validateEnvelope(value) {
5806
6352
  validateEnvelopeTimestamps(value);
5807
6353
  }
5808
6354
  function validateEnvelopeReferences(value) {
5809
- if (!SAFE_REF6.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
5810
- if (!isCealHostInputKind(value.input_kind)) throw storageError("Codex outbox input provenance is malformed.");
5811
- if (!SAFE_REF6.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
5812
- if (!SAFE_REF6.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
5813
- if (value.request_ref !== void 0 && !SAFE_REF6.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
5814
- if (value.codex_turn_id !== void 0 && !SAFE_REF6.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
6355
+ if (!SAFE_REF5.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
6356
+ if (!SAFE_REF5.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
6357
+ if (!SAFE_REF5.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
6358
+ if (value.codex_turn_id !== void 0 && !SAFE_REF5.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
5815
6359
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
5816
6360
  }
5817
6361
  function validateRegistration(value) {
5818
- if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
6362
+ if (!isRecord7(value)) throw storageError("Codex transcript registration is malformed.");
5819
6363
  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")}).`);
5820
6364
  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}`)}).`);
5821
6365
  validateRegistrationFields(value);
5822
6366
  }
5823
6367
  function validateRegistrationFields(value) {
5824
- if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF6.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 }])}).`);
6368
+ if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF5.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 }])}).`);
5825
6369
  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`)}).`);
5826
6370
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
5827
6371
  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}`)}).`);
5828
6372
  if (!isTimestamp(value.registered_at) || !isTimestamp(value.expires_at)) throw storageError(`Codex transcript registration timestamps are malformed (${refusalFacts([{ name: "registered_at", value: value.registered_at }, { name: "expires_at", value: value.expires_at }])}).`);
5829
6373
  }
5830
6374
  function validRegistrationCwd(value) {
5831
- return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
6375
+ return value === void 0 || typeof value === "string" && isAbsolute3(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
5832
6376
  }
5833
6377
  function validateCursor(value) {
5834
- if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
6378
+ if (!isRecord7(value)) throw storageError("Codex transcript cursor is malformed.");
5835
6379
  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")}).`);
5836
6380
  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}`)}).`);
5837
6381
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
@@ -5839,7 +6383,7 @@ function validateCursor(value) {
5839
6383
  if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
5840
6384
  }
5841
6385
  function validCursorSource(value) {
5842
- return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
6386
+ return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF5.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
5843
6387
  }
5844
6388
  function validCursorPosition(value) {
5845
6389
  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";
@@ -5848,23 +6392,23 @@ function validCursorStatus(value) {
5848
6392
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
5849
6393
  }
5850
6394
  function validActiveTask(value) {
5851
- 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;
6395
+ if (!isRecord7(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;
5852
6396
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
5853
6397
  }
5854
6398
  function validActiveTaskIdentity(value) {
5855
- return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate)) && isTimestamp(value.started_at);
6399
+ return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF5.test(candidate)) && isTimestamp(value.started_at);
5856
6400
  }
5857
6401
  function validActiveTaskReferences(value) {
5858
6402
  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);
5859
6403
  }
5860
6404
  function optionalSafeRef2(value) {
5861
- return value === void 0 || typeof value === "string" && SAFE_REF6.test(value);
6405
+ return value === void 0 || typeof value === "string" && SAFE_REF5.test(value);
5862
6406
  }
5863
6407
  function validActiveTaskUsage(value) {
5864
6408
  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");
5865
6409
  }
5866
6410
  function validTokenUsage(value) {
5867
- if (!isRecord5(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
6411
+ if (!isRecord7(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
5868
6412
  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;
5869
6413
  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);
5870
6414
  }
@@ -5874,7 +6418,7 @@ function nonNegativeInteger(value) {
5874
6418
  function validateEnvelopeObservations(value) {
5875
6419
  if (!Array.isArray(value.observations)) throw storageError("Codex outbox observations are malformed.");
5876
6420
  try {
5877
- for (const observation2 of value.observations) validateCealHostObservationDraft(observation2);
6421
+ for (const observation of value.observations) validateCealHostObservationDraft(observation);
5878
6422
  } catch {
5879
6423
  throw storageError("Codex outbox observations are malformed.");
5880
6424
  }
@@ -5883,34 +6427,23 @@ function validateEnvelopeTimestamps(value) {
5883
6427
  if (!isTimestamp(value.created_at)) throw storageError("Codex outbox timestamps are malformed.");
5884
6428
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
5885
6429
  }
5886
- function validateBinding(value) {
5887
- if (!isRecord5(value)) throw storageError("Codex turn binding is malformed.");
5888
- 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")}).`);
5889
- 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}`)}).`);
5890
- validateIdentity3(value.identity);
5891
- if (!SAFE_REF6.test(String(value.prompt_ref)) || !SAFE_REF6.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
5892
- if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
5893
- }
5894
6430
  function validateSession(value) {
5895
- if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
6431
+ if (!isRecord7(value)) throw storageError("Codex session snapshot is malformed.");
5896
6432
  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")}).`);
5897
6433
  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}`)}).`);
5898
- if (!SAFE_REF6.test(String(value.host_session_ref)) || !SAFE_REF6.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.");
6434
+ if (!SAFE_REF5.test(String(value.host_session_ref)) || !SAFE_REF5.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.");
5899
6435
  }
5900
6436
  function validateTurnSelection(value) {
5901
6437
  if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
5902
6438
  }
5903
6439
  function validateIdentity3(value) {
5904
- if (!isRecord5(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate))) throw storageError("Codex Host identity is malformed.");
6440
+ if (!isRecord7(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF5.test(candidate))) throw storageError("Codex Host identity is malformed.");
5905
6441
  }
5906
6442
  function isJsonValue(value) {
5907
6443
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
5908
6444
  if (typeof value === "number") return Number.isFinite(value);
5909
6445
  if (Array.isArray(value)) return value.every(isJsonValue);
5910
- return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
5911
- }
5912
- function isStringList(value) {
5913
- return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF6.test(candidate));
6446
+ return isRecord7(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
5914
6447
  }
5915
6448
  function isTimestamp(value) {
5916
6449
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -5920,142 +6453,43 @@ function sameKeys(value, required, optional = []) {
5920
6453
  const keys = Object.keys(value);
5921
6454
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
5922
6455
  }
5923
- function isRecord5(value) {
6456
+ function isRecord7(value) {
5924
6457
  return value !== null && typeof value === "object" && !Array.isArray(value);
5925
6458
  }
5926
6459
  function isNotFound(error) {
5927
- return isRecord5(error) && error.code === "ENOENT";
6460
+ return isRecord7(error) && error.code === "ENOENT";
5928
6461
  }
5929
6462
  function storageError(message) {
5930
6463
  return new CodexHostAdapterError("storage", message);
5931
6464
  }
5932
6465
 
5933
6466
  // host/codex/src/codex-producer.ts
5934
- import { createHash as createHash6 } from "node:crypto";
5935
- var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5936
6467
  var CodexProducer = class {
5937
- producer_id = "codex";
5938
- producer_label = "Codex";
5939
- outbox_directory;
5940
6468
  store;
5941
6469
  core;
5942
6470
  constructor(options) {
5943
6471
  this.store = new CodexOutboxStore(options.outbox_dir);
5944
- this.outbox_directory = this.store.directory;
5945
6472
  this.core = new HostProducerDrainCore(this, options);
5946
6473
  }
5947
6474
  drainOutbox() {
5948
6475
  return this.core.drainOutbox();
5949
6476
  }
5950
- fail(code, message) {
5951
- return new CodexHostAdapterError(code, message);
5952
- }
5953
6477
  listEnvelopes() {
5954
6478
  return this.store.list();
5955
6479
  }
5956
6480
  removeEnvelope(envelope) {
5957
6481
  return this.store.remove(envelope);
5958
6482
  }
5959
- submissionRefOf(envelope) {
5960
- return envelope.submission_ref;
5961
- }
5962
6483
  expiresAtOf(envelope) {
5963
6484
  return envelope.expires_at;
5964
6485
  }
5965
- createdAtOf(envelope) {
5966
- return envelope.created_at;
5967
- }
5968
- async mapEnvelope(envelope) {
5969
- const prompt = observation(envelope, "prompt");
5970
- if (prompt !== void 0) return this.mapInput(envelope, prompt);
5971
- return [mapTerminal(envelope)];
5972
- }
5973
- async mapInput(envelope, prompt) {
5974
- const drafts = [];
5975
- const session = observation(envelope, "session");
5976
- if (session !== void 0) {
5977
- const registrations = await this.store.listTranscriptRegistrations();
5978
- const registration = registrations.find((item) => item.host_source_ref === envelope.identity.host_source_ref && item.host_session_ref === envelope.identity.host_session_ref);
5979
- const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
5980
- drafts.push({ frame_kind: "session_started", payload: compact({
5981
- local_session_ref: envelope.identity.host_session_ref,
5982
- working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
5983
- model: recordText(session.value, "model"),
5984
- host_version: nestedText(session.value, "host_version"),
5985
- observations: [session]
5986
- }) });
5987
- }
5988
- const turn = observation(envelope, "turn");
5989
- if (turn !== void 0) drafts.push({ frame_kind: "turn_started", payload: compact({
5990
- local_session_ref: envelope.identity.host_session_ref,
5991
- local_turn_ref: localTurnRef(envelope),
5992
- observations: [turn]
5993
- }) });
5994
- if (!isCealHostPromptObservationValue(prompt.value)) throw new CodexHostAdapterError("storage", "Codex prompt observation is malformed.");
5995
- drafts.push({ frame_kind: "user_input", payload: compact({
5996
- local_session_ref: envelope.identity.host_session_ref,
5997
- local_turn_ref: localTurnRef(envelope),
5998
- local_input_ref: envelope.host_input_ref,
5999
- input_kind: envelope.input_kind,
6000
- origin_input: envelope.origin_input,
6001
- observations: [prompt],
6002
- local_turn_aliases: envelope.codex_turn_id === void 0 ? void 0 : [envelope.codex_turn_id],
6003
- context_expires_at: envelope.expires_at
6004
- }) });
6005
- return drafts;
6006
- }
6007
6486
  };
6008
- function mapTerminal(envelope) {
6009
- const timing = observation(envelope, "timing");
6010
- const timingValue = asRecord(timing?.value);
6011
- const aborted = timingValue?.terminal === "aborted";
6012
- const usage = envelope.observations.filter((item) => ["token", "cost", "model"].includes(item.observation_kind));
6013
- return { frame_kind: "turn_terminal", payload: compact({
6014
- local_session_ref: envelope.identity.host_session_ref,
6015
- local_turn_ref: localTurnRef(envelope),
6016
- terminal_state: aborted ? "aborted" : "completed",
6017
- abort_reason: aborted && typeof timingValue?.reason === "string" ? safeReasonRef(timingValue.reason) : void 0,
6018
- duration_ms: nonNegativeNumber(timingValue?.duration_ms),
6019
- time_to_first_token_ms: nonNegativeNumber(timingValue?.time_to_first_token_ms),
6020
- usage: usage.length === 0 ? void 0 : Object.fromEntries(usage.map((item) => [item.observation_kind, item.value])),
6021
- observations: envelope.observations
6022
- }) };
6023
- }
6024
- function observation(envelope, kind) {
6025
- return envelope.observations.find((item) => item.observation_kind === kind);
6026
- }
6027
- function localTurnRef(envelope) {
6028
- return envelope.identity.host_turn_ref;
6029
- }
6030
- function compact(value) {
6031
- return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
6032
- }
6033
- function asRecord(value) {
6034
- return isRecord6(value) ? value : void 0;
6035
- }
6036
- function recordText(value, key) {
6037
- const record3 = asRecord(value);
6038
- return typeof record3?.[key] === "string" ? record3[key] : void 0;
6039
- }
6040
- function nestedText(value, key) {
6041
- const nested = asRecord(asRecord(value)?.[key]);
6042
- return typeof nested?.value === "string" ? nested.value : void 0;
6043
- }
6044
- function nonNegativeNumber(value) {
6045
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
6046
- }
6047
- function safeReasonRef(value) {
6048
- return SAFE_REF7.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
6049
- }
6050
- function isRecord6(value) {
6051
- return value !== null && typeof value === "object" && !Array.isArray(value);
6052
- }
6053
6487
 
6054
6488
  // host/codex/src/codex-transcript-baseline.ts
6055
6489
  import { createHash as createHash7 } from "node:crypto";
6056
6490
 
6057
6491
  // host/codex/src/codex-transcript-decoder.ts
6058
- var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
6492
+ var SAFE_REF6 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
6059
6493
  var MAX_PROMPT_BYTES = 64 * 1024;
6060
6494
  function decodeCodexTranscriptLine(line) {
6061
6495
  let value;
@@ -6064,40 +6498,40 @@ function decodeCodexTranscriptLine(line) {
6064
6498
  } catch {
6065
6499
  reject("Codex transcript record is not valid JSON.");
6066
6500
  }
6067
- if (!isRecord7(value)) reject("Codex transcript record envelope is malformed.");
6501
+ if (!isRecord8(value)) reject("Codex transcript record envelope is malformed.");
6068
6502
  const ordinal = safeOrdinal(value.ordinal);
6069
- const timestamp4 = safeTimestamp(value.timestamp);
6070
- if (!isRecord7(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
6071
- if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
6072
- if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
6073
- if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
6074
- if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
6075
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
6076
- }
6077
- function decodeTurnContext(payload, ordinal, timestamp4) {
6503
+ const timestamp3 = safeTimestamp(value.timestamp);
6504
+ if (!isRecord8(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
6505
+ if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp3);
6506
+ if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp3);
6507
+ if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp3);
6508
+ if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp3);
6509
+ return { kind: "ignored", ordinal, timestamp: timestamp3 };
6510
+ }
6511
+ function decodeTurnContext(payload, ordinal, timestamp3) {
6078
6512
  return {
6079
6513
  kind: "turn_context",
6080
6514
  ordinal,
6081
- timestamp: timestamp4,
6082
- turn_id: safeRef5(payload.turn_id, "Codex turn context identity is invalid."),
6515
+ timestamp: timestamp3,
6516
+ turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
6083
6517
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
6084
6518
  };
6085
6519
  }
6086
- function decodeSessionMeta(payload, ordinal, timestamp4) {
6087
- const sessionId = safeRef5(payload.id, "Codex transcript session identity is invalid.");
6520
+ function decodeSessionMeta(payload, ordinal, timestamp3) {
6521
+ const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
6088
6522
  const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
6089
- return { kind: "session_meta", ordinal, timestamp: timestamp4, session_id: sessionId, cli_version: cliVersion };
6523
+ return { kind: "session_meta", ordinal, timestamp: timestamp3, session_id: sessionId, cli_version: cliVersion };
6090
6524
  }
6091
- function decodeEventMessage(payload, ordinal, timestamp4) {
6525
+ function decodeEventMessage(payload, ordinal, timestamp3) {
6092
6526
  if (payload.type === "task_started") {
6093
- return { kind: "task_started", ordinal, timestamp: timestamp4, turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
6527
+ return { kind: "task_started", ordinal, timestamp: timestamp3, turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
6094
6528
  }
6095
6529
  if (payload.type === "task_complete") {
6096
6530
  return {
6097
6531
  kind: "task_complete",
6098
6532
  ordinal,
6099
- timestamp: timestamp4,
6100
- turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
6533
+ timestamp: timestamp3,
6534
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
6101
6535
  started_at: safeNumber(payload.started_at),
6102
6536
  completed_at: safeNumber(payload.completed_at),
6103
6537
  duration_ms: safeNumber(payload.duration_ms),
@@ -6108,20 +6542,20 @@ function decodeEventMessage(payload, ordinal, timestamp4) {
6108
6542
  return {
6109
6543
  kind: "turn_aborted",
6110
6544
  ordinal,
6111
- timestamp: timestamp4,
6112
- turn_id: safeRef5(payload.turn_id, "Codex task identity is invalid."),
6545
+ timestamp: timestamp3,
6546
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
6113
6547
  started_at: safeNumber(payload.started_at),
6114
6548
  completed_at: safeNumber(payload.completed_at),
6115
6549
  duration_ms: safeNumber(payload.duration_ms),
6116
6550
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
6117
6551
  };
6118
6552
  }
6119
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
6120
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
6553
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp3);
6554
+ return { kind: "ignored", ordinal, timestamp: timestamp3 };
6121
6555
  }
6122
- function decodeTokenCount(payload, ordinal, timestamp4) {
6123
- if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
6124
- if (!isRecord7(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp4, usage_gap_reason: "token_count_shape_not_attributable" };
6556
+ function decodeTokenCount(payload, ordinal, timestamp3) {
6557
+ if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp3 };
6558
+ if (!isRecord8(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp3, usage_gap_reason: "token_count_shape_not_attributable" };
6125
6559
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
6126
6560
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
6127
6561
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -6129,7 +6563,7 @@ function decodeTokenCount(payload, ordinal, timestamp4) {
6129
6563
  return {
6130
6564
  kind: "token_count",
6131
6565
  ordinal,
6132
- timestamp: timestamp4,
6566
+ timestamp: timestamp3,
6133
6567
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
6134
6568
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
6135
6569
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -6145,7 +6579,7 @@ function optionalTokenUsage(value) {
6145
6579
  }
6146
6580
  }
6147
6581
  function decodeTokenUsage(value) {
6148
- if (!isRecord7(value)) reject("Codex token usage is malformed.");
6582
+ if (!isRecord8(value)) reject("Codex token usage is malformed.");
6149
6583
  const usage = {
6150
6584
  input_tokens: safeTokenCount(value.input_tokens),
6151
6585
  cached_input_tokens: safeTokenCount(value.cached_input_tokens),
@@ -6157,35 +6591,33 @@ function decodeTokenUsage(value) {
6157
6591
  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.");
6158
6592
  return usage;
6159
6593
  }
6160
- function decodeResponseItem(payload, ordinal, timestamp4) {
6161
- if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp4 };
6594
+ function decodeResponseItem(payload, ordinal, timestamp3) {
6595
+ if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp3 };
6162
6596
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
6163
- const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
6164
- if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp4 };
6597
+ const contentItemKind = userTextContentKind(metadata.content_item_kinds);
6598
+ if (contentItemKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp3 };
6165
6599
  const prompt = userTextContent(payload.content);
6166
6600
  return {
6167
6601
  kind: "user_text",
6168
6602
  ordinal,
6169
- timestamp: timestamp4,
6603
+ timestamp: timestamp3,
6170
6604
  prompt,
6171
- input_kind: inputKind,
6172
- message_id: safeRef5(payload.id, "Codex user message identity is invalid."),
6173
- turn_id: safeRef5(metadata.turn_id, "Codex user message task identity is invalid.")
6605
+ content_item_kind: contentItemKind,
6606
+ message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
6607
+ turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
6174
6608
  };
6175
6609
  }
6176
- function inputKindFromContentItems(kinds) {
6177
- if (kinds.length !== 1) return void 0;
6178
- if (kinds[0] === "user.text") return "human";
6179
- return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
6610
+ function userTextContentKind(kinds) {
6611
+ return kinds.length === 1 && (kinds[0] === "user.text" || kinds[0] === "goal.internal_context") ? kinds[0] : void 0;
6180
6612
  }
6181
6613
  function userMessageMetadata(value) {
6182
- if (!isRecord7(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
6614
+ if (!isRecord8(value) || !Array.isArray(value.content_item_kinds)) reject("Codex user message provenance is malformed.");
6183
6615
  return { ...value, content_item_kinds: value.content_item_kinds };
6184
6616
  }
6185
6617
  function userTextContent(value) {
6186
6618
  if (!Array.isArray(value)) reject(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
6187
6619
  if (value.length !== 1) reject(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
6188
- if (!isRecord7(value[0]) || value[0].type !== "input_text") reject(`Codex user text content is malformed (${refusalFact("item_type", isRecord7(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
6620
+ if (!isRecord8(value[0]) || value[0].type !== "input_text") reject(`Codex user text content is malformed (${refusalFact("item_type", isRecord8(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
6189
6621
  return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
6190
6622
  }
6191
6623
  function safeOrdinal(value) {
@@ -6206,8 +6638,8 @@ function safeTimestamp(value) {
6206
6638
  if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
6207
6639
  return value;
6208
6640
  }
6209
- function safeRef5(value, message) {
6210
- if (typeof value !== "string" || !SAFE_REF8.test(value)) reject(message);
6641
+ function safeRef4(value, message) {
6642
+ if (typeof value !== "string" || !SAFE_REF6.test(value)) reject(message);
6211
6643
  return value;
6212
6644
  }
6213
6645
  function boundedText(value, maximum, message) {
@@ -6221,7 +6653,7 @@ function boundedNonEmptyText(value, maximum, message) {
6221
6653
  if (result.length === 0) reject(message);
6222
6654
  return result;
6223
6655
  }
6224
- function isRecord7(value) {
6656
+ function isRecord8(value) {
6225
6657
  return value !== null && typeof value === "object" && !Array.isArray(value);
6226
6658
  }
6227
6659
  function reject(message) {
@@ -6245,46 +6677,48 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
6245
6677
  anchor_sha256: digest(Buffer.alloc(0)),
6246
6678
  header_validated: false,
6247
6679
  status: "active",
6248
- updated_at: timestamp3(now)
6680
+ updated_at: timestamp2(now)
6249
6681
  };
6250
6682
  }
6251
- async function ownedCodexTranscriptFile(handle) {
6683
+ async function ownedCodexTranscriptFile(handle, platform = process.platform) {
6252
6684
  const stats = await handle.stat();
6253
- assertCodexTranscriptOwner(stats);
6685
+ if (!stats.isFile()) throw new CodexHostAdapterError("storage", "Codex transcript source is not a regular file.");
6686
+ if (platform !== "win32" && !isSelfOwned(stats.uid, platform, handle)) throw new CodexHostAdapterError("storage", "Codex transcript source is owned by another user.");
6254
6687
  return { size: stats.size, device: String(stats.dev), inode: String(stats.ino) };
6255
6688
  }
6256
- function assertCodexTranscriptOwner(stats) {
6257
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
6258
- 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)")}).`);
6259
- if (stats.uid !== uid) throw new CodexHostAdapterError("storage", `Codex transcript source is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
6260
- }
6261
- function assertCodexTranscriptHeader(registration, record3) {
6262
- 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([
6263
- { name: "kind", value: record3.kind, expected: "session_meta" },
6264
- { name: "session_id", value: record3.kind === "session_meta" ? record3.session_id : "unavailable", expected: registration.codex_session_id }
6689
+ function assertCodexTranscriptHeader(registration, record2) {
6690
+ if (record2.kind !== "session_meta" || record2.session_id !== registration.codex_session_id) throw new CodexHostAdapterError("payload_rejected", `Codex transcript header does not match its SessionStart registration (${refusalFacts([
6691
+ { name: "kind", value: record2.kind, expected: "session_meta" },
6692
+ { name: "session_id", value: record2.kind === "session_meta" ? record2.session_id : "unavailable", expected: registration.codex_session_id }
6265
6693
  ])}).`);
6266
6694
  }
6267
6695
  function digest(value) {
6268
6696
  return createHash7("sha256").update(value).digest("hex");
6269
6697
  }
6270
- function timestamp3(now) {
6698
+ function timestamp2(now) {
6271
6699
  const value = now();
6272
6700
  if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
6273
6701
  return value.toISOString();
6274
6702
  }
6275
6703
 
6704
+ // host/codex/src/codex-runtime-paths.ts
6705
+ import { join as join5 } from "node:path";
6706
+ var CODEX_HOME_ENVIRONMENT = "CODEX_HOME";
6707
+ var CODEX_HOME_DEFAULT_DIRECTORY = ".codex";
6708
+ function resolveCodexHome(environment, home) {
6709
+ return environment[CODEX_HOME_ENVIRONMENT] || join5(home, CODEX_HOME_DEFAULT_DIRECTORY);
6710
+ }
6711
+
6276
6712
  // host/codex/src/codex-adapter.ts
6277
- var SAFE_REF9 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
6713
+ var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
6278
6714
  function codexSubmissionReference(hostInputRef, event, ordinal) {
6279
- if (!SAFE_REF9.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
6715
+ if (!SAFE_REF7.test(hostInputRef) || !Number.isSafeInteger(ordinal) || ordinal < 0) throw new CodexHostAdapterError("invalid_input", "Codex submission identity is invalid.");
6280
6716
  return `codex-submission:${cealRequestSha256({ host_input_ref: hostInputRef, event, ordinal })}`;
6281
6717
  }
6282
6718
 
6283
6719
  // host/codex/src/codex-transcript-watcher.ts
6284
6720
  var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6285
6721
  store;
6286
- registerCurrentPrompt;
6287
- releaseCurrentPrompt;
6288
6722
  diagnostic;
6289
6723
  constructor(options) {
6290
6724
  super(options, {
@@ -6293,8 +6727,6 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6293
6727
  clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
6294
6728
  });
6295
6729
  this.store = new CodexOutboxStore(options.outbox_dir);
6296
- this.registerCurrentPrompt = options.register_current_prompt;
6297
- this.releaseCurrentPrompt = options.release_current_prompt;
6298
6730
  this.diagnostic = options.diagnostic ?? (() => void 0);
6299
6731
  }
6300
6732
  transcriptPathOf(registration) {
@@ -6317,14 +6749,12 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6317
6749
  return { records: 0, enqueued: 0, quarantined: true };
6318
6750
  }
6319
6751
  async retireMissing(registration) {
6320
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, await this.store.readTranscriptCursor(registration).catch(() => null));
6321
6752
  return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
6322
6753
  }
6323
6754
  async preflight(registration, handle, size, device, inode) {
6324
6755
  const existing = await this.store.readTranscriptCursor(registration);
6325
6756
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
6326
6757
  if (cursor.status === "quarantined") {
6327
- if (cursor.reason !== "transcript_malformed") await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
6328
6758
  return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
6329
6759
  }
6330
6760
  const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
@@ -6338,22 +6768,22 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6338
6768
  let records = 0;
6339
6769
  let enqueued = 0;
6340
6770
  for (const line of complete.toString("utf8").split("\n").filter((value) => value.length > 0)) {
6341
- const record3 = decodeCodexTranscriptLine(line);
6342
- assertRecordSequence(registration, cursor, records, lastOrdinal, record3);
6343
- await this.observeSessionMetadata(registration, record3);
6344
- const outcome = await this.processRecord(registration, activeTask, record3);
6771
+ const record2 = decodeCodexTranscriptLine(line);
6772
+ assertRecordSequence(registration, cursor, records, lastOrdinal, record2);
6773
+ await this.observeSessionMetadata(registration, record2);
6774
+ const outcome = await this.processRecord(registration, activeTask, record2);
6345
6775
  activeTask = outcome.activeTask;
6346
6776
  enqueued += outcome.enqueued;
6347
- lastOrdinal = record3.ordinal;
6777
+ lastOrdinal = record2.ordinal;
6348
6778
  records += 1;
6349
6779
  }
6350
6780
  await this.commitCursor(registration, handle, cursor, complete.length, device, inode, lastOrdinal, activeTask);
6351
6781
  return { records, enqueued, quarantined: false };
6352
6782
  }
6353
- async observeSessionMetadata(registration, record3) {
6354
- if (record3.kind !== "session_meta") return;
6783
+ async observeSessionMetadata(registration, record2) {
6784
+ if (record2.kind !== "session_meta") return;
6355
6785
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
6356
- if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
6786
+ if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record2.cli_version } });
6357
6787
  }
6358
6788
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
6359
6789
  const offset = cursor.offset + consumedBytes;
@@ -6376,56 +6806,54 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6376
6806
  };
6377
6807
  await this.store.writeTranscriptCursor(quarantined);
6378
6808
  }
6379
- async processRecord(registration, activeTask, record3) {
6380
- if (record3.kind === "task_started") return this.processTaskStarted(registration, activeTask, record3);
6381
- if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
6382
- if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
6383
- if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
6384
- if (record3.kind === "task_complete" || record3.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record3);
6809
+ async processRecord(registration, activeTask, record2) {
6810
+ if (record2.kind === "task_started") return this.processTaskStarted(registration, record2);
6811
+ if (record2.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record2.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record2.model } : activeTask }, enqueued: 0 };
6812
+ if (record2.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record2) }, enqueued: 0 };
6813
+ if (record2.kind === "user_text") return this.processUserInput(registration, activeTask, record2);
6814
+ if (record2.kind === "task_complete" || record2.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record2);
6385
6815
  return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6386
6816
  }
6387
- async processTaskStarted(registration, activeTask, record3) {
6388
- 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);
6389
- 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 };
6817
+ async processTaskStarted(registration, record2) {
6818
+ return { activeTask: { codex_turn_id: record2.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id), started_at: record2.timestamp }, enqueued: 0 };
6390
6819
  }
6391
- async processUserInput(registration, activeTask, record3) {
6392
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) {
6393
- const adopted = await this.adoptHookCorrelatedTurn(registration, activeTask, record3);
6820
+ async processUserInput(registration, activeTask, record2) {
6821
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record2.turn_id) {
6822
+ const adopted = await this.adoptHookCorrelatedTurn(registration, record2);
6394
6823
  if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6395
6824
  activeTask = adopted;
6396
6825
  }
6397
- const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
6826
+ const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id, record2.message_id, record2.ordinal, record2.prompt);
6398
6827
  const origin = activeTask.origin_host_input_ref === void 0;
6399
- const promptValue = promptObservationValue(record3.prompt);
6828
+ const promptValue = promptObservationValue(record2.prompt);
6400
6829
  const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
6401
6830
  const promptRef = activeTask.prompt_ref ?? currentPromptRef;
6402
6831
  const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
6403
6832
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
6404
6833
  const observations = [{
6405
- observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
6834
+ observation_ref: observationRef(registration.host_source_ref, "transcript_user_text", hostInputRef, record2.prompt),
6406
6835
  observation_kind: "prompt",
6407
- observed_at: record3.timestamp,
6836
+ observed_at: record2.timestamp,
6408
6837
  value: promptValue
6409
6838
  }];
6410
6839
  if (origin) {
6411
- 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") });
6840
+ observations.push({ observation_ref: observationRef(registration.host_source_ref, "transcript_task_started", activeTask.host_turn_ref, record2.turn_id), observation_kind: "turn", observed_at: record2.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "started") });
6412
6841
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
6413
- 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 });
6842
+ 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: record2.timestamp, value: session.value });
6414
6843
  }
6415
6844
  const envelope = {
6416
6845
  schema_version: "ceal.codex_observation_outbox.v1",
6417
6846
  identity,
6418
6847
  host_input_ref: hostInputRef,
6419
- input_kind: record3.input_kind,
6420
6848
  prompt_ref: promptRef,
6421
6849
  observations,
6422
- codex_turn_id: record3.turn_id,
6850
+ codex_turn_id: record2.turn_id,
6423
6851
  origin_input: origin,
6424
- submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
6425
- created_at: record3.timestamp,
6852
+ submission_ref: codexSubmissionReference(hostInputRef, "input", record2.ordinal),
6853
+ created_at: record2.timestamp,
6426
6854
  expires_at: this.expire(this.outboxRetentionMs)
6427
6855
  };
6428
- const persisted = await this.persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
6856
+ const persisted = await this.persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
6429
6857
  if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
6430
6858
  return persisted;
6431
6859
  }
@@ -6452,40 +6880,21 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6452
6880
  * stay ignored. A stale active task for another turn releases first, the
6453
6881
  * same as a task_started supersession.
6454
6882
  */
6455
- async adoptHookCorrelatedTurn(registration, activeTask, record3) {
6456
- const currentPromptRef = hostProducerPromptRef(promptObservationValue(record3.prompt).body_sha256);
6883
+ async adoptHookCorrelatedTurn(registration, record2) {
6884
+ const currentPromptRef = hostProducerPromptRef(promptObservationValue(record2.prompt).body_sha256);
6457
6885
  const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
6458
6886
  if (selection?.prompt_ref !== currentPromptRef) return void 0;
6459
- if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) {
6460
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
6461
- }
6462
6887
  return {
6463
- codex_turn_id: record3.turn_id,
6464
- host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id),
6465
- started_at: record3.timestamp
6888
+ codex_turn_id: record2.turn_id,
6889
+ host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id),
6890
+ started_at: record2.timestamp
6466
6891
  };
6467
6892
  }
6468
- async persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
6469
- const custodyRegistered = await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
6470
- if (custodyRegistered) this.diagnostic("watcher_turn_observed");
6471
- try {
6472
- await this.store.put(envelope);
6473
- if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
6474
- } catch (error) {
6475
- if (custodyRegistered) await this.releasePrompt(registration.host_session_ref, activeTask, currentPromptRef).catch(() => void 0);
6476
- throw error;
6477
- }
6893
+ async persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
6894
+ await this.store.put(envelope);
6895
+ if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
6478
6896
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
6479
6897
  }
6480
- async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
6481
- if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return false;
6482
- const register = this.registerCurrentPrompt;
6483
- const installationRef = this.producerInstallationRef;
6484
- return registerHostCurrentPromptDiagnosed(
6485
- () => 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 }),
6486
- (event) => this.diagnostic(event)
6487
- );
6488
- }
6489
6898
  async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
6490
6899
  try {
6491
6900
  const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
@@ -6497,41 +6906,27 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6497
6906
  throw error;
6498
6907
  }
6499
6908
  }
6500
- async releasePrompt(sessionRef, activeTask, promptRef) {
6501
- if (this.producerInstallationRef === void 0 || this.releaseCurrentPrompt === void 0) return;
6502
- 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 });
6503
- }
6504
- async releaseStoredPromptBestEffort(sessionRef, cursor) {
6505
- await this.releaseActiveTaskBestEffort(sessionRef, cursor?.active_task);
6506
- }
6507
- async releaseActiveTaskBestEffort(sessionRef, activeTask) {
6508
- if (activeTask?.prompt_ref === void 0) return;
6509
- await this.releasePrompt(sessionRef, activeTask, activeTask.prompt_ref).catch(() => void 0);
6510
- }
6511
- async processTerminal(registration, activeTask, record3) {
6512
- 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 };
6909
+ async processTerminal(registration, activeTask, record2) {
6910
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record2.turn_id || activeTask.origin_host_input_ref === void 0 || activeTask.prompt_ref === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6513
6911
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
6514
- 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 };
6515
- const observations = terminalObservations(registration, activeTask, record3, timing);
6912
+ const timing = record2.kind === "task_complete" ? { status: "available", unit: "milliseconds", started_at: record2.started_at, completed_at: record2.completed_at, duration_ms: record2.duration_ms, time_to_first_token_ms: record2.time_to_first_token_ms } : { status: "available", unit: "milliseconds", started_at: record2.started_at, completed_at: record2.completed_at, duration_ms: record2.duration_ms, terminal: "aborted", reason: record2.reason };
6913
+ const observations = terminalObservations(registration, activeTask, record2, timing);
6516
6914
  await this.store.put({
6517
6915
  schema_version: "ceal.codex_observation_outbox.v1",
6518
6916
  identity,
6519
6917
  host_input_ref: activeTask.origin_host_input_ref,
6520
- input_kind: "host_automatic",
6521
6918
  prompt_ref: activeTask.prompt_ref,
6522
6919
  observations,
6523
- codex_turn_id: record3.turn_id,
6920
+ codex_turn_id: record2.turn_id,
6524
6921
  origin_input: false,
6525
- submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
6526
- created_at: record3.timestamp,
6922
+ submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record2.ordinal),
6923
+ created_at: record2.timestamp,
6527
6924
  expires_at: this.expire(this.outboxRetentionMs)
6528
6925
  });
6529
- await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
6530
6926
  await this.store.clearInvocationContext(identity, this.now());
6531
6927
  return { enqueued: 1 };
6532
6928
  }
6533
6929
  async quarantine(registration, cursor, device, inode, reason) {
6534
- await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
6535
6930
  const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
6536
6931
  await this.store.writeTranscriptCursor(quarantined);
6537
6932
  }
@@ -6544,10 +6939,10 @@ function codexTranscriptScanFailureKind(error) {
6544
6939
  return void 0;
6545
6940
  });
6546
6941
  }
6547
- function accumulateTokenCount(activeTask, record3) {
6548
- if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
6549
- const last = record3.last_usage;
6550
- const total = record3.total_usage;
6942
+ function accumulateTokenCount(activeTask, record2) {
6943
+ if (record2.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record2.usage_gap_reason };
6944
+ const last = record2.last_usage;
6945
+ const total = record2.total_usage;
6551
6946
  if (last === void 0 || ignoreTokenCount(activeTask.last_total_usage, total, last)) return activeTask;
6552
6947
  const tokenUsage = addUsage(activeTask.token_usage, last);
6553
6948
  return {
@@ -6561,21 +6956,16 @@ function ignoreTokenCount(previous, total, last) {
6561
6956
  if (total === void 0 || previous === void 0) return false;
6562
6957
  return sameUsage(total, previous) || regressedUsage(total, previous) && looksLikeStaleRegression(total, previous, last);
6563
6958
  }
6564
- function terminalObservations(registration, activeTask, record3, timing) {
6959
+ function terminalObservations(registration, activeTask, record2, timing) {
6565
6960
  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);
6566
- const costValue = terminalCostValue();
6567
6961
  const observations = [
6568
- { 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") },
6569
- { observation_ref: observationRef("transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record3.timestamp, value: timing },
6570
- { observation_ref: observationRef("transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record3.timestamp, value: tokenValue },
6571
- { observation_ref: observationRef("transcript_cost", activeTask.host_turn_ref, costValue), observation_kind: "cost", observed_at: record3.timestamp, value: costValue }
6962
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_terminal", activeTask.host_turn_ref, record2), observation_kind: "turn", observed_at: record2.timestamp, value: turnObservationValue(registration.codex_session_id, activeTask.host_turn_ref, "stopped") },
6963
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record2.timestamp, value: timing },
6964
+ { observation_ref: observationRef(registration.host_source_ref, "transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record2.timestamp, value: tokenValue }
6572
6965
  ];
6573
- 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" } });
6966
+ 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: record2.timestamp, value: { status: "available", value: activeTask.model, source: "turn_context.model" } });
6574
6967
  return observations;
6575
6968
  }
6576
- function terminalCostValue() {
6577
- return notRecorded("provider_cost_not_observed");
6578
- }
6579
6969
  function notRecorded(reason) {
6580
6970
  return hostObservationNotRecorded(reason);
6581
6971
  }
@@ -6622,25 +7012,21 @@ function looksLikeStaleRegression(current, previous, last) {
6622
7012
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
6623
7013
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
6624
7014
  }
6625
- function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
6626
- 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}`)}).`);
6627
- if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
7015
+ function assertRecordSequence(registration, cursor, records, lastOrdinal, record2) {
7016
+ if ((cursor.header_validated || records > 0) && record2.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record2.ordinal, `greater than ${lastOrdinal}`)}).`);
7017
+ if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record2);
6628
7018
  }
6629
7019
 
6630
7020
  // host/codex/src/codex-producer-runtime.ts
6631
7021
  async function drainCodexProducerOnce(options) {
6632
- const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
6633
7022
  const scan = await new CodexTranscriptWatcher({
6634
7023
  outbox_dir: options.outbox_dir,
6635
- producer_installation_ref: options.producer_installation_ref,
6636
- register_current_prompt: (input) => promptPort.register(input),
6637
- release_current_prompt: (identity) => promptPort.release(identity),
6638
7024
  diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
6639
7025
  }).scanOnce().catch((error) => {
6640
7026
  writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
6641
7027
  throw error;
6642
7028
  });
6643
- 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 } });
7029
+ const producer = new CodexProducer({ outbox_dir: options.outbox_dir, ...options.now === void 0 ? {} : { now: options.now } });
6644
7030
  return { scanned: scan.enqueued, ...await producer.drainOutbox() };
6645
7031
  }
6646
7032
 
@@ -6653,33 +7039,29 @@ var CODEX_PRODUCER_DESCRIPTOR = {
6653
7039
  extra_paths: [CODEX_SESSIONS_ROOT],
6654
7040
  config: (shared, extras) => ({ ...shared, codex_sessions_root: hostProducerExtraPath(extras, CODEX_SESSIONS_ROOT) }),
6655
7041
  runtime_options: (config) => Object.freeze({
6656
- outbox_dir: config.outbox_dir,
6657
- producer_installation_ref: config.producer_installation_ref,
6658
- producer_epoch: config.producer_epoch,
6659
- relay_endpoint: config.relay_endpoint,
6660
- timeout_ms: config.ipc_timeout_ms
7042
+ outbox_dir: config.outbox_dir
6661
7043
  }),
6662
7044
  drain: drainCodexProducerOnce
6663
7045
  };
6664
7046
 
6665
7047
  // host/codex/src/codex-visible-output-budget.ts
6666
- import { readFile as readFile3 } from "node:fs/promises";
7048
+ import { readFile as readFile2 } from "node:fs/promises";
6667
7049
  import { homedir } from "node:os";
6668
- import { join as join5 } from "node:path";
7050
+ import { join as join6 } from "node:path";
6669
7051
  var import_toml = __toESM(require_toml(), 1);
6670
7052
  var CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT = 5e3;
6671
7053
  var CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN = 4;
6672
7054
  async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
6673
- const codexHome = environment.CODEX_HOME || join5(homedir(), ".codex");
7055
+ const codexHome = resolveCodexHome(environment, homedir());
6674
7056
  let source;
6675
7057
  try {
6676
- source = await readFile3(join5(codexHome, "config.toml"), "utf8");
7058
+ source = await readFile2(join6(codexHome, "config.toml"), "utf8");
6677
7059
  } catch (error) {
6678
7060
  return isNotFound2(error) ? codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT) : void 0;
6679
7061
  }
6680
7062
  try {
6681
7063
  const parsed = import_toml.default.parse(source);
6682
- if (!isRecord8(parsed)) return void 0;
7064
+ if (!isRecord9(parsed)) return void 0;
6683
7065
  const configured = parsed.tool_output_token_limit;
6684
7066
  if (configured === void 0) return codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT);
6685
7067
  return typeof configured === "number" && Number.isSafeInteger(configured) && configured > 0 ? codexBytes(configured) : void 0;
@@ -6690,7 +7072,7 @@ async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
6690
7072
  function codexBytes(tokens) {
6691
7073
  return Math.min(tokens * CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN, CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES);
6692
7074
  }
6693
- function isRecord8(value) {
7075
+ function isRecord9(value) {
6694
7076
  return value !== null && typeof value === "object" && !Array.isArray(value);
6695
7077
  }
6696
7078
  function isNotFound2(error) {
@@ -6707,11 +7089,28 @@ var CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR = {
6707
7089
  config_flag: HOST_PRODUCER_CONFIG_FLAG,
6708
7090
  parse_config_flag: parseHostProducerConfigFlag,
6709
7091
  read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath),
6710
- resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes()
7092
+ resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes(),
7093
+ read_human_message_window: readCodexInvocationHumanMessageWindow
6711
7094
  };
6712
7095
  function runCodexInvocationAuthenticationCommand(args, options) {
6713
7096
  return runHostInvocationAuthenticationCommand(CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR, args, options);
6714
7097
  }
7098
+ async function readCodexInvocationHumanMessageWindow(input) {
7099
+ return readRegisteredHostInvocationHumanMessageWindow(() => input.store.listTranscriptRegistrations(), input.identity, (line, registration) => {
7100
+ let record2;
7101
+ try {
7102
+ record2 = decodeCodexTranscriptLine(line);
7103
+ } catch {
7104
+ return "malformed";
7105
+ }
7106
+ if (record2.kind !== "user_text" || record2.content_item_kind !== "user.text") return null;
7107
+ return {
7108
+ host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id),
7109
+ host_input_ref: hostInputReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id, record2.message_id, record2.ordinal, record2.prompt),
7110
+ text: record2.prompt
7111
+ };
7112
+ });
7113
+ }
6715
7114
 
6716
7115
  // host/codex/bin/ceal-codex-invocation-authentication.ts
6717
7116
  var CODEX_INVOCATION_AUTHENTICATION_CLIENT_COMMAND = {