@byok-sdk/cloud 0.14.0 → 0.16.0

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.
package/dist/index.js CHANGED
@@ -1,11 +1,30 @@
1
1
  import { BOARD_STATUSES, CapabilityDeclarationSchema, NONCE_SIGNING_DOMAIN, hasCapability, isTenantId, tenantId, principalTenant, parseDeviceProofEnvelope, deviceProofSigningInput, contentHash, parseCapabilityDeclaration, ByokCoreError, tenantKey, PRESENCE_LEVELS, createInMemoryCoreStores, authenticateDeviceAssertion, assertCapability, isCoreConflictError, isCoreError, DEVICE_PROOF_HEADER, TRUTH_RECORD_KINDS, STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS } from '@byok-sdk/core';
2
2
  export { DEVICE_PROOF_HEADER, NONCE_SIGNING_DOMAIN, isTenantId, tenantId } from '@byok-sdk/core';
3
- import { AgentEventOrUnknownSchema, PROTOCOL_VERSION, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, encodeEnvelope, decodeEnvelope, AgentHomeProjectionCompletionRequestSchema, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_AGENT_MEMORY_PROJECTIONS_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_AGENT_HOME_PROJECTION_COMPLETION_ROUTE, BYOK_BOARD_PATH, BYOK_BOARD_CLAIM_ROUTE, BYOK_BOARD_UNCLAIM_ROUTE, BYOK_BOARD_STATUS_ROUTE, BYOK_BOARD_STREAM_PATH, BYOK_PRESENCE_PATH, BYOK_ACTIVITY_PATH, BYOK_RECORDS_PATH, BYOK_RECORD_ROUTE, BYOK_SKILL_PACKS_PATH, BYOK_SKILL_PACK_FILE_ROUTE, BYOK_BLOBS_PATH, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, createEnvelope, AgentHomeProjectionPayloadSchema, AgentContentReadPayloadSchema, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AGENT_MESSAGE_EGRESS_CAPABILITY, TERMINAL_PROJECTION_SELECTION_CAPABILITY, TaskOfferForAgentWithEgressFreshPayloadSchema, AgentMessageServerContextSchema, TaskOfferForAgentWithEgressPayloadSchema, TaskOfferForAgentPayloadSchema, AgentMemoryProjectionMutationSchema, AgentMemoryProjectionReceiptSchema, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionEraseResultSchema, STRICT_AGENT_ONLY_CAPABILITY, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AgentRefSchema, PairRequestSchema, PairResponseSchema, ChallengeRequestSchema, TokenRequestSchema, AgentMemoryProjectionCommitRequestSchema, agentMemoryProjectionBase64UrlByteLength, MessagesSendRequestSchema, PresencePublishRequestSchema, CreateBlobRequestSchema, byokBlobContentPath, AgentEgressAckPayloadSchema, AgentContentReceiptPayloadSchema } from '@byok-sdk/protocol';
3
+ import { AgentEventOrUnknownSchema, PROTOCOL_VERSION, DAEMON_TO_SERVER_TYPES, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, encodeEnvelope, decodeEnvelope, AgentHomeProjectionCompletionRequestSchema, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_AGENT_MEMORY_PROJECTIONS_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_AGENT_HOME_PROJECTION_COMPLETION_ROUTE, BYOK_BOARD_PATH, BYOK_BOARD_CLAIM_ROUTE, BYOK_BOARD_UNCLAIM_ROUTE, BYOK_BOARD_STATUS_ROUTE, BYOK_BOARD_STREAM_PATH, BYOK_PRESENCE_PATH, BYOK_ACTIVITY_PATH, BYOK_RECORDS_PATH, BYOK_RECORD_ROUTE, BYOK_SKILL_PACKS_PATH, BYOK_SKILL_PACK_FILE_ROUTE, BYOK_BLOBS_PATH, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, createEnvelope, AgentHomeProjectionPayloadSchema, AgentContentReadPayloadSchema, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AGENT_MESSAGE_EGRESS_CAPABILITY, TERMINAL_PROJECTION_SELECTION_CAPABILITY, TaskOfferForAgentWithEgressFreshPayloadSchema, AgentMessageServerContextSchema, TaskOfferForAgentWithEgressPayloadSchema, TaskOfferForAgentPayloadSchema, AgentMemoryProjectionMutationSchema, AgentMemoryProjectionReceiptSchema, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionEraseResultSchema, HarnessIdSchema, STRICT_AGENT_ONLY_CAPABILITY, AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AgentRefSchema, PairRequestSchema, PairResponseSchema, ChallengeRequestSchema, TokenRequestSchema, AgentMemoryProjectionCommitRequestSchema, agentMemoryProjectionBase64UrlByteLength, MAILBOX_READ_AHEAD_MAX_SEQS, MAILBOX_READ_AHEAD_CAPABILITY, MessagesSendRequestSchema, PresencePublishRequestSchema, CreateBlobRequestSchema, byokBlobContentPath, AgentEgressAckPayloadSchema, AgentContentReceiptPayloadSchema } from '@byok-sdk/protocol';
4
4
  import { z } from 'zod';
