@bastani/atomic 0.9.61-alpha.1 → 0.9.61-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -4
- package/dist/builtin/intercom/index.bundle.mjs +3 -3
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +12 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +14 -0
- package/dist/builtin/workflows/README.md +9 -7
- package/dist/builtin/workflows/builtin/{chunk-h6bt0r0g.js → chunk-a2j0x1a6.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-g3b2zf8r.js → chunk-vzbec50q.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +1 -1
- package/dist/builtin/workflows/builtin/index.js +2 -2
- package/dist/builtin/workflows/builtin/ralph.js +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +828 -418
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +905 -429
- package/dist/builtin/workflows/src/index.js +798 -393
- package/dist/builtin/workflows/src/local-worker-entry.mjs +905 -429
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +12 -3
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +14 -4
- package/dist/core/model-fallback-failures.d.ts.map +1 -1
- package/dist/core/model-fallback-failures.js +43 -15
- package/dist/core/model-fallback-failures.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +1 -0
- package/dist/core/settings-defaults.d.ts.map +1 -1
- package/dist/core/settings-defaults.js +1 -0
- package/dist/core/settings-defaults.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +2 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-schema.d.ts +2 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +4 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-startup-chat-container.d.ts +2 -0
- package/dist/modes/interactive/interactive-startup-chat-container.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup-chat-container.js +6 -0
- package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.d.ts +8 -0
- package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +28 -6
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.d.ts +33 -5
- package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +91 -17
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/rpc/queued-writer.d.ts +2 -0
- package/dist/modes/rpc/queued-writer.d.ts.map +1 -1
- package/dist/modes/rpc/queued-writer.js +8 -0
- package/dist/modes/rpc/queued-writer.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +4 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/docs/intercom/reference.md +1 -1
- package/docs/models/evals.md +30 -2
- package/docs/settings.md +3 -0
- package/docs/subagents/reference.md +3 -1
- package/docs/workflows/api-reference.md +9 -6
- package/docs/workflows/builtins.md +1 -1
- package/docs/workflows/operations.md +4 -4
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +5 -0
|
@@ -13462,9 +13462,104 @@ var init_workflow_artifacts = __esm(() => {
|
|
|
13462
13462
|
pendingArtifactPrunes = new Map;
|
|
13463
13463
|
});
|
|
13464
13464
|
|
|
13465
|
-
// dist/builtin/workflows/src/runs/shared/worktree-
|
|
13465
|
+
// dist/builtin/workflows/src/runs/shared/worktree-allocation.ts
|
|
13466
|
+
import { randomBytes } from "node:crypto";
|
|
13466
13467
|
import * as fs from "node:fs";
|
|
13467
13468
|
import * as path from "node:path";
|
|
13469
|
+
function nextBucketId() {
|
|
13470
|
+
return nextBucketIdOverride?.() ?? randomBytes(2).toString("hex");
|
|
13471
|
+
}
|
|
13472
|
+
function errorCode(error) {
|
|
13473
|
+
return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
13474
|
+
}
|
|
13475
|
+
function allocateWorktreeCheckoutPath(root, repositoryName) {
|
|
13476
|
+
for (let attempt = 0;attempt < MAX_BUCKET_ATTEMPTS; attempt++) {
|
|
13477
|
+
const bucket = path.join(root, nextBucketId());
|
|
13478
|
+
try {
|
|
13479
|
+
fs.mkdirSync(bucket);
|
|
13480
|
+
return path.join(bucket, repositoryName);
|
|
13481
|
+
} catch (error) {
|
|
13482
|
+
if (errorCode(error) === "EEXIST")
|
|
13483
|
+
continue;
|
|
13484
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13485
|
+
throw new Error(`Failed to create worktree bucket ${bucket} under gitWorktreeDir ${root}: ${message}`);
|
|
13486
|
+
}
|
|
13487
|
+
}
|
|
13488
|
+
throw new Error(`Every worktree bucket identifier under gitWorktreeDir ${root} is already in use.`);
|
|
13489
|
+
}
|
|
13490
|
+
function removeEmptyWorktreeBucket(checkout) {
|
|
13491
|
+
try {
|
|
13492
|
+
fs.rmdirSync(path.dirname(checkout));
|
|
13493
|
+
} catch {}
|
|
13494
|
+
}
|
|
13495
|
+
function linkedGitDirectory(checkout) {
|
|
13496
|
+
let pointer;
|
|
13497
|
+
try {
|
|
13498
|
+
if (!fs.lstatSync(path.join(checkout, ".git")).isFile())
|
|
13499
|
+
return;
|
|
13500
|
+
pointer = fs.readFileSync(path.join(checkout, ".git"), "utf8");
|
|
13501
|
+
} catch {
|
|
13502
|
+
return;
|
|
13503
|
+
}
|
|
13504
|
+
if (!pointer.startsWith("gitdir:"))
|
|
13505
|
+
return;
|
|
13506
|
+
const gitDir = pointer.slice("gitdir:".length).trim();
|
|
13507
|
+
return gitDir ? path.resolve(checkout, gitDir) : undefined;
|
|
13508
|
+
}
|
|
13509
|
+
function readWorktreeOwner(gitDir) {
|
|
13510
|
+
let contents;
|
|
13511
|
+
try {
|
|
13512
|
+
contents = fs.readFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), "utf8");
|
|
13513
|
+
} catch {
|
|
13514
|
+
return;
|
|
13515
|
+
}
|
|
13516
|
+
try {
|
|
13517
|
+
const record = JSON.parse(contents);
|
|
13518
|
+
return record.version === WORKTREE_OWNER_VERSION && typeof record.ownerRunId === "string" && record.ownerRunId ? record.ownerRunId : undefined;
|
|
13519
|
+
} catch {
|
|
13520
|
+
return;
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13523
|
+
function findOwnedWorktreeCheckouts(root, repositoryName, ownerRunId) {
|
|
13524
|
+
let entries;
|
|
13525
|
+
try {
|
|
13526
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
13527
|
+
} catch {
|
|
13528
|
+
return [];
|
|
13529
|
+
}
|
|
13530
|
+
const owned = [];
|
|
13531
|
+
for (const entry of entries) {
|
|
13532
|
+
if (!entry.isDirectory() || !BUCKET_PATTERN.test(entry.name))
|
|
13533
|
+
continue;
|
|
13534
|
+
const checkout = path.join(root, entry.name, repositoryName);
|
|
13535
|
+
try {
|
|
13536
|
+
if (!fs.lstatSync(checkout).isDirectory())
|
|
13537
|
+
continue;
|
|
13538
|
+
} catch {
|
|
13539
|
+
continue;
|
|
13540
|
+
}
|
|
13541
|
+
const gitDir = linkedGitDirectory(checkout);
|
|
13542
|
+
if (gitDir !== undefined && readWorktreeOwner(gitDir) === ownerRunId)
|
|
13543
|
+
owned.push(checkout);
|
|
13544
|
+
}
|
|
13545
|
+
return owned.sort();
|
|
13546
|
+
}
|
|
13547
|
+
function bindWorktreeOwner(gitDir, ownerRunId) {
|
|
13548
|
+
const record = { version: WORKTREE_OWNER_VERSION, ownerRunId };
|
|
13549
|
+
fs.writeFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), `${JSON.stringify(record)}
|
|
13550
|
+
`, {
|
|
13551
|
+
encoding: "utf8",
|
|
13552
|
+
flag: "wx"
|
|
13553
|
+
});
|
|
13554
|
+
}
|
|
13555
|
+
var WORKTREE_OWNER_FILENAME = "atomic-workflow-run.json", WORKTREE_OWNER_VERSION = 1, BUCKET_PATTERN, MAX_BUCKET_ATTEMPTS = 65536, nextBucketIdOverride;
|
|
13556
|
+
var init_worktree_allocation = __esm(() => {
|
|
13557
|
+
BUCKET_PATTERN = /^[0-9a-f]{4}$/;
|
|
13558
|
+
});
|
|
13559
|
+
|
|
13560
|
+
// dist/builtin/workflows/src/runs/shared/worktree-generation.ts
|
|
13561
|
+
import * as fs2 from "node:fs";
|
|
13562
|
+
import * as path2 from "node:path";
|
|
13468
13563
|
function sameFileIdentity(left, right) {
|
|
13469
13564
|
return left.dev === right.dev && left.ino === right.ino;
|
|
13470
13565
|
}
|
|
@@ -13474,7 +13569,7 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
13474
13569
|
assertCurrent() {
|
|
13475
13570
|
if (disposed)
|
|
13476
13571
|
throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
|
|
13477
|
-
if (!
|
|
13572
|
+
if (!fs2.lstatSync(gitDir).isDirectory()) {
|
|
13478
13573
|
throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
|
|
13479
13574
|
}
|
|
13480
13575
|
},
|
|
@@ -13484,17 +13579,17 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
13484
13579
|
};
|
|
13485
13580
|
}
|
|
13486
13581
|
function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
13487
|
-
const gitFile =
|
|
13488
|
-
if (
|
|
13582
|
+
const gitFile = path2.join(worktreeRoot, ".git");
|
|
13583
|
+
if (fs2.lstatSync(gitFile).isDirectory())
|
|
13489
13584
|
return openMainCheckoutAnchor(gitFile);
|
|
13490
|
-
const descriptor =
|
|
13585
|
+
const descriptor = fs2.openSync(gitFile, "r");
|
|
13491
13586
|
let disposed = false;
|
|
13492
13587
|
const anchor = {
|
|
13493
13588
|
assertCurrent() {
|
|
13494
13589
|
if (disposed)
|
|
13495
13590
|
throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
|
|
13496
|
-
const held =
|
|
13497
|
-
const current =
|
|
13591
|
+
const held = fs2.fstatSync(descriptor, { bigint: true });
|
|
13592
|
+
const current = fs2.lstatSync(gitFile, { bigint: true });
|
|
13498
13593
|
if (!current.isFile() || !sameFileIdentity(held, current)) {
|
|
13499
13594
|
throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
|
|
13500
13595
|
}
|
|
@@ -13503,7 +13598,7 @@ function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
|
13503
13598
|
if (disposed)
|
|
13504
13599
|
return;
|
|
13505
13600
|
disposed = true;
|
|
13506
|
-
|
|
13601
|
+
fs2.closeSync(descriptor);
|
|
13507
13602
|
}
|
|
13508
13603
|
};
|
|
13509
13604
|
try {
|
|
@@ -13617,84 +13712,84 @@ var init_worktree_git_runner = __esm(() => {
|
|
|
13617
13712
|
});
|
|
13618
13713
|
|
|
13619
13714
|
// dist/builtin/workflows/src/runs/shared/worktree-root.ts
|
|
13620
|
-
import * as
|
|
13621
|
-
import * as
|
|
13715
|
+
import * as fs3 from "node:fs";
|
|
13716
|
+
import * as path3 from "node:path";
|
|
13622
13717
|
function pathFromPointer(contents, prefix, base) {
|
|
13623
13718
|
if (!contents.startsWith(prefix))
|
|
13624
13719
|
return;
|
|
13625
13720
|
const value2 = contents.slice(prefix.length).trim();
|
|
13626
13721
|
if (!value2)
|
|
13627
13722
|
return;
|
|
13628
|
-
return
|
|
13723
|
+
return path3.resolve(base, value2);
|
|
13629
13724
|
}
|
|
13630
13725
|
function readText(file) {
|
|
13631
13726
|
try {
|
|
13632
|
-
return
|
|
13727
|
+
return fs3.readFileSync(file, "utf8");
|
|
13633
13728
|
} catch {
|
|
13634
13729
|
return;
|
|
13635
13730
|
}
|
|
13636
13731
|
}
|
|
13637
13732
|
function samePath(left, right) {
|
|
13638
13733
|
try {
|
|
13639
|
-
const a =
|
|
13640
|
-
const b =
|
|
13734
|
+
const a = fs3.realpathSync.native(left);
|
|
13735
|
+
const b = fs3.realpathSync.native(right);
|
|
13641
13736
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
13642
13737
|
} catch {
|
|
13643
13738
|
return false;
|
|
13644
13739
|
}
|
|
13645
13740
|
}
|
|
13646
13741
|
function findGitRoot(cwd) {
|
|
13647
|
-
let current =
|
|
13742
|
+
let current = path3.resolve(cwd);
|
|
13648
13743
|
try {
|
|
13649
|
-
if (!
|
|
13650
|
-
current =
|
|
13744
|
+
if (!fs3.statSync(current).isDirectory())
|
|
13745
|
+
current = path3.dirname(current);
|
|
13651
13746
|
} catch {
|
|
13652
13747
|
return;
|
|
13653
13748
|
}
|
|
13654
13749
|
while (true) {
|
|
13655
13750
|
try {
|
|
13656
|
-
const entry =
|
|
13751
|
+
const entry = fs3.statSync(path3.join(current, ".git"));
|
|
13657
13752
|
if (entry.isDirectory() || entry.isFile())
|
|
13658
13753
|
return current;
|
|
13659
13754
|
} catch {}
|
|
13660
|
-
const parent =
|
|
13755
|
+
const parent = path3.dirname(current);
|
|
13661
13756
|
if (parent === current)
|
|
13662
13757
|
return;
|
|
13663
13758
|
current = parent;
|
|
13664
13759
|
}
|
|
13665
13760
|
}
|
|
13666
13761
|
function resolveMainRepoRoot(repoRoot) {
|
|
13667
|
-
const gitEntry =
|
|
13762
|
+
const gitEntry = path3.join(repoRoot, ".git");
|
|
13668
13763
|
let stats;
|
|
13669
13764
|
try {
|
|
13670
|
-
stats =
|
|
13765
|
+
stats = fs3.statSync(gitEntry);
|
|
13671
13766
|
} catch {
|
|
13672
13767
|
return;
|
|
13673
13768
|
}
|
|
13674
13769
|
if (stats.isDirectory())
|
|
13675
|
-
return
|
|
13770
|
+
return path3.resolve(repoRoot);
|
|
13676
13771
|
if (!stats.isFile())
|
|
13677
13772
|
return;
|
|
13678
13773
|
const pointer = readText(gitEntry);
|
|
13679
13774
|
if (pointer === undefined)
|
|
13680
13775
|
return;
|
|
13681
13776
|
const gitDir = pathFromPointer(pointer, "gitdir:", repoRoot);
|
|
13682
|
-
if (gitDir === undefined ||
|
|
13777
|
+
if (gitDir === undefined || path3.basename(path3.dirname(gitDir)) !== "worktrees")
|
|
13683
13778
|
return;
|
|
13684
|
-
const commonGitDir =
|
|
13685
|
-
if (
|
|
13779
|
+
const commonGitDir = path3.dirname(path3.dirname(gitDir));
|
|
13780
|
+
if (path3.basename(commonGitDir) !== ".git")
|
|
13686
13781
|
return;
|
|
13687
|
-
const backPointer = readText(
|
|
13688
|
-
const commonPointer = readText(
|
|
13782
|
+
const backPointer = readText(path3.join(gitDir, "gitdir"));
|
|
13783
|
+
const commonPointer = readText(path3.join(gitDir, "commondir"));
|
|
13689
13784
|
if (backPointer === undefined || commonPointer === undefined)
|
|
13690
13785
|
return;
|
|
13691
|
-
const linkedGitEntry =
|
|
13692
|
-
const declaredCommonDir =
|
|
13786
|
+
const linkedGitEntry = path3.resolve(gitDir, backPointer.trim());
|
|
13787
|
+
const declaredCommonDir = path3.resolve(gitDir, commonPointer.trim());
|
|
13693
13788
|
if (!backPointer.trim() || !commonPointer.trim())
|
|
13694
13789
|
return;
|
|
13695
13790
|
if (!samePath(linkedGitEntry, gitEntry) || !samePath(declaredCommonDir, commonGitDir))
|
|
13696
13791
|
return;
|
|
13697
|
-
return
|
|
13792
|
+
return path3.dirname(commonGitDir);
|
|
13698
13793
|
}
|
|
13699
13794
|
function findCanonicalGitRoot(cwd) {
|
|
13700
13795
|
const repoRoot = findGitRoot(cwd);
|
|
@@ -13703,33 +13798,31 @@ function findCanonicalGitRoot(cwd) {
|
|
|
13703
13798
|
var init_worktree_root = () => {};
|
|
13704
13799
|
|
|
13705
13800
|
// dist/builtin/workflows/src/runs/shared/worktree-git.ts
|
|
13706
|
-
import * as
|
|
13707
|
-
import * as
|
|
13708
|
-
function gitWorktreeSetupCacheKey(
|
|
13709
|
-
const repoRoot = repositoryRootForGitWorktree(options.cwd);
|
|
13710
|
-
const { logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
13711
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
13801
|
+
import * as fs4 from "node:fs";
|
|
13802
|
+
import * as path4 from "node:path";
|
|
13803
|
+
function gitWorktreeSetupCacheKey(request) {
|
|
13712
13804
|
return JSON.stringify([
|
|
13713
|
-
|
|
13714
|
-
comparablePathThroughExistingAncestor(
|
|
13805
|
+
comparablePathThroughExistingAncestor(request.options.cwd),
|
|
13806
|
+
comparablePathThroughExistingAncestor(request.target)
|
|
13715
13807
|
]);
|
|
13716
13808
|
}
|
|
13717
|
-
function createGitWorktreeSetupCache() {
|
|
13809
|
+
function createGitWorktreeSetupCache(ownerRunId) {
|
|
13718
13810
|
const results = new Map;
|
|
13719
13811
|
let disposed = false;
|
|
13720
13812
|
return {
|
|
13721
13813
|
get(options) {
|
|
13722
13814
|
if (disposed)
|
|
13723
13815
|
throw new Error("Git worktree setup cache is already disposed");
|
|
13724
|
-
const
|
|
13816
|
+
const request = resolveGitWorktreeSetupRequest(options);
|
|
13817
|
+
const key = gitWorktreeSetupCacheKey(request);
|
|
13725
13818
|
const cached = results.get(key);
|
|
13726
13819
|
if (cached !== undefined) {
|
|
13727
13820
|
assertCachedGitWorktreeIdentity(cached, options);
|
|
13728
13821
|
return cached.result;
|
|
13729
13822
|
}
|
|
13730
|
-
const
|
|
13731
|
-
results.set(key, {
|
|
13732
|
-
return result;
|
|
13823
|
+
const setup = setupGitWorktreeFromRequest(request, ownerRunId);
|
|
13824
|
+
results.set(key, { ...setup, identity: captureGitWorktreeIdentity(setup) });
|
|
13825
|
+
return setup.result;
|
|
13733
13826
|
},
|
|
13734
13827
|
dispose() {
|
|
13735
13828
|
if (disposed)
|
|
@@ -13761,10 +13854,10 @@ function worktreeRecoveryCommand(repositoryRoot, worktreeDir) {
|
|
|
13761
13854
|
return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
|
|
13762
13855
|
}
|
|
13763
13856
|
function hasGrandparent(value2) {
|
|
13764
|
-
const parent =
|
|
13857
|
+
const parent = path4.dirname(value2);
|
|
13765
13858
|
if (parent === value2)
|
|
13766
13859
|
return false;
|
|
13767
|
-
const grandparent =
|
|
13860
|
+
const grandparent = path4.dirname(parent);
|
|
13768
13861
|
return grandparent !== parent;
|
|
13769
13862
|
}
|
|
13770
13863
|
function pathAncestors(value2) {
|
|
@@ -13772,7 +13865,7 @@ function pathAncestors(value2) {
|
|
|
13772
13865
|
let current = value2;
|
|
13773
13866
|
while (true) {
|
|
13774
13867
|
ancestors.push(current);
|
|
13775
|
-
const parent =
|
|
13868
|
+
const parent = path4.dirname(current);
|
|
13776
13869
|
if (parent === current)
|
|
13777
13870
|
return ancestors;
|
|
13778
13871
|
current = parent;
|
|
@@ -13781,89 +13874,167 @@ function pathAncestors(value2) {
|
|
|
13781
13874
|
function shouldPreserveLogicalPath(logicalPath) {
|
|
13782
13875
|
return pathAncestors(logicalPath).some((ancestor) => {
|
|
13783
13876
|
try {
|
|
13784
|
-
return
|
|
13877
|
+
return fs4.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
|
|
13785
13878
|
} catch {
|
|
13786
13879
|
return false;
|
|
13787
13880
|
}
|
|
13788
13881
|
});
|
|
13789
13882
|
}
|
|
13790
13883
|
function canonicalizePreservingSymlinks(value2) {
|
|
13791
|
-
const logicalPath =
|
|
13884
|
+
const logicalPath = path4.resolve(value2);
|
|
13792
13885
|
const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
|
|
13793
13886
|
try {
|
|
13794
|
-
const canonical =
|
|
13887
|
+
const canonical = fs4.realpathSync.native(logicalPath);
|
|
13795
13888
|
return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
|
|
13796
13889
|
} catch {
|
|
13797
13890
|
return logicalPath;
|
|
13798
13891
|
}
|
|
13799
13892
|
}
|
|
13800
|
-
function resolveGitWorktreePath(value2,
|
|
13893
|
+
function resolveGitWorktreePath(value2, baseDir) {
|
|
13801
13894
|
const trimmed = value2.trim();
|
|
13802
13895
|
if (!trimmed)
|
|
13803
13896
|
throw new Error("gitWorktreeDir cannot be empty");
|
|
13804
13897
|
if (trimmed.includes("\x00")) {
|
|
13805
13898
|
throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
|
|
13806
13899
|
}
|
|
13807
|
-
return canonicalizePreservingSymlinks(
|
|
13900
|
+
return canonicalizePreservingSymlinks(path4.isAbsolute(trimmed) ? trimmed : path4.resolve(baseDir, trimmed));
|
|
13808
13901
|
}
|
|
13809
13902
|
function comparableRealPath(value2) {
|
|
13810
|
-
const realpath =
|
|
13903
|
+
const realpath = fs4.realpathSync.native(value2).replace(/\\/g, "/");
|
|
13811
13904
|
return process.platform === "win32" ? realpath.toLowerCase() : realpath;
|
|
13812
13905
|
}
|
|
13813
|
-
function
|
|
13814
|
-
let existing =
|
|
13906
|
+
function nearestExistingAncestor(value2) {
|
|
13907
|
+
let existing = path4.resolve(value2);
|
|
13815
13908
|
const missing = [];
|
|
13816
13909
|
while (!pathExistsSync(existing)) {
|
|
13817
|
-
const parent =
|
|
13910
|
+
const parent = path4.dirname(existing);
|
|
13818
13911
|
if (parent === existing)
|
|
13819
13912
|
break;
|
|
13820
|
-
missing.unshift(
|
|
13913
|
+
missing.unshift(path4.basename(existing));
|
|
13821
13914
|
existing = parent;
|
|
13822
13915
|
}
|
|
13823
|
-
|
|
13916
|
+
return { existing, missing };
|
|
13917
|
+
}
|
|
13918
|
+
function comparablePathThroughExistingAncestor(value2) {
|
|
13919
|
+
const { existing, missing } = nearestExistingAncestor(value2);
|
|
13920
|
+
const resolved = path4.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
|
|
13824
13921
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
13825
13922
|
}
|
|
13923
|
+
function isFileOrLink(value2) {
|
|
13924
|
+
try {
|
|
13925
|
+
const entry = fs4.lstatSync(value2);
|
|
13926
|
+
return entry.isFile() || entry.isSymbolicLink();
|
|
13927
|
+
} catch {
|
|
13928
|
+
return false;
|
|
13929
|
+
}
|
|
13930
|
+
}
|
|
13931
|
+
function isDirectory(value2) {
|
|
13932
|
+
try {
|
|
13933
|
+
return fs4.statSync(value2).isDirectory();
|
|
13934
|
+
} catch {
|
|
13935
|
+
return false;
|
|
13936
|
+
}
|
|
13937
|
+
}
|
|
13938
|
+
function looksLikeGitDirectory(directory) {
|
|
13939
|
+
if (!isDirectory(directory))
|
|
13940
|
+
return false;
|
|
13941
|
+
if (path4.basename(directory) === ".git")
|
|
13942
|
+
return true;
|
|
13943
|
+
if (!isFileOrLink(path4.join(directory, "HEAD")))
|
|
13944
|
+
return false;
|
|
13945
|
+
if (isFileOrLink(path4.join(directory, "commondir")))
|
|
13946
|
+
return true;
|
|
13947
|
+
return isDirectory(path4.join(directory, "objects")) && isDirectory(path4.join(directory, "refs"));
|
|
13948
|
+
}
|
|
13949
|
+
function enclosingGitMetadataDirectory(target) {
|
|
13950
|
+
const { existing } = nearestExistingAncestor(target);
|
|
13951
|
+
let realExisting = existing;
|
|
13952
|
+
try {
|
|
13953
|
+
realExisting = fs4.realpathSync.native(existing);
|
|
13954
|
+
} catch {}
|
|
13955
|
+
for (const candidate of new Set([...pathAncestors(existing), ...pathAncestors(realExisting)])) {
|
|
13956
|
+
if (looksLikeGitDirectory(candidate))
|
|
13957
|
+
return candidate;
|
|
13958
|
+
}
|
|
13959
|
+
const insideGitDir = runGitReadOnlyProbe(existing, ["rev-parse", "--is-inside-git-dir"]);
|
|
13960
|
+
if (insideGitDir.status !== 0 && isGitTimeoutResult(insideGitDir)) {
|
|
13961
|
+
throw new Error(`Timed out while validating gitWorktreeDir ${target}. Git reported: ${gitFailureMessage(insideGitDir)}`);
|
|
13962
|
+
}
|
|
13963
|
+
return insideGitDir.status === 0 && insideGitDir.stdout.trim() === "true" ? existing : undefined;
|
|
13964
|
+
}
|
|
13965
|
+
function assertSafeGitWorktreeTarget(target, invokingRoot) {
|
|
13966
|
+
const gitDirectory = enclosingGitMetadataDirectory(target);
|
|
13967
|
+
if (gitDirectory !== undefined) {
|
|
13968
|
+
throw new Error(`gitWorktreeDir must not be inside Git metadata: ${target} is inside the Git directory ${gitDirectory}. Choose a worktree root or a plain directory outside Git metadata.`);
|
|
13969
|
+
}
|
|
13970
|
+
if (invokingRoot !== undefined)
|
|
13971
|
+
validateWorktreeOutsideInvokingCheckout(target, invokingRoot);
|
|
13972
|
+
const { existing, missing } = nearestExistingAncestor(target);
|
|
13973
|
+
const workingTree = gitTopLevel(existing);
|
|
13974
|
+
if (workingTree === undefined)
|
|
13975
|
+
return;
|
|
13976
|
+
if (missing.length === 0 && comparableRealPath(target) === comparableRealPath(workingTree))
|
|
13977
|
+
return;
|
|
13978
|
+
throw new Error(`gitWorktreeDir must not be inside another Git working tree: ${target} is inside ${workingTree}. Pass that checkout's root to reuse it, or a path outside every Git checkout.`);
|
|
13979
|
+
}
|
|
13826
13980
|
function validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot) {
|
|
13827
13981
|
const repository = comparableRealPath(repoRoot);
|
|
13828
13982
|
const candidate = comparablePathThroughExistingAncestor(worktreeRoot);
|
|
13829
|
-
const relativePath =
|
|
13983
|
+
const relativePath = path4.relative(repository, candidate);
|
|
13830
13984
|
if (relativePath === "") {
|
|
13831
|
-
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate
|
|
13985
|
+
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate worktree path outside it.");
|
|
13832
13986
|
}
|
|
13833
|
-
if (!relativePath.startsWith(`..${
|
|
13834
|
-
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate
|
|
13987
|
+
if (!relativePath.startsWith(`..${path4.sep}`) && relativePath !== ".." && !path4.isAbsolute(relativePath)) {
|
|
13988
|
+
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate worktree path outside it.");
|
|
13835
13989
|
}
|
|
13836
13990
|
}
|
|
13837
13991
|
function gitPathFromOutput(value2, cwd) {
|
|
13838
13992
|
const trimmed = value2.trim();
|
|
13839
13993
|
if (!trimmed)
|
|
13840
13994
|
return;
|
|
13841
|
-
return
|
|
13995
|
+
return path4.isAbsolute(trimmed) ? path4.resolve(trimmed) : path4.resolve(cwd, trimmed);
|
|
13842
13996
|
}
|
|
13843
13997
|
function pathExistsSync(value2) {
|
|
13998
|
+
return pathStatSync(value2) !== undefined;
|
|
13999
|
+
}
|
|
14000
|
+
function pathStatSync(value2) {
|
|
13844
14001
|
try {
|
|
13845
|
-
|
|
13846
|
-
return true;
|
|
14002
|
+
return fs4.statSync(value2);
|
|
13847
14003
|
} catch (error) {
|
|
13848
14004
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
13849
14005
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
13850
|
-
return
|
|
14006
|
+
return;
|
|
13851
14007
|
throw error;
|
|
13852
14008
|
}
|
|
13853
14009
|
}
|
|
13854
|
-
function
|
|
14010
|
+
function probeInvokingRepository(cwd) {
|
|
13855
14011
|
const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
|
|
13856
14012
|
if (result.status !== 0) {
|
|
13857
14013
|
if (isGitTimeoutResult(result)) {
|
|
13858
14014
|
throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
13859
14015
|
}
|
|
13860
|
-
|
|
14016
|
+
return { failure: gitFailureMessage(result) };
|
|
13861
14017
|
}
|
|
13862
|
-
const
|
|
13863
|
-
if (
|
|
14018
|
+
const root = gitPathFromOutput(result.stdout, cwd);
|
|
14019
|
+
if (root === undefined) {
|
|
13864
14020
|
throw new Error(`gitWorktreeDir could not resolve the repository top level from ${cwd}: git returned an empty path.`);
|
|
13865
14021
|
}
|
|
13866
|
-
return
|
|
14022
|
+
return { repository: { root, ...cwdWithinGitRepository(cwd, root) } };
|
|
14023
|
+
}
|
|
14024
|
+
function resolveGitWorktreeSetupRequest(options) {
|
|
14025
|
+
const probe = probeInvokingRepository(options.cwd);
|
|
14026
|
+
if ("repository" in probe) {
|
|
14027
|
+
return {
|
|
14028
|
+
options,
|
|
14029
|
+
repository: probe.repository,
|
|
14030
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, probe.repository.logicalRoot)
|
|
14031
|
+
};
|
|
14032
|
+
}
|
|
14033
|
+
return {
|
|
14034
|
+
options,
|
|
14035
|
+
repositoryProbeFailure: probe.failure,
|
|
14036
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, canonicalizePreservingSymlinks(options.cwd))
|
|
14037
|
+
};
|
|
13867
14038
|
}
|
|
13868
14039
|
function gitTopLevelFromResult(result, cwd, description) {
|
|
13869
14040
|
if (result.status !== 0) {
|
|
@@ -13899,25 +14070,25 @@ function dirnameForEachRelativeComponent(base, relativePath) {
|
|
|
13899
14070
|
continue;
|
|
13900
14071
|
if (component === "..")
|
|
13901
14072
|
return;
|
|
13902
|
-
current =
|
|
14073
|
+
current = path4.dirname(current);
|
|
13903
14074
|
}
|
|
13904
14075
|
return current;
|
|
13905
14076
|
}
|
|
13906
14077
|
function cwdWithinGitRepository(cwd, repoRoot) {
|
|
13907
|
-
const sourceCwd =
|
|
13908
|
-
const sourceRepoRoot =
|
|
13909
|
-
const relativeCwd =
|
|
13910
|
-
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") ||
|
|
14078
|
+
const sourceCwd = fs4.realpathSync.native(cwd);
|
|
14079
|
+
const sourceRepoRoot = fs4.realpathSync.native(repoRoot);
|
|
14080
|
+
const relativeCwd = path4.relative(sourceRepoRoot, sourceCwd);
|
|
14081
|
+
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path4.isAbsolute(relativeCwd) ? "" : relativeCwd;
|
|
13911
14082
|
const logicalCwd = canonicalizePreservingSymlinks(cwd);
|
|
13912
14083
|
return {
|
|
13913
14084
|
relativeCwd: safeRelativeCwd,
|
|
13914
|
-
|
|
14085
|
+
logicalRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
|
|
13915
14086
|
};
|
|
13916
14087
|
}
|
|
13917
14088
|
function workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd) {
|
|
13918
|
-
return relativeCwd === "" ? worktreeRoot :
|
|
14089
|
+
return relativeCwd === "" ? worktreeRoot : path4.join(worktreeRoot, relativeCwd);
|
|
13919
14090
|
}
|
|
13920
|
-
function
|
|
14091
|
+
function validateGitWorktreeRoot(worktreeRoot) {
|
|
13921
14092
|
const topLevel = gitTopLevel(worktreeRoot);
|
|
13922
14093
|
if (topLevel === undefined) {
|
|
13923
14094
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
|
|
@@ -13925,8 +14096,18 @@ function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
|
|
|
13925
14096
|
if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
|
|
13926
14097
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
|
|
13927
14098
|
}
|
|
13928
|
-
|
|
13929
|
-
|
|
14099
|
+
return gitCommonDirForWorktree(topLevel);
|
|
14100
|
+
}
|
|
14101
|
+
function existingGitWorktreeCommonDir(directory) {
|
|
14102
|
+
return gitTopLevel(directory) === undefined ? undefined : validateGitWorktreeRoot(directory);
|
|
14103
|
+
}
|
|
14104
|
+
function sameGitCommonDir(left, right) {
|
|
14105
|
+
return comparableRealPath(left) === comparableRealPath(right);
|
|
14106
|
+
}
|
|
14107
|
+
function validateCreatedGitWorktree(worktreeRoot, repository) {
|
|
14108
|
+
assertSafeGitWorktreeTarget(worktreeRoot, repository.root);
|
|
14109
|
+
if (!sameGitCommonDir(validateGitWorktreeRoot(worktreeRoot), gitCommonDirForWorktree(repository.root))) {
|
|
14110
|
+
throw new Error(`gitWorktreeDir does not belong to the invoking Git repository: ${worktreeRoot}`);
|
|
13930
14111
|
}
|
|
13931
14112
|
}
|
|
13932
14113
|
function gitDirectoryForWorktree(cwd) {
|
|
@@ -13940,26 +14121,27 @@ function gitDirectoryForWorktree(cwd) {
|
|
|
13940
14121
|
return gitDir;
|
|
13941
14122
|
}
|
|
13942
14123
|
function captureGitWorktreeIdentitySnapshot(setup) {
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
const
|
|
14124
|
+
const { worktreeRoot, repositoryRoot } = setup.result;
|
|
14125
|
+
assertSafeGitWorktreeTarget(worktreeRoot, setup.invokingRoot);
|
|
14126
|
+
const commonDir = validateGitWorktreeRoot(worktreeRoot);
|
|
14127
|
+
const stats = fs4.statSync(worktreeRoot);
|
|
13946
14128
|
return {
|
|
13947
|
-
worktreeRealPath: comparableRealPath(
|
|
13948
|
-
repositoryRealPath: comparableRealPath(
|
|
13949
|
-
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(
|
|
13950
|
-
commonDirRealPath: comparableRealPath(
|
|
14129
|
+
worktreeRealPath: comparableRealPath(worktreeRoot),
|
|
14130
|
+
repositoryRealPath: comparableRealPath(repositoryRoot),
|
|
14131
|
+
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(worktreeRoot)),
|
|
14132
|
+
commonDirRealPath: comparableRealPath(commonDir),
|
|
13951
14133
|
device: stats.dev,
|
|
13952
14134
|
inode: stats.ino
|
|
13953
14135
|
};
|
|
13954
14136
|
}
|
|
13955
14137
|
function captureGitWorktreeIdentity(setup) {
|
|
13956
14138
|
const snapshot = captureGitWorktreeIdentitySnapshot(setup);
|
|
13957
|
-
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.worktreeRoot) };
|
|
14139
|
+
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.result.worktreeRoot) };
|
|
13958
14140
|
}
|
|
13959
14141
|
function assertCachedGitWorktreeIdentity(cached, options) {
|
|
13960
14142
|
let current;
|
|
13961
14143
|
try {
|
|
13962
|
-
current = captureGitWorktreeIdentitySnapshot(cached
|
|
14144
|
+
current = captureGitWorktreeIdentitySnapshot(cached);
|
|
13963
14145
|
cached.identity.generation.assertCurrent();
|
|
13964
14146
|
} catch (error) {
|
|
13965
14147
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -13967,34 +14149,58 @@ function assertCachedGitWorktreeIdentity(cached, options) {
|
|
|
13967
14149
|
}
|
|
13968
14150
|
const expected = cached.identity;
|
|
13969
14151
|
if (current.worktreeRealPath !== expected.worktreeRealPath || current.repositoryRealPath !== expected.repositoryRealPath || current.gitDirRealPath !== expected.gitDirRealPath || current.commonDirRealPath !== expected.commonDirRealPath || current.device !== expected.device || current.inode !== expected.inode) {
|
|
13970
|
-
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended
|
|
13971
|
-
}
|
|
14152
|
+
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended worktree.`);
|
|
14153
|
+
}
|
|
14154
|
+
}
|
|
14155
|
+
function requireInvokingRepository(request, action) {
|
|
14156
|
+
if (request.repository !== undefined)
|
|
14157
|
+
return request.repository;
|
|
14158
|
+
throw new Error([
|
|
14159
|
+
`gitWorktreeDir requires the workflow to be invoked from inside a Git repository to ${action}.`,
|
|
14160
|
+
"Start the workflow from a checkout of the repository the new worktree should come from, or set gitWorktreeDir to the root of an existing Git worktree to reuse it from any directory.",
|
|
14161
|
+
`Git reported: ${request.repositoryProbeFailure ?? "no repository"}`
|
|
14162
|
+
].join(" "));
|
|
14163
|
+
}
|
|
14164
|
+
function setupGitWorktreeFromRequest(request, ownerRunId) {
|
|
14165
|
+
const { repository, target } = request;
|
|
14166
|
+
assertSafeGitWorktreeTarget(target, repository?.root);
|
|
14167
|
+
const entry = pathStatSync(target);
|
|
14168
|
+
if (entry === undefined)
|
|
14169
|
+
return createGitWorktreeAtPath(request, false);
|
|
14170
|
+
if (!entry.isDirectory())
|
|
14171
|
+
throw new Error(`gitWorktreeDir already exists but is not a directory: ${target}`);
|
|
14172
|
+
if (fs4.readdirSync(target).length === 0)
|
|
14173
|
+
return createGitWorktreeAtPath(request, true);
|
|
14174
|
+
const commonDir = existingGitWorktreeCommonDir(target);
|
|
14175
|
+
if (commonDir === undefined)
|
|
14176
|
+
return allocateGitWorktree(request, ownerRunId);
|
|
14177
|
+
const sameRepository = repository !== undefined && sameGitCommonDir(commonDir, gitCommonDirForWorktree(repository.root));
|
|
14178
|
+
return {
|
|
14179
|
+
result: {
|
|
14180
|
+
worktreeRoot: target,
|
|
14181
|
+
cwd: sameRepository ? workspaceCwdForGitWorktreeRoot(target, repository.relativeCwd) : target,
|
|
14182
|
+
repositoryRoot: sameRepository ? repository.root : target,
|
|
14183
|
+
created: false
|
|
14184
|
+
},
|
|
14185
|
+
...repository !== undefined ? { invokingRoot: repository.root } : {}
|
|
14186
|
+
};
|
|
13972
14187
|
}
|
|
13973
|
-
function
|
|
13974
|
-
const
|
|
13975
|
-
const
|
|
14188
|
+
function createGitWorktreeAtPath(request, existingEmptyDirectory) {
|
|
14189
|
+
const { target: worktreeRoot } = request;
|
|
14190
|
+
const repository = requireInvokingRepository(request, `create a new worktree at ${worktreeRoot}`);
|
|
14191
|
+
const mainRoot = findCanonicalGitRoot(repository.root);
|
|
13976
14192
|
if (mainRoot === undefined) {
|
|
13977
|
-
throw new Error(`Unable to resolve the canonical main Git repository root from ${
|
|
13978
|
-
}
|
|
13979
|
-
const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
13980
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
13981
|
-
validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
|
|
13982
|
-
if (pathExistsSync(worktreeRoot)) {
|
|
13983
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
13984
|
-
return {
|
|
13985
|
-
worktreeRoot,
|
|
13986
|
-
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
|
|
13987
|
-
repositoryRoot: repoRoot,
|
|
13988
|
-
created: false
|
|
13989
|
-
};
|
|
14193
|
+
throw new Error(`Unable to resolve the canonical main Git repository root from ${repository.root}.`);
|
|
13990
14194
|
}
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
14195
|
+
if (!existingEmptyDirectory) {
|
|
14196
|
+
try {
|
|
14197
|
+
fs4.mkdirSync(path4.dirname(worktreeRoot), { recursive: true });
|
|
14198
|
+
} catch (error) {
|
|
14199
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14200
|
+
throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
|
|
14201
|
+
}
|
|
13996
14202
|
}
|
|
13997
|
-
const baseRef = options.baseBranch?.trim() || "HEAD";
|
|
14203
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
13998
14204
|
const result = runGit(mainRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
|
|
13999
14205
|
if (result.status !== 0) {
|
|
14000
14206
|
throw new Error([
|
|
@@ -14004,30 +14210,127 @@ function setupGitWorktree(options) {
|
|
|
14004
14210
|
`));
|
|
14005
14211
|
}
|
|
14006
14212
|
try {
|
|
14007
|
-
|
|
14008
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
14213
|
+
validateCreatedGitWorktree(worktreeRoot, repository);
|
|
14009
14214
|
} catch (error) {
|
|
14010
14215
|
runGit(mainRoot, ["worktree", "remove", "--force", worktreeRoot]);
|
|
14011
14216
|
const message = error instanceof Error ? error.message : String(error);
|
|
14012
14217
|
throw new Error(`Created gitWorktreeDir failed post-creation validation: ${message}`);
|
|
14013
14218
|
}
|
|
14014
14219
|
return {
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14220
|
+
result: {
|
|
14221
|
+
worktreeRoot,
|
|
14222
|
+
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, repository.relativeCwd),
|
|
14223
|
+
repositoryRoot: repository.root,
|
|
14224
|
+
created: true
|
|
14225
|
+
},
|
|
14226
|
+
invokingRoot: repository.root
|
|
14019
14227
|
};
|
|
14020
14228
|
}
|
|
14229
|
+
function containedWorktreeCwd(checkout, relativeCwd) {
|
|
14230
|
+
const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
|
|
14231
|
+
let resolved;
|
|
14232
|
+
try {
|
|
14233
|
+
resolved = fs4.realpathSync.native(cwd);
|
|
14234
|
+
} catch {
|
|
14235
|
+
resolved = "";
|
|
14236
|
+
}
|
|
14237
|
+
const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
|
|
14238
|
+
if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
|
|
14239
|
+
throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
|
|
14240
|
+
}
|
|
14241
|
+
return cwd;
|
|
14242
|
+
}
|
|
14243
|
+
function allocatedGitWorktreeSetup(checkout, repository, created) {
|
|
14244
|
+
return {
|
|
14245
|
+
result: {
|
|
14246
|
+
worktreeRoot: checkout,
|
|
14247
|
+
cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
|
|
14248
|
+
repositoryRoot: repository.root,
|
|
14249
|
+
created
|
|
14250
|
+
},
|
|
14251
|
+
invokingRoot: repository.root
|
|
14252
|
+
};
|
|
14253
|
+
}
|
|
14254
|
+
function validateOwnedGitWorktree(checkout, repository) {
|
|
14255
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14256
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14257
|
+
if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
|
|
14258
|
+
throw new Error(`${checkout} is not a linked worktree`);
|
|
14259
|
+
}
|
|
14260
|
+
const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
|
|
14261
|
+
if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
|
|
14262
|
+
throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
|
|
14263
|
+
}
|
|
14264
|
+
}
|
|
14265
|
+
function findOwnedGitWorktree(root, repository, ownerRunId) {
|
|
14266
|
+
const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
|
|
14267
|
+
if (checkout === undefined)
|
|
14268
|
+
return;
|
|
14269
|
+
try {
|
|
14270
|
+
validateOwnedGitWorktree(checkout, repository);
|
|
14271
|
+
return allocatedGitWorktreeSetup(checkout, repository, false);
|
|
14272
|
+
} catch (error) {
|
|
14273
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14274
|
+
throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
|
|
14275
|
+
}
|
|
14276
|
+
}
|
|
14277
|
+
function allocateGitWorktree(request, ownerRunId) {
|
|
14278
|
+
const { target: root } = request;
|
|
14279
|
+
const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
|
|
14280
|
+
if (ownerRunId !== undefined) {
|
|
14281
|
+
const owned = findOwnedGitWorktree(root, repository, ownerRunId);
|
|
14282
|
+
if (owned !== undefined)
|
|
14283
|
+
return owned;
|
|
14284
|
+
}
|
|
14285
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
14286
|
+
const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
|
|
14287
|
+
const commit = revision.status === 0 ? revision.stdout.trim() : "";
|
|
14288
|
+
if (commit === "") {
|
|
14289
|
+
throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
|
|
14290
|
+
}
|
|
14291
|
+
const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
|
|
14292
|
+
const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
|
|
14293
|
+
if (add.status !== 0) {
|
|
14294
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14295
|
+
throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
|
|
14296
|
+
}
|
|
14297
|
+
try {
|
|
14298
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14299
|
+
runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
|
|
14300
|
+
runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
|
|
14301
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14302
|
+
const setup = allocatedGitWorktreeSetup(checkout, repository, true);
|
|
14303
|
+
if (ownerRunId !== undefined)
|
|
14304
|
+
bindWorktreeOwner(gitDir, ownerRunId);
|
|
14305
|
+
return setup;
|
|
14306
|
+
} catch (error) {
|
|
14307
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14308
|
+
const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
|
|
14309
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14310
|
+
const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
|
|
14311
|
+
throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
|
|
14312
|
+
}
|
|
14313
|
+
}
|
|
14314
|
+
function runGitOrThrow(cwd, args) {
|
|
14315
|
+
const result = runGit(cwd, args);
|
|
14316
|
+
if (result.status !== 0)
|
|
14317
|
+
throw new Error(gitFailureMessage(result));
|
|
14318
|
+
}
|
|
14319
|
+
function setupGitWorktree(options) {
|
|
14320
|
+
return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
|
|
14321
|
+
}
|
|
14021
14322
|
var init_worktree_git = __esm(() => {
|
|
14323
|
+
init_worktree_allocation();
|
|
14022
14324
|
init_worktree_generation();
|
|
14023
14325
|
init_worktree_git_runner();
|
|
14024
14326
|
init_worktree_root();
|
|
14327
|
+
init_worktree_allocation();
|
|
14025
14328
|
init_worktree_git_runner();
|
|
14026
14329
|
});
|
|
14027
14330
|
|
|
14028
14331
|
// dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
|
|
14029
|
-
function createGitWorktreeSetupCacheOwner(suppliedCache) {
|
|
14030
|
-
const cache = suppliedCache ?? createGitWorktreeSetupCache();
|
|
14332
|
+
function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
|
|
14333
|
+
const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
|
|
14031
14334
|
const ownsCache = suppliedCache === undefined;
|
|
14032
14335
|
let released = false;
|
|
14033
14336
|
return {
|
|
@@ -14048,20 +14351,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
|
|
|
14048
14351
|
});
|
|
14049
14352
|
|
|
14050
14353
|
// dist/builtin/workflows/src/runs/shared/worktree-diff.ts
|
|
14051
|
-
import * as
|
|
14052
|
-
import * as
|
|
14354
|
+
import * as fs5 from "node:fs";
|
|
14355
|
+
import * as path5 from "node:path";
|
|
14053
14356
|
function safePatchAgentName(agent) {
|
|
14054
14357
|
return agent.replace(/[^\w.-]/g, "_");
|
|
14055
14358
|
}
|
|
14056
14359
|
function removeSyntheticPath(worktree, syntheticPath) {
|
|
14057
|
-
const resolved =
|
|
14058
|
-
const relative =
|
|
14059
|
-
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${
|
|
14360
|
+
const resolved = path5.resolve(worktree.path, syntheticPath);
|
|
14361
|
+
const relative = path5.relative(worktree.path, resolved);
|
|
14362
|
+
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path5.sep}`) || path5.isAbsolute(relative)) {
|
|
14060
14363
|
return;
|
|
14061
14364
|
}
|
|
14062
14365
|
let stat;
|
|
14063
14366
|
try {
|
|
14064
|
-
stat =
|
|
14367
|
+
stat = fs5.lstatSync(resolved);
|
|
14065
14368
|
} catch (error) {
|
|
14066
14369
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
14067
14370
|
if (code === "ENOENT")
|
|
@@ -14069,14 +14372,14 @@ function removeSyntheticPath(worktree, syntheticPath) {
|
|
|
14069
14372
|
throw error;
|
|
14070
14373
|
}
|
|
14071
14374
|
if (stat.isSymbolicLink()) {
|
|
14072
|
-
|
|
14375
|
+
fs5.unlinkSync(resolved);
|
|
14073
14376
|
return;
|
|
14074
14377
|
}
|
|
14075
14378
|
if (stat.isDirectory()) {
|
|
14076
|
-
|
|
14379
|
+
fs5.rmSync(resolved, { recursive: true, force: true });
|
|
14077
14380
|
return;
|
|
14078
14381
|
}
|
|
14079
|
-
|
|
14382
|
+
fs5.rmSync(resolved, { force: true });
|
|
14080
14383
|
}
|
|
14081
14384
|
function removeSyntheticPathsBeforeDiff(worktree) {
|
|
14082
14385
|
if (worktree.syntheticPaths.length === 0)
|
|
@@ -14125,7 +14428,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
14125
14428
|
const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
|
|
14126
14429
|
const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
|
|
14127
14430
|
const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
|
|
14128
|
-
|
|
14431
|
+
fs5.writeFileSync(patchPath, patch, "utf-8");
|
|
14129
14432
|
if (!patch.trim()) {
|
|
14130
14433
|
return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
|
|
14131
14434
|
}
|
|
@@ -14143,7 +14446,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
14143
14446
|
}
|
|
14144
14447
|
function writeEmptyPatch(patchPath) {
|
|
14145
14448
|
try {
|
|
14146
|
-
|
|
14449
|
+
fs5.writeFileSync(patchPath, "", "utf-8");
|
|
14147
14450
|
} catch {}
|
|
14148
14451
|
}
|
|
14149
14452
|
function hasWorktreeChanges(diff) {
|
|
@@ -14151,7 +14454,7 @@ function hasWorktreeChanges(diff) {
|
|
|
14151
14454
|
}
|
|
14152
14455
|
function diffWorktrees(setup, agents, diffsDir) {
|
|
14153
14456
|
try {
|
|
14154
|
-
|
|
14457
|
+
fs5.mkdirSync(diffsDir, { recursive: true });
|
|
14155
14458
|
} catch {
|
|
14156
14459
|
return [];
|
|
14157
14460
|
}
|
|
@@ -14159,7 +14462,7 @@ function diffWorktrees(setup, agents, diffsDir) {
|
|
|
14159
14462
|
for (let index = 0;index < setup.worktrees.length; index++) {
|
|
14160
14463
|
const worktree = setup.worktrees[index];
|
|
14161
14464
|
const agent = agents[index] ?? `task-${index + 1}`;
|
|
14162
|
-
const patchPath =
|
|
14465
|
+
const patchPath = path5.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
|
|
14163
14466
|
try {
|
|
14164
14467
|
diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
|
|
14165
14468
|
} catch {
|
|
@@ -14181,7 +14484,7 @@ function formatWorktreeDiffSummary(diffs) {
|
|
|
14181
14484
|
}
|
|
14182
14485
|
lines.push("");
|
|
14183
14486
|
}
|
|
14184
|
-
const patchesDir =
|
|
14487
|
+
const patchesDir = path5.dirname(changed[0].patchPath);
|
|
14185
14488
|
lines.push(`Full patches: ${patchesDir}`);
|
|
14186
14489
|
return lines.join(`
|
|
14187
14490
|
`).trimEnd();
|
|
@@ -14191,8 +14494,8 @@ var init_worktree_diff = __esm(() => {
|
|
|
14191
14494
|
});
|
|
14192
14495
|
|
|
14193
14496
|
// dist/builtin/workflows/src/runs/shared/worktree-post-create.ts
|
|
14194
|
-
import * as
|
|
14195
|
-
import * as
|
|
14497
|
+
import * as fs6 from "node:fs";
|
|
14498
|
+
import * as path6 from "node:path";
|
|
14196
14499
|
function tracked(repo, relativePath) {
|
|
14197
14500
|
const result = runGit(repo, ["ls-files", "--error-unmatch", "--", relativePath]);
|
|
14198
14501
|
return result.status === 0;
|
|
@@ -14212,12 +14515,12 @@ function hasTrackedPathComponent(repo, relativePath) {
|
|
|
14212
14515
|
return false;
|
|
14213
14516
|
}
|
|
14214
14517
|
function copyUntrackedFile(mainRoot, worktreeRoot, relativePath) {
|
|
14215
|
-
const source =
|
|
14216
|
-
const destination =
|
|
14217
|
-
if (!
|
|
14518
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14519
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14520
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14218
14521
|
return false;
|
|
14219
|
-
|
|
14220
|
-
|
|
14522
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14523
|
+
fs6.copyFileSync(source, destination);
|
|
14221
14524
|
return true;
|
|
14222
14525
|
}
|
|
14223
14526
|
function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
@@ -14230,14 +14533,14 @@ function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
|
14230
14533
|
return copied;
|
|
14231
14534
|
}
|
|
14232
14535
|
function populatedHooksDirectory(mainRoot) {
|
|
14233
|
-
const husky =
|
|
14536
|
+
const husky = path6.join(mainRoot, ".husky");
|
|
14234
14537
|
try {
|
|
14235
|
-
if (
|
|
14538
|
+
if (fs6.statSync(husky).isDirectory())
|
|
14236
14539
|
return husky;
|
|
14237
14540
|
} catch {}
|
|
14238
|
-
const hooks =
|
|
14541
|
+
const hooks = path6.join(mainRoot, ".git", "hooks");
|
|
14239
14542
|
try {
|
|
14240
|
-
const populated =
|
|
14543
|
+
const populated = fs6.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
|
|
14241
14544
|
return populated ? hooks : undefined;
|
|
14242
14545
|
} catch {
|
|
14243
14546
|
return;
|
|
@@ -14248,7 +14551,7 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
14248
14551
|
if (desired === undefined)
|
|
14249
14552
|
return;
|
|
14250
14553
|
const current = runGitPlain(mainRoot, ["config", "--get", "core.hooksPath"]);
|
|
14251
|
-
if (current.status === 0 &&
|
|
14554
|
+
if (current.status === 0 && path6.resolve(mainRoot, current.stdout.trim()) === desired)
|
|
14252
14555
|
return;
|
|
14253
14556
|
const configured = runGitPlain(mainRoot, ["config", "core.hooksPath", desired]);
|
|
14254
14557
|
if (configured.status !== 0) {
|
|
@@ -14257,10 +14560,10 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
14257
14560
|
}
|
|
14258
14561
|
function normalizeSymlinkDirectory(value2) {
|
|
14259
14562
|
const trimmed = value2.trim();
|
|
14260
|
-
if (!trimmed ||
|
|
14563
|
+
if (!trimmed || path6.isAbsolute(trimmed))
|
|
14261
14564
|
return;
|
|
14262
|
-
const normalized =
|
|
14263
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${
|
|
14565
|
+
const normalized = path6.normalize(trimmed);
|
|
14566
|
+
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path6.sep}`))
|
|
14264
14567
|
return;
|
|
14265
14568
|
return normalized;
|
|
14266
14569
|
}
|
|
@@ -14270,20 +14573,20 @@ function symlinkConfiguredDirectories(mainRoot, worktreeRoot, directories) {
|
|
|
14270
14573
|
const relativePath = normalizeSymlinkDirectory(rawDirectory);
|
|
14271
14574
|
if (relativePath === undefined || synthetic.includes(relativePath))
|
|
14272
14575
|
continue;
|
|
14273
|
-
const source =
|
|
14274
|
-
const destination =
|
|
14275
|
-
if (!
|
|
14576
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14577
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14578
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14276
14579
|
continue;
|
|
14277
|
-
|
|
14580
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14278
14581
|
try {
|
|
14279
|
-
|
|
14582
|
+
fs6.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
|
|
14280
14583
|
synthetic.push(relativePath);
|
|
14281
14584
|
} catch {}
|
|
14282
14585
|
}
|
|
14283
14586
|
return synthetic;
|
|
14284
14587
|
}
|
|
14285
14588
|
function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
14286
|
-
if (!
|
|
14589
|
+
if (!fs6.existsSync(path6.join(mainRoot, ".worktreeinclude")))
|
|
14287
14590
|
return;
|
|
14288
14591
|
const ignored = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-standard"]);
|
|
14289
14592
|
const included = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-from=.worktreeinclude"]);
|
|
@@ -14293,13 +14596,13 @@ function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
|
14293
14596
|
for (const relativePath of included.stdout.split(/\r?\n/).filter(Boolean)) {
|
|
14294
14597
|
if (!ignoredPaths.has(relativePath) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14295
14598
|
continue;
|
|
14296
|
-
const source =
|
|
14297
|
-
const destination =
|
|
14599
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14600
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14298
14601
|
try {
|
|
14299
|
-
if (!
|
|
14602
|
+
if (!fs6.statSync(source).isFile() || fs6.existsSync(destination))
|
|
14300
14603
|
continue;
|
|
14301
|
-
|
|
14302
|
-
|
|
14604
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14605
|
+
fs6.copyFileSync(source, destination);
|
|
14303
14606
|
} catch {}
|
|
14304
14607
|
}
|
|
14305
14608
|
}
|
|
@@ -14316,9 +14619,9 @@ var init_worktree_post_create = __esm(() => {
|
|
|
14316
14619
|
|
|
14317
14620
|
// dist/builtin/workflows/src/runs/shared/worktree-setup.ts
|
|
14318
14621
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
14319
|
-
import * as
|
|
14622
|
+
import * as fs7 from "node:fs";
|
|
14320
14623
|
import * as os from "node:os";
|
|
14321
|
-
import * as
|
|
14624
|
+
import * as path7 from "node:path";
|
|
14322
14625
|
import { createChildProcessEnvironment as createChildProcessEnvironment2 } from "@bastani/atomic";
|
|
14323
14626
|
function originDefaultBranch(mainRoot) {
|
|
14324
14627
|
const symbolic = runGit(mainRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
@@ -14338,7 +14641,7 @@ function originDefaultBranch(mainRoot) {
|
|
|
14338
14641
|
}
|
|
14339
14642
|
function resolveRepoState(cwd, explicitBaseBranch) {
|
|
14340
14643
|
const cwdRelative = resolveRepoCwdRelative(cwd);
|
|
14341
|
-
const toplevel =
|
|
14644
|
+
const toplevel = path7.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
|
|
14342
14645
|
const mainRoot = findCanonicalGitRoot(toplevel);
|
|
14343
14646
|
if (mainRoot === undefined)
|
|
14344
14647
|
throw new Error(`unable to resolve canonical main Git repository root from ${toplevel}`);
|
|
@@ -14351,9 +14654,9 @@ function resolveRepoState(cwd, explicitBaseBranch) {
|
|
|
14351
14654
|
return { toplevel, mainRoot, cwdRelative, baseCommit, baseRef };
|
|
14352
14655
|
}
|
|
14353
14656
|
function normalizeComparableCwd(cwd) {
|
|
14354
|
-
const resolved =
|
|
14657
|
+
const resolved = path7.resolve(cwd);
|
|
14355
14658
|
try {
|
|
14356
|
-
return
|
|
14659
|
+
return fs7.realpathSync(resolved);
|
|
14357
14660
|
} catch {
|
|
14358
14661
|
return resolved;
|
|
14359
14662
|
}
|
|
@@ -14364,7 +14667,7 @@ function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
|
|
|
14364
14667
|
const task = tasks[index];
|
|
14365
14668
|
if (!task.cwd)
|
|
14366
14669
|
continue;
|
|
14367
|
-
const taskCwd =
|
|
14670
|
+
const taskCwd = path7.isAbsolute(task.cwd) ? task.cwd : path7.resolve(sharedCwd, task.cwd);
|
|
14368
14671
|
if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
|
|
14369
14672
|
continue;
|
|
14370
14673
|
return { index, agent: task.agent, cwd: task.cwd };
|
|
@@ -14381,12 +14684,12 @@ function buildWorktreeBranch(runId, index) {
|
|
|
14381
14684
|
return `worktree-${flattenedWorktreeName(runId, index)}`;
|
|
14382
14685
|
}
|
|
14383
14686
|
function buildWorktreePath(mainRoot, runId, index) {
|
|
14384
|
-
return
|
|
14687
|
+
return path7.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
|
|
14385
14688
|
}
|
|
14386
14689
|
function ensureWorktreeIgnore(mainRoot) {
|
|
14387
|
-
const worktreesRoot =
|
|
14388
|
-
|
|
14389
|
-
|
|
14690
|
+
const worktreesRoot = path7.join(mainRoot, ".atomic", "worktrees");
|
|
14691
|
+
fs7.mkdirSync(worktreesRoot, { recursive: true });
|
|
14692
|
+
fs7.writeFileSync(path7.join(worktreesRoot, ".gitignore"), `*
|
|
14390
14693
|
`, "utf8");
|
|
14391
14694
|
}
|
|
14392
14695
|
function resolveRepoCwdRelative(cwd) {
|
|
@@ -14395,7 +14698,7 @@ function resolveRepoCwdRelative(cwd) {
|
|
|
14395
14698
|
throw new Error("worktree isolation requires a git repository");
|
|
14396
14699
|
}
|
|
14397
14700
|
const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
|
|
14398
|
-
const normalizedPrefix = rawPrefix ?
|
|
14701
|
+
const normalizedPrefix = rawPrefix ? path7.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
|
|
14399
14702
|
return normalizedPrefix === "." ? "" : normalizedPrefix;
|
|
14400
14703
|
}
|
|
14401
14704
|
function parseHookTimeout(timeoutMs) {
|
|
@@ -14413,19 +14716,19 @@ function resolveWorktreeSetupHook(repoRoot, config) {
|
|
|
14413
14716
|
if (!hookPath) {
|
|
14414
14717
|
throw new Error("worktree setup hook path cannot be empty");
|
|
14415
14718
|
}
|
|
14416
|
-
const expandedHookPath = hookPath.startsWith("~/") ?
|
|
14719
|
+
const expandedHookPath = hookPath.startsWith("~/") ? path7.join(os.homedir(), hookPath.slice(2)) : hookPath;
|
|
14417
14720
|
let resolvedPath;
|
|
14418
|
-
if (
|
|
14721
|
+
if (path7.isAbsolute(expandedHookPath)) {
|
|
14419
14722
|
resolvedPath = expandedHookPath;
|
|
14420
14723
|
} else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
|
|
14421
|
-
resolvedPath =
|
|
14724
|
+
resolvedPath = path7.resolve(repoRoot, expandedHookPath);
|
|
14422
14725
|
} else {
|
|
14423
14726
|
throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
|
|
14424
14727
|
}
|
|
14425
|
-
if (!
|
|
14728
|
+
if (!fs7.existsSync(resolvedPath)) {
|
|
14426
14729
|
throw new Error(`worktree setup hook not found: ${resolvedPath}`);
|
|
14427
14730
|
}
|
|
14428
|
-
if (
|
|
14731
|
+
if (fs7.statSync(resolvedPath).isDirectory()) {
|
|
14429
14732
|
throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
|
|
14430
14733
|
}
|
|
14431
14734
|
return {
|
|
@@ -14437,17 +14740,17 @@ function normalizeSyntheticPath(worktreePath, rawPath) {
|
|
|
14437
14740
|
const trimmed = rawPath.trim();
|
|
14438
14741
|
if (!trimmed)
|
|
14439
14742
|
throw new Error("synthetic path cannot be empty");
|
|
14440
|
-
if (
|
|
14743
|
+
if (path7.isAbsolute(trimmed))
|
|
14441
14744
|
throw new Error(`synthetic path must be relative: ${rawPath}`);
|
|
14442
|
-
const resolved =
|
|
14443
|
-
const relative =
|
|
14745
|
+
const resolved = path7.resolve(worktreePath, trimmed);
|
|
14746
|
+
const relative = path7.relative(worktreePath, resolved);
|
|
14444
14747
|
if (!relative || relative === ".") {
|
|
14445
14748
|
throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
|
|
14446
14749
|
}
|
|
14447
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
14750
|
+
if (relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative)) {
|
|
14448
14751
|
throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
|
|
14449
14752
|
}
|
|
14450
|
-
return
|
|
14753
|
+
return path7.normalize(relative);
|
|
14451
14754
|
}
|
|
14452
14755
|
function hasTrackedEntries(worktreePath, relativePath) {
|
|
14453
14756
|
const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
|
|
@@ -14519,16 +14822,16 @@ function waitForGitLockRelease() {
|
|
|
14519
14822
|
}
|
|
14520
14823
|
function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
14521
14824
|
for (const relativePath of new Set(relativePaths)) {
|
|
14522
|
-
const target =
|
|
14523
|
-
const relative =
|
|
14524
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
14825
|
+
const target = path7.resolve(worktreePath, relativePath);
|
|
14826
|
+
const relative = path7.relative(worktreePath, target);
|
|
14827
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative))
|
|
14525
14828
|
continue;
|
|
14526
14829
|
let current = worktreePath;
|
|
14527
|
-
for (const component of relative.split(
|
|
14528
|
-
current =
|
|
14830
|
+
for (const component of relative.split(path7.sep)) {
|
|
14831
|
+
current = path7.join(current, component);
|
|
14529
14832
|
let stat;
|
|
14530
14833
|
try {
|
|
14531
|
-
stat =
|
|
14834
|
+
stat = fs7.lstatSync(current);
|
|
14532
14835
|
} catch (error) {
|
|
14533
14836
|
const code = error.code;
|
|
14534
14837
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -14538,7 +14841,7 @@ function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
|
14538
14841
|
if (!stat.isSymbolicLink())
|
|
14539
14842
|
continue;
|
|
14540
14843
|
if (current === target)
|
|
14541
|
-
|
|
14844
|
+
fs7.unlinkSync(current);
|
|
14542
14845
|
break;
|
|
14543
14846
|
}
|
|
14544
14847
|
}
|
|
@@ -14566,7 +14869,7 @@ function createSingleWorktree(mainRoot, cwdRelative, runId, index, baseRef, base
|
|
|
14566
14869
|
cleanupSingleWorktree(mainRoot, { path: worktreePath, branch }, []);
|
|
14567
14870
|
throw new Error(message);
|
|
14568
14871
|
}
|
|
14569
|
-
const agentCwd = cwdRelative ?
|
|
14872
|
+
const agentCwd = cwdRelative ? path7.join(worktreePath, cwdRelative) : worktreePath;
|
|
14570
14873
|
const syntheticPaths = [];
|
|
14571
14874
|
try {
|
|
14572
14875
|
syntheticPaths.push(...performPostCreationSetup(mainRoot, worktreePath, symlinkDirectories));
|
|
@@ -14635,8 +14938,8 @@ var init_worktree = __esm(() => {
|
|
|
14635
14938
|
});
|
|
14636
14939
|
|
|
14637
14940
|
// dist/builtin/workflows/src/runs/shared/worktree-cwd.ts
|
|
14638
|
-
import { lstatSync as
|
|
14639
|
-
import { dirname as
|
|
14941
|
+
import { lstatSync as lstatSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
14942
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve7, sep as sep5 } from "node:path";
|
|
14640
14943
|
function relativePathWithin(root, candidate) {
|
|
14641
14944
|
const path = relative4(root, candidate);
|
|
14642
14945
|
return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path) ? undefined : path;
|
|
@@ -14655,14 +14958,14 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
14655
14958
|
if (cwd === undefined || cwd.length === 0)
|
|
14656
14959
|
return;
|
|
14657
14960
|
const absoluteInput = isAbsolute6(cwd);
|
|
14658
|
-
const candidate = absoluteInput ? cwd :
|
|
14961
|
+
const candidate = absoluteInput ? cwd : resolve7(setup.cwd, cwd);
|
|
14659
14962
|
if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
|
|
14660
14963
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
|
|
14661
14964
|
}
|
|
14662
14965
|
const candidateRealPath = existingRealPath(candidate, "cwd");
|
|
14663
14966
|
const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
|
|
14664
14967
|
if (worktreeRelative !== undefined)
|
|
14665
|
-
return
|
|
14968
|
+
return resolve7(setup.worktreeRoot, worktreeRelative);
|
|
14666
14969
|
if (!isAbsolute6(cwd)) {
|
|
14667
14970
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
|
|
14668
14971
|
}
|
|
@@ -14671,9 +14974,9 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
14671
14974
|
}
|
|
14672
14975
|
const repositoryRelative = absoluteInput ? relativePathWithin(repositoryRoot, candidateRealPath) : undefined;
|
|
14673
14976
|
if (repositoryRelative === undefined) {
|
|
14674
|
-
throw new Error(`atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
|
|
14977
|
+
throw new Error(repositoryRoot === worktreeRoot ? `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}, which belongs to a different repository than the invoking cwd; choose a cwd inside the worktree, or omit cwd.` : `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
|
|
14675
14978
|
}
|
|
14676
|
-
const mappedCwd =
|
|
14979
|
+
const mappedCwd = resolve7(setup.worktreeRoot, repositoryRelative);
|
|
14677
14980
|
const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
|
|
14678
14981
|
if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
|
|
14679
14982
|
throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
|
|
@@ -14684,7 +14987,7 @@ var init_worktree_cwd = () => {};
|
|
|
14684
14987
|
|
|
14685
14988
|
// dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts
|
|
14686
14989
|
import { existsSync as existsSync3 } from "node:fs";
|
|
14687
|
-
import { isAbsolute as isAbsolute7, resolve as
|
|
14990
|
+
import { isAbsolute as isAbsolute7, resolve as resolve8 } from "node:path";
|
|
14688
14991
|
function normalizeTaskContexts(previous) {
|
|
14689
14992
|
if (previous === undefined)
|
|
14690
14993
|
return [];
|
|
@@ -14737,7 +15040,7 @@ function taskPrevious(options) {
|
|
|
14737
15040
|
function resolveWorkflowPath(filePath, baseDir) {
|
|
14738
15041
|
if (isAbsolute7(filePath))
|
|
14739
15042
|
return filePath;
|
|
14740
|
-
return
|
|
15043
|
+
return resolve8(baseDir ?? process.cwd(), filePath);
|
|
14741
15044
|
}
|
|
14742
15045
|
function taskBaseDir(options) {
|
|
14743
15046
|
if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
|
|
@@ -14892,7 +15195,7 @@ function taskWithSharedDefaults(taskOptions, options) {
|
|
|
14892
15195
|
var init_executor_task_prompts = () => {};
|
|
14893
15196
|
|
|
14894
15197
|
// dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
|
|
14895
|
-
import { isAbsolute as isAbsolute8, join as
|
|
15198
|
+
import { isAbsolute as isAbsolute8, join as join12, resolve as resolve9 } from "node:path";
|
|
14896
15199
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
14897
15200
|
function positiveConcurrency(value2) {
|
|
14898
15201
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < 1)
|
|
@@ -15045,10 +15348,10 @@ function workflowInvocationMetadata(inputDefaults, workflowInvocationCwd, cache,
|
|
|
15045
15348
|
function resolvedTaskCwd(cwd, workflowInvocationCwd) {
|
|
15046
15349
|
if (cwd === undefined)
|
|
15047
15350
|
return;
|
|
15048
|
-
return isAbsolute8(cwd) ? cwd :
|
|
15351
|
+
return isAbsolute8(cwd) ? cwd : resolve9(workflowInvocationCwd, cwd);
|
|
15049
15352
|
}
|
|
15050
15353
|
function taskWorktreeOutputsRoot(runId) {
|
|
15051
|
-
return
|
|
15354
|
+
return join12(workflowArtifactRunPath(runId), "task-outputs");
|
|
15052
15355
|
}
|
|
15053
15356
|
function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCwd = process.cwd(), symlinkDirectories) {
|
|
15054
15357
|
if (options.worktree !== true && !tasks.some((task) => task.worktree === true)) {
|
|
@@ -15058,7 +15361,7 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
15058
15361
|
throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
|
|
15059
15362
|
}
|
|
15060
15363
|
const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
|
|
15061
|
-
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd :
|
|
15364
|
+
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve9(workflowInvocationCwd, explicitCwd);
|
|
15062
15365
|
const conflict = findWorktreeTaskCwdConflict(tasks.map((task) => ({ agent: task.name, cwd: resolvedTaskCwd(task.cwd, workflowInvocationCwd) })), sharedCwd);
|
|
15063
15366
|
if (conflict !== undefined)
|
|
15064
15367
|
throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
|
|
@@ -15073,9 +15376,9 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
15073
15376
|
tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index].agentCwd })),
|
|
15074
15377
|
setup,
|
|
15075
15378
|
agents,
|
|
15076
|
-
diffsDir:
|
|
15379
|
+
diffsDir: join12(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
|
|
15077
15380
|
outputIsolations: tasks.map((_, index) => ({
|
|
15078
|
-
baseDir:
|
|
15381
|
+
baseDir: join12(trustedRoot, runId, scope, String(index)),
|
|
15079
15382
|
trustedRoot
|
|
15080
15383
|
}))
|
|
15081
15384
|
};
|
|
@@ -16802,8 +17105,12 @@ function createStageControlRegistry() {
|
|
|
16802
17105
|
}
|
|
16803
17106
|
await disposeEntries(entries);
|
|
16804
17107
|
},
|
|
16805
|
-
async releaseIdle(runId) {
|
|
16806
|
-
|
|
17108
|
+
async releaseIdle(runId, only) {
|
|
17109
|
+
const runMap = _byRun.get(runId);
|
|
17110
|
+
const entries = only === undefined ? [...runMap ?? []] : [[only, runMap?.get(only)]];
|
|
17111
|
+
for (const [stageId, entry] of entries) {
|
|
17112
|
+
if (entry === undefined)
|
|
17113
|
+
continue;
|
|
16807
17114
|
try {
|
|
16808
17115
|
await releaseIdleEntry(runId, stageId, entry);
|
|
16809
17116
|
} catch (error) {
|
|
@@ -16864,7 +17171,7 @@ var init_possible_stages = __esm(() => {
|
|
|
16864
17171
|
|
|
16865
17172
|
// dist/builtin/workflows/src/workers/admission-host.ts
|
|
16866
17173
|
import { execFile, execFileSync } from "node:child_process";
|
|
16867
|
-
import { readdirSync as
|
|
17174
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
16868
17175
|
import { readFile } from "node:fs/promises";
|
|
16869
17176
|
import { hostname } from "node:os";
|
|
16870
17177
|
function admissionBootIdentity() {
|
|
@@ -16895,7 +17202,7 @@ function workerProcessExited(pid, final = false) {
|
|
|
16895
17202
|
return true;
|
|
16896
17203
|
if (process.platform === "linux") {
|
|
16897
17204
|
try {
|
|
16898
|
-
const stat =
|
|
17205
|
+
const stat = readFileSync4(`/proc/${pid}/stat`, "utf8");
|
|
16899
17206
|
return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
|
|
16900
17207
|
} catch {
|
|
16901
17208
|
return admissionProcessStopped(pid);
|
|
@@ -16915,7 +17222,7 @@ function scanProcessGroup(group) {
|
|
|
16915
17222
|
let complete = true;
|
|
16916
17223
|
let entries;
|
|
16917
17224
|
try {
|
|
16918
|
-
entries =
|
|
17225
|
+
entries = readdirSync4("/proc");
|
|
16919
17226
|
} catch {
|
|
16920
17227
|
return { members, complete: false };
|
|
16921
17228
|
}
|
|
@@ -16924,7 +17231,7 @@ function scanProcessGroup(group) {
|
|
|
16924
17231
|
continue;
|
|
16925
17232
|
let stat;
|
|
16926
17233
|
try {
|
|
16927
|
-
stat =
|
|
17234
|
+
stat = readFileSync4(`/proc/${entry}/stat`, "utf8");
|
|
16928
17235
|
} catch {
|
|
16929
17236
|
complete = false;
|
|
16930
17237
|
continue;
|
|
@@ -17155,6 +17462,7 @@ class SqlResourceAdmission {
|
|
|
17155
17462
|
epoch: this.options.attempt.epoch
|
|
17156
17463
|
}) : null);
|
|
17157
17464
|
});
|
|
17465
|
+
let quarantinedSince;
|
|
17158
17466
|
try {
|
|
17159
17467
|
for (;; ) {
|
|
17160
17468
|
signal?.throwIfAborted();
|
|
@@ -17164,7 +17472,9 @@ class SqlResourceAdmission {
|
|
|
17164
17472
|
}
|
|
17165
17473
|
const hostReason = this.hostReason();
|
|
17166
17474
|
const pressure = this.stageStartPressure(kind, request?.delegated);
|
|
17475
|
+
let quarantined = undefined;
|
|
17167
17476
|
const granted = await this.storage.transaction(async (tx) => {
|
|
17477
|
+
quarantined = undefined;
|
|
17168
17478
|
await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
|
|
17169
17479
|
const { root } = this.options;
|
|
17170
17480
|
if (!await this.assertCurrentAttempt(tx)) {
|
|
@@ -17182,6 +17492,8 @@ class SqlResourceAdmission {
|
|
|
17182
17492
|
if (control && control.state !== "running")
|
|
17183
17493
|
reason ??= `root ${control.state}`;
|
|
17184
17494
|
}
|
|
17495
|
+
const held = [];
|
|
17496
|
+
let blockedOtherwise = reason !== undefined;
|
|
17185
17497
|
for (const scope of [`root:${root}`, "user"]) {
|
|
17186
17498
|
const row = await tx.get(`SELECT config FROM ${this.configuration} WHERE scope = ?`, scope);
|
|
17187
17499
|
const limit = row ? JSON.parse(String(row.config))[kind] : undefined;
|
|
@@ -17191,9 +17503,21 @@ class SqlResourceAdmission {
|
|
|
17191
17503
|
const args = scope === "user" ? [kind] : [kind, root];
|
|
17192
17504
|
const count = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted'`, ...args);
|
|
17193
17505
|
const older = await tx.get(`SELECT 1 AS waiting FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'waiting' AND reason IS NOT ? AND ticket < (SELECT ticket FROM ${this.permits} WHERE operation = ?) LIMIT 1`, ...args, STAGE_START_PRESSURE_REASON, operation);
|
|
17194
|
-
|
|
17195
|
-
|
|
17506
|
+
const used = Number(count?.count);
|
|
17507
|
+
if (used < limit && !older)
|
|
17508
|
+
continue;
|
|
17509
|
+
reason ??= `${scope} ${kind}`;
|
|
17510
|
+
const quarantinedPermits = kind === "process" && used >= limit ? await tx.all(`SELECT process_identity FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted' AND reason = ?`, ...args, QUARANTINED_REASON) : [];
|
|
17511
|
+
if (quarantinedPermits.length > 0 && used - quarantinedPermits.length < limit)
|
|
17512
|
+
held.push({
|
|
17513
|
+
limit: `${scope === "user" ? "admission.userLimits" : "admission.limits"}.${kind} (${limit})`,
|
|
17514
|
+
groups: quarantinedPermits.flatMap(({ process_identity }) => process_identity === null ? [] : [JSON.parse(process_identity).id])
|
|
17515
|
+
});
|
|
17516
|
+
else
|
|
17517
|
+
blockedOtherwise = true;
|
|
17196
17518
|
}
|
|
17519
|
+
if (!blockedOtherwise && held.length > 0)
|
|
17520
|
+
quarantined = held;
|
|
17197
17521
|
if (reason && request?.delegated)
|
|
17198
17522
|
throw new Error(`Delegated session cannot be admitted without capacity headroom: ${reason}`);
|
|
17199
17523
|
const stageStart = kind === "session" && request?.delegated !== true;
|
|
@@ -17206,6 +17530,14 @@ class SqlResourceAdmission {
|
|
|
17206
17530
|
signal?.throwIfAborted();
|
|
17207
17531
|
return release;
|
|
17208
17532
|
}
|
|
17533
|
+
if (quarantined === undefined)
|
|
17534
|
+
quarantinedSince = undefined;
|
|
17535
|
+
else {
|
|
17536
|
+
const now = performance.now();
|
|
17537
|
+
quarantinedSince ??= now;
|
|
17538
|
+
if (now - quarantinedSince >= QUARANTINED_CAPACITY_WAIT_MS)
|
|
17539
|
+
throw new QuarantinedCapacityError(quarantined, now - quarantinedSince);
|
|
17540
|
+
}
|
|
17209
17541
|
await delay(50 + Math.floor(Math.random() * 25), undefined, { signal });
|
|
17210
17542
|
}
|
|
17211
17543
|
} catch (error) {
|
|
@@ -17247,9 +17579,9 @@ class SqlResourceAdmission {
|
|
|
17247
17579
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'host reboot confirmed' WHERE owner = ? AND state = 'granted'`, owner.id);
|
|
17248
17580
|
} else if (stopped) {
|
|
17249
17581
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'owner death confirmed' WHERE owner = ? AND kind = 'session' AND state = 'granted'`, owner.id);
|
|
17250
|
-
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ?`, UNCONFIRMED_REASON, owner.id, UNCONFIRMED_REASON);
|
|
17582
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ? AND reason IS NOT ?`, UNCONFIRMED_REASON, owner.id, UNCONFIRMED_REASON, QUARANTINED_REASON);
|
|
17251
17583
|
} else {
|
|
17252
|
-
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND state = 'granted' AND reason IS NOT ? AND EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS})`, EXPIRED_REASON, owner.id, EXPIRED_REASON, owner.id);
|
|
17584
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND state = 'granted' AND reason IS NOT ? AND reason IS NOT ? AND EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS})`, EXPIRED_REASON, owner.id, EXPIRED_REASON, QUARANTINED_REASON, owner.id);
|
|
17253
17585
|
}
|
|
17254
17586
|
if (owner.host === admissionHost && process.platform !== "win32") {
|
|
17255
17587
|
const processes = await tx.all(`SELECT * FROM ${this.permits} WHERE owner = ? AND state = 'granted' AND kind = 'process' AND process_identity IS NOT NULL`, owner.id);
|
|
@@ -17277,9 +17609,10 @@ class SqlResourceAdmission {
|
|
|
17277
17609
|
return true;
|
|
17278
17610
|
if (permit.state === "waiting")
|
|
17279
17611
|
return stopped || !!permit.expired;
|
|
17280
|
-
|
|
17612
|
+
const quarantined = permit.reason === QUARANTINED_REASON;
|
|
17613
|
+
if (stopped && (permit.kind === "session" || permit.reason !== UNCONFIRMED_REASON && !quarantined))
|
|
17281
17614
|
return true;
|
|
17282
|
-
if (!stopped && permit.expired && permit.reason !== EXPIRED_REASON)
|
|
17615
|
+
if (!stopped && permit.expired && permit.reason !== EXPIRED_REASON && !quarantined)
|
|
17283
17616
|
return true;
|
|
17284
17617
|
return permit.kind === "process" && permit.host === admissionHost && process.platform !== "win32" && permit.process_identity !== null && processGroupStopped(permit.process_identity);
|
|
17285
17618
|
}
|
|
@@ -17290,7 +17623,9 @@ class SqlResourceAdmission {
|
|
|
17290
17623
|
await this.reconcile();
|
|
17291
17624
|
return this.storage.transaction(async (tx) => {
|
|
17292
17625
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'worker exit confirmed' WHERE root = ? AND holder = ? AND state IN ('waiting', 'granted') AND (kind = 'session' OR state = 'waiting')`, this.options.root, holder);
|
|
17293
|
-
|
|
17626
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ?`, UNCONFIRMED_REASON, this.options.root, holder, QUARANTINED_REASON);
|
|
17627
|
+
const held = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted'`, this.options.root, holder);
|
|
17628
|
+
return Number(held?.count);
|
|
17294
17629
|
});
|
|
17295
17630
|
}
|
|
17296
17631
|
async reapStoppedProcesses(holder) {
|
|
@@ -17337,10 +17672,13 @@ async function settleProcessGroups(storage, root, scope, reap) {
|
|
|
17337
17672
|
survivors = await settle(REAP_KILL_GRACE_MS);
|
|
17338
17673
|
}
|
|
17339
17674
|
const confirmed = [...groups].flatMap(([group, operations]) => survivors.includes(group) ? [] : operations);
|
|
17340
|
-
|
|
17675
|
+
const quarantined = reap ? survivors.flatMap((group) => groups.get(group) ?? []) : [];
|
|
17676
|
+
if (confirmed.length > 0 || quarantined.length > 0)
|
|
17341
17677
|
await storage.transaction(async (tx) => {
|
|
17342
17678
|
for (const operation of confirmed)
|
|
17343
17679
|
await tx.run(`UPDATE ${permits} SET state = 'released', reason = 'process group cleanup confirmed' WHERE operation = ? AND state = 'granted'`, operation);
|
|
17680
|
+
for (const operation of quarantined)
|
|
17681
|
+
await tx.run(`UPDATE ${permits} SET reason = ? WHERE operation = ? AND state = 'granted'`, QUARANTINED_REASON, operation);
|
|
17344
17682
|
});
|
|
17345
17683
|
return { survivors, unprobeable };
|
|
17346
17684
|
}
|
|
@@ -17357,11 +17695,20 @@ async function reapProcessGroups(journal, root, scope) {
|
|
|
17357
17695
|
return { survivors: [], unprobeable: [] };
|
|
17358
17696
|
return settleProcessGroups(storage, root, scope, true);
|
|
17359
17697
|
}
|
|
17360
|
-
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
|
|
17698
|
+
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", QUARANTINED_REASON = "cleanup unconfirmed; permit quarantined", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", QUARANTINED_CAPACITY_WAIT_MS, QuarantinedCapacityError, NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
|
|
17361
17699
|
var init_resource_admission = __esm(() => {
|
|
17362
17700
|
init_internal();
|
|
17363
17701
|
init_sql_run_journal();
|
|
17702
|
+
init_workflow_infrastructure_error();
|
|
17364
17703
|
init_admission_host();
|
|
17704
|
+
QUARANTINED_CAPACITY_WAIT_MS = REAP_TERM_GRACE_MS + REAP_KILL_GRACE_MS;
|
|
17705
|
+
QuarantinedCapacityError = class QuarantinedCapacityError extends WorkflowInfrastructureError {
|
|
17706
|
+
constructor(capacity, waitedMs) {
|
|
17707
|
+
const limits = capacity.map(({ limit }) => limit).join(" and ");
|
|
17708
|
+
const groups = [...new Set(capacity.flatMap(({ groups }) => groups))].join(", ");
|
|
17709
|
+
super("worker_cleanup_unconfirmed", `Local worker process cleanup unconfirmed; process permit refused after ${Math.round(waitedMs)} ms: ${limits} ${capacity.length === 1 ? "is" : "are"} held by quarantined permits of process groups ${groups} that survived SIGKILL`);
|
|
17710
|
+
}
|
|
17711
|
+
};
|
|
17365
17712
|
});
|
|
17366
17713
|
|
|
17367
17714
|
// dist/builtin/workflows/src/workers/admission-binding.ts
|
|
@@ -53663,10 +54010,10 @@ var init_verification_prompts = __esm(() => {
|
|
|
53663
54010
|
// dist/builtin/workflows/builtin/pattern-artifact-root.ts
|
|
53664
54011
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
53665
54012
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
53666
|
-
import { join as
|
|
54013
|
+
import { join as join13 } from "node:path";
|
|
53667
54014
|
async function stableArtifactRoot(ctx, workflowName) {
|
|
53668
54015
|
const cwd = ctx.cwd ?? process.cwd();
|
|
53669
|
-
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () =>
|
|
54016
|
+
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join13(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID8()}`));
|
|
53670
54017
|
await mkdir2(artifactDir, { recursive: true });
|
|
53671
54018
|
return artifactDir;
|
|
53672
54019
|
}
|
|
@@ -53706,7 +54053,7 @@ function fold_usage(results) {
|
|
|
53706
54053
|
|
|
53707
54054
|
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
53708
54055
|
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
53709
|
-
import { join as
|
|
54056
|
+
import { join as join14 } from "node:path";
|
|
53710
54057
|
import { Type as Type4 } from "typebox";
|
|
53711
54058
|
function isRecord3(value2) {
|
|
53712
54059
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -53801,8 +54148,8 @@ async function writeInvalid(path, stage) {
|
|
|
53801
54148
|
}
|
|
53802
54149
|
async function runAdversarialVerification(ctx) {
|
|
53803
54150
|
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
53804
|
-
const criteriaPath =
|
|
53805
|
-
const candidatePath =
|
|
54151
|
+
const criteriaPath = join14(root, "criteria.md");
|
|
54152
|
+
const candidatePath = join14(root, "candidate.md");
|
|
53806
54153
|
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
53807
54154
|
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
53808
54155
|
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
@@ -53834,7 +54181,7 @@ async function runAdversarialVerification(ctx) {
|
|
|
53834
54181
|
criterion,
|
|
53835
54182
|
verifierIndex: index + 1,
|
|
53836
54183
|
name,
|
|
53837
|
-
artifactPath:
|
|
54184
|
+
artifactPath: join14(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
53838
54185
|
});
|
|
53839
54186
|
}
|
|
53840
54187
|
}
|
|
@@ -53887,8 +54234,8 @@ async function runAdversarialVerification(ctx) {
|
|
|
53887
54234
|
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
53888
54235
|
finalDecision = decision;
|
|
53889
54236
|
finalMean = meanScore(scoreReports);
|
|
53890
|
-
scoreTablePath =
|
|
53891
|
-
reviewReportPath =
|
|
54237
|
+
scoreTablePath = join14(root, `verification-summary-${round}.json`);
|
|
54238
|
+
reviewReportPath = join14(root, `review-${round}.json`);
|
|
53892
54239
|
const summary = {
|
|
53893
54240
|
scores: scoreReports,
|
|
53894
54241
|
mean: finalMean,
|
|
@@ -54069,7 +54416,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
|
|
|
54069
54416
|
|
|
54070
54417
|
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
54071
54418
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
54072
|
-
import { join as
|
|
54419
|
+
import { join as join15 } from "node:path";
|
|
54073
54420
|
import { Type as Type6 } from "typebox";
|
|
54074
54421
|
function safeName(value2) {
|
|
54075
54422
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54109,7 +54456,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54109
54456
|
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
54110
54457
|
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
54111
54458
|
const category = fallback?.category ?? exactCategory;
|
|
54112
|
-
const classificationPath =
|
|
54459
|
+
const classificationPath = join15(artifactDir, "classification.json");
|
|
54113
54460
|
await writeFile2(classificationPath, JSON.stringify({
|
|
54114
54461
|
proposed_category: proposedCategory,
|
|
54115
54462
|
selected_category: category,
|
|
@@ -54119,7 +54466,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54119
54466
|
fallback_used: needsFallback,
|
|
54120
54467
|
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
54121
54468
|
}, null, 2));
|
|
54122
|
-
const actionPath =
|
|
54469
|
+
const actionPath = join15(artifactDir, `action-${safeName(category)}.md`);
|
|
54123
54470
|
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
54124
54471
|
tools: actionTools(category),
|
|
54125
54472
|
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
@@ -54259,7 +54606,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
|
|
|
54259
54606
|
|
|
54260
54607
|
// dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
|
|
54261
54608
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
54262
|
-
import { join as
|
|
54609
|
+
import { join as join16 } from "node:path";
|
|
54263
54610
|
import { Type as Type8 } from "typebox";
|
|
54264
54611
|
function safeName2(value2, index) {
|
|
54265
54612
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54290,9 +54637,9 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54290
54637
|
context: "fresh"
|
|
54291
54638
|
});
|
|
54292
54639
|
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
54293
|
-
const partitionPath =
|
|
54640
|
+
const partitionPath = join16(artifactDir, "partition-plan.json");
|
|
54294
54641
|
await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
54295
|
-
const branchPaths = partitions.map((partition, index) =>
|
|
54642
|
+
const branchPaths = partitions.map((partition, index) => join16(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
|
|
54296
54643
|
const steps = partitions.map((partition, index) => ({
|
|
54297
54644
|
name: `branch-${safeName2(partition.label, index)}`,
|
|
54298
54645
|
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
@@ -54302,13 +54649,13 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54302
54649
|
outputMode: "file-only"
|
|
54303
54650
|
}));
|
|
54304
54651
|
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
54305
|
-
const manifestPath =
|
|
54652
|
+
const manifestPath = join16(artifactDir, "manifest.json");
|
|
54306
54653
|
await writeFile3(manifestPath, JSON.stringify({
|
|
54307
54654
|
task: ctx.inputs.prompt,
|
|
54308
54655
|
partition_plan: partitionPath,
|
|
54309
54656
|
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
|
|
54310
54657
|
}, null, 2));
|
|
54311
|
-
const synthesisPath =
|
|
54658
|
+
const synthesisPath = join16(artifactDir, "synthesis.md");
|
|
54312
54659
|
const synthesis = await ctx.task("synthesize", {
|
|
54313
54660
|
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
54314
54661
|
context: "fresh",
|
|
@@ -54473,7 +54820,7 @@ var init_generate_and_filter_prompts = __esm(() => {
|
|
|
54473
54820
|
|
|
54474
54821
|
// dist/builtin/workflows/builtin/generate-and-filter-runner.ts
|
|
54475
54822
|
import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
54476
|
-
import { join as
|
|
54823
|
+
import { join as join17 } from "node:path";
|
|
54477
54824
|
import { Type as Type10 } from "typebox";
|
|
54478
54825
|
function isRecord4(value2) {
|
|
54479
54826
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -54492,7 +54839,7 @@ function judgeDecision(value2) {
|
|
|
54492
54839
|
}
|
|
54493
54840
|
async function runGenerateAndFilter(ctx) {
|
|
54494
54841
|
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
54495
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) =>
|
|
54842
|
+
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join17(root, `candidate-${index + 1}.md`));
|
|
54496
54843
|
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
54497
54844
|
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
54498
54845
|
name: `generate-${index + 1}`,
|
|
@@ -54501,9 +54848,9 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54501
54848
|
output: path,
|
|
54502
54849
|
outputMode: "file-only"
|
|
54503
54850
|
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
54504
|
-
const manifestPath =
|
|
54851
|
+
const manifestPath = join17(root, "manifest.json");
|
|
54505
54852
|
await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
54506
|
-
const filterPath =
|
|
54853
|
+
const filterPath = join17(root, "filter.json");
|
|
54507
54854
|
const filtered = await ctx.task("dedupe-and-filter", {
|
|
54508
54855
|
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
|
|
54509
54856
|
context: "fresh",
|
|
@@ -54520,7 +54867,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54520
54867
|
let judgePath = null;
|
|
54521
54868
|
let decisionPath = filterPath;
|
|
54522
54869
|
if (ctx.inputs.use_judge) {
|
|
54523
|
-
judgePath =
|
|
54870
|
+
judgePath = join17(root, "judge.json");
|
|
54524
54871
|
const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
|
|
54525
54872
|
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
54526
54873
|
const judged = await ctx.task("judge", {
|
|
@@ -54536,7 +54883,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54536
54883
|
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
54537
54884
|
decisionPath = judgePath;
|
|
54538
54885
|
}
|
|
54539
|
-
const finalPath =
|
|
54886
|
+
const finalPath = join17(root, "shortlist.md");
|
|
54540
54887
|
const finalShortlist = await ctx.task("final-shortlist", {
|
|
54541
54888
|
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
|
|
54542
54889
|
context: "fresh",
|
|
@@ -55065,7 +55412,7 @@ var init_review_convergence = __esm(() => {
|
|
|
55065
55412
|
|
|
55066
55413
|
// dist/builtin/workflows/builtin/goal-artifacts.ts
|
|
55067
55414
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
55068
|
-
import { join as
|
|
55415
|
+
import { join as join18 } from "node:path";
|
|
55069
55416
|
function artifactSafeName(value2) {
|
|
55070
55417
|
const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
55071
55418
|
return safe.length > 0 ? safe : "artifact";
|
|
@@ -55076,7 +55423,7 @@ function withoutTurn(value2) {
|
|
|
55076
55423
|
return copy;
|
|
55077
55424
|
}
|
|
55078
55425
|
async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
|
|
55079
|
-
const artifactPath =
|
|
55426
|
+
const artifactPath = join18(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
55080
55427
|
await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
|
|
55081
55428
|
`, { encoding: "utf8" });
|
|
55082
55429
|
return artifactPath;
|
|
@@ -55085,7 +55432,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
|
|
|
55085
55432
|
reviewer: review.reviewer,
|
|
55086
55433
|
findings: review.findings
|
|
55087
55434
|
}))), reverification = []) {
|
|
55088
|
-
const artifactPath =
|
|
55435
|
+
const artifactPath = join18(artifactDir, "review-round-latest.json");
|
|
55089
55436
|
const visibleReviews = reviews.map(withoutTurn);
|
|
55090
55437
|
await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
|
|
55091
55438
|
`, { encoding: "utf8" });
|
|
@@ -55315,7 +55662,7 @@ var init_goal_review = __esm(() => {
|
|
|
55315
55662
|
// dist/builtin/workflows/builtin/goal-ledger.ts
|
|
55316
55663
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
55317
55664
|
import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
55318
|
-
import { dirname as
|
|
55665
|
+
import { dirname as dirname10, join as join19 } from "node:path";
|
|
55319
55666
|
import { isDeepStrictEqual } from "node:util";
|
|
55320
55667
|
function withoutTurn2(value2) {
|
|
55321
55668
|
const copy = { ...value2 };
|
|
@@ -55340,7 +55687,7 @@ function modelVisibleLedger(ledger) {
|
|
|
55340
55687
|
};
|
|
55341
55688
|
}
|
|
55342
55689
|
function goalLedgerStatePath(ledgerPath) {
|
|
55343
|
-
return
|
|
55690
|
+
return join19(dirname10(ledgerPath), LEDGER_STATE_FILENAME);
|
|
55344
55691
|
}
|
|
55345
55692
|
function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
|
|
55346
55693
|
ledger.lifecycle.push({
|
|
@@ -55416,7 +55763,7 @@ function recoverLegacyExecutionInterruption(ledger) {
|
|
|
55416
55763
|
return true;
|
|
55417
55764
|
}
|
|
55418
55765
|
async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
|
|
55419
|
-
const ledgerPath =
|
|
55766
|
+
const ledgerPath = join19(artifactDir, LEDGER_FILENAME);
|
|
55420
55767
|
const existing = await readExistingGoalLedger(ledgerPath);
|
|
55421
55768
|
if (existing !== undefined) {
|
|
55422
55769
|
if (recoverLegacyExecutionInterruption(existing))
|
|
@@ -55923,7 +56270,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
|
|
|
55923
56270
|
});
|
|
55924
56271
|
|
|
55925
56272
|
// dist/builtin/workflows/builtin/goal-runner.ts
|
|
55926
|
-
import { join as
|
|
56273
|
+
import { join as join20 } from "node:path";
|
|
55927
56274
|
function positiveInteger(value2, fallback) {
|
|
55928
56275
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
|
|
55929
56276
|
return fallback;
|
|
@@ -55974,7 +56321,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
55974
56321
|
appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
|
|
55975
56322
|
await writeGoalLedger(ledgerPath, ledger);
|
|
55976
56323
|
}
|
|
55977
|
-
const orchestratorReceiptPath =
|
|
56324
|
+
const orchestratorReceiptPath = join20(artifactDir, "orchestrator-receipt.md");
|
|
55978
56325
|
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
|
|
55979
56326
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
|
|
55980
56327
|
ledger,
|
|
@@ -56045,7 +56392,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
56045
56392
|
const reviewerName = result.name ?? result.stageName;
|
|
56046
56393
|
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
56047
56394
|
const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
|
|
56048
|
-
const reviewArtifactPath =
|
|
56395
|
+
const reviewArtifactPath = join20(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
|
|
56049
56396
|
const record = reviewDecisionToRecord({
|
|
56050
56397
|
turn,
|
|
56051
56398
|
reviewer: normalizedReviewerName,
|
|
@@ -56248,7 +56595,7 @@ var init_goal = __esm(() => {
|
|
|
56248
56595
|
}),
|
|
56249
56596
|
git_worktree_dir: Type15.String({
|
|
56250
56597
|
default: "",
|
|
56251
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
56598
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
56252
56599
|
}),
|
|
56253
56600
|
create_pr: Type15.Boolean({
|
|
56254
56601
|
default: false,
|
|
@@ -56366,7 +56713,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
|
|
|
56366
56713
|
|
|
56367
56714
|
// dist/builtin/workflows/builtin/loop-until-done-runner.ts
|
|
56368
56715
|
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
56369
|
-
import { join as
|
|
56716
|
+
import { join as join21 } from "node:path";
|
|
56370
56717
|
import { Type as Type16 } from "typebox";
|
|
56371
56718
|
function progressCurve(entries) {
|
|
56372
56719
|
return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
|
|
@@ -56449,18 +56796,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
|
|
|
56449
56796
|
}
|
|
56450
56797
|
async function runLoopUntilDone(ctx) {
|
|
56451
56798
|
const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
|
|
56452
|
-
const iterationsDir =
|
|
56453
|
-
const evaluationsDir =
|
|
56799
|
+
const iterationsDir = join21(artifactDir, "iterations");
|
|
56800
|
+
const evaluationsDir = join21(artifactDir, "evaluations");
|
|
56454
56801
|
await mkdir3(iterationsDir, { recursive: true });
|
|
56455
56802
|
await mkdir3(evaluationsDir, { recursive: true });
|
|
56456
|
-
const ledgerPath =
|
|
56803
|
+
const ledgerPath = join21(artifactDir, "progress-ledger.json");
|
|
56457
56804
|
const entries = [];
|
|
56458
56805
|
const iterationArtifactPaths = [];
|
|
56459
56806
|
const evaluationArtifactPaths = [];
|
|
56460
56807
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
|
|
56461
56808
|
for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
|
|
56462
|
-
const iterationPath =
|
|
56463
|
-
const evaluationPath =
|
|
56809
|
+
const iterationPath = join21(iterationsDir, `iteration-${iteration}.md`);
|
|
56810
|
+
const evaluationPath = join21(evaluationsDir, `evaluation-${iteration}.json`);
|
|
56464
56811
|
iterationArtifactPaths.push(iterationPath);
|
|
56465
56812
|
evaluationArtifactPaths.push(evaluationPath);
|
|
56466
56813
|
await ctx.task(`iteration-${iteration}`, {
|
|
@@ -56509,7 +56856,7 @@ async function runLoopUntilDone(ctx) {
|
|
|
56509
56856
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
|
|
56510
56857
|
if (decision.done) {
|
|
56511
56858
|
const report = progressReport(entries);
|
|
56512
|
-
const resultPath =
|
|
56859
|
+
const resultPath = join21(artifactDir, "result.md");
|
|
56513
56860
|
const final = await ctx.task("completion-summary", {
|
|
56514
56861
|
prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
|
|
56515
56862
|
context: "fresh",
|
|
@@ -56626,9 +56973,9 @@ var init_loop_until_done = __esm(() => {
|
|
|
56626
56973
|
|
|
56627
56974
|
// dist/builtin/workflows/builtin/open-claude-design-utils.ts
|
|
56628
56975
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
56629
|
-
import { mkdirSync as
|
|
56976
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
56630
56977
|
import { tmpdir, userInfo } from "node:os";
|
|
56631
|
-
import { join as
|
|
56978
|
+
import { join as join22 } from "node:path";
|
|
56632
56979
|
import { Type as Type18 } from "typebox";
|
|
56633
56980
|
import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
|
|
56634
56981
|
function taggedPrompt3(sections) {
|
|
@@ -56671,32 +57018,32 @@ function tmpArtifactBase() {
|
|
|
56671
57018
|
try {
|
|
56672
57019
|
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
56673
57020
|
} catch {}
|
|
56674
|
-
return
|
|
57021
|
+
return join22(tmpdir(), `open-claude-design-${user}`);
|
|
56675
57022
|
}
|
|
56676
57023
|
function prepareArtifactDir(cwd = process.cwd()) {
|
|
56677
57024
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
56678
57025
|
const tmpCandidates = [
|
|
56679
|
-
|
|
56680
|
-
|
|
57026
|
+
join22(tmpArtifactBase(), runId),
|
|
57027
|
+
join22(tmpdir(), "open-claude-design", runId)
|
|
56681
57028
|
];
|
|
56682
|
-
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [
|
|
57029
|
+
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join22(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
56683
57030
|
for (const candidate of candidates) {
|
|
56684
57031
|
try {
|
|
56685
|
-
|
|
57032
|
+
mkdirSync6(candidate, { recursive: true });
|
|
56686
57033
|
return {
|
|
56687
57034
|
runId,
|
|
56688
57035
|
artifactDir: candidate,
|
|
56689
|
-
previewPath:
|
|
56690
|
-
specPath:
|
|
57036
|
+
previewPath: join22(candidate, "preview.html"),
|
|
57037
|
+
specPath: join22(candidate, "spec.html")
|
|
56691
57038
|
};
|
|
56692
57039
|
} catch {}
|
|
56693
57040
|
}
|
|
56694
|
-
const fallback =
|
|
57041
|
+
const fallback = join22(tmpArtifactBase(), runId);
|
|
56695
57042
|
return {
|
|
56696
57043
|
runId,
|
|
56697
57044
|
artifactDir: fallback,
|
|
56698
|
-
previewPath:
|
|
56699
|
-
specPath:
|
|
57045
|
+
previewPath: join22(fallback, "preview.html"),
|
|
57046
|
+
specPath: join22(fallback, "spec.html")
|
|
56700
57047
|
};
|
|
56701
57048
|
}
|
|
56702
57049
|
function ensureAgentBrowser() {
|
|
@@ -57030,8 +57377,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
|
|
|
57030
57377
|
});
|
|
57031
57378
|
|
|
57032
57379
|
// dist/builtin/workflows/builtin/open-claude-design-setup.ts
|
|
57033
|
-
import { mkdirSync as
|
|
57034
|
-
import { join as
|
|
57380
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
57381
|
+
import { join as join23 } from "node:path";
|
|
57035
57382
|
function renderDiscoveryContext(discovery) {
|
|
57036
57383
|
return [
|
|
57037
57384
|
`Confirmed design brief: ${discovery.brief}`,
|
|
@@ -57096,10 +57443,10 @@ async function runDiscoveryAndInit(args) {
|
|
|
57096
57443
|
};
|
|
57097
57444
|
}
|
|
57098
57445
|
function designContextPath(artifactDir) {
|
|
57099
|
-
return
|
|
57446
|
+
return join23(artifactDir, DESIGN_CONTEXT_FILENAME);
|
|
57100
57447
|
}
|
|
57101
57448
|
function referencesBriefPath(artifactDir) {
|
|
57102
|
-
return
|
|
57449
|
+
return join23(artifactDir, REFERENCES_BRIEF_FILENAME);
|
|
57103
57450
|
}
|
|
57104
57451
|
function buildReferenceDiscoveryPrompt(args) {
|
|
57105
57452
|
const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
|
|
@@ -57125,8 +57472,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57125
57472
|
[
|
|
57126
57473
|
"Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
|
|
57127
57474
|
"From each gallery, choose 1-3 fitting designs and CLICK INTO each actual live or project-detail page; do not capture only the grid or thumbnail.",
|
|
57128
|
-
`Capture motion across the entire page: start \`agent-browser record start ${
|
|
57129
|
-
`Also run \`agent-browser screenshot ${
|
|
57475
|
+
`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\`.`,
|
|
57476
|
+
`Also run \`agent-browser screenshot ${join23(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
|
|
57130
57477
|
"Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
|
|
57131
57478
|
"Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
|
|
57132
57479
|
"Use ask_user_question to ask which reference direction they prefer, offering 2-4 strongest options plus `None of these fit`. If none fit, ask them to provide a reference image, screenshot, URL, or local file path and record the answer.",
|
|
@@ -57151,8 +57498,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57151
57498
|
}
|
|
57152
57499
|
function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
|
|
57153
57500
|
try {
|
|
57154
|
-
|
|
57155
|
-
|
|
57501
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
57502
|
+
writeFileSync4(filePath, `${content}
|
|
57156
57503
|
`);
|
|
57157
57504
|
} catch (error) {
|
|
57158
57505
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -57703,7 +58050,7 @@ var init_ralph_review_gate = __esm(() => {
|
|
|
57703
58050
|
|
|
57704
58051
|
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
57705
58052
|
import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
|
|
57706
|
-
import { dirname as
|
|
58053
|
+
import { dirname as dirname11, join as join24 } from "node:path";
|
|
57707
58054
|
import { Type as Type20 } from "typebox";
|
|
57708
58055
|
function taggedPrompt4(sections) {
|
|
57709
58056
|
return sections.map(([tag, content]) => {
|
|
@@ -57743,11 +58090,11 @@ function slugifyResearchTopic(prompt) {
|
|
|
57743
58090
|
}
|
|
57744
58091
|
function defaultResearchPath(prompt, now = new Date) {
|
|
57745
58092
|
const date = now.toISOString().slice(0, 10);
|
|
57746
|
-
return
|
|
58093
|
+
return join24(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
57747
58094
|
}
|
|
57748
58095
|
async function createImplementationNotesFile(prompt, runId) {
|
|
57749
58096
|
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
57750
|
-
const notesPath =
|
|
58097
|
+
const notesPath = join24(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
57751
58098
|
const initialNotes = [
|
|
57752
58099
|
"# Implementation Notes",
|
|
57753
58100
|
"",
|
|
@@ -57768,7 +58115,7 @@ async function createImplementationNotesFile(prompt, runId) {
|
|
|
57768
58115
|
}
|
|
57769
58116
|
async function createQaEvidenceVideoPath(runId) {
|
|
57770
58117
|
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
57771
|
-
return
|
|
58118
|
+
return join24(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
57772
58119
|
}
|
|
57773
58120
|
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
57774
58121
|
return [
|
|
@@ -57834,7 +58181,7 @@ function artifactSafeName2(value2) {
|
|
|
57834
58181
|
return safe.length > 0 ? safe : "artifact";
|
|
57835
58182
|
}
|
|
57836
58183
|
async function writeJsonArtifact(path, content) {
|
|
57837
|
-
await mkdir4(
|
|
58184
|
+
await mkdir4(dirname11(path), { recursive: true });
|
|
57838
58185
|
await writeFile8(path, `${JSON.stringify(content, null, 2)}
|
|
57839
58186
|
`, {
|
|
57840
58187
|
encoding: "utf8"
|
|
@@ -58172,7 +58519,7 @@ var init_ralph_models = __esm(() => {
|
|
|
58172
58519
|
|
|
58173
58520
|
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
58174
58521
|
import { existsSync as existsSync4 } from "node:fs";
|
|
58175
|
-
import { join as
|
|
58522
|
+
import { join as join25, resolve as resolve10 } from "node:path";
|
|
58176
58523
|
async function runRalphWorkflow(ctx, options) {
|
|
58177
58524
|
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
58178
58525
|
let latestReviewReportPath;
|
|
@@ -58184,7 +58531,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58184
58531
|
let finalPrReport;
|
|
58185
58532
|
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
58186
58533
|
const workflowPrompt = prompt;
|
|
58187
|
-
const workflowResearchPath =
|
|
58534
|
+
const workflowResearchPath = resolve10(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
58188
58535
|
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
58189
58536
|
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
58190
58537
|
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
@@ -58233,7 +58580,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58233
58580
|
const researchPath = workflowResearchPath;
|
|
58234
58581
|
finalResearchPath = researchPath;
|
|
58235
58582
|
finalPlanPath = researchPath;
|
|
58236
|
-
const orchestratorReportPath =
|
|
58583
|
+
const orchestratorReportPath = join25(artifactDir, "orchestrator-report.md");
|
|
58237
58584
|
const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
|
|
58238
58585
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
|
|
58239
58586
|
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
@@ -58369,7 +58716,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58369
58716
|
diagnostics: parsed.diagnostics,
|
|
58370
58717
|
allowFinalActionRemaining: createPr
|
|
58371
58718
|
});
|
|
58372
|
-
const artifactPath =
|
|
58719
|
+
const artifactPath = join25(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
|
|
58373
58720
|
await writeJsonArtifact(artifactPath, {
|
|
58374
58721
|
reviewer,
|
|
58375
58722
|
decision: parsed.decision,
|
|
@@ -58425,7 +58772,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58425
58772
|
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
58426
58773
|
}));
|
|
58427
58774
|
}
|
|
58428
|
-
latestReviewReportPath = await writeJsonArtifact(
|
|
58775
|
+
latestReviewReportPath = await writeJsonArtifact(join25(artifactDir, "review-round-latest.json"), {
|
|
58429
58776
|
convergence_decision: roundConvergenceDecision,
|
|
58430
58777
|
convergence: convergenceEntries,
|
|
58431
58778
|
consolidated_findings: reverified.batch,
|
|
@@ -58574,7 +58921,7 @@ var init_ralph = __esm(() => {
|
|
|
58574
58921
|
}),
|
|
58575
58922
|
git_worktree_dir: Type21.String({
|
|
58576
58923
|
default: "",
|
|
58577
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
58924
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
58578
58925
|
}),
|
|
58579
58926
|
create_pr: Type21.Boolean({
|
|
58580
58927
|
default: false,
|
|
@@ -58794,7 +59141,7 @@ var init_tournament_prompts = __esm(() => {
|
|
|
58794
59141
|
|
|
58795
59142
|
// dist/builtin/workflows/builtin/tournament-runner.ts
|
|
58796
59143
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
|
|
58797
|
-
import { join as
|
|
59144
|
+
import { join as join26, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve11 } from "node:path";
|
|
58798
59145
|
import { Type as Type22 } from "typebox";
|
|
58799
59146
|
function serializableObject2(value2) {
|
|
58800
59147
|
if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
|
|
@@ -58831,8 +59178,8 @@ function criterionSlug(id) {
|
|
|
58831
59178
|
}
|
|
58832
59179
|
function judgeArtifactPath(judgesDir, job, criterionIndex) {
|
|
58833
59180
|
const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
|
|
58834
|
-
const root =
|
|
58835
|
-
const path =
|
|
59181
|
+
const root = resolve11(judgesDir);
|
|
59182
|
+
const path = resolve11(judgesDir, filename);
|
|
58836
59183
|
const fromRoot = relative5(root, path);
|
|
58837
59184
|
if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
|
|
58838
59185
|
throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
|
|
@@ -58883,16 +59230,16 @@ function combineUsage(totals) {
|
|
|
58883
59230
|
}
|
|
58884
59231
|
async function runTournament(ctx) {
|
|
58885
59232
|
const artifactDir = await stableArtifactRoot(ctx, "tournament");
|
|
58886
|
-
const attemptsDir =
|
|
59233
|
+
const attemptsDir = join26(artifactDir, "attempts");
|
|
58887
59234
|
const numAttempts = ctx.inputs.num_attempts ?? 4;
|
|
58888
59235
|
const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
|
|
58889
59236
|
const nEvaluations = ctx.inputs.n_evaluations ?? 2;
|
|
58890
59237
|
const pivotCount = ctx.inputs.pivots ?? 1;
|
|
58891
59238
|
const seed = ctx.inputs.seed ?? 0;
|
|
58892
|
-
const judgesDir =
|
|
59239
|
+
const judgesDir = join26(artifactDir, "judges");
|
|
58893
59240
|
await mkdir5(attemptsDir, { recursive: true });
|
|
58894
59241
|
await mkdir5(judgesDir, { recursive: true });
|
|
58895
|
-
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
|
|
59242
|
+
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join26(attemptsDir, `attempt-${index + 1}.md`));
|
|
58896
59243
|
const models = ctx.inputs.models;
|
|
58897
59244
|
const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
|
|
58898
59245
|
name: `attempt-${index + 1}`,
|
|
@@ -59057,7 +59404,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59057
59404
|
const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
|
|
59058
59405
|
const budgetPivots = Math.min(pivotCount, entrants.length);
|
|
59059
59406
|
const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
|
|
59060
|
-
const comparisonPath =
|
|
59407
|
+
const comparisonPath = join26(artifactDir, "comparisons.json");
|
|
59061
59408
|
const assignment = modelAssignment(entrants, models);
|
|
59062
59409
|
const phaseUsage = {
|
|
59063
59410
|
attempts: fold_usage(attemptResults),
|
|
@@ -59093,7 +59440,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59093
59440
|
await writeLedger(fold_usage([]));
|
|
59094
59441
|
const winner = ranking[0];
|
|
59095
59442
|
const winnerEntrant = entrants[winner.index];
|
|
59096
|
-
const resultPath =
|
|
59443
|
+
const resultPath = join26(artifactDir, "winner.md");
|
|
59097
59444
|
const reducer = await ctx.task("comparisons-reducer", {
|
|
59098
59445
|
prompt: renderComparisonsReducerPrompt({
|
|
59099
59446
|
task: ctx.inputs.prompt,
|
|
@@ -59999,7 +60346,7 @@ class SqlPoolQueue {
|
|
|
59999
60346
|
throw new Error("Stale pool coordinator authority", { cause: error });
|
|
60000
60347
|
throw error;
|
|
60001
60348
|
});
|
|
60002
|
-
const row = await this.current(tx, lease, token);
|
|
60349
|
+
const row = await this.current(tx, lease, token, true);
|
|
60003
60350
|
if (row.epoch !== lease.epoch)
|
|
60004
60351
|
throw new Error(STALE_WORK_LEASE);
|
|
60005
60352
|
assertSession();
|
|
@@ -62233,7 +62580,7 @@ function isBrokerStatusReport(value2) {
|
|
|
62233
62580
|
|
|
62234
62581
|
// dist/builtin/intercom/broker/paths.ts
|
|
62235
62582
|
import { homedir as homedir2 } from "os";
|
|
62236
|
-
import { join as
|
|
62583
|
+
import { join as join27 } from "path";
|
|
62237
62584
|
function getHomeDir() {
|
|
62238
62585
|
if (process.platform === "win32") {
|
|
62239
62586
|
if (process.env.USERPROFILE)
|
|
@@ -62250,7 +62597,7 @@ function expandTildePath(path) {
|
|
|
62250
62597
|
if (path === "~")
|
|
62251
62598
|
return getHomeDir();
|
|
62252
62599
|
if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
|
|
62253
|
-
return
|
|
62600
|
+
return join27(getHomeDir(), path.slice(2));
|
|
62254
62601
|
}
|
|
62255
62602
|
return path;
|
|
62256
62603
|
}
|
|
@@ -62261,31 +62608,31 @@ function getAgentDir5() {
|
|
|
62261
62608
|
const piAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
62262
62609
|
if (piAgentDir)
|
|
62263
62610
|
return expandTildePath(piAgentDir);
|
|
62264
|
-
return
|
|
62611
|
+
return join27(getHomeDir(), ".atomic", "agent");
|
|
62265
62612
|
}
|
|
62266
62613
|
function sanitizePipeSegment(value2) {
|
|
62267
62614
|
return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
|
|
62268
62615
|
}
|
|
62269
62616
|
function getIntercomDirPath(agentDir = getAgentDir5()) {
|
|
62270
|
-
return
|
|
62617
|
+
return join27(agentDir, "intercom");
|
|
62271
62618
|
}
|
|
62272
62619
|
function getBrokerPidPath(agentDir = getAgentDir5()) {
|
|
62273
|
-
return
|
|
62620
|
+
return join27(getIntercomDirPath(agentDir), "broker.pid");
|
|
62274
62621
|
}
|
|
62275
62622
|
function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
62276
|
-
return
|
|
62623
|
+
return join27(getIntercomDirPath(agentDir), "broker.spawn.lock");
|
|
62277
62624
|
}
|
|
62278
62625
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
62279
|
-
return
|
|
62626
|
+
return join27(getIntercomDirPath(agentDir), "broker.log");
|
|
62280
62627
|
}
|
|
62281
62628
|
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
62282
|
-
return
|
|
62629
|
+
return join27(getIntercomDirPath(agentDir), "broker.starting");
|
|
62283
62630
|
}
|
|
62284
62631
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
62285
62632
|
if (platform === "win32") {
|
|
62286
62633
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
62287
62634
|
}
|
|
62288
|
-
return
|
|
62635
|
+
return join27(getIntercomDirPath(agentDir), "broker.sock");
|
|
62289
62636
|
}
|
|
62290
62637
|
var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
|
|
62291
62638
|
var init_paths = () => {};
|
|
@@ -63969,11 +64316,11 @@ var init_client = __esm(() => {
|
|
|
63969
64316
|
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
63970
64317
|
|
|
63971
64318
|
// dist/builtin/intercom/broker/start-announcement.ts
|
|
63972
|
-
import { readFileSync as
|
|
64319
|
+
import { readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
63973
64320
|
function readBrokerStartAnnouncement(announcement) {
|
|
63974
64321
|
let text;
|
|
63975
64322
|
try {
|
|
63976
|
-
text =
|
|
64323
|
+
text = readFileSync5(announcement.path, "utf-8");
|
|
63977
64324
|
} catch {
|
|
63978
64325
|
return;
|
|
63979
64326
|
}
|
|
@@ -63992,26 +64339,26 @@ var init_start_announcement = () => {};
|
|
|
63992
64339
|
// dist/builtin/intercom/broker/spawn.ts
|
|
63993
64340
|
import { spawn } from "child_process";
|
|
63994
64341
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
63995
|
-
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as
|
|
63996
|
-
import { join as
|
|
64342
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync6, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
64343
|
+
import { join as join28, dirname as dirname12 } from "path";
|
|
63997
64344
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
63998
64345
|
import { createRequire as createRequire3 } from "module";
|
|
63999
64346
|
import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
|
|
64000
64347
|
function isIntercomPackageRoot(dir) {
|
|
64001
|
-
return existsSync5(
|
|
64348
|
+
return existsSync5(join28(dir, "package.json")) && existsSync5(join28(dir, "broker"));
|
|
64002
64349
|
}
|
|
64003
64350
|
function resolveIntercomPackageRoot(moduleHref) {
|
|
64004
|
-
const here =
|
|
64351
|
+
const here = dirname12(fileURLToPath4(moduleHref));
|
|
64005
64352
|
if (isIntercomPackageRoot(here))
|
|
64006
64353
|
return here;
|
|
64007
|
-
return
|
|
64354
|
+
return join28(here, "..");
|
|
64008
64355
|
}
|
|
64009
64356
|
function resolveBrokerEntrypoint(packageRoot) {
|
|
64010
|
-
const bundled =
|
|
64011
|
-
return existsSync5(bundled) ? bundled :
|
|
64357
|
+
const bundled = join28(packageRoot, "broker", "broker.bundle.mjs");
|
|
64358
|
+
return existsSync5(bundled) ? bundled : join28(packageRoot, "broker", "broker.ts");
|
|
64012
64359
|
}
|
|
64013
64360
|
function ensurePrivateDirectory(path) {
|
|
64014
|
-
|
|
64361
|
+
mkdirSync8(path, { recursive: true, mode: 448 });
|
|
64015
64362
|
if (process.platform !== "win32")
|
|
64016
64363
|
chmodSync(path, 448);
|
|
64017
64364
|
}
|
|
@@ -64024,14 +64371,14 @@ function getCurrentBrokerRuntime() {
|
|
|
64024
64371
|
return isBunBinary ? "bun-binary" : "bun-source";
|
|
64025
64372
|
}
|
|
64026
64373
|
function requireFromExtensionDir(extensionDir) {
|
|
64027
|
-
return createRequire3(
|
|
64374
|
+
return createRequire3(join28(extensionDir, "package.json"));
|
|
64028
64375
|
}
|
|
64029
64376
|
function getJitiCliPath(extensionDir = EXTENSION_DIR) {
|
|
64030
64377
|
try {
|
|
64031
64378
|
const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
|
|
64032
|
-
return
|
|
64379
|
+
return join28(dirname12(jitiPackage), "lib", "jiti-cli.mjs");
|
|
64033
64380
|
} catch {
|
|
64034
|
-
return
|
|
64381
|
+
return join28(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
|
|
64035
64382
|
}
|
|
64036
64383
|
}
|
|
64037
64384
|
function getDefaultBrokerRunnerPath(extensionDir) {
|
|
@@ -64053,7 +64400,7 @@ function quoteWindowsArg(value2) {
|
|
|
64053
64400
|
return `"${value2.replace(/"/g, '""')}"`;
|
|
64054
64401
|
}
|
|
64055
64402
|
function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
|
|
64056
|
-
return
|
|
64403
|
+
return join28(intercomDir, "broker-launch.vbs");
|
|
64057
64404
|
}
|
|
64058
64405
|
function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
|
|
64059
64406
|
return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
|
|
@@ -64080,8 +64427,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
64080
64427
|
`);
|
|
64081
64428
|
}
|
|
64082
64429
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
64083
|
-
ensurePrivateDirectory(
|
|
64084
|
-
|
|
64430
|
+
ensurePrivateDirectory(dirname12(launcherPath));
|
|
64431
|
+
writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
64085
64432
|
return launcherPath;
|
|
64086
64433
|
}
|
|
64087
64434
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -64124,14 +64471,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
|
|
|
64124
64471
|
};
|
|
64125
64472
|
}
|
|
64126
64473
|
function resetBrokerLog(logPath = BROKER_LOG) {
|
|
64127
|
-
ensurePrivateDirectory(
|
|
64474
|
+
ensurePrivateDirectory(dirname12(logPath));
|
|
64128
64475
|
try {
|
|
64129
64476
|
const previous = readBrokerLogTail(logPath);
|
|
64130
64477
|
closeSync3(openSync3(logPath, "w"));
|
|
64131
64478
|
if (previous.length > 0) {
|
|
64132
64479
|
try {
|
|
64133
64480
|
const previousPath = `${logPath}.previous`;
|
|
64134
|
-
|
|
64481
|
+
writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
64135
64482
|
if (process.platform !== "win32")
|
|
64136
64483
|
chmodSync(previousPath, 384);
|
|
64137
64484
|
} catch {}
|
|
@@ -64275,7 +64622,7 @@ async function isBrokerRunning() {
|
|
|
64275
64622
|
if (!existsSync5(BROKER_PID))
|
|
64276
64623
|
return false;
|
|
64277
64624
|
try {
|
|
64278
|
-
const pid = parseInt(
|
|
64625
|
+
const pid = parseInt(readFileSync6(BROKER_PID, "utf-8").trim(), 10);
|
|
64279
64626
|
if (!Number.isFinite(pid))
|
|
64280
64627
|
return false;
|
|
64281
64628
|
process.kill(pid, 0);
|
|
@@ -64300,7 +64647,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
64300
64647
|
}
|
|
64301
64648
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
64302
64649
|
try {
|
|
64303
|
-
return
|
|
64650
|
+
return readFileSync6(lockPath, "utf-8").startsWith(owner);
|
|
64304
64651
|
} catch {
|
|
64305
64652
|
return false;
|
|
64306
64653
|
}
|
|
@@ -64312,7 +64659,7 @@ function acquireSpawnLock() {
|
|
|
64312
64659
|
${Date.now()}
|
|
64313
64660
|
`;
|
|
64314
64661
|
try {
|
|
64315
|
-
|
|
64662
|
+
writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
64316
64663
|
return owner;
|
|
64317
64664
|
} catch (error) {
|
|
64318
64665
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -64342,7 +64689,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
64342
64689
|
return false;
|
|
64343
64690
|
}
|
|
64344
64691
|
try {
|
|
64345
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
64692
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync6(lockPath, "utf-8").trim().split(`
|
|
64346
64693
|
`);
|
|
64347
64694
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
64348
64695
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -64420,14 +64767,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
64420
64767
|
});
|
|
64421
64768
|
|
|
64422
64769
|
// dist/builtin/intercom/config.ts
|
|
64423
|
-
import { existsSync as existsSync6, readFileSync as
|
|
64770
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
64424
64771
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
64425
64772
|
function loadConfig() {
|
|
64426
64773
|
if (!existsSync6(CONFIG_PATH)) {
|
|
64427
64774
|
return { ...defaults };
|
|
64428
64775
|
}
|
|
64429
64776
|
try {
|
|
64430
|
-
const raw =
|
|
64777
|
+
const raw = readFileSync7(CONFIG_PATH, "utf-8");
|
|
64431
64778
|
const parsed = JSON.parse(raw);
|
|
64432
64779
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
64433
64780
|
throw new Error("Config must be a JSON object");
|
|
@@ -65010,12 +65357,12 @@ var init_sql_pool_usage = __esm(() => {
|
|
|
65010
65357
|
|
|
65011
65358
|
// dist/builtin/workflows/src/workers/pooled-watch-trace.ts
|
|
65012
65359
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
65013
|
-
import { dirname as
|
|
65360
|
+
import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
|
|
65014
65361
|
function configurePooledWatchTrace(journalPath, processRole) {
|
|
65015
65362
|
if (setting === undefined || setting === "" || setting === "0")
|
|
65016
65363
|
return;
|
|
65017
65364
|
role = processRole;
|
|
65018
|
-
file = setting === "1" ?
|
|
65365
|
+
file = setting === "1" ? join29(dirname13(resolve12(journalPath)), "pooled-watch-trace.jsonl") : resolve12(setting);
|
|
65019
65366
|
}
|
|
65020
65367
|
function tracePooledWatch(step, detail) {
|
|
65021
65368
|
if (file === undefined)
|
|
@@ -65209,7 +65556,7 @@ import { fork } from "node:child_process";
|
|
|
65209
65556
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
65210
65557
|
import { createWriteStream } from "node:fs";
|
|
65211
65558
|
import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65212
|
-
import { dirname as
|
|
65559
|
+
import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
|
|
65213
65560
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
65214
65561
|
function isRootLeaseLost(error) {
|
|
65215
65562
|
return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
|
|
@@ -65218,7 +65565,7 @@ function unconfirmedCleanup(groups) {
|
|
|
65218
65565
|
return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
|
|
65219
65566
|
}
|
|
65220
65567
|
function workerLogDirectory(journalPath, root) {
|
|
65221
|
-
return
|
|
65568
|
+
return join30(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
65222
65569
|
}
|
|
65223
65570
|
function token(work) {
|
|
65224
65571
|
return {
|
|
@@ -65406,6 +65753,7 @@ class PoolCoordinator {
|
|
|
65406
65753
|
cleanups = new Set;
|
|
65407
65754
|
controlAcks = new Map;
|
|
65408
65755
|
lastHeard = new Map;
|
|
65756
|
+
awaiting = new Map;
|
|
65409
65757
|
pendingActivity = new Map;
|
|
65410
65758
|
batches = new Map;
|
|
65411
65759
|
publicationFailures = new Map;
|
|
@@ -66149,7 +66497,7 @@ class PoolCoordinator {
|
|
|
66149
66497
|
this.slots.add(slot);
|
|
66150
66498
|
let ready = false;
|
|
66151
66499
|
let serial = Promise.resolve();
|
|
66152
|
-
const logPath =
|
|
66500
|
+
const logPath = join30(this.logDirectory, `${worker}.log`);
|
|
66153
66501
|
this.logs.set(child, logPath);
|
|
66154
66502
|
let logFailure;
|
|
66155
66503
|
const log = createWriteStream(logPath, { flags: "a" });
|
|
@@ -66205,6 +66553,7 @@ class PoolCoordinator {
|
|
|
66205
66553
|
this.readyWorkers.delete(worker);
|
|
66206
66554
|
this.controlAcks.delete(worker);
|
|
66207
66555
|
this.lastHeard.delete(worker);
|
|
66556
|
+
this.awaiting.delete(worker);
|
|
66208
66557
|
this.slots.delete(slot);
|
|
66209
66558
|
this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
|
|
66210
66559
|
for (const settle of slot.stageCommands.values())
|
|
@@ -66462,8 +66811,19 @@ class PoolCoordinator {
|
|
|
66462
66811
|
await this.sendResult(work.id);
|
|
66463
66812
|
});
|
|
66464
66813
|
const response = handled.then((value2) => routeReady ?? value2);
|
|
66465
|
-
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
66466
|
-
|
|
66814
|
+
if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
|
|
66815
|
+
this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
|
|
66816
|
+
const answered = () => {
|
|
66817
|
+
const left = (this.awaiting.get(worker) ?? 1) - 1;
|
|
66818
|
+
if (left > 0)
|
|
66819
|
+
this.awaiting.set(worker, left);
|
|
66820
|
+
else
|
|
66821
|
+
this.awaiting.delete(worker);
|
|
66822
|
+
if (this.incarnations.get(worker) === child)
|
|
66823
|
+
this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
|
|
66824
|
+
};
|
|
66825
|
+
serial = handled.then(answered, answered);
|
|
66826
|
+
}
|
|
66467
66827
|
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
|
|
66468
66828
|
const rootLeaseLost = isRootLeaseLost(error);
|
|
66469
66829
|
if (rootLeaseLost)
|
|
@@ -66533,7 +66893,10 @@ class PoolCoordinator {
|
|
|
66533
66893
|
if (work.epoch < lease.epoch)
|
|
66534
66894
|
await this.releaseRetained(work);
|
|
66535
66895
|
else
|
|
66536
|
-
await queue.expire(lease, work)
|
|
66896
|
+
await queue.expire(lease, work).catch((error) => {
|
|
66897
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
66898
|
+
throw error;
|
|
66899
|
+
});
|
|
66537
66900
|
}
|
|
66538
66901
|
})().finally(() => {
|
|
66539
66902
|
this.recovering = undefined;
|
|
@@ -66551,7 +66914,7 @@ class PoolCoordinator {
|
|
|
66551
66914
|
isLive(worker, child) {
|
|
66552
66915
|
this.observeResponsiveness();
|
|
66553
66916
|
const heard = this.lastHeard.get(worker);
|
|
66554
|
-
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
|
|
66917
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && ((this.awaiting.get(worker) ?? 0) > 0 || performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs);
|
|
66555
66918
|
}
|
|
66556
66919
|
async stop(child) {
|
|
66557
66920
|
const pid = child.pid;
|
|
@@ -66737,26 +67100,6 @@ function isWorkflowPendingStageDeliveryFailure(error) {
|
|
|
66737
67100
|
return true;
|
|
66738
67101
|
return error?.code === "pending_stage_delivery_failed";
|
|
66739
67102
|
}
|
|
66740
|
-
function untilDrainedOrStalled(drain) {
|
|
66741
|
-
let lastProgressAt = Date.now();
|
|
66742
|
-
const running = drain(() => {
|
|
66743
|
-
lastProgressAt = Date.now();
|
|
66744
|
-
});
|
|
66745
|
-
return new Promise((resolve, reject) => {
|
|
66746
|
-
let timer;
|
|
66747
|
-
const check = () => {
|
|
66748
|
-
const remaining = lastProgressAt + PENDING_STAGE_READY_STALL_MS - Date.now();
|
|
66749
|
-
if (remaining <= 0) {
|
|
66750
|
-
resolve();
|
|
66751
|
-
return;
|
|
66752
|
-
}
|
|
66753
|
-
timer = setTimeout(check, remaining);
|
|
66754
|
-
timer.unref?.();
|
|
66755
|
-
};
|
|
66756
|
-
running.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
66757
|
-
check();
|
|
66758
|
-
});
|
|
66759
|
-
}
|
|
66760
67103
|
function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName, commit = (action) => action(), options = {}) {
|
|
66761
67104
|
let resolveReady;
|
|
66762
67105
|
let rejectReady;
|
|
@@ -66949,7 +67292,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
66949
67292
|
};
|
|
66950
67293
|
}
|
|
66951
67294
|
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
|
|
66952
|
-
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
|
|
67295
|
+
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
|
|
66953
67296
|
const candidateIds = new Set([
|
|
66954
67297
|
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
66955
67298
|
...activeStore.pendingStageMessagesFor(runId, stageName),
|
|
@@ -67005,7 +67348,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
|
|
|
67005
67348
|
}
|
|
67006
67349
|
}
|
|
67007
67350
|
}
|
|
67008
|
-
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
|
|
67351
|
+
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
|
|
67009
67352
|
const runs = activeStore.runs();
|
|
67010
67353
|
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
67011
67354
|
if (rootRunId === undefined)
|
|
@@ -67014,22 +67357,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
|
|
|
67014
67357
|
if (rootRun === undefined)
|
|
67015
67358
|
return [];
|
|
67016
67359
|
const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
|
|
67017
|
-
|
|
67360
|
+
const ended = stage?.status === "completed" || stage?.status === "skipped";
|
|
67361
|
+
if (ended && receivedByEndedStage.length === 0)
|
|
67018
67362
|
return [];
|
|
67019
67363
|
const hops = workflowBoundaryHops(runs, runId);
|
|
67020
67364
|
if (hops === undefined)
|
|
67021
67365
|
return [];
|
|
67022
67366
|
return (rootRun.pendingStageMessages ?? []).filter((entry) => {
|
|
67023
|
-
if (entry.sticky !== true || entry.status !== "queued")
|
|
67024
|
-
return false;
|
|
67025
|
-
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67026
|
-
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67027
|
-
return false;
|
|
67028
67367
|
if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId && (recipient === undefined || delivery.admission === "context" && delivery.sessionId === recipient.sessionId && (recipient.receivedMessageIds === undefined || recipient.receivedMessageIds.includes(entry.message.id)))))
|
|
67029
67368
|
return false;
|
|
67030
|
-
|
|
67369
|
+
if (ended && !receivedByEndedStage.includes(entry.message.id))
|
|
67370
|
+
return false;
|
|
67371
|
+
return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
|
|
67031
67372
|
});
|
|
67032
67373
|
}
|
|
67374
|
+
function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
|
|
67375
|
+
if (entry.sticky !== true || entry.status !== "queued")
|
|
67376
|
+
return false;
|
|
67377
|
+
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67378
|
+
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67379
|
+
return false;
|
|
67380
|
+
return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
|
|
67381
|
+
}
|
|
67033
67382
|
function claimPendingDelivery(store, runId, stageKey, messageId) {
|
|
67034
67383
|
let claims = pendingDeliveryClaims.get(store);
|
|
67035
67384
|
if (claims === undefined) {
|
|
@@ -67093,6 +67442,7 @@ class PoolStageHandoff {
|
|
|
67093
67442
|
owners = new Map;
|
|
67094
67443
|
publications = new Map;
|
|
67095
67444
|
drains = new Map;
|
|
67445
|
+
deliveryIssues = 0;
|
|
67096
67446
|
constructor(backend, store, queue, lease, claimRun) {
|
|
67097
67447
|
this.backend = backend;
|
|
67098
67448
|
this.store = store;
|
|
@@ -67173,11 +67523,23 @@ class PoolStageHandoff {
|
|
|
67173
67523
|
this.drains.set(stage, drain);
|
|
67174
67524
|
try {
|
|
67175
67525
|
await drain;
|
|
67526
|
+
} catch (error) {
|
|
67527
|
+
const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
|
|
67528
|
+
if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
|
|
67529
|
+
this.recordDeliveryIssue(error);
|
|
67530
|
+
throw error;
|
|
67176
67531
|
} finally {
|
|
67177
67532
|
if (this.drains.get(stage) === drain)
|
|
67178
67533
|
this.drains.delete(stage);
|
|
67179
67534
|
}
|
|
67180
67535
|
}
|
|
67536
|
+
recordDeliveryIssue(error) {
|
|
67537
|
+
this.deliveryIssues++;
|
|
67538
|
+
const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
|
|
67539
|
+
this.store.recordRunExecutionState(this.lease.runId, {
|
|
67540
|
+
intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
|
|
67541
|
+
});
|
|
67542
|
+
}
|
|
67181
67543
|
async complete(work) {
|
|
67182
67544
|
const root = this.lease.runId;
|
|
67183
67545
|
const result = await this.queue.result(root, work.id);
|
|
@@ -68533,7 +68895,7 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
68533
68895
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
68534
68896
|
import { fork as fork2 } from "node:child_process";
|
|
68535
68897
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
68536
|
-
import { resolve as
|
|
68898
|
+
import { resolve as resolve14 } from "node:path";
|
|
68537
68899
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
68538
68900
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
68539
68901
|
import {
|
|
@@ -68767,7 +69129,7 @@ class LocalWorkerPool {
|
|
|
68767
69129
|
async poolJournal() {
|
|
68768
69130
|
const journal = this.backend.journal;
|
|
68769
69131
|
if (this.options.durable === undefined) {
|
|
68770
|
-
if (!(journal instanceof SqlRunJournal) ||
|
|
69132
|
+
if (!(journal instanceof SqlRunJournal) || resolve14(this.options.journalPath) !== resolve14(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
68771
69133
|
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68772
69134
|
return journal;
|
|
68773
69135
|
}
|
|
@@ -69794,7 +70156,7 @@ var init_local_pool = __esm(() => {
|
|
|
69794
70156
|
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
69795
70157
|
|
|
69796
70158
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
69797
|
-
import { resolve as
|
|
70159
|
+
import { resolve as resolve15 } from "node:path";
|
|
69798
70160
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
69799
70161
|
async function restoreWorkerOptions(backend, options) {
|
|
69800
70162
|
const source = options.continuation?.source.id ?? options.runId;
|
|
@@ -69844,16 +70206,16 @@ async function activatePublicPool(backend, options) {
|
|
|
69844
70206
|
startupTimeoutMs: undefined,
|
|
69845
70207
|
leaseMs: undefined,
|
|
69846
70208
|
maxLoadPerCpu: undefined,
|
|
69847
|
-
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path:
|
|
70209
|
+
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
|
|
69848
70210
|
};
|
|
69849
70211
|
const admission = options.admission && {
|
|
69850
70212
|
...options.admission,
|
|
69851
|
-
...options.admission.userDatabase ? { userDatabase:
|
|
70213
|
+
...options.admission.userDatabase ? { userDatabase: resolve15(cwd, options.admission.userDatabase) } : {}
|
|
69852
70214
|
};
|
|
69853
70215
|
if (durable !== undefined && admission?.userLimits) {
|
|
69854
|
-
if (admission.userDatabase !== undefined && admission.userDatabase !==
|
|
69855
|
-
throw new Error(`admission.userDatabase must be omitted, or ${
|
|
69856
|
-
admission.userDatabase =
|
|
70216
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve15(poolPath))
|
|
70217
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve15(poolPath)}, for a journal that is not a local SQLite file`);
|
|
70218
|
+
admission.userDatabase = resolve15(poolPath);
|
|
69857
70219
|
}
|
|
69858
70220
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
69859
70221
|
const resources = JSON.parse(JSON.stringify({
|
|
@@ -70459,6 +70821,7 @@ function createTaskPrimitive(runtime) {
|
|
|
70459
70821
|
}
|
|
70460
70822
|
})();
|
|
70461
70823
|
const stageMeta = stage.__modelFallbackMeta();
|
|
70824
|
+
stage.__releaseIfIdle?.();
|
|
70462
70825
|
return {
|
|
70463
70826
|
name,
|
|
70464
70827
|
stageName: name,
|
|
@@ -71257,7 +71620,7 @@ function hasUsableContentBlock(block) {
|
|
|
71257
71620
|
|
|
71258
71621
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
71259
71622
|
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
71260
|
-
import { dirname as
|
|
71623
|
+
import { dirname as dirname15, resolve as resolve16 } from "node:path";
|
|
71261
71624
|
import {
|
|
71262
71625
|
JsonlSessionStore,
|
|
71263
71626
|
resolveSessionStore,
|
|
@@ -71293,11 +71656,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
|
|
|
71293
71656
|
async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
71294
71657
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
71295
71658
|
return;
|
|
71296
|
-
const location =
|
|
71297
|
-
const legacy = await JsonlSessionStore.open(
|
|
71659
|
+
const location = resolve16(sessionFile);
|
|
71660
|
+
const legacy = await JsonlSessionStore.open(dirname15(location), { exactDirectory: true, scanExisting: false });
|
|
71298
71661
|
try {
|
|
71299
71662
|
for await (const file of legacy.scanFiles()) {
|
|
71300
|
-
if (
|
|
71663
|
+
if (resolve16(file.location) !== location || file.header.id !== sessionId)
|
|
71301
71664
|
continue;
|
|
71302
71665
|
const snapshot = await file.read();
|
|
71303
71666
|
if (await store.readHeader(sessionId) === undefined)
|
|
@@ -74123,6 +74486,8 @@ function createTrackedStageCaller(input) {
|
|
|
74123
74486
|
await runtime.releaseLiveHandle().catch(() => {});
|
|
74124
74487
|
}
|
|
74125
74488
|
runtime.state.sessionCheckpointed = finalizationError === undefined;
|
|
74489
|
+
if (runtime.state.contextUnreachable)
|
|
74490
|
+
runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
|
|
74126
74491
|
input.limiter.release();
|
|
74127
74492
|
if (finalizationError !== undefined)
|
|
74128
74493
|
throwFinalizationError(finalizationError.error);
|
|
@@ -74286,7 +74651,8 @@ function createStageContext(input) {
|
|
|
74286
74651
|
recordStageNotice({ kind: "abort", to: "interrupted" });
|
|
74287
74652
|
await innerCtx.abort();
|
|
74288
74653
|
},
|
|
74289
|
-
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
|
|
74654
|
+
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
|
|
74655
|
+
__releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
|
|
74290
74656
|
};
|
|
74291
74657
|
}
|
|
74292
74658
|
|
|
@@ -75975,10 +76341,10 @@ function isRetryableSameCandidateFailure(error) {
|
|
|
75975
76341
|
return isTransientExtensionStartupFailure(error);
|
|
75976
76342
|
return isRetryableSameModelFailure(error);
|
|
75977
76343
|
}
|
|
75978
|
-
function mayAdvanceToNextCandidate(error) {
|
|
76344
|
+
function mayAdvanceToNextCandidate(error, options) {
|
|
75979
76345
|
if (isExtensionStartupFailure(error))
|
|
75980
76346
|
return isTransientExtensionStartupFailure(error);
|
|
75981
|
-
return isRetryableModelFailure(error);
|
|
76347
|
+
return isRetryableModelFailure(error, options);
|
|
75982
76348
|
}
|
|
75983
76349
|
function hasMeaningfulUsage(usage) {
|
|
75984
76350
|
if (usage === undefined)
|
|
@@ -76070,6 +76436,7 @@ class StageSessionController {
|
|
|
76070
76436
|
structuredOutputExecutionFailureValue;
|
|
76071
76437
|
structuredOutputCycleAttemptMark;
|
|
76072
76438
|
unsubscribeTerminateWatcher;
|
|
76439
|
+
unbindAbortSignal;
|
|
76073
76440
|
sessionInternalRetries = 0;
|
|
76074
76441
|
unresolvedContextOverflowMessage;
|
|
76075
76442
|
generationSealed = false;
|
|
@@ -76559,6 +76926,8 @@ class StageSessionController {
|
|
|
76559
76926
|
this.pendingListeners.clear();
|
|
76560
76927
|
this.unsubscribeTerminateWatcher?.();
|
|
76561
76928
|
this.unsubscribeTerminateWatcher = undefined;
|
|
76929
|
+
this.unbindAbortSignal?.();
|
|
76930
|
+
this.unbindAbortSignal = undefined;
|
|
76562
76931
|
this.terminatingToolCallIds.clear();
|
|
76563
76932
|
this.messageAdmission.dispose();
|
|
76564
76933
|
this.deliveryActivity.dispose();
|
|
@@ -76653,8 +77022,10 @@ class StageSessionController {
|
|
|
76653
77022
|
};
|
|
76654
77023
|
if (signal.aborted)
|
|
76655
77024
|
onAbort();
|
|
76656
|
-
else
|
|
77025
|
+
else {
|
|
76657
77026
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
77027
|
+
this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
|
|
77028
|
+
}
|
|
76658
77029
|
}
|
|
76659
77030
|
markAbort(reason) {
|
|
76660
77031
|
this.abortGeneration += 1;
|
|
@@ -76681,6 +77052,9 @@ class StageSessionController {
|
|
|
76681
77052
|
state.controller.abort(reason);
|
|
76682
77053
|
this.thrownErrorRetryStates.clear();
|
|
76683
77054
|
}
|
|
77055
|
+
fallbackFailureOptions() {
|
|
77056
|
+
return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
|
|
77057
|
+
}
|
|
76684
77058
|
retrySettings() {
|
|
76685
77059
|
const managers = [
|
|
76686
77060
|
this.sessionSettingsManager,
|
|
@@ -76955,7 +77329,7 @@ class StageSessionController {
|
|
|
76955
77329
|
const errorSettingsManager = retrySettingsManagerFromError(error);
|
|
76956
77330
|
if (errorSettingsManager !== undefined)
|
|
76957
77331
|
this.sessionSettingsManager = errorSettingsManager;
|
|
76958
|
-
const retryableFailure = isRetryableModelFailure(error);
|
|
77332
|
+
const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
|
|
76959
77333
|
const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
|
|
76960
77334
|
recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
|
|
76961
77335
|
if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
|
|
@@ -77580,7 +77954,7 @@ class StageSessionController {
|
|
|
77580
77954
|
}
|
|
77581
77955
|
throw new WorkflowPromptModelFailure(terminalFailure);
|
|
77582
77956
|
} catch (err) {
|
|
77583
|
-
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
77957
|
+
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77584
77958
|
this.artifactCapture.settleAttempt(true);
|
|
77585
77959
|
const usage = this.takeAttemptUsage(resumedSession);
|
|
77586
77960
|
this.modelAttempts.push({
|
|
@@ -77602,7 +77976,7 @@ class StageSessionController {
|
|
|
77602
77976
|
...usage === undefined ? {} : { usage },
|
|
77603
77977
|
error: message
|
|
77604
77978
|
});
|
|
77605
|
-
if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
|
|
77979
|
+
if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77606
77980
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
77607
77981
|
this.pendingFallbackWarnings.length = 0;
|
|
77608
77982
|
this.notifyModelFallbackMetaChange();
|
|
@@ -77651,7 +78025,7 @@ class StageSessionController {
|
|
|
77651
78025
|
throw err;
|
|
77652
78026
|
const message = errorMessage3(err);
|
|
77653
78027
|
const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
|
|
77654
|
-
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
78028
|
+
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77655
78029
|
this.recordSuccessfulAttempt(candidate);
|
|
77656
78030
|
return "handled";
|
|
77657
78031
|
}
|
|
@@ -77668,7 +78042,7 @@ class StageSessionController {
|
|
|
77668
78042
|
if (walk !== undefined) {
|
|
77669
78043
|
this.recordCandidateFailure(walk, index, err, candidates);
|
|
77670
78044
|
nextIndex = undefined;
|
|
77671
|
-
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
|
|
78045
|
+
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
|
|
77672
78046
|
try {
|
|
77673
78047
|
nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
|
|
77674
78048
|
} catch (error) {
|
|
@@ -77681,7 +78055,7 @@ class StageSessionController {
|
|
|
77681
78055
|
}
|
|
77682
78056
|
}
|
|
77683
78057
|
}
|
|
77684
|
-
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
|
|
78058
|
+
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
|
|
77685
78059
|
await this.settleFailedCandidate();
|
|
77686
78060
|
return "throw";
|
|
77687
78061
|
}
|
|
@@ -77776,7 +78150,7 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
77776
78150
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
77777
78151
|
import { createHash as createHash5 } from "node:crypto";
|
|
77778
78152
|
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
77779
|
-
import { basename as basename5, dirname as
|
|
78153
|
+
import { basename as basename5, dirname as dirname16, isAbsolute as isAbsolute11, join as join31, resolve as resolve17 } from "node:path";
|
|
77780
78154
|
function normalizeMaxOutput2(maxOutput) {
|
|
77781
78155
|
return {
|
|
77782
78156
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -77839,7 +78213,7 @@ function formatByteSize(bytes) {
|
|
|
77839
78213
|
}
|
|
77840
78214
|
function transcriptPath(runId, outputPath) {
|
|
77841
78215
|
const digest = createHash5("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
77842
|
-
return
|
|
78216
|
+
return join31(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
77843
78217
|
}
|
|
77844
78218
|
function appendContent(lines, content) {
|
|
77845
78219
|
if (typeof content === "string") {
|
|
@@ -77884,7 +78258,7 @@ function renderTranscript(messages, fallbackOutput) {
|
|
|
77884
78258
|
`);
|
|
77885
78259
|
}
|
|
77886
78260
|
function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
|
|
77887
|
-
const absolutePath =
|
|
78261
|
+
const absolutePath = resolve17(outputPath);
|
|
77888
78262
|
const bytes = Buffer.byteLength(fullOutput, "utf8");
|
|
77889
78263
|
const lines = countLines(fullOutput);
|
|
77890
78264
|
const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
|
|
@@ -77899,8 +78273,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
|
|
|
77899
78273
|
return;
|
|
77900
78274
|
if (isAbsolute11(output))
|
|
77901
78275
|
return output;
|
|
77902
|
-
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd :
|
|
77903
|
-
return
|
|
78276
|
+
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve17(runtimeCwd, requestedCwd);
|
|
78277
|
+
return resolve17(baseCwd, output);
|
|
77904
78278
|
}
|
|
77905
78279
|
function degenerateWarning(fullOutput) {
|
|
77906
78280
|
return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
|
|
@@ -77959,7 +78333,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
77959
78333
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
77960
78334
|
const transcript = renderTranscript(messages, fullOutput);
|
|
77961
78335
|
try {
|
|
77962
|
-
await mkdir7(
|
|
78336
|
+
await mkdir7(dirname16(outputPath), { recursive: true });
|
|
77963
78337
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
77964
78338
|
} catch (err) {
|
|
77965
78339
|
return `${displayOutput}
|
|
@@ -77971,7 +78345,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
77971
78345
|
let transcriptError;
|
|
77972
78346
|
try {
|
|
77973
78347
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
77974
|
-
await mkdir7(
|
|
78348
|
+
await mkdir7(dirname16(transcriptFile), { recursive: true });
|
|
77975
78349
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
77976
78350
|
transcriptAvailable = true;
|
|
77977
78351
|
} catch (err) {
|
|
@@ -78482,7 +78856,8 @@ function createWorkflowStageFactory(input) {
|
|
|
78482
78856
|
stageFinalized: false,
|
|
78483
78857
|
sessionCheckpointed: false,
|
|
78484
78858
|
skippedForParallelFailFast: false,
|
|
78485
|
-
stageControlDropped: false
|
|
78859
|
+
stageControlDropped: false,
|
|
78860
|
+
contextUnreachable: false
|
|
78486
78861
|
};
|
|
78487
78862
|
const activeAskUserQuestionCalls = new Set;
|
|
78488
78863
|
const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
|
|
@@ -78728,9 +79103,18 @@ function createWorkflowStageFactory(input) {
|
|
|
78728
79103
|
hasContinuation: input.opts.continuation !== undefined,
|
|
78729
79104
|
hasScopedParents: stageFailFastScope?.parentIds !== undefined
|
|
78730
79105
|
});
|
|
78731
|
-
|
|
79106
|
+
const context = createStageContext({ runtime, runTrackedStageCall });
|
|
79107
|
+
unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
|
|
79108
|
+
return context;
|
|
79109
|
+
};
|
|
79110
|
+
}
|
|
79111
|
+
function releaseWhenUnreachable(state, registry, runId, stageId) {
|
|
79112
|
+
return () => {
|
|
79113
|
+
state.contextUnreachable = true;
|
|
79114
|
+
registry.releaseIdle(runId, stageId);
|
|
78732
79115
|
};
|
|
78733
79116
|
}
|
|
79117
|
+
var unreachableStageContexts;
|
|
78734
79118
|
var init_executor_stage_factory = __esm(() => {
|
|
78735
79119
|
init_intercom_group();
|
|
78736
79120
|
init_pending_stage_route_readiness();
|
|
@@ -78745,6 +79129,7 @@ var init_executor_stage_factory = __esm(() => {
|
|
|
78745
79129
|
init_pending_stage_delivery2();
|
|
78746
79130
|
init_stage_runner();
|
|
78747
79131
|
init_stage_runner_session();
|
|
79132
|
+
unreachableStageContexts = new FinalizationRegistry((release) => release());
|
|
78748
79133
|
});
|
|
78749
79134
|
|
|
78750
79135
|
// dist/builtin/workflows/src/engine/runtime.ts
|
|
@@ -79086,7 +79471,7 @@ async function executeRun(def, resolvedInputs, opts) {
|
|
|
79086
79471
|
const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
|
|
79087
79472
|
const tracker = new GraphFrontierTracker;
|
|
79088
79473
|
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
79089
|
-
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
|
|
79474
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
|
|
79090
79475
|
const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
|
|
79091
79476
|
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
79092
79477
|
let workflowCwd;
|
|
@@ -80185,8 +80570,8 @@ var init_workflows_host_module = __esm(() => {
|
|
|
80185
80570
|
|
|
80186
80571
|
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
80187
80572
|
import { createHash as createHash6, randomUUID as randomUUID22 } from "node:crypto";
|
|
80188
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
80189
|
-
import { basename as basename6, dirname as
|
|
80573
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
|
|
80574
|
+
import { basename as basename6, dirname as dirname17, join as join32, resolve as resolve18 } from "node:path";
|
|
80190
80575
|
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
80191
80576
|
function encodeOption(value2) {
|
|
80192
80577
|
if (typeof value2 === "bigint")
|
|
@@ -80208,7 +80593,7 @@ function isReopenableSelection(selection) {
|
|
|
80208
80593
|
}
|
|
80209
80594
|
function encodeSelection(selection) {
|
|
80210
80595
|
if (selection.kind === "sqlite")
|
|
80211
|
-
return JSON.stringify({ ...selection, path:
|
|
80596
|
+
return JSON.stringify({ ...selection, path: resolve18(selection.path) });
|
|
80212
80597
|
return JSON.stringify({
|
|
80213
80598
|
...selection,
|
|
80214
80599
|
...selection.options === undefined ? {} : {
|
|
@@ -80240,7 +80625,7 @@ function openDurableJournal(durable) {
|
|
|
80240
80625
|
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
80241
80626
|
}
|
|
80242
80627
|
function poolStateDirectory(agentDir) {
|
|
80243
|
-
return
|
|
80628
|
+
return join32(dirname17(agentDir), "workflows", "pool");
|
|
80244
80629
|
}
|
|
80245
80630
|
function databaseIdentity(selection, agentDir) {
|
|
80246
80631
|
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
@@ -80248,16 +80633,16 @@ function databaseIdentity(selection, agentDir) {
|
|
|
80248
80633
|
function coordinationPath(durable) {
|
|
80249
80634
|
const selection = decodeSelection(durable.selection);
|
|
80250
80635
|
const identity = createHash6("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
80251
|
-
return
|
|
80636
|
+
return join32(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
80252
80637
|
}
|
|
80253
80638
|
function coordinationDatabase(durable) {
|
|
80254
80639
|
return basename6(coordinationPath(durable), ".sqlite");
|
|
80255
80640
|
}
|
|
80256
80641
|
function openCoordinationJournal(path) {
|
|
80257
|
-
const file =
|
|
80642
|
+
const file = resolve18(path);
|
|
80258
80643
|
let opened = coordinationJournals.get(file);
|
|
80259
80644
|
if (opened === undefined) {
|
|
80260
|
-
|
|
80645
|
+
mkdirSync9(dirname17(file), { recursive: true });
|
|
80261
80646
|
opened = resolveRunJournal({ journal: { path: file } });
|
|
80262
80647
|
coordinationJournals.set(file, opened);
|
|
80263
80648
|
opened.catch(() => {
|
|
@@ -80274,20 +80659,20 @@ function poolJournalFor(journal) {
|
|
|
80274
80659
|
return coordinations.get(journal) ?? journal;
|
|
80275
80660
|
}
|
|
80276
80661
|
function poolHostId(agentDir) {
|
|
80277
|
-
const file =
|
|
80662
|
+
const file = join32(poolStateDirectory(agentDir), "host-id");
|
|
80278
80663
|
try {
|
|
80279
|
-
const existing =
|
|
80664
|
+
const existing = readFileSync8(file, "utf8").trim();
|
|
80280
80665
|
if (existing !== "")
|
|
80281
80666
|
return existing;
|
|
80282
80667
|
} catch {}
|
|
80283
|
-
|
|
80668
|
+
mkdirSync9(dirname17(file), { recursive: true });
|
|
80284
80669
|
const id = randomUUID22();
|
|
80285
80670
|
try {
|
|
80286
|
-
|
|
80671
|
+
writeFileSync7(file, `${id}
|
|
80287
80672
|
`, { flag: "wx" });
|
|
80288
80673
|
return id;
|
|
80289
80674
|
} catch {
|
|
80290
|
-
return
|
|
80675
|
+
return readFileSync8(file, "utf8").trim();
|
|
80291
80676
|
}
|
|
80292
80677
|
}
|
|
80293
80678
|
var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
|
|
@@ -80310,7 +80695,6 @@ init_run();
|
|
|
80310
80695
|
init_run_tool_control_registry();
|
|
80311
80696
|
init_workflow_tool_abort();
|
|
80312
80697
|
init_wiring();
|
|
80313
|
-
init_pending_stage_delivery2();
|
|
80314
80698
|
init_stage_control_registry();
|
|
80315
80699
|
init_stage_queued_user_messages();
|
|
80316
80700
|
init_stage_ui_broker();
|
|
@@ -80336,6 +80720,94 @@ function poolWorkerCommit(input) {
|
|
|
80336
80720
|
return receipt;
|
|
80337
80721
|
};
|
|
80338
80722
|
}
|
|
80723
|
+
// dist/builtin/workflows/src/workers/pooled-stage-delivery.ts
|
|
80724
|
+
init_pending_stage_delivery2();
|
|
80725
|
+
init_pending_stage_delivery();
|
|
80726
|
+
init_store_pending_stage_delivery_methods();
|
|
80727
|
+
function pooledStageQueuedEntries(journal, store, root, stage) {
|
|
80728
|
+
const messages = journal.getWorkflow(root)?.pendingStageMessages ?? [];
|
|
80729
|
+
const runs = store.runs();
|
|
80730
|
+
const run = runs.find((candidate) => candidate.id === stage.runId);
|
|
80731
|
+
if (run === undefined)
|
|
80732
|
+
return [];
|
|
80733
|
+
const exact = new Set;
|
|
80734
|
+
for (const key of new Set([stage.stageId, stage.stageName]))
|
|
80735
|
+
for (const entry of pendingStageMessagesFor(messages, stage.runId, key, resolvePendingStageIdentity(run, key)))
|
|
80736
|
+
exact.add(entry);
|
|
80737
|
+
const hops = pooledStageHops(journal, runs, root, stage.runId);
|
|
80738
|
+
const sticky = hops === undefined ? [] : messages.filter((entry) => entry.runId === root && stickyEntryTargetsStage(entry, root, hops, stage.stageId, stage.stageName));
|
|
80739
|
+
return [
|
|
80740
|
+
...[...exact].map((entry) => ({ entry, index: messages.indexOf(entry) })),
|
|
80741
|
+
...sticky.map((entry) => ({ entry, index: Number.MAX_SAFE_INTEGER }))
|
|
80742
|
+
].map(({ entry, index }) => ({ entry, index, order: pendingStageMessageAdmissionOrder(entry) })).sort((left, right) => left.order - right.order || left.index - right.index).map(({ entry }) => entry);
|
|
80743
|
+
}
|
|
80744
|
+
function pooledStageHops(journal, runs, root, runId) {
|
|
80745
|
+
const byId = new Map(runs.map((run) => [run.id, run]));
|
|
80746
|
+
const hops = [];
|
|
80747
|
+
let current = byId.get(runId);
|
|
80748
|
+
while (current !== undefined && current.parentRunId !== root) {
|
|
80749
|
+
const child = current;
|
|
80750
|
+
const parent = child.parentRunId === undefined ? undefined : byId.get(child.parentRunId);
|
|
80751
|
+
const boundary = parent?.stages.find((stage) => stage.id === child.parentStageId);
|
|
80752
|
+
if (parent === undefined || boundary === undefined)
|
|
80753
|
+
return;
|
|
80754
|
+
hops.unshift({ name: boundary.name, runId: child.id });
|
|
80755
|
+
current = parent;
|
|
80756
|
+
}
|
|
80757
|
+
if (current === undefined)
|
|
80758
|
+
return;
|
|
80759
|
+
const childRunId = current.id;
|
|
80760
|
+
const boundary = journal.listCheckpoints(root).find((checkpoint) => checkpoint.kind === "stage" && checkpoint.topology?.boundary?.child.runId === childRunId);
|
|
80761
|
+
if (boundary === undefined)
|
|
80762
|
+
return;
|
|
80763
|
+
hops.unshift({ name: boundary.name, runId: childRunId });
|
|
80764
|
+
return hops;
|
|
80765
|
+
}
|
|
80766
|
+
function createPooledStageDelivery(options) {
|
|
80767
|
+
const admissions = new Map;
|
|
80768
|
+
const sinks = new Map;
|
|
80769
|
+
return {
|
|
80770
|
+
routeCapability: options.routeCapability,
|
|
80771
|
+
async deliverPending(deliver, recipient) {
|
|
80772
|
+
const sessionId = recipient?.sessionId ?? "";
|
|
80773
|
+
sinks.set(sessionId, deliver);
|
|
80774
|
+
let admitted = admissions.get(sessionId);
|
|
80775
|
+
if (admitted === undefined) {
|
|
80776
|
+
admitted = new Map;
|
|
80777
|
+
admissions.set(sessionId, admitted);
|
|
80778
|
+
}
|
|
80779
|
+
const held = admitted;
|
|
80780
|
+
for (const id of recipient?.receivedMessageIds ?? [])
|
|
80781
|
+
if (!held.has(id))
|
|
80782
|
+
held.set(id, Promise.resolve());
|
|
80783
|
+
const admit = (from, message) => {
|
|
80784
|
+
const existing = held.get(message.id);
|
|
80785
|
+
if (existing !== undefined)
|
|
80786
|
+
return existing;
|
|
80787
|
+
const sink = sinks.get(sessionId) ?? deliver;
|
|
80788
|
+
const delivery = Promise.resolve().then(() => sink(from, message));
|
|
80789
|
+
held.set(message.id, delivery);
|
|
80790
|
+
delivery.catch(() => {
|
|
80791
|
+
if (held.get(message.id) === delivery)
|
|
80792
|
+
held.delete(message.id);
|
|
80793
|
+
});
|
|
80794
|
+
return delivery;
|
|
80795
|
+
};
|
|
80796
|
+
try {
|
|
80797
|
+
for (const entry of await options.queued())
|
|
80798
|
+
await admit(toPendingStageSender(entry), entry.message);
|
|
80799
|
+
} catch {}
|
|
80800
|
+
const deliveries = [...held];
|
|
80801
|
+
const settled = await Promise.allSettled(deliveries.map(([, delivery]) => delivery));
|
|
80802
|
+
const receivedMessageIds = deliveries.flatMap(([id], index) => settled[index]?.status === "fulfilled" ? [id] : []);
|
|
80803
|
+
options.forward({ sessionId, receivedMessageIds }, admit).catch(() => {});
|
|
80804
|
+
},
|
|
80805
|
+
ready() {
|
|
80806
|
+
return;
|
|
80807
|
+
},
|
|
80808
|
+
fail: options.fail
|
|
80809
|
+
};
|
|
80810
|
+
}
|
|
80339
80811
|
|
|
80340
80812
|
// dist/builtin/workflows/src/workers/local-worker.ts
|
|
80341
80813
|
init_pooled_watch_trace();
|
|
@@ -81470,25 +81942,18 @@ async function runWorker(start) {
|
|
|
81470
81942
|
const capability = await request({ kind: "route", runId: meta.runId });
|
|
81471
81943
|
if (typeof capability !== "string")
|
|
81472
81944
|
throw new Error("Worker root route is unavailable");
|
|
81473
|
-
const pendingStageDelivery = {
|
|
81945
|
+
const pendingStageDelivery = createPooledStageDelivery({
|
|
81474
81946
|
routeCapability: capability,
|
|
81475
|
-
async
|
|
81476
|
-
await
|
|
81477
|
-
|
|
81478
|
-
progress();
|
|
81479
|
-
try {
|
|
81480
|
-
await deliver(from, message);
|
|
81481
|
-
} finally {
|
|
81482
|
-
progress();
|
|
81483
|
-
}
|
|
81484
|
-
}).then(() => {}));
|
|
81947
|
+
queued: async () => {
|
|
81948
|
+
await reader.catchUpWorkflow(start.root);
|
|
81949
|
+
return pooledStageQueuedEntries(reader, store, start.root, identity);
|
|
81485
81950
|
},
|
|
81486
|
-
async
|
|
81951
|
+
forward: async (recipient, deliver) => {
|
|
81487
81952
|
await publication;
|
|
81488
|
-
await request({ kind: "delivery
|
|
81953
|
+
await request({ kind: "delivery", ...identity, recipient }, deliver);
|
|
81489
81954
|
},
|
|
81490
81955
|
fail: options.orchestrationContext.pendingStageDelivery.fail
|
|
81491
|
-
};
|
|
81956
|
+
});
|
|
81492
81957
|
return baseAdapter.create({ ...options, orchestrationContext: { ...options.orchestrationContext, pendingStageDelivery } }, meta);
|
|
81493
81958
|
}
|
|
81494
81959
|
};
|
|
@@ -81504,7 +81969,18 @@ async function runWorker(start) {
|
|
|
81504
81969
|
const resourceAdmission = {
|
|
81505
81970
|
async acquire(kind, signal, requestOptions) {
|
|
81506
81971
|
await awaitAdmission(signal);
|
|
81507
|
-
|
|
81972
|
+
if (!admission)
|
|
81973
|
+
return async () => {};
|
|
81974
|
+
try {
|
|
81975
|
+
return await admission.acquire(kind, signal, requestOptions);
|
|
81976
|
+
} catch (error) {
|
|
81977
|
+
if (error instanceof QuarantinedCapacityError && !attemptFenced) {
|
|
81978
|
+
poolFault = error.message;
|
|
81979
|
+
attemptFenced = true;
|
|
81980
|
+
controller.abort(new WorkAttemptFencedError(error.message));
|
|
81981
|
+
}
|
|
81982
|
+
throw error;
|
|
81983
|
+
}
|
|
81508
81984
|
}
|
|
81509
81985
|
};
|
|
81510
81986
|
const admitted = admittedSessionAdapter(adapter, resourceAdmission, async (signal) => {
|