@byok-sdk/client 0.1.1 → 0.2.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,7 +1,7 @@
1
1
  import { execFile, spawn, spawnSync } from 'child_process';
2
2
  import { createHash, randomUUID, sign, createPrivateKey, generateKeyPairSync, randomBytes, createHmac, timingSafeEqual } from 'crypto';
3
- import { promises, mkdirSync, existsSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, linkSync, fstatSync, lstatSync, unlinkSync, constants, realpathSync } from 'fs';
4
- import path15, { join, isAbsolute } from 'path';
3
+ import { promises, mkdirSync, existsSync, renameSync, writeFileSync, chmodSync, statSync, readdirSync, linkSync, fstatSync, lstatSync, unlinkSync, constants, readFileSync, realpathSync } from 'fs';
4
+ import path16, { join, isAbsolute } from 'path';
5
5
  import os6 from 'os';
6
6
  import { partitionAgentEvents, TASK_TRANSITIONS, encodeEnvelope, createEnvelope, MAX_MESSAGES_PER_BATCH, RuntimeIdSchema, PROTOCOL_VERSION, decodeEnvelope, MessagesSendResponseSchema, parseMessage, UnknownMessageTypeError } from '@byok-sdk/protocol';
7
7
  import { promisify } from 'util';
@@ -71,7 +71,7 @@ function gitEnvironment(readOnly) {
71
71
  return env;
72
72
  }
73
73
  function stableGitWorkspaceOwnerId(storeDir, productId) {
74
- const identity = `${path15.resolve(storeDir)}\\0${productId}`;
74
+ const identity = `${path16.resolve(storeDir)}\\0${productId}`;
75
75
  return `store-product:${createHash("sha256").update(identity).digest("hex")}`;
76
76
  }
