@byok-sdk/client 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { randomUUID, createHash, randomBytes, createPrivateKey, generateKeyPairSync, sign, timingSafeEqual, createHmac } from 'crypto';
2
- import { promises, mkdirSync, constants, existsSync, linkSync, fstatSync, lstatSync, unlinkSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, readFileSync, opendirSync, realpathSync, openSync, readSync, closeSync } from 'fs';
2
+ import { promises, mkdirSync, constants, existsSync, linkSync, fstatSync, lstatSync, unlinkSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, readFileSync, readSync, openSync, fchmodSync, fsyncSync, closeSync, opendirSync, 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, isTaskOfferType, 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, decodeEnvelope, createEnvelope, encodeEnvelope, PROTOCOL_VERSION, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, RuntimeIdSchema, HarnessIdSchema, TERMINAL_PROJECTION_SELECTION_CAPABILITY, PROVIDER_PROFILE_BINDING_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, isServerToDaemonType, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, AgentMessagePublishPayloadSchema, AgentMessageDispositionPayloadSchema, AGENT_MEMORY_PROJECTION_CAPABILITY, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, MAILBOX_READ_AHEAD_MAX_SEQS, MAILBOX_READ_AHEAD_CAPABILITY, MESSAGE_TYPES, AGENT_MEMORY_PROJECTION_MAX_ORDERING_VALUE, AgentMemoryProjectionMutationSchema, AGENT_MEMORY_PROJECTION_MAX_REDACTED_BYTES } 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, isTaskOfferType, partitionAgentEvents, BYOK_SKILL_PACKS_PATH, byokSkillPackFilePath, BYOK_RECORDS_PATH, byokRecordPath, TASK_TRANSITIONS, AgentEgressPolicySchema, AgentMessagePublishPayloadSchema, AgentMessageDispositionPayloadSchema, BYOK_PAIR_PATH, PairResponseSchema, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, CONFIGURED_TOOLSETS_MAX_ITEMS, ToolsetIdSchema, AgentContentReceiptPayloadSchema, decodeEnvelope, createEnvelope, encodeEnvelope, PROTOCOL_VERSION, AGENT_EGRESS_RELIABLE_ACK_CAPABILITY, RuntimeIdSchema, HarnessIdSchema, TERMINAL_PROJECTION_SELECTION_CAPABILITY, PROVIDER_PROFILE_BINDING_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, isServerToDaemonType, BYOK_CAPABILITIES_PATH, BYOK_PRESENCE_PATH, AGENT_MEMORY_PROJECTION_CAPABILITY, TERMINAL_INFERENCE_USAGE_MAX_DURATION_MS, TERMINAL_INFERENCE_USAGE_MAX_TOKENS, RESULT_DOCUMENT_MAX_BYTES, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, MessagesSendResponseSchema, MAILBOX_READ_AHEAD_MAX_SEQS, MAILBOX_READ_AHEAD_CAPABILITY, MESSAGE_TYPES, 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
- import * as os4 from 'os';
8
- import os4__default from 'os';
7
+ import * as os from 'os';
8
+ import os__default from 'os';
9
9
  import { execFile, spawn, spawnSync } from 'child_process';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { createInterface } from 'readline';
@@ -246,6 +246,18 @@ var ADMINISTRATORS_SID = "*S-1-5-32-544";
246
246
  function buildIcaclsArgs(dir, username) {
247
247
  return [dir, "/inheritance:r", "/grant:r", `${username}:(OI)(CI)F`, "/grant", `${SYSTEM_SID}:(OI)(CI)F`, "/grant", `${ADMINISTRATORS_SID}:(OI)(CI)F`];
248
248
  }
