@corca-org/ceal-host-win32-x64 1.0.19 → 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,11 +3251,22 @@ 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
3269
+ var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
3012
3270
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
3013
3271
  var CEAL_RESOURCE_SEARCH_DIRECTIONS = vocabulary(["ascending", "descending"]);
3014
3272
  var CEAL_RESOURCE_SEARCH_FILTERS = vocabulary(["query", "modified_since", "since", "until", "authored_by_me", "authored_by", "include_replies", "kinds", "container_ref", "container_refs", "container_names", "addressed_to_me", "unread"]);
@@ -3021,6 +3279,8 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
3021
3279
  "resource_created",
3022
3280
  "review_submitted",
3023
3281
  "comment_created",
3282
+ "reaction_created",
3283
+ "ceal_write_completed",
3024
3284
  "event_start",
3025
3285
  "all_day_start",
3026
3286
  "file_created",
@@ -3055,6 +3315,10 @@ var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
3055
3315
  "github.review.submitted",
3056
3316
  "github.issue_comment.created",
3057
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",
3058
3322
  "calendar.organized",
3059
3323
  "calendar.accepted_invite",
3060
3324
  "calendar.recorded",
@@ -3076,6 +3340,10 @@ var CEAL_ACTIVITY_EVENT_TIMESTAMP_BASIS_MAP = Object.freeze({
3076
3340
  "github.pull_request.opened": "resource_created",
3077
3341
  "github.issue.edited": "resource_modified",
3078
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",
3079
3347
  "calendar.organized": "resource_created",
3080
3348
  "drive.file.created": "file_created",
3081
3349
  "drive.file.modified": "file_modified_by_me",
@@ -3092,12 +3360,14 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
3092
3360
  next: { required: true, timestamp: false },
3093
3361
  kind: { required: true, timestamp: false },
3094
3362
  matched_kinds: { required: false, timestamp: false },
3363
+ title_match: { required: false, timestamp: false },
3095
3364
  title: { required: true, timestamp: false },
3096
3365
  container_label: { required: true, timestamp: false },
3097
3366
  container_ref: { required: false, timestamp: false },
3098
3367
  source_url: { required: false, timestamp: false },
3099
3368
  source: { required: true, timestamp: false },
3100
3369
  owner: { required: false, timestamp: false },
3370
+ actor_kind: { required: false, timestamp: false },
3101
3371
  counterparts: { required: false, timestamp: false },
3102
3372
  attachments: { required: false, timestamp: false },
3103
3373
  created_at: { required: false, timestamp: true },
@@ -3105,9 +3375,18 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
3105
3375
  modified_at: { required: false, timestamp: true },
3106
3376
  modified_at_local: { required: false, timestamp: true },
3107
3377
  viewed_by_me_at: { required: false, timestamp: true },
3378
+ modified_by_me_at: { required: false, timestamp: true },
3108
3379
  own_ceal_write: { required: false, timestamp: false },
3109
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 },
3110
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 },
3111
3390
  start: { required: false, timestamp: false },
3112
3391
  end: { required: false, timestamp: false },
3113
3392
  status: { required: false, timestamp: false },
@@ -3180,18 +3459,29 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
3180
3459
  // The serving gate answers this while the Gateway is still starting and the
3181
3460
  // refresh was never attempted; the same attempt stays retryable. It is never
3182
3461
  // stored by the session owner, only answered at the serving edge.
3183
- "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"
3184
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");
3185
3475
 
3186
3476
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
3187
- import { createHash } from "node:crypto";
3477
+ import { createHash as createHash2 } from "node:crypto";
3188
3478
  var DIGEST = /^[a-f0-9]{64}$/u;
3189
3479
  var CEAL_SHA256_DIGEST_PATTERN = DIGEST.source;
3190
3480
  function isCealDigest(value) {
3191
3481
  return typeof value === "string" && DIGEST.test(value);
3192
3482
  }
3193
3483
  function cealRequestSha256(value) {
3194
- return createHash("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
3484
+ return createHash2("sha256").update(cealCanonicalJson(value), "utf8").digest("hex");
3195
3485
  }
3196
3486
  function operationRecord(value, message) {
3197
3487
  requireOperationRecord(value, message);
@@ -3207,40 +3497,71 @@ function requirePrefixedRef(value, prefix, message) {
3207
3497
  // packages/ceal-client-protocol/src/request-authority.ts
3208
3498
  var CEAL_REQUEST_SCHEMA_VERSION = "ceal.request.v1";
3209
3499
  var CEAL_REQUEST_ARTIFACT_OWNERS = vocabulary(["gateway", "host", "connector"]);
3210
- 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"]);
3211
3501
  var CEAL_REQUEST_ARTIFACT_RETENTION_CLASSES = vocabulary(["request", "source", "result"]);
3212
3502
  var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
3213
- 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"]);
3214
3539
  var CEAL_REQUEST_JSON_SCHEMA = {
3215
3540
  type: "object",
3216
- 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,
3217
3543
  additionalProperties: false,
3218
3544
  properties: {
3219
- schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
3220
- ceal_request_ref: { type: "string", minLength: 1, maxLength: 128, pattern: "^ceal-request:[A-Za-z0-9][A-Za-z0-9._:-]{0,114}$" },
3221
- created_at: { type: "string", minLength: 1, maxLength: 64 },
3222
- 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
+ {
3223
3553
  type: "object",
3224
- maxProperties: 5,
3225
- additionalProperties: false,
3226
- properties: {
3227
- instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3228
- access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3229
- principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3230
- execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3231
- authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
3232
- },
3233
- 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
3234
3557
  },
3235
- prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3236
- host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3237
- host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3238
- host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3239
- host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
3240
- requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
3241
- 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." }
3242
- },
3243
- 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
+ ]
3244
3565
  };
3245
3566
 
3246
3567
  // packages/ceal-client-protocol/src/request-operands.ts
@@ -3351,10 +3672,6 @@ var CEAL_REQUEST_RUN_BATCH_JSON_SCHEMA = {
3351
3672
  };
3352
3673
 
3353
3674
  // packages/ceal-client-protocol/src/host-observation.ts
3354
- var CEAL_HOST_INPUT_KINDS = vocabulary(["human", "host_automatic"]);
3355
- function isCealHostInputKind(value) {
3356
- return typeof value === "string" && CEAL_HOST_INPUT_KINDS.some((kind) => kind === value);
3357
- }
3358
3675
  var CEAL_HOST_OBSERVATION_REF_PREFIX = "host-observation:";
3359
3676
  var HOST_OBSERVATION_PRODUCER = /^[a-z][a-z0-9]{0,31}$/u;
3360
3677
  var HOST_OBSERVATION_DIGEST = /^[a-f0-9]{8,64}$/u;
@@ -3400,14 +3717,14 @@ function safeCount(value) {
3400
3717
  return Number.isSafeInteger(value) && Number(value) >= 0;
3401
3718
  }
3402
3719
  function validateCealHostObservationDraft(value) {
3403
- const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
3404
- requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
3405
- requireClosedValue(record3.observation_kind, CEAL_HOST_OBSERVATION_KINDS, "Ceal Host observation kind is invalid.");
3406
- requireIsoTimestamp(record3.observed_at, "Ceal Host observation time is invalid.");
3407
- 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);
3408
3725
  }
3409
3726
  var CEAL_REQUEST_MAX_OBSERVATION_VALUE_BYTES = 64 * 1024;
3410
- 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"]);
3411
3728
  function isCealHostPromptObservationValue(value) {
3412
3729
  return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
3413
3730
  }
@@ -3530,17 +3847,128 @@ var CEAL_REQUEST_GRAPH_NODE_PREPARE_READINESS_JSON_SCHEMA = {
3530
3847
  };
3531
3848
 
3532
3849
  // packages/ceal-client-protocol/src/host-invocation-authentication.ts
3533
- var CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA = "ceal.host_invocation_authentication_request.v1";
3534
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA = "ceal.host_invocation_authentication_result.v1";
3535
- var CEAL_HOST_NONCE_ENCODED_CHARACTERS = 43;
3536
- var CEAL_HOST_CLIENT_NONCE_PATTERN = new RegExp(`^[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
3537
- var CEAL_HOST_CONTEXT_TOKEN_PATTERN = new RegExp(`^ceal_context_[A-Za-z0-9_-]{${CEAL_HOST_NONCE_ENCODED_CHARACTERS}}$`, "u");
3538
- var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = new TextEncoder().encode(`${JSON.stringify({
3539
- schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA,
3540
- context_token: `ceal_context_${"A".repeat(CEAL_HOST_NONCE_ENCODED_CHARACTERS)}`,
3541
- expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
3542
- })}
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]])))}
3543
3970
  `).byteLength;
3971
+ }
3544
3972
  var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
3545
3973
  "request_authority_unavailable",
3546
3974
  "request_missing",
@@ -3564,6 +3992,7 @@ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
3564
3992
  "host_credential_refused",
3565
3993
  "gateway_unavailable",
3566
3994
  "gateway_rate_limited",
3995
+ "contract_mismatch",
3567
3996
  "gateway_refused",
3568
3997
  "gateway_response_invalid",
3569
3998
  "producer_frame_invalid",
@@ -3578,19 +4007,23 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
3578
4007
  invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
3579
4008
  options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
3580
4009
  session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
3581
- 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; run `ceal-host install` to repair the Host hook registration, then retry this command on a fresh Host turn" }),
3582
- context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
3583
- no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
3584
- context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
3585
- 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" }),
3586
4018
  host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
3587
4019
  host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
3588
4020
  gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
3589
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" }),
3590
4023
  gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
3591
4024
  gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
3592
- 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" }),
3593
- 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" }),
3594
4027
  relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
3595
4028
  transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
3596
4029
  mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
@@ -3600,21 +4033,33 @@ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
3600
4033
  function isCealHostAuthenticationCause(value) {
3601
4034
  return isVocabularyWord(CEAL_HOST_AUTHENTICATION_CAUSES, value);
3602
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
+ }
3603
4041
  function decodeCealHostInvocationAuthenticationRequest(value) {
3604
- 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)) {
3605
4045
  throw new TypeError("The Host invocation authentication request is invalid.");
3606
4046
  }
3607
4047
  return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: value.client_nonce });
3608
4048
  }
3609
4049
  function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__ */ new Date()) {
3610
- 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)) {
3611
4056
  throw new TypeError("The Host invocation authentication result is invalid.");
3612
4057
  }
3613
4058
  return Object.freeze({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA, context_token: value.context_token, expires_at: value.expires_at });
3614
4059
  }
3615
4060
  function validFutureTimestamp(value, now) {
3616
- const timestamp4 = Date.parse(value);
3617
- 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();
3618
4063
  }
3619
4064
  function exactKeys(value, expected) {
3620
4065
  const keys = Object.keys(value);
@@ -3628,9 +4073,6 @@ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
3628
4073
  "hook_invoked",
3629
4074
  "registration_written",
3630
4075
  "hook_failed",
3631
- "watcher_turn_observed",
3632
- "current_prompt_registered",
3633
- "current_prompt_registration_failed",
3634
4076
  "activation_recorded",
3635
4077
  "activation_failed",
3636
4078
  "watcher_scan_failed",
@@ -3653,6 +4095,9 @@ var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "un
3653
4095
  var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
3654
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"]);
3655
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
+
3656
4101
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
3657
4102
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
3658
4103
 
@@ -3711,6 +4156,7 @@ var ADMIN_UNAVAILABLE_REASONS = vocabulary([
3711
4156
  "legacy",
3712
4157
  "invalid_observation",
3713
4158
  "redacted",
4159
+ "organization_setting_disabled",
3714
4160
  "owner_unavailable",
3715
4161
  "unit_unknown",
3716
4162
  "retention_gap",
@@ -3740,15 +4186,13 @@ var ADMIN_APPROVAL_DISPOSITIONS = CEAL_OPERATION_APPROVAL_DISPOSITIONS;
3740
4186
  var ADMIN_APPROVAL_POSTURES = vocabulary([...ADMIN_APPROVAL_DISPOSITIONS, "not_applicable"]);
3741
4187
  var ADMIN_LINEAGE_NODE_KINDS = vocabulary(["source_read", "synthesis_preview", "approval", "effect", "readback"]);
3742
4188
 
3743
- // packages/ceal-client-protocol/src/actor-kind.ts
3744
- var CEAL_ACTOR_KINDS = vocabulary(["human", "bot", "app", "unknown"]);
3745
-
3746
4189
  // packages/ceal-client-protocol/src/device-enrollment.ts
3747
4190
  var CEAL_DEVICE_ENROLLMENT_POLL_FAILURE_CODES = Object.freeze(["unsupported_feature", "recovery_required", "expired", "denied"]);
3748
4191
  var POLL_RESULT_KEYS = Object.freeze(["retry_after_ms", "schema_version", "status"]);
3749
4192
 
3750
4193
  // packages/ceal-client-protocol/src/personal-client-session.ts
3751
4194
  var REFRESH_FAILURE_CODES = new Set(CEAL_REFRESH_FAILURE_CODES);
4195
+ var REVOKE_FAILURE_CODES = new Set(CEAL_CLIENT_REVOKE_FAILURE_CODES);
3752
4196
 
3753
4197
  // packages/ceal-client-protocol/src/index.ts
3754
4198
  var MAX_REQUEST_BYTES = 32 * 1024;
@@ -3840,16 +4284,59 @@ function hostClientProbeRefusal(probe, subject) {
3840
4284
  }
3841
4285
 
3842
4286
  // host/client-doctor.ts
3843
- import { createHash as createHash2 } from "node:crypto";
4287
+ import { createHash as createHash3 } from "node:crypto";
3844
4288
  import { execFile } from "node:child_process";
3845
4289
  import { access, open, readFile, realpath, stat } from "node:fs/promises";
3846
4290
  import { delimiter, isAbsolute, join as join2 } from "node:path";
3847
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
3848
4335
  var execFileAsync = promisify(execFile);
3849
4336
  var GIT_OID = /^[a-f0-9]{40}$/u;
3850
4337
  var SHA2562 = /^[a-f0-9]{64}$/u;
3851
4338
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3852
- 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;
3853
4340
  async function doctorClient(options = {}, component) {
3854
4341
  const environment = canonicalClientEnvironment(options.environment ?? process.env);
3855
4342
  const run = options.run ?? executeCealCommand;
@@ -3886,7 +4373,7 @@ async function inspectExecutable(options, environment, component) {
3886
4373
  return { ok: true, value: executable };
3887
4374
  }
3888
4375
  async function inspectVersion(options, executable, environment, run, component) {
3889
- 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)));
3890
4377
  if (probe.kind !== "value") return probeFailure(probe, "version", component, options);
3891
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.`);
3892
4379
  return { ok: true, value: probe.value };
