@bastani/atomic 0.9.60 → 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 (62) hide show
  1. package/CHANGELOG.md +80 -0
  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 +922 -473
  17. package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +1006 -484
  18. package/dist/builtin/workflows/src/index.js +892 -448
  19. package/dist/builtin/workflows/src/local-worker-entry.mjs +1006 -484
  20. package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +6 -0
  21. package/dist/core/agent-session-retry.d.ts.map +1 -1
  22. package/dist/core/agent-session-retry.js +12 -3
  23. package/dist/core/agent-session-retry.js.map +1 -1
  24. package/dist/core/model-fallback-failures.d.ts +14 -4
  25. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  26. package/dist/core/model-fallback-failures.js +43 -15
  27. package/dist/core/model-fallback-failures.js.map +1 -1
  28. package/dist/core/settings-defaults.d.ts +1 -0
  29. package/dist/core/settings-defaults.d.ts.map +1 -1
  30. package/dist/core/settings-defaults.js +1 -0
  31. package/dist/core/settings-defaults.js.map +1 -1
  32. package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
  33. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  34. package/dist/core/settings-manager-basic-accessors.js +2 -0
  35. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  36. package/dist/core/settings-schema.d.ts +2 -0
  37. package/dist/core/settings-schema.d.ts.map +1 -1
  38. package/dist/core/settings-schema.js +4 -0
  39. package/dist/core/settings-schema.js.map +1 -1
  40. package/dist/core/slash-commands.js +2 -2
  41. package/dist/core/slash-commands.js.map +1 -1
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/modes/interactive/interactive-startup-chat-container.d.ts +2 -0
  46. package/dist/modes/interactive/interactive-startup-chat-container.d.ts.map +1 -1
  47. package/dist/modes/interactive/interactive-startup-chat-container.js +6 -0
  48. package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
  49. package/dist/modes/interactive-engine/remote-renderer.d.ts +27 -5
  50. package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
  51. package/dist/modes/interactive-engine/remote-renderer.js +76 -16
  52. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  53. package/docs/intercom/reference.md +1 -1
  54. package/docs/models/evals.md +30 -2
  55. package/docs/settings.md +3 -0
  56. package/docs/subagents/reference.md +3 -1
  57. package/docs/workflows/api-reference.md +9 -6
  58. package/docs/workflows/builtins.md +1 -1
  59. package/docs/workflows/operations.md +6 -4
  60. package/npm-shrinkwrap.json +32 -32
  61. package/package.json +3 -3
  62. package/schemas/settings.schema.json +5 -0
@@ -13456,9 +13456,104 @@ var init_workflow_artifacts = __esm(() => {
13456
13456
  pendingArtifactPrunes = new Map;
13457
13457
  });
13458
13458
 
13459
- // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
13459
+ // dist/builtin/workflows/src/runs/shared/worktree-allocation.ts
13460
+ import { randomBytes } from "node:crypto";
13460
13461
  import * as fs from "node:fs";
13461
13462
  import * as path from "node:path";
13463
+ function nextBucketId() {
13464
+ return nextBucketIdOverride?.() ?? randomBytes(2).toString("hex");
13465
+ }
13466
+ function errorCode(error) {
13467
+ return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
13468
+ }
13469
+ function allocateWorktreeCheckoutPath(root, repositoryName) {
13470
+ for (let attempt = 0;attempt < MAX_BUCKET_ATTEMPTS; attempt++) {
13471
+ const bucket = path.join(root, nextBucketId());
13472
+ try {
13473
+ fs.mkdirSync(bucket);
13474
+ return path.join(bucket, repositoryName);
13475
+ } catch (error) {
13476
+ if (errorCode(error) === "EEXIST")
13477
+ continue;
13478
+ const message = error instanceof Error ? error.message : String(error);
13479
+ throw new Error(`Failed to create worktree bucket ${bucket} under gitWorktreeDir ${root}: ${message}`);
13480
+ }
13481
+ }
13482
+ throw new Error(`Every worktree bucket identifier under gitWorktreeDir ${root} is already in use.`);
13483
+ }
13484
+ function removeEmptyWorktreeBucket(checkout) {
13485
+ try {
13486
+ fs.rmdirSync(path.dirname(checkout));
13487
+ } catch {}
13488
+ }
13489
+ function linkedGitDirectory(checkout) {
13490
+ let pointer;
13491
+ try {
13492
+ if (!fs.lstatSync(path.join(checkout, ".git")).isFile())
13493
+ return;
13494
+ pointer = fs.readFileSync(path.join(checkout, ".git"), "utf8");
13495
+ } catch {
13496
+ return;
13497
+ }
13498
+ if (!pointer.startsWith("gitdir:"))
13499
+ return;
13500
+ const gitDir = pointer.slice("gitdir:".length).trim();
13501
+ return gitDir ? path.resolve(checkout, gitDir) : undefined;
13502
+ }
13503
+ function readWorktreeOwner(gitDir) {
13504
+ let contents;
13505
+ try {
13506
+ contents = fs.readFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), "utf8");
13507
+ } catch {
13508
+ return;
13509
+ }
13510
+ try {
13511
+ const record = JSON.parse(contents);
13512
+ return record.version === WORKTREE_OWNER_VERSION && typeof record.ownerRunId === "string" && record.ownerRunId ? record.ownerRunId : undefined;
13513
+ } catch {
13514
+ return;
13515
+ }
13516
+ }
13517
+ function findOwnedWorktreeCheckouts(root, repositoryName, ownerRunId) {
13518
+ let entries;
13519
+ try {
13520
+ entries = fs.readdirSync(root, { withFileTypes: true });
13521
+ } catch {
13522
+ return [];
13523
+ }
13524
+ const owned = [];
13525
+ for (const entry of entries) {
13526
+ if (!entry.isDirectory() || !BUCKET_PATTERN.test(entry.name))
13527
+ continue;
13528
+ const checkout = path.join(root, entry.name, repositoryName);
13529
+ try {
13530
+ if (!fs.lstatSync(checkout).isDirectory())
13531
+ continue;
13532
+ } catch {
13533
+ continue;
13534
+ }
13535
+ const gitDir = linkedGitDirectory(checkout);
13536
+ if (gitDir !== undefined && readWorktreeOwner(gitDir) === ownerRunId)
13537
+ owned.push(checkout);
13538
+ }
13539
+ return owned.sort();
13540
+ }
13541
+ function bindWorktreeOwner(gitDir, ownerRunId) {
13542
+ const record = { version: WORKTREE_OWNER_VERSION, ownerRunId };
13543
+ fs.writeFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), `${JSON.stringify(record)}
13544
+ `, {
13545
+ encoding: "utf8",
13546
+ flag: "wx"
13547
+ });
13548
+ }
13549
+ var WORKTREE_OWNER_FILENAME = "atomic-workflow-run.json", WORKTREE_OWNER_VERSION = 1, BUCKET_PATTERN, MAX_BUCKET_ATTEMPTS = 65536, nextBucketIdOverride;
13550
+ var init_worktree_allocation = __esm(() => {
13551
+ BUCKET_PATTERN = /^[0-9a-f]{4}$/;
13552
+ });
13553
+
13554
+ // dist/builtin/workflows/src/runs/shared/worktree-generation.ts
13555
+ import * as fs2 from "node:fs";
13556
+ import * as path2 from "node:path";
13462
13557
  function sameFileIdentity(left, right) {
13463
13558
  return left.dev === right.dev && left.ino === right.ino;
13464
13559
  }
