@corca-org/ceal-host-linux-arm64 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,9 @@ import { createRequire as __cealCreateRequire } from "node:module";
3
3
  const require = __cealCreateRequire(import.meta.url);
4
4
 
5
5
  // host/codex/src/codex-adapter.ts
6
+ import { randomUUID } from "node:crypto";
6
7
  import { homedir } from "node:os";
7
- import { isAbsolute as isAbsolute3, join as join3, relative, resolve as resolve2 } from "node:path";
8
+ import { isAbsolute as isAbsolute3, join as join4, relative, resolve as resolve2 } from "node:path";
8
9
 
9
10
  // packages/ceal-client-protocol/src/canonical-json.ts
10
11
  function cealCanonicalJson(value) {
@@ -113,6 +114,9 @@ var client_wire_contract_default = {
113
114
  "document"
114
115
  ],
115
116
  optional_fields: [
117
+ "operation_id",
118
+ "visible_output_max_bytes",
119
+ "local_delivery",
116
120
  "verified_artifact"
117
121
  ],
118
122
  bare_document_fields: [
@@ -226,6 +230,7 @@ var CEAL_WRITE_RECEIPT_PROVIDER_STATES = vocabulary(["outcome_unknown", "verifie
226
230
  var CEAL_WRITE_RECEIPT_PROVIDER_READBACKS = vocabulary(["outcome_unknown", "verified", "not_applied"]);
227
231
  var CEAL_PROTOCOL_VERSION = "1.4.0";
228
232
  var CEAL_OPERATION_ACCESS_SCHEMA_VERSION = "ceal.operation_access.v1";
233
+ var CEAL_GATEWAY_CONTINUATION_CURSOR_PHASES = vocabulary(["scan", "delivery", "terminal"]);
229
234
  var CEAL_GATEWAY_ACTIVE_CALL_PHASES = vocabulary([
230
235
  "audited_call_pending",
231
236
  "continuation_read_pending",
@@ -249,6 +254,7 @@ var CEAL_GATEWAY_ORGANIZATION_ROUTE_FACT_CALL_KEYS = Object.freeze([
249
254
  // packages/ceal-client-protocol/src/operation-next-actions.ts
250
255
  var CEAL_REPEAT_REQUEST_NEXT_ACTION = "repeat_request";
251
256
  var CEAL_INSPECT_RECEIPT_NEXT_ACTION = "inspect_receipt";
257
+ var CEAL_ANSWER_WITH_GAP_NEXT_ACTION = "answer_with_gap";
252
258
  var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
253
259
  "select_did_you_mean",
254
260
  "choose_new_output_path",
@@ -302,10 +308,20 @@ var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
302
308
  "retry_after",
303
309
  // The ref names a container of rows (a Notion database or data source), which
304
310
  // has no body of its own; the caller searches its rows instead of reading it.
305
- "search_container_rows"
311
+ "search_container_rows",
312
+ // A settled unknown write names the exact receipt Operation that can inspect
313
+ // its outcome without issuing another provider mutation.
314
+ "write_receipt.get",
315
+ // Command resolution carries the exact required Operation sequence beside
316
+ // this action, so the caller can execute each declared input in order.
317
+ "follow_required_action_sequence",
318
+ // The command needs caller-owned local materialization (for example an
319
+ // @path file) before the Gateway can receive the argument.
320
+ "materialize_local_argument"
306
321
  ];
307
322
  var CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS = Object.freeze(CALLER_RECOVERABLE_NEXT_ACTION_VALUES);
308
323
  var NON_REMEDY_NEXT_ACTION_VALUES = [
324
+ CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
309
325
  // Only an administrator can take the named step -- approving a place for an
310
326
  // Operation, granting a withheld capability -- so a non-administrator asks
311
327
  // one. The refusal names the administrator step; this word is the ask.
@@ -353,7 +369,58 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
353
369
  "select_exact_approval"
354
370
  ];
355
371
  var CEAL_NON_REMEDY_NEXT_ACTIONS = Object.freeze(NON_REMEDY_NEXT_ACTION_VALUES);
356
- var DECLARED = /* @__PURE__ */ new Set([...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS, ...CEAL_NON_REMEDY_NEXT_ACTIONS]);
372
+ var CEAL_DECLARED_NEXT_ACTIONS = Object.freeze([...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS, ...CEAL_NON_REMEDY_NEXT_ACTIONS]);
373
+ var DECLARED = new Set(CEAL_DECLARED_NEXT_ACTIONS);
374
+ function defineCealNonModelNextActions(actions) {
375
+ return actions;
376
+ }
377
+ var NON_MODEL_NEXT_ACTION_VALUES = defineCealNonModelNextActions([
378
+ CEAL_INSPECT_RECEIPT_NEXT_ACTION,
379
+ "await_pending_approval",
380
+ "inspect_gateway",
381
+ "operator_action",
382
+ "none",
383
+ "check_gateway",
384
+ "inspect_context_store",
385
+ "inspect_local_cache",
386
+ "inspect_local_client",
387
+ "inspect_local_command",
388
+ "inspect_local_output",
389
+ "inspect_local_route",
390
+ "inspect_request",
391
+ "reconcile",
392
+ "reconcile_occurrence",
393
+ "retry_after_owner_recovery",
394
+ "select_exact_approval"
395
+ ]);
396
+ var NON_MODEL_NEXT_ACTIONS = new Set(NON_MODEL_NEXT_ACTION_VALUES);
397
+ function isCealModelActionableNonRemedyNextAction(action) {
398
+ return !NON_MODEL_NEXT_ACTIONS.has(action);
399
+ }
400
+ var CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS = Object.freeze([
401
+ ...CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS,
402
+ ...CEAL_NON_REMEDY_NEXT_ACTIONS.filter(isCealModelActionableNonRemedyNextAction)
403
+ ]);
404
+ var MODEL_ACTIONABLE = new Set(CEAL_MODEL_ACTIONABLE_NEXT_ACTIONS);
405
+ var NON_MODEL_ACTION_TO_MODEL_ACTION = Object.freeze({
406
+ [CEAL_INSPECT_RECEIPT_NEXT_ACTION]: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
407
+ await_pending_approval: "ask_admin",
408
+ inspect_gateway: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
409
+ operator_action: "ask_admin",
410
+ none: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
411
+ check_gateway: "ask_admin",
412
+ inspect_context_store: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
413
+ inspect_local_cache: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
414
+ inspect_local_client: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
415
+ inspect_local_command: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
416
+ inspect_local_output: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
417
+ inspect_local_route: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
418
+ inspect_request: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
419
+ reconcile: CEAL_ANSWER_WITH_GAP_NEXT_ACTION,
420
+ reconcile_occurrence: "ask_admin",
421
+ retry_after_owner_recovery: "ask_admin",
422
+ select_exact_approval: "ask_admin"
423
+ });
357
424
  var RETRY_PROMISE_NEXT_ACTIONS = ["retry", "retry_after"];
358
425
  var RETRY_PROMISE = new Set(RETRY_PROMISE_NEXT_ACTIONS);
359
426
  var RECOVERABLE = new Set(CEAL_CALLER_RECOVERABLE_NEXT_ACTIONS);
@@ -623,21 +690,15 @@ var CEAL_OPERATION_ACCESS_CLASSES = vocabulary(["read", "write"]);
623
690
  // packages/ceal-client-protocol/src/domain-vocabulary.ts
624
691
  var CEAL_CONNECTOR_STATUSES = vocabulary(["active", "disabled", "disconnected"]);
625
692
  var CEAL_CONNECTOR_CUSTODIES = vocabulary(["organization", "personal"]);
626
- var CEAL_PROVIDER_BOUNDARY_KINDS = vocabulary([
627
- "github_account",
628
- "github_organization",
629
- "google_workspace_domain",
630
- "notion_workspace",
631
- "slack_workspace"
632
- ]);
633
- var CEAL_PROVIDER_BOUNDARY_EVIDENCE = vocabulary(["provider_readback", "operator_stated"]);
634
693
  var CEAL_ACCESS_LEVELS = vocabulary(["none", "read", "read_write"]);
635
694
  var CEAL_PERSONAL_ACCESS_CEILINGS = vocabulary(["disabled", "read", "read_write"]);
636
695
  var CEAL_TARGET_REF_PATTERN = "^[^\\p{Cc}]+$";
637
696
  var TARGET_REF = new RegExp(CEAL_TARGET_REF_PATTERN, "u");
638
697
  var CEAL_TARGET_VISIBILITIES = vocabulary(["public", "private"]);
639
- var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
698
+ var CEAL_PRINCIPAL_KINDS = vocabulary(["human", "runtime"]);
699
+ var CEAL_PERSISTED_PRINCIPAL_KINDS = vocabulary(["human", "service", "runtime"]);
640
700
  var CEAL_ORGANIZATION_ROLES = vocabulary(["member", "admin"]);
701
+ var CEAL_CALENDAR_PERIODS = vocabulary(["day", "week", "month"]);
641
702
  var LABEL_EXPECTATION = `public-safe display text of at most ${CEAL_PUBLIC_DISPLAY_NAME_MAX_BYTES} bytes`;
642
703
 
643
704
  // packages/ceal-client-protocol/src/safe-json-budget.ts
@@ -813,7 +874,7 @@ var CEAL_SCHEMA_LITERALS = [
813
874
  "ceal.operation_receipt.v1",
814
875
  "ceal.operation_result.v1",
815
876
  "ceal.operation_result.compact.v1",
816
- "ceal.local_result_materialization.v1",
877
+ "ceal.local_result_file.v1",
817
878
  "ceal.local_result_root.v1",
818
879
  "ceal.owner_bootstrap_exchange_request.v1",
819
880
  "ceal.owner_bootstrap_exchange_result.v1",
@@ -907,41 +968,6 @@ var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_JSON_SCHEMA = Object.freeze({
907
968
  }
908
969
  });
909
970
 
910
- // packages/ceal-client-protocol/src/provider-operation-vocabulary.ts
911
- var CEAL_FILE_TYPE_FAMILIES = vocabulary(["all", "image", "pdf"]);
912
- var CEAL_GITHUB_ISSUE_STATES = vocabulary(["open", "closed", "all"]);
913
- var CEAL_NOTION_UPDATABLE_BLOCK_TYPES = vocabulary([
914
- "paragraph",
915
- "heading_1",
916
- "heading_2",
917
- "heading_3",
918
- "bulleted_list_item",
919
- "numbered_list_item",
920
- "to_do",
921
- "code"
922
- ]);
923
- var CEAL_NOTION_NEUTRAL_TYPES = vocabulary([
924
- "text",
925
- "number",
926
- "boolean",
927
- "date",
928
- "select",
929
- "multi_select",
930
- "people",
931
- "url",
932
- "email",
933
- "phone",
934
- "unsupported"
935
- ]);
936
- var CEAL_NOTION_IDENTITY_GAP_REASONS = vocabulary([
937
- "identity_unavailable",
938
- "identity_stale",
939
- "identity_ambiguous",
940
- "identity_revoked",
941
- "identity_unlinked"
942
- ]);
943
- var CEAL_NOTION_STRING_VALUE_TYPES = vocabulary(["text", "select", "url", "email", "phone"]);
944
-
945
971
  // packages/ceal-client-protocol/src/opaque-reference.ts
946
972
  var CEAL_OPAQUE_HANDLE_KINDS = vocabulary(["target", "message", "thread", "artifact", "document", "block", "object"]);
947
973
  var CEAL_OPAQUE_REF_KINDS = vocabulary([...CEAL_OPAQUE_HANDLE_KINDS, "result", "operation-receipt", "reply-receipt", "field", "notion-data-source"]);
@@ -951,6 +977,7 @@ var REQUIRED_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_f
951
977
  var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_optional_fields;
952
978
 
953
979
  // packages/ceal-client-protocol/src/resource-row.ts
980
+ var CEAL_RESOURCE_ROW_TITLE_MATCH_DISPOSITIONS = vocabulary(["exact", "not_exact", "unknown"]);
954
981
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
955
982
  var CEAL_RESOURCE_SEARCH_DIRECTIONS = vocabulary(["ascending", "descending"]);
956
983
  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"]);
@@ -974,6 +1001,7 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
974
1001
  "resource_modified"
975
1002
  ]);
976
1003
  var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
1004
+ var CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE = "unsupported_event_kind";
977
1005
  var CEAL_ACTIVITY_GAP_CODES = vocabulary([
978
1006
  "provider_page_budget",
979
1007
  "call_deadline",
@@ -981,7 +1009,7 @@ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
981
1009
  "provider_cursor_unavailable",
982
1010
  "malformed_provider_page",
983
1011
  "visibility_incomplete",
984
- "unsupported_event_kind",
1012
+ CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE,
985
1013
  "direct_messages_excluded"
986
1014
  ]);
987
1015
  var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
@@ -1033,6 +1061,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1033
1061
  next: { required: true, timestamp: false },
1034
1062
  kind: { required: true, timestamp: false },
1035
1063
  matched_kinds: { required: false, timestamp: false },
1064
+ title_match: { required: false, timestamp: false },
1036
1065
  title: { required: true, timestamp: false },
1037
1066
  container_label: { required: true, timestamp: false },
1038
1067
  container_ref: { required: false, timestamp: false },
@@ -1046,6 +1075,8 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1046
1075
  modified_at: { required: false, timestamp: true },
1047
1076
  modified_at_local: { required: false, timestamp: true },
1048
1077
  viewed_by_me_at: { required: false, timestamp: true },
1078
+ own_ceal_write: { required: false, timestamp: false },
1079
+ owned_by_me: { required: false, timestamp: false },
1049
1080
  visibility: { required: false, timestamp: false },
1050
1081
  start: { required: false, timestamp: false },
1051
1082
  end: { required: false, timestamp: false },
@@ -1079,6 +1110,15 @@ function cealExcludedTargetCoverageJsonSchema() {
1079
1110
  };
1080
1111
  }
1081
1112
 
1113
+ // packages/ceal-client-protocol/src/gateway-write-identity.ts
1114
+ var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
1115
+ var CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN = /^gateway-write-request:[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/u;
1116
+ var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
1117
+ replay_identity: "idempotency_claim_sha256",
1118
+ lookup_handle: "write_request_sha256",
1119
+ collision_evidence: "normalized_mutation_sha256"
1120
+ });
1121
+
1082
1122
  // packages/ceal-client-protocol/src/write-safety-finding.ts
1083
1123
  var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
1084
1124
  var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
@@ -1106,7 +1146,11 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1106
1146
  "refresh_revoked",
1107
1147
  "authority_replaced",
1108
1148
  "refresh_recovery_unavailable",
1109
- "refresh_recovery_expired"
1149
+ "refresh_recovery_expired",
1150
+ // The serving gate answers this while the Gateway is still starting and the
1151
+ // refresh was never attempted; the same attempt stays retryable. It is never
1152
+ // stored by the session owner, only answered at the serving edge.
1153
+ "gateway_starting"
1110
1154
  ]);
1111
1155
 
1112
1156
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
@@ -1139,7 +1183,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
1139
1183
  var CEAL_REQUEST_KEYS = Object.freeze(["schema_version", "ceal_request_ref", "created_at", "authority", "prompt_ref", "host_session_ref", "host_turn_ref", "host_source_ref"]);
1140
1184
  var CEAL_REQUEST_JSON_SCHEMA = {
1141
1185
  type: "object",
1142
- maxProperties: 10,
1186
+ maxProperties: 11,
1143
1187
  additionalProperties: false,
1144
1188
  properties: {
1145
1189
  schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
@@ -1163,7 +1207,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
1163
1207
  host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1164
1208
  host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1165
1209
  host_source_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1166
- requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." }
1210
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1211
+ device_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source, description: "Device that submitted this Request through its client session; absent for Host turns and older records." }
1167
1212
  },
1168
1213
  required: CEAL_REQUEST_KEYS
1169
1214
  };
@@ -1222,6 +1267,7 @@ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
1222
1267
  retryable: { type: "boolean" },
1223
1268
  source: { type: "string", enum: ["provider", "gateway"] },
1224
1269
  retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
1270
+ write_request_ref: { type: "string", pattern: CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN.source, maxLength: 128 },
1225
1271
  excluded_targets: cealExcludedTargetCoverageJsonSchema(),
1226
1272
  repaired_input: {},
1227
1273
  unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
@@ -1286,6 +1332,43 @@ function cealHostObservationRef(producer, digest2) {
1286
1332
  if (!HOST_OBSERVATION_PRODUCER.test(producer) || !HOST_OBSERVATION_DIGEST.test(digest2)) invalid("Ceal Host observation reference parts are invalid.");
1287
1333
  return `${CEAL_HOST_OBSERVATION_REF_PREFIX}${producer}-${digest2}`;
1288
1334
  }
1335
+ var HOST_TOKEN_OBSERVATION_BREAKDOWN_KEYS = vocabulary(["cached_input", "cache_write_input", "reasoning_output"]);
1336
+ function createHostTokenObservationValue(counts, source) {
1337
+ const core = validTokenCore(counts);
1338
+ if (typeof source !== "string" || source.length === 0 || source.length > 256) invalid("Ceal Host token observation source is invalid.");
1339
+ const value = { status: "available", unit: "tokens", input: core.input, output: core.output, total: core.total, source };
1340
+ for (const breakdown of validTokenBreakdowns(counts)) value[breakdown.key] = breakdown.tokens;
1341
+ assertHostObservationValue(value, "token");
1342
+ return value;
1343
+ }
1344
+ function validTokenCore(counts) {
1345
+ if (!isOperationRecord(counts) || !safeCount(counts.input) || !safeCount(counts.output) || !safeCount(counts.total)) invalid("Ceal Host token observation counts are invalid.");
1346
+ if (counts.total !== counts.input + counts.output) invalid("Ceal Host token observation counts are invalid.");
1347
+ return { input: counts.input, output: counts.output, total: counts.total };
1348
+ }
1349
+ function validTokenBreakdowns(counts) {
1350
+ const breakdowns = [
1351
+ { key: "cached_input", tokens: counts.cached_input },
1352
+ { key: "cache_write_input", tokens: counts.cache_write_input },
1353
+ { key: "reasoning_output", tokens: counts.reasoning_output }
1354
+ ];
1355
+ const stated = breakdowns.filter((breakdown) => breakdown.tokens !== void 0).map((breakdown) => ({ key: breakdown.key, tokens: Number(breakdown.tokens) }));
1356
+ for (const breakdown of stated) {
1357
+ if (!safeCount(breakdown.tokens)) invalid("Ceal Host token observation counts are invalid.");
1358
+ }
1359
+ const cached = counts.cached_input ?? 0;
1360
+ const created = counts.cache_write_input ?? 0;
1361
+ const reasoning = counts.reasoning_output ?? 0;
1362
+ if (cached + created > counts.input || reasoning > counts.output) invalid("Ceal Host token observation counts are invalid.");
1363
+ return stated;
1364
+ }
1365
+ function hostObservationNotRecorded(reason) {
1366
+ if (typeof reason !== "string" || reason.length === 0 || reason.length > 256) invalid("Ceal Host observation gap reason is invalid.");
1367
+ return { status: "not_recorded", reason };
1368
+ }
1369
+ function safeCount(value) {
1370
+ return Number.isSafeInteger(value) && Number(value) >= 0;
1371
+ }
1289
1372
  function validateCealHostObservationDraft(value) {
1290
1373
  const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
1291
1374
  requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
@@ -1437,12 +1520,85 @@ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
1437
1520
  "host_input_mismatch",
1438
1521
  "host_prompt_mismatch"
1439
1522
  ]);
1523
+ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
1524
+ "invalid_arguments",
1525
+ "options_invalid",
1526
+ "session_unavailable",
1527
+ "context_unavailable",
1528
+ "context_replaced",
1529
+ "no_binding",
1530
+ "context_stale",
1531
+ "context_expired",
1532
+ "host_source_refused",
1533
+ "host_credential_refused",
1534
+ "gateway_unavailable",
1535
+ "gateway_rate_limited",
1536
+ "gateway_refused",
1537
+ "gateway_response_invalid",
1538
+ "producer_frame_invalid",
1539
+ "relay_permission_denied",
1540
+ "relay_unavailable",
1541
+ "transient_retryable",
1542
+ "mint_failed",
1543
+ "relay_failed",
1544
+ "host_refusal_invalid"
1545
+ ]);
1546
+ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
1547
+ invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
1548
+ options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
1549
+ session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1550
+ context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "refresh_host_invocation_context", remedy: "the Host has no invocation context from the current transcript turn; send a new message to start a fresh Host turn, then retry this command on that turn (run `ceal-host install` only if the Host hook registration is missing or drifted)" }),
1551
+ context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1552
+ no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
1553
+ context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1554
+ context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
1555
+ host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
1556
+ host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
1557
+ gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
1558
+ gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
1559
+ gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
1560
+ gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
1561
+ producer_frame_invalid: Object.freeze({ classification: "host_producer_frame_invalid", next_action: "ask_admin", remedy: "ask an administrator to inspect and repair the producer frame, then start a fresh Host turn" }),
1562
+ relay_permission_denied: Object.freeze({ classification: "host_relay_permission_denied", next_action: "rerun_outside_agent_sandbox", remedy: "an agent sandbox denied the Host Relay socket; run `ceal` as the only command, with no pipe, redirect, or `&&`, so the Host allow rule runs it outside the sandbox" }),
1563
+ relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
1564
+ transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
1565
+ mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
1566
+ relay_failed: Object.freeze({ classification: "host_relay_failed", next_action: "answer_with_gap" }),
1567
+ host_refusal_invalid: Object.freeze({ classification: "host_refusal_invalid", next_action: "answer_with_gap" })
1568
+ });
1569
+
1570
+ // packages/ceal-client-protocol/src/host-service-diagnostic.ts
1571
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA = "ceal.host_service_diagnostic.v1";
1572
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_PRODUCERS = vocabulary(["claude", "codex"]);
1573
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
1574
+ "hook_invoked",
1575
+ "registration_written",
1576
+ "hook_failed",
1577
+ "watcher_turn_observed",
1578
+ "current_prompt_registered",
1579
+ "current_prompt_registration_failed",
1580
+ "current_prompt_capacity_exhausted",
1581
+ "activation_recorded",
1582
+ "activation_failed",
1583
+ "watcher_scan_failed",
1584
+ "activation_wait_skipped",
1585
+ "activation_wait_engaged",
1586
+ "activation_wait_completed",
1587
+ "activation_wait_exhausted"
1588
+ ]);
1589
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_FAILURE_KINDS = vocabulary([
1590
+ "malformed_line",
1591
+ "other",
1592
+ "payload_rejected",
1593
+ "read_error",
1594
+ "size_budget",
1595
+ "symlink"
1596
+ ]);
1440
1597
 