77
77
  var GUIDANCE = [
@@ -83,11 +83,11 @@ var GUIDANCE = [
83
83
  "Leave incomplete work visible for recovery."
84
84
  ].join("\n");
85
85
  function canonical(value) {
86
- return path15.resolve(value);
86
+ return path16.resolve(value);
87
87
  }
88
88
  function isContained(root, candidate) {
89
- const relative = path15.relative(root, candidate);
90
- return relative === "" || !relative.startsWith(`..${path15.sep}`) && !path15.isAbsolute(relative);
89
+ const relative = path16.relative(root, candidate);
90
+ return relative === "" || !relative.startsWith(`..${path16.sep}`) && !path16.isAbsolute(relative);
91
91
  }
92
92
  function bounded(value, max) {
93
93
  return Buffer.byteLength(value, "utf8") <= max ? value : value.slice(0, max);
@@ -192,7 +192,7 @@ var GitWorkspaceManager = class {
192
192
  await this.ensureOwnerMarker();
193
193
  }
194
194
  async ensureOwnerMarker() {
195
- const markerPath = path15.join(this.workspaceRoot, OWNER_MARKER);
195
+ const markerPath = path16.join(this.workspaceRoot, OWNER_MARKER);
196
196
  let existing;
197
197
  try {
198
198
  existing = JSON.parse(await promises.readFile(markerPath, "utf8"));
@@ -351,7 +351,7 @@ ${instruction}`;
351
351
  if (error instanceof GitWorkspaceError || code !== "ENOENT" && code !== "ENOTDIR") {
352
352
  throw new GitWorkspaceError("workspace-root-invalid", "workspace directory is invalid");
353
353
  }
354
- const parent = path15.dirname(current);
354
+ const parent = path16.dirname(current);
355
355
  if (parent === current) {
356
356
  throw new GitWorkspaceError("workspace-root-invalid", "workspace directory is invalid");
357
357
  }
@@ -416,7 +416,7 @@ async function atomicWriteFile(filePath, data, options = {}) {
416
416
  await target.close();
417
417
  }
418
418
  if (process.platform !== "win32") {
419
- const directory = await promises.open(path15.dirname(filePath), "r");
419
+ const directory = await promises.open(path16.dirname(filePath), "r");
420
420
  try {
421
421
  await directory.sync();
422
422
  } finally {
@@ -541,7 +541,7 @@ function isProtected(record) {
541
541
  var GitWorkspaceStore = class {
542
542
  constructor(storeDir, options = {}) {
543
543
  this.storeDir = storeDir;
544
- this.filePath = path15.join(storeDir, FILE_NAME);
544
+ this.filePath = path16.join(storeDir, FILE_NAME);
545
545
  this.maxRecords = Math.max(1, Math.floor(options.maxRecords ?? MAX_RECORDS));
546
546
  }
547
547
  storeDir;
@@ -671,20 +671,50 @@ var GitWorkspaceStore = class {
671
671
  await atomicWriteFile(this.filePath, JSON.stringify(ledger, null, 2), { mode: 384 });
672
672
  }
673
673
  };
674
-
675
- // src/adapters/pi/resolve-bin.ts
676
674
  var PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
675
+ function readPackageJson(dir) {
676
+ const candidate = path16.join(dir, "package.json");
677
+ if (!existsSync(candidate)) return void 0;
678
+ try {
679
+ return JSON.parse(readFileSync(candidate, "utf8"));
680
+ } catch {
681
+ return void 0;
682
+ }
683
+ }
677
684
  function resolvePiBin() {
678
685
  const override = process.env.BYOK_PI_BIN;
679
686
  if (override) {
680
- return { command: override, source: "path" };
687
+ return { command: override, source: "env" };
681
688
  }
682
- return { command: "pi", source: "path" };
689
+ try {
690
+ const mainEntryUrl = import.meta.resolve(PI_PACKAGE_NAME);
691
+ let dir = path16.dirname(fileURLToPath(mainEntryUrl));
692
+ for (let depth = 0; depth < 6; depth++) {
693
+ const pkg = readPackageJson(dir);
694
+ if (pkg?.name === PI_PACKAGE_NAME) {
695
+ const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.pi;
696
+ if (binRel) {
697
+ return { command: path16.join(dir, binRel), source: "package" };
698
+ }
699
+ break;
700
+ }
701
+ const parent = path16.dirname(dir);
702
+ if (parent === dir) break;
703
+ dir = parent;
704
+ }
705
+ } catch (cause) {
706
+ throw new Error(
707
+ `Required ${PI_PACKAGE_NAME} could not be resolved; install @byok-sdk/client dependencies or set BYOK_PI_BIN to a Node 22.19+ pi sidecar`,
708
+ { cause }
709
+ );
710
+ }
711
+ throw new Error(
712
+ `Required ${PI_PACKAGE_NAME} does not expose the pi CLI; reinstall the pinned dependency or set BYOK_PI_BIN to a Node 22.19+ pi sidecar`
713
+ );
683
714
  }
684
715
 
685
716
  // src/adapters/pi/permission-mapping.ts
686
717
  var READONLY_TOOLS = ["read", "grep", "find", "ls"];
687
- var DEFAULT_ACTIVE_TOOLS = ["read", "bash", "edit", "write"];
688
718
  function mapPermissionPolicyToPiArgs(policy) {
689
719
  if (policy.network === false) {
690
720
  return {
@@ -703,22 +733,18 @@ function mapPermissionPolicyToPiArgs(policy) {
703
733
  const denyTools = policy.denyTools ?? [];
704
734
  if (policy.mode === "readonly") {
705
735
  const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS.includes(tool)) : [...READONLY_TOOLS];
706
- const effective = subtractDenied(base, denyTools);
707
- return { ok: true, args: effective.length === 0 ? ["--no-tools"] : ["--tools", effective.join(",")] };
708
- }
709
- if (denyTools.length > 0) {
710
- const base = policy.allowTools && policy.allowTools.length > 0 ? policy.allowTools : [...DEFAULT_ACTIVE_TOOLS];
711
- const effective = subtractDenied(base, denyTools);
712
- return { ok: true, args: effective.length === 0 ? ["--no-tools"] : ["--tools", effective.join(",")] };
736
+ if (base.length === 0) return { ok: true, args: ["--no-tools"] };
737
+ return {
738
+ ok: true,
739
+ args: ["--tools", base.join(","), ...denyTools.length > 0 ? ["--exclude-tools", denyTools.join(",")] : []]
740
+ };
713
741
  }
742
+ const args = [];
714
743
  if (policy.allowTools && policy.allowTools.length > 0) {
715
- return { ok: true, args: ["--tools", policy.allowTools.join(",")] };
744
+ args.push("--tools", policy.allowTools.join(","));
716
745
  }
717
- return { ok: true, args: [] };
718
- }
719
- function subtractDenied(tools, denyTools) {
720
- const denied = new Set(denyTools);
721
- return tools.filter((tool) => !denied.has(tool));
746
+ if (denyTools.length > 0) args.push("--exclude-tools", denyTools.join(","));
747
+ return { ok: true, args };
722
748
  }
723
749
 
724
750
  // src/adapters/pi/events.ts
@@ -743,7 +769,7 @@ function mapPiMessageToAgentEvent(msg) {
743
769
  output: { result: msg.result, isError: msg.isError === true }
744
770
  };
745
771
  }
746
- case "agent_end":
772
+ case "agent_settled":
747
773
  return { type: "turn_end" };
748
774
  /**
749
775
  * `artifact` is NOT a real pi RPC message — pi's own `write` tool only
@@ -779,16 +805,22 @@ function mapPiMessageToAgentEvent(msg) {
779
805
  // `recordUnmappedFrame`) can tell "known, expected, silently ignored"
780
806
  // apart from "genuinely never seen before" (falls to `default` below).
781
807
  case "agent_start":
808
+ case "agent_end":
809
+ // one low-level run; `agent_settled` is BYOK completion
782
810
  case "turn_start":
783
811
  case "turn_end":
784
- // pi's own per-LLM-turn boundary, not ours — see `agent_end` above
812
+ // pi's own per-LLM-turn boundary, not ours
785
813
  case "message_start":
786
814
  case "message_end":
815
+ case "bash_execution_update":
787
816
  case "tool_execution_update":
788
817
  case "queue_update":
789
818
  case "compaction_start":
790
819
  case "compaction_end":
791
820
  case "auto_retry_start":
821
+ case "summarization_retry_scheduled":
822
+ case "summarization_retry_attempt_start":
823
+ case "summarization_retry_finished":
792
824
  case "session_info_changed":
793
825
  case "thinking_level_changed":
794
826
  return void 0;
@@ -798,15 +830,20 @@ function mapPiMessageToAgentEvent(msg) {
798
830
  }
799
831
  var ROUTINE_PI_EVENT_TYPES = /* @__PURE__ */ new Set([
800
832
  "agent_start",
833
+ "agent_end",
801
834
  "turn_start",
802
835
  "turn_end",
803
836
  "message_start",
804
837
  "message_end",
838
+ "bash_execution_update",
805
839
  "tool_execution_update",
806
840
  "queue_update",
807
841
  "compaction_start",
808
842
  "compaction_end",
809
843
  "auto_retry_start",
844
+ "summarization_retry_scheduled",
845
+ "summarization_retry_attempt_start",
846
+ "summarization_retry_finished",
810
847
  "session_info_changed",
811
848
  "thinking_level_changed"
812
849
  ]);
@@ -940,10 +977,7 @@ var PiRpcClient = class {
940
977
  * traffic. Logs once per distinct type (not per occurrence, so a
941
978
  * repeating unmapped type can't spam stdout); the running tally is also
942
979
  * folded into this client's exit-time error message (`buildExitError`) so
943
- * a post-mortem on a failed/hung task has it without needing separate log
944
- * scraping. This is the exact mechanism that would have turned this
945
- * task's root-cause hang (`agent_end` arriving with no mapping) into a
946
- * one-line, immediate warning instead of a silent stall.
980
+ * a post-mortem on a failed/hung task has it without separate log scraping.
947
981
  */
948
982
  recordUnmappedFrame(type) {
949
983
  const next = (this.unmappedFrameCounts.get(type) ?? 0) + 1;
@@ -1084,8 +1118,8 @@ var PiAdapter = class {
1084
1118
  options;
1085
1119
  id = "pi";
1086
1120
  async detect() {
1087
- const bin = this.resolveBin();
1088
1121
  try {
1122
+ const bin = this.resolveBin();
1089
1123
  const { stdout, stderr } = await execFileAsync(bin.command, ["--version"], { timeout: DETECT_TIMEOUT_MS });
1090
1124
  const version = stdout.trim() || stderr.trim();
1091
1125
  const authPresent = KNOWN_PROVIDER_ENV_VARS.some((name) => process.env[name] !== void 0);
@@ -1231,7 +1265,7 @@ function resolveApprovalMcpBin() {
1231
1265
  if (override) {
1232
1266
  return { command: override, args: [], source: "env" };
1233
1267
  }
1234
- const distBin = path15.join(path15.dirname(fileURLToPath(import.meta.url)), "bin", "byok-approval-mcp.js");
1268
+ const distBin = path16.join(path16.dirname(fileURLToPath(import.meta.url)), "bin", "byok-approval-mcp.js");
1235
1269
  return { command: process.execPath, args: [distBin], source: "dist" };
1236
1270
  }
1237
1271
 
@@ -1262,7 +1296,7 @@ function mapPermissionPolicyToClaudeArgs(policy) {
1262
1296
  }
1263
1297
  if (policy.mode === "readonly") {
1264
1298
  const base = policy.allowTools ? policy.allowTools.filter((tool) => READONLY_TOOLS2.includes(tool)) : [...READONLY_TOOLS2];
1265
- const effective = subtractDenied2(base, denyTools);
1299
+ const effective = subtractDenied(base, denyTools);
1266
1300
  return { ok: true, args: ["--permission-mode", "default", "--tools", effective.join(",")] };
1267
1301
  }
1268
1302
  if (denyTools.length > 0) {
@@ -1279,7 +1313,7 @@ function mapPermissionPolicyToClaudeArgs(policy) {
1279
1313
  }
1280
1314
  return { ok: true, args };
1281
1315
  }
1282
- function subtractDenied2(tools, denyTools) {
1316
+ function subtractDenied(tools, denyTools) {
1283
1317
  const denied = new Set(denyTools);
1284
1318
  return tools.filter((tool) => !denied.has(tool));
1285
1319
  }
@@ -1311,7 +1345,7 @@ var EXTENSION_CONTENT_TYPES = {
1311
1345
  ".yml": "application/yaml"
1312
1346
  };
1313
1347
  function guessContentType(filePath) {
1314
- const ext = path15.extname(filePath).toLowerCase();
1348
+ const ext = path16.extname(filePath).toLowerCase();
1315
1349
  return EXTENSION_CONTENT_TYPES[ext] ?? "application/octet-stream";
1316
1350
  }
1317
1351
  function mapAssistant(msg, correlation) {
@@ -1383,11 +1417,11 @@ function tryBuildArtifactEvent(msg, workspaceDir) {
1383
1417
  const filePath = toolUseResult && typeof toolUseResult.filePath === "string" ? toolUseResult.filePath : void 0;
1384
1418
  if (!filePath) return void 0;
1385
1419
  const realWorkspaceDir = tryRealpath(workspaceDir) ?? workspaceDir;
1386
- const fileDir = path15.dirname(filePath);
1420
+ const fileDir = path16.dirname(filePath);
1387
1421
  const realFileDir = tryRealpath(fileDir) ?? fileDir;
1388
- const realFilePath = path15.join(realFileDir, path15.basename(filePath));
1389
- const relative = path15.relative(realWorkspaceDir, realFilePath);
1390
- if (relative === "" || relative.startsWith("..") || path15.isAbsolute(relative)) {
1422
+ const realFilePath = path16.join(realFileDir, path16.basename(filePath));
1423
+ const relative = path16.relative(realWorkspaceDir, realFilePath);
1424
+ if (relative === "" || relative.startsWith("..") || path16.isAbsolute(relative)) {
1391
1425
  return void 0;
1392
1426
  }
1393
1427
  return { type: "artifact", name: relative, contentType: guessContentType(filePath) };
@@ -1686,10 +1720,10 @@ var ClaudeAdapter = class {
1686
1720
  );
1687
1721
  }
1688
1722
  const approvalMcpBin = (this.options.resolveApprovalMcpBin ?? resolveApprovalMcpBin)();
1689
- approvalMcpConfigDir = await promises.mkdtemp(path15.join(os6.tmpdir(), "byok-approval-mcp-"));
1723
+ approvalMcpConfigDir = await promises.mkdtemp(path16.join(os6.tmpdir(), "byok-approval-mcp-"));
1690
1724
  await promises.chmod(approvalMcpConfigDir, 448).catch(() => {
1691
1725
  });
1692
- const mcpConfigPath = path15.join(approvalMcpConfigDir, "mcp-config.json");
1726
+ const mcpConfigPath = path16.join(approvalMcpConfigDir, "mcp-config.json");
1693
1727
  const mcpConfig = {
1694
1728
  mcpServers: {
1695
1729
  [APPROVAL_MCP_SERVER_NAME]: {
@@ -2036,8 +2070,8 @@ function extractArtifactEvents(changes, workspaceDir) {
2036
2070
  const absolutePath = typeof change.path === "string" ? change.path : void 0;
2037
2071
  const kind = typeof change.kind === "string" ? change.kind : void 0;
2038
2072
  if (!absolutePath || kind === "delete") continue;
2039
- const relative = path15.relative(workspaceDir, absolutePath);
2040
- if (relative.length === 0 || relative.startsWith("..") || path15.isAbsolute(relative)) continue;
2073
+ const relative = path16.relative(workspaceDir, absolutePath);
2074
+ if (relative.length === 0 || relative.startsWith("..") || path16.isAbsolute(relative)) continue;
2041
2075
  events.push({ type: "artifact", name: relative, contentType: guessContentType2(relative) });
2042
2076
  }
2043
2077
  return events;
@@ -2058,7 +2092,7 @@ var CONTENT_TYPE_BY_EXTENSION = {
2058
2092
  ".csv": "text/csv"
2059
2093
  };
2060
2094
  function guessContentType2(relativePath) {
2061
- return CONTENT_TYPE_BY_EXTENSION[path15.extname(relativePath).toLowerCase()] ?? "application/octet-stream";
2095
+ return CONTENT_TYPE_BY_EXTENSION[path16.extname(relativePath).toLowerCase()] ?? "application/octet-stream";
2062
2096
  }
2063
2097
  function extractErrorMessage(rawError) {
2064
2098
  if (typeof rawError === "string") return rawError;
@@ -2219,9 +2253,10 @@ var CodexAdapter = class {
2219
2253
  * Two independently-verified channel gotchas apply here, the "pi lesson"
2220
2254
  * yet again:
2221
2255
  * - `codex login status`'s human-readable "Logged in using ChatGPT"
2222
- * message prints on STDERR, not stdout (the opposite-channel
2223
- * counterpart of pi's own `--version`-goes-to-stderr surprise) both
2224
- * streams are checked here for exactly that reason.
2256
+ * message prints on STDERR, not stdout both streams are checked
2257
+ * here for exactly that reason. pi's `--version` is the same class of
2258
+ * hazard from the other direction: its channel has moved between pi
2259
+ * releases (see ../pi/pi-adapter.ts), so neither stream is assumed.
2225
2260
  * - The NOT-logged-in message/exit-code shape was deliberately never
2226
2261
  * empirically tested: this machine has a real, live ChatGPT login, and
2227
2262
  * running `codex logout` to observe the negative case would have
@@ -2664,12 +2699,12 @@ var DeviceStore = class _DeviceStore {
2664
2699
  */
2665
2700
  constructor(storeDir, secureDirOptions) {
2666
2701
  this.secureDirOptions = secureDirOptions;
2667
- this.filePath = path15.join(storeDir, "device.json");
2702
+ this.filePath = path16.join(storeDir, "device.json");
2668
2703
  }
2669
2704
  secureDirOptions;
2670
2705
  filePath;
2671
2706
  static defaultDir(productId) {
2672
- return path15.join(os6.homedir(), ".byok", productId);
2707
+ return path16.join(os6.homedir(), ".byok", productId);
2673
2708
  }
2674
2709
  /**
2675
2710
  * Resolve the one store pathname every daemon/CLI component must share.
@@ -2678,7 +2713,7 @@ var DeviceStore = class _DeviceStore {
2678
2713
  * cwd to pin a quarantine directory inode.
2679
2714
  */
2680
2715
  static resolveDir(productId, configured) {
2681
- return path15.resolve(configured ?? _DeviceStore.defaultDir(productId));
2716
+ return path16.resolve(configured ?? _DeviceStore.defaultDir(productId));
2682
2717
  }
2683
2718
  async load() {
2684
2719
  const opened = await this.openBounded();
@@ -2719,7 +2754,7 @@ var DeviceStore = class _DeviceStore {
2719
2754
  }
2720
2755
  }
2721
2756
  async save(record) {
2722
- const storeDir = path15.dirname(this.filePath);
2757
+ const storeDir = path16.dirname(this.filePath);
2723
2758
  await ensureSecureDir(storeDir, this.secureDirOptions);
2724
2759
  await atomicWriteFile(this.filePath, JSON.stringify(record, null, 2), { mode: 384 });
2725
2760
  }
@@ -3153,19 +3188,19 @@ function shortHash(input) {
3153
3188
  return createHash("sha256").update(input, "utf8").digest("hex").slice(0, 16);
3154
3189
  }
3155
3190
  function controlSocketPath(storeDir) {
3156
- const candidate = path15.join(storeDir, "control.sock");
3191
+ const candidate = path16.join(storeDir, "control.sock");
3157
3192
  if (Buffer.byteLength(candidate, "utf8") <= UNIX_SOCKET_PATH_SOFT_LIMIT) return candidate;
3158
- return path15.join(os6.tmpdir(), `byok-${shortHash(storeDir)}`, "sock");
3193
+ return path16.join(os6.tmpdir(), `byok-${shortHash(storeDir)}`, "sock");
3159
3194
  }
3160
3195
  function controlPipeName(productId, storeDir) {
3161
- const id = shortHash(`${productId}|${path15.resolve(storeDir)}`);
3196
+ const id = shortHash(`${productId}|${path16.resolve(storeDir)}`);
3162
3197
  return `\\\\.\\pipe\\byok-${id}`;
3163
3198
  }
3164
3199
  function controlEndpointPath(productId, storeDir, platform = process.platform) {
3165
3200
  return platform === "win32" ? controlPipeName(productId, storeDir) : controlSocketPath(storeDir);
3166
3201
  }
3167
3202
  function controlTokenPath(storeDir) {
3168
- return path15.join(storeDir, "control.token");
3203
+ return path16.join(storeDir, "control.token");
3169
3204
  }
3170
3205
  var SERVER_PROOF_LABEL = "byok-control-server|";
3171
3206
  var CLIENT_AUTH_LABEL = "byok-control-client|";
@@ -3310,7 +3345,7 @@ async function assertOwnedPrivateDir(dir) {
3310
3345
  }
3311
3346
  async function bindControlEndpoint(server, endpoint) {
3312
3347
  if (process.platform !== "win32") {
3313
- const endpointDir = path15.dirname(endpoint);
3348
+ const endpointDir = path16.dirname(endpoint);
3314
3349
  await promises.mkdir(endpointDir, { recursive: true, mode: 448 });
3315
3350
  await promises.chmod(endpointDir, 448).catch(() => {
3316
3351
  });
@@ -4591,7 +4626,7 @@ function sameFileState2(left, right) {
4591
4626
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs;
4592
4627
  }
4593
4628
  async function openOperationalHealthFile(storeDir) {
4594
- const filePath = path15.join(storeDir, OPERATIONAL_HEALTH_FILENAME);
4629
+ const filePath = path16.join(storeDir, OPERATIONAL_HEALTH_FILENAME);
4595
4630
  let namedBefore;
4596
4631
  try {
4597
4632
  namedBefore = await promises.lstat(filePath, { bigint: true });
@@ -4633,7 +4668,7 @@ var OperationalHealthTracker = class {
4633
4668
  #writeTail = Promise.resolve();
4634
4669
  #started = false;
4635
4670
  constructor(storeDir, options = {}) {
4636
- this.#filePath = path15.join(storeDir, OPERATIONAL_HEALTH_FILENAME);
4671
+ this.#filePath = path16.join(storeDir, OPERATIONAL_HEALTH_FILENAME);
4637
4672
  this.#windowMs = options.windowMs ?? 6e4;
4638
4673
  this.#failureThreshold = options.failureThreshold ?? 3;
4639
4674
  this.#maxFailures = options.maxFailures ?? 128;
@@ -4720,7 +4755,7 @@ var OperationalHealthTracker = class {
4720
4755
  async #load() {
4721
4756
  let opened;
4722
4757
  try {
4723
- opened = await openOperationalHealthFile(path15.dirname(this.#filePath));
4758
+ opened = await openOperationalHealthFile(path16.dirname(this.#filePath));
4724
4759
  } catch (err) {
4725
4760
  throw new Error("operational health state could not be read");
4726
4761
  }
@@ -4756,7 +4791,7 @@ var OperationalHealthTracker = class {
4756
4791
  if (!this.#state) return;
4757
4792
  const body = JSON.stringify(this.#state, null, 2);
4758
4793
  this.#writeTail = this.#writeTail.then(async () => {
4759
- await ensureSecureDir(path15.dirname(this.#filePath));
4794
+ await ensureSecureDir(path16.dirname(this.#filePath));
4760
4795
  await atomicWriteFile(this.#filePath, body, { mode: 384, fsync: true });
4761
4796
  });
4762
4797
  try {
@@ -5075,8 +5110,8 @@ async function acquireDaemonOwner(storeDir, role, clock = () => /* @__PURE__ */
5075
5110
  await mutex.close().catch(() => void 0);
5076
5111
  throw err;
5077
5112
  }
5078
- const ownerPath = path15.join(storeDir, DAEMON_OWNER_FILENAME);
5079
- const reclaimPath = path15.join(storeDir, RECLAIM_FILENAME);
5113
+ const ownerPath = path16.join(storeDir, DAEMON_OWNER_FILENAME);
5114
+ const reclaimPath = path16.join(storeDir, RECLAIM_FILENAME);
5080
5115
  const record = {
5081
5116
  version: 2,
5082
5117
  pid: process.pid,
@@ -5153,7 +5188,7 @@ var CursorStore = class {
5153
5188
  storeDir;
5154
5189
  fileFor(serverUrl, deviceId) {
5155
5190
  const key = createHash("sha256").update(`${serverUrl}::${deviceId}`).digest("hex").slice(0, 32);
5156
- return path15.join(this.storeDir, `cursor-${key}.json`);
5191
+ return path16.join(this.storeDir, `cursor-${key}.json`);
5157
5192
  }
5158
5193
  async load(serverUrl, deviceId) {
5159
5194
  let raw;
@@ -5173,7 +5208,7 @@ var CursorStore = class {
5173
5208
  }
5174
5209
  async save(serverUrl, deviceId, cursor) {
5175
5210
  const file = this.fileFor(serverUrl, deviceId);
5176
- await promises.mkdir(path15.dirname(file), { recursive: true, mode: 448 });
5211
+ await promises.mkdir(path16.dirname(file), { recursive: true, mode: 448 });
5177
5212
  await atomicWriteFile(file, JSON.stringify({ cursor }));
5178
5213
  }
5179
5214
  /** Remove any persisted cursor for (serverUrl, deviceId) — a no-op if none exists. Called from `pair()` (finding F5) so a device that's about to be replaced never leaves a cursor a future, unrelated device could somehow inherit. */
@@ -5469,7 +5504,7 @@ var SessionWorkspaceStore = class {
5469
5504
  */
5470
5505
  queue = Promise.resolve();
5471
5506
  constructor(storeDir) {
5472
- this.filePath = path15.join(storeDir, "session-workspaces.json");
5507
+ this.filePath = path16.join(storeDir, "session-workspaces.json");
5473
5508
  }
5474
5509
  async get(sessionRef) {
5475
5510
  return this.enqueue(async () => {
@@ -5527,7 +5562,7 @@ var SessionWorkspaceStore = class {
5527
5562
  }
5528
5563
  }
5529
5564
  async save(all) {
5530
- const dir = path15.dirname(this.filePath);
5565
+ const dir = path16.dirname(this.filePath);
5531
5566
  await promises.mkdir(dir, { recursive: true, mode: 448 });
5532
5567
  const tmpPath = `${this.filePath}.${process.pid}-${tmpSeq2++}.tmp`;
5533
5568
  try {
@@ -5632,9 +5667,9 @@ function isSqliteAvailable() {
5632
5667
  }
5633
5668
  }
5634
5669
  var SECURE_FILE_MODE = 384;
5635
- function openJournalDatabase(path19, busyTimeoutMs, faults) {
5670
+ function openJournalDatabase(path20, busyTimeoutMs, faults) {
5636
5671
  const { DatabaseSync } = loadSqliteModule();
5637
- const db = new DatabaseSync(path19, { timeout: busyTimeoutMs });
5672
+ const db = new DatabaseSync(path20, { timeout: busyTimeoutMs });
5638
5673
  try {
5639
5674
  faults?.onStep?.("after-open");
5640
5675
  db.exec("PRAGMA auto_vacuum = INCREMENTAL;");
@@ -5777,9 +5812,9 @@ var RECEIVED_STATE = "received";
5777
5812
  function byteLength(value) {
5778
5813
  return Buffer.byteLength(value, "utf8");
5779
5814
  }
5780
- function fileBytes(path19) {
5815
+ function fileBytes(path20) {
5781
5816
  try {
5782
- return statSync(path19).size;
5817
+ return statSync(path20).size;
5783
5818
  } catch {
5784
5819
  return 0;
5785
5820
  }
@@ -7033,8 +7068,8 @@ function estimateEventBytes(event) {
7033
7068
  }
7034
7069
  async function openArtifact(workspaceDir, name) {
7035
7070
  const realWorkspaceDir = await promises.realpath(workspaceDir).catch(() => workspaceDir);
7036
- const candidate = path15.resolve(realWorkspaceDir, name);
7037
- const prefix = realWorkspaceDir.endsWith(path15.sep) ? realWorkspaceDir : realWorkspaceDir + path15.sep;
7071
+ const candidate = path16.resolve(realWorkspaceDir, name);
7072
+ const prefix = realWorkspaceDir.endsWith(path16.sep) ? realWorkspaceDir : realWorkspaceDir + path16.sep;
7038
7073
  if (candidate !== realWorkspaceDir && !candidate.startsWith(prefix)) {
7039
7074
  return { ok: false, reason: `artifact name "${name}" resolves outside the task workspace \u2014 rejected` };
7040
7075
  }
@@ -7432,7 +7467,7 @@ var TaskRunner = class {
7432
7467
  const sameProtocolTask = ledger?.taskId === taskId;
7433
7468
  const interruptedOldTask = ledger?.phase === "interrupted" && sameProtocolTask;
7434
7469
  const activeDifferentTask = ledger !== void 0 && ledger.taskId !== taskId && (ledger.phase === "preparing" || ledger.phase === "active");
7435
- if (!known || known.workspaceKind !== "git" || !known.gitWorkspaceId || !ledger || ledger.workspaceId !== known.gitWorkspaceId || ledger.sessionRef !== payload.sessionRef || path15.resolve(ledger.workspaceDir) !== path15.resolve(known.workspaceDir) || interruptedOldTask || activeDifferentTask) {
7470
+ if (!known || known.workspaceKind !== "git" || !known.gitWorkspaceId || !ledger || ledger.workspaceId !== known.gitWorkspaceId || ledger.sessionRef !== payload.sessionRef || path16.resolve(ledger.workspaceDir) !== path16.resolve(known.workspaceDir) || interruptedOldTask || activeDifferentTask) {
7436
7471
  this.decline(taskId, "session is incompatible with Git workspace mode", true);
7437
7472
  return;
7438
7473
  }
@@ -7447,7 +7482,7 @@ var TaskRunner = class {
7447
7482
  return;
7448
7483
  }
7449
7484
  } else {
7450
- workspaceDir = path15.join(this.deps.workspaceRoot, taskId);
7485
+ workspaceDir = path16.join(this.deps.workspaceRoot, taskId);
7451
7486
  }
7452
7487
  try {
7453
7488
  gitLease = await gitManager.acquireLease(workspaceDir, payload.sessionRef);
@@ -7457,7 +7492,7 @@ var TaskRunner = class {
7457
7492
  }
7458
7493
  } else if (!this.deps.gitWorkspaceManager && !this.deps.gitWorkspaceStore) {
7459
7494
  known = payload.sessionRef ? await this.deps.sessionWorkspaces.get(payload.sessionRef) : void 0;
7460
- workspaceDir = known?.workspaceDir ?? path15.join(this.deps.workspaceRoot, taskId);
7495
+ workspaceDir = known?.workspaceDir ?? path16.join(this.deps.workspaceRoot, taskId);
7461
7496
  plainWorkspaceNeedsResolve = true;
7462
7497
  } else {
7463
7498
  this.decline(taskId, "workspace mode is unavailable", true);
@@ -8329,7 +8364,7 @@ var TaskRunner = class {
8329
8364
  }
8330
8365
  /** `reuseDir`, when set (a known sessionRef's recorded workspace), is used verbatim instead of a fresh `workspaceRoot/<taskId>` directory — `mkdir recursive` is idempotent either way, so ensuring-exists is safe to do unconditionally. */
8331
8366
  async resolveWorkspaceDir(taskId, reuseDir) {
8332
- const dir = reuseDir ?? path15.join(this.deps.workspaceRoot, taskId);
8367
+ const dir = reuseDir ?? path16.join(this.deps.workspaceRoot, taskId);
8333
8368
  await promises.mkdir(dir, { recursive: true });
8334
8369
  return dir;
8335
8370
  }
@@ -9231,8 +9266,8 @@ var TruthMemoryClient = class {
9231
9266
  #requestId;
9232
9267
  #allowedObjectDownloadOrigins;
9233
9268
  async listManifest(query = {}) {
9234
- const path19 = manifestPath(query);
9235
- const response = await this.#proofFetch(path19, {
9269
+ const path20 = manifestPath(query);
9270
+ const response = await this.#proofFetch(path20, {
9236
9271
  method: "GET",
9237
9272
  operation: "truth.list",
9238
9273
  resource: "records",
@@ -9339,9 +9374,9 @@ var TruthMemoryClient = class {
9339
9374
  }
9340
9375
  async #write(kind, recordKey, requestId, payload, expectedPrimary, expectedSnapshots) {
9341
9376
  assertDistinctExpectedWrites([expectedPrimary, ...expectedSnapshots]);
9342
- const path19 = recordPath(kind, recordKey);
9377
+ const path20 = recordPath(kind, recordKey);
9343
9378
  const body = new TextEncoder().encode(JSON.stringify(payload));
9344
- const response = await this.#proofFetch(path19, {
9379
+ const response = await this.#proofFetch(path20, {
9345
9380
  method: "PUT",
9346
9381
  operation: "truth.write",
9347
9382
  resource: `${kind}/${recordKey}`,
@@ -9367,8 +9402,8 @@ var TruthMemoryClient = class {
9367
9402
  };
9368
9403
  }
9369
9404
  async #readVerified(listed) {
9370
- const path19 = recordPath(listed.kind, listed.recordKey);
9371
- const response = await this.#proofFetch(path19, {
9405
+ const path20 = recordPath(listed.kind, listed.recordKey);
9406
+ const response = await this.#proofFetch(path20, {
9372
9407
  method: "GET",
9373
9408
  operation: "truth.read",
9374
9409
  resource: `${listed.kind}/${listed.recordKey}`,
@@ -9429,16 +9464,16 @@ var TruthMemoryClient = class {
9429
9464
  }
9430
9465
  return { ...listed, bytes };
9431
9466
  }
9432
- async #proofFetch(path19, request) {
9467
+ async #proofFetch(path20, request) {
9433
9468
  const proof = await this.options.signer.sign({
9434
9469
  method: request.method,
9435
- path: path19,
9470
+ path: path20,
9436
9471
  operation: request.operation,
9437
9472
  resource: request.resource,
9438
9473
  requestId: request.requestId,
9439
9474
  body: request.body
9440
9475
  });
9441
- const response = await this.#fetch(new URL(path19, this.#base), {
9476
+ const response = await this.#fetch(new URL(path20, this.#base), {
9442
9477
  method: request.method,
9443
9478
  headers: {
9444
9479
  ...request.headers,
@@ -9449,7 +9484,7 @@ var TruthMemoryClient = class {
9449
9484
  if (!response.ok) {
9450
9485
  throw new TruthMemoryClientError(
9451
9486
  "truth_http_failed",
9452
- `truth request ${request.method} ${path19} failed with HTTP ${response.status}`,
9487
+ `truth request ${request.method} ${path20} failed with HTTP ${response.status}`,
9453
9488
  response.status
9454
9489
  );
9455
9490
  }
@@ -9708,8 +9743,8 @@ function generateLaunchdPlist(def) {
9708
9743
  const { label, program, logDir } = def;
9709
9744
  const args = [program.command, ...program.args];
9710
9745
  const cwd = program.cwd ?? os6.homedir();
9711
- const outLog = path15.join(logDir, `${label}.out.log`);
9712
- const errLog = path15.join(logDir, `${label}.err.log`);
9746
+ const outLog = path16.join(logDir, `${label}.out.log`);
9747
+ const errLog = path16.join(logDir, `${label}.err.log`);
9713
9748
  return `<?xml version="1.0" encoding="UTF-8"?>
9714
9749
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
9715
9750
  <plist version="1.0">
@@ -9750,7 +9785,7 @@ function createLaunchdLifecycle(def, deps = {}) {
9750
9785
  return process.getuid();
9751
9786
  });
9752
9787
  const label = sanitizeServiceName(def.name);
9753
- const plistPath = () => path15.join(homedir(), "Library", "LaunchAgents", `${label}.plist`);
9788
+ const plistPath = () => path16.join(homedir(), "Library", "LaunchAgents", `${label}.plist`);
9754
9789
  const domainTarget = () => `gui/${getuid()}`;
9755
9790
  const serviceTarget = () => `${domainTarget()}/${label}`;
9756
9791
  async function fileExists(p) {
@@ -9763,7 +9798,7 @@ function createLaunchdLifecycle(def, deps = {}) {
9763
9798
  }
9764
9799
  async function writePlist(program) {
9765
9800
  const xml = generateLaunchdPlist({ label, program, logDir: def.logDir });
9766
- await fs15.mkdir(path15.dirname(plistPath()), { recursive: true });
9801
+ await fs15.mkdir(path16.dirname(plistPath()), { recursive: true });
9767
9802
  await fs15.mkdir(def.logDir, { recursive: true });
9768
9803
  await fs15.writeFile(plistPath(), xml, "utf8");
9769
9804
  }
@@ -9837,8 +9872,8 @@ function generateSystemdUnit(def) {
9837
9872
  assertNoControlChars(displayName, "displayName");
9838
9873
  const cwd = program.cwd ?? os6.homedir();
9839
9874
  assertNoControlChars(cwd, "program.cwd");
9840
- const outLog = path15.join(logDir, `${name}.out.log`);
9841
- const errLog = path15.join(logDir, `${name}.err.log`);
9875
+ const outLog = path16.join(logDir, `${name}.out.log`);
9876
+ const errLog = path16.join(logDir, `${name}.err.log`);
9842
9877
  assertNoControlChars(outLog, "logDir");
9843
9878
  assertNoControlChars(errLog, "logDir");
9844
9879
  const execStart = [program.command, ...program.args].map(quoteSystemdArg).join(" ");
@@ -9864,7 +9899,7 @@ function createSystemdLifecycle(def, deps = {}) {
9864
9899
  const homedir = deps.homedir ?? (() => os6.homedir());
9865
9900
  const name = sanitizeServiceName(def.name);
9866
9901
  const unitName = `${name}.service`;
9867
- const unitPath = () => path15.join(homedir(), ".config", "systemd", "user", unitName);
9902
+ const unitPath = () => path16.join(homedir(), ".config", "systemd", "user", unitName);
9868
9903
  async function fileExists(p) {
9869
9904
  try {
9870
9905
  await fs15.stat(p);
@@ -9875,7 +9910,7 @@ function createSystemdLifecycle(def, deps = {}) {
9875
9910
  }
9876
9911
  async function writeUnit(program) {
9877
9912
  const unit = generateSystemdUnit({ name, displayName: def.displayName ?? def.name, program, logDir: def.logDir });
9878
- await fs15.mkdir(path15.dirname(unitPath()), { recursive: true });
9913
+ await fs15.mkdir(path16.dirname(unitPath()), { recursive: true });
9879
9914
  await fs15.mkdir(def.logDir, { recursive: true });
9880
9915
  await fs15.writeFile(unitPath(), unit, "utf8");
9881
9916
  }
@@ -9957,8 +9992,8 @@ function createWinswLifecycle(def, deps = {}) {
9957
9992
  const winswBin = windows.winswBin;
9958
9993
  const id = sanitizeServiceName(def.name);
9959
9994
  const installDir = windows.installDir ?? def.logDir;
9960
- const exePath = path15.join(installDir, `${id}.exe`);
9961
- const xmlPath = path15.join(installDir, `${id}.xml`);
9995
+ const exePath = path16.join(installDir, `${id}.exe`);
9996
+ const xmlPath = path16.join(installDir, `${id}.xml`);
9962
9997
  async function fileExists(p) {
9963
9998
  try {
9964
9999
  await fs15.stat(p);