@@ -13468,7 +13563,7 @@ function openMainCheckoutAnchor(gitDir) {
13468
13563
  assertCurrent() {
13469
13564
  if (disposed)
13470
13565
  throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
13471
- if (!fs.lstatSync(gitDir).isDirectory()) {
13566
+ if (!fs2.lstatSync(gitDir).isDirectory()) {
13472
13567
  throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
13473
13568
  }
13474
13569
  },
@@ -13478,17 +13573,17 @@ function openMainCheckoutAnchor(gitDir) {
13478
13573
  };
13479
13574
  }
13480
13575
  function openGitWorktreeGenerationAnchor(worktreeRoot) {
13481
- const gitFile = path.join(worktreeRoot, ".git");
13482
- if (fs.lstatSync(gitFile).isDirectory())
13576
+ const gitFile = path2.join(worktreeRoot, ".git");
13577
+ if (fs2.lstatSync(gitFile).isDirectory())
13483
13578
  return openMainCheckoutAnchor(gitFile);
13484
- const descriptor = fs.openSync(gitFile, "r");
13579
+ const descriptor = fs2.openSync(gitFile, "r");
13485
13580
  let disposed = false;
13486
13581
  const anchor = {
13487
13582
  assertCurrent() {
13488
13583
  if (disposed)
13489
13584
  throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
13490
- const held = fs.fstatSync(descriptor, { bigint: true });
13491
- const current = fs.lstatSync(gitFile, { bigint: true });
13585
+ const held = fs2.fstatSync(descriptor, { bigint: true });
13586
+ const current = fs2.lstatSync(gitFile, { bigint: true });
13492
13587
  if (!current.isFile() || !sameFileIdentity(held, current)) {
13493
13588
  throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
13494
13589
  }
@@ -13497,7 +13592,7 @@ function openGitWorktreeGenerationAnchor(worktreeRoot) {
13497
13592
  if (disposed)
13498
13593
  return;
13499
13594
  disposed = true;
13500
- fs.closeSync(descriptor);
13595
+ fs2.closeSync(descriptor);
13501
13596
  }
13502
13597
  };
13503
13598
  try {
@@ -13611,84 +13706,84 @@ var init_worktree_git_runner = __esm(() => {
13611
13706
  });
13612
13707
 
13613
13708
  // dist/builtin/workflows/src/runs/shared/worktree-root.ts
13614
- import * as fs2 from "node:fs";
13615
- import * as path2 from "node:path";
13709
+ import * as fs3 from "node:fs";
13710
+ import * as path3 from "node:path";
13616
13711
  function pathFromPointer(contents, prefix, base) {
13617
13712
  if (!contents.startsWith(prefix))
13618
13713
  return;
13619
13714
  const value2 = contents.slice(prefix.length).trim();
13620
13715
  if (!value2)
13621
13716
  return;
13622
- return path2.resolve(base, value2);
13717
+ return path3.resolve(base, value2);
13623
13718
  }
13624
13719
  function readText(file) {
13625
13720
  try {
13626
- return fs2.readFileSync(file, "utf8");
13721
+ return fs3.readFileSync(file, "utf8");
13627
13722
  } catch {
13628
13723
  return;
13629
13724
  }
13630
13725
  }
13631
13726
  function samePath(left, right) {
13632
13727
  try {
13633
- const a = fs2.realpathSync.native(left);
13634
- const b = fs2.realpathSync.native(right);
13728
+ const a = fs3.realpathSync.native(left);
13729
+ const b = fs3.realpathSync.native(right);
13635
13730
  return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
13636
13731
  } catch {
13637
13732
  return false;
13638
13733
  }
13639
13734
  }
13640
13735
  function findGitRoot(cwd) {
13641
- let current = path2.resolve(cwd);
13736
+ let current = path3.resolve(cwd);
13642
13737
  try {
13643
- if (!fs2.statSync(current).isDirectory())
13644
- current = path2.dirname(current);
13738
+ if (!fs3.statSync(current).isDirectory())
13739
+ current = path3.dirname(current);
13645
13740
  } catch {
13646
13741
  return;
13647
13742
  }
13648
13743
  while (true) {
13649
13744
  try {
13650
- const entry = fs2.statSync(path2.join(current, ".git"));
13745
+ const entry = fs3.statSync(path3.join(current, ".git"));
13651
13746
  if (entry.isDirectory() || entry.isFile())
13652
13747
  return current;
13653
13748
  } catch {}
13654
- const parent = path2.dirname(current);
13749
+ const parent = path3.dirname(current);
13655
13750
  if (parent === current)
13656
13751
  return;
13657
13752
  current = parent;
13658
13753
  }
13659
13754
  }
13660
13755
  function resolveMainRepoRoot(repoRoot) {
13661
- const gitEntry = path2.join(repoRoot, ".git");
13756
+ const gitEntry = path3.join(repoRoot, ".git");
13662
13757
  let stats;
13663
13758
  try {
13664
- stats = fs2.statSync(gitEntry);
13759
+ stats = fs3.statSync(gitEntry);
13665
13760
  } catch {
13666
13761
  return;
13667
13762
  }
13668
13763
  if (stats.isDirectory())
13669
- return path2.resolve(repoRoot);
13764
+ return path3.resolve(repoRoot);
13670
13765
  if (!stats.isFile())
13671
13766
  return;
13672
13767
  const pointer = readText(gitEntry);
13673
13768
  if (pointer === undefined)
13674
13769
  return;
13675
13770
  const gitDir = pathFromPointer(pointer, "gitdir:", repoRoot);
13676
- if (gitDir === undefined || path2.basename(path2.dirname(gitDir)) !== "worktrees")
13771
+ if (gitDir === undefined || path3.basename(path3.dirname(gitDir)) !== "worktrees")
13677
13772
  return;
13678
- const commonGitDir = path2.dirname(path2.dirname(gitDir));
13679
- if (path2.basename(commonGitDir) !== ".git")
13773
+ const commonGitDir = path3.dirname(path3.dirname(gitDir));
13774
+ if (path3.basename(commonGitDir) !== ".git")
13680
13775
  return;
13681
- const backPointer = readText(path2.join(gitDir, "gitdir"));
13682
- const commonPointer = readText(path2.join(gitDir, "commondir"));
13776
+ const backPointer = readText(path3.join(gitDir, "gitdir"));
13777
+ const commonPointer = readText(path3.join(gitDir, "commondir"));
13683
13778
  if (backPointer === undefined || commonPointer === undefined)
13684
13779
  return;
13685
- const linkedGitEntry = path2.resolve(gitDir, backPointer.trim());
13686
- const declaredCommonDir = path2.resolve(gitDir, commonPointer.trim());
13780
+ const linkedGitEntry = path3.resolve(gitDir, backPointer.trim());
13781
+ const declaredCommonDir = path3.resolve(gitDir, commonPointer.trim());
13687
13782
  if (!backPointer.trim() || !commonPointer.trim())
13688
13783
  return;
13689
13784
  if (!samePath(linkedGitEntry, gitEntry) || !samePath(declaredCommonDir, commonGitDir))
13690
13785
  return;
13691
- return path2.dirname(commonGitDir);
13786
+ return path3.dirname(commonGitDir);
13692
13787
  }
13693
13788
  function findCanonicalGitRoot(cwd) {
13694
13789
  const repoRoot = findGitRoot(cwd);
@@ -13697,33 +13792,31 @@ function findCanonicalGitRoot(cwd) {
13697
13792
  var init_worktree_root = () => {};
13698
13793
 
13699
13794
  // dist/builtin/workflows/src/runs/shared/worktree-git.ts
13700
- import * as fs3 from "node:fs";
13701
- import * as path3 from "node:path";
13702
- function gitWorktreeSetupCacheKey(options) {
13703
- const repoRoot = repositoryRootForGitWorktree(options.cwd);
13704
- const { logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
13705
- const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
13795
+ import * as fs4 from "node:fs";
13796
+ import * as path4 from "node:path";
13797
+ function gitWorktreeSetupCacheKey(request) {
13706
13798
  return JSON.stringify([
13707
- comparableRealPath(gitCommonDirForWorktree(repoRoot)),
13708
- comparablePathThroughExistingAncestor(worktreeRoot)
13799
+ comparablePathThroughExistingAncestor(request.options.cwd),
13800
+ comparablePathThroughExistingAncestor(request.target)
13709
13801
  ]);
13710
13802
  }
13711
- function createGitWorktreeSetupCache() {
13803
+ function createGitWorktreeSetupCache(ownerRunId) {
13712
13804
  const results = new Map;
13713
13805
  let disposed = false;
13714
13806
  return {
13715
13807
  get(options) {
13716
13808
  if (disposed)
13717
13809
  throw new Error("Git worktree setup cache is already disposed");
13718
- const key = gitWorktreeSetupCacheKey(options);
13810
+ const request = resolveGitWorktreeSetupRequest(options);
13811
+ const key = gitWorktreeSetupCacheKey(request);
13719
13812
  const cached = results.get(key);
13720
13813
  if (cached !== undefined) {
13721
13814
  assertCachedGitWorktreeIdentity(cached, options);
13722
13815
  return cached.result;
13723
13816
  }
13724
- const result = setupGitWorktree(options);
13725
- results.set(key, { result, identity: captureGitWorktreeIdentity(result) });
13726
- return result;
13817
+ const setup = setupGitWorktreeFromRequest(request, ownerRunId);
13818
+ results.set(key, { ...setup, identity: captureGitWorktreeIdentity(setup) });
13819
+ return setup.result;
13727
13820
  },
13728
13821
  dispose() {
13729
13822
  if (disposed)
@@ -13755,10 +13848,10 @@ function worktreeRecoveryCommand(repositoryRoot, worktreeDir) {
13755
13848
  return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
13756
13849
  }
13757
13850
  function hasGrandparent(value2) {
13758
- const parent = path3.dirname(value2);
13851
+ const parent = path4.dirname(value2);
13759
13852
  if (parent === value2)
13760
13853
  return false;
13761
- const grandparent = path3.dirname(parent);
13854
+ const grandparent = path4.dirname(parent);
13762
13855
  return grandparent !== parent;
13763
13856
  }
13764
13857
  function pathAncestors(value2) {
@@ -13766,7 +13859,7 @@ function pathAncestors(value2) {
13766
13859
  let current = value2;
13767
13860
  while (true) {
13768
13861
  ancestors.push(current);
13769
- const parent = path3.dirname(current);
13862
+ const parent = path4.dirname(current);
13770
13863
  if (parent === current)
13771
13864
  return ancestors;
13772
13865
  current = parent;
@@ -13775,89 +13868,167 @@ function pathAncestors(value2) {
13775
13868
  function shouldPreserveLogicalPath(logicalPath) {
13776
13869
  return pathAncestors(logicalPath).some((ancestor) => {
13777
13870
  try {
13778
- return fs3.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
13871
+ return fs4.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
13779
13872
  } catch {
13780
13873
  return false;
13781
13874
  }
13782
13875
  });
13783
13876
  }
13784
13877
  function canonicalizePreservingSymlinks(value2) {
13785
- const logicalPath = path3.resolve(value2);
13878
+ const logicalPath = path4.resolve(value2);
13786
13879
  const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
13787
13880
  try {
13788
- const canonical = fs3.realpathSync.native(logicalPath);
13881
+ const canonical = fs4.realpathSync.native(logicalPath);
13789
13882
  return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
13790
13883
  } catch {
13791
13884
  return logicalPath;
13792
13885
  }
13793
13886
  }
13794
- function resolveGitWorktreePath(value2, repoRoot) {
13887
+ function resolveGitWorktreePath(value2, baseDir) {
13795
13888
  const trimmed = value2.trim();
13796
13889
  if (!trimmed)
13797
13890
  throw new Error("gitWorktreeDir cannot be empty");
13798
13891
  if (trimmed.includes("\x00")) {
13799
13892
  throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
13800
13893
  }
13801
- return canonicalizePreservingSymlinks(path3.isAbsolute(trimmed) ? trimmed : path3.resolve(repoRoot, trimmed));
13894
+ return canonicalizePreservingSymlinks(path4.isAbsolute(trimmed) ? trimmed : path4.resolve(baseDir, trimmed));
13802
13895
  }
13803
13896
  function comparableRealPath(value2) {
13804
- const realpath = fs3.realpathSync.native(value2).replace(/\\/g, "/");
13897
+ const realpath = fs4.realpathSync.native(value2).replace(/\\/g, "/");
13805
13898
  return process.platform === "win32" ? realpath.toLowerCase() : realpath;
13806
13899
  }
13807
- function comparablePathThroughExistingAncestor(value2) {
13808
- let existing = path3.resolve(value2);
13900
+ function nearestExistingAncestor(value2) {
13901
+ let existing = path4.resolve(value2);
13809
13902
  const missing = [];
13810
13903
  while (!pathExistsSync(existing)) {
13811
- const parent = path3.dirname(existing);
13904
+ const parent = path4.dirname(existing);
13812
13905
  if (parent === existing)
13813
13906
  break;
13814
- missing.unshift(path3.basename(existing));
13907
+ missing.unshift(path4.basename(existing));
13815
13908
  existing = parent;
13816
13909
  }
13817
- const resolved = path3.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
13910
+ return { existing, missing };
13911
+ }
13912
+ function comparablePathThroughExistingAncestor(value2) {
13913
+ const { existing, missing } = nearestExistingAncestor(value2);
13914
+ const resolved = path4.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
13818
13915
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
13819
13916
  }
13917
+ function isFileOrLink(value2) {
13918
+ try {
13919
+ const entry = fs4.lstatSync(value2);
13920
+ return entry.isFile() || entry.isSymbolicLink();
13921
+ } catch {
13922
+ return false;
13923
+ }
13924
+ }
13925
+ function isDirectory(value2) {
13926
+ try {
13927
+ return fs4.statSync(value2).isDirectory();
13928
+ } catch {
13929
+ return false;
13930
+ }
13931
+ }
13932
+ function looksLikeGitDirectory(directory) {
13933
+ if (!isDirectory(directory))
13934
+ return false;
13935
+ if (path4.basename(directory) === ".git")
13936
+ return true;
13937
+ if (!isFileOrLink(path4.join(directory, "HEAD")))
13938
+ return false;
13939
+ if (isFileOrLink(path4.join(directory, "commondir")))
13940
+ return true;
13941
+ return isDirectory(path4.join(directory, "objects")) && isDirectory(path4.join(directory, "refs"));
13942
+ }
13943
+ function enclosingGitMetadataDirectory(target) {
13944
+ const { existing } = nearestExistingAncestor(target);
13945
+ let realExisting = existing;
13946
+ try {
13947
+ realExisting = fs4.realpathSync.native(existing);
13948
+ } catch {}
13949
+ for (const candidate of new Set([...pathAncestors(existing), ...pathAncestors(realExisting)])) {
13950
+ if (looksLikeGitDirectory(candidate))
13951
+ return candidate;
13952
+ }
13953
+ const insideGitDir = runGitReadOnlyProbe(existing, ["rev-parse", "--is-inside-git-dir"]);
13954
+ if (insideGitDir.status !== 0 && isGitTimeoutResult(insideGitDir)) {
13955
+ throw new Error(`Timed out while validating gitWorktreeDir ${target}. Git reported: ${gitFailureMessage(insideGitDir)}`);
13956
+ }
13957
+ return insideGitDir.status === 0 && insideGitDir.stdout.trim() === "true" ? existing : undefined;
13958
+ }
13959
+ function assertSafeGitWorktreeTarget(target, invokingRoot) {
13960
+ const gitDirectory = enclosingGitMetadataDirectory(target);
13961
+ if (gitDirectory !== undefined) {
13962
+ 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.`);
13963
+ }
13964
+ if (invokingRoot !== undefined)
13965
+ validateWorktreeOutsideInvokingCheckout(target, invokingRoot);
13966
+ const { existing, missing } = nearestExistingAncestor(target);
13967
+ const workingTree = gitTopLevel(existing);
13968
+ if (workingTree === undefined)
13969
+ return;
13970
+ if (missing.length === 0 && comparableRealPath(target) === comparableRealPath(workingTree))
13971
+ return;
13972
+ 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.`);
13973
+ }
13820
13974
  function validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot) {
13821
13975
  const repository = comparableRealPath(repoRoot);
13822
13976
  const candidate = comparablePathThroughExistingAncestor(worktreeRoot);
13823
- const relativePath = path3.relative(repository, candidate);
13977
+ const relativePath = path4.relative(repository, candidate);
13824
13978
  if (relativePath === "") {
13825
- throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate same-repository worktree path.");
13979
+ throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate worktree path outside it.");
13826
13980
  }
13827
- if (!relativePath.startsWith(`..${path3.sep}`) && relativePath !== ".." && !path3.isAbsolute(relativePath)) {
13828
- throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate same-repository worktree path.");
13981
+ if (!relativePath.startsWith(`..${path4.sep}`) && relativePath !== ".." && !path4.isAbsolute(relativePath)) {
13982
+ throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate worktree path outside it.");
13829
13983
  }
13830
13984
  }
13831
13985
  function gitPathFromOutput(value2, cwd) {
13832
13986
  const trimmed = value2.trim();
13833
13987
  if (!trimmed)
13834
13988
  return;
13835
- return path3.isAbsolute(trimmed) ? path3.resolve(trimmed) : path3.resolve(cwd, trimmed);
13989
+ return path4.isAbsolute(trimmed) ? path4.resolve(trimmed) : path4.resolve(cwd, trimmed);
13836
13990
  }
13837
13991
  function pathExistsSync(value2) {
13992
+ return pathStatSync(value2) !== undefined;
13993
+ }
13994
+ function pathStatSync(value2) {
13838
13995
  try {
13839
- fs3.statSync(value2);
13840
- return true;
13996
+ return fs4.statSync(value2);
13841
13997
  } catch (error) {
13842
13998
  const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
13843
13999
  if (code === "ENOENT" || code === "ENOTDIR")
13844
- return false;
14000
+ return;
13845
14001
  throw error;
13846
14002
  }
13847
14003
  }
13848
- function repositoryRootForGitWorktree(cwd) {
14004
+ function probeInvokingRepository(cwd) {
13849
14005
  const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
13850
14006
  if (result.status !== 0) {
13851
14007
  if (isGitTimeoutResult(result)) {
13852
14008
  throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
13853
14009
  }
13854
- 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)}`);
14010
+ return { failure: gitFailureMessage(result) };
13855
14011
  }
13856
- const normalized = gitPathFromOutput(result.stdout, cwd);
13857
- if (normalized === undefined) {
14012
+ const root = gitPathFromOutput(result.stdout, cwd);
14013
+ if (root === undefined) {
13858
14014
  throw new Error(`gitWorktreeDir could not resolve the repository top level from ${cwd}: git returned an empty path.`);
13859
14015
  }
13860
- return normalized;
14016
+ return { repository: { root, ...cwdWithinGitRepository(cwd, root) } };
14017
+ }
14018
+ function resolveGitWorktreeSetupRequest(options) {
14019
+ const probe = probeInvokingRepository(options.cwd);
14020
+ if ("repository" in probe) {
14021
+ return {
14022
+ options,
14023
+ repository: probe.repository,
14024
+ target: resolveGitWorktreePath(options.gitWorktreeDir, probe.repository.logicalRoot)
14025
+ };
14026
+ }
14027
+ return {
14028
+ options,
14029
+ repositoryProbeFailure: probe.failure,
14030
+ target: resolveGitWorktreePath(options.gitWorktreeDir, canonicalizePreservingSymlinks(options.cwd))
14031
+ };
13861
14032
  }
13862
14033
  function gitTopLevelFromResult(result, cwd, description) {
13863
14034
  if (result.status !== 0) {
@@ -13893,25 +14064,25 @@ function dirnameForEachRelativeComponent(base, relativePath) {
13893
14064
  continue;
13894
14065
  if (component === "..")
13895
14066
  return;
13896
- current = path3.dirname(current);
14067
+ current = path4.dirname(current);
13897
14068
  }
13898
14069
  return current;
13899
14070
  }
13900
14071
  function cwdWithinGitRepository(cwd, repoRoot) {
13901
- const sourceCwd = fs3.realpathSync.native(cwd);
13902
- const sourceRepoRoot = fs3.realpathSync.native(repoRoot);
13903
- const relativeCwd = path3.relative(sourceRepoRoot, sourceCwd);
13904
- const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path3.isAbsolute(relativeCwd) ? "" : relativeCwd;
14072
+ const sourceCwd = fs4.realpathSync.native(cwd);
14073
+ const sourceRepoRoot = fs4.realpathSync.native(repoRoot);
14074
+ const relativeCwd = path4.relative(sourceRepoRoot, sourceCwd);
14075
+ const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path4.isAbsolute(relativeCwd) ? "" : relativeCwd;
13905
14076
  const logicalCwd = canonicalizePreservingSymlinks(cwd);
13906
14077
  return {
13907
14078
  relativeCwd: safeRelativeCwd,
13908
- logicalRepoRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
14079
+ logicalRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
13909
14080
  };
13910
14081
  }
13911
14082
  function workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd) {
13912
- return relativeCwd === "" ? worktreeRoot : path3.join(worktreeRoot, relativeCwd);
14083
+ return relativeCwd === "" ? worktreeRoot : path4.join(worktreeRoot, relativeCwd);
13913
14084
  }
13914
- function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
14085
+ function validateGitWorktreeRoot(worktreeRoot) {
13915
14086
  const topLevel = gitTopLevel(worktreeRoot);
13916
14087
  if (topLevel === undefined) {
13917
14088
  throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
@@ -13919,8 +14090,18 @@ function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
13919
14090
  if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
13920
14091
  throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
13921
14092
  }
13922
- if (comparableRealPath(gitCommonDirForWorktree(repoRoot)) !== comparableRealPath(gitCommonDirForWorktree(topLevel))) {
13923
- throw new Error(`gitWorktreeDir already exists but does not belong to the invoking Git repository: ${worktreeRoot}`);
14093
+ return gitCommonDirForWorktree(topLevel);
14094
+ }
14095
+ function existingGitWorktreeCommonDir(directory) {
14096
+ return gitTopLevel(directory) === undefined ? undefined : validateGitWorktreeRoot(directory);
14097
+ }
14098
+ function sameGitCommonDir(left, right) {
14099
+ return comparableRealPath(left) === comparableRealPath(right);
14100
+ }
14101
+ function validateCreatedGitWorktree(worktreeRoot, repository) {
14102
+ assertSafeGitWorktreeTarget(worktreeRoot, repository.root);
14103
+ if (!sameGitCommonDir(validateGitWorktreeRoot(worktreeRoot), gitCommonDirForWorktree(repository.root))) {
14104
+ throw new Error(`gitWorktreeDir does not belong to the invoking Git repository: ${worktreeRoot}`);
13924
14105
  }
13925
14106
  }
13926
14107
  function gitDirectoryForWorktree(cwd) {
@@ -13934,26 +14115,27 @@ function gitDirectoryForWorktree(cwd) {
13934
14115
  return gitDir;
13935
14116
  }
13936
14117
  function captureGitWorktreeIdentitySnapshot(setup) {
13937
- validateWorktreeOutsideInvokingCheckout(setup.worktreeRoot, setup.repositoryRoot);
13938
- validateExistingGitWorktreeRoot(setup.worktreeRoot, setup.repositoryRoot);
13939
- const stats = fs3.statSync(setup.worktreeRoot);
14118
+ const { worktreeRoot, repositoryRoot } = setup.result;
14119
+ assertSafeGitWorktreeTarget(worktreeRoot, setup.invokingRoot);
14120
+ const commonDir = validateGitWorktreeRoot(worktreeRoot);
14121
+ const stats = fs4.statSync(worktreeRoot);
13940
14122
  return {
13941
- worktreeRealPath: comparableRealPath(setup.worktreeRoot),
13942
- repositoryRealPath: comparableRealPath(setup.repositoryRoot),
13943
- gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(setup.worktreeRoot)),
13944
- commonDirRealPath: comparableRealPath(gitCommonDirForWorktree(setup.worktreeRoot)),
14123
+ worktreeRealPath: comparableRealPath(worktreeRoot),
14124
+ repositoryRealPath: comparableRealPath(repositoryRoot),
14125
+ gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(worktreeRoot)),
14126
+ commonDirRealPath: comparableRealPath(commonDir),
13945
14127
  device: stats.dev,
13946
14128
  inode: stats.ino
13947
14129
  };
13948
14130
  }
13949
14131
  function captureGitWorktreeIdentity(setup) {
13950
14132
  const snapshot = captureGitWorktreeIdentitySnapshot(setup);
13951
- return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.worktreeRoot) };
14133
+ return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.result.worktreeRoot) };
13952
14134
  }
13953
14135
  function assertCachedGitWorktreeIdentity(cached, options) {
13954
14136
  let current;
13955
14137
  try {
13956
- current = captureGitWorktreeIdentitySnapshot(cached.result);
14138
+ current = captureGitWorktreeIdentitySnapshot(cached);
13957
14139
  cached.identity.generation.assertCurrent();
13958
14140
  } catch (error) {
13959
14141
  const message = error instanceof Error ? error.message : String(error);
@@ -13961,34 +14143,58 @@ function assertCachedGitWorktreeIdentity(cached, options) {
13961
14143
  }
13962
14144
  const expected = cached.identity;
13963
14145
  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) {
13964
- throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended same-repository worktree.`);
13965
- }
14146
+ throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended worktree.`);
14147
+ }
14148
+ }
14149
+ function requireInvokingRepository(request, action) {
14150
+ if (request.repository !== undefined)
14151
+ return request.repository;
14152
+ throw new Error([
14153
+ `gitWorktreeDir requires the workflow to be invoked from inside a Git repository to ${action}.`,
14154
+ "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.",
14155
+ `Git reported: ${request.repositoryProbeFailure ?? "no repository"}`
14156
+ ].join(" "));
14157
+ }
14158
+ function setupGitWorktreeFromRequest(request, ownerRunId) {
14159
+ const { repository, target } = request;
14160
+ assertSafeGitWorktreeTarget(target, repository?.root);
14161
+ const entry = pathStatSync(target);
14162
+ if (entry === undefined)
14163
+ return createGitWorktreeAtPath(request, false);
14164
+ if (!entry.isDirectory())
14165
+ throw new Error(`gitWorktreeDir already exists but is not a directory: ${target}`);
14166
+ if (fs4.readdirSync(target).length === 0)
14167
+ return createGitWorktreeAtPath(request, true);
14168
+ const commonDir = existingGitWorktreeCommonDir(target);
14169
+ if (commonDir === undefined)
14170
+ return allocateGitWorktree(request, ownerRunId);
14171
+ const sameRepository = repository !== undefined && sameGitCommonDir(commonDir, gitCommonDirForWorktree(repository.root));
14172
+ return {
14173
+ result: {
14174
+ worktreeRoot: target,
14175
+ cwd: sameRepository ? workspaceCwdForGitWorktreeRoot(target, repository.relativeCwd) : target,
14176
+ repositoryRoot: sameRepository ? repository.root : target,
14177
+ created: false
14178
+ },
14179
+ ...repository !== undefined ? { invokingRoot: repository.root } : {}
14180
+ };
13966
14181
  }
13967
- function setupGitWorktree(options) {
13968
- const repoRoot = repositoryRootForGitWorktree(options.cwd);
13969
- const mainRoot = findCanonicalGitRoot(repoRoot);
14182
+ function createGitWorktreeAtPath(request, existingEmptyDirectory) {
14183
+ const { target: worktreeRoot } = request;
14184
+ const repository = requireInvokingRepository(request, `create a new worktree at ${worktreeRoot}`);
14185
+ const mainRoot = findCanonicalGitRoot(repository.root);
13970
14186
  if (mainRoot === undefined) {
13971
- throw new Error(`Unable to resolve the canonical main Git repository root from ${repoRoot}.`);
14187
+ throw new Error(`Unable to resolve the canonical main Git repository root from ${repository.root}.`);
13972
14188
  }
13973
- const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
13974
- const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
13975
- validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
13976
- if (pathExistsSync(worktreeRoot)) {
13977
- validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
13978
- return {
13979
- worktreeRoot,
13980
- cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
13981
- repositoryRoot: repoRoot,
13982
- created: false
13983
- };
13984
- }
13985
- try {
13986
- fs3.mkdirSync(path3.dirname(worktreeRoot), { recursive: true });
13987
- } catch (error) {
13988
- const message = error instanceof Error ? error.message : String(error);
13989
- throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
14189
+ if (!existingEmptyDirectory) {
14190
+ try {
14191
+ fs4.mkdirSync(path4.dirname(worktreeRoot), { recursive: true });
14192
+ } catch (error) {
14193
+ const message = error instanceof Error ? error.message : String(error);
14194
+ throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
14195
+ }
13990
14196
  }
13991
- const baseRef = options.baseBranch?.trim() || "HEAD";
14197
+ const baseRef = request.options.baseBranch?.trim() || "HEAD";
13992
14198
  const result = runGit(mainRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
13993
14199
  if (result.status !== 0) {
13994
14200
  throw new Error([
@@ -13998,30 +14204,127 @@ function setupGitWorktree(options) {
13998
14204
  `));
13999
14205
  }
14000
14206
  try {
14001
- validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
14002
- validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
14207
+ validateCreatedGitWorktree(worktreeRoot, repository);
14003
14208
  } catch (error) {
14004
14209
  runGit(mainRoot, ["worktree", "remove", "--force", worktreeRoot]);
14005
14210
  const message = error instanceof Error ? error.message : String(error);
14006
14211
  throw new Error(`Created gitWorktreeDir failed post-creation validation: ${message}`);
14007
14212
  }
14008
14213
  return {
14009
- worktreeRoot,
14010
- cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
14011
- repositoryRoot: repoRoot,
14012
- created: true
14214
+ result: {
14215
+ worktreeRoot,
14216
+ cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, repository.relativeCwd),
14217
+ repositoryRoot: repository.root,
14218
+ created: true
14219
+ },
14220
+ invokingRoot: repository.root
14013
14221
  };
14014
14222
  }
14223
+ function containedWorktreeCwd(checkout, relativeCwd) {
14224
+ const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
14225
+ let resolved;
14226
+ try {
14227
+ resolved = fs4.realpathSync.native(cwd);
14228
+ } catch {
14229
+ resolved = "";
14230
+ }
14231
+ const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
14232
+ if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
14233
+ throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
14234
+ }
14235
+ return cwd;
14236
+ }
14237
+ function allocatedGitWorktreeSetup(checkout, repository, created) {
14238
+ return {
14239
+ result: {
14240
+ worktreeRoot: checkout,
14241
+ cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
14242
+ repositoryRoot: repository.root,
14243
+ created
14244
+ },
14245
+ invokingRoot: repository.root
14246
+ };
14247
+ }
14248
+ function validateOwnedGitWorktree(checkout, repository) {
14249
+ validateCreatedGitWorktree(checkout, repository);
14250
+ const gitDir = gitDirectoryForWorktree(checkout);
14251
+ if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
14252
+ throw new Error(`${checkout} is not a linked worktree`);
14253
+ }
14254
+ const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
14255
+ if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
14256
+ throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
14257
+ }
14258
+ }
14259
+ function findOwnedGitWorktree(root, repository, ownerRunId) {
14260
+ const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
14261
+ if (checkout === undefined)
14262
+ return;
14263
+ try {
14264
+ validateOwnedGitWorktree(checkout, repository);
14265
+ return allocatedGitWorktreeSetup(checkout, repository, false);
14266
+ } catch (error) {
14267
+ const message = error instanceof Error ? error.message : String(error);
14268
+ throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
14269
+ }
14270
+ }
14271
+ function allocateGitWorktree(request, ownerRunId) {
14272
+ const { target: root } = request;
14273
+ const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
14274
+ if (ownerRunId !== undefined) {
14275
+ const owned = findOwnedGitWorktree(root, repository, ownerRunId);
14276
+ if (owned !== undefined)
14277
+ return owned;
14278
+ }
14279
+ const baseRef = request.options.baseBranch?.trim() || "HEAD";
14280
+ const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
14281
+ const commit = revision.status === 0 ? revision.stdout.trim() : "";
14282
+ if (commit === "") {
14283
+ throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
14284
+ }
14285
+ const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
14286
+ const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
14287
+ if (add.status !== 0) {
14288
+ removeEmptyWorktreeBucket(checkout);
14289
+ throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
14290
+ }
14291
+ try {
14292
+ const gitDir = gitDirectoryForWorktree(checkout);
14293
+ runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
14294
+ runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
14295
+ validateCreatedGitWorktree(checkout, repository);
14296
+ const setup = allocatedGitWorktreeSetup(checkout, repository, true);
14297
+ if (ownerRunId !== undefined)
14298
+ bindWorktreeOwner(gitDir, ownerRunId);
14299
+ return setup;
14300
+ } catch (error) {
14301
+ const message = error instanceof Error ? error.message : String(error);
14302
+ const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
14303
+ removeEmptyWorktreeBucket(checkout);
14304
+ const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
14305
+ throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
14306
+ }
14307
+ }
14308
+ function runGitOrThrow(cwd, args) {
14309
+ const result = runGit(cwd, args);
14310
+ if (result.status !== 0)
14311
+ throw new Error(gitFailureMessage(result));
14312
+ }
14313
+ function setupGitWorktree(options) {
14314
+ return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
14315
+ }
14015
14316
  var init_worktree_git = __esm(() => {
14317
+ init_worktree_allocation();
14016
14318
  init_worktree_generation();
14017
14319
  init_worktree_git_runner();
14018
14320
  init_worktree_root();
14321
+ init_worktree_allocation();
14019
14322
  init_worktree_git_runner();
14020
14323
  });
14021
14324
 
14022
14325
  // dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
14023
- function createGitWorktreeSetupCacheOwner(suppliedCache) {
14024
- const cache = suppliedCache ?? createGitWorktreeSetupCache();
14326
+ function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
14327
+ const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
14025
14328
  const ownsCache = suppliedCache === undefined;
14026
14329
  let released = false;
14027
14330
  return {
@@ -14042,20 +14345,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
14042
14345
  });
14043
14346
 
14044
14347
  // dist/builtin/workflows/src/runs/shared/worktree-diff.ts
14045
- import * as fs4 from "node:fs";
14046
- import * as path4 from "node:path";
14348
+ import * as fs5 from "node:fs";
14349
+ import * as path5 from "node:path";
14047
14350
  function safePatchAgentName(agent) {
14048
14351
  return agent.replace(/[^\w.-]/g, "_");
14049
14352
  }
14050
14353
  function removeSyntheticPath(worktree, syntheticPath) {
14051
- const resolved = path4.resolve(worktree.path, syntheticPath);
14052
- const relative = path4.relative(worktree.path, resolved);
14053
- if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative)) {
14354
+ const resolved = path5.resolve(worktree.path, syntheticPath);
14355
+ const relative = path5.relative(worktree.path, resolved);
14356
+ if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path5.sep}`) || path5.isAbsolute(relative)) {
14054
14357
  return;
14055
14358
  }
14056
14359
  let stat;
14057
14360
  try {
14058
- stat = fs4.lstatSync(resolved);
14361
+ stat = fs5.lstatSync(resolved);
14059
14362
  } catch (error) {
14060
14363
  const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
14061
14364
  if (code === "ENOENT")
@@ -14063,14 +14366,14 @@ function removeSyntheticPath(worktree, syntheticPath) {
14063
14366
  throw error;
14064
14367
  }
14065
14368
  if (stat.isSymbolicLink()) {
14066
- fs4.unlinkSync(resolved);
14369
+ fs5.unlinkSync(resolved);
14067
14370
  return;
14068
14371
  }
14069
14372
  if (stat.isDirectory()) {
14070
- fs4.rmSync(resolved, { recursive: true, force: true });
14373
+ fs5.rmSync(resolved, { recursive: true, force: true });
14071
14374
  return;
14072
14375
  }
14073
- fs4.rmSync(resolved, { force: true });
14376
+ fs5.rmSync(resolved, { force: true });
14074
14377
  }
14075
14378
  function removeSyntheticPathsBeforeDiff(worktree) {
14076
14379
  if (worktree.syntheticPaths.length === 0)
@@ -14119,7 +14422,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
14119
14422
  const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
14120
14423
  const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
14121
14424
  const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
14122
- fs4.writeFileSync(patchPath, patch, "utf-8");
14425
+ fs5.writeFileSync(patchPath, patch, "utf-8");
14123
14426
  if (!patch.trim()) {
14124
14427
  return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
14125
14428
  }
@@ -14137,7 +14440,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
14137
14440
  }
14138
14441
  function writeEmptyPatch(patchPath) {
14139
14442
  try {
14140
- fs4.writeFileSync(patchPath, "", "utf-8");
14443
+ fs5.writeFileSync(patchPath, "", "utf-8");
14141
14444
  } catch {}
14142
14445
  }
14143
14446
  function hasWorktreeChanges(diff) {
@@ -14145,7 +14448,7 @@ function hasWorktreeChanges(diff) {
14145
14448
  }
14146
14449
  function diffWorktrees(setup, agents, diffsDir) {
14147
14450
  try {
14148
- fs4.mkdirSync(diffsDir, { recursive: true });
14451
+ fs5.mkdirSync(diffsDir, { recursive: true });
14149
14452
  } catch {
14150
14453
  return [];
14151
14454
  }
@@ -14153,7 +14456,7 @@ function diffWorktrees(setup, agents, diffsDir) {
14153
14456
  for (let index = 0;index < setup.worktrees.length; index++) {
14154
14457
  const worktree = setup.worktrees[index];
14155
14458
  const agent = agents[index] ?? `task-${index + 1}`;
14156
- const patchPath = path4.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
14459
+ const patchPath = path5.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
14157
14460
  try {
14158
14461
  diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
14159
14462
  } catch {
@@ -14175,7 +14478,7 @@ function formatWorktreeDiffSummary(diffs) {
14175
14478
  }
14176
14479
  lines.push("");
14177
14480
  }
14178
- const patchesDir = path4.dirname(changed[0].patchPath);
14481
+ const patchesDir = path5.dirname(changed[0].patchPath);
14179
14482
  lines.push(`Full patches: ${patchesDir}`);
14180
14483
  return lines.join(`
14181
14484
  `).trimEnd();
@@ -14185,8 +14488,8 @@ var init_worktree_diff = __esm(() => {
14185
14488
  });
14186
14489
 
14187
14490
  // dist/builtin/workflows/src/runs/shared/worktree-post-create.ts
14188
- import * as fs5 from "node:fs";
14189
- import * as path5 from "node:path";
14491
+ import * as fs6 from "node:fs";
14492
+ import * as path6 from "node:path";
14190
14493
  function tracked(repo, relativePath) {
14191
14494
  const result = runGit(repo, ["ls-files", "--error-unmatch", "--", relativePath]);
14192
14495
  return result.status === 0;
@@ -14206,12 +14509,12 @@ function hasTrackedPathComponent(repo, relativePath) {
14206
14509
  return false;
14207
14510
  }
14208
14511
  function copyUntrackedFile(mainRoot, worktreeRoot, relativePath) {
14209
- const source = path5.join(mainRoot, relativePath);
14210
- const destination = path5.join(worktreeRoot, relativePath);
14211
- if (!fs5.existsSync(source) || fs5.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14512
+ const source = path6.join(mainRoot, relativePath);
14513
+ const destination = path6.join(worktreeRoot, relativePath);
14514
+ if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14212
14515
  return false;
14213
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14214
- fs5.copyFileSync(source, destination);
14516
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14517
+ fs6.copyFileSync(source, destination);
14215
14518
  return true;
14216
14519
  }
14217
14520
  function propagateLocalSettings(mainRoot, worktreeRoot) {
@@ -14224,14 +14527,14 @@ function propagateLocalSettings(mainRoot, worktreeRoot) {
14224
14527
  return copied;
14225
14528
  }
14226
14529
  function populatedHooksDirectory(mainRoot) {
14227
- const husky = path5.join(mainRoot, ".husky");
14530
+ const husky = path6.join(mainRoot, ".husky");
14228
14531
  try {
14229
- if (fs5.statSync(husky).isDirectory())
14532
+ if (fs6.statSync(husky).isDirectory())
14230
14533
  return husky;
14231
14534
  } catch {}
14232
- const hooks = path5.join(mainRoot, ".git", "hooks");
14535
+ const hooks = path6.join(mainRoot, ".git", "hooks");
14233
14536
  try {
14234
- const populated = fs5.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
14537
+ const populated = fs6.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
14235
14538
  return populated ? hooks : undefined;
14236
14539
  } catch {
14237
14540
  return;
@@ -14242,7 +14545,7 @@ function configureSharedHooksPath(mainRoot) {
14242
14545
  if (desired === undefined)
14243
14546
  return;
14244
14547
  const current = runGitPlain(mainRoot, ["config", "--get", "core.hooksPath"]);
14245
- if (current.status === 0 && path5.resolve(mainRoot, current.stdout.trim()) === desired)
14548
+ if (current.status === 0 && path6.resolve(mainRoot, current.stdout.trim()) === desired)
14246
14549
  return;
14247
14550
  const configured = runGitPlain(mainRoot, ["config", "core.hooksPath", desired]);
14248
14551
  if (configured.status !== 0) {
@@ -14251,10 +14554,10 @@ function configureSharedHooksPath(mainRoot) {
14251
14554
  }
14252
14555
  function normalizeSymlinkDirectory(value2) {
14253
14556
  const trimmed = value2.trim();
14254
- if (!trimmed || path5.isAbsolute(trimmed))
14557
+ if (!trimmed || path6.isAbsolute(trimmed))
14255
14558
  return;
14256
- const normalized = path5.normalize(trimmed);
14257
- if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path5.sep}`))
14559
+ const normalized = path6.normalize(trimmed);
14560
+ if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path6.sep}`))
14258
14561
  return;
14259
14562
  return normalized;
14260
14563
  }
@@ -14264,20 +14567,20 @@ function symlinkConfiguredDirectories(mainRoot, worktreeRoot, directories) {
14264
14567
  const relativePath = normalizeSymlinkDirectory(rawDirectory);
14265
14568
  if (relativePath === undefined || synthetic.includes(relativePath))
14266
14569
  continue;
14267
- const source = path5.join(mainRoot, relativePath);
14268
- const destination = path5.join(worktreeRoot, relativePath);
14269
- if (!fs5.existsSync(source) || fs5.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14570
+ const source = path6.join(mainRoot, relativePath);
14571
+ const destination = path6.join(worktreeRoot, relativePath);
14572
+ if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
14270
14573
  continue;
14271
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14574
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14272
14575
  try {
14273
- fs5.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
14576
+ fs6.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
14274
14577
  synthetic.push(relativePath);
14275
14578
  } catch {}
14276
14579
  }
14277
14580
  return synthetic;
14278
14581
  }
14279
14582
  function copyWorktreeIncludes(mainRoot, worktreeRoot) {
14280
- if (!fs5.existsSync(path5.join(mainRoot, ".worktreeinclude")))
14583
+ if (!fs6.existsSync(path6.join(mainRoot, ".worktreeinclude")))
14281
14584
  return;
14282
14585
  const ignored = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-standard"]);
14283
14586
  const included = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-from=.worktreeinclude"]);
@@ -14287,13 +14590,13 @@ function copyWorktreeIncludes(mainRoot, worktreeRoot) {
14287
14590
  for (const relativePath of included.stdout.split(/\r?\n/).filter(Boolean)) {
14288
14591
  if (!ignoredPaths.has(relativePath) || hasTrackedPathComponent(worktreeRoot, relativePath))
14289
14592
  continue;
14290
- const source = path5.join(mainRoot, relativePath);
14291
- const destination = path5.join(worktreeRoot, relativePath);
14593
+ const source = path6.join(mainRoot, relativePath);
14594
+ const destination = path6.join(worktreeRoot, relativePath);
14292
14595
  try {
14293
- if (!fs5.statSync(source).isFile() || fs5.existsSync(destination))
14596
+ if (!fs6.statSync(source).isFile() || fs6.existsSync(destination))
14294
14597
  continue;
14295
- fs5.mkdirSync(path5.dirname(destination), { recursive: true });
14296
- fs5.copyFileSync(source, destination);
14598
+ fs6.mkdirSync(path6.dirname(destination), { recursive: true });
14599
+ fs6.copyFileSync(source, destination);
14297
14600
  } catch {}
14298
14601
  }
14299
14602
  }
@@ -14310,9 +14613,9 @@ var init_worktree_post_create = __esm(() => {
14310
14613
 
14311
14614
  // dist/builtin/workflows/src/runs/shared/worktree-setup.ts
14312
14615
  import { spawnSync as spawnSync2 } from "node:child_process";
14313
- import * as fs6 from "node:fs";
14616
+ import * as fs7 from "node:fs";
14314
14617
  import * as os from "node:os";
14315
- import * as path6 from "node:path";
14618
+ import * as path7 from "node:path";
14316
14619
  import { createChildProcessEnvironment as createChildProcessEnvironment2 } from "@bastani/atomic";
14317
14620
  function originDefaultBranch(mainRoot) {
14318
14621
  const symbolic = runGit(mainRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
@@ -14332,7 +14635,7 @@ function originDefaultBranch(mainRoot) {
14332
14635
  }
14333
14636
  function resolveRepoState(cwd, explicitBaseBranch) {
14334
14637
  const cwdRelative = resolveRepoCwdRelative(cwd);
14335
- const toplevel = path6.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
14638
+ const toplevel = path7.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
14336
14639
  const mainRoot = findCanonicalGitRoot(toplevel);
14337
14640
  if (mainRoot === undefined)
14338
14641
  throw new Error(`unable to resolve canonical main Git repository root from ${toplevel}`);
@@ -14345,9 +14648,9 @@ function resolveRepoState(cwd, explicitBaseBranch) {
14345
14648
  return { toplevel, mainRoot, cwdRelative, baseCommit, baseRef };
14346
14649
  }
14347
14650
  function normalizeComparableCwd(cwd) {
14348
- const resolved = path6.resolve(cwd);
14651
+ const resolved = path7.resolve(cwd);
14349
14652
  try {
14350
- return fs6.realpathSync(resolved);
14653
+ return fs7.realpathSync(resolved);
14351
14654
  } catch {
14352
14655
  return resolved;
14353
14656
  }
@@ -14358,7 +14661,7 @@ function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
14358
14661
  const task = tasks[index];
14359
14662
  if (!task.cwd)
14360
14663
  continue;
14361
- const taskCwd = path6.isAbsolute(task.cwd) ? task.cwd : path6.resolve(sharedCwd, task.cwd);
14664
+ const taskCwd = path7.isAbsolute(task.cwd) ? task.cwd : path7.resolve(sharedCwd, task.cwd);
14362
14665
  if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
14363
14666
  continue;
14364
14667
  return { index, agent: task.agent, cwd: task.cwd };
@@ -14375,12 +14678,12 @@ function buildWorktreeBranch(runId, index) {
14375
14678
  return `worktree-${flattenedWorktreeName(runId, index)}`;
14376
14679
  }
14377
14680
  function buildWorktreePath(mainRoot, runId, index) {
14378
- return path6.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
14681
+ return path7.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
14379
14682
  }
14380
14683
  function ensureWorktreeIgnore(mainRoot) {
14381
- const worktreesRoot = path6.join(mainRoot, ".atomic", "worktrees");
14382
- fs6.mkdirSync(worktreesRoot, { recursive: true });
14383
- fs6.writeFileSync(path6.join(worktreesRoot, ".gitignore"), `*
14684
+ const worktreesRoot = path7.join(mainRoot, ".atomic", "worktrees");
14685
+ fs7.mkdirSync(worktreesRoot, { recursive: true });
14686
+ fs7.writeFileSync(path7.join(worktreesRoot, ".gitignore"), `*
14384
14687
  `, "utf8");
14385
14688
  }
14386
14689
  function resolveRepoCwdRelative(cwd) {
@@ -14389,7 +14692,7 @@ function resolveRepoCwdRelative(cwd) {
14389
14692
  throw new Error("worktree isolation requires a git repository");
14390
14693
  }
14391
14694
  const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
14392
- const normalizedPrefix = rawPrefix ? path6.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
14695
+ const normalizedPrefix = rawPrefix ? path7.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
14393
14696
  return normalizedPrefix === "." ? "" : normalizedPrefix;
14394
14697
  }
14395
14698
  function parseHookTimeout(timeoutMs) {
@@ -14407,19 +14710,19 @@ function resolveWorktreeSetupHook(repoRoot, config) {
14407
14710
  if (!hookPath) {
14408
14711
  throw new Error("worktree setup hook path cannot be empty");
14409
14712
  }
14410
- const expandedHookPath = hookPath.startsWith("~/") ? path6.join(os.homedir(), hookPath.slice(2)) : hookPath;
14713
+ const expandedHookPath = hookPath.startsWith("~/") ? path7.join(os.homedir(), hookPath.slice(2)) : hookPath;
14411
14714
  let resolvedPath;
14412
- if (path6.isAbsolute(expandedHookPath)) {
14715
+ if (path7.isAbsolute(expandedHookPath)) {
14413
14716
  resolvedPath = expandedHookPath;
14414
14717
  } else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
14415
- resolvedPath = path6.resolve(repoRoot, expandedHookPath);
14718
+ resolvedPath = path7.resolve(repoRoot, expandedHookPath);
14416
14719
  } else {
14417
14720
  throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
14418
14721
  }
14419
- if (!fs6.existsSync(resolvedPath)) {
14722
+ if (!fs7.existsSync(resolvedPath)) {
14420
14723
  throw new Error(`worktree setup hook not found: ${resolvedPath}`);
14421
14724
  }
14422
- if (fs6.statSync(resolvedPath).isDirectory()) {
14725
+ if (fs7.statSync(resolvedPath).isDirectory()) {
14423
14726
  throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
14424
14727
  }
14425
14728
  return {
@@ -14431,17 +14734,17 @@ function normalizeSyntheticPath(worktreePath, rawPath) {
14431
14734
  const trimmed = rawPath.trim();
14432
14735
  if (!trimmed)
14433
14736
  throw new Error("synthetic path cannot be empty");
14434
- if (path6.isAbsolute(trimmed))
14737
+ if (path7.isAbsolute(trimmed))
14435
14738
  throw new Error(`synthetic path must be relative: ${rawPath}`);
14436
- const resolved = path6.resolve(worktreePath, trimmed);
14437
- const relative = path6.relative(worktreePath, resolved);
14739
+ const resolved = path7.resolve(worktreePath, trimmed);
14740
+ const relative = path7.relative(worktreePath, resolved);
14438
14741
  if (!relative || relative === ".") {
14439
14742
  throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
14440
14743
  }
14441
- if (relative === ".." || relative.startsWith(`..${path6.sep}`) || path6.isAbsolute(relative)) {
14744
+ if (relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative)) {
14442
14745
  throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
14443
14746
  }
14444
- return path6.normalize(relative);
14747
+ return path7.normalize(relative);
14445
14748
  }
14446
14749
  function hasTrackedEntries(worktreePath, relativePath) {
14447
14750
  const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
@@ -14513,16 +14816,16 @@ function waitForGitLockRelease() {
14513
14816
  }
14514
14817
  function unlinkWorktreeLinks(worktreePath, relativePaths) {
14515
14818
  for (const relativePath of new Set(relativePaths)) {
14516
- const target = path6.resolve(worktreePath, relativePath);
14517
- const relative = path6.relative(worktreePath, target);
14518
- if (!relative || relative === ".." || relative.startsWith(`..${path6.sep}`) || path6.isAbsolute(relative))
14819
+ const target = path7.resolve(worktreePath, relativePath);
14820
+ const relative = path7.relative(worktreePath, target);
14821
+ if (!relative || relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative))
14519
14822
  continue;
14520
14823
  let current = worktreePath;
14521
- for (const component of relative.split(path6.sep)) {
14522
- current = path6.join(current, component);
14824
+ for (const component of relative.split(path7.sep)) {
14825
+ current = path7.join(current, component);
14523
14826
  let stat;
14524
14827
  try {
14525
- stat = fs6.lstatSync(current);
14828
+ stat = fs7.lstatSync(current);
14526
14829
  } catch (error) {
14527
14830
  const code = error.code;
14528
14831
  if (code === "ENOENT" || code === "ENOTDIR")
@@ -14532,7 +14835,7 @@ function unlinkWorktreeLinks(worktreePath, relativePaths) {
14532
14835
  if (!stat.isSymbolicLink())
14533
14836
  continue;
14534
14837
  if (current === target)
14535
- fs6.unlinkSync(current);
14838
+ fs7.unlinkSync(current);
14536
14839
  break;
14537
14840
  }
14538
14841
  }
@@ -14560,7 +14863,7 @@ function createSingleWorktree(mainRoot, cwdRelative, runId, index, baseRef, base
14560
14863
  cleanupSingleWorktree(mainRoot, { path: worktreePath, branch }, []);
14561
14864
  throw new Error(message);
14562
14865
  }
14563
- const agentCwd = cwdRelative ? path6.join(worktreePath, cwdRelative) : worktreePath;
14866
+ const agentCwd = cwdRelative ? path7.join(worktreePath, cwdRelative) : worktreePath;
14564
14867
  const syntheticPaths = [];
14565
14868
  try {
14566
14869
  syntheticPaths.push(...performPostCreationSetup(mainRoot, worktreePath, symlinkDirectories));
@@ -14629,8 +14932,8 @@ var init_worktree = __esm(() => {
14629
14932
  });
14630
14933
 
14631
14934
  // dist/builtin/workflows/src/runs/shared/worktree-cwd.ts
14632
- import { lstatSync as lstatSync5, realpathSync as realpathSync4 } from "node:fs";
14633
- import { dirname as dirname8, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve6, sep as sep5 } from "node:path";
14935
+ import { lstatSync as lstatSync6, realpathSync as realpathSync4 } from "node:fs";
14936
+ import { dirname as dirname9, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve7, sep as sep5 } from "node:path";
14634
14937
  function relativePathWithin(root, candidate) {
14635
14938
  const path = relative4(root, candidate);
14636
14939
  return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path) ? undefined : path;
@@ -14649,14 +14952,14 @@ function resolveWorktreeStageCwd(cwd, setup) {
14649
14952
  if (cwd === undefined || cwd.length === 0)
14650
14953
  return;
14651
14954
  const absoluteInput = isAbsolute6(cwd);
14652
- const candidate = absoluteInput ? cwd : resolve6(setup.cwd, cwd);
14955
+ const candidate = absoluteInput ? cwd : resolve7(setup.cwd, cwd);
14653
14956
  if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
14654
14957
  throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
14655
14958
  }
14656
14959
  const candidateRealPath = existingRealPath(candidate, "cwd");
14657
14960
  const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
14658
14961
  if (worktreeRelative !== undefined)
14659
- return resolve6(setup.worktreeRoot, worktreeRelative);
14962
+ return resolve7(setup.worktreeRoot, worktreeRelative);
14660
14963
  if (!isAbsolute6(cwd)) {
14661
14964
  throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
14662
14965
  }
@@ -14665,9 +14968,9 @@ function resolveWorktreeStageCwd(cwd, setup) {
14665
14968
  }
14666
14969
  const repositoryRelative = absoluteInput ? relativePathWithin(repositoryRoot, candidateRealPath) : undefined;
14667
14970
  if (repositoryRelative === undefined) {
14668
- 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.`);
14971
+ 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.`);
14669
14972
  }
14670
- const mappedCwd = resolve6(setup.worktreeRoot, repositoryRelative);
14973
+ const mappedCwd = resolve7(setup.worktreeRoot, repositoryRelative);
14671
14974
  const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
14672
14975
  if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
14673
14976
  throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
@@ -14678,7 +14981,7 @@ var init_worktree_cwd = () => {};
14678
14981
 
14679
14982
  // dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts
14680
14983
  import { existsSync as existsSync3 } from "node:fs";
14681
- import { isAbsolute as isAbsolute7, resolve as resolve7 } from "node:path";
14984
+ import { isAbsolute as isAbsolute7, resolve as resolve8 } from "node:path";
14682
14985
  function normalizeTaskContexts(previous) {
14683
14986
  if (previous === undefined)
14684
14987
  return [];
@@ -14731,7 +15034,7 @@ function taskPrevious(options) {
14731
15034
  function resolveWorkflowPath(filePath, baseDir) {
14732
15035
  if (isAbsolute7(filePath))
14733
15036
  return filePath;
14734
- return resolve7(baseDir ?? process.cwd(), filePath);
15037
+ return resolve8(baseDir ?? process.cwd(), filePath);
14735
15038
  }
14736
15039
  function taskBaseDir(options) {
14737
15040
  if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
@@ -14886,7 +15189,7 @@ function taskWithSharedDefaults(taskOptions, options) {
14886
15189
  var init_executor_task_prompts = () => {};
14887
15190
 
14888
15191
  // dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
14889
- import { isAbsolute as isAbsolute8, join as join11, resolve as resolve8 } from "node:path";
15192
+ import { isAbsolute as isAbsolute8, join as join12, resolve as resolve9 } from "node:path";
14890
15193
  import { CONFIG_DIR_NAME } from "@bastani/atomic";
14891
15194
  function positiveConcurrency(value2) {
14892
15195
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < 1)
@@ -15039,10 +15342,10 @@ function workflowInvocationMetadata(inputDefaults, workflowInvocationCwd, cache,
15039
15342
  function resolvedTaskCwd(cwd, workflowInvocationCwd) {
15040
15343
  if (cwd === undefined)
15041
15344
  return;
15042
- return isAbsolute8(cwd) ? cwd : resolve8(workflowInvocationCwd, cwd);
15345
+ return isAbsolute8(cwd) ? cwd : resolve9(workflowInvocationCwd, cwd);
15043
15346
  }
15044
15347
  function taskWorktreeOutputsRoot(runId) {
15045
- return join11(workflowArtifactRunPath(runId), "task-outputs");
15348
+ return join12(workflowArtifactRunPath(runId), "task-outputs");
15046
15349
  }
15047
15350
  function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCwd = process.cwd(), symlinkDirectories) {
15048
15351
  if (options.worktree !== true && !tasks.some((task) => task.worktree === true)) {
@@ -15052,7 +15355,7 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
15052
15355
  throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
15053
15356
  }
15054
15357
  const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
15055
- const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve8(workflowInvocationCwd, explicitCwd);
15358
+ const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve9(workflowInvocationCwd, explicitCwd);
15056
15359
  const conflict = findWorktreeTaskCwdConflict(tasks.map((task) => ({ agent: task.name, cwd: resolvedTaskCwd(task.cwd, workflowInvocationCwd) })), sharedCwd);
15057
15360
  if (conflict !== undefined)
15058
15361
  throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
@@ -15067,9 +15370,9 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
15067
15370
  tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index].agentCwd })),
15068
15371
  setup,
15069
15372
  agents,
15070
- diffsDir: join11(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
15373
+ diffsDir: join12(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
15071
15374
  outputIsolations: tasks.map((_, index) => ({
15072
- baseDir: join11(trustedRoot, runId, scope, String(index)),
15375
+ baseDir: join12(trustedRoot, runId, scope, String(index)),
15073
15376
  trustedRoot
15074
15377
  }))
15075
15378
  };
@@ -16796,8 +17099,12 @@ function createStageControlRegistry() {
16796
17099
  }
16797
17100
  await disposeEntries(entries);
16798
17101
  },
16799
- async releaseIdle(runId) {
16800
- for (const [stageId, entry] of [..._byRun.get(runId) ?? []]) {
17102
+ async releaseIdle(runId, only) {
17103
+ const runMap = _byRun.get(runId);
17104
+ const entries = only === undefined ? [...runMap ?? []] : [[only, runMap?.get(only)]];
17105
+ for (const [stageId, entry] of entries) {
17106
+ if (entry === undefined)
17107
+ continue;
16801
17108
  try {
16802
17109
  await releaseIdleEntry(runId, stageId, entry);
16803
17110
  } catch (error) {
@@ -16858,8 +17165,8 @@ var init_possible_stages = __esm(() => {
16858
17165
 
16859
17166
  // dist/builtin/workflows/src/workers/pool-journal.ts
16860
17167
  import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
16861
- import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
16862
- import { basename as basename5, dirname as dirname9, join as join12, resolve as resolve9 } from "node:path";
17168
+ import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
17169
+ import { basename as basename5, dirname as dirname10, join as join13, resolve as resolve10 } from "node:path";
16863
17170
  import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
16864
17171
  function encodeOption(value2) {
16865
17172
  if (typeof value2 === "bigint")
@@ -16881,7 +17188,7 @@ function isReopenableSelection(selection) {
16881
17188
  }
16882
17189
  function encodeSelection(selection) {
16883
17190
  if (selection.kind === "sqlite")
16884
- return JSON.stringify({ ...selection, path: resolve9(selection.path) });
17191
+ return JSON.stringify({ ...selection, path: resolve10(selection.path) });
16885
17192
  return JSON.stringify({
16886
17193
  ...selection,
16887
17194
  ...selection.options === undefined ? {} : {
@@ -16913,7 +17220,7 @@ function openDurableJournal(durable) {
16913
17220
  return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
16914
17221
  }
16915
17222
  function poolStateDirectory(agentDir) {
16916
- return join12(dirname9(agentDir), "workflows", "pool");
17223
+ return join13(dirname10(agentDir), "workflows", "pool");
16917
17224
  }
16918
17225
  function databaseIdentity(selection, agentDir) {
16919
17226
  return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
@@ -16921,16 +17228,16 @@ function databaseIdentity(selection, agentDir) {
16921
17228
  function coordinationPath(durable) {
16922
17229
  const selection = decodeSelection(durable.selection);
16923
17230
  const identity = createHash3("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
16924
- return join12(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
17231
+ return join13(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
16925
17232
  }
16926
17233
  function coordinationDatabase(durable) {
16927
17234
  return basename5(coordinationPath(durable), ".sqlite");
16928
17235
  }
16929
17236
  function openCoordinationJournal(path) {
16930
- const file = resolve9(path);
17237
+ const file = resolve10(path);
16931
17238
  let opened = coordinationJournals.get(file);
16932
17239
  if (opened === undefined) {
16933
- mkdirSync5(dirname9(file), { recursive: true });
17240
+ mkdirSync6(dirname10(file), { recursive: true });
16934
17241
  opened = resolveRunJournal({ journal: { path: file } });
16935
17242
  coordinationJournals.set(file, opened);
16936
17243
  opened.catch(() => {
@@ -16947,20 +17254,20 @@ function poolJournalFor(journal) {
16947
17254
  return coordinations.get(journal) ?? journal;
16948
17255
  }
16949
17256
  function poolHostId(agentDir) {
16950
- const file = join12(poolStateDirectory(agentDir), "host-id");
17257
+ const file = join13(poolStateDirectory(agentDir), "host-id");
16951
17258
  try {
16952
- const existing = readFileSync2(file, "utf8").trim();
17259
+ const existing = readFileSync4(file, "utf8").trim();
16953
17260
  if (existing !== "")
16954
17261
  return existing;
16955
17262
  } catch {}
16956
- mkdirSync5(dirname9(file), { recursive: true });
17263
+ mkdirSync6(dirname10(file), { recursive: true });
16957
17264
  const id = randomUUID6();
16958
17265
  try {
16959
- writeFileSync3(file, `${id}
17266
+ writeFileSync4(file, `${id}
16960
17267
  `, { flag: "wx" });
16961
17268
  return id;
16962
17269
  } catch {
16963
- return readFileSync2(file, "utf8").trim();
17270
+ return readFileSync4(file, "utf8").trim();
16964
17271
  }
16965
17272
  }
16966
17273
  var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
@@ -16975,7 +17282,7 @@ var init_pool_journal = __esm(() => {
16975
17282
 
16976
17283
  // dist/builtin/workflows/src/workers/admission-host.ts
16977
17284
  import { execFile, execFileSync } from "node:child_process";
16978
- import { readdirSync as readdirSync2, readFileSync as readFileSync3 } from "node:fs";
17285
+ import { readdirSync as readdirSync4, readFileSync as readFileSync5 } from "node:fs";
16979
17286
  import { readFile } from "node:fs/promises";
16980
17287
  import { hostname } from "node:os";
16981
17288
  function admissionBootIdentity() {
@@ -17001,13 +17308,32 @@ function admissionProcessStopped(pid) {
17001
17308
  return error.code === "ESRCH";
17002
17309
  }
17003
17310
  }
17311
+ function workerProcessExited(pid, final = false) {
17312
+ if (admissionProcessStopped(pid))
17313
+ return true;
17314
+ if (process.platform === "linux") {
17315
+ try {
17316
+ const stat = readFileSync5(`/proc/${pid}/stat`, "utf8");
17317
+ return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
17318
+ } catch {
17319
+ return admissionProcessStopped(pid);
17320
+ }
17321
+ }
17322
+ if (!final)
17323
+ return false;
17324
+ try {
17325
+ return execFileSync("ps", ["-o", "stat=", "-p", String(pid)], { encoding: "utf8", timeout: 5000 }).trim().startsWith("Z");
17326
+ } catch {
17327
+ return admissionProcessStopped(pid);
17328
+ }
17329
+ }
17004
17330
  function scanProcessGroup(group) {
17005
17331
  const members = new Map;
17006
17332
  if (process.platform === "linux") {
17007
17333
  let complete = true;
17008
17334
  let entries;
17009
17335
  try {
17010
- entries = readdirSync2("/proc");
17336
+ entries = readdirSync4("/proc");
17011
17337
  } catch {
17012
17338
  return { members, complete: false };
17013
17339
  }
@@ -17016,7 +17342,7 @@ function scanProcessGroup(group) {
17016
17342
  continue;
17017
17343
  let stat;
17018
17344
  try {
17019
- stat = readFileSync3(`/proc/${entry}/stat`, "utf8");
17345
+ stat = readFileSync5(`/proc/${entry}/stat`, "utf8");
17020
17346
  } catch {
17021
17347
  complete = false;
17022
17348
  continue;
@@ -53755,10 +54081,10 @@ var init_verification_prompts = __esm(() => {
53755
54081
  // dist/builtin/workflows/builtin/pattern-artifact-root.ts
53756
54082
  import { randomUUID as randomUUID9 } from "node:crypto";
53757
54083
  import { mkdir as mkdir2 } from "node:fs/promises";
53758
- import { join as join13 } from "node:path";
54084
+ import { join as join14 } from "node:path";
53759
54085
  async function stableArtifactRoot(ctx, workflowName) {
53760
54086
  const cwd = ctx.cwd ?? process.cwd();
53761
- const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join13(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID9()}`));
54087
+ const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join14(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID9()}`));
53762
54088
  await mkdir2(artifactDir, { recursive: true });
53763
54089
  return artifactDir;
53764
54090
  }
@@ -53798,7 +54124,7 @@ function fold_usage(results) {
53798
54124
 
53799
54125
  // dist/builtin/workflows/builtin/adversarial-verification-runner.ts
53800
54126
  import { readFile as readFile2, writeFile } from "node:fs/promises";
53801
- import { join as join14 } from "node:path";
54127
+ import { join as join15 } from "node:path";
53802
54128
  import { Type as Type4 } from "typebox";
53803
54129
  function isRecord3(value2) {
53804
54130
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
@@ -53893,8 +54219,8 @@ async function writeInvalid(path, stage) {
53893
54219
  }
53894
54220
  async function runAdversarialVerification(ctx) {
53895
54221
  const root = await stableArtifactRoot(ctx, "adversarial-verification");
53896
- const criteriaPath = join14(root, "criteria.md");
53897
- const candidatePath = join14(root, "candidate.md");
54222
+ const criteriaPath = join15(root, "criteria.md");
54223
+ const candidatePath = join15(root, "candidate.md");
53898
54224
  const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
53899
54225
  await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
53900
54226
  await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
@@ -53926,7 +54252,7 @@ async function runAdversarialVerification(ctx) {
53926
54252
  criterion,
53927
54253
  verifierIndex: index + 1,
53928
54254
  name,
53929
- artifactPath: join14(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
54255
+ artifactPath: join15(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
53930
54256
  });
53931
54257
  }
53932
54258
  }
@@ -53979,8 +54305,8 @@ async function runAdversarialVerification(ctx) {
53979
54305
  const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
53980
54306
  finalDecision = decision;
53981
54307
  finalMean = meanScore(scoreReports);
53982
- scoreTablePath = join14(root, `verification-summary-${round}.json`);
53983
- reviewReportPath = join14(root, `review-${round}.json`);
54308
+ scoreTablePath = join15(root, `verification-summary-${round}.json`);
54309
+ reviewReportPath = join15(root, `review-${round}.json`);
53984
54310
  const summary = {
53985
54311
  scores: scoreReports,
53986
54312
  mean: finalMean,
@@ -54161,7 +54487,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
54161
54487
 
54162
54488
  // dist/builtin/workflows/builtin/classify-and-act-runner.ts
54163
54489
  import { writeFile as writeFile2 } from "node:fs/promises";
54164
- import { join as join15 } from "node:path";
54490
+ import { join as join16 } from "node:path";
54165
54491
  import { Type as Type6 } from "typebox";
54166
54492
  function safeName(value2) {
54167
54493
  const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -54201,7 +54527,7 @@ async function runClassifyAndAct(ctx) {
54201
54527
  const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
54202
54528
  const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
54203
54529
  const category = fallback?.category ?? exactCategory;
54204
- const classificationPath = join15(artifactDir, "classification.json");
54530
+ const classificationPath = join16(artifactDir, "classification.json");
54205
54531
  await writeFile2(classificationPath, JSON.stringify({
54206
54532
  proposed_category: proposedCategory,
54207
54533
  selected_category: category,
@@ -54211,7 +54537,7 @@ async function runClassifyAndAct(ctx) {
54211
54537
  fallback_used: needsFallback,
54212
54538
  fallback_mode: fallback?.fallbackMode ?? "none"
54213
54539
  }, null, 2));
54214
- const actionPath = join15(artifactDir, `action-${safeName(category)}.md`);
54540
+ const actionPath = join16(artifactDir, `action-${safeName(category)}.md`);
54215
54541
  const action = await ctx.task(`action-${safeName(category)}`, {
54216
54542
  tools: actionTools(category),
54217
54543
  prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
@@ -54351,7 +54677,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
54351
54677
 
54352
54678
  // dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
54353
54679
  import { writeFile as writeFile3 } from "node:fs/promises";
54354
- import { join as join16 } from "node:path";
54680
+ import { join as join17 } from "node:path";
54355
54681
  import { Type as Type8 } from "typebox";
54356
54682
  function safeName2(value2, index) {
54357
54683
  const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
@@ -54382,9 +54708,9 @@ async function runFanOutAndSynthesize(ctx) {
54382
54708
  context: "fresh"
54383
54709
  });
54384
54710
  const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
54385
- const partitionPath = join16(artifactDir, "partition-plan.json");
54711
+ const partitionPath = join17(artifactDir, "partition-plan.json");
54386
54712
  await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
54387
- const branchPaths = partitions.map((partition, index) => join16(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
54713
+ const branchPaths = partitions.map((partition, index) => join17(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
54388
54714
  const steps = partitions.map((partition, index) => ({
54389
54715
  name: `branch-${safeName2(partition.label, index)}`,
54390
54716
  prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
@@ -54394,13 +54720,13 @@ async function runFanOutAndSynthesize(ctx) {
54394
54720
  outputMode: "file-only"
54395
54721
  }));
54396
54722
  await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
54397
- const manifestPath = join16(artifactDir, "manifest.json");
54723
+ const manifestPath = join17(artifactDir, "manifest.json");
54398
54724
  await writeFile3(manifestPath, JSON.stringify({
54399
54725
  task: ctx.inputs.prompt,
54400
54726
  partition_plan: partitionPath,
54401
54727
  branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
54402
54728
  }, null, 2));
54403
- const synthesisPath = join16(artifactDir, "synthesis.md");
54729
+ const synthesisPath = join17(artifactDir, "synthesis.md");
54404
54730
  const synthesis = await ctx.task("synthesize", {
54405
54731
  prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
54406
54732
  context: "fresh",
@@ -54565,7 +54891,7 @@ var init_generate_and_filter_prompts = __esm(() => {
54565
54891
 
54566
54892
  // dist/builtin/workflows/builtin/generate-and-filter-runner.ts
54567
54893
  import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
54568
- import { join as join17 } from "node:path";
54894
+ import { join as join18 } from "node:path";
54569
54895
  import { Type as Type10 } from "typebox";
54570
54896
  function isRecord4(value2) {
54571
54897
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
@@ -54584,7 +54910,7 @@ function judgeDecision(value2) {
54584
54910
  }
54585
54911
  async function runGenerateAndFilter(ctx) {
54586
54912
  const root = await stableArtifactRoot(ctx, "generate-and-filter");
54587
- const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join17(root, `candidate-${index + 1}.md`));
54913
+ const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join18(root, `candidate-${index + 1}.md`));
54588
54914
  const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
54589
54915
  await ctx.parallel(candidatePaths.map((path, index) => ({
54590
54916
  name: `generate-${index + 1}`,
@@ -54593,9 +54919,9 @@ async function runGenerateAndFilter(ctx) {
54593
54919
  output: path,
54594
54920
  outputMode: "file-only"
54595
54921
  })), { concurrency: ctx.inputs.max_concurrency, failFast: false });
54596
- const manifestPath = join17(root, "manifest.json");
54922
+ const manifestPath = join18(root, "manifest.json");
54597
54923
  await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
54598
- const filterPath = join17(root, "filter.json");
54924
+ const filterPath = join18(root, "filter.json");
54599
54925
  const filtered = await ctx.task("dedupe-and-filter", {
54600
54926
  prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
54601
54927
  context: "fresh",
@@ -54612,7 +54938,7 @@ async function runGenerateAndFilter(ctx) {
54612
54938
  let judgePath = null;
54613
54939
  let decisionPath = filterPath;
54614
54940
  if (ctx.inputs.use_judge) {
54615
- judgePath = join17(root, "judge.json");
54941
+ judgePath = join18(root, "judge.json");
54616
54942
  const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
54617
54943
  const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
54618
54944
  const judged = await ctx.task("judge", {
@@ -54628,7 +54954,7 @@ async function runGenerateAndFilter(ctx) {
54628
54954
  shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
54629
54955
  decisionPath = judgePath;
54630
54956
  }
54631
- const finalPath = join17(root, "shortlist.md");
54957
+ const finalPath = join18(root, "shortlist.md");
54632
54958
  const finalShortlist = await ctx.task("final-shortlist", {
54633
54959
  prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
54634
54960
  context: "fresh",
@@ -55157,7 +55483,7 @@ var init_review_convergence = __esm(() => {
55157
55483
 
55158
55484
  // dist/builtin/workflows/builtin/goal-artifacts.ts
55159
55485
  import { writeFile as writeFile5 } from "node:fs/promises";
55160
- import { join as join18 } from "node:path";
55486
+ import { join as join19 } from "node:path";
55161
55487
  function artifactSafeName(value2) {
55162
55488
  const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
55163
55489
  return safe.length > 0 ? safe : "artifact";
@@ -55168,7 +55494,7 @@ function withoutTurn(value2) {
55168
55494
  return copy;
55169
55495
  }
55170
55496
  async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
55171
- const artifactPath = join18(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
55497
+ const artifactPath = join19(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
55172
55498
  await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
55173
55499
  `, { encoding: "utf8" });
55174
55500
  return artifactPath;
@@ -55177,7 +55503,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
55177
55503
  reviewer: review.reviewer,
55178
55504
  findings: review.findings
55179
55505
  }))), reverification = []) {
55180
- const artifactPath = join18(artifactDir, "review-round-latest.json");
55506
+ const artifactPath = join19(artifactDir, "review-round-latest.json");
55181
55507
  const visibleReviews = reviews.map(withoutTurn);
55182
55508
  await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
55183
55509
  `, { encoding: "utf8" });
@@ -55407,7 +55733,7 @@ var init_goal_review = __esm(() => {
55407
55733
  // dist/builtin/workflows/builtin/goal-ledger.ts
55408
55734
  import { randomUUID as randomUUID10 } from "node:crypto";
55409
55735
  import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
55410
- import { dirname as dirname10, join as join19 } from "node:path";
55736
+ import { dirname as dirname11, join as join20 } from "node:path";
55411
55737
  import { isDeepStrictEqual } from "node:util";
55412
55738
  function withoutTurn2(value2) {
55413
55739
  const copy = { ...value2 };
@@ -55432,7 +55758,7 @@ function modelVisibleLedger(ledger) {
55432
55758
  };
55433
55759
  }
55434
55760
  function goalLedgerStatePath(ledgerPath) {
55435
- return join19(dirname10(ledgerPath), LEDGER_STATE_FILENAME);
55761
+ return join20(dirname11(ledgerPath), LEDGER_STATE_FILENAME);
55436
55762
  }
55437
55763
  function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
55438
55764
  ledger.lifecycle.push({
@@ -55508,7 +55834,7 @@ function recoverLegacyExecutionInterruption(ledger) {
55508
55834
  return true;
55509
55835
  }
55510
55836
  async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
55511
- const ledgerPath = join19(artifactDir, LEDGER_FILENAME);
55837
+ const ledgerPath = join20(artifactDir, LEDGER_FILENAME);
55512
55838
  const existing = await readExistingGoalLedger(ledgerPath);
55513
55839
  if (existing !== undefined) {
55514
55840
  if (recoverLegacyExecutionInterruption(existing))
@@ -56015,7 +56341,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
56015
56341
  });
56016
56342
 
56017
56343
  // dist/builtin/workflows/builtin/goal-runner.ts
56018
- import { join as join20 } from "node:path";
56344
+ import { join as join21 } from "node:path";
56019
56345
  function positiveInteger(value2, fallback) {
56020
56346
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
56021
56347
  return fallback;
@@ -56066,7 +56392,7 @@ async function runGoalWorkflow(ctx, options) {
56066
56392
  appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
56067
56393
  await writeGoalLedger(ledgerPath, ledger);
56068
56394
  }
56069
- const orchestratorReceiptPath = join20(artifactDir, "orchestrator-receipt.md");
56395
+ const orchestratorReceiptPath = join21(artifactDir, "orchestrator-receipt.md");
56070
56396
  const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
56071
56397
  const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
56072
56398
  ledger,
@@ -56137,7 +56463,7 @@ async function runGoalWorkflow(ctx, options) {
56137
56463
  const reviewerName = result.name ?? result.stageName;
56138
56464
  const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
56139
56465
  const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
56140
- const reviewArtifactPath = join20(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
56466
+ const reviewArtifactPath = join21(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
56141
56467
  const record = reviewDecisionToRecord({
56142
56468
  turn,
56143
56469
  reviewer: normalizedReviewerName,
@@ -56340,7 +56666,7 @@ var init_goal = __esm(() => {
56340
56666
  }),
56341
56667
  git_worktree_dir: Type15.String({
56342
56668
  default: "",
56343
- 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."
56669
+ 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."
56344
56670
  }),
56345
56671
  create_pr: Type15.Boolean({
56346
56672
  default: false,
@@ -56458,7 +56784,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
56458
56784
 
56459
56785
  // dist/builtin/workflows/builtin/loop-until-done-runner.ts
56460
56786
  import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
56461
- import { join as join21 } from "node:path";
56787
+ import { join as join22 } from "node:path";
56462
56788
  import { Type as Type16 } from "typebox";
56463
56789
  function progressCurve(entries) {
56464
56790
  return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
@@ -56541,18 +56867,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
56541
56867
  }
56542
56868
  async function runLoopUntilDone(ctx) {
56543
56869
  const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
56544
- const iterationsDir = join21(artifactDir, "iterations");
56545
- const evaluationsDir = join21(artifactDir, "evaluations");
56870
+ const iterationsDir = join22(artifactDir, "iterations");
56871
+ const evaluationsDir = join22(artifactDir, "evaluations");
56546
56872
  await mkdir3(iterationsDir, { recursive: true });
56547
56873
  await mkdir3(evaluationsDir, { recursive: true });
56548
- const ledgerPath = join21(artifactDir, "progress-ledger.json");
56874
+ const ledgerPath = join22(artifactDir, "progress-ledger.json");
56549
56875
  const entries = [];
56550
56876
  const iterationArtifactPaths = [];
56551
56877
  const evaluationArtifactPaths = [];
56552
56878
  await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
56553
56879
  for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
56554
- const iterationPath = join21(iterationsDir, `iteration-${iteration}.md`);
56555
- const evaluationPath = join21(evaluationsDir, `evaluation-${iteration}.json`);
56880
+ const iterationPath = join22(iterationsDir, `iteration-${iteration}.md`);
56881
+ const evaluationPath = join22(evaluationsDir, `evaluation-${iteration}.json`);
56556
56882
  iterationArtifactPaths.push(iterationPath);
56557
56883
  evaluationArtifactPaths.push(evaluationPath);
56558
56884
  await ctx.task(`iteration-${iteration}`, {
@@ -56601,7 +56927,7 @@ async function runLoopUntilDone(ctx) {
56601
56927
  await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
56602
56928
  if (decision.done) {
56603
56929
  const report = progressReport(entries);
56604
- const resultPath = join21(artifactDir, "result.md");
56930
+ const resultPath = join22(artifactDir, "result.md");
56605
56931
  const final = await ctx.task("completion-summary", {
56606
56932
  prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
56607
56933
  context: "fresh",
@@ -56718,9 +57044,9 @@ var init_loop_until_done = __esm(() => {
56718
57044
 
56719
57045
  // dist/builtin/workflows/builtin/open-claude-design-utils.ts
56720
57046
  import { spawnSync as spawnSync3 } from "node:child_process";
56721
- import { mkdirSync as mkdirSync6 } from "node:fs";
57047
+ import { mkdirSync as mkdirSync7 } from "node:fs";
56722
57048
  import { tmpdir, userInfo } from "node:os";
56723
- import { join as join22 } from "node:path";
57049
+ import { join as join23 } from "node:path";
56724
57050
  import { Type as Type18 } from "typebox";
56725
57051
  import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
56726
57052
  function taggedPrompt3(sections) {
@@ -56763,32 +57089,32 @@ function tmpArtifactBase() {
56763
57089
  try {
56764
57090
  user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
56765
57091
  } catch {}
56766
- return join22(tmpdir(), `open-claude-design-${user}`);
57092
+ return join23(tmpdir(), `open-claude-design-${user}`);
56767
57093
  }
56768
57094
  function prepareArtifactDir(cwd = process.cwd()) {
56769
57095
  const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
56770
57096
  const tmpCandidates = [
56771
- join22(tmpArtifactBase(), runId),
56772
- join22(tmpdir(), "open-claude-design", runId)
57097
+ join23(tmpArtifactBase(), runId),
57098
+ join23(tmpdir(), "open-claude-design", runId)
56773
57099
  ];
56774
- const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join22(cwd, "specs", "design", runId), ...tmpCandidates];
57100
+ const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join23(cwd, "specs", "design", runId), ...tmpCandidates];
56775
57101
  for (const candidate of candidates) {
56776
57102
  try {
56777
- mkdirSync6(candidate, { recursive: true });
57103
+ mkdirSync7(candidate, { recursive: true });
56778
57104
  return {
56779
57105
  runId,
56780
57106
  artifactDir: candidate,
56781
- previewPath: join22(candidate, "preview.html"),
56782
- specPath: join22(candidate, "spec.html")
57107
+ previewPath: join23(candidate, "preview.html"),
57108
+ specPath: join23(candidate, "spec.html")
56783
57109
  };
56784
57110
  } catch {}
56785
57111
  }
56786
- const fallback = join22(tmpArtifactBase(), runId);
57112
+ const fallback = join23(tmpArtifactBase(), runId);
56787
57113
  return {
56788
57114
  runId,
56789
57115
  artifactDir: fallback,
56790
- previewPath: join22(fallback, "preview.html"),
56791
- specPath: join22(fallback, "spec.html")
57116
+ previewPath: join23(fallback, "preview.html"),
57117
+ specPath: join23(fallback, "spec.html")
56792
57118
  };
56793
57119
  }
56794
57120
  function ensureAgentBrowser() {
@@ -57122,8 +57448,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
57122
57448
  });
57123
57449
 
57124
57450
  // dist/builtin/workflows/builtin/open-claude-design-setup.ts
57125
- import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
57126
- import { join as join23 } from "node:path";
57451
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "node:fs";
57452
+ import { join as join24 } from "node:path";
57127
57453
  function renderDiscoveryContext(discovery) {
57128
57454
  return [
57129
57455
  `Confirmed design brief: ${discovery.brief}`,
@@ -57188,10 +57514,10 @@ async function runDiscoveryAndInit(args) {
57188
57514
  };
57189
57515
  }
57190
57516
  function designContextPath(artifactDir) {
57191
- return join23(artifactDir, DESIGN_CONTEXT_FILENAME);
57517
+ return join24(artifactDir, DESIGN_CONTEXT_FILENAME);
57192
57518
  }
57193
57519
  function referencesBriefPath(artifactDir) {
57194
- return join23(artifactDir, REFERENCES_BRIEF_FILENAME);
57520
+ return join24(artifactDir, REFERENCES_BRIEF_FILENAME);
57195
57521
  }
57196
57522
  function buildReferenceDiscoveryPrompt(args) {
57197
57523
  const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
@@ -57217,8 +57543,8 @@ function buildReferenceDiscoveryPrompt(args) {
57217
57543
  [
57218
57544
  "Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
57219
57545
  "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.",
57220
- `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\`.`,
57221
- `Also run \`agent-browser screenshot ${join23(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
57546
+ `Capture motion across the entire page: start \`agent-browser record start ${join24(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\`.`,
57547
+ `Also run \`agent-browser screenshot ${join24(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
57222
57548
  "Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
57223
57549
  "Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
57224
57550
  "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.",
@@ -57243,8 +57569,8 @@ function buildReferenceDiscoveryPrompt(args) {
57243
57569
  }
57244
57570
  function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
57245
57571
  try {
57246
- mkdirSync7(artifactDir, { recursive: true });
57247
- writeFileSync4(filePath, `${content}
57572
+ mkdirSync8(artifactDir, { recursive: true });
57573
+ writeFileSync5(filePath, `${content}
57248
57574
  `);
57249
57575
  } catch (error) {
57250
57576
  const detail = error instanceof Error ? error.message : String(error);
@@ -57795,7 +58121,7 @@ var init_ralph_review_gate = __esm(() => {
57795
58121
 
57796
58122
  // dist/builtin/workflows/builtin/ralph-core.ts
57797
58123
  import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
57798
- import { dirname as dirname11, join as join24 } from "node:path";
58124
+ import { dirname as dirname12, join as join25 } from "node:path";
57799
58125
  import { Type as Type20 } from "typebox";
57800
58126
  function taggedPrompt4(sections) {
57801
58127
  return sections.map(([tag, content]) => {
@@ -57835,11 +58161,11 @@ function slugifyResearchTopic(prompt) {
57835
58161
  }
57836
58162
  function defaultResearchPath(prompt, now = new Date) {
57837
58163
  const date = now.toISOString().slice(0, 10);
57838
- return join24(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
58164
+ return join25(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
57839
58165
  }
57840
58166
  async function createImplementationNotesFile(prompt, runId) {
57841
58167
  const notesDir = await createWorkflowArtifactDirectory(runId);
57842
- const notesPath = join24(notesDir, IMPLEMENTATION_NOTES_FILENAME);
58168
+ const notesPath = join25(notesDir, IMPLEMENTATION_NOTES_FILENAME);
57843
58169
  const initialNotes = [
57844
58170
  "# Implementation Notes",
57845
58171
  "",
@@ -57860,7 +58186,7 @@ async function createImplementationNotesFile(prompt, runId) {
57860
58186
  }
57861
58187
  async function createQaEvidenceVideoPath(runId) {
57862
58188
  const qaDir = await createWorkflowArtifactDirectory(runId);
57863
- return join24(qaDir, QA_E2E_VIDEO_FILENAME);
58189
+ return join25(qaDir, QA_E2E_VIDEO_FILENAME);
57864
58190
  }
57865
58191
  function renderQaE2eVideoGuidance(qaVideoPath) {
57866
58192
  return [
@@ -57926,7 +58252,7 @@ function artifactSafeName2(value2) {
57926
58252
  return safe.length > 0 ? safe : "artifact";
57927
58253
  }
57928
58254
  async function writeJsonArtifact(path, content) {
57929
- await mkdir4(dirname11(path), { recursive: true });
58255
+ await mkdir4(dirname12(path), { recursive: true });
57930
58256
  await writeFile8(path, `${JSON.stringify(content, null, 2)}
57931
58257
  `, {
57932
58258
  encoding: "utf8"
@@ -58264,7 +58590,7 @@ var init_ralph_models = __esm(() => {
58264
58590
 
58265
58591
  // dist/builtin/workflows/builtin/ralph-runner.ts
58266
58592
  import { existsSync as existsSync5 } from "node:fs";
58267
- import { join as join25, resolve as resolve10 } from "node:path";
58593
+ import { join as join26, resolve as resolve11 } from "node:path";
58268
58594
  async function runRalphWorkflow(ctx, options) {
58269
58595
  const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
58270
58596
  let latestReviewReportPath;
@@ -58276,7 +58602,7 @@ async function runRalphWorkflow(ctx, options) {
58276
58602
  let finalPrReport;
58277
58603
  const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
58278
58604
  const workflowPrompt = prompt;
58279
- const workflowResearchPath = resolve10(workflowStartCwd, defaultResearchPath(workflowPrompt));
58605
+ const workflowResearchPath = resolve11(workflowStartCwd, defaultResearchPath(workflowPrompt));
58280
58606
  const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
58281
58607
  const qaVideoPath = await createQaEvidenceVideoPath(runId);
58282
58608
  const artifactDir = await createWorkflowArtifactDirectory(runId);
@@ -58325,7 +58651,7 @@ async function runRalphWorkflow(ctx, options) {
58325
58651
  const researchPath = workflowResearchPath;
58326
58652
  finalResearchPath = researchPath;
58327
58653
  finalPlanPath = researchPath;
58328
- const orchestratorReportPath = join25(artifactDir, "orchestrator-report.md");
58654
+ const orchestratorReportPath = join26(artifactDir, "orchestrator-report.md");
58329
58655
  const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
58330
58656
  const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
58331
58657
  ["acceptance_criteria", keepContext(acceptanceCriteria)],
@@ -58461,7 +58787,7 @@ Read it before implementation or delegation because it is the primary current im
58461
58787
  diagnostics: parsed.diagnostics,
58462
58788
  allowFinalActionRemaining: createPr
58463
58789
  });
58464
- const artifactPath = join25(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
58790
+ const artifactPath = join26(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
58465
58791
  await writeJsonArtifact(artifactPath, {
58466
58792
  reviewer,
58467
58793
  decision: parsed.decision,
@@ -58517,7 +58843,7 @@ Read it before implementation or delegation because it is the primary current im
58517
58843
  usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
58518
58844
  }));
58519
58845
  }
58520
- latestReviewReportPath = await writeJsonArtifact(join25(artifactDir, "review-round-latest.json"), {
58846
+ latestReviewReportPath = await writeJsonArtifact(join26(artifactDir, "review-round-latest.json"), {
58521
58847
  convergence_decision: roundConvergenceDecision,
58522
58848
  convergence: convergenceEntries,
58523
58849
  consolidated_findings: reverified.batch,
@@ -58666,7 +58992,7 @@ var init_ralph = __esm(() => {
58666
58992
  }),
58667
58993
  git_worktree_dir: Type21.String({
58668
58994
  default: "",
58669
- 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."
58995
+ 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."
58670
58996
  }),
58671
58997
  create_pr: Type21.Boolean({
58672
58998
  default: false,
@@ -58886,7 +59212,7 @@ var init_tournament_prompts = __esm(() => {
58886
59212
 
58887
59213
  // dist/builtin/workflows/builtin/tournament-runner.ts
58888
59214
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
58889
- import { join as join26, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve11 } from "node:path";
59215
+ import { join as join27, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve12 } from "node:path";
58890
59216
  import { Type as Type22 } from "typebox";
58891
59217
  function serializableObject2(value2) {
58892
59218
  if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
@@ -58923,8 +59249,8 @@ function criterionSlug(id) {
58923
59249
  }
58924
59250
  function judgeArtifactPath(judgesDir, job, criterionIndex) {
58925
59251
  const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
58926
- const root = resolve11(judgesDir);
58927
- const path = resolve11(judgesDir, filename);
59252
+ const root = resolve12(judgesDir);
59253
+ const path = resolve12(judgesDir, filename);
58928
59254
  const fromRoot = relative5(root, path);
58929
59255
  if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
58930
59256
  throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
@@ -58975,16 +59301,16 @@ function combineUsage(totals) {
58975
59301
  }
58976
59302
  async function runTournament(ctx) {
58977
59303
  const artifactDir = await stableArtifactRoot(ctx, "tournament");
58978
- const attemptsDir = join26(artifactDir, "attempts");
59304
+ const attemptsDir = join27(artifactDir, "attempts");
58979
59305
  const numAttempts = ctx.inputs.num_attempts ?? 4;
58980
59306
  const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
58981
59307
  const nEvaluations = ctx.inputs.n_evaluations ?? 2;
58982
59308
  const pivotCount = ctx.inputs.pivots ?? 1;
58983
59309
  const seed = ctx.inputs.seed ?? 0;
58984
- const judgesDir = join26(artifactDir, "judges");
59310
+ const judgesDir = join27(artifactDir, "judges");
58985
59311
  await mkdir5(attemptsDir, { recursive: true });
58986
59312
  await mkdir5(judgesDir, { recursive: true });
58987
- const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join26(attemptsDir, `attempt-${index + 1}.md`));
59313
+ const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join27(attemptsDir, `attempt-${index + 1}.md`));
58988
59314
  const models = ctx.inputs.models;
58989
59315
  const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
58990
59316
  name: `attempt-${index + 1}`,
@@ -59149,7 +59475,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
59149
59475
  const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
59150
59476
  const budgetPivots = Math.min(pivotCount, entrants.length);
59151
59477
  const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
59152
- const comparisonPath = join26(artifactDir, "comparisons.json");
59478
+ const comparisonPath = join27(artifactDir, "comparisons.json");
59153
59479
  const assignment = modelAssignment(entrants, models);
59154
59480
  const phaseUsage = {
59155
59481
  attempts: fold_usage(attemptResults),
@@ -59185,7 +59511,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
59185
59511
  await writeLedger(fold_usage([]));
59186
59512
  const winner = ranking[0];
59187
59513
  const winnerEntrant = entrants[winner.index];
59188
- const resultPath = join26(artifactDir, "winner.md");
59514
+ const resultPath = join27(artifactDir, "winner.md");
59189
59515
  const reducer = await ctx.task("comparisons-reducer", {
59190
59516
  prompt: renderComparisonsReducerPrompt({
59191
59517
  task: ctx.inputs.prompt,
@@ -59494,17 +59820,26 @@ function isSameCheckpointValue(stored, next) {
59494
59820
  const hash = (value2) => durableHash(value2);
59495
59821
  return hash(stored) === hash(next);
59496
59822
  }
59823
+ function withTimesOf(later, recorded) {
59824
+ const both = (key) => typeof recorded[key] === "number" && typeof later[key] === "number";
59825
+ return {
59826
+ ...later,
59827
+ ...both("startedAt") ? { startedAt: recorded.startedAt } : {},
59828
+ ...both("endedAt") ? { endedAt: recorded.endedAt } : {},
59829
+ ...both("completedAt") ? { completedAt: recorded.completedAt } : {}
59830
+ };
59831
+ }
59497
59832
  function isRecordedCheckpointValue(stored, next) {
59498
59833
  const recorded = stored;
59499
59834
  if (isSameCheckpointValue(recorded, next))
59500
59835
  return true;
59501
- const { completedAt, startedAt } = recorded;
59502
- if (typeof completedAt !== "number")
59836
+ if (typeof recorded.completedAt !== "number")
59503
59837
  return false;
59504
59838
  const later = next;
59505
- if (startedAt === undefined !== (later.startedAt === undefined))
59839
+ if (recorded.startedAt === undefined !== (later.startedAt === undefined))
59506
59840
  return false;
59507
- return isSameCheckpointValue({ ...later, completedAt, ...startedAt === undefined ? {} : { startedAt } }, recorded);
59841
+ const retimed = withTimesOf(later, recorded);
59842
+ return isSameCheckpointValue(recorded.topology !== undefined && later.topology !== undefined ? { ...retimed, topology: withTimesOf(later.topology, recorded.topology) } : retimed, recorded);
59508
59843
  }
59509
59844
  var MIRROR_FRESH_MS = 2000;
59510
59845
  var init_pool_remote_journal = __esm(() => {
@@ -60082,7 +60417,7 @@ class SqlPoolQueue {
60082
60417
  throw new Error("Stale pool coordinator authority", { cause: error });
60083
60418
  throw error;
60084
60419
  });
60085
- const row = await this.current(tx, lease, token);
60420
+ const row = await this.current(tx, lease, token, true);
60086
60421
  if (row.epoch !== lease.epoch)
60087
60422
  throw new Error(STALE_WORK_LEASE);
60088
60423
  assertSession();
@@ -60540,15 +60875,7 @@ class SqlPoolQueue {
60540
60875
  }
60541
60876
  }
60542
60877
  function isRecordedCheckpoint(stored, payload) {
60543
- if (stored === payload)
60544
- return true;
60545
- const { completedAt, startedAt } = JSON.parse(stored);
60546
- if (typeof completedAt !== "number")
60547
- return false;
60548
- const next = JSON.parse(payload);
60549
- if (startedAt === undefined !== (next.startedAt === undefined))
60550
- return false;
60551
- return serializeJson({ ...next, completedAt, ...startedAt === undefined ? {} : { startedAt } }) === stored;
60878
+ return stored === payload || isRecordedCheckpointValue(JSON.parse(stored), JSON.parse(payload));
60552
60879
  }
60553
60880
  function openSqlPoolQueue(journal, remote) {
60554
60881
  const storage = sqlPoolStorage(journal);
@@ -62324,7 +62651,7 @@ function isBrokerStatusReport(value2) {
62324
62651
 
62325
62652
  // dist/builtin/intercom/broker/paths.ts
62326
62653
  import { homedir as homedir2 } from "os";
62327
- import { join as join27 } from "path";
62654
+ import { join as join28 } from "path";
62328
62655
  function getHomeDir() {
62329
62656
  if (process.platform === "win32") {
62330
62657
  if (process.env.USERPROFILE)
@@ -62341,7 +62668,7 @@ function expandTildePath(path) {
62341
62668
  if (path === "~")
62342
62669
  return getHomeDir();
62343
62670
  if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
62344
- return join27(getHomeDir(), path.slice(2));
62671
+ return join28(getHomeDir(), path.slice(2));
62345
62672
  }
62346
62673
  return path;
62347
62674
  }
@@ -62352,31 +62679,31 @@ function getAgentDir5() {
62352
62679
  const piAgentDir = process.env.PI_CODING_AGENT_DIR;
62353
62680
  if (piAgentDir)
62354
62681
  return expandTildePath(piAgentDir);
62355
- return join27(getHomeDir(), ".atomic", "agent");
62682
+ return join28(getHomeDir(), ".atomic", "agent");
62356
62683
  }
62357
62684
  function sanitizePipeSegment(value2) {
62358
62685
  return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
62359
62686
  }
62360
62687
  function getIntercomDirPath(agentDir = getAgentDir5()) {
62361
- return join27(agentDir, "intercom");
62688
+ return join28(agentDir, "intercom");
62362
62689
  }
62363
62690
  function getBrokerPidPath(agentDir = getAgentDir5()) {
62364
- return join27(getIntercomDirPath(agentDir), "broker.pid");
62691
+ return join28(getIntercomDirPath(agentDir), "broker.pid");
62365
62692
  }
62366
62693
  function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
62367
- return join27(getIntercomDirPath(agentDir), "broker.spawn.lock");
62694
+ return join28(getIntercomDirPath(agentDir), "broker.spawn.lock");
62368
62695
  }
62369
62696
  function getBrokerLogPath(agentDir = getAgentDir5()) {
62370
- return join27(getIntercomDirPath(agentDir), "broker.log");
62697
+ return join28(getIntercomDirPath(agentDir), "broker.log");
62371
62698
  }
62372
62699
  function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
62373
- return join27(getIntercomDirPath(agentDir), "broker.starting");
62700
+ return join28(getIntercomDirPath(agentDir), "broker.starting");
62374
62701
  }
62375
62702
  function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
62376
62703
  if (platform === "win32") {
62377
62704
  return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
62378
62705
  }
62379
- return join27(getIntercomDirPath(agentDir), "broker.sock");
62706
+ return join28(getIntercomDirPath(agentDir), "broker.sock");
62380
62707
  }
62381
62708
  var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
62382
62709
  var init_paths = () => {};
@@ -64060,11 +64387,11 @@ var init_client = __esm(() => {
64060
64387
  var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
64061
64388
 
64062
64389
  // dist/builtin/intercom/broker/start-announcement.ts
64063
- import { readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
64390
+ import { readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
64064
64391
  function readBrokerStartAnnouncement(announcement) {
64065
64392
  let text;
64066
64393
  try {
64067
- text = readFileSync4(announcement.path, "utf-8");
64394
+ text = readFileSync6(announcement.path, "utf-8");
64068
64395
  } catch {
64069
64396
  return;
64070
64397
  }
@@ -64083,26 +64410,26 @@ var init_start_announcement = () => {};
64083
64410
  // dist/builtin/intercom/broker/spawn.ts
64084
64411
  import { spawn } from "child_process";
64085
64412
  import { randomUUID as randomUUID15 } from "crypto";
64086
- import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync5, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
64087
- import { join as join28, dirname as dirname12 } from "path";
64413
+ import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync9, openSync as openSync3, readFileSync as readFileSync7, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
64414
+ import { join as join29, dirname as dirname13 } from "path";
64088
64415
  import { fileURLToPath as fileURLToPath4 } from "url";
64089
64416
  import { createRequire as createRequire3 } from "module";
64090
64417
  import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
64091
64418
  function isIntercomPackageRoot(dir) {
64092
- return existsSync6(join28(dir, "package.json")) && existsSync6(join28(dir, "broker"));
64419
+ return existsSync6(join29(dir, "package.json")) && existsSync6(join29(dir, "broker"));
64093
64420
  }
64094
64421
  function resolveIntercomPackageRoot(moduleHref) {
64095
- const here = dirname12(fileURLToPath4(moduleHref));
64422
+ const here = dirname13(fileURLToPath4(moduleHref));
64096
64423
  if (isIntercomPackageRoot(here))
64097
64424
  return here;
64098
- return join28(here, "..");
64425
+ return join29(here, "..");
64099
64426
  }
64100
64427
  function resolveBrokerEntrypoint(packageRoot) {
64101
- const bundled = join28(packageRoot, "broker", "broker.bundle.mjs");
64102
- return existsSync6(bundled) ? bundled : join28(packageRoot, "broker", "broker.ts");
64428
+ const bundled = join29(packageRoot, "broker", "broker.bundle.mjs");
64429
+ return existsSync6(bundled) ? bundled : join29(packageRoot, "broker", "broker.ts");
64103
64430
  }
64104
64431
  function ensurePrivateDirectory(path) {
64105
- mkdirSync8(path, { recursive: true, mode: 448 });
64432
+ mkdirSync9(path, { recursive: true, mode: 448 });
64106
64433
  if (process.platform !== "win32")
64107
64434
  chmodSync(path, 448);
64108
64435
  }
@@ -64115,14 +64442,14 @@ function getCurrentBrokerRuntime() {
64115
64442
  return isBunBinary ? "bun-binary" : "bun-source";
64116
64443
  }
64117
64444
  function requireFromExtensionDir(extensionDir) {
64118
- return createRequire3(join28(extensionDir, "package.json"));
64445
+ return createRequire3(join29(extensionDir, "package.json"));
64119
64446
  }
64120
64447
  function getJitiCliPath(extensionDir = EXTENSION_DIR) {
64121
64448
  try {
64122
64449
  const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
64123
- return join28(dirname12(jitiPackage), "lib", "jiti-cli.mjs");
64450
+ return join29(dirname13(jitiPackage), "lib", "jiti-cli.mjs");
64124
64451
  } catch {
64125
- return join28(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
64452
+ return join29(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
64126
64453
  }
64127
64454
  }
64128
64455
  function getDefaultBrokerRunnerPath(extensionDir) {
@@ -64144,7 +64471,7 @@ function quoteWindowsArg(value2) {
64144
64471
  return `"${value2.replace(/"/g, '""')}"`;
64145
64472
  }
64146
64473
  function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
64147
- return join28(intercomDir, "broker-launch.vbs");
64474
+ return join29(intercomDir, "broker-launch.vbs");
64148
64475
  }
64149
64476
  function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
64150
64477
  return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
@@ -64171,8 +64498,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
64171
64498
  `);
64172
64499
  }
64173
64500
  function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
64174
- ensurePrivateDirectory(dirname12(launcherPath));
64175
- writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
64501
+ ensurePrivateDirectory(dirname13(launcherPath));
64502
+ writeFileSync7(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
64176
64503
  return launcherPath;
64177
64504
  }
64178
64505
  function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
@@ -64215,14 +64542,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
64215
64542
  };
64216
64543
  }
64217
64544
  function resetBrokerLog(logPath = BROKER_LOG) {
64218
- ensurePrivateDirectory(dirname12(logPath));
64545
+ ensurePrivateDirectory(dirname13(logPath));
64219
64546
  try {
64220
64547
  const previous = readBrokerLogTail(logPath);
64221
64548
  closeSync3(openSync3(logPath, "w"));
64222
64549
  if (previous.length > 0) {
64223
64550
  try {
64224
64551
  const previousPath = `${logPath}.previous`;
64225
- writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
64552
+ writeFileSync7(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
64226
64553
  if (process.platform !== "win32")
64227
64554
  chmodSync(previousPath, 384);
64228
64555
  } catch {}
@@ -64366,7 +64693,7 @@ async function isBrokerRunning() {
64366
64693
  if (!existsSync6(BROKER_PID))
64367
64694
  return false;
64368
64695
  try {
64369
- const pid = parseInt(readFileSync5(BROKER_PID, "utf-8").trim(), 10);
64696
+ const pid = parseInt(readFileSync7(BROKER_PID, "utf-8").trim(), 10);
64370
64697
  if (!Number.isFinite(pid))
64371
64698
  return false;
64372
64699
  process.kill(pid, 0);
@@ -64391,7 +64718,7 @@ function handSpawnLockToBroker(pid, owner) {
64391
64718
  }
64392
64719
  function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
64393
64720
  try {
64394
- return readFileSync5(lockPath, "utf-8").startsWith(owner);
64721
+ return readFileSync7(lockPath, "utf-8").startsWith(owner);
64395
64722
  } catch {
64396
64723
  return false;
64397
64724
  }
@@ -64403,7 +64730,7 @@ function acquireSpawnLock() {
64403
64730
  ${Date.now()}
64404
64731
  `;
64405
64732
  try {
64406
- writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
64733
+ writeFileSync7(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
64407
64734
  return owner;
64408
64735
  } catch (error) {
64409
64736
  if (!(error instanceof Error) || error.code !== "EEXIST") {
@@ -64433,7 +64760,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
64433
64760
  return false;
64434
64761
  }
64435
64762
  try {
64436
- const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync5(lockPath, "utf-8").trim().split(`
64763
+ const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync7(lockPath, "utf-8").trim().split(`
64437
64764
  `);
64438
64765
  const spawnerPid = Number.parseInt(spawnerLine, 10);
64439
64766
  const createdAt = Number.parseInt(createdAtLine, 10);
@@ -64511,14 +64838,14 @@ var init_reply_waiter = __esm(() => {
64511
64838
  });
64512
64839
 
64513
64840
  // dist/builtin/intercom/config.ts
64514
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
64841
+ import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
64515
64842
  import { getAgentConfigPaths } from "@bastani/atomic";
64516
64843
  function loadConfig() {
64517
64844
  if (!existsSync7(CONFIG_PATH)) {
64518
64845
  return { ...defaults };
64519
64846
  }
64520
64847
  try {
64521
- const raw = readFileSync6(CONFIG_PATH, "utf-8");
64848
+ const raw = readFileSync8(CONFIG_PATH, "utf-8");
64522
64849
  const parsed = JSON.parse(raw);
64523
64850
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
64524
64851
  throw new Error("Config must be a JSON object");
@@ -65101,12 +65428,12 @@ var init_sql_pool_usage = __esm(() => {
65101
65428
 
65102
65429
  // dist/builtin/workflows/src/workers/pooled-watch-trace.ts
65103
65430
  import { appendFileSync as appendFileSync2 } from "node:fs";
65104
- import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
65431
+ import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
65105
65432
  function configurePooledWatchTrace(journalPath, processRole) {
65106
65433
  if (setting === undefined || setting === "" || setting === "0")
65107
65434
  return;
65108
65435
  role = processRole;
65109
- file = setting === "1" ? join29(dirname13(resolve12(journalPath)), "pooled-watch-trace.jsonl") : resolve12(setting);
65436
+ file = setting === "1" ? join30(dirname14(resolve13(journalPath)), "pooled-watch-trace.jsonl") : resolve13(setting);
65110
65437
  }
65111
65438
  function tracePooledWatch(step, detail) {
65112
65439
  if (file === undefined)
@@ -65299,8 +65626,8 @@ var init_startup_timeout = () => {};
65299
65626
  import { fork } from "node:child_process";
65300
65627
  import { randomUUID as randomUUID17 } from "node:crypto";
65301
65628
  import { createWriteStream } from "node:fs";
65302
- import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
65303
- import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
65629
+ import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
65630
+ import { dirname as dirname15, join as join31, resolve as resolve14 } from "node:path";
65304
65631
  import { setTimeout as delay2 } from "node:timers/promises";
65305
65632
  function isRootLeaseLost(error) {
65306
65633
  return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
@@ -65309,7 +65636,7 @@ function unconfirmedCleanup(groups) {
65309
65636
  return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
65310
65637
  }
65311
65638
  function workerLogDirectory(journalPath, root) {
65312
- return join30(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
65639
+ return join31(dirname15(resolve14(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
65313
65640
  }
65314
65641
  function token(work) {
65315
65642
  return {
@@ -65491,9 +65818,13 @@ class PoolCoordinator {
65491
65818
  incarnations = new Map;
65492
65819
  readyWorkers = new Set;
65493
65820
  logs = new Map;
65821
+ keptLogs = new Set;
65822
+ unconfirmedExits = new WeakSet;
65823
+ failed = false;
65494
65824
  cleanups = new Set;
65495
65825
  controlAcks = new Map;
65496
65826
  lastHeard = new Map;
65827
+ awaiting = new Map;
65497
65828
  pendingActivity = new Map;
65498
65829
  batches = new Map;
65499
65830
  publicationFailures = new Map;
@@ -65538,7 +65869,6 @@ class PoolCoordinator {
65538
65869
  nextRecoveryAt = 0;
65539
65870
  cleanupFailure;
65540
65871
  held = new Set;
65541
- quarantined = new Set;
65542
65872
  unreaped = [];
65543
65873
  retained = new Map;
65544
65874
  retainedTransitions = Promise.resolve();
@@ -65731,18 +66061,15 @@ class PoolCoordinator {
65731
66061
  try {
65732
66062
  const { survivors, unprobeable } = await reapProcessGroups(this.journal, this.root, { attempt: work });
65733
66063
  if (survivors.length > 0) {
65734
- this.quarantined.add(work.id);
65735
66064
  this.unreaped.push({ attempt: work });
65736
- this.port.send({ kind: "work-failure", workId: work.id, error: unconfirmedCleanup(survivors).message });
65737
- return;
66065
+ this.reportHealth(undefined, `${unconfirmedCleanup(survivors).message}; child ${work.childRunId} of an earlier incarnation replays`);
65738
66066
  }
65739
66067
  if (unprobeable.length === 0)
65740
66068
  await this.releaseRetained(work);
65741
66069
  } catch (error) {
65742
66070
  this.cleanupFailure ??= error instanceof Error ? error : new Error(String(error));
65743
66071
  } finally {
65744
- if (!this.quarantined.has(work.id))
65745
- this.held.delete(work.id);
66072
+ this.held.delete(work.id);
65746
66073
  }
65747
66074
  }
65748
66075
  releaseRetained(work) {
@@ -65873,6 +66200,7 @@ class PoolCoordinator {
65873
66200
  });
65874
66201
  }
65875
66202
  fail(error) {
66203
+ this.failed = true;
65876
66204
  this.port.send({ kind: "failure", error: error.message });
65877
66205
  }
65878
66206
  failWork(work, error) {
@@ -66240,7 +66568,7 @@ class PoolCoordinator {
66240
66568
  this.slots.add(slot);
66241
66569
  let ready = false;
66242
66570
  let serial = Promise.resolve();
66243
- const logPath = join30(this.logDirectory, `${worker}.log`);
66571
+ const logPath = join31(this.logDirectory, `${worker}.log`);
66244
66572
  this.logs.set(child, logPath);
66245
66573
  let logFailure;
66246
66574
  const log = createWriteStream(logPath, { flags: "a" });
@@ -66281,7 +66609,11 @@ class PoolCoordinator {
66281
66609
  terminate();
66282
66610
  });
66283
66611
  const closed = new Promise((resolve) => child.once("close", () => resolve()));
66284
- child.once("exit", () => {
66612
+ let retired = false;
66613
+ const retire = () => {
66614
+ if (retired)
66615
+ return;
66616
+ retired = true;
66285
66617
  Promise.race([closed, delay2(STDERR_DRAIN_GRACE_MS)]).then(() => reject(diagnosed(timedOut ? startupTimeoutMessage(startupTimeoutMs) : "Local worker exited before readiness")));
66286
66618
  this.children.delete(child);
66287
66619
  this.logs.delete(child);
@@ -66292,6 +66624,7 @@ class PoolCoordinator {
66292
66624
  this.readyWorkers.delete(worker);
66293
66625
  this.controlAcks.delete(worker);
66294
66626
  this.lastHeard.delete(worker);
66627
+ this.awaiting.delete(worker);
66295
66628
  this.slots.delete(slot);
66296
66629
  this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
66297
66630
  for (const settle of slot.stageCommands.values())
@@ -66305,7 +66638,7 @@ class PoolCoordinator {
66305
66638
  const held = slot.work;
66306
66639
  if (held)
66307
66640
  this.held.add(held.id);
66308
- let childFailed = false;
66641
+ let unconfirmed;
66309
66642
  const cleanup = disconnected.then(() => serial).then(async () => {
66310
66643
  try {
66311
66644
  const admission = this.admission;
@@ -66318,18 +66651,13 @@ class PoolCoordinator {
66318
66651
  throw unconfirmedCleanup(alive);
66319
66652
  if (alive.length === 0)
66320
66653
  return;
66321
- const error = unconfirmedCleanup(alive);
66322
- if (held && await this.queue.result(this.root, held.id) === undefined) {
66323
- this.quarantined.add(held.id);
66324
- slot.work = undefined;
66325
- childFailed = true;
66326
- this.port.send({ kind: "work-failure", workId: held.id, error: error.message });
66327
- }
66654
+ unconfirmed = unconfirmedCleanup(alive);
66655
+ this.reportHealth(logPath, `${unconfirmed.message}; the worker was retired and replaced`);
66328
66656
  } catch (error) {
66329
66657
  this.cleanupFailure = error instanceof Error ? error : new Error(String(error));
66330
66658
  throw this.cleanupFailure;
66331
66659
  } finally {
66332
- if (held && !this.quarantined.has(held.id))
66660
+ if (held)
66333
66661
  this.held.delete(held.id);
66334
66662
  }
66335
66663
  }).then(async () => {
@@ -66350,8 +66678,8 @@ class PoolCoordinator {
66350
66678
  const settled = attempt !== undefined && await this.whileRootLate(queue, () => exhausted ? queue.failExited(lease, attempt) : queue.releaseExited(lease, attempt));
66351
66679
  const superseded = work !== undefined && !settled && await this.superseded(work);
66352
66680
  if (work !== undefined && exhausted && !superseded)
66353
- this.failWork(work, diagnosed(childRetryLimit(work, "lost its worker")));
66354
- if (work === undefined && !childFailed && ++this.replacements > 3)
66681
+ this.failWork(work, diagnosed(`${childRetryLimit(work, "lost its worker")}${unconfirmed === undefined ? "" : `; ${unconfirmed.message}`}`));
66682
+ if (work === undefined && ++this.replacements > 3)
66355
66683
  this.fail(diagnosed("Local worker retry limit"));
66356
66684
  else
66357
66685
  await this.spawn();
@@ -66360,7 +66688,9 @@ class PoolCoordinator {
66360
66688
  });
66361
66689
  this.cleanups.add(cleanup);
66362
66690
  cleanup.finally(() => this.cleanups.delete(cleanup));
66363
- });
66691
+ };
66692
+ slot.retire = retire;
66693
+ child.once("exit", retire);
66364
66694
  child.on("message", (message) => {
66365
66695
  this.observeResponsiveness();
66366
66696
  this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
@@ -66434,10 +66764,11 @@ class PoolCoordinator {
66434
66764
  const fenced = slot.work;
66435
66765
  slot.work = undefined;
66436
66766
  if (fenced && !await this.superseded(fenced)) {
66767
+ this.fence(fenced);
66437
66768
  if (this.attempts(fenced) < MAX_CHILD_ATTEMPTS)
66438
66769
  await leased(() => queue.releaseExited(lease, fenced));
66439
66770
  else if (await leased(() => queue.failExited(lease, fenced)))
66440
- this.failWork(fenced, new Error(childRetryLimit(fenced, "was refused by the root as stale on every attempt")));
66771
+ this.failWork(fenced, new Error(childRetryLimit(fenced, message.fault === undefined ? "was refused by the root as stale on every attempt" : `failed on a fault of the pool on every attempt (last: ${message.fault})`)));
66441
66772
  }
66442
66773
  return;
66443
66774
  }
@@ -66551,8 +66882,19 @@ class PoolCoordinator {
66551
66882
  await this.sendResult(work.id);
66552
66883
  });
66553
66884
  const response = handled.then((value2) => routeReady ?? value2);
66554
- if (message.kind !== "delivery" && message.kind !== "delivery-ready")
66555
- serial = handled.then(() => {}, () => {});
66885
+ if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
66886
+ this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
66887
+ const answered = () => {
66888
+ const left = (this.awaiting.get(worker) ?? 1) - 1;
66889
+ if (left > 0)
66890
+ this.awaiting.set(worker, left);
66891
+ else
66892
+ this.awaiting.delete(worker);
66893
+ if (this.incarnations.get(worker) === child)
66894
+ this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
66895
+ };
66896
+ serial = handled.then(answered, answered);
66897
+ }
66556
66898
  response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
66557
66899
  const rootLeaseLost = isRootLeaseLost(error);
66558
66900
  if (rootLeaseLost)
@@ -66598,8 +66940,6 @@ class PoolCoordinator {
66598
66940
  return;
66599
66941
  }
66600
66942
  for (const work of expired) {
66601
- if (this.quarantined.has(work.id))
66602
- continue;
66603
66943
  if (this.held.has(work.id)) {
66604
66944
  await queue.extend(lease, work, leaseMs).catch((error) => {
66605
66945
  if (error.message !== STALE_WORK_LEASE)
@@ -66615,16 +66955,19 @@ class PoolCoordinator {
66615
66955
  });
66616
66956
  continue;
66617
66957
  }
66618
- if (child && !await this.stop(child).then(() => true, () => false))
66619
- continue;
66620
- if (this.held.has(work.id) || this.quarantined.has(work.id))
66958
+ if (child && !await this.stop(child))
66959
+ this.retireUnconfirmed(child);
66960
+ if (this.held.has(work.id))
66621
66961
  continue;
66622
66962
  if ((await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
66623
66963
  continue;
66624
66964
  if (work.epoch < lease.epoch)
66625
66965
  await this.releaseRetained(work);
66626
66966
  else
66627
- await queue.expire(lease, work);
66967
+ await queue.expire(lease, work).catch((error) => {
66968
+ if (error.message !== STALE_WORK_LEASE)
66969
+ throw error;
66970
+ });
66628
66971
  }
66629
66972
  })().finally(() => {
66630
66973
  this.recovering = undefined;
@@ -66642,19 +66985,51 @@ class PoolCoordinator {
66642
66985
  isLive(worker, child) {
66643
66986
  this.observeResponsiveness();
66644
66987
  const heard = this.lastHeard.get(worker);
66645
- return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
66988
+ 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);
66646
66989
  }
66647
- stop(child) {
66648
- if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
66649
- return Promise.resolve();
66650
- return new Promise((resolve, reject) => {
66651
- const timeout = setTimeout(() => reject(new Error("Local worker cleanup was not confirmed")), 5000);
66652
- child.once("exit", () => {
66653
- clearTimeout(timeout);
66654
- resolve();
66655
- });
66656
- child.kill("SIGKILL");
66657
- });
66990
+ async stop(child) {
66991
+ const pid = child.pid;
66992
+ const exited = () => child.exitCode !== null || child.signalCode !== null;
66993
+ if (pid === undefined || exited())
66994
+ return true;
66995
+ const exit = new Promise((resolve) => child.once("exit", () => resolve()));
66996
+ const confirmed = async () => {
66997
+ await Promise.race([exit, delay2(WORKER_EXIT_CONFIRMATION_MS)]);
66998
+ return true;
66999
+ };
67000
+ this.observeResponsiveness();
67001
+ child.kill("SIGKILL");
67002
+ const since = performance.now();
67003
+ const stalledAt = this.stalledMs;
67004
+ for (;; ) {
67005
+ await Promise.race([exit, delay2(WORKER_EXIT_POLL_MS)]);
67006
+ if (exited())
67007
+ return true;
67008
+ if (workerProcessExited(pid))
67009
+ return confirmed();
67010
+ this.observeResponsiveness();
67011
+ if (performance.now() - since - (this.stalledMs - stalledAt) >= WORKER_EXIT_CONFIRMATION_MS)
67012
+ return exited() || workerProcessExited(pid, true) && confirmed();
67013
+ }
67014
+ }
67015
+ retireUnconfirmed(child) {
67016
+ if (this.unconfirmedExits.has(child))
67017
+ return;
67018
+ this.unconfirmedExits.add(child);
67019
+ this.reportHealth(this.logs.get(child), `Local worker cleanup was not confirmed: worker process ${child.pid} was still running ${WORKER_EXIT_CONFIRMATION_MS} ms after SIGKILL; it was retired and replaced`);
67020
+ if (child.connected)
67021
+ child.disconnect();
67022
+ for (const slot of this.slots)
67023
+ if (slot.child === child)
67024
+ slot.retire?.();
67025
+ }
67026
+ reportHealth(log, message) {
67027
+ if (log !== undefined) {
67028
+ this.keptLogs.add(log);
67029
+ appendFile(log, `[atomic ${new Date().toISOString()}] ${message}
67030
+ `).catch(() => {});
67031
+ }
67032
+ this.port.send({ kind: "health", message: log === undefined ? message : `${message} (worker log: ${log})` });
66658
67033
  }
66659
67034
  async close() {
66660
67035
  this.closed = true;
@@ -66664,10 +67039,15 @@ class PoolCoordinator {
66664
67039
  this.rateLimitOutbox.close();
66665
67040
  let failure;
66666
67041
  let stopping = [];
67042
+ let confirmed = [];
66667
67043
  try {
66668
67044
  await this.recovering?.catch(() => {});
66669
67045
  stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
66670
- await Promise.all(stopping.map(({ child }) => this.stop(child)));
67046
+ confirmed = await Promise.all(stopping.map(({ child }) => this.stop(child)));
67047
+ stopping.forEach(({ child }, index) => {
67048
+ if (!confirmed[index])
67049
+ this.retireUnconfirmed(child);
67050
+ });
66671
67051
  await Promise.all([...this.cleanups]);
66672
67052
  if (this.cleanupFailure)
66673
67053
  throw this.cleanupFailure;
@@ -66679,15 +67059,15 @@ class PoolCoordinator {
66679
67059
  if (alive.length > 0)
66680
67060
  throw unconfirmedCleanup(alive);
66681
67061
  if (this.desiredControl !== "quit" && this.queue !== undefined && this.lease !== undefined)
66682
- await this.queue.releaseClosed(this.lease, [...this.quarantined]).catch((error) => {
67062
+ await this.queue.releaseClosed(this.lease).catch((error) => {
66683
67063
  if (!(error instanceof StaleLeaseError))
66684
67064
  throw error;
66685
67065
  });
66686
67066
  } catch (error) {
66687
67067
  failure = error;
66688
67068
  }
66689
- if (failure === undefined) {
66690
- const stopped = stopping.flatMap(({ child, log }) => log !== undefined && (child.exitCode !== null || child.signalCode !== null) ? [log] : []);
67069
+ if (failure === undefined && !this.failed) {
67070
+ const stopped = stopping.flatMap(({ log }, index) => log !== undefined && !this.keptLogs.has(log) && confirmed[index] === true ? [log] : []);
66691
67071
  await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
66692
67072
  if (this.logDirectory !== undefined)
66693
67073
  await rmdir(this.logDirectory).catch(() => {});
@@ -66713,7 +67093,7 @@ function childRetryLimit(work, reason) {
66713
67093
  const exportName = work.definition.slice(work.definition.lastIndexOf("#") + 1);
66714
67094
  return `Local worker retry limit: child ${work.childRunId} (${exportName}) ${reason} ${MAX_CHILD_ATTEMPTS} times`;
66715
67095
  }
66716
- var CONTROL_ACKNOWLEDGEMENT_STALL_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, LATE_ROOT_POLL_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
67096
+ var CONTROL_ACKNOWLEDGEMENT_STALL_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, LATE_ROOT_POLL_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, WORKER_EXIT_CONFIRMATION_MS = 5000, WORKER_EXIT_POLL_MS = 50, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
66717
67097
  var init_pool_coordinator = __esm(() => {
66718
67098
  init_internal();
66719
67099
  init_pool_remote_journal();
@@ -66728,6 +67108,7 @@ var init_pool_coordinator = __esm(() => {
66728
67108
  init_pending_stage_route_readiness();
66729
67109
  init_store();
66730
67110
  init_workflow_infrastructure_error();
67111
+ init_admission_host();
66731
67112
  init_pool_journal();
66732
67113
  init_pooled_watch_trace();
66733
67114
  init_resource_admission();
@@ -66956,7 +67337,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
66956
67337
  };
66957
67338
  }
66958
67339
  async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
66959
- const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
67340
+ const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
66960
67341
  const candidateIds = new Set([
66961
67342
  ...activeStore.pendingStageMessagesFor(runId, stageId),
66962
67343
  ...activeStore.pendingStageMessagesFor(runId, stageName),
@@ -67012,7 +67393,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
67012
67393
  }
67013
67394
  }
67014
67395
  }
67015
- function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
67396
+ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
67016
67397
  const runs = activeStore.runs();
67017
67398
  const rootRunId = durableRootRunIdForRun(runs, runId);
67018
67399
  if (rootRunId === undefined)
@@ -67021,22 +67402,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
67021
67402
  if (rootRun === undefined)
67022
67403
  return [];
67023
67404
  const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
67024
- if (stage?.status === "completed" || stage?.status === "skipped")
67405
+ const ended = stage?.status === "completed" || stage?.status === "skipped";
67406
+ if (ended && receivedByEndedStage.length === 0)
67025
67407
  return [];
67026
67408
  const hops = workflowBoundaryHops(runs, runId);
67027
67409
  if (hops === undefined)
67028
67410
  return [];
67029
67411
  return (rootRun.pendingStageMessages ?? []).filter((entry) => {
67030
- if (entry.sticky !== true || entry.status !== "queued")
67031
- return false;
67032
- const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
67033
- if (parsed === undefined || parsed.rootRunId !== rootRunId)
67034
- return false;
67035
67412
  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)))))
67036
67413
  return false;
67037
- return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
67414
+ if (ended && !receivedByEndedStage.includes(entry.message.id))
67415
+ return false;
67416
+ return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
67038
67417
  });
67039
67418
  }
67419
+ function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
67420
+ if (entry.sticky !== true || entry.status !== "queued")
67421
+ return false;
67422
+ const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
67423
+ if (parsed === undefined || parsed.rootRunId !== rootRunId)
67424
+ return false;
67425
+ return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
67426
+ }
67040
67427
  function claimPendingDelivery(store, runId, stageKey, messageId) {
67041
67428
  let claims = pendingDeliveryClaims.get(store);
67042
67429
  if (claims === undefined) {
@@ -67100,6 +67487,7 @@ class PoolStageHandoff {
67100
67487
  owners = new Map;
67101
67488
  publications = new Map;
67102
67489
  drains = new Map;
67490
+ deliveryIssues = 0;
67103
67491
  constructor(backend, store, queue, lease, claimRun) {
67104
67492
  this.backend = backend;
67105
67493
  this.store = store;
@@ -67180,11 +67568,23 @@ class PoolStageHandoff {
67180
67568
  this.drains.set(stage, drain);
67181
67569
  try {
67182
67570
  await drain;
67571
+ } catch (error) {
67572
+ const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
67573
+ if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
67574
+ this.recordDeliveryIssue(error);
67575
+ throw error;
67183
67576
  } finally {
67184
67577
  if (this.drains.get(stage) === drain)
67185
67578
  this.drains.delete(stage);
67186
67579
  }
67187
67580
  }
67581
+ recordDeliveryIssue(error) {
67582
+ this.deliveryIssues++;
67583
+ const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
67584
+ this.store.recordRunExecutionState(this.lease.runId, {
67585
+ intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
67586
+ });
67587
+ }
67188
67588
  async complete(work) {
67189
67589
  const root = this.lease.runId;
67190
67590
  const result = await this.queue.result(root, work.id);
@@ -68540,7 +68940,7 @@ var init_pooled_stage_registry = __esm(() => {
68540
68940
  // dist/builtin/workflows/src/workers/local-pool.ts
68541
68941
  import { fork as fork2 } from "node:child_process";
68542
68942
  import { randomUUID as randomUUID19 } from "node:crypto";
68543
- import { resolve as resolve14 } from "node:path";
68943
+ import { resolve as resolve15 } from "node:path";
68544
68944
  import { setTimeout as delay3 } from "node:timers/promises";
68545
68945
  import { fileURLToPath as fileURLToPath5 } from "node:url";
68546
68946
  import {
@@ -68658,6 +69058,7 @@ class LocalWorkerPool {
68658
69058
  works = new Map;
68659
69059
  attempts = new Map;
68660
69060
  results = new Map;
69061
+ healthEvents = [];
68661
69062
  workFailures = new Map;
68662
69063
  changed = Promise.withResolvers();
68663
69064
  waiting = 0;
@@ -68715,6 +69116,9 @@ class LocalWorkerPool {
68715
69116
  if (options.admission && options.rootId === undefined)
68716
69117
  workflowResourceAdmission.set(backend, options.admission);
68717
69118
  }
69119
+ get health() {
69120
+ return this.healthEvents;
69121
+ }
68718
69122
  get workerPids() {
68719
69123
  return [...this.pids];
68720
69124
  }
@@ -68770,7 +69174,7 @@ class LocalWorkerPool {
68770
69174
  async poolJournal() {
68771
69175
  const journal = this.backend.journal;
68772
69176
  if (this.options.durable === undefined) {
68773
- if (!(journal instanceof SqlRunJournal) || resolve14(this.options.journalPath) !== resolve14(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
69177
+ if (!(journal instanceof SqlRunJournal) || resolve15(this.options.journalPath) !== resolve15(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
68774
69178
  throw new Error("Local workers require the same default-prefix SQLite journal");
68775
69179
  return journal;
68776
69180
  }
@@ -69308,14 +69712,8 @@ class LocalWorkerPool {
69308
69712
  try {
69309
69713
  return await this.dispatch(definition, inputs, options);
69310
69714
  } catch (error) {
69311
- if (error instanceof WorkflowInfrastructureError && [...this.workFailures.values()].includes(error))
69312
- throw error;
69313
- try {
69314
- if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
69315
- await this.shutdown();
69316
- } catch (closeError) {
69317
- throw asWorkflowInfrastructureError(closeError) ?? closeError;
69318
- }
69715
+ if (this.failure !== undefined || this.coordinatorLost !== undefined)
69716
+ await this.shutdown().catch(() => {});
69319
69717
  throw asWorkflowInfrastructureError(error) ?? error;
69320
69718
  }
69321
69719
  }
@@ -69383,8 +69781,13 @@ class LocalWorkerPool {
69383
69781
  try {
69384
69782
  for (;; ) {
69385
69783
  options.signal?.throwIfAborted();
69386
- if (this.closed)
69387
- throw this.closedError(root);
69784
+ if (!this.results.has(work.id) && (this.closed || this.failure !== undefined)) {
69785
+ const recorded = await this.queue?.result(root, work.id).catch(() => {
69786
+ return;
69787
+ });
69788
+ if (recorded !== undefined)
69789
+ this.results.set(work.id, recorded);
69790
+ }
69388
69791
  const result = this.results.get(work.id);
69389
69792
  if (result) {
69390
69793
  this.completing++;
@@ -69408,6 +69811,8 @@ class LocalWorkerPool {
69408
69811
  this.endFailedChild(work, failed);
69409
69812
  throw failed;
69410
69813
  }
69814
+ if (this.closed)
69815
+ throw this.closedError(root);
69411
69816
  if (this.failure)
69412
69817
  throw this.failure;
69413
69818
  if (this.budgetBlocked)
@@ -69442,6 +69847,19 @@ class LocalWorkerPool {
69442
69847
  if (this.reconnectingViews.size > 0 || this.outboxes.size > 0)
69443
69848
  this.reconnectStageViews();
69444
69849
  }
69850
+ recordHealth(message) {
69851
+ this.healthEvents.push(message);
69852
+ const root = this.root;
69853
+ if (root === undefined || this.store === undefined)
69854
+ return;
69855
+ this.store.recordNotice({
69856
+ id: `local-worker-health:${root}:${this.healthEvents.length}`,
69857
+ runId: root,
69858
+ level: "warning",
69859
+ message: `Local worker pool: ${message}`,
69860
+ createdAt: Date.now()
69861
+ });
69862
+ }
69445
69863
  evaluateBudget() {
69446
69864
  const decision = this.rootBudget?.checkpoint();
69447
69865
  const blocked = decision?.kind === "exhausted" || decision?.kind === "wrap_up";
@@ -69560,6 +69978,9 @@ class LocalWorkerPool {
69560
69978
  this.failure ??= new Error(event.error);
69561
69979
  this.signalChange();
69562
69980
  return;
69981
+ case "health":
69982
+ this.recordHealth(event.message);
69983
+ return;
69563
69984
  case "stage-events":
69564
69985
  this.stageWatches.get(event.watch)?.({ kind: "events", events: event.events });
69565
69986
  this.notice({ kind: "stage-events-applied", watch: event.watch });
@@ -69780,7 +70201,7 @@ var init_local_pool = __esm(() => {
69780
70201
  var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
69781
70202
 
69782
70203
  // dist/builtin/workflows/src/workers/public-pool.ts
69783
- import { resolve as resolve15 } from "node:path";
70204
+ import { resolve as resolve16 } from "node:path";
69784
70205
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
69785
70206
  async function restoreWorkerOptions(backend, options) {
69786
70207
  const source = options.continuation?.source.id ?? options.runId;
@@ -69830,16 +70251,16 @@ async function activatePublicPool(backend, options) {
69830
70251
  startupTimeoutMs: undefined,
69831
70252
  leaseMs: undefined,
69832
70253
  maxLoadPerCpu: undefined,
69833
- definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
70254
+ definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve16(cwd, source.path) }))
69834
70255
  };
69835
70256
  const admission = options.admission && {
69836
70257
  ...options.admission,
69837
- ...options.admission.userDatabase ? { userDatabase: resolve15(cwd, options.admission.userDatabase) } : {}
70258
+ ...options.admission.userDatabase ? { userDatabase: resolve16(cwd, options.admission.userDatabase) } : {}
69838
70259
  };
69839
70260
  if (durable !== undefined && admission?.userLimits) {
69840
- if (admission.userDatabase !== undefined && admission.userDatabase !== resolve15(poolPath))
69841
- throw new Error(`admission.userDatabase must be omitted, or ${resolve15(poolPath)}, for a journal that is not a local SQLite file`);
69842
- admission.userDatabase = resolve15(poolPath);
70261
+ if (admission.userDatabase !== undefined && admission.userDatabase !== resolve16(poolPath))
70262
+ throw new Error(`admission.userDatabase must be omitted, or ${resolve16(poolPath)}, for a journal that is not a local SQLite file`);
70263
+ admission.userDatabase = resolve16(poolPath);
69843
70264
  }
69844
70265
  const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
69845
70266
  const resources = JSON.parse(JSON.stringify({
@@ -70445,6 +70866,7 @@ function createTaskPrimitive(runtime) {
70445
70866
  }
70446
70867
  })();
70447
70868
  const stageMeta = stage.__modelFallbackMeta();
70869
+ stage.__releaseIfIdle?.();
70448
70870
  return {
70449
70871
  name,
70450
70872
  stageName: name,
@@ -71243,7 +71665,7 @@ function hasUsableContentBlock(block) {
71243
71665
 
71244
71666
  // dist/builtin/workflows/src/shared/stage-session-store.ts
71245
71667
  import { randomUUID as randomUUID21 } from "node:crypto";
71246
- import { dirname as dirname15, resolve as resolve16 } from "node:path";
71668
+ import { dirname as dirname16, resolve as resolve17 } from "node:path";
71247
71669
  import {
71248
71670
  JsonlSessionStore,
71249
71671
  resolveSessionStore,
@@ -71279,11 +71701,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
71279
71701
  async function migrateLegacyStageSession(store, sessionId, sessionFile) {
71280
71702
  if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
71281
71703
  return;
71282
- const location = resolve16(sessionFile);
71283
- const legacy = await JsonlSessionStore.open(dirname15(location), { exactDirectory: true, scanExisting: false });
71704
+ const location = resolve17(sessionFile);
71705
+ const legacy = await JsonlSessionStore.open(dirname16(location), { exactDirectory: true, scanExisting: false });
71284
71706
  try {
71285
71707
  for await (const file of legacy.scanFiles()) {
71286
- if (resolve16(file.location) !== location || file.header.id !== sessionId)
71708
+ if (resolve17(file.location) !== location || file.header.id !== sessionId)
71287
71709
  continue;
71288
71710
  const snapshot = await file.read();
71289
71711
  if (await store.readHeader(sessionId) === undefined)
@@ -74109,6 +74531,8 @@ function createTrackedStageCaller(input) {
74109
74531
  await runtime.releaseLiveHandle().catch(() => {});
74110
74532
  }
74111
74533
  runtime.state.sessionCheckpointed = finalizationError === undefined;
74534
+ if (runtime.state.contextUnreachable)
74535
+ runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
74112
74536
  input.limiter.release();
74113
74537
  if (finalizationError !== undefined)
74114
74538
  throwFinalizationError(finalizationError.error);
@@ -74272,7 +74696,8 @@ function createStageContext(input) {
74272
74696
  recordStageNotice({ kind: "abort", to: "interrupted" });
74273
74697
  await innerCtx.abort();
74274
74698
  },
74275
- __modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
74699
+ __modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
74700
+ __releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
74276
74701
  };
74277
74702
  }
74278
74703
 
@@ -75961,10 +76386,10 @@ function isRetryableSameCandidateFailure(error) {
75961
76386
  return isTransientExtensionStartupFailure(error);
75962
76387
  return isRetryableSameModelFailure(error);
75963
76388
  }
75964
- function mayAdvanceToNextCandidate(error) {
76389
+ function mayAdvanceToNextCandidate(error, options) {
75965
76390
  if (isExtensionStartupFailure(error))
75966
76391
  return isTransientExtensionStartupFailure(error);
75967
- return isRetryableModelFailure(error);
76392
+ return isRetryableModelFailure(error, options);
75968
76393
  }
75969
76394
  function hasMeaningfulUsage(usage) {
75970
76395
  if (usage === undefined)
@@ -76056,6 +76481,7 @@ class StageSessionController {
76056
76481
  structuredOutputExecutionFailureValue;
76057
76482
  structuredOutputCycleAttemptMark;
76058
76483
  unsubscribeTerminateWatcher;
76484
+ unbindAbortSignal;
76059
76485
  sessionInternalRetries = 0;
76060
76486
  unresolvedContextOverflowMessage;
76061
76487
  generationSealed = false;
@@ -76545,6 +76971,8 @@ class StageSessionController {
76545
76971
  this.pendingListeners.clear();
76546
76972
  this.unsubscribeTerminateWatcher?.();
76547
76973
  this.unsubscribeTerminateWatcher = undefined;
76974
+ this.unbindAbortSignal?.();
76975
+ this.unbindAbortSignal = undefined;
76548
76976
  this.terminatingToolCallIds.clear();
76549
76977
  this.messageAdmission.dispose();
76550
76978
  this.deliveryActivity.dispose();
@@ -76639,8 +77067,10 @@ class StageSessionController {
76639
77067
  };
76640
77068
  if (signal.aborted)
76641
77069
  onAbort();
76642
- else
77070
+ else {
76643
77071
  signal.addEventListener("abort", onAbort, { once: true });
77072
+ this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
77073
+ }
76644
77074
  }
76645
77075
  markAbort(reason) {
76646
77076
  this.abortGeneration += 1;
@@ -76667,6 +77097,9 @@ class StageSessionController {
76667
77097
  state.controller.abort(reason);
76668
77098
  this.thrownErrorRetryStates.clear();
76669
77099
  }
77100
+ fallbackFailureOptions() {
77101
+ return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
77102
+ }
76670
77103
  retrySettings() {
76671
77104
  const managers = [
76672
77105
  this.sessionSettingsManager,
@@ -76941,7 +77374,7 @@ class StageSessionController {
76941
77374
  const errorSettingsManager = retrySettingsManagerFromError(error);
76942
77375
  if (errorSettingsManager !== undefined)
76943
77376
  this.sessionSettingsManager = errorSettingsManager;
76944
- const retryableFailure = isRetryableModelFailure(error);
77377
+ const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
76945
77378
  const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
76946
77379
  recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
76947
77380
  if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
@@ -77566,7 +77999,7 @@ class StageSessionController {
77566
77999
  }
77567
78000
  throw new WorkflowPromptModelFailure(terminalFailure);
77568
78001
  } catch (err) {
77569
- if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
78002
+ if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77570
78003
  this.artifactCapture.settleAttempt(true);
77571
78004
  const usage = this.takeAttemptUsage(resumedSession);
77572
78005
  this.modelAttempts.push({
@@ -77588,7 +78021,7 @@ class StageSessionController {
77588
78021
  ...usage === undefined ? {} : { usage },
77589
78022
  error: message
77590
78023
  });
77591
- if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
78024
+ if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77592
78025
  this.modelWarnings.push(...this.pendingFallbackWarnings);
77593
78026
  this.pendingFallbackWarnings.length = 0;
77594
78027
  this.notifyModelFallbackMetaChange();
@@ -77637,7 +78070,7 @@ class StageSessionController {
77637
78070
  throw err;
77638
78071
  const message = errorMessage3(err);
77639
78072
  const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
77640
- if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
78073
+ if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
77641
78074
  this.recordSuccessfulAttempt(candidate);
77642
78075
  return "handled";
77643
78076
  }
@@ -77654,7 +78087,7 @@ class StageSessionController {
77654
78087
  if (walk !== undefined) {
77655
78088
  this.recordCandidateFailure(walk, index, err, candidates);
77656
78089
  nextIndex = undefined;
77657
- if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
78090
+ if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
77658
78091
  try {
77659
78092
  nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
77660
78093
  } catch (error) {
@@ -77667,7 +78100,7 @@ class StageSessionController {
77667
78100
  }
77668
78101
  }
77669
78102
  }
77670
- if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
78103
+ if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
77671
78104
  await this.settleFailedCandidate();
77672
78105
  return "throw";
77673
78106
  }
@@ -77762,7 +78195,7 @@ var init_stage_runner_controller = __esm(() => {
77762
78195
  // dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
77763
78196
  import { createHash as createHash6 } from "node:crypto";
77764
78197
  import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
77765
- import { basename as basename6, dirname as dirname16, isAbsolute as isAbsolute11, join as join31, resolve as resolve17 } from "node:path";
78198
+ import { basename as basename6, dirname as dirname17, isAbsolute as isAbsolute11, join as join32, resolve as resolve18 } from "node:path";
77766
78199
  function normalizeMaxOutput2(maxOutput) {
77767
78200
  return {
77768
78201
  bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
@@ -77825,7 +78258,7 @@ function formatByteSize(bytes) {
77825
78258
  }
77826
78259
  function transcriptPath(runId, outputPath) {
77827
78260
  const digest = createHash6("sha256").update(outputPath).digest("hex").slice(0, 16);
77828
- return join31(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename6(outputPath)}.transcript.md`);
78261
+ return join32(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename6(outputPath)}.transcript.md`);
77829
78262
  }
77830
78263
  function appendContent(lines, content) {
77831
78264
  if (typeof content === "string") {
@@ -77870,7 +78303,7 @@ function renderTranscript(messages, fallbackOutput) {
77870
78303
  `);
77871
78304
  }
77872
78305
  function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
77873
- const absolutePath = resolve17(outputPath);
78306
+ const absolutePath = resolve18(outputPath);
77874
78307
  const bytes = Buffer.byteLength(fullOutput, "utf8");
77875
78308
  const lines = countLines(fullOutput);
77876
78309
  const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
@@ -77885,8 +78318,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
77885
78318
  return;
77886
78319
  if (isAbsolute11(output))
77887
78320
  return output;
77888
- const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve17(runtimeCwd, requestedCwd);
77889
- return resolve17(baseCwd, output);
78321
+ const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve18(runtimeCwd, requestedCwd);
78322
+ return resolve18(baseCwd, output);
77890
78323
  }
77891
78324
  function degenerateWarning(fullOutput) {
77892
78325
  return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
@@ -77945,7 +78378,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
77945
78378
  const transcriptFile = transcriptPath(runId, outputPath);
77946
78379
  const transcript = renderTranscript(messages, fullOutput);
77947
78380
  try {
77948
- await mkdir7(dirname16(outputPath), { recursive: true });
78381
+ await mkdir7(dirname17(outputPath), { recursive: true });
77949
78382
  await writeFile10(outputPath, fullOutput, "utf8");
77950
78383
  } catch (err) {
77951
78384
  return `${displayOutput}
@@ -77957,7 +78390,7 @@ ${err instanceof Error ? err.message : String(err)}`;
77957
78390
  let transcriptError;
77958
78391
  try {
77959
78392
  await ensureWorkflowArtifactRunDirectory(runId);
77960
- await mkdir7(dirname16(transcriptFile), { recursive: true });
78393
+ await mkdir7(dirname17(transcriptFile), { recursive: true });
77961
78394
  await writeFile10(transcriptFile, transcript, "utf8");
77962
78395
  transcriptAvailable = true;
77963
78396
  } catch (err) {
@@ -78468,7 +78901,8 @@ function createWorkflowStageFactory(input) {
78468
78901
  stageFinalized: false,
78469
78902
  sessionCheckpointed: false,
78470
78903
  skippedForParallelFailFast: false,
78471
- stageControlDropped: false
78904
+ stageControlDropped: false,
78905
+ contextUnreachable: false
78472
78906
  };
78473
78907
  const activeAskUserQuestionCalls = new Set;
78474
78908
  const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
@@ -78714,9 +79148,18 @@ function createWorkflowStageFactory(input) {
78714
79148
  hasContinuation: input.opts.continuation !== undefined,
78715
79149
  hasScopedParents: stageFailFastScope?.parentIds !== undefined
78716
79150
  });
78717
- return createStageContext({ runtime, runTrackedStageCall });
79151
+ const context = createStageContext({ runtime, runTrackedStageCall });
79152
+ unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
79153
+ return context;
79154
+ };
79155
+ }
79156
+ function releaseWhenUnreachable(state, registry, runId, stageId) {
79157
+ return () => {
79158
+ state.contextUnreachable = true;
79159
+ registry.releaseIdle(runId, stageId);
78718
79160
  };
78719
79161
  }
79162
+ var unreachableStageContexts;
78720
79163
  var init_executor_stage_factory = __esm(() => {
78721
79164
  init_intercom_group();
78722
79165
  init_pending_stage_route_readiness();
@@ -78731,6 +79174,7 @@ var init_executor_stage_factory = __esm(() => {
78731
79174
  init_pending_stage_delivery2();
78732
79175
  init_stage_runner();
78733
79176
  init_stage_runner_session();
79177
+ unreachableStageContexts = new FinalizationRegistry((release) => release());
78734
79178
  });
78735
79179
 
78736
79180
  // dist/builtin/workflows/src/engine/runtime.ts
@@ -79072,7 +79516,7 @@ async function executeRun(def, resolvedInputs, opts) {
79072
79516
  const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
79073
79517
  const tracker = new GraphFrontierTracker;
79074
79518
  const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
79075
- const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
79519
+ const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
79076
79520
  const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
79077
79521
  const workflowInvocationCwd = opts.cwd ?? process.cwd();
79078
79522
  let workflowCwd;