249
+ function buildIcaclsFileArgs(filePath, username) {
250
+ return [
251
+ filePath,
252
+ "/inheritance:r",
253
+ "/grant:r",
254
+ `${username}:F`,
255
+ "/grant",
256
+ `${SYSTEM_SID}:F`,
257
+ "/grant",
258
+ `${ADMINISTRATORS_SID}:F`
259
+ ];
260
+ }
249
261
  var SecureDirHardeningError = class extends Error {
250
262
  constructor(dir, reason) {
251
263
  super(
@@ -256,6 +268,14 @@ var SecureDirHardeningError = class extends Error {
256
268
  }
257
269
  dir;
258
270
  };
271
+ var SecureFileHardeningError = class extends Error {
272
+ constructor(filePath, reason) {
273
+ super(`failed to apply a restrictive Windows ACL to "${filePath}": ${reason}`);
274
+ this.filePath = filePath;
275
+ this.name = "SecureFileHardeningError";
276
+ }
277
+ filePath;
278
+ };
259
279
  async function ensureSecureDir(dir, opts = {}) {
260
280
  const platform = opts.platform ?? process.platform;
261
281
  const run = opts.run ?? defaultRunner;
@@ -263,7 +283,7 @@ async function ensureSecureDir(dir, opts = {}) {
263
283
  await promises.chmod(dir, 448).catch(() => {
264
284
  });
265
285
  if (platform !== "win32") return;
266
- const { username } = os4__default.userInfo();
286
+ const { username } = os__default.userInfo();
267
287
  let result;
268
288
  try {
269
289
  result = await run("icacls", buildIcaclsArgs(dir, username));
@@ -274,6 +294,22 @@ async function ensureSecureDir(dir, opts = {}) {
274
294
  throw new SecureDirHardeningError(dir, `icacls exited ${result.code}: ${(result.stderr || result.stdout).trim()}`);
275
295
  }
276
296
  }
297
+ async function ensureSecureFile(filePath, opts = {}) {
298
+ const platform = opts.platform ?? process.platform;
299
+ const run = opts.run ?? defaultRunner;
300
+ await promises.chmod(filePath, 384);
301
+ if (platform !== "win32") return;
302
+ const { username } = os__default.userInfo();
303
+ let result;
304
+ try {
305
+ result = await run("icacls", buildIcaclsFileArgs(filePath, username));
306
+ } catch (err) {
307
+ throw new SecureFileHardeningError(filePath, `could not run icacls: ${err instanceof Error ? err.message : String(err)}`);
308
+ }
309
+ if (result.code !== 0) {
310
+ throw new SecureFileHardeningError(filePath, `icacls exited ${result.code}: ${(result.stderr || result.stdout).trim()}`);
311
+ }
312
+ }
277
313
 
278
314
  // src/daemon/path-mutation-gate.ts
279
315
  var PathMutationGateBusyError = class extends Error {
@@ -3365,6 +3401,19 @@ var RuntimeStartupDisposalFailure = class extends Error {
3365
3401
  function isRuntimeStartupDisposalFailure(value) {
3366
3402
  return typeof value === "object" && value !== null && value[/* @__PURE__ */ Symbol.for("@byok-sdk/client/RuntimeStartupDisposalFailure/v1")] === true && typeof value.retryDisposal === "function";
3367
3403
  }
3404
+ var GIT_ERROR_CATEGORIES = [
3405
+ "git-unavailable",
3406
+ "git-timeout",
3407
+ "git-output-limit",
3408
+ "git-command-failed",
3409
+ "workspace-root-invalid",
3410
+ "workspace-root-conflict",
3411
+ "workspace-not-owned",
3412
+ "repository-root-mismatch",
3413
+ "repository-invalid",
3414
+ "lease-busy",
3415
+ "ledger-invalid"
3416
+ ];
3368
3417
  var GitWorkspaceError = class extends Error {
3369
3418
  constructor(category, message = category) {
3370
3419
  super(message);
@@ -5125,7 +5174,7 @@ var PiAdapter = class {
5125
5174
  const taskMcpServers = startInput.mcpServers ?? {};
5126
5175
  let mcpConfigPath;
5127
5176
  try {
5128
- mcpConfigDir = await promises.mkdtemp(path3__default.join(os4__default.tmpdir(), "byok-pi-mcp-"));
5177
+ mcpConfigDir = await promises.mkdtemp(path3__default.join(os__default.tmpdir(), "byok-pi-mcp-"));
5129
5178
  await promises.chmod(mcpConfigDir, 448).catch(() => {
5130
5179
  });
5131
5180
  mcpConfigPath = path3__default.join(mcpConfigDir, "mcp-config.json");
@@ -6237,7 +6286,7 @@ var ClaudeAdapter = class {
6237
6286
  });
6238
6287
  }
6239
6288
  if (needsMcpConfig) {
6240
- mcpConfigDir = await promises.mkdtemp(path3__default.join(os4__default.tmpdir(), "byok-mcp-"));
6289
+ mcpConfigDir = await promises.mkdtemp(path3__default.join(os__default.tmpdir(), "byok-mcp-"));
6241
6290
  await promises.chmod(mcpConfigDir, 448).catch(() => {
6242
6291
  });
6243
6292
  const mcpConfigPath = path3__default.join(mcpConfigDir, "mcp-config.json");
@@ -7824,7 +7873,7 @@ function isNodeError(error, code) {
7824
7873
  return error instanceof Error && "code" in error && error.code === code;
7825
7874
  }
7826
7875
  async function scavengeStaleWindowsBridges() {
7827
- const temporaryRoot = os4.tmpdir();
7876
+ const temporaryRoot = os.tmpdir();
7828
7877
  let entries;
7829
7878
  try {
7830
7879
  entries = await fs14.readdir(temporaryRoot, { withFileTypes: true });
@@ -8043,7 +8092,7 @@ var DeviceCredentialStore = class {
8043
8092
  }
8044
8093
  async #windows(operation, encoded) {
8045
8094
  await scavengeStaleWindowsBridges();
8046
- const directory = await fs14.mkdtemp(path3.join(os4.tmpdir(), WINDOWS_BRIDGE_DIRECTORY_PREFIX));
8095
+ const directory = await fs14.mkdtemp(path3.join(os.tmpdir(), WINDOWS_BRIDGE_DIRECTORY_PREFIX));
8047
8096
  const executable = path3.join(directory, "credential-bridge.exe");
8048
8097
  const request = [
8049
8098
  operation,
@@ -8230,7 +8279,7 @@ var DeviceStore = class _DeviceStore {
8230
8279
  /** Internal test seam. Product construction always supplies productId and gets an OS store. */
8231
8280
  credentials;
8232
8281
  static defaultDir(productId) {
8233
- return path3__default.join(os4__default.homedir(), ".byok", productId);
8282
+ return path3__default.join(os__default.homedir(), ".byok", productId);
8234
8283
  }
8235
8284
  /**
8236
8285
  * Resolve the one store pathname every daemon/CLI component must share.
@@ -8502,7 +8551,7 @@ var AuthManager = class {
8502
8551
  if (!(error instanceof DeviceRecordRePairRequiredError)) throw error;
8503
8552
  }
8504
8553
  }
8505
- const observedDeviceName = this.opts.deviceName ?? os4__default.hostname();
8554
+ const observedDeviceName = this.opts.deviceName ?? os__default.hostname();
8506
8555
  const observedMachineId = await this.opts.machineId?.();
8507
8556
  let keyPair;
8508
8557
  let pairingDeviceName = observedDeviceName;
@@ -9008,9 +9057,9 @@ async function probeDarwin(run) {
9008
9057
  return DARWIN_UUID_RE.exec(result.stdout)?.[1];
9009
9058
  }
9010
9059
  async function probeLinux(readFile3) {
9011
- for (const path40 of LINUX_MACHINE_ID_PATHS) {
9060
+ for (const path43 of LINUX_MACHINE_ID_PATHS) {
9012
9061
  try {
9013
- const contents = (await readFile3(path40)).trim();
9062
+ const contents = (await readFile3(path43)).trim();
9014
9063
  if (contents.length > 0) return contents;
9015
9064
  } catch {
9016
9065
  }
@@ -9042,7 +9091,7 @@ async function withTimeout2(probe, timeoutMs) {
9042
9091
  async function resolveMachineId(options) {
9043
9092
  const platform = options.platform ?? process.platform;
9044
9093
  const run = options.run ?? runDeviceCommand;
9045
- const readFile3 = options.readFile ?? ((path40) => fs14.readFile(path40, "utf8"));
9094
+ const readFile3 = options.readFile ?? ((path43) => fs14.readFile(path43, "utf8"));
9046
9095
  let probe;
9047
9096
  if (platform === "darwin") probe = probeDarwin(run);
9048
9097
  else if (platform === "linux") probe = probeLinux(readFile3);
@@ -12188,9 +12237,9 @@ function isSqliteAvailable() {
12188
12237
  }
12189
12238
  }
12190
12239
  var SECURE_FILE_MODE = 384;
12191
- function openJournalDatabase(path40, busyTimeoutMs, faults) {
12240
+ function openJournalDatabase(path43, busyTimeoutMs, faults) {
12192
12241
  const { DatabaseSync } = loadSqliteModule();
12193
- const db = new DatabaseSync(path40, { timeout: busyTimeoutMs });
12242
+ const db = new DatabaseSync(path43, { timeout: busyTimeoutMs });
12194
12243
  try {
12195
12244
  faults?.onStep?.("after-open");
12196
12245
  db.exec("PRAGMA auto_vacuum = INCREMENTAL;");
@@ -12334,9 +12383,9 @@ var RECEIVED_STATE = "received";
12334
12383
  function byteLength2(value) {
12335
12384
  return Buffer.byteLength(value, "utf8");
12336
12385
  }
12337
- function fileBytes(path40) {
12386
+ function fileBytes(path43) {
12338
12387
  try {
12339
- return statSync(path40).size;
12388
+ return statSync(path43).size;
12340
12389
  } catch {
12341
12390
  return 0;
12342
12391
  }
@@ -14203,6 +14252,10 @@ var AgentMessageOutbox = class _AgentMessageOutbox {
14203
14252
  this.revokedTasks.add(taskId);
14204
14253
  });
14205
14254
  }
14255
+ /** The same terminal classification used by operator receipts and archival. */
14256
+ terminalRecords() {
14257
+ return Object.freeze(this.records().filter((record3) => this.isTerminalEvidence(record3.taskId)));
14258
+ }
14206
14259
  isTerminalEvidence(taskId) {
14207
14260
  return this.revokedTasks.has(taskId) || this.dispositionByTask.get(taskId)?.outcome === "refused";
14208
14261
  }
@@ -14294,7 +14347,7 @@ var AgentMessageOutbox = class _AgentMessageOutbox {
14294
14347
  async archiveTerminalRecords(archiveDirectory) {
14295
14348
  return this.exclusive(async () => {
14296
14349
  if (!path3__default.isAbsolute(archiveDirectory)) throw new AgentMessageOutboxError("message archive directory must be absolute");
14297
- const terminal = this.records().filter((record3) => this.isTerminalEvidence(record3.taskId));
14350
+ const terminal = this.terminalRecords();
14298
14351
  if (terminal.length === 0) return void 0;
14299
14352
  await ensureSecureDir(archiveDirectory);
14300
14353
  const archivePath = path3__default.join(archiveDirectory, `message-terminal-${randomUUID()}.jsonl`);
@@ -22052,8 +22105,8 @@ var TruthMemoryClient = class {
22052
22105
  #requestId;
22053
22106
  #allowedObjectDownloadOrigins;
22054
22107
  async listManifest(query = {}) {
22055
- const path40 = manifestPath(query);
22056
- const response = await this.#proofFetch(path40, {
22108
+ const path43 = manifestPath(query);
22109
+ const response = await this.#proofFetch(path43, {
22057
22110
  method: "GET",
22058
22111
  operation: "truth.list",
22059
22112
  resource: "records",
@@ -22160,9 +22213,9 @@ var TruthMemoryClient = class {
22160
22213
  }
22161
22214
  async #write(kind, recordKey, requestId, payload, expectedPrimary, expectedSnapshots) {
22162
22215
  assertDistinctExpectedWrites([expectedPrimary, ...expectedSnapshots]);
22163
- const path40 = recordPath(kind, recordKey);
22216
+ const path43 = recordPath(kind, recordKey);
22164
22217
  const body = new TextEncoder().encode(JSON.stringify(payload));
22165
- const response = await this.#proofFetch(path40, {
22218
+ const response = await this.#proofFetch(path43, {
22166
22219
  method: "PUT",
22167
22220
  operation: "truth.write",
22168
22221
  resource: `${kind}/${recordKey}`,
@@ -22188,8 +22241,8 @@ var TruthMemoryClient = class {
22188
22241
  };
22189
22242
  }
22190
22243
  async #readVerified(listed) {
22191
- const path40 = recordPath(listed.kind, listed.recordKey);
22192
- const response = await this.#proofFetch(path40, {
22244
+ const path43 = recordPath(listed.kind, listed.recordKey);
22245
+ const response = await this.#proofFetch(path43, {
22193
22246
  method: "GET",
22194
22247
  operation: "truth.read",
22195
22248
  resource: `${listed.kind}/${listed.recordKey}`,
@@ -22250,16 +22303,16 @@ var TruthMemoryClient = class {
22250
22303
  }
22251
22304
  return { ...listed, bytes };
22252
22305
  }
22253
- async #proofFetch(path40, request) {
22306
+ async #proofFetch(path43, request) {
22254
22307
  const proof = await this.options.signer.sign({
22255
22308
  method: request.method,
22256
- path: path40,
22309
+ path: path43,
22257
22310
  operation: request.operation,
22258
22311
  resource: request.resource,
22259
22312
  requestId: request.requestId,
22260
22313
  body: request.body
22261
22314
  });
22262
- const response = await this.#fetch(new URL(path40, this.#base), {
22315
+ const response = await this.#fetch(new URL(path43, this.#base), {
22263
22316
  method: request.method,
22264
22317
  headers: {
22265
22318
  ...request.headers,
@@ -22270,7 +22323,7 @@ var TruthMemoryClient = class {
22270
22323
  if (!response.ok) {
22271
22324
  throw new TruthMemoryClientError(
22272
22325
  "truth_http_failed",
22273
- `truth request ${request.method} ${path40} failed with HTTP ${response.status}`,
22326
+ `truth request ${request.method} ${path43} failed with HTTP ${response.status}`,
22274
22327
  response.status
22275
22328
  );
22276
22329
  }
@@ -22528,7 +22581,7 @@ function plistString(value) {
22528
22581
  function generateLaunchdPlist(def) {
22529
22582
  const { label, program, logDir } = def;
22530
22583
  const args = [program.command, ...program.args];
22531
- const cwd = program.cwd ?? os4__default.homedir();
22584
+ const cwd = program.cwd ?? os__default.homedir();
22532
22585
  const outLog = path3__default.join(logDir, `${label}.out.log`);
22533
22586
  const errLog = path3__default.join(logDir, `${label}.err.log`);
22534
22587
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -22562,8 +22615,8 @@ ${args.map((a) => ` ${plistString(a)}`).join("\n")}
22562
22615
  }
22563
22616
  function createLaunchdLifecycle(def, deps = {}) {
22564
22617
  const run = deps.run ?? defaultRunner;
22565
- const fs33 = deps.fs ?? promises;
22566
- const homedir = deps.homedir ?? (() => os4__default.homedir());
22618
+ const fs36 = deps.fs ?? promises;
22619
+ const homedir = deps.homedir ?? (() => os__default.homedir());
22567
22620
  const getuid = deps.getuid ?? (() => {
22568
22621
  if (typeof process.getuid !== "function") {
22569
22622
  throw new Error("launchd lifecycle requires a POSIX uid (process.getuid unavailable) \u2014 this module only runs on macOS");
@@ -22576,7 +22629,7 @@ function createLaunchdLifecycle(def, deps = {}) {
22576
22629
  const serviceTarget = () => `${domainTarget()}/${label}`;
22577
22630
  async function fileExists(p) {
22578
22631
  try {
22579
- await fs33.stat(p);
22632
+ await fs36.stat(p);
22580
22633
  return true;
22581
22634
  } catch {
22582
22635
  return false;
@@ -22584,9 +22637,9 @@ function createLaunchdLifecycle(def, deps = {}) {
22584
22637
  }
22585
22638
  async function writePlist(program) {
22586
22639
  const xml = generateLaunchdPlist({ label, program, logDir: def.logDir });
22587
- await fs33.mkdir(path3__default.dirname(plistPath()), { recursive: true });
22588
- await fs33.mkdir(def.logDir, { recursive: true });
22589
- await fs33.writeFile(plistPath(), xml, "utf8");
22640
+ await fs36.mkdir(path3__default.dirname(plistPath()), { recursive: true });
22641
+ await fs36.mkdir(def.logDir, { recursive: true });
22642
+ await fs36.writeFile(plistPath(), xml, "utf8");
22590
22643
  }
22591
22644
  async function install(opts = {}) {
22592
22645
  await writePlist(opts.program ?? def.program);
@@ -22597,7 +22650,7 @@ function createLaunchdLifecycle(def, deps = {}) {
22597
22650
  }
22598
22651
  async function uninstall() {
22599
22652
  await runIdempotent(run, "launchctl", ["bootout", serviceTarget()], "launchctl bootout", LAUNCHD_NOT_LOADED);
22600
- await fs33.rm(plistPath(), { force: true });
22653
+ await fs36.rm(plistPath(), { force: true });
22601
22654
  }
22602
22655
  async function start() {
22603
22656
  if (!await fileExists(plistPath())) {
@@ -22656,7 +22709,7 @@ function generateSystemdUnit(def) {
22656
22709
  const { name, displayName, program, logDir } = def;
22657
22710
  assertNoControlChars(name, "name");
22658
22711
  assertNoControlChars(displayName, "displayName");
22659
- const cwd = program.cwd ?? os4__default.homedir();
22712
+ const cwd = program.cwd ?? os__default.homedir();
22660
22713
  assertNoControlChars(cwd, "program.cwd");
22661
22714
  const outLog = path3__default.join(logDir, `${name}.out.log`);
22662
22715
  const errLog = path3__default.join(logDir, `${name}.err.log`);
@@ -22681,14 +22734,14 @@ WantedBy=default.target
22681
22734
  }
22682
22735
  function createSystemdLifecycle(def, deps = {}) {
22683
22736
  const run = deps.run ?? defaultRunner;
22684
- const fs33 = deps.fs ?? promises;
22685
- const homedir = deps.homedir ?? (() => os4__default.homedir());
22737
+ const fs36 = deps.fs ?? promises;
22738
+ const homedir = deps.homedir ?? (() => os__default.homedir());
22686
22739
  const name = sanitizeServiceName(def.name);
22687
22740
  const unitName = `${name}.service`;
22688
22741
  const unitPath = () => path3__default.join(homedir(), ".config", "systemd", "user", unitName);
22689
22742
  async function fileExists(p) {
22690
22743
  try {
22691
- await fs33.stat(p);
22744
+ await fs36.stat(p);
22692
22745
  return true;
22693
22746
  } catch {
22694
22747
  return false;
@@ -22696,9 +22749,9 @@ function createSystemdLifecycle(def, deps = {}) {
22696
22749
  }
22697
22750
  async function writeUnit(program) {
22698
22751
  const unit = generateSystemdUnit({ name, displayName: def.displayName ?? def.name, program, logDir: def.logDir });
22699
- await fs33.mkdir(path3__default.dirname(unitPath()), { recursive: true });
22700
- await fs33.mkdir(def.logDir, { recursive: true });
22701
- await fs33.writeFile(unitPath(), unit, "utf8");
22752
+ await fs36.mkdir(path3__default.dirname(unitPath()), { recursive: true });
22753
+ await fs36.mkdir(def.logDir, { recursive: true });
22754
+ await fs36.writeFile(unitPath(), unit, "utf8");
22702
22755
  }
22703
22756
  async function install(opts = {}) {
22704
22757
  await writeUnit(opts.program ?? def.program);
@@ -22707,7 +22760,7 @@ function createSystemdLifecycle(def, deps = {}) {
22707
22760
  }
22708
22761
  async function uninstall() {
22709
22762
  await runIdempotent(run, "systemctl", ["--user", "disable", "--now", unitName], "systemctl disable --now", SYSTEMD_NOT_LOADED);
22710
- await fs33.rm(unitPath(), { force: true });
22763
+ await fs36.rm(unitPath(), { force: true });
22711
22764
  await run("systemctl", ["--user", "daemon-reload"]);
22712
22765
  }
22713
22766
  async function start() {
@@ -22770,7 +22823,7 @@ ${argXml}${cwdXml}
22770
22823
  }
22771
22824
  function createWinswLifecycle(def, deps = {}) {
22772
22825
  const run = deps.run ?? defaultRunner;
22773
- const fs33 = deps.fs ?? promises;
22826
+ const fs36 = deps.fs ?? promises;
22774
22827
  const windows = def.windows;
22775
22828
  if (!windows) {
22776
22829
  throw new Error("WinSW service lifecycle requires `ServiceDefinition.windows.winswBin` (the product-bundled WinSW executable path)");
@@ -22782,7 +22835,7 @@ function createWinswLifecycle(def, deps = {}) {
22782
22835
  const xmlPath = path3__default.join(installDir, `${id}.xml`);
22783
22836
  async function fileExists(p) {
22784
22837
  try {
22785
- await fs33.stat(p);
22838
+ await fs36.stat(p);
22786
22839
  return true;
22787
22840
  } catch {
22788
22841
  return false;
@@ -22790,10 +22843,10 @@ function createWinswLifecycle(def, deps = {}) {
22790
22843
  }
22791
22844
  async function writeFiles(program) {
22792
22845
  const xml = generateWinswXml({ id, displayName: def.displayName ?? def.name, program, logDir: def.logDir });
22793
- await fs33.mkdir(installDir, { recursive: true });
22794
- await fs33.mkdir(def.logDir, { recursive: true });
22795
- await fs33.copyFile(winswBin, exePath);
22796
- await fs33.writeFile(xmlPath, xml, "utf8");
22846
+ await fs36.mkdir(installDir, { recursive: true });
22847
+ await fs36.mkdir(def.logDir, { recursive: true });
22848
+ await fs36.copyFile(winswBin, exePath);
22849
+ await fs36.writeFile(xmlPath, xml, "utf8");
22797
22850
  }
22798
22851
  async function install(opts = {}) {
22799
22852
  await writeFiles(opts.program ?? def.program);
@@ -22803,8 +22856,8 @@ function createWinswLifecycle(def, deps = {}) {
22803
22856
  async function uninstall() {
22804
22857
  await runIdempotent(run, exePath, ["stop"], "winsw stop", WINSW_NOT_INSTALLED);
22805
22858
  await runIdempotent(run, exePath, ["uninstall"], "winsw uninstall", WINSW_NOT_INSTALLED);
22806
- await fs33.rm(exePath, { force: true });
22807
- await fs33.rm(xmlPath, { force: true });
22859
+ await fs36.rm(exePath, { force: true });
22860
+ await fs36.rm(xmlPath, { force: true });
22808
22861
  }
22809
22862
  async function start() {
22810
22863
  if (!await fileExists(xmlPath)) {
@@ -23068,7 +23121,7 @@ async function inspectJournal(storeDir) {
23068
23121
  reason: "journal exceeds the bounded diagnostics copy limit"
23069
23122
  };
23070
23123
  }
23071
- const tempDir = await promises.mkdtemp(path3__default.join(os4__default.tmpdir(), "byok-journal-inspect-"));
23124
+ const tempDir = await promises.mkdtemp(path3__default.join(os__default.tmpdir(), "byok-journal-inspect-"));
23072
23125
  const { DatabaseSync } = loadSqliteModule();
23073
23126
  let db;
23074
23127
  try {
@@ -23425,6 +23478,204 @@ function sameInode2(left, right) {
23425
23478
  function sameFileState5(left, right) {
23426
23479
  return sameInode2(left, right) && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
23427
23480
  }
23481
+ function publishQuarantineEvidencePinned(quarantineDir, expectedDirectory, sourcePath, sourceFd, sourceStat, evidenceName, manifestName, quarantinedAt, reason) {
23482
+ const previousCwd = process.cwd();
23483
+ let entered = false;
23484
+ let evidenceCreated = false;
23485
+ let manifestCreated = false;
23486
+ let sourceRemoved = false;
23487
+ let evidenceTemp;
23488
+ let manifestTemp;
23489
+ try {
23490
+ process.chdir(quarantineDir);
23491
+ entered = true;
23492
+ const pinned = lstatSync(".", { bigint: true });
23493
+ if (!pinned.isDirectory() || !sameInode2(pinned, expectedDirectory)) {
23494
+ throw new Error("quarantine path changed before publication; refusing quarantine");
23495
+ }
23496
+ const openSource = fstatSync(sourceFd, { bigint: true });
23497
+ const namedSource = lstatSync(sourcePath, { bigint: true });
23498
+ if (!sameFileState5(openSource, sourceStat) || !sameFileState5(namedSource, sourceStat)) {
23499
+ throw new Error("operational health source identity changed before quarantine");
23500
+ }
23501
+ const sizeBytes = Number(sourceStat.size);
23502
+ if (sizeBytes > MAX_OPERATIONAL_HEALTH_FILE_BYTES) {
23503
+ throw new Error("operational health state exceeds the bounded quarantine read limit");
23504
+ }
23505
+ const bytes = Buffer.alloc(sizeBytes);
23506
+ let position = 0;
23507
+ while (position < sizeBytes) {
23508
+ const bytesRead = readSync(sourceFd, bytes, position, sizeBytes - position, position);
23509
+ if (bytesRead === 0) throw new Error("operational health state ended during bounded copy");
23510
+ position += bytesRead;
23511
+ }
23512
+ const afterRead = fstatSync(sourceFd, { bigint: true });
23513
+ if (!sameFileState5(afterRead, sourceStat)) {
23514
+ throw new Error("operational health state changed during bounded copy");
23515
+ }
23516
+ const sha2562 = createHash("sha256").update(bytes).digest("hex");
23517
+ evidenceTemp = `.${evidenceName}.${randomUUID()}.tmp`;
23518
+ const evidenceFd = openSync(evidenceTemp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 384);
23519
+ try {
23520
+ writeFileSync(evidenceFd, bytes);
23521
+ fchmodSync(evidenceFd, 384);
23522
+ fsyncSync(evidenceFd);
23523
+ } finally {
23524
+ closeSync(evidenceFd);
23525
+ }
23526
+ linkSync(evidenceTemp, evidenceName);
23527
+ evidenceCreated = true;
23528
+ const evidence = lstatSync(evidenceName, { bigint: true });
23529
+ const tempEvidence = lstatSync(evidenceTemp, { bigint: true });
23530
+ if (!evidence.isFile() || !sameInode2(evidence, tempEvidence) || evidence.size !== sourceStat.size) {
23531
+ throw new Error("quarantined operational health evidence does not match the bounded copy");
23532
+ }
23533
+ unlinkSync(evidenceTemp);
23534
+ evidenceTemp = void 0;
23535
+ const finalOpenSource = fstatSync(sourceFd, { bigint: true });
23536
+ const finalNamedSource = lstatSync(sourcePath, { bigint: true });
23537
+ if (!sameFileState5(finalOpenSource, sourceStat) || !sameFileState5(finalNamedSource, sourceStat)) {
23538
+ throw new Error("operational health source changed before removal");
23539
+ }
23540
+ const manifestBody = `${JSON.stringify(
23541
+ {
23542
+ version: 1,
23543
+ quarantinedAt,
23544
+ reason,
23545
+ sourcePath,
23546
+ evidenceFile: evidenceName,
23547
+ sha256: sha2562,
23548
+ sizeBytes
23549
+ },
23550
+ null,
23551
+ 2
23552
+ )}
23553
+ `;
23554
+ manifestTemp = `.${manifestName}.${randomUUID()}.tmp`;
23555
+ const manifestFd = openSync(manifestTemp, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 384);
23556
+ try {
23557
+ writeFileSync(manifestFd, manifestBody, "utf8");
23558
+ fchmodSync(manifestFd, 384);
23559
+ fsyncSync(manifestFd);
23560
+ } finally {
23561
+ closeSync(manifestFd);
23562
+ }
23563
+ linkSync(manifestTemp, manifestName);
23564
+ manifestCreated = true;
23565
+ unlinkSync(manifestTemp);
23566
+ manifestTemp = void 0;
23567
+ if (process.platform !== "win32") {
23568
+ const quarantineDirectoryFd = openSync(".", constants.O_RDONLY);
23569
+ try {
23570
+ fsyncSync(quarantineDirectoryFd);
23571
+ } finally {
23572
+ closeSync(quarantineDirectoryFd);
23573
+ }
23574
+ }
23575
+ const removalOpenSource = fstatSync(sourceFd, { bigint: true });
23576
+ const removalNamedSource = lstatSync(sourcePath, { bigint: true });
23577
+ if (!sameFileState5(removalOpenSource, sourceStat) || !sameFileState5(removalNamedSource, sourceStat)) {
23578
+ throw new Error("operational health source changed before removal");
23579
+ }
23580
+ unlinkSync(sourcePath);
23581
+ sourceRemoved = true;
23582
+ if (process.platform !== "win32") {
23583
+ const directoryFd = openSync(path3__default.dirname(sourcePath), constants.O_RDONLY);
23584
+ try {
23585
+ fsyncSync(directoryFd);
23586
+ } finally {
23587
+ closeSync(directoryFd);
23588
+ }
23589
+ }
23590
+ return { sha256: sha2562, sizeBytes };
23591
+ } catch (err) {
23592
+ if (evidenceTemp) {
23593
+ try {
23594
+ unlinkSync(evidenceTemp);
23595
+ } catch {
23596
+ }
23597
+ }
23598
+ if (manifestTemp) {
23599
+ try {
23600
+ unlinkSync(manifestTemp);
23601
+ } catch {
23602
+ }
23603
+ }
23604
+ if (manifestCreated && !sourceRemoved) {
23605
+ try {
23606
+ unlinkSync(manifestName);
23607
+ } catch {
23608
+ }
23609
+ }
23610
+ if (evidenceCreated && !sourceRemoved) {
23611
+ try {
23612
+ unlinkSync(evidenceName);
23613
+ } catch {
23614
+ }
23615
+ }
23616
+ throw err;
23617
+ } finally {
23618
+ if (entered) process.chdir(previousCwd);
23619
+ }
23620
+ }
23621
+ async function quarantineCorruptOperationalHealth(storeDir, options = {}) {
23622
+ const resolvedStoreDir = path3__default.resolve(storeDir);
23623
+ const owner = await acquireDaemonOwner(resolvedStoreDir, "doctor", options.clock);
23624
+ try {
23625
+ const sourcePath = path3__default.join(resolvedStoreDir, OPERATIONAL_HEALTH_FILENAME);
23626
+ let opened;
23627
+ try {
23628
+ opened = await openOperationalHealthFile(resolvedStoreDir);
23629
+ } catch (err) {
23630
+ throw new Error("operational health state could not be opened safely; refusing quarantine", { cause: err });
23631
+ }
23632
+ if (!opened) return { status: "not-needed", reason: "missing" };
23633
+ const source = opened.handle;
23634
+ try {
23635
+ const inspection = await inspectOperationalHealthHandle(source, opened.stat);
23636
+ if (inspection.status === "valid") return { status: "not-needed", reason: "valid" };
23637
+ if (inspection.status === "unavailable") {
23638
+ throw new Error(`${inspection.reason}; refusing to quarantine unconfirmed corruption`);
23639
+ }
23640
+ const sourceStat = await source.stat({ bigint: true });
23641
+ if (!sourceStat.isFile()) throw new Error("operational health state is not a regular file; refusing quarantine");
23642
+ const quarantineDir = path3__default.join(resolvedStoreDir, JOURNAL_QUARANTINE_DIRNAME);
23643
+ try {
23644
+ const existing = await promises.lstat(quarantineDir);
23645
+ if (!existing.isDirectory() || existing.isSymbolicLink()) {
23646
+ throw new Error("quarantine path is not a real directory; refusing quarantine");
23647
+ }
23648
+ } catch (err) {
23649
+ if (err.code !== "ENOENT") throw err;
23650
+ await promises.mkdir(quarantineDir, { mode: 448 });
23651
+ }
23652
+ await ensureSecureDir(quarantineDir);
23653
+ const securedQuarantine = await promises.lstat(quarantineDir, { bigint: true });
23654
+ if (!securedQuarantine.isDirectory() || securedQuarantine.isSymbolicLink()) {
23655
+ throw new Error("quarantine path changed during validation; refusing quarantine");
23656
+ }
23657
+ const stamp = (options.clock ?? (() => /* @__PURE__ */ new Date()))().toISOString().replace(/[:.]/g, "-");
23658
+ const evidenceName = `${stamp}-${randomUUID()}-${OPERATIONAL_HEALTH_FILENAME}`;
23659
+ const manifestName = `${evidenceName}.manifest.json`;
23660
+ const hashed = publishQuarantineEvidencePinned(
23661
+ quarantineDir,
23662
+ securedQuarantine,
23663
+ sourcePath,
23664
+ source.fd,
23665
+ sourceStat,
23666
+ evidenceName,
23667
+ manifestName,
23668
+ (options.clock ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
23669
+ inspection.reason
23670
+ );
23671
+ return { status: "quarantined", evidenceName, manifestName, sha256: hashed.sha256, sizeBytes: hashed.sizeBytes };
23672
+ } finally {
23673
+ await source.close();
23674
+ }
23675
+ } finally {
23676
+ await owner.release();
23677
+ }
23678
+ }
23428
23679
 
23429
23680
  // src/diagnostics/device-doctor.ts
23430
23681
  function diagnoseDevice(config, options = {}) {
@@ -23498,7 +23749,342 @@ async function repairDeviceEnrollmentMetadata(config, input) {
23498
23749
  throw new DeviceMetadataRepairError(failureCode);
23499
23750
  }
23500
23751
  }
23752
+ function auditLogPath(storeDir) {
23753
+ return path3__default.join(storeDir, "audit.jsonl");
23754
+ }
23755
+ new Set(GIT_ERROR_CATEGORIES);
23756
+
23757
+ // src/diagnostics/support-bundle.ts
23758
+ var MAX_SUPPORT_AUDIT_TAIL_BYTES = 256 * 1024;
23759
+ var MAX_SUPPORT_AUDIT_FACTS = 200;
23760
+ var AUDIT_KINDS = /* @__PURE__ */ new Set([
23761
+ "artifact",
23762
+ "awaiting-approval",
23763
+ "cancelled",
23764
+ "claimed",
23765
+ "completed",
23766
+ "connection",
23767
+ "failed",
23768
+ "git-workspace",
23769
+ "offered",
23770
+ "paired",
23771
+ "progress",
23772
+ "runtimes-detected",
23773
+ "shutdown-complete",
23774
+ "shutdown-requested",
23775
+ "stale-approval-decision",
23776
+ "started",
23777
+ "unpaired"
23778
+ ]);
23779
+ function isAuditKind(value) {
23780
+ return typeof value === "string" && AUDIT_KINDS.has(value);
23781
+ }
23782
+ function sameFileState6(left, right) {
23783
+ return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
23784
+ }
23785
+ async function recentAuditFacts(storeDir) {
23786
+ const filePath = auditLogPath(storeDir);
23787
+ let pathStat;
23788
+ try {
23789
+ pathStat = await promises.lstat(filePath, { bigint: true });
23790
+ if (!pathStat.isFile() || pathStat.isSymbolicLink()) {
23791
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23792
+ }
23793
+ } catch (err) {
23794
+ if (err.code === "ENOENT") {
23795
+ return { status: "missing", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23796
+ }
23797
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23798
+ }
23799
+ let handle;
23800
+ try {
23801
+ handle = await promises.open(
23802
+ filePath,
23803
+ constants.O_RDONLY | constants.O_NONBLOCK | (constants.O_NOFOLLOW ?? 0)
23804
+ );
23805
+ } catch (err) {
23806
+ if (err.code === "ENOENT") {
23807
+ return { status: "missing", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23808
+ }
23809
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23810
+ }
23811
+ try {
23812
+ const stat = await handle.stat({ bigint: true });
23813
+ const namedAfterOpen = await promises.lstat(filePath, { bigint: true });
23814
+ if (!stat.isFile() || !namedAfterOpen.isFile() || namedAfterOpen.isSymbolicLink() || !sameFileState6(pathStat, stat) || !sameFileState6(stat, namedAfterOpen)) {
23815
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23816
+ }
23817
+ const sourceSize = Number(stat.size);
23818
+ const length = Math.min(sourceSize, MAX_SUPPORT_AUDIT_TAIL_BYTES);
23819
+ const start = Math.max(0, sourceSize - length);
23820
+ const buffer = Buffer.alloc(length);
23821
+ const { bytesRead } = await handle.read(buffer, 0, length, start);
23822
+ const afterRead = await handle.stat({ bigint: true });
23823
+ const namedAfterRead = await promises.lstat(filePath, { bigint: true });
23824
+ if (bytesRead !== length || namedAfterRead.isSymbolicLink() || !sameFileState6(stat, afterRead) || !sameFileState6(afterRead, namedAfterRead)) {
23825
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23826
+ }
23827
+ let text = buffer.subarray(0, bytesRead).toString("utf8");
23828
+ if (start > 0) text = text.slice(Math.max(0, text.indexOf("\n") + 1));
23829
+ const lines = text.split("\n").filter(Boolean).slice(-MAX_SUPPORT_AUDIT_FACTS);
23830
+ const facts = [];
23831
+ for (const line of lines) {
23832
+ try {
23833
+ const value = JSON.parse(line);
23834
+ if (isAuditKind(value.kind) && typeof value.ts === "string" && Number.isFinite(Date.parse(value.ts))) {
23835
+ facts.push({ kind: value.kind, ts: new Date(Date.parse(value.ts)).toISOString() });
23836
+ }
23837
+ } catch {
23838
+ }
23839
+ }
23840
+ return { status: "available", included: facts.length, sourceBytesRead: bytesRead, sourceTruncated: sourceSize > bytesRead, facts };
23841
+ } catch {
23842
+ return { status: "unavailable", included: 0, sourceBytesRead: 0, sourceTruncated: false, facts: [] };
23843
+ } finally {
23844
+ await handle.close();
23845
+ }
23846
+ }
23847
+ function projectControl(control) {
23848
+ if (control.status === "offline") return { status: "offline" };
23849
+ const transport = ["connecting", "open", "closed", "revoked"].includes(control.transport) ? control.transport : "unavailable";
23850
+ const operationalHealth = control.operationalHealth.availability === "available" ? {
23851
+ availability: "available",
23852
+ state: control.operationalHealth.state,
23853
+ failureCount: control.operationalHealth.failureCount,
23854
+ windowMs: control.operationalHealth.windowMs,
23855
+ failureThreshold: control.operationalHealth.failureThreshold,
23856
+ crashCount: control.operationalHealth.crashCount
23857
+ } : { availability: "unavailable" };
23858
+ return {
23859
+ status: "online",
23860
+ pid: control.pid,
23861
+ uptimeMs: control.uptimeMs,
23862
+ transport,
23863
+ activeTaskCount: control.activeTaskCount,
23864
+ pendingApprovalCount: control.pendingApprovalCount,
23865
+ operationalHealth,
23866
+ storagePresent: control.storage !== void 0
23867
+ };
23868
+ }
23869
+ async function createSupportBundle(config, storeDir, options = {}) {
23870
+ const [snapshot, recentEvents] = await Promise.all([collectDiagnostics(config, storeDir, options), recentAuditFacts(storeDir)]);
23871
+ return {
23872
+ version: 1,
23873
+ generatedAt: snapshot.generatedAt,
23874
+ product: snapshot.product,
23875
+ system: snapshot.system,
23876
+ config: {
23877
+ serverProtocol: snapshot.config.serverProtocol,
23878
+ customStoreDir: snapshot.config.customStoreDir,
23879
+ hostedJournal: snapshot.config.hostedJournal,
23880
+ ...snapshot.config.runtimeAllowlistCount === void 0 ? {} : { runtimeAllowlistCount: snapshot.config.runtimeAllowlistCount }
23881
+ },
23882
+ device: {
23883
+ status: snapshot.device.status,
23884
+ ...snapshot.device.deviceIdHash ? { deviceIdHash: snapshot.device.deviceIdHash } : {}
23885
+ },
23886
+ runtimes: snapshot.runtimes,
23887
+ control: projectControl(snapshot.control),
23888
+ health: snapshot.health,
23889
+ journal: snapshot.journal,
23890
+ workspace: snapshot.workspace,
23891
+ quarantine: {
23892
+ status: snapshot.quarantine.status,
23893
+ count: snapshot.quarantine.count,
23894
+ scannedCount: snapshot.quarantine.scannedCount,
23895
+ truncated: snapshot.quarantine.truncated,
23896
+ entries: snapshot.quarantine.entries
23897
+ },
23898
+ checks: snapshot.checks.map(({ id, status }) => ({ id, status })),
23899
+ recentEvents,
23900
+ redaction: {
23901
+ policy: "allowlist-v1",
23902
+ omitted: [
23903
+ "server URL host/path/query",
23904
+ "store/workspace/config paths",
23905
+ "control token and provider credentials",
23906
+ "task, prompt, tool input/output and approval text",
23907
+ "raw audit and quarantine contents"
23908
+ ],
23909
+ transformed: ["productName/productId/deviceId/runtimeId/quarantine filenames -> SHA-256", "audit events -> closed kind/timestamp only"]
23910
+ }
23911
+ };
23912
+ }
23913
+ async function writeSupportBundle(outputPath, bundle, secureFileOptions = {}) {
23914
+ const dir = path3__default.dirname(outputPath);
23915
+ const parentStat = await promises.stat(dir);
23916
+ if (!parentStat.isDirectory()) throw new Error("support bundle output parent is not a directory");
23917
+ const privateDir = path3__default.join(dir, `.${path3__default.basename(outputPath)}.${process.pid}.${randomUUID()}.private`);
23918
+ const tempPath = path3__default.join(privateDir, "bundle.tmp");
23919
+ try {
23920
+ await promises.mkdir(privateDir, { mode: 448 });
23921
+ await ensureSecureDir(privateDir, secureFileOptions);
23922
+ await atomicWriteFile(tempPath, `${JSON.stringify(bundle, null, 2)}
23923
+ `, { mode: 384, fsync: true });
23924
+ await ensureSecureFile(tempPath, secureFileOptions);
23925
+ await promises.link(tempPath, outputPath);
23926
+ const published = await promises.open(outputPath, "r+");
23927
+ try {
23928
+ await published.sync();
23929
+ } finally {
23930
+ await published.close();
23931
+ }
23932
+ if (process.platform !== "win32") {
23933
+ const parent = await promises.open(dir, "r");
23934
+ try {
23935
+ await parent.sync();
23936
+ } finally {
23937
+ await parent.close();
23938
+ }
23939
+ }
23940
+ } finally {
23941
+ await promises.rm(privateDir, { recursive: true, force: true }).catch(() => void 0);
23942
+ }
23943
+ }
23944
+
23945
+ // src/diagnostics/operator-actions.ts
23946
+ var MESSAGES2 = {
23947
+ "confirmation-required": "Explicit confirmation is required for this local maintenance action.",
23948
+ "invalid-input": "The maintenance action requires valid explicit inputs.",
23949
+ "daemon-running": "Stop the host daemon before local maintenance.",
23950
+ "store-busy": "Another operation owns the device store.",
23951
+ "agent-busy": "Another operation owns the Agent home.",
23952
+ "target-mismatch": "The stored device or Agent records do not match the authorized target.",
23953
+ "source-unavailable": "The local source cannot be accessed safely; preserve it for inspection.",
23954
+ "output-exists": "The selected output already exists; it will not be overwritten.",
23955
+ "operation-failed": "The maintenance operation did not complete; preserve evidence before retrying."
23956
+ };
23957
+ var DeviceOperatorError = class extends Error {
23958
+ constructor(code) {
23959
+ super(MESSAGES2[code]);
23960
+ this.code = code;
23961
+ this.name = "DeviceOperatorError";
23962
+ }
23963
+ code;
23964
+ };
23965
+ function requireConfirmation(input) {
23966
+ if (input?.confirmed !== true) throw new DeviceOperatorError("confirmation-required");
23967
+ }
23968
+ function closedError(error) {
23969
+ if (error instanceof DeviceOperatorError) return error;
23970
+ if (error instanceof DaemonOwnerActiveError) return new DeviceOperatorError("store-busy");
23971
+ if (error instanceof AgentHomeBusyError) return new DeviceOperatorError("agent-busy");
23972
+ return new DeviceOperatorError("operation-failed");
23973
+ }
23974
+ async function requireOffline(config, storeDir) {
23975
+ const control = await connectControlClient({ productId: config.productId, storeDir });
23976
+ if (control.ok) {
23977
+ control.client.close();
23978
+ throw new DeviceOperatorError("daemon-running");
23979
+ }
23980
+ }
23981
+ async function quarantineDeviceOperationalHealth(config, input) {
23982
+ requireConfirmation(input);
23983
+ try {
23984
+ const storeDir = DeviceStore.resolveDir(config.productId, config.storeDir);
23985
+ await requireOffline(config, storeDir);
23986
+ const result = await quarantineCorruptOperationalHealth(storeDir);
23987
+ return { action: "quarantine-operational-health", scope: "device", ...result };
23988
+ } catch (error) {
23989
+ throw closedError(error);
23990
+ }
23991
+ }
23992
+ async function exportDeviceSupportBundle(config, input) {
23993
+ if (typeof input?.outputPath !== "string" || !path3__default.isAbsolute(input.outputPath)) {
23994
+ throw new DeviceOperatorError("invalid-input");
23995
+ }
23996
+ try {
23997
+ const storeDir = DeviceStore.resolveDir(config.productId, config.storeDir);
23998
+ const bundle = await createSupportBundle(config, storeDir, {
23999
+ adapters: input.adapters,
24000
+ runtimeProbeTimeoutMs: input.runtimeProbeTimeoutMs
24001
+ });
24002
+ await writeSupportBundle(input.outputPath, bundle);
24003
+ return { action: "export-support-bundle", scope: "device", status: "written", bundleVersion: bundle.version };
24004
+ } catch (error) {
24005
+ if (error?.code === "EEXIST") throw new DeviceOperatorError("output-exists");
24006
+ throw closedError(error);
24007
+ }
24008
+ }
24009
+ async function existingOutbox(home) {
24010
+ const components = [
24011
+ home,
24012
+ path3__default.join(home, AGENT_HOME_INTERNAL_DIRECTORY),
24013
+ path3__default.join(home, AGENT_MESSAGE_DIRECTORY),
24014
+ path3__default.join(home, AGENT_MESSAGE_DIRECTORY, AGENT_MESSAGE_OUTBOX_FILENAME)
24015
+ ];
24016
+ for (let index = 0; index < components.length; index += 1) {
24017
+ let stat;
24018
+ try {
24019
+ stat = await promises.lstat(components[index]);
24020
+ } catch (error) {
24021
+ if (error.code === "ENOENT") return false;
24022
+ throw new DeviceOperatorError("source-unavailable");
24023
+ }
24024
+ if (stat.isSymbolicLink() || (index === components.length - 1 ? !stat.isFile() : !stat.isDirectory())) {
24025
+ throw new DeviceOperatorError("source-unavailable");
24026
+ }
24027
+ }
24028
+ return true;
24029
+ }
24030
+ async function archiveAgentTerminalMessages(config, input) {
24031
+ requireConfirmation(input);
24032
+ const parsedRef = AgentRefSchema.safeParse(input.agentRef);
24033
+ if (!parsedRef.success || !isTenantId(input.expectedTenantId) || typeof input.expectedDeviceId !== "string" || !input.expectedDeviceId.trim() || typeof input.archiveDirectory !== "string" || !path3__default.isAbsolute(input.archiveDirectory) || !config.agentHome) {
24034
+ throw new DeviceOperatorError("invalid-input");
24035
+ }
24036
+ const notNeeded = { action: "archive-terminal-messages", scope: "agent", status: "not-needed" };
24037
+ try {
24038
+ const storeDir = DeviceStore.resolveDir(config.productId, config.storeDir);
24039
+ await requireOffline(config, storeDir);
24040
+ const owner = await acquireDaemonOwner(storeDir, "doctor");
24041
+ try {
24042
+ const metadata = await new DeviceStore(storeDir, void 0, config.productId).load();
24043
+ if (!metadata || metadata.deviceId !== input.expectedDeviceId || metadata.tenantId !== input.expectedTenantId) {
24044
+ throw new DeviceOperatorError("target-mismatch");
24045
+ }
24046
+ const manager = new AgentHomeManager({
24047
+ hostStorageRoot: config.agentHome.hostStorageRoot,
24048
+ leaseManager: new AgentHomeLeaseManager({ ownerId: stableAgentHomeOwnerId(storeDir, config.productId) })
24049
+ });
24050
+ const home = await manager.layout.canonicalHomePath(parsedRef.data);
24051
+ if (!await existingOutbox(home)) return notNeeded;
24052
+ const binding = await manager.acquire(parsedRef.data);
24053
+ try {
24054
+ if (!await existingOutbox(binding.lease.cwd)) throw new DeviceOperatorError("source-unavailable");
24055
+ const outbox = await AgentMessageOutbox.open(binding.lease.cwd);
24056
+ const records = outbox.records();
24057
+ if (records.some((record3) => record3.tenantId !== input.expectedTenantId || record3.agentRef.agentId !== parsedRef.data.agentId)) {
24058
+ throw new DeviceOperatorError("target-mismatch");
24059
+ }
24060
+ const archivedRecords = outbox.terminalRecords().length;
24061
+ if (archivedRecords === 0) return notNeeded;
24062
+ try {
24063
+ await promises.mkdir(input.archiveDirectory, { mode: 448 });
24064
+ } catch (error) {
24065
+ if (error.code === "EEXIST") throw new DeviceOperatorError("output-exists");
24066
+ throw error;
24067
+ }
24068
+ const archivePath = await outbox.archiveTerminalRecords(input.archiveDirectory);
24069
+ if (!archivePath) throw new DeviceOperatorError("operation-failed");
24070
+ return {
24071
+ action: "archive-terminal-messages",
24072
+ scope: "agent",
24073
+ status: "archived",
24074
+ archivedRecords,
24075
+ archiveFileName: path3__default.basename(archivePath)
24076
+ };
24077
+ } finally {
24078
+ await binding.lease.release();
24079
+ }
24080
+ } finally {
24081
+ await owner.release();
24082
+ }
24083
+ } catch (error) {
24084
+ throw closedError(error);
24085
+ }
24086
+ }
23501
24087
 
23502
- 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, DeviceMetadataRepairError, 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, RuntimeStartupDisposalFailure, 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, diagnoseDevice, encodeTeamMemberContext, ensureSecureDir, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isAgentMemorySecureFilesystemAvailable, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, isRuntimeStartupDisposalFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, openTeamTmuxView, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, readDeviceEnrollmentStatus, repairDeviceEnrollmentMetadata, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, resolveSdkReservedHelperBin, runSdkReservedHelperCommand, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
24088
+ 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, DeviceMetadataRepairError, DeviceOperatorError, 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, RuntimeStartupDisposalFailure, 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, archiveAgentTerminalMessages, buildIcaclsArgs, cleanupEligibleAt, cleanupOrderFor, computePressureState, createAgentHomeProjection, createAgentHomeProjectionConsumer, createDaemon, createDaemonWithAdapters, createFilesystemCleanupExecutor, createServiceLifecycle, createStatfsFreeBytesProvider, decodeTeamMemberContext, diagnoseDevice, encodeTeamMemberContext, ensureSecureDir, exportDeviceSupportBundle, freezeRuntimeAdapterDescriptor, generateLaunchdPlist, generateSystemdUnit, generateWinswXml, installSkillPacks, isAgentMemorySecureFilesystemAvailable, isGitWorkspaceConfig, isRuntimeDisposalFailure, isRuntimeExecutionFailure, isRuntimeStartupDisposalFailure, journalHash, listInstalledSkillPacks, localStateRelocation, nodeAgentProgram, openTeamTmuxView, prependGitWorkspaceGuidance, projectRuntimeBoundaryFailure, projectRuntimeExecutionFailure, projectSkillPack, quarantineDeviceOperationalHealth, readDeviceEnrollmentStatus, repairDeviceEnrollmentMetadata, requestDeviceAssertion, resolveLocalAgentReleaseIdentity, resolveLocalStoragePolicy, resolveSdkReservedHelperBin, runSdkReservedHelperCommand, sanitizeServiceName, sealRuntimeOperationManifest, skillPacksRoot, stableAgentHomeOwnerId, validateAgentRef };
23503
24089
  //# sourceMappingURL=index.js.map
23504
24090
  //# sourceMappingURL=index.js.map