@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,125 @@ 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
+ function isRepoConfigTrustError(error) {
3601
+ return error instanceof RepoConfigTrustError;
3602
+ }
3603
+ async function assertRepoConfigTrusted(repoRoot, adapter, rawConfig) {
3604
+ const status = await inspectRepoConfigTrust(repoRoot, adapter, rawConfig);
3605
+ if (status.trusted) {
3606
+ return;
3607
+ }
3608
+ throw new RepoConfigTrustError(status);
3609
+ }
3610
+ var TRUST_MESSAGE, RepoConfigTrustError;
3611
+ var init_repo_config_trust = __esm({
3612
+ "src/core/repo-config-trust.ts"() {
3613
+ "use strict";
3614
+ init_config();
3615
+ init_fingerprint2();
3616
+ init_path_utils();
3617
+ TRUST_MESSAGE = "Repository config is not trusted. Review it, then run `belay config trust`.";
3618
+ RepoConfigTrustError = class extends Error {
3619
+ status;
3620
+ constructor(status) {
3621
+ super(TRUST_MESSAGE);
3622
+ this.name = "RepoConfigTrustError";
3623
+ this.status = status;
3624
+ }
3625
+ };
3626
+ }
3627
+ });
3628
+
3629
+ // src/config-io.ts
3630
+ import { existsSync as existsSync3 } from "node:fs";
3631
+ 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
3632
  function resolveAdapterName(config) {
3517
3633
  if (config.adapter === "claude") {
3518
3634
  return "claude";
@@ -3523,10 +3639,10 @@ function resolveAdapterName(config) {
3523
3639
  return "cursor";
3524
3640
  }
3525
3641
  function detectAdapterName(repoRoot) {
3526
- if (existsSync2(configPathFor(repoRoot, "claude"))) {
3642
+ if (existsSync3(configPathFor(repoRoot, "claude"))) {
3527
3643
  return "claude";
3528
3644
  }
3529
- if (existsSync2(configPathFor(repoRoot, "codex"))) {
3645
+ if (existsSync3(configPathFor(repoRoot, "codex"))) {
3530
3646
  return "codex";
3531
3647
  }
3532
3648
  return "cursor";
@@ -3547,20 +3663,20 @@ async function loadLayeredConfig(repoRoot, adapter = detectAdapterName(repoRoot)
3547
3663
  const layout = getAdapterLayout(adapter);
3548
3664
  const configPath = configPathFor(repoRoot, adapter);
3549
3665
  let repoConfig = {};
3550
- if (existsSync2(configPath)) {
3551
- repoConfig = JSON.parse(await readFile2(configPath, "utf8"));
3666
+ if (existsSync3(configPath)) {
3667
+ repoConfig = JSON.parse(await readFile3(configPath, "utf8"));
3552
3668
  }
3553
3669
  let teamConfig = null;
3554
3670
  const teamPath = teamConfigPath();
3555
- if (existsSync2(teamPath)) {
3556
- teamConfig = JSON.parse(await readFile2(teamPath, "utf8"));
3671
+ if (existsSync3(teamPath)) {
3672
+ teamConfig = JSON.parse(await readFile3(teamPath, "utf8"));
3557
3673
  }
3558
3674
  return resolveLayeredConfig({
3559
3675
  repoConfig,
3560
3676
  adapterDefaults: layout.defaultConfig(repoRoot),
3561
3677
  teamConfig,
3562
3678
  teamConfigPath: teamPath,
3563
- repoConfigPath: existsSync2(configPath) ? configPath : void 0
3679
+ repoConfigPath: existsSync3(configPath) ? configPath : void 0
3564
3680
  });
3565
3681
  }
3566
3682
  async function loadConfigFile(repoRoot, adapter = detectAdapterName(repoRoot)) {
@@ -3575,21 +3691,22 @@ var init_config_io = __esm({
3575
3691
  init_approval_state_mutation();
3576
3692
  init_config();
3577
3693
  init_config_layers();
3694
+ init_repo_config_trust();
3578
3695
  }
3579
3696
  });
3580
3697
 
3581
3698
  // src/adapters/cursor/runtime-entry.ts
3582
3699
  init_approval();
3583
- import path65 from "node:path";
3700
+ import path67 from "node:path";
3584
3701
  import process2 from "node:process";
3585
3702
 
3586
3703
  // src/core/approval-repo-lookup.ts
3587
3704
  init_config_io();
3588
- import { readFile as readFile3 } from "node:fs/promises";
3589
- import path11 from "node:path";
3705
+ import { readFile as readFile4 } from "node:fs/promises";
3706
+ import path12 from "node:path";
3590
3707
  async function approvalStateContainsId(filePath, approvalId) {
3591
3708
  try {
3592
- const raw = await readFile3(filePath, "utf8");
3709
+ const raw = await readFile4(filePath, "utf8");
3593
3710
  const parsed = JSON.parse(raw);
3594
3711
  return parsed.approvals?.some((entry) => entry.approvalId === approvalId) ?? false;
3595
3712
  } catch {
@@ -3600,7 +3717,7 @@ async function findApprovalRepoRoots(params) {
3600
3717
  const matches = [];
3601
3718
  const seen = /* @__PURE__ */ new Set();
3602
3719
  for (const candidate of params.candidateRepoRoots) {
3603
- const repoRoot = path11.resolve(candidate);
3720
+ const repoRoot = path12.resolve(candidate);
3604
3721
  if (seen.has(repoRoot)) {
3605
3722
  continue;
3606
3723
  }
@@ -3632,15 +3749,16 @@ function formatAmbiguousApprovalRepoMessage(repoRoots) {
3632
3749
 
3633
3750
  // src/adapters/cursor/runtime-entry.ts
3634
3751
  init_config();
3752
+ init_repo_config_trust();
3635
3753
  init_cursor();
3636
3754
 
3637
3755
  // src/adapters/shared/gate-runtime.ts
3638
3756
  init_approval();
3639
3757
  init_approval_replay();
3640
3758
  import { randomUUID as randomUUID6 } from "node:crypto";
3641
- import { existsSync as existsSync16 } from "node:fs";
3642
- import { mkdir as mkdir14, readFile as readFile16, writeFile as writeFile11 } from "node:fs/promises";
3643
- import path62 from "node:path";
3759
+ import { existsSync as existsSync17 } from "node:fs";
3760
+ import { mkdir as mkdir15, readFile as readFile17, writeFile as writeFile11 } from "node:fs/promises";
3761
+ import path64 from "node:path";
3644
3762
 
3645
3763
  // src/core/approval-service.ts
3646
3764
  init_config_io();
@@ -3650,47 +3768,35 @@ init_approval_replay();
3650
3768
  // src/core/approval-token.ts
3651
3769
  init_config();
3652
3770
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
3653
- import { existsSync as existsSync3 } from "node:fs";
3654
- import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
3655
- import path12 from "node:path";
3656
- function base64UrlEncode(value) {
3657
- return Buffer.from(value, "utf8").toString("base64url");
3658
- }
3771
+ import { existsSync as existsSync4 } from "node:fs";
3772
+ import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile2 } from "node:fs/promises";
3773
+ import path13 from "node:path";
3659
3774
  function base64UrlDecode(value) {
3660
3775
  return Buffer.from(value, "base64url").toString("utf8");
3661
3776
  }
3662
3777
  function approvalSigningKeyPath(controlPlaneDir = defaultControlPlaneDir()) {
3663
- return path12.join(controlPlaneDir, "approval-signing.key");
3778
+ return path13.join(controlPlaneDir, "approval-signing.key");
3664
3779
  }
3665
3780
  async function loadOrCreateApprovalSigningKey(controlPlaneDir = defaultControlPlaneDir()) {
3666
3781
  const keyPath = approvalSigningKeyPath(controlPlaneDir);
3667
- if (existsSync3(keyPath)) {
3668
- return readFile4(keyPath);
3782
+ if (existsSync4(keyPath)) {
3783
+ return readFile5(keyPath);
3669
3784
  }
3670
- await mkdir3(controlPlaneDir, { recursive: true });
3785
+ await mkdir4(controlPlaneDir, { recursive: true });
3671
3786
  const key = randomBytes(32);
3672
3787
  await writeFile2(keyPath, key, { mode: 384 });
3673
3788
  return key;
3674
3789
  }
3675
- function signPayload(payload, key) {
3676
- const body = base64UrlEncode(JSON.stringify(payload));
3677
- const signature = createHmac("sha256", key).update(body).digest("base64url");
3678
- return `${body}.${signature}`;
3679
- }
3680
- async function issueApprovalToken(payload, controlPlaneDir = defaultControlPlaneDir()) {
3681
- const key = await loadOrCreateApprovalSigningKey(controlPlaneDir);
3682
- return signPayload(payload, key);
3683
- }
3684
3790
  async function verifyApprovalToken(token, controlPlaneDir = defaultControlPlaneDir()) {
3685
3791
  const [body, signature] = token.split(".");
3686
3792
  if (!body || !signature) {
3687
3793
  return null;
3688
3794
  }
3689
3795
  const keyPath = approvalSigningKeyPath(controlPlaneDir);
3690
- if (!existsSync3(keyPath)) {
3796
+ if (!existsSync4(keyPath)) {
3691
3797
  return null;
3692
3798
  }
3693
- const key = await readFile4(keyPath);
3799
+ const key = await readFile5(keyPath);
3694
3800
  const expected = createHmac("sha256", key).update(body).digest("base64url");
3695
3801
  const actualBuffer = Buffer.from(signature);
3696
3802
  const expectedBuffer = Buffer.from(expected);
@@ -3897,11 +4003,11 @@ init_approval_v3();
3897
4003
 
3898
4004
  // src/core/capability/boundary-attestation-sign.ts
3899
4005
  import { createHmac as createHmac2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
3900
- import { access, readFile as readFile5 } from "node:fs/promises";
4006
+ import { access, readFile as readFile6 } from "node:fs/promises";
3901
4007
  init_fingerprint2();
3902
4008
 
3903
4009
  // src/core/capability/attestation.ts
3904
- import path13 from "node:path";
4010
+ import path14 from "node:path";
3905
4011
  var BOUNDARY_ATTESTATION_VERSION = 1;
3906
4012
  var CONTAINED_EXECUTION_ATTESTATION_VERSION = 1;
3907
4013
  var KNOWN_DRIVERS = /* @__PURE__ */ new Set([
@@ -3969,7 +4075,7 @@ function validateContainedExecutionAttestation(value) {
3969
4075
  const record = value;
3970
4076
  const dockerSubstrate = record.dockerSubstrate;
3971
4077
  const dockerConfiguration = record.dockerConfiguration;
3972
- 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") {
4078
+ 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" || !path14.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:///") || !path14.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" || !path14.isAbsolute(dockerConfiguration.executable) || /[\0\n\r]/.test(dockerConfiguration.executable) || typeof dockerConfiguration.host !== "string" || !dockerConfiguration.host.startsWith("unix:///") || !path14.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") {
3973
4079
  return false;
3974
4080
  }
3975
4081
  const probedAt = Date.parse(record.probedAt);
@@ -4039,7 +4145,7 @@ async function verifySignedBoundaryAttestation(params) {
4039
4145
  return record.attestation;
4040
4146
  }
4041
4147
  async function readSignedAttestationFile(filePath) {
4042
- return JSON.parse(await readFile5(filePath, "utf8"));
4148
+ return JSON.parse(await readFile6(filePath, "utf8"));
4043
4149
  }
4044
4150
 
4045
4151
  // src/core/capability/boundary-egress.ts
@@ -4208,13 +4314,13 @@ async function runWithBoundaryRunnable(target, params) {
4208
4314
  }
4209
4315
 
4210
4316
  // src/core/capability/boundary-session.ts
4211
- import path24 from "node:path";
4317
+ import path25 from "node:path";
4212
4318
 
4213
4319
  // src/services/egress-service.ts
4214
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
4215
- import { mkdir as mkdir4, readFile as readFile6, unlink as unlink3, writeFile as writeFile3 } from "node:fs/promises";
4320
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
4321
+ import { mkdir as mkdir5, readFile as readFile7, unlink as unlink4, writeFile as writeFile3 } from "node:fs/promises";
4216
4322
  import net from "node:net";
4217
- import path14 from "node:path";
4323
+ import path15 from "node:path";
4218
4324
  init_config_io();
4219
4325
  init_config();
4220
4326
 
@@ -4227,16 +4333,16 @@ function egressStatePaths(repoRoot, config) {
4227
4333
  const stateDir = belayStateDir(config, repoLocalStateDirFor(repoRoot, config));
4228
4334
  return {
4229
4335
  stateDir,
4230
- pidPath: path14.join(stateDir, "egress-proxy.pid"),
4231
- statusPath: path14.join(stateDir, "egress-proxy.json")
4336
+ pidPath: path15.join(stateDir, "egress-proxy.pid"),
4337
+ statusPath: path15.join(stateDir, "egress-proxy.json")
4232
4338
  };
4233
4339
  }
4234
4340
  async function readStatusFile(statusPath) {
4235
- if (!existsSync4(statusPath)) {
4341
+ if (!existsSync5(statusPath)) {
4236
4342
  return null;
4237
4343
  }
4238
4344
  try {
4239
- const raw = JSON.parse(await readFile6(statusPath, "utf8"));
4345
+ const raw = JSON.parse(await readFile7(statusPath, "utf8"));
4240
4346
  if (typeof raw.pid !== "number") {
4241
4347
  return null;
4242
4348
  }
@@ -4254,9 +4360,9 @@ async function readStatusFile(statusPath) {
4254
4360
  async function isPortOpen(host, port) {
4255
4361
  return new Promise((resolve) => {
4256
4362
  const socket = net.createConnection({ host, port });
4257
- const finish = (open6) => {
4363
+ const finish = (open7) => {
4258
4364
  socket.destroy();
4259
- resolve(open6);
4365
+ resolve(open7);
4260
4366
  };
4261
4367
  socket.setTimeout(300);
4262
4368
  socket.on("connect", () => finish(true));
@@ -4267,7 +4373,7 @@ async function isPortOpen(host, port) {
4267
4373
  async function resolveLiveEgressStatus(repoRoot, config) {
4268
4374
  const { statusPath } = egressStatePaths(repoRoot, config);
4269
4375
  const statusCandidates = [statusPath];
4270
- const controlPlaneStatus = path14.join(configuredControlPlaneDir(config), "egress-proxy.json");
4376
+ const controlPlaneStatus = path15.join(configuredControlPlaneDir(config), "egress-proxy.json");
4271
4377
  if (!statusCandidates.includes(controlPlaneStatus)) {
4272
4378
  statusCandidates.push(controlPlaneStatus);
4273
4379
  }
@@ -4293,7 +4399,7 @@ function isProcessAlive(pid) {
4293
4399
  }
4294
4400
  }
4295
4401
  async function egressStatus(options = {}) {
4296
- const repoRoot = path14.resolve(options.targetDir ?? process.cwd());
4402
+ const repoRoot = path15.resolve(options.targetDir ?? process.cwd());
4297
4403
  const config = await loadConfigFile(repoRoot);
4298
4404
  const { status, host, port, portOccupied } = await resolveLiveEgressStatus(repoRoot, config);
4299
4405
  const ownedRunning = Boolean(status);
@@ -4324,7 +4430,7 @@ init_config();
4324
4430
  import { createHash as createHash8, randomUUID as randomUUID2 } from "node:crypto";
4325
4431
  import { createReadStream as createReadStream2 } from "node:fs";
4326
4432
  import { access as access2, constants as constants2, lstat as lstat4, mkdtemp as mkdtemp2, realpath as realpath2, rm as rm2 } from "node:fs/promises";
4327
- import path19 from "node:path";
4433
+ import path20 from "node:path";
4328
4434
  init_fingerprint2();
4329
4435
  init_path_utils();
4330
4436
 
@@ -4503,7 +4609,7 @@ function runProcessWithBoundedOutput(file, args, options, timeoutMs, outputPolic
4503
4609
  }
4504
4610
 
4505
4611
  // src/core/contained-execution/docker-policy.ts
4506
- import path15 from "node:path";
4612
+ import path16 from "node:path";
4507
4613
 
4508
4614
  // src/core/contained-execution/policy.ts
4509
4615
  var CONTAINED_EXECUTION_APPROVAL_FALLBACK_REASONS = [
@@ -4632,7 +4738,7 @@ var PROXY_ENV_NAMES = [
4632
4738
  var IMAGE_ID_PATTERN = /^sha256:[a-f0-9]{64}$/;
4633
4739
  var SAFE_CONTAINER_NAME = /^belay-contained-[0-9a-f-]{36}$/;
4634
4740
  function assertSafeDockerPath(value, code) {
4635
- if (!path15.isAbsolute(value) || /[\0\n\r,]/.test(value)) {
4741
+ if (!path16.isAbsolute(value) || /[\0\n\r,]/.test(value)) {
4636
4742
  throw new ContainedExecutionFailureError(code);
4637
4743
  }
4638
4744
  }
@@ -4711,11 +4817,11 @@ init_path_utils();
4711
4817
  import { createHash as createHash7 } from "node:crypto";
4712
4818
  import { constants as fsConstants } from "node:fs";
4713
4819
  import {
4714
- chmod as chmod2,
4820
+ chmod as chmod3,
4715
4821
  lstat as lstat3,
4716
- mkdir as mkdir5,
4822
+ mkdir as mkdir6,
4717
4823
  mkdtemp,
4718
- open as open3,
4824
+ open as open4,
4719
4825
  opendir,
4720
4826
  readlink as readlink2,
4721
4827
  realpath,
@@ -4723,41 +4829,41 @@ import {
4723
4829
  symlink
4724
4830
  } from "node:fs/promises";
4725
4831
  import os from "node:os";
4726
- import path18 from "node:path";
4832
+ import path19 from "node:path";
4727
4833
 
4728
4834
  // src/core/transactional/file-tree.ts
4729
4835
  import { createHash as createHash6 } from "node:crypto";
4730
4836
  import { lstat as lstat2, readdir } from "node:fs/promises";
4731
- import path17 from "node:path";
4837
+ import path18 from "node:path";
4732
4838
 
4733
4839
  // src/core/transactional/file-tree-path.ts
4734
4840
  init_path_utils();
4735
- import path16 from "node:path";
4841
+ import path17 from "node:path";
4736
4842
  var FILE_CHECKPOINT_PATH_ESCAPE = "file_checkpoint_path_escape";
4737
4843
  function validateRelativePath(relativePath) {
4738
4844
  if (!relativePath || relativePath.includes("\0")) {
4739
4845
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4740
4846
  }
4741
- if (path16.isAbsolute(relativePath)) {
4847
+ if (path17.isAbsolute(relativePath)) {
4742
4848
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4743
4849
  }
4744
4850
  if (isPathOutsideRoot(relativePath)) {
4745
4851
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4746
4852
  }
4747
- const normalized = path16.normalize(relativePath);
4748
- if (normalized === ".." || normalized.startsWith(`..${path16.sep}`)) {
4853
+ const normalized = path17.normalize(relativePath);
4854
+ if (normalized === ".." || normalized.startsWith(`..${path17.sep}`)) {
4749
4855
  throw new Error(FILE_CHECKPOINT_PATH_ESCAPE);
4750
4856
  }
4751
4857
  }
4752
4858
  function joinRelativePath(root, relativePath) {
4753
4859
  validateRelativePath(relativePath);
4754
- return path16.join(canonicalPath(root), relativePath);
4860
+ return path17.join(canonicalPath(root), relativePath);
4755
4861
  }
4756
4862
  function isRootGitMetadataPath(relativePath) {
4757
- return relativePath === ".git" || relativePath.startsWith(`.git${path16.sep}`);
4863
+ return relativePath === ".git" || relativePath.startsWith(`.git${path17.sep}`);
4758
4864
  }
4759
4865
  function isNestedGitPath(relativePath) {
4760
- const segments = relativePath.split(path16.sep).filter(Boolean);
4866
+ const segments = relativePath.split(path17.sep).filter(Boolean);
4761
4867
  if (segments.length === 0) {
4762
4868
  return false;
4763
4869
  }
@@ -4924,7 +5030,7 @@ async function readPresentNode(absolutePath, counters) {
4924
5030
  async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters, quotas, deadlineMs, entries) {
4925
5031
  assertWithinDeadline(deadlineMs);
4926
5032
  assertWithinQuotas(counters, quotas);
4927
- const absoluteDir = relativeDir ? joinRelativePath(resourceRoot, relativeDir) : path17.resolve(resourceRoot);
5033
+ const absoluteDir = relativeDir ? joinRelativePath(resourceRoot, relativeDir) : path18.resolve(resourceRoot);
4928
5034
  const dirInfo = await lstat2(absoluteDir);
4929
5035
  if (!dirInfo.isDirectory()) {
4930
5036
  throw new Error(FILE_CHECKPOINT_UNSUPPORTED_NODE);
@@ -4950,7 +5056,7 @@ async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters,
4950
5056
  const names = await readdir(absoluteDir);
4951
5057
  for (const name of names) {
4952
5058
  assertWithinDeadline(deadlineMs);
4953
- const childRelative = relativeDir ? path17.join(relativeDir, name) : name;
5059
+ const childRelative = relativeDir ? path18.join(relativeDir, name) : name;
4954
5060
  validateRelativePath(childRelative);
4955
5061
  if (isNestedGitPath(childRelative)) {
4956
5062
  throw new Error(FILE_CHECKPOINT_NESTED_REPOSITORY);
@@ -4958,7 +5064,7 @@ async function walkDirectory(resourceRoot, relativeDir, excludedRoots, counters,
4958
5064
  if (isExcludedTreePath(childRelative, excludedRoots, resourceRoot)) {
4959
5065
  continue;
4960
5066
  }
4961
- const childAbsolute = path17.join(absoluteDir, name);
5067
+ const childAbsolute = path18.join(absoluteDir, name);
4962
5068
  const childInfo = await lstat2(childAbsolute);
4963
5069
  if (childInfo.isDirectory() && !childInfo.isSymbolicLink()) {
4964
5070
  await walkDirectory(
@@ -5069,16 +5175,16 @@ function validateContainedExecutionMirrorLease(handle, expected) {
5069
5175
  );
5070
5176
  }
5071
5177
  var productionDependencies = {
5072
- makeTempRoot: () => mkdtemp(path18.join(os.tmpdir(), "belay-contained-mirror-")),
5178
+ makeTempRoot: () => mkdtemp(path19.join(os.tmpdir(), "belay-contained-mirror-")),
5073
5179
  removeRoot: (root) => rm(root, { recursive: true, force: true }),
5074
5180
  now: () => Date.now()
5075
5181
  };
5076
5182
  function isAtOrWithin(root, target) {
5077
- const relative = path18.relative(root, target);
5078
- return relative === "" || !path18.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path18.sep}`);
5183
+ const relative = path19.relative(root, target);
5184
+ return relative === "" || !path19.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path19.sep}`);
5079
5185
  }
5080
5186
  function isGitMetadataRelativePath(relativePath) {
5081
- return relativePath.split(path18.sep).some((segment) => segment.toLowerCase() === ".git");
5187
+ return relativePath.split(path19.sep).some((segment) => segment.toLowerCase() === ".git");
5082
5188
  }
5083
5189
  function identityFromStats(stats) {
5084
5190
  return {
@@ -5160,7 +5266,7 @@ async function readStableFile(absolutePath, context) {
5160
5266
  if (before.nlink > 1n) {
5161
5267
  throw new Error(FILE_CHECKPOINT_HARDLINK_UNSUPPORTED);
5162
5268
  }
5163
- const source = await open3(absolutePath, safeReadFlags());
5269
+ const source = await open4(absolutePath, safeReadFlags());
5164
5270
  try {
5165
5271
  const opened = await source.stat({ bigint: true });
5166
5272
  assertRegularSingleLinkBigInt(opened);
@@ -5215,7 +5321,7 @@ function addMetadataRoots(context, directoryPath) {
5215
5321
  }
5216
5322
  }
5217
5323
  function pathMatchesRoots(absolutePath, roots) {
5218
- const lexical = path18.resolve(absolutePath);
5324
+ const lexical = path19.resolve(absolutePath);
5219
5325
  const canonical = canonicalPath(absolutePath);
5220
5326
  for (const root of roots) {
5221
5327
  if (isAtOrWithin(root, lexical) || isAtOrWithin(root, canonical)) {
@@ -5225,7 +5331,7 @@ function pathMatchesRoots(absolutePath, roots) {
5225
5331
  return false;
5226
5332
  }
5227
5333
  function pathLexicallyMatchesRoots(absolutePath, roots) {
5228
- const lexical = path18.resolve(absolutePath);
5334
+ const lexical = path19.resolve(absolutePath);
5229
5335
  for (const root of roots) {
5230
5336
  if (isAtOrWithin(root, lexical)) {
5231
5337
  return true;
@@ -5246,11 +5352,11 @@ async function readSafeSymlink(absolutePath, context) {
5246
5352
  }
5247
5353
  const identity = identityFromStats(before);
5248
5354
  const target = await readlink2(absolutePath);
5249
- if (path18.isAbsolute(target)) {
5355
+ if (path19.isAbsolute(target)) {
5250
5356
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_UNSAFE_SYMLINK);
5251
5357
  }
5252
- const lexicalTarget = path18.resolve(path18.dirname(absolutePath), target);
5253
- if (!isAtOrWithin(context.sourceRoot, lexicalTarget) || isGitMetadataRelativePath(path18.relative(context.sourceRoot, lexicalTarget)) || pathMatchesRoots(lexicalTarget, context.protectedRoots) || pathMatchesRoots(lexicalTarget, context.metadataRoots)) {
5358
+ const lexicalTarget = path19.resolve(path19.dirname(absolutePath), target);
5359
+ if (!isAtOrWithin(context.sourceRoot, lexicalTarget) || isGitMetadataRelativePath(path19.relative(context.sourceRoot, lexicalTarget)) || pathMatchesRoots(lexicalTarget, context.protectedRoots) || pathMatchesRoots(lexicalTarget, context.metadataRoots)) {
5254
5360
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_UNSAFE_SYMLINK);
5255
5361
  }
5256
5362
  let resolvedTarget;
@@ -5286,7 +5392,7 @@ async function walkDirectory2(relativeDirectory, entries, context) {
5286
5392
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5287
5393
  }
5288
5394
  const directoryFlags = safeReadFlags() | (fsConstants.O_DIRECTORY ?? 0);
5289
- const directory = await open3(absoluteDirectory, directoryFlags);
5395
+ const directory = await open4(absoluteDirectory, directoryFlags);
5290
5396
  try {
5291
5397
  const opened = await directory.stat({ bigint: true });
5292
5398
  if (!opened.isDirectory() || !identitiesEqual(beforeIdentity, identityFromStats(opened))) {
@@ -5295,7 +5401,7 @@ async function walkDirectory2(relativeDirectory, entries, context) {
5295
5401
  const entriesDirectory = await opendir(absoluteDirectory, { bufferSize: 32 });
5296
5402
  for await (const directoryEntry of entriesDirectory) {
5297
5403
  assertDeadline(context.deadlineMs, context.now);
5298
- const relativePath = relativeDirectory ? path18.join(relativeDirectory, directoryEntry.name) : directoryEntry.name;
5404
+ const relativePath = relativeDirectory ? path19.join(relativeDirectory, directoryEntry.name) : directoryEntry.name;
5299
5405
  const absolutePath = joinRelativePath(context.sourceRoot, relativePath);
5300
5406
  const info = await lstat3(absolutePath);
5301
5407
  if (info.isSymbolicLink()) {
@@ -5379,7 +5485,7 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5379
5485
  }
5380
5486
  assertEntryIdentity(entry, identityFromStats(before));
5381
5487
  await context.beforeCopyOpen?.(sourcePath);
5382
- const source = await open3(sourcePath, safeReadFlags());
5488
+ const source = await open4(sourcePath, safeReadFlags());
5383
5489
  let destination;
5384
5490
  try {
5385
5491
  const opened = await source.stat({ bigint: true });
@@ -5389,8 +5495,8 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5389
5495
  if (entry.node.kind !== "file") {
5390
5496
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5391
5497
  }
5392
- await mkdir5(path18.dirname(destinationPath), { recursive: true, mode: 448 });
5393
- destination = await open3(
5498
+ await mkdir6(path19.dirname(destinationPath), { recursive: true, mode: 448 });
5499
+ destination = await open4(
5394
5500
  destinationPath,
5395
5501
  fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,
5396
5502
  safePermissionMode(opened.mode)
@@ -5432,7 +5538,7 @@ async function copyStableRegularFile(sourcePath, destinationPath, entry, context
5432
5538
  if (entry.node.kind !== "file") {
5433
5539
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5434
5540
  }
5435
- await chmod2(destinationPath, safePermissionMode(entry.node.mode));
5541
+ await chmod3(destinationPath, safePermissionMode(entry.node.mode));
5436
5542
  }
5437
5543
  async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, context) {
5438
5544
  const directoryEntries = [];
@@ -5441,7 +5547,7 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5441
5547
  const sourcePath = joinRelativePath(sourceRoot, entry.relativePath);
5442
5548
  const destinationPath = joinRelativePath(destinationRoot, entry.relativePath);
5443
5549
  if (entry.node.kind === "directory") {
5444
- await mkdir5(destinationPath, { recursive: true, mode: 448 });
5550
+ await mkdir6(destinationPath, { recursive: true, mode: 448 });
5445
5551
  directoryEntries.push(entry);
5446
5552
  continue;
5447
5553
  }
@@ -5453,7 +5559,7 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5453
5559
  if (current !== entry.node.target) {
5454
5560
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5455
5561
  }
5456
- await mkdir5(path18.dirname(destinationPath), { recursive: true, mode: 448 });
5562
+ await mkdir6(path19.dirname(destinationPath), { recursive: true, mode: 448 });
5457
5563
  await symlink(entry.node.target, destinationPath);
5458
5564
  continue;
5459
5565
  }
@@ -5463,12 +5569,12 @@ async function materializeSnapshot(sourceRoot, destinationRoot, snapshot, contex
5463
5569
  if (entry.node.kind !== "directory") {
5464
5570
  throw new ContainedExecutionFailureError(CONTAINED_EXECUTION_SOURCE_CHANGED);
5465
5571
  }
5466
- await chmod2(
5572
+ await chmod3(
5467
5573
  joinRelativePath(destinationRoot, entry.relativePath),
5468
5574
  safePermissionMode(entry.node.mode)
5469
5575
  );
5470
5576
  }
5471
- await chmod2(destinationRoot, 448);
5577
+ await chmod3(destinationRoot, 448);
5472
5578
  }
5473
5579
  async function assertStableCopiedSnapshot(sourceRoot, destinationRoot, protectedRoots, limits, deadlineMs, now, before) {
5474
5580
  const [after, copied] = await Promise.all([
@@ -5513,7 +5619,7 @@ async function cleanupOwnedRoot(root, dependencies) {
5513
5619
  }
5514
5620
  async function prepareWithDependencies(options, dependencies) {
5515
5621
  validateOptions(options);
5516
- const guestWorkspacePath = path18.resolve(options.sourceRoot);
5622
+ const guestWorkspacePath = path19.resolve(options.sourceRoot);
5517
5623
  const sourceRoot = canonicalPath(options.sourceRoot);
5518
5624
  const protectedRoots = options.controlPlaneRoots.map((root) => canonicalPath(root));
5519
5625
  if (pathMatchesRoots(sourceRoot, protectedRoots)) {
@@ -5521,7 +5627,7 @@ async function prepareWithDependencies(options, dependencies) {
5521
5627
  }
5522
5628
  const guestRoot = await dependencies.makeTempRoot();
5523
5629
  try {
5524
- await chmod2(guestRoot, 448);
5630
+ await chmod3(guestRoot, 448);
5525
5631
  const deadlineMs = dependencies.now() + options.limits.prepareTimeoutMs;
5526
5632
  const before = await buildSafeMirrorSnapshot(
5527
5633
  sourceRoot,
@@ -5549,7 +5655,7 @@ async function prepareWithDependencies(options, dependencies) {
5549
5655
  dependencies.now,
5550
5656
  before
5551
5657
  );
5552
- await chmod2(guestRoot, 448);
5658
+ await chmod3(guestRoot, 448);
5553
5659
  const lease = {
5554
5660
  sourceRoot,
5555
5661
  hostMirrorRoot: guestRoot,
@@ -5683,14 +5789,14 @@ async function digestFile(file) {
5683
5789
  return hash.digest("hex");
5684
5790
  }
5685
5791
  async function resolveConfiguredDockerSubstrate(params) {
5686
- if (!path19.isAbsolute(params.executable) || /[\0\n\r]/.test(params.executable)) {
5792
+ if (!path20.isAbsolute(params.executable) || /[\0\n\r]/.test(params.executable)) {
5687
5793
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_binary_invalid");
5688
5794
  }
5689
5795
  if (!params.host.startsWith("unix:///") || /[\0\n\r]/.test(params.host)) {
5690
5796
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_host_invalid");
5691
5797
  }
5692
5798
  const configuredSocket = params.host.slice("unix://".length);
5693
- if (!path19.isAbsolute(configuredSocket)) {
5799
+ if (!path20.isAbsolute(configuredSocket)) {
5694
5800
  throw new ContainedDockerBoundaryUnavailableError("contained_execution_docker_host_invalid");
5695
5801
  }
5696
5802
  let binaryPath;
@@ -5951,7 +6057,7 @@ async function validatedGuestCwd(params) {
5951
6057
  const requiredExclusions = [
5952
6058
  ...new Set([params.controlPlaneDir, ...params.protectedRoots].map(canonicalPath))
5953
6059
  ];
5954
- if (params.mirror.backend !== "file_copy" || params.mirror.guestWorkspacePath !== path19.resolve(params.repoRoot) || !path19.isAbsolute(params.guestCwd) || !pathWithinRoot(params.mirror.guestWorkspacePath, params.guestCwd))
6060
+ if (params.mirror.backend !== "file_copy" || params.mirror.guestWorkspacePath !== path20.resolve(params.repoRoot) || !path20.isAbsolute(params.guestCwd) || !pathWithinRoot(params.mirror.guestWorkspacePath, params.guestCwd))
5955
6061
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5956
6062
  const resolvedRoot = await realpath2(params.mirror.hostMirrorRoot);
5957
6063
  const protectedRoots = [canonicalPath(params.repoRoot), ...requiredExclusions];
@@ -5963,10 +6069,10 @@ async function validatedGuestCwd(params) {
5963
6069
  protectedRoots: requiredExclusions
5964
6070
  }))
5965
6071
  throw new ContainedExecutionFailureError("contained_execution_invalid_mirror_lease");
5966
- const relative = path19.relative(params.mirror.guestWorkspacePath, path19.resolve(params.guestCwd));
6072
+ const relative = path20.relative(params.mirror.guestWorkspacePath, path20.resolve(params.guestCwd));
5967
6073
  let resolvedCwd;
5968
6074
  try {
5969
- resolvedCwd = await realpath2(path19.join(resolvedRoot, relative));
6075
+ resolvedCwd = await realpath2(path20.join(resolvedRoot, relative));
5970
6076
  } catch {
5971
6077
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5972
6078
  }
@@ -5974,7 +6080,7 @@ async function validatedGuestCwd(params) {
5974
6080
  if (!info.isDirectory() || !pathWithinRoot(resolvedRoot, resolvedCwd)) {
5975
6081
  throw new ContainedExecutionFailureError("contained_execution_invalid_cwd");
5976
6082
  }
5977
- return path19.join(params.mirror.guestWorkspacePath, path19.relative(resolvedRoot, resolvedCwd));
6083
+ return path20.join(params.mirror.guestWorkspacePath, path20.relative(resolvedRoot, resolvedCwd));
5978
6084
  }
5979
6085
  function exactKeys(value, allowed) {
5980
6086
  const names = new Set(allowed);
@@ -6201,19 +6307,19 @@ async function executeContainedDocker(params) {
6201
6307
  init_path_utils();
6202
6308
  import { spawn as spawn3 } from "node:child_process";
6203
6309
  import os3 from "node:os";
6204
- import path21 from "node:path";
6310
+ import path22 from "node:path";
6205
6311
 
6206
6312
  // src/core/transactional/apply-observed-changes.ts
6207
- 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";
6313
+ 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";
6208
6314
  import os2 from "node:os";
6209
- import path20 from "node:path";
6315
+ import path21 from "node:path";
6210
6316
  var TRANSACTIONAL_APPLY_TOCTOU = "transactional_apply_toctou";
6211
6317
  var TRANSACTIONAL_APPLY_CONFLICT = "transactional_apply_conflict";
6212
6318
  var TRANSACTIONAL_APPLY_ROLLBACK_FAILED = "transactional_apply_rollback_failed";
6213
6319
  async function chmodSafe(target, mode) {
6214
6320
  try {
6215
- const { chmod: chmod4 } = await import("node:fs/promises");
6216
- await chmod4(target, mode & 511);
6321
+ const { chmod: chmod5 } = await import("node:fs/promises");
6322
+ await chmod5(target, mode & 511);
6217
6323
  } catch {
6218
6324
  }
6219
6325
  }
@@ -6247,13 +6353,13 @@ async function copyPathPreservingType(source, target) {
6247
6353
  }
6248
6354
  }
6249
6355
  await removePathIfExists(target);
6250
- await mkdir6(path20.dirname(target), { recursive: true });
6356
+ await mkdir7(path21.dirname(target), { recursive: true });
6251
6357
  if (info.isSymbolicLink()) {
6252
6358
  await symlink2(await readlink3(source), target);
6253
6359
  return;
6254
6360
  }
6255
6361
  if (info.isDirectory() && !info.isSymbolicLink()) {
6256
- await mkdir6(target, { recursive: true, mode: info.mode & 511 });
6362
+ await mkdir7(target, { recursive: true, mode: info.mode & 511 });
6257
6363
  return;
6258
6364
  }
6259
6365
  if (!info.isFile()) {
@@ -6263,12 +6369,12 @@ async function copyPathPreservingType(source, target) {
6263
6369
  await chmodSafe(target, info.mode);
6264
6370
  }
6265
6371
  async function assertParentChainSafe(targetRoot, relativePath, plannedDirectories = /* @__PURE__ */ new Set()) {
6266
- const segments = relativePath.split(path20.sep).filter(Boolean);
6372
+ const segments = relativePath.split(path21.sep).filter(Boolean);
6267
6373
  if (segments.length <= 1) {
6268
6374
  return;
6269
6375
  }
6270
6376
  for (let index = 1; index < segments.length; index++) {
6271
- const prefix = segments.slice(0, index).join(path20.sep);
6377
+ const prefix = segments.slice(0, index).join(path21.sep);
6272
6378
  const absolute = joinRelativePath(targetRoot, prefix);
6273
6379
  let info;
6274
6380
  try {
@@ -6288,8 +6394,8 @@ async function assertParentChainSafe(targetRoot, relativePath, plannedDirectorie
6288
6394
  }
6289
6395
  }
6290
6396
  async function restorePathFromBackup(backupPath, target, rollbackRoot) {
6291
- const stagingRoot = await mkdtemp3(path20.join(rollbackRoot, "restore-"));
6292
- const staged = path20.join(stagingRoot, "node");
6397
+ const stagingRoot = await mkdtemp3(path21.join(rollbackRoot, "restore-"));
6398
+ const staged = path21.join(stagingRoot, "node");
6293
6399
  try {
6294
6400
  await copyPathPreservingType(backupPath, staged);
6295
6401
  await copyPathPreservingType(staged, target);
@@ -6373,7 +6479,7 @@ async function applySingleChange(sourceRoot, targetRoot, change) {
6373
6479
  if (change.before.kind !== "directory") {
6374
6480
  await removePathIfExists(target);
6375
6481
  }
6376
- await mkdir6(target, { recursive: true, mode: change.after.mode & 511 });
6482
+ await mkdir7(target, { recursive: true, mode: change.after.mode & 511 });
6377
6483
  await chmodSafe(target, change.after.mode);
6378
6484
  return;
6379
6485
  }
@@ -6392,7 +6498,7 @@ async function applyObservedChanges(params) {
6392
6498
  await assertParentChainSafe(targetRoot, change.relativePath, plannedDirectories);
6393
6499
  await assertTargetMatches(targetRoot, change);
6394
6500
  }
6395
- const backupRoot = await mkdtemp3(path20.join(os2.tmpdir(), "belay-tx-rollback-"));
6501
+ const backupRoot = await mkdtemp3(path21.join(os2.tmpdir(), "belay-tx-rollback-"));
6396
6502
  const rollbackActions = [];
6397
6503
  let mutationAttempted = false;
6398
6504
  let resourceIdentityChanged = false;
@@ -6411,12 +6517,12 @@ async function applyObservedChanges(params) {
6411
6517
  targetExists = false;
6412
6518
  }
6413
6519
  if (targetExists) {
6414
- const backupPath = path20.join(
6520
+ const backupPath = path21.join(
6415
6521
  backupRoot,
6416
6522
  String(rollbackActions.length),
6417
6523
  change.relativePath
6418
6524
  );
6419
- await mkdir6(path20.dirname(backupPath), { recursive: true });
6525
+ await mkdir7(path21.dirname(backupPath), { recursive: true });
6420
6526
  await copyPathPreservingType(target, backupPath);
6421
6527
  await assertParentChainSafe(targetRoot, change.relativePath);
6422
6528
  rollbackActions.push({
@@ -6515,7 +6621,7 @@ function isIgnoredDirtyPath(repoRoot, relativePath, ignoreRoots) {
6515
6621
  if (ignoreRoots.length === 0) {
6516
6622
  return false;
6517
6623
  }
6518
- const absolutePath = canonicalPath(path21.join(repoRoot, relativePath));
6624
+ const absolutePath = canonicalPath(path22.join(repoRoot, relativePath));
6519
6625
  return ignoreRoots.some(
6520
6626
  (root) => pathWithinRoot(root, absolutePath) || root === absolutePath || pathWithinRoot(absolutePath, root)
6521
6627
  );
@@ -6553,7 +6659,7 @@ async function isDirtyWorktree(repoRoot, options) {
6553
6659
  }
6554
6660
  async function createGitWorktreeSnapshot(repoRoot, _stateDir) {
6555
6661
  const { mkdtemp: mkdtemp6, rm: rm10 } = await import("node:fs/promises");
6556
- const worktreePath = await mkdtemp6(path21.join(os3.tmpdir(), "belay-tx-"));
6662
+ const worktreePath = await mkdtemp6(path22.join(os3.tmpdir(), "belay-tx-"));
6557
6663
  await execGit(repoRoot, ["worktree", "add", "--detach", worktreePath, "HEAD"]);
6558
6664
  return {
6559
6665
  worktreePath,
@@ -6572,14 +6678,14 @@ async function createGitWorktreeSnapshot(repoRoot, _stateDir) {
6572
6678
  }
6573
6679
  function resolveWorktreeCwd(repoRoot, worktreePath, cwd) {
6574
6680
  const resolvedCwd = canonicalPath(cwd);
6575
- const relative = path21.relative(canonicalPath(repoRoot), resolvedCwd);
6576
- if (isPathOutsideRoot(relative) || path21.isAbsolute(relative)) {
6681
+ const relative = path22.relative(canonicalPath(repoRoot), resolvedCwd);
6682
+ if (isPathOutsideRoot(relative) || path22.isAbsolute(relative)) {
6577
6683
  return worktreePath;
6578
6684
  }
6579
6685
  if (relative === "") {
6580
6686
  return worktreePath;
6581
6687
  }
6582
- return path21.join(worktreePath, relative);
6688
+ return path22.join(worktreePath, relative);
6583
6689
  }
6584
6690
  function runShellCommand(command, cwd, timeoutMs) {
6585
6691
  return runProcessWithBoundedOutput(command, [], { cwd, shell: true, env: process.env }, timeoutMs);
@@ -6644,7 +6750,7 @@ import { spawn as spawn4 } from "node:child_process";
6644
6750
  import { randomUUID as randomUUID3 } from "node:crypto";
6645
6751
 
6646
6752
  // src/core/capability/boundary-grant-materialize.ts
6647
- import path22 from "node:path";
6753
+ import path23 from "node:path";
6648
6754
 
6649
6755
  // src/core/glob.ts
6650
6756
  init_approval();
@@ -6804,7 +6910,7 @@ function grantMatchesRequest(grant, request) {
6804
6910
  var BOUNDARY_GRANT_TTL_MS = 15 * 6e4;
6805
6911
  var BOUNDARY_GRANT_ISSUER_CONTAINER = "boundary:container";
6806
6912
  function resolveCapabilityPath(targetPath, cwd) {
6807
- const joined = path22.isAbsolute(targetPath) ? targetPath : path22.join(cwd, targetPath);
6913
+ const joined = path23.isAbsolute(targetPath) ? targetPath : path23.join(cwd, targetPath);
6808
6914
  return canonicalPath(joined);
6809
6915
  }
6810
6916
  function isPathWithinBoundaryMount(request) {
@@ -6879,7 +6985,7 @@ function materializeContainerBoundaryGrant(request, params) {
6879
6985
 
6880
6986
  // src/core/capability/boundary-workspace-mount.ts
6881
6987
  init_path_utils();
6882
- import path23 from "node:path";
6988
+ import path24 from "node:path";
6883
6989
  var HOST_PATH_ENV_VARS = [
6884
6990
  "BELAY_EGRESS_REPO_ROOT",
6885
6991
  "BELAY_JUDGE_BROKER_REPO_ROOT",
@@ -6904,23 +7010,23 @@ function validateWorkspaceMount(mount) {
6904
7010
  if (mount.cwdRelative.includes("\0")) {
6905
7011
  throw new Error("boundary_workspace_mount_invalid_cwd");
6906
7012
  }
6907
- const normalizedRelative = path23.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
7013
+ const normalizedRelative = path24.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6908
7014
  if (normalizedRelative === ".." || normalizedRelative.startsWith("../")) {
6909
7015
  throw new Error("boundary_workspace_mount_invalid_cwd");
6910
7016
  }
6911
- if (path23.posix.isAbsolute(normalizedRelative)) {
7017
+ if (path24.posix.isAbsolute(normalizedRelative)) {
6912
7018
  throw new Error("boundary_workspace_mount_invalid_cwd");
6913
7019
  }
6914
7020
  }
6915
7021
  function resolveGuestWorkdir(mount) {
6916
7022
  validateWorkspaceMount(mount);
6917
7023
  const guestTargetRoot = canonicalPath(mount.guestTargetRoot);
6918
- const normalizedRelative = path23.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
7024
+ const normalizedRelative = path24.posix.normalize(mount.cwdRelative.replace(/\\/g, "/"));
6919
7025
  if (normalizedRelative === "." || normalizedRelative === "") {
6920
7026
  return guestTargetRoot;
6921
7027
  }
6922
7028
  const segments = normalizedRelative.split("/").filter(Boolean);
6923
- return path23.posix.join(guestTargetRoot, ...segments);
7029
+ return path24.posix.join(guestTargetRoot, ...segments);
6924
7030
  }
6925
7031
  function buildWorkspaceMountSpec(mount) {
6926
7032
  validateWorkspaceMount(mount);
@@ -7211,7 +7317,7 @@ function containedExecutionFresh(attestation, config, now = Date.now()) {
7211
7317
  }
7212
7318
  function boundaryAttestationPath(repoRoot, config) {
7213
7319
  const rel = config.capability?.attestationRelPath ?? ".belay/attestation.json";
7214
- return path24.isAbsolute(rel) ? rel : path24.join(repoRoot, rel);
7320
+ return path25.isAbsolute(rel) ? rel : path25.join(repoRoot, rel);
7215
7321
  }
7216
7322
  async function loadBoundaryAttestation(filePath, expectedRepoRoot, controlPlaneDir) {
7217
7323
  try {
@@ -7316,7 +7422,7 @@ init_capability_request_hash();
7316
7422
 
7317
7423
  // src/core/capability/gate-policy-shadow.ts
7318
7424
  init_config();
7319
- import path30 from "node:path";
7425
+ import path31 from "node:path";
7320
7426
 
7321
7427
  // src/core/effect-ir/audit.ts
7322
7428
  init_fingerprint2();
@@ -7410,8 +7516,8 @@ function evidenceRank(level) {
7410
7516
  }
7411
7517
 
7412
7518
  // src/core/effect-ir/package-exec.ts
7413
- import { existsSync as existsSync5, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
7414
- import path25 from "node:path";
7519
+ import { existsSync as existsSync6, realpathSync as realpathSync3, statSync as statSync2 } from "node:fs";
7520
+ import path26 from "node:path";
7415
7521
 
7416
7522
  // src/core/network-endpoint.ts
7417
7523
  var SUPPORTED_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "ssh:", "git:"]);
@@ -7702,18 +7808,18 @@ function classifyPackageAcquisitionSpec(spec) {
7702
7808
  return { kind: "registry" };
7703
7809
  }
7704
7810
  function resolveLocalBin(binName, cwd, repoRoot) {
7705
- const base = path25.basename(binName);
7811
+ const base = path26.basename(binName);
7706
7812
  if (!base || base === "." || base === "..") {
7707
7813
  return null;
7708
7814
  }
7709
- let current = path25.resolve(cwd);
7710
- const stop = path25.resolve(repoRoot);
7815
+ let current = path26.resolve(cwd);
7816
+ const stop = path26.resolve(repoRoot);
7711
7817
  if (!pathWithinRoot(stop, current)) {
7712
7818
  return null;
7713
7819
  }
7714
7820
  while (true) {
7715
- const candidate = path25.join(current, "node_modules", ".bin", base);
7716
- if (existsSync5(candidate)) {
7821
+ const candidate = path26.join(current, "node_modules", ".bin", base);
7822
+ if (existsSync6(candidate)) {
7717
7823
  try {
7718
7824
  const resolvedCandidate = realpathSync3.native(candidate);
7719
7825
  if (!pathWithinRoot(stop, resolvedCandidate) || !statSync2(resolvedCandidate).isFile()) {
@@ -7727,7 +7833,7 @@ function resolveLocalBin(binName, cwd, repoRoot) {
7727
7833
  if (current === stop) {
7728
7834
  break;
7729
7835
  }
7730
- const parent = path25.dirname(current);
7836
+ const parent = path26.dirname(current);
7731
7837
  if (parent === current) {
7732
7838
  break;
7733
7839
  }
@@ -7922,7 +8028,7 @@ init_path_utils();
7922
8028
 
7923
8029
  // src/core/verdict/containment.ts
7924
8030
  init_git_resource_identity();
7925
- import path26 from "node:path";
8031
+ import path27 from "node:path";
7926
8032
  init_path_utils();
7927
8033
 
7928
8034
  // src/core/verdict/persistent-paths.ts
@@ -7942,7 +8048,7 @@ function expandHome(token) {
7942
8048
  if (!home) {
7943
8049
  return token;
7944
8050
  }
7945
- return token === "~" ? home : path26.join(home, token.slice(2));
8051
+ return token === "~" ? home : path27.join(home, token.slice(2));
7946
8052
  }
7947
8053
  return token;
7948
8054
  }
@@ -7954,10 +8060,10 @@ function resolveTrustedPath(token, trustedCwd, trusted) {
7954
8060
  return null;
7955
8061
  }
7956
8062
  const expanded = expandHome(token);
7957
- if (path26.isAbsolute(expanded)) {
8063
+ if (path27.isAbsolute(expanded)) {
7958
8064
  return canonicalPath(expanded);
7959
8065
  }
7960
- return canonicalPath(path26.resolve(trustedCwd, expanded));
8066
+ return canonicalPath(path27.resolve(trustedCwd, expanded));
7961
8067
  }
7962
8068
  function isGitPath(resolvedPath, repoRoot) {
7963
8069
  if (isGitMetadataPath(resolvedPath, repoRoot)) {
@@ -8074,20 +8180,20 @@ function parseTier1Json(raw) {
8074
8180
  init_judge_runtime_config();
8075
8181
 
8076
8182
  // src/core/verdict/judge-session-kill-switch.ts
8077
- import { existsSync as existsSync6 } from "node:fs";
8078
- import { mkdir as mkdir7, readFile as readFile7, unlink as unlink4, writeFile as writeFile4 } from "node:fs/promises";
8079
- import path27 from "node:path";
8183
+ import { existsSync as existsSync7 } from "node:fs";
8184
+ import { mkdir as mkdir8, readFile as readFile8, unlink as unlink5, writeFile as writeFile4 } from "node:fs/promises";
8185
+ import path28 from "node:path";
8080
8186
  var JUDGE_SESSION_KILL_FILE = "judge-session-kill.json";
8081
8187
  function judgeSessionKillSwitchPath(stateDir) {
8082
- return path27.join(stateDir, JUDGE_SESSION_KILL_FILE);
8188
+ return path28.join(stateDir, JUDGE_SESSION_KILL_FILE);
8083
8189
  }
8084
8190
  async function readJudgeSessionKillSwitch(stateDir) {
8085
8191
  const filePath = judgeSessionKillSwitchPath(stateDir);
8086
- if (!existsSync6(filePath)) {
8192
+ if (!existsSync7(filePath)) {
8087
8193
  return null;
8088
8194
  }
8089
8195
  try {
8090
- const raw = JSON.parse(await readFile7(filePath, "utf8"));
8196
+ const raw = JSON.parse(await readFile8(filePath, "utf8"));
8091
8197
  return raw.triggered === true ? raw : null;
8092
8198
  } catch {
8093
8199
  return null;
@@ -8098,7 +8204,7 @@ async function isJudgeSessionKillSwitchPersisted(stateDir) {
8098
8204
  return record?.triggered === true;
8099
8205
  }
8100
8206
  async function persistJudgeSessionKillSwitch(stateDir, reason = "shadow_mismatch") {
8101
- await mkdir7(stateDir, { recursive: true, mode: 448 });
8207
+ await mkdir8(stateDir, { recursive: true, mode: 448 });
8102
8208
  const record = {
8103
8209
  triggered: true,
8104
8210
  at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -8259,10 +8365,10 @@ function recordJudgeLatency(phase, latencyMs, at = Date.now()) {
8259
8365
 
8260
8366
  // src/core/verdict/judge-broker-service.ts
8261
8367
  import { spawn as spawn6 } from "node:child_process";
8262
- import { existsSync as existsSync7 } from "node:fs";
8263
- import { unlink as unlink5 } from "node:fs/promises";
8368
+ import { existsSync as existsSync8 } from "node:fs";
8369
+ import { unlink as unlink6 } from "node:fs/promises";
8264
8370
  import net2 from "node:net";
8265
- import path28 from "node:path";
8371
+ import path29 from "node:path";
8266
8372
  import { fileURLToPath } from "node:url";
8267
8373
 
8268
8374
  // src/core/verdict/judge-cli.ts
@@ -8808,10 +8914,10 @@ var JUDGE_BROKER_SESSION = "judge-broker-session.json";
8808
8914
  function judgeBrokerPaths(stateDir) {
8809
8915
  return {
8810
8916
  stateDir,
8811
- socketPath: path28.join(stateDir, JUDGE_BROKER_SOCKET),
8812
- statusPath: path28.join(stateDir, JUDGE_BROKER_STATUS),
8813
- pidPath: path28.join(stateDir, JUDGE_BROKER_PID),
8814
- sessionConfigPath: path28.join(stateDir, JUDGE_BROKER_SESSION)
8917
+ socketPath: path29.join(stateDir, JUDGE_BROKER_SOCKET),
8918
+ statusPath: path29.join(stateDir, JUDGE_BROKER_STATUS),
8919
+ pidPath: path29.join(stateDir, JUDGE_BROKER_PID),
8920
+ sessionConfigPath: path29.join(stateDir, JUDGE_BROKER_SESSION)
8815
8921
  };
8816
8922
  }
8817
8923
  function daemonScriptPath() {
@@ -8829,12 +8935,12 @@ function useInProcessBroker(env = process.env) {
8829
8935
  return Boolean(env.VITEST || env.VITEST_WORKER_ID || env.BELAY_JUDGE_BROKER_IN_PROCESS === "1");
8830
8936
  }
8831
8937
  async function readBrokerStatus(statusPath) {
8832
- if (!existsSync7(statusPath)) {
8938
+ if (!existsSync8(statusPath)) {
8833
8939
  return null;
8834
8940
  }
8835
8941
  try {
8836
- const { readFile: readFile17 } = await import("node:fs/promises");
8837
- const raw = JSON.parse(await readFile17(statusPath, "utf8"));
8942
+ const { readFile: readFile18 } = await import("node:fs/promises");
8943
+ const raw = JSON.parse(await readFile18(statusPath, "utf8"));
8838
8944
  if (typeof raw.pid !== "number" || typeof raw.socketPath !== "string") {
8839
8945
  return null;
8840
8946
  }
@@ -8844,13 +8950,13 @@ async function readBrokerStatus(statusPath) {
8844
8950
  }
8845
8951
  }
8846
8952
  async function readBrokerSessionConfig(sessionConfigPath) {
8847
- if (!existsSync7(sessionConfigPath)) {
8953
+ if (!existsSync8(sessionConfigPath)) {
8848
8954
  return null;
8849
8955
  }
8850
8956
  try {
8851
- const { readFile: readFile17 } = await import("node:fs/promises");
8957
+ const { readFile: readFile18 } = await import("node:fs/promises");
8852
8958
  const raw = JSON.parse(
8853
- await readFile17(sessionConfigPath, "utf8")
8959
+ await readFile18(sessionConfigPath, "utf8")
8854
8960
  );
8855
8961
  return normalizeJudgeSessionConfig({ ...raw, enabled: true });
8856
8962
  } catch {
@@ -8941,7 +9047,7 @@ async function ensureJudgeBrokerDaemon(stateDir, repoRoot, sessionConfig) {
8941
9047
  const existingConfig = await readBrokerSessionConfig(paths.sessionConfigPath);
8942
9048
  const configChanged = existingConfig !== null && brokerSessionConfigPayload(existingConfig) !== nextConfigPayload;
8943
9049
  const status = await readBrokerStatus(paths.statusPath);
8944
- if (status && isProcessAlive2(status.pid) && existsSync7(paths.socketPath) && !configChanged) {
9050
+ if (status && isProcessAlive2(status.pid) && existsSync8(paths.socketPath) && !configChanged) {
8945
9051
  await writeBrokerSessionConfig(paths, brokerSessionConfig);
8946
9052
  return paths;
8947
9053
  }
@@ -8963,7 +9069,7 @@ async function ensureJudgeBrokerDaemon(stateDir, repoRoot, sessionConfig) {
8963
9069
  child.unref();
8964
9070
  const deadline = Date.now() + sessionConfig.connectTimeoutMs;
8965
9071
  while (Date.now() < deadline) {
8966
- if (existsSync7(paths.socketPath)) {
9072
+ if (existsSync8(paths.socketPath)) {
8967
9073
  const live = await readBrokerStatus(paths.statusPath);
8968
9074
  if (live && isProcessAlive2(live.pid)) {
8969
9075
  return paths;
@@ -8980,8 +9086,8 @@ async function cleanupJudgeBrokerArtifacts(paths) {
8980
9086
  paths.pidPath,
8981
9087
  paths.sessionConfigPath
8982
9088
  ]) {
8983
- if (existsSync7(artifact)) {
8984
- await unlink5(artifact).catch(() => void 0);
9089
+ if (existsSync8(artifact)) {
9090
+ await unlink6(artifact).catch(() => void 0);
8985
9091
  }
8986
9092
  }
8987
9093
  }
@@ -9477,9 +9583,9 @@ async function evaluateWithJudgeTransport(request, options = {}) {
9477
9583
  }
9478
9584
 
9479
9585
  // src/core/capability/gate-shadow-ratchet.ts
9480
- import { existsSync as existsSync8 } from "node:fs";
9481
- import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile5 } from "node:fs/promises";
9482
- import path29 from "node:path";
9586
+ import { existsSync as existsSync9 } from "node:fs";
9587
+ import { mkdir as mkdir9, readFile as readFile9, writeFile as writeFile5 } from "node:fs/promises";
9588
+ import path30 from "node:path";
9483
9589
  var DEFAULT_STATE = {
9484
9590
  version: 1,
9485
9591
  policyJudgeComparisons: 0,
@@ -9488,15 +9594,15 @@ var DEFAULT_STATE = {
9488
9594
  updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
9489
9595
  };
9490
9596
  function ratchetPath(stateDir) {
9491
- return path29.join(stateDir, "gate-shadow-ratchet.json");
9597
+ return path30.join(stateDir, "gate-shadow-ratchet.json");
9492
9598
  }
9493
9599
  async function loadState(stateDir) {
9494
9600
  const filePath = ratchetPath(stateDir);
9495
- if (!existsSync8(filePath)) {
9601
+ if (!existsSync9(filePath)) {
9496
9602
  return { ...DEFAULT_STATE, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9497
9603
  }
9498
9604
  try {
9499
- const raw = JSON.parse(await readFile8(filePath, "utf8"));
9605
+ const raw = JSON.parse(await readFile9(filePath, "utf8"));
9500
9606
  return {
9501
9607
  ...DEFAULT_STATE,
9502
9608
  ...raw,
@@ -9507,7 +9613,7 @@ async function loadState(stateDir) {
9507
9613
  }
9508
9614
  }
9509
9615
  async function saveState(stateDir, state) {
9510
- await mkdir8(stateDir, { recursive: true, mode: 448 });
9616
+ await mkdir9(stateDir, { recursive: true, mode: 448 });
9511
9617
  await writeFile5(
9512
9618
  ratchetPath(stateDir),
9513
9619
  `${JSON.stringify({ ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)}
@@ -9630,7 +9736,7 @@ function scheduleGateShadowAudit(params) {
9630
9736
  async function runGatePolicyShadowComparison(params) {
9631
9737
  const judge = params.config.judge;
9632
9738
  const runtime = normalizeJudgeRuntimeConfig(judge.runtime);
9633
- const stateDir = params.stateDir ?? belayStateDir(params.config, path30.join(params.repoRoot, ".belay"));
9739
+ const stateDir = params.stateDir ?? belayStateDir(params.config, path31.join(params.repoRoot, ".belay"));
9634
9740
  const transport = await evaluateWithJudgeTransport(
9635
9741
  {
9636
9742
  prompt: buildTier1Prompt(params.command),
@@ -9920,15 +10026,15 @@ async function loadClassifierAuthorization(params) {
9920
10026
  }
9921
10027
 
9922
10028
  // src/core/capability/allowlist.ts
9923
- import { existsSync as existsSync9, readFileSync as readFileSync3 } from "node:fs";
10029
+ import { existsSync as existsSync10, readFileSync as readFileSync3 } from "node:fs";
9924
10030
  init_config();
9925
10031
  init_path_utils();
9926
- import path31 from "node:path";
10032
+ import path32 from "node:path";
9927
10033
  function fsScopeAllowlistPath(config, repoLocalStateDir) {
9928
- return path31.join(belayStateDir(config, repoLocalStateDir), "fs-scope-allowlist.json");
10034
+ return path32.join(belayStateDir(config, repoLocalStateDir), "fs-scope-allowlist.json");
9929
10035
  }
9930
10036
  function loadFsScopeAllowlistSync(filePath) {
9931
- if (!existsSync9(filePath)) {
10037
+ if (!existsSync10(filePath)) {
9932
10038
  return { version: 1, paths: [] };
9933
10039
  }
9934
10040
  const raw = JSON.parse(readFileSync3(filePath, "utf8"));
@@ -10020,7 +10126,7 @@ function checkGatedActionLimits(action) {
10020
10126
  // src/core/capability/paths.ts
10021
10127
  init_path_utils();
10022
10128
  init_shell_tokenizer();
10023
- import path32 from "node:path";
10129
+ import path33 from "node:path";
10024
10130
  function applyPatchTargets(patch) {
10025
10131
  const targets = [];
10026
10132
  for (const line of patch.split("\n")) {
@@ -10085,7 +10191,7 @@ function collectOutsideRepoPathsFromToolPayload(payload, cwd, repoRoot, trustedW
10085
10191
  const paths = /* @__PURE__ */ new Set();
10086
10192
  const filePath = extractToolFilePath(payload);
10087
10193
  if (filePath) {
10088
- const resolved = path32.isAbsolute(filePath) ? filePath : path32.resolve(cwd, filePath);
10194
+ const resolved = path33.isAbsolute(filePath) ? filePath : path33.resolve(cwd, filePath);
10089
10195
  if (resolveWorkspaceRootMatch(repoRoot, trustedWorkspaceRoots, resolved) === null) {
10090
10196
  paths.add(resolved);
10091
10197
  }
@@ -10095,7 +10201,7 @@ function collectOutsideRepoPathsFromToolPayload(payload, cwd, repoRoot, trustedW
10095
10201
  const patch = extractToolPatch(payload);
10096
10202
  if (patch) {
10097
10203
  for (const target of applyPatchTargets(patch)) {
10098
- const resolved = path32.isAbsolute(target) ? target : path32.resolve(cwd, target);
10204
+ const resolved = path33.isAbsolute(target) ? target : path33.resolve(cwd, target);
10099
10205
  if (resolveWorkspaceRootMatch(repoRoot, trustedWorkspaceRoots, resolved) === null) {
10100
10206
  paths.add(resolved);
10101
10207
  }
@@ -10149,7 +10255,7 @@ function policyReasonToLegacyReason(decision) {
10149
10255
  // src/core/capability/policy-engine.ts
10150
10256
  init_git_resource_identity();
10151
10257
  import { createHash as createHash10 } from "node:crypto";
10152
- import path33 from "node:path";
10258
+ import path34 from "node:path";
10153
10259
  init_path_utils();
10154
10260
  init_shell_tokenizer();
10155
10261
  init_grant();
@@ -10441,7 +10547,7 @@ function hashSession(value) {
10441
10547
  return createHash10("sha256").update(value).digest("hex").slice(0, 16);
10442
10548
  }
10443
10549
  function resolveCapabilityPath2(targetPath, cwd) {
10444
- const joined = path33.isAbsolute(targetPath) ? targetPath : path33.join(cwd, targetPath);
10550
+ const joined = path34.isAbsolute(targetPath) ? targetPath : path34.join(cwd, targetPath);
10445
10551
  return canonicalPath(joined);
10446
10552
  }
10447
10553
  function actionForFileMutation(analysis) {
@@ -10520,7 +10626,7 @@ function isRepoLocalPackageExec(request) {
10520
10626
  return false;
10521
10627
  }
10522
10628
  const commandPath = canonicalPath(request.resource.command);
10523
- return path33.isAbsolute(commandPath) && pathWithinRoot(request.principal.repoRoot, commandPath);
10629
+ return path34.isAbsolute(commandPath) && pathWithinRoot(request.principal.repoRoot, commandPath);
10524
10630
  }
10525
10631
  function isRepoLocalRoutineWrite(request, sensitivePaths) {
10526
10632
  if (!isRepoLocalShellLocation(request)) {
@@ -10784,15 +10890,15 @@ function shouldSkipBrokerApprovedRecord(brokerActive, approvalReason) {
10784
10890
  }
10785
10891
 
10786
10892
  // src/core/capability/trusted-workspace-roots.ts
10787
- import { existsSync as existsSync10, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
10893
+ import { existsSync as existsSync11, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
10788
10894
  init_config();
10789
10895
  init_path_utils();
10790
- import path34 from "node:path";
10896
+ import path35 from "node:path";
10791
10897
  function trustedWorkspaceRootsPath(config, repoLocalStateDir) {
10792
- return path34.join(belayStateDir(config, repoLocalStateDir), "trusted-workspace-roots.json");
10898
+ return path35.join(belayStateDir(config, repoLocalStateDir), "trusted-workspace-roots.json");
10793
10899
  }
10794
10900
  function loadTrustedWorkspaceRootsSync(filePath) {
10795
- if (!existsSync10(filePath)) {
10901
+ if (!existsSync11(filePath)) {
10796
10902
  return { version: 1, roots: [] };
10797
10903
  }
10798
10904
  const raw = JSON.parse(readFileSync4(filePath, "utf8"));
@@ -10818,7 +10924,7 @@ function sanitizeTrustedWorkspaceRootEntries(input) {
10818
10924
  const source = record.source === "approval" ? "approval" : void 0;
10819
10925
  return [
10820
10926
  {
10821
- path: path34.resolve(record.path),
10927
+ path: path35.resolve(record.path),
10822
10928
  approvedAt,
10823
10929
  approvalId,
10824
10930
  ...source ? { source } : {}
@@ -10847,7 +10953,7 @@ function isDirectoryPath(targetPath) {
10847
10953
  function isBroadTrustedWorkspaceRoot(targetPath) {
10848
10954
  const home = process.env.HOME ?? process.env.USERPROFILE;
10849
10955
  const root = normalizeTrustedWorkspaceRootPath(targetPath);
10850
- if (root === normalizeTrustedWorkspaceRootPath(path34.parse(root).root)) {
10956
+ if (root === normalizeTrustedWorkspaceRootPath(path35.parse(root).root)) {
10851
10957
  return true;
10852
10958
  }
10853
10959
  if (home && normalizeTrustedWorkspaceRootPath(home) === root) {
@@ -10871,7 +10977,7 @@ function isHighStakesTrustedWorkspaceRoot(targetPath) {
10871
10977
  return false;
10872
10978
  }
10873
10979
  return HOME_HIGH_STAKES_SEGMENTS.some(
10874
- (segment) => pathWithinRoot(path34.join(homeRoot, segment), normalized)
10980
+ (segment) => pathWithinRoot(path35.join(homeRoot, segment), normalized)
10875
10981
  );
10876
10982
  }
10877
10983
  function validateTrustedWorkspaceRootCandidate(params) {
@@ -10908,7 +11014,7 @@ function validateTrustedWorkspaceRootCandidate(params) {
10908
11014
  init_config_layers();
10909
11015
 
10910
11016
  // src/core/contained-execution/eligibility.ts
10911
- import path35 from "node:path";
11017
+ import path36 from "node:path";
10912
11018
  init_path_utils();
10913
11019
  var FORBIDDEN_SIGNALS = /* @__PURE__ */ new Set([
10914
11020
  "command_substitution",
@@ -10925,7 +11031,7 @@ var FORBIDDEN_SIGNALS = /* @__PURE__ */ new Set([
10925
11031
  ]);
10926
11032
  function isContainedUnknownExecutionEligible(config, action, result) {
10927
11033
  const contained = config.sandbox.containedExecution;
10928
- 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) {
11034
+ if (!contained?.enabled || !config.sandbox.enabled || config.sandbox.runtime !== "container" || action.kind !== "shell" || !path36.isAbsolute(action.repoRoot) || !hasResolvedRepoIdentity(action.repoRoot) || !config.gates.shell || result.reason !== "unknown_local_effect" || result.axes?.location !== "repo_local" || result.assessment.external) {
10929
11035
  return false;
10930
11036
  }
10931
11037
  const plan = result.effectPlan;
@@ -11205,7 +11311,7 @@ function classifySubagent(payload, repoRoot, options = {}, config) {
11205
11311
  }
11206
11312
 
11207
11313
  // src/core/classify-tool.ts
11208
- import path50 from "node:path";
11314
+ import path51 from "node:path";
11209
11315
  init_fingerprint2();
11210
11316
  init_path_utils();
11211
11317
  init_scrub();
@@ -11325,13 +11431,13 @@ function worstEffectDecision(decisions) {
11325
11431
 
11326
11432
  // src/core/effect-ir/shell-lower.ts
11327
11433
  init_shell_tokenizer();
11328
- import path49 from "node:path";
11434
+ import path50 from "node:path";
11329
11435
 
11330
11436
  // src/core/verdict/docker-compose-run.ts
11331
- import path37 from "node:path";
11437
+ import path38 from "node:path";
11332
11438
 
11333
11439
  // src/core/verdict/recursive-invocation.ts
11334
- import path36 from "node:path";
11440
+ import path37 from "node:path";
11335
11441
  var SHELL_INTERPRETERS = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish"]);
11336
11442
  var PYTHON_INTERPRETERS = /* @__PURE__ */ new Set(["python", "python3"]);
11337
11443
  var SHELL_SHORT_OPTIONS = /* @__PURE__ */ new Set(["c", "l", "e", "x", "u"]);
@@ -11393,7 +11499,7 @@ var OSASCRIPT_PROFILE = {
11393
11499
  attachedValuePrefixes: []
11394
11500
  };
11395
11501
  function normalizeInterpreter(value) {
11396
- return path36.basename(value);
11502
+ return path37.basename(value);
11397
11503
  }
11398
11504
  function scriptResult(interpreter, token) {
11399
11505
  if (!token) {
@@ -11623,7 +11729,7 @@ function parseOptions(words, start, options) {
11623
11729
  function decodeDockerComposeRun(tokens) {
11624
11730
  if (tokens.some((token) => token.kind === "operator")) return { kind: "none" };
11625
11731
  const words = tokens.filter((token) => token.kind === "word");
11626
- const head = path37.basename(words[0]?.value ?? "");
11732
+ const head = path38.basename(words[0]?.value ?? "");
11627
11733
  let index;
11628
11734
  if (head === "docker-compose") {
11629
11735
  index = 1;
@@ -11664,7 +11770,7 @@ function decodeDockerComposeRun(tokens) {
11664
11770
  }
11665
11771
 
11666
11772
  // src/core/verdict/egress-classify.ts
11667
- import path38 from "node:path";
11773
+ import path39 from "node:path";
11668
11774
  var EGRESS_TOOL_HEADS = /* @__PURE__ */ new Set([
11669
11775
  "aws",
11670
11776
  "curl",
@@ -11713,7 +11819,7 @@ function isEgressToolHead(head) {
11713
11819
  return EGRESS_TOOL_HEADS.has(head);
11714
11820
  }
11715
11821
  function decodeEgressEffects(params) {
11716
- const head = path38.basename(params.tokens[0] ?? "");
11822
+ const head = path39.basename(params.tokens[0] ?? "");
11717
11823
  if (head !== "curl" && head !== "wget" && head !== "gh") {
11718
11824
  return null;
11719
11825
  }
@@ -11721,7 +11827,7 @@ function decodeEgressEffects(params) {
11721
11827
  const provenance = { segment: params.segment };
11722
11828
  const requirements = [];
11723
11829
  for (const file of decoded.files) {
11724
- const resolved = path38.resolve(params.cwd, expandHome2(file));
11830
+ const resolved = path39.resolve(params.cwd, expandHome2(file));
11725
11831
  requirements.push(
11726
11832
  requirement("fs.read", "fs.read", { kind: "path", path: resolved }, params.segment, [
11727
11833
  "egress.explicit_file_read"
@@ -11743,7 +11849,7 @@ function decodeEgressEffects(params) {
11743
11849
  if (file === "-") {
11744
11850
  continue;
11745
11851
  }
11746
- const resolved = path38.resolve(params.cwd, expandHome2(file));
11852
+ const resolved = path39.resolve(params.cwd, expandHome2(file));
11747
11853
  if (resolved === "/dev/null") {
11748
11854
  continue;
11749
11855
  }
@@ -12221,13 +12327,13 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
12221
12327
  if (head === "wget" && !explicitOutput) {
12222
12328
  outputFiles.push(
12223
12329
  ...endpointOutputNames.map(
12224
- (name) => outputDirectory ? path38.join(outputDirectory, name) : name
12330
+ (name) => outputDirectory ? path39.join(outputDirectory, name) : name
12225
12331
  )
12226
12332
  );
12227
12333
  } else if (head === "curl" && remoteNameOutput) {
12228
12334
  outputFiles.push(
12229
12335
  ...endpointOutputNames.map(
12230
- (name) => outputDirectory ? path38.join(outputDirectory, name) : name
12336
+ (name) => outputDirectory ? path39.join(outputDirectory, name) : name
12231
12337
  )
12232
12338
  );
12233
12339
  }
@@ -12241,7 +12347,7 @@ function decodeSingleCurlWgetGrammar(head, tokens) {
12241
12347
  outputFiles: [
12242
12348
  ...new Set(
12243
12349
  outputFiles.map(
12244
- (file) => outputDirectory && directoryEligibleOutputs.has(file) && !path38.isAbsolute(file) ? path38.join(outputDirectory, file) : file
12350
+ (file) => outputDirectory && directoryEligibleOutputs.has(file) && !path39.isAbsolute(file) ? path39.join(outputDirectory, file) : file
12245
12351
  )
12246
12352
  )
12247
12353
  ],
@@ -12256,7 +12362,7 @@ function remoteOutputName(spec) {
12256
12362
  } catch {
12257
12363
  pathname = spec.split(/[?#]/, 1)[0] ?? "";
12258
12364
  }
12259
- const name = path38.posix.basename(pathname);
12365
+ const name = path39.posix.basename(pathname);
12260
12366
  return name && name !== "/" ? name : "index.html";
12261
12367
  }
12262
12368
  function decodeGhGrammar(tokens) {
@@ -12421,7 +12527,7 @@ function expandHome2(value) {
12421
12527
  return process.env.HOME ?? value;
12422
12528
  }
12423
12529
  if (value.startsWith("~/")) {
12424
- return path38.join(process.env.HOME ?? "~", value.slice(2));
12530
+ return path39.join(process.env.HOME ?? "~", value.slice(2));
12425
12531
  }
12426
12532
  return value;
12427
12533
  }
@@ -12440,7 +12546,7 @@ function requirement(tag, action, resource, segment, signals) {
12440
12546
  }
12441
12547
 
12442
12548
  // src/core/verdict/git-classifier.ts
12443
- import path39 from "node:path";
12549
+ import path40 from "node:path";
12444
12550
  init_shell_tokenizer();
12445
12551
  var GIT_BRANCH_MUTATION_FLAGS = /* @__PURE__ */ new Set([
12446
12552
  "--copy",
@@ -12536,7 +12642,7 @@ var FILE_OPERAND_SUBCOMMANDS = /* @__PURE__ */ new Set([
12536
12642
  var COMPOUND_SUBCOMMAND_HEADS = /* @__PURE__ */ new Set(["worktree", "stash", "tag"]);
12537
12643
  var REF_ONLY_WITHOUT_TERMINATOR = /* @__PURE__ */ new Set(["checkout", "show", "log"]);
12538
12644
  function isGitExecutable(token) {
12539
- return path39.basename(token) === "git";
12645
+ return path40.basename(token) === "git";
12540
12646
  }
12541
12647
  function takesValue(flag) {
12542
12648
  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=");
@@ -12564,7 +12670,7 @@ function peelGlobalOptions(tokens, baseCwd) {
12564
12670
  if (token === "-C" || token === "--work-tree" || token === "--git-dir" || token === "-c") {
12565
12671
  const value = tokens[index + 1];
12566
12672
  if (token === "-C" && value) {
12567
- effectiveCwd = path39.resolve(baseCwd, value);
12673
+ effectiveCwd = path40.resolve(baseCwd, value);
12568
12674
  } else if (token === "--work-tree" && value) {
12569
12675
  workTree = value;
12570
12676
  } else if (token === "--git-dir" && value) {
@@ -12574,7 +12680,7 @@ function peelGlobalOptions(tokens, baseCwd) {
12574
12680
  continue;
12575
12681
  }
12576
12682
  if (token.startsWith("-C") && token.length > 2) {
12577
- effectiveCwd = path39.resolve(baseCwd, token.slice(2));
12683
+ effectiveCwd = path40.resolve(baseCwd, token.slice(2));
12578
12684
  index += 1;
12579
12685
  continue;
12580
12686
  }
@@ -12717,7 +12823,7 @@ function looksLikeDiffPathOperand(token) {
12717
12823
  if (!looksLikeFileOperand(token)) {
12718
12824
  return false;
12719
12825
  }
12720
- if (token.startsWith(".") || path39.isAbsolute(token)) {
12826
+ if (token.startsWith(".") || path40.isAbsolute(token)) {
12721
12827
  return true;
12722
12828
  }
12723
12829
  return token.includes(".");
@@ -12725,12 +12831,12 @@ function looksLikeDiffPathOperand(token) {
12725
12831
  function resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir) {
12726
12832
  const resolveBase = effectiveCwd ?? baseCwd;
12727
12833
  if (workTree) {
12728
- return path39.resolve(resolveBase, workTree);
12834
+ return path40.resolve(resolveBase, workTree);
12729
12835
  }
12730
12836
  if (gitDir) {
12731
- const resolvedGitDir = path39.resolve(resolveBase, gitDir);
12732
- if (path39.basename(resolvedGitDir) === ".git") {
12733
- return path39.dirname(resolvedGitDir);
12837
+ const resolvedGitDir = path40.resolve(resolveBase, gitDir);
12838
+ if (path40.basename(resolvedGitDir) === ".git") {
12839
+ return path40.dirname(resolvedGitDir);
12734
12840
  }
12735
12841
  }
12736
12842
  return void 0;
@@ -12811,7 +12917,7 @@ function classifyGitCommand(tokens, baseCwd) {
12811
12917
  const { subcommand, args, effectiveCwd, gitDir, workTree } = normalized;
12812
12918
  const normalizedKey = `git ${subcommand}`;
12813
12919
  const gitWorkTree = resolveGitWorkTree(baseCwd, effectiveCwd, workTree, gitDir);
12814
- const effectiveGitDir = gitDir ? path39.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
12920
+ const effectiveGitDir = gitDir ? path40.resolve(effectiveCwd ?? baseCwd, gitDir) : void 0;
12815
12921
  const scopeTargets = [effectiveCwd, gitWorkTree, effectiveGitDir].filter(
12816
12922
  (target, index, targets) => Boolean(target) && targets.indexOf(target) === index
12817
12923
  );
@@ -12963,9 +13069,9 @@ function decodeGitEffects(params) {
12963
13069
  ...subcommand === "push" ? ["tier0_external"] : []
12964
13070
  ];
12965
13071
  const effectiveCwd = normalized.effectiveCwd ?? params.cwd;
12966
- const workTreeRoot = normalized.workTree ? path39.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
12967
- const gitRefRoot = normalized.gitDir ? path39.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
12968
- const gitControlRoot = normalized.gitDir ? gitRefRoot : path39.join(gitRefRoot, ".git");
13072
+ const workTreeRoot = normalized.workTree ? path40.resolve(normalized.effectiveCwd ?? params.cwd, normalized.workTree) : normalized.effectiveCwd ?? params.repoRoot;
13073
+ const gitRefRoot = normalized.gitDir ? path40.resolve(effectiveCwd, normalized.gitDir) : workTreeRoot;
13074
+ const gitControlRoot = normalized.gitDir ? gitRefRoot : path40.join(gitRefRoot, ".git");
12969
13075
  const requirements = [];
12970
13076
  if (subcommand === "fetch" || subcommand === "pull") {
12971
13077
  const positionals = gitRemotePositionals(args);
@@ -13124,7 +13230,7 @@ function decodeGitEffects(params) {
13124
13230
  gitRequirement(
13125
13231
  "control_plane.write",
13126
13232
  "control_plane.write",
13127
- { kind: "path", path: path39.join(gitControlRoot, "logs") },
13233
+ { kind: "path", path: path40.join(gitControlRoot, "logs") },
13128
13234
  params.segment,
13129
13235
  [...signals, "git_history_destructive", "git.reflog.mutate"]
13130
13236
  )
@@ -13182,7 +13288,7 @@ function decodeGitEffects(params) {
13182
13288
  gitRequirement(
13183
13289
  "fs.read",
13184
13290
  "fs.read",
13185
- { kind: "path", path: path39.resolve(workTreeRoot, operand) },
13291
+ { kind: "path", path: path40.resolve(workTreeRoot, operand) },
13186
13292
  params.segment,
13187
13293
  [...signals, "git.path.read"]
13188
13294
  )
@@ -13217,7 +13323,7 @@ function decodeGitEffects(params) {
13217
13323
  gitRequirement(
13218
13324
  "fs.write",
13219
13325
  "fs.write",
13220
- { kind: "path", path: path39.resolve(workTreeRoot, operand) },
13326
+ { kind: "path", path: path40.resolve(workTreeRoot, operand) },
13221
13327
  params.segment,
13222
13328
  [...signals, "git.path.write"]
13223
13329
  )
@@ -13401,8 +13507,8 @@ function gitRequirement(tag, action, resource, segment, signals) {
13401
13507
  }
13402
13508
 
13403
13509
  // src/core/verdict/launcher-resolve.ts
13404
- import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
13405
- import path40 from "node:path";
13510
+ import { existsSync as existsSync12, readFileSync as readFileSync5 } from "node:fs";
13511
+ import path41 from "node:path";
13406
13512
 
13407
13513
  // src/core/verdict/makefile-expand.ts
13408
13514
  var MAX_EXPAND_DEPTH = 16;
@@ -13575,8 +13681,8 @@ var PNPM_BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
13575
13681
  "why"
13576
13682
  ]);
13577
13683
  function readPackageJson(dir) {
13578
- const packagePath = path40.join(dir, "package.json");
13579
- if (!existsSync11(packagePath)) {
13684
+ const packagePath = path41.join(dir, "package.json");
13685
+ if (!existsSync12(packagePath)) {
13580
13686
  return null;
13581
13687
  }
13582
13688
  try {
@@ -13586,17 +13692,17 @@ function readPackageJson(dir) {
13586
13692
  }
13587
13693
  }
13588
13694
  function findPackageJson(startDir, stopDir) {
13589
- let current = path40.resolve(startDir);
13590
- const stop = path40.resolve(stopDir);
13695
+ let current = path41.resolve(startDir);
13696
+ const stop = path41.resolve(stopDir);
13591
13697
  while (true) {
13592
- const packagePath = path40.join(current, "package.json");
13593
- if (existsSync11(packagePath)) {
13698
+ const packagePath = path41.join(current, "package.json");
13699
+ if (existsSync12(packagePath)) {
13594
13700
  return packagePath;
13595
13701
  }
13596
- if (current === stop || current === path40.dirname(current)) {
13597
- return existsSync11(packagePath) ? packagePath : null;
13702
+ if (current === stop || current === path41.dirname(current)) {
13703
+ return existsSync12(packagePath) ? packagePath : null;
13598
13704
  }
13599
- const parent = path40.dirname(current);
13705
+ const parent = path41.dirname(current);
13600
13706
  if (!parent.startsWith(stop) && parent !== current) {
13601
13707
  }
13602
13708
  if (parent === current) {
@@ -13653,7 +13759,7 @@ function resolveNpmRecipe(cwd, repoRoot, scriptName, extraArgs) {
13653
13759
  }
13654
13760
  return { recipes: [], opaque: true, reason: "package_json_missing" };
13655
13761
  }
13656
- const pkg = readPackageJson(path40.dirname(packagePath));
13762
+ const pkg = readPackageJson(path41.dirname(packagePath));
13657
13763
  const scripts = pkg?.scripts;
13658
13764
  if (!scripts || typeof scripts !== "object") {
13659
13765
  return { recipes: [], opaque: true, reason: "package_scripts_missing" };
@@ -13744,20 +13850,20 @@ function parseMakefileRecipeContent(content) {
13744
13850
  function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
13745
13851
  const candidates = ["Makefile", "makefile", "GNUmakefile"];
13746
13852
  let makefilePath = null;
13747
- let searchDir = path40.resolve(cwd);
13748
- const stop = path40.resolve(repoRoot);
13853
+ let searchDir = path41.resolve(cwd);
13854
+ const stop = path41.resolve(repoRoot);
13749
13855
  while (true) {
13750
13856
  for (const name of candidates) {
13751
- const candidate = path40.join(searchDir, name);
13752
- if (existsSync11(candidate)) {
13857
+ const candidate = path41.join(searchDir, name);
13858
+ if (existsSync12(candidate)) {
13753
13859
  makefilePath = candidate;
13754
13860
  break;
13755
13861
  }
13756
13862
  }
13757
- if (makefilePath || searchDir === stop || searchDir === path40.dirname(searchDir)) {
13863
+ if (makefilePath || searchDir === stop || searchDir === path41.dirname(searchDir)) {
13758
13864
  break;
13759
13865
  }
13760
- searchDir = path40.dirname(searchDir);
13866
+ searchDir = path41.dirname(searchDir);
13761
13867
  }
13762
13868
  if (!makefilePath) {
13763
13869
  return { recipes: [], opaque: true, reason: "unknown_local_effect" };
@@ -13784,7 +13890,7 @@ function resolveMakeRecipe(cwd, repoRoot, target, cliVars = {}) {
13784
13890
  }
13785
13891
  const entry = targets.get(name);
13786
13892
  if (!entry) {
13787
- if (!existsSync11(path40.resolve(path40.dirname(makefilePath), name))) {
13893
+ if (!existsSync12(path41.resolve(path41.dirname(makefilePath), name))) {
13788
13894
  hasUndefinedPrerequisite = true;
13789
13895
  }
13790
13896
  return;
@@ -13883,7 +13989,7 @@ function resolveLauncherRecipe(params) {
13883
13989
  }
13884
13990
 
13885
13991
  // src/core/verdict/parser.ts
13886
- import path41 from "node:path";
13992
+ import path42 from "node:path";
13887
13993
 
13888
13994
  // src/core/shell-substitution.ts
13889
13995
  function findStructuralCommandSubstitutions(command) {
@@ -14123,7 +14229,7 @@ var INTERPRETER_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
14123
14229
  ".sh"
14124
14230
  ]);
14125
14231
  function normalizeHead(token) {
14126
- const base = path41.basename(token);
14232
+ const base = path42.basename(token);
14127
14233
  if (base && base !== "." && base !== "..") {
14128
14234
  return base;
14129
14235
  }
@@ -14433,7 +14539,7 @@ function isBareInterpreter(tokens) {
14433
14539
  return false;
14434
14540
  }
14435
14541
  const scriptArg = args.find((token) => !token.startsWith("-"));
14436
- if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path41.extname(scriptArg))) {
14542
+ if (scriptArg && INTERPRETER_SCRIPT_EXTENSIONS.has(path42.extname(scriptArg))) {
14437
14543
  return false;
14438
14544
  }
14439
14545
  if (scriptArg) {
@@ -14673,7 +14779,7 @@ function mergeNodes(nodes) {
14673
14779
  }
14674
14780
 
14675
14781
  // src/core/effect-ir/shell-lower/argv-delegate-gate.ts
14676
- import path42 from "node:path";
14782
+ import path43 from "node:path";
14677
14783
  var ARGV_DELEGATE_INNER_BLOCKLIST = /* @__PURE__ */ new Set([
14678
14784
  "sudo",
14679
14785
  "env",
@@ -14694,7 +14800,7 @@ function shouldApplyArgvDelegate(head, innerTokens, depth) {
14694
14800
  if (ARGV_DELEGATE_INNER_BLOCKLIST.has(head)) {
14695
14801
  return false;
14696
14802
  }
14697
- const innerHead = path42.basename(innerTokens[0] ?? "");
14803
+ const innerHead = path43.basename(innerTokens[0] ?? "");
14698
14804
  if (ARGV_DELEGATE_INNER_BLOCKLIST.has(innerHead)) {
14699
14805
  return false;
14700
14806
  }
@@ -14801,7 +14907,7 @@ function withInnerProvenance(requirementValue, innerCommand, launcher, outerSegm
14801
14907
 
14802
14908
  // src/core/effect-ir/shell-lower/tokens.ts
14803
14909
  init_shell_tokenizer();
14804
- import path43 from "node:path";
14910
+ import path44 from "node:path";
14805
14911
  var ENV_PREFIX_PATTERN2 = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/;
14806
14912
  var LOOPBACK_HOSTS2 = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "0:0:0:0:0:0:0:1"]);
14807
14913
  var METADATA_ONLY_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V", "--help", "-h"]);
@@ -14945,9 +15051,9 @@ function resolvePathOperand(operand, cwd) {
14945
15051
  return process.env.HOME ?? operand;
14946
15052
  }
14947
15053
  if (operand.startsWith("~/")) {
14948
- return path43.join(process.env.HOME ?? "~", operand.slice(2));
15054
+ return path44.join(process.env.HOME ?? "~", operand.slice(2));
14949
15055
  }
14950
- return path43.resolve(cwd, operand);
15056
+ return path44.resolve(cwd, operand);
14951
15057
  }
14952
15058
  function isOptionToken(value) {
14953
15059
  return value.startsWith("-") || value.startsWith("+");
@@ -14959,7 +15065,7 @@ function pipeToShell(command) {
14959
15065
  return /(?:^|[|;&]\s*)(?:bash|sh|zsh|dash|fish)(?:\s|$)/.test(command) && /\|/.test(command);
14960
15066
  }
14961
15067
  function executableBaseName(head) {
14962
- return path43.basename(head);
15068
+ return path44.basename(head);
14963
15069
  }
14964
15070
  function isMetadataOnlyArgv(argv) {
14965
15071
  return argv.length > 0 && argv.every((token) => METADATA_ONLY_FLAGS.has(token));
@@ -15078,15 +15184,22 @@ function effectChangingEnvironmentSignals(head, env, changedNames) {
15078
15184
  }
15079
15185
 
15080
15186
  // src/core/effect-ir/shell-lower/decode-process.ts
15081
- import path47 from "node:path";
15187
+ import path48 from "node:path";
15082
15188
 
15083
15189
  // src/core/effect-ir/shell-lower/decoders/belay.ts
15084
- import path44 from "node:path";
15190
+ import path45 from "node:path";
15085
15191
  function decodeBelay(args, repoRoot, segment) {
15086
15192
  const [section, operation, key] = args;
15087
15193
  const judgeCommand = section === "judge" && operation !== void 0 && ["consent", "list", "status", "test", "use"].includes(operation);
15088
15194
  const configRead = section === "config" && (operation === void 0 || operation === "list" || operation === "get" && key?.startsWith("judge."));
15089
15195
  const configJudgeMutation = section === "config" && (["set", "unset"].includes(operation ?? "") && key?.startsWith("judge.") || operation === "credential" && key === "mode");
15196
+ const approvalAuthorityCommand = [
15197
+ "approval-token",
15198
+ "approve",
15199
+ "revoke",
15200
+ "standing-allow"
15201
+ ].includes(section ?? "");
15202
+ const configTrustMutation = section === "config" && operation === "trust";
15090
15203
  if (judgeCommand || configRead || configJudgeMutation) {
15091
15204
  return [
15092
15205
  processRequirement("belay", "inspect", segment, [
@@ -15095,12 +15208,23 @@ function decodeBelay(args, repoRoot, segment) {
15095
15208
  ])
15096
15209
  ];
15097
15210
  }
15211
+ if (approvalAuthorityCommand || configTrustMutation) {
15212
+ return [
15213
+ requirement2(
15214
+ "control_plane.write",
15215
+ "control_plane.write",
15216
+ { kind: "path", path: path45.join(repoRoot, ".belay-control-plane") },
15217
+ segment,
15218
+ [approvalAuthorityCommand ? "belay.approval_authority" : "belay.config_trust"]
15219
+ )
15220
+ ];
15221
+ }
15098
15222
  if (section === "config" && ["set", "unset", "credential"].includes(operation ?? "")) {
15099
15223
  return [
15100
15224
  requirement2(
15101
15225
  "control_plane.write",
15102
15226
  "control_plane.write",
15103
- { kind: "path", path: path44.join(repoRoot, ".belay-control-plane") },
15227
+ { kind: "path", path: path45.join(repoRoot, ".belay-control-plane") },
15104
15228
  segment,
15105
15229
  ["belay.config_non_judge_mutation"]
15106
15230
  )
@@ -15341,7 +15465,7 @@ function validDockerInfo(args) {
15341
15465
  // src/core/effect-ir/shell-lower/decoders/filesystem.ts
15342
15466
  init_git_resource_identity();
15343
15467
  import { lstatSync as lstatSync2, realpathSync as realpathSync4 } from "node:fs";
15344
- import path45 from "node:path";
15468
+ import path46 from "node:path";
15345
15469
  function decodeCopyMove(head, args, cwd, segment) {
15346
15470
  const requirements = [processRequirement(head, "spawn", segment, ["process.filesystem_mutation"])];
15347
15471
  const operands = [];
@@ -15469,11 +15593,11 @@ function decodeRm(args, cwd, repoRoot, segment) {
15469
15593
  function canonicalRmOperand(targetPath, finalOperandIsSymlink) {
15470
15594
  try {
15471
15595
  if (finalOperandIsSymlink) {
15472
- return path45.join(realpathSync4.native(path45.dirname(targetPath)), path45.basename(targetPath));
15596
+ return path46.join(realpathSync4.native(path46.dirname(targetPath)), path46.basename(targetPath));
15473
15597
  }
15474
15598
  return realpathSync4.native(targetPath);
15475
15599
  } catch {
15476
- return path45.resolve(targetPath);
15600
+ return path46.resolve(targetPath);
15477
15601
  }
15478
15602
  }
15479
15603
  function isSymbolicLink(targetPath) {
@@ -15484,8 +15608,8 @@ function isSymbolicLink(targetPath) {
15484
15608
  }
15485
15609
  }
15486
15610
  function pathContains(ancestor, candidate) {
15487
- const relative = path45.relative(path45.resolve(ancestor), path45.resolve(candidate));
15488
- return relative === "" || !relative.startsWith("..") && !path45.isAbsolute(relative);
15611
+ const relative = path46.relative(path46.resolve(ancestor), path46.resolve(candidate));
15612
+ return relative === "" || !relative.startsWith("..") && !path46.isAbsolute(relative);
15489
15613
  }
15490
15614
  function filesystemReadOperands(head, args) {
15491
15615
  switch (head) {
@@ -15625,7 +15749,7 @@ function decodePrisma(args, env, repoRoot, segment) {
15625
15749
 
15626
15750
  // src/core/effect-ir/shell-lower/decoders/ruby.ts
15627
15751
  init_path_utils();
15628
- import path46 from "node:path";
15752
+ import path47 from "node:path";
15629
15753
  var RAILS_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set(["routes", "middleware", "stats", "about", "version"]);
15630
15754
  function railsReadOnlySubcommand(args) {
15631
15755
  const subcommand = args[0];
@@ -15635,7 +15759,7 @@ function railsReadOnlySubcommand(args) {
15635
15759
  return RAILS_READ_ONLY_SUBCOMMANDS.has(subcommand);
15636
15760
  }
15637
15761
  function isRubyTestScript(scriptPath) {
15638
- const base = path46.basename(scriptPath);
15762
+ const base = path47.basename(scriptPath);
15639
15763
  return base.endsWith("_test.rb") || base.endsWith("_spec.rb");
15640
15764
  }
15641
15765
  function parseRubyTestInvocation(args) {
@@ -16049,7 +16173,7 @@ function decodeProcessOrFilesystem(params) {
16049
16173
  requirement2(
16050
16174
  "fs.read",
16051
16175
  "fs.read",
16052
- { kind: "path", path: path47.resolve(cwd, syntax) },
16176
+ { kind: "path", path: path48.resolve(cwd, syntax) },
16053
16177
  segment,
16054
16178
  ["shell.syntax_source_read"]
16055
16179
  )
@@ -16255,7 +16379,7 @@ function packageExecInnerIsMetadata(peel) {
16255
16379
 
16256
16380
  // src/core/effect-ir/shell-lower/segment.ts
16257
16381
  init_shell_tokenizer();
16258
- import path48 from "node:path";
16382
+ import path49 from "node:path";
16259
16383
  var DYNAMIC_SHELL_VALUE_PATTERN = /(?:\$\(|`|\$(?:\d+|[@*#?$!-]|\{[^}]*\}|[A-Za-z_][A-Za-z0-9_]*))/;
16260
16384
  var SHELL_GLOB_PATTERN = /[*?[]/;
16261
16385
  function requiresKnownCwd(requirementValue) {
@@ -16270,11 +16394,11 @@ function joinNestedOpacity(outer, nested) {
16270
16394
  }
16271
16395
  function startsLocalPostgresService(command) {
16272
16396
  const tokens = tokenizeShell(command);
16273
- return path48.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
16397
+ return path49.basename(tokens[0] ?? "") === "docker" && tokens[1] === "compose" && ["up", "start", "restart"].includes(tokens[2] ?? "") && tokens.includes("postgres");
16274
16398
  }
16275
16399
  function resolveCdTransition(command, currentCwd) {
16276
16400
  const tokens = tokenizeShell(command);
16277
- if (path48.basename(tokens[0] ?? "") !== "cd") {
16401
+ if (path49.basename(tokens[0] ?? "") !== "cd") {
16278
16402
  return null;
16279
16403
  }
16280
16404
  const target = tokens[1] ?? "~";
@@ -16437,7 +16561,7 @@ function lowerSegment(command, context) {
16437
16561
  stripStructuredRedirects(lexed.tokens),
16438
16562
  stripRedirects(parsedTokens)
16439
16563
  );
16440
- const head = path49.basename(tokens[0] ?? parsed.head);
16564
+ const head = path50.basename(tokens[0] ?? parsed.head);
16441
16565
  let opacity = segmentOpacity(command);
16442
16566
  const signals = /* @__PURE__ */ new Set();
16443
16567
  const requirements = [];
@@ -17289,7 +17413,7 @@ async function classifyToolUse(payload, repoRoot, cwd, config, options = {}) {
17289
17413
  };
17290
17414
  }
17291
17415
  const signals = [];
17292
- const resolvedPath = path50.isAbsolute(filePath) ? filePath : path50.resolve(cwd, filePath);
17416
+ const resolvedPath = path51.isAbsolute(filePath) ? filePath : path51.resolve(cwd, filePath);
17293
17417
  const hitsProtectedRoot = protectedRoots.some((root) => pathWithinRoot(root, resolvedPath));
17294
17418
  if (hitsProtectedRoot) {
17295
17419
  signals.push("control_plane_path");
@@ -17875,7 +17999,7 @@ function hashDecisionConfig(config) {
17875
17999
  init_fingerprint2();
17876
18000
 
17877
18001
  // src/version.ts
17878
- var PACKAGE_VERSION = "0.9.4";
18002
+ var PACKAGE_VERSION = "0.10.0";
17879
18003
 
17880
18004
  // src/runtime-provenance.ts
17881
18005
  function resolveRuntimeArtifactHash(artifactHash) {
@@ -17948,56 +18072,56 @@ function capabilityRequestsBlockRecovery(requests) {
17948
18072
  init_fingerprint2();
17949
18073
  init_path_utils();
17950
18074
  import { randomUUID as randomUUID5 } from "node:crypto";
17951
- import { existsSync as existsSync15 } from "node:fs";
17952
- import { mkdir as mkdir11, readdir as readdir3, readFile as readFile13, rename as rename3, rm as rm6 } from "node:fs/promises";
17953
- import path55 from "node:path";
18075
+ import { existsSync as existsSync16 } from "node:fs";
18076
+ import { mkdir as mkdir12, readdir as readdir3, readFile as readFile14, rename as rename4, rm as rm6 } from "node:fs/promises";
18077
+ import path56 from "node:path";
17954
18078
 
17955
18079
  // src/core/recovery/artifact-store.ts
17956
18080
  init_fingerprint2();
17957
18081
  init_path_utils();
17958
18082
  import { randomUUID as randomUUID4 } from "node:crypto";
17959
- import { existsSync as existsSync13 } from "node:fs";
17960
- import { lstat as lstat7, mkdir as mkdir10, open as open5, readdir as readdir2, readFile as readFile10, rename as rename2, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
17961
- import path52 from "node:path";
18083
+ import { existsSync as existsSync14 } from "node:fs";
18084
+ import { lstat as lstat7, mkdir as mkdir11, open as open6, readdir as readdir2, readFile as readFile11, rename as rename3, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
18085
+ import path53 from "node:path";
17962
18086
 
17963
18087
  // src/core/recovery/snapshot-node.ts
17964
18088
  init_fingerprint2();
17965
18089
  init_path_utils();
17966
18090
  import { createHash as createHash12 } from "node:crypto";
17967
- import { existsSync as existsSync12 } from "node:fs";
18091
+ import { existsSync as existsSync13 } from "node:fs";
17968
18092
  import {
17969
- chmod as chmod3,
18093
+ chmod as chmod4,
17970
18094
  copyFile as copyFile2,
17971
18095
  lstat as lstat6,
17972
- mkdir as mkdir9,
17973
- open as open4,
17974
- readFile as readFile9,
18096
+ mkdir as mkdir10,
18097
+ open as open5,
18098
+ readFile as readFile10,
17975
18099
  readlink as readlink4,
17976
18100
  rm as rm4,
17977
18101
  rmdir as rmdir2,
17978
18102
  symlink as symlink3,
17979
18103
  writeFile as writeFile6
17980
18104
  } from "node:fs/promises";
17981
- import path51 from "node:path";
18105
+ import path52 from "node:path";
17982
18106
  var RECOVERY_UNSUPPORTED_FILE_KIND = "recovery_unsupported_file_kind";
17983
18107
  function validRecoveryRelativePath(relativePath) {
17984
- if (!relativePath || relativePath.includes("\0") || path51.isAbsolute(relativePath)) return false;
17985
- const normalized = path51.normalize(relativePath);
17986
- return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path51.sep}`);
18108
+ if (!relativePath || relativePath.includes("\0") || path52.isAbsolute(relativePath)) return false;
18109
+ const normalized = path52.normalize(relativePath);
18110
+ return normalized !== "." && normalized !== ".." && !normalized.startsWith(`..${path52.sep}`);
17987
18111
  }
17988
18112
  async function assertRecoverySafeTarget(resourceRoot, relativePath) {
17989
18113
  if (!validRecoveryRelativePath(relativePath)) throw new Error("recovery_path_escape");
17990
18114
  const root = canonicalPath(resourceRoot);
17991
- const target = path51.resolve(root, relativePath);
17992
- const relative = path51.relative(root, target);
17993
- if (relative === ".." || relative.startsWith(`..${path51.sep}`) || path51.isAbsolute(relative)) {
18115
+ const target = path52.resolve(root, relativePath);
18116
+ const relative = path52.relative(root, target);
18117
+ if (relative === ".." || relative.startsWith(`..${path52.sep}`) || path52.isAbsolute(relative)) {
17994
18118
  throw new Error("recovery_path_escape");
17995
18119
  }
17996
18120
  let current = root;
17997
- const parentParts = path51.relative(root, path51.dirname(target)).split(path51.sep).filter(Boolean);
18121
+ const parentParts = path52.relative(root, path52.dirname(target)).split(path52.sep).filter(Boolean);
17998
18122
  for (const part of parentParts) {
17999
- current = path51.join(current, part);
18000
- if (!existsSync12(current)) break;
18123
+ current = path52.join(current, part);
18124
+ if (!existsSync13(current)) break;
18001
18125
  const info = await lstat6(current);
18002
18126
  if (info.isSymbolicLink()) throw new Error("recovery_symlink_escape");
18003
18127
  if (!info.isDirectory()) break;
@@ -18005,7 +18129,7 @@ async function assertRecoverySafeTarget(resourceRoot, relativePath) {
18005
18129
  return target;
18006
18130
  }
18007
18131
  async function fsyncPath(filePath) {
18008
- const handle = await open4(filePath, "r");
18132
+ const handle = await open5(filePath, "r");
18009
18133
  try {
18010
18134
  await handle.sync();
18011
18135
  } finally {
@@ -18047,13 +18171,13 @@ async function captureRecoverySnapshot(filePath, options) {
18047
18171
  return { kind: "directory", mode, hash: recoveryDirectoryHash(mode) };
18048
18172
  }
18049
18173
  if (!info.isFile()) throw new Error(RECOVERY_UNSUPPORTED_FILE_KIND);
18050
- const content = await readFile9(filePath);
18174
+ const content = await readFile10(filePath);
18051
18175
  const hash = createHash12("sha256").update(content).digest("hex");
18052
18176
  let blob;
18053
18177
  if (options?.blobDir) {
18054
- await mkdir9(options.blobDir, { recursive: true, mode: 448 });
18055
- const blobPath = path51.join(options.blobDir, hash);
18056
- if (!existsSync12(blobPath)) {
18178
+ await mkdir10(options.blobDir, { recursive: true, mode: 448 });
18179
+ const blobPath = path52.join(options.blobDir, hash);
18180
+ if (!existsSync13(blobPath)) {
18057
18181
  await writeFile6(blobPath, content, { mode: 384 });
18058
18182
  await fsyncPath(blobPath);
18059
18183
  }
@@ -18107,7 +18231,7 @@ async function validateRecoverySnapshot(params) {
18107
18231
  if (record.blob !== `blobs/${record.hash}`) throw new Error(params.corruptReason);
18108
18232
  let content;
18109
18233
  try {
18110
- content = await readFile9(path51.join(params.artifactDir, record.blob));
18234
+ content = await readFile10(path52.join(params.artifactDir, record.blob));
18111
18235
  } catch {
18112
18236
  throw new Error(params.corruptReason);
18113
18237
  }
@@ -18135,16 +18259,16 @@ var RECOVERY_STATES = /* @__PURE__ */ new Set([
18135
18259
  ]);
18136
18260
  var STAGING_STALE_MS = 5 * 6e4;
18137
18261
  function checkpointsRoot(stateDir) {
18138
- return path52.join(stateDir, "recovery", "checkpoints");
18262
+ return path53.join(stateDir, "recovery", "checkpoints");
18139
18263
  }
18140
18264
  function checkpointDir(stateDir, checkpointId) {
18141
18265
  if (!/^cp_[a-f0-9]{24}$/.test(checkpointId)) {
18142
18266
  throw new Error("invalid_recovery_checkpoint_id");
18143
18267
  }
18144
- return path52.join(checkpointsRoot(stateDir), checkpointId);
18268
+ return path53.join(checkpointsRoot(stateDir), checkpointId);
18145
18269
  }
18146
18270
  async function fsyncPath2(filePath) {
18147
- const handle = await open5(filePath, "r");
18271
+ const handle = await open6(filePath, "r");
18148
18272
  try {
18149
18273
  await handle.sync();
18150
18274
  } finally {
@@ -18152,13 +18276,13 @@ async function fsyncPath2(filePath) {
18152
18276
  }
18153
18277
  }
18154
18278
  async function atomicWriteJson(filePath, value) {
18155
- await mkdir10(path52.dirname(filePath), { recursive: true, mode: 448 });
18279
+ await mkdir11(path53.dirname(filePath), { recursive: true, mode: 448 });
18156
18280
  const temporary = `${filePath}.tmp-${randomUUID4()}`;
18157
18281
  await writeFile7(temporary, `${JSON.stringify(value, null, 2)}
18158
18282
  `, { mode: 384 });
18159
18283
  await fsyncPath2(temporary);
18160
- await rename2(temporary, filePath);
18161
- await fsyncPath2(path52.dirname(filePath));
18284
+ await rename3(temporary, filePath);
18285
+ await fsyncPath2(path53.dirname(filePath));
18162
18286
  }
18163
18287
  async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
18164
18288
  const value = {
@@ -18168,13 +18292,13 @@ async function writeRecoveryState(artifactDir, state, manifestHash, detail) {
18168
18292
  manifestHash,
18169
18293
  ...detail ? { detail } : {}
18170
18294
  };
18171
- await atomicWriteJson(path52.join(artifactDir, "state.json"), value);
18295
+ await atomicWriteJson(path53.join(artifactDir, "state.json"), value);
18172
18296
  }
18173
18297
  async function directorySize(root) {
18174
- if (!existsSync13(root)) return 0;
18298
+ if (!existsSync14(root)) return 0;
18175
18299
  let total = 0;
18176
18300
  for (const entry of await readdir2(root, { withFileTypes: true })) {
18177
- const entryPath = path52.join(root, entry.name);
18301
+ const entryPath = path53.join(root, entry.name);
18178
18302
  if (entry.isDirectory()) total += await directorySize(entryPath);
18179
18303
  else total += (await lstat7(entryPath)).size;
18180
18304
  }
@@ -18219,9 +18343,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18219
18343
  let rawManifest;
18220
18344
  let state;
18221
18345
  try {
18222
- rawManifest = JSON.parse(await readFile10(path52.join(artifactDir, "manifest.json"), "utf8"));
18346
+ rawManifest = JSON.parse(await readFile11(path53.join(artifactDir, "manifest.json"), "utf8"));
18223
18347
  state = JSON.parse(
18224
- await readFile10(path52.join(artifactDir, "state.json"), "utf8")
18348
+ await readFile11(path53.join(artifactDir, "state.json"), "utf8")
18225
18349
  );
18226
18350
  } catch {
18227
18351
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
@@ -18237,10 +18361,10 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18237
18361
  }
18238
18362
  const entryPaths = /* @__PURE__ */ new Set();
18239
18363
  for (const entry of manifest.entries) {
18240
- 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))) {
18364
+ 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(path53.normalize(entry.path))) {
18241
18365
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
18242
18366
  }
18243
- entryPaths.add(path52.normalize(entry.path));
18367
+ entryPaths.add(path53.normalize(entry.path));
18244
18368
  for (const [side, snapshot] of [
18245
18369
  ["before", entry.before],
18246
18370
  ["after", entry.after]
@@ -18254,9 +18378,9 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18254
18378
  });
18255
18379
  }
18256
18380
  }
18257
- const receiptPath = path52.join(artifactDir, "receipt.json");
18381
+ const receiptPath = path53.join(artifactDir, "receipt.json");
18258
18382
  let receipt;
18259
- if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync13(receiptPath)) {
18383
+ if (["applied", "restoring", "restored", "conflict"].includes(state.state) || existsSync14(receiptPath)) {
18260
18384
  receipt = await readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
18261
18385
  }
18262
18386
  return { artifactDir, manifest, state, manifestHash, ...receipt ? { receipt } : {} };
@@ -18264,7 +18388,7 @@ async function readRecoveryArtifact(stateDir, checkpointId) {
18264
18388
  async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash) {
18265
18389
  let rawReceipt;
18266
18390
  try {
18267
- rawReceipt = JSON.parse(await readFile10(path52.join(artifactDir, "receipt.json"), "utf8"));
18391
+ rawReceipt = JSON.parse(await readFile11(path53.join(artifactDir, "receipt.json"), "utf8"));
18268
18392
  } catch {
18269
18393
  throw new Error(RECOVERY_CHECKPOINT_CORRUPT);
18270
18394
  }
@@ -18287,8 +18411,8 @@ async function readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHas
18287
18411
  return receipt;
18288
18412
  }
18289
18413
  async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
18290
- const receiptPath = path52.join(artifactDir, "receipt.json");
18291
- if (existsSync13(receiptPath)) {
18414
+ const receiptPath = path53.join(artifactDir, "receipt.json");
18415
+ if (existsSync14(receiptPath)) {
18292
18416
  return readAndValidateRecoveryReceipt(artifactDir, manifest, manifestHash);
18293
18417
  }
18294
18418
  const receipt = {
@@ -18305,14 +18429,14 @@ async function ensureRecoveryReceipt(artifactDir, manifest, manifestHash) {
18305
18429
  }
18306
18430
  async function checkpointIds(stateDir) {
18307
18431
  const root = checkpointsRoot(stateDir);
18308
- if (!existsSync13(root)) return [];
18432
+ if (!existsSync14(root)) return [];
18309
18433
  return (await readdir2(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && /^cp_[a-f0-9]{24}$/.test(entry.name)).map((entry) => entry.name);
18310
18434
  }
18311
18435
  async function artifactRepoRoot(stateDir, checkpointId) {
18312
18436
  const artifactDir = checkpointDir(stateDir, checkpointId);
18313
18437
  try {
18314
18438
  const manifest = JSON.parse(
18315
- await readFile10(path52.join(artifactDir, "manifest.json"), "utf8")
18439
+ await readFile11(path53.join(artifactDir, "manifest.json"), "utf8")
18316
18440
  );
18317
18441
  if (typeof manifest.repoRoot === "string" && manifest.repoRoot) {
18318
18442
  return canonicalPath(manifest.repoRoot);
@@ -18320,7 +18444,7 @@ async function artifactRepoRoot(stateDir, checkpointId) {
18320
18444
  } catch {
18321
18445
  }
18322
18446
  try {
18323
- const owner = JSON.parse(await readFile10(path52.join(artifactDir, "owner.json"), "utf8"));
18447
+ const owner = JSON.parse(await readFile11(path53.join(artifactDir, "owner.json"), "utf8"));
18324
18448
  return typeof owner.repoRoot === "string" && owner.repoRoot ? canonicalPath(owner.repoRoot) : null;
18325
18449
  } catch {
18326
18450
  return null;
@@ -18336,14 +18460,14 @@ async function checkpointIdsForRepo(stateDir, repoRoot) {
18336
18460
  }
18337
18461
  async function cleanupOrphanedStaging(stateDir) {
18338
18462
  const root = checkpointsRoot(stateDir);
18339
- if (!existsSync13(root)) return;
18463
+ if (!existsSync14(root)) return;
18340
18464
  const now = Date.now();
18341
18465
  for (const entry of await readdir2(root, { withFileTypes: true })) {
18342
18466
  if (!entry.isDirectory() || !/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) continue;
18343
- const stagingPath = path52.join(root, entry.name);
18467
+ const stagingPath = path53.join(root, entry.name);
18344
18468
  let stale = false;
18345
18469
  try {
18346
- const owner = JSON.parse(await readFile10(path52.join(stagingPath, "owner.json"), "utf8"));
18470
+ const owner = JSON.parse(await readFile11(path53.join(stagingPath, "owner.json"), "utf8"));
18347
18471
  const pid = typeof owner.pid === "number" ? owner.pid : Number.NaN;
18348
18472
  const createdAt = typeof owner.createdAt === "string" ? Date.parse(owner.createdAt) : NaN;
18349
18473
  let alive = false;
@@ -18383,9 +18507,9 @@ async function markRecoveryCheckpointApplied(stateDir, checkpoint) {
18383
18507
 
18384
18508
  // src/core/recovery/reconcile.ts
18385
18509
  init_fingerprint2();
18386
- import { existsSync as existsSync14 } from "node:fs";
18387
- import { readFile as readFile11 } from "node:fs/promises";
18388
- import path53 from "node:path";
18510
+ import { existsSync as existsSync15 } from "node:fs";
18511
+ import { readFile as readFile12 } from "node:fs/promises";
18512
+ import path54 from "node:path";
18389
18513
  async function matchRecoverySide(resourceRoot, entries, side) {
18390
18514
  for (const entry of entries) {
18391
18515
  const target = await assertRecoverySafeTarget(resourceRoot, entry.path);
@@ -18399,9 +18523,9 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
18399
18523
  loaded = await readRecoveryArtifact(stateDir, checkpointId);
18400
18524
  } catch {
18401
18525
  const artifactDir = checkpointDir(stateDir, checkpointId);
18402
- if (existsSync14(artifactDir)) {
18403
- const manifestPath = path53.join(artifactDir, "manifest.json");
18404
- const hash = existsSync14(manifestPath) ? hashValue(await readFile11(manifestPath, "utf8")) : "unavailable";
18526
+ if (existsSync15(artifactDir)) {
18527
+ const manifestPath = path54.join(artifactDir, "manifest.json");
18528
+ const hash = existsSync15(manifestPath) ? hashValue(await readFile12(manifestPath, "utf8")) : "unavailable";
18405
18529
  await writeRecoveryState(artifactDir, "corrupt", hash, RECOVERY_CHECKPOINT_CORRUPT);
18406
18530
  }
18407
18531
  return "corrupt";
@@ -18436,8 +18560,8 @@ async function reconcileRecoveryCheckpoint(stateDir, checkpointId) {
18436
18560
 
18437
18561
  // src/core/recovery/resource-identity.ts
18438
18562
  init_fingerprint2();
18439
- import { lstat as lstat8, readFile as readFile12, realpath as realpath3 } from "node:fs/promises";
18440
- import path54 from "node:path";
18563
+ import { lstat as lstat8, readFile as readFile13, realpath as realpath3 } from "node:fs/promises";
18564
+ import path55 from "node:path";
18441
18565
  async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
18442
18566
  const resolvedRoot = await realpath3(resourceRoot);
18443
18567
  if (resourceKind === "directory") {
@@ -18445,13 +18569,13 @@ async function currentRecoveryResourceIdentity(resourceRoot, resourceKind) {
18445
18569
  if (!rootInfo.isDirectory()) throw new Error("recovery_repo_identity_unavailable");
18446
18570
  return hashValue(`${resolvedRoot}\0${rootInfo.dev}:${rootInfo.ino}:${rootInfo.birthtimeMs}`);
18447
18571
  }
18448
- const dotGit = path54.join(resolvedRoot, ".git");
18572
+ const dotGit = path55.join(resolvedRoot, ".git");
18449
18573
  const gitInfo = await lstat8(dotGit);
18450
18574
  let gitMetadataPath = dotGit;
18451
18575
  if (gitInfo.isFile()) {
18452
- const marker = (await readFile12(dotGit, "utf8")).trim();
18576
+ const marker = (await readFile13(dotGit, "utf8")).trim();
18453
18577
  if (!marker.startsWith("gitdir:")) throw new Error("recovery_repo_identity_unavailable");
18454
- gitMetadataPath = path54.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
18578
+ gitMetadataPath = path55.resolve(resolvedRoot, marker.slice("gitdir:".length).trim());
18455
18579
  } else if (!gitInfo.isDirectory()) {
18456
18580
  throw new Error("recovery_repo_identity_unavailable");
18457
18581
  }
@@ -18516,7 +18640,7 @@ async function garbageCollect(stateDir, config, repoRoot) {
18516
18640
  async function prepareRecoveryCheckpoint(params) {
18517
18641
  const backend = params.backend ?? "git_worktree";
18518
18642
  const resourceKind = await resolveRecoveryResourceKind(backend, params.repoRoot);
18519
- await mkdir11(checkpointsRoot(params.stateDir), { recursive: true, mode: 448 });
18643
+ await mkdir12(checkpointsRoot(params.stateDir), { recursive: true, mode: 448 });
18520
18644
  await cleanupOrphanedStaging(params.stateDir);
18521
18645
  await garbageCollect(params.stateDir, params.config, params.repoRoot);
18522
18646
  const existing = await checkpointIdsForRepo(params.stateDir, params.repoRoot);
@@ -18524,16 +18648,16 @@ async function prepareRecoveryCheckpoint(params) {
18524
18648
  throw new Error(RECOVERY_CHECKPOINT_QUOTA);
18525
18649
  }
18526
18650
  const checkpointId = `cp_${randomUUID5().replaceAll("-", "").slice(0, 24)}`;
18527
- const temporary = path55.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
18651
+ const temporary = path56.join(checkpointsRoot(params.stateDir), `.tmp-${checkpointId}`);
18528
18652
  const finalDir = checkpointDir(params.stateDir, checkpointId);
18529
- await mkdir11(temporary, { recursive: true, mode: 448 });
18530
- await atomicWriteJson(path55.join(temporary, "owner.json"), {
18653
+ await mkdir12(temporary, { recursive: true, mode: 448 });
18654
+ await atomicWriteJson(path56.join(temporary, "owner.json"), {
18531
18655
  version: 1,
18532
18656
  pid: process.pid,
18533
18657
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
18534
18658
  repoRoot: canonicalPath(params.repoRoot)
18535
18659
  });
18536
- await mkdir11(path55.join(temporary, "blobs"), { recursive: true, mode: 448 });
18660
+ await mkdir12(path56.join(temporary, "blobs"), { recursive: true, mode: 448 });
18537
18661
  try {
18538
18662
  const entries = [];
18539
18663
  const protectedRoots = (params.protectedRoots ?? []).map(canonicalPath);
@@ -18542,8 +18666,8 @@ async function prepareRecoveryCheckpoint(params) {
18542
18666
  )) {
18543
18667
  const target = await assertRecoverySafeTarget(params.repoRoot, change.relativePath);
18544
18668
  if (protectedRoots.some((root) => {
18545
- const relative = path55.relative(root, target);
18546
- return relative === "" || relative !== ".." && !relative.startsWith(`..${path55.sep}`) && !path55.isAbsolute(relative);
18669
+ const relative = path56.relative(root, target);
18670
+ return relative === "" || relative !== ".." && !relative.startsWith(`..${path56.sep}`) && !path56.isAbsolute(relative);
18547
18671
  })) {
18548
18672
  throw new Error("recovery_protected_path");
18549
18673
  }
@@ -18555,7 +18679,7 @@ async function prepareRecoveryCheckpoint(params) {
18555
18679
  entries.push({
18556
18680
  path: change.relativePath,
18557
18681
  before: await captureRecoverySnapshot(baseline, {
18558
- blobDir: path55.join(temporary, "blobs")
18682
+ blobDir: path56.join(temporary, "blobs")
18559
18683
  }),
18560
18684
  after: withoutRecoveryBlob(await captureRecoverySnapshot(source))
18561
18685
  });
@@ -18592,12 +18716,12 @@ async function prepareRecoveryCheckpoint(params) {
18592
18716
  entries
18593
18717
  };
18594
18718
  const manifestHash = hashValue(canonicalStringify(manifest));
18595
- await atomicWriteJson(path55.join(temporary, "manifest.json"), manifest);
18719
+ await atomicWriteJson(path56.join(temporary, "manifest.json"), manifest);
18596
18720
  await writeRecoveryState(temporary, "prepared", manifestHash);
18597
18721
  await fsyncPath2(temporary);
18598
18722
  const projectedBytes = await recoveryCheckpointStorageBytes(params.stateDir, params.repoRoot);
18599
18723
  if (projectedBytes > params.config.maxBytes) throw new Error(RECOVERY_CHECKPOINT_QUOTA);
18600
- await rename3(temporary, finalDir);
18724
+ await rename4(temporary, finalDir);
18601
18725
  await fsyncPath2(checkpointsRoot(params.stateDir));
18602
18726
  return {
18603
18727
  checkpointId,
@@ -18635,7 +18759,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18635
18759
  } catch {
18636
18760
  try {
18637
18761
  const raw = JSON.parse(
18638
- await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18762
+ await readFile14(path56.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18639
18763
  );
18640
18764
  rootFromArtifact = typeof raw.repoRoot === "string" && raw.repoRoot ? raw.repoRoot : void 0;
18641
18765
  } catch {
@@ -18669,7 +18793,7 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18669
18793
  } catch {
18670
18794
  try {
18671
18795
  const manifest = JSON.parse(
18672
- await readFile13(path55.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18796
+ await readFile14(path56.join(checkpointDir(stateDir, id), "manifest.json"), "utf8")
18673
18797
  );
18674
18798
  if (manifest.checkpointId !== id || ![1, 2].includes(manifest.version)) continue;
18675
18799
  if (repoRoot && canonicalPath(manifest.repoRoot) !== canonicalPath(repoRoot)) continue;
@@ -18694,12 +18818,12 @@ async function listRecoveryCheckpoints(stateDir, repoRoot) {
18694
18818
  async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
18695
18819
  const root = checkpointsRoot(stateDir);
18696
18820
  if (!repoRoot) return directorySize(root);
18697
- if (!existsSync15(root)) return 0;
18821
+ if (!existsSync16(root)) return 0;
18698
18822
  const expected = canonicalPath(repoRoot);
18699
18823
  let total = 0;
18700
18824
  for (const entry of await readdir3(root, { withFileTypes: true })) {
18701
18825
  if (!entry.isDirectory()) continue;
18702
- const entryPath = path55.join(root, entry.name);
18826
+ const entryPath = path56.join(root, entry.name);
18703
18827
  if (/^cp_[a-f0-9]{24}$/.test(entry.name)) {
18704
18828
  if (await artifactRepoRoot(stateDir, entry.name) === expected) {
18705
18829
  total += await directorySize(entryPath);
@@ -18708,7 +18832,7 @@ async function recoveryCheckpointStorageBytes(stateDir, repoRoot) {
18708
18832
  }
18709
18833
  if (/^\.tmp-cp_[a-f0-9]{24}$/.test(entry.name)) {
18710
18834
  try {
18711
- const owner = JSON.parse(await readFile13(path55.join(entryPath, "owner.json"), "utf8"));
18835
+ const owner = JSON.parse(await readFile14(path56.join(entryPath, "owner.json"), "utf8"));
18712
18836
  if (typeof owner.repoRoot === "string" && canonicalPath(owner.repoRoot) === expected) {
18713
18837
  total += await directorySize(entryPath);
18714
18838
  }
@@ -18750,16 +18874,16 @@ function recoveryFailClosedResult(predicted, reason, signals = []) {
18750
18874
  init_scrub();
18751
18875
 
18752
18876
  // src/core/transactional/file-checkpoint-backend.ts
18753
- import { cp, lstat as lstat11, mkdir as mkdir13, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
18877
+ import { cp, lstat as lstat11, mkdir as mkdir14, mkdtemp as mkdtemp5, readdir as readdir6, rm as rm9, writeFile as writeFile10 } from "node:fs/promises";
18754
18878
  import os5 from "node:os";
18755
- import path59 from "node:path";
18879
+ import path60 from "node:path";
18756
18880
 
18757
18881
  // src/core/transactional/file-checkpoint-git.ts
18758
18882
  init_path_utils();
18759
18883
  import { spawn as spawn8 } from "node:child_process";
18760
18884
  import { createHash as createHash13 } from "node:crypto";
18761
- import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile14 } from "node:fs/promises";
18762
- import path56 from "node:path";
18885
+ import { copyFile as copyFile3, lstat as lstat9, readdir as readdir4, readFile as readFile15 } from "node:fs/promises";
18886
+ import path57 from "node:path";
18763
18887
  var FILE_CHECKPOINT_GIT_METADATA_CHANGED = "file_checkpoint_git_metadata_changed";
18764
18888
  var FILE_CHECKPOINT_SOURCE_CHANGED = "file_checkpoint_source_changed";
18765
18889
  var FILE_CHECKPOINT_CWD_OUTSIDE_ROOT = "file_checkpoint_cwd_outside_root";
@@ -18793,7 +18917,7 @@ function rethrowStableFileCheckpointError(error) {
18793
18917
  }
18794
18918
  async function rootGitMetadataPresent(repoRoot) {
18795
18919
  try {
18796
- await lstat9(path56.join(repoRoot, ".git"));
18920
+ await lstat9(path57.join(repoRoot, ".git"));
18797
18921
  return true;
18798
18922
  } catch {
18799
18923
  return false;
@@ -18842,10 +18966,10 @@ function execGit2(repoRoot, args) {
18842
18966
  }
18843
18967
  async function resolveGitPath(repoRoot, gitPath) {
18844
18968
  const trimmed = gitPath.trim();
18845
- if (path56.isAbsolute(trimmed)) {
18969
+ if (path57.isAbsolute(trimmed)) {
18846
18970
  return trimmed;
18847
18971
  }
18848
- return path56.join(repoRoot, trimmed);
18972
+ return path57.join(repoRoot, trimmed);
18849
18973
  }
18850
18974
  async function cloneBareWorktreeCopy(sourceRoot, destinationRoot) {
18851
18975
  await execGit2(sourceRoot, [
@@ -18887,7 +19011,7 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
18887
19011
  destinationRoot,
18888
19012
  await execGit2(destinationRoot, ["rev-parse", "--git-dir"])
18889
19013
  );
18890
- const destinationShared = path56.join(destinationGitDir, path56.basename(sourceShared));
19014
+ const destinationShared = path57.join(destinationGitDir, path57.basename(sourceShared));
18891
19015
  try {
18892
19016
  await copyFile3(sourceShared, destinationShared);
18893
19017
  } catch (error) {
@@ -18896,14 +19020,14 @@ async function copyGitIndexState(sourceRoot, destinationRoot) {
18896
19020
  }
18897
19021
  async function readGitFile(gitDir, relativePath) {
18898
19022
  try {
18899
- return await readFile14(path56.join(gitDir, relativePath));
19023
+ return await readFile15(path57.join(gitDir, relativePath));
18900
19024
  } catch {
18901
19025
  return null;
18902
19026
  }
18903
19027
  }
18904
19028
  async function readAbsoluteGitFile(absolutePath) {
18905
19029
  try {
18906
- return await readFile14(absolutePath);
19030
+ return await readFile15(absolutePath);
18907
19031
  } catch {
18908
19032
  return null;
18909
19033
  }
@@ -18920,8 +19044,8 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
18920
19044
  repoRoot,
18921
19045
  await execGit2(repoRoot, ["rev-parse", "--git-path", gitPath])
18922
19046
  );
18923
- const relative = path56.resolve(resolved).startsWith(path56.resolve(gitDir)) ? path56.relative(gitDir, resolved) : resolved;
18924
- const content = typeof relative === "string" && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
19047
+ const relative = path57.resolve(resolved).startsWith(path57.resolve(gitDir)) ? path57.relative(gitDir, resolved) : resolved;
19048
+ const content = typeof relative === "string" && !relative.startsWith("..") && !path57.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
18925
19049
  if (content !== null) {
18926
19050
  hashGitFileContent(hash, gitPath, content);
18927
19051
  }
@@ -18931,13 +19055,13 @@ async function hashResolvedGitPath(repoRoot, gitDir, gitPath, hash) {
18931
19055
  async function hashGitTree(gitDir, relativeDir, hash) {
18932
19056
  let names;
18933
19057
  try {
18934
- names = await readdir4(path56.join(gitDir, relativeDir));
19058
+ names = await readdir4(path57.join(gitDir, relativeDir));
18935
19059
  } catch {
18936
19060
  return;
18937
19061
  }
18938
19062
  for (const name of names.sort()) {
18939
- const relativePath = relativeDir ? path56.join(relativeDir, name) : name;
18940
- const absolutePath = path56.join(gitDir, relativePath);
19063
+ const relativePath = relativeDir ? path57.join(relativeDir, name) : name;
19064
+ const absolutePath = path57.join(gitDir, relativePath);
18941
19065
  let childNames = null;
18942
19066
  try {
18943
19067
  childNames = await readdir4(absolutePath);
@@ -18959,7 +19083,7 @@ async function hashGitTree(gitDir, relativeDir, hash) {
18959
19083
  }
18960
19084
  async function computeGitMetadataFingerprint(repoRoot) {
18961
19085
  const gitDirRel = (await execGit2(repoRoot, ["rev-parse", "--git-dir"])).trim();
18962
- const gitDir = path56.isAbsolute(gitDirRel) ? gitDirRel : path56.join(repoRoot, gitDirRel);
19086
+ const gitDir = path57.isAbsolute(gitDirRel) ? gitDirRel : path57.join(repoRoot, gitDirRel);
18963
19087
  const hash = createHash13("sha256");
18964
19088
  for (const file of [
18965
19089
  "HEAD",
@@ -18982,8 +19106,8 @@ async function computeGitMetadataFingerprint(repoRoot) {
18982
19106
  const sharedIndex = (await execGit2(repoRoot, ["rev-parse", "--shared-index-path"])).trim();
18983
19107
  if (sharedIndex) {
18984
19108
  const resolved = await resolveGitPath(repoRoot, sharedIndex);
18985
- const relative = path56.relative(gitDir, resolved);
18986
- const content = relative && !relative.startsWith("..") && !path56.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
19109
+ const relative = path57.relative(gitDir, resolved);
19110
+ const content = relative && !relative.startsWith("..") && !path57.isAbsolute(relative) ? await readGitFile(gitDir, relative) : await readAbsoluteGitFile(resolved);
18987
19111
  if (content !== null) {
18988
19112
  hashGitFileContent(hash, "shared-index", content);
18989
19113
  }
@@ -18994,7 +19118,7 @@ async function computeGitMetadataFingerprint(repoRoot) {
18994
19118
  await hashResolvedGitPath(repoRoot, gitDir, gitPath, hash);
18995
19119
  }
18996
19120
  try {
18997
- const rootGitPath = path56.join(repoRoot, ".git");
19121
+ const rootGitPath = path57.join(repoRoot, ".git");
18998
19122
  const rootGitInfo = await lstat9(rootGitPath);
18999
19123
  if (rootGitInfo.isFile()) {
19000
19124
  const content = await readAbsoluteGitFile(rootGitPath);
@@ -19010,14 +19134,14 @@ async function computeGitMetadataFingerprint(repoRoot) {
19010
19134
  function resolveExecutionCwdRelative(resourceRoot, cwd) {
19011
19135
  const resolvedCwd = canonicalPath(cwd);
19012
19136
  const resourceCanonical = canonicalPath(resourceRoot);
19013
- const relative = path56.relative(resourceCanonical, resolvedCwd);
19137
+ const relative = path57.relative(resourceCanonical, resolvedCwd);
19014
19138
  if (relative === "" || relative === ".") {
19015
19139
  return "";
19016
19140
  }
19017
- if (relative.startsWith("..") || path56.isAbsolute(relative)) {
19141
+ if (relative.startsWith("..") || path57.isAbsolute(relative)) {
19018
19142
  throw new Error(FILE_CHECKPOINT_CWD_OUTSIDE_ROOT);
19019
19143
  }
19020
- return relative.split(path56.sep).join("/");
19144
+ return relative.split(path57.sep).join("/");
19021
19145
  }
19022
19146
 
19023
19147
  // src/core/transactional/file-checkpoint-isolation.ts
@@ -19038,8 +19162,8 @@ function fileCheckpointIsolationReason(context) {
19038
19162
  }
19039
19163
 
19040
19164
  // src/core/transactional/file-checkpoint-staging.ts
19041
- import { readdir as readdir5, readFile as readFile15, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
19042
- import path57 from "node:path";
19165
+ import { readdir as readdir5, readFile as readFile16, rm as rm7, writeFile as writeFile8 } from "node:fs/promises";
19166
+ import path58 from "node:path";
19043
19167
  function isOwnerProcessAlive(pid) {
19044
19168
  try {
19045
19169
  process.kill(pid, 0);
@@ -19049,12 +19173,12 @@ function isOwnerProcessAlive(pid) {
19049
19173
  }
19050
19174
  }
19051
19175
  async function writeOwnerMarker(stagingRoot, marker) {
19052
- await writeFile8(path57.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
19176
+ await writeFile8(path58.join(stagingRoot, "owner.json"), `${JSON.stringify(marker)}
19053
19177
  `, "utf8");
19054
19178
  }
19055
19179
  async function readOwnerMarker(stagingRoot) {
19056
19180
  try {
19057
- const raw = await readFile15(path57.join(stagingRoot, "owner.json"), "utf8");
19181
+ const raw = await readFile16(path58.join(stagingRoot, "owner.json"), "utf8");
19058
19182
  return JSON.parse(raw.trim());
19059
19183
  } catch {
19060
19184
  return null;
@@ -19072,7 +19196,7 @@ async function collectDeadOwnerStaging(parentDir) {
19072
19196
  if (!name.startsWith("belay-file-checkpoint-")) {
19073
19197
  continue;
19074
19198
  }
19075
- const stagingRoot = path57.join(parentDir, name);
19199
+ const stagingRoot = path58.join(parentDir, name);
19076
19200
  const marker = await readOwnerMarker(stagingRoot);
19077
19201
  if (!marker) {
19078
19202
  dead.push(stagingRoot);
@@ -19095,7 +19219,7 @@ import { constants as fsConstants2 } from "node:fs";
19095
19219
  import {
19096
19220
  copyFile as copyFile4,
19097
19221
  lstat as lstat10,
19098
- mkdir as mkdir12,
19222
+ mkdir as mkdir13,
19099
19223
  mkdtemp as mkdtemp4,
19100
19224
  readlink as readlink5,
19101
19225
  rm as rm8,
@@ -19104,17 +19228,17 @@ import {
19104
19228
  writeFile as writeFile9
19105
19229
  } from "node:fs/promises";
19106
19230
  import os4 from "node:os";
19107
- import path58 from "node:path";
19231
+ import path59 from "node:path";
19108
19232
  var FILE_CHECKPOINT_COPY_FAILED = "file_checkpoint_copy_failed";
19109
19233
  async function chmodSafe2(target, mode) {
19110
19234
  try {
19111
- const { chmod: chmod4 } = await import("node:fs/promises");
19112
- await chmod4(target, mode & 511);
19235
+ const { chmod: chmod5 } = await import("node:fs/promises");
19236
+ await chmod5(target, mode & 511);
19113
19237
  } catch {
19114
19238
  }
19115
19239
  }
19116
19240
  async function copyRegularFile(sourcePath, destinationPath, mode, strategy) {
19117
- await mkdir12(path58.dirname(destinationPath), { recursive: true });
19241
+ await mkdir13(path59.dirname(destinationPath), { recursive: true });
19118
19242
  if (strategy === "clonefile" && fsConstants2.COPYFILE_FICLONE !== void 0) {
19119
19243
  try {
19120
19244
  await copyFile4(sourcePath, destinationPath, fsConstants2.COPYFILE_FICLONE);
@@ -19136,11 +19260,11 @@ async function copyNode(sourceRoot, destinationRoot, relativePath, strategy) {
19136
19260
  const info = await lstat10(sourcePath);
19137
19261
  await rm8(destinationPath, { force: true, recursive: false });
19138
19262
  if (info.isDirectory() && !info.isSymbolicLink()) {
19139
- await mkdir12(destinationPath, { recursive: true, mode: info.mode & 511 });
19263
+ await mkdir13(destinationPath, { recursive: true, mode: info.mode & 511 });
19140
19264
  return strategy;
19141
19265
  }
19142
19266
  if (info.isSymbolicLink()) {
19143
- await mkdir12(path58.dirname(destinationPath), { recursive: true });
19267
+ await mkdir13(path59.dirname(destinationPath), { recursive: true });
19144
19268
  await symlink4(await readlink5(sourcePath), destinationPath);
19145
19269
  return strategy;
19146
19270
  }
@@ -19196,9 +19320,9 @@ async function mapWithConcurrency(items, concurrency, worker) {
19196
19320
  async function probeFileCloneStrategy() {
19197
19321
  let tempDir = null;
19198
19322
  try {
19199
- tempDir = await mkdtemp4(path58.join(os4.tmpdir(), "belay-clone-probe-"));
19200
- const source = path58.join(tempDir, "source.txt");
19201
- const destination = path58.join(tempDir, "dest.txt");
19323
+ tempDir = await mkdtemp4(path59.join(os4.tmpdir(), "belay-clone-probe-"));
19324
+ const source = path59.join(tempDir, "source.txt");
19325
+ const destination = path59.join(tempDir, "dest.txt");
19202
19326
  await writeFile9(source, "probe\n");
19203
19327
  if (fsConstants2.COPYFILE_FICLONE_FORCE !== void 0) {
19204
19328
  try {
@@ -19351,11 +19475,11 @@ async function protectedRootState(root) {
19351
19475
  return `directory:${node.hash}:${index.treeHash}`;
19352
19476
  }
19353
19477
  function executionProtectedRoot(resourceRoot, executionRoot, protectedRoot) {
19354
- const relative = path59.relative(path59.resolve(resourceRoot), path59.resolve(protectedRoot));
19355
- if (relative === "" || relative.startsWith("..") || path59.isAbsolute(relative)) {
19478
+ const relative = path60.relative(path60.resolve(resourceRoot), path60.resolve(protectedRoot));
19479
+ if (relative === "" || relative.startsWith("..") || path60.isAbsolute(relative)) {
19356
19480
  return null;
19357
19481
  }
19358
- return path59.join(executionRoot, relative);
19482
+ return path60.join(executionRoot, relative);
19359
19483
  }
19360
19484
  async function captureProtectedRootStates(resourceRoot, executionRoot, protectedRoots) {
19361
19485
  const states = /* @__PURE__ */ new Map();
@@ -19380,15 +19504,15 @@ async function directoryByteSize(root, deadlineMs) {
19380
19504
  }
19381
19505
  let total = 0;
19382
19506
  for (const name of await readdir6(root)) {
19383
- total += await directoryByteSize(path59.join(root, name), deadlineMs);
19507
+ total += await directoryByteSize(path60.join(root, name), deadlineMs);
19384
19508
  }
19385
19509
  return total;
19386
19510
  }
19387
19511
  async function copyGitMetadataDirectory(sourceRoot, destinationRoot) {
19388
19512
  const gitDirRel = (await execGit2(sourceRoot, ["rev-parse", "--git-dir"])).trim();
19389
- const sourceGitDir = path59.isAbsolute(gitDirRel) ? gitDirRel : path59.join(sourceRoot, gitDirRel);
19390
- const relativeGitDir = path59.relative(path59.resolve(sourceRoot), path59.resolve(sourceGitDir));
19391
- const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path59.join(destinationRoot, relativeGitDir) : path59.join(destinationRoot, ".git");
19513
+ const sourceGitDir = path60.isAbsolute(gitDirRel) ? gitDirRel : path60.join(sourceRoot, gitDirRel);
19514
+ const relativeGitDir = path60.relative(path60.resolve(sourceRoot), path60.resolve(sourceGitDir));
19515
+ const destinationGitDir = relativeGitDir && !relativeGitDir.startsWith("..") ? path60.join(destinationRoot, relativeGitDir) : path60.join(destinationRoot, ".git");
19392
19516
  await cp(sourceGitDir, destinationGitDir, { recursive: true, force: true });
19393
19517
  }
19394
19518
  async function prepareDirtyGitSnapshot(context) {
@@ -19397,7 +19521,7 @@ async function prepareDirtyGitSnapshot(context) {
19397
19521
  const quotas = context.fileCheckpoint;
19398
19522
  const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
19399
19523
  await removeDeadOwnerStaging(os5.tmpdir());
19400
- const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
19524
+ const stagingRoot = await mkdtemp5(path60.join(os5.tmpdir(), "belay-file-checkpoint-"));
19401
19525
  await writeOwnerMarker(stagingRoot, {
19402
19526
  version: 1,
19403
19527
  pid: process.pid,
@@ -19405,8 +19529,8 @@ async function prepareDirtyGitSnapshot(context) {
19405
19529
  resourceRoot: context.repoRoot,
19406
19530
  backend: "file_checkpoint"
19407
19531
  });
19408
- const baselineRoot = path59.join(stagingRoot, "baseline");
19409
- const executionRoot = path59.join(stagingRoot, "execution");
19532
+ const baselineRoot = path60.join(stagingRoot, "baseline");
19533
+ const executionRoot = path60.join(stagingRoot, "execution");
19410
19534
  try {
19411
19535
  resolveExecutionCwdRelative(context.repoRoot, context.cwd);
19412
19536
  const sourceGitMetadataFingerprint = await computeGitMetadataFingerprint(context.repoRoot);
@@ -19440,7 +19564,7 @@ async function prepareDirtyGitSnapshot(context) {
19440
19564
  throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
19441
19565
  }
19442
19566
  await writeFile10(
19443
- path59.join(stagingRoot, "baseline-index.json"),
19567
+ path60.join(stagingRoot, "baseline-index.json"),
19444
19568
  `${JSON.stringify(baselineIndex)}
19445
19569
  `,
19446
19570
  "utf8"
@@ -19490,7 +19614,7 @@ async function prepareNonGitSnapshot(context) {
19490
19614
  const quotas = context.fileCheckpoint;
19491
19615
  const deadlineMs = Date.now() + quotas.prepareTimeoutMs;
19492
19616
  await removeDeadOwnerStaging(os5.tmpdir());
19493
- const stagingRoot = await mkdtemp5(path59.join(os5.tmpdir(), "belay-file-checkpoint-"));
19617
+ const stagingRoot = await mkdtemp5(path60.join(os5.tmpdir(), "belay-file-checkpoint-"));
19494
19618
  await writeOwnerMarker(stagingRoot, {
19495
19619
  version: 1,
19496
19620
  pid: process.pid,
@@ -19498,8 +19622,8 @@ async function prepareNonGitSnapshot(context) {
19498
19622
  resourceRoot: context.repoRoot,
19499
19623
  backend: "file_checkpoint"
19500
19624
  });
19501
- const baselineRoot = path59.join(stagingRoot, "baseline");
19502
- const executionRoot = path59.join(stagingRoot, "execution");
19625
+ const baselineRoot = path60.join(stagingRoot, "baseline");
19626
+ const executionRoot = path60.join(stagingRoot, "execution");
19503
19627
  try {
19504
19628
  resolveExecutionCwdRelative(context.repoRoot, context.cwd);
19505
19629
  const resourceIdentity = await currentRecoveryResourceIdentity(context.repoRoot, "directory");
@@ -19508,7 +19632,7 @@ async function prepareNonGitSnapshot(context) {
19508
19632
  quotas,
19509
19633
  deadlineMs
19510
19634
  });
19511
- await mkdir13(baselineRoot, { recursive: true });
19635
+ await mkdir14(baselineRoot, { recursive: true });
19512
19636
  const baselineIndex = await buildFileTreeIndex({
19513
19637
  resourceRoot: baselineRoot,
19514
19638
  excludedRoots,
@@ -19528,7 +19652,7 @@ async function prepareNonGitSnapshot(context) {
19528
19652
  throw new Error(FILE_CHECKPOINT_SOURCE_CHANGED);
19529
19653
  }
19530
19654
  await writeFile10(
19531
- path59.join(stagingRoot, "baseline-index.json"),
19655
+ path60.join(stagingRoot, "baseline-index.json"),
19532
19656
  `${JSON.stringify(baselineIndex)}
19533
19657
  `,
19534
19658
  "utf8"
@@ -19538,7 +19662,7 @@ async function prepareNonGitSnapshot(context) {
19538
19662
  quotas,
19539
19663
  deadlineMs
19540
19664
  });
19541
- await mkdir13(executionRoot, { recursive: true });
19665
+ await mkdir14(executionRoot, { recursive: true });
19542
19666
  const finalSourceIndex = await buildFileTreeIndex({
19543
19667
  resourceRoot: context.repoRoot,
19544
19668
  excludedRoots,
@@ -19881,10 +20005,10 @@ async function selectTransactionalBackend(context) {
19881
20005
  }
19882
20006
 
19883
20007
  // src/core/transactional/diff-evaluator.ts
19884
- import path60 from "node:path";
20008
+ import path61 from "node:path";
19885
20009
  init_path_utils();
19886
20010
  function categorizeChange(change, ctx) {
19887
- const absolutePath = canonicalPath(path60.join(ctx.repoRoot, change.relativePath));
20011
+ const absolutePath = canonicalPath(path61.join(ctx.repoRoot, change.relativePath));
19888
20012
  if (!pathWithinRoot(ctx.repoRoot, absolutePath)) {
19889
20013
  return "repo_outside";
19890
20014
  }
@@ -20434,17 +20558,55 @@ function formatJudgeInfrastructureDenyMessage(params) {
20434
20558
  }
20435
20559
 
20436
20560
  // src/core/notify.ts
20561
+ init_path_utils();
20437
20562
  import { execFile } from "node:child_process";
20563
+ import path62 from "node:path";
20438
20564
  import { promisify } from "node:util";
20439
20565
  var execFileAsync = promisify(execFile);
20440
- async function notifyDeny(config, event) {
20441
- const payload = JSON.stringify(event);
20442
- if (config.webhookUrl) {
20566
+ var LOOPBACK_WEBHOOK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
20567
+ function webhookConfigIssue(url) {
20568
+ let parsed;
20569
+ try {
20570
+ parsed = new URL(url);
20571
+ } catch {
20572
+ return `notifications.webhookUrl is invalid: ${url}`;
20573
+ }
20574
+ if (parsed.protocol === "https:") {
20575
+ return null;
20576
+ }
20577
+ const normalizedHostname = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, "");
20578
+ if (parsed.protocol === "http:" && LOOPBACK_WEBHOOK_HOSTS.has(normalizedHostname)) {
20579
+ return null;
20580
+ }
20581
+ return `notifications.webhookUrl must use https (http is allowed only for localhost, 127.0.0.1, or ::1): ${url}`;
20582
+ }
20583
+ function commandHookConfigIssue(commandHook, repoRoot) {
20584
+ if (!path62.isAbsolute(commandHook)) {
20585
+ return `notifications.commandHook must be an absolute path: ${commandHook}`;
20586
+ }
20587
+ if (pathWithinRoot(canonicalPath(repoRoot), canonicalPath(commandHook))) {
20588
+ return `notifications.commandHook must not be inside the repository: ${commandHook}`;
20589
+ }
20590
+ return null;
20591
+ }
20592
+ async function notifyDeny(config, event, deps = {
20593
+ fetch: globalThis.fetch.bind(globalThis),
20594
+ execFile: (file, args, options) => execFileAsync(file, [...args], options)
20595
+ }) {
20596
+ const payload = JSON.stringify({
20597
+ approvalId: event.approvalId,
20598
+ reason: event.reason,
20599
+ summary: event.summary,
20600
+ repoRoot: event.repoRoot,
20601
+ fingerprint: event.fingerprint
20602
+ });
20603
+ const webhookIssue = config.webhookUrl ? webhookConfigIssue(config.webhookUrl) : null;
20604
+ if (config.webhookUrl && !webhookIssue) {
20443
20605
  try {
20444
20606
  const controller = new AbortController();
20445
20607
  const timeout = setTimeout(() => controller.abort(), 5e3);
20446
20608
  try {
20447
- await fetch(config.webhookUrl, {
20609
+ await deps.fetch(config.webhookUrl, {
20448
20610
  method: "POST",
20449
20611
  headers: { "content-type": "application/json" },
20450
20612
  body: payload,
@@ -20456,17 +20618,16 @@ async function notifyDeny(config, event) {
20456
20618
  } catch {
20457
20619
  }
20458
20620
  }
20459
- if (config.commandHook) {
20621
+ const commandHookIssue = config.commandHook ? commandHookConfigIssue(config.commandHook, event.repoRoot) : null;
20622
+ if (config.commandHook && !commandHookIssue) {
20460
20623
  try {
20461
- await execFileAsync(config.commandHook, [], {
20624
+ await deps.execFile(config.commandHook, [], {
20462
20625
  env: {
20463
- ...process.env,
20464
20626
  BELAY_APPROVAL_ID: event.approvalId,
20465
20627
  BELAY_REASON: event.reason,
20466
20628
  BELAY_SUMMARY: event.summary,
20467
20629
  BELAY_REPO_ROOT: event.repoRoot,
20468
- BELAY_FINGERPRINT: event.fingerprint,
20469
- BELAY_APPROVAL_TOKEN: event.approvalToken ?? ""
20630
+ BELAY_FINGERPRINT: event.fingerprint
20470
20631
  }
20471
20632
  });
20472
20633
  } catch {
@@ -20476,9 +20637,10 @@ async function notifyDeny(config, event) {
20476
20637
 
20477
20638
  // src/adapters/shared/gate-runtime.ts
20478
20639
  init_path_utils();
20640
+ init_repo_config_trust();
20479
20641
 
20480
20642
  // src/adapters/layouts/protected-paths.ts
20481
- import path61 from "node:path";
20643
+ import path63 from "node:path";
20482
20644
  function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
20483
20645
  const roots = [
20484
20646
  layout.configPath(repoRoot),
@@ -20490,7 +20652,7 @@ function protectedArtifactRoots(layout, repoRoot, controlPlaneDir) {
20490
20652
  if (controlPlaneDir) {
20491
20653
  roots.push(controlPlaneDir);
20492
20654
  }
20493
- return roots.map((entry) => path61.resolve(entry));
20655
+ return roots.map((entry) => path63.resolve(entry));
20494
20656
  }
20495
20657
 
20496
20658
  // src/adapters/shared/gate-runtime.ts
@@ -20531,7 +20693,7 @@ async function appendReplayAuditSafely(ctx, deps, event) {
20531
20693
  }
20532
20694
  async function loadJsonFile(filePath, fallback) {
20533
20695
  try {
20534
- const raw = await readFile16(filePath, "utf8");
20696
+ const raw = await readFile17(filePath, "utf8");
20535
20697
  return JSON.parse(raw);
20536
20698
  } catch {
20537
20699
  return fallback;
@@ -20540,11 +20702,18 @@ async function loadJsonFile(filePath, fallback) {
20540
20702
  function createDefaultGateRuntimeDeps() {
20541
20703
  return {
20542
20704
  async readConfig(configPath) {
20543
- return loadJsonFile(configPath, {});
20705
+ try {
20706
+ return JSON.parse(await readFile17(configPath, "utf8"));
20707
+ } catch (error) {
20708
+ if (error.code === "ENOENT") {
20709
+ return {};
20710
+ }
20711
+ throw error;
20712
+ }
20544
20713
  },
20545
20714
  async appendAudit(ctx, event) {
20546
- const auditPath = path62.join(ctx.repoRoot, ctx.config.audit.logPath);
20547
- await mkdir14(path62.dirname(auditPath), { recursive: true });
20715
+ const auditPath = path64.join(ctx.repoRoot, ctx.config.audit.logPath);
20716
+ await mkdir15(path64.dirname(auditPath), { recursive: true });
20548
20717
  const provenance = auditProvenance(ctx.config);
20549
20718
  const record = {
20550
20719
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -20577,7 +20746,7 @@ function createDefaultGateRuntimeDeps() {
20577
20746
  };
20578
20747
  },
20579
20748
  async writeApprovals(filePath, state) {
20580
- await mkdir14(path62.dirname(filePath), { recursive: true });
20749
+ await mkdir15(path64.dirname(filePath), { recursive: true });
20581
20750
  await writeFile11(filePath, `${JSON.stringify(compactApprovals(state), null, 2)}
20582
20751
  `, "utf8");
20583
20752
  },
@@ -20598,10 +20767,11 @@ function createDefaultGateRuntimeDeps() {
20598
20767
  }
20599
20768
  async function resolveGateConfig(ctx, deps) {
20600
20769
  const loaded = await deps.readConfig(ctx.configPath);
20770
+ await assertRepoConfigTrusted(ctx.repoRoot, ctx.layout.name, loaded);
20601
20771
  let teamConfig = null;
20602
20772
  const teamPath = teamConfigPath();
20603
- if (existsSync16(teamPath)) {
20604
- teamConfig = JSON.parse(await readFile16(teamPath, "utf8"));
20773
+ if (existsSync17(teamPath)) {
20774
+ teamConfig = JSON.parse(await readFile17(teamPath, "utf8"));
20605
20775
  }
20606
20776
  return resolveLayeredConfig({
20607
20777
  repoConfig: loaded,
@@ -20739,7 +20909,7 @@ function deriveWorkspaceRootScopeHint(params) {
20739
20909
  if (!targetPath) {
20740
20910
  return void 0;
20741
20911
  }
20742
- const candidateRoot = canonicalPath(path62.dirname(targetPath));
20912
+ const candidateRoot = canonicalPath(path64.dirname(targetPath));
20743
20913
  const validation = validateTrustedWorkspaceRootCandidate({
20744
20914
  candidatePath: candidateRoot,
20745
20915
  repoRoot: action.repoRoot,
@@ -21130,7 +21300,21 @@ async function evaluateGatedAction(ctx, deps, params) {
21130
21300
  ...authorization,
21131
21301
  egressProxyActive
21132
21302
  };
21133
- const predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
21303
+ let predicted = await classifyGatedActionAsync(action, ctx.config, enrichedClassifierOptions);
21304
+ if (action.kind === "tool" && predicted.reason === "unclassified_tool" && (ctx.config.policy.codexUnmappedTool ?? "deny") === "deny") {
21305
+ predicted = {
21306
+ ...predicted,
21307
+ verdict: "deny_pending_approval",
21308
+ reason: "unmapped_tool",
21309
+ assessment: {
21310
+ reversibility: "irreversible",
21311
+ external: false,
21312
+ blastRadius: "unknown tool action",
21313
+ confidence: 0.5,
21314
+ signals: ["unmapped_tool"]
21315
+ }
21316
+ };
21317
+ }
21134
21318
  if (action.kind === "shell" && action.command && isContainedUnknownExecutionEligible(ctx.config, action, predicted)) {
21135
21319
  const mediated = await mediateContainedUnknownExecution({
21136
21320
  ctx,
@@ -21315,7 +21499,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21315
21499
  event: auditEvent,
21316
21500
  sourceEvent,
21317
21501
  kind,
21318
- repoLabel: path62.basename(ctx.repoRoot),
21502
+ repoLabel: path64.basename(ctx.repoRoot),
21319
21503
  ...auditExtras.toolInvocationCorrelationId ? { toolInvocationCorrelationId: auditExtras.toolInvocationCorrelationId } : {},
21320
21504
  fingerprint: result.fingerprint,
21321
21505
  summary: result.normalizedCommand ?? result.summary ?? "",
@@ -21347,21 +21531,6 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21347
21531
  if (created) {
21348
21532
  await recordGateApprovalAsk(stateDir, result.reason, false);
21349
21533
  }
21350
- let approvalToken;
21351
- try {
21352
- approvalToken = await issueApprovalToken(
21353
- {
21354
- approvalId: approval.approvalId,
21355
- fingerprint: approval.fingerprint,
21356
- repoRoot: approval.repoRoot,
21357
- issuedAt: approval.createdAt,
21358
- expiresAt: approval.expiresAt
21359
- },
21360
- configuredControlPlaneDir(ctx.config)
21361
- );
21362
- } catch {
21363
- approvalToken = void 0;
21364
- }
21365
21534
  const denialReason = failure?.reason ?? result.reason;
21366
21535
  if (ctx.config.notifications.webhookUrl || ctx.config.notifications.commandHook) {
21367
21536
  await notifyDeny(ctx.config.notifications, {
@@ -21369,8 +21538,7 @@ async function gateDecisionToVerdict(ctx, deps, kind, result, auditExtras = {})
21369
21538
  reason: denialReason,
21370
21539
  summary: result.normalizedCommand ?? result.summary ?? "",
21371
21540
  repoRoot: ctx.repoRoot,
21372
- fingerprint: result.fingerprint,
21373
- approvalToken
21541
+ fingerprint: result.fingerprint
21374
21542
  });
21375
21543
  }
21376
21544
  const failureAuditFields = typeof failure?.auditFields === "function" ? failure.auditFields(approval) : failure?.auditFields;
@@ -21762,38 +21930,38 @@ async function appendObservedAudit(ctx, deps, eventName, payload) {
21762
21930
  }
21763
21931
 
21764
21932
  // src/adapters/shared/repo-root.ts
21765
- import { existsSync as existsSync17 } from "node:fs";
21766
- import path63 from "node:path";
21933
+ import { existsSync as existsSync18 } from "node:fs";
21934
+ import path65 from "node:path";
21767
21935
  function belayConfigPath(current, adapterName) {
21768
21936
  if (adapterName === "cursor") {
21769
- return path63.join(current, ".cursor", "belay.config.json");
21937
+ return path65.join(current, ".cursor", "belay.config.json");
21770
21938
  }
21771
21939
  if (adapterName === "claude") {
21772
- return path63.join(current, ".claude", "belay.config.json");
21940
+ return path65.join(current, ".claude", "belay.config.json");
21773
21941
  }
21774
- return path63.join(current, ".codex", "belay.config.json");
21942
+ return path65.join(current, ".codex", "belay.config.json");
21775
21943
  }
21776
21944
  function markerMatches(current, marker, layout) {
21777
- const markerPath = path63.join(current, marker);
21778
- if (!existsSync17(markerPath)) {
21945
+ const markerPath = path65.join(current, marker);
21946
+ if (!existsSync18(markerPath)) {
21779
21947
  return false;
21780
21948
  }
21781
21949
  if (marker === ".cursor" || marker === ".claude" || marker === ".codex") {
21782
- return existsSync17(belayConfigPath(current, layout.name));
21950
+ return existsSync18(belayConfigPath(current, layout.name));
21783
21951
  }
21784
21952
  return true;
21785
21953
  }
21786
21954
  function findRepoRoot(startPath, layout) {
21787
- let current = path63.resolve(startPath);
21955
+ let current = path65.resolve(startPath);
21788
21956
  while (true) {
21789
21957
  for (const marker of layout.repoRootMarkers) {
21790
21958
  if (markerMatches(current, marker, layout)) {
21791
21959
  return current;
21792
21960
  }
21793
21961
  }
21794
- const parent = path63.dirname(current);
21962
+ const parent = path65.dirname(current);
21795
21963
  if (parent === current) {
21796
- return path63.resolve(startPath);
21964
+ return path65.resolve(startPath);
21797
21965
  }
21798
21966
  current = parent;
21799
21967
  }
@@ -21801,7 +21969,7 @@ function findRepoRoot(startPath, layout) {
21801
21969
 
21802
21970
  // src/adapters/cursor/cwd-resolution.ts
21803
21971
  import os6 from "node:os";
21804
- import path64 from "node:path";
21972
+ import path66 from "node:path";
21805
21973
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21806
21974
  function nonEmptyPathString(value) {
21807
21975
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -21813,36 +21981,36 @@ function resolveCursorActionCwdDetails(payload, fallback = process.cwd()) {
21813
21981
  const workspaceRoot = Array.isArray(payload.workspace_roots) ? payload.workspace_roots.map(nonEmptyPathString).find(Boolean) : void 0;
21814
21982
  if (toolInputWorkingDirectory) {
21815
21983
  return {
21816
- cwd: path64.resolve(toolInputWorkingDirectory),
21984
+ cwd: path66.resolve(toolInputWorkingDirectory),
21817
21985
  source: "tool_input.working_directory",
21818
21986
  fromPayload: true
21819
21987
  };
21820
21988
  }
21821
21989
  if (topLevelCwd) {
21822
21990
  return {
21823
- cwd: path64.resolve(topLevelCwd),
21991
+ cwd: path66.resolve(topLevelCwd),
21824
21992
  source: "cwd",
21825
21993
  fromPayload: true
21826
21994
  };
21827
21995
  }
21828
21996
  if (workspaceRoot) {
21829
21997
  return {
21830
- cwd: path64.resolve(workspaceRoot),
21998
+ cwd: path66.resolve(workspaceRoot),
21831
21999
  source: "workspace_roots",
21832
22000
  fromPayload: true
21833
22001
  };
21834
22002
  }
21835
22003
  return {
21836
- cwd: path64.resolve(fallback),
22004
+ cwd: path66.resolve(fallback),
21837
22005
  source: "fallback",
21838
22006
  fromPayload: false
21839
22007
  };
21840
22008
  }
21841
22009
  function isGlobalCursorHookRuntime() {
21842
22010
  try {
21843
- const runtimePath = path64.resolve(fileURLToPath2(import.meta.url));
21844
- const globalRuntimeDir = path64.resolve(path64.join(os6.homedir(), ".cursor", "belay", "runtime"));
21845
- return runtimePath === globalRuntimeDir || runtimePath.startsWith(`${globalRuntimeDir}${path64.sep}`);
22011
+ const runtimePath = path66.resolve(fileURLToPath2(import.meta.url));
22012
+ const globalRuntimeDir = path66.resolve(path66.join(os6.homedir(), ".cursor", "belay", "runtime"));
22013
+ return runtimePath === globalRuntimeDir || runtimePath.startsWith(`${globalRuntimeDir}${path66.sep}`);
21846
22014
  } catch {
21847
22015
  return false;
21848
22016
  }
@@ -21892,7 +22060,7 @@ function resolveCursorToolActionCwdDetails(payload, fallback, eventName, toolNam
21892
22060
  function collectCandidateRepoRoots(payload, resolution) {
21893
22061
  const roots = [];
21894
22062
  const add = (value) => {
21895
- const resolved = path65.resolve(value);
22063
+ const resolved = path67.resolve(value);
21896
22064
  if (!roots.includes(resolved)) {
21897
22065
  roots.push(resolved);
21898
22066
  }
@@ -21954,6 +22122,9 @@ function isSubagentEvent(payload, eventName) {
21954
22122
  function isFileMutationTool(toolName) {
21955
22123
  return toolName === "Write" || toolName === "StrReplace" || toolName === "Delete";
21956
22124
  }
22125
+ function isCursorPreToolUseEvent(eventName) {
22126
+ return eventName === "preToolUse" || eventName === "PreToolUse";
22127
+ }
21957
22128
  async function handleBeforeSubmitPromptHook(payload) {
21958
22129
  try {
21959
22130
  const prompt = String(payload.prompt ?? "");
@@ -21978,7 +22149,13 @@ async function handleBeforeSubmitPromptHook(payload) {
21978
22149
  ...result.user_message ? { user_message: result.user_message } : {},
21979
22150
  ...result.replay ? { replay: result.replay } : {}
21980
22151
  };
21981
- } catch {
22152
+ } catch (error) {
22153
+ if (isRepoConfigTrustError(error)) {
22154
+ return {
22155
+ continue: false,
22156
+ user_message: error.message
22157
+ };
22158
+ }
21982
22159
  return {
21983
22160
  continue: false,
21984
22161
  user_message: "belay failed while processing approval state. Run belay doctor, then retry."
@@ -22009,7 +22186,13 @@ async function handleShellGateHook(payload) {
22009
22186
  sourceEvent: "beforeShellExecution"
22010
22187
  });
22011
22188
  return gateVerdictToCursorResponse(verdict2);
22012
- } catch {
22189
+ } catch (error) {
22190
+ if (isRepoConfigTrustError(error)) {
22191
+ return {
22192
+ permission: "deny",
22193
+ user_message: error.message
22194
+ };
22195
+ }
22013
22196
  return {
22014
22197
  permission: "deny",
22015
22198
  user_message: "belay failed while classifying this shell command. Run belay doctor, then retry."
@@ -22022,6 +22205,9 @@ async function runShellGateHook() {
22022
22205
  async function handleToolGateHook(eventName, payload) {
22023
22206
  try {
22024
22207
  const toolName = String(payload.tool_name ?? "");
22208
+ if (isCursorPreToolUseEvent(eventName) && toolName === "Shell") {
22209
+ return { permission: "allow" };
22210
+ }
22025
22211
  const resolution = resolveCursorToolActionCwdDetails(
22026
22212
  payload,
22027
22213
  process2.cwd(),
@@ -22046,9 +22232,9 @@ async function handleToolGateHook(eventName, payload) {
22046
22232
  });
22047
22233
  return gateVerdictToCursorResponse(verdict2);
22048
22234
  }
22049
- if (toolName === "Shell") {
22235
+ if (isFileMutationTool(toolName)) {
22050
22236
  const verdict2 = await evaluateGatedAction(ctx, deps, {
22051
- kind: "shell",
22237
+ kind: "tool",
22052
22238
  cwd,
22053
22239
  payload,
22054
22240
  toolName,
@@ -22056,27 +22242,33 @@ async function handleToolGateHook(eventName, payload) {
22056
22242
  });
22057
22243
  return gateVerdictToCursorResponse(verdict2);
22058
22244
  }
22059
- if (isFileMutationTool(toolName)) {
22245
+ if (payload.tool_name === "Task") {
22060
22246
  const verdict2 = await evaluateGatedAction(ctx, deps, {
22061
- kind: "tool",
22247
+ kind: "subagent",
22062
22248
  cwd,
22063
22249
  payload,
22064
- toolName,
22065
22250
  sourceEvent: eventName
22066
22251
  });
22067
22252
  return gateVerdictToCursorResponse(verdict2);
22068
22253
  }
22069
- if (payload.tool_name === "Task") {
22254
+ if (isCursorPreToolUseEvent(eventName)) {
22070
22255
  const verdict2 = await evaluateGatedAction(ctx, deps, {
22071
- kind: "subagent",
22256
+ kind: "tool",
22072
22257
  cwd,
22073
22258
  payload,
22259
+ toolName,
22074
22260
  sourceEvent: eventName
22075
22261
  });
22076
22262
  return gateVerdictToCursorResponse(verdict2);
22077
22263
  }
22078
22264
  return { permission: "allow" };
22079
- } catch {
22265
+ } catch (error) {
22266
+ if (isRepoConfigTrustError(error)) {
22267
+ return {
22268
+ permission: "deny",
22269
+ user_message: error.message
22270
+ };
22271
+ }
22080
22272
  return {
22081
22273
  permission: "deny",
22082
22274
  user_message: "belay failed while classifying this tool action. Run belay doctor, then retry."