@guilz-dev/belay 0.9.4 → 0.10.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.
Files changed (49) hide show
  1. package/README.md +3 -2
  2. package/dist/adapters/cursor/hook-dispatch-entry.d.ts +3 -0
  3. package/dist/adapters/cursor/hook-dispatch-entry.js +11 -0
  4. package/dist/adapters/cursor/hook-router.js +14 -7
  5. package/dist/adapters/cursor/hooks.d.ts +1 -1
  6. package/dist/adapters/cursor/hooks.js +16 -5
  7. package/dist/adapters/cursor/routing-config-trust.d.ts +1 -0
  8. package/dist/adapters/cursor/routing-config-trust.js +67 -0
  9. package/dist/adapters/cursor/runtime-entry.d.ts +2 -2
  10. package/dist/adapters/cursor/runtime-entry.js +35 -10
  11. package/dist/adapters/shared/gate-runtime.js +28 -17
  12. package/dist/bundle/claude-runtime.mjs +602 -438
  13. package/dist/bundle/codex-runtime.mjs +612 -448
  14. package/dist/bundle/cursor-dispatcher.mjs +100 -26
  15. package/dist/bundle/cursor-runtime.mjs +662 -470
  16. package/dist/cli.js +53 -4
  17. package/dist/commands/approval-token.d.ts +10 -0
  18. package/dist/commands/approval-token.js +26 -0
  19. package/dist/commands/audit.d.ts +2 -1
  20. package/dist/commands/audit.js +2 -2
  21. package/dist/commands/config.d.ts +1 -1
  22. package/dist/commands/config.js +28 -2
  23. package/dist/commands/doctor.js +10 -54
  24. package/dist/commands/dogfood-check.d.ts +3 -0
  25. package/dist/commands/dogfood-check.js +116 -0
  26. package/dist/commands/dogfood.d.ts +1 -0
  27. package/dist/commands/dogfood.js +4 -3
  28. package/dist/commands/judge.js +2 -2
  29. package/dist/commands/recovery-checkpoints.js +2 -11
  30. package/dist/config-io.d.ts +1 -0
  31. package/dist/config-io.js +8 -1
  32. package/dist/core/dogfood-environment.d.ts +8 -0
  33. package/dist/core/dogfood-environment.js +55 -0
  34. package/dist/core/effect-ir/shell-lower/decoders/belay.js +12 -0
  35. package/dist/core/egress-approval.js +0 -18
  36. package/dist/core/notify.d.ts +8 -2
  37. package/dist/core/notify.js +63 -7
  38. package/dist/core/recovery/operator-guidance.js +4 -4
  39. package/dist/core/repo-config-trust.d.ts +31 -0
  40. package/dist/core/repo-config-trust.js +152 -0
  41. package/dist/corpus/benign-probe-cores.d.ts +1 -1
  42. package/dist/corpus/benign-probe-cores.js +0 -1
  43. package/dist/defaults.js +0 -25
  44. package/dist/installer/scope-config.js +2 -2
  45. package/dist/installer.js +4 -4
  46. package/dist/types.d.ts +19 -0
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/package.json +5 -1
@@ -3510,9 +3510,122 @@ var init_config_layers = __esm({
3510
3510
  }
3511
3511
  });
3512
3512
 
3513
- // src/config-io.ts
3513
+ // src/core/repo-config-trust.ts
3514
3514
  import { existsSync as existsSync2 } from "node:fs";