1441
1598
  // packages/ceal-client-protocol/src/client-result-materialization.ts
1442
1599
  var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
1443
- var CEAL_MODEL_VISIBLE_COMMAND_OUTPUT_MAX_BYTES = 32 * 1024;
1444
- var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "read_argv"]);
1445
- var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "local_result_root", "continue_argv", "model_disclosure"]);
1600
+ var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
1601
+ var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "items_path", "row_count", "result_complete", "coverage", "local_result_root", "model_disclosure", "continue_argv", "how_to_read"]);
1446
1602
 
1447
1603
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
1448
1604
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -1472,14 +1628,6 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
1472
1628
  "target_specific_scope_not_declared"
1473
1629
  ]);
1474
1630
 
1475
- // packages/ceal-client-protocol/src/gateway-write-identity.ts
1476
- var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
1477
- var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
1478
- replay_identity: "idempotency_claim_sha256",
1479
- lookup_handle: "write_request_sha256",
1480
- collision_evidence: "normalized_mutation_sha256"
1481
- });
1482
-
1483
1631
  // packages/ceal-client-protocol/src/gateway-scoped-identity-projection-validation.ts
1484
1632
  var PROJECTION_REVISION_KEYS = Object.freeze(["graph_revision", "subject_key_revision", "projection_revision"]);
1485
1633
 
