@byok-sdk/client 0.11.0 → 0.12.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
@@ -2,7 +2,7 @@ import { randomUUID, createHash, randomBytes, createPrivateKey, generateKeyPairS
2
2
  import { promises, mkdirSync, constants, existsSync, linkSync, fstatSync, lstatSync, unlinkSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, readFileSync, realpathSync } from 'fs';
3
3
  import * as path3 from 'path';
4
4
  import path3__default, { join, isAbsolute } from 'path';
5
- import { AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AgentRefSchema, AgentHomeProjectionPayloadSchema, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, AgentEgressPolicySchema, BYOK_PAIR_PATH, PairResponseSchema, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, AgentContentReceiptPayloadSchema, encodeEnvelope, PROTOCOL_VERSION, createEnvelope, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, TERMINAL_PROJECTION_SELECTION_CAPABILITY, STRICT_AGENT_ONLY_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AGENT_MESSAGE_EGRESS_CAPABILITY, AgentHomeProjectionCompletionRequestSchema, byokAgentHomeProjectionCompletionPath, AgentHomeProjectionReadbackSchema, parseMessage, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, AgentMessagePublishPayloadSchema, AgentMessageDispositionPayloadSchema, RuntimeIdSchema, AGENT_MEMORY_PROJECTION_CAPABILITY, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, decodeEnvelope, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, UnknownMessageTypeError, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionMutationSchema, AGENT_MEMORY_PROJECTION_MAX_REDACTED_BYTES, BYOK_WS_PATH } from '@byok-sdk/protocol';
5
+ import { AGENT_CONTENT_ARTIFACT_READ_CAPABILITY, AGENT_CONTENT_TRANSCRIPT_READ_CAPABILITY, AGENT_CONTENT_WORKSPACE_READ_CAPABILITY, AgentRefSchema, AgentHomeProjectionPayloadSchema, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, AgentEgressPolicySchema, BYOK_PAIR_PATH, PairResponseSchema, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, AgentContentReceiptPayloadSchema, encodeEnvelope, PROTOCOL_VERSION, createEnvelope, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, TERMINAL_PROJECTION_SELECTION_CAPABILITY, STRICT_AGENT_ONLY_CAPABILITY, AGENT_HOME_PROJECTION_CAPABILITY, AGENT_EGRESS_POLICY_CAPABILITY, AGENT_EGRESS_FRESH_SESSION_CAPABILITY, AGENT_MESSAGE_EGRESS_CAPABILITY, AgentHomeProjectionCompletionRequestSchema, byokAgentHomeProjectionCompletionPath, AgentHomeProjectionReadbackSchema, parseMessage, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, AgentMessagePublishPayloadSchema, AgentMessageDispositionPayloadSchema, RuntimeIdSchema, AGENT_MEMORY_PROJECTION_CAPABILITY, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, decodeEnvelope, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, UnknownMessageTypeError, BYOK_WS_PATH, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionMutationSchema, AGENT_MEMORY_PROJECTION_MAX_REDACTED_BYTES } from '@byok-sdk/protocol';
6
6
  import net2, { createServer, createConnection } from 'net';
7
7
  import * as os4 from 'os';
8
8
  import os4__default from 'os';
@@ -746,6 +746,120 @@ var AgentHomeLeaseManager = class _AgentHomeLeaseManager {
746
746
  }
747
747
  }
748
748
  };
