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

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"]);
@@ -974,6 +1000,7 @@ var CEAL_ACTIVITY_TIMESTAMP_BASES = vocabulary([
974
1000
  "resource_modified"
975
1001
  ]);
976
1002
  var CEAL_ACTIVITY_CONNECTOR_KINDS = vocabulary(["slack", "github", "google-calendar", "google-drive", "notion"]);
1003
+ var CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE = "unsupported_event_kind";
977
1004
  var CEAL_ACTIVITY_GAP_CODES = vocabulary([
978
1005
  "provider_page_budget",
979
1006
  "call_deadline",
@@ -981,7 +1008,7 @@ var CEAL_ACTIVITY_GAP_CODES = vocabulary([
981
1008
  "provider_cursor_unavailable",
982
1009
  "malformed_provider_page",
983
1010
  "visibility_incomplete",
984
- "unsupported_event_kind",
1011
+ CEAL_ACTIVITY_UNSUPPORTED_EVENT_KIND_CODE,
985
1012
  "direct_messages_excluded"
986
1013
  ]);
987
1014
  var CEAL_ACTIVITY_EVENT_KINDS = vocabulary([
@@ -1046,6 +1073,8 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1046
1073
  modified_at: { required: false, timestamp: true },
1047
1074
  modified_at_local: { required: false, timestamp: true },
1048
1075
  viewed_by_me_at: { required: false, timestamp: true },
1076
+ own_ceal_write: { required: false, timestamp: false },
1077
+ owned_by_me: { required: false, timestamp: false },
1049
1078
  visibility: { required: false, timestamp: false },
1050
1079
  start: { required: false, timestamp: false },
1051
1080
  end: { required: false, timestamp: false },
@@ -1079,6 +1108,15 @@ function cealExcludedTargetCoverageJsonSchema() {
1079
1108
  };
1080
1109
  }
1081
1110
 
1111
+ // packages/ceal-client-protocol/src/gateway-write-identity.ts
1112
+ var CEAL_GATEWAY_WRITE_IDENTITY_ROLES = Object.freeze(["replay_identity", "lookup_handle", "collision_evidence"]);
1113
+ var CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN = /^gateway-write-request:[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$/u;
1114
+ var CEAL_GATEWAY_WRITE_IDENTITY_FIELDS = Object.freeze({
1115
+ replay_identity: "idempotency_claim_sha256",
1116
+ lookup_handle: "write_request_sha256",
1117
+ collision_evidence: "normalized_mutation_sha256"
1118
+ });
1119
+
1082
1120
  // packages/ceal-client-protocol/src/write-safety-finding.ts
1083
1121
  var CEAL_WRITE_SAFETY_FINDING_STATUSES = vocabulary(["warning", "unchecked"]);
1084
1122
  var CEAL_WRITE_SAFETY_AUDIENCES = vocabulary(["workspace", "person", "members", "unknown"]);
@@ -1106,7 +1144,11 @@ var CEAL_REFRESH_FAILURE_CODES = vocabulary([
1106
1144
  "refresh_revoked",
1107
1145
  "authority_replaced",
1108
1146
  "refresh_recovery_unavailable",
1109
- "refresh_recovery_expired"
1147
+ "refresh_recovery_expired",
1148
+ // The serving gate answers this while the Gateway is still starting and the
1149
+ // refresh was never attempted; the same attempt stays retryable. It is never
1150
+ // stored by the session owner, only answered at the serving edge.
1151
+ "gateway_starting"
1110
1152
  ]);
1111
1153
 
1112
1154
  // packages/ceal-client-protocol/src/request-validation-primitives.ts
@@ -1139,7 +1181,7 @@ var CANCELLATION_STATES = vocabulary(["requested", "cancelled"]);
1139
1181
  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
1182
  var CEAL_REQUEST_JSON_SCHEMA = {
1141
1183
  type: "object",
1142
- maxProperties: 10,
1184
+ maxProperties: 11,
1143
1185
  additionalProperties: false,
1144
1186
  properties: {
1145
1187
  schema_version: { type: "string", const: CEAL_REQUEST_SCHEMA_VERSION, maxLength: 32 },
@@ -1163,7 +1205,8 @@ var CEAL_REQUEST_JSON_SCHEMA = {
1163
1205
  host_turn_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1164
1206
  host_input_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
1165
1207
  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." }
1208
+ requester_timezone: { type: "string", minLength: 1, maxLength: 128, description: "IANA timezone observed for the requester on this Request." },
1209
+ 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
1210
  },
1168
1211
  required: CEAL_REQUEST_KEYS
1169
1212
  };
@@ -1222,6 +1265,7 @@ var REQUEST_EXECUTION_PREPARE_REFUSAL_PROPERTIES = {
1222
1265
  retryable: { type: "boolean" },
1223
1266
  source: { type: "string", enum: ["provider", "gateway"] },
1224
1267
  retry_after_ms: { type: "integer", minimum: 0, maximum: CEAL_RETRY_AFTER_MAX_MS },
1268
+ write_request_ref: { type: "string", pattern: CEAL_GATEWAY_WRITE_REQUEST_REF_PATTERN.source, maxLength: 128 },
1225
1269
  excluded_targets: cealExcludedTargetCoverageJsonSchema(),
1226
1270
  repaired_input: {},
1227
1271
  unrepaired_pointers: { type: "array", maxItems: 128, items: { type: "string", minLength: 1, maxLength: 256 } },
@@ -1286,6 +1330,43 @@ function cealHostObservationRef(producer, digest2) {
1286
1330
  if (!HOST_OBSERVATION_PRODUCER.test(producer) || !HOST_OBSERVATION_DIGEST.test(digest2)) invalid("Ceal Host observation reference parts are invalid.");
1287
1331
  return `${CEAL_HOST_OBSERVATION_REF_PREFIX}${producer}-${digest2}`;
1288
1332
  }
1333
+ var HOST_TOKEN_OBSERVATION_BREAKDOWN_KEYS = vocabulary(["cached_input", "cache_write_input", "reasoning_output"]);
1334
+ function createHostTokenObservationValue(counts, source) {
1335
+ const core = validTokenCore(counts);
1336
+ if (typeof source !== "string" || source.length === 0 || source.length > 256) invalid("Ceal Host token observation source is invalid.");
1337
+ const value = { status: "available", unit: "tokens", input: core.input, output: core.output, total: core.total, source };
1338
+ for (const breakdown of validTokenBreakdowns(counts)) value[breakdown.key] = breakdown.tokens;
1339
+ assertHostObservationValue(value, "token");
1340
+ return value;
1341
+ }
1342
+ function validTokenCore(counts) {
1343
+ if (!isOperationRecord(counts) || !safeCount(counts.input) || !safeCount(counts.output) || !safeCount(counts.total)) invalid("Ceal Host token observation counts are invalid.");
1344
+ if (counts.total !== counts.input + counts.output) invalid("Ceal Host token observation counts are invalid.");
1345
+ return { input: counts.input, output: counts.output, total: counts.total };
1346
+ }
1347
+ function validTokenBreakdowns(counts) {
1348
+ const breakdowns = [
1349
+ { key: "cached_input", tokens: counts.cached_input },
1350
+ { key: "cache_write_input", tokens: counts.cache_write_input },
1351
+ { key: "reasoning_output", tokens: counts.reasoning_output }
1352
+ ];
1353
+ const stated = breakdowns.filter((breakdown) => breakdown.tokens !== void 0).map((breakdown) => ({ key: breakdown.key, tokens: Number(breakdown.tokens) }));
1354
+ for (const breakdown of stated) {
1355
+ if (!safeCount(breakdown.tokens)) invalid("Ceal Host token observation counts are invalid.");
1356
+ }
1357
+ const cached = counts.cached_input ?? 0;
1358
+ const created = counts.cache_write_input ?? 0;
1359
+ const reasoning = counts.reasoning_output ?? 0;
1360
+ if (cached + created > counts.input || reasoning > counts.output) invalid("Ceal Host token observation counts are invalid.");
1361
+ return stated;
1362
+ }
1363
+ function hostObservationNotRecorded(reason) {
1364
+ if (typeof reason !== "string" || reason.length === 0 || reason.length > 256) invalid("Ceal Host observation gap reason is invalid.");
1365
+ return { status: "not_recorded", reason };
1366
+ }
1367
+ function safeCount(value) {
1368
+ return Number.isSafeInteger(value) && Number(value) >= 0;
1369
+ }
1289
1370
  function validateCealHostObservationDraft(value) {
1290
1371
  const record3 = operationRecord(value, "Ceal Host observation draft is invalid.");
1291
1372
  requirePrefixedRef(record3.observation_ref, CEAL_HOST_OBSERVATION_REF_PREFIX, "Ceal Host observation reference is invalid.");
@@ -1437,12 +1518,83 @@ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
1437
1518
  "host_input_mismatch",
1438
1519
  "host_prompt_mismatch"
1439
1520
  ]);
1521
+ var CEAL_HOST_AUTHENTICATION_CAUSES = vocabulary([
1522
+ "invalid_arguments",
1523
+ "options_invalid",
1524
+ "session_unavailable",
1525
+ "context_unavailable",
1526
+ "context_replaced",
1527
+ "no_binding",
1528
+ "context_stale",
1529
+ "context_expired",
1530
+ "host_source_refused",
1531
+ "host_credential_refused",
1532
+ "gateway_unavailable",
1533
+ "gateway_rate_limited",
1534
+ "gateway_refused",
1535
+ "gateway_response_invalid",
1536
+ "producer_frame_invalid",
1537
+ "relay_permission_denied",
1538
+ "relay_unavailable",
1539
+ "transient_retryable",
1540
+ "mint_failed",
1541
+ "relay_failed",
1542
+ "host_refusal_invalid"
1543
+ ]);
1544
+ var CEAL_HOST_AUTHENTICATION_POLICY = Object.freeze({
1545
+ invalid_arguments: Object.freeze({ classification: "host_arguments_invalid", next_action: "answer_with_gap" }),
1546
+ options_invalid: Object.freeze({ classification: "host_configuration_invalid", next_action: "answer_with_gap" }),
1547
+ session_unavailable: Object.freeze({ classification: "host_session_unavailable", next_action: "answer_with_gap" }),
1548
+ context_unavailable: Object.freeze({ classification: "host_context_unavailable", next_action: "refresh_host_invocation_context", remedy: "the Host has no invocation context from the current transcript turn; run `ceal-host install` to repair the Host hook registration, then retry this command on a fresh Host turn" }),
1549
+ context_replaced: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1550
+ no_binding: Object.freeze({ classification: "host_binding_unavailable", next_action: "refresh_host_invocation_context" }),
1551
+ context_stale: Object.freeze({ classification: "host_invocation_context_stale", next_action: "refresh_host_invocation_context" }),
1552
+ context_expired: Object.freeze({ classification: "host_invocation_context_expired", next_action: "refresh_host_invocation_context" }),
1553
+ host_source_refused: Object.freeze({ classification: "host_source_refused", next_action: "answer_with_gap" }),
1554
+ host_credential_refused: Object.freeze({ classification: "host_registration_credential_refused", next_action: "ask_admin" }),
1555
+ gateway_unavailable: Object.freeze({ classification: "host_mint_gateway_unavailable", next_action: "ask_admin" }),
1556
+ gateway_rate_limited: Object.freeze({ classification: "host_mint_gateway_rate_limited", next_action: "answer_with_gap" }),
1557
+ gateway_refused: Object.freeze({ classification: "host_mint_gateway_refused", next_action: "answer_with_gap" }),
1558
+ gateway_response_invalid: Object.freeze({ classification: "host_mint_gateway_response_invalid", next_action: "answer_with_gap" }),
1559
+ 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" }),
1560
+ 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" }),
1561
+ relay_unavailable: Object.freeze({ classification: "host_relay_unavailable", next_action: "answer_with_gap" }),
1562
+ transient_retryable: Object.freeze({ classification: "host_mint_transient_retryable", next_action: "retry" }),
1563
+ mint_failed: Object.freeze({ classification: "host_mint_failed", next_action: "answer_with_gap" }),
1564
+ relay_failed: Object.freeze({ classification: "host_relay_failed", next_action: "answer_with_gap" }),
1565
+ host_refusal_invalid: Object.freeze({ classification: "host_refusal_invalid", next_action: "answer_with_gap" })
1566
+ });
1567
+
1568
+ // packages/ceal-client-protocol/src/host-service-diagnostic.ts
1569
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_PRODUCERS = vocabulary(["claude", "codex"]);
1570
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_EVENTS = vocabulary([
1571
+ "hook_invoked",
1572
+ "registration_written",
1573
+ "hook_failed",
1574
+ "watcher_turn_observed",
1575
+ "current_prompt_registered",
1576
+ "current_prompt_registration_failed",
1577
+ "activation_recorded",
1578
+ "activation_failed",
1579
+ "watcher_scan_failed",
1580
+ "activation_wait_skipped",
1581
+ "activation_wait_engaged",
1582
+ "activation_wait_completed",
1583
+ "activation_wait_exhausted"
1584
+ ]);
1585
+ var CEAL_HOST_SERVICE_DIAGNOSTIC_FAILURE_KINDS = vocabulary([
1586
+ "malformed_line",
1587
+ "other",
1588
+ "payload_rejected",
1589
+ "read_error",
1590
+ "size_budget",
1591
+ "symlink"
1592
+ ]);
1440
1593
 
1441
1594
  // packages/ceal-client-protocol/src/client-result-materialization.ts
1442
1595
  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"]);
1596
+ var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "path", "sha256"]);
1597
+ 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
1598
 
1447
1599
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
1448
1600
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -1472,14 +1624,6 @@ var CEAL_GATEWAY_ANNOUNCEMENT_POLICY_NON_CLAIMS = vocabulary([
1472
1624
  "target_specific_scope_not_declared"
1473
1625
  ]);
1474
1626
 
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
1627
  // packages/ceal-client-protocol/src/gateway-scoped-identity-projection-validation.ts
1484
1628
  var PROJECTION_REVISION_KEYS = Object.freeze(["graph_revision", "subject_key_revision", "projection_revision"]);
1485
1629
 
@@ -1492,6 +1636,18 @@ var CEAL_SUPPORTED_GATEWAY_PROTOCOL_RANGE = Object.freeze({
1492
1636
  // packages/ceal-client-protocol/src/admin-projection-vocabulary.ts
1493
1637
  var ADMIN_PROJECTION_STATES = vocabulary(["ready", "empty", "partial", "unknown"]);
1494
1638
  var ADMIN_VIEW_KINDS = vocabulary(["request_detail", "resource_access_timeline", "weekly_usage"]);
1639
+ var ADMIN_RECORD_PROJECTION_KINDS = vocabulary([
1640
+ "request_list",
1641
+ "usage_series",
1642
+ "connector_health",
1643
+ "person_connections",
1644
+ "client_sessions",
1645
+ "knowledge_base",
1646
+ "change_history",
1647
+ "approval_queue",
1648
+ "access_group_list",
1649
+ "capability_catalogue"
1650
+ ]);
1495
1651
  var ADMIN_GAP_KINDS = vocabulary(["unknown", "unavailable", "partial"]);
1496
1652
  var ADMIN_UNAVAILABLE_REASONS = vocabulary([
1497
1653
  "not_recorded",
@@ -1515,7 +1671,11 @@ var ADMIN_SOURCE_OWNERS = vocabulary([
1515
1671
  "person",
1516
1672
  "resource",
1517
1673
  "prompt",
1518
- "usage"
1674
+ "usage",
1675
+ "connector",
1676
+ "session",
1677
+ "knowledge",
1678
+ "policy"
1519
1679
  ]);
1520
1680
  var ADMIN_COMPLETENESS_STATES = vocabulary(["complete", "partial", "unknown"]);
1521
1681
  var ADMIN_OPERATION_OUTCOMES = vocabulary(["completed", "failed", "denied", "cancelled", "unknown"]);
@@ -1552,11 +1712,7 @@ var CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION = "ceal.codex_invocation_context.v1"
1552
1712
  var CODEX_TRANSCRIPT_REGISTRATION_SCHEMA_VERSION = "ceal.codex_transcript_registration.v1";
1553
1713
  var CODEX_TRANSCRIPT_CURSOR_SCHEMA_VERSION = "ceal.codex_transcript_cursor.v1";
1554
1714
  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
- }
1715
+ var CODEX_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit"];
1560
1716
  var CodexHostAdapterError = class extends Error {
1561
1717
  name = "CodexHostAdapterError";
1562
1718
  code;
@@ -1571,12 +1727,12 @@ function isCodexHookEvent(value) {
1571
1727
 
1572
1728
  // host/codex/src/codex-decoder.ts
1573
1729
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1574
- var MAX_PAYLOAD_BYTES = 64 * 1024;
1730
+ var MAX_PAYLOAD_BYTES = 512 * 1024;
1575
1731
  var MAX_TEXT = 256;
1576
1732
  function decodeCodexHookPayload(event, raw) {
1577
- if (event !== "SessionStart") reject(`Codex hook event is not installed by this adapter (${refusalFact("event", event, "SessionStart")})`);
1578
1733
  const input = parsePayload(raw);
1579
- return decodeSession(input, event);
1734
+ if (event === "SessionStart") return decodeSession(input, event);
1735
+ return decodeUserPromptSubmit(input, event);
1580
1736
  }
1581
1737
  function observationRef(event, identity, value) {
1582
1738
  return cealHostObservationRef("codex", shortDigest({ event, identity, value }));
@@ -1628,6 +1784,20 @@ function decodeSession(input, event) {
1628
1784
  transcript_path: requiredText(input.transcript_path, "transcript_path", 4096)
1629
1785
  };
1630
1786
  }
1787
+ function decodeUserPromptSubmit(input, event) {
1788
+ exactKeys(input, ["cwd", "hook_event_name", "model", "permission_mode", "prompt", "session_id", "transcript_path", "turn_id"], []);
1789
+ validateHookEventName(input, event);
1790
+ const cwd = requiredText(input.cwd, "cwd", 4096);
1791
+ if (!isAbsolute(cwd) || cwd.includes("\0")) reject("Codex cwd is invalid");
1792
+ return {
1793
+ event,
1794
+ cwd: resolve(cwd),
1795
+ session_id: requiredText(input.session_id, "session_id", MAX_TEXT),
1796
+ transcript_path: requiredText(input.transcript_path, "transcript_path", 4096),
1797
+ turn_id: requiredText(input.turn_id, "turn_id", MAX_TEXT),
1798
+ prompt: requiredText(input.prompt, "prompt", MAX_PAYLOAD_BYTES)
1799
+ };
1800
+ }
1631
1801
  function parsePayload(raw) {
1632
1802
  try {
1633
1803
  const text = typeof raw === "string" ? raw : JSON.stringify(raw);
@@ -1670,9 +1840,9 @@ function reject(message) {
1670
1840
  }
1671
1841
 
1672
1842
  // 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";
1843
+ import { O_NOFOLLOW as O_NOFOLLOW2, O_RDONLY as O_RDONLY3 } from "node:constants";
1844
+ import { lstat as lstat2, mkdir as mkdir3, open as open3, readdir, rename as rename3, unlink as unlink2 } from "node:fs/promises";
1845
+ import { dirname, isAbsolute as isAbsolute2, join as join3 } from "node:path";
1676
1846
 
1677
1847
  // host/invocation-context.ts
1678
1848
  var HOST_INVOCATION_IDENTITY_KEYS = ["host_session_ref", "host_turn_ref", "host_source_ref"];
@@ -1686,17 +1856,32 @@ function hasHostInvocationIdentityKeys(value) {
1686
1856
  function hasHostInvocationContextKeys(value, optional = []) {
1687
1857
  return requiredKeys(value, HOST_INVOCATION_CONTEXT_REQUIRED_KEYS, optional);
1688
1858
  }
1859
+ async function readLatestSessionProjection(file, hostSourceRef, hostSessionRef, readProjection) {
1860
+ const context = await readProjection(file);
1861
+ if (context === null || context.identity.host_source_ref !== hostSourceRef || context.identity.host_session_ref !== hostSessionRef) return null;
1862
+ return context;
1863
+ }
1864
+ function isLiveSessionProjection(context, now) {
1865
+ return context !== null && Date.parse(context.expires_at) > now.getTime();
1866
+ }
1689
1867
  function invocationContextFromTurn(identity, promptRef, expiresAt, descriptor) {
1690
1868
  const context = {
1691
1869
  schema_version: descriptor.schema_version,
1692
1870
  identity,
1693
1871
  prompt_ref: promptRef,
1694
1872
  expires_at: expiresAt,
1873
+ ...descriptor.turn_generation_ref === void 0 ? {} : { turn_generation_ref: descriptor.turn_generation_ref },
1695
1874
  ...descriptor.working_directory === void 0 ? {} : { working_directory: descriptor.working_directory }
1696
1875
  };
1697
1876
  descriptor.validate(context);
1698
1877
  return Object.freeze(context);
1699
1878
  }
1879
+ function isHostInvocationTurnSelection(value) {
1880
+ 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]));
1881
+ }
1882
+ function invocationTurnSelectionMatches(context, selection) {
1883
+ 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;
1884
+ }
1700
1885
  function exactKeys2(value, keys) {
1701
1886
  const actual = Object.keys(value);
1702
1887
  return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key)) && actual.every((key) => keys.includes(key));
@@ -1706,145 +1891,908 @@ function requiredKeys(value, required, optional) {
1706
1891
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
1707
1892
  return actual.length >= required.length && actual.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && actual.every((key) => allowed.has(key));
1708
1893
  }
1894
+ function isRecord2(value) {
1895
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1896
+ }
1897
+ function safeRef(value) {
1898
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
1899
+ }
1709
1900
 
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 });
1901
+ // host/relay/src/producer-frame.ts
1902
+ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1903
+ var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1904
+ var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
1905
+ var SAFE_REF3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1906
+ var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
1907
+ var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
1908
+ var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
1909
+ function isHostProducerFrameKind(value) {
1910
+ return typeof value === "string" && FRAME_KINDS.has(value);
1713
1911
  }
1714
- function validateCodexHostInvocationContext(value) {
1715
- if (!isContextShape(value)) {
1716
- throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
1912
+ var HOST_PRODUCER_FRAME_ERROR_CODES = [
1913
+ "invalid_frame_encoding",
1914
+ "invalid_frame_length",
1915
+ "frame_truncated",
1916
+ "unsupported_frame_schema",
1917
+ "invalid_frame_shape",
1918
+ "invalid_producer_identity",
1919
+ "frame_too_large"
1920
+ ];
1921
+ var HostProducerFrameError = class extends Error {
1922
+ code;
1923
+ constructor(code, message = code) {
1924
+ super(message);
1925
+ this.code = code;
1717
1926
  }
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);
1927
+ };
1928
+ function encodeHostProducerFrame(frame) {
1929
+ validateFrame(frame);
1930
+ const json = Buffer.from(JSON.stringify(frame), "utf8");
1931
+ 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}`)}`);
1932
+ const result = Buffer.allocUnsafe(json.byteLength + HOST_PRODUCER_FRAME_LENGTH_BYTES);
1933
+ result.writeUInt32BE(json.byteLength, 0);
1934
+ json.copy(result, HOST_PRODUCER_FRAME_LENGTH_BYTES);
1935
+ return result;
1733
1936
  }
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.");
1937
+ function decodeHostProducerFrame(input) {
1938
+ 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}`)}`);
1939
+ const length = input.readUInt32BE(0);
1940
+ 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}`)}`);
1941
+ if (length === 0) throw new HostProducerFrameError("invalid_frame_length");
1942
+ 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");
1943
+ const bytes = input.subarray(HOST_PRODUCER_FRAME_LENGTH_BYTES);
1944
+ const text = new TextDecoder("utf-8", { fatal: true });
1945
+ let value;
1946
+ try {
1947
+ value = JSON.parse(text.decode(bytes));
1948
+ } catch (error) {
1949
+ if (error instanceof TypeError) throw new HostProducerFrameError("invalid_frame_encoding");
1950
+ throw new HostProducerFrameError("frame_truncated");
1737
1951
  }
1952
+ validateFrame(value);
1953
+ return value;
1738
1954
  }