@@ -3903,8 +4390,8 @@ function probeCode(code) {
3903
4390
  return "ceal_output_unreadable";
3904
4391
  }
3905
4392
  async function inspectCanonicalContext(options, executable, environment, run, component) {
3906
- const probe = hostClientProbe(await safeRun(run, executable.path, ["access-group", "list"], environment), (result) => selectedContext(commandDocument(result)));
3907
- 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);
3908
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}.`);
3909
4396
  return { ok: true, value: probe.value };
3910
4397
  }
@@ -3925,7 +4412,7 @@ async function resolveCealExecutable(command, environment) {
3925
4412
  const metadata = await stat(path);
3926
4413
  if (!metadata.isFile()) continue;
3927
4414
  if (await isLauncher(path)) return resolveLauncherBinary(path, environment);
3928
- return { path, sha256: createHash2("sha256").update(await readFile(path)).digest("hex") };
4415
+ return { path, sha256: createHash3("sha256").update(await readFile(path)).digest("hex") };
3929
4416
  } catch {
3930
4417
  }
3931
4418
  }
@@ -3944,18 +4431,19 @@ async function isLauncher(path) {
3944
4431
  }
3945
4432
  }
3946
4433
  async function resolveLauncherBinary(launcherPath, environment) {
3947
- 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 } });
3948
4436
  let parsed;
3949
4437
  try {
3950
4438
  parsed = JSON.parse(result.stdout);
3951
4439
  } catch {
3952
4440
  throw new Error("launcher doctor returned unreadable output");
3953
4441
  }
3954
- 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");
3955
4443
  const binaryPath = await realpath(parsed.binary_path);
3956
4444
  const metadata = await stat(binaryPath);
3957
4445
  if (!metadata.isFile()) throw new Error("launcher doctor reported a non-file binary path");
3958
- 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") };
3959
4447
  }
3960
4448
  async function executeCealCommand(executable, args, environment) {
3961
4449
  try {
@@ -3990,7 +4478,7 @@ function selectedContextRecord(item) {
3990
4478
  return { name: item.name, instance_ref: item.instance_ref };
3991
4479
  }
3992
4480
  function versionIdentity(value) {
3993
- 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;
3994
4482
  if (value.version.length === 0 || !GIT_OID.test(value.source_commit) || !GIT_OID.test(value.source_tree)) return null;
3995
4483
  return { version: value.version, source_commit: value.source_commit, source_tree: value.source_tree };
3996
4484
  }
@@ -4014,16 +4502,9 @@ async function doctorCodexClient(options = {}) {
4014
4502
  import { performance } from "node:perf_hooks";
4015
4503
 
4016
4504
  // host/relay/src/producer-frame.ts
4017
- var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
4018
- var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
4019
4505
  var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
4020
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
4021
- var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
4022
- 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"];
4023
4507
  var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
4024
- function isHostProducerFrameKind(value) {
4025
- return typeof value === "string" && FRAME_KINDS.has(value);
4026
- }
4027
4508
  var HOST_PRODUCER_FRAME_ERROR_CODES = [
4028
4509
  "invalid_frame_encoding",
4029
4510
  "invalid_frame_length",
@@ -4033,444 +4514,217 @@ var HOST_PRODUCER_FRAME_ERROR_CODES = [
4033
4514
  "invalid_producer_identity",
4034
4515
  "frame_too_large"
4035
4516
  ];
4036
- var HostProducerFrameError = class extends Error {
4037
- code;
4038
- 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) {
4039
4531
  super(message);
4040
- 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";
4041
4540
  }
4042
4541
  };
4043
- function encodeHostProducerFrame(frame) {
4044
- validateFrame(frame);
4045
- const json = Buffer.from(JSON.stringify(frame), "utf8");
4046
- 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}`)}`);
4047
- const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
4048
- result.writeUInt32BE(json.byteLength, 0);
4049
- json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
4050
- return result;
4051
- }
4052
- function decodeHostProducerFrame(input) {
4053
- 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}`)}`);
4054
- const length = input.readUInt32BE(0);
4055
- 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}`)}`);
4056
- if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
4057
- 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");
4058
- const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
4059
- const text = new TextDecoder("utf-8", { fatal: true });
4060
- 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);
4061
4558
  try {
4062
- 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;
4063
4564
  } catch (error) {
4064
- if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
4065
- throw new HostProducerFrameError("frame_truncated");
4565
+ await handle.close();
4566
+ throw error;
4066
4567
  }
4067
- validateFrame(value);
4068
- return value;
4069
4568
  }
4070
- function isHostSafeRef(value) {
4071
- return safeRef(value);
4072
- }
4073
- function validateFrame(value) {
4074
- if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
4075
- 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)}`);
4076
- if (!exactKeys2(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
4077
- if (!PRODUCERS.has(String(value.producer_id)) || !safeRef(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
4078
- 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");
4079
- validatePayload(value.frame_kind, value.payload);
4080
- }
4081
- function validatePayload(kind, value) {
4082
- const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
4083
- if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
4084
- }
4085
- function validSession(value) {
4086
- 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
+ });
4087
4614
  }
4088
- function validTurn(value) {
4089
- 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.");
4090
4629
  }
4091
- function validInput(value) {
4092
- 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");
4093
4633
  }
4094
- function validInputObservations(value) {
4095
- 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);
4096
4636
  }
4097
- function validInputOptionals(value) {
4098
- 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;
4099
4639
  }
4100
- function validTerminal(value) {
4101
- 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());
4102
4643
  }
4103
- function validTerminalDisposition(state, reason) {
4104
- return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef(reason));
4105
- }
4106
- function validStatus(value) {
4107
- return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef(value.reason_code) && optionalText(value.detail, 4096);
4108
- }
4109
- function optionalText(value, maxLength) {
4110
- return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
4111
- }
4112
- function optionalNonNegative(value) {
4113
- return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
4114
- }
4115
- function optionalRefs(value) {
4116
- return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef);
4117
- }
4118
- function validObservations(value) {
4119
- if (value === void 0) return true;
4120
- if (!Array.isArray(value) || value.length > 32) return false;
4121
- return value.every((item) => {
4122
- try {
4123
- validateCealHostObservationDraft(item);
4124
- return true;
4125
- } catch {
4126
- return false;
4127
- }
4128
- });
4129
- }
4130
- function jsonValue(value, depth = 0) {
4131
- if (depth > 16) return false;
4132
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
4133
- if (typeof value === "number") return Number.isFinite(value);
4134
- if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
4135
- return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
4136
- }
4137
- function record(value) {
4138
- return value !== null && typeof value === "object" && !Array.isArray(value);
4139
- }
4140
- function safeRef(value) {
4141
- return typeof value === "string" && SAFE_REF3.test(value);
4142
- }
4143
- function positive(value) {
4144
- return Number.isSafeInteger(value) && Number(value) > 0;
4145
- }
4146
- function timestamp(value) {
4147
- return typeof value === "string" && Number.isFinite(Date.parse(value));
4148
- }
4149
- function hostProducerFrameKind(value) {
4150
- return isHostProducerFrameKind(value);
4151
- }
4152
- function exactKeys2(value, keys) {
4153
- return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
4154
- }
4155
- function exactOptional(value, required, optional) {
4156
- const keys = Object.keys(value);
4157
- 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;
4158
4647
  }
4159
4648
 
4160
4649
  // host/relay/src/host-producer-core.ts