749
+ function executionKey(input) {
750
+ const value = input.sessionRef === void 0 ? input.taskId : input.sessionRef;
751
+ const label = input.sessionRef === void 0 ? "taskId" : "sessionRef";
752
+ if (typeof value !== "string" || value.length === 0 || /[\u0000\r\n]/u.test(value)) {
753
+ throw new AgentHomeResolutionError(`Agent execution ${label} must be a non-empty single-line string`);
754
+ }
755
+ return `${input.sessionRef === void 0 ? "task" : "session"}\0${value}`;
756
+ }
757
+ var AgentHomeExecutionLeaseManager = class _AgentHomeExecutionLeaseManager {
758
+ constructor(manager) {
759
+ this.manager = manager;
760
+ }
761
+ manager;
762
+ static groups = /* @__PURE__ */ new Map();
763
+ static queues = /* @__PURE__ */ new Map();
764
+ async acquire(resolution, input) {
765
+ const initialKey = executionKey(input);
766
+ return this.exclusive(resolution.canonicalHome, async () => {
767
+ let group = _AgentHomeExecutionLeaseManager.groups.get(resolution.canonicalHome);
768
+ if (group === void 0) {
769
+ const baseLease = await this.manager.acquire(resolution);
770
+ group = {
771
+ manager: this.manager,
772
+ baseLease,
773
+ agentId: resolution.agentRef.agentId,
774
+ leasesByKey: /* @__PURE__ */ new Map()
775
+ };
776
+ _AgentHomeExecutionLeaseManager.groups.set(resolution.canonicalHome, group);
777
+ } else if (group.manager !== this.manager || group.agentId !== resolution.agentRef.agentId) {
778
+ throw new AgentHomeBusyError(`Agent home ${resolution.canonicalHome} is active under another execution owner`);
779
+ }
780
+ if (group.leasesByKey.has(initialKey)) {
781
+ throw new AgentHomeBusyError(`Agent session already has an active execution lease in ${resolution.canonicalHome}`);
782
+ }
783
+ const leaseId = randomUUID();
784
+ group.leasesByKey.set(initialKey, leaseId);
785
+ let currentKey = initialKey;
786
+ let sessionBound = input.sessionRef !== void 0;
787
+ let released = false;
788
+ return Object.freeze({
789
+ leaseId,
790
+ agentRef: resolution.agentRef,
791
+ canonicalHome: resolution.canonicalHome,
792
+ cwd: resolution.canonicalHome,
793
+ homeIdentity: group.baseLease.homeIdentity,
794
+ bindSession: async (sessionRef) => {
795
+ const nextKey = executionKey({ taskId: input.taskId, sessionRef });
796
+ await this.exclusive(resolution.canonicalHome, async () => {
797
+ if (released) throw new AgentHomeBusyError(`Agent execution lease ${leaseId} is already released`);
798
+ const currentGroup = _AgentHomeExecutionLeaseManager.groups.get(resolution.canonicalHome);
799
+ if (currentGroup !== group || currentGroup.leasesByKey.get(currentKey) !== leaseId) {
800
+ throw new AgentHomeBusyError(`Agent execution lease ${leaseId} is no longer owned by this process`);
801
+ }
802
+ if (nextKey === currentKey) return;
803
+ if (sessionBound) {
804
+ throw new AgentHomeBusyError(
805
+ `Agent session execution lease ${leaseId} cannot rebind to a different runtime session`
806
+ );
807
+ }
808
+ if (currentGroup.leasesByKey.has(nextKey)) {
809
+ throw new AgentHomeBusyError(`Agent session already has an active execution lease in ${resolution.canonicalHome}`);
810
+ }
811
+ currentGroup.leasesByKey.set(nextKey, leaseId);
812
+ currentGroup.leasesByKey.delete(currentKey);
813
+ currentKey = nextKey;
814
+ sessionBound = true;
815
+ });
816
+ },
817
+ release: async () => {
818
+ await this.exclusive(resolution.canonicalHome, async () => {
819
+ if (released) return;
820
+ const currentGroup = _AgentHomeExecutionLeaseManager.groups.get(resolution.canonicalHome);
821
+ if (currentGroup !== group || currentGroup.leasesByKey.get(currentKey) !== leaseId) {
822
+ released = true;
823
+ throw new AgentHomeBusyError(`Agent execution lease ${leaseId} is no longer owned by this process`);
824
+ }
825
+ currentGroup.leasesByKey.delete(currentKey);
826
+ released = true;
827
+ if (currentGroup.leasesByKey.size === 0) {
828
+ _AgentHomeExecutionLeaseManager.groups.delete(resolution.canonicalHome);
829
+ await currentGroup.baseLease.release();
830
+ }
831
+ });
832
+ }
833
+ });
834
+ });
835
+ }
836
+ async mutate(binding, operation) {
837
+ return this.exclusive(binding.resolution.canonicalHome, async () => {
838
+ const group = _AgentHomeExecutionLeaseManager.groups.get(binding.resolution.canonicalHome);
839
+ if (group === void 0 || group.manager !== this.manager || ![...group.leasesByKey.values()].includes(binding.lease.leaseId)) {
840
+ throw new AgentHomeBusyError("Agent execution lease does not own this home mutation");
841
+ }
842
+ return operation();
843
+ });
844
+ }
845
+ async exclusive(canonicalHome, operation) {
846
+ const prior = _AgentHomeExecutionLeaseManager.queues.get(canonicalHome) ?? Promise.resolve();
847
+ let release;
848
+ const tail = new Promise((resolve) => {
849
+ release = resolve;
850
+ });
851
+ _AgentHomeExecutionLeaseManager.queues.set(canonicalHome, tail);
852
+ await prior;
853
+ try {
854
+ return await operation();
855
+ } finally {
856
+ release();
857
+ if (_AgentHomeExecutionLeaseManager.queues.get(canonicalHome) === tail) {
858
+ _AgentHomeExecutionLeaseManager.queues.delete(canonicalHome);
859
+ }
860
+ }
861
+ }
862
+ };
749
863
  async function initializeAgentHome(resolution) {
750
864
  await ensureDirectoryNoSymlink(
751
865
  resolution.canonicalHome,
@@ -821,10 +935,12 @@ var AgentHomeManager = class {
821
935
  layout;
822
936
  projection;
823
937
  leaseManager;
938
+ executionLeaseManager;
824
939
  constructor(options) {
825
940
  this.layout = new AgentHomeLayout(options.hostStorageRoot);
826
941
  this.projection = options.projection;
827
942
  this.leaseManager = options.leaseManager ?? new AgentHomeLeaseManager();
943
+ this.executionLeaseManager = new AgentHomeExecutionLeaseManager(this.leaseManager);
828
944
  }
829
945
  async prepare(agentRef) {
830
946
  const binding = await this.acquire(agentRef);
@@ -851,12 +967,25 @@ var AgentHomeManager = class {
851
967
  const lease = await this.leaseManager.acquire(resolution);
852
968
  return Object.freeze({ resolution, lease });
853
969
  }
970
+ async acquireExecution(agentRef, input) {
971
+ const resolution = await this.layout.resolve(agentRef);
972
+ const lease = await this.executionLeaseManager.acquire(resolution, input);
973
+ return Object.freeze({ resolution, lease });
974
+ }
854
975
  /** Initialize only after any requested session exact-match has succeeded. */
855
976
  async initialize(binding) {
856
- const { resolution, lease } = binding;
977
+ await this.initializeResolved(binding.resolution, binding.lease.cwd);
978
+ }
979
+ async initializeExecution(binding) {
980
+ await this.mutateExecution(binding, () => this.initializeResolved(binding.resolution, binding.lease.cwd));
981
+ }
982
+ async mutateExecution(binding, operation) {
983
+ return this.executionLeaseManager.mutate(binding, operation);
984
+ }
985
+ async initializeResolved(resolution, cwd) {
857
986
  await initializeAgentHome(resolution);
858
987
  const prepare = this.projection?.prepare;
859
- if (prepare !== void 0) await prepare({ ...resolution, cwd: lease.cwd });
988
+ if (prepare !== void 0) await prepare({ ...resolution, cwd });
860
989
  if (await promises.realpath(resolution.homeDir) !== resolution.canonicalHome) {
861
990
  throw new AgentHomeResolutionError("Agent projection changed the canonical home path");
862
991
  }
@@ -6983,9 +7112,18 @@ function assertRecord(value) {
6983
7112
  throw new DeviceCredentialStoreError("OS credential entry has an incomplete device credential");
6984
7113
  }
6985
7114
  }
6986
- function encode(record3) {
6987
- assertRecord(record3);
6988
- const encoded = Buffer.from(JSON.stringify(record3), "utf8").toString("base64");
7115
+ function isFirstPairingAttempt(value) {
7116
+ return "kind" in value && value.kind === "first-pairing-attempt-v1";
7117
+ }
7118
+ function assertFirstPairingAttempt(value) {
7119
+ if (typeof value !== "object" || value === null || Array.isArray(value) || value.kind !== "first-pairing-attempt-v1" || typeof value.deviceName !== "string" || typeof value.devicePublicKey !== "string" || typeof value.devicePrivateKeyPem !== "string" || value.machineId !== void 0 && typeof value.machineId !== "string" || value.deviceName.length === 0 || value.devicePublicKey.length === 0 || value.devicePrivateKeyPem.length === 0) {
7120
+ throw new DeviceCredentialStoreError("OS credential entry has an invalid first-pairing attempt shape");
7121
+ }
7122
+ }
7123
+ function encode(authority) {
7124
+ if (isFirstPairingAttempt(authority)) assertFirstPairingAttempt(authority);
7125
+ else assertRecord(authority);
7126
+ const encoded = Buffer.from(JSON.stringify(authority), "utf8").toString("base64");
6989
7127
  const value = `${ENCODED_PREFIX}${encoded}`;
6990
7128
  if (Buffer.byteLength(value, "utf8") > 2400) {
6991
7129
  throw new DeviceCredentialStoreError("device credential exceeds the OS credential entry bound");
@@ -7014,6 +7152,16 @@ function decode(value) {
7014
7152
  } catch {
7015
7153
  throw new DeviceCredentialStoreError("OS credential entry is not valid JSON");
7016
7154
  }
7155
+ if (typeof parsed === "object" && parsed !== null && parsed.kind === "first-pairing-attempt-v1") {
7156
+ assertFirstPairingAttempt(parsed);
7157
+ return Object.freeze({
7158
+ kind: parsed.kind,
7159
+ deviceName: parsed.deviceName,
7160
+ devicePublicKey: parsed.devicePublicKey,
7161
+ devicePrivateKeyPem: parsed.devicePrivateKeyPem,
7162
+ ...parsed.machineId === void 0 ? {} : { machineId: parsed.machineId }
7163
+ });
7164
+ }
7017
7165
  assertRecord(parsed);
7018
7166
  return Object.freeze({
7019
7167
  deviceId: parsed.deviceId,
@@ -7044,6 +7192,18 @@ var DeviceCredentialStore = class {
7044
7192
  this.#run = options.commandRunner ?? runDeviceCommand;
7045
7193
  }
7046
7194
  async read() {
7195
+ const authority = await this.#readAuthority();
7196
+ return authority === void 0 || isFirstPairingAttempt(authority) ? void 0 : authority;
7197
+ }
7198
+ async readFirstPairingAttempt() {
7199
+ const authority = await this.#readAuthority();
7200
+ return authority !== void 0 && isFirstPairingAttempt(authority) ? authority : void 0;
7201
+ }
7202
+ async saveFirstPairingAttempt(attempt) {
7203
+ assertFirstPairingAttempt(attempt);
7204
+ await this.#replaceAuthority(attempt);
7205
+ }
7206
+ async #readAuthority() {
7047
7207
  const result = await this.#invoke("read");
7048
7208
  if (result.exitCode === NOT_FOUND || this.#platform === "linux" && result.exitCode === 1 && result.stderr.trim().length === 0) return void 0;
7049
7209
  if (result.exitCode === 127) throw new DeviceCredentialStoreUnavailableError();
@@ -7056,6 +7216,12 @@ var DeviceCredentialStore = class {
7056
7216
  }
7057
7217
  async replace(record3) {
7058
7218
  const encoded = encode(record3);
7219
+ await this.#replaceEncoded(encoded);
7220
+ }
7221
+ async #replaceAuthority(authority) {
7222
+ await this.#replaceEncoded(encode(authority));
7223
+ }
7224
+ async #replaceEncoded(encoded) {
7059
7225
  const result = await this.#invoke("replace", encoded);
7060
7226
  if (result.exitCode === 127) throw new DeviceCredentialStoreUnavailableError();
7061
7227
  if (result.exitCode !== 0) {
@@ -7066,7 +7232,7 @@ var DeviceCredentialStore = class {
7066
7232
  }
7067
7233
  /** Returns true only after the sole secret authority is confirmed absent. */
7068
7234
  async clear() {
7069
- const before = await this.read();
7235
+ const before = await this.#readAuthority();
7070
7236
  if (before === void 0) return false;
7071
7237
  const result = await this.#invoke("clear");
7072
7238
  if (result.exitCode === 127) throw new DeviceCredentialStoreUnavailableError();
@@ -7075,7 +7241,7 @@ var DeviceCredentialStore = class {
7075
7241
  `operating-system credential provider could not clear device credentials${providerDiagnostic(result.stderr)}`
7076
7242
  );
7077
7243
  }
7078
- if (await this.read() !== void 0) {
7244
+ if (await this.#readAuthority() !== void 0) {
7079
7245
  throw new DeviceCredentialStoreError("operating-system credential provider reported deletion but device credentials remain");
7080
7246
  }
7081
7247
  return true;
@@ -7150,17 +7316,24 @@ var DeviceCredentialStore = class {
7150
7316
  }
7151
7317
  };
7152
7318
  var InMemoryDeviceCredentialStore = class {
7153
- #record;
7319
+ #authority;
7154
7320
  async read() {
7155
- return this.#record === void 0 ? void 0 : Object.freeze({ ...this.#record });
7321
+ return this.#authority === void 0 || isFirstPairingAttempt(this.#authority) ? void 0 : Object.freeze({ ...this.#authority });
7322
+ }
7323
+ async readFirstPairingAttempt() {
7324
+ return this.#authority !== void 0 && isFirstPairingAttempt(this.#authority) ? Object.freeze({ ...this.#authority }) : void 0;
7325
+ }
7326
+ async saveFirstPairingAttempt(attempt) {
7327
+ assertFirstPairingAttempt(attempt);
7328
+ this.#authority = Object.freeze({ ...attempt });
7156
7329
  }
7157
7330
  async replace(record3) {
7158
7331
  assertRecord(record3);
7159
- this.#record = Object.freeze({ ...record3 });
7332
+ this.#authority = Object.freeze({ ...record3 });
7160
7333
  }
7161
7334
  async clear() {
7162
- const had = this.#record !== void 0;
7163
- this.#record = void 0;
7335
+ const had = this.#authority !== void 0;
7336
+ this.#authority = void 0;
7164
7337
  return had;
7165
7338
  }
7166
7339
  };
@@ -7447,6 +7620,10 @@ function describeEndpoint(transport, url) {
7447
7620
  const parsed = typeof url === "string" ? new URL(url) : url;
7448
7621
  return { transport, host: parsed.host, path: parsed.pathname };
7449
7622
  }
7623
+ function formatServerUrl(value) {
7624
+ const url = typeof value === "string" ? new URL(value) : value;
7625
+ return `${url.protocol}//${url.host}${url.pathname}`;
7626
+ }
7450
7627
  var InsecureServerUrlError = class extends Error {
7451
7628
  constructor(message) {
7452
7629
  super(message);
@@ -7465,9 +7642,10 @@ function assertServerUrlAllowed(rawUrl, opts = {}) {
7465
7642
  let url;
7466
7643
  try {
7467
7644
  url = new URL(rawUrl);
7468
- } catch (err) {
7469
- throw new InsecureServerUrlError(`invalid server URL "${rawUrl}": ${err instanceof Error ? err.message : String(err)}`);
7645
+ } catch {
7646
+ throw new InsecureServerUrlError("invalid server URL");
7470
7647
  }
7648
+ const endpoint = formatServerUrl(url);
7471
7649
  switch (url.protocol) {
7472
7650
  case "https:":
7473
7651
  case "wss:":
@@ -7476,11 +7654,11 @@ function assertServerUrlAllowed(rawUrl, opts = {}) {
7476
7654
  case "ws:":
7477
7655
  if (opts.dangerouslyAllowInsecureRemote || isLoopbackHostname(url.hostname)) return;
7478
7656
  throw new InsecureServerUrlError(
7479
- `refusing to connect to "${rawUrl}" over plaintext ${url.protocol.replace(":", "")} \u2014 "${url.hostname}" is not a loopback host. Use wss:/https: for any non-loopback server, or pass { dangerouslyAllowInsecureRemote: true } (DaemonConfig) if you understand and accept the risk of sending device credentials over an unencrypted connection.`
7657
+ `refusing to connect to "${endpoint}" over plaintext ${url.protocol.replace(":", "")} \u2014 "${url.hostname}" is not a loopback host. Use wss:/https: for any non-loopback server, or pass { dangerouslyAllowInsecureRemote: true } (DaemonConfig) if you understand and accept the risk of sending device credentials over an unencrypted connection.`
7480
7658
  );
7481
7659
  default:
7482
7660
  throw new InsecureServerUrlError(
7483
- `refusing to connect to "${rawUrl}" \u2014 unsupported scheme "${url.protocol}" (expected http:, https:, ws:, or wss:).`
7661
+ `refusing to connect to "${endpoint}" \u2014 unsupported scheme "${url.protocol}" (expected http:, https:, ws:, or wss:).`
7484
7662
  );
7485
7663
  }
7486
7664
  }
@@ -7492,12 +7670,22 @@ var DeviceRevokedError = class extends Error {
7492
7670
  this.name = "DeviceRevokedError";
7493
7671
  }
7494
7672
  };
7673
+ var AuthRequestAbortedError = class extends Error {
7674
+ constructor(reason) {
7675
+ super(reason === "deadline" ? "authentication request exceeded its deadline" : "authentication request was cancelled during shutdown");
7676
+ this.reason = reason;
7677
+ this.name = "AuthRequestAbortedError";
7678
+ }
7679
+ reason;
7680
+ };
7495
7681
  var ASSUMED_PAIR_TOKEN_TTL_MS = 45 * 60 * 1e3;
7496
7682
  var RENEW_MARGIN_MS = 60 * 1e3;
7683
+ var DEFAULT_AUTH_REQUEST_DEADLINE_MS = 15e3;
7497
7684
  var AuthManager = class {
7498
7685
  constructor(opts) {
7499
7686
  this.opts = opts;
7500
7687
  this.credentials = opts.credentials ?? opts.store.credentials;
7688
+ this.requestDeadlineMs = resolveRequestDeadlineMs(opts.authRequestDeadlineMs);
7501
7689
  }
7502
7690
  opts;
7503
7691
  record;
@@ -7507,7 +7695,10 @@ var AuthManager = class {
7507
7695
  stopped = false;
7508
7696
  pairing = false;
7509
7697
  credentialMutationTail = Promise.resolve();
7698
+ /** The sole cancellation authority for the request currently inside the serialized credential mutation. */
7699
+ activeRequest;
7510
7700
  credentials;
7701
+ requestDeadlineMs;
7511
7702
  get deviceId() {
7512
7703
  return this.record?.deviceId;
7513
7704
  }
@@ -7543,23 +7734,51 @@ var AuthManager = class {
7543
7734
  if (!(error instanceof DeviceRecordRePairRequiredError)) throw error;
7544
7735
  }
7545
7736
  }
7546
- const keyPair = existing ? { privateKey: importPrivateKeyPem(existing.devicePrivateKeyPem), publicKeyBase64Url: existing.devicePublicKey } : generateDeviceKeyPair();
7737
+ const observedDeviceName = this.opts.deviceName ?? os4__default.hostname();
7738
+ const observedMachineId = await this.opts.machineId?.();
7739
+ let keyPair;
7740
+ let pairingDeviceName = observedDeviceName;
7741
+ let pairingMachineId = observedMachineId;
7742
+ if (existing) {
7743
+ keyPair = { privateKey: importPrivateKeyPem(existing.devicePrivateKeyPem), publicKeyBase64Url: existing.devicePublicKey };
7744
+ } else {
7745
+ const firstAttempt = await this.credentials.readFirstPairingAttempt();
7746
+ if (firstAttempt) {
7747
+ keyPair = {
7748
+ privateKey: importPrivateKeyPem(firstAttempt.devicePrivateKeyPem),
7749
+ publicKeyBase64Url: firstAttempt.devicePublicKey
7750
+ };
7751
+ pairingDeviceName = firstAttempt.deviceName;
7752
+ pairingMachineId = firstAttempt.machineId;
7753
+ } else {
7754
+ keyPair = generateDeviceKeyPair();
7755
+ await this.credentials.saveFirstPairingAttempt({
7756
+ kind: "first-pairing-attempt-v1",
7757
+ deviceName: pairingDeviceName,
7758
+ devicePublicKey: keyPair.publicKeyBase64Url,
7759
+ devicePrivateKeyPem: exportPrivateKeyPem(keyPair.privateKey),
7760
+ ...pairingMachineId === void 0 ? {} : { machineId: pairingMachineId }
7761
+ });
7762
+ }
7763
+ }
7547
7764
  const url = new URL(BYOK_PAIR_PATH, toHttpBase(this.opts.serverUrl));
7548
- const machineId = await this.opts.machineId?.();
7549
- const res = await fetch(url, {
7550
- method: "POST",
7551
- headers: { "content-type": "application/json" },
7552
- body: JSON.stringify({
7553
- pairingCode,
7554
- deviceName: this.opts.deviceName ?? os4__default.hostname(),
7555
- devicePublicKey: keyPair.publicKeyBase64Url,
7556
- ...machineId === void 0 ? {} : { machineId }
7557
- })
7765
+ const body = await this.runRequest(async (signal) => {
7766
+ const res = await fetch(url, {
7767
+ method: "POST",
7768
+ headers: { "content-type": "application/json" },
7769
+ body: JSON.stringify({
7770
+ pairingCode,
7771
+ deviceName: pairingDeviceName,
7772
+ devicePublicKey: keyPair.publicKeyBase64Url,
7773
+ ...pairingMachineId === void 0 ? {} : { machineId: pairingMachineId }
7774
+ }),
7775
+ signal
7776
+ });
7777
+ if (!res.ok) {
7778
+ throw new Error(`pairing failed: HTTP ${res.status} ${await safeErrorText(res)}`.trimEnd());
7779
+ }
7780
+ return PairResponseSchema.parse(await res.json());
7558
7781
  });
7559
- if (!res.ok) {
7560
- throw new Error(`pairing failed: HTTP ${res.status} ${await safeErrorText(res)}`.trimEnd());
7561
- }
7562
- const body = PairResponseSchema.parse(await res.json());
7563
7782
  const metadata = {
7564
7783
  deviceId: body.deviceId,
7565
7784
  tenantId: body.tenantId,
@@ -7598,6 +7817,7 @@ var AuthManager = class {
7598
7817
  this.stopped = true;
7599
7818
  if (this.proactiveTimer) clearTimeout(this.proactiveTimer);
7600
7819
  this.proactiveTimer = void 0;
7820
+ this.activeRequest?.abort();
7601
7821
  await this.credentialMutationTail;
7602
7822
  }
7603
7823
  async renew() {
@@ -7614,29 +7834,35 @@ var AuthManager = class {
7614
7834
  const record3 = this.record;
7615
7835
  const base = toHttpBase(this.opts.serverUrl);
7616
7836
  const privateKey = importPrivateKeyPem(record3.devicePrivateKeyPem);
7617
- const challengeRes = await fetch(new URL(BYOK_CHALLENGE_PATH, base), {
7618
- method: "POST",
7619
- headers: { "content-type": "application/json" },
7620
- body: JSON.stringify({ deviceId: record3.deviceId })
7837
+ const { nonce } = await this.runRequest(async (signal) => {
7838
+ const challengeRes = await fetch(new URL(BYOK_CHALLENGE_PATH, base), {
7839
+ method: "POST",
7840
+ headers: { "content-type": "application/json" },
7841
+ body: JSON.stringify({ deviceId: record3.deviceId }),
7842
+ signal
7843
+ });
7844
+ if (challengeRes.status === 401) this.markRevoked();
7845
+ if (!challengeRes.ok) {
7846
+ throw new Error(
7847
+ `token renewal (challenge) failed: HTTP ${challengeRes.status} ${await safeErrorText(challengeRes)}`.trimEnd()
7848
+ );
7849
+ }
7850
+ return await challengeRes.json();
7621
7851
  });
7622
- if (challengeRes.status === 401) this.markRevoked();
7623
- if (!challengeRes.ok) {
7624
- throw new Error(
7625
- `token renewal (challenge) failed: HTTP ${challengeRes.status} ${await safeErrorText(challengeRes)}`.trimEnd()
7626
- );
7627
- }
7628
- const { nonce } = await challengeRes.json();
7629
7852
  const signature = signNonce(privateKey, nonce);
7630
- const tokenRes = await fetch(new URL(BYOK_TOKEN_PATH, base), {
7631
- method: "POST",
7632
- headers: { "content-type": "application/json" },
7633
- body: JSON.stringify({ deviceId: record3.deviceId, nonce, signature })
7853
+ const body = await this.runRequest(async (signal) => {
7854
+ const tokenRes = await fetch(new URL(BYOK_TOKEN_PATH, base), {
7855
+ method: "POST",
7856
+ headers: { "content-type": "application/json" },
7857
+ body: JSON.stringify({ deviceId: record3.deviceId, nonce, signature }),
7858
+ signal
7859
+ });
7860
+ if (tokenRes.status === 401) this.markRevoked();
7861
+ if (!tokenRes.ok) {
7862
+ throw new Error(`token renewal (token) failed: HTTP ${tokenRes.status} ${await safeErrorText(tokenRes)}`.trimEnd());
7863
+ }
7864
+ return await tokenRes.json();
7634
7865
  });
7635
- if (tokenRes.status === 401) this.markRevoked();
7636
- if (!tokenRes.ok) {
7637
- throw new Error(`token renewal (token) failed: HTTP ${tokenRes.status} ${await safeErrorText(tokenRes)}`.trimEnd());
7638
- }
7639
- const body = await tokenRes.json();
7640
7866
  const updated = {
7641
7867
  ...record3,
7642
7868
  accessToken: body.accessToken,
@@ -7666,6 +7892,37 @@ var AuthManager = class {
7666
7892
  timer.unref?.();
7667
7893
  this.proactiveTimer = timer;
7668
7894
  }
7895
+ /**
7896
+ * Bounds one complete auth exchange rather than fetch alone. Keeping the
7897
+ * controller active through `json()`/`text()` makes a non-cooperative or
7898
+ * partial response body cancellable by the same authority that owns fetch.
7899
+ */
7900
+ async runRequest(operation) {
7901
+ if (this.stopped) throw new AuthRequestAbortedError("stopped");
7902
+ const controller = new AbortController();
7903
+ this.activeRequest = controller;
7904
+ let deadlineElapsed = false;
7905
+ const deadline = setTimeout(() => {
7906
+ deadlineElapsed = true;
7907
+ controller.abort();
7908
+ }, this.requestDeadlineMs);
7909
+ let rejectOnAbort;
7910
+ const aborted = new Promise((_, reject) => {
7911
+ rejectOnAbort = reject;
7912
+ });
7913
+ const onAbort = () => rejectOnAbort(new AuthRequestAbortedError(deadlineElapsed ? "deadline" : "stopped"));
7914
+ controller.signal.addEventListener("abort", onAbort, { once: true });
7915
+ try {
7916
+ return await Promise.race([operation(controller.signal), aborted]);
7917
+ } catch (error) {
7918
+ if (controller.signal.aborted) throw new AuthRequestAbortedError(deadlineElapsed ? "deadline" : "stopped");
7919
+ throw error;
7920
+ } finally {
7921
+ clearTimeout(deadline);
7922
+ controller.signal.removeEventListener("abort", onAbort);
7923
+ if (this.activeRequest === controller) this.activeRequest = void 0;
7924
+ }
7925
+ }
7669
7926
  async runCredentialMutation(operation) {
7670
7927
  const predecessor = this.credentialMutationTail;
7671
7928
  let release;
@@ -7708,6 +7965,13 @@ function resolvePairExpiry(refreshHint) {
7708
7965
  }
7709
7966
  return new Date(Date.now() + ASSUMED_PAIR_TOKEN_TTL_MS).toISOString();
7710
7967
  }
7968
+ function resolveRequestDeadlineMs(value) {
7969
+ const deadline = value ?? DEFAULT_AUTH_REQUEST_DEADLINE_MS;
7970
+ if (!Number.isSafeInteger(deadline) || deadline <= 0) {
7971
+ throw new Error("authRequestDeadlineMs must be a positive safe integer");
7972
+ }
7973
+ return deadline;
7974
+ }
7711
7975
  async function safeErrorText(res) {
7712
7976
  try {
7713
7977
  return await res.text();
@@ -7729,37 +7993,48 @@ function withAuth(init, token) {
7729
7993
  }
7730
7994
 
7731
7995
  // src/daemon/blob-client.ts
7732
- async function safeErrorText2(res) {
7733
- try {
7734
- return await res.text();
7735
- } catch {
7736
- return "";
7996
+ var BlobRequestAbortedError = class extends Error {
7997
+ constructor(reason) {
7998
+ super(reason === "deadline" ? "blob request deadline elapsed" : "blob request cancelled");
7999
+ this.reason = reason;
8000
+ this.name = "BlobRequestAbortedError";
7737
8001
  }
7738
- }
8002
+ reason;
8003
+ };
7739
8004
  var BlobClient = class {
7740
- constructor(serverUrl, auth) {
8005
+ constructor(serverUrl, auth, options = {}) {
7741
8006
  this.serverUrl = serverUrl;
7742
8007
  this.auth = auth;
8008
+ this.options = options;
8009
+ const requestDeadlineMs = options.requestDeadlineMs ?? 15e3;
8010
+ if (!Number.isSafeInteger(requestDeadlineMs) || requestDeadlineMs <= 0) {
8011
+ throw new Error("BlobClient requestDeadlineMs must be a positive safe integer");
8012
+ }
8013
+ this.requestDeadlineMs = requestDeadlineMs;
7743
8014
  }
7744
8015
  serverUrl;
7745
8016
  auth;
8017
+ options;
8018
+ requestDeadlineMs;
7746
8019
  /** `blobRef` -> `GET /byok/blobs/:id/url` -> fetch the presigned download URL -> text content. Always resolves fresh rather than trusting any inlined `BlobRef.url`, per docs/protocol.md §7. */
7747
- async resolveInstruction(blobRef) {
8020
+ async resolveInstruction(blobRef, options = {}) {
7748
8021
  const base = toHttpBase(this.serverUrl);
7749
- const urlRes = await authedFetch(
7750
- new URL(byokBlobUrlPath(blobRef.blobId), base),
7751
- { method: "GET" },
7752
- this.auth
8022
+ const urlRes = await this.#request(
8023
+ (signal) => authedFetch(new URL(byokBlobUrlPath(blobRef.blobId), base), { method: "GET", signal }, this.auth),
8024
+ options.signal
7753
8025
  );
7754
8026
  if (!urlRes.ok) {
7755
- throw new Error(`failed to resolve blob download url: HTTP ${urlRes.status} ${await safeErrorText2(urlRes)}`.trimEnd());
8027
+ throw new Error(`failed to resolve blob download url: HTTP ${urlRes.status} ${await this.#safeErrorText(urlRes, options.signal)}`.trimEnd());
8028
+ }
8029
+ const { downloadUrl } = await this.#readJson(urlRes, options.signal);
8030
+ if (typeof downloadUrl !== "string" || downloadUrl.length === 0) {
8031
+ throw new Error("failed to resolve blob download url: response omitted downloadUrl");
7756
8032
  }
7757
- const { downloadUrl } = await urlRes.json();
7758
- const contentRes = await fetch(new URL(downloadUrl, base));
8033
+ const contentRes = await this.#request((signal) => fetch(new URL(downloadUrl, base), { signal }), options.signal);
7759
8034
  if (!contentRes.ok) {
7760
8035
  throw new Error(`failed to download blob content: HTTP ${contentRes.status}`);
7761
8036
  }
7762
- const bytes = new Uint8Array(await contentRes.arrayBuffer());
8037
+ const bytes = await this.#readBody(contentRes, options.signal);
7763
8038
  const observedHash = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
7764
8039
  if (observedHash !== blobRef.contentHash || bytes.length !== blobRef.size) {
7765
8040
  throw new Error(
@@ -7768,63 +8043,71 @@ var BlobClient = class {
7768
8043
  }
7769
8044
  return new TextDecoder().decode(bytes);
7770
8045
  }
7771
- /** `POST /byok/blobs` (declares size/contentType/contentHash) -> PUT the bytes to the presigned upload URL -> a `BlobRef` for `task.artifact.blobRef`. */
8046
+ /** `POST /byok/blobs` -> PUT the bytes to the presigned URL -> finalize into a `BlobRef`. */
7772
8047
  async uploadArtifact(content, contentType, options = {}) {
7773
8048
  const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
7774
8049
  const contentHash4 = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
7775
8050
  const base = toHttpBase(this.serverUrl);
7776
8051
  const reservationId = options.idempotencyKey ?? `blob_${randomUUID()}`;
7777
- const createRes = await authedFetch(
7778
- new URL(BYOK_BLOBS_PATH, base),
7779
- {
7780
- method: "POST",
7781
- headers: {
7782
- "content-type": "application/json",
7783
- "idempotency-key": reservationId
8052
+ const createRes = await this.#request(
8053
+ (signal) => authedFetch(
8054
+ new URL(BYOK_BLOBS_PATH, base),
8055
+ {
8056
+ method: "POST",
8057
+ headers: { "content-type": "application/json", "idempotency-key": reservationId },
8058
+ body: JSON.stringify({ size: bytes.length, contentType, contentHash: contentHash4 }),
8059
+ signal
7784
8060
  },
7785
- body: JSON.stringify({ size: bytes.length, contentType, contentHash: contentHash4 })
7786
- },
7787
- this.auth
8061
+ this.auth
8062
+ ),
8063
+ options.signal
7788
8064
  );
7789
8065
  if (!createRes.ok) {
7790
- throw new Error(`failed to create blob: HTTP ${createRes.status} ${await safeErrorText2(createRes)}`.trimEnd());
8066
+ throw new Error(`failed to create blob: HTTP ${createRes.status} ${await this.#safeErrorText(createRes, options.signal)}`.trimEnd());
8067
+ }
8068
+ const { blobId, uploadUrl } = await this.#readJson(createRes, options.signal);
8069
+ if (typeof blobId !== "string" || blobId.length === 0 || typeof uploadUrl !== "string" || uploadUrl.length === 0) {
8070
+ throw new Error("failed to create blob: response omitted blobId or uploadUrl");
7791
8071
  }
7792
- const { blobId, uploadUrl } = await createRes.json();
7793
8072
  const blobRef = { blobId, contentHash: contentHash4, size: bytes.length, contentType };
7794
- if (options.idempotencyKey !== void 0 && await this.#hasExactCommittedBlob(base, blobRef)) {
8073
+ if (options.idempotencyKey !== void 0 && await this.#hasExactCommittedBlob(base, blobRef, options.signal)) {
7795
8074
  return blobRef;
7796
8075
  }
7797
- const putRes = await fetch(new URL(uploadUrl, base), {
7798
- method: "PUT",
7799
- headers: { "content-type": contentType },
7800
- body: bytes
7801
- });
8076
+ const putRes = await this.#request(
8077
+ (signal) => fetch(new URL(uploadUrl, base), {
8078
+ method: "PUT",
8079
+ headers: { "content-type": contentType },
8080
+ body: bytes,
8081
+ signal
8082
+ }),
8083
+ options.signal
8084
+ );
7802
8085
  if (!putRes.ok) {
7803
8086
  throw new Error(`failed to upload blob content: HTTP ${putRes.status}`);
7804
8087
  }
7805
- await this.#finalize(base, blobId, reservationId);
8088
+ this.#throwIfAborted(options.signal);
8089
+ await this.#finalize(base, blobId, reservationId, options.signal);
7806
8090
  return blobRef;
7807
8091
  }
7808
- async #hasExactCommittedBlob(base, blobRef) {
7809
- const urlRes = await authedFetch(
7810
- new URL(byokBlobUrlPath(blobRef.blobId), base),
7811
- { method: "GET" },
7812
- this.auth
8092
+ async #hasExactCommittedBlob(base, blobRef, signal) {
8093
+ const urlRes = await this.#request(
8094
+ (requestSignal) => authedFetch(new URL(byokBlobUrlPath(blobRef.blobId), base), { method: "GET", signal: requestSignal }, this.auth),
8095
+ signal
7813
8096
  );
7814
8097
  if (urlRes.status === 404) return false;
7815
8098
  if (!urlRes.ok) {
7816
- throw new Error(`failed to read back idempotent blob: HTTP ${urlRes.status} ${await safeErrorText2(urlRes)}`.trimEnd());
8099
+ throw new Error(`failed to read back idempotent blob: HTTP ${urlRes.status} ${await this.#safeErrorText(urlRes, signal)}`.trimEnd());
7817
8100
  }
7818
- const { downloadUrl } = await urlRes.json();
8101
+ const { downloadUrl } = await this.#readJson(urlRes, signal);
7819
8102
  if (typeof downloadUrl !== "string" || downloadUrl.length === 0) {
7820
8103
  throw new Error("failed to read back idempotent blob: response omitted downloadUrl");
7821
8104
  }
7822
- const contentRes = await fetch(new URL(downloadUrl, base));
8105
+ const contentRes = await this.#request((requestSignal) => fetch(new URL(downloadUrl, base), { signal: requestSignal }), signal);
7823
8106
  if (contentRes.status === 404) return false;
7824
8107
  if (!contentRes.ok) {
7825
8108
  throw new Error(`failed to read back idempotent blob content: HTTP ${contentRes.status}`);
7826
8109
  }
7827
- const bytes = new Uint8Array(await contentRes.arrayBuffer());
8110
+ const bytes = await this.#readBody(contentRes, signal);
7828
8111
  const observedHash = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
7829
8112
  if (observedHash !== blobRef.contentHash || bytes.length !== blobRef.size) {
7830
8113
  throw new Error(
@@ -7833,18 +8116,19 @@ var BlobClient = class {
7833
8116
  }
7834
8117
  return true;
7835
8118
  }
7836
- async #finalize(base, blobId, reservationId) {
8119
+ async #finalize(base, blobId, reservationId, signal) {
7837
8120
  let lastFailure;
7838
8121
  for (let attempt = 1; attempt <= 2; attempt += 1) {
8122
+ this.#throwIfAborted(signal);
7839
8123
  let response;
7840
8124
  try {
7841
- response = await authedFetch(
7842
- new URL(byokBlobFinalizePath(blobId), base),
7843
- {
7844
- method: "POST",
7845
- headers: { "idempotency-key": reservationId }
7846
- },
7847
- this.auth
8125
+ response = await this.#request(
8126
+ (requestSignal) => authedFetch(
8127
+ new URL(byokBlobFinalizePath(blobId), base),
8128
+ { method: "POST", headers: { "idempotency-key": reservationId }, signal: requestSignal },
8129
+ this.auth
8130
+ ),
8131
+ signal
7848
8132
  );
7849
8133
  } catch (error) {
7850
8134
  lastFailure = error;
@@ -7854,13 +8138,105 @@ var BlobClient = class {
7854
8138
  if (response.ok) return;
7855
8139
  if (response.status < 500 || attempt === 2) {
7856
8140
  throw new Error(
7857
- `failed to finalize blob: HTTP ${response.status} ${await safeErrorText2(response)}`.trimEnd()
8141
+ `failed to finalize blob: HTTP ${response.status} ${await this.#safeErrorText(response, signal)}`.trimEnd()
7858
8142
  );
7859
8143
  }
7860
8144
  lastFailure = new Error(`failed to finalize blob: HTTP ${response.status}`);
7861
8145
  }
7862
8146
  throw lastFailure;
7863
8147
  }
8148
+ async #readJson(res, signal) {
8149
+ return JSON.parse(await this.#readText(res, signal));
8150
+ }
8151
+ async #safeErrorText(res, signal) {
8152
+ try {
8153
+ return await this.#readText(res, signal);
8154
+ } catch (error) {
8155
+ if (error instanceof BlobRequestAbortedError) throw error;
8156
+ return "";
8157
+ }
8158
+ }
8159
+ async #readText(res, signal) {
8160
+ return new TextDecoder().decode(await this.#readBody(res, signal));
8161
+ }
8162
+ /**
8163
+ * `Response.arrayBuffer()` only leaves cancellation observable through the
8164
+ * Fetch implementation. Read the body directly so our lifecycle/deadline
8165
+ * authority cancels the actual stream even when a fetch implementation has
8166
+ * already resolved at headers.
8167
+ */
8168
+ async #readBody(res, signal) {
8169
+ return this.#request(async (requestSignal) => {
8170
+ if (res.body === null) return new Uint8Array();
8171
+ const reader = res.body.getReader();
8172
+ const cancelBody = () => {
8173
+ void reader.cancel().catch(() => void 0);
8174
+ };
8175
+ requestSignal.addEventListener("abort", cancelBody, { once: true });
8176
+ try {
8177
+ const chunks = [];
8178
+ let length = 0;
8179
+ for (; ; ) {
8180
+ const { done, value } = await reader.read();
8181
+ if (done) break;
8182
+ chunks.push(value);
8183
+ length += value.byteLength;
8184
+ }
8185
+ const bytes = new Uint8Array(length);
8186
+ let offset = 0;
8187
+ for (const chunk of chunks) {
8188
+ bytes.set(chunk, offset);
8189
+ offset += chunk.byteLength;
8190
+ }
8191
+ return bytes;
8192
+ } finally {
8193
+ requestSignal.removeEventListener("abort", cancelBody);
8194
+ reader.releaseLock();
8195
+ }
8196
+ }, signal);
8197
+ }
8198
+ #throwIfAborted(signal) {
8199
+ if (this.options.signal?.aborted || signal?.aborted) {
8200
+ throw new BlobRequestAbortedError("cancelled");
8201
+ }
8202
+ }
8203
+ async #request(request, signal) {
8204
+ this.#throwIfAborted(signal);
8205
+ const controller = new AbortController();
8206
+ let abortReason = "cancelled";
8207
+ const abort = (reason) => {
8208
+ if (controller.signal.aborted) return;
8209
+ abortReason = reason;
8210
+ controller.abort();
8211
+ };
8212
+ const inheritedSignals = [this.options.signal, signal].filter((value) => value !== void 0);
8213
+ const abortForCancellation = () => abort("cancelled");
8214
+ for (const inheritedSignal of inheritedSignals) {
8215
+ inheritedSignal.addEventListener("abort", abortForCancellation, { once: true });
8216
+ }
8217
+ const deadline = setTimeout(() => abort("deadline"), this.requestDeadlineMs);
8218
+ deadline.unref?.();
8219
+ let rejectAbort = () => {
8220
+ };
8221
+ const aborted = new Promise((_resolve, reject) => {
8222
+ rejectAbort = reject;
8223
+ });
8224
+ const rejectOnAbort = () => rejectAbort(new BlobRequestAbortedError(abortReason));
8225
+ controller.signal.addEventListener("abort", rejectOnAbort, { once: true });
8226
+ try {
8227
+ return await Promise.race([request(controller.signal), aborted]);
8228
+ } catch (error) {
8229
+ if (error instanceof BlobRequestAbortedError) throw error;
8230
+ if (controller.signal.aborted) throw new BlobRequestAbortedError(abortReason);
8231
+ throw error;
8232
+ } finally {
8233
+ clearTimeout(deadline);
8234
+ controller.signal.removeEventListener("abort", rejectOnAbort);
8235
+ for (const inheritedSignal of inheritedSignals) {
8236
+ inheritedSignal.removeEventListener("abort", abortForCancellation);
8237
+ }
8238
+ }
8239
+ }
7864
8240
  };
7865
8241
  var DEFAULT_TIMEOUT_MS2 = 2e3;
7866
8242
  var DARWIN_UUID_RE = /"IOPlatformUUID"\s*=\s*"([^"]+)"/u;
@@ -8107,6 +8483,7 @@ var AnotherControlServerRunningError = class extends Error {
8107
8483
  }
8108
8484
  };
8109
8485
  var MAX_HALF_OPEN_CONNECTIONS = 8;
8486
+ var MAX_OUTBOUND_QUEUE_BYTES = 1024 * 1024;
8110
8487
  function errorMessage5(err) {
8111
8488
  return err instanceof Error ? err.message : String(err);
8112
8489
  }
@@ -8183,11 +8560,12 @@ async function bindControlEndpoint(server, endpoint) {
8183
8560
  }
8184
8561
  function handleConnection(socket, token, methods, handshakeTimeoutMs, onHandshakeSettled) {
8185
8562
  const reader = new NdjsonLineReader();
8186
- const activeStreams = /* @__PURE__ */ new Map();
8563
+ const activeRequests = /* @__PURE__ */ new Map();
8187
8564
  let phase = "client-hello";
8188
8565
  let serverNonce = "";
8189
8566
  let destroyed = false;
8190
8567
  let handshakeSettled = false;
8568
+ let disposeOutboundWriter;
8191
8569
  function settleHandshake() {
8192
8570
  if (handshakeSettled) return;
8193
8571
  handshakeSettled = true;
@@ -8197,8 +8575,83 @@ function handleConnection(socket, token, methods, handshakeTimeoutMs, onHandshak
8197
8575
  if (phase !== "ready") socket.destroy();
8198
8576
  }, handshakeTimeoutMs);
8199
8577
  handshakeTimer.unref?.();
8578
+ function terminateConnection() {
8579
+ if (destroyed) return;
8580
+ destroyed = true;
8581
+ clearTimeout(handshakeTimer);
8582
+ settleHandshake();
8583
+ disposeOutboundWriter?.();
8584
+ const requests = [...activeRequests.values()];
8585
+ activeRequests.clear();
8586
+ for (const request of requests) {
8587
+ if (request.kind === "stream" && !request.controller.signal.aborted) request.controller.abort();
8588
+ }
8589
+ if (!socket.destroyed) socket.destroy();
8590
+ }
8591
+ const queuedFrames = [];
8592
+ let queuedBytes = 0;
8593
+ let blocked = false;
8594
+ let terminal = false;
8595
+ let drainListening = false;
8596
+ function disposeQueuedFrames() {
8597
+ terminal = true;
8598
+ blocked = false;
8599
+ queuedFrames.length = 0;
8600
+ queuedBytes = 0;
8601
+ if (drainListening) {
8602
+ socket.removeListener("drain", onDrain);
8603
+ drainListening = false;
8604
+ }
8605
+ }
8606
+ function waitForDrain() {
8607
+ if (drainListening || terminal) return;
8608
+ drainListening = true;
8609
+ socket.once("drain", onDrain);
8610
+ }
8611
+ function writeEncodedFrame(encoded) {
8612
+ if (terminal) return;
8613
+ if (!socket.writable) {
8614
+ terminateConnection();
8615
+ return;
8616
+ }
8617
+ try {
8618
+ if (!socket.write(encoded)) {
8619
+ blocked = true;
8620
+ waitForDrain();
8621
+ }
8622
+ } catch {
8623
+ terminateConnection();
8624
+ }
8625
+ }
8626
+ function onDrain() {
8627
+ drainListening = false;
8628
+ if (terminal) return;
8629
+ blocked = false;
8630
+ while (!blocked && queuedFrames.length > 0) {
8631
+ const frame = queuedFrames.shift();
8632
+ queuedBytes -= frame.bytes;
8633
+ writeEncodedFrame(frame.encoded);
8634
+ }
8635
+ }
8636
+ disposeOutboundWriter = disposeQueuedFrames;
8200
8637
  function sendFrame(frame) {
8201
- if (!destroyed && socket.writable) socket.write(encodeFrame(frame));
8638
+ if (destroyed || terminal) return;
8639
+ const encoded = encodeFrame(frame);
8640
+ const bytes = Buffer.byteLength(encoded);
8641
+ if (bytes > MAX_OUTBOUND_QUEUE_BYTES) {
8642
+ terminateConnection();
8643
+ return;
8644
+ }
8645
+ if (blocked) {
8646
+ if (queuedBytes + bytes > MAX_OUTBOUND_QUEUE_BYTES) {
8647
+ terminateConnection();
8648
+ return;
8649
+ }
8650
+ queuedFrames.push({ encoded, bytes });
8651
+ queuedBytes += bytes;
8652
+ return;
8653
+ }
8654
+ writeEncodedFrame(encoded);
8202
8655
  }
8203
8656
  function handleClientHello(parsed) {
8204
8657
  const hello = parseClientHello(parsed);
@@ -8221,21 +8674,51 @@ function handleConnection(socket, token, methods, handshakeTimeoutMs, onHandshak
8221
8674
  settleHandshake();
8222
8675
  sendFrame({ v: 1, ready: true });
8223
8676
  }
8677
+ function rejectDuplicateRequest(id) {
8678
+ sendFrame({
8679
+ v: 1,
8680
+ id,
8681
+ ok: false,
8682
+ error: { code: "duplicate_request_id", message: `request id "${id}" is already active` }
8683
+ });
8684
+ }
8685
+ function registerRequest(id, record3) {
8686
+ if (activeRequests.has(id)) {
8687
+ rejectDuplicateRequest(id);
8688
+ return false;
8689
+ }
8690
+ activeRequests.set(id, record3);
8691
+ return true;
8692
+ }
8693
+ function releaseRequest(id, record3) {
8694
+ if (activeRequests.get(id) !== record3) return false;
8695
+ activeRequests.delete(id);
8696
+ return true;
8697
+ }
8224
8698
  function dispatch(id, method, params) {
8225
8699
  const unary = methods.unary[method];
8226
8700
  if (unary) {
8227
- Promise.resolve().then(() => unary(params)).then((result) => sendFrame({ v: 1, id, ok: true, result })).catch((err) => sendFrame({ v: 1, id, ok: false, error: toControlErrorShape(err) }));
8701
+ const record3 = { kind: "unary" };
8702
+ if (!registerRequest(id, record3)) return;
8703
+ Promise.resolve().then(() => unary(params)).then((result) => {
8704
+ if (!releaseRequest(id, record3)) return;
8705
+ sendFrame({ v: 1, id, ok: true, result });
8706
+ }).catch((err) => {
8707
+ if (!releaseRequest(id, record3)) return;
8708
+ sendFrame({ v: 1, id, ok: false, error: toControlErrorShape(err) });
8709
+ });
8228
8710
  return;
8229
8711
  }
8230
8712
  const stream = methods.stream[method];
8231
8713
  if (stream) {
8232
8714
  const controller = new AbortController();
8233
- activeStreams.set(id, controller);
8234
- stream(params, { emit: (event) => sendFrame({ v: 1, id, event }), signal: controller.signal }).then(() => {
8235
- activeStreams.delete(id);
8715
+ const record3 = { kind: "stream", controller };
8716
+ if (!registerRequest(id, record3)) return;
8717
+ Promise.resolve().then(() => stream(params, { emit: (event) => sendFrame({ v: 1, id, event }), signal: controller.signal })).then(() => {
8718
+ if (!releaseRequest(id, record3)) return;
8236
8719
  if (!controller.signal.aborted) sendFrame({ v: 1, id, ok: true, done: true });
8237
8720
  }).catch((err) => {
8238
- activeStreams.delete(id);
8721
+ if (!releaseRequest(id, record3)) return;
8239
8722
  sendFrame({ v: 1, id, ok: false, error: toControlErrorShape(err) });
8240
8723
  });
8241
8724
  return;
@@ -8277,13 +8760,10 @@ function handleConnection(socket, token, methods, handshakeTimeoutMs, onHandshak
8277
8760
  for (const line of lines) handleLine(line);
8278
8761
  });
8279
8762
  socket.on("error", () => {
8763
+ terminateConnection();
8280
8764
  });
8281
8765
  socket.on("close", () => {
8282
- destroyed = true;
8283
- clearTimeout(handshakeTimer);
8284
- settleHandshake();
8285
- for (const controller of activeStreams.values()) controller.abort();
8286
- activeStreams.clear();
8766
+ terminateConnection();
8287
8767
  });
8288
8768
  }
8289
8769
  async function startControlServer(opts) {
@@ -9201,6 +9681,20 @@ function createFleetJitter(productId, deviceId) {
9201
9681
  delay: (domain, sequence, baseMs) => deterministicJitterMs({ seed, domain, sequence, baseMs })
9202
9682
  };
9203
9683
  }
9684
+
9685
+ // src/daemon/replay-cursor.ts
9686
+ var ReplayCursorTooOldError = class extends Error {
9687
+ constructor(recoverableFrom) {
9688
+ super(
9689
+ recoverableFrom === void 0 ? "server cannot replay the acknowledged cursor; re-pair or operator recovery is required" : `server cannot replay the acknowledged cursor; retained history starts at ${recoverableFrom}`
9690
+ );
9691
+ this.recoverableFrom = recoverableFrom;
9692
+ this.name = "ReplayCursorTooOldError";
9693
+ }
9694
+ recoverableFrom;
9695
+ };
9696
+
9697
+ // src/daemon/long-poll-transport.ts
9204
9698
  var LongPollRouteError = class extends Error {
9205
9699
  constructor(endpoint, status, cause) {
9206
9700
  super(
@@ -9380,6 +9874,12 @@ var LongPollClient = class {
9380
9874
  throw err;
9381
9875
  }
9382
9876
  if (!res.ok) {
9877
+ const replayCursorTooOld = await parseReplayCursorTooOld(res);
9878
+ if (replayCursorTooOld) {
9879
+ this.running = false;
9880
+ this.opts.onReplayCursorTooOld?.(replayCursorTooOld);
9881
+ return;
9882
+ }
9383
9883
  this.warnRouteFailure(this.eventsEndpoint, res.status, void 0);
9384
9884
  this.opts.onServerCapabilities?.([]);
9385
9885
  this.opts.onOperationalOutcome?.("failure");
@@ -9448,6 +9948,21 @@ var LongPollClient = class {
9448
9948
  }
9449
9949
  }
9450
9950
  };
9951
+ async function parseReplayCursorTooOld(res) {
9952
+ if (res.status !== 409) return void 0;
9953
+ let body;
9954
+ try {
9955
+ body = await res.json();
9956
+ } catch {
9957
+ return void 0;
9958
+ }
9959
+ if (typeof body !== "object" || body === null) return void 0;
9960
+ const { error, recoverableFrom } = body;
9961
+ if (error !== "cursor_too_old" || typeof recoverableFrom !== "number" || !Number.isSafeInteger(recoverableFrom) || recoverableFrom < 0) {
9962
+ return void 0;
9963
+ }
9964
+ return new ReplayCursorTooOldError(recoverableFrom);
9965
+ }
9451
9966
  function sleep(ms) {
9452
9967
  return new Promise((resolve) => setTimeout(resolve, ms));
9453
9968
  }
@@ -9592,16 +10107,17 @@ var WsTransport = class {
9592
10107
  }
9593
10108
  this.opts.onEnvelope(envelope);
9594
10109
  });
9595
- socket.on("close", () => {
10110
+ socket.on("close", (code, reason) => {
9596
10111
  this.socket = void 0;
9597
10112
  this.stopLivenessCheck();
9598
10113
  this.opts.onStateChange?.("closed");
9599
10114
  const acked = this.everAckedThisAttempt;
9600
10115
  const status = this.lastUnexpectedStatus;
9601
10116
  this.lastUnexpectedStatus = void 0;
10117
+ const replayCursorTooOld = code === 1008 && reason.toString("utf8") === "cursor_too_old" ? new ReplayCursorTooOldError() : void 0;
9602
10118
  this.opts.onConnectOutcome?.(
9603
10119
  acked,
9604
- status !== void 0 ? new WsUnexpectedStatusError(status, endpoint) : void 0,
10120
+ replayCursorTooOld ?? (status !== void 0 ? new WsUnexpectedStatusError(status, endpoint) : void 0),
9605
10121
  endpoint
9606
10122
  );
9607
10123
  if (!this.closedByUser && this.autoReconnect) this.scheduleReconnect();
@@ -9687,6 +10203,7 @@ var ConnectionManager = class {
9687
10203
  if (this.mode === "long-poll") this.serverCapabilities = capabilities;
9688
10204
  },
9689
10205
  onRevoked: () => this.enterRevoked(),
10206
+ onReplayCursorTooOld: (error) => this.enterReplayCursorTooOld(error),
9690
10207
  // M4 Phase 4 (version-negotiation drill fix): a batch entry
9691
10208
  // LongPollClient couldn't parse into a known Envelope at all (an
9692
10209
  // unrecognized message type) still needs its cursor/watermark
@@ -9775,6 +10292,7 @@ var ConnectionManager = class {
9775
10292
  draining = false;
9776
10293
  stopped = false;
9777
10294
  revoked = false;
10295
+ terminalError;
9778
10296
  settledWaiters = [];
9779
10297
  pendingCursorSave = Promise.resolve();
9780
10298
  /**
@@ -9847,6 +10365,7 @@ var ConnectionManager = class {
9847
10365
  */
9848
10366
  serverCapabilities = [];
9849
10367
  async start() {
10368
+ if (this.terminalError) throw this.terminalError;
9850
10369
  this.cursor = await this.opts.cursorStore.load(this.opts.serverUrl, this.opts.deviceId);
9851
10370
  this.ws.connect({ auto: true });
9852
10371
  }
@@ -9962,6 +10481,12 @@ var ConnectionManager = class {
9962
10481
  getServerCapabilities() {
9963
10482
  return this.serverCapabilities;
9964
10483
  }
10484
+ getTerminalError() {
10485
+ return this.terminalError;
10486
+ }
10487
+ getMode() {
10488
+ return this.mode;
10489
+ }
9965
10490
  isConnected() {
9966
10491
  return this.mode === "ws" && this.ws.isOpen;
9967
10492
  }
@@ -9982,6 +10507,7 @@ var ConnectionManager = class {
9982
10507
  */
9983
10508
  waitForAck(timeoutMs = 1e4) {
9984
10509
  if (this.ws.isOpen || this.mode === "long-poll") return Promise.resolve();
10510
+ if (this.terminalError) return Promise.reject(this.terminalError);
9985
10511
  if (this.revoked) return Promise.reject(new DeviceRevokedError());
9986
10512
  return new Promise((resolve, reject) => {
9987
10513
  let settle = () => {
@@ -10310,6 +10836,7 @@ var ConnectionManager = class {
10310
10836
  * (which is close-only) at all.
10311
10837
  */
10312
10838
  onAcked(capabilities) {
10839
+ if (this.terminalError) return;
10313
10840
  this.serverCapabilities = capabilities;
10314
10841
  this.consecutiveFailures = 0;
10315
10842
  this.notifySettled();
@@ -10318,6 +10845,10 @@ var ConnectionManager = class {
10318
10845
  void this.drainOutbox();
10319
10846
  }
10320
10847
  onWsOutcome(acked, err) {
10848
+ if (err instanceof ReplayCursorTooOldError) {
10849
+ this.enterReplayCursorTooOld(err);
10850
+ return;
10851
+ }
10321
10852
  if (this.stopped || this.revoked) return;
10322
10853
  if (acked) this.serverCapabilities = [];
10323
10854
  if (err instanceof WsUnexpectedStatusError && err.status === 401) {
@@ -10354,6 +10885,20 @@ var ConnectionManager = class {
10354
10885
  void this.drainOutbox();
10355
10886
  this.scheduleWsProbe();
10356
10887
  }
10888
+ enterReplayCursorTooOld(error) {
10889
+ if (this.terminalError) return;
10890
+ this.terminalError = error;
10891
+ this.stopped = true;
10892
+ this.serverCapabilities = [];
10893
+ if (this.wsRetryTimer) clearInterval(this.wsRetryTimer);
10894
+ this.longPoll.stop();
10895
+ this.ws.stopAutoReconnect();
10896
+ this.ws.close();
10897
+ this.cancelPendingDrainRetry?.();
10898
+ this.notifySettled(error);
10899
+ this.opts.onStateChange?.("closed");
10900
+ this.opts.onTerminalError?.(error);
10901
+ }
10357
10902
  exitLongPoll() {
10358
10903
  if (this.wsRetryTimer) {
10359
10904
  clearInterval(this.wsRetryTimer);
@@ -13083,21 +13628,28 @@ async function recordAuditWarning(context, kind, values) {
13083
13628
  }
13084
13629
  }
13085
13630
  var agentMemoryHomeQueues = /* @__PURE__ */ new Map();
13086
- async function exclusiveAgentMemoryHome(home, fn) {
13087
- const previous = agentMemoryHomeQueues.get(home) ?? Promise.resolve();
13631
+ var agentMemoryProjectionTransactionQueues = /* @__PURE__ */ new Map();
13632
+ async function exclusiveAgentMemoryHomeQueue(queues2, home, fn) {
13633
+ const previous = queues2.get(home) ?? Promise.resolve();
13088
13634
  let release;
13089
13635
  const next = new Promise((resolve) => {
13090
13636
  release = resolve;
13091
13637
  });
13092
- agentMemoryHomeQueues.set(home, next);
13638
+ queues2.set(home, next);
13093
13639
  await previous;
13094
13640
  try {
13095
13641
  return await fn();
13096
13642
  } finally {
13097
13643
  release();
13098
- if (agentMemoryHomeQueues.get(home) === next) agentMemoryHomeQueues.delete(home);
13644
+ if (queues2.get(home) === next) queues2.delete(home);
13099
13645
  }
13100
13646
  }
13647
+ async function exclusiveAgentMemoryHome(home, fn) {
13648
+ return exclusiveAgentMemoryHomeQueue(agentMemoryHomeQueues, home, fn);
13649
+ }
13650
+ async function exclusiveAgentMemoryProjectionTransaction(home, fn) {
13651
+ return exclusiveAgentMemoryHomeQueue(agentMemoryProjectionTransactionQueues, home, fn);
13652
+ }
13101
13653
  var AgentMemoryService = class {
13102
13654
  constructor(input) {
13103
13655
  this.input = input;
@@ -13401,13 +13953,16 @@ var AgentMemoryRedactedOutbox = class _AgentMemoryRedactedOutbox {
13401
13953
  async function snapshotAndProjectAgentMemory(input, projection) {
13402
13954
  if (projection?.capability !== AGENT_MEMORY_PROJECTION_CAPABILITY || !projection.grant || !projection.redactor || !projection.port) return;
13403
13955
  const context = taskContext(input);
13404
- const outbox = await AgentMemoryRedactedOutbox.open(context, projection.grant);
13405
- const initialReplay = await outbox.replay(projection.port);
13406
- if (initialReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(initialReplay);
13407
- const snapshot = await captureAgentMemorySnapshot(context);
13408
- await outbox.append(redactedBytes(snapshot, await projection.redactor.redact(snapshot)));
13409
- const trailingReplay = await outbox.replay(projection.port);
13410
- if (trailingReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(trailingReplay);
13956
+ const { grant, redactor, port } = projection;
13957
+ await exclusiveAgentMemoryProjectionTransaction(context.canonicalHome, async () => {
13958
+ const outbox = await AgentMemoryRedactedOutbox.open(context, grant);
13959
+ const initialReplay = await outbox.replay(port);
13960
+ if (initialReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(initialReplay);
13961
+ const snapshot = await captureAgentMemorySnapshot(context);
13962
+ await outbox.append(redactedBytes(snapshot, await redactor.redact(snapshot)));
13963
+ const trailingReplay = await outbox.replay(port);
13964
+ if (trailingReplay.status === "pending") throw new AgentMemoryProjectionReplayPendingError(trailingReplay);
13965
+ });
13411
13966
  }
13412
13967
  var AGENT_MEMORY_FILESYSTEM_HELPER_PROTOCOL = 2;
13413
13968
  var AGENT_MEMORY_FILESYSTEM_HELPER_VERSION = "2";
@@ -13815,6 +14370,7 @@ var TaskRunner = class {
13815
14370
  deps;
13816
14371
  tasks = /* @__PURE__ */ new Map();
13817
14372
  pendingMessageTasks = /* @__PURE__ */ new Map();
14373
+ messageOutboxesByHome = /* @__PURE__ */ new Map();
13818
14374
  messageContextByToken = /* @__PURE__ */ new Map();
13819
14375
  messageContextByTask = /* @__PURE__ */ new Map();
13820
14376
  memoryContextByToken = /* @__PURE__ */ new Map();
@@ -13875,6 +14431,8 @@ var TaskRunner = class {
13875
14431
  * costs nothing.
13876
14432
  */
13877
14433
  inFlightOffers = /* @__PURE__ */ new Set();
14434
+ /** Blob I/O before an offer becomes an active task still belongs to that offer's cancellation authority. */
14435
+ inFlightBlobAborts = /* @__PURE__ */ new Map();
13878
14436
  /**
13879
14437
  * Finding P2 (Fix 2c): taskIds that have reached a terminal outcome
13880
14438
  * (Complete/Failed/Cancelled) this session — populated in `finish()`.
@@ -14001,6 +14559,7 @@ var TaskRunner = class {
14001
14559
  async recoverAgentMessageOutboxes(agentsRoot) {
14002
14560
  if (this.deps.tenantId === void 0) throw new Error("Agent message recovery requires authenticated tenant enrollment");
14003
14561
  for (const outbox of await AgentMessageOutbox.recover(agentsRoot, this.deps.tenantId)) {
14562
+ this.messageOutboxesByHome.set(outbox.homeDir, Promise.resolve(outbox));
14004
14563
  for (const record3 of outbox.retryableRecords()) {
14005
14564
  if (record3.sessionRef === void 0) continue;
14006
14565
  const existing = this.recoveredMessageOutboxes.get(record3.taskId);
@@ -14009,6 +14568,16 @@ var TaskRunner = class {
14009
14568
  }
14010
14569
  }
14011
14570
  }
14571
+ agentMessageOutbox(homeDir) {
14572
+ const existing = this.messageOutboxesByHome.get(homeDir);
14573
+ if (existing !== void 0) return existing;
14574
+ const opened = AgentMessageOutbox.open(homeDir);
14575
+ this.messageOutboxesByHome.set(homeDir, opened);
14576
+ void opened.catch(() => {
14577
+ if (this.messageOutboxesByHome.get(homeDir) === opened) this.messageOutboxesByHome.delete(homeDir);
14578
+ });
14579
+ return opened;
14580
+ }
14012
14581
  /** Retry stable recovered records after a transport handshake/re-handshake. */
14013
14582
  retryRecoveredAgentMessages() {
14014
14583
  for (const [taskId, outbox] of this.recoveredMessageOutboxes) {
@@ -14164,6 +14733,7 @@ var TaskRunner = class {
14164
14733
  if (active.finalizationStarted) return this.finish(active.taskId);
14165
14734
  if (!this.reserveSemanticTerminal(active)) return active.semanticTerminalSettled ?? false;
14166
14735
  active.beingTornDown = true;
14736
+ active.blobAbort.abort();
14167
14737
  await this.observeGit(active, "salvage");
14168
14738
  const timeoutMs = this.deps.shutdownInterruptTimeoutMs ?? DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS;
14169
14739
  await raceSettleFirst(() => active.session.interrupt(), timeoutMs);
@@ -14310,6 +14880,8 @@ var TaskRunner = class {
14310
14880
  return;
14311
14881
  }
14312
14882
  this.inFlightOffers.add(taskId);
14883
+ const blobAbort = new AbortController();
14884
+ this.inFlightBlobAborts.set(taskId, blobAbort);
14313
14885
  let agentBinding;
14314
14886
  let agentLeaseTransferred = false;
14315
14887
  try {
@@ -14468,7 +15040,7 @@ var TaskRunner = class {
14468
15040
  }
14469
15041
  if (agentRef !== void 0) {
14470
15042
  try {
14471
- agentBinding = await this.deps.agentHome.acquire(agentRef);
15043
+ agentBinding = await this.deps.agentHome.acquireExecution(agentRef, { taskId, sessionRef });
14472
15044
  } catch (error) {
14473
15045
  decline(
14474
15046
  `Agent home admission failed: ${errorMessage6(error)}`,
@@ -14503,7 +15075,7 @@ var TaskRunner = class {
14503
15075
  }
14504
15076
  }
14505
15077
  try {
14506
- await this.deps.agentHome.initialize(agentBinding);
15078
+ await this.deps.agentHome.initializeExecution(agentBinding);
14507
15079
  } catch (error) {
14508
15080
  await agentBinding.lease.release().catch(() => {
14509
15081
  });
@@ -14513,7 +15085,7 @@ var TaskRunner = class {
14513
15085
  }
14514
15086
  if (messageRequirement !== void 0) {
14515
15087
  try {
14516
- const outbox = await AgentMessageOutbox.open(agentBinding.resolution.canonicalHome);
15088
+ const outbox = await this.agentMessageOutbox(agentBinding.resolution.canonicalHome);
14517
15089
  this.pendingMessageTasks.set(taskId, {
14518
15090
  taskId,
14519
15091
  agentRef: agentBinding.resolution.agentRef,
@@ -14632,7 +15204,7 @@ var TaskRunner = class {
14632
15204
  );
14633
15205
  let resolvedInstruction;
14634
15206
  try {
14635
- resolvedInstruction = await this.resolveInstruction(payload.instruction);
15207
+ resolvedInstruction = await this.resolveInstruction(payload.instruction, blobAbort.signal);
14636
15208
  if (plainWorkspaceNeedsResolve) workspaceDir = await this.resolveWorkspaceDir(taskId, known?.workspaceDir);
14637
15209
  } catch (err) {
14638
15210
  gitLease?.release();
@@ -14745,9 +15317,29 @@ var TaskRunner = class {
14745
15317
  }
14746
15318
  return;
14747
15319
  }
15320
+ if (agentBinding !== void 0) {
15321
+ try {
15322
+ await agentBinding.lease.bindSession(session.sessionRef);
15323
+ } catch (error) {
15324
+ await session.close().catch(() => {
15325
+ });
15326
+ await this.failClaimedAgent(
15327
+ taskId,
15328
+ `Agent session execution lease could not bind the runtime session: ${errorMessage6(error)}`,
15329
+ false,
15330
+ {
15331
+ binding: agentBinding,
15332
+ runtimeId: pick.descriptor.id,
15333
+ sessionRef: session.sessionRef
15334
+ }
15335
+ );
15336
+ return;
15337
+ }
15338
+ }
14748
15339
  let active;
14749
15340
  active = {
14750
15341
  taskId,
15342
+ blobAbort,
14751
15343
  egressEnabled: "egressPolicy" in payload,
14752
15344
  adapter: pick.adapter,
14753
15345
  session,
@@ -14788,15 +15380,16 @@ var TaskRunner = class {
14788
15380
  ...terminalProjection === void 0 ? {} : { terminalProjection }
14789
15381
  };
14790
15382
  if (agentBinding !== void 0) {
15383
+ const binding = agentBinding;
14791
15384
  try {
14792
- await this.deps.agentSessionHandoffs.record({
14793
- agentRef: agentBinding.resolution.agentRef,
15385
+ await this.deps.agentHome.mutateExecution(binding, () => this.deps.agentSessionHandoffs.record({
15386
+ agentRef: binding.resolution.agentRef,
14794
15387
  taskId,
14795
15388
  sessionRef: session.sessionRef,
14796
15389
  runtimeId: pick.descriptor.id,
14797
15390
  cwd: workspaceDir,
14798
- leaseId: agentBinding.lease.leaseId
14799
- });
15391
+ leaseId: binding.lease.leaseId
15392
+ }));
14800
15393
  } catch (error) {
14801
15394
  await session.close().catch(() => {
14802
15395
  });
@@ -14838,6 +15431,7 @@ var TaskRunner = class {
14838
15431
  }
14839
15432
  this.deps.send(createEnvelope("task.started", {}, { taskId }));
14840
15433
  agentLeaseTransferred = agentBinding !== void 0;
15434
+ this.inFlightBlobAborts.delete(taskId);
14841
15435
  this.tasks.set(taskId, active);
14842
15436
  this.pendingMessageTasks.delete(taskId);
14843
15437
  if (active.messageOutbox !== void 0 && activatedMessageRecord !== void 0) {
@@ -14869,6 +15463,7 @@ var TaskRunner = class {
14869
15463
  await agentBinding.lease.release().catch(() => {
14870
15464
  });
14871
15465
  }
15466
+ this.inFlightBlobAborts.delete(taskId);
14872
15467
  this.inFlightOffers.delete(taskId);
14873
15468
  }
14874
15469
  }
@@ -15020,9 +15615,9 @@ var TaskRunner = class {
15020
15615
  void this.closeAgentMemoryFilesystem(taskId);
15021
15616
  }
15022
15617
  /** Protocol §7: an instruction too large to inline arrives as a `blobRef` — resolve it via the blob client rather than failing closed. */
15023
- async resolveInstruction(instruction) {
15618
+ async resolveInstruction(instruction, signal) {
15024
15619
  if (typeof instruction === "string") return instruction;
15025
- return this.deps.blobClient.resolveInstruction(instruction.blobRef);
15620
+ return this.deps.blobClient.resolveInstruction(instruction.blobRef, { signal });
15026
15621
  }
15027
15622
  /** Resolve every requested logical id locally and reject missing/colliding server authority before claim. */
15028
15623
  resolveMcpServers(requiredToolsets) {
@@ -15254,7 +15849,9 @@ var TaskRunner = class {
15254
15849
  }
15255
15850
  }
15256
15851
  try {
15257
- const blobRef = await this.deps.blobClient.uploadArtifact(bytes, contentType);
15852
+ const blobRef = await this.deps.blobClient.uploadArtifact(bytes, contentType, {
15853
+ signal: active.blobAbort.signal
15854
+ });
15258
15855
  this.deps.send(createEnvelope("task.artifact", { name, contentType, blobRef }, { taskId: active.taskId }));
15259
15856
  } catch (err) {
15260
15857
  this.reportArtifactError(active, name, `failed to upload artifact "${name}": ${errorMessage6(err)}`);
@@ -15269,6 +15866,7 @@ var TaskRunner = class {
15269
15866
  const active = this.tasks.get(taskId);
15270
15867
  if (!active) {
15271
15868
  this.setPendingCancelled(taskId, reason);
15869
+ this.inFlightBlobAborts.get(taskId)?.abort();
15272
15870
  return;
15273
15871
  }
15274
15872
  if (active.finalizationStarted) {
@@ -15279,6 +15877,7 @@ var TaskRunner = class {
15279
15877
  await active.semanticTerminalSettled;
15280
15878
  return;
15281
15879
  }
15880
+ active.blobAbort.abort();
15282
15881
  try {
15283
15882
  await active.session.interrupt();
15284
15883
  } catch {
@@ -15778,7 +16377,7 @@ var TaskRunner = class {
15778
16377
  async failClaimedAgent(taskId, reason, retryable, context) {
15779
16378
  const agentRef = context.binding.resolution.agentRef;
15780
16379
  const result = await this.retryAgentTerminalEvidence(
15781
- () => this.deps.agentSessionHandoffs.recordTaskTerminal({
16380
+ () => this.deps.agentHome.mutateExecution(context.binding, () => this.deps.agentSessionHandoffs.recordTaskTerminal({
15782
16381
  agentRef,
15783
16382
  taskId,
15784
16383
  runtimeId: context.runtimeId,
@@ -15786,7 +16385,7 @@ var TaskRunner = class {
15786
16385
  leaseId: context.binding.lease.leaseId,
15787
16386
  ...context.sessionRef === void 0 ? {} : { sessionRef: context.sessionRef },
15788
16387
  terminalReason: reason
15789
- })
16388
+ }))
15790
16389
  );
15791
16390
  if (!result.ok) {
15792
16391
  this.reportAgentTerminalEvidenceFailure({
@@ -16775,6 +17374,8 @@ var AgentEgressController = class {
16775
17374
  options;
16776
17375
  latest = new AgentLatestValueState();
16777
17376
  spools = /* @__PURE__ */ new Map();
17377
+ spoolOpens = /* @__PURE__ */ new Map();
17378
+ reliableAppendTail = Promise.resolve();
16778
17379
  latestStatus = emptyLane();
16779
17380
  reliableStatus = emptyLane();
16780
17381
  drops = [];
@@ -16829,7 +17430,8 @@ var AgentEgressController = class {
16829
17430
  return latest === void 0 ? [] : Object.freeze([latest]);
16830
17431
  }
16831
17432
  async appendReliable(input) {
16832
- if (!this.active || this.options.tenantId === void 0) {
17433
+ const tenantId = this.options.tenantId;
17434
+ if (!this.active || tenantId === void 0) {
16833
17435
  this.noteDrop("reliable", "policy_denied", input.agentRef);
16834
17436
  return { ok: false, reason: "policy_denied" };
16835
17437
  }
@@ -16844,17 +17446,21 @@ var AgentEgressController = class {
16844
17446
  return { ok: false, reason: "sanitizer_rejected" };
16845
17447
  }
16846
17448
  try {
16847
- const spool = await this.spoolFor(input.homeDir, input.agentRef);
16848
- const record3 = await spool.append({
16849
- agentRef: input.agentRef,
16850
- tenantId: this.options.tenantId,
16851
- policyRevision: this.options.policy.policyRevision,
16852
- payload,
16853
- sessionRef: input.sessionRef,
16854
- ...input.taskId === void 0 ? {} : { taskId: input.taskId },
16855
- ...input.eventId === void 0 ? {} : { eventId: input.eventId }
16856
- }, this.options.policy, this.tenantPendingBytes());
16857
- return { ok: true, record: record3 };
17449
+ const spoolOpen = this.spoolFor(input.homeDir, input.agentRef);
17450
+ return await this.withAppendTail(async () => {
17451
+ const spool = await spoolOpen;
17452
+ this.bindSpool(input.agentRef, spool, spoolOpen);
17453
+ const record3 = await spool.append({
17454
+ agentRef: input.agentRef,
17455
+ tenantId,
17456
+ policyRevision: this.options.policy.policyRevision,
17457
+ payload,
17458
+ sessionRef: input.sessionRef,
17459
+ ...input.taskId === void 0 ? {} : { taskId: input.taskId },
17460
+ ...input.eventId === void 0 ? {} : { eventId: input.eventId }
17461
+ }, this.options.policy, this.tenantPendingBytes());
17462
+ return { ok: true, record: record3 };
17463
+ });
16858
17464
  } catch (error) {
16859
17465
  const reason = error instanceof AgentReliableQuotaError ? error.reason : "backpressure";
16860
17466
  this.noteDrop("reliable", reason, input.agentRef);
@@ -16867,21 +17473,26 @@ var AgentEgressController = class {
16867
17473
  * with `wireType: agent.content.receipt` before any transport attempt.
16868
17474
  */
16869
17475
  async appendContentReceipt(input) {
16870
- if (!this.active || this.options.tenantId === void 0) {
17476
+ const tenantId = this.options.tenantId;
17477
+ if (!this.active || tenantId === void 0) {
16871
17478
  this.noteDrop("reliable", "policy_denied", input.agentRef);
16872
17479
  return { ok: false, reason: "policy_denied" };
16873
17480
  }
16874
17481
  try {
16875
- const spool = await this.spoolFor(input.homeDir, input.agentRef);
16876
- const record3 = await spool.appendContentReceipt({
16877
- agentRef: input.agentRef,
16878
- tenantId: this.options.tenantId,
16879
- policyRevision: this.options.policy.policyRevision,
16880
- sessionRef: input.payload.sessionRef,
16881
- payload: input.payload,
16882
- ...input.taskId === void 0 ? {} : { taskId: input.taskId }
16883
- }, this.options.policy, this.tenantPendingBytes());
16884
- return { ok: true, record: record3 };
17482
+ const spoolOpen = this.spoolFor(input.homeDir, input.agentRef);
17483
+ return await this.withAppendTail(async () => {
17484
+ const spool = await spoolOpen;
17485
+ this.bindSpool(input.agentRef, spool, spoolOpen);
17486
+ const record3 = await spool.appendContentReceipt({
17487
+ agentRef: input.agentRef,
17488
+ tenantId,
17489
+ policyRevision: this.options.policy.policyRevision,
17490
+ sessionRef: input.payload.sessionRef,
17491
+ payload: input.payload,
17492
+ ...input.taskId === void 0 ? {} : { taskId: input.taskId }
17493
+ }, this.options.policy, this.tenantPendingBytes());
17494
+ return { ok: true, record: record3 };
17495
+ });
16885
17496
  } catch (error) {
16886
17497
  const reason = error instanceof AgentReliableQuotaError ? error.reason : "backpressure";
16887
17498
  this.noteDrop("reliable", reason, input.agentRef);
@@ -16956,20 +17567,59 @@ var AgentEgressController = class {
16956
17567
  }
16957
17568
  return this.reliableRecords();
16958
17569
  }
16959
- async spoolFor(homeDir, agentRef) {
17570
+ spoolFor(homeDir, agentRef) {
16960
17571
  const key = agentKey(agentRef);
16961
17572
  const existing = this.spools.get(key);
16962
- if (existing) return existing;
16963
- const spool = await AgentReliableSpool.open(homeDir);
16964
- if (spool.records().some((record3) => !sameAgent(record3.agentRef, agentRef))) {
16965
- throw new Error("Agent-local reliable spool has a different AgentRef");
17573
+ if (existing) {
17574
+ if (existing.homeDir !== homeDir) throw new Error("Agent reliable spool is already bound to a different home");
17575
+ return Promise.resolve(existing);
17576
+ }
17577
+ const inFlight = this.spoolOpens.get(key);
17578
+ if (inFlight !== void 0) {
17579
+ if (inFlight.homeDir !== homeDir) throw new Error("Agent reliable spool opening is already bound to a different home");
17580
+ return inFlight.promise;
17581
+ }
17582
+ const opened = (async () => {
17583
+ const spool = await AgentReliableSpool.open(homeDir);
17584
+ if (spool.records().some((record3) => !sameAgent(record3.agentRef, agentRef))) {
17585
+ throw new Error("Agent-local reliable spool has a different AgentRef");
17586
+ }
17587
+ return spool;
17588
+ })();
17589
+ const slot = { homeDir, promise: opened };
17590
+ this.spoolOpens.set(key, slot);
17591
+ void opened.catch(() => {
17592
+ if (this.spoolOpens.get(key) === slot) this.spoolOpens.delete(key);
17593
+ });
17594
+ return opened;
17595
+ }
17596
+ bindSpool(agentRef, spool, spoolOpen) {
17597
+ const key = agentKey(agentRef);
17598
+ const existing = this.spools.get(key);
17599
+ try {
17600
+ if (existing && existing !== spool) throw new Error("multiple Agent egress spools claim the same AgentRef");
17601
+ this.spools.set(key, spool);
17602
+ } finally {
17603
+ const slot = this.spoolOpens.get(key);
17604
+ if (slot?.promise === spoolOpen) this.spoolOpens.delete(key);
16966
17605
  }
16967
- this.spools.set(key, spool);
16968
- return spool;
16969
17606
  }
16970
17607
  tenantPendingBytes() {
16971
17608
  return this.reliableRecords().reduce((total, record3) => total + record3.byteCount, 0);
16972
17609
  }
17610
+ async withAppendTail(operation) {
17611
+ const previous = this.reliableAppendTail;
17612
+ let release;
17613
+ this.reliableAppendTail = new Promise((resolve) => {
17614
+ release = resolve;
17615
+ });
17616
+ try {
17617
+ await previous;
17618
+ return await operation();
17619
+ } finally {
17620
+ release();
17621
+ }
17622
+ }
16973
17623
  noteDrop(lane, reason, agentRef, countDrop = true) {
16974
17624
  const laneStatus = lane === "latest-value" ? this.latestStatus : this.reliableStatus;
16975
17625
  if (countDrop) laneStatus.dropped += 1;
@@ -18241,6 +18891,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
18241
18891
  const observer = new DaemonObserver();
18242
18892
  const approvalRegistry = new ApprovalRegistry();
18243
18893
  let connection;
18894
+ let blobLifecycleAbort;
18244
18895
  let connectionState = "closed";
18245
18896
  let daemonStarted = false;
18246
18897
  let tenantRebinding = false;
@@ -18259,6 +18910,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
18259
18910
  function buildAuthManager() {
18260
18911
  return new AuthManager({
18261
18912
  serverUrl: config.serverUrl,
18913
+ authRequestDeadlineMs: config.authRequestDeadlineMs,
18262
18914
  store,
18263
18915
  deviceName: config.deviceName,
18264
18916
  machineId: config.machineId ?? (() => resolveMachineId({ productId: config.productId })),
@@ -18276,7 +18928,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
18276
18928
  assertServerUrlAllowed(config.serverUrl, { dangerouslyAllowInsecureRemote: true });
18277
18929
  const reason = err instanceof Error ? err.message : String(err);
18278
18930
  console.warn(
18279
- `[byok/client] WARNING: dangerouslyAllowInsecureRemote is set \u2014 proceeding with an insecure server URL (${config.serverUrl}). Device credentials and task data will be sent in the clear to a non-loopback host. This should never be used in a real deployment. (${reason})`
18931
+ `[byok/client] WARNING: dangerouslyAllowInsecureRemote is set \u2014 proceeding with an insecure server URL (${formatServerUrl(config.serverUrl)}). Device credentials and task data will be sent in the clear to a non-loopback host. This should never be used in a real deployment. (${reason})`
18280
18932
  );
18281
18933
  }
18282
18934
  }
@@ -18436,9 +19088,10 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
18436
19088
  await gitWorkspaceStore?.initialize();
18437
19089
  await gitWorkspaceStore?.reconcile();
18438
19090
  }
19091
+ blobLifecycleAbort = new AbortController();
18439
19092
  const [runtimes, blobClient] = await Promise.all([
18440
19093
  detectRuntimes(adapters),
18441
- Promise.resolve(new BlobClient(config.serverUrl, auth))
19094
+ Promise.resolve(new BlobClient(config.serverUrl, auth, { signal: blobLifecycleAbort.signal }))
18442
19095
  ]);
18443
19096
  observer.noteRuntimesDetected(runtimes);
18444
19097
  detectedRuntimeFacts = runtimes;
@@ -18867,6 +19520,8 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
18867
19520
  }
18868
19521
  async function runShutdownSequence(reason, opts = {}) {
18869
19522
  shuttingDown = true;
19523
+ blobLifecycleAbort?.abort();
19524
+ blobLifecycleAbort = void 0;
18870
19525
  const errors = [];
18871
19526
  let mutationBarrierComplete = hostedStorageInitializationBarrierComplete;
18872
19527
  if (!hostedStorageInitializationBarrierComplete) {
@@ -20687,6 +21342,6 @@ function createServiceLifecycle(def, opts = {}) {
20687
21342
  }
20688
21343
  }
20689
21344
 
20690
- export { AGENT_CONTENT_READ_CAPABILITIES, AGENT_CONTENT_READ_CAPABILITY_ARTIFACT, AGENT_CONTENT_READ_CAPABILITY_TRANSCRIPT, AGENT_CONTENT_READ_CAPABILITY_WORKSPACE, AGENT_HOME_PROJECTION_STATE_FILE, AGENT_MEMORY_AUDIT_FILENAME, AGENT_MEMORY_OUTBOX_FILENAME, AgentHomeBusyError, AgentHomeCollisionError, AgentHomeError, AgentHomeLayout, AgentHomeLeaseCorruptError, AgentHomeLeaseManager, AgentHomeManager, AgentHomeResolutionError, AgentMemoryError, AgentMemoryRevisionConflictError, AgentRefValidationError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, AgentSessionHandoffStore, AgentSessionHandoffStoreError, BYOK_SDK_HELPER_SUBCOMMAND, BlobClient, ClaudeAdapter, CodexAdapter, DEFAULT_ACK_CRITICAL_RESERVE_BYTES, DEFAULT_CLEANUP_BATCH_LIMIT, DEFAULT_HARD_BUDGET_RATIO, DEFAULT_INCREMENTAL_VACUUM_PAGES, DEFAULT_LOG_ROTATION, DEFAULT_NORMAL_COMPACTION_INTERVAL_MS, DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS, DEFAULT_RETENTION_MS, DEFAULT_SOFT_BUDGET_RATIO, DaemonObserver, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStateRelocationBusyError, LocalStateRelocationError, LocalStateRelocationIntegrityError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, LocalTeamWorkspace, LocalTeamWorkspace as LocalTeamWorkspaceService, McpToolsetDefinitionRevisionConflictError, McpToolsetRevisionConflictError, PI_PACKAGE_NAME, PiAdapter, PolicyUnsupportedError, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, RuntimeDisposalFailure, RuntimeExecutionFailure, SKILL_PACKS_CAPABILITY, SKILL_PACKS_DIRNAME, SKILL_PACK_AUDIT_FILENAME, SKILL_PACK_INSTALL_ERROR_CODES, SKILL_PACK_LOCK_FILENAME, SKILL_PACK_LOCK_SCHEMA, SKILL_PACK_RESPONSE_MAX_BYTES, SecureDirHardeningError, SkillPackInstallError, SqliteLocalTaskJournal, SteerUnsupportedError, TeamTmuxViewError, TeamWorkspaceConflictError, TeamWorkspaceCorruptError, TeamWorkspaceError, TeamWorkspaceLeaseError, TeamWorkspaceNotFoundError, TeamWorkspaceQuotaError, TeamWorkspaceReceiptError, TeamWorkspaceValidationError, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createAgentHomeProjection, createAgentHomeProjectionConsumer, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, decodeTeamMemberContext, encodeTeamMemberContext, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isAgentMemorySecureFilesystemAvailable, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, openTeamTmuxView, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, readDeviceEnrollmentStatus, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, resolveSdkReservedHelperBin, runSdkReservedHelperCommand, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
21345
+ export { AGENT_CONTENT_READ_CAPABILITIES, AGENT_CONTENT_READ_CAPABILITY_ARTIFACT, AGENT_CONTENT_READ_CAPABILITY_TRANSCRIPT, AGENT_CONTENT_READ_CAPABILITY_WORKSPACE, AGENT_HOME_PROJECTION_STATE_FILE, AGENT_MEMORY_AUDIT_FILENAME, AGENT_MEMORY_OUTBOX_FILENAME, AgentHomeBusyError, AgentHomeCollisionError, AgentHomeError, AgentHomeLayout, AgentHomeLeaseCorruptError, AgentHomeLeaseManager, AgentHomeManager, AgentHomeResolutionError, AgentMemoryError, AgentMemoryRevisionConflictError, AgentRefValidationError, AgentSessionHandoffCorruptError, AgentSessionHandoffMismatchError, AgentSessionHandoffStore, AgentSessionHandoffStoreError, BYOK_SDK_HELPER_SUBCOMMAND, BlobClient, BlobRequestAbortedError, ClaudeAdapter, CodexAdapter, DEFAULT_ACK_CRITICAL_RESERVE_BYTES, DEFAULT_CLEANUP_BATCH_LIMIT, DEFAULT_HARD_BUDGET_RATIO, DEFAULT_INCREMENTAL_VACUUM_PAGES, DEFAULT_LOG_ROTATION, DEFAULT_NORMAL_COMPACTION_INTERVAL_MS, DEFAULT_PRESSURE_COMPACTION_INTERVAL_MS, DEFAULT_RETENTION_MS, DEFAULT_SOFT_BUDGET_RATIO, DaemonObserver, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStateRelocationBusyError, LocalStateRelocationError, LocalStateRelocationIntegrityError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, LocalTeamWorkspace, LocalTeamWorkspace as LocalTeamWorkspaceService, McpToolsetDefinitionRevisionConflictError, McpToolsetRevisionConflictError, PI_PACKAGE_NAME, PiAdapter, PolicyUnsupportedError, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, ReplayCursorTooOldError, RuntimeDisposalFailure, RuntimeExecutionFailure, SKILL_PACKS_CAPABILITY, SKILL_PACKS_DIRNAME, SKILL_PACK_AUDIT_FILENAME, SKILL_PACK_INSTALL_ERROR_CODES, SKILL_PACK_LOCK_FILENAME, SKILL_PACK_LOCK_SCHEMA, SKILL_PACK_RESPONSE_MAX_BYTES, SecureDirHardeningError, SkillPackInstallError, SqliteLocalTaskJournal, SteerUnsupportedError, TeamTmuxViewError, TeamWorkspaceConflictError, TeamWorkspaceCorruptError, TeamWorkspaceError, TeamWorkspaceLeaseError, TeamWorkspaceNotFoundError, TeamWorkspaceQuotaError, TeamWorkspaceReceiptError, TeamWorkspaceValidationError, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createAgentHomeProjection, createAgentHomeProjectionConsumer, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, decodeTeamMemberContext, encodeTeamMemberContext, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isAgentMemorySecureFilesystemAvailable, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, openTeamTmuxView, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, readDeviceEnrollmentStatus, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, resolveSdkReservedHelperBin, runSdkReservedHelperCommand, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
20691
21346
  //# sourceMappingURL=index.js.map
20692
21347
  //# sourceMappingURL=index.js.map