5
5
  import { Hono } from 'hono';
6
6
 
7
7
  // src/index.ts
8
8
 
9
+ // src/offer-identity.ts
10
+ function uuidFromSha256(value) {
11
+ const match = /^sha256:([0-9a-f]{64})$/.exec(value);
12
+ if (match === null) throw new Error("CloudCrypto.sha256 must return canonical sha256 hex");
13
+ const digest = match[1];
14
+ if (digest === void 0) throw new Error("CloudCrypto.sha256 must return canonical sha256 hex");
15
+ const hex = digest.slice(0, 32).split("");
16
+ hex[12] = "8";
17
+ hex[16] = ["8", "9", "a", "b"][Number.parseInt(hex[16], 16) & 3];
18
+ return `${hex.slice(0, 8).join("")}-${hex.slice(8, 12).join("")}-${hex.slice(12, 16).join("")}-${hex.slice(16, 20).join("")}-${hex.slice(20).join("")}`;
19
+ }
20
+ async function taskOfferMessageId(tenant, taskId, deviceId, agentRef, sha256) {
21
+ return uuidFromSha256(await sha256(new TextEncoder().encode(JSON.stringify({ domain: "byok:task-offer", tenant, taskId, deviceId, agentRef }))));
22
+ }
23
+ async function hashOfferBytes(bytes) {
24
+ const hash = new Uint8Array(await crypto.subtle.digest("SHA-256", new Uint8Array(bytes)));
25
+ return `sha256:${Array.from(hash, (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
26
+ }
27
+
9
28
  // src/approval-control.ts
10
29
  var StaleApprovalError = class extends Error {
11
30
  constructor(taskId, requestedApprovalId, currentApprovalId) {
@@ -668,7 +687,8 @@ function tenantStoresFor(principal, root) {
668
687
  revoke: (deviceId) => cloud.devices.revoke(tenant, deviceId),
669
688
  recordCapabilities: (input) => principal.kind === "device" ? cloud.devices.recordCapabilities(tenant, {
670
689
  deviceId: principal.deviceId,
671
- capabilities: input.capabilities
690
+ capabilities: input.capabilities,
691
+ ...input.harnesses === void 0 ? {} : { harnesses: input.harnesses }
672
692
  }) : Promise.resolve(void 0),
673
693
  readiness: () => cloud.devices.readiness(tenant, core.presence)
674
694
  },
@@ -1029,6 +1049,8 @@ function tokenHandler(deps) {
1029
1049
  };
1030
1050
  }
1031
1051
  var CLOUD_PROTOCOL_CAPABILITIES = [
1052
+ "custom-harness",
1053
+ MAILBOX_READ_AHEAD_CAPABILITY,
1032
1054
  "result-document",
1033
1055
  // The kernel's inbound handles `task.approval_resolved` on both the plain
1034
1056
  // and the approval-timeline paths (`packages/cloud/src/inbound.ts:576,610`).
@@ -1065,7 +1087,13 @@ function eventsHandler(deps) {
1065
1087
  }
1066
1088
  cursor = parsedCursor;
1067
1089
  }
1090
+ const afterRaw = c.req.query("afterSeq");
1091
+ const afterSeq = afterRaw === void 0 ? cursor : Number(afterRaw);
1092
+ if (!Number.isSafeInteger(afterSeq) || afterSeq < cursor || afterSeq - cursor > MAILBOX_READ_AHEAD_MAX_SEQS) {
1093
+ return c.json({ error: "invalid read-ahead offset" }, 400);
1094
+ }
1068
1095
  const acked = await stores.mailbox.readCursor(device.deviceId);
1096
+ if (afterRaw !== void 0 && afterSeq > acked.deliveredSeq) return c.json({ error: "read offset exceeds delivered watermark" }, 409);
1069
1097
  if (cursor > acked.ackedSeq) {
1070
1098
  try {
1071
1099
  await stores.mailbox.advanceCursor({ deviceId: device.deviceId, ackedSeq: cursor });
@@ -1078,7 +1106,7 @@ function eventsHandler(deps) {
1078
1106
  }
1079
1107
  const attempts = Math.max(1, Math.ceil(deps.longPollHoldMs / deps.longPollIntervalMs));
1080
1108
  for (let attempt = 0; attempt < attempts; attempt += 1) {
1081
- let scanCursor = cursor;
1109
+ let scanCursor = afterSeq;
1082
1110
  while (true) {
1083
1111
  const page = await stores.mailbox.readAfter({
1084
1112
  deviceId: device.deviceId,
@@ -1122,7 +1150,7 @@ function eventsHandler(deps) {
1122
1150
  }
1123
1151
  const response = {
1124
1152
  events: [],
1125
- cursor,
1153
+ cursor: afterSeq,
1126
1154
  capabilities: CLOUD_PROTOCOL_CAPABILITIES
1127
1155
  };
1128
1156
  return c.json(response, 200);
@@ -1385,6 +1413,7 @@ function agentRefEchoRequired(envelope) {
1385
1413
  return envelope.type === "task.claim" || envelope.type === "task.decline" || envelope.type === "task.complete" || envelope.type === "task.fail" || envelope.type === "task.cancelled";
1386
1414
  }
1387
1415
  async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds = DEFAULT_ACTIVITY_BOUNDS, agentMessageConsume, observer) {
1416
+ if (envelope.v !== PROTOCOL_VERSION) return "rejected";
1388
1417
  const outcome = await applyInboundGate(
1389
1418
  stores,
1390
1419
  deviceId,
@@ -1404,12 +1433,13 @@ async function applyInboundGate(stores, deviceId, envelope, activityBounds, agen
1404
1433
  if (!await stores.rateLimiter.consume(deviceId)) return "rate_limited";
1405
1434
  if (envelope.type === "conn.hello") {
1406
1435
  if (envelope.payload.deviceId !== deviceId) return "rejected";
1436
+ if (envelope.payload.harnesses !== void 0 && !envelope.payload.capabilities.includes("custom-harness")) return "rejected";
1407
1437
  if (!envelope.payload.protocolVersions.includes(PROTOCOL_VERSION)) return "rejected";
1408
1438
  const device = await stores.devices.get(deviceId);
1409
1439
  if (device === void 0 || device.revoked || device.productId !== envelope.payload.productId) {
1410
1440
  return "rejected";
1411
1441
  }
1412
- if (await stores.devices.recordCapabilities({ capabilities: envelope.payload.capabilities }) === void 0) {
1442
+ if (await stores.devices.recordCapabilities({ capabilities: envelope.payload.capabilities, ...envelope.payload.harnesses === void 0 ? {} : { harnesses: envelope.payload.harnesses } }) === void 0) {
1413
1443
  return "rejected";
1414
1444
  }
1415
1445
  return completeInboundEnvelope(stores, deviceId, envelope.id, void 0);
@@ -1456,6 +1486,34 @@ async function applyInboundGate(stores, deviceId, envelope, activityBounds, agen
1456
1486
  if (attempt === void 0 || attempt.deviceId !== deviceId) return "rejected";
1457
1487
  if (attempt?.ownerDeviceId !== void 0 && attempt.ownerDeviceId !== deviceId) return "rejected";
1458
1488
  if (envelope.type === "task.claim" && envelope.payload.deviceId !== deviceId) return "rejected";
1489
+ if (envelope.type === "task.claim") {
1490
+ const harnessId = envelope.payload.harnessId;
1491
+ if (harnessId !== void 0 && envelope.payload.runtime !== void 0) return "rejected";
1492
+ if (attempt.ownerDeviceId !== void 0 && (harnessId !== void 0 || attempt.claimedHarnessId !== void 0) && harnessId !== attempt.claimedHarnessId) return "rejected";
1493
+ const device = await stores.devices.get(deviceId);
1494
+ if (harnessId !== void 0 && (!device?.capabilities?.includes("custom-harness") || !device.harnesses?.some((harness) => harness.id === harnessId))) return "rejected";
1495
+ const messageId = await taskOfferMessageId(stores.tenant, taskId, deviceId, attempt.agentRef, hashOfferBytes);
1496
+ const offer = await stores.receipts.get(`task-offer:${messageId}`);
1497
+ if (offer !== void 0) {
1498
+ const sealed = JSON.parse(offer.body);
1499
+ if (harnessId !== void 0 && (sealed.payload.runtime !== void 0 || sealed.payload.dispatchSelection !== void 0)) return "rejected";
1500
+ if (sealed.payload.harnessId !== void 0 && sealed.payload.harnessId !== harnessId) return "rejected";
1501
+ } else if (harnessId !== void 0) return "rejected";
1502
+ }
1503
+ let unclaimedInterruption = false;
1504
+ if (envelope.type === "task.fail" && envelope.payload.recovery !== void 0) {
1505
+ if (envelope.payload.reason !== "daemon_interrupted" || envelope.payload.retryable !== false) return "rejected";
1506
+ const messageId = await taskOfferMessageId(stores.tenant, taskId, deviceId, attempt.agentRef, hashOfferBytes);
1507
+ if (envelope.payload.recovery.offerId !== messageId) return "rejected";
1508
+ const offer = await stores.receipts.get(`task-offer:${messageId}`);
1509
+ if (offer === void 0) return "rejected";
1510
+ const sealed = JSON.parse(offer.body);
1511
+ const harnessId = envelope.payload.harnessId;
1512
+ if (sealed.payload.harnessId !== void 0 && sealed.payload.harnessId !== harnessId) return "rejected";
1513
+ if (harnessId !== void 0 && (sealed.payload.runtime !== void 0 || sealed.payload.dispatchSelection !== void 0)) return "rejected";
1514
+ unclaimedInterruption = attempt.ownerDeviceId === void 0 && attempt.claimedHarnessId === void 0;
1515
+ }
1516
+ if ((envelope.type === "task.complete" || envelope.type === "task.fail" || envelope.type === "task.cancelled") && !unclaimedInterruption && envelope.payload.harnessId !== attempt.claimedHarnessId) return "rejected";
1459
1517
  if (attempt?.agentRef !== void 0 && agentRefEchoRequired(envelope) && !sameAgentRef(attempt.agentRef, inboundAgentRef(envelope))) {
1460
1518
  return "rejected";
1461
1519
  }
@@ -1487,7 +1545,8 @@ async function applyInboundGate(stores, deviceId, envelope, activityBounds, agen
1487
1545
  throw caught;
1488
1546
  }
1489
1547
  }
1490
- await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, attempt?.agentRef);
1548
+ const lifecycleOutcome = await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, attempt?.agentRef);
1549
+ if (lifecycleOutcome === "rejected") return "rejected";
1491
1550
  return completeInboundEnvelope(stores, deviceId, envelope.id, attempt?.agentRef);
1492
1551
  }
1493
1552
  async function completeInboundEnvelope(stores, deviceId, envelopeId, agentRef) {
@@ -1496,14 +1555,17 @@ async function completeInboundEnvelope(stores, deviceId, envelopeId, agentRef) {
1496
1555
  }
1497
1556
  async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds, persistedAgentRef) {
1498
1557
  switch (envelope.type) {
1499
- case "task.claim":
1500
- await stores.tasks.claim({
1558
+ case "task.claim": {
1559
+ const claimed = await stores.tasks.claim({
1501
1560
  taskId,
1502
1561
  deviceId,
1503
1562
  ...envelope.payload.runtime === void 0 ? {} : { runtime: envelope.payload.runtime },
1563
+ ...envelope.payload.harnessId === void 0 ? {} : { harnessId: envelope.payload.harnessId },
1504
1564
  ...envelope.payload.capabilities === void 0 ? {} : { capabilities: envelope.payload.capabilities }
1505
1565
  });
1566
+ if (claimed === void 0 || claimed.ownerDeviceId !== deviceId || claimed.claimedRuntime !== envelope.payload.runtime || claimed.claimedHarnessId !== envelope.payload.harnessId) return "rejected";
1506
1567
  return;
1568
+ }
1507
1569
  case "task.started":
1508
1570
  await stores.tasks.recordStatus({
1509
1571
  taskId,
@@ -2620,6 +2682,7 @@ function projectTerminalResult(taskId, receipt) {
2620
2682
  sessionRef: envelope.payload.sessionRef,
2621
2683
  ...envelope.payload.artifactRefs !== void 0 ? { artifactRefs: envelope.payload.artifactRefs } : {},
2622
2684
  ...envelope.payload.document !== void 0 ? { document: envelope.payload.document } : {},
2685
+ ...envelope.payload.harnessId === void 0 ? {} : { harnessId: envelope.payload.harnessId },
2623
2686
  ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
2624
2687
  recordedAt: receipt.recordedAt
2625
2688
  };
@@ -2628,9 +2691,11 @@ function projectTerminalResult(taskId, receipt) {
2628
2691
  taskId,
2629
2692
  state: "failed",
2630
2693
  ...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
2694
+ ...envelope.payload.recovery === void 0 ? {} : { recovery: envelope.payload.recovery },
2631
2695
  reason: envelope.payload.reason,
2632
2696
  terminalCause: envelope.payload.reason,
2633
2697
  ...envelope.payload.retryable !== void 0 ? { retryable: envelope.payload.retryable } : {},
2698
+ ...envelope.payload.harnessId === void 0 ? {} : { harnessId: envelope.payload.harnessId },
2634
2699
  ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
2635
2700
  recordedAt: receipt.recordedAt
2636
2701
  };
@@ -2656,6 +2721,7 @@ function projectTerminalResult(taskId, receipt) {
2656
2721
  ...envelope.payload.agentRef === void 0 ? {} : { agentRef: envelope.payload.agentRef },
2657
2722
  ...envelope.payload.reason !== void 0 ? { reason: envelope.payload.reason } : {},
2658
2723
  ...envelope.payload.reason === void 0 ? {} : { terminalCause: envelope.payload.reason },
2724
+ ...envelope.payload.harnessId === void 0 ? {} : { harnessId: envelope.payload.harnessId },
2659
2725
  ...envelope.payload.usage !== void 0 ? { usage: envelope.payload.usage } : {},
2660
2726
  recordedAt: receipt.recordedAt
2661
2727
  };
@@ -2679,16 +2745,6 @@ function isTerminalAttemptStatus(status) {
2679
2745
  function sameAgentRef2(expected, actual) {
2680
2746
  return actual?.agentId === expected.agentId && actual.profileRevision === expected.profileRevision;
2681
2747
  }
2682
- function uuidFromSha256(value) {
2683
- const match = /^sha256:([0-9a-f]{64})$/.exec(value);
2684
- if (match === null) throw new Error("CloudCrypto.sha256 must return canonical sha256 hex");
2685
- const digest = match[1];
2686
- if (digest === void 0) throw new Error("CloudCrypto.sha256 must return canonical sha256 hex");
2687
- const hex = digest.slice(0, 32).split("");
2688
- hex[12] = "8";
2689
- hex[16] = ["8", "9", "a", "b"][Number.parseInt(hex[16], 16) & 3];
2690
- return `${hex.slice(0, 8).join("")}-${hex.slice(8, 12).join("")}-${hex.slice(12, 16).join("")}-${hex.slice(16, 20).join("")}-${hex.slice(20).join("")}`;
2691
- }
2692
2748
  function sameOfferEnvelope(expected, actual) {
2693
2749
  return expected.id === actual.id && expected.type === actual.type && expected.task_id === actual.task_id && JSON.stringify(expected.payload) === JSON.stringify(actual.payload);
2694
2750
  }
@@ -2895,13 +2951,16 @@ function createByokCloud(options) {
2895
2951
  async function enqueueTaskEnvelope(tenant, deviceId, requestedTaskId, agentRef, buildEnvelope, beforeMailbox) {
2896
2952
  const stores = tenantStoresFor(controlPlane(tenant), root);
2897
2953
  const taskId = requestedTaskId ?? `task_${options.crypto.randomUuid()}`;
2898
- const messageId = uuidFromSha256(
2899
- await options.crypto.sha256(
2900
- new TextEncoder().encode(
2901
- JSON.stringify({ domain: "byok:task-offer", tenant, taskId, deviceId, agentRef })
2902
- )
2903
- )
2904
- );
2954
+ const messageId = await taskOfferMessageId(tenant, taskId, deviceId, agentRef, (bytes) => options.crypto.sha256(bytes));
2955
+ const proposed = buildEnvelope(taskId, 0, messageId);
2956
+ const selection = proposed.payload;
2957
+ if (selection.harnessId !== void 0) {
2958
+ HarnessIdSchema.parse(selection.harnessId);
2959
+ if (selection.runtime !== void 0 || selection.dispatchSelection !== void 0) throw new ByokCloudError("coordination_input_invalid", "harnessId conflicts with built-in runtime selection");
2960
+ await assertAgentCapabilities(tenant, deviceId, ["custom-harness"]);
2961
+ const device = await options.cloud.devices.get(tenant, deviceId);
2962
+ if (!device?.harnesses?.some((harness) => harness.id === selection.harnessId)) throw new ByokCloudError("coordination_input_invalid", "requested custom harness is not advertised by this device");
2963
+ }
2905
2964
  const reservation = agentRef === void 0 ? void 0 : await stores.tasks.reserveAgentOffer({ taskId, deviceId, agentRef });
2906
2965
  const openedBeforeAppend = reservation?.attempt ?? (agentRef === void 0 ? await stores.tasks.open({ taskId, deviceId }) : void 0);
2907
2966
  if (openedBeforeAppend === void 0 || openedBeforeAppend.deviceId !== deviceId || (agentRef === void 0 ? openedBeforeAppend.agentRef !== void 0 : openedBeforeAppend.agentRef === void 0 || !sameAgentRef2(agentRef, openedBeforeAppend.agentRef))) {
@@ -2918,7 +2977,6 @@ function createByokCloud(options) {
2918
2977
  `Task ${taskId} already has a durable delivered attempt and cannot be enqueued again.`
2919
2978
  );
2920
2979
  }
2921
- const proposed = buildEnvelope(taskId, 0, messageId);
2922
2980
  const proposedBody = JSON.stringify({
2923
2981
  deviceId,
2924
2982
  type: proposed.type,
@@ -3983,7 +4041,8 @@ var InMemoryDeviceDirectory = class {
3983
4041
  if (record === void 0 || record.revoked) return void 0;
3984
4042
  const updated = {
3985
4043
  ...record,
3986
- capabilities: Object.freeze([...input.capabilities])
4044
+ capabilities: Object.freeze([...input.capabilities]),
4045
+ harnesses: Object.freeze((input.harnesses ?? []).map((value) => Object.freeze({ ...value })))
3987
4046
  };
3988
4047
  this.#byTenant.set(key, updated);
3989
4048
  return updated;
@@ -4365,6 +4424,7 @@ var InMemoryTaskAttemptStore = class {
4365
4424
  ...existing,
4366
4425
  ownerDeviceId: input.deviceId,
4367
4426
  ...input.runtime === void 0 ? {} : { claimedRuntime: input.runtime },
4427
+ ...input.harnessId === void 0 ? {} : { claimedHarnessId: input.harnessId },
4368
4428
  ...input.capabilities === void 0 ? {} : { claimedRuntimeCapabilities: { ...input.capabilities } },
4369
4429
  status: "claimed",
4370
4430
  updatedAt: this.#now()