@byok-sdk/client 0.4.2 → 0.6.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.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export type { RuntimeAdapter, RuntimeAdapterDescriptor, RuntimeAdapterPrepareInput, RuntimeAdapterPrepareResult, RuntimeAdapterRejectedOperation, RuntimeAdapterPreparedOperation, PreparedRuntimeOperation, RuntimeOperationManifest, RuntimeOperationStartInput, RuntimeCapabilities, RuntimeDetectResult, Session, GitWorkspaceConfig, McpStdioServerConfig, McpToolsetConfig, } from './types';
2
2
  export { PolicyUnsupportedError, SteerUnsupportedError, freezeRuntimeAdapterDescriptor, sealRuntimeOperationManifest } from './types';
3
3
  export type { RuntimeEnvironmentRequirements } from './daemon/environment';
4
+ export { resolveLocalAgentReleaseIdentity } from './release-identity';
5
+ export type { LocalAgentReleaseIdentity } from './release-identity';
4
6
  export { RuntimeExecutionFailure, RuntimeDisposalFailure, RUNTIME_ADAPTER_CONTRACT_VIOLATION_REASON, isRuntimeDisposalFailure, isRuntimeExecutionFailure, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, } from './runtime-failure';
5
7
  export type { RuntimeExecutionFailureInput, RuntimeDisposalFailureInput, RuntimeDisposalStage, RuntimeFailureCategory, RuntimeFailurePhase, RuntimeFailureProjection, RuntimeRetryDisposition, } from './runtime-failure';
6
8
  export { GitWorkspaceManager, GitWorkspaceError, isGitWorkspaceConfig, prependGitWorkspaceGuidance } from './daemon/git-workspace';
@@ -9,6 +11,7 @@ export { GitWorkspaceStore } from './daemon/git-workspace-store';
9
11
  export type { GitWorkspaceLedger, GitWorkspaceLedgerRecord, GitWorkspacePhase } from './daemon/git-workspace-store';
10
12
  export { createDaemon, createDaemonWithAdapters } from './daemon/create-daemon';
11
13
  export type { Daemon, DaemonConfig, DaemonStatus, DaemonOverrides, DaemonBranding, HostedJournalConfig, DeviceAssertionConfig } from './daemon/create-daemon';
