@corca-org/ceal-host-win32-x64 1.0.7 → 1.0.9

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.
@@ -74,11 +74,28 @@ var client_wire_contract_default = {
74
74
  ],
75
75
  bare_document_fields: [
76
76
  "invocation",
77
- "next",
77
+ "required_action_sequence",
78
+ "entrypoints",
78
79
  "common_concepts",
79
80
  "operations",
80
81
  "catalog_revision"
81
82
  ],
83
+ prompt_field: "prompt",
84
+ prompt_schema_version: "ceal.prompt.v1",
85
+ focused_prompt_document_fields: [
86
+ "catalog_revision",
87
+ "prompt"
88
+ ],
89
+ focused_prompt_continuation_document_fields: [
90
+ "catalog_revision",
91
+ "remaining_work",
92
+ "prompt"
93
+ ],
94
+ discovery_command: "discovery",
95
+ discovery_manifest_schema_version: "ceal.discovery_manifest.v1",
96
+ discovery_manifest_document_fields: [
97
+ "discovery_manifest"
98
+ ],
82
99
  exit_code_max: 125,
83
100
  bare_document_max_bytes: 65536,
84
101
  complete_max_bytes: 66019,
@@ -105,8 +122,15 @@ var CEAL_VERIFIED_ARTIFACT_MAX_BYTES = artifact.max_bytes;
105
122
  var CEAL_VERIFIED_ARTIFACT_DESCRIPTOR_MAX_BYTES = artifact.envelope_max_bytes;
106
123
  var CEAL_COMMAND_REQUEST_SCHEMA_VERSION = request.schema_version;
107
124
  var CEAL_COMMAND_REQUEST_MAX_BYTES = request.absolute_transport_max_bytes;
108
- var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_FIELDS = response.bare_document_fields;
109
125
  var CEAL_COMMAND_RESPONSE_BARE_DOCUMENT_MAX_BYTES = response.bare_document_max_bytes;
126
+ var CEAL_COMMAND_RESPONSE_PROMPT_FIELD = response.prompt_field;
127
+ var CEAL_COMMAND_RESPONSE_PROMPT_SCHEMA_VERSION = response.prompt_schema_version;
128
+ var CEAL_COMMAND_RESPONSE_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.bare_document_fields, response.prompt_field]);
129
+ var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_document_fields]);
130
+ var CEAL_COMMAND_RESPONSE_FOCUSED_PROMPT_CONTINUATION_DOCUMENT_FIELDS = Object.freeze([...response.focused_prompt_continuation_document_fields]);
131
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_COMMAND = response.discovery_command;
132
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_SCHEMA_VERSION = response.discovery_manifest_schema_version;
133
+ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([...response.discovery_manifest_document_fields]);
110
134
  var CEAL_COMMAND_RESPONSE_MAX_BYTES = response.absolute_transport_max_bytes;
111
135
 
112
136
  // packages/ceal-client-protocol/src/vocabulary.ts