4161
- import { createHash as createHash3 } from "node:crypto";
4162
- import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
4163
- import { mkdir as mkdir2, open as open3, readFile as readFile2, rename as rename2, writeFile } from "node:fs/promises";
4164
- import { join as join3 } from "node:path";
4165
-
4166
- // host/relay/src/relay-ipc.ts
4167
- import { createConnection, createServer } from "node:net";
4168
-
4169
- // host/relay/src/durable-atomic-replacement.ts
4170
- import { O_RDONLY } from "node:constants";
4171
- import { lstat, mkdir, open as open2, rename, unlink } from "node:fs/promises";
4172
- var DEFAULT_PORT = {
4173
- platform: process.platform,
4174
- mkdir: (path, options) => mkdir(path, options),
4175
- lstat: (path) => lstat(path),
4176
- open_file: (path) => open2(path, "wx", 384),
4177
- rename,
4178
- unlink,
4179
- open_directory: (path) => open2(path, O_RDONLY),
4180
- unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
4181
- };
4182
-
4183
- // host/relay/src/relay-request-binding-store.ts
4184
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
4185
-
4186
- // host/relay/src/current-prompt-custody.ts
4187
- var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
4188
-
4189
- // host/relay/src/relay-ipc.ts
4190
- var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
4191
- "schema_version",
4192
- "producer_id",
4193
- "producer_installation_ref",
4194
- "local_session_ref",
4195
- "local_turn_ref",
4196
- "local_turn_aliases",
4197
- "prompt_ref",
4198
- "request_ref",
4199
- "bound_at",
4200
- "host_source_ref",
4201
- "host_session_ref",
4202
- "host_turn_ref",
4203
- "host_input_ref"
4204
- ]);
4205
- var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
4206
- var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
4207
- var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
4208
- var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
4209
- var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
4210
- var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
4211
- var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
4212
- var HOST_RELAY_QUERY_RESPONSE_MAX_BYTES = 8192;
4213
- var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
4214
- "context_stale",
4215
- "context_expired",
4216
- "host_source_refused",
4217
- "host_credential_refused",
4218
- "gateway_unavailable",
4219
- "gateway_refused",
4220
- "gateway_response_invalid",
4221
- "gateway_rate_limited",
4222
- "producer_frame_invalid",
4223
- "deadline",
4224
- "cancelled",
4225
- "mint_failed",
4226
- "relay_failed",
4227
- "request_authority_unavailable",
4228
- "request_missing",
4229
- "authority_mismatch",
4230
- "host_source_mismatch",
4231
- "host_session_mismatch",
4232
- "host_turn_mismatch",
4233
- "host_input_mismatch",
4234
- "host_prompt_mismatch"
4235
- ]);
4236
- var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
4237
- "context_stale",
4238
- "context_expired",
4239
- "host_source_refused",
4240
- "host_credential_refused",
4241
- "gateway_unavailable",
4242
- "gateway_rate_limited",
4243
- "gateway_refused",
4244
- "gateway_response_invalid",
4245
- "producer_frame_invalid"
4246
- ]);
4247
- var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
4248
- var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
4249
- "permission_denied",
4250
- "socket_missing",
4251
- "connection_refused",
4252
- "closed_early",
4253
- "response_invalid",
4254
- "timed_out",
4255
- "cancelled",
4256
- "unavailable"
4257
- ]);
4258
- var HostRelayIpcError = class extends Error {
4259
- code;
4260
- /** Set only when the client-side socket exchange itself failed. */
4261
- failure;
4262
- constructor(code, message = code, failure2) {
4263
- super(message);
4264
- this.code = code;
4265
- this.failure = failure2;
4266
- }
4267
- };
4268
- function hostRelayExchangeFailure(error) {
4269
- return error instanceof HostRelayIpcError ? error.failure : void 0;
4270
- }
4271
- function socketErrorFailure(error) {
4272
- switch (errorCode2(error)) {
4273
- case "EACCES":
4274
- case "EPERM":
4275
- return "permission_denied";
4276
- case "ENOENT":
4277
- return "socket_missing";
4278
- case "ECONNREFUSED":
4279
- return "connection_refused";
4280
- default:
4281
- return "unavailable";
4282
- }
4283
- }
4284
- var HostRelayInvocationContextPort = class {
4285
- endpoint;
4286
- constructor(endpoint) {
4287
- this.endpoint = endpoint;
4288
- }
4289
- mintInvocationContext(input, signal) {
4290
- return queryHostRelayInvocationContext(this.endpoint, input, signal);
4291
- }
4292
- };
4293
- var HostRelayIpcAdmissionPort = class {
4294
- endpoint;
4295
- timeout_ms;
4296
- constructor(endpoint, timeoutMs = 5e3) {
4297
- this.endpoint = endpoint;
4298
- this.timeout_ms = timeoutMs;
4299
- }
4300
- async admit(frame) {
4301
- const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
4302
- if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
4303
- return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
4304
- }
4305
- };
4306
- var HostRelayCurrentPromptPort = class {
4307
- endpoint;
4308
- timeout_ms;
4309
- constructor(endpoint, timeoutMs = 5e3) {
4310
- this.endpoint = endpoint;
4311
- this.timeout_ms = timeoutMs;
4312
- }
4313
- async register(input) {
4314
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
4315
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
4316
- if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
4317
- }
4318
- };
4319
- function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
4320
- return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
4321
- }
4322
- function queryHostRelayInvocationContext(endpoint, query, signal) {
4323
- return exchange(endpoint, encodeInvocationContextQuery(query), void 0, decodeInvocationContextResponseBuffer, signal);
4324
- }
4325
- function exchange(endpoint, encoded, timeoutMs, decode, signal) {
4326
- return new Promise((resolve, reject2) => {
4327
- const socket = createConnection(endpoint);
4328
- let buffer = Buffer.alloc(0);
4329
- let settled = false;
4330
- const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
4331
- const finish = (error, response2) => {
4332
- if (settled) return;
4333
- settled = true;
4334
- signal?.removeEventListener("abort", aborted);
4335
- socket.destroy();
4336
- if (error !== null) reject2(error);
4337
- else if (response2 !== void 0) resolve(response2);
4338
- };
4339
- if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
4340
- if (signal?.aborted === true) {
4341
- aborted();
4342
- return;
4343
- }
4344
- signal?.addEventListener("abort", aborted, { once: true });
4345
- socket.once("error", (error) => {
4346
- const failure2 = socketErrorFailure(error);
4347
- finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure2}.`, failure2));
4348
- });
4349
- socket.once("connect", () => socket.write(encoded));
4350
- socket.on("data", (chunk) => {
4351
- try {
4352
- buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
4353
- const decoded = decode(buffer);
4354
- if (decoded !== null) finish(null, decoded);
4355
- } catch (error) {
4356
- finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
4357
- }
4358
- });
4359
- socket.once("end", () => {
4360
- if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
4361
- });
4362
- });
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);
4363
4653
  }
4364
- function decodeHostRelayIpcResponse(input) {
4365
- 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}`)}.`);
4366
- const length = input.readUInt32BE(0);
4367
- 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}` }])}.`);
4368
- 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);
4369
4660
  try {
4370
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
4371
- } catch {
4372
- 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();
4373
4669
  }
4374
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
4375
- return value;
4376
- }
4377
- function relayAdmissionCode(value) {
4378
- 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";
4379
- }
4380
- function validResponse(value) {
4381
- 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;
4382
- }
4383
- function hostRelayIpcCode(value) {
4384
- 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);
4385
- }
4386
- function nonnegative(value) {
4387
- return Number.isSafeInteger(value) && Number(value) >= 0;
4388
- }
4389
- function record2(value) {
4390
- return value !== null && typeof value === "object" && !Array.isArray(value);
4391
- }
4392
- function decodeResponseBuffer(buffer) {
4393
- if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
4394
- const length = buffer.readUInt32BE(0);
4395
- 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}`)}.`);
4396
- if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
4397
- 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}` }])}.`);
4398
- return decodeHostRelayIpcResponse(buffer);
4399
- }
4400
- function decodeInvocationContextResponseBuffer(buffer) {
4401
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_QUERY_RESPONSE_MAX_BYTES);
4402
- if (value === null) return null;
4403
- if (!validInvocationContextResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay invocation context response is invalid.");
4404
- return value;
4405
- }
4406
- function decodeCurrentPromptResponseBuffer(buffer) {
4407
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
4408
- if (value === null) return null;
4409
- if (!record2(value) || !exactKeys3(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "current_prompt_unavailable") throw new HostRelayIpcError("relay_unavailable");
4410
- return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
4411
- }
4412
- function encodeInvocationContextQuery(query) {
4413
- const value = { schema_version: HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA, ...query };
4414
- if (!validInvocationContextQueryRequest(value)) throw new HostRelayIpcError("invalid_frame_shape");
4415
- return encodeLengthPrefixed(value);
4416
- }
4417
- function validInvocationContextQueryRequest(value) {
4418
- 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));
4419
- }
4420
- function validQueryIdentity(value, schema) {
4421
- 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);
4422
- }
4423
- function validVisibleOutputBudget(value) {
4424
- return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES;
4425
4670
  }
4426
- function validInvocationContextResponse(value) {
4427
- if (!record2(value) || value.schema_version !== HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA) return false;
4428
- if (value.status === "no_binding") return Object.keys(value).length === 2;
4429
- if (value.status === "refused") return Object.keys(value).length === 3 && isVocabularyWord(HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS, value.reason);
4430
- if (value.status !== "ready" || Object.keys(value).length !== 3) return false;
4431
- try {
4432
- decodeCealHostInvocationAuthenticationResult(value.result);
4433
- return true;
4434
- } catch {
4435
- 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;
4436
4678
  }
4679
+ return output.subarray(0, offset);
4437
4680
  }
4438
- function decodeLengthPrefixedJson(input, maximum) {
4439
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
4440
- const length = input.readUInt32BE(0);
4441
- 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}`)}.`);
4442
- if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
4443
- 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) {
4444
4687
  try {
4445
- 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));
4446
4691
  } catch {
4447
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
4448
- }
4449
- }
4450
- function encodeLengthPrefixed(value) {
4451
- const body = Buffer.from(JSON.stringify(value), "utf8");
4452
- const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
4453
- output.writeUInt32BE(body.length, 0);
4454
- body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
4455
- return output;
4456
- }
4457
- function exactKeys3(value, required, optional = []) {
4458
- const keys = Object.keys(value);
4459
- return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
4460
- }
4461
- function safeRef2(value) {
4462
- return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
4463
- }
4464
- function errorCode2(error) {
4465
- return record2(error) && typeof error.code === "string" ? error.code : null;
4466
- }
4467
-
4468
- // host/relay/src/host-producer-core.ts
4469
- var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
4470
- function isHostTranscriptCursorReason(value) {
4471
- return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
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);
4713
+ }
4714
+ return boundCealHostInvocationHumanMessageWindow(newestFirst, truncated);
4715
+ }
4716
+ function transcriptScanFailureKind(error, adapterFailureKind) {
4717
+ if (transcriptErrorCode(error) === "ELOOP") return "symlink";
4718
+ const adapter = adapterFailureKind(error);
4719
+ if (adapter !== void 0) return adapter;
4720
+ const code = transcriptErrorCode(error);
4721
+ if (code === "EFBIG") return "size_budget";
4722
+ if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
4723
+ return "other";
4724
+ }
4725
+ function transcriptErrorCode(error) {
4726
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
4472
4727
  }
4473
- var TRANSCRIPT_MISSING_REASON = "transcript_missing";
4474
4728
  var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
4475
4729
  async function readTranscriptCompleteChunk(handle, offset, size) {
4476
4730
  const available = Math.max(0, size - offset);
@@ -4515,10 +4769,10 @@ async function transcriptCursorBoundsReason(handle, cursor, size) {
4515
4769
  return null;
4516
4770
  }
4517
4771
  function transcriptSha256(value) {
4518
- return createHash3("sha256").update(value).digest("hex");
4772
+ return createHash4("sha256").update(value).digest("hex");
4519
4773
  }
4520
4774
  function transcriptObjectSha256(value) {
4521
- return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
4775
+ return createHash4("sha256").update(JSON.stringify(value), "utf8").digest("hex");
4522
4776
  }
4523
4777
  function isTranscriptRecord(value) {
4524
4778
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -4587,11 +4841,10 @@ var HostTranscriptWatcher = class {
4587
4841
  async openTranscript(registration, scan, handlers) {
4588
4842
  let handle;
4589
4843
  try {
4590
- handle = await open3(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
4844
+ handle = await openNoFollow(this.transcriptPathOf(registration));
4591
4845
  return await scan(handle);
4592
4846
  } catch (error) {
4593
4847
  if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
4594
- if (hostRelayExchangeFailure(error) !== void 0) throw error;
4595
4848
  return handlers.failed(handle, error);
4596
4849
  } finally {
4597
4850
  await handle?.close();
@@ -4637,29 +4890,12 @@ var HostTranscriptWatcher = class {
4637
4890
  return transcriptCursorBoundsReason(handle, cursor, size);
4638
4891
  }
4639
4892
  };
4640
- var HOST_PRODUCER_STATE_IDENTITY = {
4641
- codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
4642
- claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
4643
- };
4644
4893
  var HostProducerDrainCore = class {
4645
4894
  host;
4646
- relay;
4647
- statePath;
4648
- stateSchema;
4649
- installationRef;
4650
- epoch;
4651
4895
  now;
4652
4896
  tail = Promise.resolve();
4653
4897
  constructor(host, runtime) {
4654
- if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
4655
- const epoch = runtime.producer_epoch ?? 1;
4656
- if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
4657
4898
  this.host = host;
4658
- this.relay = runtime.relay;
4659
- this.statePath = join3(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
4660
- this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
4661
- this.installationRef = runtime.producer_installation_ref;
4662
- this.epoch = epoch;
4663
4899
  this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
4664
4900
  }
4665
4901
  drainOutbox() {
@@ -4669,156 +4905,563 @@ var HostProducerDrainCore = class {
4669
4905
  }
4670
4906
  async drainLocked() {
4671
4907
  const read = await this.host.listEnvelopes();
4672
- let admitted = 0;
4908
+ let removed = 0;
4673
4909
  let expired = 0;
4674
- let retained = 0;
4675
4910
  for (const envelope of read.entries) {
4676
- const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
4677
- if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
4678
- await this.host.removeEnvelope(envelope);
4679
- expired += 1;
4680
- 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;
4681
5130
  }
4682
- const frames = await this.reserve(envelope);
4683
- let complete = true;
4684
- for (const frame of frames) {
4685
- const outcome = await this.relay.admit(frame);
4686
- if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
4687
- complete = false;
4688
- break;
4689
- }
5131
+ if (frame !== null) {
5132
+ buffer = frame.rest;
5133
+ resolve({ value: frame.value, rest: Buffer.alloc(0) });
5134
+ return;
4690
5135
  }
4691
- if (!complete) {
4692
- retained += 1;
4693
- 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);
4694
5143
  }
4695
- await this.host.removeEnvelope(envelope);
4696
- await this.release(this.host.submissionRefOf(envelope));
4697
- admitted += 1;
4698
5144
  }
4699
- return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
4700
- }
4701
- async hasReservation(submissionRef) {
4702
- return (await this.readState()).pending[submissionRef] !== void 0;
4703
- }
4704
- async reserve(envelope) {
4705
- const state = await this.readState();
4706
- const submissionRef = this.host.submissionRefOf(envelope);
4707
- const existing = state.pending[submissionRef];
4708
- if (existing !== void 0) return existing;
4709
- const drafts = await this.host.mapEnvelope(envelope);
4710
- const frames = drafts.map((draft, offset) => ({
4711
- schema_version: "ceal.host_producer_frame.v1",
4712
- producer_id: this.host.producer_id,
4713
- producer_installation_ref: this.installationRef,
4714
- producer_epoch: this.epoch,
4715
- sequence: state.next_sequence + offset,
4716
- frame_kind: draft.frame_kind,
4717
- occurred_at: this.host.createdAtOf(envelope),
4718
- payload: draft.payload
4719
- }));
4720
- await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
4721
- 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();
5190
+ }
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;
4722
5228
  }
4723
- async release(submissionRef) {
4724
- const state = await this.readState();
4725
- if (state.pending[submissionRef] === void 0) return;
4726
- const pending = { ...state.pending };
4727
- delete pending[submissionRef];
4728
- await this.writeState({ ...state, pending });
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;
4729
5254
  }
4730
- async readState() {
4731
- try {
4732
- const value = JSON.parse(await readFile2(this.statePath, "utf8"));
4733
- return this.decodeState(value);
4734
- } catch (error) {
4735
- if (errorCode3(error) !== "ENOENT") throw error;
4736
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
4737
- }
5255
+ mintInvocationContext(input, signal) {
5256
+ return queryHostRelayInvocationContext(this.endpoint, input, this.timeout_ms, signal, this.pipe_key);
4738
5257
  }
4739
- async writeState(state) {
4740
- await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
4741
- const temporary = `${this.statePath}.${process.pid}.new`;
4742
- await writeFile(temporary, JSON.stringify(state), { mode: 384 });
4743
- await rename2(temporary, this.statePath);
4744
- }
4745
- decodeState(value) {
4746
- const label = this.host.producer_label;
4747
- const fail = (code, message) => this.host.fail(code, message);
4748
- if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
4749
- throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
4750
- { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
4751
- { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
4752
- ])}).`);
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;
4753
5280
  }
4754
- 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}`)}).`);
4755
- const pending = {};
4756
- const storedEpoch = Number(value.producer_epoch);
4757
- for (const [submissionRef, frames] of Object.entries(value.pending)) {
4758
- if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
4759
- 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);
4760
5317
  }
4761
- return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
4762
- }
4763
- decodeStoredFrame(value, storedEpoch) {
4764
- const label = this.host.producer_label;
4765
- const json = Buffer.from(JSON.stringify(value), "utf8");
4766
- const encoded = Buffer.allocUnsafe(json.length + 4);
4767
- encoded.writeUInt32BE(json.length, 0);
4768
- json.copy(encoded, 4);
4769
- const frame = decodeHostProducerFrame(encoded);
4770
- 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([
4771
- { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
4772
- { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
4773
- { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
4774
- ])}).`);
4775
- 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;
4776
5348
  }
4777
- };
4778
- function isDrainStateHeader(value, schema, installationRef) {
4779
- 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);
4780
5397
  }
4781
5398
  function errorCode3(error) {
4782
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
5399
+ return record(error) && typeof error.code === "string" ? error.code : null;
4783
5400
  }
4784
5401
 
4785
- // host/relay/src/relay-quarantine-store.ts
4786
- var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
4787
- var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
4788
- var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
4789
-
4790
- // host/relay/src/relay-admission-store.ts
4791
- var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
4792
- var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
4793
- var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
4794
-
4795
5402
  // host/service-log.ts
4796
- function writeHostServiceDiagnostic(producer_id, event, failure_kind) {
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
+ `;
4797
5409
  try {
4798
- process.stderr.write(`${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {} })}
4799
- `);
5410
+ (sink ?? defaultHostServiceDiagnosticSink)(line);
4800
5411
  } catch {
4801
5412
  }
4802
5413
  }
5414
+ function defaultHostServiceDiagnosticSink(line) {
5415
+ writeHostServiceLogLine(line);
5416
+ process.stderr.write(line);
5417
+ }
4803
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
+ }
4804
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
+ }
5443
+
5444
+ // host/local-capability-descriptor.ts
5445
+ var HOST_LOCAL_CAPABILITY_AUTHENTICATION_SUFFIX = Object.freeze(["authenticate", "--client-nonce"]);
4805
5446
 
4806
5447
  // host/invocation-authentication-command.ts
4807
- var HOST_INVOCATION_AUTHENTICATION_COMMAND_PREFIX = ["authenticate", "--client-nonce"];
4808
- var HOST_AUTHENTICATION_BUDGET_ENVIRONMENT = "CEAL_HOST_AUTHENTICATION_BUDGET_MS";
4809
5448
  var HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS = 2e4;
4810
5449
  var CODEX_CONTEXT_ACTIVATION_WAIT_MAX_MS = HOST_CONTEXT_ACTIVATION_WAIT_MAX_MS;
4811
5450
  var HOST_AUTHENTICATION_COMPLETION_RESERVE_MS = 5e3;
4812
5451
  var INVOCATION_CONTEXT_POLL_INTERVAL_MS = 250;
4813
5452
  var REFUSAL_REASON_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
4814
5453
  function installedHostInvocationAuthenticationCommandOptions(config, contextBudgetMs, maxContextWaitMs) {
4815
- 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
+ };
4816
5459
  return {
4817
5460
  host_source_ref: config.host_source_ref,
4818
5461
  outbox_dir: config.outbox_dir,
4819
5462
  producer_installation_ref: config.producer_installation_ref,
4820
5463
  context_activation_wait_ms: boundedContextActivationWait(contextBudgetMs, config.ipc_timeout_ms, maxContextWaitMs),
4821
- 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)
4822
5465
  };
4823
5466
  }
