@bastani/atomic 0.9.61-alpha.1 → 0.9.61-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -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 +779 -409
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +844 -419
- package/dist/builtin/workflows/src/index.js +749 -384
- package/dist/builtin/workflows/src/local-worker-entry.mjs +844 -419
- 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/remote-renderer.d.ts +27 -5
- package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +76 -16
- package/dist/modes/interactive-engine/remote-renderer.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 +3 -3
- 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
|
|
14227
|
+
};
|
|
14228
|
+
}
|
|
14229
|
+
function containedWorktreeCwd(checkout, relativeCwd) {
|
|
14230
|
+
const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
|
|
14231
|
+
let resolved;
|
|
14232
|
+
try {
|
|
14233
|
+
resolved = fs4.realpathSync.native(cwd);
|
|
14234
|
+
} catch {
|
|
14235
|
+
resolved = "";
|
|
14236
|
+
}
|
|
14237
|
+
const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
|
|
14238
|
+
if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
|
|
14239
|
+
throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
|
|
14240
|
+
}
|
|
14241
|
+
return cwd;
|
|
14242
|
+
}
|
|
14243
|
+
function allocatedGitWorktreeSetup(checkout, repository, created) {
|
|
14244
|
+
return {
|
|
14245
|
+
result: {
|
|
14246
|
+
worktreeRoot: checkout,
|
|
14247
|
+
cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
|
|
14248
|
+
repositoryRoot: repository.root,
|
|
14249
|
+
created
|
|
14250
|
+
},
|
|
14251
|
+
invokingRoot: repository.root
|
|
14019
14252
|
};
|
|
14020
14253
|
}
|
|
14254
|
+
function validateOwnedGitWorktree(checkout, repository) {
|
|
14255
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14256
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14257
|
+
if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
|
|
14258
|
+
throw new Error(`${checkout} is not a linked worktree`);
|
|
14259
|
+
}
|
|
14260
|
+
const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
|
|
14261
|
+
if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
|
|
14262
|
+
throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
|
|
14263
|
+
}
|
|
14264
|
+
}
|
|
14265
|
+
function findOwnedGitWorktree(root, repository, ownerRunId) {
|
|
14266
|
+
const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
|
|
14267
|
+
if (checkout === undefined)
|
|
14268
|
+
return;
|
|
14269
|
+
try {
|
|
14270
|
+
validateOwnedGitWorktree(checkout, repository);
|
|
14271
|
+
return allocatedGitWorktreeSetup(checkout, repository, false);
|
|
14272
|
+
} catch (error) {
|
|
14273
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14274
|
+
throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
|
|
14275
|
+
}
|
|
14276
|
+
}
|
|
14277
|
+
function allocateGitWorktree(request, ownerRunId) {
|
|
14278
|
+
const { target: root } = request;
|
|
14279
|
+
const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
|
|
14280
|
+
if (ownerRunId !== undefined) {
|
|
14281
|
+
const owned = findOwnedGitWorktree(root, repository, ownerRunId);
|
|
14282
|
+
if (owned !== undefined)
|
|
14283
|
+
return owned;
|
|
14284
|
+
}
|
|
14285
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
14286
|
+
const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
|
|
14287
|
+
const commit = revision.status === 0 ? revision.stdout.trim() : "";
|
|
14288
|
+
if (commit === "") {
|
|
14289
|
+
throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
|
|
14290
|
+
}
|
|
14291
|
+
const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
|
|
14292
|
+
const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
|
|
14293
|
+
if (add.status !== 0) {
|
|
14294
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14295
|
+
throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
|
|
14296
|
+
}
|
|
14297
|
+
try {
|
|
14298
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14299
|
+
runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
|
|
14300
|
+
runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
|
|
14301
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14302
|
+
const setup = allocatedGitWorktreeSetup(checkout, repository, true);
|
|
14303
|
+
if (ownerRunId !== undefined)
|
|
14304
|
+
bindWorktreeOwner(gitDir, ownerRunId);
|
|
14305
|
+
return setup;
|
|
14306
|
+
} catch (error) {
|
|
14307
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14308
|
+
const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
|
|
14309
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14310
|
+
const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
|
|
14311
|
+
throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
|
|
14312
|
+
}
|
|
14313
|
+
}
|
|
14314
|
+
function runGitOrThrow(cwd, args) {
|
|
14315
|
+
const result = runGit(cwd, args);
|
|
14316
|
+
if (result.status !== 0)
|
|
14317
|
+
throw new Error(gitFailureMessage(result));
|
|
14318
|
+
}
|
|
14319
|
+
function setupGitWorktree(options) {
|
|
14320
|
+
return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
|
|
14321
|
+
}
|
|
14021
14322
|
var init_worktree_git = __esm(() => {
|
|
14323
|
+
init_worktree_allocation();
|
|
14022
14324
|
init_worktree_generation();
|
|
14023
14325
|
init_worktree_git_runner();
|
|
14024
14326
|
init_worktree_root();
|
|
14327
|
+
init_worktree_allocation();
|
|
14025
14328
|
init_worktree_git_runner();
|
|
14026
14329
|
});
|
|
14027
14330
|
|
|
14028
14331
|
// dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
|
|
14029
|
-
function createGitWorktreeSetupCacheOwner(suppliedCache) {
|
|
14030
|
-
const cache = suppliedCache ?? createGitWorktreeSetupCache();
|
|
14332
|
+
function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
|
|
14333
|
+
const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
|
|
14031
14334
|
const ownsCache = suppliedCache === undefined;
|
|
14032
14335
|
let released = false;
|
|
14033
14336
|
return {
|
|
@@ -14048,20 +14351,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
|
|
|
14048
14351
|
});
|
|
14049
14352
|
|
|
14050
14353
|
// dist/builtin/workflows/src/runs/shared/worktree-diff.ts
|
|
14051
|
-
import * as
|
|
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;
|
|
@@ -53663,10 +53970,10 @@ var init_verification_prompts = __esm(() => {
|
|
|
53663
53970
|
// dist/builtin/workflows/builtin/pattern-artifact-root.ts
|
|
53664
53971
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
53665
53972
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
53666
|
-
import { join as
|
|
53973
|
+
import { join as join13 } from "node:path";
|
|
53667
53974
|
async function stableArtifactRoot(ctx, workflowName) {
|
|
53668
53975
|
const cwd = ctx.cwd ?? process.cwd();
|
|
53669
|
-
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () =>
|
|
53976
|
+
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join13(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID8()}`));
|
|
53670
53977
|
await mkdir2(artifactDir, { recursive: true });
|
|
53671
53978
|
return artifactDir;
|
|
53672
53979
|
}
|
|
@@ -53706,7 +54013,7 @@ function fold_usage(results) {
|
|
|
53706
54013
|
|
|
53707
54014
|
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
53708
54015
|
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
53709
|
-
import { join as
|
|
54016
|
+
import { join as join14 } from "node:path";
|
|
53710
54017
|
import { Type as Type4 } from "typebox";
|
|
53711
54018
|
function isRecord3(value2) {
|
|
53712
54019
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -53801,8 +54108,8 @@ async function writeInvalid(path, stage) {
|
|
|
53801
54108
|
}
|
|
53802
54109
|
async function runAdversarialVerification(ctx) {
|
|
53803
54110
|
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
53804
|
-
const criteriaPath =
|
|
53805
|
-
const candidatePath =
|
|
54111
|
+
const criteriaPath = join14(root, "criteria.md");
|
|
54112
|
+
const candidatePath = join14(root, "candidate.md");
|
|
53806
54113
|
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
53807
54114
|
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
53808
54115
|
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
@@ -53834,7 +54141,7 @@ async function runAdversarialVerification(ctx) {
|
|
|
53834
54141
|
criterion,
|
|
53835
54142
|
verifierIndex: index + 1,
|
|
53836
54143
|
name,
|
|
53837
|
-
artifactPath:
|
|
54144
|
+
artifactPath: join14(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
53838
54145
|
});
|
|
53839
54146
|
}
|
|
53840
54147
|
}
|
|
@@ -53887,8 +54194,8 @@ async function runAdversarialVerification(ctx) {
|
|
|
53887
54194
|
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
53888
54195
|
finalDecision = decision;
|
|
53889
54196
|
finalMean = meanScore(scoreReports);
|
|
53890
|
-
scoreTablePath =
|
|
53891
|
-
reviewReportPath =
|
|
54197
|
+
scoreTablePath = join14(root, `verification-summary-${round}.json`);
|
|
54198
|
+
reviewReportPath = join14(root, `review-${round}.json`);
|
|
53892
54199
|
const summary = {
|
|
53893
54200
|
scores: scoreReports,
|
|
53894
54201
|
mean: finalMean,
|
|
@@ -54069,7 +54376,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
|
|
|
54069
54376
|
|
|
54070
54377
|
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
54071
54378
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
54072
|
-
import { join as
|
|
54379
|
+
import { join as join15 } from "node:path";
|
|
54073
54380
|
import { Type as Type6 } from "typebox";
|
|
54074
54381
|
function safeName(value2) {
|
|
54075
54382
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54109,7 +54416,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54109
54416
|
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
54110
54417
|
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
54111
54418
|
const category = fallback?.category ?? exactCategory;
|
|
54112
|
-
const classificationPath =
|
|
54419
|
+
const classificationPath = join15(artifactDir, "classification.json");
|
|
54113
54420
|
await writeFile2(classificationPath, JSON.stringify({
|
|
54114
54421
|
proposed_category: proposedCategory,
|
|
54115
54422
|
selected_category: category,
|
|
@@ -54119,7 +54426,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54119
54426
|
fallback_used: needsFallback,
|
|
54120
54427
|
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
54121
54428
|
}, null, 2));
|
|
54122
|
-
const actionPath =
|
|
54429
|
+
const actionPath = join15(artifactDir, `action-${safeName(category)}.md`);
|
|
54123
54430
|
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
54124
54431
|
tools: actionTools(category),
|
|
54125
54432
|
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
@@ -54259,7 +54566,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
|
|
|
54259
54566
|
|
|
54260
54567
|
// dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
|
|
54261
54568
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
54262
|
-
import { join as
|
|
54569
|
+
import { join as join16 } from "node:path";
|
|
54263
54570
|
import { Type as Type8 } from "typebox";
|
|
54264
54571
|
function safeName2(value2, index) {
|
|
54265
54572
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54290,9 +54597,9 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54290
54597
|
context: "fresh"
|
|
54291
54598
|
});
|
|
54292
54599
|
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
54293
|
-
const partitionPath =
|
|
54600
|
+
const partitionPath = join16(artifactDir, "partition-plan.json");
|
|
54294
54601
|
await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
54295
|
-
const branchPaths = partitions.map((partition, index) =>
|
|
54602
|
+
const branchPaths = partitions.map((partition, index) => join16(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
|
|
54296
54603
|
const steps = partitions.map((partition, index) => ({
|
|
54297
54604
|
name: `branch-${safeName2(partition.label, index)}`,
|
|
54298
54605
|
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
@@ -54302,13 +54609,13 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54302
54609
|
outputMode: "file-only"
|
|
54303
54610
|
}));
|
|
54304
54611
|
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
54305
|
-
const manifestPath =
|
|
54612
|
+
const manifestPath = join16(artifactDir, "manifest.json");
|
|
54306
54613
|
await writeFile3(manifestPath, JSON.stringify({
|
|
54307
54614
|
task: ctx.inputs.prompt,
|
|
54308
54615
|
partition_plan: partitionPath,
|
|
54309
54616
|
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
|
|
54310
54617
|
}, null, 2));
|
|
54311
|
-
const synthesisPath =
|
|
54618
|
+
const synthesisPath = join16(artifactDir, "synthesis.md");
|
|
54312
54619
|
const synthesis = await ctx.task("synthesize", {
|
|
54313
54620
|
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
54314
54621
|
context: "fresh",
|
|
@@ -54473,7 +54780,7 @@ var init_generate_and_filter_prompts = __esm(() => {
|
|
|
54473
54780
|
|
|
54474
54781
|
// dist/builtin/workflows/builtin/generate-and-filter-runner.ts
|
|
54475
54782
|
import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
54476
|
-
import { join as
|
|
54783
|
+
import { join as join17 } from "node:path";
|
|
54477
54784
|
import { Type as Type10 } from "typebox";
|
|
54478
54785
|
function isRecord4(value2) {
|
|
54479
54786
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -54492,7 +54799,7 @@ function judgeDecision(value2) {
|
|
|
54492
54799
|
}
|
|
54493
54800
|
async function runGenerateAndFilter(ctx) {
|
|
54494
54801
|
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
54495
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) =>
|
|
54802
|
+
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join17(root, `candidate-${index + 1}.md`));
|
|
54496
54803
|
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
54497
54804
|
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
54498
54805
|
name: `generate-${index + 1}`,
|
|
@@ -54501,9 +54808,9 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54501
54808
|
output: path,
|
|
54502
54809
|
outputMode: "file-only"
|
|
54503
54810
|
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
54504
|
-
const manifestPath =
|
|
54811
|
+
const manifestPath = join17(root, "manifest.json");
|
|
54505
54812
|
await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
54506
|
-
const filterPath =
|
|
54813
|
+
const filterPath = join17(root, "filter.json");
|
|
54507
54814
|
const filtered = await ctx.task("dedupe-and-filter", {
|
|
54508
54815
|
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
|
|
54509
54816
|
context: "fresh",
|
|
@@ -54520,7 +54827,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54520
54827
|
let judgePath = null;
|
|
54521
54828
|
let decisionPath = filterPath;
|
|
54522
54829
|
if (ctx.inputs.use_judge) {
|
|
54523
|
-
judgePath =
|
|
54830
|
+
judgePath = join17(root, "judge.json");
|
|
54524
54831
|
const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
|
|
54525
54832
|
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
54526
54833
|
const judged = await ctx.task("judge", {
|
|
@@ -54536,7 +54843,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54536
54843
|
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
54537
54844
|
decisionPath = judgePath;
|
|
54538
54845
|
}
|
|
54539
|
-
const finalPath =
|
|
54846
|
+
const finalPath = join17(root, "shortlist.md");
|
|
54540
54847
|
const finalShortlist = await ctx.task("final-shortlist", {
|
|
54541
54848
|
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
|
|
54542
54849
|
context: "fresh",
|
|
@@ -55065,7 +55372,7 @@ var init_review_convergence = __esm(() => {
|
|
|
55065
55372
|
|
|
55066
55373
|
// dist/builtin/workflows/builtin/goal-artifacts.ts
|
|
55067
55374
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
55068
|
-
import { join as
|
|
55375
|
+
import { join as join18 } from "node:path";
|
|
55069
55376
|
function artifactSafeName(value2) {
|
|
55070
55377
|
const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
55071
55378
|
return safe.length > 0 ? safe : "artifact";
|
|
@@ -55076,7 +55383,7 @@ function withoutTurn(value2) {
|
|
|
55076
55383
|
return copy;
|
|
55077
55384
|
}
|
|
55078
55385
|
async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
|
|
55079
|
-
const artifactPath =
|
|
55386
|
+
const artifactPath = join18(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
55080
55387
|
await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
|
|
55081
55388
|
`, { encoding: "utf8" });
|
|
55082
55389
|
return artifactPath;
|
|
@@ -55085,7 +55392,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
|
|
|
55085
55392
|
reviewer: review.reviewer,
|
|
55086
55393
|
findings: review.findings
|
|
55087
55394
|
}))), reverification = []) {
|
|
55088
|
-
const artifactPath =
|
|
55395
|
+
const artifactPath = join18(artifactDir, "review-round-latest.json");
|
|
55089
55396
|
const visibleReviews = reviews.map(withoutTurn);
|
|
55090
55397
|
await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
|
|
55091
55398
|
`, { encoding: "utf8" });
|
|
@@ -55315,7 +55622,7 @@ var init_goal_review = __esm(() => {
|
|
|
55315
55622
|
// dist/builtin/workflows/builtin/goal-ledger.ts
|
|
55316
55623
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
55317
55624
|
import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
55318
|
-
import { dirname as
|
|
55625
|
+
import { dirname as dirname10, join as join19 } from "node:path";
|
|
55319
55626
|
import { isDeepStrictEqual } from "node:util";
|
|
55320
55627
|
function withoutTurn2(value2) {
|
|
55321
55628
|
const copy = { ...value2 };
|
|
@@ -55340,7 +55647,7 @@ function modelVisibleLedger(ledger) {
|
|
|
55340
55647
|
};
|
|
55341
55648
|
}
|
|
55342
55649
|
function goalLedgerStatePath(ledgerPath) {
|
|
55343
|
-
return
|
|
55650
|
+
return join19(dirname10(ledgerPath), LEDGER_STATE_FILENAME);
|
|
55344
55651
|
}
|
|
55345
55652
|
function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
|
|
55346
55653
|
ledger.lifecycle.push({
|
|
@@ -55416,7 +55723,7 @@ function recoverLegacyExecutionInterruption(ledger) {
|
|
|
55416
55723
|
return true;
|
|
55417
55724
|
}
|
|
55418
55725
|
async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
|
|
55419
|
-
const ledgerPath =
|
|
55726
|
+
const ledgerPath = join19(artifactDir, LEDGER_FILENAME);
|
|
55420
55727
|
const existing = await readExistingGoalLedger(ledgerPath);
|
|
55421
55728
|
if (existing !== undefined) {
|
|
55422
55729
|
if (recoverLegacyExecutionInterruption(existing))
|
|
@@ -55923,7 +56230,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
|
|
|
55923
56230
|
});
|
|
55924
56231
|
|
|
55925
56232
|
// dist/builtin/workflows/builtin/goal-runner.ts
|
|
55926
|
-
import { join as
|
|
56233
|
+
import { join as join20 } from "node:path";
|
|
55927
56234
|
function positiveInteger(value2, fallback) {
|
|
55928
56235
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
|
|
55929
56236
|
return fallback;
|
|
@@ -55974,7 +56281,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
55974
56281
|
appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
|
|
55975
56282
|
await writeGoalLedger(ledgerPath, ledger);
|
|
55976
56283
|
}
|
|
55977
|
-
const orchestratorReceiptPath =
|
|
56284
|
+
const orchestratorReceiptPath = join20(artifactDir, "orchestrator-receipt.md");
|
|
55978
56285
|
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
|
|
55979
56286
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
|
|
55980
56287
|
ledger,
|
|
@@ -56045,7 +56352,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
56045
56352
|
const reviewerName = result.name ?? result.stageName;
|
|
56046
56353
|
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
56047
56354
|
const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
|
|
56048
|
-
const reviewArtifactPath =
|
|
56355
|
+
const reviewArtifactPath = join20(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
|
|
56049
56356
|
const record = reviewDecisionToRecord({
|
|
56050
56357
|
turn,
|
|
56051
56358
|
reviewer: normalizedReviewerName,
|
|
@@ -56248,7 +56555,7 @@ var init_goal = __esm(() => {
|
|
|
56248
56555
|
}),
|
|
56249
56556
|
git_worktree_dir: Type15.String({
|
|
56250
56557
|
default: "",
|
|
56251
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
56558
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
56252
56559
|
}),
|
|
56253
56560
|
create_pr: Type15.Boolean({
|
|
56254
56561
|
default: false,
|
|
@@ -56366,7 +56673,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
|
|
|
56366
56673
|
|
|
56367
56674
|
// dist/builtin/workflows/builtin/loop-until-done-runner.ts
|
|
56368
56675
|
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
56369
|
-
import { join as
|
|
56676
|
+
import { join as join21 } from "node:path";
|
|
56370
56677
|
import { Type as Type16 } from "typebox";
|
|
56371
56678
|
function progressCurve(entries) {
|
|
56372
56679
|
return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
|
|
@@ -56449,18 +56756,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
|
|
|
56449
56756
|
}
|
|
56450
56757
|
async function runLoopUntilDone(ctx) {
|
|
56451
56758
|
const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
|
|
56452
|
-
const iterationsDir =
|
|
56453
|
-
const evaluationsDir =
|
|
56759
|
+
const iterationsDir = join21(artifactDir, "iterations");
|
|
56760
|
+
const evaluationsDir = join21(artifactDir, "evaluations");
|
|
56454
56761
|
await mkdir3(iterationsDir, { recursive: true });
|
|
56455
56762
|
await mkdir3(evaluationsDir, { recursive: true });
|
|
56456
|
-
const ledgerPath =
|
|
56763
|
+
const ledgerPath = join21(artifactDir, "progress-ledger.json");
|
|
56457
56764
|
const entries = [];
|
|
56458
56765
|
const iterationArtifactPaths = [];
|
|
56459
56766
|
const evaluationArtifactPaths = [];
|
|
56460
56767
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
|
|
56461
56768
|
for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
|
|
56462
|
-
const iterationPath =
|
|
56463
|
-
const evaluationPath =
|
|
56769
|
+
const iterationPath = join21(iterationsDir, `iteration-${iteration}.md`);
|
|
56770
|
+
const evaluationPath = join21(evaluationsDir, `evaluation-${iteration}.json`);
|
|
56464
56771
|
iterationArtifactPaths.push(iterationPath);
|
|
56465
56772
|
evaluationArtifactPaths.push(evaluationPath);
|
|
56466
56773
|
await ctx.task(`iteration-${iteration}`, {
|
|
@@ -56509,7 +56816,7 @@ async function runLoopUntilDone(ctx) {
|
|
|
56509
56816
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
|
|
56510
56817
|
if (decision.done) {
|
|
56511
56818
|
const report = progressReport(entries);
|
|
56512
|
-
const resultPath =
|
|
56819
|
+
const resultPath = join21(artifactDir, "result.md");
|
|
56513
56820
|
const final = await ctx.task("completion-summary", {
|
|
56514
56821
|
prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
|
|
56515
56822
|
context: "fresh",
|
|
@@ -56626,9 +56933,9 @@ var init_loop_until_done = __esm(() => {
|
|
|
56626
56933
|
|
|
56627
56934
|
// dist/builtin/workflows/builtin/open-claude-design-utils.ts
|
|
56628
56935
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
56629
|
-
import { mkdirSync as
|
|
56936
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
56630
56937
|
import { tmpdir, userInfo } from "node:os";
|
|
56631
|
-
import { join as
|
|
56938
|
+
import { join as join22 } from "node:path";
|
|
56632
56939
|
import { Type as Type18 } from "typebox";
|
|
56633
56940
|
import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
|
|
56634
56941
|
function taggedPrompt3(sections) {
|
|
@@ -56671,32 +56978,32 @@ function tmpArtifactBase() {
|
|
|
56671
56978
|
try {
|
|
56672
56979
|
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
56673
56980
|
} catch {}
|
|
56674
|
-
return
|
|
56981
|
+
return join22(tmpdir(), `open-claude-design-${user}`);
|
|
56675
56982
|
}
|
|
56676
56983
|
function prepareArtifactDir(cwd = process.cwd()) {
|
|
56677
56984
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
56678
56985
|
const tmpCandidates = [
|
|
56679
|
-
|
|
56680
|
-
|
|
56986
|
+
join22(tmpArtifactBase(), runId),
|
|
56987
|
+
join22(tmpdir(), "open-claude-design", runId)
|
|
56681
56988
|
];
|
|
56682
|
-
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [
|
|
56989
|
+
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join22(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
56683
56990
|
for (const candidate of candidates) {
|
|
56684
56991
|
try {
|
|
56685
|
-
|
|
56992
|
+
mkdirSync6(candidate, { recursive: true });
|
|
56686
56993
|
return {
|
|
56687
56994
|
runId,
|
|
56688
56995
|
artifactDir: candidate,
|
|
56689
|
-
previewPath:
|
|
56690
|
-
specPath:
|
|
56996
|
+
previewPath: join22(candidate, "preview.html"),
|
|
56997
|
+
specPath: join22(candidate, "spec.html")
|
|
56691
56998
|
};
|
|
56692
56999
|
} catch {}
|
|
56693
57000
|
}
|
|
56694
|
-
const fallback =
|
|
57001
|
+
const fallback = join22(tmpArtifactBase(), runId);
|
|
56695
57002
|
return {
|
|
56696
57003
|
runId,
|
|
56697
57004
|
artifactDir: fallback,
|
|
56698
|
-
previewPath:
|
|
56699
|
-
specPath:
|
|
57005
|
+
previewPath: join22(fallback, "preview.html"),
|
|
57006
|
+
specPath: join22(fallback, "spec.html")
|
|
56700
57007
|
};
|
|
56701
57008
|
}
|
|
56702
57009
|
function ensureAgentBrowser() {
|
|
@@ -57030,8 +57337,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
|
|
|
57030
57337
|
});
|
|
57031
57338
|
|
|
57032
57339
|
// dist/builtin/workflows/builtin/open-claude-design-setup.ts
|
|
57033
|
-
import { mkdirSync as
|
|
57034
|
-
import { join as
|
|
57340
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
57341
|
+
import { join as join23 } from "node:path";
|
|
57035
57342
|
function renderDiscoveryContext(discovery) {
|
|
57036
57343
|
return [
|
|
57037
57344
|
`Confirmed design brief: ${discovery.brief}`,
|
|
@@ -57096,10 +57403,10 @@ async function runDiscoveryAndInit(args) {
|
|
|
57096
57403
|
};
|
|
57097
57404
|
}
|
|
57098
57405
|
function designContextPath(artifactDir) {
|
|
57099
|
-
return
|
|
57406
|
+
return join23(artifactDir, DESIGN_CONTEXT_FILENAME);
|
|
57100
57407
|
}
|
|
57101
57408
|
function referencesBriefPath(artifactDir) {
|
|
57102
|
-
return
|
|
57409
|
+
return join23(artifactDir, REFERENCES_BRIEF_FILENAME);
|
|
57103
57410
|
}
|
|
57104
57411
|
function buildReferenceDiscoveryPrompt(args) {
|
|
57105
57412
|
const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
|
|
@@ -57125,8 +57432,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57125
57432
|
[
|
|
57126
57433
|
"Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
|
|
57127
57434
|
"From each gallery, choose 1-3 fitting designs and CLICK INTO each actual live or project-detail page; do not capture only the grid or thumbnail.",
|
|
57128
|
-
`Capture motion across the entire page: start \`agent-browser record start ${
|
|
57129
|
-
`Also run \`agent-browser screenshot ${
|
|
57435
|
+
`Capture motion across the entire page: start \`agent-browser record start ${join23(args.artifactDir, "ref-<site>-<n>.webm")}\`, scroll smoothly in small increments with waits (using repeated \`agent-browser scroll down 600\` or \`agent-browser mouse wheel 600\`) so animations fire and lazy content loads, then run \`agent-browser record stop\`.`,
|
|
57436
|
+
`Also run \`agent-browser screenshot ${join23(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
|
|
57130
57437
|
"Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
|
|
57131
57438
|
"Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
|
|
57132
57439
|
"Use ask_user_question to ask which reference direction they prefer, offering 2-4 strongest options plus `None of these fit`. If none fit, ask them to provide a reference image, screenshot, URL, or local file path and record the answer.",
|
|
@@ -57151,8 +57458,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57151
57458
|
}
|
|
57152
57459
|
function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
|
|
57153
57460
|
try {
|
|
57154
|
-
|
|
57155
|
-
|
|
57461
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
57462
|
+
writeFileSync4(filePath, `${content}
|
|
57156
57463
|
`);
|
|
57157
57464
|
} catch (error) {
|
|
57158
57465
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -57703,7 +58010,7 @@ var init_ralph_review_gate = __esm(() => {
|
|
|
57703
58010
|
|
|
57704
58011
|
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
57705
58012
|
import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
|
|
57706
|
-
import { dirname as
|
|
58013
|
+
import { dirname as dirname11, join as join24 } from "node:path";
|
|
57707
58014
|
import { Type as Type20 } from "typebox";
|
|
57708
58015
|
function taggedPrompt4(sections) {
|
|
57709
58016
|
return sections.map(([tag, content]) => {
|
|
@@ -57743,11 +58050,11 @@ function slugifyResearchTopic(prompt) {
|
|
|
57743
58050
|
}
|
|
57744
58051
|
function defaultResearchPath(prompt, now = new Date) {
|
|
57745
58052
|
const date = now.toISOString().slice(0, 10);
|
|
57746
|
-
return
|
|
58053
|
+
return join24(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
57747
58054
|
}
|
|
57748
58055
|
async function createImplementationNotesFile(prompt, runId) {
|
|
57749
58056
|
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
57750
|
-
const notesPath =
|
|
58057
|
+
const notesPath = join24(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
57751
58058
|
const initialNotes = [
|
|
57752
58059
|
"# Implementation Notes",
|
|
57753
58060
|
"",
|
|
@@ -57768,7 +58075,7 @@ async function createImplementationNotesFile(prompt, runId) {
|
|
|
57768
58075
|
}
|
|
57769
58076
|
async function createQaEvidenceVideoPath(runId) {
|
|
57770
58077
|
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
57771
|
-
return
|
|
58078
|
+
return join24(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
57772
58079
|
}
|
|
57773
58080
|
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
57774
58081
|
return [
|
|
@@ -57834,7 +58141,7 @@ function artifactSafeName2(value2) {
|
|
|
57834
58141
|
return safe.length > 0 ? safe : "artifact";
|
|
57835
58142
|
}
|
|
57836
58143
|
async function writeJsonArtifact(path, content) {
|
|
57837
|
-
await mkdir4(
|
|
58144
|
+
await mkdir4(dirname11(path), { recursive: true });
|
|
57838
58145
|
await writeFile8(path, `${JSON.stringify(content, null, 2)}
|
|
57839
58146
|
`, {
|
|
57840
58147
|
encoding: "utf8"
|
|
@@ -58172,7 +58479,7 @@ var init_ralph_models = __esm(() => {
|
|
|
58172
58479
|
|
|
58173
58480
|
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
58174
58481
|
import { existsSync as existsSync4 } from "node:fs";
|
|
58175
|
-
import { join as
|
|
58482
|
+
import { join as join25, resolve as resolve10 } from "node:path";
|
|
58176
58483
|
async function runRalphWorkflow(ctx, options) {
|
|
58177
58484
|
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
58178
58485
|
let latestReviewReportPath;
|
|
@@ -58184,7 +58491,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58184
58491
|
let finalPrReport;
|
|
58185
58492
|
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
58186
58493
|
const workflowPrompt = prompt;
|
|
58187
|
-
const workflowResearchPath =
|
|
58494
|
+
const workflowResearchPath = resolve10(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
58188
58495
|
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
58189
58496
|
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
58190
58497
|
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
@@ -58233,7 +58540,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58233
58540
|
const researchPath = workflowResearchPath;
|
|
58234
58541
|
finalResearchPath = researchPath;
|
|
58235
58542
|
finalPlanPath = researchPath;
|
|
58236
|
-
const orchestratorReportPath =
|
|
58543
|
+
const orchestratorReportPath = join25(artifactDir, "orchestrator-report.md");
|
|
58237
58544
|
const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
|
|
58238
58545
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
|
|
58239
58546
|
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
@@ -58369,7 +58676,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58369
58676
|
diagnostics: parsed.diagnostics,
|
|
58370
58677
|
allowFinalActionRemaining: createPr
|
|
58371
58678
|
});
|
|
58372
|
-
const artifactPath =
|
|
58679
|
+
const artifactPath = join25(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
|
|
58373
58680
|
await writeJsonArtifact(artifactPath, {
|
|
58374
58681
|
reviewer,
|
|
58375
58682
|
decision: parsed.decision,
|
|
@@ -58425,7 +58732,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58425
58732
|
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
58426
58733
|
}));
|
|
58427
58734
|
}
|
|
58428
|
-
latestReviewReportPath = await writeJsonArtifact(
|
|
58735
|
+
latestReviewReportPath = await writeJsonArtifact(join25(artifactDir, "review-round-latest.json"), {
|
|
58429
58736
|
convergence_decision: roundConvergenceDecision,
|
|
58430
58737
|
convergence: convergenceEntries,
|
|
58431
58738
|
consolidated_findings: reverified.batch,
|
|
@@ -58574,7 +58881,7 @@ var init_ralph = __esm(() => {
|
|
|
58574
58881
|
}),
|
|
58575
58882
|
git_worktree_dir: Type21.String({
|
|
58576
58883
|
default: "",
|
|
58577
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
58884
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
58578
58885
|
}),
|
|
58579
58886
|
create_pr: Type21.Boolean({
|
|
58580
58887
|
default: false,
|
|
@@ -58794,7 +59101,7 @@ var init_tournament_prompts = __esm(() => {
|
|
|
58794
59101
|
|
|
58795
59102
|
// dist/builtin/workflows/builtin/tournament-runner.ts
|
|
58796
59103
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
|
|
58797
|
-
import { join as
|
|
59104
|
+
import { join as join26, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve11 } from "node:path";
|
|
58798
59105
|
import { Type as Type22 } from "typebox";
|
|
58799
59106
|
function serializableObject2(value2) {
|
|
58800
59107
|
if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
|
|
@@ -58831,8 +59138,8 @@ function criterionSlug(id) {
|
|
|
58831
59138
|
}
|
|
58832
59139
|
function judgeArtifactPath(judgesDir, job, criterionIndex) {
|
|
58833
59140
|
const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
|
|
58834
|
-
const root =
|
|
58835
|
-
const path =
|
|
59141
|
+
const root = resolve11(judgesDir);
|
|
59142
|
+
const path = resolve11(judgesDir, filename);
|
|
58836
59143
|
const fromRoot = relative5(root, path);
|
|
58837
59144
|
if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
|
|
58838
59145
|
throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
|
|
@@ -58883,16 +59190,16 @@ function combineUsage(totals) {
|
|
|
58883
59190
|
}
|
|
58884
59191
|
async function runTournament(ctx) {
|
|
58885
59192
|
const artifactDir = await stableArtifactRoot(ctx, "tournament");
|
|
58886
|
-
const attemptsDir =
|
|
59193
|
+
const attemptsDir = join26(artifactDir, "attempts");
|
|
58887
59194
|
const numAttempts = ctx.inputs.num_attempts ?? 4;
|
|
58888
59195
|
const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
|
|
58889
59196
|
const nEvaluations = ctx.inputs.n_evaluations ?? 2;
|
|
58890
59197
|
const pivotCount = ctx.inputs.pivots ?? 1;
|
|
58891
59198
|
const seed = ctx.inputs.seed ?? 0;
|
|
58892
|
-
const judgesDir =
|
|
59199
|
+
const judgesDir = join26(artifactDir, "judges");
|
|
58893
59200
|
await mkdir5(attemptsDir, { recursive: true });
|
|
58894
59201
|
await mkdir5(judgesDir, { recursive: true });
|
|
58895
|
-
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
|
|
59202
|
+
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join26(attemptsDir, `attempt-${index + 1}.md`));
|
|
58896
59203
|
const models = ctx.inputs.models;
|
|
58897
59204
|
const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
|
|
58898
59205
|
name: `attempt-${index + 1}`,
|
|
@@ -59057,7 +59364,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59057
59364
|
const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
|
|
59058
59365
|
const budgetPivots = Math.min(pivotCount, entrants.length);
|
|
59059
59366
|
const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
|
|
59060
|
-
const comparisonPath =
|
|
59367
|
+
const comparisonPath = join26(artifactDir, "comparisons.json");
|
|
59061
59368
|
const assignment = modelAssignment(entrants, models);
|
|
59062
59369
|
const phaseUsage = {
|
|
59063
59370
|
attempts: fold_usage(attemptResults),
|
|
@@ -59093,7 +59400,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59093
59400
|
await writeLedger(fold_usage([]));
|
|
59094
59401
|
const winner = ranking[0];
|
|
59095
59402
|
const winnerEntrant = entrants[winner.index];
|
|
59096
|
-
const resultPath =
|
|
59403
|
+
const resultPath = join26(artifactDir, "winner.md");
|
|
59097
59404
|
const reducer = await ctx.task("comparisons-reducer", {
|
|
59098
59405
|
prompt: renderComparisonsReducerPrompt({
|
|
59099
59406
|
task: ctx.inputs.prompt,
|
|
@@ -59999,7 +60306,7 @@ class SqlPoolQueue {
|
|
|
59999
60306
|
throw new Error("Stale pool coordinator authority", { cause: error });
|
|
60000
60307
|
throw error;
|
|
60001
60308
|
});
|
|
60002
|
-
const row = await this.current(tx, lease, token);
|
|
60309
|
+
const row = await this.current(tx, lease, token, true);
|
|
60003
60310
|
if (row.epoch !== lease.epoch)
|
|
60004
60311
|
throw new Error(STALE_WORK_LEASE);
|
|
60005
60312
|
assertSession();
|
|
@@ -62233,7 +62540,7 @@ function isBrokerStatusReport(value2) {
|
|
|
62233
62540
|
|
|
62234
62541
|
// dist/builtin/intercom/broker/paths.ts
|
|
62235
62542
|
import { homedir as homedir2 } from "os";
|
|
62236
|
-
import { join as
|
|
62543
|
+
import { join as join27 } from "path";
|
|
62237
62544
|
function getHomeDir() {
|
|
62238
62545
|
if (process.platform === "win32") {
|
|
62239
62546
|
if (process.env.USERPROFILE)
|
|
@@ -62250,7 +62557,7 @@ function expandTildePath(path) {
|
|
|
62250
62557
|
if (path === "~")
|
|
62251
62558
|
return getHomeDir();
|
|
62252
62559
|
if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
|
|
62253
|
-
return
|
|
62560
|
+
return join27(getHomeDir(), path.slice(2));
|
|
62254
62561
|
}
|
|
62255
62562
|
return path;
|
|
62256
62563
|
}
|
|
@@ -62261,31 +62568,31 @@ function getAgentDir5() {
|
|
|
62261
62568
|
const piAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
62262
62569
|
if (piAgentDir)
|
|
62263
62570
|
return expandTildePath(piAgentDir);
|
|
62264
|
-
return
|
|
62571
|
+
return join27(getHomeDir(), ".atomic", "agent");
|
|
62265
62572
|
}
|
|
62266
62573
|
function sanitizePipeSegment(value2) {
|
|
62267
62574
|
return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
|
|
62268
62575
|
}
|
|
62269
62576
|
function getIntercomDirPath(agentDir = getAgentDir5()) {
|
|
62270
|
-
return
|
|
62577
|
+
return join27(agentDir, "intercom");
|
|
62271
62578
|
}
|
|
62272
62579
|
function getBrokerPidPath(agentDir = getAgentDir5()) {
|
|
62273
|
-
return
|
|
62580
|
+
return join27(getIntercomDirPath(agentDir), "broker.pid");
|
|
62274
62581
|
}
|
|
62275
62582
|
function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
62276
|
-
return
|
|
62583
|
+
return join27(getIntercomDirPath(agentDir), "broker.spawn.lock");
|
|
62277
62584
|
}
|
|
62278
62585
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
62279
|
-
return
|
|
62586
|
+
return join27(getIntercomDirPath(agentDir), "broker.log");
|
|
62280
62587
|
}
|
|
62281
62588
|
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
62282
|
-
return
|
|
62589
|
+
return join27(getIntercomDirPath(agentDir), "broker.starting");
|
|
62283
62590
|
}
|
|
62284
62591
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
62285
62592
|
if (platform === "win32") {
|
|
62286
62593
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
62287
62594
|
}
|
|
62288
|
-
return
|
|
62595
|
+
return join27(getIntercomDirPath(agentDir), "broker.sock");
|
|
62289
62596
|
}
|
|
62290
62597
|
var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
|
|
62291
62598
|
var init_paths = () => {};
|
|
@@ -63969,11 +64276,11 @@ var init_client = __esm(() => {
|
|
|
63969
64276
|
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
63970
64277
|
|
|
63971
64278
|
// dist/builtin/intercom/broker/start-announcement.ts
|
|
63972
|
-
import { readFileSync as
|
|
64279
|
+
import { readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
63973
64280
|
function readBrokerStartAnnouncement(announcement) {
|
|
63974
64281
|
let text;
|
|
63975
64282
|
try {
|
|
63976
|
-
text =
|
|
64283
|
+
text = readFileSync5(announcement.path, "utf-8");
|
|
63977
64284
|
} catch {
|
|
63978
64285
|
return;
|
|
63979
64286
|
}
|
|
@@ -63992,26 +64299,26 @@ var init_start_announcement = () => {};
|
|
|
63992
64299
|
// dist/builtin/intercom/broker/spawn.ts
|
|
63993
64300
|
import { spawn } from "child_process";
|
|
63994
64301
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
63995
|
-
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as
|
|
63996
|
-
import { join as
|
|
64302
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync6, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
64303
|
+
import { join as join28, dirname as dirname12 } from "path";
|
|
63997
64304
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
63998
64305
|
import { createRequire as createRequire3 } from "module";
|
|
63999
64306
|
import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
|
|
64000
64307
|
function isIntercomPackageRoot(dir) {
|
|
64001
|
-
return existsSync5(
|
|
64308
|
+
return existsSync5(join28(dir, "package.json")) && existsSync5(join28(dir, "broker"));
|
|
64002
64309
|
}
|
|
64003
64310
|
function resolveIntercomPackageRoot(moduleHref) {
|
|
64004
|
-
const here =
|
|
64311
|
+
const here = dirname12(fileURLToPath4(moduleHref));
|
|
64005
64312
|
if (isIntercomPackageRoot(here))
|
|
64006
64313
|
return here;
|
|
64007
|
-
return
|
|
64314
|
+
return join28(here, "..");
|
|
64008
64315
|
}
|
|
64009
64316
|
function resolveBrokerEntrypoint(packageRoot) {
|
|
64010
|
-
const bundled =
|
|
64011
|
-
return existsSync5(bundled) ? bundled :
|
|
64317
|
+
const bundled = join28(packageRoot, "broker", "broker.bundle.mjs");
|
|
64318
|
+
return existsSync5(bundled) ? bundled : join28(packageRoot, "broker", "broker.ts");
|
|
64012
64319
|
}
|
|
64013
64320
|
function ensurePrivateDirectory(path) {
|
|
64014
|
-
|
|
64321
|
+
mkdirSync8(path, { recursive: true, mode: 448 });
|
|
64015
64322
|
if (process.platform !== "win32")
|
|
64016
64323
|
chmodSync(path, 448);
|
|
64017
64324
|
}
|
|
@@ -64024,14 +64331,14 @@ function getCurrentBrokerRuntime() {
|
|
|
64024
64331
|
return isBunBinary ? "bun-binary" : "bun-source";
|
|
64025
64332
|
}
|
|
64026
64333
|
function requireFromExtensionDir(extensionDir) {
|
|
64027
|
-
return createRequire3(
|
|
64334
|
+
return createRequire3(join28(extensionDir, "package.json"));
|
|
64028
64335
|
}
|
|
64029
64336
|
function getJitiCliPath(extensionDir = EXTENSION_DIR) {
|
|
64030
64337
|
try {
|
|
64031
64338
|
const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
|
|
64032
|
-
return
|
|
64339
|
+
return join28(dirname12(jitiPackage), "lib", "jiti-cli.mjs");
|
|
64033
64340
|
} catch {
|
|
64034
|
-
return
|
|
64341
|
+
return join28(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
|
|
64035
64342
|
}
|
|
64036
64343
|
}
|
|
64037
64344
|
function getDefaultBrokerRunnerPath(extensionDir) {
|
|
@@ -64053,7 +64360,7 @@ function quoteWindowsArg(value2) {
|
|
|
64053
64360
|
return `"${value2.replace(/"/g, '""')}"`;
|
|
64054
64361
|
}
|
|
64055
64362
|
function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
|
|
64056
|
-
return
|
|
64363
|
+
return join28(intercomDir, "broker-launch.vbs");
|
|
64057
64364
|
}
|
|
64058
64365
|
function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
|
|
64059
64366
|
return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
|
|
@@ -64080,8 +64387,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
64080
64387
|
`);
|
|
64081
64388
|
}
|
|
64082
64389
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
64083
|
-
ensurePrivateDirectory(
|
|
64084
|
-
|
|
64390
|
+
ensurePrivateDirectory(dirname12(launcherPath));
|
|
64391
|
+
writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
64085
64392
|
return launcherPath;
|
|
64086
64393
|
}
|
|
64087
64394
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -64124,14 +64431,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
|
|
|
64124
64431
|
};
|
|
64125
64432
|
}
|
|
64126
64433
|
function resetBrokerLog(logPath = BROKER_LOG) {
|
|
64127
|
-
ensurePrivateDirectory(
|
|
64434
|
+
ensurePrivateDirectory(dirname12(logPath));
|
|
64128
64435
|
try {
|
|
64129
64436
|
const previous = readBrokerLogTail(logPath);
|
|
64130
64437
|
closeSync3(openSync3(logPath, "w"));
|
|
64131
64438
|
if (previous.length > 0) {
|
|
64132
64439
|
try {
|
|
64133
64440
|
const previousPath = `${logPath}.previous`;
|
|
64134
|
-
|
|
64441
|
+
writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
64135
64442
|
if (process.platform !== "win32")
|
|
64136
64443
|
chmodSync(previousPath, 384);
|
|
64137
64444
|
} catch {}
|
|
@@ -64275,7 +64582,7 @@ async function isBrokerRunning() {
|
|
|
64275
64582
|
if (!existsSync5(BROKER_PID))
|
|
64276
64583
|
return false;
|
|
64277
64584
|
try {
|
|
64278
|
-
const pid = parseInt(
|
|
64585
|
+
const pid = parseInt(readFileSync6(BROKER_PID, "utf-8").trim(), 10);
|
|
64279
64586
|
if (!Number.isFinite(pid))
|
|
64280
64587
|
return false;
|
|
64281
64588
|
process.kill(pid, 0);
|
|
@@ -64300,7 +64607,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
64300
64607
|
}
|
|
64301
64608
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
64302
64609
|
try {
|
|
64303
|
-
return
|
|
64610
|
+
return readFileSync6(lockPath, "utf-8").startsWith(owner);
|
|
64304
64611
|
} catch {
|
|
64305
64612
|
return false;
|
|
64306
64613
|
}
|
|
@@ -64312,7 +64619,7 @@ function acquireSpawnLock() {
|
|
|
64312
64619
|
${Date.now()}
|
|
64313
64620
|
`;
|
|
64314
64621
|
try {
|
|
64315
|
-
|
|
64622
|
+
writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
64316
64623
|
return owner;
|
|
64317
64624
|
} catch (error) {
|
|
64318
64625
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -64342,7 +64649,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
64342
64649
|
return false;
|
|
64343
64650
|
}
|
|
64344
64651
|
try {
|
|
64345
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
64652
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync6(lockPath, "utf-8").trim().split(`
|
|
64346
64653
|
`);
|
|
64347
64654
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
64348
64655
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -64420,14 +64727,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
64420
64727
|
});
|
|
64421
64728
|
|
|
64422
64729
|
// dist/builtin/intercom/config.ts
|
|
64423
|
-
import { existsSync as existsSync6, readFileSync as
|
|
64730
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
|
|
64424
64731
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
64425
64732
|
function loadConfig() {
|
|
64426
64733
|
if (!existsSync6(CONFIG_PATH)) {
|
|
64427
64734
|
return { ...defaults };
|
|
64428
64735
|
}
|
|
64429
64736
|
try {
|
|
64430
|
-
const raw =
|
|
64737
|
+
const raw = readFileSync7(CONFIG_PATH, "utf-8");
|
|
64431
64738
|
const parsed = JSON.parse(raw);
|
|
64432
64739
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
64433
64740
|
throw new Error("Config must be a JSON object");
|
|
@@ -65010,12 +65317,12 @@ var init_sql_pool_usage = __esm(() => {
|
|
|
65010
65317
|
|
|
65011
65318
|
// dist/builtin/workflows/src/workers/pooled-watch-trace.ts
|
|
65012
65319
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
65013
|
-
import { dirname as
|
|
65320
|
+
import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
|
|
65014
65321
|
function configurePooledWatchTrace(journalPath, processRole) {
|
|
65015
65322
|
if (setting === undefined || setting === "" || setting === "0")
|
|
65016
65323
|
return;
|
|
65017
65324
|
role = processRole;
|
|
65018
|
-
file = setting === "1" ?
|
|
65325
|
+
file = setting === "1" ? join29(dirname13(resolve12(journalPath)), "pooled-watch-trace.jsonl") : resolve12(setting);
|
|
65019
65326
|
}
|
|
65020
65327
|
function tracePooledWatch(step, detail) {
|
|
65021
65328
|
if (file === undefined)
|
|
@@ -65209,7 +65516,7 @@ import { fork } from "node:child_process";
|
|
|
65209
65516
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
65210
65517
|
import { createWriteStream } from "node:fs";
|
|
65211
65518
|
import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65212
|
-
import { dirname as
|
|
65519
|
+
import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
|
|
65213
65520
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
65214
65521
|
function isRootLeaseLost(error) {
|
|
65215
65522
|
return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
|
|
@@ -65218,7 +65525,7 @@ function unconfirmedCleanup(groups) {
|
|
|
65218
65525
|
return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
|
|
65219
65526
|
}
|
|
65220
65527
|
function workerLogDirectory(journalPath, root) {
|
|
65221
|
-
return
|
|
65528
|
+
return join30(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
65222
65529
|
}
|
|
65223
65530
|
function token(work) {
|
|
65224
65531
|
return {
|
|
@@ -65406,6 +65713,7 @@ class PoolCoordinator {
|
|
|
65406
65713
|
cleanups = new Set;
|
|
65407
65714
|
controlAcks = new Map;
|
|
65408
65715
|
lastHeard = new Map;
|
|
65716
|
+
awaiting = new Map;
|
|
65409
65717
|
pendingActivity = new Map;
|
|
65410
65718
|
batches = new Map;
|
|
65411
65719
|
publicationFailures = new Map;
|
|
@@ -66149,7 +66457,7 @@ class PoolCoordinator {
|
|
|
66149
66457
|
this.slots.add(slot);
|
|
66150
66458
|
let ready = false;
|
|
66151
66459
|
let serial = Promise.resolve();
|
|
66152
|
-
const logPath =
|
|
66460
|
+
const logPath = join30(this.logDirectory, `${worker}.log`);
|
|
66153
66461
|
this.logs.set(child, logPath);
|
|
66154
66462
|
let logFailure;
|
|
66155
66463
|
const log = createWriteStream(logPath, { flags: "a" });
|
|
@@ -66205,6 +66513,7 @@ class PoolCoordinator {
|
|
|
66205
66513
|
this.readyWorkers.delete(worker);
|
|
66206
66514
|
this.controlAcks.delete(worker);
|
|
66207
66515
|
this.lastHeard.delete(worker);
|
|
66516
|
+
this.awaiting.delete(worker);
|
|
66208
66517
|
this.slots.delete(slot);
|
|
66209
66518
|
this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
|
|
66210
66519
|
for (const settle of slot.stageCommands.values())
|
|
@@ -66462,8 +66771,19 @@ class PoolCoordinator {
|
|
|
66462
66771
|
await this.sendResult(work.id);
|
|
66463
66772
|
});
|
|
66464
66773
|
const response = handled.then((value2) => routeReady ?? value2);
|
|
66465
|
-
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
66466
|
-
|
|
66774
|
+
if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
|
|
66775
|
+
this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
|
|
66776
|
+
const answered = () => {
|
|
66777
|
+
const left = (this.awaiting.get(worker) ?? 1) - 1;
|
|
66778
|
+
if (left > 0)
|
|
66779
|
+
this.awaiting.set(worker, left);
|
|
66780
|
+
else
|
|
66781
|
+
this.awaiting.delete(worker);
|
|
66782
|
+
if (this.incarnations.get(worker) === child)
|
|
66783
|
+
this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
|
|
66784
|
+
};
|
|
66785
|
+
serial = handled.then(answered, answered);
|
|
66786
|
+
}
|
|
66467
66787
|
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
|
|
66468
66788
|
const rootLeaseLost = isRootLeaseLost(error);
|
|
66469
66789
|
if (rootLeaseLost)
|
|
@@ -66533,7 +66853,10 @@ class PoolCoordinator {
|
|
|
66533
66853
|
if (work.epoch < lease.epoch)
|
|
66534
66854
|
await this.releaseRetained(work);
|
|
66535
66855
|
else
|
|
66536
|
-
await queue.expire(lease, work)
|
|
66856
|
+
await queue.expire(lease, work).catch((error) => {
|
|
66857
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
66858
|
+
throw error;
|
|
66859
|
+
});
|
|
66537
66860
|
}
|
|
66538
66861
|
})().finally(() => {
|
|
66539
66862
|
this.recovering = undefined;
|
|
@@ -66551,7 +66874,7 @@ class PoolCoordinator {
|
|
|
66551
66874
|
isLive(worker, child) {
|
|
66552
66875
|
this.observeResponsiveness();
|
|
66553
66876
|
const heard = this.lastHeard.get(worker);
|
|
66554
|
-
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
|
|
66877
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && ((this.awaiting.get(worker) ?? 0) > 0 || performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs);
|
|
66555
66878
|
}
|
|
66556
66879
|
async stop(child) {
|
|
66557
66880
|
const pid = child.pid;
|
|
@@ -66737,26 +67060,6 @@ function isWorkflowPendingStageDeliveryFailure(error) {
|
|
|
66737
67060
|
return true;
|
|
66738
67061
|
return error?.code === "pending_stage_delivery_failed";
|
|
66739
67062
|
}
|
|
66740
|
-
function untilDrainedOrStalled(drain) {
|
|
66741
|
-
let lastProgressAt = Date.now();
|
|
66742
|
-
const running = drain(() => {
|
|
66743
|
-
lastProgressAt = Date.now();
|
|
66744
|
-
});
|
|
66745
|
-
return new Promise((resolve, reject) => {
|
|
66746
|
-
let timer;
|
|
66747
|
-
const check = () => {
|
|
66748
|
-
const remaining = lastProgressAt + PENDING_STAGE_READY_STALL_MS - Date.now();
|
|
66749
|
-
if (remaining <= 0) {
|
|
66750
|
-
resolve();
|
|
66751
|
-
return;
|
|
66752
|
-
}
|
|
66753
|
-
timer = setTimeout(check, remaining);
|
|
66754
|
-
timer.unref?.();
|
|
66755
|
-
};
|
|
66756
|
-
running.then(resolve, reject).finally(() => clearTimeout(timer));
|
|
66757
|
-
check();
|
|
66758
|
-
});
|
|
66759
|
-
}
|
|
66760
67063
|
function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName, commit = (action) => action(), options = {}) {
|
|
66761
67064
|
let resolveReady;
|
|
66762
67065
|
let rejectReady;
|
|
@@ -66949,7 +67252,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
66949
67252
|
};
|
|
66950
67253
|
}
|
|
66951
67254
|
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
|
|
66952
|
-
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
|
|
67255
|
+
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
|
|
66953
67256
|
const candidateIds = new Set([
|
|
66954
67257
|
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
66955
67258
|
...activeStore.pendingStageMessagesFor(runId, stageName),
|
|
@@ -67005,7 +67308,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
|
|
|
67005
67308
|
}
|
|
67006
67309
|
}
|
|
67007
67310
|
}
|
|
67008
|
-
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
|
|
67311
|
+
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
|
|
67009
67312
|
const runs = activeStore.runs();
|
|
67010
67313
|
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
67011
67314
|
if (rootRunId === undefined)
|
|
@@ -67014,22 +67317,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
|
|
|
67014
67317
|
if (rootRun === undefined)
|
|
67015
67318
|
return [];
|
|
67016
67319
|
const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
|
|
67017
|
-
|
|
67320
|
+
const ended = stage?.status === "completed" || stage?.status === "skipped";
|
|
67321
|
+
if (ended && receivedByEndedStage.length === 0)
|
|
67018
67322
|
return [];
|
|
67019
67323
|
const hops = workflowBoundaryHops(runs, runId);
|
|
67020
67324
|
if (hops === undefined)
|
|
67021
67325
|
return [];
|
|
67022
67326
|
return (rootRun.pendingStageMessages ?? []).filter((entry) => {
|
|
67023
|
-
if (entry.sticky !== true || entry.status !== "queued")
|
|
67024
|
-
return false;
|
|
67025
|
-
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67026
|
-
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67027
|
-
return false;
|
|
67028
67327
|
if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId && (recipient === undefined || delivery.admission === "context" && delivery.sessionId === recipient.sessionId && (recipient.receivedMessageIds === undefined || recipient.receivedMessageIds.includes(entry.message.id)))))
|
|
67029
67328
|
return false;
|
|
67030
|
-
|
|
67329
|
+
if (ended && !receivedByEndedStage.includes(entry.message.id))
|
|
67330
|
+
return false;
|
|
67331
|
+
return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
|
|
67031
67332
|
});
|
|
67032
67333
|
}
|
|
67334
|
+
function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
|
|
67335
|
+
if (entry.sticky !== true || entry.status !== "queued")
|
|
67336
|
+
return false;
|
|
67337
|
+
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67338
|
+
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67339
|
+
return false;
|
|
67340
|
+
return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
|
|
67341
|
+
}
|
|
67033
67342
|
function claimPendingDelivery(store, runId, stageKey, messageId) {
|
|
67034
67343
|
let claims = pendingDeliveryClaims.get(store);
|
|
67035
67344
|
if (claims === undefined) {
|
|
@@ -67093,6 +67402,7 @@ class PoolStageHandoff {
|
|
|
67093
67402
|
owners = new Map;
|
|
67094
67403
|
publications = new Map;
|
|
67095
67404
|
drains = new Map;
|
|
67405
|
+
deliveryIssues = 0;
|
|
67096
67406
|
constructor(backend, store, queue, lease, claimRun) {
|
|
67097
67407
|
this.backend = backend;
|
|
67098
67408
|
this.store = store;
|
|
@@ -67173,11 +67483,23 @@ class PoolStageHandoff {
|
|
|
67173
67483
|
this.drains.set(stage, drain);
|
|
67174
67484
|
try {
|
|
67175
67485
|
await drain;
|
|
67486
|
+
} catch (error) {
|
|
67487
|
+
const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
|
|
67488
|
+
if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
|
|
67489
|
+
this.recordDeliveryIssue(error);
|
|
67490
|
+
throw error;
|
|
67176
67491
|
} finally {
|
|
67177
67492
|
if (this.drains.get(stage) === drain)
|
|
67178
67493
|
this.drains.delete(stage);
|
|
67179
67494
|
}
|
|
67180
67495
|
}
|
|
67496
|
+
recordDeliveryIssue(error) {
|
|
67497
|
+
this.deliveryIssues++;
|
|
67498
|
+
const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
|
|
67499
|
+
this.store.recordRunExecutionState(this.lease.runId, {
|
|
67500
|
+
intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
|
|
67501
|
+
});
|
|
67502
|
+
}
|
|
67181
67503
|
async complete(work) {
|
|
67182
67504
|
const root = this.lease.runId;
|
|
67183
67505
|
const result = await this.queue.result(root, work.id);
|
|
@@ -68533,7 +68855,7 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
68533
68855
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
68534
68856
|
import { fork as fork2 } from "node:child_process";
|
|
68535
68857
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
68536
|
-
import { resolve as
|
|
68858
|
+
import { resolve as resolve14 } from "node:path";
|
|
68537
68859
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
68538
68860
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
68539
68861
|
import {
|
|
@@ -68767,7 +69089,7 @@ class LocalWorkerPool {
|
|
|
68767
69089
|
async poolJournal() {
|
|
68768
69090
|
const journal = this.backend.journal;
|
|
68769
69091
|
if (this.options.durable === undefined) {
|
|
68770
|
-
if (!(journal instanceof SqlRunJournal) ||
|
|
69092
|
+
if (!(journal instanceof SqlRunJournal) || resolve14(this.options.journalPath) !== resolve14(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
68771
69093
|
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68772
69094
|
return journal;
|
|
68773
69095
|
}
|
|
@@ -69794,7 +70116,7 @@ var init_local_pool = __esm(() => {
|
|
|
69794
70116
|
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
69795
70117
|
|
|
69796
70118
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
69797
|
-
import { resolve as
|
|
70119
|
+
import { resolve as resolve15 } from "node:path";
|
|
69798
70120
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
69799
70121
|
async function restoreWorkerOptions(backend, options) {
|
|
69800
70122
|
const source = options.continuation?.source.id ?? options.runId;
|
|
@@ -69844,16 +70166,16 @@ async function activatePublicPool(backend, options) {
|
|
|
69844
70166
|
startupTimeoutMs: undefined,
|
|
69845
70167
|
leaseMs: undefined,
|
|
69846
70168
|
maxLoadPerCpu: undefined,
|
|
69847
|
-
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path:
|
|
70169
|
+
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
|
|
69848
70170
|
};
|
|
69849
70171
|
const admission = options.admission && {
|
|
69850
70172
|
...options.admission,
|
|
69851
|
-
...options.admission.userDatabase ? { userDatabase:
|
|
70173
|
+
...options.admission.userDatabase ? { userDatabase: resolve15(cwd, options.admission.userDatabase) } : {}
|
|
69852
70174
|
};
|
|
69853
70175
|
if (durable !== undefined && admission?.userLimits) {
|
|
69854
|
-
if (admission.userDatabase !== undefined && admission.userDatabase !==
|
|
69855
|
-
throw new Error(`admission.userDatabase must be omitted, or ${
|
|
69856
|
-
admission.userDatabase =
|
|
70176
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve15(poolPath))
|
|
70177
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve15(poolPath)}, for a journal that is not a local SQLite file`);
|
|
70178
|
+
admission.userDatabase = resolve15(poolPath);
|
|
69857
70179
|
}
|
|
69858
70180
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
69859
70181
|
const resources = JSON.parse(JSON.stringify({
|
|
@@ -70459,6 +70781,7 @@ function createTaskPrimitive(runtime) {
|
|
|
70459
70781
|
}
|
|
70460
70782
|
})();
|
|
70461
70783
|
const stageMeta = stage.__modelFallbackMeta();
|
|
70784
|
+
stage.__releaseIfIdle?.();
|
|
70462
70785
|
return {
|
|
70463
70786
|
name,
|
|
70464
70787
|
stageName: name,
|
|
@@ -71257,7 +71580,7 @@ function hasUsableContentBlock(block) {
|
|
|
71257
71580
|
|
|
71258
71581
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
71259
71582
|
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
71260
|
-
import { dirname as
|
|
71583
|
+
import { dirname as dirname15, resolve as resolve16 } from "node:path";
|
|
71261
71584
|
import {
|
|
71262
71585
|
JsonlSessionStore,
|
|
71263
71586
|
resolveSessionStore,
|
|
@@ -71293,11 +71616,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
|
|
|
71293
71616
|
async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
71294
71617
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
71295
71618
|
return;
|
|
71296
|
-
const location =
|
|
71297
|
-
const legacy = await JsonlSessionStore.open(
|
|
71619
|
+
const location = resolve16(sessionFile);
|
|
71620
|
+
const legacy = await JsonlSessionStore.open(dirname15(location), { exactDirectory: true, scanExisting: false });
|
|
71298
71621
|
try {
|
|
71299
71622
|
for await (const file of legacy.scanFiles()) {
|
|
71300
|
-
if (
|
|
71623
|
+
if (resolve16(file.location) !== location || file.header.id !== sessionId)
|
|
71301
71624
|
continue;
|
|
71302
71625
|
const snapshot = await file.read();
|
|
71303
71626
|
if (await store.readHeader(sessionId) === undefined)
|
|
@@ -74123,6 +74446,8 @@ function createTrackedStageCaller(input) {
|
|
|
74123
74446
|
await runtime.releaseLiveHandle().catch(() => {});
|
|
74124
74447
|
}
|
|
74125
74448
|
runtime.state.sessionCheckpointed = finalizationError === undefined;
|
|
74449
|
+
if (runtime.state.contextUnreachable)
|
|
74450
|
+
runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
|
|
74126
74451
|
input.limiter.release();
|
|
74127
74452
|
if (finalizationError !== undefined)
|
|
74128
74453
|
throwFinalizationError(finalizationError.error);
|
|
@@ -74286,7 +74611,8 @@ function createStageContext(input) {
|
|
|
74286
74611
|
recordStageNotice({ kind: "abort", to: "interrupted" });
|
|
74287
74612
|
await innerCtx.abort();
|
|
74288
74613
|
},
|
|
74289
|
-
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
|
|
74614
|
+
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
|
|
74615
|
+
__releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
|
|
74290
74616
|
};
|
|
74291
74617
|
}
|
|
74292
74618
|
|
|
@@ -75975,10 +76301,10 @@ function isRetryableSameCandidateFailure(error) {
|
|
|
75975
76301
|
return isTransientExtensionStartupFailure(error);
|
|
75976
76302
|
return isRetryableSameModelFailure(error);
|
|
75977
76303
|
}
|
|
75978
|
-
function mayAdvanceToNextCandidate(error) {
|
|
76304
|
+
function mayAdvanceToNextCandidate(error, options) {
|
|
75979
76305
|
if (isExtensionStartupFailure(error))
|
|
75980
76306
|
return isTransientExtensionStartupFailure(error);
|
|
75981
|
-
return isRetryableModelFailure(error);
|
|
76307
|
+
return isRetryableModelFailure(error, options);
|
|
75982
76308
|
}
|
|
75983
76309
|
function hasMeaningfulUsage(usage) {
|
|
75984
76310
|
if (usage === undefined)
|
|
@@ -76070,6 +76396,7 @@ class StageSessionController {
|
|
|
76070
76396
|
structuredOutputExecutionFailureValue;
|
|
76071
76397
|
structuredOutputCycleAttemptMark;
|
|
76072
76398
|
unsubscribeTerminateWatcher;
|
|
76399
|
+
unbindAbortSignal;
|
|
76073
76400
|
sessionInternalRetries = 0;
|
|
76074
76401
|
unresolvedContextOverflowMessage;
|
|
76075
76402
|
generationSealed = false;
|
|
@@ -76559,6 +76886,8 @@ class StageSessionController {
|
|
|
76559
76886
|
this.pendingListeners.clear();
|
|
76560
76887
|
this.unsubscribeTerminateWatcher?.();
|
|
76561
76888
|
this.unsubscribeTerminateWatcher = undefined;
|
|
76889
|
+
this.unbindAbortSignal?.();
|
|
76890
|
+
this.unbindAbortSignal = undefined;
|
|
76562
76891
|
this.terminatingToolCallIds.clear();
|
|
76563
76892
|
this.messageAdmission.dispose();
|
|
76564
76893
|
this.deliveryActivity.dispose();
|
|
@@ -76653,8 +76982,10 @@ class StageSessionController {
|
|
|
76653
76982
|
};
|
|
76654
76983
|
if (signal.aborted)
|
|
76655
76984
|
onAbort();
|
|
76656
|
-
else
|
|
76985
|
+
else {
|
|
76657
76986
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
76987
|
+
this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
|
|
76988
|
+
}
|
|
76658
76989
|
}
|
|
76659
76990
|
markAbort(reason) {
|
|
76660
76991
|
this.abortGeneration += 1;
|
|
@@ -76681,6 +77012,9 @@ class StageSessionController {
|
|
|
76681
77012
|
state.controller.abort(reason);
|
|
76682
77013
|
this.thrownErrorRetryStates.clear();
|
|
76683
77014
|
}
|
|
77015
|
+
fallbackFailureOptions() {
|
|
77016
|
+
return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
|
|
77017
|
+
}
|
|
76684
77018
|
retrySettings() {
|
|
76685
77019
|
const managers = [
|
|
76686
77020
|
this.sessionSettingsManager,
|
|
@@ -76955,7 +77289,7 @@ class StageSessionController {
|
|
|
76955
77289
|
const errorSettingsManager = retrySettingsManagerFromError(error);
|
|
76956
77290
|
if (errorSettingsManager !== undefined)
|
|
76957
77291
|
this.sessionSettingsManager = errorSettingsManager;
|
|
76958
|
-
const retryableFailure = isRetryableModelFailure(error);
|
|
77292
|
+
const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
|
|
76959
77293
|
const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
|
|
76960
77294
|
recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
|
|
76961
77295
|
if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
|
|
@@ -77580,7 +77914,7 @@ class StageSessionController {
|
|
|
77580
77914
|
}
|
|
77581
77915
|
throw new WorkflowPromptModelFailure(terminalFailure);
|
|
77582
77916
|
} catch (err) {
|
|
77583
|
-
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
77917
|
+
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77584
77918
|
this.artifactCapture.settleAttempt(true);
|
|
77585
77919
|
const usage = this.takeAttemptUsage(resumedSession);
|
|
77586
77920
|
this.modelAttempts.push({
|
|
@@ -77602,7 +77936,7 @@ class StageSessionController {
|
|
|
77602
77936
|
...usage === undefined ? {} : { usage },
|
|
77603
77937
|
error: message
|
|
77604
77938
|
});
|
|
77605
|
-
if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
|
|
77939
|
+
if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77606
77940
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
77607
77941
|
this.pendingFallbackWarnings.length = 0;
|
|
77608
77942
|
this.notifyModelFallbackMetaChange();
|
|
@@ -77651,7 +77985,7 @@ class StageSessionController {
|
|
|
77651
77985
|
throw err;
|
|
77652
77986
|
const message = errorMessage3(err);
|
|
77653
77987
|
const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
|
|
77654
|
-
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
77988
|
+
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77655
77989
|
this.recordSuccessfulAttempt(candidate);
|
|
77656
77990
|
return "handled";
|
|
77657
77991
|
}
|
|
@@ -77668,7 +78002,7 @@ class StageSessionController {
|
|
|
77668
78002
|
if (walk !== undefined) {
|
|
77669
78003
|
this.recordCandidateFailure(walk, index, err, candidates);
|
|
77670
78004
|
nextIndex = undefined;
|
|
77671
|
-
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
|
|
78005
|
+
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
|
|
77672
78006
|
try {
|
|
77673
78007
|
nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
|
|
77674
78008
|
} catch (error) {
|
|
@@ -77681,7 +78015,7 @@ class StageSessionController {
|
|
|
77681
78015
|
}
|
|
77682
78016
|
}
|
|
77683
78017
|
}
|
|
77684
|
-
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
|
|
78018
|
+
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
|
|
77685
78019
|
await this.settleFailedCandidate();
|
|
77686
78020
|
return "throw";
|
|
77687
78021
|
}
|
|
@@ -77776,7 +78110,7 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
77776
78110
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
77777
78111
|
import { createHash as createHash5 } from "node:crypto";
|
|
77778
78112
|
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
77779
|
-
import { basename as basename5, dirname as
|
|
78113
|
+
import { basename as basename5, dirname as dirname16, isAbsolute as isAbsolute11, join as join31, resolve as resolve17 } from "node:path";
|
|
77780
78114
|
function normalizeMaxOutput2(maxOutput) {
|
|
77781
78115
|
return {
|
|
77782
78116
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -77839,7 +78173,7 @@ function formatByteSize(bytes) {
|
|
|
77839
78173
|
}
|
|
77840
78174
|
function transcriptPath(runId, outputPath) {
|
|
77841
78175
|
const digest = createHash5("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
77842
|
-
return
|
|
78176
|
+
return join31(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
77843
78177
|
}
|
|
77844
78178
|
function appendContent(lines, content) {
|
|
77845
78179
|
if (typeof content === "string") {
|
|
@@ -77884,7 +78218,7 @@ function renderTranscript(messages, fallbackOutput) {
|
|
|
77884
78218
|
`);
|
|
77885
78219
|
}
|
|
77886
78220
|
function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
|
|
77887
|
-
const absolutePath =
|
|
78221
|
+
const absolutePath = resolve17(outputPath);
|
|
77888
78222
|
const bytes = Buffer.byteLength(fullOutput, "utf8");
|
|
77889
78223
|
const lines = countLines(fullOutput);
|
|
77890
78224
|
const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
|
|
@@ -77899,8 +78233,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
|
|
|
77899
78233
|
return;
|
|
77900
78234
|
if (isAbsolute11(output))
|
|
77901
78235
|
return output;
|
|
77902
|
-
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd :
|
|
77903
|
-
return
|
|
78236
|
+
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve17(runtimeCwd, requestedCwd);
|
|
78237
|
+
return resolve17(baseCwd, output);
|
|
77904
78238
|
}
|
|
77905
78239
|
function degenerateWarning(fullOutput) {
|
|
77906
78240
|
return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
|
|
@@ -77959,7 +78293,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
77959
78293
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
77960
78294
|
const transcript = renderTranscript(messages, fullOutput);
|
|
77961
78295
|
try {
|
|
77962
|
-
await mkdir7(
|
|
78296
|
+
await mkdir7(dirname16(outputPath), { recursive: true });
|
|
77963
78297
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
77964
78298
|
} catch (err) {
|
|
77965
78299
|
return `${displayOutput}
|
|
@@ -77971,7 +78305,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
77971
78305
|
let transcriptError;
|
|
77972
78306
|
try {
|
|
77973
78307
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
77974
|
-
await mkdir7(
|
|
78308
|
+
await mkdir7(dirname16(transcriptFile), { recursive: true });
|
|
77975
78309
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
77976
78310
|
transcriptAvailable = true;
|
|
77977
78311
|
} catch (err) {
|
|
@@ -78482,7 +78816,8 @@ function createWorkflowStageFactory(input) {
|
|
|
78482
78816
|
stageFinalized: false,
|
|
78483
78817
|
sessionCheckpointed: false,
|
|
78484
78818
|
skippedForParallelFailFast: false,
|
|
78485
|
-
stageControlDropped: false
|
|
78819
|
+
stageControlDropped: false,
|
|
78820
|
+
contextUnreachable: false
|
|
78486
78821
|
};
|
|
78487
78822
|
const activeAskUserQuestionCalls = new Set;
|
|
78488
78823
|
const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
|
|
@@ -78728,9 +79063,18 @@ function createWorkflowStageFactory(input) {
|
|
|
78728
79063
|
hasContinuation: input.opts.continuation !== undefined,
|
|
78729
79064
|
hasScopedParents: stageFailFastScope?.parentIds !== undefined
|
|
78730
79065
|
});
|
|
78731
|
-
|
|
79066
|
+
const context = createStageContext({ runtime, runTrackedStageCall });
|
|
79067
|
+
unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
|
|
79068
|
+
return context;
|
|
79069
|
+
};
|
|
79070
|
+
}
|
|
79071
|
+
function releaseWhenUnreachable(state, registry, runId, stageId) {
|
|
79072
|
+
return () => {
|
|
79073
|
+
state.contextUnreachable = true;
|
|
79074
|
+
registry.releaseIdle(runId, stageId);
|
|
78732
79075
|
};
|
|
78733
79076
|
}
|
|
79077
|
+
var unreachableStageContexts;
|
|
78734
79078
|
var init_executor_stage_factory = __esm(() => {
|
|
78735
79079
|
init_intercom_group();
|
|
78736
79080
|
init_pending_stage_route_readiness();
|
|
@@ -78745,6 +79089,7 @@ var init_executor_stage_factory = __esm(() => {
|
|
|
78745
79089
|
init_pending_stage_delivery2();
|
|
78746
79090
|
init_stage_runner();
|
|
78747
79091
|
init_stage_runner_session();
|
|
79092
|
+
unreachableStageContexts = new FinalizationRegistry((release) => release());
|
|
78748
79093
|
});
|
|
78749
79094
|
|
|
78750
79095
|
// dist/builtin/workflows/src/engine/runtime.ts
|
|
@@ -79086,7 +79431,7 @@ async function executeRun(def, resolvedInputs, opts) {
|
|
|
79086
79431
|
const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
|
|
79087
79432
|
const tracker = new GraphFrontierTracker;
|
|
79088
79433
|
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
79089
|
-
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
|
|
79434
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
|
|
79090
79435
|
const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
|
|
79091
79436
|
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
79092
79437
|
let workflowCwd;
|
|
@@ -80185,8 +80530,8 @@ var init_workflows_host_module = __esm(() => {
|
|
|
80185
80530
|
|
|
80186
80531
|
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
80187
80532
|
import { createHash as createHash6, randomUUID as randomUUID22 } from "node:crypto";
|
|
80188
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
80189
|
-
import { basename as basename6, dirname as
|
|
80533
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
|
|
80534
|
+
import { basename as basename6, dirname as dirname17, join as join32, resolve as resolve18 } from "node:path";
|
|
80190
80535
|
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
80191
80536
|
function encodeOption(value2) {
|
|
80192
80537
|
if (typeof value2 === "bigint")
|
|
@@ -80208,7 +80553,7 @@ function isReopenableSelection(selection) {
|
|
|
80208
80553
|
}
|
|
80209
80554
|
function encodeSelection(selection) {
|
|
80210
80555
|
if (selection.kind === "sqlite")
|
|
80211
|
-
return JSON.stringify({ ...selection, path:
|
|
80556
|
+
return JSON.stringify({ ...selection, path: resolve18(selection.path) });
|
|
80212
80557
|
return JSON.stringify({
|
|
80213
80558
|
...selection,
|
|
80214
80559
|
...selection.options === undefined ? {} : {
|
|
@@ -80240,7 +80585,7 @@ function openDurableJournal(durable) {
|
|
|
80240
80585
|
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
80241
80586
|
}
|
|
80242
80587
|
function poolStateDirectory(agentDir) {
|
|
80243
|
-
return
|
|
80588
|
+
return join32(dirname17(agentDir), "workflows", "pool");
|
|
80244
80589
|
}
|
|
80245
80590
|
function databaseIdentity(selection, agentDir) {
|
|
80246
80591
|
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
@@ -80248,16 +80593,16 @@ function databaseIdentity(selection, agentDir) {
|
|
|
80248
80593
|
function coordinationPath(durable) {
|
|
80249
80594
|
const selection = decodeSelection(durable.selection);
|
|
80250
80595
|
const identity = createHash6("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
80251
|
-
return
|
|
80596
|
+
return join32(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
80252
80597
|
}
|
|
80253
80598
|
function coordinationDatabase(durable) {
|
|
80254
80599
|
return basename6(coordinationPath(durable), ".sqlite");
|
|
80255
80600
|
}
|
|
80256
80601
|
function openCoordinationJournal(path) {
|
|
80257
|
-
const file =
|
|
80602
|
+
const file = resolve18(path);
|
|
80258
80603
|
let opened = coordinationJournals.get(file);
|
|
80259
80604
|
if (opened === undefined) {
|
|
80260
|
-
|
|
80605
|
+
mkdirSync9(dirname17(file), { recursive: true });
|
|
80261
80606
|
opened = resolveRunJournal({ journal: { path: file } });
|
|
80262
80607
|
coordinationJournals.set(file, opened);
|
|
80263
80608
|
opened.catch(() => {
|
|
@@ -80274,20 +80619,20 @@ function poolJournalFor(journal) {
|
|
|
80274
80619
|
return coordinations.get(journal) ?? journal;
|
|
80275
80620
|
}
|
|
80276
80621
|
function poolHostId(agentDir) {
|
|
80277
|
-
const file =
|
|
80622
|
+
const file = join32(poolStateDirectory(agentDir), "host-id");
|
|
80278
80623
|
try {
|
|
80279
|
-
const existing =
|
|
80624
|
+
const existing = readFileSync8(file, "utf8").trim();
|
|
80280
80625
|
if (existing !== "")
|
|
80281
80626
|
return existing;
|
|
80282
80627
|
} catch {}
|
|
80283
|
-
|
|
80628
|
+
mkdirSync9(dirname17(file), { recursive: true });
|
|
80284
80629
|
const id = randomUUID22();
|
|
80285
80630
|
try {
|
|
80286
|
-
|
|
80631
|
+
writeFileSync7(file, `${id}
|
|
80287
80632
|
`, { flag: "wx" });
|
|
80288
80633
|
return id;
|
|
80289
80634
|
} catch {
|
|
80290
|
-
return
|
|
80635
|
+
return readFileSync8(file, "utf8").trim();
|
|
80291
80636
|
}
|
|
80292
80637
|
}
|
|
80293
80638
|
var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
|
|
@@ -80310,7 +80655,6 @@ init_run();
|
|
|
80310
80655
|
init_run_tool_control_registry();
|
|
80311
80656
|
init_workflow_tool_abort();
|
|
80312
80657
|
init_wiring();
|
|
80313
|
-
init_pending_stage_delivery2();
|
|
80314
80658
|
init_stage_control_registry();
|
|
80315
80659
|
init_stage_queued_user_messages();
|
|
80316
80660
|
init_stage_ui_broker();
|
|
@@ -80336,6 +80680,94 @@ function poolWorkerCommit(input) {
|
|
|
80336
80680
|
return receipt;
|
|
80337
80681
|
};
|
|
80338
80682
|
}
|
|
80683
|
+
// dist/builtin/workflows/src/workers/pooled-stage-delivery.ts
|
|
80684
|
+
init_pending_stage_delivery2();
|
|
80685
|
+
init_pending_stage_delivery();
|
|
80686
|
+
init_store_pending_stage_delivery_methods();
|
|
80687
|
+
function pooledStageQueuedEntries(journal, store, root, stage) {
|
|
80688
|
+
const messages = journal.getWorkflow(root)?.pendingStageMessages ?? [];
|
|
80689
|
+
const runs = store.runs();
|
|
80690
|
+
const run = runs.find((candidate) => candidate.id === stage.runId);
|
|
80691
|
+
if (run === undefined)
|
|
80692
|
+
return [];
|
|
80693
|
+
const exact = new Set;
|
|
80694
|
+
for (const key of new Set([stage.stageId, stage.stageName]))
|
|
80695
|
+
for (const entry of pendingStageMessagesFor(messages, stage.runId, key, resolvePendingStageIdentity(run, key)))
|
|
80696
|
+
exact.add(entry);
|
|
80697
|
+
const hops = pooledStageHops(journal, runs, root, stage.runId);
|
|
80698
|
+
const sticky = hops === undefined ? [] : messages.filter((entry) => entry.runId === root && stickyEntryTargetsStage(entry, root, hops, stage.stageId, stage.stageName));
|
|
80699
|
+
return [
|
|
80700
|
+
...[...exact].map((entry) => ({ entry, index: messages.indexOf(entry) })),
|
|
80701
|
+
...sticky.map((entry) => ({ entry, index: Number.MAX_SAFE_INTEGER }))
|
|
80702
|
+
].map(({ entry, index }) => ({ entry, index, order: pendingStageMessageAdmissionOrder(entry) })).sort((left, right) => left.order - right.order || left.index - right.index).map(({ entry }) => entry);
|
|
80703
|
+
}
|
|
80704
|
+
function pooledStageHops(journal, runs, root, runId) {
|
|
80705
|
+
const byId = new Map(runs.map((run) => [run.id, run]));
|
|
80706
|
+
const hops = [];
|
|
80707
|
+
let current = byId.get(runId);
|
|
80708
|
+
while (current !== undefined && current.parentRunId !== root) {
|
|
80709
|
+
const child = current;
|
|
80710
|
+
const parent = child.parentRunId === undefined ? undefined : byId.get(child.parentRunId);
|
|
80711
|
+
const boundary = parent?.stages.find((stage) => stage.id === child.parentStageId);
|
|
80712
|
+
if (parent === undefined || boundary === undefined)
|
|
80713
|
+
return;
|
|
80714
|
+
hops.unshift({ name: boundary.name, runId: child.id });
|
|
80715
|
+
current = parent;
|
|
80716
|
+
}
|
|
80717
|
+
if (current === undefined)
|
|
80718
|
+
return;
|
|
80719
|
+
const childRunId = current.id;
|
|
80720
|
+
const boundary = journal.listCheckpoints(root).find((checkpoint) => checkpoint.kind === "stage" && checkpoint.topology?.boundary?.child.runId === childRunId);
|
|
80721
|
+
if (boundary === undefined)
|
|
80722
|
+
return;
|
|
80723
|
+
hops.unshift({ name: boundary.name, runId: childRunId });
|
|
80724
|
+
return hops;
|
|
80725
|
+
}
|
|
80726
|
+
function createPooledStageDelivery(options) {
|
|
80727
|
+
const admissions = new Map;
|
|
80728
|
+
const sinks = new Map;
|
|
80729
|
+
return {
|
|
80730
|
+
routeCapability: options.routeCapability,
|
|
80731
|
+
async deliverPending(deliver, recipient) {
|
|
80732
|
+
const sessionId = recipient?.sessionId ?? "";
|
|
80733
|
+
sinks.set(sessionId, deliver);
|
|
80734
|
+
let admitted = admissions.get(sessionId);
|
|
80735
|
+
if (admitted === undefined) {
|
|
80736
|
+
admitted = new Map;
|
|
80737
|
+
admissions.set(sessionId, admitted);
|
|
80738
|
+
}
|
|
80739
|
+
const held = admitted;
|
|
80740
|
+
for (const id of recipient?.receivedMessageIds ?? [])
|
|
80741
|
+
if (!held.has(id))
|
|
80742
|
+
held.set(id, Promise.resolve());
|
|
80743
|
+
const admit = (from, message) => {
|
|
80744
|
+
const existing = held.get(message.id);
|
|
80745
|
+
if (existing !== undefined)
|
|
80746
|
+
return existing;
|
|
80747
|
+
const sink = sinks.get(sessionId) ?? deliver;
|
|
80748
|
+
const delivery = Promise.resolve().then(() => sink(from, message));
|
|
80749
|
+
held.set(message.id, delivery);
|
|
80750
|
+
delivery.catch(() => {
|
|
80751
|
+
if (held.get(message.id) === delivery)
|
|
80752
|
+
held.delete(message.id);
|
|
80753
|
+
});
|
|
80754
|
+
return delivery;
|
|
80755
|
+
};
|
|
80756
|
+
try {
|
|
80757
|
+
for (const entry of await options.queued())
|
|
80758
|
+
await admit(toPendingStageSender(entry), entry.message);
|
|
80759
|
+
} catch {}
|
|
80760
|
+
const deliveries = [...held];
|
|
80761
|
+
const settled = await Promise.allSettled(deliveries.map(([, delivery]) => delivery));
|
|
80762
|
+
const receivedMessageIds = deliveries.flatMap(([id], index) => settled[index]?.status === "fulfilled" ? [id] : []);
|
|
80763
|
+
options.forward({ sessionId, receivedMessageIds }, admit).catch(() => {});
|
|
80764
|
+
},
|
|
80765
|
+
ready() {
|
|
80766
|
+
return;
|
|
80767
|
+
},
|
|
80768
|
+
fail: options.fail
|
|
80769
|
+
};
|
|
80770
|
+
}
|
|
80339
80771
|
|
|
80340
80772
|
// dist/builtin/workflows/src/workers/local-worker.ts
|
|
80341
80773
|
init_pooled_watch_trace();
|
|
@@ -81470,25 +81902,18 @@ async function runWorker(start) {
|
|
|
81470
81902
|
const capability = await request({ kind: "route", runId: meta.runId });
|
|
81471
81903
|
if (typeof capability !== "string")
|
|
81472
81904
|
throw new Error("Worker root route is unavailable");
|
|
81473
|
-
const pendingStageDelivery = {
|
|
81905
|
+
const pendingStageDelivery = createPooledStageDelivery({
|
|
81474
81906
|
routeCapability: capability,
|
|
81475
|
-
async
|
|
81476
|
-
await
|
|
81477
|
-
|
|
81478
|
-
progress();
|
|
81479
|
-
try {
|
|
81480
|
-
await deliver(from, message);
|
|
81481
|
-
} finally {
|
|
81482
|
-
progress();
|
|
81483
|
-
}
|
|
81484
|
-
}).then(() => {}));
|
|
81907
|
+
queued: async () => {
|
|
81908
|
+
await reader.catchUpWorkflow(start.root);
|
|
81909
|
+
return pooledStageQueuedEntries(reader, store, start.root, identity);
|
|
81485
81910
|
},
|
|
81486
|
-
async
|
|
81911
|
+
forward: async (recipient, deliver) => {
|
|
81487
81912
|
await publication;
|
|
81488
|
-
await request({ kind: "delivery
|
|
81913
|
+
await request({ kind: "delivery", ...identity, recipient }, deliver);
|
|
81489
81914
|
},
|
|
81490
81915
|
fail: options.orchestrationContext.pendingStageDelivery.fail
|
|
81491
|
-
};
|
|
81916
|
+
});
|
|
81492
81917
|
return baseAdapter.create({ ...options, orchestrationContext: { ...options.orchestrationContext, pendingStageDelivery } }, meta);
|
|
81493
81918
|
}
|
|
81494
81919
|
};
|