3515
- import { chmod, mkdir as mkdir2, open as open2, readFile as readFile2, rename, unlink as unlink2, writeFile } from "node:fs/promises";
3515
+ import { chmod, mkdir as mkdir2, open as open2, readFile as readFile2, rename, unlink as unlink2 } from "node:fs/promises";
3516
+ import path11 from "node:path";
3517
+ function isObjectRecord(value) {
3518
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3519
+ }
3520
+ function hasOnlyExpectedKeys(value) {
3521
+ const expected = /* @__PURE__ */ new Set([
3522
+ "schemaVersion",
3523
+ "repoRoot",
3524
+ "adapter",
3525
+ "repoConfigFingerprint",
3526
+ "trustedAt"
3527
+ ]);
3528
+ const keys = Object.keys(value);
3529
+ if (keys.length !== expected.size) {
3530
+ return false;
3531
+ }
3532
+ return keys.every((key) => expected.has(key));
3533
+ }
3534
+ function isAdapterName(value) {
3535
+ return value === "cursor" || value === "claude" || value === "codex";
3536
+ }
3537
+ function isIsoTimestamp(value) {
3538
+ return Number.isFinite(Date.parse(value));
3539
+ }
3540
+ function parseStrictTrustRecord(value) {
3541
+ if (!isObjectRecord(value) || !hasOnlyExpectedKeys(value)) {
3542
+ return null;
3543
+ }
3544
+ if (value.schemaVersion !== 1) {
3545
+ return null;
3546
+ }
3547
+ if (typeof value.repoRoot !== "string" || value.repoRoot.trim().length === 0) {
3548
+ return null;
3549
+ }
3550
+ if (!isAdapterName(value.adapter)) {
3551
+ return null;
3552
+ }
3553
+ if (typeof value.repoConfigFingerprint !== "string" || !/^[a-f0-9]{64}$/.test(value.repoConfigFingerprint)) {
3554
+ return null;
3555
+ }
3556
+ if (typeof value.trustedAt !== "string" || !isIsoTimestamp(value.trustedAt)) {
3557
+ return null;
3558
+ }
3559
+ return {
3560
+ schemaVersion: 1,
3561
+ repoRoot: value.repoRoot,
3562
+ adapter: value.adapter,
3563
+ repoConfigFingerprint: value.repoConfigFingerprint,
3564
+ trustedAt: value.trustedAt
3565
+ };
3566
+ }
3567
+ function repoConfigFingerprint(rawConfig) {
3568
+ return hashValue(canonicalStringify(rawConfig));
3569
+ }
3570
+ function repoConfigTrustPath(repoRoot, adapter) {
3571
+ const canonicalRepoRoot = canonicalPath(repoRoot);
3572
+ const identity = hashValue(`${canonicalRepoRoot}\0${adapter}`);
3573
+ return path11.join(defaultControlPlaneDir(), "config-trust", `${identity}.json`);
3574
+ }
3575
+ async function inspectRepoConfigTrust(repoRoot, adapter, rawConfig) {
3576
+ const canonicalRepoRoot = canonicalPath(repoRoot);
3577
+ const recordPath = repoConfigTrustPath(repoRoot, adapter);
3578
+ if (!existsSync2(recordPath)) {
3579
+ return { trusted: false, recordPath, reason: "missing" };
3580
+ }
3581
+ let parsed;
3582
+ try {
3583
+ parsed = JSON.parse(await readFile2(recordPath, "utf8"));
3584
+ } catch {
3585
+ return { trusted: false, recordPath, reason: "malformed" };
3586
+ }
3587
+ const record = parseStrictTrustRecord(parsed);
3588
+ if (!record) {
3589
+ return { trusted: false, recordPath, reason: "malformed" };
3590
+ }
3591
+ if (record.adapter !== adapter || canonicalPath(record.repoRoot) !== canonicalRepoRoot) {
3592
+ return { trusted: false, recordPath, reason: "identity_mismatch" };
3593
+ }
3594
+ const fingerprint = repoConfigFingerprint(rawConfig);
3595
+ if (record.repoConfigFingerprint !== fingerprint) {
3596
+ return { trusted: false, recordPath, reason: "fingerprint_mismatch" };
3597
+ }
3598
+ return { trusted: true, recordPath, fingerprint };
3599
+ }
3600
+ async function assertRepoConfigTrusted(repoRoot, adapter, rawConfig) {
3601
+ const status = await inspectRepoConfigTrust(repoRoot, adapter, rawConfig);
3602
+ if (status.trusted) {
3603
+ return;
3604
+ }
3605
+ throw new RepoConfigTrustError(status);
3606
+ }
3607
+ var TRUST_MESSAGE, RepoConfigTrustError;
3608
+ var init_repo_config_trust = __esm({
3609
+ "src/core/repo-config-trust.ts"() {
3610
+ "use strict";
3611
+ init_config();
3612
+ init_fingerprint2();
3613
+ init_path_utils();
3614
+ TRUST_MESSAGE = "Repository config is not trusted. Review it, then run `belay config trust`.";
3615
+ RepoConfigTrustError = class extends Error {
3616
+ status;
3617
+ constructor(status) {
3618
+ super(TRUST_MESSAGE);
3619
+ this.name = "RepoConfigTrustError";
3620
+ this.status = status;
3621
+ }
3622
+ };
3623
+ }
3624
+ });
3625
+
3626
+ // src/config-io.ts
3627
+ import { existsSync as existsSync3 } from "node:fs";
3628
+ import { chmod as chmod2, mkdir as mkdir3, open as open3, readFile as readFile3, rename as rename2, unlink as unlink3, writeFile } from "node:fs/promises";
3516
3629
  function resolveAdapterName(config) {
3517
3630
  if (config.adapter === "claude") {
3518
3631
  return "claude";
@@ -3523,10 +3636,10 @@ function resolveAdapterName(config) {
3523
3636
  return "cursor";
3524
3637
  }
3525
3638
  function detectAdapterName(repoRoot) {
3526
- if (existsSync2(configPathFor(repoRoot, "claude"))) {
3639
+ if (existsSync3(configPathFor(repoRoot, "claude"))) {
3527
3640
  return "claude";
3528
3641
  }
3529
- if (existsSync2(configPathFor(repoRoot, "codex"))) {
3642
+ if (existsSync3(configPathFor(repoRoot, "codex"))) {
3530
3643
  return "codex";
3531
3644
  }
3532
3645
  return "cursor";
@@ -3541,20 +3654,20 @@ async function loadLayeredConfig(repoRoot, adapter = detectAdapterName(repoRoot)
3541
3654
  const layout = getAdapterLayout(adapter);
3542
3655
  const configPath = configPathFor(repoRoot, adapter);
3543
3656
  let repoConfig = {};
3544
- if (existsSync2(configPath)) {
3545
- repoConfig = JSON.parse(await readFile2(configPath, "utf8"));
3657
+ if (existsSync3(configPath)) {
3658
+ repoConfig = JSON.parse(await readFile3(configPath, "utf8"));
3546
3659
  }
3547
3660
  let teamConfig = null;
3548
3661
  const teamPath = teamConfigPath();
3549
- if (existsSync2(teamPath)) {
3550
- teamConfig = JSON.parse(await readFile2(teamPath, "utf8"));
3662
+ if (existsSync3(teamPath)) {
3663
+ teamConfig = JSON.parse(await readFile3(teamPath, "utf8"));
3551
3664
  }
3552
3665
  return resolveLayeredConfig({
3553
3666
  repoConfig,
3554
3667
  adapterDefaults: layout.defaultConfig(repoRoot),
3555
3668
  teamConfig,
3556
3669
  teamConfigPath: teamPath,
3557
- repoConfigPath: existsSync2(configPath) ? configPath : void 0
3670
+ repoConfigPath: existsSync3(configPath) ? configPath : void 0
3558
3671
  });
3559
3672
  }
3560
3673
  async function loadConfigFile(repoRoot, adapter = detectAdapterName(repoRoot)) {
@@ -3569,21 +3682,22 @@ var init_config_io = __esm({
3569
3682
  init_approval_state_mutation();
3570
3683
  init_config();
3571
3684
  init_config_layers();
3685
+ init_repo_config_trust();
3572
3686
  }
3573
3687
  });
3574
3688
 
3575
3689
  // src/adapters/codex/runtime-entry.ts
3576
3690
  init_codex();
3577
- import path63 from "node:path";
3691
+ import path65 from "node:path";
3578
3692
  import process2 from "node:process";
3579
3693
 
3580
3694
  // src/adapters/shared/gate-runtime.ts
3581
3695
  init_approval();
3582
3696
  init_approval_replay();
3583
3697
  import { randomUUID as randomUUID6 } from "node:crypto";
3584
- import { existsSync as existsSync16 } from "node:fs";
3585
- import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile11 } from "node:fs/promises";
3586
- import path61 from "node:path";
3698
+ import { existsSync as existsSync17 } from "node:fs";
3699
+ import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile11 } from "node:fs/promises";
3700
+ import path63 from "node:path";
3587
3701
 
3588
3702
  // src/core/approval-service.ts
3589
3703
  init_config_io();
@@ -3593,47 +3707,35 @@ init_approval_replay();
3593
3707
  // src/core/approval-token.ts
3594
3708
  init_config();
3595
3709
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
3596
- import { existsSync as existsSync3 } from "node:fs";
3597
- import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
3598
- import path11 from "node:path";
3599
- function base64UrlEncode(value) {
3600
- return Buffer.from(value, "utf8").toString("base64url");
3601
- }
3710
+ import { existsSync as existsSync4 } from "node:fs";
3711
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
3712
+ import path12 from "node:path";
3602
3713
  function base64UrlDecode(value) {
3603
3714
  return Buffer.from(value, "base64url").toString("utf8");
3604
3715
  }
3605
3716
  function approvalSigningKeyPath(controlPlaneDir = defaultControlPlaneDir()) {
3606
- return path11.join(controlPlaneDir, "approval-signing.key");
3717
+ return path12.join(controlPlaneDir, "approval-signing.key");
3607
3718
  }
3608
3719
  async function loadOrCreateApprovalSigningKey(controlPlaneDir = defaultControlPlaneDir()) {
3609
3720
  const keyPath = approvalSigningKeyPath(controlPlaneDir);
3610
- if (existsSync3(keyPath)) {
3611
- return readFile3(keyPath);
3721
+ if (existsSync4(keyPath)) {
3722
+ return readFile4(keyPath);
3612
3723
  }
3613
- await mkdir3(controlPlaneDir, { recursive: true });
3724
+ await mkdir4(controlPlaneDir, { recursive: true });
3614
3725
  const key = randomBytes(32);
3615
3726
  await writeFile2(keyPath, key, { mode: 384 });
3616
3727
  return key;
3617
3728
  }
3618
- function signPayload(payload, key) {
3619
- const body = base64UrlEncode(JSON.stringify(payload));
3620
- const signature = createHmac("sha256", key).update(body).digest("base64url");
3621
- return `${body}.${signature}`;
3622
- }
3623
- async function issueApprovalToken(payload, controlPlaneDir = defaultControlPlaneDir()) {
3624
- const key = await loadOrCreateApprovalSigningKey(controlPlaneDir);
3625
- return signPayload(payload, key);
3626
- }
3627
3729
  async function verifyApprovalToken(token, controlPlaneDir = defaultControlPlaneDir()) {
3628
3730
  const [body, signature] = token.split(".");
3629
3731
  if (!body || !signature) {
3630
3732
  return null;
3631
3733
  }
3632
3734
  const keyPath = approvalSigningKeyPath(controlPlaneDir);
3633
- if (!existsSync3(keyPath)) {
3735
+ if (!existsSync4(keyPath)) {
3634
3736
  return null;
3635
3737
  }
3636
- const key = await readFile3(keyPath);
3738
+ const key = await readFile4(keyPath);
3637
3739
  const expected = createHmac("sha256", key).update(body).digest("base64url");
3638
3740
  const actualBuffer = Buffer.from(signature);
3639
3741
  const expectedBuffer = Buffer.from(expected);
@@ -3840,11 +3942,11 @@ init_approval_v3();
3840
3942
 
3841
3943
  // src/core/capability/boundary-attestation-sign.ts
3842
3944
  import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
3843
- import { access, readFile as readFile4 } from "node:fs/promises";
3945
+ import { access, readFile as readFile5 } from "node:fs/promises";
3844
3946
  init_fingerprint2();
3845
3947
 
3846
3948
  // src/core/capability/attestation.ts
3847
- import path12 from "node:path";
3949
+ import path13 from "node:path";
3848
3950
  var BOUNDARY_ATTESTATION_VERSION = 1;
3849
3951
  var CONTAINED_EXECUTION_ATTESTATION_VERSION = 1;
3850
3952
  var KNOWN_DRIVERS = /* @__PURE__ */ new Set([
@@ -3912,7 +4014,7 @@ function validateContainedExecutionAttestation(value) {
3912
4014
  const record = value;
3913
4015
  const dockerSubstrate = record.dockerSubstrate;
3914
4016
  const dockerConfiguration = record.dockerConfiguration;
3915
- if (record.version !== CONTAINED_EXECUTION_ATTESTATION_VERSION || typeof record.imageId !== "string" || !/^sha256:[a-f0-9]{64}$/i.test(record.imageId) || typeof record.imageReference !== "string" || !record.imageReference || /[\0\n\r]/.test(record.imageReference) || record.networkNone !== true || record.isolatesWorkspaceMirror !== true || record.readOnlyRoot !== true || record.sanitizedEnvironment !== true || !isRecord(dockerSubstrate) || typeof dockerSubstrate.binaryPath !== "string" || !path12.isAbsolute(dockerSubstrate.binaryPath) || /[\0\n\r]/.test(dockerSubstrate.binaryPath) || typeof dockerSubstrate.binarySha256 !== "string" || !/^[a-f0-9]{64}$/.test(dockerSubstrate.binarySha256) || typeof dockerSubstrate.endpoint !== "string" || !dockerSubstrate.endpoint.startsWith("unix:///") || !path12.isAbsolute(dockerSubstrate.endpoint.slice("unix://".length)) || /[\0\n\r]/.test(dockerSubstrate.endpoint) || typeof dockerSubstrate.daemonId !== "string" || !dockerSubstrate.daemonId || /[\0\n\r]/.test(dockerSubstrate.daemonId) || !isRecord(dockerConfiguration) || typeof dockerConfiguration.executable !== "string" || !path12.isAbsolute(dockerConfiguration.executable) || /[\0\n\r]/.test(dockerConfiguration.executable) || typeof dockerConfiguration.host !== "string" || !dockerConfiguration.host.startsWith("unix:///") || !path12.isAbsolute(dockerConfiguration.host.slice("unix://".length)) || /[\0\n\r]/.test(dockerConfiguration.host) || typeof record.user !== "string" || !/^\d+:\d+$/.test(record.user) || record.entrypoint !== "/bin/sh" || record.capDropAll !== true || record.noNewPrivileges !== true || record.logDriver !== "none" || record.proxyEnvironment !== "neutralized-empty" || typeof record.probedAt !== "string" || typeof record.expiresAt !== "string") {
4017
+ if (record.version !== CONTAINED_EXECUTION_ATTESTATION_VERSION || typeof record.imageId !== "string" || !/^sha256:[a-f0-9]{64}$/i.test(record.imageId) || typeof record.imageReference !== "string" || !record.imageReference || /[\0\n\r]/.test(record.imageReference) || record.networkNone !== true || record.isolatesWorkspaceMirror !== true || record.readOnlyRoot !== true || record.sanitizedEnvironment !== true || !isRecord(dockerSubstrate) || typeof dockerSubstrate.binaryPath !== "string" || !path13.isAbsolute(dockerSubstrate.binaryPath) || /[\0\n\r]/.test(dockerSubstrate.binaryPath) || typeof dockerSubstrate.binarySha256 !== "string" || !/^[a-f0-9]{64}$/.test(dockerSubstrate.binarySha256) || typeof dockerSubstrate.endpoint !== "string" || !dockerSubstrate.endpoint.startsWith("unix:///") || !path13.isAbsolute(dockerSubstrate.endpoint.slice("unix://".length)) || /[\0\n\r]/.test(dockerSubstrate.endpoint) || typeof dockerSubstrate.daemonId !== "string" || !dockerSubstrate.daemonId || /[\0\n\r]/.test(dockerSubstrate.daemonId) || !isRecord(dockerConfiguration) || typeof dockerConfiguration.executable !== "string" || !path13.isAbsolute(dockerConfiguration.executable) || /[\0\n\r]/.test(dockerConfiguration.executable) || typeof dockerConfiguration.host !== "string" || !dockerConfiguration.host.startsWith("unix:///") || !path13.isAbsolute(dockerConfiguration.host.slice("unix://".length)) || /[\0\n\r]/.test(dockerConfiguration.host) || typeof record.user !== "string" || !/^\d+:\d+$/.test(record.user) || record.entrypoint !== "/bin/sh" || record.capDropAll !== true || record.noNewPrivileges !== true || record.logDriver !== "none" || record.proxyEnvironment !== "neutralized-empty" || typeof record.probedAt !== "string" || typeof record.expiresAt !== "string") {
3916
4018
  return false;
3917
4019
  }
3918
4020
  const probedAt = Date.parse(record.probedAt);
@@ -3982,7 +4084,7 @@ async function verifySignedBoundaryAttestation(params) {
3982
4084
  return record.attestation;
3983
4085
  }
3984
4086
  async function readSignedAttestationFile(filePath) {
3985
- return JSON.parse(await readFile4(filePath, "utf8"));
4087
+ return JSON.parse(await readFile5(filePath, "utf8"));
3986
4088
  }
3987
4089
 
3988
4090
  // src/core/capability/boundary-egress.ts
@@ -4151,13 +4253,13 @@ async function runWithBoundaryRunnable(target, params) {
4151
4253
  }
4152
4254
 
4153
4255
  // src/core/capability/boundary-session.ts
4154
- import path23 from "node:path";
4256
+ import path24 from "node:path";
4155
4257
 
4156
4258
  // src/services/egress-service.ts
4157
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
4158
- import { mkdir as mkdir4, readFile as readFile5, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
4259
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
4260
+ import { mkdir as mkdir5, readFile as readFile6, unlink as unlink4, writeFile as writeFile3 } from "node:fs/promises";
4159
4261
  import net from "node:net";
4160
- import path13 from "node:path";
4262
+ import path14 from "node:path";
4161
4263
  init_config_io();
4162
4264
  init_config();
4163
4265
 
@@ -4170,16 +4272,16 @@ function egressStatePaths(repoRoot, config) {
4170
4272
  const stateDir = belayStateDir(config, repoLocalStateDirFor(repoRoot, config));
4171
4273
  return {
4172
4274
  stateDir,
4173
- pidPath: path13.join(stateDir, "egress-proxy.pid"),
4174
- statusPath: path13.join(stateDir, "egress-proxy.json")
4275
+ pidPath: path14.join(stateDir, "egress-proxy.pid"),
4276
+ statusPath: path14.join(stateDir, "egress-proxy.json")
4175
4277
  };
4176
4278
  }
4177
4279
  async function readStatusFile(statusPath) {
4178
- if (!existsSync4(statusPath)) {
4280
+ if (!existsSync5(statusPath)) {
4179
4281
  return null;
4180
4282
  }
4181
4283
  try {
4182
- const raw = JSON.parse(await readFile5(statusPath, "utf8"));
4284
+ const raw = JSON.parse(await readFile6(statusPath, "utf8"));
4183
4285
  if (typeof raw.pid !== "number") {
4184
4286
  return null;
4185
4287
  }
@@ -4197,9 +4299,9 @@ async function readStatusFile(statusPath) {
4197
4299
  async function isPortOpen(host, port) {
4198
4300
  return new Promise((resolve) => {
4199
4301
  const socket = net.createConnection({ host, port });
4200
- const finish = (open6) => {
4302
+ const finish = (open7) => {
4201
4303
  socket.destroy();
4202
- resolve(open6);
4304
+ resolve(open7);
4203
4305
  };
4204
4306
  socket.setTimeout(300);
4205
4307
  socket.on("connect", () => finish(true));
@@ -4210,7 +4312,7 @@ async function isPortOpen(host, port) {
4210
4312
  async function resolveLiveEgressStatus(repoRoot, config) {
4211
4313
  const { statusPath } = egressStatePaths(repoRoot, config);
4212
4314
  const statusCandidates = [statusPath];
4213
- const controlPlaneStatus = path13.join(configuredControlPlaneDir(config), "egress-proxy.json");
4315
+ const controlPlaneStatus = path14.join(configuredControlPlaneDir(config), "egress-proxy.json");
4214
4316
  if (!statusCandidates.includes(controlPlaneStatus)) {
4215
4317
  statusCandidates.push(controlPlaneStatus);
4216
4318
  }
@@ -4236,7 +4338,7 @@ function isProcessAlive(pid) {
4236
4338
  }
4237
4339
  }
4238
4340
  async function egressStatus(options = {}) {
4239
- const repoRoot = path13.resolve(options.targetDir ?? process.cwd());
4341
+ const repoRoot = path14.resolve(options.targetDir ?? process.cwd());
4240
4342
  const config = await loadConfigFile(repoRoot);
4241
4343
  const { status, host, port, portOccupied } = await resolveLiveEgressStatus(repoRoot, config);
4242
4344
  const ownedRunning = Boolean(status);
@@ -4267,7 +4369,7 @@ init_config();
4267
4369
  import { createHash as createHash8, randomUUID as randomUUID2 } from "node:crypto";
4268
4370
  import { createReadStream as createReadStream2 } from "node:fs";
4269
4371
  import { access as access2, constants as constants2, lstat as lstat4, mkdtemp as mkdtemp2, realpath as realpath2, rm as rm2 } from "node:fs/promises";
4270
- import path18 from "node:path";
4372
+ import path19 from "node:path";
4271
4373
  init_fingerprint2();
4272
4374
  init_path_utils();
4273
4375
 
@@ -4446,7 +4548,7 @@ function runProcessWithBoundedOutput(file, args, options, timeoutMs, outputPolic
4446
4548
  }
4447
4549
 
4448
4550
  // src/core/contained-execution/docker-policy.ts
4449
- import path14 from "node:path";
4551
+ import path15 from "node:path";
4450
4552
 
4451
4553
  // src/core/contained-execution/policy.ts
4452
4554
  var CONTAINED_EXECUTION_APPROVAL_FALLBACK_REASONS = [
@@ -4575,7 +4677,7 @@ var PROXY_ENV_NAMES = [
4575
4677
  var IMAGE_ID_PATTERN = /^sha256:[a-f0-9]{64}$/;
4576
4678
  var SAFE_CONTAINER_NAME = /^belay-contained-[0-9a-f-]{36}$/;
4577
4679
  function assertSafeDockerPath(value, code) {
4578
- if (!path14.isAbsolute(value) || /[\0\n\r,]/.test(value)) {
4680
+ if (!path15.isAbsolute(value) || /[\0\n\r,]/.test(value)) {
4579
4681
  throw new ContainedExecutionFailureError(code);
4580
4682
  }
4581
4683
  }
@@ -4654,11 +4756,11 @@ init_path_utils();
4654
4756
  import { createHash as createHash7 } from "node:crypto";
4655
4757
  import { constants as fsConstants } from "node:fs";
4656
4758
  import {
4657
- chmod as chmod2,
4759
+ chmod as chmod3,
4658
4760
  lstat as lstat3,
4659
- mkdir as mkdir5,
4761
+ mkdir as mkdir6,
4660
4762
  mkdtemp,
4661
- open as open3,
4763
+ open as open4,
4662
4764
  opendir,
4663
4765
  readlink as readlink2,
4664
4766
  realpath,
@@ -4666,41 +4768,41 @@ import {
4666
4768
  symlink
4667
4769
  } from "node:fs/promises";
4668
4770
  import os from "node:os";
4669
- import path17 from "node:path";
4771
+ import path18 from "node:path";
4670
4772
 
4671
4773
  // src/core/transactional/file-tree.ts
4672
4774
  import { createHash as createHash6 } from "node:crypto";
4673
4775
  import { lstat as lstat2, readdir } from "node:fs/promises";
4674
- import path16 from "node:path";
4776
+ import path17 from "node:path";
4675
4777
 
4676
4778
  // src/core/transactional/file-tree-path.ts
4677
4779
  init_path_utils();
4678
- import path15 from "node:path";
4780
+ import path16 from "node:path";
4679
4781
  var FILE_CHECKPOINT_PATH_ESCAPE = "file_checkpoint_path_escape";
4680
4782
  function validateRelativePath(relativePath) {
4681
4783
  if (!relativePath || relativePath.includes("\0")) {
4682
4784
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4683
4785
  }
4684
- if (path15.isAbsolute(relativePath)) {
4786
+ if (path16.isAbsolute(relativePath)) {
4685
4787
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4686
4788
  }
4687
4789
  if (isPathOutsideRoot(relativePath)) {
4688
4790
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4689
4791
  }
4690
- const normalized = path15.normalize(relativePath);
4691
- if (normalized === ".." || normalized.startsWith(`..${path15.sep}`)) {
4792
+ const normalized = path16.normalize(relativePath);
4793
+ if (normalized === ".." || normalized.startsWith(`..${path16.sep}`)) {
4692
4794
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4693
4795
  }
4694
4796
  }
4695
4797
  function joinRelativePath(root, relativePath) {
4696
4798
  validateRelativePath(relativePath);
4697
- return path15.join(canonicalPath(root), relativePath);
4799
+ return path16.join(canonicalPath(root), relativePath);
4698
4800
  }
4699
4801
  function isRootGitMetadataPath(relativePath) {
4700
- return relativePath === ".git" || relativePath.startsWith(`.git${path15.sep}`);
4802
+ return relativePath === ".git" || relativePath.startsWith(`.git${path16.sep}`);
4701
4803
  }
4702
4804
  function isNestedGitPath(relativePath) {
4703
- const segments = relativePath.split(path15.sep).filter(Boolean);
4805
+ const segments = relativePath.split(path16.sep).filter(Boolean);
4704
4806
  if (segments.length === 0) {
4705
4807
  return false;
4706
4808
  }
@@ -4867,7 +4969,7 @@ async function readPresentNode(absolutePath, counters) {
4867
4969
  async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters, quotas, deadlineMs, entries) {
4868
4970
  assertWithinDeadline(deadlineMs);
4869
4971
  assertWithinQuotas(counters, quotas);
4870
- const absoluteDir = relativeDir ? joinRelativePath(resourceRoot, relativeDir) : path16.resolve(resourceRoot);
4972
+ const absoluteDir = relativeDir ? joinRelativePath(resourceRoot, relativeDir) : path17.resolve(resourceRoot);
4871
4973
  const dirInfo = await lstat2(absoluteDir);
4872
4974
  if (!dirInfo.isDirectory()) {
4873
4975
  throw new Error(FILE_CHECKPOINT_UNSUPPORTED_NODE);
@@ -4893,7 +4995,7 @@ async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters,
4893
4995
  const names = await readdir(absoluteDir);
4894
4996
  for (const name of names) {
4895
4997
  assertWithinDeadline(deadlineMs);
4896
- const childRelative = relativeDir ? path16.join(relativeDir, name) : name;
4998
+ const childRelative = relativeDir ? path17.join(relativeDir, name) : name;
4897
4999
  validateRelativePath(childRelative);
4898
5000
  if (isNestedGitPath(childRelative)) {
4899
5001
  throw new Error(FILE_CHECKPOINT_NESTED_REPOSITORY);
@@ -4901,7 +5003,7 @@ async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters,
4901
5003
  if (isExcludedTreePath(childRelative, excludedRoots, resourceRoot)) {
4902
5004
  continue;
4903
5005
  }
4904
- const childAbsolute = path16.join(absoluteDir, name);
5006
+ const childAbsolute = path17.join(absoluteDir, name);
4905
5007
  const childInfo = await lstat2(childAbsolute);
4906
5008
  if (childInfo.isDirectory() && !childInfo.isSymbolicLink()) {
4907
5009
  await walkDirectory(
@@ -5012,16 +5114,16 @@ function validateContainedExecutionMirrorLease(handle, expected) {
5012
5114
  );
5013
5115
  }
5014
5116
  var productionDependencies = {
5015
- makeTempRoot: () => mkdtemp(path17.join(os.tmpdir(), "belay-contained-mirror-")),
5117
+ makeTempRoot: () => mkdtemp(path18.join(os.tmpdir(), "belay-contained-mirror-")),
5016
5118
  removeRoot: (root) => rm(root, { recursive: true, force: true }),
5017
5119
  now: () => Date.now()
5018
5120
  };
5019
5121
  function isAtOrWithin(root, target) {
5020
- const relative = path17.relative(root, target);
5021
- return relative === "" || !path17.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path17.sep}`);
5122
+ const relative = path18.relative(root, target);
5123
+ return relative === "" || !path18.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path18.sep}`);
5022
5124
  }
5023
5125
  function isGitMetadataRelativePath(relativePath) {
5024
- return relativePath.split(path17.sep).some((segment) => segment.toLowerCase() === ".git");
5126
+ return relativePath.split(path18.sep).some((segment) => segment.toLowerCase() === ".git");
5025
5127
  }
5026
5128
  function identityFromStats(stats) {
5027
5129
  return {
@@ -5103,7 +5205,7 @@ async function readStableFile(absolutePath, context) {
5103
5205
  if (before.nlink > 1n) {
5104
5206
  throw new Error(FILE_CHECKPOINT_HARDLINK_UNSUPPORTED);
5105
5207
  }
5106
- const source = await open3(absolutePath, safeReadFlags());
5208
+ const source = await open4(absolutePath, safeReadFlags());
5107
5209
  try {
5108
5210
  const opened = await source.stat({ bigint: true });
5109
5211
  assertRegularSingleLinkBigInt(opened);
@@ -5158,7 +5260,7 @@ function addMetadataRoots(context, directoryPath) {
5158
5260
  }
5159
5261
  }
5160
5262
  function pathMatchesRoots(absolutePath, roots) {
5161
- const lexical = path17.resolve(absolutePath);
5263
+ const lexical = path18.resolve(absolutePath);
5162
5264
  const canonical = canonicalPath(absolutePath);
5163
5265
  for (const root of roots) {
5164
5266
  if (isAtOrWithin(root, lexical) || isAtOrWithin(root, canonical)) {
@@ -5168,7 +5270,7 @@ function pathMatchesRoots(absolutePath, roots) {
5168
5270
  return false;
5169
5271
  }
5170
5272
  function pathLexicallyMatchesRoots(absolutePath, roots) {
5171
- const lexical = path17.resolve(absolutePath);
5273
+ const lexical = path18.resolve(absolutePath);
5172
5274
  for (const root of roots) {
5173
5275
  if (isAtOrWithin(root, lexical)) {
5174
5276
  return true;
@@ -5189,11 +5291,11 @@ async function readSafeSymlink(absolutePath, context) {
5189
5291
  }
5190
5292
  const identity = identityFromStats(before);
5191
5293
  const target = await readlink2(absolutePath);
5192
- if (path17.isAbsolute(target)) {
5294
+ if (path18.isAbsolute(target)) {
5193
5295
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_UNSAFE_SYMLINK);
5194
5296
  }
5195
- const lexicalTarget = path17.resolve(path17.dirname(absolutePath), target);
5196
- if (!isAtOrWithin(context.sourceRoot, lexicalTarget) || isGitMetadataRelativePath(path17.relative(context.sourceRoot, lexicalTarget)) || pathMatchesRoots(lexicalTarget, context.protectedRoots) || pathMatchesRoots(lexicalTarget, context.metadataRoots)) {
5297
+ const lexicalTarget = path18.resolve(path18.dirname(absolutePath), target);
5298
+ if (!isAtOrWithin(context.sourceRoot, lexicalTarget) || isGitMetadataRelativePath(path18.relative(context.sourceRoot, lexicalTarget)) || pathMatchesRoots(lexicalTarget, context.protectedRoots) || pathMatchesRoots(lexicalTarget, context.metadataRoots)) {
5197
5299
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_UNSAFE_SYMLINK);
5198
5300
  }
5199
5301
  let resolvedTarget;
@@ -5229,7 +5331,7 @@ async function walkDirectory2(relativeDirectory, entries, context) {
5229
5331
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5230
5332
  }
5231
5333
  const directoryFlags = safeReadFlags() | (fsConstants.O_DIRECTORY ?? 0);
5232
- const directory = await open3(absoluteDirectory, directoryFlags);
5334
+ const directory = await open4(absoluteDirectory, directoryFlags);
5233
5335
  try {
5234
5336
  const opened = await directory.stat({ bigint: true });
5235
5337
  if (!opened.isDirectory() || !identitiesEqual(beforeIdentity, identityFromStats(opened))) {
@@ -5238,7 +5340,7 @@ async function walkDirectory2(relativeDirectory, entries, context) {
5238
5340
  const entriesDirectory = await opendir(absoluteDirectory, { bufferSize: 32 });
5239
5341
  for await (const directoryEntry of entriesDirectory) {
5240
5342
  assertDeadline(context.deadlineMs, context.now);
5241
- const relativePath = relativeDirectory ? path17.join(relativeDirectory, directoryEntry.name) : directoryEntry.name;
5343
+ const relativePath = relativeDirectory ? path18.join(relativeDirectory, directoryEntry.name) : directoryEntry.name;
5242
5344
  const absolutePath = joinRelativePath(context.sourceRoot, relativePath);
5243
5345
  const info = await lstat3(absolutePath);
5244
5346
  if (info.isSymbolicLink()) {
@@ -5322,7 +5424,7 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5322
5424
  }
5323
5425
  assertEntryIdentity(entry, identityFromStats(before));
5324
5426
  await context.beforeCopyOpen?.(sourcePath);
5325
- const source = await open3(sourcePath, safeReadFlags());
5427
+ const source = await open4(sourcePath, safeReadFlags());
5326
5428
  let destination;
5327
5429
  try {
5328
5430
  const opened = await source.stat({ bigint: true });
@@ -5332,8 +5434,8 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5332
5434
  if (entry.node.kind !== "file") {
5333
5435
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5334
5436
  }
5335
- await mkdir5(path17.dirname(destinationPath), { recursive: true, mode: 448 });
5336
- destination = await open3(
5437
+ await mkdir6(path18.dirname(destinationPath), { recursive: true, mode: 448 });
5438
+ destination = await open4(
5337
5439
  destinationPath,
5338
5440
  fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,
5339
5441
  safePermissionMode(opened.mode)
@@ -5375,7 +5477,7 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5375
5477
  if (entry.node.kind !== "file") {
5376
5478
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5377
5479
  }
5378
- await chmod2(destinationPath, safePermissionMode(entry.node.mode));
5480
+ await chmod3(destinationPath, safePermissionMode(entry.node.mode));
5379
5481
  }
5380
5482
  async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, context) {
5381
5483
  const directoryEntries = [];
@@ -5384,7 +5486,7 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5384
5486
  const sourcePath = joinRelativePath(sourceRoot, entry.relativePath);
5385
5487
  const destinationPath = joinRelativePath(destinationRoot, entry.relativePath);
5386
5488
  if (entry.node.kind === "directory") {
5387
- await mkdir5(destinationPath, { recursive: true, mode: 448 });
5489
+ await mkdir6(destinationPath, { recursive: true, mode: 448 });
5388
5490
  directoryEntries.push(entry);
5389
5491
  continue;
5390
5492
  }
@@ -5396,7 +5498,7 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5396
5498
  if (current !== entry.node.target) {
5397
5499
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5398
5500
  }
5399
- await mkdir5(path17.dirname(destinationPath), { recursive: true, mode: 448 });
5501
+ await mkdir6(path18.dirname(destinationPath), { recursive: true, mode: 448 });
5400
5502
  await symlink(entry.node.target, destinationPath);
5401
5503
  continue;
5402
5504
  }
@@ -5406,12 +5508,12 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5406
5508
  if (entry.node.kind !== "directory") {
5407
5509
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5408
5510
  }
5409
- await chmod2(
5511
+ await chmod3(
5410
5512
  joinRelativePath(destinationRoot, entry.relativePath),
5411
5513
  safePermissionMode(entry.node.mode)
5412
5514
  );
5413
5515
  }
5414
- await chmod2(destinationRoot, 448);
5516
+ await chmod3(destinationRoot, 448);
5415
5517
  }
5416
5518
  async function assertStableCopiedSnapshot(sourceRoot, destinationRoot, protectedRoots, limits, deadlineMs, now, before) {
5417
5519
  const [after, copied] = await Promise.all([
@@ -5456,7 +5558,7 @@ async function cleanupOwnedRoot(root, dependencies) {
5456
5558
  }
5457
5559
  async function prepareWithDependencies(options, dependencies) {
5458
5560
  validateOptions(options);
5459
- const guestWorkspacePath = path17.resolve(options.sourceRoot);
5561
+ const guestWorkspacePath = path18.resolve(options.sourceRoot);
5460
5562
  const sourceRoot = canonicalPath(options.sourceRoot);
5461
5563
  const protectedRoots = options.controlPlaneRoots.map((root) => canonicalPath(root));
5462
5564
  if (pathMatchesRoots(sourceRoot, protectedRoots)) {
@@ -5464,7 +5566,7 @@ async function prepareWithDependencies(options, dependencies) {
5464
5566
  }
5465
5567
  const guestRoot = await dependencies.makeTempRoot();
5466
5568
  try {
5467
- await chmod2(guestRoot, 448);
5569
+ await chmod3(guestRoot, 448);
5468
5570
  const deadlineMs = dependencies.now() + options.limits.prepareTimeoutMs;
5469
5571
  const before = await buildSafeMirrorSnapshot(
5470
5572
  sourceRoot,
@@ -5492,7 +5594,7 @@ async function prepareWithDependencies(options, dependencies) {
5492
5594
  dependencies.now,
5493
5595
  before
5494
5596
  );
5495
- await chmod2(guestRoot, 448);
5597
+ await chmod3(guestRoot, 448);
5496
5598
  const lease = {
5497
5599
  sourceRoot,
5498
5600
  hostMirrorRoot: guestRoot,
@@ -5626,14 +5728,14 @@ async function digestFile(file) {
5626
5728
  return hash.digest("hex");
5627
5729
  }
5628
5730
  async function resolveConfiguredDockerSubstrate(params) {
5629
- if (!path18.isAbsolute(params.executable) || /[\0\n\r]/.test(params.executable)) {
5731
+ if (!path19.isAbsolute(params.executable) || /[\0\n\r]/.test(params.executable)) {
5630
5732
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_binary_invalid");
5631
5733
  }
5632
5734
  if (!params.host.startsWith("unix:///") || /[\0\n\r]/.test(params.host)) {
5633
5735
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_host_invalid");
5634
5736
  }
5635
5737
  const configuredSocket = params.host.slice("unix://".length);
5636
- if (!path18.isAbsolute(configuredSocket)) {
5738
+ if (!path19.isAbsolute(configuredSocket)) {
5637
5739
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_host_invalid");
5638
5740
  }
5639
5741
  let binaryPath;
@@ -5894,7 +5996,7 @@ async function validatedGuestCwd(params) {
5894
5996
  const requiredExclusions = [
5895
5997
  ...new Set([params.controlPlaneDir, ...params.protectedRoots].map(canonicalPath))
5896
5998
  ];
5897
- if (params.mirror.backend !== "file_copy" || params.mirror.guestWorkspacePath !== path18.resolve(params.repoRoot) || !path18.isAbsolute(params.guestCwd) || !pathWithinRoot(params.mirror.guestWorkspacePath, params.guestCwd))
5999
+ if (params.mirror.backend !== "file_copy" || params.mirror.guestWorkspacePath !== path19.resolve(params.repoRoot) || !path19.isAbsolute(params.guestCwd) || !pathWithinRoot(params.mirror.guestWorkspacePath, params.guestCwd))
5898
6000
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5899
6001
  const resolvedRoot = await realpath2(params.mirror.hostMirrorRoot);
5900
6002
  const protectedRoots = [canonicalPath(params.repoRoot), ...requiredExclusions];
@@ -5906,10 +6008,10 @@ async function validatedGuestCwd(params) {
5906
6008
  protectedRoots: requiredExclusions
5907
6009
  }))
5908
6010
  throw new ContainedExecutionFailureError("contained_execution_invalid_mirror_lease");
5909
- const relative = path18.relative(params.mirror.guestWorkspacePath, path18.resolve(params.guestCwd));
6011
+ const relative = path19.relative(params.mirror.guestWorkspacePath, path19.resolve(params.guestCwd));
5910
6012
  let resolvedCwd;
5911
6013
  try {
5912
- resolvedCwd = await realpath2(path18.join(resolvedRoot, relative));
6014
+ resolvedCwd = await realpath2(path19.join(resolvedRoot, relative));
5913
6015
  } catch {
5914
6016
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5915
6017
  }
@@ -5917,7 +6019,7 @@ async function validatedGuestCwd(params) {
5917
6019
  if (!info.isDirectory() || !pathWithinRoot(resolvedRoot, resolvedCwd)) {
5918
6020
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5919
6021
  }
5920
- return path18.join(params.mirror.guestWorkspacePath, path18.relative(resolvedRoot, resolvedCwd));
6022
+ return path19.join(params.mirror.guestWorkspacePath, path19.relative(resolvedRoot, resolvedCwd));
5921
6023
  }
5922
6024
  function exactKeys(value, allowed) {
5923
6025
  const names = new Set(allowed);
@@ -6144,19 +6246,19 @@ async function executeContainedDocker(params) {
6144
6246
  init_path_utils();
6145
6247
  import { spawn as spawn3 } from "node:child_process";
6146
6248
  import os3 from "node:os";
6147
- import path20 from "node:path";
6249
+ import path21 from "node:path";
6148
6250
 
6149
6251
  // src/core/transactional/apply-observed-changes.ts
6150
- import { copyFile, lstat as lstat5, mkdir as mkdir6, mkdtemp as mkdtemp3, readlink as readlink3, rm as rm3, rmdir, symlink as symlink2 } from "node:fs/promises";
6252
+ import { copyFile, lstat as lstat5, mkdir as mkdir7, mkdtemp as mkdtemp3, readlink as readlink3, rm as rm3, rmdir, symlink as symlink2 } from "node:fs/promises";
6151
6253
  import os2 from "node:os";
6152
- import path19 from "node:path";
6254
+ import path20 from "node:path";
6153
6255
  var TRANSACTIONAL_APPLY_TOCTOU = "transactional_apply_toctou";
6154
6256
  var TRANSACTIONAL_APPLY_CONFLICT = "transactional_apply_conflict";
6155
6257
  var TRANSACTIONAL_APPLY_ROLLBACK_FAILED = "transactional_apply_rollback_failed";
6156
6258
  async function chmodSafe(target, mode) {
6157
6259
  try {
6158
- const { chmod: chmod4 } = await import("node:fs/promises");
6159
- await chmod4(target, mode & 511);
6260
+ const { chmod: chmod5 } = await import("node:fs/promises");
6261
+ await chmod5(target, mode & 511);
6160
6262
  } catch {
6161
6263
  }
6162
6264
  }
@@ -6190,13 +6292,13 @@ async function copyPathPreservingType(source, target) {
6190
6292
  }
6191
6293
  }
6192
6294
  await removePathIfExists(target);
6193
- await mkdir6(path19.dirname(target), { recursive: true });
6295
+ await mkdir7(path20.dirname(target), { recursive: true });
6194
6296
  if (info.isSymbolicLink()) {
6195
6297
  await symlink2(await readlink3(source), target);
6196
6298
  return;
6197
6299
  }
6198
6300
  if (info.isDirectory() && !info.isSymbolicLink()) {
6199
- await mkdir6(target, { recursive: true, mode: info.mode & 511 });
6301
+ await mkdir7(target, { recursive: true, mode: info.mode & 511 });
6200
6302
  return;
6201
6303
  }
6202
6304
  if (!info.isFile()) {
@@ -6206,12 +6308,12 @@ async function copyPathPreservingType(source, target) {
6206
6308
  await chmodSafe(target, info.mode);
6207
6309
  }
6208
6310
  async function assertParentChainSafe(targetRoot, relativePath, plannedDirectories = /* @__PURE__ */ new Set()) {
6209
- const segments = relativePath.split(path19.sep).filter(Boolean);
6311
+ const segments = relativePath.split(path20.sep).filter(Boolean);
6210
6312
  if (segments.length <= 1) {
6211
6313
  return;
6212
6314
  }
6213
6315
  for (let index = 1; index < segments.length; index++) {
6214
- const prefix = segments.slice(0, index).join(path19.sep);
6316
+ const prefix = segments.slice(0, index).join(path20.sep);
6215
6317
  const absolute = joinRelativePath(targetRoot, prefix);
6216
6318
  let info;
6217
6319
  try {
@@ -6231,8 +6333,8 @@ async function assertParentChainSafe(targetRoot, relativePath, plannedDirectorie
6231
6333
  }
6232
6334
  }
6233
6335
  async function restorePathFromBackup(backupPath, target, rollbackRoot) {
6234
- const stagingRoot = await mkdtemp3(path19.join(rollbackRoot, "restore-"));
6235
- const staged = path19.join(stagingRoot, "node");
6336
+ const stagingRoot = await mkdtemp3(path20.join(rollbackRoot, "restore-"));
6337
+ const staged = path20.join(stagingRoot, "node");
6236
6338
  try {
6237
6339
  await copyPathPreservingType(backupPath, staged);
6238
6340
  await copyPathPreservingType(staged, target);
@@ -6316,7 +6418,7 @@ async function applySingleChange(sourceRoot, targetRoot, change) {
6316
6418
  if (change.before.kind !== "directory") {
6317
6419
  await removePathIfExists(target);
6318
6420
  }
6319
- await mkdir6(target, { recursive: true, mode: change.after.mode & 511 });
6421
+ await mkdir7(target, { recursive: true, mode: change.after.mode & 511 });
6320
6422
  await chmodSafe(target, change.after.mode);
6321
6423
  return;
6322
6424
  }
@@ -6335,7 +6437,7 @@ async function applyObservedChanges(params) {
6335
6437
  await assertParentChainSafe(targetRoot, change.relativePath, plannedDirectories);
6336
6438
  await assertTargetMatches(targetRoot, change);
6337
6439
  }
6338
- const backupRoot = await mkdtemp3(path19.join(os2.tmpdir(), "belay-tx-rollback-"));
6440
+ const backupRoot = await mkdtemp3(path20.join(os2.tmpdir(), "belay-tx-rollback-"));
6339
6441
  const rollbackActions = [];
6340
6442
  let mutationAttempted = false;
6341
6443
  let resourceIdentityChanged = false;
@@ -6354,12 +6456,12 @@ async function applyObservedChanges(params) {
6354
6456
  targetExists = false;
6355
6457
  }
6356
6458
  if (targetExists) {
6357
- const backupPath = path19.join(
6459
+ const backupPath = path20.join(
6358
6460
  backupRoot,
6359
6461
  String(rollbackActions.length),
6360
6462
  change.relativePath
6361
6463
  );
6362
- await mkdir6(path19.dirname(backupPath), { recursive: true });
6464
+ await mkdir7(path20.dirname(backupPath), { recursive: true });
6363
6465
  await copyPathPreservingType(target, backupPath);
6364
6466
  await assertParentChainSafe(targetRoot, change.relativePath);
6365
6467
  rollbackActions.push({
@@ -6458,7 +6560,7 @@ function isIgnoredDirtyPath(repoRoot, relativePath, ignoreRoots) {
6458
6560
  if (ignoreRoots.length === 0) {
6459
6561
  return false;
6460
6562
  }
6461
- const absolutePath = canonicalPath(path20.join(repoRoot, relativePath));
6563
+ const absolutePath = canonicalPath(path21.join(repoRoot, relativePath));
6462
6564
  return ignoreRoots.some(
6463
6565
  (root) => pathWithinRoot(root, absolutePath) || root === absolutePath || pathWithinRoot(absolutePath, root)
6464
6566
  );
@@ -6496,7 +6598,7 @@ async function isDirtyWorktree(repoRoot, options) {
6496
6598
  }
6497
6599
  async function createGitWorktreeSnapshot(repoRoot, _stateDir) {
6498
6600
  const { mkdtemp: mkdtemp6, rm: rm10 } = await import("node:fs/promises");
6499
- const worktreePath = await mkdtemp6(path20.join(os3.tmpdir(), "belay-tx-"));
6601
+ const worktreePath = await mkdtemp6(path21.join(os3.tmpdir(), "belay-tx-"));
6500
6602
  await execGit(repoRoot, ["worktree", "add", "--detach", worktreePath, "HEAD"]);
6501
6603
  return {
6502
6604
  worktreePath,
@@ -6515,14 +6617,14 @@ async function createGitWorktreeSnapshot(repoRoot, _stateDir) {
6515
6617
  }
6516
6618
  function resolveWorktreeCwd(repoRoot, worktreePath, cwd) {
6517
6619
  const resolvedCwd = canonicalPath(cwd);
6518
- const relative = path20.relative(canonicalPath(repoRoot), resolvedCwd);
6519
- if (isPathOutsideRoot(relative) || path20.isAbsolute(relative)) {
6620
+ const relative = path21.relative(canonicalPath(repoRoot), resolvedCwd);
6621
+ if (isPathOutsideRoot(relative) || path21.isAbsolute(relative)) {
6520
6622
  return worktreePath;
6521
6623
  }
6522
6624
  if (relative === "") {
6523
6625
  return worktreePath;
6524
6626
  }
6525
- return path20.join(worktreePath, relative);
6627
+ return path21.join(worktreePath, relative);
6526
6628
  }
6527
6629
  function runShellCommand(command, cwd, timeoutMs) {
6528
6630
  return runProcessWithBoundedOutput(command, [], { cwd, shell: true, env: process.env }, timeoutMs);
@@ -6587,7 +6689,7 @@ import { spawn as spawn4 } from "node:child_process";
6587
6689
  import { randomUUID as randomUUID3 } from "node:crypto";
6588
6690
 
6589
6691
  // src/core/capability/boundary-grant-materialize.ts
6590
- import path21 from "node:path";
6692
+ import path22 from "node:path";
6591
6693
 
6592
6694
  // src/core/glob.ts
6593
6695
  init_approval();
@@ -6747,7 +6849,7 @@ function grantMatchesRequest(grant, request) {
6747
6849
  var BOUNDARY_GRANT_TTL_MS = 15 * 6e4;
6748
6850
  var BOUNDARY_GRANT_ISSUER_CONTAINER = "boundary:container";
6749
6851
  function resolveCapabilityPath(targetPath, cwd) {
6750
- const joined = path21.isAbsolute(targetPath) ? targetPath : path21.join(cwd, targetPath);
6852
+ const joined = path22.isAbsolute(targetPath) ? targetPath : path22.join(cwd, targetPath);
6751
6853
  return canonicalPath(joined);
6752
6854
  }
6753
6855
  function isPathWithinBoundaryMount(request) {
@@ -6822,7 +6924,7 @@ function materializeContainerBoundaryGrant(request, params) {
6822
6924
 
6823
6925
  // src/core/capability/boundary-workspace-mount.ts
6824
6926
  init_path_utils();
6825
- import path22 from "node:path";
6927
+ import path23 from "node:path";
6826
6928
  var HOST_PATH_ENV_VARS = [
6827
6929
  "BELAY_EGRESS_REPO_ROOT",
6828
6930
  "BELAY_JUDGE_BROKER_REPO_ROOT",
@@ -6847,23 +6949,23 @@ function validateWorkspaceMount(mount) {
6847
6949
  if (mount.cwdRelative.includes("\0")) {
6848
6950
  throw new Error("boundary_workspace_mount_invalid_cwd");
6849
6951
  }
6850
- const normalizedRelative = path22.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6952
+ const normalizedRelative = path23.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6851
6953
  if (normalizedRelative === ".." || normalizedRelative.startsWith("../")) {
6852
6954
  throw new Error("boundary_workspace_mount_invalid_cwd");
6853
6955
  }
6854
- if (path22.posix.isAbsolute(normalizedRelative)) {
6956
+ if (path23.posix.isAbsolute(normalizedRelative)) {
6855
6957
  throw new Error("boundary_workspace_mount_invalid_cwd");
6856
6958
  }
6857
6959
  }
6858
6960
  function resolveGuestWorkdir(mount) {
6859
6961
  validateWorkspaceMount(mount);
6860
6962
  const guestTargetRoot = canonicalPath(mount.guestTargetRoot);
6861
- const normalizedRelative = path22.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6963
+ const normalizedRelative = path23.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6862
6964
  if (normalizedRelative === "." || normalizedRelative === "") {
6863
6965
  return guestTargetRoot;
6864
6966
  }
6865
6967
  const segments = normalizedRelative.split("/").filter(Boolean);
6866
- return path22.posix.join(guestTargetRoot, ...segments);
6968
+ return path23.posix.join(guestTargetRoot, ...segments);
6867
6969
  }
6868
6970
  function buildWorkspaceMountSpec(mount) {
6869
6971
  validateWorkspaceMount(mount);
@@ -7154,7 +7256,7 @@ function containedExecutionFresh(attestation, config, now = Date.now()) {
7154
7256
  }
7155
7257
  function boundaryAttestationPath(repoRoot, config) {
7156
7258
  const rel = config.capability?.attestationRelPath ?? ".belay/attestation.json";
7157
- return path23.isAbsolute(rel) ? rel : path23.join(repoRoot, rel);
7259
+ return path24.isAbsolute(rel) ? rel : path24.join(repoRoot, rel);
7158
7260
  }
7159
7261
  async function loadBoundaryAttestation(filePath, expectedRepoRoot, controlPlaneDir) {
7160
7262
  try {
@@ -7259,7 +7361,7 @@ init_capability_request_hash();
7259
7361
 
7260
7362
  // src/core/capability/gate-policy-shadow.ts
7261
7363
  init_config();
7262
- import path29 from "node:path";
7364
+ import path30 from "node:path";
7263
7365
 
7264
7366
  // src/core/effect-ir/audit.ts
7265
7367
  init_fingerprint2();
@@ -7353,8 +7455,8 @@ function evidenceRank(level) {
7353
7455
  }
7354
7456
 
7355
7457
  // src/core/effect-ir/package-exec.ts
7356
- import { existsSync as existsSync5, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
7357
- import path24 from "node:path";
7458
+ import { existsSync as existsSync6, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
7459
+ import path25 from "node:path";
7358
7460
 
7359
7461
  // src/core/network-endpoint.ts
7360
7462
  var SUPPORTED_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "ssh:", "git:"]);
@@ -7645,18 +7747,18 @@ function classifyPackageAcquisitionSpec(spec) {
7645
7747
  return { kind: "registry" };
7646
7748
  }
7647
7749
  function resolveLocalBin(binName, cwd, repoRoot) {
7648
- const base = path24.basename(binName);
7750
+ const base = path25.basename(binName);
7649
7751
  if (!base || base === "." || base === "..") {
7650
7752
  return null;
7651
7753
  }
7652
- let current = path24.resolve(cwd);
7653
- const stop = path24.resolve(repoRoot);
7754
+ let current = path25.resolve(cwd);
7755
+ const stop = path25.resolve(repoRoot);
7654
7756
  if (!pathWithinRoot(stop, current)) {
7655
7757
  return null;
7656
7758
  }
7657
7759
  while (true) {
7658
- const candidate = path24.join(current, "node_modules", ".bin", base);
7659
- if (existsSync5(candidate)) {
7760
+ const candidate = path25.join(current, "node_modules", ".bin", base);
7761
+ if (existsSync6(candidate)) {
7660
7762
  try {
7661
7763
  const resolvedCandidate = realpathSync3.native(candidate);
7662
7764
  if (!pathWithinRoot(stop, resolvedCandidate) || !statSync2(resolvedCandidate).isFile()) {
@@ -7670,7 +7772,7 @@ function resolveLocalBin(binName, cwd, repoRoot) {
7670
7772
  if (current === stop) {
7671
7773
  break;
7672
7774
  }
7673
- const parent = path24.dirname(current);
7775
+ const parent = path25.dirname(current);
7674
7776
  if (parent === current) {
7675
7777
  break;
7676
7778
  }
@@ -7865,7 +7967,7 @@ init_path_utils();
7865
7967
 
7866
7968
  // src/core/verdict/containment.ts
7867
7969
  init_git_resource_identity();
7868
- import path25 from "node:path";
7970
+ import path26 from "node:path";
7869
7971
  init_path_utils();
7870
7972
 
7871
7973
  // src/core/verdict/persistent-paths.ts
@@ -7885,7 +7987,7 @@ function expandHome(token) {
7885
7987
  if (!home) {
7886
7988
  return token;
7887
7989
  }
7888
- return token === "~" ? home : path25.join(home, token.slice(2));
7990
+ return token === "~" ? home : path26.join(home, token.slice(2));
7889
7991
  }
7890
7992
  return token;
7891
7993
  }
@@ -7897,10 +7999,10 @@ function resolveTrustedPath(token, trustedCwd, trusted) {
7897
7999
  return null;
7898
8000
  }
7899
8001
  const expanded = expandHome(token);
7900
- if (path25.isAbsolute(expanded)) {
8002
+ if (path26.isAbsolute(expanded)) {
7901
8003
  return canonicalPath(expanded);
7902
8004
  }
7903
- return canonicalPath(path25.resolve(trustedCwd, expanded));
8005
+ return canonicalPath(path26.resolve(trustedCwd, expanded));
7904
8006
  }
7905
8007
  function isGitPath(resolvedPath, repoRoot) {
7906
8008
  if (isGitMetadataPath(resolvedPath, repoRoot)) {
@@ -8017,20 +8119,20 @@ function parseTier1Json(raw) {
8017
8119
  init_judge_runtime_config();
8018
8120
 
8019
8121
  // src/core/verdict/judge-session-kill-switch.ts
8020
- import { existsSync as existsSync6 } from "node:fs";
8021
- import { mkdir as mkdir7, readFile as readFile6, unlink as unlink4, writeFile as writeFile4 } from "node:fs/promises";
8022
- import path26 from "node:path";
8122
+ import { existsSync as existsSync7 } from "node:fs";
8123
+ import { mkdir as mkdir8, readFile as readFile7, unlink as unlink5, writeFile as writeFile4 } from "node:fs/promises";
8124
+ import path27 from "node:path";
8023
8125
  var JUDGE_SESSION_KILL_FILE = "judge-session-kill.json";
8024
8126
  function judgeSessionKillSwitchPath(stateDir) {
8025
- return path26.join(stateDir, JUDGE_SESSION_KILL_FILE);
8127
+ return path27.join(stateDir, JUDGE_SESSION_KILL_FILE);
8026
8128
  }
8027
8129
  async function readJudgeSessionKillSwitch(stateDir) {
8028
8130
  const filePath = judgeSessionKillSwitchPath(stateDir);
8029
- if (!existsSync6(filePath)) {
8131
+ if (!existsSync7(filePath)) {
8030
8132
  return null;
8031
8133
  }
8032
8134
  try {
8033
- const raw = JSON.parse(await readFile6(filePath, "utf8"));
8135
+ const raw = JSON.parse(await readFile7(filePath, "utf8"));
8034
8136
  return raw.triggered === true ? raw : null;
8035
8137
  } catch {
8036
8138
  return null;
@@ -8041,7 +8143,7 @@ async function isJudgeSessionKillSwitchPersisted(stateDir) {
8041
8143
  return record?.triggered === true;
8042
8144
  }
8043
8145
  async function persistJudgeSessionKillSwitch(stateDir, reason = "shadow_mismatch") {
8044
- await mkdir7(stateDir, { recursive: true, mode: 448 });
8146
+ await mkdir8(stateDir, { recursive: true, mode: 448 });
8045
8147
  const record = {
8046
8148
  triggered: true,
8047
8149
  at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -8202,10 +8304,10 @@ function recordJudgeLatency(phase, latencyMs, at = Date.now()) {
8202
8304
 
8203
8305
  // src/core/verdict/judge-broker-service.ts
8204
8306
  import { spawn as spawn6 } from "node:child_process";
8205
- import { existsSync as existsSync7 } from "node:fs";
8206
- import { unlink as unlink5 } from "node:fs/promises";
8307
+ import { existsSync as existsSync8 } from "node:fs";
8308
+ import { unlink as unlink6 } from "node:fs/promises";
8207
8309
  import net2 from "node:net";
8208
- import path27 from "node:path";
8310
+ import path28 from "node:path";
8209
8311
  import { fileURLToPath } from "node:url";
8210
8312
 
8211
8313
  // src/core/verdict/judge-cli.ts
@@ -8751,10 +8853,10 @@ var JUDGE_BROKER_SESSION = "judge-broker-session.json";
8751
8853
  function judgeBrokerPaths(stateDir) {
8752
8854
  return {
8753
8855
  stateDir,
8754
- socketPath: path27.join(stateDir, JUDGE_BROKER_SOCKET),
8755
- statusPath: path27.join(stateDir, JUDGE_BROKER_STATUS),
8756
- pidPath: path27.join(stateDir, JUDGE_BROKER_PID),
8757
- sessionConfigPath: path27.join(stateDir, JUDGE_BROKER_SESSION)
8856
+ socketPath: path28.join(stateDir, JUDGE_BROKER_SOCKET),
8857
+ statusPath: path28.join(stateDir, JUDGE_BROKER_STATUS),
8858
+ pidPath: path28.join(stateDir, JUDGE_BROKER_PID),
8859
+ sessionConfigPath: path28.join(stateDir, JUDGE_BROKER_SESSION)
8758
8860
  };
8759
8861
  }
8760
8862
  function daemonScriptPath() {
@@ -8772,12 +8874,12 @@ function useInProcessBroker(env = process.env) {
8772
8874
  return Boolean(env.VITEST || env.VITEST_WORKER_ID || env.BELAY_JUDGE_BROKER_IN_PROCESS === "1");
8773
8875
  }
8774
8876
  async function readBrokerStatus(statusPath) {
8775
- if (!existsSync7(statusPath)) {
8877
+ if (!existsSync8(statusPath)) {
8776
8878
  return null;
8777
8879
  }
8778
8880
  try {
8779
- const { readFile: readFile16 } = await import("node:fs/promises");
8780
- const raw = JSON.parse(await readFile16(statusPath, "utf8"));
8881
+ const { readFile: readFile17 } = await import("node:fs/promises");
8882
+ const raw = JSON.parse(await readFile17(statusPath, "utf8"));
8781
8883
  if (typeof raw.pid !== "number" || typeof raw.socketPath !== "string") {
8782
8884
  return null;
8783
8885
  }
@@ -8787,13 +8889,13 @@ async function readBrokerStatus(statusPath) {
8787
8889
  }
8788
8890
  }
8789
8891
  async function readBrokerSessionConfig(sessionConfigPath) {
8790
- if (!existsSync7(sessionConfigPath)) {
8892
+ if (!existsSync8(sessionConfigPath)) {
8791
8893
  return null;
8792
8894
  }
8793
8895
  try {
8794
- const { readFile: readFile16 } = await import("node:fs/promises");
8896
+ const { readFile: readFile17 } = await import("node:fs/promises");
8795
8897
  const raw = JSON.parse(
8796
- await readFile16(sessionConfigPath, "utf8")
8898
+ await readFile17(sessionConfigPath, "utf8")
8797
8899
  );
8798
8900
  return normalizeJudgeSessionConfig({ ...raw, enabled: true });
8799
8901
  } catch {
@@ -8884,7 +8986,7 @@ async function ensureJudgeBrokerDaemon(stateDir, repoRoot, sessionConfig) {
8884
8986
  const existingConfig = await readBrokerSessionConfig(paths.sessionConfigPath);
8885
8987
  const configChanged = existingConfig !== null && brokerSessionConfigPayload(existingConfig) !== nextConfigPayload;
8886
8988
  const status = await readBrokerStatus(paths.statusPath);
8887
- if (status && isProcessAlive2(status.pid) && existsSync7(paths.socketPath) && !configChanged) {
8989
+ if (status && isProcessAlive2(status.pid) && existsSync8(paths.socketPath) && !configChanged) {
8888
8990
  await writeBrokerSessionConfig(paths, brokerSessionConfig);
8889
8991
  return paths;
8890
8992
  }
@@ -8906,7 +9008,7 @@ async function ensureJudgeBrokerDaemon(stateDir, repoRoot, sessionConfig) {
8906
9008
  child.unref();
8907
9009
  const deadline = Date.now() + sessionConfig.connectTimeoutMs;
8908
9010
  while (Date.now() < deadline) {
8909
- if (existsSync7(paths.socketPath)) {
9011
+ if (existsSync8(paths.socketPath)) {
8910
9012
  const live = await readBrokerStatus(paths.statusPath);
8911
9013
  if (live && isProcessAlive2(live.pid)) {
8912
9014
  return paths;
@@ -8923,8 +9025,8 @@ async function cleanupJudgeBrokerArtifacts(paths) {
8923
9025
  paths.pidPath,
8924
9026
  paths.sessionConfigPath
8925
9027
  ]) {
8926
- if (existsSync7(artifact)) {
8927
- await unlink5(artifact).catch(() => void 0);
9028
+ if (existsSync8(artifact)) {
9029
+ await unlink6(artifact).catch(() => void 0);
8928
9030
  }
8929
9031
  }
8930
9032
  }
@@ -9420,9 +9522,9 @@ async function evaluateWithJudgeTransport(request, options = {}) {
9420
9522
  }
9421
9523
 
9422
9524
  // src/core/capability/gate-shadow-ratchet.ts
9423
- import { existsSync as existsSync8 } from "node:fs";
9424
- import { mkdir as mkdir8, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
9425
- import path28 from "node:path";
9525
+ import { existsSync as existsSync9 } from "node:fs";
9526
+ import { mkdir as mkdir9, readFile as readFile8, writeFile as writeFile5 } from "node:fs/promises";
9527
+ import path29 from "node:path";
9426
9528
  var DEFAULT_STATE = {
9427
9529
  version: 1,
9428
9530
  policyJudgeComparisons: 0,
@@ -9431,15 +9533,15 @@ var DEFAULT_STATE = {
9431
9533
  updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
9432
9534
  };
9433
9535
  function ratchetPath(stateDir) {
9434
- return path28.join(stateDir, "gate-shadow-ratchet.json");
9536
+ return path29.join(stateDir, "gate-shadow-ratchet.json");
9435
9537
  }
9436
9538
  async function loadState(stateDir) {
9437
9539
  const filePath = ratchetPath(stateDir);
9438
- if (!existsSync8(filePath)) {
9540
+ if (!existsSync9(filePath)) {
9439
9541
  return { ...DEFAULT_STATE, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9440
9542
  }
9441
9543
  try {
9442
- const raw = JSON.parse(await readFile7(filePath, "utf8"));
9544
+ const raw = JSON.parse(await readFile8(filePath, "utf8"));
9443
9545
  return {
9444
9546
  ...DEFAULT_STATE,
9445
9547
  ...raw,
@@ -9450,7 +9552,7 @@ async function loadState(stateDir) {
9450
9552
  }
9451
9553
  }
9452
9554
  async function saveState(stateDir, state) {
9453
- await mkdir8(stateDir, { recursive: true, mode: 448 });
9555
+ await mkdir9(stateDir, { recursive: true, mode: 448 });
9454
9556
  await writeFile5(
9455
9557
  ratchetPath(stateDir),
9456
9558
  `${JSON.stringify({ ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)}
@@ -9573,7 +9675,7 @@ function scheduleGateShadowAudit(params) {
9573
9675
  async function runGatePolicyShadowComparison(params) {
9574
9676
  const judge = params.config.judge;
9575
9677
  const runtime = normalizeJudgeRuntimeConfig(judge.runtime);
9576
- const stateDir = params.stateDir ?? belayStateDir(params.config, path29.join(params.repoRoot, ".belay"));
9678
+ const stateDir = params.stateDir ?? belayStateDir(params.config, path30.join(params.repoRoot, ".belay"));
9577
9679
  const transport = await evaluateWithJudgeTransport(
9578
9680
  {
9579
9681
  prompt: buildTier1Prompt(params.command),
@@ -9863,15 +9965,15 @@ async function loadClassifierAuthorization(params) {
9863
9965
  }
9864
9966
 
9865
9967
  // src/core/capability/allowlist.ts
9866
- import { existsSync as existsSync9, readFileSync as readFileSync3 } from "node:fs";
9968
+ import { existsSync as existsSync10, readFileSync as readFileSync3 } from "node:fs";
9867
9969
  init_config();
9868
9970
  init_path_utils();
9869
- import path30 from "node:path";
9971
+ import path31 from "node:path";
9870
9972
  function fsScopeAllowlistPath(config, repoLocalStateDir) {
9871
- return path30.join(belayStateDir(config, repoLocalStateDir), "fs-scope-allowlist.json");
9973
+ return path31.join(belayStateDir(config, repoLocalStateDir), "fs-scope-allowlist.json");
9872
9974
  }
9873
9975
  function loadFsScopeAllowlistSync(filePath) {
9874
- if (!existsSync9(filePath)) {
9976
+ if (!existsSync10(filePath)) {
9875
9977
  return { version: 1, paths: [] };
9876
9978
  }
9877
9979
  const raw = JSON.parse(readFileSync3(filePath, "utf8"));
@@ -9963,7 +10065,7 @@ function checkGatedActionLimits(action) {
9963
10065
  // src/core/capability/paths.ts
9964
10066
  init_path_utils();
9965
10067
  init_shell_tokenizer();
9966
- import path31 from "node:path";
10068
+ import path32 from "node:path";
9967
10069
  function applyPatchTargets(patch) {
9968
10070
  const targets = [];
9969
10071
  for (const line of patch.split("\n")) {
@@ -10028,7 +10130,7 @@ function collectOutsideRepoPathsFromToolPayload(payload, cwd, repoRoot, trustedW
10028
10130
  const paths = /* @__PURE__ */ new Set();
10029
10131
  const filePath = extractToolFilePath(payload);
10030
10132
  if (filePath) {
10031
- const resolved = path31.isAbsolute(filePath) ? filePath : path31.resolve(cwd, filePath);
10133
+ const resolved = path32.isAbsolute(filePath) ? filePath : path32.resolve(cwd, filePath);
10032
10134
  if (resolveWorkspaceRootMatch(repoRoot, trustedWorkspaceRoots, resolved) === null) {
10033
10135
  paths.add(resolved);
10034
10136
  }
@@ -10038,7 +10140,7 @@ function collectOutsideRepoPathsFromToolPayload(payload, cwd, repoRoot, trustedW
10038
10140
  const patch = extractToolPatch(payload);
10039
10141
  if (patch) {
10040
10142
  for (const target of applyPatchTargets(patch)) {
10041
- const resolved = path31.isAbsolute(target) ? target : path31.resolve(cwd, target);
10143
+ const resolved = path32.isAbsolute(target) ? target : path32.resolve(cwd, target);
10042
10144
  if (resolveWorkspaceRootMatch(repoRoot, trustedWorkspaceRoots, resolved) === null) {
10043
10145
  paths.add(resolved);
10044
10146
  }
@@ -10092,7 +10194,7 @@ function policyReasonToLegacyReason(decision) {
10092
10194
  // src/core/capability/policy-engine.ts
10093
10195
  init_git_resource_identity();
10094
10196
  import { createHash as createHash10 } from "node:crypto";
10095
- import path32 from "node:path";
10197
+ import path33 from "node:path";
10096
10198
  init_path_utils();
10097
10199
  init_shell_tokenizer();
10098
10200
  init_grant();
@@ -10384,7 +10486,7 @@ function hashSession(value) {
10384
10486
  return createHash10("sha256").update(value).digest("hex").slice(0, 16);
10385
10487
  }
10386
10488
  function resolveCapabilityPath2(targetPath, cwd) {
10387
- const joined = path32.isAbsolute(targetPath) ? targetPath : path32.join(cwd, targetPath);
10489
+ const joined = path33.isAbsolute(targetPath) ? targetPath : path33.join(cwd, targetPath);
10388
10490
  return canonicalPath(joined);
10389
10491
  }
10390
10492
  function actionForFileMutation(analysis) {
@@ -10463,7 +10565,7 @@ function isRepoLocalPackageExec(request) {
10463
10565
  return false;
10464
10566
  }
10465
10567
  const commandPath = canonicalPath(request.resource.command);
10466
- return path32.isAbsolute(commandPath) && pathWithinRoot(request.principal.repoRoot, commandPath);
10568
+ return path33.isAbsolute(commandPath) && pathWithinRoot(request.principal.repoRoot, commandPath);
10467
10569
  }
10468
10570
  function isRepoLocalRoutineWrite(request, sensitivePaths) {
10469
10571
  if (!isRepoLocalShellLocation(request)) {
@@ -10727,15 +10829,15 @@ function shouldSkipBrokerApprovedRecord(brokerActive, approvalReason) {
10727
10829
  }
10728
10830
 
10729
10831
  // src/core/capability/trusted-workspace-roots.ts
10730
- import { existsSync as existsSync10, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
10832
+ import { existsSync as existsSync11, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
10731
10833
  init_config();
10732
10834
  init_path_utils();
10733
- import path33 from "node:path";
10835
+ import path34 from "node:path";
10734
10836
  function trustedWorkspaceRootsPath(config, repoLocalStateDir) {
10735
- return path33.join(belayStateDir(config, repoLocalStateDir), "trusted-workspace-roots.json");
10837
+ return path34.join(belayStateDir(config, repoLocalStateDir), "trusted-workspace-roots.json");
10736
10838
  }
10737
10839
  function loadTrustedWorkspaceRootsSync(filePath) {
10738
- if (!existsSync10(filePath)) {
10840
+ if (!existsSync11(filePath)) {
10739
10841
  return { version: 1, roots: [] };
10740
10842
  }
10741
10843
  const raw = JSON.parse(readFileSync4(filePath, "utf8"));
@@ -10761,7 +10863,7 @@ function sanitizeTrustedWorkspaceRootEntries(input) {
10761
10863
  const source = record.source === "approval" ? "approval" : void 0;
10762
10864
  return [
10763
10865
  {
10764
- path: path33.resolve(record.path),
10866
+ path: path34.resolve(record.path),
10765
10867
  approvedAt,
10766
10868
  approvalId,
10767
10869
  ...source ? { source } : {}
@@ -10790,7 +10892,7 @@ function isDirectoryPath(targetPath) {
10790
10892
  function isBroadTrustedWorkspaceRoot(targetPath) {
10791
10893
  const home = process.env.HOME ?? process.env.USERPROFILE;
10792
10894
  const root = normalizeTrustedWorkspaceRootPath(targetPath);
10793
- if (root === normalizeTrustedWorkspaceRootPath(path33.parse(root).root)) {
10895
+ if (root === normalizeTrustedWorkspaceRootPath(path34.parse(root).root)) {
10794
10896
  return true;
10795
10897
  }
10796
10898
  if (home && normalizeTrustedWorkspaceRootPath(home) === root) {
@@ -10814,7 +10916,7 @@ function isHighStakesTrustedWorkspaceRoot(targetPath) {
10814
10916
  return false;
10815
10917
  }
10816
10918
  return HOME_HIGH_STAKES_SEGMENTS.some(
10817
- (segment) => pathWithinRoot(path33.join(homeRoot, segment), normalized)
10919
+ (segment) => pathWithinRoot(path34.join(homeRoot, segment), normalized)
10818
10920
  );
10819
10921
  }
10820
10922
  function validateTrustedWorkspaceRootCandidate(params) {
@@ -10851,7 +10953,7 @@ function validateTrustedWorkspaceRootCandidate(params) {
10851
10953
  init_config_layers();
10852
10954
 
10853
10955
  // src/core/contained-execution/eligibility.ts
10854
- import path34 from "node:path";
10956
+ import path35 from "node:path";
10855
10957
  init_path_utils();
10856
10958
  var FORBIDDEN_SIGNALS = /* @__PURE__ */ new Set([
10857
10959
  "command_substitution",
@@ -10868,7 +10970,7 @@ var FORBIDDEN_SIGNALS = /* @__PURE__ */ new Set([
10868
10970
  ]);
10869
10971
  function isContainedUnknownExecutionEligible(config, action, result) {
10870
10972
  const contained = config.sandbox.containedExecution;
10871
- if (!contained?.enabled || !config.sandbox.enabled || config.sandbox.runtime !== "container" || action.kind !== "shell" || !path34.isAbsolute(action.repoRoot) || !hasResolvedRepoIdentity(action.repoRoot) || !config.gates.shell || result.reason !== "unknown_local_effect" || result.axes?.location !== "repo_local" || result.assessment.external) {
10973
+ if (!contained?.enabled || !config.sandbox.enabled || config.sandbox.runtime !== "container" || action.kind !== "shell" || !path35.isAbsolute(action.repoRoot) || !hasResolvedRepoIdentity(action.repoRoot) || !config.gates.shell || result.reason !== "unknown_local_effect" || result.axes?.location !== "repo_local" || result.assessment.external) {
10872
10974
  return false;
10873
10975
  }
10874
10976
  const plan = result.effectPlan;
@@ -11148,7 +11250,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
11148
11250
  }
11149
11251
 
11150
11252
  // src/core/classify-tool.ts
11151
- import path49 from "node:path";
11253
+ import path50 from "node:path";
11152
11254
  init_fingerprint2();
11153
11255
  init_path_utils();
11154
11256
  init_scrub();
@@ -11268,13 +11370,13 @@ function worstEffectDecision(decisions) {
11268
11370
 
11269
11371
  // src/core/effect-ir/shell-lower.ts
11270
11372
  init_shell_tokenizer();
11271
- import path48 from "node:path";
11373
+ import path49 from "node:path";
11272
11374
 
11273
11375
  // src/core/verdict/docker-compose-run.ts
11274
- import path36 from "node:path";
11376
+ import path37 from "node:path";
11275
11377
 
11276
11378
  // src/core/verdict/recursive-invocation.ts
11277
- import path35 from "node:path";
11379
+ import path36 from "node:path";
11278
11380
  var SHELL_INTERPRETERS = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
11279
11381
  var PYTHON_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3"]);
11280
11382
  var SHELL_SHORT_OPTIONS = /* @__PURE__ */ new Set(["c", "l", "e", "x", "u"]);
@@ -11336,7 +11438,7 @@ var OSASCRIPT_PROFILE = {
11336
11438
  attachedValuePrefixes: []
11337
11439
  };
11338
11440
  function normalizeInterpreter(value) {
11339
- return path35.basename(value);
11441
+ return path36.basename(value);
11340
11442
  }
11341
11443
  function scriptResult(interpreter, token) {
11342
11444
  if (!token) {
@@ -11566,7 +11668,7 @@ function parseOptions(words, start, options) {
11566
11668
  function decodeDockerComposeRun(tokens) {
11567
11669
  if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
11568
11670
  const words = tokens.filter((token) => token.kind === "word");
11569
- const head = path36.basename(words[0]?.value ?? "");
11671
+ const head = path37.basename(words[0]?.value ?? "");
11570
11672
  let index;
11571
11673
  if (head === "docker-compose") {
11572
11674
  index = 1;
@@ -11607,7 +11709,7 @@ function decodeDockerComposeRun(tokens) {
11607
11709
  }
11608
11710
 
11609
11711
  // src/core/verdict/egress-classify.ts
11610
- import path37 from "node:path";
11712
+ import path38 from "node:path";
11611
11713
  var EGRESS_TOOL_HEADS = /* @__PURE__ */ new Set([
11612
11714
  "aws",
11613
11715
  "curl",
@@ -11656,7 +11758,7 @@ function isEgressToolHead(head) {
11656
11758
  return EGRESS_TOOL_HEADS.has(head);
11657
11759
  }
11658
11760
  function decodeEgressEffects(params) {
11659
- const head = path37.basename(params.tokens[0] ?? "");
11761
+ const head = path38.basename(params.tokens[0] ?? "");
11660
11762
  if (head !== "curl" && head !== "wget" && head !== "gh") {
11661
11763
  return null;
11662
11764
  }
@@ -11664,7 +11766,7 @@ function decodeEgressEffects(params) {
11664
11766
  const provenance = { segment: params.segment };
11665
11767
  const requirements = [];
11666
11768
  for (const file of decoded.files) {
11667
- const resolved = path37.resolve(params.cwd, expandHome2(file));
11769
+ const resolved = path38.resolve(params.cwd, expandHome2(file));
11668
11770
  requirements.push(
11669
11771
  requirement("fs.read", "fs.read", { kind: "path", path: resolved }, params.segment, [
11670
11772
  "egress.explicit_file_read"
@@ -11686,7 +11788,7 @@ function decodeEgressEffects(params) {
11686
11788
  if (file === "-") {
11687
11789
  continue;
11688
11790
  }
11689
- const resolved = path37.resolve(params.cwd, expandHome2(file));
11791
+ const resolved = path38.resolve(params.cwd, expandHome2(file));
11690
11792
  if (resolved === "/dev/null") {
11691
11793
  continue;
11692
11794
  }
@@ -12164,13 +12266,13 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
12164
12266
  if (head === "wget" && !explicitOutput) {
12165
12267
  outputFiles.push(
12166
12268
  ...endpointOutputNames.map(
12167
- (name) => outputDirectory ? path37.join(outputDirectory, name) : name
12269
+ (name) => outputDirectory ? path38.join(outputDirectory, name) : name
12168
12270
  )
12169
12271
  );
12170
12272
  } else if (head === "curl" && remoteNameOutput) {
12171
12273
  outputFiles.push(
12172
12274
  ...endpointOutputNames.map(
12173
- (name) => outputDirectory ? path37.join(outputDirectory, name) : name
12275
+ (name) => outputDirectory ? path38.join(outputDirectory, name) : name
12174
12276
  )
12175
12277
  );
12176
12278
  }
@@ -12184,7 +12286,7 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
12184
12286
  outputFiles: [
12185
12287
  ...new Set(
12186
12288
  outputFiles.map(
12187
- (file) => outputDirectory && directoryEligibleOutputs.has(file) && !path37.isAbsolute(file) ? path37.join(outputDirectory, file) : file
12289
+ (file) => outputDirectory && directoryEligibleOutputs.has(file) && !path38.isAbsolute(file) ? path38.join(outputDirectory, file) : file
12188
12290
  )
12189
12291
  )
12190
12292
  ],
@@ -12199,7 +12301,7 @@ function remoteOutputName(spec) {
12199
12301
  } catch {
12200
12302
  pathname = spec.split(/[?#]/, 1)[0] ?? "";
12201
12303
  }
12202
- const name = path37.posix.basename(pathname);
12304
+ const name = path38.posix.basename(pathname);
12203
12305
  return name && name !== "/" ? name : "index.html";
12204
12306
  }
12205
12307
  function decodeGhGrammar(tokens) {
@@ -12364,7 +12466,7 @@ function expandHome2(value) {
12364
12466
  return process.env.HOME ?? value;
12365
12467
  }
12366
12468
  if (value.startsWith("~/")) {
12367
- return path37.join(process.env.HOME ?? "~", value.slice(2));
12469
+ return path38.join(process.env.HOME ?? "~", value.slice(2));
12368
12470
  }
12369
12471
  return value;
12370
12472
  }
@@ -12383,7 +12485,7 @@ function requirement(tag, action, resource, segment, signals) {
12383
12485
  }
12384
12486
 
12385
12487
  // src/core/verdict/git-classifier.ts
12386
- import path38 from "node:path";
12488
+ import path39 from "node:path";
12387
12489
  init_shell_tokenizer();
12388
12490
  var GIT_BRANCH_MUTATION_FLAGS = /* @__PURE__ */ new Set([
12389
12491
  "--copy",
@@ -12479,7 +12581,7 @@ var FILE_OPERAND_SUBCOMMANDS = /* @__PURE__ */ new Set([
12479
12581
  var COMPOUND_SUBCOMMAND_HEADS = /* @__PURE__ */ new Set(["worktree", "stash", "tag"]);
12480
12582
  var REF_ONLY_WITHOUT_TERMINATOR = /* @__PURE__ */ new Set(["checkout", "show", "log"]);
12481
12583
  function isGitExecutable(token) {
12482
- return path38.basename(token) === "git";
12584
+ return path39.basename(token) === "git";
12483
12585
  }
12484
12586
  function takesValue(flag) {
12485
12587
  return flag === "-C" || flag === "-c" || flag === "--git-dir" || flag === "--work-tree" || flag === "--exec-path" || flag === "--paginate" || flag === "--config-env" || flag.startsWith("-C") || flag.startsWith("-c") || flag.startsWith("--git-dir=") || flag.startsWith("--work-tree=");
@@ -12507,7 +12609,7 @@ function peelGlobalOptions(tokens, baseCwd) {
12507
12609
  if (token === "-C" || token === "--work-tree" || token === "--git-dir" || token === "-c") {
12508
12610
  const value = tokens[index + 1];
12509
12611
  if (token === "-C" && value) {
12510
- effectiveCwd = path38.resolve(baseCwd, value);
12612
+ effectiveCwd = path39.resolve(baseCwd, value);
12511
12613
  } else if (token === "--work-tree" && value) {
12512
12614
  workTree = value;
12513
12615
  } else if (token === "--git-dir" && value) {
@@ -12517,7 +12619,7 @@ function peelGlobalOptions(tokens, baseCwd) {
12517
12619
  continue;
12518
12620
  }
12519
12621
  if (token.startsWith("-C") && token.length > 2) {
12520
- effectiveCwd = path38.resolve(baseCwd, token.slice(2));
12622
+ effectiveCwd = path39.resolve(baseCwd, token.slice(2));
12521
12623
  index += 1;
12522
12624
  continue;
12523
12625
  }
@@ -12660,7 +12762,7 @@ function looksLikeDiffPathOperand(token) {
12660
12762
  if (!looksLikeFileOperand(token)) {
12661
12763
  return false;
12662
12764
  }
12663
- if (token.startsWith(".") || path38.isAbsolute(token)) {
12765
+ if (token.startsWith(".") || path39.isAbsolute(token)) {
12664
12766
  return true;
12665
12767
  }
12666
12768
  return token.includes(".");
@@ -12668,12 +12770,12 @@ function looksLikeDiffPathOperand(token) {
12668
12770
  function resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir) {
12669
12771
  const resolveBase = effectiveCwd ?? baseCwd;
12670
12772
  if (workTree) {
12671
- return path38.resolve(resolveBase, workTree);
12773
+ return path39.resolve(resolveBase, workTree);
12672
12774
  }
12673
12775
  if (gitDir) {
12674
- const resolvedGitDir = path38.resolve(resolveBase, gitDir);
12675
- if (path38.basename(resolvedGitDir) === ".git") {
12676
- return path38.dirname(resolvedGitDir);
12776
+ const resolvedGitDir = path39.resolve(resolveBase, gitDir);
12777
+ if (path39.basename(resolvedGitDir) === ".git") {
12778
+ return path39.dirname(resolvedGitDir);
12677
12779
  }
12678
12780
  }
12679
12781
  return void 0;
@@ -12754,7 +12856,7 @@ function classifyGitCommand(tokens, baseCwd) {
12754
12856
  const { subcommand, args, effectiveCwd, gitDir, workTree } = normalized;
12755
12857
  const normalizedKey = `git ${subcommand}`;
12756
12858
  const gitWorkTree = resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir);
12757
- const effectiveGitDir = gitDir ? path38.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
12859
+ const effectiveGitDir = gitDir ? path39.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
12758
12860
  const scopeTargets = [effectiveCwd, gitWorkTree, effectiveGitDir].filter(
12759
12861
  (target, index, targets) => Boolean(target) && targets.indexOf(target) === index
12760
12862
  );
@@ -12906,9 +13008,9 @@ function decodeGitEffects(params) {
12906
13008
  ...subcommand === "push" ? ["tier0_external"] : []
12907
13009
  ];
12908
13010
  const effectiveCwd = normalized.effectiveCwd ?? params.cwd;
12909
- const workTreeRoot = normalized.workTree ? path38.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
12910
- const gitRefRoot = normalized.gitDir ? path38.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
12911
- const gitControlRoot = normalized.gitDir ? gitRefRoot : path38.join(gitRefRoot, ".git");
13011
+ const workTreeRoot = normalized.workTree ? path39.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
13012
+ const gitRefRoot = normalized.gitDir ? path39.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
13013
+ const gitControlRoot = normalized.gitDir ? gitRefRoot : path39.join(gitRefRoot, ".git");
12912
13014
  const requirements = [];
12913
13015
  if (subcommand === "fetch" || subcommand === "pull") {
12914
13016
  const positionals = gitRemotePositionals(args);
@@ -13067,7 +13169,7 @@ function decodeGitEffects(params) {
13067
13169
  gitRequirement(
13068
13170
  "control_plane.write",
13069
13171
  "control_plane.write",
13070
- { kind: "path", path: path38.join(gitControlRoot, "logs") },
13172
+ { kind: "path", path: path39.join(gitControlRoot, "logs") },
13071
13173
  params.segment,
13072
13174
  [...signals, "git_history_destructive", "git.reflog.mutate"]
13073
13175
  )
@@ -13125,7 +13227,7 @@ function decodeGitEffects(params) {
13125
13227
  gitRequirement(
13126
13228
  "fs.read",
13127
13229
  "fs.read",
13128
- { kind: "path", path: path38.resolve(workTreeRoot, operand) },
13230
+ { kind: "path", path: path39.resolve(workTreeRoot, operand) },
13129
13231
  params.segment,
13130
13232
  [...signals, "git.path.read"]
13131
13233
  )
@@ -13160,7 +13262,7 @@ function decodeGitEffects(params) {
13160
13262
  gitRequirement(
13161
13263
  "fs.write",
13162
13264
  "fs.write",
13163
- { kind: "path", path: path38.resolve(workTreeRoot, operand) },
13265
+ { kind: "path", path: path39.resolve(workTreeRoot, operand) },
13164
13266
  params.segment,
13165
13267
  [...signals, "git.path.write"]
13166
13268
  )
@@ -13344,8 +13446,8 @@ function gitRequirement(tag, action, resource, segment, signals) {
13344
13446
  }
13345
13447
 
13346
13448
  // src/core/verdict/launcher-resolve.ts
13347
- import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
13348
- import path39 from "node:path";
13449
+ import { existsSync as existsSync12, readFileSync as readFileSync5 } from "node:fs";
13450
+ import path40 from "node:path";
13349
13451
 
13350
13452
  // src/core/verdict/makefile-expand.ts
13351
13453
  var MAX_EXPAND_DEPTH = 16;
@@ -13518,8 +13620,8 @@ var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
13518
13620
  "why"
13519
13621
  ]);
13520
13622
  function readPackageJson(dir) {
13521
- const packagePath = path39.join(dir, "package.json");
13522
- if (!existsSync11(packagePath)) {
13623
+ const packagePath = path40.join(dir, "package.json");
13624
+ if (!existsSync12(packagePath)) {
13523
13625
  return null;
13524
13626
  }
13525
13627
  try {
@@ -13529,17 +13631,17 @@ function readPackageJson(dir) {
13529
13631
  }
13530
13632
  }
13531
13633
  function findPackageJson(startDir, stopDir) {
13532
- let current = path39.resolve(startDir);
13533
- const stop = path39.resolve(stopDir);
13634
+ let current = path40.resolve(startDir);
13635
+ const stop = path40.resolve(stopDir);
13534
13636
  while (true) {
13535
- const packagePath = path39.join(current, "package.json");
13536
- if (existsSync11(packagePath)) {
13637
+ const packagePath = path40.join(current, "package.json");
13638
+ if (existsSync12(packagePath)) {
13537
13639
  return packagePath;
13538
13640
  }
13539
- if (current === stop || current === path39.dirname(current)) {
13540
- return existsSync11(packagePath) ? packagePath : null;
13641
+ if (current === stop || current === path40.dirname(current)) {
13642
+ return existsSync12(packagePath) ? packagePath : null;
13541
13643
  }
13542
- const parent = path39.dirname(current);
13644
+ const parent = path40.dirname(current);
13543
13645
  if (!parent.startsWith(stop) && parent !== current) {
13544
13646
  }
13545
13647
  if (parent === current) {
@@ -13596,7 +13698,7 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
13596
13698
  }
13597
13699
  return { recipes: [], opaque: true, reason: "package_json_missing" };
13598
13700
  }
13599
- const pkg = readPackageJson(path39.dirname(packagePath));
13701
+ const pkg = readPackageJson(path40.dirname(packagePath));
13600
13702
  const scripts = pkg?.scripts;
13601
13703
  if (!scripts || typeof scripts !== "object") {
13602
13704
  return { recipes: [], opaque: true, reason: "package_scripts_missing" };
@@ -13687,20 +13789,20 @@ function parseMakefileRecipeContent(content) {
13687
13789
  function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
13688
13790
  const candidates = ["Makefile", "makefile", "GNUmakefile"];
13689
13791
  let makefilePath = null;
13690
- let searchDir = path39.resolve(cwd);
13691
- const stop = path39.resolve(repoRoot);
13792
+ let searchDir = path40.resolve(cwd);
13793
+ const stop = path40.resolve(repoRoot);
13692
13794
  while (true) {
13693
13795
  for (const name of candidates) {
13694
- const candidate = path39.join(searchDir, name);
13695
- if (existsSync11(candidate)) {
13796
+ const candidate = path40.join(searchDir, name);
13797
+ if (existsSync12(candidate)) {
13696
13798
  makefilePath = candidate;
13697
13799
  break;
13698
13800
  }
13699
13801
  }
13700
- if (makefilePath || searchDir === stop || searchDir === path39.dirname(searchDir)) {
13802
+ if (makefilePath || searchDir === stop || searchDir === path40.dirname(searchDir)) {
13701
13803
  break;
13702
13804
  }
13703
- searchDir = path39.dirname(searchDir);
13805
+ searchDir = path40.dirname(searchDir);
13704
13806
  }
13705
13807
  if (!makefilePath) {
13706
13808
  return { recipes: [], opaque: true, reason: "unknown_local_effect" };
@@ -13727,7 +13829,7 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
13727
13829
  }
13728
13830
  const entry = targets.get(name);
13729
13831
  if (!entry) {
13730
- if (!existsSync11(path39.resolve(path39.dirname(makefilePath), name))) {
13832
+ if (!existsSync12(path40.resolve(path40.dirname(makefilePath), name))) {
13731
13833
  hasUndefinedPrerequisite = true;
13732
13834
  }
13733
13835
  return;
@@ -13826,7 +13928,7 @@ function resolveLauncherRecipe(params) {
13826
13928
  }
13827
13929
 
13828
13930
  // src/core/verdict/parser.ts
13829
- import path40 from "node:path";
13931
+ import path41 from "node:path";
13830
13932
 
13831
13933
  // src/core/shell-substitution.ts
13832
13934
  function findStructuralCommandSubstitutions(command) {
@@ -14066,7 +14168,7 @@ var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
14066
14168
  ".sh"
14067
14169
  ]);
14068
14170
  function normalizeHead(token) {
14069
- const base = path40.basename(token);
14171
+ const base = path41.basename(token);
14070
14172
  if (base && base !== "." && base !== "..") {
14071
14173
  return base;
14072
14174
  }
@@ -14376,7 +14478,7 @@ function isBareInterpreter(tokens) {
14376
14478
  return false;
14377
14479
  }
14378
14480
  const scriptArg = args.find((token) => !token.startsWith("-"));
14379
- if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path40.extname(scriptArg))) {
14481
+ if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path41.extname(scriptArg))) {
14380
14482
  return false;
14381
14483
  }
14382
14484
  if (scriptArg) {
@@ -14616,7 +14718,7 @@ function mergeNodes(nodes) {
14616
14718
  }
14617
14719
 
14618
14720
  // src/core/effect-ir/shell-lower/argv-delegate-gate.ts
14619
- import path41 from "node:path";
14721
+ import path42 from "node:path";
14620
14722
  var ARGV_DELEGATE_INNER_BLOCKLIST = /* @__PURE__ */ new Set([
14621
14723
  "sudo",
14622
14724
  "env",
@@ -14637,7 +14739,7 @@ function shouldApplyArgvDelegate(head, innerTokens, depth) {
14637
14739
  if (ARGV_DELEGATE_INNER_BLOCKLIST.has(head)) {
14638
14740
  return false;
14639
14741
  }
14640
- const innerHead = path41.basename(innerTokens[0] ?? "");
14742
+ const innerHead = path42.basename(innerTokens[0] ?? "");
14641
14743
  if (ARGV_DELEGATE_INNER_BLOCKLIST.has(innerHead)) {
14642
14744
  return false;
14643
14745
  }
@@ -14744,7 +14846,7 @@ function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegm
14744
14846
 
14745
14847
  // src/core/effect-ir/shell-lower/tokens.ts
14746
14848
  init_shell_tokenizer();
14747
- import path42 from "node:path";
14849
+ import path43 from "node:path";
14748
14850
  var ENV_PREFIX_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
14749
14851
  var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1"]);
14750
14852
  var METADATA_ONLY_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V", "--help", "-h"]);
@@ -14888,9 +14990,9 @@ function resolvePathOperand(operand, cwd) {
14888
14990
  return process.env.HOME ?? operand;
14889
14991
  }
14890
14992
  if (operand.startsWith("~/")) {
14891
- return path42.join(process.env.HOME ?? "~", operand.slice(2));
14993
+ return path43.join(process.env.HOME ?? "~", operand.slice(2));
14892
14994
  }
14893
- return path42.resolve(cwd, operand);
14995
+ return path43.resolve(cwd, operand);
14894
14996
  }
14895
14997
  function isOptionToken(value) {
14896
14998
  return value.startsWith("-") || value.startsWith("+");
@@ -14902,7 +15004,7 @@ function pipeToShell(command) {
14902
15004
  return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
14903
15005
  }
14904
15006
  function executableBaseName(head) {
14905
- return path42.basename(head);
15007
+ return path43.basename(head);
14906
15008
  }
14907
15009
  function isMetadataOnlyArgv(argv) {
14908
15010
  return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
@@ -15021,15 +15123,22 @@ function effectChangingEnvironmentSignals(head, env, changedNames) {
15021
15123
  }
15022
15124
 
15023
15125
  // src/core/effect-ir/shell-lower/decode-process.ts
15024
- import path46 from "node:path";
15126
+ import path47 from "node:path";
15025
15127
 
15026
15128
  // src/core/effect-ir/shell-lower/decoders/belay.ts
15027
- import path43 from "node:path";
15129
+ import path44 from "node:path";
15028
15130
  function decodeBelay(args, repoRoot, segment) {
15029
15131
  const [section, operation, key] = args;
15030
15132
  const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
15031
15133
  const configRead = section === "config" && (operation === void 0 || operation === "list" || operation === "get" && key?.startsWith("judge."));
15032
15134
  const configJudgeMutation = section === "config" && (["set", "unset"].includes(operation ?? "") && key?.startsWith("judge.") || operation === "credential" && key === "mode");
15135
+ const approvalAuthorityCommand = [
15136
+ "approval-token",
15137
+ "approve",
15138
+ "revoke",
15139
+ "standing-allow"
15140
+ ].includes(section ?? "");
15141
+ const configTrustMutation = section === "config" && operation === "trust";
15033
15142
  if (judgeCommand || configRead || configJudgeMutation) {
15034
15143
  return [
15035
15144
  processRequirement("belay", "inspect", segment, [
@@ -15038,12 +15147,23 @@ function decodeBelay(args, repoRoot, segment) {
15038
15147
  ])
15039
15148
  ];
15040
15149
  }
15150
+ if (approvalAuthorityCommand || configTrustMutation) {
15151
+ return [
15152
+ requirement2(
15153
+ "control_plane.write",
15154
+ "control_plane.write",
15155
+ { kind: "path", path: path44.join(repoRoot, ".belay-control-plane") },
15156
+ segment,
15157
+ [approvalAuthorityCommand ? "belay.approval_authority" : "belay.config_trust"]
15158
+ )
15159
+ ];
15160
+ }
15041
15161
  if (section === "config" && ["set", "unset", "credential"].includes(operation ?? "")) {
15042
15162
  return [
15043
15163
  requirement2(
15044
15164
  "control_plane.write",
15045
15165
  "control_plane.write",
15046
- { kind: "path", path: path43.join(repoRoot, ".belay-control-plane") },
15166
+ { kind: "path", path: path44.join(repoRoot, ".belay-control-plane") },
15047
15167
  segment,
15048
15168
  ["belay.config_non_judge_mutation"]
15049
15169
  )
@@ -15284,7 +15404,7 @@ function validDockerInfo(args) {
15284
15404
  // src/core/effect-ir/shell-lower/decoders/filesystem.ts
15285
15405
  init_git_resource_identity();
15286
15406
  import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
15287
- import path44 from "node:path";
15407
+ import path45 from "node:path";
15288
15408
  function decodeCopyMove(head, args, cwd, segment) {
15289
15409
  const requirements = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
15290
15410
  const operands = [];
@@ -15412,11 +15532,11 @@ function decodeRm(args, cwd, repoRoot, segment) {
15412
15532
  function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
15413
15533
  try {
15414
15534
  if (finalOperandIsSymlink) {
15415
- return path44.join(realpathSync4.native(path44.dirname(targetPath)), path44.basename(targetPath));
15535
+ return path45.join(realpathSync4.native(path45.dirname(targetPath)), path45.basename(targetPath));
15416
15536
  }
15417
15537
  return realpathSync4.native(targetPath);
15418
15538
  } catch {
15419
- return path44.resolve(targetPath);
15539
+ return path45.resolve(targetPath);
15420
15540
  }
15421
15541
  }
15422
15542
  function isSymbolicLink(targetPath) {
@@ -15427,8 +15547,8 @@ function isSymbolicLink(targetPath) {
15427
15547
  }
15428
15548
  }
15429
15549
  function pathContains(ancestor, candidate) {
15430
- const relative = path44.relative(path44.resolve(ancestor), path44.resolve(candidate));
15431
- return relative === "" || !relative.startsWith("..") && !path44.isAbsolute(relative);
15550
+ const relative = path45.relative(path45.resolve(ancestor), path45.resolve(candidate));
15551
+ return relative === "" || !relative.startsWith("..") && !path45.isAbsolute(relative);
15432
15552
  }
15433
15553
  function filesystemReadOperands(head, args) {
15434
15554
  switch (head) {
@@ -15568,7 +15688,7 @@ function decodePrisma(args, env, repoRoot, segment) {
15568
15688
 
15569
15689
  // src/core/effect-ir/shell-lower/decoders/ruby.ts
15570
15690
  init_path_utils();
15571
- import path45 from "node:path";
15691
+ import path46 from "node:path";
15572
15692
  var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
15573
15693
  function railsReadOnlySubcommand(args) {
15574
15694
  const subcommand = args[0];
@@ -15578,7 +15698,7 @@ function railsReadOnlySubcommand(args) {
15578
15698
  return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
15579
15699
  }
15580
15700
  function isRubyTestScript(scriptPath) {
15581
- const base = path45.basename(scriptPath);
15701
+ const base = path46.basename(scriptPath);
15582
15702
  return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
15583
15703
  }
15584
15704
  function parseRubyTestInvocation(args) {
@@ -15992,7 +16112,7 @@ function decodeProcessOrFilesystem(params) {
15992
16112
  requirement2(
15993
16113
  "fs.read",
15994
16114
  "fs.read",
15995
- { kind: "path", path: path46.resolve(cwd, syntax) },
16115
+ { kind: "path", path: path47.resolve(cwd, syntax) },
15996
16116
  segment,
15997
16117
  ["shell.syntax_source_read"]
15998
16118
  )
@@ -16198,7 +16318,7 @@ function packageExecInnerIsMetadata(peel) {
16198
16318
 
16199
16319
  // src/core/effect-ir/shell-lower/segment.ts
16200
16320
  init_shell_tokenizer();
16201
- import path47 from "node:path";
16321
+ import path48 from "node:path";
16202
16322
  var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
16203
16323
  var SHELL_GLOB_PATTERN = /[*?[]/;
16204
16324
  function requiresKnownCwd(requirementValue) {
@@ -16213,11 +16333,11 @@ function joinNestedOpacity(outer, nested) {
16213
16333
  }
16214
16334
  function startsLocalPostgresService(command) {
16215
16335
  const tokens = tokenizeShell(command);
16216
- return path47.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
16336
+ return path48.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
16217
16337
  }
16218
16338
  function resolveCdTransition(command, currentCwd) {
16219
16339
  const tokens = tokenizeShell(command);
16220
- if (path47.basename(tokens[0] ?? "") !== "cd") {
16340
+ if (path48.basename(tokens[0] ?? "") !== "cd") {
16221
16341
  return null;
16222
16342
  }
16223
16343
  const target = tokens[1] ?? "~";
@@ -16380,7 +16500,7 @@ function lowerSegment(command, context) {
16380
16500
  stripStructuredRedirects(lexed.tokens),
16381
16501
  stripRedirects(parsedTokens)
16382
16502
  );
16383
- const head = path48.basename(tokens[0] ?? parsed.head);
16503
+ const head = path49.basename(tokens[0] ?? parsed.head);
16384
16504
  let opacity = segmentOpacity(command);
16385
16505
  const signals = /* @__PURE__ */ new Set();
16386
16506
  const requirements = [];
@@ -17232,7 +17352,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
17232
17352
  };
17233
17353
  }
17234
17354
  const signals = [];
17235
- const resolvedPath = path49.isAbsolute(filePath) ? filePath : path49.resolve(cwd, filePath);
17355
+ const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
17236
17356
  const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
17237
17357
  if (hitsProtectedRoot) {
17238
17358
  signals.push("control_plane_path");
@@ -17818,7 +17938,7 @@ function hashDecisionConfig(config) {
17818
17938
  init_fingerprint2();
17819
17939
 
17820
17940
  // src/version.ts
17821
- var PACKAGE_VERSION = "0.9.4";
17941
+ var PACKAGE_VERSION = "0.10.0";
17822
17942
 
17823
17943
  // src/runtime-provenance.ts
17824
17944
  function resolveRuntimeArtifactHash(artifactHash) {
@@ -17891,56 +18011,56 @@ function capabilityRequestsBlockRecovery(requests) {
17891
18011
  init_fingerprint2();
17892
18012
  init_path_utils();
17893
18013
  import { randomUUID as randomUUID5 } from "node:crypto";
17894
- import { existsSync as existsSync15 } from "node:fs";
17895
- import { mkdir as mkdir11, readdir as readdir3, readFile as readFile12, rename as rename3, rm as rm6 } from "node:fs/promises";
17896
- import path54 from "node:path";
18014
+ import { existsSync as existsSync16 } from "node:fs";
18015
+ import { mkdir as mkdir12, readdir as readdir3, readFile as readFile13, rename as rename4, rm as rm6 } from "node:fs/promises";
18016
+ import path55 from "node:path";
17897
18017
 
17898
18018
  // src/core/recovery/artifact-store.ts
17899
18019
  init_fingerprint2();
17900
18020
  init_path_utils();
17901
18021
  import { randomUUID as randomUUID4 } from "node:crypto";
17902
- import { existsSync as existsSync13 } from "node:fs";
17903
- import { lstat as lstat7, mkdir as mkdir10, open as open5, readdir as readdir2, readFile as readFile9, rename as rename2, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
17904
- import path51 from "node:path";
18022
+ import { existsSync as existsSync14 } from "node:fs";
18023
+ import { lstat as lstat7, mkdir as mkdir11, open as open6, readdir as readdir2, readFile as readFile10, rename as rename3, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
18024
+ import path52 from "node:path";
17905
18025
 
17906
18026
  // src/core/recovery/snapshot-node.ts
17907
18027
  init_fingerprint2();
17908
18028
  init_path_utils();
17909
18029
  import { createHash as createHash12 } from "node:crypto";
17910
- import { existsSync as existsSync12 } from "node:fs";
18030
+ import { existsSync as existsSync13 } from "node:fs";
17911
18031
  import {
17912
- chmod as chmod3,
18032
+ chmod as chmod4,
17913
18033
  copyFile as copyFile2,
17914
18034
  lstat as lstat6,
17915
- mkdir as mkdir9,
17916
- open as open4,
17917
- readFile as readFile8,
18035
+ mkdir as mkdir10,
18036
+ open as open5,
18037
+ readFile as readFile9,
17918
18038
  readlink as readlink4,
17919
18039
  rm as rm4,
17920
18040
  rmdir as rmdir2,
17921
18041
  symlink as symlink3,
17922
18042
  writeFile as writeFile6
17923
18043
  } from "node:fs/promises";
17924
- import path50 from "node:path";
18044
+ import path51 from "node:path";
17925
18045
  var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
17926
18046
  function validRecoveryRelativePath(relativePath) {
17927
- if (!relativePath || relativePath.includes("\0") || path50.isAbsolute(relativePath)) return false;
17928
- const normalized = path50.normalize(relativePath);
17929
- return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path50.sep}`);
18047
+ if (!relativePath || relativePath.includes("\0") || path51.isAbsolute(relativePath)) return false;
18048
+ const normalized = path51.normalize(relativePath);
18049
+ return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path51.sep}`);
17930
18050
  }
17931
18051
  async function assertRecoverySafeTarget(resourceRoot, relativePath) {
17932
18052
  if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
17933
18053
  const root = canonicalPath(resourceRoot);
17934
- const target = path50.resolve(root, relativePath);
17935
- const relative = path50.relative(root, target);
17936
- if (relative === ".." || relative.startsWith(`..${path50.sep}`) || path50.isAbsolute(relative)) {
18054
+ const target = path51.resolve(root, relativePath);
18055
+ const relative = path51.relative(root, target);
18056
+ if (relative === ".." || relative.startsWith(`..${path51.sep}`) || path51.isAbsolute(relative)) {
17937
18057
  throw new Error("recovery_path_escape");
17938
18058
  }
17939
18059
  let current = root;
17940
- const parentParts = path50.relative(root, path50.dirname(target)).split(path50.sep).filter(Boolean);
18060
+ const parentParts = path51.relative(root, path51.dirname(target)).split(path51.sep).filter(Boolean);
17941
18061
  for (const part of parentParts) {
17942
- current = path50.join(current, part);
17943
- if (!existsSync12(current)) break;
18062
+ current = path51.join(current, part);
18063
+ if (!existsSync13(current)) break;
17944
18064
  const info = await lstat6(current);
17945
18065
  if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
17946
18066
  if (!info.isDirectory()) break;
@@ -17948,7 +18068,7 @@ async function assertRecoverySafeTarget(resourceRoot, relativePath) {
17948
18068
  return target;
17949
18069
  }
17950
18070
  async function fsyncPath(filePath) {
17951
- const handle = await open4(filePath, "r");
18071
+ const handle = await open5(filePath, "r");
17952
18072
  try {
17953
18073
  await handle.sync();
17954
18074
  } finally {
@@ -17990,13 +18110,13 @@ async function captureRecoverySnapshot(filePath, options) {
17990
18110
  return { kind: "directory", mode, hash: recoveryDirectoryHash(mode) };
17991
18111
  }
17992
18112
  if (!info.isFile()) throw new Error(RECOVERY_UNSUPPORTED_FILE_KIND);
17993
- const content = await readFile8(filePath);
18113
+ const content = await readFile9(filePath);
17994
18114
  const hash = createHash12("sha256").update(content).digest("hex");
17995
18115
  let blob;
17996
18116
  if (options?.blobDir) {
17997
- await mkdir9(options.blobDir, { recursive: true, mode: 448 });
17998
- const blobPath = path50.join(options.blobDir, hash);
17999
- if (!existsSync12(blobPath)) {
18117
+ await mkdir10(options.blobDir, { recursive: true, mode: 448 });
18118
+ const blobPath = path51.join(options.blobDir, hash);
18119
+ if (!existsSync13(blobPath)) {
18000
18120
  await writeFile6(blobPath, content, { mode: 384 });
18001
18121
  await fsyncPath(blobPath);
18002
18122
  }
@@ -18050,7 +18170,7 @@ async function validateRecoverySnapshot(params) {
18050
18170
  if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
18051
18171
  let content;
18052
18172
  try {
18053
- content = await readFile8(path50.join(params.artifactDir, record.blob));
18173
+ content = await readFile9(path51.join(params.artifactDir, record.blob));
18054
18174
  } catch {
18055
18175
  throw new Error(params.corruptReason);
18056
18176
  }
@@ -18078,16 +18198,16 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
18078
18198
  ]);
18079
18199
  var STAGING_STALE_MS = 5 * 6e4;
18080
18200
  function checkpointsRoot(stateDir) {
18081
- return path51.join(stateDir, "recovery", "checkpoints");
18201
+ return path52.join(stateDir, "recovery", "checkpoints");
18082
18202
  }
18083
18203
  function checkpointDir(stateDir, checkpointId) {
18084
18204
  if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
18085
18205
  throw new Error("invalid_recovery_checkpoint_id");
18086
18206
  }
18087
- return path51.join(checkpointsRoot(stateDir), checkpointId);
18207
+ return path52.join(checkpointsRoot(stateDir), checkpointId);
18088
18208
  }
18089
18209
  async function fsyncPath2(filePath) {
18090
- const handle = await open5(filePath, "r");
18210
+ const handle = await open6(filePath, "r");
18091
18211
  try {
18092
18212
  await handle.sync();
18093
18213
  } finally {
@@ -18095,13 +18215,13 @@ async function fsyncPath2(filePath) {
18095
18215
  }
18096
18216
  }
18097
18217
  async function atomicWriteJson(filePath, value) {
18098
- await mkdir10(path51.dirname(filePath), { recursive: true, mode: 448 });
18218
+ await mkdir11(path52.dirname(filePath), { recursive: true, mode: 448 });
18099
18219
  const temporary = `${filePath}.tmp-${randomUUID4()}`;
18100
18220
  await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
18101
18221
  `, { mode: 384 });
18102
18222
  await fsyncPath2(temporary);
18103
- await rename2(temporary, filePath);
18104
- await fsyncPath2(path51.dirname(filePath));
18223
+ await rename3(temporary, filePath);
18224
+ await fsyncPath2(path52.dirname(filePath));
18105
18225
  }
18106
18226
  async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
18107
18227
  const value = {
@@ -18111,13 +18231,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
18111
18231
  manifestHash,
18112
18232
  ...detail ? { detail } : {}
18113
18233
  };
18114
- await atomicWriteJson(path51.join(artifactDir, "state.json"), value);
18234
+ await atomicWriteJson(path52.join(artifactDir, "state.json"), value);
18115
18235
  }
18116
18236
  async function directorySize(root) {
18117
- if (!existsSync13(root)) return 0;
18237
+ if (!existsSync14(root)) return 0;
18118
18238
  let total = 0;
18119
18239
  for (const entry of await readdir2(root, { withFileTypes: true })) {
18120
- const entryPath = path51.join(root, entry.name);
18240
+ const entryPath = path52.join(root, entry.name);
18121
18241
  if (entry.isDirectory()) total += await directorySize(entryPath);
18122
18242
  else total += (await lstat7(entryPath)).size;
18123
18243
  }
@@ -18162,9 +18282,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18162
18282
  let rawManifest;
18163
18283
  let state;
18164
18284
  try {
18165
- rawManifest = JSON.parse(await readFile9(path51.join(artifactDir, "manifest.json"), "utf8"));
18285
+ rawManifest = JSON.parse(await readFile10(path52.join(artifactDir, "manifest.json"), "utf8"));
18166
18286
  state = JSON.parse(
18167
- await readFile9(path51.join(artifactDir, "state.json"), "utf8")
18287
+ await readFile10(path52.join(artifactDir, "state.json"), "utf8")
18168
18288
  );
18169
18289
  } catch {
18170
18290
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
@@ -18180,10 +18300,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18180
18300
  }
18181
18301
  const entryPaths = /* @__PURE__ */ new Set();
18182
18302
  for (const entry of manifest.entries) {
18183
- if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(path51.normalize(entry.path))) {
18303
+ if (!entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).length !== 3 || !Object.keys(entry).every((key) => ["path", "before", "after"].includes(key)) || typeof entry.path !== "string" || !("before" in entry) || !("after" in entry) || !validRecoveryRelativePath(entry.path) || entryPaths.has(path52.normalize(entry.path))) {
18184
18304
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
18185
18305
  }
18186
- entryPaths.add(path51.normalize(entry.path));
18306
+ entryPaths.add(path52.normalize(entry.path));
18187
18307
  for (const [side, snapshot] of [
18188
18308
  ["before", entry.before],
18189
18309
  ["after", entry.after]
@@ -18197,9 +18317,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18197
18317
  });
18198
18318
  }
18199
18319
  }
18200
- const receiptPath = path51.join(artifactDir, "receipt.json");
18320
+ const receiptPath = path52.join(artifactDir, "receipt.json");
18201
18321
  let receipt;
18202
- if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
18322
+ if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync14(receiptPath)) {
18203
18323
  receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
18204
18324
  }
18205
18325
  return { artifactDir, manifest, state, manifestHash, ...receipt ? { receipt } : {} };
@@ -18207,7 +18327,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18207
18327
  async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
18208
18328
  let rawReceipt;
18209
18329
  try {
18210
- rawReceipt = JSON.parse(await readFile9(path51.join(artifactDir, "receipt.json"), "utf8"));
18330
+ rawReceipt = JSON.parse(await readFile10(path52.join(artifactDir, "receipt.json"), "utf8"));
18211
18331
  } catch {
18212
18332
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
18213
18333
  }
@@ -18230,8 +18350,8 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
18230
18350
  return receipt;
18231
18351
  }
18232
18352
  async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
18233
- const receiptPath = path51.join(artifactDir, "receipt.json");
18234
- if (existsSync13(receiptPath)) {
18353
+ const receiptPath = path52.join(artifactDir, "receipt.json");
18354
+ if (existsSync14(receiptPath)) {
18235
18355
  return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
18236
18356
  }
18237
18357
  const receipt = {
@@ -18248,14 +18368,14 @@ async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
18248
18368
  }
18249
18369
  async function checkpointIds(stateDir) {
18250
18370
  const root = checkpointsRoot(stateDir);
18251
- if (!existsSync13(root)) return [];
18371
+ if (!existsSync14(root)) return [];
18252
18372
  return (await readdir2(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^cp_[a-f0-9]{24}$/.test(entry.name)).map((entry) => entry.name);
18253
18373
  }
18254
18374
  async function artifactRepoRoot(stateDir, checkpointId) {
18255
18375
  const artifactDir = checkpointDir(stateDir, checkpointId);
18256
18376
  try {
18257
18377
  const manifest = JSON.parse(
18258
- await readFile9(path51.join(artifactDir, "manifest.json"), "utf8")
18378
+ await readFile10(path52.join(artifactDir, "manifest.json"), "utf8")
18259
18379
  );
18260
18380
  if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
18261
18381
  return canonicalPath(manifest.repoRoot);
@@ -18263,7 +18383,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
18263
18383
  } catch {
18264
18384
  }
18265
18385
  try {
18266
- const owner = JSON.parse(await readFile9(path51.join(artifactDir, "owner.json"), "utf8"));
18386
+ const owner = JSON.parse(await readFile10(path52.join(artifactDir, "owner.json"), "utf8"));
18267
18387
  return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
18268
18388
  } catch {
18269
18389
  return null;
@@ -18279,14 +18399,14 @@ async function checkpointIdsForRepo(stateDir, repoRoot) {
18279
18399
  }
18280
18400
  async function cleanupOrphanedStaging(stateDir) {
18281
18401
  const root = checkpointsRoot(stateDir);
18282
- if (!existsSync13(root)) return;
18402
+ if (!existsSync14(root)) return;
18283
18403
  const now = Date.now();
18284
18404
  for (const entry of await readdir2(root, { withFileTypes: true })) {
18285
18405
  if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
18286
- const stagingPath = path51.join(root, entry.name);
18406
+ const stagingPath = path52.join(root, entry.name);
18287
18407
  let stale = false;
18288
18408
  try {
18289
- const owner = JSON.parse(await readFile9(path51.join(stagingPath, "owner.json"), "utf8"));
18409
+ const owner = JSON.parse(await readFile10(path52.join(stagingPath, "owner.json"), "utf8"));
18290
18410
  const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
18291
18411
  const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
18292
18412
  let alive = false;
@@ -18326,9 +18446,9 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
18326
18446
 
18327
18447
  // src/core/recovery/reconcile.ts
18328
18448
  init_fingerprint2();
18329
- import { existsSync as existsSync14 } from "node:fs";
18330
- import { readFile as readFile10 } from "node:fs/promises";
18331
- import path52 from "node:path";
18449
+ import { existsSync as existsSync15 } from "node:fs";
18450
+ import { readFile as readFile11 } from "node:fs/promises";
18451
+ import path53 from "node:path";
18332
18452
  async function matchRecoverySide(resourceRoot, entries, side) {
18333
18453
  for (const entry of entries) {
18334
18454
  const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
@@ -18342,9 +18462,9 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
18342
18462
  loaded = await readRecoveryArtifact(stateDir, checkpointId);
18343
18463
  } catch {
18344
18464
  const artifactDir = checkpointDir(stateDir, checkpointId);
18345
- if (existsSync14(artifactDir)) {
18346
- const manifestPath = path52.join(artifactDir, "manifest.json");
18347
- const hash = existsSync14(manifestPath) ? hashValue(await readFile10(manifestPath, "utf8")) : "unavailable";
18465
+ if (existsSync15(artifactDir)) {
18466
+ const manifestPath = path53.join(artifactDir, "manifest.json");
18467
+ const hash = existsSync15(manifestPath) ? hashValue(await readFile11(manifestPath, "utf8")) : "unavailable";
18348
18468
  await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
18349
18469
  }
18350
18470
  return "corrupt";
@@ -18379,8 +18499,8 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
18379
18499
 
18380
18500
  // src/core/recovery/resource-identity.ts
18381
18501
  init_fingerprint2();
18382
- import { lstat as lstat8, readFile as readFile11, realpath as realpath3 } from "node:fs/promises";
18383
- import path53 from "node:path";
18502
+ import { lstat as lstat8, readFile as readFile12, realpath as realpath3 } from "node:fs/promises";
18503
+ import path54 from "node:path";
18384
18504
  async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
18385
18505
  const resolvedRoot = await realpath3(resourceRoot);
18386
18506
  if (resourceKind === "directory") {
@@ -18388,13 +18508,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
18388
18508
  if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
18389
18509
  return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
18390
18510
  }
18391
- const dotGit = path53.join(resolvedRoot, ".git");
18511
+ const dotGit = path54.join(resolvedRoot, ".git");
18392
18512
  const gitInfo = await lstat8(dotGit);
18393
18513
  let gitMetadataPath = dotGit;
18394
18514
  if (gitInfo.isFile()) {
18395
- const marker = (await readFile11(dotGit, "utf8")).trim();
18515
+ const marker = (await readFile12(dotGit, "utf8")).trim();
18396
18516
  if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
18397
- gitMetadataPath = path53.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
18517
+ gitMetadataPath = path54.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
18398
18518
  } else if (!gitInfo.isDirectory()) {
18399
18519
  throw new Error("recovery_repo_identity_unavailable");
18400
18520
  }
@@ -18459,7 +18579,7 @@ async function garbageCollect(stateDir, config, repoRoot) {
18459
18579
  async function prepareRecoveryCheckpoint(params) {
18460
18580
  const backend = params.backend ?? "git_worktree";
18461
18581
  const resourceKind = await resolveRecoveryResourceKind(backend, params.repoRoot);
18462
- await mkdir11(checkpointsRoot(params.stateDir), { recursive: true, mode: 448 });
18582
+ await mkdir12(checkpointsRoot(params.stateDir), { recursive: true, mode: 448 });
18463
18583
  await cleanupOrphanedStaging(params.stateDir);
18464
18584
  await garbageCollect(params.stateDir, params.config, params.repoRoot);
18465
18585
  const existing = await checkpointIdsForRepo(params.stateDir, params.repoRoot);
@@ -18467,16 +18587,16 @@ async function prepareRecoveryCheckpoint(params) {
18467
18587
  throw new Error(RECOVERY_CHECKPOINT_QUOTA);
18468
18588
  }
18469
18589
  const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
18470
- const temporary = path54.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
18590
+ const temporary = path55.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
18471
18591
  const finalDir = checkpointDir(params.stateDir, checkpointId);
18472
- await mkdir11(temporary, { recursive: true, mode: 448 });
18473
- await atomicWriteJson(path54.join(temporary, "owner.json"), {
18592
+ await mkdir12(temporary, { recursive: true, mode: 448 });
18593
+ await atomicWriteJson(path55.join(temporary, "owner.json"), {
18474
18594
  version: 1,
18475
18595
  pid: process.pid,
18476
18596
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
18477
18597
  repoRoot: canonicalPath(params.repoRoot)
18478
18598
  });
18479
- await mkdir11(path54.join(temporary, "blobs"), { recursive: true, mode: 448 });
18599
+ await mkdir12(path55.join(temporary, "blobs"), { recursive: true, mode: 448 });
18480
18600
  try {
18481
18601
  const entries = [];
18482
18602
  const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
@@ -18485,8 +18605,8 @@ async function prepareRecoveryCheckpoint(params) {
18485
18605
  )) {
18486
18606
  const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
18487
18607
  if (protectedRoots.some((root) => {
18488
- const relative = path54.relative(root, target);
18489
- return relative === "" || relative !== ".." && !relative.startsWith(`..${path54.sep}`) && !path54.isAbsolute(relative);
18608
+ const relative = path55.relative(root, target);
18609
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path55.sep}`) && !path55.isAbsolute(relative);
18490
18610
  })) {
18491
18611
  throw new Error("recovery_protected_path");
18492
18612
  }
@@ -18498,7 +18618,7 @@ async function prepareRecoveryCheckpoint(params) {
18498
18618
  entries.push({
18499
18619
  path: change.relativePath,
18500
18620
  before: await captureRecoverySnapshot(baseline, {
18501
- blobDir: path54.join(temporary, "blobs")
18621
+ blobDir: path55.join(temporary, "blobs")
18502
18622
  }),
18503
18623
  after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
18504
18624
  });
@@ -18535,12 +18655,12 @@ async function prepareRecoveryCheckpoint(params) {
18535
18655
  entries
18536
18656
  };
18537
18657
  const manifestHash = hashValue(canonicalStringify(manifest));
18538
- await atomicWriteJson(path54.join(temporary, "manifest.json"), manifest);
18658
+ await atomicWriteJson(path55.join(temporary, "manifest.json"), manifest);
18539
18659
  await writeRecoveryState(temporary, "prepared", manifestHash);
18540
18660
  await fsyncPath2(temporary);
18541
18661
  const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
18542
18662
  if (projectedBytes > params.config.maxBytes) throw new Error(RECOVERY_CHECKPOINT_QUOTA);
18543
- await rename3(temporary, finalDir);
18663
+ await rename4(temporary, finalDir);
18544
18664
  await fsyncPath2(checkpointsRoot(params.stateDir));
18545
18665
  return {
18546
18666
  checkpointId,
@@ -18578,7 +18698,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18578
18698
  } catch {
18579
18699
  try {
18580
18700
  const raw = JSON.parse(
18581
- await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18701
+ await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18582
18702
  );
18583
18703
  rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
18584
18704
  } catch {
@@ -18612,7 +18732,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18612
18732
  } catch {
18613
18733
  try {
18614
18734
  const manifest = JSON.parse(
18615
- await readFile12(path54.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18735
+ await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18616
18736
  );
18617
18737
  if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
18618
18738
  if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
@@ -18637,12 +18757,12 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18637
18757
  async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
18638
18758
  const root = checkpointsRoot(stateDir);
18639
18759
  if (!repoRoot) return directorySize(root);
18640
- if (!existsSync15(root)) return 0;
18760
+ if (!existsSync16(root)) return 0;
18641
18761
  const expected = canonicalPath(repoRoot);
18642
18762
  let total = 0;
18643
18763
  for (const entry of await readdir3(root, { withFileTypes: true })) {
18644
18764
  if (!entry.isDirectory()) continue;
18645
- const entryPath = path54.join(root, entry.name);
18765
+ const entryPath = path55.join(root, entry.name);
18646
18766
  if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
18647
18767
  if (await artifactRepoRoot(stateDir, entry.name) === expected) {
18648
18768
  total += await directorySize(entryPath);
@@ -18651,7 +18771,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
18651
18771
  }
18652
18772
  if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
18653
18773
  try {
18654
- const owner = JSON.parse(await readFile12(path54.join(entryPath, "owner.json"), "utf8"));
18774
+ const owner = JSON.parse(await readFile13(path55.join(entryPath, "owner.json"), "utf8"));
18655
18775
  if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
18656
18776
  total += await directorySize(entryPath);
18657
18777
  }
@@ -18693,16 +18813,16 @@ function recoveryFailClosedResult(predicted, reason, signals = []) {
18693
18813
  init_scrub();
18694
18814
 
18695
18815
  // src/core/transactional/file-checkpoint-backend.ts
18696
- import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
18816
+ import { cp, lstat as lstat11, mkdir as mkdir14, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
18697
18817
  import os5 from "node:os";
18698
- import path58 from "node:path";
18818
+ import path59 from "node:path";
18699
18819
 
18700
18820
  // src/core/transactional/file-checkpoint-git.ts
18701
18821
  init_path_utils();
18702
18822
  import { spawn as spawn8 } from "node:child_process";
18703
18823
  import { createHash as createHash13 } from "node:crypto";
18704
- import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile13 } from "node:fs/promises";
18705
- import path55 from "node:path";
18824
+ import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile14 } from "node:fs/promises";
18825
+ import path56 from "node:path";
18706
18826
  var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
18707
18827
  var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
18708
18828
  var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
@@ -18736,7 +18856,7 @@ function rethrowStableFileCheckpointError(error) {
18736
18856
  }
18737
18857
  async function rootGitMetadataPresent(repoRoot) {
18738
18858
  try {
18739
- await lstat9(path55.join(repoRoot, ".git"));
18859
+ await lstat9(path56.join(repoRoot, ".git"));
18740
18860
  return true;
18741
18861
  } catch {
18742
18862
  return false;
@@ -18785,10 +18905,10 @@ function execGit2(repoRoot, args) {
18785
18905
  }
18786
18906
  async function resolveGitPath(repoRoot, gitPath) {
18787
18907
  const trimmed = gitPath.trim();
18788
- if (path55.isAbsolute(trimmed)) {
18908
+ if (path56.isAbsolute(trimmed)) {
18789
18909
  return trimmed;
18790
18910
  }
18791
- return path55.join(repoRoot, trimmed);
18911
+ return path56.join(repoRoot, trimmed);
18792
18912
  }
18793
18913
  async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
18794
18914
  await execGit2(sourceRoot, [
@@ -18830,7 +18950,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
18830
18950
  destinationRoot,
18831
18951
  await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
18832
18952
  );
18833
- const destinationShared = path55.join(destinationGitDir, path55.basename(sourceShared));
18953
+ const destinationShared = path56.join(destinationGitDir, path56.basename(sourceShared));
18834
18954
  try {
18835
18955
  await copyFile3(sourceShared, destinationShared);
18836
18956
  } catch (error) {
@@ -18839,14 +18959,14 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
18839
18959
  }
18840
18960
  async function readGitFile(gitDir, relativePath) {
18841
18961
  try {
18842
- return await readFile13(path55.join(gitDir, relativePath));
18962
+ return await readFile14(path56.join(gitDir, relativePath));
18843
18963
  } catch {
18844
18964
  return null;
18845
18965
  }
18846
18966
  }
18847
18967
  async function readAbsoluteGitFile(absolutePath) {
18848
18968
  try {
18849
- return await readFile13(absolutePath);
18969
+ return await readFile14(absolutePath);
18850
18970
  } catch {
18851
18971
  return null;
18852
18972
  }
@@ -18863,8 +18983,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
18863
18983
  repoRoot,
18864
18984
  await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
18865
18985
  );
18866
- const relative = path55.resolve(resolved).startsWith(path55.resolve(gitDir)) ? path55.relative(gitDir, resolved) : resolved;
18867
- const content = typeof relative === "string" && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
18986
+ const relative = path56.resolve(resolved).startsWith(path56.resolve(gitDir)) ? path56.relative(gitDir, resolved) : resolved;
18987
+ const content = typeof relative === "string" && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
18868
18988
  if (content !== null) {
18869
18989
  hashGitFileContent(hash, gitPath, content);
18870
18990
  }
@@ -18874,13 +18994,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
18874
18994
  async function hashGitTree(gitDir, relativeDir, hash) {
18875
18995
  let names;
18876
18996
  try {
18877
- names = await readdir4(path55.join(gitDir, relativeDir));
18997
+ names = await readdir4(path56.join(gitDir, relativeDir));
18878
18998
  } catch {
18879
18999
  return;
18880
19000
  }
18881
19001
  for (const name of names.sort()) {
18882
- const relativePath = relativeDir ? path55.join(relativeDir, name) : name;
18883
- const absolutePath = path55.join(gitDir, relativePath);
19002
+ const relativePath = relativeDir ? path56.join(relativeDir, name) : name;
19003
+ const absolutePath = path56.join(gitDir, relativePath);
18884
19004
  let childNames = null;
18885
19005
  try {
18886
19006
  childNames = await readdir4(absolutePath);
@@ -18902,7 +19022,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
18902
19022
  }
18903
19023
  async function computeGitMetadataFingerprint(repoRoot) {
18904
19024
  const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
18905
- const gitDir = path55.isAbsolute(gitDirRel) ? gitDirRel : path55.join(repoRoot, gitDirRel);
19025
+ const gitDir = path56.isAbsolute(gitDirRel) ? gitDirRel : path56.join(repoRoot, gitDirRel);
18906
19026
  const hash = createHash13("sha256");
18907
19027
  for (const file of [
18908
19028
  "HEAD",
@@ -18925,8 +19045,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
18925
19045
  const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
18926
19046
  if (sharedIndex) {
18927
19047
  const resolved = await resolveGitPath(repoRoot, sharedIndex);
18928
- const relative = path55.relative(gitDir, resolved);
18929
- const content = relative && !relative.startsWith("..") && !path55.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
19048
+ const relative = path56.relative(gitDir, resolved);
19049
+ const content = relative && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
18930
19050
  if (content !== null) {
18931
19051
  hashGitFileContent(hash, "shared-index", content);
18932
19052
  }
@@ -18937,7 +19057,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
18937
19057
  await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
18938
19058
  }
18939
19059
  try {
18940
- const rootGitPath = path55.join(repoRoot, ".git");
19060
+ const rootGitPath = path56.join(repoRoot, ".git");
18941
19061
  const rootGitInfo = await lstat9(rootGitPath);
18942
19062
  if (rootGitInfo.isFile()) {
18943
19063
  const content = await readAbsoluteGitFile(rootGitPath);
@@ -18953,14 +19073,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
18953
19073
  function resolveExecutionCwdRelative(resourceRoot, cwd) {
18954
19074
  const resolvedCwd = canonicalPath(cwd);
18955
19075
  const resourceCanonical = canonicalPath(resourceRoot);
18956
- const relative = path55.relative(resourceCanonical, resolvedCwd);
19076
+ const relative = path56.relative(resourceCanonical, resolvedCwd);
18957
19077
  if (relative === "" || relative === ".") {
18958
19078
  return "";
18959
19079
  }
18960
- if (relative.startsWith("..") || path55.isAbsolute(relative)) {
19080
+ if (relative.startsWith("..") || path56.isAbsolute(relative)) {
18961
19081
  throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
18962
19082
  }
18963
- return relative.split(path55.sep).join("/");
19083
+ return relative.split(path56.sep).join("/");
18964
19084
  }
18965
19085
 
18966
19086
  // src/core/transactional/file-checkpoint-isolation.ts
@@ -18981,8 +19101,8 @@ function fileCheckpointIsolationReason(context) {
18981
19101
  }
18982
19102
 
18983
19103
  // src/core/transactional/file-checkpoint-staging.ts
18984
- import { readdir as readdir5, readFile as readFile14, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
18985
- import path56 from "node:path";
19104
+ import { readdir as readdir5, readFile as readFile15, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
19105
+ import path57 from "node:path";
18986
19106
  function isOwnerProcessAlive(pid) {
18987
19107
  try {
18988
19108
  process.kill(pid, 0);
@@ -18992,12 +19112,12 @@ function isOwnerProcessAlive(pid) {
18992
19112
  }
18993
19113
  }
18994
19114
  async function writeOwnerMarker(stagingRoot, marker) {
18995
- await writeFile8(path56.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
19115
+ await writeFile8(path57.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
18996
19116
  `, "utf8");
18997
19117
  }
18998
19118
  async function readOwnerMarker(stagingRoot) {
18999
19119
  try {
19000
- const raw = await readFile14(path56.join(stagingRoot, "owner.json"), "utf8");
19120
+ const raw = await readFile15(path57.join(stagingRoot, "owner.json"), "utf8");
19001
19121
  return JSON.parse(raw.trim());
19002
19122
  } catch {
19003
19123
  return null;
@@ -19015,7 +19135,7 @@ async function collectDeadOwnerStaging(parentDir) {
19015
19135
  if (!name.startsWith("belay-file-checkpoint-")) {
19016
19136
  continue;
19017
19137
  }
19018
- const stagingRoot = path56.join(parentDir, name);
19138
+ const stagingRoot = path57.join(parentDir, name);
19019
19139
  const marker = await readOwnerMarker(stagingRoot);
19020
19140
  if (!marker) {
19021
19141
  dead.push(stagingRoot);
@@ -19038,7 +19158,7 @@ import { constants as fsConstants2 } from "node:fs";
19038
19158
  import {
19039
19159
  copyFile as copyFile4,
19040
19160
  lstat as lstat10,
19041
- mkdir as mkdir12,
19161
+ mkdir as mkdir13,
19042
19162
  mkdtemp as mkdtemp4,
19043
19163
  readlink as readlink5,
19044
19164
  rm as rm8,
@@ -19047,17 +19167,17 @@ import {
19047
19167
  writeFile as writeFile9
19048
19168
  } from "node:fs/promises";
19049
19169
  import os4 from "node:os";
19050
- import path57 from "node:path";
19170
+ import path58 from "node:path";
19051
19171
  var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
19052
19172
  async function chmodSafe2(target, mode) {
19053
19173
  try {
19054
- const { chmod: chmod4 } = await import("node:fs/promises");
19055
- await chmod4(target, mode & 511);
19174
+ const { chmod: chmod5 } = await import("node:fs/promises");
19175
+ await chmod5(target, mode & 511);
19056
19176
  } catch {
19057
19177
  }
19058
19178
  }
19059
19179
  async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
19060
- await mkdir12(path57.dirname(destinationPath), { recursive: true });
19180
+ await mkdir13(path58.dirname(destinationPath), { recursive: true });
19061
19181
  if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
19062
19182
  try {
19063
19183
  await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
@@ -19079,11 +19199,11 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
19079
19199
  const info = await lstat10(sourcePath);
19080
19200
  await rm8(destinationPath, { force: true, recursive: false });
19081
19201
  if (info.isDirectory() && !info.isSymbolicLink()) {
19082
- await mkdir12(destinationPath, { recursive: true, mode: info.mode & 511 });
19202
+ await mkdir13(destinationPath, { recursive: true, mode: info.mode & 511 });
19083
19203
  return strategy;
19084
19204
  }
19085
19205
  if (info.isSymbolicLink()) {
19086
- await mkdir12(path57.dirname(destinationPath), { recursive: true });
19206
+ await mkdir13(path58.dirname(destinationPath), { recursive: true });
19087
19207
  await symlink4(await readlink5(sourcePath), destinationPath);
19088
19208
  return strategy;
19089
19209
  }
@@ -19139,9 +19259,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
19139
19259
  async function probeFileCloneStrategy() {
19140
19260
  let tempDir = null;
19141
19261
  try {
19142
- tempDir = await mkdtemp4(path57.join(os4.tmpdir(), "belay-clone-probe-"));
19143
- const source = path57.join(tempDir, "source.txt");
19144
- const destination = path57.join(tempDir, "dest.txt");
19262
+ tempDir = await mkdtemp4(path58.join(os4.tmpdir(), "belay-clone-probe-"));
19263
+ const source = path58.join(tempDir, "source.txt");
19264
+ const destination = path58.join(tempDir, "dest.txt");
19145
19265
  await writeFile9(source, "probe\n");
19146
19266
  if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
19147
19267
  try {
@@ -19294,11 +19414,11 @@ async function protectedRootState(root) {
19294
19414
  return `directory:${node.hash}:${index.treeHash}`;
19295
19415
  }
19296
19416
  function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
19297
- const relative = path58.relative(path58.resolve(resourceRoot), path58.resolve(protectedRoot));
19298
- if (relative === "" || relative.startsWith("..") || path58.isAbsolute(relative)) {
19417
+ const relative = path59.relative(path59.resolve(resourceRoot), path59.resolve(protectedRoot));
19418
+ if (relative === "" || relative.startsWith("..") || path59.isAbsolute(relative)) {
19299
19419
  return null;
19300
19420
  }
19301
- return path58.join(executionRoot, relative);
19421
+ return path59.join(executionRoot, relative);
19302
19422
  }
19303
19423
  async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
19304
19424
  const states = /* @__PURE__ */ new Map();
@@ -19323,15 +19443,15 @@ async function directoryByteSize(root, deadlineMs) {
19323
19443
  }
19324
19444
  let total = 0;
19325
19445
  for (const name of await readdir6(root)) {
19326
- total += await directoryByteSize(path58.join(root, name), deadlineMs);
19446
+ total += await directoryByteSize(path59.join(root, name), deadlineMs);
19327
19447
  }
19328
19448
  return total;
19329
19449
  }
19330
19450
  async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
19331
19451
  const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
19332
- const sourceGitDir = path58.isAbsolute(gitDirRel) ? gitDirRel : path58.join(sourceRoot, gitDirRel);
19333
- const relativeGitDir = path58.relative(path58.resolve(sourceRoot), path58.resolve(sourceGitDir));
19334
- const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path58.join(destinationRoot, relativeGitDir) : path58.join(destinationRoot, ".git");
19452
+ const sourceGitDir = path59.isAbsolute(gitDirRel) ? gitDirRel : path59.join(sourceRoot, gitDirRel);
19453
+ const relativeGitDir = path59.relative(path59.resolve(sourceRoot), path59.resolve(sourceGitDir));
19454
+ const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path59.join(destinationRoot, relativeGitDir) : path59.join(destinationRoot, ".git");
19335
19455
  await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
19336
19456
  }
19337
19457
  async function prepareDirtyGitSnapshot(context) {
@@ -19340,7 +19460,7 @@ async function prepareDirtyGitSnapshot(context) {
19340
19460
  const quotas = context.fileCheckpoint;
19341
19461
  const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
19342
19462
  await removeDeadOwnerStaging(os5.tmpdir());
19343
- const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
19463
+ const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
19344
19464
  await writeOwnerMarker(stagingRoot, {
19345
19465
  version: 1,
19346
19466
  pid: process.pid,
@@ -19348,8 +19468,8 @@ async function prepareDirtyGitSnapshot(context) {
19348
19468
  resourceRoot: context.repoRoot,
19349
19469
  backend: "file_checkpoint"
19350
19470
  });
19351
- const baselineRoot = path58.join(stagingRoot, "baseline");
19352
- const executionRoot = path58.join(stagingRoot, "execution");
19471
+ const baselineRoot = path59.join(stagingRoot, "baseline");
19472
+ const executionRoot = path59.join(stagingRoot, "execution");
19353
19473
  try {
19354
19474
  resolveExecutionCwdRelative(context.repoRoot, context.cwd);
19355
19475
  const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
@@ -19383,7 +19503,7 @@ async function prepareDirtyGitSnapshot(context) {
19383
19503
  throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
19384
19504
  }
19385
19505
  await writeFile10(
19386
- path58.join(stagingRoot, "baseline-index.json"),
19506
+ path59.join(stagingRoot, "baseline-index.json"),
19387
19507
  `${JSON.stringify(baselineIndex)}
19388
19508
  `,
19389
19509
  "utf8"
@@ -19433,7 +19553,7 @@ async function prepareNonGitSnapshot(context) {
19433
19553
  const quotas = context.fileCheckpoint;
19434
19554
  const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
19435
19555
  await removeDeadOwnerStaging(os5.tmpdir());
19436
- const stagingRoot = await mkdtemp5(path58.join(os5.tmpdir(), "belay-file-checkpoint-"));
19556
+ const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
19437
19557
  await writeOwnerMarker(stagingRoot, {
19438
19558
  version: 1,
19439
19559
  pid: process.pid,
@@ -19441,8 +19561,8 @@ async function prepareNonGitSnapshot(context) {
19441
19561
  resourceRoot: context.repoRoot,
19442
19562
  backend: "file_checkpoint"
19443
19563
  });
19444
- const baselineRoot = path58.join(stagingRoot, "baseline");
19445
- const executionRoot = path58.join(stagingRoot, "execution");
19564
+ const baselineRoot = path59.join(stagingRoot, "baseline");
19565
+ const executionRoot = path59.join(stagingRoot, "execution");
19446
19566
  try {
19447
19567
  resolveExecutionCwdRelative(context.repoRoot, context.cwd);
19448
19568
  const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
@@ -19451,7 +19571,7 @@ async function prepareNonGitSnapshot(context) {
19451
19571
  quotas,
19452
19572
  deadlineMs
19453
19573
  });
19454
- await mkdir13(baselineRoot, { recursive: true });
19574
+ await mkdir14(baselineRoot, { recursive: true });
19455
19575
  const baselineIndex = await buildFileTreeIndex({
19456
19576
  resourceRoot: baselineRoot,
19457
19577
  excludedRoots,
@@ -19471,7 +19591,7 @@ async function prepareNonGitSnapshot(context) {
19471
19591
  throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
19472
19592
  }
19473
19593
  await writeFile10(
19474
- path58.join(stagingRoot, "baseline-index.json"),
19594
+ path59.join(stagingRoot, "baseline-index.json"),
19475
19595
  `${JSON.stringify(baselineIndex)}
19476
19596
  `,
19477
19597
  "utf8"
@@ -19481,7 +19601,7 @@ async function prepareNonGitSnapshot(context) {
19481
19601
  quotas,
19482
19602
  deadlineMs
19483
19603
  });
19484
- await mkdir13(executionRoot, { recursive: true });
19604
+ await mkdir14(executionRoot, { recursive: true });
19485
19605
  const finalSourceIndex = await buildFileTreeIndex({
19486
19606
  resourceRoot: context.repoRoot,
19487
19607
  excludedRoots,
@@ -19824,10 +19944,10 @@ async function selectTransactionalBackend(context) {
19824
19944
  }
19825
19945
 
19826
19946
  // src/core/transactional/diff-evaluator.ts
19827
- import path59 from "node:path";
19947
+ import path60 from "node:path";
19828
19948
  init_path_utils();
19829
19949
  function categorizeChange(change, ctx) {
19830
- const absolutePath = canonicalPath(path59.join(ctx.repoRoot, change.relativePath));
19950
+ const absolutePath = canonicalPath(path60.join(ctx.repoRoot, change.relativePath));
19831
19951
  if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
19832
19952
  return "repo_outside";
19833
19953
  }
@@ -20377,17 +20497,55 @@ function formatJudgeInfrastructureDenyMessage(params) {
20377
20497
  }
20378
20498
 
20379
20499
  // src/core/notify.ts
20500
+ init_path_utils();
20380
20501
  import { execFile } from "node:child_process";
20502
+ import path61 from "node:path";
20381
20503
  import { promisify } from "node:util";
20382
20504
  var execFileAsync = promisify(execFile);
20383
- async function notifyDeny(config, event) {
20384
- const payload = JSON.stringify(event);
20385
- if (config.webhookUrl) {
20505
+ var LOOPBACK_WEBHOOK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
20506
+ function webhookConfigIssue(url) {
20507
+ let parsed;
20508
+ try {
20509
+ parsed = new URL(url);
20510
+ } catch {
20511
+ return `notifications.webhookUrl is invalid: ${url}`;
20512
+ }
20513
+ if (parsed.protocol === "https:") {
20514
+ return null;
20515
+ }
20516
+ const normalizedHostname = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, "");
20517
+ if (parsed.protocol === "http:" && LOOPBACK_WEBHOOK_HOSTS.has(normalizedHostname)) {
20518
+ return null;
20519
+ }
20520
+ return `notifications.webhookUrl must use https (http is allowed only for localhost, 127.0.0.1, or ::1): ${url}`;
20521
+ }
20522
+ function commandHookConfigIssue(commandHook, repoRoot) {
20523
+ if (!path61.isAbsolute(commandHook)) {
20524
+ return `notifications.commandHook must be an absolute path: ${commandHook}`;
20525
+ }
20526
+ if (pathWithinRoot(canonicalPath(repoRoot), canonicalPath(commandHook))) {
20527
+ return `notifications.commandHook must not be inside the repository: ${commandHook}`;
20528
+ }
20529
+ return null;
20530
+ }
20531
+ async function notifyDeny(config, event, deps = {
20532
+ fetch: globalThis.fetch.bind(globalThis),
20533
+ execFile: (file, args, options) => execFileAsync(file, [...args], options)
20534
+ }) {
20535
+ const payload = JSON.stringify({
20536
+ approvalId: event.approvalId,
20537
+ reason: event.reason,
20538
+ summary: event.summary,
20539
+ repoRoot: event.repoRoot,
20540
+ fingerprint: event.fingerprint
20541
+ });
20542
+ const webhookIssue = config.webhookUrl ? webhookConfigIssue(config.webhookUrl) : null;
20543
+ if (config.webhookUrl && !webhookIssue) {
20386
20544
  try {
20387
20545
  const controller = new AbortController();
20388
20546
  const timeout = setTimeout(() => controller.abort(), 5e3);
20389
20547
  try {
20390
- await fetch(config.webhookUrl, {
20548
+ await deps.fetch(config.webhookUrl, {
20391
20549
  method: "POST",
20392
20550
  headers: { "content-type": "application/json" },
20393
20551
  body: payload,
@@ -20399,17 +20557,16 @@ async function notifyDeny(config, event) {
20399
20557
  } catch {
20400
20558
  }
20401
20559
  }
20402
- if (config.commandHook) {
20560
+ const commandHookIssue = config.commandHook ? commandHookConfigIssue(config.commandHook, event.repoRoot) : null;
20561
+ if (config.commandHook && !commandHookIssue) {
20403
20562
  try {
20404
- await execFileAsync(config.commandHook, [], {
20563
+ await deps.execFile(config.commandHook, [], {
20405
20564
  env: {
20406
- ...process.env,
20407
20565
  BELAY_APPROVAL_ID: event.approvalId,
20408
20566
  BELAY_REASON: event.reason,
20409
20567
  BELAY_SUMMARY: event.summary,
20410
20568
  BELAY_REPO_ROOT: event.repoRoot,
20411
- BELAY_FINGERPRINT: event.fingerprint,
20412
- BELAY_APPROVAL_TOKEN: event.approvalToken ?? ""
20569
+ BELAY_FINGERPRINT: event.fingerprint
20413
20570
  }
20414
20571
  });
20415
20572
  } catch {
@@ -20419,9 +20576,10 @@ async function notifyDeny(config, event) {
20419
20576
 
20420
20577
  // src/adapters/shared/gate-runtime.ts
20421
20578
  init_path_utils();
20579
+ init_repo_config_trust();
20422
20580
 
20423
20581
  // src/adapters/layouts/protected-paths.ts
20424
- import path60 from "node:path";
20582
+ import path62 from "node:path";
20425
20583
  function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
20426
20584
  const roots = [
20427
20585
  layout.configPath(repoRoot),
@@ -20433,7 +20591,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
20433
20591
  if (controlPlaneDir) {
20434
20592
  roots.push(controlPlaneDir);
20435
20593
  }
20436
- return roots.map((entry) => path60.resolve(entry));
20594
+ return roots.map((entry) => path62.resolve(entry));
20437
20595
  }
20438
20596
 
20439
20597
  // src/adapters/shared/gate-runtime.ts
@@ -20474,7 +20632,7 @@ async function appendReplayAuditSafely(ctx, deps, event) {
20474
20632
  }
20475
20633
  async function loadJsonFile(filePath, fallback) {
20476
20634
  try {
20477
- const raw = await readFile15(filePath, "utf8");
20635
+ const raw = await readFile16(filePath, "utf8");
20478
20636
  return JSON.parse(raw);
20479
20637
  } catch {
20480
20638
  return fallback;
@@ -20483,11 +20641,18 @@ async function loadJsonFile(filePath, fallback) {
20483
20641
  function createDefaultGateRuntimeDeps() {
20484
20642
  return {
20485
20643
  async readConfig(configPath) {
20486
- return loadJsonFile(configPath, {});
20644
+ try {
20645
+ return JSON.parse(await readFile16(configPath, "utf8"));
20646
+ } catch (error) {
20647
+ if (error.code === "ENOENT") {
20648
+ return {};
20649
+ }
20650
+ throw error;
20651
+ }
20487
20652
  },
20488
20653
  async appendAudit(ctx, event) {
20489
- const auditPath = path61.join(ctx.repoRoot, ctx.config.audit.logPath);
20490
- await mkdir14(path61.dirname(auditPath), { recursive: true });
20654
+ const auditPath = path63.join(ctx.repoRoot, ctx.config.audit.logPath);
20655
+ await mkdir15(path63.dirname(auditPath), { recursive: true });
20491
20656
  const provenance = auditProvenance(ctx.config);
20492
20657
  const record = {
20493
20658
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -20520,7 +20685,7 @@ function createDefaultGateRuntimeDeps() {
20520
20685
  };
20521
20686
  },
20522
20687
  async writeApprovals(filePath, state) {
20523
- await mkdir14(path61.dirname(filePath), { recursive: true });
20688
+ await mkdir15(path63.dirname(filePath), { recursive: true });
20524
20689
  await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
20525
20690
  `, "utf8");
20526
20691
  },
@@ -20541,10 +20706,11 @@ function createDefaultGateRuntimeDeps() {
20541
20706
  }
20542
20707
  async function resolveGateConfig(ctx, deps) {
20543
20708
  const loaded = await deps.readConfig(ctx.configPath);
20709
+ await assertRepoConfigTrusted(ctx.repoRoot, ctx.layout.name, loaded);
20544
20710
  let teamConfig = null;
20545
20711
  const teamPath = teamConfigPath();
20546
- if (existsSync16(teamPath)) {
20547
- teamConfig = JSON.parse(await readFile15(teamPath, "utf8"));
20712
+ if (existsSync17(teamPath)) {
20713
+ teamConfig = JSON.parse(await readFile16(teamPath, "utf8"));
20548
20714
  }
20549
20715
  return resolveLayeredConfig({
20550
20716
  repoConfig: loaded,
@@ -20682,7 +20848,7 @@ function deriveWorkspaceRootScopeHint(params) {
20682
20848
  if (!targetPath) {
20683
20849
  return void 0;
20684
20850
  }
20685
- const candidateRoot = canonicalPath(path61.dirname(targetPath));
20851
+ const candidateRoot = canonicalPath(path63.dirname(targetPath));
20686
20852
  const validation = validateTrustedWorkspaceRootCandidate({
20687
20853
  candidatePath: candidateRoot,
20688
20854
  repoRoot: action.repoRoot,
@@ -21073,7 +21239,21 @@ async function evaluateGatedAction(ctx, deps, params) {
21073
21239
  ...authorization,
21074
21240
  egressProxyActive
21075
21241
  };
21076
- const predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
21242
+ let predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
21243
+ if (action.kind === "tool" && predicted.reason === "unclassified_tool" && (ctx.config.policy.codexUnmappedTool ?? "deny") === "deny") {
21244
+ predicted = {
21245
+ ...predicted,
21246
+ verdict: "deny_pending_approval",
21247
+ reason: "unmapped_tool",
21248
+ assessment: {
21249
+ reversibility: "irreversible",
21250
+ external: false,
21251
+ blastRadius: "unknown tool action",
21252
+ confidence: 0.5,
21253
+ signals: ["unmapped_tool"]
21254
+ }
21255
+ };
21256
+ }
21077
21257
  if (action.kind === "shell" && action.command && isContainedUnknownExecutionEligible(ctx.config, action, predicted)) {
21078
21258
  const mediated = await mediateContainedUnknownExecution({
21079
21259
  ctx,
@@ -21292,7 +21472,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21292
21472
  event: auditEvent,
21293
21473
  sourceEvent,
21294
21474
  kind,
21295
- repoLabel: path61.basename(ctx.repoRoot),
21475
+ repoLabel: path63.basename(ctx.repoRoot),
21296
21476
  ...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
21297
21477
  fingerprint: result.fingerprint,
21298
21478
  summary: result.normalizedCommand ?? result.summary ?? "",
@@ -21324,21 +21504,6 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21324
21504
  if (created) {
21325
21505
  await recordGateApprovalAsk(stateDir, result.reason, false);
21326
21506
  }
21327
- let approvalToken;
21328
- try {
21329
- approvalToken = await issueApprovalToken(
21330
- {
21331
- approvalId: approval.approvalId,
21332
- fingerprint: approval.fingerprint,
21333
- repoRoot: approval.repoRoot,
21334
- issuedAt: approval.createdAt,
21335
- expiresAt: approval.expiresAt
21336
- },
21337
- configuredControlPlaneDir(ctx.config)
21338
- );
21339
- } catch {
21340
- approvalToken = void 0;
21341
- }
21342
21507
  const denialReason = failure?.reason ?? result.reason;
21343
21508
  if (ctx.config.notifications.webhookUrl || ctx.config.notifications.commandHook) {
21344
21509
  await notifyDeny(ctx.config.notifications, {
@@ -21346,8 +21511,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21346
21511
  reason: denialReason,
21347
21512
  summary: result.normalizedCommand ?? result.summary ?? "",
21348
21513
  repoRoot: ctx.repoRoot,
21349
- fingerprint: result.fingerprint,
21350
- approvalToken
21514
+ fingerprint: result.fingerprint
21351
21515
  });
21352
21516
  }
21353
21517
  const failureAuditFields = typeof failure?.auditFields === "function" ? failure.auditFields(approval) : failure?.auditFields;
@@ -21762,38 +21926,38 @@ async function appendObservedAudit(ctx, deps, eventName, payload) {
21762
21926
  }
21763
21927
 
21764
21928
  // src/adapters/shared/repo-root.ts
21765
- import { existsSync as existsSync17 } from "node:fs";
21766
- import path62 from "node:path";
21929
+ import { existsSync as existsSync18 } from "node:fs";
21930
+ import path64 from "node:path";
21767
21931
  function belayConfigPath(current, adapterName) {
21768
21932
  if (adapterName === "cursor") {
21769
- return path62.join(current, ".cursor", "belay.config.json");
21933
+ return path64.join(current, ".cursor", "belay.config.json");
21770
21934
  }
21771
21935
  if (adapterName === "claude") {
21772
- return path62.join(current, ".claude", "belay.config.json");
21936
+ return path64.join(current, ".claude", "belay.config.json");
21773
21937
  }
21774
- return path62.join(current, ".codex", "belay.config.json");
21938
+ return path64.join(current, ".codex", "belay.config.json");
21775
21939
  }
21776
21940
  function markerMatches(current, marker, layout) {
21777
- const markerPath = path62.join(current, marker);
21778
- if (!existsSync17(markerPath)) {
21941
+ const markerPath = path64.join(current, marker);
21942
+ if (!existsSync18(markerPath)) {
21779
21943
  return false;
21780
21944
  }
21781
21945
  if (marker === ".cursor" || marker === ".claude" || marker === ".codex") {
21782
- return existsSync17(belayConfigPath(current, layout.name));
21946
+ return existsSync18(belayConfigPath(current, layout.name));
21783
21947
  }
21784
21948
  return true;
21785
21949
  }
21786
21950
  function findRepoRoot(startPath, layout) {
21787
- let current = path62.resolve(startPath);
21951
+ let current = path64.resolve(startPath);
21788
21952
  while (true) {
21789
21953
  for (const marker of layout.repoRootMarkers) {
21790
21954
  if (markerMatches(current, marker, layout)) {
21791
21955
  return current;
21792
21956
  }
21793
21957
  }
21794
- const parent = path62.dirname(current);
21958
+ const parent = path64.dirname(current);
21795
21959
  if (parent === current) {
21796
- return path62.resolve(startPath);
21960
+ return path64.resolve(startPath);
21797
21961
  }
21798
21962
  current = parent;
21799
21963
  }
@@ -21827,7 +21991,7 @@ function resolveCodexActionCwd(payload, fallbackCwd = process2.cwd(), options =
21827
21991
  const nestedCwd = options.includeToolInputCwd ? nonEmptyPathString(toolInput?.working_directory) ?? nonEmptyPathString(toolInput?.cwd) : void 0;
21828
21992
  const payloadCwd = nonEmptyPathString(payload.cwd);
21829
21993
  const workspaceRoot = Array.isArray(payload.workspace_roots) ? payload.workspace_roots.map(nonEmptyPathString).find(Boolean) : void 0;
21830
- return path63.resolve(nestedCwd ?? payloadCwd ?? workspaceRoot ?? fallbackCwd);
21994
+ return path65.resolve(nestedCwd ?? payloadCwd ?? workspaceRoot ?? fallbackCwd);
21831
21995
  }
21832
21996
  async function loadRuntimeContext(cwd) {
21833
21997
  const repoRoot = findRepoRoot(cwd, codexLayout);