@@ -142,7 +166,7 @@ var CEAL_OPERATION_RECOVERY_KINDS = vocabulary(["none", "reconcile", "compensate
142
166
  var CEAL_OPERATION_RECOVERY_STATUSES = vocabulary(["not_started", "active", "completed"]);
143
167
  var CEAL_OPERATION_PROVIDER_READBACK_AVAILABILITY = vocabulary(["not_started", "not_applicable", "not_available", "pending", "available"]);
144
168
  var CEAL_OPERATION_OFFERED_HANDOFF_STATES = vocabulary(["accepted", "rejected", "unknown"]);
145
- var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "profile_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
169
+ var CEAL_OPERATION_RECEIPT_AUTHORITY_KEYS = Object.freeze(["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]);
146
170
  var CEAL_OPERATION_APPROVAL_DISPOSITIONS = vocabulary([
147
171
  "approval_not_required_by_policy",
148
172
  "interactive_pending",
@@ -157,6 +181,8 @@ var CEAL_CAPABILITY_READINESS_VALUES = vocabulary(["ready", "degraded", "unavail
157
181
  var CEAL_TARGET_REQUIREMENTS = vocabulary(["required", "optional", "none"]);
158
182
  var CEAL_AUDIT_OUTCOMES = vocabulary(["succeeded", "denied", "failed"]);
159
183
  var CEAL_GATEWAY_PROVIDER_STEP_OUTCOMES = vocabulary(["completed", "rejected", "throttled", "failed"]);
184
+ var CEAL_GATEWAY_READ_REUSE_DISPOSITIONS = vocabulary(["response_cache_hit", "corpus_hit", "corpus_hit_after_revalidation", "corpus_partial_provider_supplement", "provider_direct", "provider_continuation", "reuse_unavailable"]);
185
+ var CEAL_GATEWAY_READ_REUSE_UNAVAILABLE_REASONS = vocabulary(["not_reported", "storage_unavailable", "coverage_incomplete", "freshness_refresh_required", "not_reusable", "bypassed"]);
160
186
  var CEAL_POLICY_DECISIONS = vocabulary(["allowed", "denied", "not_evaluated"]);
161
187
  var CEAL_CONNECTOR_ROUTE_PHASES = vocabulary(["scope_observation", "target_selection", "route_resolution"]);
162
188
  var CEAL_CONNECTOR_ROUTE_CAUSES = vocabulary(["provider_throttled", "provider_unavailable", "binding_invalid", "scope_limit_exceeded"]);
@@ -429,8 +455,10 @@ function requireIsoTimestamp(value, message) {
429
455
  var JSON_DESCRIPTION_CONTROL_CHARACTER = new RegExp("\\p{Cc}", "u");
430
456
 
431
457
  // packages/ceal-client-protocol/src/operation-contract-validation.ts
432
- var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["profile", "instance_binding", "target", "admission_recheck"]);
458
+ var CEAL_OPERATION_AUTHORITY_POLICY_KEYS = Object.freeze(["access_group", "instance_binding", "target", "admission_recheck"]);
433
459
  var MAX_OPERATION_INPUT_RESOLVER_BINDINGS = 96;
460
+ var CEAL_OPERATION_DESCRIPTOR_REQUIRED_ENVELOPE_KEYS = Object.freeze(["schema_version", "id", "input_contract", "result_contract", "policy"]);
461
+ var CEAL_OPERATION_DESCRIPTOR_OPTIONAL_ENVELOPE_KEYS = Object.freeze(["input_resolution", "summary"]);
434
462
  var CEAL_OPERATION_RESULT_KEYS = vocabulary(["ok", "operation_id", "operation_receipt", "schema_version", "value"]);
435
463
  var CEAL_OPERATION_COMPACT_RESULT_KEYS = vocabulary(["ok", "operation_evidence", "operation_id", "schema_version", "value"]);
436
464
 
@@ -504,6 +532,7 @@ var CEAL_SCHEMA_LITERALS = [
504
532
  "ceal.operation_descriptor.v1",
505
533
  "ceal.operation_error.v1",
506
534
  "ceal.operation_failure.v1",
535
+ "ceal.operation_failure.compact.v1",
507
536
  "ceal.operation_receipt.v1",
508
537
  "ceal.operation_result.v1",
509
538
  "ceal.operation_result.compact.v1",
@@ -529,17 +558,16 @@ var CEAL_BOUNDED_SERIES_CATALOG = Object.freeze({
529
558
  engagement_signal: (root) => join(root, "runtime-state", "slack-feedback.jsonl"),
530
559
  runtime_error: (root) => join(root, "runtime-state", "runtime-errors.jsonl"),
531
560
  turn_bridge_request: (root) => join(root, ".ceal", "turn-bridge", "requests.jsonl"),
532
- channel_log: (root) => join(root, "log.jsonl"),
533
561
  thread_run_events: (root) => join(root, "run-events.jsonl"),
534
562
  bounded_store_sidecar: (root) => `${root}.jsonl`,
535
563
  gateway_audit_archive: (root) => `${root}.jsonl`,
536
564
  gateway_capability_audit: (root) => join(root, "capability-audit.jsonl"),
537
565
  gateway_retrieval_waste_partition: (root) => `${root}.jsonl`,
538
566
  gateway_access_policy_publication: (root) => join(root, "access-policy-publications.jsonl"),
539
- gateway_profile_connector_control_audit: (root) => `${root}.audit.jsonl`,
540
- gateway_profile_connector_scope_audit: (root) => join(root, "profile-connector-scope-audit.jsonl"),
541
- gateway_profile_connector_activity_scope_audit: (root) => join(root, "profile-connector-activity-scope-audit.jsonl"),
542
- gateway_profile_connector_readiness_audit: (root) => join(root, "profile-connector-readiness.audit.jsonl"),
567
+ gateway_access_group_connector_control_audit: (root) => `${root}.audit.jsonl`,
568
+ gateway_access_group_connector_scope_audit: (root) => join(root, "profile-connector-scope-audit.jsonl"),
569
+ gateway_access_group_connector_activity_scope_audit: (root) => join(root, "profile-connector-activity-scope-audit.jsonl"),
570
+ gateway_access_group_connector_readiness_audit: (root) => join(root, "profile-connector-readiness.audit.jsonl"),
543
571
  gateway_organization_audit_ledger: (root) => join(root, "organization-ledger.jsonl"),
544
572
  gateway_personal_client_audit: (root) => join(root, "audit.jsonl"),
545
573
  gateway_personal_client_access_audit: (root) => join(root, "access-audit.jsonl"),
@@ -590,12 +618,6 @@ var CEAL_AGENT_SESSION_COMMIT_KEYS = vocabulary(["attempt_ref", "expected_sessio
590
618
  // packages/ceal-client-protocol/src/operation-next-actions.ts
591
619
  var CALLER_RECOVERABLE_NEXT_ACTION_VALUES = [
592
620
  "select_did_you_mean",
593
- // The graph, not the argument list, is what the caller must change: the
594
- // resolver that owns this input has no producing node upstream, and no edit
595
- // to the invocation can conjure one. `resolver_dependency_absent` carried no
596
- // remedy at all rather than borrow a word that means something else, so the
597
- // scorer read a fully-diagnosed, caller-fixable refusal as a failed run.
598
- "request.graph.append",
599
621
  "choose_new_output_path",
600
622
  "choose_new_idempotency_key",
601
623
  "restart_search",
@@ -647,8 +669,6 @@ var NON_REMEDY_NEXT_ACTION_VALUES = [
647
669
  "reconcile_occurrence",
648
670
  "reduce_request_size",
649
671
  "repair_or_adopt_session",
650
- "request.effect_approval.read",
651
- "request.run",
652
672
  "retry",
653
673
  // The owner -- a correlation hook, an approval hook -- is not serving right
654
674
  // now. The caller changes nothing and the same call succeeds once the owner
@@ -745,12 +765,12 @@ var CEAL_REQUEST_JSON_SCHEMA = {
745
765
  additionalProperties: false,
746
766
  properties: {
747
767
  instance_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
748
- profile_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
768
+ access_group_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
749
769
  principal_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
750
770
  execution_subject_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
751
771
  authority_revision_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source }
752
772
  },
753
- required: ["instance_ref", "profile_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
773
+ required: ["instance_ref", "access_group_ref", "principal_ref", "execution_subject_ref", "authority_revision_ref"]
754
774
  },
755
775
  prompt_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
756
776
  host_session_ref: { type: "string", minLength: 1, maxLength: 128, pattern: SAFE_REF.source },
@@ -876,7 +896,7 @@ var CEAL_HOST_OBSERVATION_KINDS = vocabulary(["prompt", "session", "turn", "mode
876
896
  function isCealHostPromptObservationValue(value) {
877
897
  return isOperationRecord(value) && Object.keys(value).length === 1 && isCealDigest(value.body_sha256);
878
898
  }
879
- var HOST_RESERVED_KEY = /^(?:admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
899
+ var HOST_RESERVED_KEY = /^(?:access_group|admission|approval|audit|authorization|cancellation|capability|effect|grant|occurrence|operation|policy|profile|provider_readback|receipt|reconciliation|replay|target|write_request)(?:_|$)/iu;
880
900
  function assertHostObservationValue(value, kind) {
881
901
  if (value === void 0) invalid("Ceal Host observation value is invalid.");
882
902
  if (kind === "prompt" && !isCealHostPromptObservationValue(value)) invalid("Ceal Host prompt observation must contain only its body digest.");
@@ -896,6 +916,14 @@ function inspectHostKeys(value) {
896
916
  }
897
917
  }
898
918
 
919
+ // packages/ceal-client-protocol/src/host-prompt-ref.ts
920
+ var CEAL_HOST_PROMPT_DIGEST_PATTERN = "^[a-f0-9]{64}$";
921
+ var PROMPT_DIGEST = new RegExp(CEAL_HOST_PROMPT_DIGEST_PATTERN, "u");
922
+ function hostProducerPromptRef(promptSha256) {
923
+ if (!PROMPT_DIGEST.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
924
+ return `ceal-host-prompt:${promptSha256}`;
925
+ }
926
+
899
927
  // packages/ceal-client-protocol/src/request-effect-approval.ts
900
928
  var CEAL_EFFECT_APPROVAL_DECISION_CHECK_PHRASES = Object.freeze([
901
929
  "observed after this approval was raised and before it expires",
@@ -911,6 +939,12 @@ var OWNER_WRITE_STATES = Object.freeze(["attempt_started", "provider_acknowledge
911
939
  var OWNER_EFFECT_STATES = Object.freeze(["none", "applied", "failed", "unknown", "reconciled"]);
912
940
  var OWNER_RECEIPT_STATES = Object.freeze(["pending", "available", "failed", "unknown", "reconciled"]);
913
941
 
942
+ // packages/ceal-client-protocol/src/thread-excerpt.ts
943
+ var CEAL_THREAD_RECENT_WINDOW = 6;
944
+ var CEAL_THREAD_LAST_APP_MESSAGES_WINDOW = 3;
945
+ var CEAL_THREAD_OLDER_SUMMARY_WINDOW = 4;
946
+ var CEAL_FED_THREAD_MESSAGE_LIMIT = CEAL_THREAD_RECENT_WINDOW + CEAL_THREAD_OLDER_SUMMARY_WINDOW + CEAL_THREAD_LAST_APP_MESSAGES_WINDOW;
947
+
914
948
  // packages/ceal-client-protocol/src/request-graph-readiness.ts
915
949
  var REQUEST_GRAPH_PRODUCER_TO_APPEND_SCHEMA = {
916
950
  type: "object",
@@ -1010,6 +1044,13 @@ function exactKeys(value, expected) {
1010
1044
  var REQUIRED_FIELDS = Object.freeze(["schema_version", "operation_id", "local_path", "content_json_pointer", "size_bytes", "sha256", "read_argv"]);
1011
1045
  var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS, "local_result_root", "model_disclosure"]);
1012
1046
 
1047
+ // packages/ceal-client-protocol/src/session-start-affordance.ts
1048
+ var CEAL_SESSION_ENTRY_INVOCATION = "ceal";
1049
+ var CEAL_LINK_RESOURCE_PRECEDENCE = `When the user asks to use Ceal or provides a link to information that may be available through installed organizational capabilities, run bare \`${CEAL_SESSION_ENTRY_INVOCATION}\`. The Host supplies the current user prompt without exposing it to the client command, and the Gateway returns the applicable entry in that one response. Treat a supplied link as a candidate Ceal resource rather than a public web-search target. Reach for a generic web fetch or web search only when the Gateway offered nothing.`;
1050
+
1051
+ // packages/ceal-client-protocol/src/discovery-manifest.ts
1052
+ var CEAL_DISCOVERY_MANIFEST_CONNECTOR_KINDS = vocabulary(["github", "google-workspace", "notion", "slack"]);
1053
+
1013
1054
  // packages/ceal-client-protocol/src/conversation-contracts.ts
1014
1055
  var CEAL_APPROVAL_POLICY_KINDS = vocabulary(["requester_only", "named_users", "role_based"]);
1015
1056
  var CEAL_APPROVAL_TARGET_KINDS = vocabulary([
@@ -1226,7 +1267,7 @@ var CEAL_PRESENTATION_INTENTS = vocabulary(["progress", ...CEAL_FINAL_PRESENTATI
1226
1267
 
1227
1268
  // packages/ceal-client-protocol/src/personal-client-vocabulary.ts
1228
1269
  var CEAL_PERSONAL_CLIENT_BINDING_KEYS = vocabulary([
1229
- "profile_ref",
1270
+ "access_group_ref",
1230
1271
  "membership_ref",
1231
1272
  "registration_ref",
1232
1273
  "client_ref",
@@ -1386,7 +1427,6 @@ var HOST_PRODUCER_FRAME_SCHEMA = "ceal.host_producer_frame.v1";
1386
1427
  var HOST_PRODUCER_MAX_JSON_BYTES = 262144;
1387
1428
  var HOST_PRODUCER_FRAME_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
1388
1429
  var SAFE_REF2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
1389
- var DIGEST2 = /^[a-f0-9]{64}$/u;
1390
1430
  var PRODUCERS = /* @__PURE__ */ new Set(["codex", "claude"]);
1391
1431
  var HOST_PRODUCER_FRAME_KINDS = ["session_started", "turn_started", "user_input", "turn_terminal", "producer_status"];
1392
1432
  var FRAME_KINDS = new Set(HOST_PRODUCER_FRAME_KINDS);
@@ -1450,10 +1490,6 @@ function hostProducerInputRef(hostSourceRef, frame, localSessionRef, localTurnRe
1450
1490
  function hostProducerSubmissionRef(hostSourceRef, frame) {
1451
1491
  return requiredIdentity(hostProducerIdentityRefs(hostSourceRef, frame).submission_ref);
1452
1492
  }
1453
- function hostProducerPromptRef(promptSha256) {
1454
- if (!DIGEST2.test(promptSha256)) throw new TypeError("Canonical Host prompt digest is invalid.");
1455
- return `ceal-host-prompt:${promptSha256}`;
1456
- }
1457
1493
  function opaqueHostSourceRef(value) {
1458
1494
  return typeof value === "string" && SAFE_REF2.test(value) && !value.startsWith("ceal-host-source:");
1459
1495
  }
@@ -1752,6 +1788,7 @@ function errorCode3(error) {
1752
1788
  var DEFAULT_LIMITS = { global_count: 8192, global_bytes: 64 * 1024 * 1024, producer_count: 4096, producer_bytes: 32 * 1024 * 1024 };
1753
1789
  var PRODUCER_ORDER = ["codex", "claude"];
1754
1790
  var RETRY_SECONDS = [1, 2, 4, 8, 16, 32, 60];
1791
+ var MAX_RETRYABLE_ATTEMPTS = RETRY_SECONDS.length + 10;
1755
1792
  var RelayAdmissionStore = class {
1756
1793
  tail = Promise.resolve();
1757
1794
  root;
@@ -1822,7 +1859,8 @@ var RelayAdmissionStore = class {
1822
1859
  if (!head || head.retry_at_ms > options.now_ms) continue;
1823
1860
  const input = { frame: structuredClone(head.frame), host_source_ref: options.host_source_ref, submission_ref: hostProducerSubmissionRef(options.host_source_ref, head.frame) };
1824
1861
  const outcome = await deliver(input);
1825
- if (outcome.status === "retryable") {
1862
+ const exhausted = retryExhausted(outcome, head);
1863
+ if (outcome.status === "retryable" && !exhausted) {
1826
1864
  scheduleRetry(head, options.now_ms, outcome.reason);
1827
1865
  retained.push(input.submission_ref);
1828
1866
  await this.write(state);
@@ -1830,9 +1868,9 @@ var RelayAdmissionStore = class {
1830
1868
  }
1831
1869
  const installation2 = state.installations[installationKey(head.frame)];
1832
1870
  if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
1833
- if (outcome.status === "refused") {
1871
+ if (outcome.status === "refused" || exhausted) {
1834
1872
  await this.quarantine.retainFrame(head.frame, "gateway_refused");
1835
- installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, code: outcome.code, message: outcome.message, refused_at_ms: options.now_ms };
1873
+ installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
1836
1874
  refused.push(input.submission_ref);
1837
1875
  } else {
1838
1876
  await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
@@ -1866,6 +1904,14 @@ function replayCode(existing, hash, sequence, installation2) {
1866
1904
  function bytes(entries) {
1867
1905
  return entries.reduce((total, entry2) => total + entry2.charged_bytes, 0);
1868
1906
  }
1907
+ function retryExhausted(outcome, entry2) {
1908
+ return outcome.status === "retryable" && entry2.retry_attempts >= MAX_RETRYABLE_ATTEMPTS;
1909
+ }
1910
+ function refusalCause(outcome, entry2) {
1911
+ if (outcome.status === "refused") return { code: outcome.code, message: outcome.message };
1912
+ const reason = outcome.status === "retryable" ? outcome.reason ?? "no reason reported" : "no reason reported";
1913
+ return { code: "retry_exhausted", message: `Gateway delivery stayed retryable through ${entry2.retry_attempts} attempts: ${reason}` };
1914
+ }
1869
1915
  function scheduleRetry(entry2, nowMs, reason) {
1870
1916
  if (reason === void 0) delete entry2.retry_reason;
1871
1917
  else entry2.retry_reason = reason;
@@ -2622,6 +2668,52 @@ function acknowledgement(value) {
2622
2668
  // host/relay/src/relay-ipc.ts
2623
2669
  import { chmod, lstat as lstat3, unlink as unlink2 } from "node:fs/promises";
2624
2670
  import { createConnection, createServer } from "node:net";
2671
+
2672
+ // host/relay/src/current-prompt-custody.ts
2673
+ import { createHash as createHash4 } from "node:crypto";
2674
+ var HOST_CURRENT_PROMPT_MAX_BYTES = 256 * 1024;
2675
+ var MAX_CURRENT_PROMPTS = 1024;
2676
+ var HostCurrentPromptCustody = class {
2677
+ #records = /* @__PURE__ */ new Map();
2678
+ #consumed = /* @__PURE__ */ new Map();
2679
+ #now;
2680
+ constructor(now = Date.now) {
2681
+ this.#now = now;
2682
+ }
2683
+ register(identity, prompt, expiresAt) {
2684
+ const bytes2 = Buffer.byteLength(prompt, "utf8");
2685
+ const expiry = Date.parse(expiresAt);
2686
+ if (bytes2 === 0 || bytes2 > HOST_CURRENT_PROMPT_MAX_BYTES || !Number.isFinite(expiry) || expiry <= this.#now()) throw new TypeError("current_prompt_unavailable");
2687
+ if (hostProducerPromptRef(createHash4("sha256").update(prompt, "utf8").digest("hex")) !== identity.prompt_ref) throw new TypeError("current_prompt_unavailable");
2688
+ this.#purge();
2689
+ const key = promptKey(identity);
2690
+ if (this.#consumed.has(key)) return;
2691
+ if (!this.#records.has(key) && this.#records.size + this.#consumed.size >= MAX_CURRENT_PROMPTS) throw new TypeError("current_prompt_unavailable");
2692
+ this.#records.set(key, { prompt, expires_at_ms: expiry });
2693
+ }
2694
+ /** Transfer this turn's prompt into at most one authenticated invocation. */
2695
+ take(identity) {
2696
+ this.#purge();
2697
+ const key = promptKey(identity);
2698
+ const prompt = this.#records.get(key)?.prompt;
2699
+ if (prompt !== void 0) {
2700
+ const expiresAt = this.#records.get(key)?.expires_at_ms;
2701
+ this.#records.delete(key);
2702
+ if (expiresAt !== void 0) this.#consumed.set(key, expiresAt);
2703
+ }
2704
+ return prompt;
2705
+ }
2706
+ #purge() {
2707
+ const now = this.#now();
2708
+ for (const [key, value] of this.#records) if (value.expires_at_ms <= now) this.#records.delete(key);
2709
+ for (const [key, expiresAt] of this.#consumed) if (expiresAt <= now) this.#consumed.delete(key);
2710
+ }
2711
+ };
2712
+ function promptKey(value) {
2713
+ return [value.producer_id, value.producer_installation_ref, value.local_session_ref, value.local_turn_ref, value.prompt_ref].join("\0");
2714
+ }
2715
+
2716
+ // host/relay/src/relay-ipc.ts
2625
2717
  var HOST_RELAY_REQUEST_BINDING_KEYS = Object.freeze([
2626
2718
  "schema_version",
2627
2719
  "producer_id",
@@ -2642,6 +2734,8 @@ var HOST_RELAY_BINDING_QUERY_SCHEMA = "ceal.host_relay_binding_query.v1";
2642
2734
  var HOST_RELAY_BINDING_RESULT_SCHEMA = "ceal.host_relay_binding_result.v1";
2643
2735
  var HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA = "ceal.host_relay_invocation_context_query.v1";
2644
2736
  var HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA = "ceal.host_relay_invocation_context_result.v1";
2737
+ var HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA = "ceal.host_relay_current_prompt_register.v1";
2738
+ var HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA = "ceal.host_relay_current_prompt_result.v1";
2645
2739
  var HOST_RELAY_IPC_LENGTH_BYTES = Uint32Array.BYTES_PER_ELEMENT;
2646
2740
  var HostRelayIpcError = class extends Error {
2647
2741
  code;
@@ -2655,7 +2749,8 @@ async function startHostRelayIpcServer(options) {
2655
2749
  const active = /* @__PURE__ */ new Map();
2656
2750
  const sockets = /* @__PURE__ */ new Set();
2657
2751
  const quarantine = options.quarantine ?? options.admission.quarantine;
2658
- const server = createServer((socket) => serveSocket(socket, options.admission, options.bindings, options.mintInvocationContext, quarantine, active, sockets));
2752
+ const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
2753
+ const server = createServer((socket) => serveSocket(socket, options.admission, options.bindings, currentPrompts, options.mintInvocationContext, quarantine, active, sockets));
2659
2754
  await listen(server, options.endpoint);
2660
2755
  if (process.platform !== "win32") await chmod(options.endpoint, 384);
2661
2756
  return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
@@ -2667,12 +2762,12 @@ function encodeHostRelayIpcResponse(response2) {
2667
2762
  body.copy(result2, HOST_RELAY_IPC_LENGTH_BYTES);
2668
2763
  return result2;
2669
2764
  }
2670
- function serveSocket(socket, admission, bindings, mintInvocationContext, quarantine, active, sockets) {
2671
- const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve() };
2765
+ function serveSocket(socket, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active, sockets) {
2766
+ const state = { buffer: Buffer.alloc(0), closed: false, tail: Promise.resolve(), abort: new AbortController() };
2672
2767
  sockets.add(socket);
2673
2768
  socket.on("data", (chunk) => {
2674
2769
  state.buffer = Buffer.concat([state.buffer, Buffer.from(chunk)]);
2675
- state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings, mintInvocationContext, quarantine, active)).catch(() => {
2770
+ state.tail = state.tail.then(() => drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)).catch(() => {
2676
2771
  writeResponse(socket, errorResponse("relay_unavailable"));
2677
2772
  socket.end();
2678
2773
  });
@@ -2680,24 +2775,26 @@ function serveSocket(socket, admission, bindings, mintInvocationContext, quarant
2680
2775
  socket.once("error", () => closeConnection(socket, state, active, sockets));
2681
2776
  socket.once("close", () => closeConnection(socket, state, active, sockets));
2682
2777
  socket.once("end", () => {
2683
- if (state.buffer.length > 0) void quarantine.retainMalformed(state.buffer, "frame_truncated").finally(() => {
2778
+ if (state.buffer.length > 0 && currentPromptWire(state.buffer)) {
2779
+ writeCurrentPromptResponse(socket, "current_prompt_unavailable");
2780
+ socket.end();
2781
+ } else if (state.buffer.length > 0) void quarantine.retainMalformed(state.buffer, "frame_truncated").finally(() => {
2684
2782
  writeResponse(socket, errorResponse("frame_truncated"));
2685
2783
  socket.end();
2686
2784
  });
2687
2785
  else socket.end();
2688
2786
  });
2689
2787
  }
2690
- async function drainFrames(socket, state, admission, bindings, mintInvocationContext, quarantine, active) {
2691
- while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings, mintInvocationContext, quarantine, active)) {
2788
+ async function drainFrames(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
2789
+ while (!state.closed && state.buffer.length >= HOST_RELAY_IPC_LENGTH_BYTES && await processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active)) {
2692
2790
  }
2693
2791
  }
2694
- async function processBufferedRequest(socket, state, admission, bindings, mintInvocationContext, quarantine, active) {
2792
+ async function processBufferedRequest(socket, state, admission, bindings, currentPrompts, mintInvocationContext2, quarantine, active) {
2695
2793
  const length = state.buffer.readUInt32BE(0);
2696
- if (length === 0 || length > HOST_PRODUCER_MAX_JSON_BYTES) {
2697
- const code = length === 0 ? "invalid_frame_length" : "frame_too_large";
2698
- const raw = state.buffer.subarray(0, Math.min(state.buffer.length, length + HOST_RELAY_IPC_LENGTH_BYTES));
2699
- await quarantine.retainMalformed(raw, code);
2700
- writeResponse(socket, errorResponse(code));
2794
+ const promptWire = currentPromptWire(state.buffer);
2795
+ const maximum = promptWire ? HOST_CURRENT_PROMPT_MAX_BYTES + 4096 : HOST_PRODUCER_MAX_JSON_BYTES;
2796
+ if (length === 0 || length > maximum) {
2797
+ await refuseInvalidBufferedRequest(socket, state.buffer, length, promptWire, quarantine);
2701
2798
  state.buffer = Buffer.alloc(0);
2702
2799
  socket.end();
2703
2800
  return false;
@@ -2709,15 +2806,40 @@ async function processBufferedRequest(socket, state, admission, bindings, mintIn
2709
2806
  try {
2710
2807
  request2 = decodeIpcRequest(encoded);
2711
2808
  } catch (error) {
2712
- const code = error instanceof HostProducerFrameError ? error.code : "invalid_frame_shape";
2713
- await quarantine.retainMalformed(encoded, code);
2714
- writeResponse(socket, errorResponse(code));
2809
+ await refuseMalformedRequest(socket, encoded, promptWire, error, quarantine);
2810
+ return true;
2811
+ }
2812
+ if (request2.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
2813
+ try {
2814
+ currentPrompts.register(request2, request2.current_prompt, request2.context_expires_at);
2815
+ writeCurrentPromptResponse(socket, "registered");
2816
+ } catch {
2817
+ writeCurrentPromptResponse(socket, "current_prompt_unavailable");
2818
+ }
2715
2819
  return true;
2716
2820
  }
2717
- if (await processHostQuery(socket, request2, bindings, mintInvocationContext)) return true;
2821
+ if (await processHostQuery(socket, request2, bindings, currentPrompts, mintInvocationContext2, state.abort.signal)) return true;
2718
2822
  await processProducerRequest(socket, state, request2, encoded, admission, quarantine, active);
2719
2823
  return true;
2720
2824
  }
2825
+ async function refuseInvalidBufferedRequest(socket, rawBuffer, length, promptWire, quarantine) {
2826
+ if (promptWire) {
2827
+ writeCurrentPromptResponse(socket, "current_prompt_unavailable");
2828
+ return;
2829
+ }
2830
+ const code = length === 0 ? "invalid_frame_length" : "frame_too_large";
2831
+ await quarantine.retainMalformed(rawBuffer.subarray(0, Math.min(rawBuffer.length, length + HOST_RELAY_IPC_LENGTH_BYTES)), code);
2832
+ writeResponse(socket, errorResponse(code));
2833
+ }
2834
+ async function refuseMalformedRequest(socket, encoded, promptWire, error, quarantine) {
2835
+ if (promptWire) {
2836
+ writeCurrentPromptResponse(socket, "current_prompt_unavailable");
2837
+ return;
2838
+ }
2839
+ const code = error instanceof HostProducerFrameError ? error.code : "invalid_frame_shape";
2840
+ await quarantine.retainMalformed(encoded, code);
2841
+ writeResponse(socket, errorResponse(code));
2842
+ }
2721
2843
  async function processProducerRequest(socket, state, request2, encoded, admission, quarantine, active) {
2722
2844
  if (!("producer_epoch" in request2)) throw new HostRelayIpcError("relay_unavailable");
2723
2845
  const ownership = claimProducer(socket, state, request2, active);
@@ -2729,13 +2851,13 @@ async function processProducerRequest(socket, state, request2, encoded, admissio
2729
2851
  }
2730
2852
  writeResponse(socket, admissionResponse(await admission.admit(request2)));
2731
2853
  }
2732
- async function processHostQuery(socket, request2, bindings, mint) {
2854
+ async function processHostQuery(socket, request2, bindings, currentPrompts, mint, signal) {
2733
2855
  if (request2.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
2734
2856
  writeBindingResponse(socket, await bindings.query(bindingQueryFromRequest(request2)));
2735
2857
  return true;
2736
2858
  }
2737
2859
  if (request2.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
2738
- writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, mint));
2860
+ writeInvocationContextResponse(socket, await resolveInvocationContext(request2, bindings, currentPrompts, mint, signal));
2739
2861
  return true;
2740
2862
  }
2741
2863
  return false;
@@ -2755,6 +2877,7 @@ function claimProducer(socket, state, frame, active) {
2755
2877
  }
2756
2878
  function closeConnection(socket, state, active, sockets) {
2757
2879
  state.closed = true;
2880
+ state.abort.abort();
2758
2881
  sockets.delete(socket);
2759
2882
  if (state.producer_key !== void 0 && active.get(state.producer_key)?.socket === socket) active.delete(state.producer_key);
2760
2883
  }
@@ -2768,11 +2891,15 @@ function writeBindingResponse(socket, result2) {
2768
2891
  function writeInvocationContextResponse(socket, response2) {
2769
2892
  if (!socket.destroyed) socket.write(encodeLengthPrefixed(response2));
2770
2893
  }
2771
- async function resolveInvocationContext(request2, bindings, mint) {
2894
+ function writeCurrentPromptResponse(socket, status) {
2895
+ if (!socket.destroyed) socket.write(encodeLengthPrefixed({ schema_version: HOST_RELAY_CURRENT_PROMPT_RESULT_SCHEMA, status }));
2896
+ }
2897
+ async function resolveInvocationContext(request2, bindings, currentPrompts, mint, signal) {
2772
2898
  if (mint === void 0) throw new HostRelayIpcError("relay_unavailable");
2773
2899
  const binding = await bindings.query(bindingQueryFromRequest(request2));
2774
2900
  if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, ...binding };
2775
- const result2 = await mint({ client_nonce: request2.client_nonce, context_expires_at: binding.binding.context_expires_at ?? binding.binding.bound_at, request_work_context: relayRequestWorkContextFromBinding(binding.binding) }, new AbortController().signal);
2901
+ const currentPrompt = currentPrompts.take({ producer_id: request2.producer_id, producer_installation_ref: request2.producer_installation_ref, local_session_ref: request2.local_session_ref, local_turn_ref: request2.local_turn_ref, prompt_ref: binding.binding.prompt_ref });
2902
+ const result2 = await mint({ client_nonce: request2.client_nonce, context_expires_at: binding.binding.context_expires_at ?? binding.binding.bound_at, request_work_context: relayRequestWorkContextFromBinding(binding.binding), ...currentPrompt === void 0 ? {} : { current_prompt: currentPrompt } }, signal);
2776
2903
  return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "ready", result: result2 };
2777
2904
  }
2778
2905
  function admissionResponse(result2) {
@@ -2788,16 +2915,29 @@ function record4(value) {
2788
2915
  return value !== null && typeof value === "object" && !Array.isArray(value);
2789
2916
  }
2790
2917
  function decodeIpcRequest(input) {
2791
- const value = decodeLengthPrefixedJson(input, HOST_PRODUCER_MAX_JSON_BYTES);
2792
- if (value !== null && record4(value) && value.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
2918
+ const value = decodeLengthPrefixedJson(input, Math.max(HOST_PRODUCER_MAX_JSON_BYTES, HOST_CURRENT_PROMPT_MAX_BYTES + 4096));
2919
+ const local = decodeLocalRequest(value);
2920
+ if (local !== void 0) return local;
2921
+ return decodeHostProducerFrame(input);
2922
+ }
2923
+ function decodeLocalRequest(value) {
2924
+ if (!record4(value)) return void 0;
2925
+ if (value.schema_version === HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) {
2926
+ if (!validCurrentPromptRegisterRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
2927
+ return value;
2928
+ }
2929
+ if (value.schema_version === HOST_RELAY_BINDING_QUERY_SCHEMA) {
2793
2930
  if (!validBindingQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
2794
2931
  return value;
2795
2932
  }
2796
- if (value !== null && record4(value) && value.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
2933
+ if (value.schema_version === HOST_RELAY_INVOCATION_CONTEXT_QUERY_SCHEMA) {
2797
2934
  if (!validInvocationContextQueryRequest(value)) throw new HostProducerFrameError("invalid_frame_shape");
2798
2935
  return value;
2799
2936
  }
2800
- return decodeHostProducerFrame(input);
2937
+ return void 0;
2938
+ }
2939
+ function validCurrentPromptRegisterRequest(value) {
2940
+ return validQueryIdentity(value, HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA) && exactKeys4(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref", "prompt_ref", "current_prompt", "context_expires_at"]) && safeRef3(value.prompt_ref) && typeof value.current_prompt === "string" && Buffer.byteLength(value.current_prompt, "utf8") > 0 && Buffer.byteLength(value.current_prompt, "utf8") <= HOST_CURRENT_PROMPT_MAX_BYTES && validTimestamp2(value.context_expires_at);
2801
2941
  }
2802
2942
  function validBindingQueryRequest(value) {
2803
2943
  return validQueryIdentity(value, HOST_RELAY_BINDING_QUERY_SCHEMA) && exactKeys4(value, ["schema_version", "producer_id", "producer_installation_ref", "local_session_ref", "local_turn_ref"]);
@@ -2830,12 +2970,18 @@ function encodeLengthPrefixed(value) {
2830
2970
  body.copy(output, HOST_RELAY_IPC_LENGTH_BYTES);
2831
2971
  return output;
2832
2972
  }
2973
+ function currentPromptWire(value) {
2974
+ return value.subarray(HOST_RELAY_IPC_LENGTH_BYTES, Math.min(value.length, HOST_RELAY_IPC_LENGTH_BYTES + 128)).includes(Buffer.from(`"schema_version":"${HOST_RELAY_CURRENT_PROMPT_REGISTER_SCHEMA}"`, "utf8"));
2975
+ }
2833
2976
  function exactKeys4(value, keys) {
2834
2977
  return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2835
2978
  }
2836
2979
  function safeRef3(value) {
2837
2980
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(value);
2838
2981
  }
2982
+ function validTimestamp2(value) {
2983
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
2984
+ }
2839
2985
  async function assertEndpointVacant(endpoint) {
2840
2986
  try {
2841
2987
  await lstat3(endpoint);
@@ -2931,7 +3077,7 @@ async function serveHostRelay(config, signal, dependencies = {}) {
2931
3077
  } });
2932
3078
  let server;
2933
3079
  try {
2934
- server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) => gateway.mintInvocationContext(input, invocationSignal) });
3080
+ server = await (dependencies.startIpc ?? startHostRelayIpcServer)({ endpoint: config.ipc_endpoint, admission, bindings, mintInvocationContext: (input, invocationSignal) => mintInvocationContext(gateway, input, invocationSignal, config.gateway_timeout_ms, dependencies.observeInvocationMint ?? reportInvocationMint, dependencies.scheduleInvocationMintDeadline ?? scheduleInvocationMintDeadline) });
2935
3081
  while (!signal.aborted) {
2936
3082
  const round = await admission.drainRound((input) => bridge.deliver(input), { now_ms: (dependencies.now ?? Date.now)(), host_source_ref: config.host_source_ref });
2937
3083
  if (round.delivered.length === 0 && round.refused.length === 0) await (dependencies.wait ?? ((milliseconds, waitSignal) => waitForAbort(waitSignal, milliseconds)))(config.drain_interval_ms, signal);
@@ -2940,6 +3086,41 @@ async function serveHostRelay(config, signal, dependencies = {}) {
2940
3086
  await server?.close();
2941
3087
  }
2942
3088
  }
3089
+ async function mintInvocationContext(gateway, input, callerSignal, timeoutMs, observe, scheduleDeadline) {
3090
+ const controller2 = new AbortController();
3091
+ const started = process.hrtime.bigint();
3092
+ let cancellation = null;
3093
+ let outcome = "failed";
3094
+ const cancel = (cause) => {
3095
+ if (cancellation === null) cancellation = cause;
3096
+ controller2.abort();
3097
+ };
3098
+ const callerCancelled = () => cancel("caller_cancelled");
3099
+ const clearDeadline = scheduleDeadline(() => cancel("deadline"), timeoutMs);
3100
+ if (callerSignal.aborted) callerCancelled();
3101
+ else callerSignal.addEventListener("abort", callerCancelled, { once: true });
3102
+ const cancelled = new Promise((_resolve, reject) => controller2.signal.addEventListener("abort", () => reject(new Error("invocation mint cancelled")), { once: true }));
3103
+ try {
3104
+ const result2 = await Promise.race([gateway.mintInvocationContext(input, controller2.signal), cancelled]);
3105
+ outcome = "completed";
3106
+ return result2;
3107
+ } catch (error) {
3108
+ outcome = cancellation ?? "failed";
3109
+ throw error;
3110
+ } finally {
3111
+ clearDeadline();
3112
+ callerSignal.removeEventListener("abort", callerCancelled);
3113
+ observe({ outcome, elapsed_ms: Number((process.hrtime.bigint() - started) / 1000000n) });
3114
+ }
3115
+ }
3116
+ function scheduleInvocationMintDeadline(expire, milliseconds) {
3117
+ const timeout = setTimeout(expire, milliseconds);
3118
+ return () => clearTimeout(timeout);
3119
+ }
3120
+ function reportInvocationMint(observation) {
3121
+ process.stderr.write(`[host-relay-invocation-mint] outcome=${observation.outcome} elapsed_ms=${observation.elapsed_ms}
3122
+ `);
3123
+ }
2943
3124
  async function runHostRelayCli(args, signal, dependencies = {}) {
2944
3125
  try {
2945
3126
  const configPath = parseServeArgs(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corca-org/ceal-host-win32-x64",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",