4824
5467
  async function runHostInvocationAuthenticationCommand(descriptor2, args, options) {
@@ -4839,26 +5482,31 @@ function authenticationRefusalReason(error) {
4839
5482
  return isCealHostAuthenticationCause(message) ? message : "host_refusal_invalid";
4840
5483
  }
4841
5484
  async function authenticateHostInvocation(descriptor2, input, options) {
4842
- 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");
4843
5486
  const request2 = decodeCealHostInvocationAuthenticationRequest({ schema_version: CEAL_HOST_INVOCATION_AUTHENTICATION_REQUEST_SCHEMA, client_nonce: input[2] });
4844
5487
  const config = validateOptions(options);
4845
5488
  const now = config.now ?? (() => /* @__PURE__ */ new Date());
4846
5489
  const { store, current } = await currentInvocation(descriptor2, config, now);
4847
5490
  if (config.mint_invocation_context === void 0) throw new TypeError("relay_failed");
4848
- const query = {
4849
- producer_id: descriptor2.producer_id,
4850
- producer_installation_ref: config.producer_installation_ref,
4851
- local_session_ref: current.identity.host_session_ref,
4852
- local_turn_ref: current.identity.host_turn_ref,
4853
- client_nonce: request2.client_nonce,
4854
- ...await visibleOutputBudget(descriptor2)
4855
- };
5491
+ const query = await invocationMintQuery(descriptor2, store, current, request2.client_nonce, config);
4856
5492
  const response2 = await mintedResult(config.mint_invocation_context, query);
4857
5493
  const completedAt = now();
4858
5494
  const rechecked = await store.readInvocationContext(current.identity.host_source_ref, current.identity.host_session_ref, completedAt);
4859
5495
  if (rechecked === null || !sameTurn(current, rechecked)) throw new TypeError("context_replaced");
4860
5496
  return decodeCealHostInvocationAuthenticationResult(response2.result, completedAt);
4861
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
+ }
4862
5510
  async function visibleOutputBudget(descriptor2) {
4863
5511
  const bytes = await descriptor2.resolve_visible_output_max_bytes?.();
4864
5512
  return bytes === void 0 ? {} : { visible_output_max_bytes: bytes };
@@ -4868,30 +5516,15 @@ async function mintedResult(mint, query) {
4868
5516
  try {
4869
5517
  response2 = await mint(query);
4870
5518
  } catch (error) {
4871
- throw new TypeError(exchangeFailureCause(hostRelayExchangeFailure(error) ?? "unavailable"));
5519
+ throw new TypeError(cealHostAuthenticationCauseForExchangeFailure(hostRelayExchangeFailure(error) ?? "unavailable"));
4872
5520
  }
4873
- if (response2.status === "refused") throw new TypeError(mintRefusalCause(response2.reason));
4874
- 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");
4875
5522
  return response2;
4876
5523
  }
4877
- function mintRefusalCause(reason) {
4878
- if (isDirectMintRefusalCause(reason)) return reason;
4879
- if (reason === "deadline" || reason === "cancelled") return "transient_retryable";
4880
- if (reason === "mint_failed" || reason === "relay_failed") return reason;
4881
- return isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, reason) ? "context_stale" : "host_refusal_invalid";
4882
- }
4883
- function isDirectMintRefusalCause(reason) {
4884
- return isVocabularyWord(HOST_RELAY_DIRECT_WIRE_MINT_REASONS, reason);
4885
- }
4886
- function exchangeFailureCause(failure2) {
4887
- if (failure2 === "permission_denied") return "relay_permission_denied";
4888
- if (failure2 === "timed_out") return "transient_retryable";
4889
- return "relay_unavailable";
4890
- }
4891
5524
  async function currentInvocation(descriptor2, config, now) {
4892
5525
  const store = descriptor2.create_store(config.outbox_dir);
4893
5526
  const identity = resolveIdentity(descriptor2, config);
4894
- if (identity.status !== "ready") throw new TypeError(identity.status);
5527
+ if (identity.status === "session_unavailable") throw new TypeError("no_binding");
4895
5528
  const waitBudgetMs = config.context_activation_wait_ms ?? 0;
4896
5529
  const monotonicNow = config.monotonic_now ?? (() => performance.now());
4897
5530
  const deadline = monotonicNow() + waitBudgetMs;
@@ -4899,36 +5532,36 @@ async function currentInvocation(descriptor2, config, now) {
4899
5532
  let waitEngaged = false;
4900
5533
  while (true) {
4901
5534
  if (!firstCheck && monotonicNow() >= deadline) {
4902
- recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs);
5535
+ recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs, config.diagnostic_sink);
4903
5536
  throw new TypeError("context_unavailable");
4904
5537
  }
4905
5538
  firstCheck = false;
4906
5539
  const observedAt = now();
4907
5540
  const current = await readLiveSessionContext(store, identity.identity.host_source_ref, identity.identity.host_session_ref, observedAt);
4908
5541
  if (current !== null) {
4909
- recordActivationWaitCompletion(descriptor2.producer_id, waitEngaged);
5542
+ recordActivationWaitCompletion(descriptor2.producer_id, waitEngaged, config.diagnostic_sink);
4910
5543
  return { store, current };
4911
5544
  }
4912
5545
  const remainingMs = deadline - monotonicNow();
4913
5546
  if (remainingMs <= 0) {
4914
- recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs);
5547
+ recordActivationWaitExhaustion(descriptor2.producer_id, waitEngaged, waitBudgetMs, config.diagnostic_sink);
4915
5548
  throw new TypeError("context_unavailable");
4916
5549
  }
4917
- recordActivationWaitEngagement(descriptor2.producer_id, waitEngaged);
5550
+ recordActivationWaitEngagement(descriptor2.producer_id, waitEngaged, config.diagnostic_sink);
4918
5551
  waitEngaged = true;
4919
5552
  const intervalMs = Math.min(INVOCATION_CONTEXT_POLL_INTERVAL_MS, remainingMs);
4920
5553
  await (config.wait ?? waitForContextActivation)(intervalMs);
4921
5554
  }
4922
5555
  }
4923
- function recordActivationWaitExhaustion(producer, engaged, budgetMs) {
4924
- if (engaged || budgetMs > 0) writeHostServiceDiagnostic(producer, "activation_wait_exhausted");
4925
- else writeHostServiceDiagnostic(producer, "activation_wait_skipped");
5556
+ function recordActivationWaitExhaustion(producer, engaged, budgetMs, sink) {
5557
+ if (engaged || budgetMs > 0) writeHostServiceDiagnostic(producer, "activation_wait_exhausted", void 0, void 0, sink);
5558
+ else writeHostServiceDiagnostic(producer, "activation_wait_skipped", void 0, void 0, sink);
4926
5559
  }
4927
- function recordActivationWaitCompletion(producer, engaged) {
4928
- if (engaged) writeHostServiceDiagnostic(producer, "activation_wait_completed");
5560
+ function recordActivationWaitCompletion(producer, engaged, sink) {
5561
+ if (engaged) writeHostServiceDiagnostic(producer, "activation_wait_completed", void 0, void 0, sink);
4929
5562
  }
4930
- function recordActivationWaitEngagement(producer, engaged) {
4931
- if (!engaged) writeHostServiceDiagnostic(producer, "activation_wait_engaged");
5563
+ function recordActivationWaitEngagement(producer, engaged, sink) {
5564
+ if (!engaged) writeHostServiceDiagnostic(producer, "activation_wait_engaged", void 0, void 0, sink);
4932
5565
  }
4933
5566
  async function readLiveSessionContext(store, hostSourceRef, hostSessionRef, now) {
4934
5567
  const current = await store.readInvocationContext(hostSourceRef, hostSessionRef, now);
@@ -4955,9 +5588,9 @@ async function resolveOptions(descriptor2, args, options) {
4955
5588
  };
4956
5589
  }
4957
5590
  function authenticationBudgetMsFromEnvironment() {
4958
- const value = process.env[HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
5591
+ const value = process.env[CEAL_HOST_AUTHENTICATION_BUDGET_ENVIRONMENT];
4959
5592
  if (value === void 0) return 0;
4960
- 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");
4961
5594
  return Number(value);
4962
5595
  }
4963
5596
  function boundedContextActivationWait(contextBudgetMs, relayTimeoutMs, maxContextWaitMs) {
@@ -4994,16 +5627,16 @@ function writeResult(value, sink) {
4994
5627
  }
4995
5628
 
4996
5629
  // host/producer-service.ts
4997
- import { posix as posix3, win32 as win323 } from "node:path";
5630
+ import { posix as posix4, win32 as win326 } from "node:path";
4998
5631
 
4999
5632
  // host/runtime-source-paths.ts
5000
- import { createHash as createHash4 } from "node:crypto";
5001
- 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";
5002
5635
 
5003
5636
  // host/absolute-path.ts
5004
- import { posix, win32 } from "node:path";
5637
+ import { posix as posix2, win32 as win324 } from "node:path";
5005
5638
  function isAbsoluteNormalizedNonRootPath(value, flavor = process.platform, allowRoot = false) {
5006
- const pathApi = flavor === "win32" || flavor === "windows" ? win32 : posix;
5639
+ const pathApi = flavor === "win32" || flavor === "windows" ? win324 : posix2;
5007
5640
  return typeof value === "string" && value.length <= 4096 && !value.includes("\0") && pathApi.isAbsolute(value) && pathApi.normalize(value) === value && (allowRoot || pathApi.parse(value).root !== value);
5008
5641
  }
5009
5642
 
@@ -5015,28 +5648,23 @@ function hostSourceUuid(sourceRef) {
5015
5648
  function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platform) {
5016
5649
  const sourceId = hostSourceUuid(sourceRef);
5017
5650
  if (!isAbsoluteNormalizedNonRootPath(stateRoot, platform) || sourceId === null) throw new TypeError("Host runtime source identity is invalid.");
5018
- const path = platform === "win32" ? win322 : posix2;
5651
+ const path = platform === "win32" ? win325 : posix3;
5019
5652
  const sourcesRoot = path.join(stateRoot, "sources");
5020
5653
  const sourceRoot = path.join(sourcesRoot, sourceId);
5021
5654
  const runtimeRoot = path.join(stateRoot, "run");
5022
- const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash4("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
5023
- 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`);
5024
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 };
5025
5657
  }
5026
- function assertHostRuntimeIpcLength(endpoint, platform) {
5027
- if (platform === "win32") return;
5028
- const maximum = platform === "linux" ? 107 : 103;
5029
- 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" });
5030
- }
5031
5658
  function assertHostProducerSourcePaths(stateRoot, config, producer, platform = process.platform) {
5032
5659
  const paths = hostRuntimeSourcePaths(stateRoot, config.host_source_ref, platform);
5033
- 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;
5034
5662
  }
5035
5663
 
5036
5664
  // host/producer-service.ts
5037
- import { constants } from "node:fs";
5038
- import { lstat as lstat2, open as open4 } from "node:fs/promises";
5039
- 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;
5040
5668
  var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
5041
5669
  var HostProducerServiceError = class extends Error {
5042
5670
  code;
@@ -5047,18 +5675,19 @@ var HostProducerServiceError = class extends Error {
5047
5675
  }
5048
5676
  };
5049
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";
5050
5679
  var HOST_PRODUCER_TIMING_DEFAULTS = Object.freeze({ reconcile_interval_ms: 250, retry_backoff_ms: 1e3, ipc_timeout_ms: 5e3 });
5051
5680
  function hostProducerExtraPath(extras, key) {
5052
5681
  const value = extras[key];
5053
- if (value === void 0) throw hostProducerError("invalid_config");
5682
+ if (value === void 0) throw hostProducerError("invalid_config", refusalFact(key, "missing", "an absolute path"));
5054
5683
  return value;
5055
5684
  }
5056
5685
  function parseHostProducerConfigFlag(args, platform = process.platform) {
5057
5686
  return parseProducerHostConfigFlag(args, HOST_PRODUCER_CONFIG_FLAG, platform, hostProducerError);
5058
5687
  }
5059
- async function readHostProducerConfig(descriptor2, configPath, platform = process.platform) {
5060
- const config = decodeHostProducerConfigText(descriptor2, await readProducerConfigText(configPath, platform, hostProducerError), platform);
5061
- 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;
5062
5691
  const root = path.resolve(config.outbox_dir, "../../../../..");
5063
5692
  try {
5064
5693
  assertHostProducerSourcePaths(root, config, descriptor2.producer_id, platform);
@@ -5084,15 +5713,31 @@ function parseProducerHostConfigFlag(args, flag, platform, error) {
5084
5713
  assertProducerAbsolutePath(value, platform, "config", error);
5085
5714
  return value;
5086
5715
  }
5087
- async function readProducerConfigText(configPath, platform, error) {
5088
- 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
+ }
5089
5735
  const pathStat = await configPathStat(configPath, error);
5090
5736
  validateConfigFile(pathStat, platform, error);
5091
- const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
5092
- const handle = await openConfigFile(configPath, constants.O_RDONLY | noFollow, error);
5737
+ const handle = await openConfigFile(configPath, platform, error, custody);
5093
5738
  try {
5094
5739
  const opened = await handle.stat();
5095
- validateConfigFile(opened, platform, error);
5740
+ validateConfigFile(opened, platform, error, handle);
5096
5741
  validateOpenedFile(opened, pathStat, platform, error);
5097
5742
  return await readBoundedConfig(handle, opened.size, error);
5098
5743
  } finally {
@@ -5100,8 +5745,9 @@ async function readProducerConfigText(configPath, platform, error) {
5100
5745
  }
5101
5746
  }
5102
5747
  function decodeProducerConfigCore(text, options) {
5748
+ const ownership = producerConfigKeyOwnership(options.keys, options.platform);
5103
5749
  const value = parseCanonicalJson(text, options.error);
5104
- 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 })));
5105
5751
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
5106
5752
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
5107
5753
  const producerEpoch = validateIdentity(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -5119,14 +5765,21 @@ function decodeProducerConfigCore(text, options) {
5119
5765
  producer_installation_ref: installationRef,
5120
5766
  producer_epoch: producerEpoch,
5121
5767
  outbox_dir: value.outbox_dir,
5122
- relay_endpoint: value.relay_endpoint,
5768
+ relay_endpoint: producerConfigEndpoint(value),
5123
5769
  reconcile_interval_ms: intervals[0],
5124
5770
  retry_backoff_ms: intervals[1],
5125
5771
  ipc_timeout_ms: intervals[2]
5126
5772
  };
5127
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
+ }
5128
5781
  function assertProducerRelayEndpoint(value, platform, error) {
5129
- 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;
5130
5783
  assertProducerAbsolutePath(value, platform, "runtime", error);
5131
5784
  }
5132
5785
  function assertProducerAbsolutePath(value, platform, kind, error) {
@@ -5134,26 +5787,27 @@ function assertProducerAbsolutePath(value, platform, kind, error) {
5134
5787
  }
5135
5788
  async function configPathStat(configPath, error) {
5136
5789
  try {
5137
- return await lstat2(configPath);
5790
+ return await lstat3(configPath);
5138
5791
  } catch {
5139
5792
  throw error("config_unavailable");
5140
5793
  }
5141
5794
  }
5142
- function validateConfigFile(value, platform, error) {
5795
+ function validateConfigFile(value, platform, error, handle) {
5143
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" }]));
5144
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}`));
5145
- 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" }]));
5146
5799
  }
5147
- async function openConfigFile(configPath, flags, error) {
5800
+ async function openConfigFile(configPath, platform, error, custody) {
5148
5801
  try {
5149
- return await open4(configPath, flags);
5150
- } 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");
5151
5805
  throw error("config_unavailable");
5152
5806
  }
5153
5807
  }
5154
5808
  function validateOpenedFile(opened, pathStat, platform, error) {
5155
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" }]));
5156
- 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) }]));
5157
5811
  }