14
+ export type { ProgressBatcherOptions } from './daemon/progress-batcher';
12
15
  /**
13
16
  * Plan `device-assertion-broker`: the ONLY control-socket capability this
14
17
  * package exposes publicly. `connectControlClient`/`ControlClient` are
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { promises, mkdirSync, existsSync, renameSync, writeFileSync, chmodSync,
4
4
  import path17, { join, isAbsolute } from 'path';
5
5
  import os5 from 'os';
6
6
  import { parseDeviceAssertionEnvelope, tenantId, DeviceProofProtectedClaimsSchema, deviceProofSigningInput, DEVICE_PROOF_SCHEMA_ID, SKILL_PACK_MAX_BYTES, hasCapability, parseSkillPackManifest, checkSkillPackManifest, skillPackContentHashInput, checkSkillPackFileContent, SKILL_PACK_ENTRY_PATH, checkSkillPackEntry, isSkillPackPathSafe, DEVICE_PROOF_HEADER, contentHash, TRUTH_RECORD_KINDS, nonceSigningBytes, DEVICE_ASSERTION_AUDIENCE_MAX_BYTES, DEVICE_ASSERTION_DEFAULT_TTL_MS, DEVICE_ASSERTION_MAX_TTL_MS, CONTENT_HASH_PATTERN, CapabilityDeclarationSchema, DeviceAssertionClaimsSchema, deviceAssertionSigningInput, DEVICE_ASSERTION_SCHEMA_ID } from '@byok-sdk/core';
7
- import { BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, encodeEnvelope, createEnvelope, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, RuntimeIdSchema, RESULT_DOCUMENT_MAX_BYTES, PROTOCOL_VERSION, decodeEnvelope, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, BYOK_EVENTS_PATH, parseMessage, UnknownMessageTypeError, BYOK_WS_PATH } from '@byok-sdk/protocol';
7
+ import { BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, byokBlobUrlPath, BYOK_BLOBS_PATH, byokBlobFinalizePath, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, encodeEnvelope, PROTOCOL_VERSION, createEnvelope, checkResultDocument, MAX_MESSAGES_PER_BATCH, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, RuntimeIdSchema, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, decodeEnvelope, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, BYOK_EVENTS_PATH, parseMessage, UnknownMessageTypeError, BYOK_WS_PATH } from '@byok-sdk/protocol';
8
8
  import { promisify } from 'util';
9
9
  import { fileURLToPath } from 'url';
10
10
  import 'readline';
@@ -75,6 +75,28 @@ var SteerUnsupportedError = class extends Error {
75
75
  }
76
76
  };
77
77
 
78
+ // src/release-identity.ts
79
+ var LOCAL_AGENT_RELEASE_VERSION_MAX_LENGTH = 128;
80
+ var LOCAL_AGENT_RELEASE_BUILD_ID_MAX_LENGTH = 128;
81
+ var STRICT_SEMVER_PATTERN = new RegExp(
82
+ "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$"
83
+ );
84
+ var BUILD_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
85
+ function resolveLocalAgentReleaseIdentity(input) {
86
+ if (input === void 0 || typeof input.version !== "string" || input.version.length > LOCAL_AGENT_RELEASE_VERSION_MAX_LENGTH || !STRICT_SEMVER_PATTERN.test(input.version)) {
87
+ throw new Error("DaemonConfig.localAgentRelease.version must be canonical strict SemVer");
88
+ }
89
+ if (input.buildId !== void 0 && (typeof input.buildId !== "string" || input.buildId.length > LOCAL_AGENT_RELEASE_BUILD_ID_MAX_LENGTH || !BUILD_ID_PATTERN.test(input.buildId))) {
90
+ throw new Error(
91
+ `DaemonConfig.localAgentRelease.buildId must be 1-${LOCAL_AGENT_RELEASE_BUILD_ID_MAX_LENGTH} safe opaque characters`
92
+ );
93
+ }
94
+ return Object.freeze({
95
+ version: input.version,
96
+ ...input.buildId === void 0 ? {} : { buildId: input.buildId }
97
+ });
98
+ }
99
+
78
100
  // src/runtime-failure.ts
79
101
  var RUNTIME_EXECUTION_FAILURE_BRAND = /* @__PURE__ */ Symbol.for("@byok-sdk/client/RuntimeExecutionFailure/v1");
80
102
  var RUNTIME_DISPOSAL_FAILURE_BRAND = /* @__PURE__ */ Symbol.for("@byok-sdk/client/RuntimeDisposalFailure/v1");
@@ -4366,7 +4388,20 @@ var PresencePublisher = class {
4366
4388
  headers: { "content-type": "application/json" },
4367
4389
  body: JSON.stringify({
4368
4390
  level: "online",
4369
- ...this.opts.configuredToolsets === void 0 ? {} : { configuredToolsets: this.opts.configuredToolsets }
4391
+ ...this.opts.configuredToolsets === void 0 ? {} : { configuredToolsets: this.opts.configuredToolsets },
4392
+ ...this.opts.clientVersion === void 0 ? {} : { clientVersion: this.opts.clientVersion },
4393
+ ...this.opts.protocolVersions === void 0 ? {} : { protocolVersions: [...this.opts.protocolVersions] },
4394
+ // Presence is a lightweight readiness fact, not a second
4395
+ // capability-negotiation channel. Keep its projection identical
4396
+ // to the persisted presence contract: the conn.hello snapshot's
4397
+ // runtime identity/version/auth facts, with no capabilities blob.
4398
+ ...this.opts.runtimes === void 0 ? {} : {
4399
+ runtimes: this.opts.runtimes.map(({ id, version, authPresent }) => ({
4400
+ id,
4401
+ ...version === void 0 ? {} : { version },
4402
+ ...authPresent === void 0 ? {} : { authPresent }
4403
+ }))
4404
+ }
4370
4405
  })
4371
4406
  },
4372
4407
  this.opts.auth
