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

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.
@@ -200,6 +200,9 @@ var CEAL_COMMAND_RESPONSE_DISCOVERY_MANIFEST_DOCUMENT_FIELDS = Object.freeze([..
200
200
  function vocabulary(words) {
201
201
  return Object.freeze(words);
202
202
  }
203
+ function isVocabularyWord(words, value) {
204
+ return words.some((word) => word === value);
205
+ }
203
206
 
204
207
  // packages/ceal-client-protocol/src/gateway-response-types.ts
205
208
  var CEAL_OPERATION_READINESS_VALUES = vocabulary(["ready", "degraded", "unavailable", "unknown"]);
@@ -950,7 +953,7 @@ var OPTIONAL_FIELDS = CEAL_CLIENT_WIRE_CONTRACT.command_response.bare_document_o
950
953
  // packages/ceal-client-protocol/src/resource-row.ts
951
954
  var CEAL_RESOURCE_SEARCH_ORDERS = vocabulary(["relevance", "modified", "viewed", "created"]);
952
955
  var CEAL_RESOURCE_SEARCH_DIRECTIONS = vocabulary(["ascending", "descending"]);
953
- var CEAL_RESOURCE_SEARCH_FILTERS = vocabulary(["query", "modified_since", "since", "until", "authored_by_me", "include_replies", "kinds", "container_ref", "container_refs", "container_names", "addressed_to_me", "unread"]);
956
+ var CEAL_RESOURCE_SEARCH_FILTERS = vocabulary(["query", "modified_since", "since", "until", "authored_by_me", "authored_by", "include_replies", "kinds", "container_ref", "container_refs", "container_names", "addressed_to_me", "unread"]);
954
957
  var CEAL_RESOURCE_TIME_BASES = vocabulary(["created", "modified", "viewed"]);
955
958
  var CEAL_REPOSITORY_VISIBILITIES = vocabulary(["public", "private", "internal"]);
956
959
  var CEAL_ACTIVITY_V3_KINDS = vocabulary(["authored", "edited", "messaged", "responded"]);
@@ -1029,6 +1032,7 @@ var RESOURCE_ROW_KEY_RULES = Object.freeze({
1029
1032
  ref: { required: true, timestamp: false },
1030
1033
  next: { required: true, timestamp: false },
1031
1034
  kind: { required: true, timestamp: false },
1035
+ matched_kinds: { required: false, timestamp: false },
1032
1036
  title: { required: true, timestamp: false },
1033
1037
  container_label: { required: true, timestamp: false },
1034
1038
  container_ref: { required: false, timestamp: false },
@@ -1419,6 +1423,16 @@ var CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_MAX_BYTES = new TextEncoder().enc
1419
1423
  expires_at: (/* @__PURE__ */ new Date("+010000-01-01T00:00:00.000Z")).toISOString()
1420
1424
  })}
1421
1425
  `).byteLength;
1426
+ var CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS = vocabulary([
1427
+ "request_authority_unavailable",
1428
+ "request_missing",
1429
+ "authority_mismatch",
1430
+ "host_source_mismatch",
1431
+ "host_session_mismatch",
1432
+ "host_turn_mismatch",
1433
+ "host_input_mismatch",
1434
+ "host_prompt_mismatch"
1435
+ ]);
1422
1436
  function decodeCealHostInvocationAuthenticationResult(value, now = /* @__PURE__ */ new Date()) {
1423
1437
  if (!isCealJsonRecord(value) || !exactKeys(value, ["schema_version", "context_token", "expires_at"]) || value.schema_version !== CEAL_HOST_INVOCATION_AUTHENTICATION_RESULT_SCHEMA || typeof value.context_token !== "string" || !CEAL_HOST_CONTEXT_TOKEN_PATTERN.test(value.context_token) || typeof value.expires_at !== "string" || !validFutureTimestamp(value.expires_at, now)) {
1424
1438
  throw new TypeError("The Host invocation authentication result is invalid.");
@@ -1437,8 +1451,8 @@ function exactKeys(value, expected) {
1437
1451
  // packages/ceal-client-protocol/src/client-result-materialization.ts
1438
1452
  var CEAL_UNREAD_REASONS = vocabulary(["blocked", "unavailable", "too_large", "unsupported", "download_failed", "permission_denied"]);
1439
1453
  var CEAL_MODEL_VISIBLE_COMMAND_OUTPUT_MAX_BYTES = 32 * 1024;
1440
- var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id"]);
1441
- var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "read_argv", "local_result_root", "continue_argv", "model_disclosure", "item_read_argv"]);
1454
+ var REQUIRED_FIELDS2 = Object.freeze(["schema_version", "operation_id", "read_argv"]);
1455
+ var FIELDS = /* @__PURE__ */ new Set([...REQUIRED_FIELDS2, "local_result_root", "continue_argv", "model_disclosure"]);
1442
1456
 
1443
1457
  // packages/ceal-client-protocol/src/gateway-cache-origin-validation.ts
1444
1458
  var CEAL_MAX_CACHE_ORIGIN_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -1649,7 +1663,7 @@ function assertHostRelaySourcePaths(stateRoot, config, platform = process.platfo
1649
1663
  // host/relay/src/host-relay-runtime.ts
1650
1664
  import { O_NOFOLLOW as O_NOFOLLOW3, O_RDONLY as O_RDONLY4 } from "node:constants";
1651
1665
  import { lstat as lstat4, open as open5 } from "node:fs/promises";
1652
- import { dirname as dirname3, join as join6 } from "node:path";
1666
+ import { dirname as dirname4, join as join7 } from "node:path";
1653
1667
 
1654
1668
  // host/abortable-wait.ts
1655
1669
  function waitForAbort(signal, milliseconds) {
@@ -1753,6 +1767,9 @@ var HostProducerFrameError = class extends Error {
1753
1767
  this.code = code;
1754
1768
  }
1755
1769
  };
1770
+ function assertHostProducerFrame(value) {
1771
+ validateFrame(value);
1772
+ }
1756
1773
  function encodeHostProducerFrame(frame) {
1757
1774
  validateFrame(frame);
1758
1775
  const json = Buffer.from(JSON.stringify(frame), "utf8");
@@ -2433,31 +2450,53 @@ var RelayAdmissionStore = class {
2433
2450
  for (const producerId of PRODUCER_ORDER) {
2434
2451
  const head = state.entries.find((entry2) => entry2.producer_id === producerId);
2435
2452
  if (!head || head.retry_at_ms > options.now_ms) continue;
2436
- const input = { frame: structuredClone(head.frame), host_source_ref: options.host_source_ref, submission_ref: hostProducerSubmissionRef(options.host_source_ref, head.frame) };
2437
- const outcome = await deliver(input);
2438
- const exhausted = retryExhausted(outcome, head);
2439
- if (outcome.status === "retryable" && !exhausted) {
2440
- scheduleRetry(head, options.now_ms, outcome.reason);
2441
- retained.push(input.submission_ref);
2442
- await this.write(state);
2443
- continue;
2444
- }
2445
- const installation2 = state.installations[installationKey(head.frame)];
2446
- if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
2447
- if (outcome.status === "refused" || exhausted) {
2448
- await this.quarantine.retainFrame(head.frame, "gateway_refused");
2449
- installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
2450
- refused.push(input.submission_ref);
2451
- } else {
2452
- await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
2453
- delivered.push(input.submission_ref);
2454
- }
2455
- state.entries.splice(state.entries.indexOf(head), 1);
2456
- installation2.delivered_through_sequence = Math.max(installation2.delivered_through_sequence, head.sequence);
2457
- await this.write(state);
2453
+ if (await this.refusePoisonHead(state, head, options, refused)) continue;
2454
+ await this.deliverHead(state, head, deliver, options, delivered, retained, refused);
2458
2455
  }
2459
2456
  return { delivered, retained, refused };
2460
2457
  }
2458
+ async deliverHead(state, head, deliver, options, delivered, retained, refused) {
2459
+ const input = { frame: structuredClone(head.frame), host_source_ref: options.host_source_ref, submission_ref: hostProducerSubmissionRef(options.host_source_ref, head.frame) };
2460
+ const outcome = await deliver(input);
2461
+ const exhausted = retryExhausted(outcome, head);
2462
+ if (outcome.status === "retryable" && !exhausted) {
2463
+ scheduleRetry(head, options.now_ms, outcome.reason);
2464
+ retained.push(input.submission_ref);
2465
+ await this.write(state);
2466
+ return;
2467
+ }
2468
+ const installation2 = state.installations[installationKey(head.frame)];
2469
+ if (!installation2) throw new TypeError("Host Relay delivery installation is unavailable.");
2470
+ if (outcome.status === "refused" || exhausted) {
2471
+ await this.quarantine.retainFrame(head.frame, "gateway_refused");
2472
+ installation2.last_refusal = { sequence: head.sequence, submission_ref: input.submission_ref, ...refusalCause(outcome, head), refused_at_ms: options.now_ms };
2473
+ refused.push(input.submission_ref);
2474
+ } else {
2475
+ await options.after_gateway_accept_before_delivery_fsync?.({ fault_point: "after_gateway_accept_before_delivery_fsync", delivery: structuredClone(input) });
2476
+ delivered.push(input.submission_ref);
2477
+ }
2478
+ state.entries.splice(state.entries.indexOf(head), 1);
2479
+ installation2.delivered_through_sequence = Math.max(installation2.delivered_through_sequence, head.sequence);
2480
+ await this.write(state);
2481
+ }
2482
+ async refusePoisonHead(state, head, options, refused) {
2483
+ const poison = poisonFrameError(head.frame);
2484
+ if (poison === null) return false;
2485
+ const installation2 = state.installations[installationKey(head)];
2486
+ if (!hasIntactAdmissionEnvelope(head, installation2)) throw new TypeError("Host Relay admission state is invalid.");
2487
+ const json = Buffer.from(JSON.stringify(head.frame), "utf8");
2488
+ const raw = Buffer.allocUnsafe(json.byteLength + 4);
2489
+ raw.writeUInt32BE(json.byteLength, 0);
2490
+ json.copy(raw, 4);
2491
+ await this.quarantine.retainMalformed(raw, poison.code);
2492
+ const submissionRef = hostProducerSubmissionRef(options.host_source_ref, { producer_id: head.producer_id, producer_installation_ref: head.producer_installation_ref, sequence: head.sequence });
2493
+ installation2.last_refusal = { sequence: head.sequence, submission_ref: submissionRef, code: poison.code, message: `Host Relay persisted frame is invalid: ${poison.code}.`, refused_at_ms: options.now_ms };
2494
+ refused.push(submissionRef);
2495
+ state.entries.splice(state.entries.indexOf(head), 1);
2496
+ installation2.delivered_through_sequence = Math.max(installation2.delivered_through_sequence, head.sequence);
2497
+ await this.write(state);
2498
+ return true;
2499
+ }
2461
2500
  async read() {
2462
2501
  try {
2463
2502
  return decodeState3(JSON.parse(await readFile2(join4(this.root, "admission.json"), "utf8")));
@@ -2523,6 +2562,8 @@ function decodeState3(value) {
2523
2562
  const entries = [];
2524
2563
  for (const item of value.entries) {
2525
2564
  if (!entry(item)) throw new TypeError("Host Relay entry state is invalid.");
2565
+ poisonFrameError(item.frame);
2566
+ if (!hasIntactAdmissionEnvelope(item, installations[installationKey(item)])) throw new TypeError("Host Relay admission state is invalid.");
2526
2567
  entries.push(item);
2527
2568
  }
2528
2569
  return { schema_version: "ceal.host_relay_admission_state.v1", installations, entries };
@@ -2545,6 +2586,60 @@ function producer2(value) {
2545
2586
  function object(value) {
2546
2587
  return typeof value === "object" && value !== null && !Array.isArray(value);
2547
2588
  }
2589
+ function poisonFrameError(frame) {
2590
+ try {
2591
+ assertHostProducerFrame(frame);
2592
+ return null;
2593
+ } catch (error) {
2594
+ if (error instanceof HostProducerFrameError) return error;
2595
+ throw error;
2596
+ }
2597
+ }
2598
+ function hasIntactAdmissionEnvelope(entryValue, installation2) {
2599
+ if (installation2 === void 0) return false;
2600
+ return poisonIdentityValid(entryValue) && poisonEnvelopeMatches(entryValue, installation2) && poisonIntegrityMatches(entryValue) && poisonSequenceInRange(entryValue, installation2);
2601
+ }
2602
+ function poisonIdentityValid(entryValue) {
2603
+ if (entryValue.producer_id !== "codex" && entryValue.producer_id !== "claude") return false;
2604
+ if (!opaqueHostSourceRef(entryValue.producer_installation_ref)) return false;
2605
+ return Number.isSafeInteger(entryValue.sequence) && entryValue.sequence > 0;
2606
+ }
2607
+ function poisonEnvelopeMatches(entryValue, installation2) {
2608
+ const frame = entryValue.frame;
2609
+ if (!object(frame)) return false;
2610
+ return poisonEnvelopeSchema(frame) && poisonEnvelopeProducer(frame, entryValue) && poisonEnvelopeInstallation(frame, entryValue) && poisonEnvelopeEpoch(frame, installation2) && poisonEnvelopeSequence(frame, entryValue) && poisonEnvelopeKind(frame) && poisonEnvelopeTimestamp(frame);
2611
+ }
2612
+ function poisonEnvelopeSchema(frame) {
2613
+ return frame.schema_version === "ceal.host_producer_frame.v1";
2614
+ }
2615
+ function poisonEnvelopeProducer(frame, entryValue) {
2616
+ return producer2(frame.producer_id) && frame.producer_id === entryValue.producer_id;
2617
+ }
2618
+ function poisonEnvelopeInstallation(frame, entryValue) {
2619
+ return opaqueHostSourceRef(frame.producer_installation_ref) && frame.producer_installation_ref === entryValue.producer_installation_ref;
2620
+ }
2621
+ function poisonEnvelopeEpoch(frame, installation2) {
2622
+ return Number.isSafeInteger(frame.producer_epoch) && typeof frame.producer_epoch === "number" && frame.producer_epoch > 0 && frame.producer_epoch <= installation2.epoch;
2623
+ }
2624
+ function poisonEnvelopeSequence(frame, entryValue) {
2625
+ return Number.isSafeInteger(frame.sequence) && frame.sequence === entryValue.sequence;
2626
+ }
2627
+ function poisonEnvelopeKind(frame) {
2628
+ return isHostProducerFrameKind(frame.frame_kind);
2629
+ }
2630
+ function poisonEnvelopeTimestamp(frame) {
2631
+ return typeof frame.occurred_at === "string" && Number.isFinite(Date.parse(frame.occurred_at));
2632
+ }
2633
+ function poisonIntegrityMatches(entryValue) {
2634
+ const frame = entryValue.frame;
2635
+ if (!object(frame)) return false;
2636
+ const json = JSON.stringify(frame);
2637
+ return entryValue.charged_bytes === 4 + Buffer.byteLength(json, "utf8") && entryValue.hash === hostProducerFrameHash(entryValue.frame);
2638
+ }
2639
+ function poisonSequenceInRange(entryValue, installation2) {
2640
+ if (entryValue.sequence <= installation2.delivered_through_sequence) return false;
2641
+ return entryValue.sequence <= installation2.admitted_through_sequence;
2642
+ }
2548
2643
 
2549
2644
  // host/relay/src/relay-gateway-bridge.ts
2550
2645
  import { readFile as readFile3 } from "node:fs/promises";
@@ -2889,20 +2984,29 @@ var HostRelayGatewayError = class extends Error {
2889
2984
  status;
2890
2985
  /** The Gateway's own refusal word, when it named one; a bounded token, never its message. */
2891
2986
  error_code;
2892
- constructor(code, message, status, errorCode9) {
2987
+ /** The Gateway mint refusal's bounded continuity reason, when it named one; a fixed token, never its message. */
2988
+ refusal_reason;
2989
+ constructor(code, message, status, errorCode9, refusalReason) {
2893
2990
  super(message);
2894
2991
  this.code = code;
2895
2992
  if (status !== void 0) this.status = status;
2896
2993
  if (errorCode9 !== void 0) this.error_code = errorCode9;
2994
+ if (refusalReason !== void 0) this.refusal_reason = refusalReason;
2897
2995
  }
2898
2996
  };
2899
2997
  var GATEWAY_REFUSAL_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/u;
2900
- async function gatewayRefusalCode(response2) {
2998
+ async function gatewayRefusal(response2) {
2901
2999
  try {
2902
3000
  const body = await response2.json();
2903
- return isCealJsonRecord(body) && typeof body.error_code === "string" && GATEWAY_REFUSAL_CODE_PATTERN.test(body.error_code) ? body.error_code : void 0;
3001
+ if (!isCealJsonRecord(body)) return {};
3002
+ const code = typeof body.error_code === "string" && GATEWAY_REFUSAL_CODE_PATTERN.test(body.error_code) ? body.error_code : void 0;
3003
+ const reason = code === "request_context_refused" && typeof body.reason === "string" && GATEWAY_REFUSAL_CODE_PATTERN.test(body.reason) && isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, body.reason) ? body.reason : void 0;
3004
+ return {
3005
+ ...code === void 0 ? {} : { code },
3006
+ ...reason === void 0 ? {} : { reason }
3007
+ };
2904
3008
  } catch {
2905
- return void 0;
3009
+ return {};
2906
3010
  }
2907
3011
  }
2908
3012
  function refusalMessage(status, body) {
@@ -2950,7 +3054,10 @@ function createHostRelayGatewayHttpPort(options) {
2950
3054
  } catch {
2951
3055
  throw new HostRelayGatewayError("gateway_unavailable", "Gateway Host invocation context is unavailable.");
2952
3056
  }
2953
- if (!response2.ok) throw new HostRelayGatewayError(response2.status === 401 ? "credential" : "gateway_refused", `Gateway Host invocation context was refused (${response2.status}).`, response2.status, await gatewayRefusalCode(response2));
3057
+ if (!response2.ok) {
3058
+ const refusal = await gatewayRefusal(response2);
3059
+ throw new HostRelayGatewayError(response2.status === 401 ? "credential" : "gateway_refused", `Gateway Host invocation context was refused (${response2.status}).`, response2.status, refusal.code, refusal.reason);
3060
+ }
2954
3061
  let value;
2955
3062
  try {
2956
3063
  value = await response2.json();
@@ -3071,8 +3178,9 @@ function acknowledgement(value) {
3071
3178
  }
3072
3179
 
3073
3180
  // host/relay/src/relay-ipc.ts
3074
- import { chmod, lstat as lstat3, unlink as unlink2 } from "node:fs/promises";
3181
+ import { chmod, lstat as lstat3, rename as rename2, unlink as unlink2 } from "node:fs/promises";
3075
3182
  import { createConnection, createServer } from "node:net";
3183
+ import { dirname as dirname3, join as join6 } from "node:path";
3076
3184
 
3077
3185
  // host/relay/src/current-prompt-custody.ts
3078
3186
  import { createHash as createHash5 } from "node:crypto";
@@ -3153,7 +3261,15 @@ var HOST_RELAY_INVOCATION_MINT_REFUSAL_REASONS = vocabulary([
3153
3261
  "deadline",
3154
3262
  "cancelled",
3155
3263
  "mint_failed",
3156
- "relay_failed"
3264
+ "relay_failed",
3265
+ "request_authority_unavailable",
3266
+ "request_missing",
3267
+ "authority_mismatch",
3268
+ "host_source_mismatch",
3269
+ "host_session_mismatch",
3270
+ "host_turn_mismatch",
3271
+ "host_input_mismatch",
3272
+ "host_prompt_mismatch"
3157
3273
  ]);
3158
3274
  var HostRelayInvocationMintRefusal = class extends Error {
3159
3275
  reason;
@@ -3185,15 +3301,42 @@ var HostRelayIpcError = class extends Error {
3185
3301
  }
3186
3302
  };
3187
3303
  async function startHostRelayIpcServer(options) {
3188
- await assertEndpointVacant(options.endpoint);
3189
- const active = /* @__PURE__ */ new Map();
3190
- const sockets = /* @__PURE__ */ new Set();
3191
- const quarantine = options.quarantine ?? options.admission.quarantine;
3192
- const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
3193
- const server = createServer((socket) => serveSocket(socket, options, currentPrompts, quarantine, active, sockets));
3194
- await listen(server, options.endpoint);
3195
- if (process.platform !== "win32") await chmod(options.endpoint, 384);
3196
- return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
3304
+ return withRelayEndpointLock(options.endpoint, async () => {
3305
+ if (process.platform === "win32") {
3306
+ await assertEndpointVacant(options.endpoint);
3307
+ } else {
3308
+ await assertTrustedEndpointParent(options.endpoint);
3309
+ await removeStaleRelayEndpoint(options.endpoint, options.testHooks);
3310
+ }
3311
+ const active = /* @__PURE__ */ new Map();
3312
+ const sockets = /* @__PURE__ */ new Set();
3313
+ const quarantine = options.quarantine ?? options.admission.quarantine;
3314
+ const currentPrompts = options.currentPrompts ?? new HostCurrentPromptCustody();
3315
+ const server = createServer((socket) => serveSocket(socket, options, currentPrompts, quarantine, active, sockets));
3316
+ if (process.platform === "win32") {
3317
+ try {
3318
+ await listen(server, options.endpoint);
3319
+ } catch (error) {
3320
+ await abandonRelayServer(server, sockets);
3321
+ throw error;
3322
+ }
3323
+ return { endpoint: options.endpoint, close: () => closeServer(server, sockets, options.endpoint) };
3324
+ }
3325
+ const staging = stagingRelayEndpoint(options.endpoint);
3326
+ await listenStagingRelayEndpoint(server, sockets, staging);
3327
+ let owned;
3328
+ try {
3329
+ await options.testHooks?.beforeCaptureOwnedEndpoint?.(options.endpoint);
3330
+ owned = await readStagingRelayEndpointIdentity(staging);
3331
+ await chmod(staging, 384);
3332
+ const identity = await publishStagingRelayEndpoint(staging, owned, options.endpoint);
3333
+ return { endpoint: options.endpoint, close: () => closeRelayServer(server, sockets, options.endpoint, identity, options.testHooks) };
3334
+ } catch (error) {
3335
+ if (owned !== void 0) await releaseOwnedRelayEndpoint(server, sockets, options.endpoint, owned);
3336
+ else await abandonRelayServer(server, sockets);
3337
+ throw error;
3338
+ }
3339
+ });
3197
3340
  }
3198
3341
  function encodeHostRelayIpcResponse(response2) {
3199
3342
  const body = Buffer.from(JSON.stringify(response2), "utf8");
@@ -3355,8 +3498,9 @@ function writeCurrentPromptResponse(socket, status) {
3355
3498
  async function resolveInvocationContext(request2, admission, bindings, currentPrompts, mint, signal) {
3356
3499
  if (mint === void 0) throw new HostRelayIpcError("relay_unavailable");
3357
3500
  const query = bindingQueryFromRequest(request2);
3501
+ const expectedSequences = pendingAdmissionSequences(await admission.snapshot(), query);
3358
3502
  const binding = await waitForRequestBinding(query, admission, bindings, signal);
3359
- if (binding.status !== "ready") return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "no_binding" };
3503
+ if (binding.status !== "ready") return unboundInvocationContextRefusal(await admission.snapshot(), query, expectedSequences) ?? { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "no_binding" };
3360
3504
  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 });
3361
3505
  let result2;
3362
3506
  try {
@@ -3366,6 +3510,24 @@ async function resolveInvocationContext(request2, admission, bindings, currentPr
3366
3510
  }
3367
3511
  return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "ready", result: result2 };
3368
3512
  }
3513
+ function unboundInvocationContextRefusal(snapshot, query, expectedSequences) {
3514
+ if (expectedSequences.length === 0) return null;
3515
+ const refusal = snapshot.installations[`${query.producer_id}\0${query.producer_installation_ref}`]?.last_refusal;
3516
+ if (refusal === void 0 || !expectedSequences.includes(refusal.sequence) || refusal.code !== "gateway_refused") return null;
3517
+ return { schema_version: HOST_RELAY_INVOCATION_CONTEXT_RESULT_SCHEMA, status: "refused", reason: "gateway_refused" };
3518
+ }
3519
+ function pendingAdmissionSequences(snapshot, query) {
3520
+ const sequences = [];
3521
+ for (const entry2 of snapshot.entries) {
3522
+ if (entry2.frame.frame_kind !== "user_input") continue;
3523
+ const payload = entry2.frame.payload;
3524
+ if (typeof payload.local_session_ref !== "string" || typeof payload.local_turn_ref !== "string") continue;
3525
+ const aliases = Array.isArray(payload.local_turn_aliases) ? payload.local_turn_aliases.filter((value) => typeof value === "string") : [];
3526
+ if (!relayRequestBindingMatchesQuery(query, { producer_id: entry2.frame.producer_id, producer_installation_ref: entry2.frame.producer_installation_ref, local_session_ref: payload.local_session_ref, local_turn_ref: payload.local_turn_ref, local_turn_aliases: aliases })) continue;
3527
+ sequences.push(entry2.sequence);
3528
+ }
3529
+ return sequences;
3530
+ }
3369
3531
  async function waitForRequestBinding(query, admission, bindings, signal) {
3370
3532
  let binding = await bindings.query(query);
3371
3533
  if (binding.status === "ready") return binding;
@@ -3541,6 +3703,160 @@ async function closeServer(server, sockets, endpoint) {
3541
3703
  await new Promise((resolve) => server.close(() => resolve()));
3542
3704
  if (process.platform !== "win32") await unlink2(endpoint).catch(() => void 0);
3543
3705
  }
3706
+ var relayEndpointLocks = /* @__PURE__ */ new Map();
3707
+ function withRelayEndpointLock(endpoint, run) {
3708
+ const prior = relayEndpointLocks.get(endpoint) ?? Promise.resolve();
3709
+ let release;
3710
+ const gate = new Promise((resolve) => {
3711
+ release = resolve;
3712
+ });
3713
+ const tail = prior.then(() => gate);
3714
+ relayEndpointLocks.set(endpoint, tail);
3715
+ return prior.then(run).finally(() => {
3716
+ release?.();
3717
+ if (relayEndpointLocks.get(endpoint) === tail) relayEndpointLocks.delete(endpoint);
3718
+ });
3719
+ }
3720
+ function currentUid(fallback) {
3721
+ return typeof process.geteuid === "function" ? process.geteuid() : fallback;
3722
+ }
3723
+ async function assertTrustedEndpointParent(endpoint) {
3724
+ const parent = dirname3(endpoint);
3725
+ let stats;
3726
+ try {
3727
+ stats = await lstat3(parent);
3728
+ } catch {
3729
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint parent is unavailable; leaving it untouched.");
3730
+ }
3731
+ if (!stats.isDirectory() || stats.uid !== currentUid(stats.uid) || (stats.mode & 63) !== 0) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint parent is not an owner-private directory; leaving it untouched.");
3732
+ }
3733
+ var HOST_RELAY_ENDPOINT_PROBE_TIMEOUT_MS = 1e3;
3734
+ function probeRelayEndpoint(endpoint) {
3735
+ return new Promise((resolve) => {
3736
+ let settled = false;
3737
+ const socket = createConnection(endpoint);
3738
+ const finish = (outcome) => {
3739
+ if (settled) return;
3740
+ settled = true;
3741
+ clearTimeout(timer);
3742
+ socket.destroy();
3743
+ resolve(outcome);
3744
+ };
3745
+ const timer = setTimeout(() => finish("ambiguous"), HOST_RELAY_ENDPOINT_PROBE_TIMEOUT_MS);
3746
+ timer.unref?.();
3747
+ socket.once("connect", () => finish("live"));
3748
+ socket.once("error", (error) => {
3749
+ const code = errorCode8(error);
3750
+ if (code === "ECONNREFUSED") finish("stale");
3751
+ else if (code === "ENOENT") finish("missing");
3752
+ else finish("ambiguous");
3753
+ });
3754
+ });
3755
+ }
3756
+ async function removeStaleRelayEndpoint(endpoint, testHooks) {
3757
+ const observed = await readEndpointStats(endpoint);
3758
+ if (observed === null) return;
3759
+ if (!observed.isSocket()) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is already present and is not a socket; leaving it untouched.");
3760
+ if (observed.uid !== currentUid(observed.uid)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is not owned by the current uid; leaving it untouched.");
3761
+ const captured = { uid: observed.uid, dev: observed.dev, ino: observed.ino };
3762
+ await requireStaleEndpoint(endpoint);
3763
+ await testHooks?.beforeRemoveStaleEndpoint?.(endpoint);
3764
+ const current = await readEndpointStats(endpoint);
3765
+ if (current === null) return;
3766
+ requireSameEndpointIdentity(current, captured, "Host Relay IPC endpoint changed before cleanup; leaving it untouched.");
3767
+ await unlinkRelayEndpoint(endpoint);
3768
+ }
3769
+ async function requireStaleEndpoint(endpoint) {
3770
+ switch (await probeRelayEndpoint(endpoint)) {
3771
+ case "missing":
3772
+ case "stale":
3773
+ return;
3774
+ case "live":
3775
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is already served by a live Relay; leaving it untouched.");
3776
+ case "ambiguous":
3777
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint liveness is ambiguous; leaving it untouched.");
3778
+ }
3779
+ }
3780
+ async function readEndpointStats(endpoint) {
3781
+ try {
3782
+ return await lstat3(endpoint);
3783
+ } catch (error) {
3784
+ if (errorCode8(error) === "ENOENT") return null;
3785
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint identity is ambiguous; leaving it untouched.");
3786
+ }
3787
+ }
3788
+ function requireSameEndpointIdentity(current, owned, message) {
3789
+ if (!current.isSocket() || current.uid !== owned.uid || current.dev !== owned.dev || current.ino !== owned.ino) throw new HostRelayIpcError("relay_unavailable", message);
3790
+ }
3791
+ async function unlinkRelayEndpoint(endpoint) {
3792
+ try {
3793
+ await unlink2(endpoint);
3794
+ } catch (error) {
3795
+ if (errorCode8(error) !== "ENOENT") throw error;
3796
+ }
3797
+ }
3798
+ var relayStagingSequence = 0;
3799
+ function stagingRelayEndpoint(canonical) {
3800
+ const parent = dirname3(canonical);
3801
+ const pid = process.pid.toString(36);
3802
+ const sequence = (relayStagingSequence++ % (36 * 36)).toString(36);
3803
+ return join6(parent, `.r${pid}${sequence}`);
3804
+ }
3805
+ async function readStagingRelayEndpointIdentity(staging) {
3806
+ let created;
3807
+ try {
3808
+ created = await lstat3(staging);
3809
+ } catch {
3810
+ throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is unavailable after listen; leaving it untouched.");
3811
+ }
3812
+ if (!created.isSocket()) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint was replaced before this server listened; leaving it untouched.");
3813
+ if (created.uid !== currentUid(created.uid)) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is not owned by the current uid after listen; leaving it untouched.");
3814
+ return { uid: created.uid, dev: created.dev, ino: created.ino };
3815
+ }
3816
+ async function listenStagingRelayEndpoint(server, sockets, staging) {
3817
+ try {
3818
+ await listen(server, staging);
3819
+ } catch (error) {
3820
+ await abandonRelayServer(server, sockets);
3821
+ throw error;
3822
+ }
3823
+ }
3824
+ async function publishStagingRelayEndpoint(staging, owned, canonical) {
3825
+ const incumbent = await readEndpointStats(canonical);
3826
+ if (incumbent !== null) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint was replaced before this server listened; leaving it untouched.");
3827
+ await rename2(staging, canonical);
3828
+ const published = await readEndpointStats(canonical);
3829
+ if (published === null) throw new HostRelayIpcError("relay_unavailable", "Host Relay IPC endpoint is unavailable after listen; leaving it untouched.");
3830
+ requireSameEndpointIdentity(published, owned, "Host Relay IPC endpoint was replaced before this server listened; leaving it untouched.");
3831
+ return { uid: published.uid, dev: published.dev, ino: published.ino };
3832
+ }
3833
+ async function releaseOwnedRelayEndpoint(server, sockets, endpoint, owned) {
3834
+ await abandonRelayServer(server, sockets);
3835
+ try {
3836
+ const current = await readEndpointStats(endpoint);
3837
+ if (current === null) return;
3838
+ requireSameEndpointIdentity(current, owned, "Host Relay IPC endpoint changed while releasing a failed startup; leaving it untouched.");
3839
+ await unlinkRelayEndpoint(endpoint);
3840
+ } catch {
3841
+ }
3842
+ }
3843
+ async function closeRelayServer(server, sockets, endpoint, owned, testHooks) {
3844
+ await withRelayEndpointLock(endpoint, async () => {
3845
+ for (const socket of sockets) socket.destroy();
3846
+ await new Promise((resolve) => server.close(() => resolve()));
3847
+ await testHooks?.beforeRemoveOwnedEndpoint?.(endpoint);
3848
+ const current = await readEndpointStats(endpoint);
3849
+ if (current === null) return;
3850
+ requireSameEndpointIdentity(current, owned, "Host Relay IPC endpoint was replaced after this server listened; leaving it untouched.");
3851
+ await unlinkRelayEndpoint(endpoint);
3852
+ });
3853
+ }
3854
+ async function abandonRelayServer(server, sockets) {
3855
+ for (const socket of sockets) socket.destroy();
3856
+ await new Promise((resolve) => {
3857
+ server.close(() => resolve());
3858
+ });
3859
+ }
3544
3860
  function errorCode8(error) {
3545
3861
  return record4(error) && typeof error.code === "string" ? error.code : null;
3546
3862
  }
@@ -3562,7 +3878,7 @@ async function readHostRelayConfig(path) {
3562
3878
  if (!isAbsoluteNormalizedNonRootPath(path, process.platform, true)) throw new HostRelayConfigError("invalid_config_path", `invalid_config_path: Host Relay config path is invalid: ${refusalFact("config_path", path, "absolute, normalized, and non-root")}.`);
3563
3879
  let handle;
3564
3880
  try {
3565
- await assertOwnerPrivateDirectory2(dirname3(path));
3881
+ await assertOwnerPrivateDirectory2(dirname4(path));
3566
3882
  handle = await open5(path, O_RDONLY4 | O_NOFOLLOW3);
3567
3883
  const stats = await handle.stat();
3568
3884
  if (!stats.isFile() || !ownerPrivate4(stats)) throw new HostRelayConfigError("config_not_private", "Host Relay config file is not owner-private.");
@@ -3587,7 +3903,7 @@ async function readHostRelayConfig(path) {
3587
3903
  }
3588
3904
  function validateHostRelaySourcePaths(config) {
3589
3905
  try {
3590
- assertHostRelaySourcePaths(dirname3(config.registration_state_file), config);
3906
+ assertHostRelaySourcePaths(dirname4(config.registration_state_file), config);
3591
3907
  } catch (error) {
3592
3908
  throw new HostRelayConfigError("invalid_config", error instanceof Error ? error.message : "Host Relay source tuple is invalid.");
3593
3909
  }
@@ -3617,10 +3933,10 @@ function validConfigRuntime(value) {
3617
3933
  var HOST_RELAY_INVOCATION_MINT_LOG_TAG = "[host-relay-invocation-mint]";
3618
3934
  var HOST_RELAY_INVOCATION_MINT_LINE = new RegExp(`^${HOST_RELAY_INVOCATION_MINT_LOG_TAG.replace(/[[\]]/gu, "\\$&")} outcome=([a-z_]+)(?: reason=([a-z][a-z0-9_]{0,63}))? elapsed_ms=[0-9]+$`, "u");
3619
3935
  async function serveHostRelay(config, signal, dependencies = {}) {
3620
- const admission = new RelayAdmissionStore(join6(config.state_root, "admission"));
3621
- const bindings = new RelayRequestBindingStore(join6(config.state_root, "bindings"));
3936
+ const admission = new RelayAdmissionStore(join7(config.state_root, "admission"));
3937
+ const bindings = new RelayRequestBindingStore(join7(config.state_root, "bindings"));
3622
3938
  const gateway = (dependencies.createGateway ?? createHostRelayGatewayHttpPort)({ registration_state_file: config.registration_state_file, host_source_ref: config.host_source_ref });
3623
- const bridge = new RelayGatewayBridge({ state_root: join6(config.state_root, "gateway"), host_source_ref: config.host_source_ref, gateway, timeout_ms: config.gateway_timeout_ms, on_request_bound: async (binding) => {
3939
+ const bridge = new RelayGatewayBridge({ state_root: join7(config.state_root, "gateway"), host_source_ref: config.host_source_ref, gateway, timeout_ms: config.gateway_timeout_ms, on_request_bound: async (binding) => {
3624
3940
  await bindings.bind(binding);
3625
3941
  } });
3626
3942
  let server;
@@ -3661,7 +3977,11 @@ function invocationMintRefusalReason(error, cancellation) {
3661
3977
  if (error.code === "gateway_unavailable") return "gateway_unavailable";
3662
3978
  if (error.code === "invalid_response") return "gateway_response_invalid";
3663
3979
  if (error.code !== "gateway_refused") return "mint_failed";
3664
- return (error.error_code === void 0 ? void 0 : GATEWAY_MINT_REFUSAL_REASONS.get(error.error_code)) ?? "gateway_refused";
3980
+ return gatewayMintRefusalReason(error);
3981
+ }
3982
+ function gatewayMintRefusalReason(error) {
3983
+ if (error.error_code === "request_context_refused" && isVocabularyWord(CEAL_HOST_MINT_REQUEST_CONTEXT_REFUSAL_REASONS, error.refusal_reason)) return error.refusal_reason;
3984
+ return GATEWAY_MINT_REFUSAL_REASONS.get(error.error_code ?? "") ?? "gateway_refused";
3665
3985
  }
3666
3986
  var GATEWAY_MINT_REFUSAL_REASONS = /* @__PURE__ */ new Map([
3667
3987
  ["request_context_refused", "context_stale"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corca-org/ceal-host-linux-arm64",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",