5158
5812
  async function readBoundedConfig(handle, expectedBytes, error) {
5159
5813
  const buffer = Buffer.allocUnsafe(expectedBytes + 1);
@@ -5185,34 +5839,58 @@ function firstDifferenceIndex(left, right) {
5185
5839
  for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
5186
5840
  return shared;
5187
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
+ }
5188
5853
  function validateIdentity(sourceRef, installationRef, epoch, error) {
5189
- 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)));
5190
5855
  return epoch;
5191
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
+ }
5192
5864
  function validateIntervals(reconcile, retry, timeout, error) {
5193
- 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)));
5194
5866
  return [reconcile, retry, timeout];
5195
5867
  }
5196
- function hasConfigKeys(value, required) {
5197
- 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;
5198
5874
  }
5199
- 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) {
5200
5879
  return value !== null && typeof value === "object" && !Array.isArray(value);
5201
5880
  }
5202
- function positive2(value, maximum) {
5881
+ function positive(value, maximum) {
5203
5882
  return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
5204
5883
  }
5205
5884
  function boundedMilliseconds(value) {
5206
- return positive2(value, 6e4) && Number(value) >= 25;
5885
+ return positive(value, 6e4) && Number(value) >= 25;
5207
5886
  }
5208
5887
 
5209
5888
  // host/codex/src/codex-decoder.ts
5210
- import { createHash as createHash5 } from "node:crypto";
5889
+ import { createHash as createHash6 } from "node:crypto";
5211
5890
 
5212
5891
  // host/codex/src/codex-types.ts
5213
5892
  var CODEX_THREAD_ID_ENVIRONMENT = "CODEX_THREAD_ID";
5214
5893
  var CODEX_OUTBOX_SCHEMA_VERSION = "ceal.codex_observation_outbox.v1";
5215
- var CODEX_TURN_BINDING_SCHEMA_VERSION = "ceal.codex_turn_binding.v1";
5216
5894
  var CODEX_SESSION_SCHEMA_VERSION = "ceal.codex_session.v1";
5217
5895
  var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1";
5218
5896
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
@@ -5228,20 +5906,20 @@ var CodexHostAdapterError = class extends Error {
5228
5906
  };
5229
5907
 
5230
5908
  // host/codex/src/codex-decoder.ts
5231
- 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;
5232
5910
  var MAX_PAYLOAD_BYTES = 512 * 1024;
5233
- function observationRef(event, identity, value) {
5234
- 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 }));
5235
5913
  }
5236
5914
  function hostSessionReference(sourceRef, sessionId) {
5237
5915
  return `codex-session:${shortDigest({ source_ref: sourceRef, session_id: sessionId })}`;
5238
5916
  }
5239
5917
  function hostTurnReference(sourceRef, sessionRef, nativeTurnId) {
5240
- 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.");
5241
5919
  return `codex-turn:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId })}`;
5242
5920
  }
5243
5921
  function hostInputReference(sourceRef, sessionRef, nativeTurnId, messageId, ordinal, prompt) {
5244
- 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) {
5245
5923
  throw new CodexHostAdapterError("invalid_input", "Codex input identity is invalid.");
5246
5924
  }
5247
5925
  return `codex-input:${shortDigest({ source_ref: sourceRef, session_ref: sessionRef, native_turn_id: nativeTurnId, message_id: messageId, ordinal, prompt_sha256: sha256(prompt) })}`;
@@ -5253,25 +5931,24 @@ function turnObservationValue(sessionId, turnRef, status) {
5253
5931
  return { status, host_session_id_sha256: sha256(sessionId), host_turn_ref: turnRef };
5254
5932
  }
5255
5933
  function sha256(value) {
5256
- return createHash5("sha256").update(value, "utf8").digest("hex");
5934
+ return createHash6("sha256").update(value, "utf8").digest("hex");
5257
5935
  }
5258
5936
  function shortDigest(value) {
5259
5937
  return cealRequestSha256(value);
5260
5938
  }
5261
5939
 
5262
5940
  // host/codex/src/codex-outbox.ts
5263
- import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
5264
- import { lstat as lstat3, mkdir as mkdir3, open as open5, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
5265
- 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";
5266
5943
 
5267
5944
  // host/invocation-context.ts
5268
- 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";
5269
5946
  var HOST_INVOCATION_CONTEXT_REQUIRED_KEYS = ["schema_version", "identity", "prompt_ref", "expires_at"];
5270
5947
  function invocationContextKey(identity) {
5271
5948
  return cealRequestSha256({ host_source_ref: identity.host_source_ref, host_session_ref: identity.host_session_ref });
5272
5949
  }
5273
5950
  function hasHostInvocationIdentityKeys(value) {
5274
- return exactKeys4(value, HOST_INVOCATION_IDENTITY_KEYS);
5951
+ return exactKeys3(value, CEAL_HOST_INVOCATION_IDENTITY_KEYS);
5275
5952
  }
5276
5953
  function hasHostInvocationContextKeys(value, optional = []) {
5277
5954
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
@@ -5297,12 +5974,9 @@ function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor2)
5297
5974
  return Object.freeze(context);
5298
5975
  }
5299
5976
  function isHostInvocationTurnSelection(value) {
5300
- 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]));
5301
5978
  }