@@ -5092,6 +5127,7 @@ var WsTransport = class {
5092
5127
  capabilities: this.opts.capabilities,
5093
5128
  deviceId: this.opts.deviceId,
5094
5129
  productId: this.opts.productId,
5130
+ clientVersion: this.opts.clientVersion,
5095
5131
  runtimes: this.opts.runtimes,
5096
5132
  configuredToolsets: this.opts.configuredToolsets === void 0 ? void 0 : [...this.opts.configuredToolsets],
5097
5133
  cursor: this.opts.getCursor?.()
@@ -5182,6 +5218,7 @@ var ConnectionManager = class {
5182
5218
  deviceId: opts.deviceId,
5183
5219
  productId: opts.productId,
5184
5220
  capabilities: opts.capabilities,
5221
+ clientVersion: opts.clientVersion,
5185
5222
  runtimes: opts.runtimes,
5186
5223
  configuredToolsets: opts.configuredToolsets,
5187
5224
  getCursor: () => this.cursor,
@@ -8188,6 +8225,11 @@ function createStatfsFreeBytesProvider(dir) {
8188
8225
  var BASE_PLATFORM_ALLOWLIST = [
8189
8226
  "PATH",
8190
8227
  "HOME",
8228
+ // macOS credential-store discovery used by subscription-authenticated
8229
+ // agent CLIs depends on the login account name as well as HOME. Omitting
8230
+ // USER makes `claude auth status` report logged out under the filtered
8231
+ // child environment even when the host CLI is logged in.
8232
+ "USER",
8191
8233
  "USERPROFILE",
8192
8234
  "TMPDIR",
8193
8235
  "TEMP",
@@ -8295,11 +8337,37 @@ function computeEffectivePolicy(offered, ceiling) {
8295
8337
  }
8296
8338
 
8297
8339
  // src/daemon/progress-batcher.ts
8340
+ var ProgressEventTooLargeError = class extends Error {
8341
+ constructor(actualBytes, maxBatchBytes) {
8342
+ super(`Progress event requires ${actualBytes} UTF-8 bytes, exceeding maxBatchBytes ${maxBatchBytes}.`);
8343
+ this.actualBytes = actualBytes;
8344
+ this.maxBatchBytes = maxBatchBytes;
8345
+ this.name = "ProgressEventTooLargeError";
8346
+ }
8347
+ actualBytes;
8348
+ maxBatchBytes;
8349
+ };
8350
+ var encoder = new TextEncoder();
8351
+ function assertPositiveSafeInteger(value, name) {
8352
+ if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) {
8353
+ throw new TypeError(`${name} must be a positive safe integer when configured.`);
8354
+ }
8355
+ }
8356
+ function validateProgressBatcherOptions(options = {}) {
8357
+ assertPositiveSafeInteger(options.maxBatchSize, "maxBatchSize");
8358
+ assertPositiveSafeInteger(options.flushIntervalMs, "flushIntervalMs");
8359
+ assertPositiveSafeInteger(options.maxBatchBytes, "maxBatchBytes");
8360
+ }
8361
+ function encodedEventsBytes(events) {
8362
+ return encoder.encode(JSON.stringify(events)).length;
8363
+ }
8298
8364
  var ProgressBatcher = class {
8299
8365
  constructor(emit, options = {}) {
8300
8366
  this.emit = emit;
8367
+ validateProgressBatcherOptions(options);
8301
8368
  this.maxBatchSize = options.maxBatchSize ?? 10;
8302
8369
  this.flushIntervalMs = options.flushIntervalMs ?? 250;
8370
+ this.maxBatchBytes = options.maxBatchBytes;
8303
8371
  }
8304
8372
  emit;
8305
8373
  buffer = [];
@@ -8307,7 +8375,17 @@ var ProgressBatcher = class {
8307
8375
  timer;
8308
8376
  maxBatchSize;
8309
8377
  flushIntervalMs;
8378
+ maxBatchBytes;
8310
8379
  push(event) {
8380
+ if (this.maxBatchBytes !== void 0) {
8381
+ const eventBytes = encodedEventsBytes([event]);
8382
+ if (eventBytes > this.maxBatchBytes) {
8383
+ throw new ProgressEventTooLargeError(eventBytes, this.maxBatchBytes);
8384
+ }
8385
+ if (this.buffer.length > 0 && encodedEventsBytes([...this.buffer, event]) > this.maxBatchBytes) {
8386
+ this.flush();
8387
+ }
8388
+ }
8311
8389
  this.buffer.push(event);
8312
8390
  if (this.buffer.length >= this.maxBatchSize) {
8313
8391
  this.flush();
@@ -8360,6 +8438,7 @@ var MAX_INLINE_ARTIFACT_BYTES = 64 * 1024;
8360
8438
  var MAX_TRACKED_TASK_IDS = 2e3;
8361
8439
  var MAX_DURATION_EXCEEDED_REASON_PREFIX = "resource limit exceeded: maxDurationMs";
8362
8440
  var MAX_OUTPUT_BYTES_EXCEEDED_REASON_PREFIX = "resource limit exceeded: maxTaskOutputBytes";
8441
+ var MAX_PROGRESS_BATCH_BYTES_EXCEEDED_REASON_PREFIX = "resource limit exceeded: progressBatch.maxBatchBytes";
8363
8442
  var RESULT_DOCUMENT_UNDELIVERABLE_REASON_PREFIX = "result document undeliverable";
8364
8443
  function resultDocumentRejectionDetail(check) {
8365
8444
  switch (check.reason) {
@@ -8379,6 +8458,9 @@ var DEFAULT_MAX_TASK_OUTPUT_BYTES = 64 * 1024 * 1024;
8379
8458
  function isKnownRuntimeId(id) {
8380
8459
  return RuntimeIdSchema.safeParse(id).success;
8381
8460
  }
8461
+ function terminalUsageNumber(value, maximum) {
8462
+ return value !== void 0 && Number.isSafeInteger(value) && value >= 0 && value <= maximum ? value : void 0;
8463
+ }
8382
8464
  var DEFAULT_RUNTIME_PREFERENCE = ["claude", "codex", "pi"];
8383
8465
  function orderByPreference(candidates, preference) {
8384
8466
  const rank = new Map(preference.map((id, index) => [id, index]));
@@ -8678,7 +8760,13 @@ var TaskRunner = class {
8678
8760
  const timeoutMs = this.deps.shutdownInterruptTimeoutMs ?? DEFAULT_SHUTDOWN_INTERRUPT_TIMEOUT_MS;
8679
8761
  await raceSettleFirst(() => active.session.interrupt(), timeoutMs);
8680
8762
  if (this.tasks.get(active.taskId) !== active) return true;
8681
- this.deps.send(createEnvelope("task.fail", { reason, retryable }, { taskId: active.taskId }));
8763
+ this.deps.send(
8764
+ createEnvelope(
8765
+ "task.fail",
8766
+ { reason, retryable, ...this.terminalInferenceUsagePayload(active) },
8767
+ { taskId: active.taskId }
8768
+ )
8769
+ );
8682
8770
  return this.finish(active.taskId);
8683
8771
  }
8684
8772
  /** Graceful-shutdown caller of {@link teardownActiveTask} — see `shutdownActiveTasks`'s own doc comment. `retryable: true`: nothing about the task/policy itself was ever at fault, only this device's own availability right now. */
@@ -9056,7 +9144,8 @@ var TaskRunner = class {
9056
9144
  this.deps.batcherOptions
9057
9145
  ),
9058
9146
  approvalQueue: [],
9059
- outputBytesSoFar: 0
9147
+ outputBytesSoFar: 0,
9148
+ startedAtMs: Date.now()
9060
9149
  };
9061
9150
  if (this.pendingCancelled.has(taskId)) {
9062
9151
  const reason = this.pendingCancelled.get(taskId);
@@ -9068,7 +9157,13 @@ var TaskRunner = class {
9068
9157
  } catch {
9069
9158
  }
9070
9159
  await this.updateGitPhaseBestEffort(gitWorkspaceId, "cancelled");
9071
- this.deps.send(createEnvelope("task.cancelled", { reason }, { taskId }));
9160
+ this.deps.send(
9161
+ createEnvelope(
9162
+ "task.cancelled",
9163
+ { reason, ...this.terminalInferenceUsagePayload(active) },
9164
+ { taskId }
9165
+ )
9166
+ );
9072
9167
  await this.finish(taskId);
9073
9168
  return;
9074
9169
  }
@@ -9141,6 +9236,9 @@ var TaskRunner = class {
9141
9236
  );
9142
9237
  return;
9143
9238
  }
9239
+ if (event.type === "usage") {
9240
+ active.lastUsage = event;
9241
+ }
9144
9242
  if (event.type === "needs_approval") {
9145
9243
  active.batcher.flush();
9146
9244
  const { taskId } = active;
@@ -9193,7 +9291,8 @@ var TaskRunner = class {
9193
9291
  // (where the codec actually serializes it), so a contextual
9194
9292
  // `toJSON(key)` or an unstable getter cannot make the wire
9195
9293
  // bytes differ from what the cap gate approved.
9196
- ...outcome.document !== void 0 ? { document: outcome.document } : {}
9294
+ ...outcome.document !== void 0 ? { document: outcome.document } : {},
9295
+ ...this.terminalInferenceUsagePayload(active)
9197
9296
  },
9198
9297
  { taskId: active.taskId, sessionRef: active.session.sessionRef }
9199
9298
  )
@@ -9216,6 +9315,13 @@ var TaskRunner = class {
9216
9315
  } catch (err) {
9217
9316
  if (this.tasks.get(active.taskId) !== active || active.beingTornDown) return;
9218
9317
  active.batcher.flush();
9318
+ if (err instanceof ProgressEventTooLargeError) {
9319
+ await this.failActiveTaskForResourceLimit(
9320
+ active.taskId,
9321
+ `${MAX_PROGRESS_BATCH_BYTES_EXCEEDED_REASON_PREFIX}: event requires ${err.actualBytes} UTF-8 bytes, exceeding the configured limit of ${err.maxBatchBytes} bytes`
9322
+ );
9323
+ return;
9324
+ }
9219
9325
  const failure = projectRuntimeBoundaryFailure(err, "run");
9220
9326
  if (failure.contractViolation) {
9221
9327
  console.error("[byok/client] runtime adapter events iterable returned an untyped failure", err);
@@ -9303,7 +9409,13 @@ var TaskRunner = class {
9303
9409
  } catch {
9304
9410
  }
9305
9411
  await this.observeGit(active, "salvage");
9306
- this.deps.send(createEnvelope("task.cancelled", { reason }, { taskId }));
9412
+ this.deps.send(
9413
+ createEnvelope(
9414
+ "task.cancelled",
9415
+ { reason, ...this.terminalInferenceUsagePayload(active) },
9416
+ { taskId }
9417
+ )
9418
+ );
9307
9419
  await this.finish(taskId);
9308
9420
  }
9309
9421
  /** M3-B: bounded insert for `pendingCancelled` — see its class-level doc comment and `MAX_TRACKED_TASK_IDS`. Evicts the oldest SAFE-TO-EVICT entry once over cap — see `evictPendingCancelled` (finding #5: not simply "the oldest entry", which could be an in-flight offer's own cancel marker). */
@@ -9741,7 +9853,13 @@ var TaskRunner = class {
9741
9853
  } catch {
9742
9854
  }
9743
9855
  await this.observeGit(active, "salvage");
9744
- this.deps.send(createEnvelope("task.fail", { reason: reason ?? "rejected", retryable: false }, { taskId }));
9856
+ this.deps.send(
9857
+ createEnvelope(
9858
+ "task.fail",
9859
+ { reason: reason ?? "rejected", retryable: false, ...this.terminalInferenceUsagePayload(active) },
9860
+ { taskId }
9861
+ )
9862
+ );
9745
9863
  await this.finish(taskId);
9746
9864
  }
9747
9865
  /** Pre-claim, fail-closed rejection (protocol §3.2) — never claims first. */
@@ -9759,9 +9877,44 @@ var TaskRunner = class {
9759
9877
  return;
9760
9878
  }
9761
9879
  if (active) await this.observeGit(active, "salvage");
9762
- this.deps.send(createEnvelope("task.fail", { reason, retryable }, { taskId }));
9880
+ this.deps.send(
9881
+ createEnvelope(
9882
+ "task.fail",
9883
+ active === void 0 ? { reason, retryable } : { reason, retryable, ...this.terminalInferenceUsagePayload(active) },
9884
+ { taskId }
9885
+ )
9886
+ );
9763
9887
  await this.finish(taskId);
9764
9888
  }
9889
+ /**
9890
+ * Build the optional terminal observation from facts this running daemon
9891
+ * actually has. No offered `dispatchSelection` is echoed here: it is a
9892
+ * requested execution target, not an adapter-reported provider/model fact.
9893
+ * The bundled adapter event contracts currently expose token observations
9894
+ * (Codex and Claude) but no provider/model observation, so those keys stay
9895
+ * absent. Pi exposes no native usage observation, so its terminal payload
9896
+ * omits this optional block rather than fabricating a usage observation from
9897
+ * independently known runtime, elapsed duration, or Local Agent version.
9898
+ */
9899
+ terminalInferenceUsagePayload(active) {
9900
+ const release = this.deps.localAgentRelease;
9901
+ const runtimeId = active.adapter.descriptor.id;
9902
+ if (release === void 0 || active.lastUsage === void 0 || !isKnownRuntimeId(runtimeId)) return {};
9903
+ const nowMs = Date.now();
9904
+ const durationMs = terminalUsageNumber(nowMs - active.startedAtMs, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS);
9905
+ const promptTokens = terminalUsageNumber(active.lastUsage?.inputTokens, TERMINAL_INFERENCE_USAGE_MAX_TOKENS);
9906
+ const completionTokens = terminalUsageNumber(active.lastUsage?.outputTokens, TERMINAL_INFERENCE_USAGE_MAX_TOKENS);
9907
+ return {
9908
+ usage: {
9909
+ runtime: runtimeId,
9910
+ clientVersion: release.version,
9911
+ reportedAt: new Date(nowMs).toISOString(),
9912
+ ...promptTokens === void 0 ? {} : { promptTokens },
9913
+ ...completionTokens === void 0 ? {} : { completionTokens },
9914
+ ...durationMs === void 0 ? {} : { durationMs }
9915
+ }
9916
+ };
9917
+ }
9765
9918
  /**
9766
9919
  * additive-minor (`task.complete.document`): the whole daemon-side gate
9767
9920
  * between a configured {@link ResultDocumentExtractor} and the wire —
@@ -10290,6 +10443,7 @@ function createDaemonWithAdapters(config, adapters, overrides = {}) {
10290
10443
  return buildDaemonWithAdapters(config, adapters, overrides);
10291
10444
  }
10292
10445
  function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProbe) {
10446
+ const localAgentRelease = resolveLocalAgentReleaseIdentity(config.localAgentRelease);
10293
10447
  const mcpToolsets = resolveMcpToolsets(config.mcpToolsets);
10294
10448
  const configuredToolsets = Object.freeze(
10295
10449
  [...mcpToolsets?.keys() ?? []].sort()
@@ -10302,6 +10456,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10302
10456
  `DaemonConfig.maxTaskOutputBytes must be a positive number (or omitted to use the ${DEFAULT_MAX_TASK_OUTPUT_BYTES}-byte default) \u2014 got ${config.maxTaskOutputBytes}. Pass Number.POSITIVE_INFINITY to explicitly disable the cap; 0 or a negative number is rejected rather than silently treated as "disabled".`
10303
10457
  );
10304
10458
  }
10459
+ validateProgressBatcherOptions(config.progressBatch);
10305
10460
  const presenceCadence = {
10306
10461
  intervalMs: config.presence?.intervalMs ?? DEFAULT_PRESENCE_HEARTBEAT_INTERVAL_MS,
10307
10462
  ttlMs: config.presence?.ttlMs ?? DEFAULT_PRESENCE_TTL_MS,
@@ -10402,6 +10557,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10402
10557
  let controlServerHandle;
10403
10558
  let daemonOwnerLease;
10404
10559
  let presencePublisher;
10560
+ let detectedRuntimeFacts = [];
10405
10561
  let presenceDiscovery;
10406
10562
  let presenceDiscoveryInFlight = false;
10407
10563
  let shutdownPromise;
@@ -10535,6 +10691,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10535
10691
  Promise.resolve(new BlobClient(config.serverUrl, auth))
10536
10692
  ]);
10537
10693
  observer.noteRuntimesDetected(runtimes);
10694
+ detectedRuntimeFacts = runtimes;
10538
10695
  const capabilities = computeCapabilities(adapters);
10539
10696
  const journalIdentity = config.hostedJournal ? { tenantId: config.hostedJournal.tenantId, productId: config.productId, deviceId: record.deviceId } : void 0;
10540
10697
  const sendEnvelope = activeJournal && journalIdentity ? (envelope) => {
@@ -10587,7 +10744,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10587
10744
  // untouched. See `observer.ts`'s module doc comment.
10588
10745
  send: sendEnvelope,
10589
10746
  blobClient,
10590
- batcherOptions: overrides.batch,
10747
+ batcherOptions: config.progressBatch,
10591
10748
  sessionWorkspaces,
10592
10749
  gitWorkspaceManager,
10593
10750
  gitWorkspaceStore,
@@ -10612,6 +10769,10 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10612
10769
  approvalRegistry,
10613
10770
  storeDir,
10614
10771
  productId: config.productId,
10772
+ // U2 terminal inference usage consumes the one U4a-resolved,
10773
+ // process-immutable identity captured above. This is composition-only:
10774
+ // TaskRunner receives no config, manifest, or second identity resolver.
10775
+ localAgentRelease,
10615
10776
  approvalTimeoutMs: overrides.approvalTimeoutMs,
10616
10777
  // Finding F5(a): see TaskRunnerDeps.shutdownInterruptTimeoutMs's own doc comment.
10617
10778
  shutdownInterruptTimeoutMs: overrides.shutdown?.taskInterruptTimeoutMs,
@@ -10657,6 +10818,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10657
10818
  deviceId: record.deviceId,
10658
10819
  productId: config.productId,
10659
10820
  capabilities,
10821
+ clientVersion: localAgentRelease.version,
10660
10822
  runtimes,
10661
10823
  configuredToolsets,
10662
10824
  auth,
@@ -10746,6 +10908,9 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10746
10908
  serverUrl: config.serverUrl,
10747
10909
  auth,
10748
10910
  configuredToolsets,
10911
+ clientVersion: localAgentRelease.version,
10912
+ protocolVersions: [PROTOCOL_VERSION],
10913
+ runtimes: detectedRuntimeFacts,
10749
10914
  ...presenceCadence,
10750
10915
  onDegraded: (reason) => console.warn(`[byok/client] ${reason}`)
10751
10916
  });
@@ -10927,6 +11092,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
10927
11092
  const activeTasks = observer.tasks().filter((task) => TASK_TRANSITIONS[task.state].length > 0).map((task) => ({ taskId: task.taskId, state: task.state }));
10928
11093
  const pendingApprovals = approvalRegistry.list();
10929
11094
  return {
11095
+ localAgentRelease,
10930
11096
  pid: process.pid,
10931
11097
  uptimeMs: startedAt !== void 0 ? Date.now() - startedAt : 0,
10932
11098
  paired: auth.deviceId !== void 0,
@@ -11125,6 +11291,7 @@ function buildDaemonWithAdapters(config, adapters, overrides = {}, assertionProb
11125
11291
  }
11126
11292
  function status() {
11127
11293
  return {
11294
+ localAgentRelease,
11128
11295
  paired: auth.deviceId !== void 0,
11129
11296
  connected: connectionState === "open",
11130
11297
  degraded: connection?.isTransportDegraded() ?? false,
@@ -12639,6 +12806,6 @@ function createServiceLifecycle(def, opts = {}) {
12639
12806
  }
12640
12807
  }
12641
12808
 
12642
- export { AuthManager, 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, DeviceRevokedError, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, 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, StoredDeviceProofSigner, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, nodeAgentProgram, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, requestDeviceAssertion, resolveLocalStoragePolicy, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot };
12809
+ export { AuthManager, 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, DeviceRevokedError, GitWorkspaceError, GitWorkspaceManager, GitWorkspaceStore, JOURNAL_DB_FILENAME, JOURNAL_QUARANTINE_DIRNAME, JOURNAL_TASK_REF_PREFIX, JournalClosedError, JournalCorruptError, JournalRecordTooLargeError, JournalUnavailableError, JournalUnknownTaskError, LocalStorageEmergencyError, LocalStoragePolicyError, LocalStoragePressureEngine, 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, StoredDeviceProofSigner, TruthMemoryClient, TruthMemoryClientError, UnsupportedServicePlatformError, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, journalHash, listInstalledSkillPacks, nodeAgentProgram, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot };
12643
12810
  //# sourceMappingURL=index.js.map
12644
12811
  //# sourceMappingURL=index.js.map