@bastani/atomic 0.9.61-alpha.1 → 0.9.61-alpha.2

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 (61) hide show
  1. package/CHANGELOG.md +54 -4
  2. package/dist/builtin/intercom/index.bundle.mjs +3 -3
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/package.json +1 -1
  5. package/dist/builtin/subagents/CHANGELOG.md +12 -0
  6. package/dist/builtin/subagents/package.json +1 -1
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +14 -0
  9. package/dist/builtin/workflows/README.md +9 -7
  10. package/dist/builtin/workflows/builtin/{chunk-h6bt0r0g.js → chunk-a2j0x1a6.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-g3b2zf8r.js → chunk-vzbec50q.js} +1 -1
  12. package/dist/builtin/workflows/builtin/goal.js +1 -1
  13. package/dist/builtin/workflows/builtin/index.js +2 -2
  14. package/dist/builtin/workflows/builtin/ralph.js +1 -1
  15. package/dist/builtin/workflows/package.json +1 -1
  16. package/dist/builtin/workflows/src/extension/index.bundle.mjs +779 -409
  17. package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +844 -419
  18. package/dist/builtin/workflows/src/index.js +749 -384
  19. package/dist/builtin/workflows/src/local-worker-entry.mjs +844 -419
  20. package/dist/core/agent-session-retry.d.ts.map +1 -1
  21. package/dist/core/agent-session-retry.js +12 -3
  22. package/dist/core/agent-session-retry.js.map +1 -1
  23. package/dist/core/model-fallback-failures.d.ts +14 -4
  24. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  25. package/dist/core/model-fallback-failures.js +43 -15
  26. package/dist/core/model-fallback-failures.js.map +1 -1
  27. package/dist/core/settings-defaults.d.ts +1 -0
  28. package/dist/core/settings-defaults.d.ts.map +1 -1
  29. package/dist/core/settings-defaults.js +1 -0
  30. package/dist/core/settings-defaults.js.map +1 -1
  31. package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
  32. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  33. package/dist/core/settings-manager-basic-accessors.js +2 -0
  34. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  35. package/dist/core/settings-schema.d.ts +2 -0
  36. package/dist/core/settings-schema.d.ts.map +1 -1
  37. package/dist/core/settings-schema.js +4 -0
  38. package/dist/core/settings-schema.js.map +1 -1
  39. package/dist/core/slash-commands.js +2 -2
  40. package/dist/core/slash-commands.js.map +1 -1
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/modes/interactive/interactive-startup-chat-container.d.ts +2 -0
  45. package/dist/modes/interactive/interactive-startup-chat-container.d.ts.map +1 -1
  46. package/dist/modes/interactive/interactive-startup-chat-container.js +6 -0
  47. package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
  48. package/dist/modes/interactive-engine/remote-renderer.d.ts +27 -5
  49. package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
  50. package/dist/modes/interactive-engine/remote-renderer.js +76 -16
  51. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  52. package/docs/intercom/reference.md +1 -1
  53. package/docs/models/evals.md +30 -2
  54. package/docs/settings.md +3 -0
  55. package/docs/subagents/reference.md +3 -1
  56. package/docs/workflows/api-reference.md +9 -6
  57. package/docs/workflows/builtins.md +1 -1
  58. package/docs/workflows/operations.md +3 -3
  59. package/npm-shrinkwrap.json +32 -32
  60. package/package.json +3 -3
  61. package/schemas/settings.schema.json +5 -0
@@ -13462,9 +13462,104 @@ var init_workflow_artifacts = __esm(() => {
13462
13462
  pendingArtifactPrunes = new Map;
13463
13463
  });
13464
13464
 
13465
- // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
13465
+ // dist/builtin/workflows/src/runs/shared/worktree-allocation.ts
13466
+ import { randomBytes } from "node:crypto";
13466
13467
  import * as fs from "node:fs";
13467
13468
  import * as path from "node:path";
13469
+ function nextBucketId() {
13470
+ return nextBucketIdOverride?.() ?? randomBytes(2).toString("hex");
13471
+ }
13472
+ function errorCode(error) {
13473
+ return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
13474
+ }
13475
+ function allocateWorktreeCheckoutPath(root, repositoryName) {
13476
+ for (let attempt = 0;attempt < MAX_BUCKET_ATTEMPTS; attempt++) {
13477
+ const bucket = path.join(root, nextBucketId());
13478
+ try {
13479
+ fs.mkdirSync(bucket);
13480
+ return path.join(bucket, repositoryName);
13481
+ } catch (error) {
13482
+ if (errorCode(error) === "EEXIST")
13483
+ continue;
13484
+ const message = error instanceof Error ? error.message : String(error);
13485
+ throw new Error(`Failed to create worktree bucket ${bucket} under gitWorktreeDir ${root}: ${message}`);
13486
+ }
13487
+ }
13488
+ throw new Error(`Every worktree bucket identifier under gitWorktreeDir ${root} is already in use.`);
13489
+ }
13490
+ function removeEmptyWorktreeBucket(checkout) {
13491
+ try {
13492
+ fs.rmdirSync(path.dirname(checkout));
13493
+ } catch {}
13494
+ }
13495
+ function linkedGitDirectory(checkout) {
13496
+ let pointer;
13497
+ try {
13498
+ if (!fs.lstatSync(path.join(checkout, ".git")).isFile())
13499
+ return;
13500
+ pointer = fs.readFileSync(path.join(checkout, ".git"), "utf8");
13501
+ } catch {
13502
+ return;
13503
+ }
13504
+ if (!pointer.startsWith("gitdir:"))
13505
+ return;
13506
+ const gitDir = pointer.slice("gitdir:".length).trim();
13507
+ return gitDir ? path.resolve(checkout, gitDir) : undefined;
13508
+ }
13509
+ function readWorktreeOwner(gitDir) {
13510
+ let contents;
13511
+ try {
13512
+ contents = fs.readFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), "utf8");
13513
+ } catch {
13514
+ return;
13515
+ }
13516
+ try {
13517
+ const record = JSON.parse(contents);
13518
+ return record.version === WORKTREE_OWNER_VERSION && typeof record.ownerRunId === "string" && record.ownerRunId ? record.ownerRunId : undefined;
13519
+ } catch {
13520
+ return;
13521
+ }
13522
+ }
13523
+ function findOwnedWorktreeCheckouts(root, repositoryName, ownerRunId) {
13524
+ let entries;
13525
+ try {
13526
+ entries = fs.readdirSync(root, { withFileTypes: true });
13527
+ } catch {
13528
+ return [];
13529
+ }
13530
+ const owned = [];
13531
+ for (const entry of entries) {
13532
+ if (!entry.isDirectory() || !BUCKET_PATTERN.test(entry.name))
13533
+ continue;
13534
+ const checkout = path.join(root, entry.name, repositoryName);
13535
+ try {
13536
+ if (!fs.lstatSync(checkout).isDirectory())
13537
+ continue;
13538
+ } catch {
13539
+ continue;
13540
+ }
13541
+ const gitDir = linkedGitDirectory(checkout);
13542
+ if (gitDir !== undefined && readWorktreeOwner(gitDir) === ownerRunId)
13543
+ owned.push(checkout);
13544
+ }
13545
+ return owned.sort();
13546
+ }
13547
+ function bindWorktreeOwner(gitDir, ownerRunId) {
13548
+ const record = { version: WORKTREE_OWNER_VERSION, ownerRunId };
13549
+ fs.writeFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), `${JSON.stringify(record)}
13550
+ `, {
13551
+ encoding: "utf8",
13552
+ flag: "wx"
13553
+ });
13554
+ }
13555
+ var WORKTREE_OWNER_FILENAME = "atomic-workflow-run.json", WORKTREE_OWNER_VERSION = 1, BUCKET_PATTERN, MAX_BUCKET_ATTEMPTS = 65536, nextBucketIdOverride;
13556
+ var init_worktree_allocation = __esm(() => {
13557
+ BUCKET_PATTERN = /^[0-9a-f]{4}$/;
13558
+ });
13559
+
13560
+ // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
13561
+ import * as fs2 from "node:fs";
13562
+ import * as path2 from "node:path";
13468
13563
  function sameFileIdentity(left, right) {
13469
13564
  return left.dev === right.dev && left.ino === right.ino;
13470
13565
  }