5302
- function invocationTurnSelectionMatches(context, selection) {
5303
- 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;
5304
- }
5305
- function exactKeys4(value, keys) {
5979
+ function exactKeys3(value, keys) {
5306
5980
  const actual = Object.keys(value);
5307
5981
  return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
5308
5982
  }
@@ -5311,10 +5985,10 @@ function requiredKeys(value, required, optional) {
5311
5985
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
5312
5986
  return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
5313
5987
  }
5314
- function isRecord3(value) {
5988
+ function isRecord5(value) {
5315
5989
  return value !== null && typeof value === "object" && !Array.isArray(value);
5316
5990
  }
5317
- function safeRef3(value) {
5991
+ function safeRef2(value) {
5318
5992
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
5319
5993
  }
5320
5994
 
@@ -5330,59 +6004,40 @@ function validateCodexHostInvocationContext(value) {
5330
6004
  validateContextReferences(value);
5331
6005
  validateContextTimes(value);
5332
6006
  }
5333
- function invocationContextFromBinding(binding, turnGenerationRef) {
5334
- const context = {
5335
- schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
5336
- identity: binding.identity,
5337
- prompt_ref: binding.prompt_ref,
5338
- request_ref: binding.request_ref,
5339
- bound_at: binding.bound_at,
5340
- expires_at: binding.expires_at,
5341
- ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
5342
- };
5343
- validateCodexHostInvocationContext(context);
5344
- return Object.freeze(context);
5345
- }
5346
6007
  function validateIdentity2(value) {
5347
- 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)) {
5348
6009
  throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
5349
6010
  }
5350
6011
  }
5351
6012
  function isContextShape(value) {
5352
- 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;
5353
6014
  }
5354
6015
  function validateContextReferences(value) {
5355
- 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.");
5356
6017
  }
5357
6018
  function validateContextTimes(value) {
5358
6019
  const expiresAt = value.expires_at;
5359
- const boundAt = value.bound_at;
5360
- if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
5361
- 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.");
5362
6021
  }
5363
6022
  function optionalSafeRef(value) {
5364
- return value === void 0 || safeRef4(value);
5365
- }
5366
- function optionalTimestamp(value) {
5367
- return value === void 0 || timestamp2(value);
6023
+ return value === void 0 || safeRef3(value);
5368
6024
  }
5369
- function safeRef4(value) {
6025
+ function safeRef3(value) {
5370
6026
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
5371
6027
  }
5372
- function timestamp2(value) {
6028
+ function timestamp(value) {
5373
6029
  return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
5374
6030
  }
5375
- function isRecord4(value) {
6031
+ function isRecord6(value) {
5376
6032
  return value !== null && typeof value === "object" && !Array.isArray(value);
5377
6033
  }
5378
6034
 
5379
6035
  // host/codex/src/codex-outbox.ts
5380
- 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;
5381
6037
  var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
5382
6038
  var CodexOutboxStore = class {
5383
6039
  directory;
5384
6040
  entriesDirectory;
5385
- bindingsDirectory;
5386
6041
  sessionsDirectory;
5387
6042
  activeContextsDirectory;
5388
6043
  turnSelectionsDirectory;
@@ -5392,7 +6047,6 @@ var CodexOutboxStore = class {
5392
6047
  if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
5393
6048
  this.directory = directory;
5394
6049
  this.entriesDirectory = join4(directory, "entries");
5395
- this.bindingsDirectory = join4(directory, "bindings");
5396
6050
  this.sessionsDirectory = join4(directory, "sessions");
5397
6051
  this.activeContextsDirectory = join4(directory, "active-contexts");
5398
6052
  this.turnSelectionsDirectory = join4(directory, "turn-selections");
@@ -5400,8 +6054,8 @@ var CodexOutboxStore = class {
5400
6054
  this.cursorsDirectory = join4(directory, "transcript-cursors");
5401
6055
  }
5402
6056
  async prepare() {
5403
- for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
5404
- 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);
5405
6059
  }
5406
6060
  }
5407
6061
  async put(entry) {
@@ -5416,7 +6070,7 @@ var CodexOutboxStore = class {
5416
6070
  for (const name of await readdir(this.entriesDirectory)) {
5417
6071
  if (!name.endsWith(".json")) continue;
5418
6072
  try {
5419
- const value = JSON.parse(await readPrivateFile(join4(this.entriesDirectory, name)));
6073
+ const value = JSON.parse(await readOwnerStateFile(join4(this.entriesDirectory, name)));
5420
6074
  validateEnvelope(value);
5421
6075
  entries.push(value);
5422
6076
  } catch {
@@ -5429,16 +6083,11 @@ var CodexOutboxStore = class {
5429
6083
  async remove(entry) {
5430
6084
  validateEnvelope(entry);
5431
6085
  try {
5432
- await unlink2(this.entryPath(entry.submission_ref));
6086
+ await unlink3(this.entryPath(entry.submission_ref));
5433
6087
  } catch (error) {
5434
6088
  if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
5435
6089
  }
5436
6090
  }
5437
- async writeBinding(binding) {
5438
- validateBinding(binding);
5439
- await this.prepare();
5440
- await writeAtomicJson(this.bindingPath(binding.identity), binding);
5441
- }
5442
6091
  /**
5443
6092
  * Select the exact Host turn that model-reachable commands may use. A new
5444
6093
  * prompt replaces this projection, so it cannot inherit the prior turn's
@@ -5452,7 +6101,7 @@ var CodexOutboxStore = class {
5452
6101
  await writeAtomicJson(path, context);
5453
6102
  } catch (error) {
5454
6103
  try {
5455
- await unlink2(path);
6104
+ await unlink3(path);
5456
6105
  } catch (unlinkError) {
5457
6106
  if (!isNotFound(unlinkError)) throw storageError("Unable to clear a failed Codex Host context replacement.");
5458
6107
  }
@@ -5465,7 +6114,7 @@ var CodexOutboxStore = class {
5465
6114
  await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
5466
6115
  }
5467
6116
  async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
5468
- 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.");
5469
6118
  await this.prepare();
5470
6119
  return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
5471
6120
  }
@@ -5478,23 +6127,11 @@ var CodexOutboxStore = class {
5478
6127
  await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
5479
6128
  return true;
5480
6129
  }
5481
- /**
5482
- * Publish a Request reference only while the acknowledged binding is still
5483
- * the active turn. A delayed relay response therefore cannot overwrite a
5484
- * newer prompt's context.
5485
- */
5486
- async bindInvocationContext(binding, now = /* @__PURE__ */ new Date()) {
5487
- validateBinding(binding);
5488
- const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
5489
- if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
5490
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
5491
- return true;
5492
- }
5493
6130
  /** Return only the live session projection; never fall back to another turn. */
5494
6131
  async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
5495
6132
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
5496
6133
  const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
5497
- return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
6134
+ return isLiveSessionProjection(context, now) ? context : null;
5498
6135
  }
5499
6136
  /**
5500
6137
  * The latest Codex session projection even when past expiry, so the
@@ -5502,10 +6139,10 @@ var CodexOutboxStore = class {
5502
6139
  * a missing one. Every other caller keeps the fail-closed read above.
5503
6140
  */
5504
6141
  async readRawInvocationContext(hostSourceRef, hostSessionRef) {
5505
- 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.");
5506
6143
  await this.prepare();
5507
6144
  const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
5508
- return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
6145
+ return context;
5509
6146
  }
5510
6147
  /** Clear the projection only if the caller still owns its exact active turn. */
5511
6148
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -5513,17 +6150,12 @@ var CodexOutboxStore = class {
5513
6150
  const active = await this.readInvocationContext(identity.host_source_ref, identity.host_session_ref, now);
5514
6151
  if (active === null || !sameIdentity(active.identity, identity)) return false;
5515
6152
  try {
5516
- await unlink2(this.activeContextPath(identity));
6153
+ await unlink3(this.activeContextPath(identity));
5517
6154
  } catch (error) {
5518
6155
  if (!isNotFound(error)) throw storageError("Unable to clear the Codex Host invocation context.");
5519
6156
  }
5520
6157
  return true;
5521
6158
  }
5522
- async readBinding(identity) {
5523
- validateIdentity3(identity);
5524
- await this.prepare();
5525
- return readOptionalJson(this.bindingPath(identity), validateBinding);
5526
- }
5527
6159
  async saveSession(snapshot) {
5528
6160
  validateSession(snapshot);
5529
6161
  await this.prepare();
@@ -5531,7 +6163,7 @@ var CodexOutboxStore = class {
5531
6163
  }
5532
6164
  async readSession(sourceRef, sessionRef) {
5533
6165
  const identity = { host_source_ref: sourceRef, host_session_ref: sessionRef };
5534
- 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.");
5535
6167
  await this.prepare();
5536
6168
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
5537
6169
  }
@@ -5564,7 +6196,7 @@ var CodexOutboxStore = class {
5564
6196
  for (const name of await readdir(this.registrationsDirectory)) {
5565
6197
  if (!name.endsWith(".json")) continue;
5566
6198
  try {
5567
- const value = JSON.parse(await readPrivateFile(join4(this.registrationsDirectory, name)));
6199
+ const value = JSON.parse(await readOwnerStateFile(join4(this.registrationsDirectory, name)));
5568
6200
  validateRegistration(value);
5569
6201
  registrations.push(value);
5570
6202
  } catch {
@@ -5583,34 +6215,23 @@ var CodexOutboxStore = class {
5583
6215
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
5584
6216
  }
5585
6217
  async findByAlias(sourceRef, sessionRef, alias) {
5586
- 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;
5587
6219
  const read = await this.list();
5588
6220
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
5589
6221
  if (envelope !== null) return envelopeMatch(envelope);
5590
6222
  await this.prepare();
5591
- const binding = await findBindingByAlias(this.bindingsDirectory, sourceRef, sessionRef, alias);
5592
- if (binding !== null) return bindingMatch(binding);
5593
6223
  return null;
5594
6224
  }
5595
6225
  async hasPriorTurn(sourceRef, sessionRef) {
5596
- if (!SAFE_REF6.test(sourceRef) || !SAFE_REF6.test(sessionRef)) return false;
6226
+ if (!SAFE_REF5.test(sourceRef) || !SAFE_REF5.test(sessionRef)) return false;
5597
6227
  const read = await this.list();
5598
6228
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
5599
- await this.prepare();
5600
- for (const name of await readdir(this.bindingsDirectory)) {
5601
- if (!name.endsWith(".json")) continue;
5602
- const binding = await readBindingCandidate(this.bindingsDirectory, name);
5603
- if (binding?.identity.host_source_ref === sourceRef && binding.identity.host_session_ref === sessionRef) return true;
5604
- }
5605
6229
  return false;
5606
6230
  }
5607
6231
  entryPath(submissionRef) {
5608
- 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.");
5609
6233
  return join4(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
5610
6234
  }
5611
- bindingPath(identity) {
5612
- return join4(this.bindingsDirectory, `${identityKey(identity)}.json`);
5613
- }
5614
6235
  sessionPath(sourceRef, sessionRef) {
5615
6236
  return join4(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
5616
6237
  }
@@ -5629,20 +6250,17 @@ var CodexOutboxStore = class {
5629
6250
  };
5630
6251
  async function removeOwnerState(path, what) {
5631
6252
  try {
5632
- await unlink2(path);
6253
+ await unlink3(path);
5633
6254
  } catch (error) {
5634
6255
  if (!isNotFound(error)) throw storageError(`Unable to retire the Codex transcript ${what}.`);
5635
6256
  }
5636
6257
  }
5637
6258
  function sessionStateKey(sourceRef, sessionRef) {
5638
- 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.");
5639
6260
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
5640
6261
  }
5641
6262
  function envelopeMatch(envelope) {
5642
- return { identity: envelope.identity, prompt_ref: envelope.prompt_ref, ...envelope.request_ref === void 0 ? {} : { request_ref: envelope.request_ref }, envelope };
5643
- }
5644
- function bindingMatch(binding) {
5645
- 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 };
5646
6264
  }
5647
6265
  function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
5648
6266
  for (const envelope of entries) {
@@ -5651,24 +6269,6 @@ function findEnvelopeByAlias(entries, sourceRef, sessionRef, alias) {
5651
6269
  }
5652
6270
  return null;
5653
6271
  }
5654
- async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
5655
- for (const name of await readdir(directory)) {
5656
- if (!name.endsWith(".json")) continue;
5657
- const binding = await readBindingCandidate(directory, name);
5658
- if (binding === null || binding.identity.host_source_ref !== sourceRef || binding.identity.host_session_ref !== sessionRef) continue;
5659
- if (binding.codex_turn_ids.includes(alias)) return binding;
5660
- }
5661
- return null;
5662
- }
5663
- async function readBindingCandidate(directory, name) {
5664
- try {
5665
- const value = JSON.parse(await readPrivateFile(join4(directory, name)));
5666
- validateBinding(value);
5667
- return value;
5668
- } catch {
5669
- return null;
5670
- }
5671
- }
5672
6272
  function identityKey(identity) {
5673
6273
  validateIdentity3(identity);
5674
6274
  return cealRequestSha256(identity);
@@ -5681,18 +6281,18 @@ async function writeAtomicJson(path, value) {
5681
6281
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
5682
6282
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
5683
6283
  try {
5684
- const handle = await open5(temp, "wx", 384);
6284
+ const handle = await open4(temp, "wx");
5685
6285
  try {
5686
6286
  await handle.writeFile(text, "utf8");
5687
6287
  await handle.sync();
5688
6288
  } finally {
5689
6289
  await handle.close();
5690
6290
  }
5691
- await rename3(temp, path);
5692
- await syncDirectory(dirname(path));
6291
+ await rename2(temp, path);
6292
+ await syncDirectory(dirname4(path));
5693
6293
  } catch (error) {
5694
6294
  try {
5695
- await unlink2(temp);
6295
+ await unlink3(temp);
5696
6296
  } catch {
5697
6297
  }
5698
6298
  if (error instanceof CodexHostAdapterError) throw error;
@@ -5701,7 +6301,7 @@ async function writeAtomicJson(path, value) {
5701
6301
  }
5702
6302
  async function syncDirectory(path) {
5703
6303
  try {
5704
- const handle = await open5(path, "r");
6304
+ const handle = await open4(path, "r");
5705
6305
  try {
5706
6306
  await handle.sync();
5707
6307
  } finally {
@@ -5712,7 +6312,7 @@ async function syncDirectory(path) {
5712
6312
  }
5713
6313
  async function readOptionalJson(path, validate) {
5714
6314
  try {
5715
- const value = JSON.parse(await readPrivateFile(path));
6315
+ const value = JSON.parse(await readOwnerStateFile(path));
5716
6316
  validate(value);
5717
6317
  return value;
5718
6318
  } catch (error) {
@@ -5721,36 +6321,30 @@ async function readOptionalJson(path, validate) {
5721
6321
  throw storageError("Codex owner state is malformed.");
5722
6322
  }
5723
6323
  }
5724
- async function ensurePrivateOwnerDirectory(path) {
6324
+ async function ensureOwnerDirectory(path) {
5725
6325
  try {
5726
- await lstat3(path);
6326
+ await stat3(path);
5727
6327
  } catch (error) {
5728
6328
  if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
5729
- await mkdir3(path, { recursive: true, mode: 448 });
6329
+ await mkdir3(path, { recursive: true });
5730
6330
  }
5731
- const stats = await lstat3(path);
5732
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
5733
- 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)")}).`);
5734
- 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")}).`);
5735
- 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.");
5736
6333
  }
5737
- async function readPrivateFile(path) {
6334
+ async function readOwnerStateFile(path) {
5738
6335
  let handle;
5739
6336
  try {
5740
- handle = await open5(path, O_RDONLY3 | O_NOFOLLOW2);
6337
+ handle = await open4(path);
5741
6338
  const stats = await handle.stat();
5742
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
5743
- 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)")}).`);
5744
- 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")}).`);
5745
- 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.");
5746
6340
  return await handle.readFile("utf8");
5747
6341
  } finally {
5748
6342
  await handle?.close();
5749
6343
  }
5750
6344
  }
5751
6345
  function validateEnvelope(value) {
5752
- if (!isRecord5(value)) throw storageError("Codex outbox entry is malformed.");
5753
- 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")}).`);
5754
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}`)}).`);
5755
6349
  validateIdentity3(value.identity);
5756
6350
  validateEnvelopeReferences(value);
@@ -5758,32 +6352,30 @@ function validateEnvelope(value) {
5758
6352
  validateEnvelopeTimestamps(value);
5759
6353
  }
5760
6354
  function validateEnvelopeReferences(value) {
5761
- if (!SAFE_REF6.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
5762
- if (!isCealHostInputKind(value.input_kind)) throw storageError("Codex outbox input provenance is malformed.");
5763
- if (!SAFE_REF6.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
5764
- if (!SAFE_REF6.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
5765
- if (value.request_ref !== void 0 && !SAFE_REF6.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
5766
- 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.");
5767
6359
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
5768
6360
  }
5769
6361
  function validateRegistration(value) {
5770
- if (!isRecord5(value)) throw storageError("Codex transcript registration is malformed.");
6362
+ if (!isRecord7(value)) throw storageError("Codex transcript registration is malformed.");
5771
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")}).`);
5772
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}`)}).`);
5773
6365
  validateRegistrationFields(value);
5774
6366
  }
5775
6367
  function validateRegistrationFields(value) {
5776
- 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 }])}).`);
5777
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`)}).`);
5778
6370
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
5779
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}`)}).`);
5780
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 }])}).`);
5781
6373
  }
5782
6374
  function validRegistrationCwd(value) {
5783
- 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");
5784
6376
  }
5785
6377
  function validateCursor(value) {
5786
- if (!isRecord5(value)) throw storageError("Codex transcript cursor is malformed.");
6378
+ if (!isRecord7(value)) throw storageError("Codex transcript cursor is malformed.");
5787
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")}).`);
5788
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}`)}).`);
5789
6381
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
@@ -5791,7 +6383,7 @@ function validateCursor(value) {
5791
6383
  if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
5792
6384
  }
5793
6385
  function validCursorSource(value) {
5794
- 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";
5795
6387
  }
5796
6388
  function validCursorPosition(value) {
5797
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";
@@ -5800,23 +6392,23 @@ function validCursorStatus(value) {
5800
6392
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
5801
6393
  }
5802
6394
  function validActiveTask(value) {
5803
- 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;
5804
6396
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
5805
6397
  }
5806
6398
  function validActiveTaskIdentity(value) {
5807
- 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);
5808
6400
  }
5809
6401
  function validActiveTaskReferences(value) {
5810
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);
5811
6403
  }
5812
6404
  function optionalSafeRef2(value) {
5813
- return value === void 0 || typeof value === "string" && SAFE_REF6.test(value);
6405
+ return value === void 0 || typeof value === "string" && SAFE_REF5.test(value);
5814
6406
  }
5815
6407
  function validActiveTaskUsage(value) {
5816
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");
5817
6409
  }
5818
6410
  function validTokenUsage(value) {
5819
- 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;
5820
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;
5821
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);
5822
6414
  }
@@ -5826,7 +6418,7 @@ function nonNegativeInteger(value) {
5826
6418
  function validateEnvelopeObservations(value) {
5827
6419
  if (!Array.isArray(value.observations)) throw storageError("Codex outbox observations are malformed.");
5828
6420
  try {
5829
- for (const observation2 of value.observations) validateCealHostObservationDraft(observation2);
6421
+ for (const observation of value.observations) validateCealHostObservationDraft(observation);
5830
6422
  } catch {
5831
6423
  throw storageError("Codex outbox observations are malformed.");
5832
6424
  }
@@ -5835,34 +6427,23 @@ function validateEnvelopeTimestamps(value) {
5835
6427
  if (!isTimestamp(value.created_at)) throw storageError("Codex outbox timestamps are malformed.");
5836
6428
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
5837
6429
  }
5838
- function validateBinding(value) {
5839
- if (!isRecord5(value)) throw storageError("Codex turn binding is malformed.");
5840
- 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")}).`);
5841
- 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}`)}).`);
5842
- validateIdentity3(value.identity);
5843
- if (!SAFE_REF6.test(String(value.prompt_ref)) || !SAFE_REF6.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
5844
- if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
5845
- }
5846
6430
  function validateSession(value) {
5847
- if (!isRecord5(value)) throw storageError("Codex session snapshot is malformed.");
6431
+ if (!isRecord7(value)) throw storageError("Codex session snapshot is malformed.");
5848
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")}).`);
5849
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}`)}).`);
5850
- 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.");
5851
6435
  }
5852
6436
  function validateTurnSelection(value) {
5853
6437
  if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
5854
6438
  }
5855
6439
  function validateIdentity3(value) {
5856
- 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.");
5857
6441
  }
5858
6442
  function isJsonValue(value) {
5859
6443
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
5860
6444
  if (typeof value === "number") return Number.isFinite(value);
5861
6445
  if (Array.isArray(value)) return value.every(isJsonValue);
5862
- return isRecord5(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
5863
- }
5864
- function isStringList(value) {
5865
- 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));
5866
6447
  }
5867
6448
  function isTimestamp(value) {
5868
6449
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -5872,142 +6453,43 @@ function sameKeys(value, required, optional = []) {
5872
6453
  const keys = Object.keys(value);
5873
6454
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
5874
6455
  }
5875
- function isRecord5(value) {
6456
+ function isRecord7(value) {
5876
6457
  return value !== null && typeof value === "object" && !Array.isArray(value);
5877
6458
  }
5878
6459
  function isNotFound(error) {
5879
- return isRecord5(error) && error.code === "ENOENT";
6460
+ return isRecord7(error) && error.code === "ENOENT";
5880
6461
  }
5881
6462
  function storageError(message) {
5882
6463
  return new CodexHostAdapterError("storage", message);
5883
6464
  }
5884
6465
 
5885
6466
  // host/codex/src/codex-producer.ts
5886
- import { createHash as createHash6 } from "node:crypto";
5887
- var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
5888
6467
  var CodexProducer = class {
5889
- producer_id = "codex";
5890
- producer_label = "Codex";
5891
- outbox_directory;
5892
6468
  store;
5893
6469
  core;
5894
6470
  constructor(options) {
5895
6471
  this.store = new CodexOutboxStore(options.outbox_dir);
5896
- this.outbox_directory = this.store.directory;
5897
6472
  this.core = new HostProducerDrainCore(this, options);
5898
6473
  }
5899
6474
  drainOutbox() {
5900
6475
  return this.core.drainOutbox();
5901
6476
  }
5902
- fail(code, message) {
5903
- return new CodexHostAdapterError(code, message);
5904
- }
5905
6477
  listEnvelopes() {
5906
6478
  return this.store.list();
5907
6479
  }
5908
6480
  removeEnvelope(envelope) {
5909
6481
  return this.store.remove(envelope);
5910
6482
  }
5911
- submissionRefOf(envelope) {
5912
- return envelope.submission_ref;
5913
- }
5914
6483
  expiresAtOf(envelope) {
5915
6484
  return envelope.expires_at;
5916
6485
  }
5917
- createdAtOf(envelope) {
5918
- return envelope.created_at;
5919
- }
5920
- async mapEnvelope(envelope) {
5921
- const prompt = observation(envelope, "prompt");
5922
- if (prompt !== void 0) return this.mapInput(envelope, prompt);
5923
- return [mapTerminal(envelope)];
5924
- }
5925
- async mapInput(envelope, prompt) {
5926
- const drafts = [];
5927
- const session = observation(envelope, "session");
5928
- if (session !== void 0) {
5929
- const registrations = await this.store.listTranscriptRegistrations();
5930
- const registration = registrations.find((item) => item.host_source_ref === envelope.identity.host_source_ref && item.host_session_ref === envelope.identity.host_session_ref);
5931
- const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
5932
- drafts.push({ frame_kind: "session_started", payload: compact({
5933
- local_session_ref: envelope.identity.host_session_ref,
5934
- working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
5935
- model: recordText(session.value, "model"),
5936
- host_version: nestedText(session.value, "host_version"),
5937
- observations: [session]
5938
- }) });
5939
- }
5940
- const turn = observation(envelope, "turn");
5941
- if (turn !== void 0) drafts.push({ frame_kind: "turn_started", payload: compact({
5942
- local_session_ref: envelope.identity.host_session_ref,
5943
- local_turn_ref: localTurnRef(envelope),
5944
- observations: [turn]
5945
- }) });
5946
- if (!isCealHostPromptObservationValue(prompt.value)) throw new CodexHostAdapterError("storage", "Codex prompt observation is malformed.");
5947
- drafts.push({ frame_kind: "user_input", payload: compact({
5948
- local_session_ref: envelope.identity.host_session_ref,
5949
- local_turn_ref: localTurnRef(envelope),
5950
- local_input_ref: envelope.host_input_ref,
5951
- input_kind: envelope.input_kind,
5952
- origin_input: envelope.origin_input,
5953
- observations: [prompt],
5954
- local_turn_aliases: envelope.codex_turn_id === void 0 ? void 0 : [envelope.codex_turn_id],
5955
- context_expires_at: envelope.expires_at
5956
- }) });
5957
- return drafts;
5958
- }
5959
6486
  };
5960
- function mapTerminal(envelope) {
5961
- const timing = observation(envelope, "timing");
5962
- const timingValue = asRecord(timing?.value);
5963
- const aborted = timingValue?.terminal === "aborted";
5964
- const usage = envelope.observations.filter((item) => ["token", "cost", "model"].includes(item.observation_kind));
5965
- return { frame_kind: "turn_terminal", payload: compact({
5966
- local_session_ref: envelope.identity.host_session_ref,
5967
- local_turn_ref: localTurnRef(envelope),
5968
- terminal_state: aborted ? "aborted" : "completed",
5969
- abort_reason: aborted && typeof timingValue?.reason === "string" ? safeReasonRef(timingValue.reason) : void 0,
5970
- duration_ms: nonNegativeNumber(timingValue?.duration_ms),
5971
- time_to_first_token_ms: nonNegativeNumber(timingValue?.time_to_first_token_ms),
5972
- usage: usage.length === 0 ? void 0 : Object.fromEntries(usage.map((item) => [item.observation_kind, item.value])),
5973
- observations: envelope.observations
5974
- }) };
5975
- }
5976
- function observation(envelope, kind) {
5977
- return envelope.observations.find((item) => item.observation_kind === kind);
5978
- }
5979
- function localTurnRef(envelope) {
5980
- return envelope.identity.host_turn_ref;
5981
- }
5982
- function compact(value) {
5983
- return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
5984
- }
5985
- function asRecord(value) {
5986
- return isRecord6(value) ? value : void 0;
5987
- }
5988
- function recordText(value, key) {
5989
- const record3 = asRecord(value);
5990
- return typeof record3?.[key] === "string" ? record3[key] : void 0;
5991
- }
5992
- function nestedText(value, key) {
5993
- const nested = asRecord(asRecord(value)?.[key]);
5994
- return typeof nested?.value === "string" ? nested.value : void 0;
5995
- }
5996
- function nonNegativeNumber(value) {
5997
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
5998
- }
5999
- function safeReasonRef(value) {
6000
- return SAFE_REF7.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
6001
- }
6002
- function isRecord6(value) {
6003
- return value !== null && typeof value === "object" && !Array.isArray(value);
6004
- }
6005
6487
 
6006
6488
  // host/codex/src/codex-transcript-baseline.ts
6007
6489
  import { createHash as createHash7 } from "node:crypto";
6008
6490
 
6009
6491
  // host/codex/src/codex-transcript-decoder.ts
6010
- 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;
6011
6493
  var MAX_PROMPT_BYTES = 64 * 1024;
6012
6494
  function decodeCodexTranscriptLine(line) {
6013
6495
  let value;
@@ -6016,40 +6498,40 @@ function decodeCodexTranscriptLine(line) {
6016
6498
  } catch {
6017
6499
  reject("Codex transcript record is not valid JSON.");
6018
6500
  }
6019
- if (!isRecord7(value)) reject("Codex transcript record envelope is malformed.");
6501
+ if (!isRecord8(value)) reject("Codex transcript record envelope is malformed.");
6020
6502
  const ordinal = safeOrdinal(value.ordinal);
6021
- const timestamp4 = safeTimestamp(value.timestamp);
6022
- if (!isRecord7(value.payload) || typeof value.type !== "string") reject("Codex transcript record payload is malformed.");
6023
- if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp4);
6024
- if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp4);
6025
- if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp4);
6026
- if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp4);
6027
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
6028
- }
6029
- 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) {
6030
6512
  return {
6031
6513
  kind: "turn_context",
6032
6514
  ordinal,
6033
- timestamp: timestamp4,
6034
- 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."),
6035
6517
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
6036
6518
  };
6037
6519
  }