@@ -1492,6 +1640,18 @@ var CEAL_SUPPORTED_GATEWAY_PROTOCOL_RANGE = Object.freeze({
1492
1640
  // packages/ceal-client-protocol/src/admin-projection-vocabulary.ts
1493
1641
  var ADMIN_PROJECTION_STATES = vocabulary(["ready", "empty", "partial", "unknown"]);
1494
1642
  var ADMIN_VIEW_KINDS = vocabulary(["request_detail", "resource_access_timeline", "weekly_usage"]);
1643
+ var ADMIN_RECORD_PROJECTION_KINDS = vocabulary([
1644
+ "request_list",
1645
+ "usage_series",
1646
+ "connector_health",
1647
+ "person_connections",
1648
+ "client_sessions",
1649
+ "knowledge_base",
1650
+ "change_history",
1651
+ "approval_queue",
1652
+ "access_group_list",
1653
+ "capability_catalogue"
1654
+ ]);
1495
1655
  var ADMIN_GAP_KINDS = vocabulary(["unknown", "unavailable", "partial"]);
1496
1656
  var ADMIN_UNAVAILABLE_REASONS = vocabulary([
1497
1657
  "not_recorded",
@@ -1515,7 +1675,11 @@ var ADMIN_SOURCE_OWNERS = vocabulary([
1515
1675
  "person",
1516
1676
  "resource",
1517
1677
  "prompt",
1518
- "usage"
1678
+ "usage",
1679
+ "connector",
1680
+ "session",
1681
+ "knowledge",
1682
+ "policy"
1519
1683
  ]);
1520
1684
  var ADMIN_COMPLETENESS_STATES = vocabulary(["complete", "partial", "unknown"]);
1521
1685
  var ADMIN_OPERATION_OUTCOMES = vocabulary(["completed", "failed", "denied", "cancelled", "unknown"]);
@@ -1552,11 +1716,7 @@ var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1"
1552
1716
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
1553
1717
  var CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION = "ceal.codex_transcript_cursor.v1";
1554
1718
  var CODEX_DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1e3;
1555
- var CODEX_HOOK_EVENTS = ["SessionStart"];
1556
- var CODEX_TRANSCRIPT_CURSOR_REASONS = ["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"];
1557
- function isCodexTranscriptCursorReason(value) {
1558
- return typeof value === "string" && CODEX_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
1559
- }
1719
+ var CODEX_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit"];
1560
1720
  var CodexHostAdapterError = class extends Error {
1561
1721
  name = "CodexHostAdapterError";
1562
1722
  code;
@@ -1571,12 +1731,12 @@ function isCodexHookEvent(value) {
1571
1731
 
1572
1732
  // host/codex/src/codex-decoder.ts
1573
1733
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1574
- var MAX_PAYLOAD_BYTES = 64 * 1024;
1734
+ var MAX_PAYLOAD_BYTES = 512 * 1024;
1575
1735
  var MAX_TEXT = 256;
1576
1736
  function decodeCodexHookPayload(event, raw) {
1577
- if (event !== "SessionStart") reject(`Codex hook event is not installed by this adapter (${refusalFact("event", event, "SessionStart")})`);
1578
1737
  const input = parsePayload(raw);
1579
- return decodeSession(input, event);
1738
+ if (event === "SessionStart") return decodeSession(input, event);
1739
+ return decodeUserPromptSubmit(input, event);
1580
1740
  }
1581
1741
  function observationRef(event, identity, value) {
1582
1742
  return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
@@ -1628,6 +1788,20 @@ function decodeSession(input, event) {
1628
1788
  transcript_path: requiredText(input.transcript_path, "transcript_path", 4096)
1629
1789
  };
1630
1790
  }
1791
+ function decodeUserPromptSubmit(input, event) {
1792
+ exactKeys(input, ["cwd", "hook_event_name", "model", "permission_mode", "prompt", "session_id", "transcript_path", "turn_id"], []);
1793
+ validateHookEventName(input, event);
1794
+ const cwd = requiredText(input.cwd, "cwd", 4096);
1795
+ if (!isAbsolute(cwd) || cwd.includes("\0")) reject("Codex cwd is invalid");
1796
+ return {
1797
+ event,
1798
+ cwd: resolve(cwd),
1799
+ session_id: requiredText(input.session_id, "session_id", MAX_TEXT),
1800
+ transcript_path: requiredText(input.transcript_path, "transcript_path", 4096),
1801
+ turn_id: requiredText(input.turn_id, "turn_id", MAX_TEXT),
1802
+ prompt: requiredText(input.prompt, "prompt", MAX_PAYLOAD_BYTES)
1803
+ };
1804
+ }
1631
1805
  function parsePayload(raw) {
1632
1806
  try {
1633
1807
  const text = typeof raw === "string" ? raw : JSON.stringify(raw);
@@ -1670,9 +1844,9 @@ function reject(message) {
1670
1844
  }
1671
1845
 
1672
1846
  // host/codex/src/codex-outbox.ts
1673
- import { O_NOFOLLOW, O_RDONLY } from "node:constants";
1674
- import { lstat, mkdir, open, readdir, rename, unlink } from "node:fs/promises";
1675
- import { dirname, isAbsolute as isAbsolute2, join as join2 } from "node:path";
1847
+ import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
1848
+ import { lstat as lstat2, mkdir as mkdir3, open as open3, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
1849
+ import { dirname, isAbsolute as isAbsolute2, join as join3 } from "node:path";
1676
1850
 
1677
1851
  // host/invocation-context.ts
1678
1852
  var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
@@ -1686,17 +1860,32 @@ function hasHostInvocationIdentityKeys(value) {
1686
1860
  function hasHostInvocationContextKeys(value, optional = []) {
1687
1861
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
1688
1862
  }
1863
+ async function readLatestSessionProjection(file, hostSourceRef, hostSessionRef, readProjection) {
1864
+ const context = await readProjection(file);
1865
+ if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
1866
+ return context;
1867
+ }
1868
+ function isLiveSessionProjection(context, now) {
1869
+ return context !== null && Date.parse(context.expires_at) > now.getTime();
1870
+ }
1689
1871
  function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
1690
1872
  const context = {
1691
1873
  schema_version: descriptor.schema_version,
1692
1874
  identity,
1693
1875
  prompt_ref: promptRef,
1694
1876
  expires_at: expiresAt,
1877
+ ...descriptor.turn_generation_ref === void 0 ? {} : { turn_generation_ref: descriptor.turn_generation_ref },
1695
1878
  ...descriptor.working_directory === void 0 ? {} : { working_directory: descriptor.working_directory }
1696
1879
  };
1697
1880
  descriptor.validate(context);
1698
1881
  return Object.freeze(context);
1699
1882
  }
1883
+ function isHostInvocationTurnSelection(value) {
1884
+ return isRecord2(value) && Object.keys(value).length === 5 && value.schema_version === "ceal.host_invocation_turn_selection.v1" && ["host_source_ref", "host_session_ref", "prompt_ref", "turn_generation_ref"].every((key) => safeRef(value[key]));
1885
+ }
1886
+ function invocationTurnSelectionMatches(context, selection) {
1887
+ return selection === null || context !== null && selection.host_source_ref === context.identity.host_source_ref && selection.host_session_ref === context.identity.host_session_ref && selection.prompt_ref === context.prompt_ref && selection.turn_generation_ref === context.turn_generation_ref;
1888
+ }
1700
1889
  function exactKeys2(value, keys) {
1701
1890
  const actual = Object.keys(value);
1702
1891
  return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
@@ -1706,145 +1895,964 @@ function requiredKeys(value, required, optional) {
1706
1895
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
1707
1896
  return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
1708
1897
  }
1898
+ function isRecord2(value) {
1899
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1900
+ }
1901
+ function safeRef(value) {
1902
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
1903
+ }
1709
1904
 
1710
- // host/codex/src/codex-invocation-context.ts
1711
- function codexInvocationContextFromTurn(identity, promptRef, expiresAt) {
1712
- return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext });
1905
+ // host/relay/src/producer-frame.ts
1906
+ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1907
+ var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1908
+ var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
1909
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1910
+ var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
1911
+ var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
1912
+ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
1913
+ function isHostProducerFrameKind(value) {
1914
+ return typeof value === "string" && FRAME_KINDS.has(value);
1713
1915
  }
1714
- function validateCodexHostInvocationContext(value) {
1715
- if (!isContextShape(value)) {
1716
- throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
1916
+ var HOST_PRODUCER_FRAME_ERROR_CODES = [
1917
+ "invalid_frame_encoding",
1918
+ "invalid_frame_length",
1919
+ "frame_truncated",
1920
+ "unsupported_frame_schema",
1921
+ "invalid_frame_shape",
1922
+ "invalid_producer_identity",
1923
+ "frame_too_large"
1924
+ ];
1925
+ var HostProducerFrameError = class extends Error {
1926
+ code;
1927
+ constructor(code, message = code) {
1928
+ super(message);
1929
+ this.code = code;
1717
1930
  }
1718
- validateIdentity(value.identity);
1719
- validateContextReferences(value);
1720
- validateContextTimes(value);
1721
- }
1722
- function invocationContextFromBinding(binding) {
1723
- const context = {
1724
- schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
1725
- identity: binding.identity,
1726
- prompt_ref: binding.prompt_ref,
1727
- request_ref: binding.request_ref,
1728
- bound_at: binding.bound_at,
1729
- expires_at: binding.expires_at
1730
- };
1731
- validateCodexHostInvocationContext(context);
1732
- return Object.freeze(context);
1931
+ };
1932
+ function encodeHostProducerFrame(frame) {
1933
+ validateFrame(frame);
1934
+ const json = Buffer.from(JSON.stringify(frame), "utf8");
1935
+ if (json.byteLength > HOST_PRODUCER_MAX_JSON_BYTES) throw new HostProducerFrameError("frame_too_large", `frame_too_large: ${refusalFact("frame_bytes", json.byteLength, `at most ${HOST_PRODUCER_MAX_JSON_BYTES}`)}`);
1936
+ const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
1937
+ result.writeUInt32BE(json.byteLength, 0);
1938
+ json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
1939
+ return result;
1733
1940
  }
1734
- function validateIdentity(value) {
1735
- if (!isRecord2(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef)) {
1736
- throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
1941
+ function decodeHostProducerFrame(input) {
1942
+ if (input.byteLength < HOST_PRODUCER_FRAME_LENGTH_BYTES) throw new HostProducerFrameError("frame_truncated", `frame_truncated: ${refusalFact("frame_bytes", input.byteLength, `at least ${HOST_PRODUCER_FRAME_LENGTH_BYTES}`)}`);
1943
+ const length = input.readUInt32BE(0);
1944
+ if (length > HOST_PRODUCER_MAX_JSON_BYTES) throw new HostProducerFrameError("frame_too_large", `frame_too_large: ${refusalFact("declared_bytes", length, `at most ${HOST_PRODUCER_MAX_JSON_BYTES}`)}`);
1945
+ if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
1946
+ if (input.byteLength !== length + HOST_PRODUCER_FRAME_LENGTH_BYTES) throw new HostProducerFrameError(input.byteLength < length + HOST_PRODUCER_FRAME_LENGTH_BYTES ? "frame_truncated" : "invalid_frame_length");
1947
+ const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
1948
+ const text = new TextDecoder("utf-8", { fatal: true });
1949
+ let value;
1950
+ try {
1951
+ value = JSON.parse(text.decode(bytes));
1952
+ } catch (error) {
1953
+ if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
1954
+ throw new HostProducerFrameError("frame_truncated");
1737
1955
  }
1956
+ validateFrame(value);
1957
+ return value;
1738
1958
  }
1739
- function isContextShape(value) {
1740
- return isRecord2(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
1959
+ function isHostSafeRef(value) {
1960
+ return safeRef2(value);
1741
1961
  }
1742
- function validateContextReferences(value) {
1743
- if (!safeRef(value.prompt_ref) || !optionalSafeRef(value.request_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
1962
+ function validateFrame(value) {
1963
+ if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
1964
+ if (value.schema_version !== HOST_PRODUCER_FRAME_SCHEMA) throw new HostProducerFrameError("unsupported_frame_schema", `unsupported_frame_schema: ${refusalFact("schema_version", value.schema_version, HOST_PRODUCER_FRAME_SCHEMA)}`);
1965
+ if (!exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
1966
+ if (!PRODUCERS.has(String(value.producer_id)) || !safeRef2(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
1967
+ if (!positive(value.producer_epoch) || !positive(value.sequence) || !hostProducerFrameKind(value.frame_kind) || !timestamp(value.occurred_at) || !record(value.payload)) throw new HostProducerFrameError("invalid_frame_shape");
1968
+ validatePayload(value.frame_kind, value.payload);
1744
1969
  }
1745
- function validateContextTimes(value) {
1746
- const expiresAt = value.expires_at;
1747
- const boundAt = value.bound_at;
1748
- if (!timestamp(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
1749
- 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}`)}).`);
1970
+ function validatePayload(kind, value) {
1971
+ const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
1972
+ if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
1750
1973
  }
1751
- function optionalSafeRef(value) {
1752
- return value === void 0 || safeRef(value);
1974
+ function validSession(value) {
1975
+ return exactOptional(value, ["local_session_ref", "working_directory_ref"], ["model", "host_version", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.working_directory_ref) && optionalText(value.model, 256) && optionalText(value.host_version, 256) && validObservations(value.observations);
1753
1976
  }
1754
- function optionalTimestamp(value) {
1755
- return value === void 0 || timestamp(value);
1977
+ function validTurn(value) {
1978
+ return exactOptional(value, ["local_session_ref", "local_turn_ref"], ["model", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && optionalText(value.model, 256) && validObservations(value.observations);
1756
1979
  }
1757
- function safeRef(value) {
1758
- return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
1980
+ function validInput(value) {
1981
+ return exactOptional(value, ["local_session_ref", "local_turn_ref", "local_input_ref", "input_kind", "origin_input", "observations"], ["local_turn_aliases", "context_expires_at"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && safeRef2(value.local_input_ref) && validInputObservations(value.observations) && isCealHostInputKind(value.input_kind) && typeof value.origin_input === "boolean" && validInputOptionals(value);
1759
1982
  }
1760
- function timestamp(value) {
1761
- return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
1983
+ function validInputObservations(value) {
1984
+ return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
1762
1985
  }
1763
- function isRecord2(value) {
1764
- return value !== null && typeof value === "object" && !Array.isArray(value);
1986
+ function validInputOptionals(value) {
1987
+ return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp(value.context_expires_at));
1765
1988
  }
1766
-
1767
- // host/codex/src/codex-outbox.ts
1768
- var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1769
- var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
1770
- var CodexOutboxStore = class {
1771
- directory;
1772
- entriesDirectory;
1773
- bindingsDirectory;
1774
- sessionsDirectory;
1775
- activeContextsDirectory;
1776
- registrationsDirectory;
1777
- cursorsDirectory;
1778
- constructor(directory) {
1779
- if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
1780
- this.directory = directory;
1781
- this.entriesDirectory = join2(directory, "entries");
1782
- this.bindingsDirectory = join2(directory, "bindings");
1783
- this.sessionsDirectory = join2(directory, "sessions");
1784
- this.activeContextsDirectory = join2(directory, "active-contexts");
1785
- this.registrationsDirectory = join2(directory, "transcript-registrations");
1786
- this.cursorsDirectory = join2(directory, "transcript-cursors");
1787
- }
1788
- async prepare() {
1789
- for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
1790
- await ensurePrivateOwnerDirectory(path);
1791
- }
1792
- }
1793
- async put(entry) {
1794
- validateEnvelope(entry);
1795
- await this.prepare();
1796
- await writeAtomicJson(this.entryPath(entry.submission_ref), entry);
1797
- }
1798
- async list() {
1799
- await this.prepare();
1800
- const entries = [];
1801
- let malformed = 0;
1802
- for (const name of await readdir(this.entriesDirectory)) {
1803
- if (!name.endsWith(".json")) continue;
1804
- try {
1805
- const value = JSON.parse(await readPrivateFile(join2(this.entriesDirectory, name)));
1806
- validateEnvelope(value);
1807
- entries.push(value);
1808
- } catch {
1809
- malformed += 1;
1810
- }
1811
- }
1812
- entries.sort((left, right) => left.created_at.localeCompare(right.created_at));
1813
- return { entries, malformed };
1814
- }
1815
- async remove(entry) {
1816
- validateEnvelope(entry);
1989
+ function validTerminal(value) {
1990
+ return exactOptional(value, ["local_session_ref", "local_turn_ref", "terminal_state"], ["abort_reason", "duration_ms", "time_to_first_token_ms", "usage", "observations"]) && safeRef2(value.local_session_ref) && safeRef2(value.local_turn_ref) && validTerminalDisposition(value.terminal_state, value.abort_reason) && optionalNonNegative(value.duration_ms) && optionalNonNegative(value.time_to_first_token_ms) && (value.usage === void 0 || jsonValue(value.usage)) && validObservations(value.observations);
1991
+ }
1992
+ function validTerminalDisposition(state, reason) {
1993
+ return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef2(reason));
1994
+ }
1995
+ function validStatus(value) {
1996
+ return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef2(value.reason_code) && optionalText(value.detail, 4096);
1997
+ }
1998
+ function optionalText(value, maxLength) {
1999
+ return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
2000
+ }
2001
+ function optionalNonNegative(value) {
2002
+ return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
2003
+ }
2004
+ function optionalRefs(value) {
2005
+ return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef2);
2006
+ }
2007
+ function validObservations(value) {
2008
+ if (value === void 0) return true;
2009
+ if (!Array.isArray(value) || value.length > 32) return false;
2010
+ return value.every((item) => {
1817
2011
  try {
1818
- await unlink(this.entryPath(entry.submission_ref));
1819
- } catch (error) {
1820
- if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
2012
+ validateCealHostObservationDraft(item);
2013
+ return true;
2014
+ } catch {
2015
+ return false;
1821
2016
  }
1822
- }
1823
- async writeBinding(binding) {
1824
- validateBinding(binding);
1825
- await this.prepare();
1826
- await writeAtomicJson(this.bindingPath(binding.identity), binding);
1827
- }
1828
- /**
1829
- * Select the exact Host turn that model-reachable commands may use. A new
1830
- * prompt replaces this projection, so it cannot inherit the prior turn's
1831
- * Request by session alone.
1832
- */
1833
- async activateInvocationContext(identity, promptRef, expiresAt) {
1834
- const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt);
1835
- await this.prepare();
1836
- const path = this.activeContextPath(identity);
1837
- try {
2017
+ });
2018
+ }
2019
+ function jsonValue(value, depth = 0) {
2020
+ if (depth > 16) return false;
2021
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2022
+ if (typeof value === "number") return Number.isFinite(value);
2023
+ if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
2024
+ return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
2025
+ }
2026
+ function record(value) {
2027
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2028
+ }
2029
+ function safeRef2(value) {
2030
+ return typeof value === "string" && SAFE_REF3.test(value);
2031
+ }
2032
+ function positive(value) {
2033
+ return Number.isSafeInteger(value) && Number(value) > 0;
2034
+ }
2035
+ function timestamp(value) {
2036
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
2037
+ }
2038
+ function hostProducerFrameKind(value) {
2039
+ return isHostProducerFrameKind(value);
2040
+ }
2041
+ function exactKeys3(value, keys) {
2042
+ return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
2043
+ }
2044
+ function exactOptional(value, required, optional) {
2045
+ const keys = Object.keys(value);
2046
+ return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2047
+ }
2048
+
2049
+ // host/relay/src/host-producer-core.ts
2050
+ import { createHash as createHash3 } from "node:crypto";
2051
+ import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
2052
+ import { mkdir as mkdir2, open as open2, readFile, rename as rename2, writeFile } from "node:fs/promises";
2053
+ import { join as join2 } from "node:path";
2054
+
2055
+ // host/relay/src/relay-ipc.ts
2056
+ import { createConnection, createServer } from "node:net";
2057
+
2058
+ // host/relay/src/durable-atomic-replacement.ts
2059
+ import { O_RDONLY } from "node:constants";
2060
+ import { lstat, mkdir, open, rename, unlink } from "node:fs/promises";
2061
+ var DEFAULT_PORT = {
2062
+ platform: process.platform,
2063
+ mkdir: (path, options) => mkdir(path, options),
2064
+ lstat: (path) => lstat(path),
2065
+ open_file: (path) => open(path, "wx", 384),
2066
+ rename,
2067
+ unlink,
2068
+ open_directory: (path) => open(path, O_RDONLY),
2069
+ unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2070
+ };
2071
+
2072
+ // host/relay/src/relay-request-binding-store.ts
2073
+ var MAX_STATE_BYTES = 8 * 1024 * 1024;
2074
+
2075
+ // host/relay/src/current-prompt-custody.ts
2076
+ var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2077
+
2078
+ // host/service-log.ts
2079
+ function writeHostServiceDiagnostic(producer_id, event, failure_kind, cause, sink) {
2080
+ const line = `${JSON.stringify({ schema_version: CEAL_HOST_SERVICE_DIAGNOSTIC_SCHEMA, producer_id, event, ...event === "watcher_scan_failed" && failure_kind !== void 0 ? { failure_kind } : {}, ...event === "watcher_scan_failed" && cause !== void 0 ? { cause } : {} })}
2081
+ `;
2082
+ try {
2083
+ (sink ?? defaultHostServiceDiagnosticSink)(line);
2084
+ } catch {
2085
+ }
2086
+ }
2087
+ function defaultHostServiceDiagnosticSink(line) {
2088
+ process.stderr.write(line);
2089
+ }
2090
+ var HOST_SERVICE_LOG_MAX_BYTES = 1024 * 1024;
2091
+ var HOST_SERVICE_LOG_TAIL_BYTES = 64 * 1024;
2092
+
2093
+ // host/relay/src/relay-ipc.ts
2094
+ var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
2095
+ "schema_version",
2096
+ "producer_id",
2097
+ "producer_installation_ref",
2098
+ "local_session_ref",
2099
+ "local_turn_ref",
2100
+ "local_turn_aliases",
2101
+ "prompt_ref",
2102
+ "request_ref",
2103
+ "bound_at",
2104
+ "host_source_ref",
2105
+ "host_session_ref",
2106
+ "host_turn_ref",
2107
+ "host_input_ref"
2108
+ ]);
2109
+ var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
2110
+ var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2111
+ var HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA = "ceal.host_relay_current_prompt_release.v1";
2112
+ var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2113
+ var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2114
+ var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
2115
+ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
2116
+ "context_stale",
2117
+ "context_expired",
2118
+ "host_source_refused",
2119
+ "host_credential_refused",
2120
+ "gateway_unavailable",
2121
+ "gateway_refused",
2122
+ "gateway_response_invalid",
2123
+ "gateway_rate_limited",
2124
+ "producer_frame_invalid",
2125
+ "deadline",
2126
+ "cancelled",
2127
+ "mint_failed",
2128
+ "relay_failed",
2129
+ "request_authority_unavailable",
2130
+ "request_missing",
2131
+ "authority_mismatch",
2132
+ "host_source_mismatch",
2133
+ "host_session_mismatch",
2134
+ "host_turn_mismatch",
2135
+ "host_input_mismatch",
2136
+ "host_prompt_mismatch"
2137
+ ]);
2138
+ var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
2139
+ "context_stale",
2140
+ "context_expired",
2141
+ "host_source_refused",
2142
+ "host_credential_refused",
2143
+ "gateway_unavailable",
2144
+ "gateway_rate_limited",
2145
+ "gateway_refused",
2146
+ "gateway_response_invalid",
2147
+ "producer_frame_invalid"
2148
+ ]);
2149
+ var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
2150
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2151
+ "permission_denied",
2152
+ "socket_missing",
2153
+ "connection_refused",
2154
+ "closed_early",
2155
+ "response_invalid",
2156
+ "timed_out",
2157
+ "cancelled",
2158
+ "unavailable"
2159
+ ]);
2160
+ var HostRelayIpcError = class extends Error {
2161
+ code;
2162
+ /** Set only when the client-side socket exchange itself failed. */
2163
+ failure;
2164
+ constructor(code, message = code, failure) {
2165
+ super(message);
2166
+ this.code = code;
2167
+ this.failure = failure;
2168
+ }
2169
+ };
2170
+ var HostRelayCurrentPromptCapacityRefusal = class extends Error {
2171
+ constructor() {
2172
+ super("current_prompt_capacity_exhausted");
2173
+ this.name = "HostRelayCurrentPromptCapacityRefusal";
2174
+ }
2175
+ };
2176
+ function hostRelayExchangeFailure(error) {
2177
+ return error instanceof HostRelayIpcError ? error.failure : void 0;
2178
+ }
2179
+ function socketErrorFailure(error) {
2180
+ switch (errorCode(error)) {
2181
+ case "EACCES":
2182
+ case "EPERM":
2183
+ return "permission_denied";
2184
+ case "ENOENT":
2185
+ return "socket_missing";
2186
+ case "ECONNREFUSED":
2187
+ return "connection_refused";
2188
+ default:
2189
+ return "unavailable";
2190
+ }
2191
+ }
2192
+ var HostRelayIpcAdmissionPort = class {
2193
+ endpoint;
2194
+ timeout_ms;
2195
+ constructor(endpoint, timeoutMs = 5e3) {
2196
+ this.endpoint = endpoint;
2197
+ this.timeout_ms = timeoutMs;
2198
+ }
2199
+ async admit(frame) {
2200
+ const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
2201
+ if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
2202
+ return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
2203
+ }
2204
+ };
2205
+ var HostRelayCurrentPromptPort = class {
2206
+ endpoint;
2207
+ timeout_ms;
2208
+ constructor(endpoint, timeoutMs = 5e3) {
2209
+ this.endpoint = endpoint;
2210
+ this.timeout_ms = timeoutMs;
2211
+ }
2212
+ async register(input) {
2213
+ const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
2214
+ const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2215
+ if (response2.status === "capacity_exhausted") throw new HostRelayCurrentPromptCapacityRefusal();
2216
+ if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
2217
+ }
2218
+ async release(identity) {
2219
+ const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_RELEASE_SCHEMA, ...identity };
2220
+ const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2221
+ if (response2.status !== "released") throw new HostRelayIpcError("relay_unavailable", response2.status, "response_invalid");
2222
+ }
2223
+ };
2224
+ function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
2225
+ return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
2226
+ }
2227
+ function exchange(endpoint, encoded, timeoutMs, decode, signal) {
2228
+ return new Promise((resolve3, reject3) => {
2229
+ const socket = createConnection(endpoint);
2230
+ let buffer = Buffer.alloc(0);
2231
+ let settled = false;
2232
+ const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
2233
+ const finish = (error, response2) => {
2234
+ if (settled) return;
2235
+ settled = true;
2236
+ signal?.removeEventListener("abort", aborted);
2237
+ socket.destroy();
2238
+ if (error !== null) reject3(error);
2239
+ else if (response2 !== void 0) resolve3(response2);
2240
+ };
2241
+ if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
2242
+ if (signal?.aborted === true) {
2243
+ aborted();
2244
+ return;
2245
+ }
2246
+ signal?.addEventListener("abort", aborted, { once: true });
2247
+ socket.once("error", (error) => {
2248
+ const failure = socketErrorFailure(error);
2249
+ finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure}.`, failure));
2250
+ });
2251
+ socket.once("connect", () => socket.write(encoded));
2252
+ socket.on("data", (chunk) => {
2253
+ try {
2254
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
2255
+ const decoded = decode(buffer);
2256
+ if (decoded !== null) finish(null, decoded);
2257
+ } catch (error) {
2258
+ finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
2259
+ }
2260
+ });
2261
+ socket.once("end", () => {
2262
+ if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
2263
+ });
2264
+ });
2265
+ }
2266
+ function decodeHostRelayIpcResponse(input) {
2267
+ if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response is truncated: ${refusalFact("response_bytes", input.byteLength, `at least ${HOST_RELAY_IPC_LENGTH_BYTES}`)}.`);
2268
+ const length = input.readUInt32BE(0);
2269
+ if (length === 0 || length > HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES || input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response length is invalid: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `between 1 and ${HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2270
+ let value;
2271
+ try {
2272
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2273
+ } catch {
2274
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
2275
+ }
2276
+ if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
2277
+ return value;
2278
+ }
2279
+ function relayAdmissionCode(value) {
2280
+ return value === "admitted" || value === "already_admitted" || value === "producer_epoch_stale" || value === "sequence_gap" || value === "frame_identity_conflict" || value === "producer_queue_full" || value === "relay_queue_full" || value === "producer_already_connected" || value === "invalid_producer_identity";
2281
+ }
2282
+ function validResponse(value) {
2283
+ return record2(value) && value.schema_version === HOST_RELAY_IPC_RESPONSE_SCHEMA && hostRelayIpcCode(value.code) && nonnegative(value.admitted_through_sequence) && nonnegative(value.delivered_through_sequence) && Object.keys(value).length === 4;
2284
+ }
2285
+ function hostRelayIpcCode(value) {
2286
+ return typeof value === "string" && ["admitted", "already_admitted", "producer_epoch_stale", "sequence_gap", "frame_identity_conflict", "producer_queue_full", "relay_queue_full", "invalid_frame_encoding", "invalid_frame_length", "frame_truncated", "unsupported_frame_schema", "invalid_frame_shape", "invalid_producer_identity", "frame_too_large", "producer_already_connected", "relay_unavailable"].includes(value);
2287
+ }
2288
+ function nonnegative(value) {
2289
+ return Number.isSafeInteger(value) && Number(value) >= 0;
2290
+ }
2291
+ function record2(value) {
2292
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2293
+ }
2294
+ function decodeResponseBuffer(buffer) {
2295
+ if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2296
+ const length = buffer.readUInt32BE(0);
2297
+ if (length === 0 || length > HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC response length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES}`)}.`);
2298
+ if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2299
+ if (buffer.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC returned trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: buffer.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2300
+ return decodeHostRelayIpcResponse(buffer);
2301
+ }
2302
+ function decodeCurrentPromptResponseBuffer(buffer) {
2303
+ const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
2304
+ if (value === null) return null;
2305
+ if (!record2(value) || !exactKeys4(value, ["schema_version", "status"]) || value.schema_version !== HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA || value.status !== "registered" && value.status !== "capacity_exhausted" && value.status !== "current_prompt_unavailable" && value.status !== "released") throw new HostRelayIpcError("relay_unavailable", "Host Relay current-prompt response is invalid.", "response_invalid");
2306
+ return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
2307
+ }
2308
+ function decodeLengthPrefixedJson(input, maximum) {
2309
+ if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2310
+ const length = input.readUInt32BE(0);
2311
+ if (length === 0 || length > maximum) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message length is invalid: ${refusalFact("declared_bytes", length, `between 1 and ${maximum}`)}.`);
2312
+ if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2313
+ if (input.length !== length + HOST_RELAY_IPC_LENGTH_BYTES) throw new HostRelayIpcError("relay_unavailable", `Host Relay IPC message has trailing bytes: ${refusalFacts([{ name: "declared_bytes", value: length, expected: `the received message length minus ${HOST_RELAY_IPC_LENGTH_BYTES}` }, { name: "received_bytes", value: input.byteLength, expected: `exactly ${length + HOST_RELAY_IPC_LENGTH_BYTES}` }])}.`);
2314
+ try {
2315
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2316
+ } catch {
2317
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
2318
+ }
2319
+ }
2320
+ function encodeLengthPrefixed(value) {
2321
+ const body = Buffer.from(JSON.stringify(value), "utf8");
2322
+ const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
2323
+ output.writeUInt32BE(body.length, 0);
2324
+ body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
2325
+ return output;
2326
+ }
2327
+ function exactKeys4(value, required, optional = []) {
2328
+ const keys = Object.keys(value);
2329
+ return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2330
+ }
2331
+ function errorCode(error) {
2332
+ return record2(error) && typeof error.code === "string" ? error.code : null;
2333
+ }
2334
+
2335
+ // host/relay/src/host-producer-core.ts
2336
+ var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
2337
+ function isHostTranscriptCursorReason(value) {
2338
+ return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
2339
+ }
2340
+ var TRANSCRIPT_MISSING_REASON = "transcript_missing";
2341
+ var TRANSCRIPT_SCAN_READ_ERROR_ERRNOS = ["EBADF", "EACCES", "EIO", "EMFILE", "ENFILE", "ENOENT", "ENOTDIR", "EPERM"];
2342
+ function transcriptScanFailureKind(error, adapterFailureKind) {
2343
+ if (transcriptErrorCode(error) === "ELOOP") return "symlink";
2344
+ const adapter = adapterFailureKind(error);
2345
+ if (adapter !== void 0) return adapter;
2346
+ const code = transcriptErrorCode(error);
2347
+ if (code === "EFBIG") return "size_budget";
2348
+ if (code !== null && TRANSCRIPT_SCAN_READ_ERROR_ERRNOS.includes(code)) return "read_error";
2349
+ return "other";
2350
+ }
2351
+ async function registerHostCurrentPromptDiagnosed(register, diagnostic) {
2352
+ try {
2353
+ await register();
2354
+ diagnostic("current_prompt_registered");
2355
+ return true;
2356
+ } catch (error) {
2357
+ if (!(error instanceof HostRelayCurrentPromptCapacityRefusal)) diagnostic("current_prompt_registration_failed");
2358
+ throw error;
2359
+ }
2360
+ }
2361
+ function transcriptErrorCode(error) {
2362
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
2363
+ }
2364
+ var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
2365
+ async function readTranscriptCompleteChunk(handle, offset, size) {
2366
+ const available = Math.max(0, size - offset);
2367
+ if (available === 0) return "empty";
2368
+ const chunks = [];
2369
+ let position = offset;
2370
+ let total = 0;
2371
+ let lastNewline = -1;
2372
+ while (position < size) {
2373
+ const buffer = Buffer.alloc(Math.min(HOST_TRANSCRIPT_READ_CHUNK_BYTES, size - position));
2374
+ const read = await handle.read(buffer, 0, buffer.length, position);
2375
+ if (read.bytesRead === 0) break;
2376
+ const chunk = buffer.subarray(0, read.bytesRead);
2377
+ chunks.push(chunk);
2378
+ const newline = chunk.lastIndexOf(10);
2379
+ if (newline >= 0) lastNewline = total + newline;
2380
+ total += chunk.length;
2381
+ position += chunk.length;
2382
+ if (lastNewline >= 0) break;
2383
+ }
2384
+ if (lastNewline < 0) return "partial";
2385
+ return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
2386
+ }
2387
+ async function readTranscriptAnchor(handle, offset, anchorBytes) {
2388
+ const start = Math.max(0, offset - anchorBytes);
2389
+ const anchor = Buffer.alloc(offset - start);
2390
+ if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, start);
2391
+ return { start, sha256: transcriptSha256(anchor) };
2392
+ }
2393
+ async function transcriptAnchorMatches(handle, cursor) {
2394
+ const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
2395
+ if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
2396
+ return transcriptSha256(buffer) === cursor.anchor_sha256;
2397
+ }
2398
+ function transcriptCursorIdentityReason(cursor, transcriptPath, device, inode) {
2399
+ if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== transcriptPath) return "transcript_replaced";
2400
+ return null;
2401
+ }
2402
+ async function transcriptCursorBoundsReason(handle, cursor, size) {
2403
+ if (size < cursor.offset) return "transcript_truncated";
2404
+ if (cursor.offset > 0 && !await transcriptAnchorMatches(handle, cursor)) return "transcript_rewritten";
2405
+ return null;
2406
+ }
2407
+ function transcriptSha256(value) {
2408
+ return createHash3("sha256").update(value).digest("hex");
2409
+ }
2410
+ function transcriptObjectSha256(value) {
2411
+ return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2412
+ }
2413
+ function isTranscriptRecord(value) {
2414
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2415
+ }
2416
+ function isMissingTranscriptError(error) {
2417
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2418
+ }
2419
+ function transcriptTimestamp(now, fail) {
2420
+ const value = now();
2421
+ if (!Number.isFinite(value.getTime())) throw fail();
2422
+ return value.toISOString();
2423
+ }
2424
+ function transcriptExpiration(now, retentionMs, fail) {
2425
+ return new Date(Date.parse(transcriptTimestamp(now, fail)) + retentionMs).toISOString();
2426
+ }
2427
+ function createTranscriptWatcherBase(options, owner) {
2428
+ if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw owner.invalid_outbox();
2429
+ return {
2430
+ outboxRetentionMs: options.retention_ms ?? owner.default_retention_ms,
2431
+ now: options.now ?? (() => /* @__PURE__ */ new Date()),
2432
+ log: options.log ?? ((line) => {
2433
+ process.stderr.write(`${line}
2434
+ `);
2435
+ }),
2436
+ producerInstallationRef: options.producer_installation_ref
2437
+ };
2438
+ }
2439
+ async function scanTranscriptRegistrations(registrations, scanOne) {
2440
+ let records = 0;
2441
+ let enqueued = 0;
2442
+ let quarantined = 0;
2443
+ for (const registration of registrations) {
2444
+ const result = await scanOne(registration);
2445
+ records += result.records;
2446
+ enqueued += result.enqueued;
2447
+ if (result.quarantined) quarantined += 1;
2448
+ }
2449
+ return { registrations: registrations.length, records, enqueued, quarantined };
2450
+ }
2451
+ function formatRetiredTranscriptLog(producerLabel, transcriptPath) {
2452
+ return `${producerLabel} retired a transcript registration: transcript_path=${JSON.stringify(transcriptPath)}, reason=${TRANSCRIPT_MISSING_REASON}.`;
2453
+ }
2454
+ var HostTranscriptWatcher = class {
2455
+ outboxRetentionMs;
2456
+ now;
2457
+ log;
2458
+ producerInstallationRef;
2459
+ clockFailure;
2460
+ constructor(options, owner) {
2461
+ const base = createTranscriptWatcherBase(options, owner);
2462
+ this.outboxRetentionMs = base.outboxRetentionMs;
2463
+ this.now = base.now;
2464
+ this.log = base.log;
2465
+ this.producerInstallationRef = base.producerInstallationRef;
2466
+ this.clockFailure = owner.clock_failure;
2467
+ }
2468
+ async scanOnce() {
2469
+ return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
2470
+ }
2471
+ async scanRegistration(registration) {
2472
+ try {
2473
+ return await this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2474
+ missing: () => this.retireMissing(registration),
2475
+ failed: (handle, error) => this.scanFailed(handle, registration, error)
2476
+ });
2477
+ } catch (error) {
2478
+ if (error instanceof HostRelayCurrentPromptCapacityRefusal) return { records: 0, enqueued: 0, quarantined: false };
2479
+ throw error;
2480
+ }
2481
+ }
2482
+ async openTranscript(registration, scan, handlers) {
2483
+ let handle;
2484
+ try {
2485
+ handle = await open2(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
2486
+ return await scan(handle);
2487
+ } catch (error) {
2488
+ if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
2489
+ if (hostRelayExchangeFailure(error) !== void 0 || error instanceof HostRelayCurrentPromptCapacityRefusal) throw error;
2490
+ return handlers.failed(handle, error);
2491
+ } finally {
2492
+ await handle?.close();
2493
+ }
2494
+ }
2495
+ /**
2496
+ * A transcript the Host deleted never comes back, so retrying its
2497
+ * registration once per reconcile interval is a failure with no end.
2498
+ * Retire it at the scan that finds it missing and say so once. Only
2499
+ * ENOENT means gone; a permission or busy failure is about this moment,
2500
+ * not about the file, and keeps the registration for the next scan.
2501
+ */
2502
+ async retireMissingTranscript(transcriptPath, producerLabel, retire) {
2503
+ await retire();
2504
+ this.log(formatRetiredTranscriptLog(producerLabel, transcriptPath));
2505
+ return { records: 0, enqueued: 0, quarantined: false };
2506
+ }
2507
+ stamp() {
2508
+ return transcriptTimestamp(this.now, this.clockFailure);
2509
+ }
2510
+ expire(retentionMs) {
2511
+ return transcriptExpiration(this.now, retentionMs, this.clockFailure);
2512
+ }
2513
+ sha(value) {
2514
+ return transcriptSha256(value);
2515
+ }
2516
+ objectSha(value) {
2517
+ return transcriptObjectSha256(value);
2518
+ }
2519
+ isRecord(value) {
2520
+ return isTranscriptRecord(value);
2521
+ }
2522
+ readChunk(handle, offset, size) {
2523
+ return readTranscriptCompleteChunk(handle, offset, size);
2524
+ }
2525
+ readAnchor(handle, offset, anchorBytes) {
2526
+ return readTranscriptAnchor(handle, offset, anchorBytes);
2527
+ }
2528
+ cursorIdentityReason(cursor, transcriptPath, device, inode) {
2529
+ return transcriptCursorIdentityReason(cursor, transcriptPath, device, inode);
2530
+ }
2531
+ cursorBoundsReason(handle, cursor, size) {
2532
+ return transcriptCursorBoundsReason(handle, cursor, size);
2533
+ }
2534
+ };
2535
+ var HOST_PRODUCER_STATE_IDENTITY = {
2536
+ codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
2537
+ claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
2538
+ };
2539
+ var HostProducerDrainCore = class {
2540
+ host;
2541
+ relay;
2542
+ statePath;
2543
+ stateSchema;
2544
+ installationRef;
2545
+ epoch;
2546
+ now;
2547
+ tail = Promise.resolve();
2548
+ constructor(host, runtime) {
2549
+ if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
2550
+ const epoch = runtime.producer_epoch ?? 1;
2551
+ if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
2552
+ this.host = host;
2553
+ this.relay = runtime.relay;
2554
+ this.statePath = join2(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
2555
+ this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
2556
+ this.installationRef = runtime.producer_installation_ref;
2557
+ this.epoch = epoch;
2558
+ this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
2559
+ }
2560
+ drainOutbox() {
2561
+ const run = this.tail.then(() => this.drainLocked());
2562
+ this.tail = run.then(() => void 0, () => void 0);
2563
+ return run;
2564
+ }
2565
+ async drainLocked() {
2566
+ const read = await this.host.listEnvelopes();
2567
+ let admitted = 0;
2568
+ let expired = 0;
2569
+ let retained = 0;
2570
+ for (const envelope of read.entries) {
2571
+ const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
2572
+ if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
2573
+ await this.host.removeEnvelope(envelope);
2574
+ expired += 1;
2575
+ continue;
2576
+ }
2577
+ const frames = await this.reserve(envelope);
2578
+ let complete = true;
2579
+ for (const frame of frames) {
2580
+ const outcome = await this.relay.admit(frame);
2581
+ if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
2582
+ complete = false;
2583
+ break;
2584
+ }
2585
+ }
2586
+ if (!complete) {
2587
+ retained += 1;
2588
+ break;
2589
+ }
2590
+ await this.host.removeEnvelope(envelope);
2591
+ await this.release(this.host.submissionRefOf(envelope));
2592
+ admitted += 1;
2593
+ }
2594
+ return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
2595
+ }
2596
+ async hasReservation(submissionRef) {
2597
+ return (await this.readState()).pending[submissionRef] !== void 0;
2598
+ }
2599
+ async reserve(envelope) {
2600
+ const state = await this.readState();
2601
+ const submissionRef = this.host.submissionRefOf(envelope);
2602
+ const existing = state.pending[submissionRef];
2603
+ if (existing !== void 0) return existing;
2604
+ const drafts = await this.host.mapEnvelope(envelope);
2605
+ const frames = drafts.map((draft, offset) => ({
2606
+ schema_version: "ceal.host_producer_frame.v1",
2607
+ producer_id: this.host.producer_id,
2608
+ producer_installation_ref: this.installationRef,
2609
+ producer_epoch: this.epoch,
2610
+ sequence: state.next_sequence + offset,
2611
+ frame_kind: draft.frame_kind,
2612
+ occurred_at: this.host.createdAtOf(envelope),
2613
+ payload: draft.payload
2614
+ }));
2615
+ await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
2616
+ return frames;
2617
+ }
2618
+ async release(submissionRef) {
2619
+ const state = await this.readState();
2620
+ if (state.pending[submissionRef] === void 0) return;
2621
+ const pending = { ...state.pending };
2622
+ delete pending[submissionRef];
2623
+ await this.writeState({ ...state, pending });
2624
+ }
2625
+ async readState() {
2626
+ try {
2627
+ const value = JSON.parse(await readFile(this.statePath, "utf8"));
2628
+ return this.decodeState(value);
2629
+ } catch (error) {
2630
+ if (errorCode2(error) !== "ENOENT") throw error;
2631
+ return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
2632
+ }
2633
+ }
2634
+ async writeState(state) {
2635
+ await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
2636
+ const temporary = `${this.statePath}.${process.pid}.new`;
2637
+ await writeFile(temporary, JSON.stringify(state), { mode: 384 });
2638
+ await rename2(temporary, this.statePath);
2639
+ }
2640
+ decodeState(value) {
2641
+ const label = this.host.producer_label;
2642
+ const fail = (code, message) => this.host.fail(code, message);
2643
+ if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
2644
+ throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
2645
+ { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
2646
+ { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
2647
+ ])}).`);
2648
+ }
2649
+ if (Number(value.producer_epoch) > this.epoch) throw fail("storage", `${label} producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${this.epoch}`)}).`);
2650
+ const pending = {};
2651
+ const storedEpoch = Number(value.producer_epoch);
2652
+ for (const [submissionRef, frames] of Object.entries(value.pending)) {
2653
+ if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
2654
+ pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
2655
+ }
2656
+ return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
2657
+ }
2658
+ decodeStoredFrame(value, storedEpoch) {
2659
+ const label = this.host.producer_label;
2660
+ const json = Buffer.from(JSON.stringify(value), "utf8");
2661
+ const encoded = Buffer.allocUnsafe(json.length + 4);
2662
+ encoded.writeUInt32BE(json.length, 0);
2663
+ json.copy(encoded, 4);
2664
+ const frame = decodeHostProducerFrame(encoded);
2665
+ if (frame.producer_id !== this.host.producer_id || frame.producer_installation_ref !== this.installationRef || frame.producer_epoch > storedEpoch) throw this.host.fail("storage", `${label} producer pending frame identity is malformed (${refusalFacts([
2666
+ { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
2667
+ { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
2668
+ { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
2669
+ ])}).`);
2670
+ return frame;
2671
+ }
2672
+ };
2673
+ function isDrainStateHeader(value, schema, installationRef) {
2674
+ return isTranscriptRecord(value) && value.schema_version === schema && value.producer_installation_ref === installationRef && Number.isSafeInteger(value.producer_epoch) && Number(value.producer_epoch) > 0 && Number.isSafeInteger(value.next_sequence) && Number(value.next_sequence) > 0 && isTranscriptRecord(value.pending);
2675
+ }
2676
+ function errorCode2(error) {
2677
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
2678
+ }
2679
+
2680
+ // host/relay/src/relay-quarantine-store.ts
2681
+ var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
2682
+ var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
2683
+ var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
2684
+
2685
+ // host/relay/src/relay-admission-store.ts
2686
+ var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
2687
+ var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
2688
+ var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
2689
+
2690
+ // host/relay/src/relay-gateway-bridge.ts
2691
+ var HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS = ["created", "adopted", "replayed", "approval_approved", "approval_denied", "approval_replayed"];
2692
+ function isHostGatewayAcknowledgementDisposition(value) {
2693
+ return typeof value === "string" && HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS.some((disposition) => disposition === value);
2694
+ }
2695
+
2696
+ // host/codex/src/codex-invocation-context.ts
2697
+ function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
2698
+ return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext, turn_generation_ref: turnGenerationRef });
2699
+ }
2700
+ function validateCodexHostInvocationContext(value) {
2701
+ if (!isContextShape(value)) {
2702
+ throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2703
+ }
2704
+ validateIdentity(value.identity);
2705
+ validateContextReferences(value);
2706
+ validateContextTimes(value);
2707
+ }
2708
+ function invocationContextFromBinding(binding, turnGenerationRef) {
2709
+ const context = {
2710
+ schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
2711
+ identity: binding.identity,
2712
+ prompt_ref: binding.prompt_ref,
2713
+ request_ref: binding.request_ref,
2714
+ bound_at: binding.bound_at,
2715
+ expires_at: binding.expires_at,
2716
+ ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
2717
+ };
2718
+ validateCodexHostInvocationContext(context);
2719
+ return Object.freeze(context);
2720
+ }
2721
+ function validateIdentity(value) {
2722
+ if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
2723
+ throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
2724
+ }
2725
+ }
2726
+ function isContextShape(value) {
2727
+ return isRecord3(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2728
+ }
2729
+ function validateContextReferences(value) {
2730
+ if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2731
+ }
2732
+ function validateContextTimes(value) {
2733
+ const expiresAt = value.expires_at;
2734
+ const boundAt = value.bound_at;
2735
+ if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2736
+ if (typeof boundAt === "string" && Date.parse(boundAt) > Date.parse(expiresAt)) throw new CodexHostAdapterError("storage", `Codex Host invocation context has invalid binding time (${refusalFact("bound_at", boundAt, `at or before ${expiresAt}`)}).`);
2737
+ }
2738
+ function optionalSafeRef(value) {
2739
+ return value === void 0 || safeRef3(value);
2740
+ }
2741
+ function optionalTimestamp(value) {
2742
+ return value === void 0 || timestamp2(value);
2743
+ }
2744
+ function safeRef3(value) {
2745
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2746
+ }
2747
+ function timestamp2(value) {
2748
+ return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
2749
+ }
2750
+ function isRecord3(value) {
2751
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2752
+ }
2753
+
2754
+ // host/codex/src/codex-outbox.ts
2755
+ var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2756
+ var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
2757
+ var CodexOutboxStore = class {
2758
+ directory;
2759
+ entriesDirectory;
2760
+ bindingsDirectory;
2761
+ sessionsDirectory;
2762
+ activeContextsDirectory;
2763
+ turnSelectionsDirectory;
2764
+ registrationsDirectory;
2765
+ cursorsDirectory;
2766
+ constructor(directory) {
2767
+ if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
2768
+ this.directory = directory;
2769
+ this.entriesDirectory = join3(directory, "entries");
2770
+ this.bindingsDirectory = join3(directory, "bindings");
2771
+ this.sessionsDirectory = join3(directory, "sessions");
2772
+ this.activeContextsDirectory = join3(directory, "active-contexts");
2773
+ this.turnSelectionsDirectory = join3(directory, "turn-selections");
2774
+ this.registrationsDirectory = join3(directory, "transcript-registrations");
2775
+ this.cursorsDirectory = join3(directory, "transcript-cursors");
2776
+ }
2777
+ async prepare() {
2778
+ for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2779
+ await ensurePrivateOwnerDirectory(path);
2780
+ }
2781
+ }
2782
+ async put(entry) {
2783
+ validateEnvelope(entry);
2784
+ await this.prepare();
2785
+ await writeAtomicJson(this.entryPath(entry.submission_ref), entry);
2786
+ }
2787
+ async list() {
2788
+ await this.prepare();
2789
+ const entries = [];
2790
+ let malformed = 0;
2791
+ for (const name of await readdir(this.entriesDirectory)) {
2792
+ if (!name.endsWith(".json")) continue;
2793
+ try {
2794
+ const value = JSON.parse(await readPrivateFile(join3(this.entriesDirectory, name)));
2795
+ validateEnvelope(value);
2796
+ entries.push(value);
2797
+ } catch {
2798
+ malformed += 1;
2799
+ }
2800
+ }
2801
+ entries.sort((left, right) => left.created_at.localeCompare(right.created_at));
2802
+ return { entries, malformed };
2803
+ }
2804
+ async remove(entry) {
2805
+ validateEnvelope(entry);
2806
+ try {
2807
+ await unlink2(this.entryPath(entry.submission_ref));
2808
+ } catch (error) {
2809
+ if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
2810
+ }
2811
+ }
2812
+ async writeBinding(binding) {
2813
+ validateBinding(binding);
2814
+ await this.prepare();
2815
+ await writeAtomicJson(this.bindingPath(binding.identity), binding);
2816
+ }
2817
+ /**
2818
+ * Select the exact Host turn that model-reachable commands may use. A new
2819
+ * prompt replaces this projection, so it cannot inherit the prior turn's
2820
+ * Request by session alone.
2821
+ */
2822
+ async activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef) {
2823
+ const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef);
2824
+ await this.prepare();
2825
+ const path = this.activeContextPath(identity);
2826
+ try {
1838
2827
  await writeAtomicJson(path, context);
1839
2828
  } catch (error) {
1840
2829
  try {
1841
- await unlink(path);
2830
+ await unlink2(path);
1842
2831
  } catch (unlinkError) {
1843
2832
  if (!isNotFound(unlinkError)) throw storageError("Unable to clear a failed Codex Host context replacement.");
1844
2833
  }
1845
2834
  throw error;
1846
2835
  }
1847
2836
  }
2837
+ async writeInvocationTurnSelection(selection) {
2838
+ if (!isHostInvocationTurnSelection(selection)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection is invalid.");
2839
+ await this.prepare();
2840
+ await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
2841
+ }
2842
+ async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
2843
+ if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
2844
+ await this.prepare();
2845
+ return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
2846
+ }
2847
+ async attachInvocationTurnGeneration(identity, promptRef, turnGenerationRef) {
2848
+ const selection = await this.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
2849
+ if (selection === null || selection.prompt_ref !== promptRef || selection.turn_generation_ref !== turnGenerationRef) return false;
2850
+ const path = this.activeContextPath(identity);
2851
+ const active = await readOptionalJson(path, validateCodexHostInvocationContext);
2852
+ if (active === null || active.prompt_ref !== promptRef || !sameIdentity(active.identity, identity)) return false;
2853
+ await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
2854
+ return true;
2855
+ }
1848
2856
  /**
1849
2857
  * Publish a Request reference only while the acknowledged binding is still
1850
2858
  * the active turn. A delayed relay response therefore cannot overwrite a
@@ -1854,17 +2862,25 @@ var CodexOutboxStore = class {
1854
2862
  validateBinding(binding);
1855
2863
  const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
1856
2864
  if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
1857
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding));
2865
+ await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
1858
2866
  return true;
1859
2867
  }
1860
- /** Return only the active session projection; never fall back to another turn. */
2868
+ /** Return only the live session projection; never fall back to another turn. */
1861
2869
  async readInvocationContext(hostSourceRef, hostSessionRef, now = /* @__PURE__ */ new Date()) {
1862
- if (!SAFE_REF3.test(hostSourceRef) || !SAFE_REF3.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
1863
2870
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
2871
+ const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
2872
+ return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
2873
+ }
2874
+ /**
2875
+ * The latest Codex session projection even when past expiry, so the
2876
+ * invocation authenticator can report an expired context distinctly from
2877
+ * a missing one. Every other caller keeps the fail-closed read above.
2878
+ */
2879
+ async readRawInvocationContext(hostSourceRef, hostSessionRef) {
2880
+ if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
1864
2881
  await this.prepare();
1865
- const context = await readOptionalJson(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), validateCodexHostInvocationContext);
1866
- if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
1867
- return Date.parse(context.expires_at) > now.getTime() ? context : null;
2882
+ const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
2883
+ return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
1868
2884
  }
1869
2885
  /** Clear the projection only if the caller still owns its exact active turn. */
1870
2886
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -1872,7 +2888,7 @@ var CodexOutboxStore = class {
1872
2888
  const active = await this.readInvocationContext(identity.host_source_ref, identity.host_session_ref, now);
1873
2889
  if (active === null || !sameIdentity(active.identity, identity)) return false;
1874
2890
  try {
1875
- await unlink(this.activeContextPath(identity));
2891
+ await unlink2(this.activeContextPath(identity));
1876
2892
  } catch (error) {
1877
2893
  if (!isNotFound(error)) throw storageError("Unable to clear the Codex Host invocation context.");
1878
2894
  }
@@ -1890,7 +2906,7 @@ var CodexOutboxStore = class {
1890
2906
  }
1891
2907
  async readSession(sourceRef, sessionRef) {
1892
2908
  const identity = { host_source_ref: sourceRef, host_session_ref: sessionRef };
1893
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
2909
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
1894
2910
  await this.prepare();
1895
2911
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
1896
2912
  }
@@ -1923,7 +2939,7 @@ var CodexOutboxStore = class {
1923
2939
  for (const name of await readdir(this.registrationsDirectory)) {
1924
2940
  if (!name.endsWith(".json")) continue;
1925
2941
  try {
1926
- const value = JSON.parse(await readPrivateFile(join2(this.registrationsDirectory, name)));
2942
+ const value = JSON.parse(await readPrivateFile(join3(this.registrationsDirectory, name)));
1927
2943
  validateRegistration(value);
1928
2944
  registrations.push(value);
1929
2945
  } catch {
@@ -1942,7 +2958,7 @@ var CodexOutboxStore = class {
1942
2958
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
1943
2959
  }
1944
2960
  async findByAlias(sourceRef, sessionRef, alias) {
1945
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef) || !SAFE_REF3.test(alias)) return null;
2961
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef) || !SAFE_REF4.test(alias)) return null;
1946
2962
  const read = await this.list();
1947
2963
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
1948
2964
  if (envelope !== null) return envelopeMatch(envelope);
@@ -1952,7 +2968,7 @@ var CodexOutboxStore = class {
1952
2968
  return null;
1953
2969
  }
1954
2970
  async hasPriorTurn(sourceRef, sessionRef) {
1955
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) return false;
2971
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) return false;
1956
2972
  const read = await this.list();
1957
2973
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
1958
2974
  await this.prepare();
@@ -1964,34 +2980,37 @@ var CodexOutboxStore = class {
1964
2980
  return false;
1965
2981
  }
1966
2982
  entryPath(submissionRef) {
1967
- if (!SAFE_REF3.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
1968
- return join2(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
2983
+ if (!SAFE_REF4.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
2984
+ return join3(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
1969
2985
  }
1970
2986
  bindingPath(identity) {
1971
- return join2(this.bindingsDirectory, `${identityKey(identity)}.json`);
2987
+ return join3(this.bindingsDirectory, `${identityKey(identity)}.json`);
1972
2988
  }
1973
2989
  sessionPath(sourceRef, sessionRef) {
1974
- return join2(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
2990
+ return join3(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
1975
2991
  }
1976
2992
  activeContextPath(identity) {
1977
- return join2(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2993
+ return join3(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2994
+ }
2995
+ turnSelectionPath(sourceRef, sessionRef) {
2996
+ return join3(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
1978
2997
  }
1979
2998
  registrationPath(sourceRef, sessionRef) {
1980
- return join2(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
2999
+ return join3(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
1981
3000
  }
1982
3001
  cursorPath(sourceRef, sessionRef) {
1983
- return join2(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
3002
+ return join3(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
1984
3003
  }
1985
3004
  };
1986
3005
  async function removeOwnerState(path, what) {
1987
3006
  try {
1988
- await unlink(path);
3007
+ await unlink2(path);
1989
3008
  } catch (error) {
1990
3009
  if (!isNotFound(error)) throw storageError(`Unable to retire the Codex transcript ${what}.`);
1991
3010
  }
1992
3011
  }
1993
3012
  function sessionStateKey(sourceRef, sessionRef) {
1994
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
3013
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
1995
3014
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
1996
3015
  }
1997
3016
  function envelopeMatch(envelope) {
@@ -2018,7 +3037,7 @@ async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
2018
3037
  }
2019
3038
  async function readBindingCandidate(directory, name) {
2020
3039
  try {
2021
- const value = JSON.parse(await readPrivateFile(join2(directory, name)));
3040
+ const value = JSON.parse(await readPrivateFile(join3(directory, name)));
2022
3041
  validateBinding(value);
2023
3042
  return value;
2024
3043
  } catch {
@@ -2037,18 +3056,18 @@ async function writeAtomicJson(path, value) {
2037
3056
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
2038
3057
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
2039
3058
  try {
2040
- const handle = await open(temp, "wx", 384);
3059
+ const handle = await open3(temp, "wx", 384);
2041
3060
  try {
2042
3061
  await handle.writeFile(text, "utf8");
2043
3062
  await handle.sync();
2044
3063
  } finally {
2045
3064
  await handle.close();
2046
3065
  }
2047
- await rename(temp, path);
3066
+ await rename3(temp, path);
2048
3067
  await syncDirectory(dirname(path));
2049
3068
  } catch (error) {
2050
3069
  try {
2051
- await unlink(temp);
3070
+ await unlink2(temp);
2052
3071
  } catch {
2053
3072
  }
2054
3073
  if (error instanceof CodexHostAdapterError) throw error;
@@ -2057,7 +3076,7 @@ async function writeAtomicJson(path, value) {
2057
3076
  }
2058
3077
  async function syncDirectory(path) {
2059
3078
  try {
2060
- const handle = await open(path, "r");
3079
+ const handle = await open3(path, "r");
2061
3080
  try {
2062
3081
  await handle.sync();
2063
3082
  } finally {
@@ -2079,12 +3098,12 @@ async function readOptionalJson(path, validate) {
2079
3098
  }
2080
3099
  async function ensurePrivateOwnerDirectory(path) {
2081
3100
  try {
2082
- await lstat(path);
3101
+ await lstat2(path);
2083
3102
  } catch (error) {
2084
3103
  if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
2085
- await mkdir(path, { recursive: true, mode: 448 });
3104
+ await mkdir3(path, { recursive: true, mode: 448 });
2086
3105
  }
2087
- const stats = await lstat(path);
3106
+ const stats = await lstat2(path);
2088
3107
  const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2089
3108
  if (!stats.isDirectory() || stats.isSymbolicLink()) throw storageError(`Codex owner state path is not a directory (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a directory mode (0o40xxx)")}).`);
2090
3109
  if ((stats.mode & 63) !== 0) throw storageError(`Codex owner state directory is readable beyond its owner (${refusalFact("permission_bits", `0o${(stats.mode & 511).toString(8)}`, "no group or other bits")}).`);
@@ -2093,7 +3112,7 @@ async function ensurePrivateOwnerDirectory(path) {
2093
3112
  async function readPrivateFile(path) {
2094
3113
  let handle;
2095
3114
  try {
2096
- handle = await open(path, O_RDONLY | O_NOFOLLOW);
3115
+ handle = await open3(path, O_RDONLY3 | O_NOFOLLOW2);
2097
3116
  const stats = await handle.stat();
2098
3117
  const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2099
3118
  if (!stats.isFile()) throw storageError(`Codex owner state path is not a regular file (${refusalFact("mode", `0o${stats.mode.toString(8)}`, "a regular-file mode (0o100xxx)")}).`);
@@ -2105,7 +3124,7 @@ async function readPrivateFile(path) {
2105
3124
  }
2106
3125
  }
2107
3126
  function validateEnvelope(value) {
2108
- if (!isRecord3(value)) throw storageError("Codex outbox entry is malformed.");
3127
+ if (!isRecord4(value)) throw storageError("Codex outbox entry is malformed.");
2109
3128
  if (!sameKeys(value, ["schema_version", "identity", "host_input_ref", "input_kind", "prompt_ref", "observations", "origin_input", "submission_ref", "created_at", "expires_at"], ["request_ref", "codex_turn_id"])) throw storageError(`Codex outbox entry key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the outbox entry key set")}).`);
2110
3129
  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}`)}).`);
2111
3130
  validateIdentity2(value.identity);
@@ -2114,22 +3133,22 @@ function validateEnvelope(value) {
2114
3133
  validateEnvelopeTimestamps(value);
2115
3134
  }
2116
3135
  function validateEnvelopeReferences(value) {
2117
- if (!SAFE_REF3.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
3136
+ if (!SAFE_REF4.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
2118
3137
  if (!isCealHostInputKind(value.input_kind)) throw storageError("Codex outbox input provenance is malformed.");
2119
- if (!SAFE_REF3.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
2120
- if (!SAFE_REF3.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
2121
- if (value.request_ref !== void 0 && !SAFE_REF3.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
2122
- if (value.codex_turn_id !== void 0 && !SAFE_REF3.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
3138
+ if (!SAFE_REF4.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
3139
+ if (!SAFE_REF4.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
3140
+ if (value.request_ref !== void 0 && !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
3141
+ if (value.codex_turn_id !== void 0 && !SAFE_REF4.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
2123
3142
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
2124
3143
  }
2125
3144
  function validateRegistration(value) {
2126
- if (!isRecord3(value)) throw storageError("Codex transcript registration is malformed.");
3145
+ if (!isRecord4(value)) throw storageError("Codex transcript registration is malformed.");
2127
3146
  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")}).`);
2128
3147
  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}`)}).`);
2129
3148
  validateRegistrationFields(value);
2130
3149
  }
2131
3150
  function validateRegistrationFields(value) {
2132
- if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate))) throw storageError(`Codex transcript registration references are malformed (${refusalFacts([{ name: "host_source_ref", value: value.host_source_ref }, { name: "host_session_ref", value: value.host_session_ref }, { name: "codex_session_id", value: value.codex_session_id }])}).`);
3151
+ if (![value.host_source_ref, value.host_session_ref, value.codex_session_id].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate))) throw storageError(`Codex transcript registration references are malformed (${refusalFacts([{ name: "host_source_ref", value: value.host_source_ref }, { name: "host_session_ref", value: value.host_session_ref }, { name: "codex_session_id", value: value.codex_session_id }])}).`);
2133
3152
  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`)}).`);
2134
3153
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
2135
3154
  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}`)}).`);
@@ -2139,15 +3158,15 @@ function validRegistrationCwd(value) {
2139
3158
  return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
2140
3159
  }
2141
3160
  function validateCursor(value) {
2142
- if (!isRecord3(value)) throw storageError("Codex transcript cursor is malformed.");
3161
+ if (!isRecord4(value)) throw storageError("Codex transcript cursor is malformed.");
2143
3162
  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")}).`);
2144
3163
  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}`)}).`);
2145
3164
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
2146
3165
  if (value.active_task !== void 0 && !validActiveTask(value.active_task)) throw storageError("Codex transcript task cursor is malformed.");
2147
- if (value.reason !== void 0 && !isCodexTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
3166
+ if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
2148
3167
  }
2149
3168
  function validCursorSource(value) {
2150
- return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
3169
+ return [value.host_source_ref, value.host_session_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && typeof value.transcript_path === "string" && value.transcript_path.length > 0 && typeof value.device === "string" && typeof value.inode === "string";
2151
3170
  }
2152
3171
  function validCursorPosition(value) {
2153
3172
  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";
@@ -2156,23 +3175,23 @@ function validCursorStatus(value) {
2156
3175
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
2157
3176
  }
2158
3177
  function validActiveTask(value) {
2159
- if (!isRecord3(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;
3178
+ if (!isRecord4(value) || !sameKeys(value, ["codex_turn_id", "host_turn_ref", "started_at"], ["origin_host_input_ref", "prompt_ref", "model", "token_usage", "last_total_usage", "token_usage_gap_reason"])) return false;
2160
3179
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
2161
3180
  }
2162
3181
  function validActiveTaskIdentity(value) {
2163
- return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate)) && isTimestamp(value.started_at);
3182
+ return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && isTimestamp(value.started_at);
2164
3183
  }
2165
3184
  function validActiveTaskReferences(value) {
2166
3185
  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);
2167
3186
  }
2168
3187
  function optionalSafeRef2(value) {
2169
- return value === void 0 || typeof value === "string" && SAFE_REF3.test(value);
3188
+ return value === void 0 || typeof value === "string" && SAFE_REF4.test(value);
2170
3189
  }
2171
3190
  function validActiveTaskUsage(value) {
2172
3191
  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");
2173
3192
  }
2174
3193
  function validTokenUsage(value) {
2175
- if (!isRecord3(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
3194
+ if (!isRecord4(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
2176
3195
  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;
2177
3196
  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);
2178
3197
  }
@@ -2192,30 +3211,33 @@ function validateEnvelopeTimestamps(value) {
2192
3211
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
2193
3212
  }
2194
3213
  function validateBinding(value) {
2195
- if (!isRecord3(value)) throw storageError("Codex turn binding is malformed.");
3214
+ if (!isRecord4(value)) throw storageError("Codex turn binding is malformed.");
2196
3215
  if (!sameKeys(value, ["schema_version", "identity", "prompt_ref", "request_ref", "codex_turn_ids", "bound_at", "expires_at"])) throw storageError(`Codex turn binding key set is malformed (${refusalFact("keys", Object.keys(value), "exactly the turn binding key set")}).`);
2197
3216
  if (value.schema_version !== CODEX_TURN_BINDING_SCHEMA_VERSION) throw storageError(`Codex turn binding is malformed (${refusalFact("schema_version", value.schema_version, `expected ${CODEX_TURN_BINDING_SCHEMA_VERSION}`)}).`);
2198
3217
  validateIdentity2(value.identity);
2199
- if (!SAFE_REF3.test(String(value.prompt_ref)) || !SAFE_REF3.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
3218
+ if (!SAFE_REF4.test(String(value.prompt_ref)) || !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
2200
3219
  if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
2201
3220
  }
2202
3221
  function validateSession(value) {
2203
- if (!isRecord3(value)) throw storageError("Codex session snapshot is malformed.");
3222
+ if (!isRecord4(value)) throw storageError("Codex session snapshot is malformed.");
2204
3223
  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")}).`);
2205
3224
  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}`)}).`);
2206
- if (!SAFE_REF3.test(String(value.host_session_ref)) || !SAFE_REF3.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
3225
+ if (!SAFE_REF4.test(String(value.host_session_ref)) || !SAFE_REF4.test(String(value.host_source_ref)) || !isTimestamp(value.observed_at) || !isTimestamp(value.expires_at) || !isJsonValue(value.value)) throw storageError("Codex session snapshot fields are malformed.");
3226
+ }
3227
+ function validateTurnSelection(value) {
3228
+ if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
2207
3229
  }
2208
3230
  function validateIdentity2(value) {
2209
- if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate))) throw storageError("Codex Host identity is malformed.");
3231
+ if (!isRecord4(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate))) throw storageError("Codex Host identity is malformed.");
2210
3232
  }
2211
3233
  function isJsonValue(value) {
2212
3234
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2213
3235
  if (typeof value === "number") return Number.isFinite(value);
2214
3236
  if (Array.isArray(value)) return value.every(isJsonValue);
2215
- return isRecord3(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
3237
+ return isRecord4(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
2216
3238
  }
2217
3239
  function isStringList(value) {
2218
- return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate));
3240
+ return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate));
2219
3241
  }
2220
3242
  function isTimestamp(value) {
2221
3243
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -2225,23 +3247,23 @@ function sameKeys(value, required, optional = []) {
2225
3247
  const keys = Object.keys(value);
2226
3248
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
2227
3249
  }
2228
- function isRecord3(value) {
3250
+ function isRecord4(value) {
2229
3251
  return value !== null && typeof value === "object" && !Array.isArray(value);
2230
3252
  }
2231
3253
  function isNotFound(error) {
2232
- return isRecord3(error) && error.code === "ENOENT";
3254
+ return isRecord4(error) && error.code === "ENOENT";
2233
3255
  }
2234
3256
  function storageError(message) {
2235
3257
  return new CodexHostAdapterError("storage", message);
2236
3258
  }
2237
3259
 
2238
3260
  // host/codex/src/codex-transcript-baseline.ts
2239
- import { createHash as createHash3 } from "node:crypto";
2240
- import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY2 } from "node:constants";
2241
- import { open as open2 } from "node:fs/promises";
3261
+ import { createHash as createHash4 } from "node:crypto";
3262
+ import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
3263
+ import { open as open4 } from "node:fs/promises";
2242
3264
 
2243
3265
  // host/codex/src/codex-transcript-decoder.ts
2244
- var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3266
+ var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
2245
3267
  var MAX_PROMPT_BYTES = 64 * 1024;
2246
3268
  function decodeCodexTranscriptLine(line) {
2247
3269
  let value;
@@ -2250,40 +3272,40 @@ function decodeCodexTranscriptLine(line) {
2250
3272
  } catch {
2251
3273
  reject2("Codex transcript record is not valid JSON.");
2252
3274
  }
2253
- if (!isRecord4(value)) reject2("Codex transcript record envelope is malformed.");
3275
+ if (!isRecord5(value)) reject2("Codex transcript record envelope is malformed.");
2254
3276
  const ordinal = safeOrdinal(value.ordinal);
2255
- const timestamp6 = safeTimestamp(value.timestamp);
2256
- if (!isRecord4(value.payload) || typeof value.type !== "string") reject2("Codex transcript record payload is malformed.");
2257
- if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp6);
2258
- if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp6);
2259
- if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp6);
2260
- if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp6);
2261
- return { kind: "ignored", ordinal, timestamp: timestamp6 };
2262
- }
2263
- function decodeTurnContext(payload, ordinal, timestamp6) {
3277
+ const timestamp5 = safeTimestamp(value.timestamp);
3278
+ if (!isRecord5(value.payload) || typeof value.type !== "string") reject2("Codex transcript record payload is malformed.");
3279
+ if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp5);
3280
+ if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp5);
3281
+ if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp5);
3282
+ if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp5);
3283
+ return { kind: "ignored", ordinal, timestamp: timestamp5 };
3284
+ }
3285
+ function decodeTurnContext(payload, ordinal, timestamp5) {
2264
3286
  return {
2265
3287
  kind: "turn_context",
2266
3288
  ordinal,
2267
- timestamp: timestamp6,
2268
- turn_id: safeRef2(payload.turn_id, "Codex turn context identity is invalid."),
3289
+ timestamp: timestamp5,
3290
+ turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
2269
3291
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
2270
3292
  };
2271
3293
  }
2272
- function decodeSessionMeta(payload, ordinal, timestamp6) {
2273
- const sessionId = safeRef2(payload.id, "Codex transcript session identity is invalid.");
3294
+ function decodeSessionMeta(payload, ordinal, timestamp5) {
3295
+ const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
2274
3296
  const cliVersion = boundedNonEmptyText(payload.cli_version, 64, "Codex transcript version is invalid.");
2275
- return { kind: "session_meta", ordinal, timestamp: timestamp6, session_id: sessionId, cli_version: cliVersion };
3297
+ return { kind: "session_meta", ordinal, timestamp: timestamp5, session_id: sessionId, cli_version: cliVersion };
2276
3298
  }
2277
- function decodeEventMessage(payload, ordinal, timestamp6) {
3299
+ function decodeEventMessage(payload, ordinal, timestamp5) {
2278
3300
  if (payload.type === "task_started") {
2279
- return { kind: "task_started", ordinal, timestamp: timestamp6, turn_id: safeRef2(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
3301
+ return { kind: "task_started", ordinal, timestamp: timestamp5, turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."), started_at: safeNumber(payload.started_at) };
2280
3302
  }
2281
3303
  if (payload.type === "task_complete") {
2282
3304
  return {
2283
3305
  kind: "task_complete",
2284
3306
  ordinal,
2285
- timestamp: timestamp6,
2286
- turn_id: safeRef2(payload.turn_id, "Codex task identity is invalid."),
3307
+ timestamp: timestamp5,
3308
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
2287
3309
  started_at: safeNumber(payload.started_at),
2288
3310
  completed_at: safeNumber(payload.completed_at),
2289
3311
  duration_ms: safeNumber(payload.duration_ms),
@@ -2294,20 +3316,20 @@ function decodeEventMessage(payload, ordinal, timestamp6) {
2294
3316
  return {
2295
3317
  kind: "turn_aborted",
2296
3318
  ordinal,
2297
- timestamp: timestamp6,
2298
- turn_id: safeRef2(payload.turn_id, "Codex task identity is invalid."),
3319
+ timestamp: timestamp5,
3320
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
2299
3321
  started_at: safeNumber(payload.started_at),
2300
3322
  completed_at: safeNumber(payload.completed_at),
2301
3323
  duration_ms: safeNumber(payload.duration_ms),
2302
3324
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
2303
3325
  };
2304
3326
  }
2305
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp6);
2306
- return { kind: "ignored", ordinal, timestamp: timestamp6 };
3327
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp5);
3328
+ return { kind: "ignored", ordinal, timestamp: timestamp5 };
2307
3329
  }
2308
- function decodeTokenCount(payload, ordinal, timestamp6) {
2309
- if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp6 };
2310
- if (!isRecord4(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp6, usage_gap_reason: "token_count_shape_not_attributable" };
3330
+ function decodeTokenCount(payload, ordinal, timestamp5) {
3331
+ if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp5 };
3332
+ if (!isRecord5(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp5, usage_gap_reason: "token_count_shape_not_attributable" };
2311
3333
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
2312
3334
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
2313
3335
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -2315,7 +3337,7 @@ function decodeTokenCount(payload, ordinal, timestamp6) {
2315
3337
  return {
2316
3338
  kind: "token_count",
2317
3339
  ordinal,
2318
- timestamp: timestamp6,
3340
+ timestamp: timestamp5,
2319
3341
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
2320
3342
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
2321
3343
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -2331,7 +3353,7 @@ function optionalTokenUsage(value) {
2331
3353
  }
2332
3354
  }
2333
3355
  function decodeTokenUsage(value) {
2334
- if (!isRecord4(value)) reject2("Codex token usage is malformed.");
3356
+ if (!isRecord5(value)) reject2("Codex token usage is malformed.");
2335
3357
  const usage = {
2336
3358
  input_tokens: safeTokenCount(value.input_tokens),
2337
3359
  cached_input_tokens: safeTokenCount(value.cached_input_tokens),
@@ -2343,20 +3365,20 @@ function decodeTokenUsage(value) {
2343
3365
  if (usage.total_tokens !== usage.input_tokens + usage.output_tokens || usage.cached_input_tokens + usage.cache_write_input_tokens > usage.input_tokens || usage.reasoning_output_tokens > usage.output_tokens) reject2("Codex token usage buckets are inconsistent.");
2344
3366
  return usage;
2345
3367
  }
2346
- function decodeResponseItem(payload, ordinal, timestamp6) {
2347
- if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp6 };
3368
+ function decodeResponseItem(payload, ordinal, timestamp5) {
3369
+ if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp5 };
2348
3370
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
2349
3371
  const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
2350
- if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp6 };
3372
+ if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp5 };
2351
3373
  const prompt = userTextContent(payload.content);
2352
3374
  return {
2353
3375
  kind: "user_text",
2354
3376
  ordinal,
2355
- timestamp: timestamp6,
3377
+ timestamp: timestamp5,
2356
3378
  prompt,
2357
3379
  input_kind: inputKind,
2358
- message_id: safeRef2(payload.id, "Codex user message identity is invalid."),
2359
- turn_id: safeRef2(metadata.turn_id, "Codex user message task identity is invalid.")
3380
+ message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
3381
+ turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
2360
3382
  };
2361
3383
  }
2362
3384
  function inputKindFromContentItems(kinds) {
@@ -2365,13 +3387,13 @@ function inputKindFromContentItems(kinds) {
2365
3387
  return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
2366
3388
  }
2367
3389
  function userMessageMetadata(value) {
2368
- if (!isRecord4(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
3390
+ if (!isRecord5(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
2369
3391
  return { ...value, content_item_kinds: value.content_item_kinds };
2370
3392
  }
2371
3393
  function userTextContent(value) {
2372
3394
  if (!Array.isArray(value)) reject2(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
2373
3395
  if (value.length !== 1) reject2(`Codex user text content is malformed (${refusalFact("items", value.length, "exactly one")}).`);
2374
- if (!isRecord4(value[0]) || value[0].type !== "input_text") reject2(`Codex user text content is malformed (${refusalFact("item_type", isRecord4(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
3396
+ if (!isRecord5(value[0]) || value[0].type !== "input_text") reject2(`Codex user text content is malformed (${refusalFact("item_type", isRecord5(value[0]) ? value[0].type : typeof value[0], "input_text")}).`);
2375
3397
  return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
2376
3398
  }
2377
3399
  function safeOrdinal(value) {
@@ -2392,8 +3414,8 @@ function safeTimestamp(value) {
2392
3414
  if (!Number.isFinite(Date.parse(value))) reject2(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
2393
3415
  return value;
2394
3416
  }
2395
- function safeRef2(value, message) {
2396
- if (typeof value !== "string" || !SAFE_REF4.test(value)) reject2(message);
3417
+ function safeRef4(value, message) {
3418
+ if (typeof value !== "string" || !SAFE_REF5.test(value)) reject2(message);
2397
3419
  return value;
2398
3420
  }
2399
3421
  function boundedText(value, maximum, message) {
@@ -2407,7 +3429,7 @@ function boundedNonEmptyText(value, maximum, message) {
2407
3429
  if (result.length === 0) reject2(message);
2408
3430
  return result;
2409
3431
  }
2410
- function isRecord4(value) {
3432
+ function isRecord5(value) {
2411
3433
  return value !== null && typeof value === "object" && !Array.isArray(value);
2412
3434
  }
2413
3435
  function reject2(message) {
@@ -2420,7 +3442,7 @@ var CODEX_TRANSCRIPT_ANCHOR_BYTES = 256;
2420
3442
  async function captureCodexTranscriptBaseline(registration, now = () => /* @__PURE__ */ new Date()) {
2421
3443
  let handle;
2422
3444
  try {
2423
- handle = await open2(registration.transcript_path, O_RDONLY2 | O_NOFOLLOW2);
3445
+ handle = await open4(registration.transcript_path, O_RDONLY4 | O_NOFOLLOW3);
2424
3446
  const { size, device, inode } = await ownedCodexTranscriptFile(handle);
2425
3447
  const empty = codexTranscriptInitialCursor(registration, device, inode, now);
2426
3448
  const headerLine = await firstCompleteLine(handle, size);
@@ -2440,7 +3462,7 @@ async function captureCodexTranscriptBaseline(registration, now = () => /* @__PU
2440
3462
  anchor_start: anchorStart,
2441
3463
  anchor_sha256: digest(anchor),
2442
3464
  header_validated: true,
2443
- updated_at: timestamp2(now)
3465
+ updated_at: timestamp3(now)
2444
3466
  };
2445
3467
  } finally {
2446
3468
  await handle?.close();
@@ -2460,7 +3482,7 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
2460
3482
  anchor_sha256: digest(Buffer.alloc(0)),
2461
3483
  header_validated: false,
2462
3484
  status: "active",
2463
- updated_at: timestamp2(now)
3485
+ updated_at: timestamp3(now)
2464
3486
  };
2465
3487
  }
2466
3488
  async function ownedCodexTranscriptFile(handle) {
@@ -2541,188 +3563,33 @@ function decodeHistoryLine(bytes) {
2541
3563
  throw error;
2542
3564
  }
2543
3565
  }
2544
- async function* completeLinesBackward(handle, end) {
2545
- if (end <= 0) return;
2546
- let position = end - 1;
2547
- let carry = [];
2548
- while (position > 0) {
2549
- const start = Math.max(0, position - BASELINE_READ_CHUNK_BYTES);
2550
- const buffer = Buffer.alloc(position - start);
2551
- const read = await handle.read(buffer, 0, buffer.length, start);
2552
- if (read.bytesRead !== buffer.length) throw new CodexHostAdapterError("storage", "Codex transcript changed size during baseline capture.");
2553
- let lineEnd = buffer.length;
2554
- for (let newline = buffer.lastIndexOf(10, lineEnd - 1); newline >= 0; newline = lineEnd > 0 ? buffer.lastIndexOf(10, lineEnd - 1) : -1) {
2555
- yield { start: start + newline + 1, bytes: Buffer.concat([buffer.subarray(newline + 1, lineEnd), ...carry]) };
2556
- carry = [];
2557
- lineEnd = newline;
2558
- }
2559
- carry = [buffer.subarray(0, lineEnd), ...carry];
2560
- position = start;
2561
- }
2562
- yield { start: 0, bytes: Buffer.concat(carry) };
2563
- }
2564
- function digest(value) {
2565
- return createHash3("sha256").update(value).digest("hex");
2566
- }
2567
- function timestamp2(now) {
2568
- const value = now();
2569
- if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
2570
- return value.toISOString();
2571
- }
2572
-
2573
- // host/relay/src/durable-atomic-replacement.ts
2574
- import { O_RDONLY as O_RDONLY3 } from "node:constants";
2575
- import { lstat as lstat2, mkdir as mkdir2, open as open3, rename as rename2, unlink as unlink2 } from "node:fs/promises";
2576
- var DEFAULT_PORT = {
2577
- platform: process.platform,
2578
- mkdir: (path, options) => mkdir2(path, options),
2579
- lstat: (path) => lstat2(path),
2580
- open_file: (path) => open3(path, "wx", 384),
2581
- rename: rename2,
2582
- unlink: unlink2,
2583
- open_directory: (path) => open3(path, O_RDONLY3),
2584
- unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2585
- };
2586
-
2587
- // host/relay/src/producer-frame.ts
2588
- var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
2589
- var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
2590
- var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2591
- var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2592
- var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
2593
- var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
2594
- var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
2595
- function isHostProducerFrameKind(value) {
2596
- return typeof value === "string" && FRAME_KINDS.has(value);
2597
- }
2598
- var HostProducerFrameError = class extends Error {
2599
- code;
2600
- constructor(code, message = code) {
2601
- super(message);
2602
- this.code = code;
2603
- }
2604
- };
2605
- function encodeHostProducerFrame(frame) {
2606
- validateFrame(frame);
2607
- const json = Buffer.from(JSON.stringify(frame), "utf8");
2608
- 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}`)}`);
2609
- const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
2610
- result.writeUInt32BE(json.byteLength, 0);
2611
- json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
2612
- return result;
2613
- }
2614
- function decodeHostProducerFrame(input) {
2615
- 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}`)}`);
2616
- const length = input.readUInt32BE(0);
2617
- 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}`)}`);
2618
- if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
2619
- 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");
2620
- const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
2621
- const text = new TextDecoder("utf-8", { fatal: true });
2622
- let value;
2623
- try {
2624
- value = JSON.parse(text.decode(bytes));
2625
- } catch (error) {
2626
- if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
2627
- throw new HostProducerFrameError("frame_truncated");
2628
- }
2629
- validateFrame(value);
2630
- return value;
2631
- }
2632
- function validateFrame(value) {
2633
- if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
2634
- 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)}`);
2635
- if (!exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
2636
- if (!PRODUCERS.has(String(value.producer_id)) || !safeRef3(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
2637
- if (!positive(value.producer_epoch) || !positive(value.sequence) || !hostProducerFrameKind(value.frame_kind) || !timestamp3(value.occurred_at) || !record(value.payload)) throw new HostProducerFrameError("invalid_frame_shape");
2638
- validatePayload(value.frame_kind, value.payload);
2639
- }
2640
- function validatePayload(kind, value) {
2641
- const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
2642
- if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
2643
- }
2644
- function validSession(value) {
2645
- return exactOptional(value, ["local_session_ref", "working_directory_ref"], ["model", "host_version", "observations"]) && safeRef3(value.local_session_ref) && safeRef3(value.working_directory_ref) && optionalText(value.model, 256) && optionalText(value.host_version, 256) && validObservations(value.observations);
2646
- }
2647
- function validTurn(value) {
2648
- return exactOptional(value, ["local_session_ref", "local_turn_ref"], ["model", "observations"]) && safeRef3(value.local_session_ref) && safeRef3(value.local_turn_ref) && optionalText(value.model, 256) && validObservations(value.observations);
2649
- }
2650
- function validInput(value) {
2651
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "local_input_ref", "input_kind", "origin_input", "observations"], ["local_turn_aliases", "context_expires_at"]) && safeRef3(value.local_session_ref) && safeRef3(value.local_turn_ref) && safeRef3(value.local_input_ref) && validInputObservations(value.observations) && isCealHostInputKind(value.input_kind) && typeof value.origin_input === "boolean" && validInputOptionals(value);
2652
- }
2653
- function validInputObservations(value) {
2654
- return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
2655
- }
2656
- function validInputOptionals(value) {
2657
- return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp3(value.context_expires_at));
2658
- }
2659
- function validTerminal(value) {
2660
- return exactOptional(value, ["local_session_ref", "local_turn_ref", "terminal_state"], ["abort_reason", "duration_ms", "time_to_first_token_ms", "usage", "observations"]) && safeRef3(value.local_session_ref) && safeRef3(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);
2661
- }
2662
- function validTerminalDisposition(state, reason) {
2663
- return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef3(reason));
2664
- }
2665
- function validStatus(value) {
2666
- return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef3(value.reason_code) && optionalText(value.detail, 4096);
2667
- }
2668
- function optionalText(value, maxLength) {
2669
- return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
2670
- }
2671
- function optionalNonNegative(value) {
2672
- return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
2673
- }
2674
- function optionalRefs(value) {
2675
- return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef3);
2676
- }
2677
- function validObservations(value) {
2678
- if (value === void 0) return true;
2679
- if (!Array.isArray(value) || value.length > 32) return false;
2680
- return value.every((item) => {
2681
- try {
2682
- validateCealHostObservationDraft(item);
2683
- return true;
2684
- } catch {
2685
- return false;
2686
- }
2687
- });
2688
- }
2689
- function jsonValue(value, depth = 0) {
2690
- if (depth > 16) return false;
2691
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2692
- if (typeof value === "number") return Number.isFinite(value);
2693
- if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
2694
- return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
2695
- }
2696
- function record(value) {
2697
- return value !== null && typeof value === "object" && !Array.isArray(value);
2698
- }
2699
- function safeRef3(value) {
2700
- return typeof value === "string" && SAFE_REF5.test(value);
2701
- }
2702
- function positive(value) {
2703
- return Number.isSafeInteger(value) && Number(value) > 0;
2704
- }
2705
- function timestamp3(value) {
2706
- return typeof value === "string" && Number.isFinite(Date.parse(value));
2707
- }
2708
- function hostProducerFrameKind(value) {
2709
- return isHostProducerFrameKind(value);
2710
- }
2711
- function exactKeys3(value, keys) {
2712
- return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
3566
+ async function* completeLinesBackward(handle, end) {
3567
+ if (end <= 0) return;
3568
+ let position = end - 1;
3569
+ let carry = [];
3570
+ while (position > 0) {
3571
+ const start = Math.max(0, position - BASELINE_READ_CHUNK_BYTES);
3572
+ const buffer = Buffer.alloc(position - start);
3573
+ const read = await handle.read(buffer, 0, buffer.length, start);
3574
+ if (read.bytesRead !== buffer.length) throw new CodexHostAdapterError("storage", "Codex transcript changed size during baseline capture.");
3575
+ let lineEnd = buffer.length;
3576
+ for (let newline = buffer.lastIndexOf(10, lineEnd - 1); newline >= 0; newline = lineEnd > 0 ? buffer.lastIndexOf(10, lineEnd - 1) : -1) {
3577
+ yield { start: start + newline + 1, bytes: Buffer.concat([buffer.subarray(newline + 1, lineEnd), ...carry]) };
3578
+ carry = [];
3579
+ lineEnd = newline;
3580
+ }
3581
+ carry = [buffer.subarray(0, lineEnd), ...carry];
3582
+ position = start;
3583
+ }
3584
+ yield { start: 0, bytes: Buffer.concat(carry) };
2713
3585
  }
2714
- function exactOptional(value, required, optional) {
2715
- const keys = Object.keys(value);
2716
- return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
3586
+ function digest(value) {
3587
+ return createHash4("sha256").update(value).digest("hex");
2717
3588
  }
2718
-
2719
- // host/relay/src/relay-request-binding-store.ts
2720
- var MAX_STATE_BYTES = 8 * 1024 * 1024;
2721
-
2722
- // host/relay/src/relay-gateway-bridge.ts
2723
- var HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS = ["created", "adopted", "replayed", "approval_approved", "approval_denied", "approval_replayed"];
2724
- function isHostGatewayAcknowledgementDisposition(value) {
2725
- return typeof value === "string" && HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS.some((disposition) => disposition === value);
3589
+ function timestamp3(now) {
3590
+ const value = now();
3591
+ if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
3592
+ return value.toISOString();
2726
3593
  }
2727
3594
 
2728
3595
  // host/codex/src/codex-adapter.ts
@@ -2748,7 +3615,7 @@ function createCodexHostObservationAdapter(options) {
2748
3615
  });
2749
3616
  }
2750
3617
  async function registerSession(event, options, store, now, retentionMs) {
2751
- const defaultRoot = join3(process.env.CODEX_HOME || join3(homedir(), ".codex"), "sessions");
3618
+ const defaultRoot = join4(process.env.CODEX_HOME || join4(homedir(), ".codex"), "sessions");
2752
3619
  const transcriptPath = sourceBoundTranscriptPath(event.transcript_path, options.codex_sessions_root ?? defaultRoot);
2753
3620
  const hostSessionRef = hostSessionReference(options.host_source_ref, event.session_id);
2754
3621
  const observedAt = timestamp4(now);
@@ -2763,20 +3630,59 @@ async function registerSession(event, options, store, now, retentionMs) {
2763
3630
  registered_at: observedAt,
2764
3631
  expires_at: expiresAt
2765
3632
  };
3633
+ const currentTurn = await selectCurrentTurn(event, options, store, hostSessionRef);
2766
3634
  const existing = (await store.listTranscriptRegistrations()).find((candidate) => candidate.host_source_ref === registration.host_source_ref && candidate.host_session_ref === registration.host_session_ref);
2767
3635
  if (existing === void 0) {
2768
3636
  await store.writeTranscriptCursor(await captureCodexTranscriptBaseline(registration, now));
2769
3637
  }
2770
3638
  await store.registerTranscript(registration);
2771
- await store.saveSession({
2772
- schema_version: "ceal.codex_session.v1",
2773
- host_session_ref: hostSessionRef,
3639
+ if (existing !== void 0 && currentTurn !== void 0 && (await store.readTranscriptCursor(registration))?.status === "quarantined") {
3640
+ await store.writeTranscriptCursor(await captureCodexTranscriptBaseline(registration, now));
3641
+ }
3642
+ if (event.event === "SessionStart") {
3643
+ await store.saveSession({
3644
+ schema_version: "ceal.codex_session.v1",
3645
+ host_session_ref: hostSessionRef,
3646
+ host_source_ref: options.host_source_ref,
3647
+ observed_at: observedAt,
3648
+ value: sessionObservationValue(event),
3649
+ expires_at: expiresAt
3650
+ });
3651
+ } else if (currentTurn !== void 0) {
3652
+ await store.attachInvocationTurnGeneration({ host_source_ref: options.host_source_ref, host_session_ref: hostSessionRef, host_turn_ref: currentTurn.host_turn_ref }, currentTurn.prompt_ref, currentTurn.turn_generation_ref);
3653
+ }
3654
+ return { event: event.event, disposition: "ignored", reason: "transcript_registered", ...currentTurn === void 0 ? {} : { host_turn_ref: currentTurn.host_turn_ref } };
3655
+ }
3656
+ async function selectCurrentTurn(event, options, store, hostSessionRef) {
3657
+ if (event.event !== "UserPromptSubmit") return void 0;
3658
+ const host_turn_ref = hostTurnReference(options.host_source_ref, hostSessionRef, event.turn_id);
3659
+ const steered = await liveSteeredTurn(options, store, hostSessionRef, host_turn_ref);
3660
+ if (steered !== void 0) return steered;
3661
+ const currentTurn = {
3662
+ host_turn_ref,
3663
+ prompt_ref: hostProducerPromptRef(promptObservationValue(event.prompt).body_sha256),
3664
+ turn_generation_ref: options.random_uuid?.() ?? randomUUID()
3665
+ };
3666
+ await store.writeInvocationTurnSelection({
3667
+ schema_version: "ceal.host_invocation_turn_selection.v1",
2774
3668
  host_source_ref: options.host_source_ref,
2775
- observed_at: observedAt,
2776
- value: sessionObservationValue(event),
2777
- expires_at: expiresAt
3669
+ host_session_ref: hostSessionRef,
3670
+ prompt_ref: currentTurn.prompt_ref,
3671
+ turn_generation_ref: currentTurn.turn_generation_ref
2778
3672
  });
2779
- return { event: "SessionStart", disposition: "ignored", reason: "transcript_registered" };
3673
+ return currentTurn;
3674
+ }
3675
+ async function liveSteeredTurn(options, store, hostSessionRef, hostTurnRef) {
3676
+ let live;
3677
+ try {
3678
+ live = await store.readInvocationContext(options.host_source_ref, hostSessionRef, (options.now ?? (() => /* @__PURE__ */ new Date()))());
3679
+ } catch {
3680
+ return void 0;
3681
+ }
3682
+ if (live === null || live.identity.host_turn_ref !== hostTurnRef) return void 0;
3683
+ const selection = await store.readInvocationTurnSelection(options.host_source_ref, hostSessionRef).catch(() => null);
3684
+ if (selection === null || selection.prompt_ref !== live.prompt_ref || selection.turn_generation_ref !== live.turn_generation_ref) return void 0;
3685
+ return { host_turn_ref: hostTurnRef, prompt_ref: selection.prompt_ref, turn_generation_ref: selection.turn_generation_ref };
2780
3686
  }
2781
3687
  function sourceBoundTranscriptPath(path, sessionsRoot) {
2782
3688
  if (!isAbsolute3(path) || !isAbsolute3(sessionsRoot)) throw new CodexHostAdapterError("configuration", "Codex transcript registration paths must be absolute.");
@@ -2884,7 +3790,7 @@ async function submitWithDeadline(gateway, submission, timeoutMs, signal) {
2884
3790
  });
2885
3791
  try {
2886
3792
  const acknowledgement = await Promise.race([gateway.submitHostTurn(submission, controller.signal), timeout]);
2887
- if (!isRecord5(acknowledgement) || !SAFE_REF6.test(String(acknowledgement.request_ref)) || !isHostGatewayAcknowledgementDisposition(acknowledgement.disposition)) {
3793
+ if (!isRecord6(acknowledgement) || !SAFE_REF6.test(String(acknowledgement.request_ref)) || !isHostGatewayAcknowledgementDisposition(acknowledgement.disposition)) {
2888
3794
  throw new CodexHostAdapterError("payload_rejected", "Gateway Host acknowledgement is invalid.");
2889
3795
  }
2890
3796
  return acknowledgement;
@@ -2914,12 +3820,12 @@ function timestamp4(now) {
2914
3820
  return value.toISOString();
2915
3821
  }
2916
3822
  function validateOptions(options) {
2917
- if (!isRecord5(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
3823
+ if (!isRecord6(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
2918
3824
  validateAdapterOwner(options);
2919
3825
  validateAdapterBehavior(options);
2920
3826
  }
2921
3827
  function validateAdapterOwner(options) {
2922
- if (!SAFE_REF6.test(options.host_source_ref) || options.outbox_dir.length === 0 || !isRecord5(options.gateway) || typeof options.gateway.submitHostTurn !== "function") {
3828
+ if (!SAFE_REF6.test(options.host_source_ref) || options.outbox_dir.length === 0 || !isRecord6(options.gateway) || typeof options.gateway.submitHostTurn !== "function") {
2923
3829
  throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
2924
3830
  }
2925
3831
  if (options.codex_sessions_root !== void 0 && !isAbsolute3(options.codex_sessions_root)) throw new CodexHostAdapterError("configuration", "Codex sessions root is invalid.");
@@ -2931,7 +3837,7 @@ function validateAdapterBehavior(options) {
2931
3837
  function safeReason(error) {
2932
3838
  return error instanceof CodexHostAdapterError ? error.message.slice(0, 128) : "codex_session_registration_rejected";
2933
3839
  }
2934
- function isRecord5(value) {
3840
+ function isRecord6(value) {
2935
3841
  return value !== null && typeof value === "object" && !Array.isArray(value);
2936
3842
  }
2937
3843
 
@@ -2939,7 +3845,7 @@ function isRecord5(value) {
2939
3845
  import { posix as posix3, win32 as win323 } from "node:path";
2940
3846
 
2941
3847
  // host/runtime-source-paths.ts
2942
- import { createHash as createHash4 } from "node:crypto";
3848
+ import { createHash as createHash5 } from "node:crypto";
2943
3849
  import { posix as posix2, win32 as win322 } from "node:path";
2944
3850
 
2945
3851
  // host/absolute-path.ts
@@ -2961,7 +3867,7 @@ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platfor
2961
3867
  const sourcesRoot = path.join(stateRoot, "sources");
2962
3868
  const sourceRoot = path.join(sourcesRoot, sourceId);
2963
3869
  const runtimeRoot = path.join(stateRoot, "run");
2964
- const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash4("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
3870
+ const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash5("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
2965
3871
  assertHostRuntimeIpcLength(endpoint, platform);
2966
3872
  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 };
2967
3873
  }
@@ -2977,7 +3883,7 @@ function assertHostProducerSourcePaths(stateRoot, config, producer, platform = p
2977
3883
 
2978
3884
  // host/producer-service.ts
2979
3885
  import { constants } from "node:fs";
2980
- import { lstat as lstat3, open as open4 } from "node:fs/promises";
3886
+ import { lstat as lstat3, open as open5 } from "node:fs/promises";
2981
3887
  var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2982
3888
  var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
2983
3889
  var HostProducerServiceError = class extends Error {
@@ -3043,7 +3949,7 @@ async function readProducerConfigText(configPath, platform, error) {
3043
3949
  }
3044
3950
  function decodeProducerConfigCore(text, options) {
3045
3951
  const value = parseCanonicalJson(text, options.error);
3046
- if (!isRecord6(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
3952
+ if (!isRecord7(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
3047
3953
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
3048
3954
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
3049
3955
  const producerEpoch = validateIdentity3(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -3088,7 +3994,7 @@ function validateConfigFile(value, platform, error) {
3088
3994
  }
3089
3995
  async function openConfigFile(configPath, flags, error) {
3090
3996
  try {
3091
- return await open4(configPath, flags);
3997
+ return await open5(configPath, flags);
3092
3998
  } catch {
3093
3999
  throw error("config_unavailable");
3094
4000
  }
@@ -3105,363 +4011,83 @@ async function readBoundedConfig(handle, expectedBytes, error) {
3105
4011
  if (bytesRead === 0) break;
3106
4012
  offset += bytesRead;
3107
4013
  }
3108
- if (offset !== expectedBytes) throw error("invalid_config", refusalFact("bytes_read", offset, `the opened file's ${expectedBytes} bytes without growth or truncation`));
3109
- try {
3110
- return new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, offset));
3111
- } catch {
3112
- throw error("invalid_config");
3113
- }
3114
- }
3115
- function parseCanonicalJson(text, error) {
3116
- try {
3117
- const value = JSON.parse(text);
3118
- const canonical = JSON.stringify(value);
3119
- if (canonical !== text.trim()) throw new Error(`noncanonical: ${refusalFacts([{ name: "config_bytes", value: Buffer.byteLength(text.trim(), "utf8"), expected: `the ${Buffer.byteLength(canonical, "utf8")} bytes of its canonical form` }, { name: "first_difference_index", value: firstDifferenceIndex(text.trim(), canonical) }])}`);
3120
- return value;
3121
- } catch (parseError) {
3122
- throw error("invalid_config", refusalFacts([{ name: "parse_error", value: parseError }, { name: "config_bytes", value: Buffer.byteLength(text, "utf8"), expected: "canonical JSON" }]));
3123
- }
3124
- }
3125
- function firstDifferenceIndex(left, right) {
3126
- const shared = Math.min(left.length, right.length);
3127
- for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
3128
- return shared;
3129
- }
3130
- function validateIdentity3(sourceRef, installationRef, epoch, error) {
3131
- if (!SAFE_REF7.test(sourceRef) || !SAFE_REF7.test(installationRef) || !positive2(epoch, 2147483647)) throw error("invalid_config");
3132
- return epoch;
3133
- }
3134
- function validateIntervals(reconcile, retry, timeout, error) {
3135
- if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
3136
- return [reconcile, retry, timeout];
3137
- }
3138
- function hasConfigKeys(value, required) {
3139
- return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
3140
- }
3141
- function isRecord6(value) {
3142
- return value !== null && typeof value === "object" && !Array.isArray(value);
3143
- }
3144
- function positive2(value, maximum) {
3145
- return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
3146
- }
3147
- function boundedMilliseconds(value) {
3148
- return positive2(value, 6e4) && Number(value) >= 25;
3149
- }
3150
-
3151
- // host/relay/src/relay-quarantine-store.ts
3152
- var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
3153
-
3154
- // host/relay/src/relay-admission-store.ts
3155
- var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
3156
- var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
3157
- var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
3158
-
3159
- // host/relay/src/relay-ipc.ts
3160
- import { createConnection, createServer } from "node:net";
3161
-
3162
- // host/relay/src/current-prompt-custody.ts
3163
- var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
3164
-
3165
- // host/relay/src/relay-ipc.ts
3166
- var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
3167
- "schema_version",
3168
- "producer_id",
3169
- "producer_installation_ref",
3170
- "local_session_ref",
3171
- "local_turn_ref",
3172
- "local_turn_aliases",
3173
- "prompt_ref",
3174
- "request_ref",
3175
- "bound_at",
3176
- "host_source_ref",
3177
- "host_session_ref",
3178
- "host_turn_ref",
3179
- "host_input_ref"
3180
- ]);
3181
- var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
3182
- var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
3183
- var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
3184
- var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
3185
- var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
3186
- var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
3187
- "context_stale",
3188
- "context_expired",
3189
- "host_source_refused",
3190
- "host_credential_refused",
3191
- "gateway_unavailable",
3192
- "gateway_refused",
3193
- "gateway_response_invalid",
3194
- "deadline",
3195
- "cancelled",
3196
- "mint_failed",
3197
- "relay_failed",
3198
- "request_authority_unavailable",
3199
- "request_missing",
3200
- "authority_mismatch",
3201
- "host_source_mismatch",
3202
- "host_session_mismatch",
3203
- "host_turn_mismatch",
3204
- "host_input_mismatch",
3205
- "host_prompt_mismatch"
3206
- ]);
3207
- var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
3208
- var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
3209
- "permission_denied",
3210
- "socket_missing",
3211
- "connection_refused",
3212
- "closed_early",
3213
- "response_invalid",
3214
- "timed_out",
3215
- "cancelled",
3216
- "unavailable"
3217
- ]);
3218
- var HostRelayIpcError = class extends Error {
3219
- code;
3220
- /** Set only when the client-side socket exchange itself failed. */
3221
- failure;
3222
- constructor(code, message = code, failure) {
3223
- super(message);
3224
- this.code = code;
3225
- this.failure = failure;
3226
- }
3227
- };
3228
- function socketErrorFailure(error) {
3229
- switch (errorCode(error)) {
3230
- case "EACCES":
3231
- case "EPERM":
3232
- return "permission_denied";
3233
- case "ENOENT":
3234
- return "socket_missing";
3235
- case "ECONNREFUSED":
3236
- return "connection_refused";
3237
- default:
3238
- return "unavailable";
3239
- }
3240
- }
3241
- var HostRelayIpcAdmissionPort = class {
3242
- endpoint;
3243
- timeout_ms;
3244
- constructor(endpoint, timeoutMs = 5e3) {
3245
- this.endpoint = endpoint;
3246
- this.timeout_ms = timeoutMs;
3247
- }
3248
- async admit(frame) {
3249
- const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
3250
- if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
3251
- return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
3252
- }
3253
- };
3254
- var HostRelayCurrentPromptPort = class {
3255
- endpoint;
3256
- timeout_ms;
3257
- constructor(endpoint, timeoutMs = 5e3) {
3258
- this.endpoint = endpoint;
3259
- this.timeout_ms = timeoutMs;
3260
- }
3261
- async register(input) {
3262
- const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
3263
- const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
3264
- if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
3265
- }
3266
- };
3267
- function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
3268
- return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
3269
- }
3270
- function exchange(endpoint, encoded, timeoutMs, decode, signal) {
3271
- return new Promise((resolve3, reject3) => {
3272
- const socket = createConnection(endpoint);
3273
- let buffer = Buffer.alloc(0);
3274
- let settled = false;
3275
- const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
3276
- const finish = (error, response2) => {
3277
- if (settled) return;
3278
- settled = true;
3279
- signal?.removeEventListener("abort", aborted);
3280
- socket.destroy();
3281
- if (error !== null) reject3(error);
3282
- else if (response2 !== void 0) resolve3(response2);
3283
- };
3284
- if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
3285
- if (signal?.aborted === true) {
3286
- aborted();
3287
- return;
3288
- }
3289
- signal?.addEventListener("abort", aborted, { once: true });
3290
- socket.once("error", (error) => {
3291
- const failure = socketErrorFailure(error);
3292
- finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure}.`, failure));
3293
- });
3294
- socket.once("connect", () => socket.write(encoded));
3295
- socket.on("data", (chunk) => {
3296
- try {
3297
- buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
3298
- const decoded = decode(buffer);
3299
- if (decoded !== null) finish(null, decoded);
3300
- } catch (error) {
3301
- finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
3302
- }
3303
- });
3304
- socket.once("end", () => {
3305
- if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
3306
- });
3307
- });
3308
- }
3309
- function decodeHostRelayIpcResponse(input) {
3310
- 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}`)}.`);
3311
- const length = input.readUInt32BE(0);
3312
- 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}` }])}.`);
3313
- let value;
4014
+ if (offset !== expectedBytes) throw error("invalid_config", refusalFact("bytes_read", offset, `the opened file's ${expectedBytes} bytes without growth or truncation`));
3314
4015
  try {
3315
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
4016
+ return new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, offset));
3316
4017
  } catch {
3317
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
4018
+ throw error("invalid_config");
3318
4019
  }
3319
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
3320
- return value;
3321
- }
3322
- function relayAdmissionCode(value) {
3323
- 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";
3324
- }
3325
- function validResponse(value) {
3326
- 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;
3327
- }
3328
- function hostRelayIpcCode(value) {
3329
- 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);
3330
4020
  }
3331
- function nonnegative(value) {
3332
- return Number.isSafeInteger(value) && Number(value) >= 0;
4021
+ function parseCanonicalJson(text, error) {
4022
+ try {
4023
+ const value = JSON.parse(text);
4024
+ const canonical = JSON.stringify(value);
4025
+ if (canonical !== text.trim()) throw new Error(`noncanonical: ${refusalFacts([{ name: "config_bytes", value: Buffer.byteLength(text.trim(), "utf8"), expected: `the ${Buffer.byteLength(canonical, "utf8")} bytes of its canonical form` }, { name: "first_difference_index", value: firstDifferenceIndex(text.trim(), canonical) }])}`);
4026
+ return value;
4027
+ } catch (parseError) {
4028
+ throw error("invalid_config", refusalFacts([{ name: "parse_error", value: parseError }, { name: "config_bytes", value: Buffer.byteLength(text, "utf8"), expected: "canonical JSON" }]));
4029
+ }
3333
4030
  }
3334
- function record2(value) {
3335
- return value !== null && typeof value === "object" && !Array.isArray(value);
4031
+ function firstDifferenceIndex(left, right) {
4032
+ const shared = Math.min(left.length, right.length);
4033
+ for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
4034
+ return shared;
3336
4035
  }
3337
- function decodeResponseBuffer(buffer) {
3338
- if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
3339
- const length = buffer.readUInt32BE(0);
3340
- 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}`)}.`);
3341
- if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
3342
- 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}` }])}.`);
3343
- return decodeHostRelayIpcResponse(buffer);
4036
+ function validateIdentity3(sourceRef, installationRef, epoch, error) {
4037
+ if (!SAFE_REF7.test(sourceRef) || !SAFE_REF7.test(installationRef) || !positive2(epoch, 2147483647)) throw error("invalid_config");
4038
+ return epoch;
3344
4039
  }
3345
- function decodeCurrentPromptResponseBuffer(buffer) {
3346
- const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
3347
- if (value === null) return null;
3348
- if (!record2(value) || !exactKeys4(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");
3349
- return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
4040
+ function validateIntervals(reconcile, retry, timeout, error) {
4041
+ if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
4042
+ return [reconcile, retry, timeout];
3350
4043
  }
3351
- function decodeLengthPrefixedJson(input, maximum) {
3352
- if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
3353
- const length = input.readUInt32BE(0);
3354
- 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}`)}.`);
3355
- if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
3356
- 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}` }])}.`);
3357
- try {
3358
- return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
3359
- } catch {
3360
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
3361
- }
4044
+ function hasConfigKeys(value, required) {
4045
+ return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
3362
4046
  }
3363
- function encodeLengthPrefixed(value) {
3364
- const body = Buffer.from(JSON.stringify(value), "utf8");
3365
- const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
3366
- output.writeUInt32BE(body.length, 0);
3367
- body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
3368
- return output;
4047
+ function isRecord7(value) {
4048
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3369
4049
  }
3370
- function exactKeys4(value, keys) {
3371
- return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
4050
+ function positive2(value, maximum) {
4051
+ return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
3372
4052
  }
3373
- function errorCode(error) {
3374
- return record2(error) && typeof error.code === "string" ? error.code : null;
4053
+ function boundedMilliseconds(value) {
4054
+ return positive2(value, 6e4) && Number(value) >= 25;
3375
4055
  }
3376
4056
 
3377
4057
  // host/codex/src/codex-producer.ts
3378
- import { createHash as createHash5 } from "node:crypto";
3379
- import { mkdir as mkdir3, readFile, rename as rename3, writeFile } from "node:fs/promises";
3380
- import { join as join4 } from "node:path";
3381
- var STATE_SCHEMA = "ceal.codex_producer_state.v1";
4058
+ import { createHash as createHash6 } from "node:crypto";
3382
4059
  var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3383
4060
  var CodexProducer = class {
4061
+ producer_id = "codex";
4062
+ producer_label = "Codex";
4063
+ outbox_directory;
3384
4064
  store;
3385
- statePath;
3386
- installationRef;
3387
- epoch;
3388
- relay;
3389
- now;
3390
- tail = Promise.resolve();
4065
+ core;
3391
4066
  constructor(options) {
3392
- if (!SAFE_REF8.test(options.producer_installation_ref)) throw new CodexHostAdapterError("configuration", "Codex producer installation identity is invalid.");
3393
- const epoch = options.producer_epoch ?? 1;
3394
- if (!Number.isSafeInteger(epoch) || epoch <= 0) throw new CodexHostAdapterError("configuration", "Codex producer epoch is invalid.");
3395
4067
  this.store = new CodexOutboxStore(options.outbox_dir);
3396
- this.statePath = join4(options.outbox_dir, "codex-producer-state.json");
3397
- this.installationRef = options.producer_installation_ref;
3398
- this.epoch = epoch;
3399
- this.relay = options.relay;
3400
- this.now = options.now ?? (() => /* @__PURE__ */ new Date());
4068
+ this.outbox_directory = this.store.directory;
4069
+ this.core = new HostProducerDrainCore(this, options);
3401
4070
  }
3402
4071
  drainOutbox() {
3403
- const run = this.tail.then(() => this.drainLocked());
3404
- this.tail = run.then(() => void 0, () => void 0);
3405
- return run;
4072
+ return this.core.drainOutbox();
3406
4073
  }
3407
- async drainLocked() {
3408
- const read = await this.store.list();
3409
- let admitted = 0;
3410
- let expired = 0;
3411
- let retained = 0;
3412
- for (const envelope of read.entries) {
3413
- const reserved = await this.hasReservation(envelope.submission_ref);
3414
- if (!reserved && Date.parse(envelope.expires_at) <= this.now().getTime()) {
3415
- await this.store.remove(envelope);
3416
- expired += 1;
3417
- continue;
3418
- }
3419
- const frames = await this.reserve(envelope);
3420
- let complete = true;
3421
- for (const frame of frames) {
3422
- const outcome = await this.relay.admit(frame);
3423
- if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
3424
- complete = false;
3425
- break;
3426
- }
3427
- }
3428
- if (!complete) {
3429
- retained += 1;
3430
- break;
3431
- }
3432
- await this.store.remove(envelope);
3433
- await this.release(envelope.submission_ref);
3434
- admitted += 1;
3435
- }
3436
- return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
4074
+ fail(code, message) {
4075
+ return new CodexHostAdapterError(code, message);
3437
4076
  }
3438
- async hasReservation(submissionRef) {
3439
- return (await this.readState()).pending[submissionRef] !== void 0;
4077
+ listEnvelopes() {
4078
+ return this.store.list();
3440
4079
  }
3441
- async reserve(envelope) {
3442
- const state = await this.readState();
3443
- const existing = state.pending[envelope.submission_ref];
3444
- if (existing !== void 0) return existing;
3445
- const drafts = await this.mapEnvelope(envelope);
3446
- const frames = drafts.map((draft, offset) => ({
3447
- schema_version: "ceal.host_producer_frame.v1",
3448
- producer_id: "codex",
3449
- producer_installation_ref: this.installationRef,
3450
- producer_epoch: this.epoch,
3451
- sequence: state.next_sequence + offset,
3452
- frame_kind: draft.frame_kind,
3453
- occurred_at: envelope.created_at,
3454
- payload: draft.payload
3455
- }));
3456
- await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [envelope.submission_ref]: frames } });
3457
- return frames;
4080
+ removeEnvelope(envelope) {
4081
+ return this.store.remove(envelope);
3458
4082
  }
3459
- async release(submissionRef) {
3460
- const state = await this.readState();
3461
- if (state.pending[submissionRef] === void 0) return;
3462
- const pending = { ...state.pending };
3463
- delete pending[submissionRef];
3464
- await this.writeState({ ...state, pending });
4083
+ submissionRefOf(envelope) {
4084
+ return envelope.submission_ref;
4085
+ }
4086
+ expiresAtOf(envelope) {
4087
+ return envelope.expires_at;
4088
+ }
4089
+ createdAtOf(envelope) {
4090
+ return envelope.created_at;
3465
4091
  }
3466
4092
  async mapEnvelope(envelope) {
3467
4093
  const prompt = observation(envelope, "prompt");
@@ -3477,7 +4103,7 @@ var CodexProducer = class {
3477
4103
  const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
3478
4104
  drafts.push({ frame_kind: "session_started", payload: compact({
3479
4105
  local_session_ref: envelope.identity.host_session_ref,
3480
- working_directory_ref: `workspace:${createHash5("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
4106
+ working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
3481
4107
  model: recordText(session.value, "model"),
3482
4108
  host_version: nestedText(session.value, "host_version"),
3483
4109
  observations: [session]
@@ -3502,21 +4128,6 @@ var CodexProducer = class {
3502
4128
  }) });
3503
4129
  return drafts;
3504
4130
  }
3505
- async readState() {
3506
- try {
3507
- const value = JSON.parse(await readFile(this.statePath, "utf8"));
3508
- return decodeState(value, this.installationRef, this.epoch);
3509
- } catch (error) {
3510
- if (errorCode2(error) !== "ENOENT") throw error;
3511
- return { schema_version: STATE_SCHEMA, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
3512
- }
3513
- }
3514
- async writeState(state) {
3515
- await mkdir3(this.store.directory, { recursive: true, mode: 448 });
3516
- const temporary = `${this.statePath}.${process.pid}.new`;
3517
- await writeFile(temporary, JSON.stringify(state), { mode: 384 });
3518
- await rename3(temporary, this.statePath);
3519
- }
3520
4131
  };
3521
4132
  function mapTerminal(envelope) {
3522
4133
  const timing = observation(envelope, "timing");
@@ -3544,7 +4155,7 @@ function compact(value) {
3544
4155
  return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
3545
4156
  }
3546
4157
  function asRecord(value) {
3547
- return isRecord7(value) ? value : void 0;
4158
+ return isRecord8(value) ? value : void 0;
3548
4159
  }
3549
4160
  function recordText(value, key) {
3550
4161
  const record3 = asRecord(value);
@@ -3558,122 +4169,60 @@ function nonNegativeNumber(value) {
3558
4169
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
3559
4170
  }
3560
4171
  function safeReasonRef(value) {
3561
- return SAFE_REF8.test(value) ? value : `reason:${createHash5("sha256").update(value, "utf8").digest("hex")}`;
3562
- }
3563
- function errorCode2(error) {
3564
- return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
3565
- }
3566
- function decodeState(value, installationRef, epoch) {
3567
- if (!validStateHeader(value, installationRef)) {
3568
- throw new CodexHostAdapterError("storage", `Codex producer state header is malformed or belongs to another installation (${refusalFacts([
3569
- { name: "schema_version", value: isRecord7(value) ? value.schema_version : void 0, expected: STATE_SCHEMA },
3570
- { name: "producer_installation_ref", value: isRecord7(value) ? value.producer_installation_ref : void 0, expected: installationRef }
3571
- ])}).`);
3572
- }
3573
- if (Number(value.producer_epoch) > epoch) throw new CodexHostAdapterError("storage", `Codex producer state epoch is ahead of this installation (${refusalFact("producer_epoch", value.producer_epoch, `at most ${epoch}`)}).`);
3574
- const pending = {};
3575
- for (const [submissionRef, frames] of Object.entries(value.pending)) {
3576
- if (!SAFE_REF8.test(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw new CodexHostAdapterError("storage", "Codex producer pending reservation is malformed.");
3577
- pending[submissionRef] = frames.map((frame) => decodeStoredFrame(frame, installationRef, Number(value.producer_epoch)));
3578
- }
3579
- return { schema_version: STATE_SCHEMA, producer_installation_ref: installationRef, producer_epoch: epoch, next_sequence: Number(value.next_sequence), pending };
3580
- }
3581
- function validStateHeader(value, installationRef) {
3582
- return isRecord7(value) && value.schema_version === STATE_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 && isRecord7(value.pending);
3583
- }
3584
- function decodeStoredFrame(value, installationRef, epoch) {
3585
- const json = Buffer.from(JSON.stringify(value), "utf8");
3586
- const encoded = Buffer.allocUnsafe(json.length + 4);
3587
- encoded.writeUInt32BE(json.length, 0);
3588
- json.copy(encoded, 4);
3589
- const frame = decodeHostProducerFrame(encoded);
3590
- if (frame.producer_id !== "codex" || frame.producer_installation_ref !== installationRef || frame.producer_epoch > epoch) throw new CodexHostAdapterError("storage", `Codex producer pending frame identity is malformed (${refusalFacts([
3591
- { name: "producer_id", value: frame.producer_id, expected: "codex" },
3592
- { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: installationRef },
3593
- { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${epoch}` }
3594
- ])}).`);
3595
- return frame;
4172
+ return SAFE_REF8.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
3596
4173
  }
3597
- function isRecord7(value) {
4174
+ function isRecord8(value) {
3598
4175
  return value !== null && typeof value === "object" && !Array.isArray(value);
3599
4176
  }
3600
4177
 
3601
4178
  // host/codex/src/codex-transcript-watcher.ts
3602
- import { createHash as createHash6 } from "node:crypto";
3603
- import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
3604
- import { open as open5 } from "node:fs/promises";
3605
- var READ_CHUNK_BYTES = 256 * 1024;
3606
- var TRANSCRIPT_MISSING_REASON = "transcript_missing";
3607
- var CodexTranscriptWatcher = class {
4179
+ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3608
4180
  store;
3609
- outboxRetentionMs;
3610
- now;
3611
- log;
3612
- producerInstallationRef;
3613
4181
  registerCurrentPrompt;
4182
+ releaseCurrentPrompt;
4183
+ diagnostic;
3614
4184
  constructor(options) {
3615
- if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid.");
3616
- this.store = new CodexOutboxStore(options.outbox_dir);
3617
- this.outboxRetentionMs = options.retention_ms ?? CODEX_DEFAULT_RETENTION_MS;
3618
- this.now = options.now ?? (() => /* @__PURE__ */ new Date());
3619
- this.log = options.log ?? ((line) => {
3620
- process.stderr.write(`${line}
3621
- `);
4185
+ super(options, {
4186
+ default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
4187
+ invalid_outbox: () => new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid."),
4188
+ clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
3622
4189
  });
3623
- this.producerInstallationRef = options.producer_installation_ref;
4190
+ this.store = new CodexOutboxStore(options.outbox_dir);
3624
4191
  this.registerCurrentPrompt = options.register_current_prompt;
4192
+ this.releaseCurrentPrompt = options.release_current_prompt;
4193
+ this.diagnostic = options.diagnostic ?? (() => void 0);
3625
4194
  }
3626
- async scanOnce() {
3627
- const registrations = await this.store.listTranscriptRegistrations();
3628
- let records = 0;
3629
- let enqueued = 0;
3630
- let quarantined = 0;
3631
- for (const registration of registrations) {
3632
- const result = await this.scanRegistration(registration);
3633
- records += result.records;
3634
- enqueued += result.enqueued;
3635
- if (result.quarantined) quarantined += 1;
3636
- }
3637
- return { registrations: registrations.length, records, enqueued, quarantined };
4195
+ transcriptPathOf(registration) {
4196
+ return registration.transcript_path;
3638
4197
  }
3639
- async scanRegistration(registration) {
3640
- let handle;
3641
- try {
3642
- handle = await open5(registration.transcript_path, O_RDONLY4 | O_NOFOLLOW3);
3643
- const { size, device, inode } = await ownedCodexTranscriptFile(handle);
3644
- const preflight = await this.preflight(registration, handle, size, device, inode);
3645
- if (preflight.cursor === null) return preflight.result;
3646
- const complete = await readCompleteChunk(handle, preflight.cursor, size);
3647
- if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
3648
- return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
3649
- } catch (error) {
3650
- if (handle === void 0 && isMissingTranscript(error)) return await this.retireRegistration(registration);
3651
- await this.quarantineFailure(registration, handle);
3652
- return { records: 0, enqueued: 0, quarantined: true };
3653
- } finally {
3654
- await handle?.close();
3655
- }
4198
+ async listRegistrations() {
4199
+ return this.store.listTranscriptRegistrations();
3656
4200
  }
3657
- /**
3658
- * A transcript the Host deleted never comes back, so retrying its
3659
- * registration once per reconcile interval is a failure with no end: a
3660
- * long-lived installation collects one permanently failing registration for
3661
- * every session Codex or the operator removes. Retire it at the scan that
3662
- * finds it missing and say so once, so the removal is readable and the next
3663
- * scan has nothing left to retry. Only ENOENT means gone; a permission or
3664
- * busy failure is about this moment, not about the file, and keeps the
3665
- * registration for the next scan.
3666
- */
3667
- async retireRegistration(registration) {
3668
- await this.store.retireTranscriptRegistration(registration);
3669
- this.log(`Codex retired a transcript registration: transcript_path=${JSON.stringify(registration.transcript_path)}, reason=${TRANSCRIPT_MISSING_REASON}.`);
3670
- return { records: 0, enqueued: 0, quarantined: false };
4201
+ async scanOpened(handle, registration) {
4202
+ const { size, device, inode } = await ownedCodexTranscriptFile(handle);
4203
+ const preflight = await this.preflight(registration, handle, size, device, inode);
4204
+ if (preflight.cursor === null) return preflight.result;
4205
+ const complete = await this.readChunk(handle, preflight.cursor.offset, size);
4206
+ if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
4207
+ return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
4208
+ }
4209
+ async scanFailed(handle, registration, error) {
4210
+ this.diagnostic("watcher_scan_failed", codexTranscriptScanFailureKind(error));
4211
+ await this.quarantineFailure(registration, handle);
4212
+ return { records: 0, enqueued: 0, quarantined: true };
4213
+ }
4214
+ async retireMissing(registration) {
4215
+ await this.releaseStoredPromptBestEffort(registration.host_session_ref, await this.store.readTranscriptCursor(registration).catch(() => null));
4216
+ return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
3671
4217
  }
3672
4218
  async preflight(registration, handle, size, device, inode) {
3673
4219
  const existing = await this.store.readTranscriptCursor(registration);
3674
4220
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
3675
- if (cursor.status === "quarantined") return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
3676
- const reason = await cursorFailureReason(registration, handle, cursor, size, device, inode);
4221
+ if (cursor.status === "quarantined") {
4222
+ if (cursor.reason !== "transcript_malformed") await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
4223
+ return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
4224
+ }
4225
+ const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
3677
4226
  if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
3678
4227
  await this.quarantine(registration, cursor, device, inode, reason);
3679
4228
  return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
@@ -3699,39 +4248,53 @@ var CodexTranscriptWatcher = class {
3699
4248
  async observeSessionMetadata(registration, record3) {
3700
4249
  if (record3.kind !== "session_meta") return;
3701
4250
  const session = await this.store.readSession(registration.host_source_ref, registration.host_session_ref);
3702
- if (session !== null && isRecord8(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
4251
+ if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
3703
4252
  }
3704
4253
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
3705
4254
  const offset = cursor.offset + consumedBytes;
3706
- const anchorStart = Math.max(0, offset - CODEX_TRANSCRIPT_ANCHOR_BYTES);
3707
- const anchor = Buffer.alloc(offset - anchorStart);
3708
- if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, anchorStart);
3709
- await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchorStart, anchor_sha256: sha2562(anchor), header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: timestamp5(this.now) });
4255
+ const anchor = await this.readAnchor(handle, offset, CODEX_TRANSCRIPT_ANCHOR_BYTES);
4256
+ await this.store.writeTranscriptCursor({ schema_version: "ceal.codex_transcript_cursor.v1", host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, transcript_path: registration.transcript_path, device, inode, offset, last_ordinal: lastOrdinal, anchor_start: anchor.start, anchor_sha256: anchor.sha256, header_validated: true, ...activeTask === void 0 ? {} : { active_task: activeTask }, status: "active", updated_at: this.stamp() });
3710
4257
  }
3711
4258
  async quarantineFailure(registration, handle) {
3712
4259
  if (handle === void 0) return;
3713
4260
  const stats = await handle.stat().catch(() => null);
3714
4261
  if (stats === null) return;
3715
4262
  const existing = await this.store.readTranscriptCursor(registration).catch(() => null);
3716
- await this.quarantine(registration, existing ?? codexTranscriptInitialCursor(registration, String(stats.dev), String(stats.ino), this.now), String(stats.dev), String(stats.ino), "transcript_malformed");
4263
+ const quarantined = {
4264
+ ...existing ?? codexTranscriptInitialCursor(registration, String(stats.dev), String(stats.ino), this.now),
4265
+ transcript_path: registration.transcript_path,
4266
+ device: String(stats.dev),
4267
+ inode: String(stats.ino),
4268
+ status: "quarantined",
4269
+ reason: "transcript_malformed",
4270
+ updated_at: this.stamp()
4271
+ };
4272
+ await this.store.writeTranscriptCursor(quarantined);
3717
4273
  }
3718
4274
  async processRecord(registration, activeTask, record3) {
3719
- if (record3.kind === "task_started") {
3720
- 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 };
3721
- }
4275
+ if (record3.kind === "task_started") return this.processTaskStarted(registration, activeTask, record3);
3722
4276
  if (record3.kind === "turn_context") return { ...activeTask === void 0 ? {} : { activeTask: record3.turn_id === activeTask.codex_turn_id ? { ...activeTask, model: record3.model } : activeTask }, enqueued: 0 };
3723
4277
  if (record3.kind === "token_count") return { ...activeTask === void 0 ? {} : { activeTask: accumulateTokenCount(activeTask, record3) }, enqueued: 0 };
3724
4278
  if (record3.kind === "user_text") return this.processUserInput(registration, activeTask, record3);
3725
4279
  if (record3.kind === "task_complete" || record3.kind === "turn_aborted") return this.processTerminal(registration, activeTask, record3);
3726
4280
  return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
3727
4281
  }
4282
+ async processTaskStarted(registration, activeTask, record3) {
4283
+ if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4284
+ return { activeTask: { codex_turn_id: record3.turn_id, host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id), started_at: record3.timestamp }, enqueued: 0 };
4285
+ }
3728
4286
  async processUserInput(registration, activeTask, record3) {
3729
- if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4287
+ if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id) {
4288
+ const adopted = await this.adoptHookCorrelatedTurn(registration, activeTask, record3);
4289
+ if (adopted === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
4290
+ activeTask = adopted;
4291
+ }
3730
4292
  const hostInputRef = hostInputReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id, record3.message_id, record3.ordinal, record3.prompt);
3731
4293
  const origin = activeTask.origin_host_input_ref === void 0;
3732
4294
  const promptValue = promptObservationValue(record3.prompt);
3733
4295
  const currentPromptRef = hostProducerPromptRef(promptValue.body_sha256);
3734
4296
  const promptRef = activeTask.prompt_ref ?? currentPromptRef;
4297
+ const steeredPromptRef = await this.steeredPromptRef(registration, activeTask, origin, currentPromptRef);
3735
4298
  const identity = { host_source_ref: registration.host_source_ref, host_session_ref: registration.host_session_ref, host_turn_ref: activeTask.host_turn_ref };
3736
4299
  const observations = [{
3737
4300
  observation_ref: observationRef("transcript_user_text", hostInputRef, record3.prompt),
@@ -3755,16 +4318,90 @@ var CodexTranscriptWatcher = class {
3755
4318
  origin_input: origin,
3756
4319
  submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
3757
4320
  created_at: record3.timestamp,
3758
- expires_at: expiration(this.now, this.outboxRetentionMs)
4321
+ expires_at: this.expire(this.outboxRetentionMs)
4322
+ };
4323
+ const persisted = await this.persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope);
4324
+ if (steeredPromptRef !== null) await this.activateTranscriptTurnContext(identity, steeredPromptRef, envelope.expires_at);
4325
+ return persisted;
4326
+ }
4327
+ /**
4328
+ * The steered prompt to re-activate under the running task, or null when
4329
+ * there is nothing to repair. A steered message joins the running turn
4330
+ * with new prompt bytes but no task_started. When the steer hook already
4331
+ * replaced the turn selection (a turn id the hook did not recognize as
4332
+ * the running one, or a hook that ran before any context was live), the
4333
+ * running task's context no longer matches and the next invocation would
4334
+ * wait for a boundary that never comes. When the hook kept the live
4335
+ * selection, the context still matches and this stays null.
4336
+ */
4337
+ async steeredPromptRef(registration, activeTask, origin, currentPromptRef) {
4338
+ if (origin || activeTask.prompt_ref === void 0 || activeTask.prompt_ref === currentPromptRef) return null;
4339
+ const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref).catch(() => null);
4340
+ return selection?.prompt_ref === currentPromptRef ? currentPromptRef : null;
4341
+ }
4342
+ /**
4343
+ * Adopt the live hooked turn when its transcript message arrives before
4344
+ * (or without) its task_started, as an interrupted turn's follow-up can.
4345
+ * The UserPromptSubmit hook names the exact hooked prompt, so only a
4346
+ * message carrying those bytes adopts; inherited history and other turns
4347
+ * stay ignored. A stale active task for another turn releases first, the
4348
+ * same as a task_started supersession.
4349
+ */
4350
+ async adoptHookCorrelatedTurn(registration, activeTask, record3) {
4351
+ const currentPromptRef = hostProducerPromptRef(promptObservationValue(record3.prompt).body_sha256);
4352
+ const selection = await this.store.readInvocationTurnSelection(registration.host_source_ref, registration.host_session_ref);
4353
+ if (selection?.prompt_ref !== currentPromptRef) return void 0;
4354
+ if (activeTask !== void 0 && activeTask.codex_turn_id !== record3.turn_id && activeTask.prompt_ref !== void 0) {
4355
+ await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
4356
+ }
4357
+ return {
4358
+ codex_turn_id: record3.turn_id,
4359
+ host_turn_ref: hostTurnReference(registration.host_source_ref, registration.host_session_ref, record3.turn_id),
4360
+ started_at: record3.timestamp
3759
4361
  };
3760
- await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
3761
- await this.store.put(envelope);
3762
- if (origin) await this.store.activateInvocationContext(identity, promptRef, envelope.expires_at);
4362
+ }
4363
+ async persistUserInputTurn(registration, activeTask, record3, hostInputRef, origin, currentPromptRef, promptRef, identity, envelope) {
4364
+ const custodyRegistered = await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
4365
+ if (custodyRegistered) this.diagnostic("watcher_turn_observed");
4366
+ try {
4367
+ await this.store.put(envelope);
4368
+ if (origin) await this.activateTranscriptTurnContext(identity, promptRef, envelope.expires_at);
4369
+ } catch (error) {
4370
+ if (custodyRegistered) await this.releasePrompt(registration.host_session_ref, activeTask, currentPromptRef).catch(() => void 0);
4371
+ throw error;
4372
+ }
3763
4373
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
3764
4374
  }
3765
4375
  async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
3766
- if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return;
3767
- 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 });
4376
+ if (!origin || this.producerInstallationRef === void 0 || this.registerCurrentPrompt === void 0) return false;
4377
+ const register = this.registerCurrentPrompt;
4378
+ const installationRef = this.producerInstallationRef;
4379
+ return registerHostCurrentPromptDiagnosed(
4380
+ () => register({ producer_id: "codex", producer_installation_ref: installationRef, local_session_ref: registration.host_session_ref, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef, current_prompt: prompt, context_expires_at: expiresAt }),
4381
+ (event) => this.diagnostic(event)
4382
+ );
4383
+ }
4384
+ async activateTranscriptTurnContext(identity, promptRef, expiresAt) {
4385
+ try {
4386
+ const selection = await this.store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
4387
+ const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
4388
+ await this.store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
4389
+ this.diagnostic("activation_recorded");
4390
+ } catch (error) {
4391
+ this.diagnostic("activation_failed");
4392
+ throw error;
4393
+ }
4394
+ }
4395
+ async releasePrompt(sessionRef, activeTask, promptRef) {
4396
+ if (this.producerInstallationRef === void 0 || this.releaseCurrentPrompt === void 0) return;
4397
+ await this.releaseCurrentPrompt({ producer_id: "codex", producer_installation_ref: this.producerInstallationRef, local_session_ref: sessionRef, local_turn_ref: activeTask.host_turn_ref, prompt_ref: promptRef });
4398
+ }
4399
+ async releaseStoredPromptBestEffort(sessionRef, cursor) {
4400
+ await this.releaseActiveTaskBestEffort(sessionRef, cursor?.active_task);
4401
+ }
4402
+ async releaseActiveTaskBestEffort(sessionRef, activeTask) {
4403
+ if (activeTask?.prompt_ref === void 0) return;
4404
+ await this.releasePrompt(sessionRef, activeTask, activeTask.prompt_ref).catch(() => void 0);
3768
4405
  }
3769
4406
  async processTerminal(registration, activeTask, record3) {
3770
4407
  if (activeTask === void 0 || activeTask.codex_turn_id !== record3.turn_id || activeTask.origin_host_input_ref === void 0 || activeTask.prompt_ref === void 0) return { ...activeTask === void 0 ? {} : { activeTask }, enqueued: 0 };
@@ -3782,16 +4419,26 @@ var CodexTranscriptWatcher = class {
3782
4419
  origin_input: false,
3783
4420
  submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
3784
4421
  created_at: record3.timestamp,
3785
- expires_at: expiration(this.now, this.outboxRetentionMs)
4422
+ expires_at: this.expire(this.outboxRetentionMs)
3786
4423
  });
4424
+ await this.releasePrompt(registration.host_session_ref, activeTask, activeTask.prompt_ref);
3787
4425
  await this.store.clearInvocationContext(identity, this.now());
3788
4426
  return { enqueued: 1 };
3789
4427
  }
3790
4428
  async quarantine(registration, cursor, device, inode, reason) {
3791
- const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: timestamp5(this.now) };
4429
+ await this.releaseStoredPromptBestEffort(registration.host_session_ref, cursor);
4430
+ const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
3792
4431
  await this.store.writeTranscriptCursor(quarantined);
3793
4432
  }
3794
4433
  };
4434
+ function codexTranscriptScanFailureKind(error) {
4435
+ return transcriptScanFailureKind(error, (candidate) => {
4436
+ if (!(candidate instanceof CodexHostAdapterError)) return void 0;
4437
+ if (candidate.code === "payload_rejected") return "payload_rejected";
4438
+ if (candidate.code === "storage") return "read_error";
4439
+ return void 0;
4440
+ });
4441
+ }
3795
4442
  function accumulateTokenCount(activeTask, record3) {
3796
4443
  if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
3797
4444
  const last = record3.last_usage;
@@ -3825,19 +4472,18 @@ function terminalCostValue() {
3825
4472
  return notRecorded("provider_cost_not_observed");
3826
4473
  }
3827
4474
  function notRecorded(reason) {
3828
- return { status: "not_recorded", reason };
4475
+ return hostObservationNotRecorded(reason);
3829
4476
  }
3830
4477
  function tokenObservationValue(usage) {
3831
4478
  return {
3832
- status: "available",
3833
- unit: "tokens",
3834
- input: usage.input_tokens,
3835
- output: usage.output_tokens,
3836
- total: usage.total_tokens,
3837
- cached_input: usage.cached_input_tokens,
3838
- cache_write_input: usage.cache_write_input_tokens,
3839
- reasoning_output: usage.reasoning_output_tokens,
3840
- source: "codex_transcript.event_msg.token_count.info.last_token_usage",
4479
+ ...createHostTokenObservationValue({
4480
+ input: usage.input_tokens,
4481
+ output: usage.output_tokens,
4482
+ total: usage.total_tokens,
4483
+ cached_input: usage.cached_input_tokens,
4484
+ cache_write_input: usage.cache_write_input_tokens,
4485
+ reasoning_output: usage.reasoning_output_tokens
4486
+ }, "codex_transcript.event_msg.token_count.info.last_token_usage"),
3841
4487
  attribution: "sequential_active_task",
3842
4488
  total_usage_role: "dedup_and_reset_detection_only"
3843
4489
  };
@@ -3871,65 +4517,24 @@ function looksLikeStaleRegression(current, previous, last) {
3871
4517
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
3872
4518
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
3873
4519
  }
3874
- function isMissingTranscript(error) {
3875
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
3876
- }
3877
- async function cursorFailureReason(registration, handle, cursor, size, device, inode) {
3878
- if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== registration.transcript_path) return "transcript_replaced";
3879
- if (size < cursor.offset) return "transcript_truncated";
3880
- if (cursor.offset > 0 && !await anchorMatches(handle, cursor)) return "transcript_rewritten";
3881
- return null;
3882
- }
3883
- async function readCompleteChunk(handle, cursor, size) {
3884
- const available = Math.max(0, size - cursor.offset);
3885
- if (available === 0) return "empty";
3886
- const chunks = [];
3887
- let position = cursor.offset;
3888
- let total = 0;
3889
- let lastNewline = -1;
3890
- while (position < size) {
3891
- const buffer = Buffer.alloc(Math.min(READ_CHUNK_BYTES, size - position));
3892
- const read = await handle.read(buffer, 0, buffer.length, position);
3893
- if (read.bytesRead === 0) break;
3894
- const chunk = buffer.subarray(0, read.bytesRead);
3895
- chunks.push(chunk);
3896
- const newline = chunk.lastIndexOf(10);
3897
- if (newline >= 0) lastNewline = total + newline;
3898
- total += chunk.length;
3899
- position += chunk.length;
3900
- if (lastNewline >= 0) break;
3901
- }
3902
- if (lastNewline < 0) return "partial";
3903
- return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
3904
- }
3905
4520
  function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
3906
4521
  if ((cursor.header_validated || records > 0) && record3.ordinal <= lastOrdinal) throw new CodexHostAdapterError("payload_rejected", `Codex transcript ordinal is not monotonic (${refusalFact("ordinal", record3.ordinal, `greater than ${lastOrdinal}`)}).`);
3907
4522
  if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
3908
4523
  }
3909
- async function anchorMatches(handle, cursor) {
3910
- const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
3911
- if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
3912
- return sha2562(buffer) === cursor.anchor_sha256;
3913
- }
3914
- function sha2562(value) {
3915
- return createHash6("sha256").update(value).digest("hex");
3916
- }
3917
- function isRecord8(value) {
3918
- return value !== null && typeof value === "object" && !Array.isArray(value);
3919
- }
3920
- function timestamp5(now) {
3921
- const value = now();
3922
- if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
3923
- return value.toISOString();
3924
- }
3925
- function expiration(now, retentionMs) {
3926
- return new Date(Date.parse(timestamp5(now)) + retentionMs).toISOString();
3927
- }
3928
4524
 
3929
4525
  // host/codex/src/codex-producer-runtime.ts
3930
4526
  async function drainCodexProducerOnce(options) {
3931
4527
  const promptPort = new HostRelayCurrentPromptPort(options.relay_endpoint, options.timeout_ms);
3932
- 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();
4528
+ const scan = await new CodexTranscriptWatcher({
4529
+ outbox_dir: options.outbox_dir,
4530
+ producer_installation_ref: options.producer_installation_ref,
4531
+ register_current_prompt: (input) => promptPort.register(input),
4532
+ release_current_prompt: (identity) => promptPort.release(identity),
4533
+ diagnostic: (event, failure_kind) => writeHostServiceDiagnostic("codex", event, failure_kind)
4534
+ }).scanOnce().catch((error) => {
4535
+ writeHostServiceDiagnostic("codex", "watcher_scan_failed", codexTranscriptScanFailureKind(error));
4536
+ throw error;
4537
+ });
3933
4538
  const producer = new CodexProducer({ outbox_dir: options.outbox_dir, producer_installation_ref: options.producer_installation_ref, relay: new HostRelayIpcAdmissionPort(options.relay_endpoint, options.timeout_ms), ...options.producer_epoch === void 0 ? {} : { producer_epoch: options.producer_epoch }, ...options.now === void 0 ? {} : { now: options.now } });
3934
4539
  return { scanned: scan.enqueued, ...await producer.drainOutbox() };
3935
4540
  }
@@ -3953,7 +4558,7 @@ var CODEX_PRODUCER_DESCRIPTOR = {
3953
4558
  };
3954
4559
 
3955
4560
  // host/codex/src/codex-hook-runner.ts
3956
- var MAX_STDIN_BYTES = 64 * 1024;
4561
+ var MAX_STDIN_BYTES = 512 * 1024;
3957
4562
  async function runCodexHookFromStdin(event, stdin, options) {
3958
4563
  const adapter = createCodexHostObservationAdapter(options);
3959
4564
  return adapter.handle(event, await readStdin(stdin));