1739
- function isContextShape(value) {
1740
- return isRecord2(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
1955
+ function isHostSafeRef(value) {
1956
+ return safeRef2(value);
1741
1957
  }
1742
- function validateContextReferences(value) {
1743
- if (!safeRef(value.prompt_ref) || !optionalSafeRef(value.request_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
1958
+ function validateFrame(value) {
1959
+ if (!record(value)) throw new HostProducerFrameError("invalid_frame_shape");
1960
+ 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)}`);
1961
+ if (!exactKeys3(value, ["schema_version", "producer_id", "producer_installation_ref", "producer_epoch", "sequence", "frame_kind", "occurred_at", "payload"])) throw new HostProducerFrameError("invalid_frame_shape");
1962
+ if (!PRODUCERS.has(String(value.producer_id)) || !safeRef2(value.producer_installation_ref)) throw new HostProducerFrameError("invalid_producer_identity");
1963
+ 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");
1964
+ validatePayload(value.frame_kind, value.payload);
1744
1965
  }
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}`)}).`);
1966
+ function validatePayload(kind, value) {
1967
+ const valid = kind === "session_started" ? validSession(value) : kind === "turn_started" ? validTurn(value) : kind === "user_input" ? validInput(value) : kind === "turn_terminal" ? validTerminal(value) : validStatus(value);
1968
+ if (!valid) throw new HostProducerFrameError("invalid_frame_shape");
1750
1969
  }
1751
- function optionalSafeRef(value) {
1752
- return value === void 0 || safeRef(value);
1970
+ function validSession(value) {
1971
+ 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
1972
  }
1754
- function optionalTimestamp(value) {
1755
- return value === void 0 || timestamp(value);
1973
+ function validTurn(value) {
1974
+ 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
1975
  }
1757
- function safeRef(value) {
1758
- return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
1976
+ function validInput(value) {
1977
+ 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
1978
  }
1760
- function timestamp(value) {
1761
- return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
1979
+ function validInputObservations(value) {
1980
+ return validObservations(value) && Array.isArray(value) && value.filter((item) => record(item) && item.observation_kind === "prompt").length === 1;
1762
1981
  }
1763
- function isRecord2(value) {
1764
- return value !== null && typeof value === "object" && !Array.isArray(value);
1982
+ function validInputOptionals(value) {
1983
+ return optionalRefs(value.local_turn_aliases) && (value.context_expires_at === void 0 || timestamp(value.context_expires_at));
1765
1984
  }
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);
1985
+ function validTerminal(value) {
1986
+ 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);
1987
+ }
1988
+ function validTerminalDisposition(state, reason) {
1989
+ return (state === "completed" || state === "aborted") && (reason === void 0 || state === "aborted" && safeRef2(reason));
1990
+ }
1991
+ function validStatus(value) {
1992
+ return exactOptional(value, ["status", "reason_code"], ["detail"]) && ["ready", "degraded", "stopping"].includes(String(value.status)) && safeRef2(value.reason_code) && optionalText(value.detail, 4096);
1993
+ }
1994
+ function optionalText(value, maxLength) {
1995
+ return value === void 0 || typeof value === "string" && value.length > 0 && value.length <= maxLength;
1996
+ }
1997
+ function optionalNonNegative(value) {
1998
+ return value === void 0 || typeof value === "number" && Number.isFinite(value) && value >= 0;
1999
+ }
2000
+ function optionalRefs(value) {
2001
+ return value === void 0 || Array.isArray(value) && value.length <= 16 && value.every(safeRef2);
2002
+ }
2003
+ function validObservations(value) {
2004
+ if (value === void 0) return true;
2005
+ if (!Array.isArray(value) || value.length > 32) return false;
2006
+ return value.every((item) => {
1817
2007
  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.");
2008
+ validateCealHostObservationDraft(item);
2009
+ return true;
2010
+ } catch {
2011
+ return false;
1821
2012
  }
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 {
2013
+ });
2014
+ }
2015
+ function jsonValue(value, depth = 0) {
2016
+ if (depth > 16) return false;
2017
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2018
+ if (typeof value === "number") return Number.isFinite(value);
2019
+ if (Array.isArray(value)) return value.length <= 256 && value.every((item) => jsonValue(item, depth + 1));
2020
+ return record(value) && Object.keys(value).length <= 256 && Object.entries(value).every(([key, item]) => key.length > 0 && key.length <= 128 && jsonValue(item, depth + 1));
2021
+ }
2022
+ function record(value) {
2023
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2024
+ }
2025
+ function safeRef2(value) {
2026
+ return typeof value === "string" && SAFE_REF3.test(value);
2027
+ }
2028
+ function positive(value) {
2029
+ return Number.isSafeInteger(value) && Number(value) > 0;
2030
+ }
2031
+ function timestamp(value) {
2032
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
2033
+ }
2034
+ function hostProducerFrameKind(value) {
2035
+ return isHostProducerFrameKind(value);
2036
+ }
2037
+ function exactKeys3(value, keys) {
2038
+ return JSON.stringify(Object.keys(value).sort()) === JSON.stringify([...keys].sort());
2039
+ }
2040
+ function exactOptional(value, required, optional) {
2041
+ const keys = Object.keys(value);
2042
+ return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2043
+ }
2044
+
2045
+ // host/relay/src/host-producer-core.ts
2046
+ import { createHash as createHash3 } from "node:crypto";
2047
+ import { O_NOFOLLOW, O_RDONLY as O_RDONLY2 } from "node:constants";
2048
+ import { mkdir as mkdir2, open as open2, readFile, rename as rename2, writeFile } from "node:fs/promises";
2049
+ import { join as join2 } from "node:path";
2050
+
2051
+ // host/relay/src/relay-ipc.ts
2052
+ import { createConnection, createServer } from "node:net";
2053
+
2054
+ // host/relay/src/durable-atomic-replacement.ts
2055
+ import { O_RDONLY } from "node:constants";
2056
+ import { lstat, mkdir, open, rename, unlink } from "node:fs/promises";
2057
+ var DEFAULT_PORT = {
2058
+ platform: process.platform,
2059
+ mkdir: (path, options) => mkdir(path, options),
2060
+ lstat: (path) => lstat(path),
2061
+ open_file: (path) => open(path, "wx", 384),
2062
+ rename,
2063
+ unlink,
2064
+ open_directory: (path) => open(path, O_RDONLY),
2065
+ unique_ref: () => `${process.pid}.${crypto.randomUUID()}`
2066
+ };
2067
+
2068
+ // host/relay/src/relay-request-binding-store.ts
2069
+ var MAX_STATE_BYTES = 8 * 1024 * 1024;
2070
+
2071
+ // host/relay/src/current-prompt-custody.ts
2072
+ var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2073
+
2074
+ // host/relay/src/relay-ipc.ts
2075
+ var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
2076
+ "schema_version",
2077
+ "producer_id",
2078
+ "producer_installation_ref",
2079
+ "local_session_ref",
2080
+ "local_turn_ref",
2081
+ "local_turn_aliases",
2082
+ "prompt_ref",
2083
+ "request_ref",
2084
+ "bound_at",
2085
+ "host_source_ref",
2086
+ "host_session_ref",
2087
+ "host_turn_ref",
2088
+ "host_input_ref"
2089
+ ]);
2090
+ var HOST_RELAY_IPC_RESPONSE_SCHEMA = "ceal.host_relay_admission.v1";
2091
+ var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2092
+ var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2093
+ var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2094
+ var HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES = 4096;
2095
+ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
2096
+ "context_stale",
2097
+ "context_expired",
2098
+ "host_source_refused",
2099
+ "host_credential_refused",
2100
+ "gateway_unavailable",
2101
+ "gateway_refused",
2102
+ "gateway_response_invalid",
2103
+ "gateway_rate_limited",
2104
+ "producer_frame_invalid",
2105
+ "deadline",
2106
+ "cancelled",
2107
+ "mint_failed",
2108
+ "relay_failed",
2109
+ "request_authority_unavailable",
2110
+ "request_missing",
2111
+ "authority_mismatch",
2112
+ "host_source_mismatch",
2113
+ "host_session_mismatch",
2114
+ "host_turn_mismatch",
2115
+ "host_input_mismatch",
2116
+ "host_prompt_mismatch"
2117
+ ]);
2118
+ var HOST_RELAY_DIRECT_WIRE_MINT_REASONS = vocabulary([
2119
+ "context_stale",
2120
+ "context_expired",
2121
+ "host_source_refused",
2122
+ "host_credential_refused",
2123
+ "gateway_unavailable",
2124
+ "gateway_rate_limited",
2125
+ "gateway_refused",
2126
+ "gateway_response_invalid",
2127
+ "producer_frame_invalid"
2128
+ ]);
2129
+ var HOST_RELAY_INVOCATION_MINT_OUTCOMES = vocabulary(["completed", "caller_cancelled", "deadline", "failed", "no_binding"]);
2130
+ var HOST_RELAY_EXCHANGE_FAILURES = vocabulary([
2131
+ "permission_denied",
2132
+ "socket_missing",
2133
+ "connection_refused",
2134
+ "closed_early",
2135
+ "response_invalid",
2136
+ "timed_out",
2137
+ "cancelled",
2138
+ "unavailable"
2139
+ ]);
2140
+ var HostRelayIpcError = class extends Error {
2141
+ code;
2142
+ /** Set only when the client-side socket exchange itself failed. */
2143
+ failure;
2144
+ constructor(code, message = code, failure) {
2145
+ super(message);
2146
+ this.code = code;
2147
+ this.failure = failure;
2148
+ }
2149
+ };
2150
+ function hostRelayExchangeFailure(error) {
2151
+ return error instanceof HostRelayIpcError ? error.failure : void 0;
2152
+ }
2153
+ function socketErrorFailure(error) {
2154
+ switch (errorCode(error)) {
2155
+ case "EACCES":
2156
+ case "EPERM":
2157
+ return "permission_denied";
2158
+ case "ENOENT":
2159
+ return "socket_missing";
2160
+ case "ECONNREFUSED":
2161
+ return "connection_refused";
2162
+ default:
2163
+ return "unavailable";
2164
+ }
2165
+ }
2166
+ var HostRelayIpcAdmissionPort = class {
2167
+ endpoint;
2168
+ timeout_ms;
2169
+ constructor(endpoint, timeoutMs = 5e3) {
2170
+ this.endpoint = endpoint;
2171
+ this.timeout_ms = timeoutMs;
2172
+ }
2173
+ async admit(frame) {
2174
+ const response2 = await submitHostProducerFrame(this.endpoint, frame, this.timeout_ms);
2175
+ if (!relayAdmissionCode(response2.code)) throw new HostRelayIpcError(response2.code);
2176
+ return { code: response2.code, admitted_through_sequence: response2.admitted_through_sequence, delivered_through_sequence: response2.delivered_through_sequence };
2177
+ }
2178
+ };
2179
+ var HostRelayCurrentPromptPort = class {
2180
+ endpoint;
2181
+ timeout_ms;
2182
+ constructor(endpoint, timeoutMs = 5e3) {
2183
+ this.endpoint = endpoint;
2184
+ this.timeout_ms = timeoutMs;
2185
+ }
2186
+ async register(input) {
2187
+ const request2 = { schema_version: HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA, ...input };
2188
+ const response2 = await exchange(this.endpoint, encodeLengthPrefixed(request2), this.timeout_ms, decodeCurrentPromptResponseBuffer);
2189
+ if (response2.status !== "registered") throw new HostRelayIpcError("relay_unavailable", response2.status);
2190
+ }
2191
+ };
2192
+ function submitHostProducerFrame(endpoint, frame, timeoutMs = 5e3) {
2193
+ return exchange(endpoint, encodeHostProducerFrame(frame), timeoutMs, decodeResponseBuffer);
2194
+ }
2195
+ function exchange(endpoint, encoded, timeoutMs, decode, signal) {
2196
+ return new Promise((resolve3, reject3) => {
2197
+ const socket = createConnection(endpoint);
2198
+ let buffer = Buffer.alloc(0);
2199
+ let settled = false;
2200
+ const aborted = () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC was cancelled.", "cancelled"));
2201
+ const finish = (error, response2) => {
2202
+ if (settled) return;
2203
+ settled = true;
2204
+ signal?.removeEventListener("abort", aborted);
2205
+ socket.destroy();
2206
+ if (error !== null) reject3(error);
2207
+ else if (response2 !== void 0) resolve3(response2);
2208
+ };
2209
+ if (timeoutMs !== void 0) socket.setTimeout(timeoutMs, () => finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC timed out.", "timed_out")));
2210
+ if (signal?.aborted === true) {
2211
+ aborted();
2212
+ return;
2213
+ }
2214
+ signal?.addEventListener("abort", aborted, { once: true });
2215
+ socket.once("error", (error) => {
2216
+ const failure = socketErrorFailure(error);
2217
+ finish(new HostRelayIpcError("relay_unavailable", `Host Relay IPC is unavailable: ${failure}.`, failure));
2218
+ });
2219
+ socket.once("connect", () => socket.write(encoded));
2220
+ socket.on("data", (chunk) => {
2221
+ try {
2222
+ buffer = Buffer.concat([buffer, Buffer.from(chunk)]);
2223
+ const decoded = decode(buffer);
2224
+ if (decoded !== null) finish(null, decoded);
2225
+ } catch (error) {
2226
+ finish(new HostRelayIpcError("relay_unavailable", error instanceof Error ? error.message : "Host Relay IPC response is invalid.", "response_invalid"));
2227
+ }
2228
+ });
2229
+ socket.once("end", () => {
2230
+ if (!settled) finish(new HostRelayIpcError("relay_unavailable", "Host Relay IPC closed without a response.", "closed_early"));
2231
+ });
2232
+ });
2233
+ }
2234
+ function decodeHostRelayIpcResponse(input) {
2235
+ 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}`)}.`);
2236
+ const length = input.readUInt32BE(0);
2237
+ 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}` }])}.`);
2238
+ let value;
2239
+ try {
2240
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2241
+ } catch {
2242
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
2243
+ }
2244
+ if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
2245
+ return value;
2246
+ }
2247
+ function relayAdmissionCode(value) {
2248
+ 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";
2249
+ }
2250
+ function validResponse(value) {
2251
+ 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;
2252
+ }
2253
+ function hostRelayIpcCode(value) {
2254
+ 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);
2255
+ }
2256
+ function nonnegative(value) {
2257
+ return Number.isSafeInteger(value) && Number(value) >= 0;
2258
+ }
2259
+ function record2(value) {
2260
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2261
+ }
2262
+ function decodeResponseBuffer(buffer) {
2263
+ if (buffer.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2264
+ const length = buffer.readUInt32BE(0);
2265
+ 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}`)}.`);
2266
+ if (buffer.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2267
+ 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}` }])}.`);
2268
+ return decodeHostRelayIpcResponse(buffer);
2269
+ }
2270
+ function decodeCurrentPromptResponseBuffer(buffer) {
2271
+ const value = decodeLengthPrefixedJson(buffer, HOST_RELAY_ADMISSION_RESPONSE_MAX_BYTES);
2272
+ if (value === null) return null;
2273
+ 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");
2274
+ return { schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status: value.status };
2275
+ }
2276
+ function decodeLengthPrefixedJson(input, maximum) {
2277
+ if (input.length < HOST_RELAY_IPC_LENGTH_BYTES) return null;
2278
+ const length = input.readUInt32BE(0);
2279
+ 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}`)}.`);
2280
+ if (input.length < length + HOST_RELAY_IPC_LENGTH_BYTES) return null;
2281
+ 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}` }])}.`);
2282
+ try {
2283
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
2284
+ } catch {
2285
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC message is invalid.");
2286
+ }
2287
+ }
2288
+ function encodeLengthPrefixed(value) {
2289
+ const body = Buffer.from(JSON.stringify(value), "utf8");
2290
+ const output = Buffer.allocUnsafe(body.length + HOST_RELAY_IPC_LENGTH_BYTES);
2291
+ output.writeUInt32BE(body.length, 0);
2292
+ body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
2293
+ return output;
2294
+ }
2295
+ function exactKeys4(value, required, optional = []) {
2296
+ const keys = Object.keys(value);
2297
+ return required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => required.includes(key) || optional.includes(key));
2298
+ }
2299
+ function errorCode(error) {
2300
+ return record2(error) && typeof error.code === "string" ? error.code : null;
2301
+ }
2302
+
2303
+ // host/relay/src/host-producer-core.ts
2304
+ var HOST_TRANSCRIPT_CURSOR_REASONS = vocabulary(["transcript_replaced", "transcript_truncated", "transcript_rewritten", "transcript_malformed"]);
2305
+ function isHostTranscriptCursorReason(value) {
2306
+ return typeof value === "string" && HOST_TRANSCRIPT_CURSOR_REASONS.some((reason) => reason === value);
2307
+ }
2308
+ var TRANSCRIPT_MISSING_REASON = "transcript_missing";
2309
+ var HOST_TRANSCRIPT_READ_CHUNK_BYTES = 256 * 1024;
2310
+ async function readTranscriptCompleteChunk(handle, offset, size) {
2311
+ const available = Math.max(0, size - offset);
2312
+ if (available === 0) return "empty";
2313
+ const chunks = [];
2314
+ let position = offset;
2315
+ let total = 0;
2316
+ let lastNewline = -1;
2317
+ while (position < size) {
2318
+ const buffer = Buffer.alloc(Math.min(HOST_TRANSCRIPT_READ_CHUNK_BYTES, size - position));
2319
+ const read = await handle.read(buffer, 0, buffer.length, position);
2320
+ if (read.bytesRead === 0) break;
2321
+ const chunk = buffer.subarray(0, read.bytesRead);
2322
+ chunks.push(chunk);
2323
+ const newline = chunk.lastIndexOf(10);
2324
+ if (newline >= 0) lastNewline = total + newline;
2325
+ total += chunk.length;
2326
+ position += chunk.length;
2327
+ if (lastNewline >= 0) break;
2328
+ }
2329
+ if (lastNewline < 0) return "partial";
2330
+ return Buffer.concat(chunks, total).subarray(0, lastNewline + 1);
2331
+ }
2332
+ async function readTranscriptAnchor(handle, offset, anchorBytes) {
2333
+ const start = Math.max(0, offset - anchorBytes);
2334
+ const anchor = Buffer.alloc(offset - start);
2335
+ if (anchor.length > 0) await handle.read(anchor, 0, anchor.length, start);
2336
+ return { start, sha256: transcriptSha256(anchor) };
2337
+ }
2338
+ async function transcriptAnchorMatches(handle, cursor) {
2339
+ const buffer = Buffer.alloc(cursor.offset - cursor.anchor_start);
2340
+ if (buffer.length > 0) await handle.read(buffer, 0, buffer.length, cursor.anchor_start);
2341
+ return transcriptSha256(buffer) === cursor.anchor_sha256;
2342
+ }
2343
+ function transcriptCursorIdentityReason(cursor, transcriptPath, device, inode) {
2344
+ if (cursor.device !== device || cursor.inode !== inode || cursor.transcript_path !== transcriptPath) return "transcript_replaced";
2345
+ return null;
2346
+ }
2347
+ async function transcriptCursorBoundsReason(handle, cursor, size) {
2348
+ if (size < cursor.offset) return "transcript_truncated";
2349
+ if (cursor.offset > 0 && !await transcriptAnchorMatches(handle, cursor)) return "transcript_rewritten";
2350
+ return null;
2351
+ }
2352
+ function transcriptSha256(value) {
2353
+ return createHash3("sha256").update(value).digest("hex");
2354
+ }
2355
+ function transcriptObjectSha256(value) {
2356
+ return createHash3("sha256").update(JSON.stringify(value), "utf8").digest("hex");
2357
+ }
2358
+ function isTranscriptRecord(value) {
2359
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2360
+ }
2361
+ function isMissingTranscriptError(error) {
2362
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
2363
+ }
2364
+ function transcriptTimestamp(now, fail) {
2365
+ const value = now();
2366
+ if (!Number.isFinite(value.getTime())) throw fail();
2367
+ return value.toISOString();
2368
+ }
2369
+ function transcriptExpiration(now, retentionMs, fail) {
2370
+ return new Date(Date.parse(transcriptTimestamp(now, fail)) + retentionMs).toISOString();
2371
+ }
2372
+ function createTranscriptWatcherBase(options, owner) {
2373
+ if (typeof options.outbox_dir !== "string" || options.outbox_dir.length === 0) throw owner.invalid_outbox();
2374
+ return {
2375
+ outboxRetentionMs: options.retention_ms ?? owner.default_retention_ms,
2376
+ now: options.now ?? (() => /* @__PURE__ */ new Date()),
2377
+ log: options.log ?? ((line) => {
2378
+ process.stderr.write(`${line}
2379
+ `);
2380
+ }),
2381
+ producerInstallationRef: options.producer_installation_ref
2382
+ };
2383
+ }
2384
+ async function scanTranscriptRegistrations(registrations, scanOne) {
2385
+ let records = 0;
2386
+ let enqueued = 0;
2387
+ let quarantined = 0;
2388
+ for (const registration of registrations) {
2389
+ const result = await scanOne(registration);
2390
+ records += result.records;
2391
+ enqueued += result.enqueued;
2392
+ if (result.quarantined) quarantined += 1;
2393
+ }
2394
+ return { registrations: registrations.length, records, enqueued, quarantined };
2395
+ }
2396
+ function formatRetiredTranscriptLog(producerLabel, transcriptPath) {
2397
+ return `${producerLabel} retired a transcript registration: transcript_path=${JSON.stringify(transcriptPath)}, reason=${TRANSCRIPT_MISSING_REASON}.`;
2398
+ }
2399
+ var HostTranscriptWatcher = class {
2400
+ outboxRetentionMs;
2401
+ now;
2402
+ log;
2403
+ producerInstallationRef;
2404
+ clockFailure;
2405
+ constructor(options, owner) {
2406
+ const base = createTranscriptWatcherBase(options, owner);
2407
+ this.outboxRetentionMs = base.outboxRetentionMs;
2408
+ this.now = base.now;
2409
+ this.log = base.log;
2410
+ this.producerInstallationRef = base.producerInstallationRef;
2411
+ this.clockFailure = owner.clock_failure;
2412
+ }
2413
+ async scanOnce() {
2414
+ return scanTranscriptRegistrations(await this.listRegistrations(), (registration) => this.scanRegistration(registration));
2415
+ }
2416
+ async scanRegistration(registration) {
2417
+ return this.openTranscript(registration, (handle) => this.scanOpened(handle, registration), {
2418
+ missing: () => this.retireMissing(registration),
2419
+ failed: (handle, error) => this.scanFailed(handle, registration, error)
2420
+ });
2421
+ }
2422
+ async openTranscript(registration, scan, handlers) {
2423
+ let handle;
2424
+ try {
2425
+ handle = await open2(this.transcriptPathOf(registration), O_RDONLY2 | O_NOFOLLOW);
2426
+ return await scan(handle);
2427
+ } catch (error) {
2428
+ if (handle === void 0 && isMissingTranscriptError(error)) return handlers.missing();
2429
+ if (hostRelayExchangeFailure(error) !== void 0) throw error;
2430
+ return handlers.failed(handle, error);
2431
+ } finally {
2432
+ await handle?.close();
2433
+ }
2434
+ }
2435
+ /**
2436
+ * A transcript the Host deleted never comes back, so retrying its
2437
+ * registration once per reconcile interval is a failure with no end.
2438
+ * Retire it at the scan that finds it missing and say so once. Only
2439
+ * ENOENT means gone; a permission or busy failure is about this moment,
2440
+ * not about the file, and keeps the registration for the next scan.
2441
+ */
2442
+ async retireMissingTranscript(transcriptPath, producerLabel, retire) {
2443
+ await retire();
2444
+ this.log(formatRetiredTranscriptLog(producerLabel, transcriptPath));
2445
+ return { records: 0, enqueued: 0, quarantined: false };
2446
+ }
2447
+ stamp() {
2448
+ return transcriptTimestamp(this.now, this.clockFailure);
2449
+ }
2450
+ expire(retentionMs) {
2451
+ return transcriptExpiration(this.now, retentionMs, this.clockFailure);
2452
+ }
2453
+ sha(value) {
2454
+ return transcriptSha256(value);
2455
+ }
2456
+ objectSha(value) {
2457
+ return transcriptObjectSha256(value);
2458
+ }
2459
+ isRecord(value) {
2460
+ return isTranscriptRecord(value);
2461
+ }
2462
+ readChunk(handle, offset, size) {
2463
+ return readTranscriptCompleteChunk(handle, offset, size);
2464
+ }
2465
+ readAnchor(handle, offset, anchorBytes) {
2466
+ return readTranscriptAnchor(handle, offset, anchorBytes);
2467
+ }
2468
+ cursorIdentityReason(cursor, transcriptPath, device, inode) {
2469
+ return transcriptCursorIdentityReason(cursor, transcriptPath, device, inode);
2470
+ }
2471
+ cursorBoundsReason(handle, cursor, size) {
2472
+ return transcriptCursorBoundsReason(handle, cursor, size);
2473
+ }
2474
+ };
2475
+ var HOST_PRODUCER_STATE_IDENTITY = {
2476
+ codex: { file_name: "codex-producer-state.json", schema: "ceal.codex_producer_state.v1" },
2477
+ claude: { file_name: "claude-producer-state.json", schema: "ceal.claude_producer_state.v1" }
2478
+ };
2479
+ var HostProducerDrainCore = class {
2480
+ host;
2481
+ relay;
2482
+ statePath;
2483
+ stateSchema;
2484
+ installationRef;
2485
+ epoch;
2486
+ now;
2487
+ tail = Promise.resolve();
2488
+ constructor(host, runtime) {
2489
+ if (!isHostSafeRef(runtime.producer_installation_ref)) throw host.fail("configuration", `${host.producer_label} producer installation identity is invalid.`);
2490
+ const epoch = runtime.producer_epoch ?? 1;
2491
+ if (!Number.isSafeInteger(epoch) || epoch <= 0) throw host.fail("configuration", `${host.producer_label} producer epoch is invalid.`);
2492
+ this.host = host;
2493
+ this.relay = runtime.relay;
2494
+ this.statePath = join2(host.outbox_directory, HOST_PRODUCER_STATE_IDENTITY[host.producer_id].file_name);
2495
+ this.stateSchema = HOST_PRODUCER_STATE_IDENTITY[host.producer_id].schema;
2496
+ this.installationRef = runtime.producer_installation_ref;
2497
+ this.epoch = epoch;
2498
+ this.now = runtime.now ?? (() => /* @__PURE__ */ new Date());
2499
+ }
2500
+ drainOutbox() {
2501
+ const run = this.tail.then(() => this.drainLocked());
2502
+ this.tail = run.then(() => void 0, () => void 0);
2503
+ return run;
2504
+ }
2505
+ async drainLocked() {
2506
+ const read = await this.host.listEnvelopes();
2507
+ let admitted = 0;
2508
+ let expired = 0;
2509
+ let retained = 0;
2510
+ for (const envelope of read.entries) {
2511
+ const reserved = await this.hasReservation(this.host.submissionRefOf(envelope));
2512
+ if (!reserved && Date.parse(this.host.expiresAtOf(envelope)) <= this.now().getTime()) {
2513
+ await this.host.removeEnvelope(envelope);
2514
+ expired += 1;
2515
+ continue;
2516
+ }
2517
+ const frames = await this.reserve(envelope);
2518
+ let complete = true;
2519
+ for (const frame of frames) {
2520
+ const outcome = await this.relay.admit(frame);
2521
+ if (outcome.code !== "admitted" && outcome.code !== "already_admitted") {
2522
+ complete = false;
2523
+ break;
2524
+ }
2525
+ }
2526
+ if (!complete) {
2527
+ retained += 1;
2528
+ break;
2529
+ }
2530
+ await this.host.removeEnvelope(envelope);
2531
+ await this.release(this.host.submissionRefOf(envelope));
2532
+ admitted += 1;
2533
+ }
2534
+ return { admitted, retained: retained + Math.max(0, read.entries.length - admitted - expired - retained), expired, malformed: read.malformed };
2535
+ }
2536
+ async hasReservation(submissionRef) {
2537
+ return (await this.readState()).pending[submissionRef] !== void 0;
2538
+ }
2539
+ async reserve(envelope) {
2540
+ const state = await this.readState();
2541
+ const submissionRef = this.host.submissionRefOf(envelope);
2542
+ const existing = state.pending[submissionRef];
2543
+ if (existing !== void 0) return existing;
2544
+ const drafts = await this.host.mapEnvelope(envelope);
2545
+ const frames = drafts.map((draft, offset) => ({
2546
+ schema_version: "ceal.host_producer_frame.v1",
2547
+ producer_id: this.host.producer_id,
2548
+ producer_installation_ref: this.installationRef,
2549
+ producer_epoch: this.epoch,
2550
+ sequence: state.next_sequence + offset,
2551
+ frame_kind: draft.frame_kind,
2552
+ occurred_at: this.host.createdAtOf(envelope),
2553
+ payload: draft.payload
2554
+ }));
2555
+ await this.writeState({ ...state, next_sequence: state.next_sequence + frames.length, pending: { ...state.pending, [submissionRef]: frames } });
2556
+ return frames;
2557
+ }
2558
+ async release(submissionRef) {
2559
+ const state = await this.readState();
2560
+ if (state.pending[submissionRef] === void 0) return;
2561
+ const pending = { ...state.pending };
2562
+ delete pending[submissionRef];
2563
+ await this.writeState({ ...state, pending });
2564
+ }
2565
+ async readState() {
2566
+ try {
2567
+ const value = JSON.parse(await readFile(this.statePath, "utf8"));
2568
+ return this.decodeState(value);
2569
+ } catch (error) {
2570
+ if (errorCode2(error) !== "ENOENT") throw error;
2571
+ return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: 1, pending: {} };
2572
+ }
2573
+ }
2574
+ async writeState(state) {
2575
+ await mkdir2(this.host.outbox_directory, { recursive: true, mode: 448 });
2576
+ const temporary = `${this.statePath}.${process.pid}.new`;
2577
+ await writeFile(temporary, JSON.stringify(state), { mode: 384 });
2578
+ await rename2(temporary, this.statePath);
2579
+ }
2580
+ decodeState(value) {
2581
+ const label = this.host.producer_label;
2582
+ const fail = (code, message) => this.host.fail(code, message);
2583
+ if (!isDrainStateHeader(value, this.stateSchema, this.installationRef)) {
2584
+ throw fail("storage", `${label} producer state header is malformed or belongs to another installation (${refusalFacts([
2585
+ { name: "schema_version", value: isTranscriptRecord(value) ? value.schema_version : void 0, expected: this.stateSchema },
2586
+ { name: "producer_installation_ref", value: isTranscriptRecord(value) ? value.producer_installation_ref : void 0, expected: this.installationRef }
2587
+ ])}).`);
2588
+ }
2589
+ 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}`)}).`);
2590
+ const pending = {};
2591
+ const storedEpoch = Number(value.producer_epoch);
2592
+ for (const [submissionRef, frames] of Object.entries(value.pending)) {
2593
+ if (!isHostSafeRef(submissionRef) || !Array.isArray(frames) || frames.length === 0) throw fail("storage", `${label} producer pending reservation is malformed.`);
2594
+ pending[submissionRef] = frames.map((frame) => this.decodeStoredFrame(frame, storedEpoch));
2595
+ }
2596
+ return { schema_version: this.stateSchema, producer_installation_ref: this.installationRef, producer_epoch: this.epoch, next_sequence: Number(value.next_sequence), pending };
2597
+ }
2598
+ decodeStoredFrame(value, storedEpoch) {
2599
+ const label = this.host.producer_label;
2600
+ const json = Buffer.from(JSON.stringify(value), "utf8");
2601
+ const encoded = Buffer.allocUnsafe(json.length + 4);
2602
+ encoded.writeUInt32BE(json.length, 0);
2603
+ json.copy(encoded, 4);
2604
+ const frame = decodeHostProducerFrame(encoded);
2605
+ 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([
2606
+ { name: "producer_id", value: frame.producer_id, expected: this.host.producer_id },
2607
+ { name: "producer_installation_ref", value: frame.producer_installation_ref, expected: this.installationRef },
2608
+ { name: "producer_epoch", value: frame.producer_epoch, expected: `at most ${storedEpoch}` }
2609
+ ])}).`);
2610
+ return frame;
2611
+ }
2612
+ };
2613
+ function isDrainStateHeader(value, schema, installationRef) {
2614
+ 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);
2615
+ }
2616
+ function errorCode2(error) {
2617
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : null;
2618
+ }
2619
+
2620
+ // host/relay/src/relay-quarantine-store.ts
2621
+ var RELAY_QUARANTINE_MAX_BYTES = 16 * 1024 * 1024;
2622
+ var RELAY_QUARANTINE_FRAME_REASONS = ["frame_identity_conflict", "sequence_gap", "gateway_refused"];
2623
+ var RELAY_QUARANTINE_REASONS = [...RELAY_QUARANTINE_FRAME_REASONS, ...HOST_PRODUCER_FRAME_ERROR_CODES];
2624
+
2625
+ // host/relay/src/relay-admission-store.ts
2626
+ var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
2627
+ var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
2628
+ var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
2629
+
2630
+ // host/relay/src/relay-gateway-bridge.ts
2631
+ var HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS = ["created", "adopted", "replayed", "approval_approved", "approval_denied", "approval_replayed"];
2632
+ function isHostGatewayAcknowledgementDisposition(value) {
2633
+ return typeof value === "string" && HOST_GATEWAY_ACKNOWLEDGEMENT_DISPOSITIONS.some((disposition) => disposition === value);
2634
+ }
2635
+
2636
+ // host/codex/src/codex-invocation-context.ts
2637
+ function codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef) {
2638
+ return invocationContextFromTurn(identity, promptRef, expiresAt, { schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION, validate: validateCodexHostInvocationContext, turn_generation_ref: turnGenerationRef });
2639
+ }
2640
+ function validateCodexHostInvocationContext(value) {
2641
+ if (!isContextShape(value)) {
2642
+ throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2643
+ }
2644
+ validateIdentity(value.identity);
2645
+ validateContextReferences(value);
2646
+ validateContextTimes(value);
2647
+ }
2648
+ function invocationContextFromBinding(binding, turnGenerationRef) {
2649
+ const context = {
2650
+ schema_version: CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION,
2651
+ identity: binding.identity,
2652
+ prompt_ref: binding.prompt_ref,
2653
+ request_ref: binding.request_ref,
2654
+ bound_at: binding.bound_at,
2655
+ expires_at: binding.expires_at,
2656
+ ...turnGenerationRef === void 0 ? {} : { turn_generation_ref: turnGenerationRef }
2657
+ };
2658
+ validateCodexHostInvocationContext(context);
2659
+ return Object.freeze(context);
2660
+ }
2661
+ function validateIdentity(value) {
2662
+ if (!isRecord3(value) || !hasHostInvocationIdentityKeys(value) || ![value.host_session_ref, value.host_turn_ref, value.host_source_ref].every(safeRef3)) {
2663
+ throw new CodexHostAdapterError("storage", "Codex Host invocation identity is malformed.");
2664
+ }
2665
+ }
2666
+ function isContextShape(value) {
2667
+ return isRecord3(value) && hasHostInvocationContextKeys(value, ["request_ref", "bound_at", "turn_generation_ref"]) && value.schema_version === CODEX_INVOCATION_CONTEXT_SCHEMA_VERSION;
2668
+ }
2669
+ function validateContextReferences(value) {
2670
+ if (!safeRef3(value.prompt_ref) || !optionalSafeRef(value.request_ref) || !optionalSafeRef(value.turn_generation_ref)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2671
+ }
2672
+ function validateContextTimes(value) {
2673
+ const expiresAt = value.expires_at;
2674
+ const boundAt = value.bound_at;
2675
+ if (!timestamp2(expiresAt) || !optionalTimestamp(boundAt)) throw new CodexHostAdapterError("storage", "Codex Host invocation context is malformed.");
2676
+ 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}`)}).`);
2677
+ }
2678
+ function optionalSafeRef(value) {
2679
+ return value === void 0 || safeRef3(value);
2680
+ }
2681
+ function optionalTimestamp(value) {
2682
+ return value === void 0 || timestamp2(value);
2683
+ }
2684
+ function safeRef3(value) {
2685
+ return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2686
+ }
2687
+ function timestamp2(value) {
2688
+ return typeof value === "string" && value.length <= 64 && Number.isFinite(Date.parse(value));
2689
+ }
2690
+ function isRecord3(value) {
2691
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2692
+ }
2693
+
2694
+ // host/codex/src/codex-outbox.ts
2695
+ var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2696
+ var CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS = 4096;
2697
+ var CodexOutboxStore = class {
2698
+ directory;
2699
+ entriesDirectory;
2700
+ bindingsDirectory;
2701
+ sessionsDirectory;
2702
+ activeContextsDirectory;
2703
+ turnSelectionsDirectory;
2704
+ registrationsDirectory;
2705
+ cursorsDirectory;
2706
+ constructor(directory) {
2707
+ if (typeof directory !== "string" || directory.length === 0) throw new CodexHostAdapterError("configuration", "Codex outbox directory is required.");
2708
+ this.directory = directory;
2709
+ this.entriesDirectory = join3(directory, "entries");
2710
+ this.bindingsDirectory = join3(directory, "bindings");
2711
+ this.sessionsDirectory = join3(directory, "sessions");
2712
+ this.activeContextsDirectory = join3(directory, "active-contexts");
2713
+ this.turnSelectionsDirectory = join3(directory, "turn-selections");
2714
+ this.registrationsDirectory = join3(directory, "transcript-registrations");
2715
+ this.cursorsDirectory = join3(directory, "transcript-cursors");
2716
+ }
2717
+ async prepare() {
2718
+ for (const path of [this.directory, this.entriesDirectory, this.bindingsDirectory, this.sessionsDirectory, this.activeContextsDirectory, this.turnSelectionsDirectory, this.registrationsDirectory, this.cursorsDirectory]) {
2719
+ await ensurePrivateOwnerDirectory(path);
2720
+ }
2721
+ }
2722
+ async put(entry) {
2723
+ validateEnvelope(entry);
2724
+ await this.prepare();
2725
+ await writeAtomicJson(this.entryPath(entry.submission_ref), entry);
2726
+ }
2727
+ async list() {
2728
+ await this.prepare();
2729
+ const entries = [];
2730
+ let malformed = 0;
2731
+ for (const name of await readdir(this.entriesDirectory)) {
2732
+ if (!name.endsWith(".json")) continue;
2733
+ try {
2734
+ const value = JSON.parse(await readPrivateFile(join3(this.entriesDirectory, name)));
2735
+ validateEnvelope(value);
2736
+ entries.push(value);
2737
+ } catch {
2738
+ malformed += 1;
2739
+ }
2740
+ }
2741
+ entries.sort((left, right) => left.created_at.localeCompare(right.created_at));
2742
+ return { entries, malformed };
2743
+ }
2744
+ async remove(entry) {
2745
+ validateEnvelope(entry);
2746
+ try {
2747
+ await unlink2(this.entryPath(entry.submission_ref));
2748
+ } catch (error) {
2749
+ if (!isNotFound(error)) throw storageError("Unable to remove the Codex outbox entry.");
2750
+ }
2751
+ }
2752
+ async writeBinding(binding) {
2753
+ validateBinding(binding);
2754
+ await this.prepare();
2755
+ await writeAtomicJson(this.bindingPath(binding.identity), binding);
2756
+ }
2757
+ /**
2758
+ * Select the exact Host turn that model-reachable commands may use. A new
2759
+ * prompt replaces this projection, so it cannot inherit the prior turn's
2760
+ * Request by session alone.
2761
+ */
2762
+ async activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef) {
2763
+ const context = codexInvocationContextFromTurn(identity, promptRef, expiresAt, turnGenerationRef);
2764
+ await this.prepare();
2765
+ const path = this.activeContextPath(identity);
2766
+ try {
1838
2767
  await writeAtomicJson(path, context);
1839
2768
  } catch (error) {
1840
2769
  try {
1841
- await unlink(path);
2770
+ await unlink2(path);
1842
2771
  } catch (unlinkError) {
1843
2772
  if (!isNotFound(unlinkError)) throw storageError("Unable to clear a failed Codex Host context replacement.");
1844
2773
  }
1845
2774
  throw error;
1846
2775
  }
1847
2776
  }