6038
- function decodeSessionMeta(payload, ordinal, timestamp4) {
6039
- 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.");
6040
6522
  const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
6041
- 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 };
6042
6524
  }
6043
- function decodeEventMessage(payload, ordinal, timestamp4) {
6525
+ function decodeEventMessage(payload, ordinal, timestamp3) {
6044
6526
  if (payload.type === "task_started") {
6045
- 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) };
6046
6528
  }
6047
6529
  if (payload.type === "task_complete") {
6048
6530
  return {
6049
6531
  kind: "task_complete",
6050
6532
  ordinal,
6051
- timestamp: timestamp4,
6052
- 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."),
6053
6535
  started_at: safeNumber(payload.started_at),
6054
6536
  completed_at: safeNumber(payload.completed_at),
6055
6537
  duration_ms: safeNumber(payload.duration_ms),
@@ -6060,20 +6542,20 @@ function decodeEventMessage(payload, ordinal, timestamp4) {
6060
6542
  return {
6061
6543
  kind: "turn_aborted",
6062
6544
  ordinal,
6063
- timestamp: timestamp4,
6064
- 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."),
6065
6547
  started_at: safeNumber(payload.started_at),
6066
6548
  completed_at: safeNumber(payload.completed_at),
6067
6549
  duration_ms: safeNumber(payload.duration_ms),
6068
6550
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
6069
6551
  };
6070
6552
  }
6071
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp4);
6072
- return { kind: "ignored", ordinal, timestamp: timestamp4 };
6553
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp3);
6554
+ return { kind: "ignored", ordinal, timestamp: timestamp3 };
6073
6555
  }