@@ -13474,7 +13569,7 @@ function openMainCheckoutAnchor(gitDir) {
13474
13569
  assertCurrent() {
13475
13570
  if (disposed)
13476
13571
  throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
13477
- if (!fs.lstatSync(gitDir).isDirectory()) {
13572
+ if (!fs2.lstatSync(gitDir).isDirectory()) {
13478
13573
  throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
13479
13574
  }
13480
13575
  },
@@ -13484,17 +13579,17 @@ function openMainCheckoutAnchor(gitDir) {
13484
13579
  };
13485
13580
  }
13486
13581
  function openGitWorktreeGenerationAnchor(worktreeRoot) {
13487
- const gitFile = path.join(worktreeRoot, ".git");
13488
- if (fs.lstatSync(gitFile).isDirectory())
13582
+ const gitFile = path2.join(worktreeRoot, ".git");
13583
+ if (fs2.lstatSync(gitFile).isDirectory())
13489
13584
  return openMainCheckoutAnchor(gitFile);
13490
- const descriptor = fs.openSync(gitFile, "r");
13585
+ const descriptor = fs2.openSync(gitFile, "r");
13491
13586
  let disposed = false;
13492
13587
  const anchor = {
13493
13588
  assertCurrent() {
13494
13589
  if (disposed)
13495
13590
  throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
13496
- const held = fs.fstatSync(descriptor, { bigint: true });
13497
- const current = fs.lstatSync(gitFile, { bigint: true });
13591
+ const held = fs2.fstatSync(descriptor, { bigint: true });
13592
+ const current = fs2.lstatSync(gitFile, { bigint: true });
13498
13593
  if (!current.isFile() || !sameFileIdentity(held, current)) {
13499
13594
  throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
13500
13595
  }
@@ -13503,7 +13598,7 @@ function openGitWorktreeGenerationAnchor(worktreeRoot) {
13503
13598
  if (disposed)
13504
13599
  return;
13505
13600
  disposed = true;
13506
- fs.closeSync(descriptor);
13601
+ fs2.closeSync(descriptor);
13507
13602
  }
13508
13603
  };
13509
13604
  try {
@@ -13617,84 +13712,84 @@ var init_worktree_git_runner = __esm(() => {
13617
13712
  });
13618
13713
 
13619
13714
  // dist/builtin/workflows/src/runs/shared/worktree-root.ts
13620
- import * as fs2 from "node:fs";
13621
- import * as path2 from "node:path";
13715
+ import * as fs3 from "node:fs";
13716
+ import * as path3 from "node:path";
13622
13717
  function pathFromPointer(contents, prefix, base) {
13623
13718
  if (!contents.startsWith(prefix))
13624
13719
  return;
13625
13720
  const value2 = contents.slice(prefix.length).trim();
13626
13721
  if (!value2)
13627
13722
  return;
13628
- return path2.resolve(base, value2);
13723
+ return path3.resolve(base, value2);
13629
13724
  }
13630
13725
  function readText(file) {
13631
13726
  try {
13632
- return fs2.readFileSync(file, "utf8");
13727
+ return fs3.readFileSync(file, "utf8");
13633
13728
  } catch {
13634
13729
  return;
13635
13730
  }
13636
13731
  }
13637
13732
  function samePath(left, right) {
13638
13733
  try {
13639
- const a = fs2.realpathSync.native(left);
13640
- const b = fs2.realpathSync.native(right);
13734
+ const a = fs3.realpathSync.native(left);
13735
+ const b = fs3.realpathSync.native(right);
13641
13736
  return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
13642
13737
  } catch {
13643
13738
  return false;
13644
13739
  }
13645
13740
  }
13646
13741
  function findGitRoot(cwd) {
13647
- let current = path2.resolve(cwd);
13742
+ let current = path3.resolve(cwd);
13648
13743
  try {
13649
- if (!fs2.statSync(current).isDirectory())
13650
- current = path2.dirname(current);
13744
+ if (!fs3.statSync(current).isDirectory())
13745
+ current = path3.dirname(current);
13651
13746
  } catch {
13652
13747
  return;
13653
13748
  }
13654
13749
  while (true) {
13655
13750
  try {
13656
- const entry = fs2.statSync(path2.join(current, ".git"));
13751
+ const entry = fs3.statSync(path3.join(current, ".git"));
13657
13752
  if (entry.isDirectory() || entry.isFile())
13658
13753
  return current;
13659
13754
  } catch {}
13660
- const parent = path2.dirname(current);
13755
+ const parent = path3.dirname(current);
13661
13756
  if (parent === current)
13662
13757
  return;
13663
13758
  current = parent;
13664
13759
  }
13665
13760
  }
13666
13761
  function resolveMainRepoRoot(repoRoot) {
13667
- const gitEntry = path2.join(repoRoot, ".git");
13762
+ const gitEntry = path3.join(repoRoot, ".git");
13668
13763
  let stats;
13669
13764
  try {
13670
- stats = fs2.statSync(gitEntry);
13765
+ stats = fs3.statSync(gitEntry);
13671
13766
  } catch {
13672
13767
  return;
13673
13768
  }
13674
13769
  if (stats.isDirectory())
13675
- return path2.resolve(repoRoot);
13770
+ return path3.resolve(repoRoot);
13676
13771
  if (!stats.isFile())
13677
13772
  return;
13678
13773
  const pointer = readText(gitEntry);
13679
13774
  if (pointer === undefined)
13680
13775
  return;
13681
13776
  const gitDir = pathFromPointer(pointer, "gitdir:", repoRoot);
13682
- if (gitDir === undefined || path2.basename(path2.dirname(gitDir)) !== "worktrees")
13777
+ if (gitDir === undefined || path3.basename(path3.dirname(gitDir)) !== "worktrees")
13683
13778
  return;
13684
- const commonGitDir = path2.dirname(path2.dirname(gitDir));
13685
- if (path2.basename(commonGitDir) !== ".git")
13779
+ const commonGitDir = path3.dirname(path3.dirname(gitDir));
13780
+ if (path3.basename(commonGitDir) !== ".git")
13686
13781
  return;
13687
- const backPointer = readText(path2.join(gitDir, "gitdir"));
13688
- const commonPointer = readText(path2.join(gitDir, "commondir"));
13782
+ const backPointer = readText(path3.join(gitDir, "gitdir"));
13783
+ const commonPointer = readText(path3.join(gitDir, "commondir"));
13689
13784
  if (backPointer === undefined || commonPointer === undefined)
13690
13785
  return;
13691
- const linkedGitEntry = path2.resolve(gitDir, backPointer.trim());
13692
- const declaredCommonDir = path2.resolve(gitDir, commonPointer.trim());
13786
+ const linkedGitEntry = path3.resolve(gitDir, backPointer.trim());
13787
+ const declaredCommonDir = path3.resolve(gitDir, commonPointer.trim());
13693
13788
  if (!backPointer.trim() || !commonPointer.trim())
13694
13789
  return;
13695
13790
  if (!samePath(linkedGitEntry, gitEntry) || !samePath(declaredCommonDir, commonGitDir))
13696
13791
  return;
13697
- return path2.dirname(commonGitDir);
13792
+ return path3.dirname(commonGitDir);
13698
13793
  }
13699
13794
  function findCanonicalGitRoot(cwd) {
13700
13795
  const repoRoot = findGitRoot(cwd);
@@ -13703,33 +13798,31 @@ function findCanonicalGitRoot(cwd) {
13703
13798
  var init_worktree_root = () => {};
13704
13799
 
13705
13800
  // dist/builtin/workflows/src/runs/shared/worktree-git.ts
13706
- import * as fs3 from "node:fs";
13707
- import * as path3 from "node:path";
13708
- function gitWorktreeSetupCacheKey(options) {
13709
- const repoRoot = repositoryRootForGitWorktree(options.cwd);
13710
- const { logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
13711
- const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
13801
+ import * as fs4 from "node:fs";
13802
+ import * as path4 from "node:path";
13803
+ function gitWorktreeSetupCacheKey(request) {
13712
13804
  return JSON.stringify([
13713
- comparableRealPath(gitCommonDirForWorktree(repoRoot)),
13714
- comparablePathThroughExistingAncestor(worktreeRoot)
13805
+ comparablePathThroughExistingAncestor(request.options.cwd),
13806
+ comparablePathThroughExistingAncestor(request.target)
13715
13807
  ]);
13716
13808
  }
13717
- function createGitWorktreeSetupCache() {
13809
+ function createGitWorktreeSetupCache(ownerRunId) {
13718
13810
  const results = new Map;
13719
13811
  let disposed = false;
13720
13812
  return {
13721
13813
  get(options) {
13722
13814
  if (disposed)
13723
13815
  throw new Error("Git worktree setup cache is already disposed");
13724
- const key = gitWorktreeSetupCacheKey(options);
13816
+ const request = resolveGitWorktreeSetupRequest(options);
13817
+ const key = gitWorktreeSetupCacheKey(request);
13725
13818
  const cached = results.get(key);
13726
13819
  if (cached !== undefined) {
13727
13820
  assertCachedGitWorktreeIdentity(cached, options);
13728
13821
  return cached.result;
13729
13822
  }
13730
- const result = setupGitWorktree(options);
13731
- results.set(key, { result, identity: captureGitWorktreeIdentity(result) });
13732
- return result;
13823
+ const setup = setupGitWorktreeFromRequest(request, ownerRunId);
13824
+ results.set(key, { ...setup, identity: captureGitWorktreeIdentity(setup) });
13825
+ return setup.result;
13733
13826
  },
13734
13827
  dispose() {
13735
13828
  if (disposed)
@@ -13761,10 +13854,10 @@ function worktreeRecoveryCommand(repositoryRoot, worktreeDir) {
13761
13854
  return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
13762
13855
  }
13763
13856
  function hasGrandparent(value2) {
13764
- const parent = path3.dirname(value2);
13857
+ const parent = path4.dirname(value2);
13765
13858
  if (parent === value2)
13766
13859
  return false;
13767
- const grandparent = path3.dirname(parent);
13860
+ const grandparent = path4.dirname(parent);
13768
13861
  return grandparent !== parent;
13769
13862
  }
13770
13863
  function pathAncestors(value2) {
@@ -13772,7 +13865,7 @@ function pathAncestors(value2) {
13772
13865
  let current = value2;
13773
13866
  while (true) {
13774
13867
  ancestors.push(current);
13775
- const parent = path3.dirname(current);
13868
+ const parent = path4.dirname(current);
13776
13869
  if (parent === current)
13777
13870
  return ancestors;
13778
13871
  current = parent;
@@ -13781,89 +13874,167 @@ function pathAncestors(value2) {
13781
13874
  function shouldPreserveLogicalPath(logicalPath) {
13782
13875
  return pathAncestors(logicalPath).some((ancestor) => {
13783
13876
  try {
13784
- return fs3.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
13877
+ return fs4.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
13785
13878
  } catch {
13786
13879
  return false;
13787
13880
  }
13788
13881
  });
13789
13882
  }
13790
13883
  function canonicalizePreservingSymlinks(value2) {
13791
- const logicalPath = path3.resolve(value2);
13884
+ const logicalPath = path4.resolve(value2);
13792
13885
  const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
13793
13886
  try {
13794
- const canonical = fs3.realpathSync.native(logicalPath);
13887
+ const canonical = fs4.realpathSync.native(logicalPath);
13795
13888
  return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
13796
13889
  } catch {
13797
13890
  return logicalPath;
13798
13891
  }
13799
13892
  }
13800
- function resolveGitWorktreePath(value2, repoRoot) {
13893
+ function resolveGitWorktreePath(value2, baseDir) {
13801
13894
  const trimmed = value2.trim();
13802
13895
  if (!trimmed)
13803
13896
  throw new Error("gitWorktreeDir cannot be empty");
13804
13897
  if (trimmed.includes("\x00")) {
13805
13898
  throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
13806
13899
  }
13807
- return canonicalizePreservingSymlinks(path3.isAbsolute(trimmed) ? trimmed : path3.resolve(repoRoot, trimmed));
13900
+ return canonicalizePreservingSymlinks(path4.isAbsolute(trimmed) ? trimmed : path4.resolve(baseDir, trimmed));
13808
13901
  }
13809
13902
  function comparableRealPath(value2) {
13810
- const realpath = fs3.realpathSync.native(value2).replace(/\\/g, "/");
13903
+ const realpath = fs4.realpathSync.native(value2).replace(/\\/g, "/");
13811
13904
  return process.platform === "win32" ? realpath.toLowerCase() : realpath;
13812
13905
  }
13813
- function comparablePathThroughExistingAncestor(value2) {
13814
- let existing = path3.resolve(value2);
13906
+ function nearestExistingAncestor(value2) {
13907
+ let existing = path4.resolve(value2);
13815
13908
  const missing = [];
13816
13909
  while (!pathExistsSync(existing)) {
13817
- const parent = path3.dirname(existing);
13910
+ const parent = path4.dirname(existing);
13818
13911
  if (parent === existing)
13819
13912
  break;
13820
- missing.unshift(path3.basename(existing));
13913
+ missing.unshift(path4.basename(existing));
13821
13914
  existing = parent;
13822
13915
  }
13823
- const resolved = path3.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
13916
+ return { existing, missing };
13917
+ }
13918
+ function comparablePathThroughExistingAncestor(value2) {
13919
+ const { existing, missing } = nearestExistingAncestor(value2);
13920
+ const resolved = path4.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
13824
13921
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
13825
13922
  }
13923
+ function isFileOrLink(value2) {
13924
+ try {
13925
+ const entry = fs4.lstatSync(value2);
13926
+ return entry.isFile() || entry.isSymbolicLink();
13927
+ } catch {
13928
+ return false;
13929
+ }
13930
+ }
13931
+ function isDirectory(value2) {
13932
+ try {
13933
+ return fs4.statSync(value2).isDirectory();
13934
+ } catch {
13935
+ return false;
13936
+ }
13937
+ }
13938
+ function looksLikeGitDirectory(directory) {
13939
+ if (!isDirectory(directory))
13940
+ return false;
13941
+ if (path4.basename(directory) === ".git")
13942
+ return true;
13943
+ if (!isFileOrLink(path4.join(directory, "HEAD")))
13944
+ return false;
13945
+ if (isFileOrLink(path4.join(directory, "commondir")))
13946
+ return true;
13947
+ return isDirectory(path4.join(directory, "objects")) && isDirectory(path4.join(directory, "refs"));
13948
+ }
13949
+ function enclosingGitMetadataDirectory(target) {
13950
+ const { existing } = nearestExistingAncestor(target);
13951
+ let realExisting = existing;
13952
+ try {
13953
+ realExisting = fs4.realpathSync.native(existing);
13954
+ } catch {}
13955
+ for (const candidate of new Set([...pathAncestors(existing), ...pathAncestors(realExisting)])) {
13956
+ if (looksLikeGitDirectory(candidate))
13957
+ return candidate;
13958
+ }
13959
+ const insideGitDir = runGitReadOnlyProbe(existing, ["rev-parse", "--is-inside-git-dir"]);
13960
+ if (insideGitDir.status !== 0 && isGitTimeoutResult(insideGitDir)) {
13961
+ throw new Error(`Timed out while validating gitWorktreeDir ${target}. Git reported: ${gitFailureMessage(insideGitDir)}`);
13962
+ }
13963
+ return insideGitDir.status === 0 && insideGitDir.stdout.trim() === "true" ? existing : undefined;
13964
+ }
13965
+ function assertSafeGitWorktreeTarget(target, invokingRoot) {
13966
+ const gitDirectory = enclosingGitMetadataDirectory(target);
13967
+ if (gitDirectory !== undefined) {
13968
+ throw new Error(`gitWorktreeDir must not be inside Git metadata: ${target} is inside the Git directory ${gitDirectory}. Choose a worktree root or a plain directory outside Git metadata.`);
13969
+ }
13970
+ if (invokingRoot !== undefined)
13971
+ validateWorktreeOutsideInvokingCheckout(target, invokingRoot);
13972
+ const { existing, missing } = nearestExistingAncestor(target);
13973
+ const workingTree = gitTopLevel(existing);
13974
+ if (workingTree === undefined)
13975
+ return;
13976
+ if (missing.length === 0 && comparableRealPath(target) === comparableRealPath(workingTree))
13977
+ return;
13978
+ throw new Error(`gitWorktreeDir must not be inside another Git working tree: ${target} is inside ${workingTree}. Pass that checkout's root to reuse it, or a path outside every Git checkout.`);
13979
+ }
13826
13980
  function validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot) {
13827
13981
  const repository = comparableRealPath(repoRoot);
13828
13982
  const candidate = comparablePathThroughExistingAncestor(worktreeRoot);
13829
- const relativePath = path3.relative(repository, candidate);
13983
+ const relativePath = path4.relative(repository, candidate);
13830
13984
  if (relativePath === "") {
13831
- throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate same-repository worktree path.");
13985
+ throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate worktree path outside it.");
13832
13986
  }
13833
- if (!relativePath.startsWith(`..${path3.sep}`) && relativePath !== ".." && !path3.isAbsolute(relativePath)) {
13834
- throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate same-repository worktree path.");
13987
+ if (!relativePath.startsWith(`..${path4.sep}`) && relativePath !== ".." && !path4.isAbsolute(relativePath)) {
13988
+ throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate worktree path outside it.");
13835
13989
  }
13836
13990
  }
13837
13991
  function gitPathFromOutput(value2, cwd) {
13838
13992
  const trimmed = value2.trim();
13839
13993
  if (!trimmed)
13840
13994
  return;
13841
- return path3.isAbsolute(trimmed) ? path3.resolve(trimmed) : path3.resolve(cwd, trimmed);
13995
+ return path4.isAbsolute(trimmed) ? path4.resolve(trimmed) : path4.resolve(cwd, trimmed);
13842
13996
  }
13843
13997
  function pathExistsSync(value2) {
13998
+ return pathStatSync(value2) !== undefined;
13999
+ }
14000
+ function pathStatSync(value2) {
13844
14001
  try {
13845
- fs3.statSync(value2);
13846
- return true;
14002
+ return fs4.statSync(value2);
13847
14003
  } catch (error) {
13848
14004
  const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
13849
14005
  if (code === "ENOENT" || code === "ENOTDIR")
13850
- return false;
14006
+ return;
13851
14007
  throw error;
13852
14008
  }
13853
14009
  }
13854
- function repositoryRootForGitWorktree(cwd) {
14010
+ function probeInvokingRepository(cwd) {
13855
14011
  const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
13856
14012
  if (result.status !== 0) {
13857
14013
  if (isGitTimeoutResult(result)) {
13858
14014
  throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
13859
14015
  }
13860
- throw new Error(`gitWorktreeDir requires the workflow to be invoked from inside a Git repository. Start from a Git checkout or omit gitWorktreeDir. Git reported: ${gitFailureMessage(result)}`);
14016
+ return { failure: gitFailureMessage(result) };
13861
14017
  }
13862
- const normalized = gitPathFromOutput(result.stdout, cwd);
13863
- if (normalized === undefined) {
14018
+ const root = gitPathFromOutput(result.stdout, cwd);
14019
+ if (root === undefined) {
13864
14020
  throw new Error(`gitWorktreeDir could not resolve the repository top level from ${cwd}: git returned an empty path.`);
13865
14021
  }
13866
- return normalized;
14022
+ return { repository: { root, ...cwdWithinGitRepository(cwd, root) } };
14023
+ }
14024
+ function resolveGitWorktreeSetupRequest(options) {
14025
+ const probe = probeInvokingRepository(options.cwd);
14026
+ if ("repository" in probe) {
14027
+ return {
14028
+ options,
14029
+ repository: probe.repository,
14030
+ target: resolveGitWorktreePath(options.gitWorktreeDir, probe.repository.logicalRoot)
14031
+ };
14032
+ }
14033
+ return {
14034
+ options,
14035
+ repositoryProbeFailure: probe.failure,
14036
+ target: resolveGitWorktreePath(options.gitWorktreeDir, canonicalizePreservingSymlinks(options.cwd))
14037
+ };
13867
14038
  }
13868
14039
  function gitTopLevelFromResult(result, cwd, description) {
13869
14040
  if (result.status !== 0) {
@@ -13899,25 +14070,25 @@ function dirnameForEachRelativeComponent(base, relativePath) {
13899
14070
  continue;
13900
14071
  if (component === "..")
13901
14072
  return;
13902
- current = path3.dirname(current);
14073
+ current = path4.dirname(current);
13903
14074
  }
13904
14075
  return current;
13905
14076
  }
13906
14077
  function cwdWithinGitRepository(cwd, repoRoot) {
13907
- const sourceCwd = fs3.realpathSync.native(cwd);
13908
- const sourceRepoRoot = fs3.realpathSync.native(repoRoot);
13909
- const relativeCwd = path3.relative(sourceRepoRoot, sourceCwd);
13910
- const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path3.isAbsolute(relativeCwd) ? "" : relativeCwd;
14078
+ const sourceCwd = fs4.realpathSync.native(cwd);
14079
+ const sourceRepoRoot = fs4.realpathSync.native(repoRoot);
14080
+ const relativeCwd = path4.relative(sourceRepoRoot, sourceCwd);
14081
+ const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path4.isAbsolute(relativeCwd) ? "" : relativeCwd;
13911
14082
  const logicalCwd = canonicalizePreservingSymlinks(cwd);
13912
14083
  return {
13913
14084
  relativeCwd: safeRelativeCwd,
13914
- logicalRepoRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
14085
+ logicalRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
13915
14086
  };
13916
14087
  }
13917
14088
  function workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd) {
13918
- return relativeCwd === "" ? worktreeRoot : path3.join(worktreeRoot, relativeCwd);
14089
+ return relativeCwd === "" ? worktreeRoot : path4.join(worktreeRoot, relativeCwd);
13919
14090
  }
13920
- function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
14091
+ function validateGitWorktreeRoot(worktreeRoot) {
13921
14092
  const topLevel = gitTopLevel(worktreeRoot);
13922
14093
  if (topLevel === undefined) {
13923
14094
  throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
@@ -13925,8 +14096,18 @@ function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
13925
14096
  if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
13926
14097
  throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
13927
14098
  }
13928
- if (comparableRealPath(gitCommonDirForWorktree(repoRoot)) !== comparableRealPath(gitCommonDirForWorktree(topLevel))) {
13929
- throw new Error(`gitWorktreeDir already exists but does not belong to the invoking Git repository: ${worktreeRoot}`);
14099
+ return gitCommonDirForWorktree(topLevel);
14100
+ }
14101
+ function existingGitWorktreeCommonDir(directory) {
14102
+ return gitTopLevel(directory) === undefined ? undefined : validateGitWorktreeRoot(directory);
14103
+ }
14104
+ function sameGitCommonDir(left, right) {
14105
+ return comparableRealPath(left) === comparableRealPath(right);
14106
+ }
14107
+ function validateCreatedGitWorktree(worktreeRoot, repository) {
14108
+ assertSafeGitWorktreeTarget(worktreeRoot, repository.root);
14109
+ if (!sameGitCommonDir(validateGitWorktreeRoot(worktreeRoot), gitCommonDirForWorktree(repository.root))) {
14110
+ throw new Error(`gitWorktreeDir does not belong to the invoking Git repository: ${worktreeRoot}`);
13930
14111
  }
13931
14112
  }
13932
14113
  function gitDirectoryForWorktree(cwd) {
@@ -13940,26 +14121,27 @@ function gitDirectoryForWorktree(cwd) {
13940
14121
  return gitDir;
13941
14122
  }
13942
14123
  function captureGitWorktreeIdentitySnapshot(setup) {
13943
- validateWorktreeOutsideInvokingCheckout(setup.worktreeRoot, setup.repositoryRoot);
13944
- validateExistingGitWorktreeRoot(setup.worktreeRoot, setup.repositoryRoot);
13945
- const stats = fs3.statSync(setup.worktreeRoot);
14124
+ const { worktreeRoot, repositoryRoot } = setup.result;
14125
+ assertSafeGitWorktreeTarget(worktreeRoot, setup.invokingRoot);
14126
+ const commonDir = validateGitWorktreeRoot(worktreeRoot);
14127
+ const stats = fs4.statSync(worktreeRoot);
13946
14128
  return {
13947
- worktreeRealPath: comparableRealPath(setup.worktreeRoot),
13948
- repositoryRealPath: comparableRealPath(setup.repositoryRoot),
13949
- gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(setup.worktreeRoot)),
13950
- commonDirRealPath: comparableRealPath(gitCommonDirForWorktree(setup.worktreeRoot)),
14129
+ worktreeRealPath: comparableRealPath(worktreeRoot),
14130
+ repositoryRealPath: comparableRealPath(repositoryRoot),
14131
+ gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(worktreeRoot)),
14132
+ commonDirRealPath: comparableRealPath(commonDir),
13951
14133
  device: stats.dev,
13952
14134
  inode: stats.ino
13953
14135
  };
13954
14136
  }
13955
14137
  function captureGitWorktreeIdentity(setup) {
13956
14138
  const snapshot = captureGitWorktreeIdentitySnapshot(setup);
13957
- return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.worktreeRoot) };
14139
+ return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.result.worktreeRoot) };
13958
14140
  }
13959
14141
  function assertCachedGitWorktreeIdentity(cached, options) {
13960
14142
  let current;
13961
14143
  try {
13962
- current = captureGitWorktreeIdentitySnapshot(cached.result);
14144
+ current = captureGitWorktreeIdentitySnapshot(cached);
13963
14145
  cached.identity.generation.assertCurrent();
13964
14146
  } catch (error) {
13965
14147
  const message = error instanceof Error ? error.message : String(error);
@@ -13967,34 +14149,58 @@ function assertCachedGitWorktreeIdentity(cached, options) {
13967
14149
  }
13968
14150
  const expected = cached.identity;
13969
14151
  if (current.worktreeRealPath !== expected.worktreeRealPath || current.repositoryRealPath !== expected.repositoryRealPath || current.gitDirRealPath !== expected.gitDirRealPath || current.commonDirRealPath !== expected.commonDirRealPath || current.device !== expected.device || current.inode !== expected.inode) {
13970
- throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended same-repository worktree.`);
13971
- }
14152
+ throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended worktree.`);
14153
+ }
14154
+ }
14155
+ function requireInvokingRepository(request, action) {
14156
+ if (request.repository !== undefined)
14157
+ return request.repository;
14158
+ throw new Error([
14159
+ `gitWorktreeDir requires the workflow to be invoked from inside a Git repository to ${action}.`,
14160
+ "Start the workflow from a checkout of the repository the new worktree should come from, or set gitWorktreeDir to the root of an existing Git worktree to reuse it from any directory.",
14161
+ `Git reported: ${request.repositoryProbeFailure ?? "no repository"}`
14162
+ ].join(" "));
14163
+ }
14164
+ function setupGitWorktreeFromRequest(request, ownerRunId) {
14165
+ const { repository, target } = request;
14166
+ assertSafeGitWorktreeTarget(target, repository?.root);
14167
+ const entry = pathStatSync(target);
14168
+ if (entry === undefined)
14169
+ return createGitWorktreeAtPath(request, false);
14170
+ if (!entry.isDirectory())
14171
+ throw new Error(`gitWorktreeDir already exists but is not a directory: ${target}`);
14172
+ if (fs4.readdirSync(target).length === 0)
14173
+ return createGitWorktreeAtPath(request, true);
14174
+ const commonDir = existingGitWorktreeCommonDir(target);
14175
+ if (commonDir === undefined)
14176
+ return allocateGitWorktree(request, ownerRunId);
14177
+ const sameRepository = repository !== undefined && sameGitCommonDir(commonDir, gitCommonDirForWorktree(repository.root));
14178
+ return {
14179
+ result: {
14180
+ worktreeRoot: target,
14181
+ cwd: sameRepository ? workspaceCwdForGitWorktreeRoot(target, repository.relativeCwd) : target,
14182
+ repositoryRoot: sameRepository ? repository.root : target,
14183
+ created: false
14184
+ },
14185
+ ...repository !== undefined ? { invokingRoot: repository.root } : {}
14186
+ };
13972
14187
  }
13973
- function setupGitWorktree(options) {
13974
- const repoRoot = repositoryRootForGitWorktree(options.cwd);
13975
- const mainRoot = findCanonicalGitRoot(repoRoot);
14188
+ function createGitWorktreeAtPath(request, existingEmptyDirectory) {
14189
+ const { target: worktreeRoot } = request;
14190
+ const repository = requireInvokingRepository(request, `create a new worktree at ${worktreeRoot}`);
14191
+ const mainRoot = findCanonicalGitRoot(repository.root);
13976
14192
  if (mainRoot === undefined) {
13977
- throw new Error(`Unable to resolve the canonical main Git repository root from ${repoRoot}.`);
13978
- }
13979
- const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
13980
- const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
13981
- validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
13982
- if (pathExistsSync(worktreeRoot)) {
13983
- validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
13984
- return {
13985
- worktreeRoot,
13986
- cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
13987
- repositoryRoot: repoRoot,
13988
- created: false
13989
- };
14193
+ throw new Error(`Unable to resolve the canonical main Git repository root from ${repository.root}.`);
13990
14194
  }
13991
- try {
13992
- fs3.mkdirSync(path3.dirname(worktreeRoot), { recursive: true });
13993
- } catch (error) {
13994
- const message = error instanceof Error ? error.message : String(error);
13995
- throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
14195
+ if (!existingEmptyDirectory) {
14196
+ try {
14197
+ fs4.mkdirSync(path4.dirname(worktreeRoot), { recursive: true });
14198
+ } catch (error) {
14199
+ const message = error instanceof Error ? error.message : String(error);
14200
+ throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
14201
+ }
13996
14202
  }
13997
- const baseRef = options.baseBranch?.trim() || "HEAD";
14203
+ const baseRef = request.options.baseBranch?.trim() || "HEAD";
13998
14204
  const result = runGit(mainRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
13999
14205
  if (result.status !== 0) {
14000
14206
  throw new Error([
@@ -14004,30 +14210,127 @@ function setupGitWorktree(options) {
14004
14210
  `));
14005
14211
  }
14006
14212
  try {
14007
- validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
14008
- validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
14213
+ validateCreatedGitWorktree(worktreeRoot, repository);
14009
14214
  } catch (error) {
14010
14215
  runGit(mainRoot, ["worktree", "remove", "--force", worktreeRoot]);
14011
14216
  const message = error instanceof Error ? error.message : String(error);
14012
14217
  throw new Error(`Created gitWorktreeDir failed post-creation validation: ${message}`);
14013
14218
  }
14014
14219
  return {
14015
- worktreeRoot,
14016
- cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
14017
- repositoryRoot: repoRoot,
14018
- created: true
14220
+ result: {
14221
+ worktreeRoot,
14222
+ cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, repository.relativeCwd),
14223
+ repositoryRoot: repository.root,
14224
+ created: true
14225
+ },
14226
+ invokingRoot: repository.root
14227
+ };
14228
+ }
14229
+ function containedWorktreeCwd(checkout, relativeCwd) {
14230
+ const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
14231
+ let resolved;
14232
+ try {
14233
+ resolved = fs4.realpathSync.native(cwd);
14234
+ } catch {
14235
+ resolved = "";
14236
+ }
14237
+ const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
14238
+ if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
14239
+ throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
14240
+ }
14241
+ return cwd;
14242
+ }
14243
+ function allocatedGitWorktreeSetup(checkout, repository, created) {
14244
+ return {
14245
+ result: {
14246
+ worktreeRoot: checkout,
14247
+ cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
14248
+ repositoryRoot: repository.root,
14249
+ created
14250
+ },
14251
+ invokingRoot: repository.root
14019
14252
  };
14020
14253
  }
14254
+ function validateOwnedGitWorktree(checkout, repository) {
14255
+ validateCreatedGitWorktree(checkout, repository);
14256
+ const gitDir = gitDirectoryForWorktree(checkout);
14257
+ if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
14258
+ throw new Error(`${checkout} is not a linked worktree`);
14259
+ }
14260
+ const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
14261
+ if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
14262
+ throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
14263
+ }
14264
+ }
14265
+ function findOwnedGitWorktree(root, repository, ownerRunId) {
14266
+ const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
14267
+ if (checkout === undefined)
14268
+ return;
14269
+ try {
14270
+ validateOwnedGitWorktree(checkout, repository);
14271
+ return allocatedGitWorktreeSetup(checkout, repository, false);
14272
+ } catch (error) {
14273
+ const message = error instanceof Error ? error.message : String(error);
14274
+ throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
14275
+ }
14276
+ }
14277
+ function allocateGitWorktree(request, ownerRunId) {
14278
+ const { target: root } = request;
14279
+ const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
14280
+ if (ownerRunId !== undefined) {
14281
+ const owned = findOwnedGitWorktree(root, repository, ownerRunId);
14282
+ if (owned !== undefined)
14283
+ return owned;
14284
+ }
14285
+ const baseRef = request.options.baseBranch?.trim() || "HEAD";
14286
+ const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
14287
+ const commit = revision.status === 0 ? revision.stdout.trim() : "";
14288
+ if (commit === "") {
14289
+ throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
14290
+ }
14291
+ const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
14292
+ const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
14293
+ if (add.status !== 0) {
14294
+ removeEmptyWorktreeBucket(checkout);
14295
+ throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
14296
+ }
14297
+ try {
14298
+ const gitDir = gitDirectoryForWorktree(checkout);
14299
+ runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
14300
+ runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
14301
+ validateCreatedGitWorktree(checkout, repository);
14302
+ const setup = allocatedGitWorktreeSetup(checkout, repository, true);
14303
+ if (ownerRunId !== undefined)
14304
+ bindWorktreeOwner(gitDir, ownerRunId);
14305
+ return setup;
14306
+ } catch (error) {
14307
+ const message = error instanceof Error ? error.message : String(error);
14308
+ const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
14309
+ removeEmptyWorktreeBucket(checkout);
14310
+ const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
14311
+ throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
14312
+ }
14313
+ }
14314
+ function runGitOrThrow(cwd, args) {
14315
+ const result = runGit(cwd, args);
14316
+ if (result.status !== 0)
14317
+ throw new Error(gitFailureMessage(result));
14318
+ }
14319
+ function setupGitWorktree(options) {
14320
+ return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
14321
+ }
14021
14322
  var init_worktree_git = __esm(() => {
14323
+ init_worktree_allocation();
14022
14324
  init_worktree_generation();
14023
14325
  init_worktree_git_runner();
14024
14326
  init_worktree_root();
14327
+ init_worktree_allocation();
14025
14328
  init_worktree_git_runner();
14026
14329
  });
14027
14330
 
14028
14331
  // dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
14029
- function createGitWorktreeSetupCacheOwner(suppliedCache) {
14030
- const cache = suppliedCache ?? createGitWorktreeSetupCache();
14332
+ function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
14333
+ const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
14031
14334
  const ownsCache = suppliedCache === undefined;
14032
14335
  let released = false;
14033
14336
  return {
@@ -14048,20 +14351,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
14048
14351
  });
14049
14352
 
14050
14353
  // dist/builtin/workflows/src/runs/shared/worktree-diff.ts
14051
- import * as fs4 from "node:fs";
14052
- import * as path4 from "node:path";
14354
+ import * as fs5 from "node:fs";
14355
+ import * as path5 from "node:path";
14053
14356
  function safePatchAgentName(agent) {
14054
14357
  return agent.replace(/[^\w.-]/g, "_");
14055
14358
  }
14056
14359
  function removeSyntheticPath(worktree, syntheticPath) {
14057
- const resolved = path4.resolve(worktree.path, syntheticPath);
14058
- const relative = path4.relative(worktree.path, resolved);
14059
- if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative)) {
14360
+ const resolved = path5.resolve(worktree.path, syntheticPath);
14361
+ const relative = path5.relative(worktree.path, resolved);
14362
+ if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path5.sep}`) || path5.isAbsolute(relative)) {
14060
14363
  return;
14061
14364
  }
14062
14365
  let stat;
14063
14366
  try {
14064
- stat = fs4.lstatSync(resolved);
14367
+ stat = fs5.lstatSync(resolved);
14065
14368
  } catch (error) {
14066
14369
  const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
14067
14370
  if (code === "ENOENT")
@@ -14069,14 +14372,14 @@ function removeSyntheticPath(worktree, syntheticPath) {
14069
14372
  throw error;
14070
14373
  }
14071
14374
  if (stat.isSymbolicLink()) {
14072
- fs4.unlinkSync(resolved);
14375
+ fs5.unlinkSync(resolved);
14073
14376
  return;
14074
14377
  }
14075
14378
  if (stat.isDirectory()) {
14076
- fs4.rmSync(resolved, { recursive: true, force: true });
14379
+ fs5.rmSync(resolved, { recursive: true, force: true });
14077
14380
  return;
14078
14381
  }
14079
- fs4.rmSync(resolved, { force: true });
14382
+ fs5.rmSync(resolved, { force: true });
14080
14383
  }
14081
14384
  function removeSyntheticPathsBeforeDiff(worktree) {
14082
14385
  if (worktree.syntheticPaths.length === 0)
@@ -14125,7 +14428,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
14125
14428
  const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
14126
14429
  const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
14127
14430
  const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
14128
- fs4.writeFileSync(patchPath, patch, "utf-8");
14431
+ fs5.writeFileSync(patchPath, patch, "utf-8");
14129
14432
  if (!patch.trim()) {
14130
14433
  return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
14131
14434
  }
@@ -14143,7 +14446,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
14143
14446
  }
14144
14447
  function writeEmptyPatch(patchPath) {
14145
14448
  try {
14146
- fs4.writeFileSync(patchPath, "", "utf-8");
14449
+ fs5.writeFileSync(patchPath, "", "utf-8");
14147
14450
  } catch {}
14148
14451
  }
14149
14452
  function hasWorktreeChanges(diff) {
@@ -14151,7 +14454,7 @@ function hasWorktreeChanges(diff) {
14151
14454
  }
14152
14455
  function diffWorktrees(setup, agents, diffsDir) {
14153
14456
  try {
14154
- fs4.mkdirSync(diffsDir, { recursive: true });
14457
+ fs5.mkdirSync(diffsDir, { recursive: true });
14155
14458
  } catch {
14156
14459
  return [];
14157
14460
  }
@@ -14159,7 +14462,7 @@ function diffWorktrees(setup, agents, diffsDir) {
14159
14462
  for (let index = 0;index < setup.worktrees.length; index++) {
14160
14463
  const worktree = setup.worktrees[index];
14161
14464
  const agent = agents[index] ?? `task-${index + 1}`;
14162
- const patchPath = path4.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
14465
+ const patchPath = path5.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
14163
14466
  try {
14164
14467
  diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
14165
14468
  } catch {
@@ -14181,7 +14484,7 @@ function formatWorktreeDiffSummary(diffs) {
14181
14484
  }
14182
14485
  lines.push("");
14183
14486
  }
14184
- const patchesDir = path4.dirname(changed[0].patchPath);
14487
+ const patchesDir = path5.dirname(changed[0].patchPath);
14185
14488
  lines.push(`Full patches: ${patchesDir}`);
14186
14489
  return lines.join(`
14187
14490
  `).trimEnd();
@@ -14191,8 +14494,8 @@ var init_worktree_diff = __esm(() => {
14191
14494
  });
14192
14495
 
14193
14496
  // dist/builtin/workflows/src/runs/shared/worktree-post-create.ts
14194
- import * as fs5 from "node:fs";
14195
- import * as path5 from "node:path";
14497
+ import * as fs6 from "node:fs";
14498
+ import * as path6 from "node:path";
14196
14499
  function tracked(repo, relativePath) {
14197
14500
  const result = runGit(repo, ["ls-files", "--error-unmatch", "--", relativePath]);
14198
14501
  return result.status === 0;
@@ -14212,12 +14515,12 @@ function hasTrackedPathComponent(repo, relativePath) {
14212
14515
  return false;
14213
14516
  }
14214
14517
  function copyUntrackedFile(mainRoot, worktreeRoot, relativePath) {
14215
- const source = path5.join(mainRoot, relativePath);
14216
- const destination = path5.join(worktreeRoot, relativePath);
14217
- if (!fs5.existsSync(source) || fs5.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14518
+ const source = path6.join(mainRoot, relativePath);
14519
+ const destination = path6.join(worktreeRoot, relativePath);
14520
+ if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14218
14521
  return false;
14219
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14220
- fs5.copyFileSync(source, destination);
14522
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14523
+ fs6.copyFileSync(source, destination);
14221
14524
  return true;
14222
14525
  }
14223
14526
  function propagateLocalSettings(mainRoot, worktreeRoot) {
@@ -14230,14 +14533,14 @@ function propagateLocalSettings(mainRoot, worktreeRoot) {
14230
14533
  return copied;
14231
14534
  }
14232
14535
  function populatedHooksDirectory(mainRoot) {
14233
- const husky = path5.join(mainRoot, ".husky");
14536
+ const husky = path6.join(mainRoot, ".husky");
14234
14537
  try {
14235
- if (fs5.statSync(husky).isDirectory())
14538
+ if (fs6.statSync(husky).isDirectory())
14236
14539
  return husky;
14237
14540
  } catch {}
14238
- const hooks = path5.join(mainRoot, ".git", "hooks");
14541
+ const hooks = path6.join(mainRoot, ".git", "hooks");
14239
14542
  try {
14240
- const populated = fs5.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
14543
+ const populated = fs6.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
14241
14544
  return populated ? hooks : undefined;
14242
14545
  } catch {
14243
14546
  return;
@@ -14248,7 +14551,7 @@ function configureSharedHooksPath(mainRoot) {
14248
14551
  if (desired === undefined)
14249
14552
  return;
14250
14553
  const current = runGitPlain(mainRoot, ["config", "--get", "core.hooksPath"]);
14251
- if (current.status === 0 && path5.resolve(mainRoot, current.stdout.trim()) === desired)
14554
+ if (current.status === 0 && path6.resolve(mainRoot, current.stdout.trim()) === desired)
14252
14555
  return;
14253
14556
  const configured = runGitPlain(mainRoot, ["config", "core.hooksPath", desired]);
14254
14557
  if (configured.status !== 0) {
@@ -14257,10 +14560,10 @@ function configureSharedHooksPath(mainRoot) {
14257
14560
  }
14258
14561
  function normalizeSymlinkDirectory(value2) {
14259
14562
  const trimmed = value2.trim();
14260
- if (!trimmed || path5.isAbsolute(trimmed))
14563
+ if (!trimmed || path6.isAbsolute(trimmed))
14261
14564
  return;
14262
- const normalized = path5.normalize(trimmed);
14263
- if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path5.sep}`))
14565
+ const normalized = path6.normalize(trimmed);
14566
+ if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path6.sep}`))
14264
14567
  return;
14265
14568
  return normalized;
14266
14569
  }
@@ -14270,20 +14573,20 @@ function symlinkConfiguredDirectories(mainRoot, worktreeRoot, directories) {
14270
14573
  const relativePath = normalizeSymlinkDirectory(rawDirectory);
14271
14574
  if (relativePath === undefined || synthetic.includes(relativePath))
14272
14575
  continue;
14273
- const source = path5.join(mainRoot, relativePath);
14274
- const destination = path5.join(worktreeRoot, relativePath);
14275
- if (!fs5.existsSync(source) || fs5.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14576
+ const source = path6.join(mainRoot, relativePath);
14577
+ const destination = path6.join(worktreeRoot, relativePath);
14578
+ if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14276
14579
  continue;
14277
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14580
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14278
14581
  try {
14279
- fs5.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
14582
+ fs6.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
14280
14583
  synthetic.push(relativePath);
14281
14584
  } catch {}
14282
14585
  }
14283
14586
  return synthetic;
14284
14587
  }
14285
14588
  function copyWorktreeIncludes(mainRoot, worktreeRoot) {
14286
- if (!fs5.existsSync(path5.join(mainRoot, ".worktreeinclude")))
14589
+ if (!fs6.existsSync(path6.join(mainRoot, ".worktreeinclude")))
14287
14590
  return;
14288
14591
  const ignored = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-standard"]);
14289
14592
  const included = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-from=.worktreeinclude"]);
@@ -14293,13 +14596,13 @@ function copyWorktreeIncludes(mainRoot, worktreeRoot) {
14293
14596
  for (const relativePath of included.stdout.split(/\r?\n/).filter(Boolean)) {
14294
14597
  if (!ignoredPaths.has(relativePath) || hasTrackedPathComponent(worktreeRoot, relativePath))
14295
14598
  continue;
14296
- const source = path5.join(mainRoot, relativePath);
14297
- const destination = path5.join(worktreeRoot, relativePath);
14599
+ const source = path6.join(mainRoot, relativePath);
14600
+ const destination = path6.join(worktreeRoot, relativePath);
14298
14601
  try {
14299
- if (!fs5.statSync(source).isFile() || fs5.existsSync(destination))
14602
+ if (!fs6.statSync(source).isFile() || fs6.existsSync(destination))
14300
14603
  continue;
14301
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14302
- fs5.copyFileSync(source, destination);
14604
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14605
+ fs6.copyFileSync(source, destination);
14303
14606
  } catch {}
14304
14607
  }
14305
14608
  }
@@ -14316,9 +14619,9 @@ var init_worktree_post_create = __esm(() => {
14316
14619
 
14317
14620
  // dist/builtin/workflows/src/runs/shared/worktree-setup.ts
14318
14621
  import { spawnSync as spawnSync2 } from "node:child_process";
14319
- import * as fs6 from "node:fs";
14622
+ import * as fs7 from "node:fs";
14320
14623
  import * as os from "node:os";
14321
- import * as path6 from "node:path";
14624
+ import * as path7 from "node:path";
14322
14625
  import { createChildProcessEnvironment as createChildProcessEnvironment2 } from "@bastani/atomic";
14323
14626
  function originDefaultBranch(mainRoot) {
14324
14627
  const symbolic = runGit(mainRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
@@ -14338,7 +14641,7 @@ function originDefaultBranch(mainRoot) {
14338
14641
  }
14339
14642
  function resolveRepoState(cwd, explicitBaseBranch) {
14340
14643
  const cwdRelative = resolveRepoCwdRelative(cwd);
14341
- const toplevel = path6.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
14644
+ const toplevel = path7.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
14342
14645
  const mainRoot = findCanonicalGitRoot(toplevel);
14343
14646
  if (mainRoot === undefined)
14344
14647
  throw new Error(`unable to resolve canonical main Git repository root from ${toplevel}`);
@@ -14351,9 +14654,9 @@ function resolveRepoState(cwd, explicitBaseBranch) {
14351
14654
  return { toplevel, mainRoot, cwdRelative, baseCommit, baseRef };
14352
14655
  }
14353
14656
  function normalizeComparableCwd(cwd) {
14354
- const resolved = path6.resolve(cwd);
14657
+ const resolved = path7.resolve(cwd);
14355
14658
  try {
14356
- return fs6.realpathSync(resolved);
14659
+ return fs7.realpathSync(resolved);
14357
14660
  } catch {
14358
14661
  return resolved;
14359
14662
  }
@@ -14364,7 +14667,7 @@ function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
14364
14667
  const task = tasks[index];
14365
14668
  if (!task.cwd)
14366
14669
  continue;
14367
- const taskCwd = path6.isAbsolute(task.cwd) ? task.cwd : path6.resolve(sharedCwd, task.cwd);
14670
+ const taskCwd = path7.isAbsolute(task.cwd) ? task.cwd : path7.resolve(sharedCwd, task.cwd);
14368
14671
  if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
14369
14672
  continue;
14370
14673
  return { index, agent: task.agent, cwd: task.cwd };
@@ -14381,12 +14684,12 @@ function buildWorktreeBranch(runId, index) {
14381
14684
  return `worktree-${flattenedWorktreeName(runId, index)}`;
14382
14685
  }
14383
14686
  function buildWorktreePath(mainRoot, runId, index) {
14384
- return path6.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
14687
+ return path7.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
14385
14688
  }
14386
14689
  function ensureWorktreeIgnore(mainRoot) {
14387
- const worktreesRoot = path6.join(mainRoot, ".atomic", "worktrees");
14388
- fs6.mkdirSync(worktreesRoot, { recursive: true });
14389
- fs6.writeFileSync(path6.join(worktreesRoot, ".gitignore"), `*
14690
+ const worktreesRoot = path7.join(mainRoot, ".atomic", "worktrees");
14691
+ fs7.mkdirSync(worktreesRoot, { recursive: true });
14692
+ fs7.writeFileSync(path7.join(worktreesRoot, ".gitignore"), `*
14390
14693
  `, "utf8");
14391
14694
  }
14392
14695
  function resolveRepoCwdRelative(cwd) {
@@ -14395,7 +14698,7 @@ function resolveRepoCwdRelative(cwd) {
14395
14698
  throw new Error("worktree isolation requires a git repository");
14396
14699
  }
14397
14700
  const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
14398
- const normalizedPrefix = rawPrefix ? path6.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
14701
+ const normalizedPrefix = rawPrefix ? path7.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
14399
14702
  return normalizedPrefix === "." ? "" : normalizedPrefix;
14400
14703
  }
14401
14704
  function parseHookTimeout(timeoutMs) {
@@ -14413,19 +14716,19 @@ function resolveWorktreeSetupHook(repoRoot, config) {
14413
14716
  if (!hookPath) {
14414
14717
  throw new Error("worktree setup hook path cannot be empty");
14415
14718
  }
14416
- const expandedHookPath = hookPath.startsWith("~/") ? path6.join(os.homedir(), hookPath.slice(2)) : hookPath;
14719
+ const expandedHookPath = hookPath.startsWith("~/") ? path7.join(os.homedir(), hookPath.slice(2)) : hookPath;
14417
14720
  let resolvedPath;
14418
- if (path6.isAbsolute(expandedHookPath)) {
14721
+ if (path7.isAbsolute(expandedHookPath)) {
14419
14722
  resolvedPath = expandedHookPath;
14420
14723
  } else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
14421
- resolvedPath = path6.resolve(repoRoot, expandedHookPath);
14724
+ resolvedPath = path7.resolve(repoRoot, expandedHookPath);
14422
14725
  } else {
14423
14726
  throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
14424
14727
  }
14425
- if (!fs6.existsSync(resolvedPath)) {
14728
+ if (!fs7.existsSync(resolvedPath)) {
14426
14729
  throw new Error(`worktree setup hook not found: ${resolvedPath}`);
14427
14730
  }
14428
- if (fs6.statSync(resolvedPath).isDirectory()) {
14731
+ if (fs7.statSync(resolvedPath).isDirectory()) {
14429
14732
  throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
14430
14733
  }
14431
14734
  return {
@@ -14437,17 +14740,17 @@ function normalizeSyntheticPath(worktreePath, rawPath) {
14437
14740
  const trimmed = rawPath.trim();
14438
14741
  if (!trimmed)
14439
14742
  throw new Error("synthetic path cannot be empty");
14440
- if (path6.isAbsolute(trimmed))
14743
+ if (path7.isAbsolute(trimmed))
14441
14744
  throw new Error(`synthetic path must be relative: ${rawPath}`);
14442
- const resolved = path6.resolve(worktreePath, trimmed);
14443
- const relative = path6.relative(worktreePath, resolved);
14745
+ const resolved = path7.resolve(worktreePath, trimmed);
14746
+ const relative = path7.relative(worktreePath, resolved);
14444
14747
  if (!relative || relative === ".") {
14445
14748
  throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
14446
14749
  }
14447
- if (relative === ".." || relative.startsWith(`..${path6.sep}`) || path6.isAbsolute(relative)) {
14750
+ if (relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative)) {
14448
14751
  throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
14449
14752
  }
14450
- return path6.normalize(relative);
14753
+ return path7.normalize(relative);
14451
14754
  }
14452
14755
  function hasTrackedEntries(worktreePath, relativePath) {
14453
14756
  const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
@@ -14519,16 +14822,16 @@ function waitForGitLockRelease() {
14519
14822
  }
14520
14823
  function unlinkWorktreeLinks(worktreePath, relativePaths) {
14521
14824
  for (const relativePath of new Set(relativePaths)) {
14522
- const target = path6.resolve(worktreePath, relativePath);
14523
- const relative = path6.relative(worktreePath, target);
14524
- if (!relative || relative === ".." || relative.startsWith(`..${path6.sep}`) || path6.isAbsolute(relative))
14825
+ const target = path7.resolve(worktreePath, relativePath);
14826
+ const relative = path7.relative(worktreePath, target);
14827
+ if (!relative || relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative))
14525
14828
  continue;
14526
14829
  let current = worktreePath;
14527
- for (const component of relative.split(path6.sep)) {
14528
- current = path6.join(current, component);
14830
+ for (const component of relative.split(path7.sep)) {
14831
+ current = path7.join(current, component);
14529
14832
  let stat;
14530
14833
  try {
14531
- stat = fs6.lstatSync(current);
14834
+ stat = fs7.lstatSync(current);
14532
14835
  } catch (error) {
14533
14836
  const code = error.code;
14534
14837
  if (code === "ENOENT" || code === "ENOTDIR")
@@ -14538,7 +14841,7 @@ function unlinkWorktreeLinks(worktreePath, relativePaths) {
14538
14841
  if (!stat.isSymbolicLink())
14539
14842
  continue;
14540
14843
  if (current === target)
14541
- fs6.unlinkSync(current);
14844
+ fs7.unlinkSync(current);
14542
14845
  break;
14543
14846
  }
14544
14847
  }
@@ -14566,7 +14869,7 @@ function createSingleWorktree(mainRoot, cwdRelative, runId, index, baseRef, base
14566
14869
  cleanupSingleWorktree(mainRoot, { path: worktreePath, branch }, []);
14567
14870
  throw new Error(message);
14568
14871
  }
14569
- const agentCwd = cwdRelative ? path6.join(worktreePath, cwdRelative) : worktreePath;
14872
+ const agentCwd = cwdRelative ? path7.join(worktreePath, cwdRelative) : worktreePath;
14570
14873
  const syntheticPaths = [];
14571
14874
  try {
14572
14875
  syntheticPaths.push(...performPostCreationSetup(mainRoot, worktreePath, symlinkDirectories));
@@ -14635,8 +14938,8 @@ var init_worktree = __esm(() => {
14635
14938
  });
14636
14939
 
14637
14940
  // dist/builtin/workflows/src/runs/shared/worktree-cwd.ts
14638
- import { lstatSync as lstatSync5, realpathSync as realpathSync4 } from "node:fs";
14639
- import { dirname as dirname8, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve6, sep as sep5 } from "node:path";
14941
+ import { lstatSync as lstatSync6, realpathSync as realpathSync4 } from "node:fs";
14942
+ import { dirname as dirname9, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve7, sep as sep5 } from "node:path";
14640
14943
  function relativePathWithin(root, candidate) {
14641
14944
  const path = relative4(root, candidate);
14642
14945
  return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path) ? undefined : path;
@@ -14655,14 +14958,14 @@ function resolveWorktreeStageCwd(cwd, setup) {
14655
14958
  if (cwd === undefined || cwd.length === 0)
14656
14959
  return;
14657
14960
  const absoluteInput = isAbsolute6(cwd);
14658
- const candidate = absoluteInput ? cwd : resolve6(setup.cwd, cwd);
14961
+ const candidate = absoluteInput ? cwd : resolve7(setup.cwd, cwd);
14659
14962
  if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
14660
14963
  throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
14661
14964
  }
14662
14965
  const candidateRealPath = existingRealPath(candidate, "cwd");
14663
14966
  const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
14664
14967
  if (worktreeRelative !== undefined)
14665
- return resolve6(setup.worktreeRoot, worktreeRelative);
14968
+ return resolve7(setup.worktreeRoot, worktreeRelative);
14666
14969
  if (!isAbsolute6(cwd)) {
14667
14970
  throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
14668
14971
  }
@@ -14671,9 +14974,9 @@ function resolveWorktreeStageCwd(cwd, setup) {
14671
14974
  }
14672
14975
  const repositoryRelative = absoluteInput ? relativePathWithin(repositoryRoot, candidateRealPath) : undefined;
14673
14976
  if (repositoryRelative === undefined) {
14674
- throw new Error(`atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
14977
+ throw new Error(repositoryRoot === worktreeRoot ? `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}, which belongs to a different repository than the invoking cwd; choose a cwd inside the worktree, or omit cwd.` : `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
14675
14978
  }
14676
- const mappedCwd = resolve6(setup.worktreeRoot, repositoryRelative);
14979
+ const mappedCwd = resolve7(setup.worktreeRoot, repositoryRelative);
14677
14980
  const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
14678
14981
  if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
14679
14982
  throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
@@ -14684,7 +14987,7 @@ var init_worktree_cwd = () => {};
14684
14987
 
14685
14988
  // dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts
14686
14989
  import { existsSync as existsSync3 } from "node:fs";
14687
- import { isAbsolute as isAbsolute7, resolve as resolve7 } from "node:path";
14990
+ import { isAbsolute as isAbsolute7, resolve as resolve8 } from "node:path";
14688
14991
  function normalizeTaskContexts(previous) {
14689
14992
  if (previous === undefined)
14690
14993
  return [];
@@ -14737,7 +15040,7 @@ function taskPrevious(options) {
14737
15040
  function resolveWorkflowPath(filePath, baseDir) {
14738
15041
  if (isAbsolute7(filePath))
14739
15042
  return filePath;
14740
- return resolve7(baseDir ?? process.cwd(), filePath);
15043
+ return resolve8(baseDir ?? process.cwd(), filePath);
14741
15044
  }
14742
15045
  function taskBaseDir(options) {
14743
15046
  if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
@@ -14892,7 +15195,7 @@ function taskWithSharedDefaults(taskOptions, options) {
14892
15195
  var init_executor_task_prompts = () => {};
14893
15196
 
14894
15197
  // dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
14895
- import { isAbsolute as isAbsolute8, join as join11, resolve as resolve8 } from "node:path";
15198
+ import { isAbsolute as isAbsolute8, join as join12, resolve as resolve9 } from "node:path";
14896
15199
  import { CONFIG_DIR_NAME } from "@bastani/atomic";
14897
15200
  function positiveConcurrency(value2) {
14898
15201
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < 1)
@@ -15045,10 +15348,10 @@ function workflowInvocationMetadata(inputDefaults, workflowInvocationCwd, cache,
15045
15348
  function resolvedTaskCwd(cwd, workflowInvocationCwd) {
15046
15349
  if (cwd === undefined)
15047
15350
  return;
15048
- return isAbsolute8(cwd) ? cwd : resolve8(workflowInvocationCwd, cwd);
15351
+ return isAbsolute8(cwd) ? cwd : resolve9(workflowInvocationCwd, cwd);
15049
15352
  }
15050
15353
  function taskWorktreeOutputsRoot(runId) {
15051
- return join11(workflowArtifactRunPath(runId), "task-outputs");
15354
+ return join12(workflowArtifactRunPath(runId), "task-outputs");
15052
15355
  }
15053
15356
  function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCwd = process.cwd(), symlinkDirectories) {
15054
15357
  if (options.worktree !== true && !tasks.some((task) => task.worktree === true)) {
@@ -15058,7 +15361,7 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
15058
15361
  throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
15059
15362
  }
15060
15363
  const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
15061
- const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve8(workflowInvocationCwd, explicitCwd);
15364
+ const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve9(workflowInvocationCwd, explicitCwd);
15062
15365
  const conflict = findWorktreeTaskCwdConflict(tasks.map((task) => ({ agent: task.name, cwd: resolvedTaskCwd(task.cwd, workflowInvocationCwd) })), sharedCwd);
15063
15366
  if (conflict !== undefined)
15064
15367
  throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
@@ -15073,9 +15376,9 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
15073
15376
  tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index].agentCwd })),
15074
15377
  setup,
15075
15378
  agents,
15076
- diffsDir: join11(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
15379
+ diffsDir: join12(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
15077
15380
  outputIsolations: tasks.map((_, index) => ({
15078
- baseDir: join11(trustedRoot, runId, scope, String(index)),
15381
+ baseDir: join12(trustedRoot, runId, scope, String(index)),
15079
15382
  trustedRoot
15080
15383
  }))
15081
15384
  };
@@ -16802,8 +17105,12 @@ function createStageControlRegistry() {
16802
17105
  }
16803
17106
  await disposeEntries(entries);
16804
17107
  },
16805
- async releaseIdle(runId) {
16806
- for (const [stageId, entry] of [..._byRun.get(runId) ?? []]) {
17108
+ async releaseIdle(runId, only) {
17109
+ const runMap = _byRun.get(runId);
17110
+ const entries = only === undefined ? [...runMap ?? []] : [[only, runMap?.get(only)]];
17111
+ for (const [stageId, entry] of entries) {
17112
+ if (entry === undefined)
17113
+ continue;
16807
17114
  try {
16808
17115
  await releaseIdleEntry(runId, stageId, entry);
16809
17116
  } catch (error) {
@@ -16864,7 +17171,7 @@ var init_possible_stages = __esm(() => {
16864
17171
 
16865
17172
  // dist/builtin/workflows/src/workers/admission-host.ts
16866
17173
  import { execFile, execFileSync } from "node:child_process";
16867
- import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
17174
+ import { readdirSync as readdirSync4, readFileSync as readFileSync4 } from "node:fs";
16868
17175
  import { readFile } from "node:fs/promises";
16869
17176
  import { hostname } from "node:os";
16870
17177
  function admissionBootIdentity() {
@@ -16895,7 +17202,7 @@ function workerProcessExited(pid, final = false) {
16895
17202
  return true;
16896
17203
  if (process.platform === "linux") {
16897
17204
  try {
16898
- const stat = readFileSync2(`/proc/${pid}/stat`, "utf8");
17205
+ const stat = readFileSync4(`/proc/${pid}/stat`, "utf8");
16899
17206
  return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
16900
17207
  } catch {
16901
17208
  return admissionProcessStopped(pid);
@@ -16915,7 +17222,7 @@ function scanProcessGroup(group) {
16915
17222
  let complete = true;
16916
17223
  let entries;
16917
17224
  try {
16918
- entries = readdirSync2("/proc");
17225
+ entries = readdirSync4("/proc");
16919
17226
  } catch {
16920
17227
  return { members, complete: false };
16921
17228
  }
@@ -16924,7 +17231,7 @@ function scanProcessGroup(group) {
16924
17231
  continue;
16925
17232
  let stat;
16926
17233
  try {
16927
- stat = readFileSync2(`/proc/${entry}/stat`, "utf8");
17234
+ stat = readFileSync4(`/proc/${entry}/stat`, "utf8");
16928
17235
  } catch {
16929
17236
  complete = false;
16930
17237
  continue;
@@ -53663,10 +53970,10 @@ var init_verification_prompts = __esm(() => {
53663
53970
  // dist/builtin/workflows/builtin/pattern-artifact-root.ts
53664
53971
  import { randomUUID as randomUUID8 } from "node:crypto";
53665
53972
  import { mkdir as mkdir2 } from "node:fs/promises";
53666
- import { join as join12 } from "node:path";
53973
+ import { join as join13 } from "node:path";
53667
53974
  async function stableArtifactRoot(ctx, workflowName) {
53668
53975
  const cwd = ctx.cwd ?? process.cwd();
53669
- const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join12(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID8()}`));
53976
+ const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join13(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID8()}`));
53670
53977
  await mkdir2(artifactDir, { recursive: true });
53671
53978
  return artifactDir;
53672
53979
  }
@@ -53706,7 +54013,7 @@ function fold_usage(results) {
53706
54013
 
53707
54014
  // dist/builtin/workflows/builtin/adversarial-verification-runner.ts
53708
54015
  import { readFile as readFile2, writeFile } from "node:fs/promises";
53709
- import { join as join13 } from "node:path";
54016
+ import { join as join14 } from "node:path";
53710
54017
  import { Type as Type4 } from "typebox";
53711
54018
  function isRecord3(value2) {
53712
54019
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
@@ -53801,8 +54108,8 @@ async function writeInvalid(path, stage) {
53801
54108
  }
53802
54109
  async function runAdversarialVerification(ctx) {
53803
54110
  const root = await stableArtifactRoot(ctx, "adversarial-verification");
53804
- const criteriaPath = join13(root, "criteria.md");
53805
- const candidatePath = join13(root, "candidate.md");
54111
+ const criteriaPath = join14(root, "criteria.md");
54112
+ const candidatePath = join14(root, "candidate.md");
53806
54113
  const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
53807
54114
  await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
53808
54115
  await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
@@ -53834,7 +54141,7 @@ async function runAdversarialVerification(ctx) {
53834
54141
  criterion,
53835
54142
  verifierIndex: index + 1,
53836
54143
  name,
53837
- artifactPath: join13(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
54144
+ artifactPath: join14(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
53838
54145
  });
53839
54146
  }
53840
54147
  }
@@ -53887,8 +54194,8 @@ async function runAdversarialVerification(ctx) {
53887
54194
  const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
53888
54195
  finalDecision = decision;
53889
54196
  finalMean = meanScore(scoreReports);
53890
- scoreTablePath = join13(root, `verification-summary-${round}.json`);
53891
- reviewReportPath = join13(root, `review-${round}.json`);
54197
+ scoreTablePath = join14(root, `verification-summary-${round}.json`);
54198
+ reviewReportPath = join14(root, `review-${round}.json`);
53892
54199
  const summary = {
53893
54200
  scores: scoreReports,
53894
54201
  mean: finalMean,
@@ -54069,7 +54376,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
54069
54376
 
54070
54377
  // dist/builtin/workflows/builtin/classify-and-act-runner.ts
54071
54378
  import { writeFile as writeFile2 } from "node:fs/promises";
54072
- import { join as join14 } from "node:path";
54379
+ import { join as join15 } from "node:path";
54073
54380
  import { Type as Type6 } from "typebox";
54074
54381
  function safeName(value2) {
54075
54382
  const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -54109,7 +54416,7 @@ async function runClassifyAndAct(ctx) {
54109
54416
  const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
54110
54417
  const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
54111
54418
  const category = fallback?.category ?? exactCategory;
54112
- const classificationPath = join14(artifactDir, "classification.json");
54419
+ const classificationPath = join15(artifactDir, "classification.json");
54113
54420
  await writeFile2(classificationPath, JSON.stringify({
54114
54421
  proposed_category: proposedCategory,
54115
54422
  selected_category: category,
@@ -54119,7 +54426,7 @@ async function runClassifyAndAct(ctx) {
54119
54426
  fallback_used: needsFallback,
54120
54427
  fallback_mode: fallback?.fallbackMode ?? "none"
54121
54428
  }, null, 2));
54122
- const actionPath = join14(artifactDir, `action-${safeName(category)}.md`);
54429
+ const actionPath = join15(artifactDir, `action-${safeName(category)}.md`);
54123
54430
  const action = await ctx.task(`action-${safeName(category)}`, {
54124
54431
  tools: actionTools(category),
54125
54432
  prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
@@ -54259,7 +54566,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
54259
54566
 
54260
54567
  // dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
54261
54568
  import { writeFile as writeFile3 } from "node:fs/promises";
54262
- import { join as join15 } from "node:path";
54569
+ import { join as join16 } from "node:path";
54263
54570
  import { Type as Type8 } from "typebox";
54264
54571
  function safeName2(value2, index) {
54265
54572
  const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -54290,9 +54597,9 @@ async function runFanOutAndSynthesize(ctx) {
54290
54597
  context: "fresh"
54291
54598
  });
54292
54599
  const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
54293
- const partitionPath = join15(artifactDir, "partition-plan.json");
54600
+ const partitionPath = join16(artifactDir, "partition-plan.json");
54294
54601
  await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
54295
- const branchPaths = partitions.map((partition, index) => join15(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
54602
+ const branchPaths = partitions.map((partition, index) => join16(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
54296
54603
  const steps = partitions.map((partition, index) => ({
54297
54604
  name: `branch-${safeName2(partition.label, index)}`,
54298
54605
  prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
@@ -54302,13 +54609,13 @@ async function runFanOutAndSynthesize(ctx) {
54302
54609
  outputMode: "file-only"
54303
54610
  }));
54304
54611
  await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
54305
- const manifestPath = join15(artifactDir, "manifest.json");
54612
+ const manifestPath = join16(artifactDir, "manifest.json");
54306
54613
  await writeFile3(manifestPath, JSON.stringify({
54307
54614
  task: ctx.inputs.prompt,
54308
54615
  partition_plan: partitionPath,
54309
54616
  branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
54310
54617
  }, null, 2));
54311
- const synthesisPath = join15(artifactDir, "synthesis.md");
54618
+ const synthesisPath = join16(artifactDir, "synthesis.md");
54312
54619
  const synthesis = await ctx.task("synthesize", {
54313
54620
  prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
54314
54621
  context: "fresh",
@@ -54473,7 +54780,7 @@ var init_generate_and_filter_prompts = __esm(() => {
54473
54780
 
54474
54781
  // dist/builtin/workflows/builtin/generate-and-filter-runner.ts
54475
54782
  import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
54476
- import { join as join16 } from "node:path";
54783
+ import { join as join17 } from "node:path";
54477
54784
  import { Type as Type10 } from "typebox";
54478
54785
  function isRecord4(value2) {
54479
54786
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
@@ -54492,7 +54799,7 @@ function judgeDecision(value2) {
54492
54799
  }
54493
54800
  async function runGenerateAndFilter(ctx) {
54494
54801
  const root = await stableArtifactRoot(ctx, "generate-and-filter");
54495
- const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join16(root, `candidate-${index + 1}.md`));
54802
+ const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join17(root, `candidate-${index + 1}.md`));
54496
54803
  const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
54497
54804
  await ctx.parallel(candidatePaths.map((path, index) => ({
54498
54805
  name: `generate-${index + 1}`,
@@ -54501,9 +54808,9 @@ async function runGenerateAndFilter(ctx) {
54501
54808
  output: path,
54502
54809
  outputMode: "file-only"
54503
54810
  })), { concurrency: ctx.inputs.max_concurrency, failFast: false });
54504
- const manifestPath = join16(root, "manifest.json");
54811
+ const manifestPath = join17(root, "manifest.json");
54505
54812
  await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
54506
- const filterPath = join16(root, "filter.json");
54813
+ const filterPath = join17(root, "filter.json");
54507
54814
  const filtered = await ctx.task("dedupe-and-filter", {
54508
54815
  prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
54509
54816
  context: "fresh",
@@ -54520,7 +54827,7 @@ async function runGenerateAndFilter(ctx) {
54520
54827
  let judgePath = null;
54521
54828
  let decisionPath = filterPath;
54522
54829
  if (ctx.inputs.use_judge) {
54523
- judgePath = join16(root, "judge.json");
54830
+ judgePath = join17(root, "judge.json");
54524
54831
  const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
54525
54832
  const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
54526
54833
  const judged = await ctx.task("judge", {
@@ -54536,7 +54843,7 @@ async function runGenerateAndFilter(ctx) {
54536
54843
  shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
54537
54844
  decisionPath = judgePath;
54538
54845
  }
54539
- const finalPath = join16(root, "shortlist.md");
54846
+ const finalPath = join17(root, "shortlist.md");
54540
54847
  const finalShortlist = await ctx.task("final-shortlist", {
54541
54848
  prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
54542
54849
  context: "fresh",
@@ -55065,7 +55372,7 @@ var init_review_convergence = __esm(() => {
55065
55372
 
55066
55373
  // dist/builtin/workflows/builtin/goal-artifacts.ts
55067
55374
  import { writeFile as writeFile5 } from "node:fs/promises";
55068
- import { join as join17 } from "node:path";
55375
+ import { join as join18 } from "node:path";
55069
55376
  function artifactSafeName(value2) {
55070
55377
  const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
55071
55378
  return safe.length > 0 ? safe : "artifact";
@@ -55076,7 +55383,7 @@ function withoutTurn(value2) {
55076
55383
  return copy;
55077
55384
  }
55078
55385
  async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
55079
- const artifactPath = join17(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
55386
+ const artifactPath = join18(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
55080
55387
  await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
55081
55388
  `, { encoding: "utf8" });
55082
55389
  return artifactPath;
@@ -55085,7 +55392,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
55085
55392
  reviewer: review.reviewer,
55086
55393
  findings: review.findings
55087
55394
  }))), reverification = []) {
55088
- const artifactPath = join17(artifactDir, "review-round-latest.json");
55395
+ const artifactPath = join18(artifactDir, "review-round-latest.json");
55089
55396
  const visibleReviews = reviews.map(withoutTurn);
55090
55397
  await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
55091
55398
  `, { encoding: "utf8" });
@@ -55315,7 +55622,7 @@ var init_goal_review = __esm(() => {
55315
55622
  // dist/builtin/workflows/builtin/goal-ledger.ts
55316
55623
  import { randomUUID as randomUUID9 } from "node:crypto";
55317
55624
  import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
55318
- import { dirname as dirname9, join as join18 } from "node:path";
55625
+ import { dirname as dirname10, join as join19 } from "node:path";
55319
55626
  import { isDeepStrictEqual } from "node:util";
55320
55627
  function withoutTurn2(value2) {
55321
55628
  const copy = { ...value2 };
@@ -55340,7 +55647,7 @@ function modelVisibleLedger(ledger) {
55340
55647
  };
55341
55648
  }
55342
55649
  function goalLedgerStatePath(ledgerPath) {
55343
- return join18(dirname9(ledgerPath), LEDGER_STATE_FILENAME);
55650
+ return join19(dirname10(ledgerPath), LEDGER_STATE_FILENAME);
55344
55651
  }
55345
55652
  function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
55346
55653
  ledger.lifecycle.push({
@@ -55416,7 +55723,7 @@ function recoverLegacyExecutionInterruption(ledger) {
55416
55723
  return true;
55417
55724
  }
55418
55725
  async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
55419
- const ledgerPath = join18(artifactDir, LEDGER_FILENAME);
55726
+ const ledgerPath = join19(artifactDir, LEDGER_FILENAME);
55420
55727
  const existing = await readExistingGoalLedger(ledgerPath);
55421
55728
  if (existing !== undefined) {
55422
55729
  if (recoverLegacyExecutionInterruption(existing))
@@ -55923,7 +56230,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
55923
56230
  });
55924
56231
 
55925
56232
  // dist/builtin/workflows/builtin/goal-runner.ts
55926
- import { join as join19 } from "node:path";
56233
+ import { join as join20 } from "node:path";
55927
56234
  function positiveInteger(value2, fallback) {
55928
56235
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
55929
56236
  return fallback;
@@ -55974,7 +56281,7 @@ async function runGoalWorkflow(ctx, options) {
55974
56281
  appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
55975
56282
  await writeGoalLedger(ledgerPath, ledger);
55976
56283
  }
55977
- const orchestratorReceiptPath = join19(artifactDir, "orchestrator-receipt.md");
56284
+ const orchestratorReceiptPath = join20(artifactDir, "orchestrator-receipt.md");
55978
56285
  const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
55979
56286
  const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
55980
56287
  ledger,
@@ -56045,7 +56352,7 @@ async function runGoalWorkflow(ctx, options) {
56045
56352
  const reviewerName = result.name ?? result.stageName;
56046
56353
  const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
56047
56354
  const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
56048
- const reviewArtifactPath = join19(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
56355
+ const reviewArtifactPath = join20(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
56049
56356
  const record = reviewDecisionToRecord({
56050
56357
  turn,
56051
56358
  reviewer: normalizedReviewerName,
@@ -56248,7 +56555,7 @@ var init_goal = __esm(() => {
56248
56555
  }),
56249
56556
  git_worktree_dir: Type15.String({
56250
56557
  default: "",
56251
- description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Must start inside a Git repo; absolute paths are used as-is, relative paths resolve from the repo root, existing Git worktrees from the invoking repository are reused/shared as-is, and missing paths are created from base_branch."
56558
+ description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
56252
56559
  }),
56253
56560
  create_pr: Type15.Boolean({
56254
56561
  default: false,
@@ -56366,7 +56673,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
56366
56673
 
56367
56674
  // dist/builtin/workflows/builtin/loop-until-done-runner.ts
56368
56675
  import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
56369
- import { join as join20 } from "node:path";
56676
+ import { join as join21 } from "node:path";
56370
56677
  import { Type as Type16 } from "typebox";
56371
56678
  function progressCurve(entries) {
56372
56679
  return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
@@ -56449,18 +56756,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
56449
56756
  }
56450
56757
  async function runLoopUntilDone(ctx) {
56451
56758
  const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
56452
- const iterationsDir = join20(artifactDir, "iterations");
56453
- const evaluationsDir = join20(artifactDir, "evaluations");
56759
+ const iterationsDir = join21(artifactDir, "iterations");
56760
+ const evaluationsDir = join21(artifactDir, "evaluations");
56454
56761
  await mkdir3(iterationsDir, { recursive: true });
56455
56762
  await mkdir3(evaluationsDir, { recursive: true });
56456
- const ledgerPath = join20(artifactDir, "progress-ledger.json");
56763
+ const ledgerPath = join21(artifactDir, "progress-ledger.json");
56457
56764
  const entries = [];
56458
56765
  const iterationArtifactPaths = [];
56459
56766
  const evaluationArtifactPaths = [];
56460
56767
  await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
56461
56768
  for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
56462
- const iterationPath = join20(iterationsDir, `iteration-${iteration}.md`);
56463
- const evaluationPath = join20(evaluationsDir, `evaluation-${iteration}.json`);
56769
+ const iterationPath = join21(iterationsDir, `iteration-${iteration}.md`);
56770
+ const evaluationPath = join21(evaluationsDir, `evaluation-${iteration}.json`);
56464
56771
  iterationArtifactPaths.push(iterationPath);
56465
56772
  evaluationArtifactPaths.push(evaluationPath);
56466
56773
  await ctx.task(`iteration-${iteration}`, {
@@ -56509,7 +56816,7 @@ async function runLoopUntilDone(ctx) {
56509
56816
  await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
56510
56817
  if (decision.done) {
56511
56818
  const report = progressReport(entries);
56512
- const resultPath = join20(artifactDir, "result.md");
56819
+ const resultPath = join21(artifactDir, "result.md");
56513
56820
  const final = await ctx.task("completion-summary", {
56514
56821
  prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
56515
56822
  context: "fresh",
@@ -56626,9 +56933,9 @@ var init_loop_until_done = __esm(() => {
56626
56933
 
56627
56934
  // dist/builtin/workflows/builtin/open-claude-design-utils.ts
56628
56935
  import { spawnSync as spawnSync3 } from "node:child_process";
56629
- import { mkdirSync as mkdirSync5 } from "node:fs";
56936
+ import { mkdirSync as mkdirSync6 } from "node:fs";
56630
56937
  import { tmpdir, userInfo } from "node:os";
56631
- import { join as join21 } from "node:path";
56938
+ import { join as join22 } from "node:path";
56632
56939
  import { Type as Type18 } from "typebox";
56633
56940
  import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
56634
56941
  function taggedPrompt3(sections) {
@@ -56671,32 +56978,32 @@ function tmpArtifactBase() {
56671
56978
  try {
56672
56979
  user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
56673
56980
  } catch {}
56674
- return join21(tmpdir(), `open-claude-design-${user}`);
56981
+ return join22(tmpdir(), `open-claude-design-${user}`);
56675
56982
  }
56676
56983
  function prepareArtifactDir(cwd = process.cwd()) {
56677
56984
  const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
56678
56985
  const tmpCandidates = [
56679
- join21(tmpArtifactBase(), runId),
56680
- join21(tmpdir(), "open-claude-design", runId)
56986
+ join22(tmpArtifactBase(), runId),
56987
+ join22(tmpdir(), "open-claude-design", runId)
56681
56988
  ];
56682
- const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join21(cwd, "specs", "design", runId), ...tmpCandidates];
56989
+ const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join22(cwd, "specs", "design", runId), ...tmpCandidates];
56683
56990
  for (const candidate of candidates) {
56684
56991
  try {
56685
- mkdirSync5(candidate, { recursive: true });
56992
+ mkdirSync6(candidate, { recursive: true });
56686
56993
  return {
56687
56994
  runId,
56688
56995
  artifactDir: candidate,
56689
- previewPath: join21(candidate, "preview.html"),
56690
- specPath: join21(candidate, "spec.html")
56996
+ previewPath: join22(candidate, "preview.html"),
56997
+ specPath: join22(candidate, "spec.html")
56691
56998
  };
56692
56999
  } catch {}
56693
57000
  }
56694
- const fallback = join21(tmpArtifactBase(), runId);
57001
+ const fallback = join22(tmpArtifactBase(), runId);
56695
57002
  return {
56696
57003
  runId,
56697
57004
  artifactDir: fallback,
56698
- previewPath: join21(fallback, "preview.html"),
56699
- specPath: join21(fallback, "spec.html")
57005
+ previewPath: join22(fallback, "preview.html"),
57006
+ specPath: join22(fallback, "spec.html")
56700
57007
  };
56701
57008
  }
56702
57009
  function ensureAgentBrowser() {
@@ -57030,8 +57337,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
57030
57337
  });
57031
57338
 
57032
57339
  // dist/builtin/workflows/builtin/open-claude-design-setup.ts
57033
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync3 } from "node:fs";
57034
- import { join as join22 } from "node:path";
57340
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
57341
+ import { join as join23 } from "node:path";
57035
57342
  function renderDiscoveryContext(discovery) {
57036
57343
  return [
57037
57344
  `Confirmed design brief: ${discovery.brief}`,
@@ -57096,10 +57403,10 @@ async function runDiscoveryAndInit(args) {
57096
57403
  };
57097
57404
  }
57098
57405
  function designContextPath(artifactDir) {
57099
- return join22(artifactDir, DESIGN_CONTEXT_FILENAME);
57406
+ return join23(artifactDir, DESIGN_CONTEXT_FILENAME);
57100
57407
  }
57101
57408
  function referencesBriefPath(artifactDir) {
57102
- return join22(artifactDir, REFERENCES_BRIEF_FILENAME);
57409
+ return join23(artifactDir, REFERENCES_BRIEF_FILENAME);
57103
57410
  }
57104
57411
  function buildReferenceDiscoveryPrompt(args) {
57105
57412
  const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
@@ -57125,8 +57432,8 @@ function buildReferenceDiscoveryPrompt(args) {
57125
57432
  [
57126
57433
  "Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
57127
57434
  "From each gallery, choose 1-3 fitting designs and CLICK INTO each actual live or project-detail page; do not capture only the grid or thumbnail.",
57128
- `Capture motion across the entire page: start \`agent-browser record start ${join22(args.artifactDir, "ref-<site>-<n>.webm")}\`, scroll smoothly in small increments with waits (using repeated \`agent-browser scroll down 600\` or \`agent-browser mouse wheel 600\`) so animations fire and lazy content loads, then run \`agent-browser record stop\`.`,
57129
- `Also run \`agent-browser screenshot ${join22(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
57435
+ `Capture motion across the entire page: start \`agent-browser record start ${join23(args.artifactDir, "ref-<site>-<n>.webm")}\`, scroll smoothly in small increments with waits (using repeated \`agent-browser scroll down 600\` or \`agent-browser mouse wheel 600\`) so animations fire and lazy content loads, then run \`agent-browser record stop\`.`,
57436
+ `Also run \`agent-browser screenshot ${join23(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
57130
57437
  "Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
57131
57438
  "Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
57132
57439
  "Use ask_user_question to ask which reference direction they prefer, offering 2-4 strongest options plus `None of these fit`. If none fit, ask them to provide a reference image, screenshot, URL, or local file path and record the answer.",
@@ -57151,8 +57458,8 @@ function buildReferenceDiscoveryPrompt(args) {
57151
57458
  }
57152
57459
  function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
57153
57460
  try {
57154
- mkdirSync6(artifactDir, { recursive: true });
57155
- writeFileSync3(filePath, `${content}
57461
+ mkdirSync7(artifactDir, { recursive: true });
57462
+ writeFileSync4(filePath, `${content}
57156
57463
  `);
57157
57464
  } catch (error) {
57158
57465
  const detail = error instanceof Error ? error.message : String(error);
@@ -57703,7 +58010,7 @@ var init_ralph_review_gate = __esm(() => {
57703
58010
 
57704
58011
  // dist/builtin/workflows/builtin/ralph-core.ts
57705
58012
  import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
57706
- import { dirname as dirname10, join as join23 } from "node:path";
58013
+ import { dirname as dirname11, join as join24 } from "node:path";
57707
58014
  import { Type as Type20 } from "typebox";
57708
58015
  function taggedPrompt4(sections) {
57709
58016
  return sections.map(([tag, content]) => {
@@ -57743,11 +58050,11 @@ function slugifyResearchTopic(prompt) {
57743
58050
  }
57744
58051
  function defaultResearchPath(prompt, now = new Date) {
57745
58052
  const date = now.toISOString().slice(0, 10);
57746
- return join23(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
58053
+ return join24(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
57747
58054
  }
57748
58055
  async function createImplementationNotesFile(prompt, runId) {
57749
58056
  const notesDir = await createWorkflowArtifactDirectory(runId);
57750
- const notesPath = join23(notesDir, IMPLEMENTATION_NOTES_FILENAME);
58057
+ const notesPath = join24(notesDir, IMPLEMENTATION_NOTES_FILENAME);
57751
58058
  const initialNotes = [
57752
58059
  "# Implementation Notes",
57753
58060
  "",
@@ -57768,7 +58075,7 @@ async function createImplementationNotesFile(prompt, runId) {
57768
58075
  }
57769
58076
  async function createQaEvidenceVideoPath(runId) {
57770
58077
  const qaDir = await createWorkflowArtifactDirectory(runId);
57771
- return join23(qaDir, QA_E2E_VIDEO_FILENAME);
58078
+ return join24(qaDir, QA_E2E_VIDEO_FILENAME);
57772
58079
  }
57773
58080
  function renderQaE2eVideoGuidance(qaVideoPath) {
57774
58081
  return [
@@ -57834,7 +58141,7 @@ function artifactSafeName2(value2) {
57834
58141
  return safe.length > 0 ? safe : "artifact";
57835
58142
  }
57836
58143
  async function writeJsonArtifact(path, content) {
57837
- await mkdir4(dirname10(path), { recursive: true });
58144
+ await mkdir4(dirname11(path), { recursive: true });
57838
58145
  await writeFile8(path, `${JSON.stringify(content, null, 2)}
57839
58146
  `, {
57840
58147
  encoding: "utf8"
@@ -58172,7 +58479,7 @@ var init_ralph_models = __esm(() => {
58172
58479
 
58173
58480
  // dist/builtin/workflows/builtin/ralph-runner.ts
58174
58481
  import { existsSync as existsSync4 } from "node:fs";
58175
- import { join as join24, resolve as resolve9 } from "node:path";
58482
+ import { join as join25, resolve as resolve10 } from "node:path";
58176
58483
  async function runRalphWorkflow(ctx, options) {
58177
58484
  const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
58178
58485
  let latestReviewReportPath;
@@ -58184,7 +58491,7 @@ async function runRalphWorkflow(ctx, options) {
58184
58491
  let finalPrReport;
58185
58492
  const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
58186
58493
  const workflowPrompt = prompt;
58187
- const workflowResearchPath = resolve9(workflowStartCwd, defaultResearchPath(workflowPrompt));
58494
+ const workflowResearchPath = resolve10(workflowStartCwd, defaultResearchPath(workflowPrompt));
58188
58495
  const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
58189
58496
  const qaVideoPath = await createQaEvidenceVideoPath(runId);
58190
58497
  const artifactDir = await createWorkflowArtifactDirectory(runId);
@@ -58233,7 +58540,7 @@ async function runRalphWorkflow(ctx, options) {
58233
58540
  const researchPath = workflowResearchPath;
58234
58541
  finalResearchPath = researchPath;
58235
58542
  finalPlanPath = researchPath;
58236
- const orchestratorReportPath = join24(artifactDir, "orchestrator-report.md");
58543
+ const orchestratorReportPath = join25(artifactDir, "orchestrator-report.md");
58237
58544
  const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
58238
58545
  const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
58239
58546
  ["acceptance_criteria", keepContext(acceptanceCriteria)],
@@ -58369,7 +58676,7 @@ Read it before implementation or delegation because it is the primary current im
58369
58676
  diagnostics: parsed.diagnostics,
58370
58677
  allowFinalActionRemaining: createPr
58371
58678
  });
58372
- const artifactPath = join24(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
58679
+ const artifactPath = join25(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
58373
58680
  await writeJsonArtifact(artifactPath, {
58374
58681
  reviewer,
58375
58682
  decision: parsed.decision,
@@ -58425,7 +58732,7 @@ Read it before implementation or delegation because it is the primary current im
58425
58732
  usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
58426
58733
  }));
58427
58734
  }
58428
- latestReviewReportPath = await writeJsonArtifact(join24(artifactDir, "review-round-latest.json"), {
58735
+ latestReviewReportPath = await writeJsonArtifact(join25(artifactDir, "review-round-latest.json"), {
58429
58736
  convergence_decision: roundConvergenceDecision,
58430
58737
  convergence: convergenceEntries,
58431
58738
  consolidated_findings: reverified.batch,
@@ -58574,7 +58881,7 @@ var init_ralph = __esm(() => {
58574
58881
  }),
58575
58882
  git_worktree_dir: Type21.String({
58576
58883
  default: "",
58577
- description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Must start inside a Git repo; absolute paths are used as-is, relative paths resolve from the repo root, existing Git worktrees from the invoking repository are reused/shared as-is, and missing paths are created from base_branch."
58884
+ description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
58578
58885
  }),
58579
58886
  create_pr: Type21.Boolean({
58580
58887
  default: false,
@@ -58794,7 +59101,7 @@ var init_tournament_prompts = __esm(() => {
58794
59101
 
58795
59102
  // dist/builtin/workflows/builtin/tournament-runner.ts
58796
59103
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
58797
- import { join as join25, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve10 } from "node:path";
59104
+ import { join as join26, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve11 } from "node:path";
58798
59105
  import { Type as Type22 } from "typebox";
58799
59106
  function serializableObject2(value2) {
58800
59107
  if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
@@ -58831,8 +59138,8 @@ function criterionSlug(id) {
58831
59138
  }
58832
59139
  function judgeArtifactPath(judgesDir, job, criterionIndex) {
58833
59140
  const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
58834
- const root = resolve10(judgesDir);
58835
- const path = resolve10(judgesDir, filename);
59141
+ const root = resolve11(judgesDir);
59142
+ const path = resolve11(judgesDir, filename);
58836
59143
  const fromRoot = relative5(root, path);
58837
59144
  if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
58838
59145
  throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
@@ -58883,16 +59190,16 @@ function combineUsage(totals) {
58883
59190
  }
58884
59191
  async function runTournament(ctx) {
58885
59192
  const artifactDir = await stableArtifactRoot(ctx, "tournament");
58886
- const attemptsDir = join25(artifactDir, "attempts");
59193
+ const attemptsDir = join26(artifactDir, "attempts");
58887
59194
  const numAttempts = ctx.inputs.num_attempts ?? 4;
58888
59195
  const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
58889
59196
  const nEvaluations = ctx.inputs.n_evaluations ?? 2;
58890
59197
  const pivotCount = ctx.inputs.pivots ?? 1;
58891
59198
  const seed = ctx.inputs.seed ?? 0;
58892
- const judgesDir = join25(artifactDir, "judges");
59199
+ const judgesDir = join26(artifactDir, "judges");
58893
59200
  await mkdir5(attemptsDir, { recursive: true });
58894
59201
  await mkdir5(judgesDir, { recursive: true });
58895
- const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join25(attemptsDir, `attempt-${index + 1}.md`));
59202
+ const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join26(attemptsDir, `attempt-${index + 1}.md`));
58896
59203
  const models = ctx.inputs.models;
58897
59204
  const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
58898
59205
  name: `attempt-${index + 1}`,
@@ -59057,7 +59364,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
59057
59364
  const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
59058
59365
  const budgetPivots = Math.min(pivotCount, entrants.length);
59059
59366
  const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
59060
- const comparisonPath = join25(artifactDir, "comparisons.json");
59367
+ const comparisonPath = join26(artifactDir, "comparisons.json");
59061
59368
  const assignment = modelAssignment(entrants, models);
59062
59369
  const phaseUsage = {
59063
59370
  attempts: fold_usage(attemptResults),
@@ -59093,7 +59400,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
59093
59400
  await writeLedger(fold_usage([]));
59094
59401
  const winner = ranking[0];
59095
59402
  const winnerEntrant = entrants[winner.index];
59096
- const resultPath = join25(artifactDir, "winner.md");
59403
+ const resultPath = join26(artifactDir, "winner.md");
59097
59404
  const reducer = await ctx.task("comparisons-reducer", {
59098
59405
  prompt: renderComparisonsReducerPrompt({
59099
59406
  task: ctx.inputs.prompt,
@@ -59999,7 +60306,7 @@ class SqlPoolQueue {
59999
60306
  throw new Error("Stale pool coordinator authority", { cause: error });
60000
60307
  throw error;
60001
60308
  });
60002
- const row = await this.current(tx, lease, token);
60309
+ const row = await this.current(tx, lease, token, true);
60003
60310
  if (row.epoch !== lease.epoch)
60004
60311
  throw new Error(STALE_WORK_LEASE);
60005
60312
  assertSession();
@@ -62233,7 +62540,7 @@ function isBrokerStatusReport(value2) {
62233
62540
 
62234
62541
  // dist/builtin/intercom/broker/paths.ts
62235
62542
  import { homedir as homedir2 } from "os";
62236
- import { join as join26 } from "path";
62543
+ import { join as join27 } from "path";
62237
62544
  function getHomeDir() {
62238
62545
  if (process.platform === "win32") {
62239
62546
  if (process.env.USERPROFILE)
@@ -62250,7 +62557,7 @@ function expandTildePath(path) {
62250
62557
  if (path === "~")
62251
62558
  return getHomeDir();
62252
62559
  if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
62253
- return join26(getHomeDir(), path.slice(2));
62560
+ return join27(getHomeDir(), path.slice(2));
62254
62561
  }
62255
62562
  return path;
62256
62563
  }
@@ -62261,31 +62568,31 @@ function getAgentDir5() {
62261
62568
  const piAgentDir = process.env.PI_CODING_AGENT_DIR;
62262
62569
  if (piAgentDir)
62263
62570
  return expandTildePath(piAgentDir);
62264
- return join26(getHomeDir(), ".atomic", "agent");
62571
+ return join27(getHomeDir(), ".atomic", "agent");
62265
62572
  }
62266
62573
  function sanitizePipeSegment(value2) {
62267
62574
  return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
62268
62575
  }
62269
62576
  function getIntercomDirPath(agentDir = getAgentDir5()) {
62270
- return join26(agentDir, "intercom");
62577
+ return join27(agentDir, "intercom");
62271
62578
  }
62272
62579
  function getBrokerPidPath(agentDir = getAgentDir5()) {
62273
- return join26(getIntercomDirPath(agentDir), "broker.pid");
62580
+ return join27(getIntercomDirPath(agentDir), "broker.pid");
62274
62581
  }
62275
62582
  function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
62276
- return join26(getIntercomDirPath(agentDir), "broker.spawn.lock");
62583
+ return join27(getIntercomDirPath(agentDir), "broker.spawn.lock");
62277
62584
  }
62278
62585
  function getBrokerLogPath(agentDir = getAgentDir5()) {
62279
- return join26(getIntercomDirPath(agentDir), "broker.log");
62586
+ return join27(getIntercomDirPath(agentDir), "broker.log");
62280
62587
  }
62281
62588
  function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
62282
- return join26(getIntercomDirPath(agentDir), "broker.starting");
62589
+ return join27(getIntercomDirPath(agentDir), "broker.starting");
62283
62590
  }
62284
62591
  function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
62285
62592
  if (platform === "win32") {
62286
62593
  return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
62287
62594
  }
62288
- return join26(getIntercomDirPath(agentDir), "broker.sock");
62595
+ return join27(getIntercomDirPath(agentDir), "broker.sock");
62289
62596
  }
62290
62597
  var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
62291
62598
  var init_paths = () => {};
@@ -63969,11 +64276,11 @@ var init_client = __esm(() => {
63969
64276
  var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
63970
64277
 
63971
64278
  // dist/builtin/intercom/broker/start-announcement.ts
63972
- import { readFileSync as readFileSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
64279
+ import { readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
63973
64280
  function readBrokerStartAnnouncement(announcement) {
63974
64281
  let text;
63975
64282
  try {
63976
- text = readFileSync3(announcement.path, "utf-8");
64283
+ text = readFileSync5(announcement.path, "utf-8");
63977
64284
  } catch {
63978
64285
  return;
63979
64286
  }
@@ -63992,26 +64299,26 @@ var init_start_announcement = () => {};
63992
64299
  // dist/builtin/intercom/broker/spawn.ts
63993
64300
  import { spawn } from "child_process";
63994
64301
  import { randomUUID as randomUUID14 } from "crypto";
63995
- import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync4, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "fs";
63996
- import { join as join27, dirname as dirname11 } from "path";
64302
+ import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync6, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
64303
+ import { join as join28, dirname as dirname12 } from "path";
63997
64304
  import { fileURLToPath as fileURLToPath4 } from "url";
63998
64305
  import { createRequire as createRequire3 } from "module";
63999
64306
  import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
64000
64307
  function isIntercomPackageRoot(dir) {
64001
- return existsSync5(join27(dir, "package.json")) && existsSync5(join27(dir, "broker"));
64308
+ return existsSync5(join28(dir, "package.json")) && existsSync5(join28(dir, "broker"));
64002
64309
  }
64003
64310
  function resolveIntercomPackageRoot(moduleHref) {
64004
- const here = dirname11(fileURLToPath4(moduleHref));
64311
+ const here = dirname12(fileURLToPath4(moduleHref));
64005
64312
  if (isIntercomPackageRoot(here))
64006
64313
  return here;
64007
- return join27(here, "..");
64314
+ return join28(here, "..");
64008
64315
  }
64009
64316
  function resolveBrokerEntrypoint(packageRoot) {
64010
- const bundled = join27(packageRoot, "broker", "broker.bundle.mjs");
64011
- return existsSync5(bundled) ? bundled : join27(packageRoot, "broker", "broker.ts");
64317
+ const bundled = join28(packageRoot, "broker", "broker.bundle.mjs");
64318
+ return existsSync5(bundled) ? bundled : join28(packageRoot, "broker", "broker.ts");
64012
64319
  }
64013
64320
  function ensurePrivateDirectory(path) {
64014
- mkdirSync7(path, { recursive: true, mode: 448 });
64321
+ mkdirSync8(path, { recursive: true, mode: 448 });
64015
64322
  if (process.platform !== "win32")
64016
64323
  chmodSync(path, 448);
64017
64324
  }
@@ -64024,14 +64331,14 @@ function getCurrentBrokerRuntime() {
64024
64331
  return isBunBinary ? "bun-binary" : "bun-source";
64025
64332
  }
64026
64333
  function requireFromExtensionDir(extensionDir) {
64027
- return createRequire3(join27(extensionDir, "package.json"));
64334
+ return createRequire3(join28(extensionDir, "package.json"));
64028
64335
  }
64029
64336
  function getJitiCliPath(extensionDir = EXTENSION_DIR) {
64030
64337
  try {
64031
64338
  const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
64032
- return join27(dirname11(jitiPackage), "lib", "jiti-cli.mjs");
64339
+ return join28(dirname12(jitiPackage), "lib", "jiti-cli.mjs");
64033
64340
  } catch {
64034
- return join27(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
64341
+ return join28(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
64035
64342
  }
64036
64343
  }
64037
64344
  function getDefaultBrokerRunnerPath(extensionDir) {
@@ -64053,7 +64360,7 @@ function quoteWindowsArg(value2) {
64053
64360
  return `"${value2.replace(/"/g, '""')}"`;
64054
64361
  }
64055
64362
  function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
64056
- return join27(intercomDir, "broker-launch.vbs");
64363
+ return join28(intercomDir, "broker-launch.vbs");
64057
64364
  }
64058
64365
  function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
64059
64366
  return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
@@ -64080,8 +64387,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
64080
64387
  `);
64081
64388
  }
64082
64389
  function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
64083
- ensurePrivateDirectory(dirname11(launcherPath));
64084
- writeFileSync5(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
64390
+ ensurePrivateDirectory(dirname12(launcherPath));
64391
+ writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
64085
64392
  return launcherPath;
64086
64393
  }
64087
64394
  function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
@@ -64124,14 +64431,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
64124
64431
  };
64125
64432
  }
64126
64433
  function resetBrokerLog(logPath = BROKER_LOG) {
64127
- ensurePrivateDirectory(dirname11(logPath));
64434
+ ensurePrivateDirectory(dirname12(logPath));
64128
64435
  try {
64129
64436
  const previous = readBrokerLogTail(logPath);
64130
64437
  closeSync3(openSync3(logPath, "w"));
64131
64438
  if (previous.length > 0) {
64132
64439
  try {
64133
64440
  const previousPath = `${logPath}.previous`;
64134
- writeFileSync5(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
64441
+ writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
64135
64442
  if (process.platform !== "win32")
64136
64443
  chmodSync(previousPath, 384);
64137
64444
  } catch {}
@@ -64275,7 +64582,7 @@ async function isBrokerRunning() {
64275
64582
  if (!existsSync5(BROKER_PID))
64276
64583
  return false;
64277
64584
  try {
64278
- const pid = parseInt(readFileSync4(BROKER_PID, "utf-8").trim(), 10);
64585
+ const pid = parseInt(readFileSync6(BROKER_PID, "utf-8").trim(), 10);
64279
64586
  if (!Number.isFinite(pid))
64280
64587
  return false;
64281
64588
  process.kill(pid, 0);
@@ -64300,7 +64607,7 @@ function handSpawnLockToBroker(pid, owner) {
64300
64607
  }
64301
64608
  function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
64302
64609
  try {
64303
- return readFileSync4(lockPath, "utf-8").startsWith(owner);
64610
+ return readFileSync6(lockPath, "utf-8").startsWith(owner);
64304
64611
  } catch {
64305
64612
  return false;
64306
64613
  }
@@ -64312,7 +64619,7 @@ function acquireSpawnLock() {
64312
64619
  ${Date.now()}
64313
64620
  `;
64314
64621
  try {
64315
- writeFileSync5(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
64622
+ writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
64316
64623
  return owner;
64317
64624
  } catch (error) {
64318
64625
  if (!(error instanceof Error) || error.code !== "EEXIST") {
@@ -64342,7 +64649,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
64342
64649
  return false;
64343
64650
  }
64344
64651
  try {
64345
- const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync4(lockPath, "utf-8").trim().split(`
64652
+ const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync6(lockPath, "utf-8").trim().split(`
64346
64653
  `);
64347
64654
  const spawnerPid = Number.parseInt(spawnerLine, 10);
64348
64655
  const createdAt = Number.parseInt(createdAtLine, 10);
@@ -64420,14 +64727,14 @@ var init_reply_waiter = __esm(() => {
64420
64727
  });
64421
64728
 
64422
64729
  // dist/builtin/intercom/config.ts
64423
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
64730
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
64424
64731
  import { getAgentConfigPaths } from "@bastani/atomic";
64425
64732
  function loadConfig() {
64426
64733
  if (!existsSync6(CONFIG_PATH)) {
64427
64734
  return { ...defaults };
64428
64735
  }
64429
64736
  try {
64430
- const raw = readFileSync5(CONFIG_PATH, "utf-8");
64737
+ const raw = readFileSync7(CONFIG_PATH, "utf-8");
64431
64738
  const parsed = JSON.parse(raw);
64432
64739
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
64433
64740
  throw new Error("Config must be a JSON object");
@@ -65010,12 +65317,12 @@ var init_sql_pool_usage = __esm(() => {
65010
65317
 
65011
65318
  // dist/builtin/workflows/src/workers/pooled-watch-trace.ts
65012
65319
  import { appendFileSync as appendFileSync2 } from "node:fs";
65013
- import { dirname as dirname12, join as join28, resolve as resolve11 } from "node:path";
65320
+ import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
65014
65321
  function configurePooledWatchTrace(journalPath, processRole) {
65015
65322
  if (setting === undefined || setting === "" || setting === "0")
65016
65323
  return;
65017
65324
  role = processRole;
65018
- file = setting === "1" ? join28(dirname12(resolve11(journalPath)), "pooled-watch-trace.jsonl") : resolve11(setting);
65325
+ file = setting === "1" ? join29(dirname13(resolve12(journalPath)), "pooled-watch-trace.jsonl") : resolve12(setting);
65019
65326
  }
65020
65327
  function tracePooledWatch(step, detail) {
65021
65328
  if (file === undefined)
@@ -65209,7 +65516,7 @@ import { fork } from "node:child_process";
65209
65516
  import { randomUUID as randomUUID16 } from "node:crypto";
65210
65517
  import { createWriteStream } from "node:fs";
65211
65518
  import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
65212
- import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
65519
+ import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
65213
65520
  import { setTimeout as delay2 } from "node:timers/promises";
65214
65521
  function isRootLeaseLost(error) {
65215
65522
  return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
@@ -65218,7 +65525,7 @@ function unconfirmedCleanup(groups) {
65218
65525
  return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
65219
65526
  }
65220
65527
  function workerLogDirectory(journalPath, root) {
65221
- return join29(dirname13(resolve12(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
65528
+ return join30(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
65222
65529
  }
65223
65530
  function token(work) {
65224
65531
  return {
@@ -65406,6 +65713,7 @@ class PoolCoordinator {
65406
65713
  cleanups = new Set;
65407
65714
  controlAcks = new Map;
65408
65715
  lastHeard = new Map;
65716
+ awaiting = new Map;
65409
65717
  pendingActivity = new Map;
65410
65718
  batches = new Map;
65411
65719
  publicationFailures = new Map;
@@ -66149,7 +66457,7 @@ class PoolCoordinator {
66149
66457
  this.slots.add(slot);
66150
66458
  let ready = false;
66151
66459
  let serial = Promise.resolve();
66152
- const logPath = join29(this.logDirectory, `${worker}.log`);
66460
+ const logPath = join30(this.logDirectory, `${worker}.log`);
66153
66461
  this.logs.set(child, logPath);
66154
66462
  let logFailure;
66155
66463
  const log = createWriteStream(logPath, { flags: "a" });
@@ -66205,6 +66513,7 @@ class PoolCoordinator {
66205
66513
  this.readyWorkers.delete(worker);
66206
66514
  this.controlAcks.delete(worker);
66207
66515
  this.lastHeard.delete(worker);
66516
+ this.awaiting.delete(worker);
66208
66517
  this.slots.delete(slot);
66209
66518
  this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
66210
66519
  for (const settle of slot.stageCommands.values())
@@ -66462,8 +66771,19 @@ class PoolCoordinator {
66462
66771
  await this.sendResult(work.id);
66463
66772
  });
66464
66773
  const response = handled.then((value2) => routeReady ?? value2);
66465
- if (message.kind !== "delivery" && message.kind !== "delivery-ready")
66466
- serial = handled.then(() => {}, () => {});
66774
+ if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
66775
+ this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
66776
+ const answered = () => {
66777
+ const left = (this.awaiting.get(worker) ?? 1) - 1;
66778
+ if (left > 0)
66779
+ this.awaiting.set(worker, left);
66780
+ else
66781
+ this.awaiting.delete(worker);
66782
+ if (this.incarnations.get(worker) === child)
66783
+ this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
66784
+ };
66785
+ serial = handled.then(answered, answered);
66786
+ }
66467
66787
  response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
66468
66788
  const rootLeaseLost = isRootLeaseLost(error);
66469
66789
  if (rootLeaseLost)
@@ -66533,7 +66853,10 @@ class PoolCoordinator {
66533
66853
  if (work.epoch < lease.epoch)
66534
66854
  await this.releaseRetained(work);
66535
66855
  else
66536
- await queue.expire(lease, work);
66856
+ await queue.expire(lease, work).catch((error) => {
66857
+ if (error.message !== STALE_WORK_LEASE)
66858
+ throw error;
66859
+ });
66537
66860
  }
66538
66861
  })().finally(() => {
66539
66862
  this.recovering = undefined;
@@ -66551,7 +66874,7 @@ class PoolCoordinator {
66551
66874
  isLive(worker, child) {
66552
66875
  this.observeResponsiveness();
66553
66876
  const heard = this.lastHeard.get(worker);
66554
- return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
66877
+ return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && ((this.awaiting.get(worker) ?? 0) > 0 || performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs);
66555
66878
  }
66556
66879
  async stop(child) {
66557
66880
  const pid = child.pid;
@@ -66737,26 +67060,6 @@ function isWorkflowPendingStageDeliveryFailure(error) {
66737
67060
  return true;
66738
67061
  return error?.code === "pending_stage_delivery_failed";
66739
67062
  }
66740
- function untilDrainedOrStalled(drain) {
66741
- let lastProgressAt = Date.now();
66742
- const running = drain(() => {
66743
- lastProgressAt = Date.now();
66744
- });
66745
- return new Promise((resolve, reject) => {
66746
- let timer;
66747
- const check = () => {
66748
- const remaining = lastProgressAt + PENDING_STAGE_READY_STALL_MS - Date.now();
66749
- if (remaining <= 0) {
66750
- resolve();
66751
- return;
66752
- }
66753
- timer = setTimeout(check, remaining);
66754
- timer.unref?.();
66755
- };
66756
- running.then(resolve, reject).finally(() => clearTimeout(timer));
66757
- check();
66758
- });
66759
- }
66760
67063
  function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName, commit = (action) => action(), options = {}) {
66761
67064
  let resolveReady;
66762
67065
  let rejectReady;
@@ -66949,7 +67252,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
66949
67252
  };
66950
67253
  }
66951
67254
  async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
66952
- const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
67255
+ const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
66953
67256
  const candidateIds = new Set([
66954
67257
  ...activeStore.pendingStageMessagesFor(runId, stageId),
66955
67258
  ...activeStore.pendingStageMessagesFor(runId, stageName),
@@ -67005,7 +67308,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
67005
67308
  }
67006
67309
  }
67007
67310
  }
67008
- function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
67311
+ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
67009
67312
  const runs = activeStore.runs();
67010
67313
  const rootRunId = durableRootRunIdForRun(runs, runId);
67011
67314
  if (rootRunId === undefined)
@@ -67014,22 +67317,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
67014
67317
  if (rootRun === undefined)
67015
67318
  return [];
67016
67319
  const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
67017
- if (stage?.status === "completed" || stage?.status === "skipped")
67320
+ const ended = stage?.status === "completed" || stage?.status === "skipped";
67321
+ if (ended && receivedByEndedStage.length === 0)
67018
67322
  return [];
67019
67323
  const hops = workflowBoundaryHops(runs, runId);
67020
67324
  if (hops === undefined)
67021
67325
  return [];
67022
67326
  return (rootRun.pendingStageMessages ?? []).filter((entry) => {
67023
- if (entry.sticky !== true || entry.status !== "queued")
67024
- return false;
67025
- const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
67026
- if (parsed === undefined || parsed.rootRunId !== rootRunId)
67027
- return false;
67028
67327
  if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId && (recipient === undefined || delivery.admission === "context" && delivery.sessionId === recipient.sessionId && (recipient.receivedMessageIds === undefined || recipient.receivedMessageIds.includes(entry.message.id)))))
67029
67328
  return false;
67030
- return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
67329
+ if (ended && !receivedByEndedStage.includes(entry.message.id))
67330
+ return false;
67331
+ return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
67031
67332
  });
67032
67333
  }
67334
+ function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
67335
+ if (entry.sticky !== true || entry.status !== "queued")
67336
+ return false;
67337
+ const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
67338
+ if (parsed === undefined || parsed.rootRunId !== rootRunId)
67339
+ return false;
67340
+ return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
67341
+ }
67033
67342
  function claimPendingDelivery(store, runId, stageKey, messageId) {
67034
67343
  let claims = pendingDeliveryClaims.get(store);
67035
67344
  if (claims === undefined) {
@@ -67093,6 +67402,7 @@ class PoolStageHandoff {
67093
67402
  owners = new Map;
67094
67403
  publications = new Map;
67095
67404
  drains = new Map;
67405
+ deliveryIssues = 0;
67096
67406
  constructor(backend, store, queue, lease, claimRun) {
67097
67407
  this.backend = backend;
67098
67408
  this.store = store;
@@ -67173,11 +67483,23 @@ class PoolStageHandoff {
67173
67483
  this.drains.set(stage, drain);
67174
67484
  try {
67175
67485
  await drain;
67486
+ } catch (error) {
67487
+ const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
67488
+ if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
67489
+ this.recordDeliveryIssue(error);
67490
+ throw error;
67176
67491
  } finally {
67177
67492
  if (this.drains.get(stage) === drain)
67178
67493
  this.drains.delete(stage);
67179
67494
  }
67180
67495
  }
67496
+ recordDeliveryIssue(error) {
67497
+ this.deliveryIssues++;
67498
+ const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
67499
+ this.store.recordRunExecutionState(this.lease.runId, {
67500
+ intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
67501
+ });
67502
+ }
67181
67503
  async complete(work) {
67182
67504
  const root = this.lease.runId;
67183
67505
  const result = await this.queue.result(root, work.id);
@@ -68533,7 +68855,7 @@ var init_pooled_stage_registry = __esm(() => {
68533
68855
  // dist/builtin/workflows/src/workers/local-pool.ts
68534
68856
  import { fork as fork2 } from "node:child_process";
68535
68857
  import { randomUUID as randomUUID18 } from "node:crypto";
68536
- import { resolve as resolve13 } from "node:path";
68858
+ import { resolve as resolve14 } from "node:path";
68537
68859
  import { setTimeout as delay3 } from "node:timers/promises";
68538
68860
  import { fileURLToPath as fileURLToPath5 } from "node:url";
68539
68861
  import {
@@ -68767,7 +69089,7 @@ class LocalWorkerPool {
68767
69089
  async poolJournal() {
68768
69090
  const journal = this.backend.journal;
68769
69091
  if (this.options.durable === undefined) {
68770
- if (!(journal instanceof SqlRunJournal) || resolve13(this.options.journalPath) !== resolve13(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
69092
+ if (!(journal instanceof SqlRunJournal) || resolve14(this.options.journalPath) !== resolve14(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
68771
69093
  throw new Error("Local workers require the same default-prefix SQLite journal");
68772
69094
  return journal;
68773
69095
  }
@@ -69794,7 +70116,7 @@ var init_local_pool = __esm(() => {
69794
70116
  var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
69795
70117
 
69796
70118
  // dist/builtin/workflows/src/workers/public-pool.ts
69797
- import { resolve as resolve14 } from "node:path";
70119
+ import { resolve as resolve15 } from "node:path";
69798
70120
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
69799
70121
  async function restoreWorkerOptions(backend, options) {
69800
70122
  const source = options.continuation?.source.id ?? options.runId;
@@ -69844,16 +70166,16 @@ async function activatePublicPool(backend, options) {
69844
70166
  startupTimeoutMs: undefined,
69845
70167
  leaseMs: undefined,
69846
70168
  maxLoadPerCpu: undefined,
69847
- definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve14(cwd, source.path) }))
70169
+ definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
69848
70170
  };
69849
70171
  const admission = options.admission && {
69850
70172
  ...options.admission,
69851
- ...options.admission.userDatabase ? { userDatabase: resolve14(cwd, options.admission.userDatabase) } : {}
70173
+ ...options.admission.userDatabase ? { userDatabase: resolve15(cwd, options.admission.userDatabase) } : {}
69852
70174
  };
69853
70175
  if (durable !== undefined && admission?.userLimits) {
69854
- if (admission.userDatabase !== undefined && admission.userDatabase !== resolve14(poolPath))
69855
- throw new Error(`admission.userDatabase must be omitted, or ${resolve14(poolPath)}, for a journal that is not a local SQLite file`);
69856
- admission.userDatabase = resolve14(poolPath);
70176
+ if (admission.userDatabase !== undefined && admission.userDatabase !== resolve15(poolPath))
70177
+ throw new Error(`admission.userDatabase must be omitted, or ${resolve15(poolPath)}, for a journal that is not a local SQLite file`);
70178
+ admission.userDatabase = resolve15(poolPath);
69857
70179
  }
69858
70180
  const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
69859
70181
  const resources = JSON.parse(JSON.stringify({
@@ -70459,6 +70781,7 @@ function createTaskPrimitive(runtime) {
70459
70781
  }
70460
70782
  })();
70461
70783
  const stageMeta = stage.__modelFallbackMeta();
70784
+ stage.__releaseIfIdle?.();
70462
70785
  return {
70463
70786
  name,
70464
70787
  stageName: name,
@@ -71257,7 +71580,7 @@ function hasUsableContentBlock(block) {
71257
71580
 
71258
71581
  // dist/builtin/workflows/src/shared/stage-session-store.ts
71259
71582
  import { randomUUID as randomUUID20 } from "node:crypto";
71260
- import { dirname as dirname14, resolve as resolve15 } from "node:path";
71583
+ import { dirname as dirname15, resolve as resolve16 } from "node:path";
71261
71584
  import {
71262
71585
  JsonlSessionStore,
71263
71586
  resolveSessionStore,
@@ -71293,11 +71616,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
71293
71616
  async function migrateLegacyStageSession(store, sessionId, sessionFile) {
71294
71617
  if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
71295
71618
  return;
71296
- const location = resolve15(sessionFile);
71297
- const legacy = await JsonlSessionStore.open(dirname14(location), { exactDirectory: true, scanExisting: false });
71619
+ const location = resolve16(sessionFile);
71620
+ const legacy = await JsonlSessionStore.open(dirname15(location), { exactDirectory: true, scanExisting: false });
71298
71621
  try {
71299
71622
  for await (const file of legacy.scanFiles()) {
71300
- if (resolve15(file.location) !== location || file.header.id !== sessionId)
71623
+ if (resolve16(file.location) !== location || file.header.id !== sessionId)
71301
71624
  continue;
71302
71625
  const snapshot = await file.read();
71303
71626
  if (await store.readHeader(sessionId) === undefined)
@@ -74123,6 +74446,8 @@ function createTrackedStageCaller(input) {
74123
74446
  await runtime.releaseLiveHandle().catch(() => {});
74124
74447
  }
74125
74448
  runtime.state.sessionCheckpointed = finalizationError === undefined;
74449
+ if (runtime.state.contextUnreachable)
74450
+ runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
74126
74451
  input.limiter.release();
74127
74452
  if (finalizationError !== undefined)
74128
74453
  throwFinalizationError(finalizationError.error);
@@ -74286,7 +74611,8 @@ function createStageContext(input) {
74286
74611
  recordStageNotice({ kind: "abort", to: "interrupted" });
74287
74612
  await innerCtx.abort();
74288
74613
  },
74289
- __modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
74614
+ __modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
74615
+ __releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
74290
74616
  };
74291
74617
  }
74292
74618
 
@@ -75975,10 +76301,10 @@ function isRetryableSameCandidateFailure(error) {
75975
76301
  return isTransientExtensionStartupFailure(error);
75976
76302
  return isRetryableSameModelFailure(error);
75977
76303
  }
75978
- function mayAdvanceToNextCandidate(error) {
76304
+ function mayAdvanceToNextCandidate(error, options) {
75979
76305
  if (isExtensionStartupFailure(error))
75980
76306
  return isTransientExtensionStartupFailure(error);
75981
- return isRetryableModelFailure(error);
76307
+ return isRetryableModelFailure(error, options);
75982
76308
  }
75983
76309
  function hasMeaningfulUsage(usage) {
75984
76310
  if (usage === undefined)
@@ -76070,6 +76396,7 @@ class StageSessionController {
76070
76396
  structuredOutputExecutionFailureValue;
76071
76397
  structuredOutputCycleAttemptMark;
76072
76398
  unsubscribeTerminateWatcher;
76399
+ unbindAbortSignal;
76073
76400
  sessionInternalRetries = 0;
76074
76401
  unresolvedContextOverflowMessage;
76075
76402
  generationSealed = false;
@@ -76559,6 +76886,8 @@ class StageSessionController {
76559
76886
  this.pendingListeners.clear();
76560
76887
  this.unsubscribeTerminateWatcher?.();
76561
76888
  this.unsubscribeTerminateWatcher = undefined;
76889
+ this.unbindAbortSignal?.();
76890
+ this.unbindAbortSignal = undefined;
76562
76891
  this.terminatingToolCallIds.clear();
76563
76892
  this.messageAdmission.dispose();
76564
76893
  this.deliveryActivity.dispose();
@@ -76653,8 +76982,10 @@ class StageSessionController {
76653
76982
  };
76654
76983
  if (signal.aborted)
76655
76984
  onAbort();
76656
- else
76985
+ else {
76657
76986
  signal.addEventListener("abort", onAbort, { once: true });
76987
+ this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
76988
+ }
76658
76989
  }
76659
76990
  markAbort(reason) {
76660
76991
  this.abortGeneration += 1;
@@ -76681,6 +77012,9 @@ class StageSessionController {
76681
77012
  state.controller.abort(reason);
76682
77013
  this.thrownErrorRetryStates.clear();
76683
77014
  }
77015
+ fallbackFailureOptions() {
77016
+ return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
77017
+ }
76684
77018
  retrySettings() {
76685
77019
  const managers = [
76686
77020
  this.sessionSettingsManager,
@@ -76955,7 +77289,7 @@ class StageSessionController {
76955
77289
  const errorSettingsManager = retrySettingsManagerFromError(error);
76956
77290
  if (errorSettingsManager !== undefined)
76957
77291
  this.sessionSettingsManager = errorSettingsManager;
76958
- const retryableFailure = isRetryableModelFailure(error);
77292
+ const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
76959
77293
  const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
76960
77294
  recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
76961
77295
  if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
@@ -77580,7 +77914,7 @@ class StageSessionController {
77580
77914
  }
77581
77915
  throw new WorkflowPromptModelFailure(terminalFailure);
77582
77916
  } catch (err) {
77583
- if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
77917
+ if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77584
77918
  this.artifactCapture.settleAttempt(true);
77585
77919
  const usage = this.takeAttemptUsage(resumedSession);
77586
77920
  this.modelAttempts.push({
@@ -77602,7 +77936,7 @@ class StageSessionController {
77602
77936
  ...usage === undefined ? {} : { usage },
77603
77937
  error: message
77604
77938
  });
77605
- if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
77939
+ if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77606
77940
  this.modelWarnings.push(...this.pendingFallbackWarnings);
77607
77941
  this.pendingFallbackWarnings.length = 0;
77608
77942
  this.notifyModelFallbackMetaChange();
@@ -77651,7 +77985,7 @@ class StageSessionController {
77651
77985
  throw err;
77652
77986
  const message = errorMessage3(err);
77653
77987
  const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
77654
- if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
77988
+ if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77655
77989
  this.recordSuccessfulAttempt(candidate);
77656
77990
  return "handled";
77657
77991
  }
@@ -77668,7 +78002,7 @@ class StageSessionController {
77668
78002
  if (walk !== undefined) {
77669
78003
  this.recordCandidateFailure(walk, index, err, candidates);
77670
78004
  nextIndex = undefined;
77671
- if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
78005
+ if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
77672
78006
  try {
77673
78007
  nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
77674
78008
  } catch (error) {
@@ -77681,7 +78015,7 @@ class StageSessionController {
77681
78015
  }
77682
78016
  }
77683
78017
  }
77684
- if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
78018
+ if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
77685
78019
  await this.settleFailedCandidate();
77686
78020
  return "throw";
77687
78021
  }
@@ -77776,7 +78110,7 @@ var init_stage_runner_controller = __esm(() => {
77776
78110
  // dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
77777
78111
  import { createHash as createHash5 } from "node:crypto";
77778
78112
  import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
77779
- import { basename as basename5, dirname as dirname15, isAbsolute as isAbsolute11, join as join30, resolve as resolve16 } from "node:path";
78113
+ import { basename as basename5, dirname as dirname16, isAbsolute as isAbsolute11, join as join31, resolve as resolve17 } from "node:path";
77780
78114
  function normalizeMaxOutput2(maxOutput) {
77781
78115
  return {
77782
78116
  bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
@@ -77839,7 +78173,7 @@ function formatByteSize(bytes) {
77839
78173
  }
77840
78174
  function transcriptPath(runId, outputPath) {
77841
78175
  const digest = createHash5("sha256").update(outputPath).digest("hex").slice(0, 16);
77842
- return join30(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
78176
+ return join31(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
77843
78177
  }
77844
78178
  function appendContent(lines, content) {
77845
78179
  if (typeof content === "string") {
@@ -77884,7 +78218,7 @@ function renderTranscript(messages, fallbackOutput) {
77884
78218
  `);
77885
78219
  }
77886
78220
  function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
77887
- const absolutePath = resolve16(outputPath);
78221
+ const absolutePath = resolve17(outputPath);
77888
78222
  const bytes = Buffer.byteLength(fullOutput, "utf8");
77889
78223
  const lines = countLines(fullOutput);
77890
78224
  const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
@@ -77899,8 +78233,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
77899
78233
  return;
77900
78234
  if (isAbsolute11(output))
77901
78235
  return output;
77902
- const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve16(runtimeCwd, requestedCwd);
77903
- return resolve16(baseCwd, output);
78236
+ const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve17(runtimeCwd, requestedCwd);
78237
+ return resolve17(baseCwd, output);
77904
78238
  }
77905
78239
  function degenerateWarning(fullOutput) {
77906
78240
  return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
@@ -77959,7 +78293,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
77959
78293
  const transcriptFile = transcriptPath(runId, outputPath);
77960
78294
  const transcript = renderTranscript(messages, fullOutput);
77961
78295
  try {
77962
- await mkdir7(dirname15(outputPath), { recursive: true });
78296
+ await mkdir7(dirname16(outputPath), { recursive: true });
77963
78297
  await writeFile10(outputPath, fullOutput, "utf8");
77964
78298
  } catch (err) {
77965
78299
  return `${displayOutput}
@@ -77971,7 +78305,7 @@ ${err instanceof Error ? err.message : String(err)}`;
77971
78305
  let transcriptError;
77972
78306
  try {
77973
78307
  await ensureWorkflowArtifactRunDirectory(runId);
77974
- await mkdir7(dirname15(transcriptFile), { recursive: true });
78308
+ await mkdir7(dirname16(transcriptFile), { recursive: true });
77975
78309
  await writeFile10(transcriptFile, transcript, "utf8");
77976
78310
  transcriptAvailable = true;
77977
78311
  } catch (err) {
@@ -78482,7 +78816,8 @@ function createWorkflowStageFactory(input) {
78482
78816
  stageFinalized: false,
78483
78817
  sessionCheckpointed: false,
78484
78818
  skippedForParallelFailFast: false,
78485
- stageControlDropped: false
78819
+ stageControlDropped: false,
78820
+ contextUnreachable: false
78486
78821
  };
78487
78822
  const activeAskUserQuestionCalls = new Set;
78488
78823
  const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
@@ -78728,9 +79063,18 @@ function createWorkflowStageFactory(input) {
78728
79063
  hasContinuation: input.opts.continuation !== undefined,
78729
79064
  hasScopedParents: stageFailFastScope?.parentIds !== undefined
78730
79065
  });
78731
- return createStageContext({ runtime, runTrackedStageCall });
79066
+ const context = createStageContext({ runtime, runTrackedStageCall });
79067
+ unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
79068
+ return context;
79069
+ };
79070
+ }
79071
+ function releaseWhenUnreachable(state, registry, runId, stageId) {
79072
+ return () => {
79073
+ state.contextUnreachable = true;
79074
+ registry.releaseIdle(runId, stageId);
78732
79075
  };
78733
79076
  }
79077
+ var unreachableStageContexts;
78734
79078
  var init_executor_stage_factory = __esm(() => {
78735
79079
  init_intercom_group();
78736
79080
  init_pending_stage_route_readiness();
@@ -78745,6 +79089,7 @@ var init_executor_stage_factory = __esm(() => {
78745
79089
  init_pending_stage_delivery2();
78746
79090
  init_stage_runner();
78747
79091
  init_stage_runner_session();
79092
+ unreachableStageContexts = new FinalizationRegistry((release) => release());
78748
79093
  });
78749
79094
 
78750
79095
  // dist/builtin/workflows/src/engine/runtime.ts
@@ -79086,7 +79431,7 @@ async function executeRun(def, resolvedInputs, opts) {
79086
79431
  const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
79087
79432
  const tracker = new GraphFrontierTracker;
79088
79433
  const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
79089
- const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
79434
+ const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
79090
79435
  const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
79091
79436
  const workflowInvocationCwd = opts.cwd ?? process.cwd();
79092
79437
  let workflowCwd;
@@ -80185,8 +80530,8 @@ var init_workflows_host_module = __esm(() => {
80185
80530
 
80186
80531
  // dist/builtin/workflows/src/workers/pool-journal.ts
80187
80532
  import { createHash as createHash6, randomUUID as randomUUID22 } from "node:crypto";
80188
- import { existsSync as existsSync7, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
80189
- import { basename as basename6, dirname as dirname16, join as join31, resolve as resolve17 } from "node:path";
80533
+ import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
80534
+ import { basename as basename6, dirname as dirname17, join as join32, resolve as resolve18 } from "node:path";
80190
80535
  import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
80191
80536
  function encodeOption(value2) {
80192
80537
  if (typeof value2 === "bigint")
@@ -80208,7 +80553,7 @@ function isReopenableSelection(selection) {
80208
80553
  }
80209
80554
  function encodeSelection(selection) {
80210
80555
  if (selection.kind === "sqlite")
80211
- return JSON.stringify({ ...selection, path: resolve17(selection.path) });
80556
+ return JSON.stringify({ ...selection, path: resolve18(selection.path) });
80212
80557
  return JSON.stringify({
80213
80558
  ...selection,
80214
80559
  ...selection.options === undefined ? {} : {
@@ -80240,7 +80585,7 @@ function openDurableJournal(durable) {
80240
80585
  return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
80241
80586
  }
80242
80587
  function poolStateDirectory(agentDir) {
80243
- return join31(dirname16(agentDir), "workflows", "pool");
80588
+ return join32(dirname17(agentDir), "workflows", "pool");
80244
80589
  }
80245
80590
  function databaseIdentity(selection, agentDir) {
80246
80591
  return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
@@ -80248,16 +80593,16 @@ function databaseIdentity(selection, agentDir) {
80248
80593
  function coordinationPath(durable) {
80249
80594
  const selection = decodeSelection(durable.selection);
80250
80595
  const identity = createHash6("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
80251
- return join31(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
80596
+ return join32(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
80252
80597
  }
80253
80598
  function coordinationDatabase(durable) {
80254
80599
  return basename6(coordinationPath(durable), ".sqlite");
80255
80600
  }
80256
80601
  function openCoordinationJournal(path) {
80257
- const file = resolve17(path);
80602
+ const file = resolve18(path);
80258
80603
  let opened = coordinationJournals.get(file);
80259
80604
  if (opened === undefined) {
80260
- mkdirSync8(dirname16(file), { recursive: true });
80605
+ mkdirSync9(dirname17(file), { recursive: true });
80261
80606
  opened = resolveRunJournal({ journal: { path: file } });
80262
80607
  coordinationJournals.set(file, opened);
80263
80608
  opened.catch(() => {
@@ -80274,20 +80619,20 @@ function poolJournalFor(journal) {
80274
80619
  return coordinations.get(journal) ?? journal;
80275
80620
  }
80276
80621
  function poolHostId(agentDir) {
80277
- const file = join31(poolStateDirectory(agentDir), "host-id");
80622
+ const file = join32(poolStateDirectory(agentDir), "host-id");
80278
80623
  try {
80279
- const existing = readFileSync6(file, "utf8").trim();
80624
+ const existing = readFileSync8(file, "utf8").trim();
80280
80625
  if (existing !== "")
80281
80626
  return existing;
80282
80627
  } catch {}
80283
- mkdirSync8(dirname16(file), { recursive: true });
80628
+ mkdirSync9(dirname17(file), { recursive: true });
80284
80629
  const id = randomUUID22();
80285
80630
  try {
80286
- writeFileSync6(file, `${id}
80631
+ writeFileSync7(file, `${id}
80287
80632
  `, { flag: "wx" });
80288
80633
  return id;
80289
80634
  } catch {
80290
- return readFileSync6(file, "utf8").trim();
80635
+ return readFileSync8(file, "utf8").trim();
80291
80636
  }
80292
80637
  }
80293
80638
  var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
@@ -80310,7 +80655,6 @@ init_run();
80310
80655
  init_run_tool_control_registry();
80311
80656
  init_workflow_tool_abort();
80312
80657
  init_wiring();
80313
- init_pending_stage_delivery2();
80314
80658
  init_stage_control_registry();
80315
80659
  init_stage_queued_user_messages();
80316
80660
  init_stage_ui_broker();
@@ -80336,6 +80680,94 @@ function poolWorkerCommit(input) {
80336
80680
  return receipt;
80337
80681
  };
80338
80682
  }
80683
+ // dist/builtin/workflows/src/workers/pooled-stage-delivery.ts
80684
+ init_pending_stage_delivery2();
80685
+ init_pending_stage_delivery();
80686
+ init_store_pending_stage_delivery_methods();
80687
+ function pooledStageQueuedEntries(journal, store, root, stage) {
80688
+ const messages = journal.getWorkflow(root)?.pendingStageMessages ?? [];
80689
+ const runs = store.runs();
80690
+ const run = runs.find((candidate) => candidate.id === stage.runId);
80691
+ if (run === undefined)
80692
+ return [];
80693
+ const exact = new Set;
80694
+ for (const key of new Set([stage.stageId, stage.stageName]))
80695
+ for (const entry of pendingStageMessagesFor(messages, stage.runId, key, resolvePendingStageIdentity(run, key)))
80696
+ exact.add(entry);
80697
+ const hops = pooledStageHops(journal, runs, root, stage.runId);
80698
+ const sticky = hops === undefined ? [] : messages.filter((entry) => entry.runId === root && stickyEntryTargetsStage(entry, root, hops, stage.stageId, stage.stageName));
80699
+ return [
80700
+ ...[...exact].map((entry) => ({ entry, index: messages.indexOf(entry) })),
80701
+ ...sticky.map((entry) => ({ entry, index: Number.MAX_SAFE_INTEGER }))
80702
+ ].map(({ entry, index }) => ({ entry, index, order: pendingStageMessageAdmissionOrder(entry) })).sort((left, right) => left.order - right.order || left.index - right.index).map(({ entry }) => entry);
80703
+ }
80704
+ function pooledStageHops(journal, runs, root, runId) {
80705
+ const byId = new Map(runs.map((run) => [run.id, run]));
80706
+ const hops = [];
80707
+ let current = byId.get(runId);
80708
+ while (current !== undefined && current.parentRunId !== root) {
80709
+ const child = current;
80710
+ const parent = child.parentRunId === undefined ? undefined : byId.get(child.parentRunId);
80711
+ const boundary = parent?.stages.find((stage) => stage.id === child.parentStageId);
80712
+ if (parent === undefined || boundary === undefined)
80713
+ return;
80714
+ hops.unshift({ name: boundary.name, runId: child.id });
80715
+ current = parent;
80716
+ }
80717
+ if (current === undefined)
80718
+ return;
80719
+ const childRunId = current.id;
80720
+ const boundary = journal.listCheckpoints(root).find((checkpoint) => checkpoint.kind === "stage" && checkpoint.topology?.boundary?.child.runId === childRunId);
80721
+ if (boundary === undefined)
80722
+ return;
80723
+ hops.unshift({ name: boundary.name, runId: childRunId });
80724
+ return hops;
80725
+ }
80726
+ function createPooledStageDelivery(options) {
80727
+ const admissions = new Map;
80728
+ const sinks = new Map;
80729
+ return {
80730
+ routeCapability: options.routeCapability,
80731
+ async deliverPending(deliver, recipient) {
80732
+ const sessionId = recipient?.sessionId ?? "";
80733
+ sinks.set(sessionId, deliver);
80734
+ let admitted = admissions.get(sessionId);
80735
+ if (admitted === undefined) {
80736
+ admitted = new Map;
80737
+ admissions.set(sessionId, admitted);
80738
+ }
80739
+ const held = admitted;
80740
+ for (const id of recipient?.receivedMessageIds ?? [])
80741
+ if (!held.has(id))
80742
+ held.set(id, Promise.resolve());
80743
+ const admit = (from, message) => {
80744
+ const existing = held.get(message.id);
80745
+ if (existing !== undefined)
80746
+ return existing;
80747
+ const sink = sinks.get(sessionId) ?? deliver;
80748
+ const delivery = Promise.resolve().then(() => sink(from, message));
80749
+ held.set(message.id, delivery);
80750
+ delivery.catch(() => {
80751
+ if (held.get(message.id) === delivery)
80752
+ held.delete(message.id);
80753
+ });
80754
+ return delivery;
80755
+ };
80756
+ try {
80757
+ for (const entry of await options.queued())
80758
+ await admit(toPendingStageSender(entry), entry.message);
80759
+ } catch {}
80760
+ const deliveries = [...held];
80761
+ const settled = await Promise.allSettled(deliveries.map(([, delivery]) => delivery));
80762
+ const receivedMessageIds = deliveries.flatMap(([id], index) => settled[index]?.status === "fulfilled" ? [id] : []);
80763
+ options.forward({ sessionId, receivedMessageIds }, admit).catch(() => {});
80764
+ },
80765
+ ready() {
80766
+ return;
80767
+ },
80768
+ fail: options.fail
80769
+ };
80770
+ }
80339
80771
 
80340
80772
  // dist/builtin/workflows/src/workers/local-worker.ts
80341
80773
  init_pooled_watch_trace();
@@ -81470,25 +81902,18 @@ async function runWorker(start) {
81470
81902
  const capability = await request({ kind: "route", runId: meta.runId });
81471
81903
  if (typeof capability !== "string")
81472
81904
  throw new Error("Worker root route is unavailable");
81473
- const pendingStageDelivery = {
81905
+ const pendingStageDelivery = createPooledStageDelivery({
81474
81906
  routeCapability: capability,
81475
- async deliverPending(deliver, recipient) {
81476
- await publication;
81477
- await untilDrainedOrStalled((progress) => request({ kind: "delivery", ...identity, recipient }, async (from, message) => {
81478
- progress();
81479
- try {
81480
- await deliver(from, message);
81481
- } finally {
81482
- progress();
81483
- }
81484
- }).then(() => {}));
81907
+ queued: async () => {
81908
+ await reader.catchUpWorkflow(start.root);
81909
+ return pooledStageQueuedEntries(reader, store, start.root, identity);
81485
81910
  },
81486
- async ready(sessionId) {
81911
+ forward: async (recipient, deliver) => {
81487
81912
  await publication;
81488
- await request({ kind: "delivery-ready", ...identity, sessionId });
81913
+ await request({ kind: "delivery", ...identity, recipient }, deliver);
81489
81914
  },
81490
81915
  fail: options.orchestrationContext.pendingStageDelivery.fail
81491
- };
81916
+ });
81492
81917
  return baseAdapter.create({ ...options, orchestrationContext: { ...options.orchestrationContext, pendingStageDelivery } }, meta);
81493
81918
  }
81494
81919
  };