2777
+ async writeInvocationTurnSelection(selection) {
2778
+ if (!isHostInvocationTurnSelection(selection)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection is invalid.");
2779
+ await this.prepare();
2780
+ await writeAtomicJson(this.turnSelectionPath(selection.host_source_ref, selection.host_session_ref), selection);
2781
+ }
2782
+ async readInvocationTurnSelection(hostSourceRef, hostSessionRef) {
2783
+ if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host turn selection identity is invalid.");
2784
+ await this.prepare();
2785
+ return readOptionalJson(this.turnSelectionPath(hostSourceRef, hostSessionRef), validateTurnSelection);
2786
+ }
2787
+ async attachInvocationTurnGeneration(identity, promptRef, turnGenerationRef) {
2788
+ const selection = await this.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
2789
+ if (selection === null || selection.prompt_ref !== promptRef || selection.turn_generation_ref !== turnGenerationRef) return false;
2790
+ const path = this.activeContextPath(identity);
2791
+ const active = await readOptionalJson(path, validateCodexHostInvocationContext);
2792
+ if (active === null || active.prompt_ref !== promptRef || !sameIdentity(active.identity, identity)) return false;
2793
+ await writeAtomicJson(path, { ...active, turn_generation_ref: turnGenerationRef });
2794
+ return true;
2795
+ }
1848
2796
  /**
1849
2797
  * Publish a Request reference only while the acknowledged binding is still
1850
2798
  * the active turn. A delayed relay response therefore cannot overwrite a
@@ -1854,17 +2802,25 @@ var CodexOutboxStore = class {
1854
2802
  validateBinding(binding);
1855
2803
  const active = await this.readInvocationContext(binding.identity.host_source_ref, binding.identity.host_session_ref, now);
1856
2804
  if (active === null || !sameIdentity(active.identity, binding.identity)) return false;
1857
- await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding));
2805
+ await writeAtomicJson(this.activeContextPath(binding.identity), invocationContextFromBinding(binding, active.turn_generation_ref));
1858
2806
  return true;
1859
2807
  }
1860
- /** Return only the active session projection; never fall back to another turn. */
2808
+ /** Return only the live session projection; never fall back to another turn. */
1861
2809
  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
2810
  if (!(now instanceof Date) || !Number.isFinite(now.getTime())) throw new CodexHostAdapterError("invalid_input", "Codex Host context clock is invalid.");
2811
+ const context = await this.readRawInvocationContext(hostSourceRef, hostSessionRef);
2812
+ return isLiveSessionProjection(context, now) && invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
2813
+ }
2814
+ /**
2815
+ * The latest Codex session projection even when past expiry, so the
2816
+ * invocation authenticator can report an expired context distinctly from
2817
+ * a missing one. Every other caller keeps the fail-closed read above.
2818
+ */
2819
+ async readRawInvocationContext(hostSourceRef, hostSessionRef) {
2820
+ if (!SAFE_REF4.test(hostSourceRef) || !SAFE_REF4.test(hostSessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex Host session identity is invalid.");
1864
2821
  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;
2822
+ const context = await readLatestSessionProjection(this.activeContextPath({ host_source_ref: hostSourceRef, host_session_ref: hostSessionRef }), hostSourceRef, hostSessionRef, (file) => readOptionalJson(file, validateCodexHostInvocationContext));
2823
+ return invocationTurnSelectionMatches(context, await this.readInvocationTurnSelection(hostSourceRef, hostSessionRef)) ? context : null;
1868
2824
  }
1869
2825
  /** Clear the projection only if the caller still owns its exact active turn. */
1870
2826
  async clearInvocationContext(identity, now = /* @__PURE__ */ new Date()) {
@@ -1872,7 +2828,7 @@ var CodexOutboxStore = class {
1872
2828
  const active = await this.readInvocationContext(identity.host_source_ref, identity.host_session_ref, now);
1873
2829
  if (active === null || !sameIdentity(active.identity, identity)) return false;
1874
2830
  try {
1875
- await unlink(this.activeContextPath(identity));
2831
+ await unlink2(this.activeContextPath(identity));
1876
2832
  } catch (error) {
1877
2833
  if (!isNotFound(error)) throw storageError("Unable to clear the Codex Host invocation context.");
1878
2834
  }
@@ -1890,7 +2846,7 @@ var CodexOutboxStore = class {
1890
2846
  }
1891
2847
  async readSession(sourceRef, sessionRef) {
1892
2848
  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.");
2849
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw new CodexHostAdapterError("invalid_input", "Codex session identity is invalid.");
1894
2850
  await this.prepare();
1895
2851
  return readOptionalJson(this.sessionPath(identity.host_source_ref, identity.host_session_ref), validateSession);
1896
2852
  }
@@ -1923,7 +2879,7 @@ var CodexOutboxStore = class {
1923
2879
  for (const name of await readdir(this.registrationsDirectory)) {
1924
2880
  if (!name.endsWith(".json")) continue;
1925
2881
  try {
1926
- const value = JSON.parse(await readPrivateFile(join2(this.registrationsDirectory, name)));
2882
+ const value = JSON.parse(await readPrivateFile(join3(this.registrationsDirectory, name)));
1927
2883
  validateRegistration(value);
1928
2884
  registrations.push(value);
1929
2885
  } catch {
@@ -1942,7 +2898,7 @@ var CodexOutboxStore = class {
1942
2898
  await writeAtomicJson(this.cursorPath(cursor.host_source_ref, cursor.host_session_ref), cursor);
1943
2899
  }
1944
2900
  async findByAlias(sourceRef, sessionRef, alias) {
1945
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef) || !SAFE_REF3.test(alias)) return null;
2901
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef) || !SAFE_REF4.test(alias)) return null;
1946
2902
  const read = await this.list();
1947
2903
  const envelope = findEnvelopeByAlias(read.entries, sourceRef, sessionRef, alias);
1948
2904
  if (envelope !== null) return envelopeMatch(envelope);
@@ -1952,7 +2908,7 @@ var CodexOutboxStore = class {
1952
2908
  return null;
1953
2909
  }
1954
2910
  async hasPriorTurn(sourceRef, sessionRef) {
1955
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) return false;
2911
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) return false;
1956
2912
  const read = await this.list();
1957
2913
  if (read.entries.some((entry) => entry.identity.host_source_ref === sourceRef && entry.identity.host_session_ref === sessionRef)) return true;
1958
2914
  await this.prepare();
@@ -1964,34 +2920,37 @@ var CodexOutboxStore = class {
1964
2920
  return false;
1965
2921
  }
1966
2922
  entryPath(submissionRef) {
1967
- if (!SAFE_REF3.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
1968
- return join2(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
2923
+ if (!SAFE_REF4.test(submissionRef)) throw storageError("Codex submission identity is malformed.");
2924
+ return join3(this.entriesDirectory, `${cealRequestSha256(submissionRef)}.json`);
1969
2925
  }
1970
2926
  bindingPath(identity) {
1971
- return join2(this.bindingsDirectory, `${identityKey(identity)}.json`);
2927
+ return join3(this.bindingsDirectory, `${identityKey(identity)}.json`);
1972
2928
  }
1973
2929
  sessionPath(sourceRef, sessionRef) {
1974
- return join2(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
2930
+ return join3(this.sessionsDirectory, `${identityKey({ host_source_ref: sourceRef, host_session_ref: sessionRef, host_turn_ref: "session" })}.json`);
1975
2931
  }
1976
2932
  activeContextPath(identity) {
1977
- return join2(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2933
+ return join3(this.activeContextsDirectory, `${invocationContextKey(identity)}.json`);
2934
+ }
2935
+ turnSelectionPath(sourceRef, sessionRef) {
2936
+ return join3(this.turnSelectionsDirectory, `${invocationContextKey({ host_source_ref: sourceRef, host_session_ref: sessionRef })}.json`);
1978
2937
  }
1979
2938
  registrationPath(sourceRef, sessionRef) {
1980
- return join2(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
2939
+ return join3(this.registrationsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
1981
2940
  }
1982
2941
  cursorPath(sourceRef, sessionRef) {
1983
- return join2(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
2942
+ return join3(this.cursorsDirectory, `${sessionStateKey(sourceRef, sessionRef)}.json`);
1984
2943
  }
1985
2944
  };
1986
2945
  async function removeOwnerState(path, what) {
1987
2946
  try {
1988
- await unlink(path);
2947
+ await unlink2(path);
1989
2948
  } catch (error) {
1990
2949
  if (!isNotFound(error)) throw storageError(`Unable to retire the Codex transcript ${what}.`);
1991
2950
  }
1992
2951
  }
1993
2952
  function sessionStateKey(sourceRef, sessionRef) {
1994
- if (!SAFE_REF3.test(sourceRef) || !SAFE_REF3.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
2953
+ if (!SAFE_REF4.test(sourceRef) || !SAFE_REF4.test(sessionRef)) throw storageError("Codex transcript session identity is malformed.");
1995
2954
  return cealRequestSha256({ host_source_ref: sourceRef, host_session_ref: sessionRef });
1996
2955
  }
1997
2956
  function envelopeMatch(envelope) {
@@ -2018,7 +2977,7 @@ async function findBindingByAlias(directory, sourceRef, sessionRef, alias) {
2018
2977
  }
2019
2978
  async function readBindingCandidate(directory, name) {
2020
2979
  try {
2021
- const value = JSON.parse(await readPrivateFile(join2(directory, name)));
2980
+ const value = JSON.parse(await readPrivateFile(join3(directory, name)));
2022
2981
  validateBinding(value);
2023
2982
  return value;
2024
2983
  } catch {
@@ -2037,18 +2996,18 @@ async function writeAtomicJson(path, value) {
2037
2996
  if (text === void 0) throw storageError("Codex owner state cannot be serialized.");
2038
2997
  const temp = `${path}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
2039
2998
  try {
2040
- const handle = await open(temp, "wx", 384);
2999
+ const handle = await open3(temp, "wx", 384);
2041
3000
  try {
2042
3001
  await handle.writeFile(text, "utf8");
2043
3002
  await handle.sync();
2044
3003
  } finally {
2045
3004
  await handle.close();
2046
3005
  }
2047
- await rename(temp, path);
3006
+ await rename3(temp, path);
2048
3007
  await syncDirectory(dirname(path));
2049
3008
  } catch (error) {
2050
3009
  try {
2051
- await unlink(temp);
3010
+ await unlink2(temp);
2052
3011
  } catch {
2053
3012
  }
2054
3013
  if (error instanceof CodexHostAdapterError) throw error;
@@ -2057,7 +3016,7 @@ async function writeAtomicJson(path, value) {
2057
3016
  }
2058
3017
  async function syncDirectory(path) {
2059
3018
  try {
2060
- const handle = await open(path, "r");
3019
+ const handle = await open3(path, "r");
2061
3020
  try {
2062
3021
  await handle.sync();
2063
3022
  } finally {
@@ -2079,12 +3038,12 @@ async function readOptionalJson(path, validate) {
2079
3038
  }
2080
3039
  async function ensurePrivateOwnerDirectory(path) {
2081
3040
  try {
2082
- await lstat(path);
3041
+ await lstat2(path);
2083
3042
  } catch (error) {
2084
3043
  if (!isNotFound(error)) throw storageError("Codex owner state directory is unavailable.");
2085
- await mkdir(path, { recursive: true, mode: 448 });
3044
+ await mkdir3(path, { recursive: true, mode: 448 });
2086
3045
  }
2087
- const stats = await lstat(path);
3046
+ const stats = await lstat2(path);
2088
3047
  const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2089
3048
  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
3049
  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 +3052,7 @@ async function ensurePrivateOwnerDirectory(path) {
2093
3052
  async function readPrivateFile(path) {
2094
3053
  let handle;
2095
3054
  try {
2096
- handle = await open(path, O_RDONLY | O_NOFOLLOW);
3055
+ handle = await open3(path, O_RDONLY3 | O_NOFOLLOW2);
2097
3056
  const stats = await handle.stat();
2098
3057
  const uid = typeof process.geteuid === "function" ? process.geteuid() : stats.uid;
2099
3058
  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 +3064,7 @@ async function readPrivateFile(path) {
2105
3064
  }
2106
3065
  }
2107
3066
  function validateEnvelope(value) {
2108
- if (!isRecord3(value)) throw storageError("Codex outbox entry is malformed.");
3067
+ if (!isRecord4(value)) throw storageError("Codex outbox entry is malformed.");
2109
3068
  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
3069
  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
3070
  validateIdentity2(value.identity);
@@ -2114,22 +3073,22 @@ function validateEnvelope(value) {
2114
3073
  validateEnvelopeTimestamps(value);
2115
3074
  }
2116
3075
  function validateEnvelopeReferences(value) {
2117
- if (!SAFE_REF3.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
3076
+ if (!SAFE_REF4.test(String(value.host_input_ref))) throw storageError("Codex outbox input reference is malformed.");
2118
3077
  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.");
3078
+ if (!SAFE_REF4.test(String(value.prompt_ref))) throw storageError("Codex outbox references are malformed.");
3079
+ if (!SAFE_REF4.test(String(value.submission_ref))) throw storageError("Codex outbox references are malformed.");
3080
+ if (value.request_ref !== void 0 && !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex outbox Request reference is malformed.");
3081
+ if (value.codex_turn_id !== void 0 && !SAFE_REF4.test(String(value.codex_turn_id))) throw storageError("Codex outbox turn identity is malformed.");
2123
3082
  if (typeof value.origin_input !== "boolean") throw storageError("Codex outbox origin disposition is malformed.");
2124
3083
  }
2125
3084
  function validateRegistration(value) {
2126
- if (!isRecord3(value)) throw storageError("Codex transcript registration is malformed.");
3085
+ if (!isRecord4(value)) throw storageError("Codex transcript registration is malformed.");
2127
3086
  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
3087
  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
3088
  validateRegistrationFields(value);
2130
3089
  }
2131
3090
  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 }])}).`);
3091
+ 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
3092
  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
3093
  if (typeof value.transcript_path !== "string") throw storageError(`Codex transcript registration path is malformed (${refusalFact("kind", typeof value.transcript_path, "string")}).`);
2135
3094
  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 +3098,15 @@ function validRegistrationCwd(value) {
2139
3098
  return value === void 0 || typeof value === "string" && isAbsolute2(value) && value.length <= CODEX_TRANSCRIPT_PATH_MAX_CHARACTERS && !value.includes("\0");
2140
3099
  }
2141
3100
  function validateCursor(value) {
2142
- if (!isRecord3(value)) throw storageError("Codex transcript cursor is malformed.");
3101
+ if (!isRecord4(value)) throw storageError("Codex transcript cursor is malformed.");
2143
3102
  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
3103
  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
3104
  if (!validCursorSource(value) || !validCursorPosition(value) || !validCursorStatus(value)) throw storageError("Codex transcript cursor fields are malformed.");
2146
3105
  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.");
3106
+ if (value.reason !== void 0 && !isHostTranscriptCursorReason(value.reason)) throw storageError("Codex transcript cursor reason is malformed.");
2148
3107
  }
2149
3108
  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";
3109
+ 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
3110
  }
2152
3111
  function validCursorPosition(value) {
2153
3112
  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 +3115,23 @@ function validCursorStatus(value) {
2156
3115
  return (value.status === "active" || value.status === "quarantined") && isTimestamp(value.updated_at);
2157
3116
  }
2158
3117
  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;
3118
+ 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
3119
  return validActiveTaskIdentity(value) && validActiveTaskReferences(value) && validActiveTaskUsage(value);
2161
3120
  }
2162
3121
  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);
3122
+ return [value.codex_turn_id, value.host_turn_ref].every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate)) && isTimestamp(value.started_at);
2164
3123
  }
2165
3124
  function validActiveTaskReferences(value) {
2166
3125
  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
3126
  }
2168
3127
  function optionalSafeRef2(value) {
2169
- return value === void 0 || typeof value === "string" && SAFE_REF3.test(value);
3128
+ return value === void 0 || typeof value === "string" && SAFE_REF4.test(value);
2170
3129
  }
2171
3130
  function validActiveTaskUsage(value) {
2172
3131
  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
3132
  }
2174
3133
  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;
3134
+ if (!isRecord4(value) || !sameKeys(value, ["input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens"])) return false;
2176
3135
  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
3136
  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
3137
  }
@@ -2192,30 +3151,33 @@ function validateEnvelopeTimestamps(value) {
2192
3151
  if (!isTimestamp(value.expires_at)) throw storageError("Codex outbox timestamps are malformed.");
2193
3152
  }
2194
3153
  function validateBinding(value) {
2195
- if (!isRecord3(value)) throw storageError("Codex turn binding is malformed.");
3154
+ if (!isRecord4(value)) throw storageError("Codex turn binding is malformed.");
2196
3155
  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
3156
  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
3157
  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.");
3158
+ if (!SAFE_REF4.test(String(value.prompt_ref)) || !SAFE_REF4.test(String(value.request_ref))) throw storageError("Codex turn binding references are malformed.");
2200
3159
  if (!isStringList(value.codex_turn_ids) || !isTimestamp(value.bound_at) || !isTimestamp(value.expires_at)) throw storageError("Codex turn binding fields are malformed.");
2201
3160
  }
2202
3161
  function validateSession(value) {
2203
- if (!isRecord3(value)) throw storageError("Codex session snapshot is malformed.");
3162
+ if (!isRecord4(value)) throw storageError("Codex session snapshot is malformed.");
2204
3163
  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
3164
  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.");
3165
+ 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.");
3166
+ }
3167
+ function validateTurnSelection(value) {
3168
+ if (!isHostInvocationTurnSelection(value)) throw storageError("Codex Host turn selection is malformed.");
2207
3169
  }
2208
3170
  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.");
3171
+ 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
3172
  }
2211
3173
  function isJsonValue(value) {
2212
3174
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
2213
3175
  if (typeof value === "number") return Number.isFinite(value);
2214
3176
  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));
3177
+ return isRecord4(value) && Object.entries(value).every(([key, child]) => key.length > 0 && key.length <= 128 && isJsonValue(child));
2216
3178
  }
2217
3179
  function isStringList(value) {
2218
- return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF3.test(candidate));
3180
+ return Array.isArray(value) && value.every((candidate) => typeof candidate === "string" && SAFE_REF4.test(candidate));
2219
3181
  }
2220
3182
  function isTimestamp(value) {
2221
3183
  return typeof value === "string" && value.length <= 64 && !Number.isNaN(Date.parse(value));
@@ -2225,23 +3187,23 @@ function sameKeys(value, required, optional = []) {
2225
3187
  const keys = Object.keys(value);
2226
3188
  return keys.length >= required.length && keys.length <= allowed.size && required.every((key) => Object.hasOwn(value, key)) && keys.every((key) => allowed.has(key));
2227
3189
  }
2228
- function isRecord3(value) {
3190
+ function isRecord4(value) {
2229
3191
  return value !== null && typeof value === "object" && !Array.isArray(value);
2230
3192
  }
2231
3193
  function isNotFound(error) {
2232
- return isRecord3(error) && error.code === "ENOENT";
3194
+ return isRecord4(error) && error.code === "ENOENT";
2233
3195
  }
2234
3196
  function storageError(message) {
2235
3197
  return new CodexHostAdapterError("storage", message);
2236
3198
  }
2237
3199
 
2238
3200
  // 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";
3201
+ import { createHash as createHash4 } from "node:crypto";
3202
+ import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
3203
+ import { open as open4 } from "node:fs/promises";
2242
3204
 
2243
3205
  // host/codex/src/codex-transcript-decoder.ts
2244
- var SAFE_REF4 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
3206
+ var SAFE_REF5 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
2245
3207
  var MAX_PROMPT_BYTES = 64 * 1024;
2246
3208
  function decodeCodexTranscriptLine(line) {
2247
3209
  let value;
@@ -2250,40 +3212,40 @@ function decodeCodexTranscriptLine(line) {
2250
3212
  } catch {
2251
3213
  reject2("Codex transcript record is not valid JSON.");
2252
3214
  }
2253
- if (!isRecord4(value)) reject2("Codex transcript record envelope is malformed.");
3215
+ if (!isRecord5(value)) reject2("Codex transcript record envelope is malformed.");
2254
3216
  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) {
3217
+ const timestamp5 = safeTimestamp(value.timestamp);
3218
+ if (!isRecord5(value.payload) || typeof value.type !== "string") reject2("Codex transcript record payload is malformed.");
3219
+ if (value.type === "session_meta") return decodeSessionMeta(value.payload, ordinal, timestamp5);
3220
+ if (value.type === "turn_context") return decodeTurnContext(value.payload, ordinal, timestamp5);
3221
+ if (value.type === "event_msg") return decodeEventMessage(value.payload, ordinal, timestamp5);
3222
+ if (value.type === "response_item") return decodeResponseItem(value.payload, ordinal, timestamp5);
3223
+ return { kind: "ignored", ordinal, timestamp: timestamp5 };
3224
+ }
3225
+ function decodeTurnContext(payload, ordinal, timestamp5) {
2264
3226
  return {
2265
3227
  kind: "turn_context",
2266
3228
  ordinal,
2267
- timestamp: timestamp6,
2268
- turn_id: safeRef2(payload.turn_id, "Codex turn context identity is invalid."),
3229
+ timestamp: timestamp5,
3230
+ turn_id: safeRef4(payload.turn_id, "Codex turn context identity is invalid."),
2269
3231
  model: boundedNonEmptyText(payload.model, 256, "Codex turn context model is invalid.")
2270
3232
  };
2271
3233
  }
2272
- function decodeSessionMeta(payload, ordinal, timestamp6) {
2273
- const sessionId = safeRef2(payload.id, "Codex transcript session identity is invalid.");
3234
+ function decodeSessionMeta(payload, ordinal, timestamp5) {
3235
+ const sessionId = safeRef4(payload.id, "Codex transcript session identity is invalid.");
2274
3236
  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 };
3237
+ return { kind: "session_meta", ordinal, timestamp: timestamp5, session_id: sessionId, cli_version: cliVersion };
2276
3238
  }
2277
- function decodeEventMessage(payload, ordinal, timestamp6) {
3239
+ function decodeEventMessage(payload, ordinal, timestamp5) {
2278
3240
  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) };
3241
+ 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
3242
  }
2281
3243
  if (payload.type === "task_complete") {
2282
3244
  return {
2283
3245
  kind: "task_complete",
2284
3246
  ordinal,
2285
- timestamp: timestamp6,
2286
- turn_id: safeRef2(payload.turn_id, "Codex task identity is invalid."),
3247
+ timestamp: timestamp5,
3248
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
2287
3249
  started_at: safeNumber(payload.started_at),
2288
3250
  completed_at: safeNumber(payload.completed_at),
2289
3251
  duration_ms: safeNumber(payload.duration_ms),
@@ -2294,20 +3256,20 @@ function decodeEventMessage(payload, ordinal, timestamp6) {
2294
3256
  return {
2295
3257
  kind: "turn_aborted",
2296
3258
  ordinal,
2297
- timestamp: timestamp6,
2298
- turn_id: safeRef2(payload.turn_id, "Codex task identity is invalid."),
3259
+ timestamp: timestamp5,
3260
+ turn_id: safeRef4(payload.turn_id, "Codex task identity is invalid."),
2299
3261
  started_at: safeNumber(payload.started_at),
2300
3262
  completed_at: safeNumber(payload.completed_at),
2301
3263
  duration_ms: safeNumber(payload.duration_ms),
2302
3264
  reason: boundedText(payload.reason, 256, "Codex task abort reason is invalid.")
2303
3265
  };
2304
3266
  }
2305
- if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp6);
2306
- return { kind: "ignored", ordinal, timestamp: timestamp6 };
3267
+ if (payload.type === "token_count") return decodeTokenCount(payload, ordinal, timestamp5);
3268
+ return { kind: "ignored", ordinal, timestamp: timestamp5 };
2307
3269
  }
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" };
3270
+ function decodeTokenCount(payload, ordinal, timestamp5) {
3271
+ if (payload.info === null) return { kind: "token_count", ordinal, timestamp: timestamp5 };
3272
+ if (!isRecord5(payload.info)) return { kind: "token_count", ordinal, timestamp: timestamp5, usage_gap_reason: "token_count_shape_not_attributable" };
2311
3273
  const lastUsage = optionalTokenUsage(payload.info.last_token_usage);
2312
3274
  const totalUsage = optionalTokenUsage(payload.info.total_token_usage);
2313
3275
  const gap = lastUsage.status === "invalid" || totalUsage.status === "invalid";
@@ -2315,7 +3277,7 @@ function decodeTokenCount(payload, ordinal, timestamp6) {
2315
3277
  return {
2316
3278
  kind: "token_count",
2317
3279
  ordinal,
2318
- timestamp: timestamp6,
3280
+ timestamp: timestamp5,
2319
3281
  ...lastUsage.status === "valid" ? { last_usage: lastUsage.value } : {},
2320
3282
  ...totalUsage.status === "valid" ? { total_usage: totalUsage.value } : {},
2321
3283
  ...usageGapReason === void 0 ? {} : { usage_gap_reason: usageGapReason }
@@ -2331,7 +3293,7 @@ function optionalTokenUsage(value) {
2331
3293
  }
2332
3294
  }
2333
3295
  function decodeTokenUsage(value) {
2334
- if (!isRecord4(value)) reject2("Codex token usage is malformed.");
3296
+ if (!isRecord5(value)) reject2("Codex token usage is malformed.");
2335
3297
  const usage = {
2336
3298
  input_tokens: safeTokenCount(value.input_tokens),
2337
3299
  cached_input_tokens: safeTokenCount(value.cached_input_tokens),
@@ -2343,20 +3305,20 @@ function decodeTokenUsage(value) {
2343
3305
  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
3306
  return usage;
2345
3307
  }
2346
- function decodeResponseItem(payload, ordinal, timestamp6) {
2347
- if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp6 };
3308
+ function decodeResponseItem(payload, ordinal, timestamp5) {
3309
+ if (payload.type !== "message" || payload.role !== "user") return { kind: "ignored", ordinal, timestamp: timestamp5 };
2348
3310
  const metadata = userMessageMetadata(payload.internal_chat_message_metadata_passthrough);
2349
3311
  const inputKind = inputKindFromContentItems(metadata.content_item_kinds);
2350
- if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp6 };
3312
+ if (inputKind === void 0) return { kind: "ignored", ordinal, timestamp: timestamp5 };
2351
3313
  const prompt = userTextContent(payload.content);
2352
3314
  return {
2353
3315
  kind: "user_text",
2354
3316
  ordinal,
2355
- timestamp: timestamp6,
3317
+ timestamp: timestamp5,
2356
3318
  prompt,
2357
3319
  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.")
3320
+ message_id: safeRef4(payload.id, "Codex user message identity is invalid."),
3321
+ turn_id: safeRef4(metadata.turn_id, "Codex user message task identity is invalid.")
2360
3322
  };
2361
3323
  }
2362
3324
  function inputKindFromContentItems(kinds) {
@@ -2365,13 +3327,13 @@ function inputKindFromContentItems(kinds) {
2365
3327
  return kinds[0] === "goal.internal_context" ? "host_automatic" : void 0;
2366
3328
  }
2367
3329
  function userMessageMetadata(value) {
2368
- if (!isRecord4(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
3330
+ if (!isRecord5(value) || !Array.isArray(value.content_item_kinds)) reject2("Codex user message provenance is malformed.");
2369
3331
  return { ...value, content_item_kinds: value.content_item_kinds };
2370
3332
  }
2371
3333
  function userTextContent(value) {
2372
3334
  if (!Array.isArray(value)) reject2(`Codex user text content is malformed (${refusalFact("kind", typeof value, "array")}).`);
2373
3335
  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")}).`);
3336
+ 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
3337
  return boundedText(value[0].text, MAX_PROMPT_BYTES, "Codex user text is invalid.");
2376
3338
  }
2377
3339
  function safeOrdinal(value) {
@@ -2392,8 +3354,8 @@ function safeTimestamp(value) {
2392
3354
  if (!Number.isFinite(Date.parse(value))) reject2(`Codex transcript timestamp is invalid (${refusalFact("parsed_ms", Date.parse(value), "a finite epoch milliseconds value")}).`);
2393
3355
  return value;
2394
3356
  }
2395
- function safeRef2(value, message) {
2396
- if (typeof value !== "string" || !SAFE_REF4.test(value)) reject2(message);
3357
+ function safeRef4(value, message) {
3358
+ if (typeof value !== "string" || !SAFE_REF5.test(value)) reject2(message);
2397
3359
  return value;
2398
3360
  }
2399
3361
  function boundedText(value, maximum, message) {
@@ -2407,7 +3369,7 @@ function boundedNonEmptyText(value, maximum, message) {
2407
3369
  if (result.length === 0) reject2(message);
2408
3370
  return result;
2409
3371
  }
2410
- function isRecord4(value) {
3372
+ function isRecord5(value) {
2411
3373
  return value !== null && typeof value === "object" && !Array.isArray(value);
2412
3374
  }
2413
3375
  function reject2(message) {
@@ -2420,7 +3382,7 @@ var CODEX_TRANSCRIPT_ANCHOR_BYTES = 256;
2420
3382
  async function captureCodexTranscriptBaseline(registration, now = () => /* @__PURE__ */ new Date()) {
2421
3383
  let handle;
2422
3384
  try {
2423
- handle = await open2(registration.transcript_path, O_RDONLY2 | O_NOFOLLOW2);
3385
+ handle = await open4(registration.transcript_path, O_RDONLY4 | O_NOFOLLOW3);
2424
3386
  const { size, device, inode } = await ownedCodexTranscriptFile(handle);
2425
3387
  const empty = codexTranscriptInitialCursor(registration, device, inode, now);
2426
3388
  const headerLine = await firstCompleteLine(handle, size);
@@ -2440,7 +3402,7 @@ async function captureCodexTranscriptBaseline(registration, now = () => /* @__PU
2440
3402
  anchor_start: anchorStart,
2441
3403
  anchor_sha256: digest(anchor),
2442
3404
  header_validated: true,
2443
- updated_at: timestamp2(now)
3405
+ updated_at: timestamp3(now)
2444
3406
  };
2445
3407
  } finally {
2446
3408
  await handle?.close();
@@ -2460,7 +3422,7 @@ function codexTranscriptInitialCursor(registration, device, inode, now) {
2460
3422
  anchor_sha256: digest(Buffer.alloc(0)),
2461
3423
  header_validated: false,
2462
3424
  status: "active",
2463
- updated_at: timestamp2(now)
3425
+ updated_at: timestamp3(now)
2464
3426
  };
2465
3427
  }
2466
3428
  async function ownedCodexTranscriptFile(handle) {
@@ -2561,168 +3523,13 @@ async function* completeLinesBackward(handle, end) {
2561
3523
  }
2562
3524
  yield { start: 0, bytes: Buffer.concat(carry) };
2563
3525
  }
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());
2713
- }
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));
2717
- }
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);
3526
+ function digest(value) {
3527
+ return createHash4("sha256").update(value).digest("hex");
3528
+ }
3529
+ function timestamp3(now) {
3530
+ const value = now();
3531
+ if (!Number.isFinite(value.getTime())) throw new CodexHostAdapterError("storage", "Codex watcher clock is invalid.");
3532
+ return value.toISOString();
2726
3533
  }
2727
3534
 
2728
3535
  // host/codex/src/codex-adapter.ts
@@ -2748,7 +3555,7 @@ function createCodexHostObservationAdapter(options) {
2748
3555
  });
2749
3556
  }
2750
3557
  async function registerSession(event, options, store, now, retentionMs) {
2751
- const defaultRoot = join3(process.env.CODEX_HOME || join3(homedir(), ".codex"), "sessions");
3558
+ const defaultRoot = join4(process.env.CODEX_HOME || join4(homedir(), ".codex"), "sessions");
2752
3559
  const transcriptPath = sourceBoundTranscriptPath(event.transcript_path, options.codex_sessions_root ?? defaultRoot);
2753
3560
  const hostSessionRef = hostSessionReference(options.host_source_ref, event.session_id);
2754
3561
  const observedAt = timestamp4(now);
@@ -2763,20 +3570,41 @@ async function registerSession(event, options, store, now, retentionMs) {
2763
3570
  registered_at: observedAt,
2764
3571
  expires_at: expiresAt
2765
3572
  };
3573
+ const currentTurn = await selectCurrentTurn(event, options, store, hostSessionRef);
2766
3574
  const existing = (await store.listTranscriptRegistrations()).find((candidate) => candidate.host_source_ref === registration.host_source_ref && candidate.host_session_ref === registration.host_session_ref);
2767
3575
  if (existing === void 0) {
2768
3576
  await store.writeTranscriptCursor(await captureCodexTranscriptBaseline(registration, now));
2769
3577
  }
2770
3578
  await store.registerTranscript(registration);
2771
- await store.saveSession({
2772
- schema_version: "ceal.codex_session.v1",
2773
- host_session_ref: hostSessionRef,
3579
+ if (event.event === "SessionStart") {
3580
+ await store.saveSession({
3581
+ schema_version: "ceal.codex_session.v1",
3582
+ host_session_ref: hostSessionRef,
3583
+ host_source_ref: options.host_source_ref,
3584
+ observed_at: observedAt,
3585
+ value: sessionObservationValue(event),
3586
+ expires_at: expiresAt
3587
+ });
3588
+ } else if (currentTurn !== void 0) {
3589
+ 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);
3590
+ }
3591
+ return { event: event.event, disposition: "ignored", reason: "transcript_registered", ...currentTurn === void 0 ? {} : { host_turn_ref: currentTurn.host_turn_ref } };
3592
+ }
3593
+ async function selectCurrentTurn(event, options, store, hostSessionRef) {
3594
+ if (event.event !== "UserPromptSubmit") return void 0;
3595
+ const currentTurn = {
3596
+ host_turn_ref: hostTurnReference(options.host_source_ref, hostSessionRef, event.turn_id),
3597
+ prompt_ref: hostProducerPromptRef(promptObservationValue(event.prompt).body_sha256),
3598
+ turn_generation_ref: options.random_uuid?.() ?? randomUUID()
3599
+ };
3600
+ await store.writeInvocationTurnSelection({
3601
+ schema_version: "ceal.host_invocation_turn_selection.v1",
2774
3602
  host_source_ref: options.host_source_ref,
2775
- observed_at: observedAt,
2776
- value: sessionObservationValue(event),
2777
- expires_at: expiresAt
3603
+ host_session_ref: hostSessionRef,
3604
+ prompt_ref: currentTurn.prompt_ref,
3605
+ turn_generation_ref: currentTurn.turn_generation_ref
2778
3606
  });
2779
- return { event: "SessionStart", disposition: "ignored", reason: "transcript_registered" };
3607
+ return currentTurn;
2780
3608
  }
2781
3609
  function sourceBoundTranscriptPath(path, sessionsRoot) {
2782
3610
  if (!isAbsolute3(path) || !isAbsolute3(sessionsRoot)) throw new CodexHostAdapterError("configuration", "Codex transcript registration paths must be absolute.");
@@ -2884,7 +3712,7 @@ async function submitWithDeadline(gateway, submission, timeoutMs, signal) {
2884
3712
  });
2885
3713
  try {
2886
3714
  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)) {
3715
+ if (!isRecord6(acknowledgement) || !SAFE_REF6.test(String(acknowledgement.request_ref)) || !isHostGatewayAcknowledgementDisposition(acknowledgement.disposition)) {
2888
3716
  throw new CodexHostAdapterError("payload_rejected", "Gateway Host acknowledgement is invalid.");
2889
3717
  }
2890
3718
  return acknowledgement;
@@ -2914,12 +3742,12 @@ function timestamp4(now) {
2914
3742
  return value.toISOString();
2915
3743
  }
2916
3744
  function validateOptions(options) {
2917
- if (!isRecord5(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
3745
+ if (!isRecord6(options)) throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
2918
3746
  validateAdapterOwner(options);
2919
3747
  validateAdapterBehavior(options);
2920
3748
  }
2921
3749
  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") {
3750
+ if (!SAFE_REF6.test(options.host_source_ref) || options.outbox_dir.length === 0 || !isRecord6(options.gateway) || typeof options.gateway.submitHostTurn !== "function") {
2923
3751
  throw new CodexHostAdapterError("configuration", "Codex adapter options are invalid.");
2924
3752
  }
2925
3753
  if (options.codex_sessions_root !== void 0 && !isAbsolute3(options.codex_sessions_root)) throw new CodexHostAdapterError("configuration", "Codex sessions root is invalid.");
@@ -2931,7 +3759,7 @@ function validateAdapterBehavior(options) {
2931
3759
  function safeReason(error) {
2932
3760
  return error instanceof CodexHostAdapterError ? error.message.slice(0, 128) : "codex_session_registration_rejected";
2933
3761
  }
2934
- function isRecord5(value) {
3762
+ function isRecord6(value) {
2935
3763
  return value !== null && typeof value === "object" && !Array.isArray(value);
2936
3764
  }
2937
3765
 
@@ -2939,7 +3767,7 @@ function isRecord5(value) {
2939
3767
  import { posix as posix3, win32 as win323 } from "node:path";
2940
3768
 
2941
3769
  // host/runtime-source-paths.ts
2942
- import { createHash as createHash4 } from "node:crypto";
3770
+ import { createHash as createHash5 } from "node:crypto";
2943
3771
  import { posix as posix2, win32 as win322 } from "node:path";
2944
3772
 
2945
3773
  // host/absolute-path.ts
@@ -2961,7 +3789,7 @@ function hostRuntimeSourcePaths(stateRoot, sourceRef, platform = process.platfor
2961
3789
  const sourcesRoot = path.join(stateRoot, "sources");
2962
3790
  const sourceRoot = path.join(sourcesRoot, sourceId);
2963
3791
  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`);
3792
+ const endpoint = platform === "win32" ? `\\\\.\\pipe\\ceal-host-${createHash5("sha256").update(`${stateRoot}\0${sourceRef}`).digest("hex").slice(0, 24)}` : path.join(runtimeRoot, `${sourceId}.sock`);
2965
3793
  assertHostRuntimeIpcLength(endpoint, platform);
2966
3794
  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
3795
  }
@@ -2977,7 +3805,7 @@ function assertHostProducerSourcePaths(stateRoot, config, producer, platform = p
2977
3805
 
2978
3806
  // host/producer-service.ts
2979
3807
  import { constants } from "node:fs";
2980
- import { lstat as lstat3, open as open4 } from "node:fs/promises";
3808
+ import { lstat as lstat3, open as open5 } from "node:fs/promises";
2981
3809
  var SAFE_REF7 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
2982
3810
  var HOST_PRODUCER_CONFIG_FLAG = "--ceal-host-config";
2983
3811
  var HostProducerServiceError = class extends Error {
@@ -3043,7 +3871,7 @@ async function readProducerConfigText(configPath, platform, error) {
3043
3871
  }
3044
3872
  function decodeProducerConfigCore(text, options) {
3045
3873
  const value = parseCanonicalJson(text, options.error);
3046
- if (!isRecord6(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
3874
+ if (!isRecord7(value) || !hasConfigKeys(value, options.keys) || value.schema_version !== options.schema) throw options.error("invalid_config");
3047
3875
  const hostSourceRef = typeof value.host_source_ref === "string" ? value.host_source_ref : "";
3048
3876
  const installationRef = typeof value.producer_installation_ref === "string" ? value.producer_installation_ref : "";
3049
3877
  const producerEpoch = validateIdentity3(hostSourceRef, installationRef, value.producer_epoch, options.error);
@@ -3071,397 +3899,117 @@ function assertProducerRelayEndpoint(value, platform, error) {
3071
3899
  if (platform === "win32" && typeof value === "string" && /^\\\\\.\\pipe\\[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)) return;
3072
3900
  assertProducerAbsolutePath(value, platform, "runtime", error);
3073
3901
  }
3074
- function assertProducerAbsolutePath(value, platform, kind, error) {
3075
- if (!isAbsoluteNormalizedNonRootPath(value, platform) || /[\r\n]/u.test(value)) throw error(kind === "config" ? "invalid_config_path" : "invalid_config", refusalFact("path", value, "absolute, normalized, non-root, and without line breaks"));
3076
- }
3077
- async function configPathStat(configPath, error) {
3078
- try {
3079
- return await lstat3(configPath);
3080
- } catch {
3081
- throw error("config_unavailable");
3082
- }
3083
- }
3084
- function validateConfigFile(value, platform, error) {
3085
- if (!value.isFile() || value.isSymbolicLink()) throw error("invalid_config", refusalFacts([{ name: "config_is_file", value: value.isFile(), expected: "true" }, { name: "config_is_symlink", value: value.isSymbolicLink(), expected: "false" }]));
3086
- if (value.size <= 0 || value.size > CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES) throw error("invalid_config", refusalFact("config_bytes", value.size, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
3087
- if (platform !== "win32" && (value.uid !== process.getuid?.() || (value.mode & 63) !== 0)) throw error("config_not_private", refusalFacts([{ name: "platform", value: platform, expected: "win32 or owner-private" }, { name: "config_uid", value: value.uid, expected: "the current user" }, { name: "config_mode", value: value.mode, expected: "owner-private" }]));
3088
- }
3089
- async function openConfigFile(configPath, flags, error) {
3090
- try {
3091
- return await open4(configPath, flags);
3092
- } catch {
3093
- throw error("config_unavailable");
3094
- }
3095
- }
3096
- function validateOpenedFile(opened, pathStat, platform, error) {
3097
- if (!opened.isFile()) throw error("config_unavailable", refusalFacts([{ name: "opened_is_file", value: opened.isFile(), expected: "true" }, { name: "opened_mode", value: opened.mode.toString(8), expected: "a regular file mode" }]));
3098
- if (platform !== "win32" && (opened.dev !== pathStat.dev || opened.ino !== pathStat.ino)) throw error("config_unavailable", refusalFacts([{ name: "platform", value: platform, expected: "win32, or the same file the path named" }, { name: "opened_device", value: opened.dev, expected: String(pathStat.dev) }, { name: "opened_inode", value: opened.ino, expected: String(pathStat.ino) }]));
3099
- }
3100
- async function readBoundedConfig(handle, expectedBytes, error) {
3101
- const buffer = Buffer.allocUnsafe(expectedBytes + 1);
3102
- let offset = 0;
3103
- while (offset < buffer.byteLength) {
3104
- const { bytesRead } = await handle.read(buffer, offset, buffer.byteLength - offset, offset);
3105
- if (bytesRead === 0) break;
3106
- offset += bytesRead;
3107
- }
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
- });
3902
+ function assertProducerAbsolutePath(value, platform, kind, error) {
3903
+ if (!isAbsoluteNormalizedNonRootPath(value, platform) || /[\r\n]/u.test(value)) throw error(kind === "config" ? "invalid_config_path" : "invalid_config", refusalFact("path", value, "absolute, normalized, non-root, and without line breaks"));
3308
3904
  }
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;
3905
+ async function configPathStat(configPath, error) {
3314
3906
  try {
3315
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input.subarray(HOST_RELAY_IPC_LENGTH_BYTES)));
3907
+ return await lstat3(configPath);
3316
3908
  } catch {
3317
- throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response is invalid.");
3909
+ throw error("config_unavailable");
3318
3910
  }
3319
- if (!validResponse(value)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC response shape is invalid.");
3320
- return value;
3321
3911
  }
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";
3912
+ function validateConfigFile(value, platform, error) {
3913
+ if (!value.isFile() || value.isSymbolicLink()) throw error("invalid_config", refusalFacts([{ name: "config_is_file", value: value.isFile(), expected: "true" }, { name: "config_is_symlink", value: value.isSymbolicLink(), expected: "false" }]));
3914
+ if (value.size <= 0 || value.size > CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES) throw error("invalid_config", refusalFact("config_bytes", value.size, `between 1 and ${CEAL_ENCODED_JSON_DOCUMENT_MAX_BYTES}`));
3915
+ if (platform !== "win32" && (value.uid !== process.getuid?.() || (value.mode & 63) !== 0)) throw error("config_not_private", refusalFacts([{ name: "platform", value: platform, expected: "win32 or owner-private" }, { name: "config_uid", value: value.uid, expected: "the current user" }, { name: "config_mode", value: value.mode, expected: "owner-private" }]));
3324
3916
  }
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;
3917
+ async function openConfigFile(configPath, flags, error) {
3918
+ try {
3919
+ return await open5(configPath, flags);
3920
+ } catch {
3921
+ throw error("config_unavailable");
3922
+ }
3327
3923
  }
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);
3924
+ function validateOpenedFile(opened, pathStat, platform, error) {
3925
+ if (!opened.isFile()) throw error("config_unavailable", refusalFacts([{ name: "opened_is_file", value: opened.isFile(), expected: "true" }, { name: "opened_mode", value: opened.mode.toString(8), expected: "a regular file mode" }]));
3926
+ if (platform !== "win32" && (opened.dev !== pathStat.dev || opened.ino !== pathStat.ino)) throw error("config_unavailable", refusalFacts([{ name: "platform", value: platform, expected: "win32, or the same file the path named" }, { name: "opened_device", value: opened.dev, expected: String(pathStat.dev) }, { name: "opened_inode", value: opened.ino, expected: String(pathStat.ino) }]));
3330
3927
  }
3331
- function nonnegative(value) {
3332
- return Number.isSafeInteger(value) && Number(value) >= 0;
3928
+ async function readBoundedConfig(handle, expectedBytes, error) {
3929
+ const buffer = Buffer.allocUnsafe(expectedBytes + 1);
3930
+ let offset = 0;
3931
+ while (offset < buffer.byteLength) {
3932
+ const { bytesRead } = await handle.read(buffer, offset, buffer.byteLength - offset, offset);
3933
+ if (bytesRead === 0) break;
3934
+ offset += bytesRead;
3935
+ }
3936
+ if (offset !== expectedBytes) throw error("invalid_config", refusalFact("bytes_read", offset, `the opened file's ${expectedBytes} bytes without growth or truncation`));
3937
+ try {
3938
+ return new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, offset));
3939
+ } catch {
3940
+ throw error("invalid_config");
3941
+ }
3333
3942
  }
3334
- function record2(value) {
3335
- return value !== null && typeof value === "object" && !Array.isArray(value);
3943
+ function parseCanonicalJson(text, error) {
3944
+ try {
3945
+ const value = JSON.parse(text);
3946
+ const canonical = JSON.stringify(value);
3947
+ 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) }])}`);
3948
+ return value;
3949
+ } catch (parseError) {
3950
+ throw error("invalid_config", refusalFacts([{ name: "parse_error", value: parseError }, { name: "config_bytes", value: Buffer.byteLength(text, "utf8"), expected: "canonical JSON" }]));
3951
+ }
3336
3952
  }
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);
3953
+ function firstDifferenceIndex(left, right) {
3954
+ const shared = Math.min(left.length, right.length);
3955
+ for (let index = 0; index < shared; index += 1) if (left[index] !== right[index]) return index;
3956
+ return shared;
3344
3957
  }
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 };
3958
+ function validateIdentity3(sourceRef, installationRef, epoch, error) {
3959
+ if (!SAFE_REF7.test(sourceRef) || !SAFE_REF7.test(installationRef) || !positive2(epoch, 2147483647)) throw error("invalid_config");
3960
+ return epoch;
3350
3961
  }
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
- }
3962
+ function validateIntervals(reconcile, retry, timeout, error) {
3963
+ if (!boundedMilliseconds(reconcile) || !boundedMilliseconds(retry) || !boundedMilliseconds(timeout)) throw error("invalid_config");
3964
+ return [reconcile, retry, timeout];
3362
3965
  }
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;
3966
+ function hasConfigKeys(value, required) {
3967
+ return required.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => required.includes(key) || Object.hasOwn(HOST_PRODUCER_TIMING_DEFAULTS, key));
3369
3968
  }
3370
- function exactKeys4(value, keys) {
3371
- return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
3969
+ function isRecord7(value) {
3970
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3372
3971
  }
3373
- function errorCode(error) {
3374
- return record2(error) && typeof error.code === "string" ? error.code : null;
3972
+ function positive2(value, maximum) {
3973
+ return Number.isSafeInteger(value) && Number(value) > 0 && Number(value) <= maximum;
3974
+ }
3975
+ function boundedMilliseconds(value) {
3976
+ return positive2(value, 6e4) && Number(value) >= 25;
3375
3977
  }
3376
3978
 
3377
3979
  // 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";
3980
+ import { createHash as createHash6 } from "node:crypto";
3382
3981
  var SAFE_REF8 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
3383
3982
  var CodexProducer = class {
3983
+ producer_id = "codex";
3984
+ producer_label = "Codex";
3985
+ outbox_directory;
3384
3986
  store;
3385
- statePath;
3386
- installationRef;
3387
- epoch;
3388
- relay;
3389
- now;
3390
- tail = Promise.resolve();
3987
+ core;
3391
3988
  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
3989
  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());
3990
+ this.outbox_directory = this.store.directory;
3991
+ this.core = new HostProducerDrainCore(this, options);
3401
3992
  }
3402
3993
  drainOutbox() {
3403
- const run = this.tail.then(() => this.drainLocked());
3404
- this.tail = run.then(() => void 0, () => void 0);
3405
- return run;
3994
+ return this.core.drainOutbox();
3406
3995
  }
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 };
3996
+ fail(code, message) {
3997
+ return new CodexHostAdapterError(code, message);
3437
3998
  }
3438
- async hasReservation(submissionRef) {
3439
- return (await this.readState()).pending[submissionRef] !== void 0;
3999
+ listEnvelopes() {
4000
+ return this.store.list();
3440
4001
  }
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;
4002
+ removeEnvelope(envelope) {
4003
+ return this.store.remove(envelope);
3458
4004
  }
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 });
4005
+ submissionRefOf(envelope) {
4006
+ return envelope.submission_ref;
4007
+ }
4008
+ expiresAtOf(envelope) {
4009
+ return envelope.expires_at;
4010
+ }
4011
+ createdAtOf(envelope) {
4012
+ return envelope.created_at;
3465
4013
  }
3466
4014
  async mapEnvelope(envelope) {
3467
4015
  const prompt = observation(envelope, "prompt");
@@ -3477,7 +4025,7 @@ var CodexProducer = class {
3477
4025
  const directoryIdentity = registration?.cwd ?? envelope.identity.host_session_ref;
3478
4026
  drafts.push({ frame_kind: "session_started", payload: compact({
3479
4027
  local_session_ref: envelope.identity.host_session_ref,
3480
- working_directory_ref: `workspace:${createHash5("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
4028
+ working_directory_ref: `workspace:${createHash6("sha256").update(directoryIdentity, "utf8").digest("hex")}`,
3481
4029
  model: recordText(session.value, "model"),
3482
4030
  host_version: nestedText(session.value, "host_version"),
3483
4031
  observations: [session]
@@ -3502,21 +4050,6 @@ var CodexProducer = class {
3502
4050
  }) });
3503
4051
  return drafts;
3504
4052
  }
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
4053
  };
3521
4054
  function mapTerminal(envelope) {
3522
4055
  const timing = observation(envelope, "timing");
@@ -3544,7 +4077,7 @@ function compact(value) {
3544
4077
  return Object.fromEntries(Object.entries(value).filter((entry) => entry[1] !== void 0));
3545
4078
  }
3546
4079
  function asRecord(value) {
3547
- return isRecord7(value) ? value : void 0;
4080
+ return isRecord8(value) ? value : void 0;
3548
4081
  }
3549
4082
  function recordText(value, key) {
3550
4083
  const record3 = asRecord(value);
@@ -3558,122 +4091,51 @@ function nonNegativeNumber(value) {
3558
4091
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
3559
4092
  }
3560
4093
  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;
4094
+ return SAFE_REF8.test(value) ? value : `reason:${createHash6("sha256").update(value, "utf8").digest("hex")}`;
3596
4095
  }
3597
- function isRecord7(value) {
4096
+ function isRecord8(value) {
3598
4097
  return value !== null && typeof value === "object" && !Array.isArray(value);
3599
4098
  }
3600
4099
 
3601
4100
  // 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 {
4101
+ var CodexTranscriptWatcher = class extends HostTranscriptWatcher {
3608
4102
  store;
3609
- outboxRetentionMs;
3610
- now;
3611
- log;
3612
- producerInstallationRef;
3613
4103
  registerCurrentPrompt;
3614
4104
  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
- `);
4105
+ super(options, {
4106
+ default_retention_ms: CODEX_DEFAULT_RETENTION_MS,
4107
+ invalid_outbox: () => new CodexHostAdapterError("configuration", "Codex transcript watcher outbox is invalid."),
4108
+ clock_failure: () => new CodexHostAdapterError("storage", "Codex watcher clock is invalid.")
3622
4109
  });
3623
- this.producerInstallationRef = options.producer_installation_ref;
4110
+ this.store = new CodexOutboxStore(options.outbox_dir);
3624
4111
  this.registerCurrentPrompt = options.register_current_prompt;
3625
4112
  }
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 };
4113
+ transcriptPathOf(registration) {
4114
+ return registration.transcript_path;
3638
4115
  }
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
- }
4116
+ async listRegistrations() {
4117
+ return this.store.listTranscriptRegistrations();
3656
4118
  }
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 };
4119
+ async scanOpened(handle, registration) {
4120
+ const { size, device, inode } = await ownedCodexTranscriptFile(handle);
4121
+ const preflight = await this.preflight(registration, handle, size, device, inode);
4122
+ if (preflight.cursor === null) return preflight.result;
4123
+ const complete = await this.readChunk(handle, preflight.cursor.offset, size);
4124
+ if (complete === "empty" || complete === "partial") return { records: 0, enqueued: 0, quarantined: false };
4125
+ return await this.consumeCompleteChunk(registration, handle, preflight.cursor, complete, device, inode);
4126
+ }
4127
+ async scanFailed(handle, registration, _error) {
4128
+ await this.quarantineFailure(registration, handle);
4129
+ return { records: 0, enqueued: 0, quarantined: true };
4130
+ }
4131
+ async retireMissing(registration) {
4132
+ return this.retireMissingTranscript(registration.transcript_path, "Codex", () => this.store.retireTranscriptRegistration(registration));
3671
4133
  }
3672
4134
  async preflight(registration, handle, size, device, inode) {
3673
4135
  const existing = await this.store.readTranscriptCursor(registration);
3674
4136
  let cursor = existing ?? codexTranscriptInitialCursor(registration, device, inode, this.now);
3675
4137
  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);
4138
+ const reason = this.cursorIdentityReason(cursor, registration.transcript_path, device, inode) ?? await this.cursorBoundsReason(handle, cursor, size);
3677
4139
  if (reason === null) return { cursor, result: { records: 0, enqueued: 0, quarantined: false } };
3678
4140
  await this.quarantine(registration, cursor, device, inode, reason);
3679
4141
  return { cursor: null, result: { records: 0, enqueued: 0, quarantined: true } };
@@ -3699,14 +4161,12 @@ var CodexTranscriptWatcher = class {
3699
4161
  async observeSessionMetadata(registration, record3) {
3700
4162
  if (record3.kind !== "session_meta") return;
3701
4163
  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 } });
4164
+ if (session !== null && this.isRecord(session.value)) await this.store.saveSession({ ...session, value: { ...session.value, host_version: record3.cli_version } });
3703
4165
  }
3704
4166
  async commitCursor(registration, handle, cursor, consumedBytes, device, inode, lastOrdinal, activeTask) {
3705
4167
  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) });
4168
+ const anchor = await this.readAnchor(handle, offset, CODEX_TRANSCRIPT_ANCHOR_BYTES);
4169
+ 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
4170
  }
3711
4171
  async quarantineFailure(registration, handle) {
3712
4172
  if (handle === void 0) return;
@@ -3755,11 +4215,11 @@ var CodexTranscriptWatcher = class {
3755
4215
  origin_input: origin,
3756
4216
  submission_ref: codexSubmissionReference(hostInputRef, "input", record3.ordinal),
3757
4217
  created_at: record3.timestamp,
3758
- expires_at: expiration(this.now, this.outboxRetentionMs)
4218
+ expires_at: this.expire(this.outboxRetentionMs)
3759
4219
  };
3760
4220
  await this.registerPrompt(origin, registration, activeTask, currentPromptRef, record3.prompt, envelope.expires_at);
3761
4221
  await this.store.put(envelope);
3762
- if (origin) await this.store.activateInvocationContext(identity, promptRef, envelope.expires_at);
4222
+ if (origin) await activateTranscriptTurnContext(this.store, identity, promptRef, envelope.expires_at);
3763
4223
  return { activeTask: { ...activeTask, origin_host_input_ref: activeTask.origin_host_input_ref ?? hostInputRef, prompt_ref: activeTask.prompt_ref ?? currentPromptRef }, enqueued: 1 };
3764
4224
  }
3765
4225
  async registerPrompt(origin, registration, activeTask, promptRef, prompt, expiresAt) {
@@ -3782,16 +4242,21 @@ var CodexTranscriptWatcher = class {
3782
4242
  origin_input: false,
3783
4243
  submission_ref: codexSubmissionReference(activeTask.origin_host_input_ref, "terminal", record3.ordinal),
3784
4244
  created_at: record3.timestamp,
3785
- expires_at: expiration(this.now, this.outboxRetentionMs)
4245
+ expires_at: this.expire(this.outboxRetentionMs)
3786
4246
  });
3787
4247
  await this.store.clearInvocationContext(identity, this.now());
3788
4248
  return { enqueued: 1 };
3789
4249
  }
3790
4250
  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) };
4251
+ const quarantined = { ...cursor, transcript_path: registration.transcript_path, device, inode, status: "quarantined", reason, updated_at: this.stamp() };
3792
4252
  await this.store.writeTranscriptCursor(quarantined);
3793
4253
  }
3794
4254
  };
4255
+ async function activateTranscriptTurnContext(store, identity, promptRef, expiresAt) {
4256
+ const selection = await store.readInvocationTurnSelection(identity.host_source_ref, identity.host_session_ref);
4257
+ const turnGenerationRef = selection?.prompt_ref === promptRef ? selection.turn_generation_ref : void 0;
4258
+ await store.activateInvocationContext(identity, promptRef, expiresAt, turnGenerationRef);
4259
+ }
3795
4260
  function accumulateTokenCount(activeTask, record3) {
3796
4261
  if (record3.usage_gap_reason !== void 0) return { ...activeTask, token_usage_gap_reason: record3.usage_gap_reason };
3797
4262
  const last = record3.last_usage;
@@ -3825,19 +4290,18 @@ function terminalCostValue() {
3825
4290
  return notRecorded("provider_cost_not_observed");
3826
4291
  }
3827
4292
  function notRecorded(reason) {
3828
- return { status: "not_recorded", reason };
4293
+ return hostObservationNotRecorded(reason);
3829
4294
  }
3830
4295
  function tokenObservationValue(usage) {
3831
4296
  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",
4297
+ ...createHostTokenObservationValue({
4298
+ input: usage.input_tokens,
4299
+ output: usage.output_tokens,
4300
+ total: usage.total_tokens,
4301
+ cached_input: usage.cached_input_tokens,
4302
+ cache_write_input: usage.cache_write_input_tokens,
4303
+ reasoning_output: usage.reasoning_output_tokens
4304
+ }, "codex_transcript.event_msg.token_count.info.last_token_usage"),
3841
4305
  attribution: "sequential_active_task",
3842
4306
  total_usage_role: "dedup_and_reset_detection_only"
3843
4307
  };
@@ -3871,60 +4335,10 @@ function looksLikeStaleRegression(current, previous, last) {
3871
4335
  if (previous.total_tokens <= 0 || current.total_tokens <= 0 || last.total_tokens <= 0) return false;
3872
4336
  return current.total_tokens * 100 >= previous.total_tokens * 98 || current.total_tokens + last.total_tokens * 2 >= previous.total_tokens;
3873
4337
  }
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
4338
  function assertRecordSequence(registration, cursor, records, lastOrdinal, record3) {
3906
4339
  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
4340
  if (!cursor.header_validated && records === 0) assertCodexTranscriptHeader(registration, record3);
3908
4341
  }
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
4342
 
3929
4343
  // host/codex/src/codex-producer-runtime.ts
3930
4344
  async function drainCodexProducerOnce(options) {
@@ -3953,7 +4367,7 @@ var CODEX_PRODUCER_DESCRIPTOR = {
3953
4367
  };
3954
4368
 
3955
4369
  // host/codex/src/codex-hook-runner.ts
3956
- var MAX_STDIN_BYTES = 64 * 1024;
4370
+ var MAX_STDIN_BYTES = 512 * 1024;
3957
4371
  async function runCodexHookFromStdin(event, stdin, options) {
3958
4372
  const adapter = createCodexHostObservationAdapter(options);
3959
4373
  return adapter.handle(event, await readStdin(stdin));