6074
- function decodeTokenCount(payload, ordinal, timestamp4) {
6075
- if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp4 };
6076
- 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" };
6077
6559
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
6078
6560
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
6079
6561
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -6081,7 +6563,7 @@ function decodeTokenCount(payload, ordinal, timestamp4) {
6081
6563
  return {
6082
6564
  kind: "token_count",
6083
6565
  ordinal,
6084
- timestamp: timestamp4,
6566
+ timestamp: timestamp3,
6085
6567
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
6086
6568
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
6087
6569
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -6097,7 +6579,7 @@ function optionalTokenUsage(value) {
6097
6579
  }
6098
6580
  }
6099
6581
  function decodeTokenUsage(value) {
6100
- if (!isRecord7(value)) reject("Codex token usage is malformed.");
6582
+ if (!isRecord8(value)) reject("Codex token usage is malformed.");
6101
6583
  const usage = {
6102
6584
  input_tokens: safeTokenCount(value.input_tokens),
6103
6585
  cached_input_tokens: safeTokenCount(value.cached_input_tokens),
@@ -6109,35 +6591,33 @@ function decodeTokenUsage(value) {
6109
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.");
6110
6592
  return usage;
6111
6593
  }
6112
- function decodeResponseItem(payload, ordinal, timestamp4) {
6113
- 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 };
6114
6596
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
6115
- const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
6116
- 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 };
6117
6599
  const prompt = userTextContent(payload.content);
6118
6600
  return {
6119
6601
  kind: "user_text",
6120
6602
  ordinal,
6121
- timestamp: timestamp4,
6603
+ timestamp: timestamp3,
6122
6604
  prompt,
6123
- input_kind: inputKind,
6124
- message_id: safeRef5(payload.id, "Codex user message identity is invalid."),
6125
- 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.")
6126
6608
  };
6127
6609
  }
6128
- function inputKindFromContentItems(kinds) {
6129
- if (kinds.length !== 1) return void 0;
6130
- if (kinds[0] === "user.text") return "human";
6131
- 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;
6132
6612
  }
6133
6613
  function userMessageMetadata(value) {
6134
- 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.");
6135
6615
  return { ...value, content_item_kinds: value.content_item_kinds };
6136
6616
  }
6137
6617
  function userTextContent(value) {
6138
6618
  if (!Array.isArray(value)) reject(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
6139
6619
  if (value.length !== 1) reject(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
6140
- 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")}).`);
6141
6621
  return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
6142
6622
  }
6143
6623
  function safeOrdinal(value) {
@@ -6158,8 +6638,8 @@ function safeTimestamp(value) {
6158
6638
  if (!Number.isFinite(Date.parse(value))) reject(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
6159
6639
  return value;
6160
6640
  }
6161
- function safeRef5(value, message) {
6162
- 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);
6163
6643
  return value;
6164
6644
  }
6165
6645
  function boundedText(value, maximum, message) {
@@ -6173,7 +6653,7 @@ function boundedNonEmptyText(value, maximum, message) {
6173
6653
  if (result.length === 0) reject(message);
6174
6654
  return result;
6175
6655
  }
6176
- function isRecord7(value) {
6656
+ function isRecord8(value) {
6177
6657
  return value !== null && typeof value === "object" && !Array.isArray(value);
6178
6658
  }
6179
6659
  function reject(message) {
@@ -6197,45 +6677,49 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
6197
6677
  anchor_sha256: digest(Buffer.alloc(0)),
6198
6678
  header_validated: false,
6199
6679
  status: "active",
6200
- updated_at: timestamp3(now)
6680
+ updated_at: timestamp2(now)
6201
6681
  };
6202
6682
  }
6203
- async function ownedCodexTranscriptFile(handle) {
6683
+ async function ownedCodexTranscriptFile(handle, platform = process.platform) {
6204
6684
  const stats = await handle.stat();
6205
- 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.");
6206
6687
  return { size: stats.size, device: String(stats.dev), inode: String(stats.ino) };
6207
6688
  }
6208
- function assertCodexTranscriptOwner(stats) {
6209
- const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
6210
- 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)")}).`);
6211
- if (stats.uid !== uid) throw new CodexHostAdapterError("storage", `Codex transcript source is owned by another user (${refusalFact("uid", stats.uid, `expected ${uid}`)}).`);
6212
- }
6213
- function assertCodexTranscriptHeader(registration, record3) {
6214
- 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([
6215
- { name: "kind", value: record3.kind, expected: "session_meta" },
6216
- { 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 }
6217
6693
  ])}).`);
6218
6694
  }
6219
6695
  function digest(value) {
6220
6696
  return createHash7("sha256").update(value).digest("hex");
6221
6697
  }
6222
- function timestamp3(now) {
6698
+ function timestamp2(now) {
6223
6699
  const value = now();
6224
6700
  if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
6225
6701
  return value.toISOString();
6226
6702
  }
6227
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
+
6228
6712
  // host/codex/src/codex-adapter.ts
6229
- 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;
6230
6714
  function codexSubmissionReference(hostInputRef, event, ordinal) {
6231
- 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.");
6232
6716
  return `codex-submission:${cealRequestSha256({ host_input_ref: hostInputRef, event, ordinal })}`;
6233
6717
  }
6234
6718
 
6235
6719
  // host/codex/src/codex-transcript-watcher.ts
6236
6720
  var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6237
6721
  store;
6238
- registerCurrentPrompt;
6722
+ diagnostic;
6239
6723
  constructor(options) {
6240
6724
  super(options, {
6241
6725
  default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
@@ -6243,7 +6727,7 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6243
6727
  clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
6244
6728
  });
6245
6729
  this.store = new CodexOutboxStore(options.outbox_dir);
6246
- this.registerCurrentPrompt = options.register_current_prompt;
6730
+ this.diagnostic = options.diagnostic ?? (() => void 0);
6247
6731
  }
6248
6732
  transcriptPathOf(registration) {
6249
6733
  return registration.transcript_path;
@@ -6259,7 +6743,8 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6259
6743
  if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
6260
6744
  return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
6261
6745
  }
6262
- async scanFailed(handle, registration, _error) {
6746
+ async scanFailed(handle, registration, error) {
6747
+ this.diagnostic("watcher_scan_failed", codexTranscriptScanFailureKind(error));
6263
6748
  await this.quarantineFailure(registration, handle);
6264
6749
  return { records: 0, enqueued: 0, quarantined: true };
6265
6750
  }
@@ -6269,7 +6754,9 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6269
6754
  async preflight(registration, handle, size, device, inode) {
6270
6755
  const existing = await this.store.readTranscriptCursor(registration);
6271
6756
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
6272
- if (cursor.status === "quarantined") return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
6757
+ if (cursor.status === "quarantined") {
6758
+ return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
6759
+ }
6273
6760
  const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
6274
6761
  if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
6275
6762
  await this.quarantine(registration, cursor, device, inode, reason);
@@ -6281,22 +6768,22 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6281
6768
  let records = 0;
6282
6769
  let enqueued = 0;
6283
6770
  for (const line of complete.toString("utf8").split("\n").filter((value) => value.length > 0)) {
6284
- const record3 = decodeCodexTranscriptLine(line);
6285
- assertRecordSequence(registration, cursor, records, lastOrdinal, record3);
6286
- await this.observeSessionMetadata(registration, record3);
6287
- 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);
6288
6775
  activeTask = outcome.activeTask;
6289
6776
  enqueued += outcome.enqueued;
6290
- lastOrdinal = record3.ordinal;
6777
+ lastOrdinal = record2.ordinal;
6291
6778
  records += 1;
6292
6779
  }
6293
6780
  await this.commitCursor(registration, handle, cursor, complete.length, device, inode, lastOrdinal, activeTask);
6294
6781
  return { records, enqueued, quarantined: false };
6295
6782
  }
6296
- async observeSessionMetadata(registration, record3) {
6297
- if (record3.kind !== "session_meta") return;
6783
+ async observeSessionMetadata(registration, record2) {
6784
+ if (record2.kind !== "session_meta") return;
6298
6785
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
6299
- 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 } });
6300
6787
  }
6301
6788
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
6302
6789
  const offset = cursor.offset + consumedBytes;
@@ -6308,75 +6795,132 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6308
6795
  const stats = await handle.stat().catch(() => null);
6309
6796
  if (stats === null) return;
6310
6797
  const existing = await this.store.readTranscriptCursor(registration).catch(() => null);
6311
- await this.quarantine(registration, existing ?? codexTranscriptInitialCursor(registration, String(stats.dev), String(stats.ino), this.now), String(stats.dev), String(stats.ino), "transcript_malformed");
6798
+ const quarantined = {
6799
+ ...existing ?? codexTranscriptInitialCursor(registration, String(stats.dev), String(stats.ino), this.now),
6800
+ transcript_path: registration.transcript_path,
6801
+ device: String(stats.dev),
6802
+ inode: String(stats.ino),
6803
+ status: "quarantined",
6804
+ reason: "transcript_malformed",
6805
+ updated_at: this.stamp()
6806
+ };
6807
+ await this.store.writeTranscriptCursor(quarantined);
6312
6808
  }
6313
- async processRecord(registration, activeTask, record3) {
6314
- if (record3.kind === "task_started") {
6315
- 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 };
6316
- }
6317
- if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
6318
- if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
6319
- if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
6320
- 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);
6321
6815
  return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6322
6816
  }
6323
- async processUserInput(registration, activeTask, record3) {
6324
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6325
- const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
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 };
6819
+ }
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);
6823
+ if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
6824
+ activeTask = adopted;
6825
+ }
6826
+ const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record2.turn_id, record2.message_id, record2.ordinal, record2.prompt);
6326
6827
  const origin = activeTask.origin_host_input_ref === void 0;
6327
- const promptValue = promptObservationValue(record3.prompt);
6828
+ const promptValue = promptObservationValue(record2.prompt);
6328
6829
  const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
6329
6830
  const promptRef = activeTask.prompt_ref ?? currentPromptRef;
6831
+ const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
6330
6832
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
6331
6833
  const observations = [{
6332
- observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
6834
+ observation_ref: observationRef(registration.host_source_ref, "transcript_user_text", hostInputRef, record2.prompt),
6333
6835
  observation_kind: "prompt",
6334
- observed_at: record3.timestamp,
6836
+ observed_at: record2.timestamp,
6335
6837
  value: promptValue
6336
6838
  }];
6337
6839
  if (origin) {
6338
- 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") });
6339
6841
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
6340
- 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 });
6341
6843
  }
6342
6844
  const envelope = {
6343
6845
  schema_version: "ceal.codex_observation_outbox.v1",
6344
6846
  identity,
6345
6847
  host_input_ref: hostInputRef,
6346
- input_kind: record3.input_kind,
6347
6848
  prompt_ref: promptRef,
6348
6849
  observations,
6349
- codex_turn_id: record3.turn_id,
6850
+ codex_turn_id: record2.turn_id,
6350
6851
  origin_input: origin,
6351
- submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
6352
- created_at: record3.timestamp,
6852
+ submission_ref: codexSubmissionReference(hostInputRef, "input", record2.ordinal),
6853
+ created_at: record2.timestamp,
6353
6854
  expires_at: this.expire(this.outboxRetentionMs)
6354
6855
  };
6355
- await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
6856
+ const persisted = await this.persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
6857
+ if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
6858
+ return persisted;
6859
+ }
6860
+ /**
6861
+ * The steered prompt to re-activate under the running task, or null when
6862
+ * there is nothing to repair. A steered message joins the running turn
6863
+ * with new prompt bytes but no task_started. When the steer hook already
6864
+ * replaced the turn selection (a turn id the hook did not recognize as
6865
+ * the running one, or a hook that ran before any context was live), the
6866
+ * running task's context no longer matches and the next invocation would
6867
+ * wait for a boundary that never comes. When the hook kept the live
6868
+ * selection, the context still matches and this stays null.
6869
+ */
6870
+ async steeredPromptRef(registration, activeTask, origin, currentPromptRef) {
6871
+ if (origin || activeTask.prompt_ref === void 0 || activeTask.prompt_ref === currentPromptRef) return null;
6872
+ const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref).catch(() => null);
6873
+ return selection?.prompt_ref === currentPromptRef ? currentPromptRef : null;
6874
+ }
6875
+ /**
6876
+ * Adopt the live hooked turn when its transcript message arrives before
6877
+ * (or without) its task_started, as an interrupted turn's follow-up can.
6878
+ * The UserPromptSubmit hook names the exact hooked prompt, so only a
6879
+ * message carrying those bytes adopts; inherited history and other turns
6880
+ * stay ignored. A stale active task for another turn releases first, the
6881
+ * same as a task_started supersession.
6882
+ */
6883
+ async adoptHookCorrelatedTurn(registration, record2) {
6884
+ const currentPromptRef = hostProducerPromptRef(promptObservationValue(record2.prompt).body_sha256);
6885
+ const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
6886
+ if (selection?.prompt_ref !== currentPromptRef) return void 0;
6887
+ return {
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
6891
+ };
6892
+ }
6893
+ async persistUserInputTurn(activeTask, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
6356
6894
  await this.store.put(envelope);
6357
- if (origin) await activateTranscriptTurnContext(this.store, identity, promptRef, envelope.expires_at);
6895
+ if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
6358
6896
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
6359
6897
  }
6360
- async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
6361
- if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return;
6362
- await this.registerCurrentPrompt({ producer_id: "codex", producer_installation_ref: this.producerInstallationRef, local_session_ref: registration.host_session_ref, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef, current_prompt: prompt, context_expires_at: expiresAt });
6898
+ async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
6899
+ try {
6900
+ const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
6901
+ const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
6902
+ await this.store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
6903
+ this.diagnostic("activation_recorded");
6904
+ } catch (error) {
6905
+ this.diagnostic("activation_failed");
6906
+ throw error;
6907
+ }
6363
6908
  }
6364
- async processTerminal(registration, activeTask, record3) {
6365
- 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 };
6366
6911
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
6367
- 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 };
6368
- 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);
6369
6914
  await this.store.put({
6370
6915
  schema_version: "ceal.codex_observation_outbox.v1",
6371
6916
  identity,
6372
6917
  host_input_ref: activeTask.origin_host_input_ref,
6373
- input_kind: "host_automatic",
6374
6918
  prompt_ref: activeTask.prompt_ref,
6375
6919
  observations,
6376
- codex_turn_id: record3.turn_id,
6920
+ codex_turn_id: record2.turn_id,
6377
6921
  origin_input: false,
6378
- submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
6379
- created_at: record3.timestamp,
6922
+ submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record2.ordinal),
6923
+ created_at: record2.timestamp,
6380
6924
  expires_at: this.expire(this.outboxRetentionMs)
6381
6925
  });
6382
6926
  await this.store.clearInvocationContext(identity, this.now());
@@ -6387,15 +6931,18 @@ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
6387
6931
  await this.store.writeTranscriptCursor(quarantined);
6388
6932
  }
6389
6933
  };
6390
- async function activateTranscriptTurnContext(store, identity, promptRef, expiresAt) {
6391
- const selection = await store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
6392
- const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
6393
- await store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
6394
- }
6395
- function accumulateTokenCount(activeTask, record3) {
6396
- if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
6397
- const last = record3.last_usage;
6398
- const total = record3.total_usage;
6934
+ function codexTranscriptScanFailureKind(error) {
6935
+ return transcriptScanFailureKind(error, (candidate) => {
6936
+ if (!(candidate instanceof CodexHostAdapterError)) return void 0;
6937
+ if (candidate.code === "payload_rejected") return "payload_rejected";
6938
+ if (candidate.code === "storage") return "read_error";
6939
+ return void 0;
6940
+ });
6941
+ }
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;
6399
6946
  if (last === void 0 || ignoreTokenCount(activeTask.last_total_usage, total, last)) return activeTask;
6400
6947
  const tokenUsage = addUsage(activeTask.token_usage, last);
6401
6948
  return {
@@ -6409,21 +6956,16 @@ function ignoreTokenCount(previous, total, last) {
6409
6956
  if (total === void 0 || previous === void 0) return false;
6410
6957
  return sameUsage(total, previous) || regressedUsage(total, previous) && looksLikeStaleRegression(total, previous, last);
6411
6958
  }
6412
- function terminalObservations(registration, activeTask, record3, timing) {
6959
+ function terminalObservations(registration, activeTask, record2, timing) {
6413
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);
6414
- const costValue = terminalCostValue();
6415
6961
  const observations = [
6416
- { 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") },
6417
- { observation_ref: observationRef("transcript_timing", activeTask.host_turn_ref, timing), observation_kind: "timing", observed_at: record3.timestamp, value: timing },
6418
- { observation_ref: observationRef("transcript_token", activeTask.host_turn_ref, tokenValue), observation_kind: "token", observed_at: record3.timestamp, value: tokenValue },
6419
- { 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 }
6420
6965
  ];
6421
- 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" } });
6422
6967
  return observations;
6423
6968
  }
6424
- function terminalCostValue() {
6425
- return notRecorded("provider_cost_not_observed");
6426
- }
6427
6969
  function notRecorded(reason) {
6428
6970
  return hostObservationNotRecorded(reason);
6429
6971
  }
@@ -6470,16 +7012,21 @@ function looksLikeStaleRegression(current, previous, last) {
6470
7012
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
6471
7013
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
6472
7014
  }
6473
- function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
6474
- 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}`)}).`);
6475
- 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);
6476
7018
  }
6477
7019
 
6478
7020
  // host/codex/src/codex-producer-runtime.ts
6479
7021
  async function drainCodexProducerOnce(options) {
6480
- const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
6481
- const scan = await new CodexTranscriptWatcher({ outbox_dir: options.outbox_dir, producer_installation_ref: options.producer_installation_ref, register_current_prompt: (input) => promptPort.register(input) }).scanOnce();
6482
- 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 } });
7022
+ const scan = await new CodexTranscriptWatcher({
7023
+ outbox_dir: options.outbox_dir,
7024
+ diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
7025
+ }).scanOnce().catch((error) => {
7026
+ writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
7027
+ throw error;
7028
+ });
7029
+ const producer = new CodexProducer({ outbox_dir: options.outbox_dir, ...options.now === void 0 ? {} : { now: options.now } });
6483
7030
  return { scanned: scan.enqueued, ...await producer.drainOutbox() };
6484
7031
  }
6485
7032
 
@@ -6492,33 +7039,29 @@ var CODEX_PRODUCER_DESCRIPTOR = {
6492
7039
  extra_paths: [CODEX_SESSIONS_ROOT],
6493
7040
  config: (shared, extras) => ({ ...shared, codex_sessions_root: hostProducerExtraPath(extras, CODEX_SESSIONS_ROOT) }),
6494
7041
  runtime_options: (config) => Object.freeze({
6495
- outbox_dir: config.outbox_dir,
6496
- producer_installation_ref: config.producer_installation_ref,
6497
- producer_epoch: config.producer_epoch,
6498
- relay_endpoint: config.relay_endpoint,
6499
- timeout_ms: config.ipc_timeout_ms
7042
+ outbox_dir: config.outbox_dir
6500
7043
  }),
6501
7044
  drain: drainCodexProducerOnce
6502
7045
  };
6503
7046
 
6504
7047
  // host/codex/src/codex-visible-output-budget.ts
6505
- import { readFile as readFile3 } from "node:fs/promises";
7048
+ import { readFile as readFile2 } from "node:fs/promises";
6506
7049
  import { homedir } from "node:os";
6507
- import { join as join5 } from "node:path";
7050
+ import { join as join6 } from "node:path";
6508
7051
  var import_toml = __toESM(require_toml(), 1);
6509
7052
  var CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT = 5e3;
6510
7053
  var CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN = 4;
6511
7054
  async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
6512
- const codexHome = environment.CODEX_HOME || join5(homedir(), ".codex");
7055
+ const codexHome = resolveCodexHome(environment, homedir());
6513
7056
  let source;
6514
7057
  try {
6515
- source = await readFile3(join5(codexHome, "config.toml"), "utf8");
7058
+ source = await readFile2(join6(codexHome, "config.toml"), "utf8");
6516
7059
  } catch (error) {
6517
7060
  return isNotFound2(error) ? codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT) : void 0;
6518
7061
  }
6519
7062
  try {
6520
7063
  const parsed = import_toml.default.parse(source);
6521
- if (!isRecord8(parsed)) return void 0;
7064
+ if (!isRecord9(parsed)) return void 0;
6522
7065
  const configured = parsed.tool_output_token_limit;
6523
7066
  if (configured === void 0) return codexBytes(CODEX_DEFAULT_TOOL_OUTPUT_TOKEN_LIMIT);
6524
7067
  return typeof configured === "number" && Number.isSafeInteger(configured) && configured > 0 ? codexBytes(configured) : void 0;
@@ -6529,7 +7072,7 @@ async function resolveCodexVisibleOutputMaxBytes(environment = process.env) {
6529
7072
  function codexBytes(tokens) {
6530
7073
  return Math.min(tokens * CODEX_UTF8_BYTES_PER_OUTPUT_TOKEN, CEAL_CANONICAL_HTTP_MAX_RESPONSE_BYTES);
6531
7074
  }
6532
- function isRecord8(value) {
7075
+ function isRecord9(value) {
6533
7076
  return value !== null && typeof value === "object" && !Array.isArray(value);
6534
7077
  }
6535
7078
  function isNotFound2(error) {
@@ -6546,11 +7089,28 @@ var CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR = {
6546
7089
  config_flag: HOST_PRODUCER_CONFIG_FLAG,
6547
7090
  parse_config_flag: parseHostProducerConfigFlag,
6548
7091
  read_producer_config: (configPath) => readHostProducerConfig(CODEX_PRODUCER_DESCRIPTOR, configPath),
6549
- resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes()
7092
+ resolve_visible_output_max_bytes: () => resolveCodexVisibleOutputMaxBytes(),
7093
+ read_human_message_window: readCodexInvocationHumanMessageWindow
6550
7094
  };
6551
7095
  function runCodexInvocationAuthenticationCommand(args, options) {
6552
7096
  return runHostInvocationAuthenticationCommand(CODEX_INVOCATION_AUTHENTICATION_DESCRIPTOR, args, options);
6553
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
+ }
6554
7114
 
6555
7115
  // host/codex/bin/ceal-codex-invocation-authentication.ts
6556
7116
  var CODEX_INVOCATION_AUTHENTICATION_CLIENT_COMMAND = {