@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
|
@@ -13456,9 +13456,104 @@ var init_workflow_artifacts = __esm(() => {
|
|
|
13456
13456
|
pendingArtifactPrunes = new Map;
|
|
13457
13457
|
});
|
|
13458
13458
|
|
|
13459
|
-
// dist/builtin/workflows/src/runs/shared/worktree-
|
|
13459
|
+
// dist/builtin/workflows/src/runs/shared/worktree-allocation.ts
|
|
13460
|
+
import { randomBytes } from "node:crypto";
|
|
13460
13461
|
import * as fs from "node:fs";
|
|
13461
13462
|
import * as path from "node:path";
|
|
13463
|
+
function nextBucketId() {
|
|
13464
|
+
return nextBucketIdOverride?.() ?? randomBytes(2).toString("hex");
|
|
13465
|
+
}
|
|
13466
|
+
function errorCode(error) {
|
|
13467
|
+
return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
13468
|
+
}
|
|
13469
|
+
function allocateWorktreeCheckoutPath(root, repositoryName) {
|
|
13470
|
+
for (let attempt = 0;attempt < MAX_BUCKET_ATTEMPTS; attempt++) {
|
|
13471
|
+
const bucket = path.join(root, nextBucketId());
|
|
13472
|
+
try {
|
|
13473
|
+
fs.mkdirSync(bucket);
|
|
13474
|
+
return path.join(bucket, repositoryName);
|
|
13475
|
+
} catch (error) {
|
|
13476
|
+
if (errorCode(error) === "EEXIST")
|
|
13477
|
+
continue;
|
|
13478
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13479
|
+
throw new Error(`Failed to create worktree bucket ${bucket} under gitWorktreeDir ${root}: ${message}`);
|
|
13480
|
+
}
|
|
13481
|
+
}
|
|
13482
|
+
throw new Error(`Every worktree bucket identifier under gitWorktreeDir ${root} is already in use.`);
|
|
13483
|
+
}
|
|
13484
|
+
function removeEmptyWorktreeBucket(checkout) {
|
|
13485
|
+
try {
|
|
13486
|
+
fs.rmdirSync(path.dirname(checkout));
|
|
13487
|
+
} catch {}
|
|
13488
|
+
}
|
|
13489
|
+
function linkedGitDirectory(checkout) {
|
|
13490
|
+
let pointer;
|
|
13491
|
+
try {
|
|
13492
|
+
if (!fs.lstatSync(path.join(checkout, ".git")).isFile())
|
|
13493
|
+
return;
|
|
13494
|
+
pointer = fs.readFileSync(path.join(checkout, ".git"), "utf8");
|
|
13495
|
+
} catch {
|
|
13496
|
+
return;
|
|
13497
|
+
}
|
|
13498
|
+
if (!pointer.startsWith("gitdir:"))
|
|
13499
|
+
return;
|
|
13500
|
+
const gitDir = pointer.slice("gitdir:".length).trim();
|
|
13501
|
+
return gitDir ? path.resolve(checkout, gitDir) : undefined;
|
|
13502
|
+
}
|
|
13503
|
+
function readWorktreeOwner(gitDir) {
|
|
13504
|
+
let contents;
|
|
13505
|
+
try {
|
|
13506
|
+
contents = fs.readFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), "utf8");
|
|
13507
|
+
} catch {
|
|
13508
|
+
return;
|
|
13509
|
+
}
|
|
13510
|
+
try {
|
|
13511
|
+
const record = JSON.parse(contents);
|
|
13512
|
+
return record.version === WORKTREE_OWNER_VERSION && typeof record.ownerRunId === "string" && record.ownerRunId ? record.ownerRunId : undefined;
|
|
13513
|
+
} catch {
|
|
13514
|
+
return;
|
|
13515
|
+
}
|
|
13516
|
+
}
|
|
13517
|
+
function findOwnedWorktreeCheckouts(root, repositoryName, ownerRunId) {
|
|
13518
|
+
let entries;
|
|
13519
|
+
try {
|
|
13520
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
13521
|
+
} catch {
|
|
13522
|
+
return [];
|
|
13523
|
+
}
|
|
13524
|
+
const owned = [];
|
|
13525
|
+
for (const entry of entries) {
|
|
13526
|
+
if (!entry.isDirectory() || !BUCKET_PATTERN.test(entry.name))
|
|
13527
|
+
continue;
|
|
13528
|
+
const checkout = path.join(root, entry.name, repositoryName);
|
|
13529
|
+
try {
|
|
13530
|
+
if (!fs.lstatSync(checkout).isDirectory())
|
|
13531
|
+
continue;
|
|
13532
|
+
} catch {
|
|
13533
|
+
continue;
|
|
13534
|
+
}
|
|
13535
|
+
const gitDir = linkedGitDirectory(checkout);
|
|
13536
|
+
if (gitDir !== undefined && readWorktreeOwner(gitDir) === ownerRunId)
|
|
13537
|
+
owned.push(checkout);
|
|
13538
|
+
}
|
|
13539
|
+
return owned.sort();
|
|
13540
|
+
}
|
|
13541
|
+
function bindWorktreeOwner(gitDir, ownerRunId) {
|
|
13542
|
+
const record = { version: WORKTREE_OWNER_VERSION, ownerRunId };
|
|
13543
|
+
fs.writeFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), `${JSON.stringify(record)}
|
|
13544
|
+
`, {
|
|
13545
|
+
encoding: "utf8",
|
|
13546
|
+
flag: "wx"
|
|
13547
|
+
});
|
|
13548
|
+
}
|
|
13549
|
+
var WORKTREE_OWNER_FILENAME = "atomic-workflow-run.json", WORKTREE_OWNER_VERSION = 1, BUCKET_PATTERN, MAX_BUCKET_ATTEMPTS = 65536, nextBucketIdOverride;
|
|
13550
|
+
var init_worktree_allocation = __esm(() => {
|
|
13551
|
+
BUCKET_PATTERN = /^[0-9a-f]{4}$/;
|
|
13552
|
+
});
|
|
13553
|
+
|
|
13554
|
+
// dist/builtin/workflows/src/runs/shared/worktree-generation.ts
|
|
13555
|
+
import * as fs2 from "node:fs";
|
|
13556
|
+
import * as path2 from "node:path";
|
|
13462
13557
|
function sameFileIdentity(left, right) {
|
|
13463
13558
|
return left.dev === right.dev && left.ino === right.ino;
|
|
13464
13559
|
}
|
|
@@ -13468,7 +13563,7 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
13468
13563
|
assertCurrent() {
|
|
13469
13564
|
if (disposed)
|
|
13470
13565
|
throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
|
|
13471
|
-
if (!
|
|
13566
|
+
if (!fs2.lstatSync(gitDir).isDirectory()) {
|
|
13472
13567
|
throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
|
|
13473
13568
|
}
|
|
13474
13569
|
},
|
|
@@ -13478,17 +13573,17 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
13478
13573
|
};
|
|
13479
13574
|
}
|
|
13480
13575
|
function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
13481
|
-
const gitFile =
|
|
13482
|
-
if (
|
|
13576
|
+
const gitFile = path2.join(worktreeRoot, ".git");
|
|
13577
|
+
if (fs2.lstatSync(gitFile).isDirectory())
|
|
13483
13578
|
return openMainCheckoutAnchor(gitFile);
|
|
13484
|
-
const descriptor =
|
|
13579
|
+
const descriptor = fs2.openSync(gitFile, "r");
|
|
13485
13580
|
let disposed = false;
|
|
13486
13581
|
const anchor = {
|
|
13487
13582
|
assertCurrent() {
|
|
13488
13583
|
if (disposed)
|
|
13489
13584
|
throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
|
|
13490
|
-
const held =
|
|
13491
|
-
const current =
|
|
13585
|
+
const held = fs2.fstatSync(descriptor, { bigint: true });
|
|
13586
|
+
const current = fs2.lstatSync(gitFile, { bigint: true });
|
|
13492
13587
|
if (!current.isFile() || !sameFileIdentity(held, current)) {
|
|
13493
13588
|
throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
|
|
13494
13589
|
}
|
|
@@ -13497,7 +13592,7 @@ function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
|
13497
13592
|
if (disposed)
|
|
13498
13593
|
return;
|
|
13499
13594
|
disposed = true;
|
|
13500
|
-
|
|
13595
|
+
fs2.closeSync(descriptor);
|
|
13501
13596
|
}
|
|
13502
13597
|
};
|
|
13503
13598
|
try {
|
|
@@ -13611,84 +13706,84 @@ var init_worktree_git_runner = __esm(() => {
|
|
|
13611
13706
|
});
|
|
13612
13707
|
|
|
13613
13708
|
// dist/builtin/workflows/src/runs/shared/worktree-root.ts
|
|
13614
|
-
import * as
|
|
13615
|
-
import * as
|
|
13709
|
+
import * as fs3 from "node:fs";
|
|
13710
|
+
import * as path3 from "node:path";
|
|
13616
13711
|
function pathFromPointer(contents, prefix, base) {
|
|
13617
13712
|
if (!contents.startsWith(prefix))
|
|
13618
13713
|
return;
|
|
13619
13714
|
const value2 = contents.slice(prefix.length).trim();
|
|
13620
13715
|
if (!value2)
|
|
13621
13716
|
return;
|
|
13622
|
-
return
|
|
13717
|
+
return path3.resolve(base, value2);
|
|
13623
13718
|
}
|
|
13624
13719
|
function readText(file) {
|
|
13625
13720
|
try {
|
|
13626
|
-
return
|
|
13721
|
+
return fs3.readFileSync(file, "utf8");
|
|
13627
13722
|
} catch {
|
|
13628
13723
|
return;
|
|
13629
13724
|
}
|
|
13630
13725
|
}
|
|
13631
13726
|
function samePath(left, right) {
|
|
13632
13727
|
try {
|
|
13633
|
-
const a =
|
|
13634
|
-
const b =
|
|
13728
|
+
const a = fs3.realpathSync.native(left);
|
|
13729
|
+
const b = fs3.realpathSync.native(right);
|
|
13635
13730
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
13636
13731
|
} catch {
|
|
13637
13732
|
return false;
|
|
13638
13733
|
}
|
|
13639
13734
|
}
|
|
13640
13735
|
function findGitRoot(cwd) {
|
|
13641
|
-
let current =
|
|
13736
|
+
let current = path3.resolve(cwd);
|
|
13642
13737
|
try {
|
|
13643
|
-
if (!
|
|
13644
|
-
current =
|
|
13738
|
+
if (!fs3.statSync(current).isDirectory())
|
|
13739
|
+
current = path3.dirname(current);
|
|
13645
13740
|
} catch {
|
|
13646
13741
|
return;
|
|
13647
13742
|
}
|
|
13648
13743
|
while (true) {
|
|
13649
13744
|
try {
|
|
13650
|
-
const entry =
|
|
13745
|
+
const entry = fs3.statSync(path3.join(current, ".git"));
|
|
13651
13746
|
if (entry.isDirectory() || entry.isFile())
|
|
13652
13747
|
return current;
|
|
13653
13748
|
} catch {}
|
|
13654
|
-
const parent =
|
|
13749
|
+
const parent = path3.dirname(current);
|
|
13655
13750
|
if (parent === current)
|
|
13656
13751
|
return;
|
|
13657
13752
|
current = parent;
|
|
13658
13753
|
}
|
|
13659
13754
|
}
|
|
13660
13755
|
function resolveMainRepoRoot(repoRoot) {
|
|
13661
|
-
const gitEntry =
|
|
13756
|
+
const gitEntry = path3.join(repoRoot, ".git");
|
|
13662
13757
|
let stats;
|
|
13663
13758
|
try {
|
|
13664
|
-
stats =
|
|
13759
|
+
stats = fs3.statSync(gitEntry);
|
|
13665
13760
|
} catch {
|
|
13666
13761
|
return;
|
|
13667
13762
|
}
|
|
13668
13763
|
if (stats.isDirectory())
|
|
13669
|
-
return
|
|
13764
|
+
return path3.resolve(repoRoot);
|
|
13670
13765
|
if (!stats.isFile())
|
|
13671
13766
|
return;
|
|
13672
13767
|
const pointer = readText(gitEntry);
|
|
13673
13768
|
if (pointer === undefined)
|
|
13674
13769
|
return;
|
|
13675
13770
|
const gitDir = pathFromPointer(pointer, "gitdir:", repoRoot);
|
|
13676
|
-
if (gitDir === undefined ||
|
|
13771
|
+
if (gitDir === undefined || path3.basename(path3.dirname(gitDir)) !== "worktrees")
|
|
13677
13772
|
return;
|
|
13678
|
-
const commonGitDir =
|
|
13679
|
-
if (
|
|
13773
|
+
const commonGitDir = path3.dirname(path3.dirname(gitDir));
|
|
13774
|
+
if (path3.basename(commonGitDir) !== ".git")
|
|
13680
13775
|
return;
|
|
13681
|
-
const backPointer = readText(
|
|
13682
|
-
const commonPointer = readText(
|
|
13776
|
+
const backPointer = readText(path3.join(gitDir, "gitdir"));
|
|
13777
|
+
const commonPointer = readText(path3.join(gitDir, "commondir"));
|
|
13683
13778
|
if (backPointer === undefined || commonPointer === undefined)
|
|
13684
13779
|
return;
|
|
13685
|
-
const linkedGitEntry =
|
|
13686
|
-
const declaredCommonDir =
|
|
13780
|
+
const linkedGitEntry = path3.resolve(gitDir, backPointer.trim());
|
|
13781
|
+
const declaredCommonDir = path3.resolve(gitDir, commonPointer.trim());
|
|
13687
13782
|
if (!backPointer.trim() || !commonPointer.trim())
|
|
13688
13783
|
return;
|
|
13689
13784
|
if (!samePath(linkedGitEntry, gitEntry) || !samePath(declaredCommonDir, commonGitDir))
|
|
13690
13785
|
return;
|
|
13691
|
-
return
|
|
13786
|
+
return path3.dirname(commonGitDir);
|
|
13692
13787
|
}
|
|
13693
13788
|
function findCanonicalGitRoot(cwd) {
|
|
13694
13789
|
const repoRoot = findGitRoot(cwd);
|
|
@@ -13697,33 +13792,31 @@ function findCanonicalGitRoot(cwd) {
|
|
|
13697
13792
|
var init_worktree_root = () => {};
|
|
13698
13793
|
|
|
13699
13794
|
// dist/builtin/workflows/src/runs/shared/worktree-git.ts
|
|
13700
|
-
import * as
|
|
13701
|
-
import * as
|
|
13702
|
-
function gitWorktreeSetupCacheKey(
|
|
13703
|
-
const repoRoot = repositoryRootForGitWorktree(options.cwd);
|
|
13704
|
-
const { logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
13705
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
13795
|
+
import * as fs4 from "node:fs";
|
|
13796
|
+
import * as path4 from "node:path";
|
|
13797
|
+
function gitWorktreeSetupCacheKey(request) {
|
|
13706
13798
|
return JSON.stringify([
|
|
13707
|
-
|
|
13708
|
-
comparablePathThroughExistingAncestor(
|
|
13799
|
+
comparablePathThroughExistingAncestor(request.options.cwd),
|
|
13800
|
+
comparablePathThroughExistingAncestor(request.target)
|
|
13709
13801
|
]);
|
|
13710
13802
|
}
|
|
13711
|
-
function createGitWorktreeSetupCache() {
|
|
13803
|
+
function createGitWorktreeSetupCache(ownerRunId) {
|
|
13712
13804
|
const results = new Map;
|
|
13713
13805
|
let disposed = false;
|
|
13714
13806
|
return {
|
|
13715
13807
|
get(options) {
|
|
13716
13808
|
if (disposed)
|
|
13717
13809
|
throw new Error("Git worktree setup cache is already disposed");
|
|
13718
|
-
const
|
|
13810
|
+
const request = resolveGitWorktreeSetupRequest(options);
|
|
13811
|
+
const key = gitWorktreeSetupCacheKey(request);
|
|
13719
13812
|
const cached = results.get(key);
|
|
13720
13813
|
if (cached !== undefined) {
|
|
13721
13814
|
assertCachedGitWorktreeIdentity(cached, options);
|
|
13722
13815
|
return cached.result;
|
|
13723
13816
|
}
|
|
13724
|
-
const
|
|
13725
|
-
results.set(key, {
|
|
13726
|
-
return result;
|
|
13817
|
+
const setup = setupGitWorktreeFromRequest(request, ownerRunId);
|
|
13818
|
+
results.set(key, { ...setup, identity: captureGitWorktreeIdentity(setup) });
|
|
13819
|
+
return setup.result;
|
|
13727
13820
|
},
|
|
13728
13821
|
dispose() {
|
|
13729
13822
|
if (disposed)
|
|
@@ -13755,10 +13848,10 @@ function worktreeRecoveryCommand(repositoryRoot, worktreeDir) {
|
|
|
13755
13848
|
return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
|
|
13756
13849
|
}
|
|
13757
13850
|
function hasGrandparent(value2) {
|
|
13758
|
-
const parent =
|
|
13851
|
+
const parent = path4.dirname(value2);
|
|
13759
13852
|
if (parent === value2)
|
|
13760
13853
|
return false;
|
|
13761
|
-
const grandparent =
|
|
13854
|
+
const grandparent = path4.dirname(parent);
|
|
13762
13855
|
return grandparent !== parent;
|
|
13763
13856
|
}
|
|
13764
13857
|
function pathAncestors(value2) {
|
|
@@ -13766,7 +13859,7 @@ function pathAncestors(value2) {
|
|
|
13766
13859
|
let current = value2;
|
|
13767
13860
|
while (true) {
|
|
13768
13861
|
ancestors.push(current);
|
|
13769
|
-
const parent =
|
|
13862
|
+
const parent = path4.dirname(current);
|
|
13770
13863
|
if (parent === current)
|
|
13771
13864
|
return ancestors;
|
|
13772
13865
|
current = parent;
|
|
@@ -13775,89 +13868,167 @@ function pathAncestors(value2) {
|
|
|
13775
13868
|
function shouldPreserveLogicalPath(logicalPath) {
|
|
13776
13869
|
return pathAncestors(logicalPath).some((ancestor) => {
|
|
13777
13870
|
try {
|
|
13778
|
-
return
|
|
13871
|
+
return fs4.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
|
|
13779
13872
|
} catch {
|
|
13780
13873
|
return false;
|
|
13781
13874
|
}
|
|
13782
13875
|
});
|
|
13783
13876
|
}
|
|
13784
13877
|
function canonicalizePreservingSymlinks(value2) {
|
|
13785
|
-
const logicalPath =
|
|
13878
|
+
const logicalPath = path4.resolve(value2);
|
|
13786
13879
|
const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
|
|
13787
13880
|
try {
|
|
13788
|
-
const canonical =
|
|
13881
|
+
const canonical = fs4.realpathSync.native(logicalPath);
|
|
13789
13882
|
return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
|
|
13790
13883
|
} catch {
|
|
13791
13884
|
return logicalPath;
|
|
13792
13885
|
}
|
|
13793
13886
|
}
|
|
13794
|
-
function resolveGitWorktreePath(value2,
|
|
13887
|
+
function resolveGitWorktreePath(value2, baseDir) {
|
|
13795
13888
|
const trimmed = value2.trim();
|
|
13796
13889
|
if (!trimmed)
|
|
13797
13890
|
throw new Error("gitWorktreeDir cannot be empty");
|
|
13798
13891
|
if (trimmed.includes("\x00")) {
|
|
13799
13892
|
throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
|
|
13800
13893
|
}
|
|
13801
|
-
return canonicalizePreservingSymlinks(
|
|
13894
|
+
return canonicalizePreservingSymlinks(path4.isAbsolute(trimmed) ? trimmed : path4.resolve(baseDir, trimmed));
|
|
13802
13895
|
}
|
|
13803
13896
|
function comparableRealPath(value2) {
|
|
13804
|
-
const realpath =
|
|
13897
|
+
const realpath = fs4.realpathSync.native(value2).replace(/\\/g, "/");
|
|
13805
13898
|
return process.platform === "win32" ? realpath.toLowerCase() : realpath;
|
|
13806
13899
|
}
|
|
13807
|
-
function
|
|
13808
|
-
let existing =
|
|
13900
|
+
function nearestExistingAncestor(value2) {
|
|
13901
|
+
let existing = path4.resolve(value2);
|
|
13809
13902
|
const missing = [];
|
|
13810
13903
|
while (!pathExistsSync(existing)) {
|
|
13811
|
-
const parent =
|
|
13904
|
+
const parent = path4.dirname(existing);
|
|
13812
13905
|
if (parent === existing)
|
|
13813
13906
|
break;
|
|
13814
|
-
missing.unshift(
|
|
13907
|
+
missing.unshift(path4.basename(existing));
|
|
13815
13908
|
existing = parent;
|
|
13816
13909
|
}
|
|
13817
|
-
|
|
13910
|
+
return { existing, missing };
|
|
13911
|
+
}
|
|
13912
|
+
function comparablePathThroughExistingAncestor(value2) {
|
|
13913
|
+
const { existing, missing } = nearestExistingAncestor(value2);
|
|
13914
|
+
const resolved = path4.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
|
|
13818
13915
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
13819
13916
|
}
|
|
13917
|
+
function isFileOrLink(value2) {
|
|
13918
|
+
try {
|
|
13919
|
+
const entry = fs4.lstatSync(value2);
|
|
13920
|
+
return entry.isFile() || entry.isSymbolicLink();
|
|
13921
|
+
} catch {
|
|
13922
|
+
return false;
|
|
13923
|
+
}
|
|
13924
|
+
}
|
|
13925
|
+
function isDirectory(value2) {
|
|
13926
|
+
try {
|
|
13927
|
+
return fs4.statSync(value2).isDirectory();
|
|
13928
|
+
} catch {
|
|
13929
|
+
return false;
|
|
13930
|
+
}
|
|
13931
|
+
}
|
|
13932
|
+
function looksLikeGitDirectory(directory) {
|
|
13933
|
+
if (!isDirectory(directory))
|
|
13934
|
+
return false;
|
|
13935
|
+
if (path4.basename(directory) === ".git")
|
|
13936
|
+
return true;
|
|
13937
|
+
if (!isFileOrLink(path4.join(directory, "HEAD")))
|
|
13938
|
+
return false;
|
|
13939
|
+
if (isFileOrLink(path4.join(directory, "commondir")))
|
|
13940
|
+
return true;
|
|
13941
|
+
return isDirectory(path4.join(directory, "objects")) && isDirectory(path4.join(directory, "refs"));
|
|
13942
|
+
}
|
|
13943
|
+
function enclosingGitMetadataDirectory(target) {
|
|
13944
|
+
const { existing } = nearestExistingAncestor(target);
|
|
13945
|
+
let realExisting = existing;
|
|
13946
|
+
try {
|
|
13947
|
+
realExisting = fs4.realpathSync.native(existing);
|
|
13948
|
+
} catch {}
|
|
13949
|
+
for (const candidate of new Set([...pathAncestors(existing), ...pathAncestors(realExisting)])) {
|
|
13950
|
+
if (looksLikeGitDirectory(candidate))
|
|
13951
|
+
return candidate;
|
|
13952
|
+
}
|
|
13953
|
+
const insideGitDir = runGitReadOnlyProbe(existing, ["rev-parse", "--is-inside-git-dir"]);
|
|
13954
|
+
if (insideGitDir.status !== 0 && isGitTimeoutResult(insideGitDir)) {
|
|
13955
|
+
throw new Error(`Timed out while validating gitWorktreeDir ${target}. Git reported: ${gitFailureMessage(insideGitDir)}`);
|
|
13956
|
+
}
|
|
13957
|
+
return insideGitDir.status === 0 && insideGitDir.stdout.trim() === "true" ? existing : undefined;
|
|
13958
|
+
}
|
|
13959
|
+
function assertSafeGitWorktreeTarget(target, invokingRoot) {
|
|
13960
|
+
const gitDirectory = enclosingGitMetadataDirectory(target);
|
|
13961
|
+
if (gitDirectory !== undefined) {
|
|
13962
|
+
throw new Error(`gitWorktreeDir must not be inside Git metadata: ${target} is inside the Git directory ${gitDirectory}. Choose a worktree root or a plain directory outside Git metadata.`);
|
|
13963
|
+
}
|
|
13964
|
+
if (invokingRoot !== undefined)
|
|
13965
|
+
validateWorktreeOutsideInvokingCheckout(target, invokingRoot);
|
|
13966
|
+
const { existing, missing } = nearestExistingAncestor(target);
|
|
13967
|
+
const workingTree = gitTopLevel(existing);
|
|
13968
|
+
if (workingTree === undefined)
|
|
13969
|
+
return;
|
|
13970
|
+
if (missing.length === 0 && comparableRealPath(target) === comparableRealPath(workingTree))
|
|
13971
|
+
return;
|
|
13972
|
+
throw new Error(`gitWorktreeDir must not be inside another Git working tree: ${target} is inside ${workingTree}. Pass that checkout's root to reuse it, or a path outside every Git checkout.`);
|
|
13973
|
+
}
|
|
13820
13974
|
function validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot) {
|
|
13821
13975
|
const repository = comparableRealPath(repoRoot);
|
|
13822
13976
|
const candidate = comparablePathThroughExistingAncestor(worktreeRoot);
|
|
13823
|
-
const relativePath =
|
|
13977
|
+
const relativePath = path4.relative(repository, candidate);
|
|
13824
13978
|
if (relativePath === "") {
|
|
13825
|
-
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate
|
|
13979
|
+
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate worktree path outside it.");
|
|
13826
13980
|
}
|
|
13827
|
-
if (!relativePath.startsWith(`..${
|
|
13828
|
-
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate
|
|
13981
|
+
if (!relativePath.startsWith(`..${path4.sep}`) && relativePath !== ".." && !path4.isAbsolute(relativePath)) {
|
|
13982
|
+
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate worktree path outside it.");
|
|
13829
13983
|
}
|
|
13830
13984
|
}
|
|
13831
13985
|
function gitPathFromOutput(value2, cwd) {
|
|
13832
13986
|
const trimmed = value2.trim();
|
|
13833
13987
|
if (!trimmed)
|
|
13834
13988
|
return;
|
|
13835
|
-
return
|
|
13989
|
+
return path4.isAbsolute(trimmed) ? path4.resolve(trimmed) : path4.resolve(cwd, trimmed);
|
|
13836
13990
|
}
|
|
13837
13991
|
function pathExistsSync(value2) {
|
|
13992
|
+
return pathStatSync(value2) !== undefined;
|
|
13993
|
+
}
|
|
13994
|
+
function pathStatSync(value2) {
|
|
13838
13995
|
try {
|
|
13839
|
-
|
|
13840
|
-
return true;
|
|
13996
|
+
return fs4.statSync(value2);
|
|
13841
13997
|
} catch (error) {
|
|
13842
13998
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
13843
13999
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
13844
|
-
return
|
|
14000
|
+
return;
|
|
13845
14001
|
throw error;
|
|
13846
14002
|
}
|
|
13847
14003
|
}
|
|
13848
|
-
function
|
|
14004
|
+
function probeInvokingRepository(cwd) {
|
|
13849
14005
|
const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
|
|
13850
14006
|
if (result.status !== 0) {
|
|
13851
14007
|
if (isGitTimeoutResult(result)) {
|
|
13852
14008
|
throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
13853
14009
|
}
|
|
13854
|
-
|
|
14010
|
+
return { failure: gitFailureMessage(result) };
|
|
13855
14011
|
}
|
|
13856
|
-
const
|
|
13857
|
-
if (
|
|
14012
|
+
const root = gitPathFromOutput(result.stdout, cwd);
|
|
14013
|
+
if (root === undefined) {
|
|
13858
14014
|
throw new Error(`gitWorktreeDir could not resolve the repository top level from ${cwd}: git returned an empty path.`);
|
|
13859
14015
|
}
|
|
13860
|
-
return
|
|
14016
|
+
return { repository: { root, ...cwdWithinGitRepository(cwd, root) } };
|
|
14017
|
+
}
|
|
14018
|
+
function resolveGitWorktreeSetupRequest(options) {
|
|
14019
|
+
const probe = probeInvokingRepository(options.cwd);
|
|
14020
|
+
if ("repository" in probe) {
|
|
14021
|
+
return {
|
|
14022
|
+
options,
|
|
14023
|
+
repository: probe.repository,
|
|
14024
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, probe.repository.logicalRoot)
|
|
14025
|
+
};
|
|
14026
|
+
}
|
|
14027
|
+
return {
|
|
14028
|
+
options,
|
|
14029
|
+
repositoryProbeFailure: probe.failure,
|
|
14030
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, canonicalizePreservingSymlinks(options.cwd))
|
|
14031
|
+
};
|
|
13861
14032
|
}
|
|
13862
14033
|
function gitTopLevelFromResult(result, cwd, description) {
|
|
13863
14034
|
if (result.status !== 0) {
|
|
@@ -13893,25 +14064,25 @@ function dirnameForEachRelativeComponent(base, relativePath) {
|
|
|
13893
14064
|
continue;
|
|
13894
14065
|
if (component === "..")
|
|
13895
14066
|
return;
|
|
13896
|
-
current =
|
|
14067
|
+
current = path4.dirname(current);
|
|
13897
14068
|
}
|
|
13898
14069
|
return current;
|
|
13899
14070
|
}
|
|
13900
14071
|
function cwdWithinGitRepository(cwd, repoRoot) {
|
|
13901
|
-
const sourceCwd =
|
|
13902
|
-
const sourceRepoRoot =
|
|
13903
|
-
const relativeCwd =
|
|
13904
|
-
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") ||
|
|
14072
|
+
const sourceCwd = fs4.realpathSync.native(cwd);
|
|
14073
|
+
const sourceRepoRoot = fs4.realpathSync.native(repoRoot);
|
|
14074
|
+
const relativeCwd = path4.relative(sourceRepoRoot, sourceCwd);
|
|
14075
|
+
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path4.isAbsolute(relativeCwd) ? "" : relativeCwd;
|
|
13905
14076
|
const logicalCwd = canonicalizePreservingSymlinks(cwd);
|
|
13906
14077
|
return {
|
|
13907
14078
|
relativeCwd: safeRelativeCwd,
|
|
13908
|
-
|
|
14079
|
+
logicalRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
|
|
13909
14080
|
};
|
|
13910
14081
|
}
|
|
13911
14082
|
function workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd) {
|
|
13912
|
-
return relativeCwd === "" ? worktreeRoot :
|
|
14083
|
+
return relativeCwd === "" ? worktreeRoot : path4.join(worktreeRoot, relativeCwd);
|
|
13913
14084
|
}
|
|
13914
|
-
function
|
|
14085
|
+
function validateGitWorktreeRoot(worktreeRoot) {
|
|
13915
14086
|
const topLevel = gitTopLevel(worktreeRoot);
|
|
13916
14087
|
if (topLevel === undefined) {
|
|
13917
14088
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
|
|
@@ -13919,8 +14090,18 @@ function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
|
|
|
13919
14090
|
if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
|
|
13920
14091
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
|
|
13921
14092
|
}
|
|
13922
|
-
|
|
13923
|
-
|
|
14093
|
+
return gitCommonDirForWorktree(topLevel);
|
|
14094
|
+
}
|
|
14095
|
+
function existingGitWorktreeCommonDir(directory) {
|
|
14096
|
+
return gitTopLevel(directory) === undefined ? undefined : validateGitWorktreeRoot(directory);
|
|
14097
|
+
}
|
|
14098
|
+
function sameGitCommonDir(left, right) {
|
|
14099
|
+
return comparableRealPath(left) === comparableRealPath(right);
|
|
14100
|
+
}
|
|
14101
|
+
function validateCreatedGitWorktree(worktreeRoot, repository) {
|
|
14102
|
+
assertSafeGitWorktreeTarget(worktreeRoot, repository.root);
|
|
14103
|
+
if (!sameGitCommonDir(validateGitWorktreeRoot(worktreeRoot), gitCommonDirForWorktree(repository.root))) {
|
|
14104
|
+
throw new Error(`gitWorktreeDir does not belong to the invoking Git repository: ${worktreeRoot}`);
|
|
13924
14105
|
}
|
|
13925
14106
|
}
|
|
13926
14107
|
function gitDirectoryForWorktree(cwd) {
|
|
@@ -13934,26 +14115,27 @@ function gitDirectoryForWorktree(cwd) {
|
|
|
13934
14115
|
return gitDir;
|
|
13935
14116
|
}
|
|
13936
14117
|
function captureGitWorktreeIdentitySnapshot(setup) {
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
const
|
|
14118
|
+
const { worktreeRoot, repositoryRoot } = setup.result;
|
|
14119
|
+
assertSafeGitWorktreeTarget(worktreeRoot, setup.invokingRoot);
|
|
14120
|
+
const commonDir = validateGitWorktreeRoot(worktreeRoot);
|
|
14121
|
+
const stats = fs4.statSync(worktreeRoot);
|
|
13940
14122
|
return {
|
|
13941
|
-
worktreeRealPath: comparableRealPath(
|
|
13942
|
-
repositoryRealPath: comparableRealPath(
|
|
13943
|
-
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(
|
|
13944
|
-
commonDirRealPath: comparableRealPath(
|
|
14123
|
+
worktreeRealPath: comparableRealPath(worktreeRoot),
|
|
14124
|
+
repositoryRealPath: comparableRealPath(repositoryRoot),
|
|
14125
|
+
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(worktreeRoot)),
|
|
14126
|
+
commonDirRealPath: comparableRealPath(commonDir),
|
|
13945
14127
|
device: stats.dev,
|
|
13946
14128
|
inode: stats.ino
|
|
13947
14129
|
};
|
|
13948
14130
|
}
|
|
13949
14131
|
function captureGitWorktreeIdentity(setup) {
|
|
13950
14132
|
const snapshot = captureGitWorktreeIdentitySnapshot(setup);
|
|
13951
|
-
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.worktreeRoot) };
|
|
14133
|
+
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.result.worktreeRoot) };
|
|
13952
14134
|
}
|
|
13953
14135
|
function assertCachedGitWorktreeIdentity(cached, options) {
|
|
13954
14136
|
let current;
|
|
13955
14137
|
try {
|
|
13956
|
-
current = captureGitWorktreeIdentitySnapshot(cached
|
|
14138
|
+
current = captureGitWorktreeIdentitySnapshot(cached);
|
|
13957
14139
|
cached.identity.generation.assertCurrent();
|
|
13958
14140
|
} catch (error) {
|
|
13959
14141
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -13961,34 +14143,58 @@ function assertCachedGitWorktreeIdentity(cached, options) {
|
|
|
13961
14143
|
}
|
|
13962
14144
|
const expected = cached.identity;
|
|
13963
14145
|
if (current.worktreeRealPath !== expected.worktreeRealPath || current.repositoryRealPath !== expected.repositoryRealPath || current.gitDirRealPath !== expected.gitDirRealPath || current.commonDirRealPath !== expected.commonDirRealPath || current.device !== expected.device || current.inode !== expected.inode) {
|
|
13964
|
-
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended
|
|
13965
|
-
}
|
|
14146
|
+
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended worktree.`);
|
|
14147
|
+
}
|
|
14148
|
+
}
|
|
14149
|
+
function requireInvokingRepository(request, action) {
|
|
14150
|
+
if (request.repository !== undefined)
|
|
14151
|
+
return request.repository;
|
|
14152
|
+
throw new Error([
|
|
14153
|
+
`gitWorktreeDir requires the workflow to be invoked from inside a Git repository to ${action}.`,
|
|
14154
|
+
"Start the workflow from a checkout of the repository the new worktree should come from, or set gitWorktreeDir to the root of an existing Git worktree to reuse it from any directory.",
|
|
14155
|
+
`Git reported: ${request.repositoryProbeFailure ?? "no repository"}`
|
|
14156
|
+
].join(" "));
|
|
14157
|
+
}
|
|
14158
|
+
function setupGitWorktreeFromRequest(request, ownerRunId) {
|
|
14159
|
+
const { repository, target } = request;
|
|
14160
|
+
assertSafeGitWorktreeTarget(target, repository?.root);
|
|
14161
|
+
const entry = pathStatSync(target);
|
|
14162
|
+
if (entry === undefined)
|
|
14163
|
+
return createGitWorktreeAtPath(request, false);
|
|
14164
|
+
if (!entry.isDirectory())
|
|
14165
|
+
throw new Error(`gitWorktreeDir already exists but is not a directory: ${target}`);
|
|
14166
|
+
if (fs4.readdirSync(target).length === 0)
|
|
14167
|
+
return createGitWorktreeAtPath(request, true);
|
|
14168
|
+
const commonDir = existingGitWorktreeCommonDir(target);
|
|
14169
|
+
if (commonDir === undefined)
|
|
14170
|
+
return allocateGitWorktree(request, ownerRunId);
|
|
14171
|
+
const sameRepository = repository !== undefined && sameGitCommonDir(commonDir, gitCommonDirForWorktree(repository.root));
|
|
14172
|
+
return {
|
|
14173
|
+
result: {
|
|
14174
|
+
worktreeRoot: target,
|
|
14175
|
+
cwd: sameRepository ? workspaceCwdForGitWorktreeRoot(target, repository.relativeCwd) : target,
|
|
14176
|
+
repositoryRoot: sameRepository ? repository.root : target,
|
|
14177
|
+
created: false
|
|
14178
|
+
},
|
|
14179
|
+
...repository !== undefined ? { invokingRoot: repository.root } : {}
|
|
14180
|
+
};
|
|
13966
14181
|
}
|
|
13967
|
-
function
|
|
13968
|
-
const
|
|
13969
|
-
const
|
|
14182
|
+
function createGitWorktreeAtPath(request, existingEmptyDirectory) {
|
|
14183
|
+
const { target: worktreeRoot } = request;
|
|
14184
|
+
const repository = requireInvokingRepository(request, `create a new worktree at ${worktreeRoot}`);
|
|
14185
|
+
const mainRoot = findCanonicalGitRoot(repository.root);
|
|
13970
14186
|
if (mainRoot === undefined) {
|
|
13971
|
-
throw new Error(`Unable to resolve the canonical main Git repository root from ${
|
|
13972
|
-
}
|
|
13973
|
-
const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
13974
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
13975
|
-
validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
|
|
13976
|
-
if (pathExistsSync(worktreeRoot)) {
|
|
13977
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
13978
|
-
return {
|
|
13979
|
-
worktreeRoot,
|
|
13980
|
-
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
|
|
13981
|
-
repositoryRoot: repoRoot,
|
|
13982
|
-
created: false
|
|
13983
|
-
};
|
|
14187
|
+
throw new Error(`Unable to resolve the canonical main Git repository root from ${repository.root}.`);
|
|
13984
14188
|
}
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
14189
|
+
if (!existingEmptyDirectory) {
|
|
14190
|
+
try {
|
|
14191
|
+
fs4.mkdirSync(path4.dirname(worktreeRoot), { recursive: true });
|
|
14192
|
+
} catch (error) {
|
|
14193
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14194
|
+
throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
|
|
14195
|
+
}
|
|
13990
14196
|
}
|
|
13991
|
-
const baseRef = options.baseBranch?.trim() || "HEAD";
|
|
14197
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
13992
14198
|
const result = runGit(mainRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
|
|
13993
14199
|
if (result.status !== 0) {
|
|
13994
14200
|
throw new Error([
|
|
@@ -13998,30 +14204,127 @@ function setupGitWorktree(options) {
|
|
|
13998
14204
|
`));
|
|
13999
14205
|
}
|
|
14000
14206
|
try {
|
|
14001
|
-
|
|
14002
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
14207
|
+
validateCreatedGitWorktree(worktreeRoot, repository);
|
|
14003
14208
|
} catch (error) {
|
|
14004
14209
|
runGit(mainRoot, ["worktree", "remove", "--force", worktreeRoot]);
|
|
14005
14210
|
const message = error instanceof Error ? error.message : String(error);
|
|
14006
14211
|
throw new Error(`Created gitWorktreeDir failed post-creation validation: ${message}`);
|
|
14007
14212
|
}
|
|
14008
14213
|
return {
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14214
|
+
result: {
|
|
14215
|
+
worktreeRoot,
|
|
14216
|
+
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, repository.relativeCwd),
|
|
14217
|
+
repositoryRoot: repository.root,
|
|
14218
|
+
created: true
|
|
14219
|
+
},
|
|
14220
|
+
invokingRoot: repository.root
|
|
14221
|
+
};
|
|
14222
|
+
}
|
|
14223
|
+
function containedWorktreeCwd(checkout, relativeCwd) {
|
|
14224
|
+
const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
|
|
14225
|
+
let resolved;
|
|
14226
|
+
try {
|
|
14227
|
+
resolved = fs4.realpathSync.native(cwd);
|
|
14228
|
+
} catch {
|
|
14229
|
+
resolved = "";
|
|
14230
|
+
}
|
|
14231
|
+
const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
|
|
14232
|
+
if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
|
|
14233
|
+
throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
|
|
14234
|
+
}
|
|
14235
|
+
return cwd;
|
|
14236
|
+
}
|
|
14237
|
+
function allocatedGitWorktreeSetup(checkout, repository, created) {
|
|
14238
|
+
return {
|
|
14239
|
+
result: {
|
|
14240
|
+
worktreeRoot: checkout,
|
|
14241
|
+
cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
|
|
14242
|
+
repositoryRoot: repository.root,
|
|
14243
|
+
created
|
|
14244
|
+
},
|
|
14245
|
+
invokingRoot: repository.root
|
|
14013
14246
|
};
|
|
14014
14247
|
}
|
|
14248
|
+
function validateOwnedGitWorktree(checkout, repository) {
|
|
14249
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14250
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14251
|
+
if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
|
|
14252
|
+
throw new Error(`${checkout} is not a linked worktree`);
|
|
14253
|
+
}
|
|
14254
|
+
const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
|
|
14255
|
+
if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
|
|
14256
|
+
throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
|
|
14257
|
+
}
|
|
14258
|
+
}
|
|
14259
|
+
function findOwnedGitWorktree(root, repository, ownerRunId) {
|
|
14260
|
+
const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
|
|
14261
|
+
if (checkout === undefined)
|
|
14262
|
+
return;
|
|
14263
|
+
try {
|
|
14264
|
+
validateOwnedGitWorktree(checkout, repository);
|
|
14265
|
+
return allocatedGitWorktreeSetup(checkout, repository, false);
|
|
14266
|
+
} catch (error) {
|
|
14267
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14268
|
+
throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
|
|
14269
|
+
}
|
|
14270
|
+
}
|
|
14271
|
+
function allocateGitWorktree(request, ownerRunId) {
|
|
14272
|
+
const { target: root } = request;
|
|
14273
|
+
const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
|
|
14274
|
+
if (ownerRunId !== undefined) {
|
|
14275
|
+
const owned = findOwnedGitWorktree(root, repository, ownerRunId);
|
|
14276
|
+
if (owned !== undefined)
|
|
14277
|
+
return owned;
|
|
14278
|
+
}
|
|
14279
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
14280
|
+
const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
|
|
14281
|
+
const commit = revision.status === 0 ? revision.stdout.trim() : "";
|
|
14282
|
+
if (commit === "") {
|
|
14283
|
+
throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
|
|
14284
|
+
}
|
|
14285
|
+
const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
|
|
14286
|
+
const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
|
|
14287
|
+
if (add.status !== 0) {
|
|
14288
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14289
|
+
throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
|
|
14290
|
+
}
|
|
14291
|
+
try {
|
|
14292
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
14293
|
+
runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
|
|
14294
|
+
runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
|
|
14295
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
14296
|
+
const setup = allocatedGitWorktreeSetup(checkout, repository, true);
|
|
14297
|
+
if (ownerRunId !== undefined)
|
|
14298
|
+
bindWorktreeOwner(gitDir, ownerRunId);
|
|
14299
|
+
return setup;
|
|
14300
|
+
} catch (error) {
|
|
14301
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
14302
|
+
const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
|
|
14303
|
+
removeEmptyWorktreeBucket(checkout);
|
|
14304
|
+
const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
|
|
14305
|
+
throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
|
|
14306
|
+
}
|
|
14307
|
+
}
|
|
14308
|
+
function runGitOrThrow(cwd, args) {
|
|
14309
|
+
const result = runGit(cwd, args);
|
|
14310
|
+
if (result.status !== 0)
|
|
14311
|
+
throw new Error(gitFailureMessage(result));
|
|
14312
|
+
}
|
|
14313
|
+
function setupGitWorktree(options) {
|
|
14314
|
+
return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
|
|
14315
|
+
}
|
|
14015
14316
|
var init_worktree_git = __esm(() => {
|
|
14317
|
+
init_worktree_allocation();
|
|
14016
14318
|
init_worktree_generation();
|
|
14017
14319
|
init_worktree_git_runner();
|
|
14018
14320
|
init_worktree_root();
|
|
14321
|
+
init_worktree_allocation();
|
|
14019
14322
|
init_worktree_git_runner();
|
|
14020
14323
|
});
|
|
14021
14324
|
|
|
14022
14325
|
// dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
|
|
14023
|
-
function createGitWorktreeSetupCacheOwner(suppliedCache) {
|
|
14024
|
-
const cache = suppliedCache ?? createGitWorktreeSetupCache();
|
|
14326
|
+
function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
|
|
14327
|
+
const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
|
|
14025
14328
|
const ownsCache = suppliedCache === undefined;
|
|
14026
14329
|
let released = false;
|
|
14027
14330
|
return {
|
|
@@ -14042,20 +14345,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
|
|
|
14042
14345
|
});
|
|
14043
14346
|
|
|
14044
14347
|
// dist/builtin/workflows/src/runs/shared/worktree-diff.ts
|
|
14045
|
-
import * as
|
|
14046
|
-
import * as
|
|
14348
|
+
import * as fs5 from "node:fs";
|
|
14349
|
+
import * as path5 from "node:path";
|
|
14047
14350
|
function safePatchAgentName(agent) {
|
|
14048
14351
|
return agent.replace(/[^\w.-]/g, "_");
|
|
14049
14352
|
}
|
|
14050
14353
|
function removeSyntheticPath(worktree, syntheticPath) {
|
|
14051
|
-
const resolved =
|
|
14052
|
-
const relative =
|
|
14053
|
-
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${
|
|
14354
|
+
const resolved = path5.resolve(worktree.path, syntheticPath);
|
|
14355
|
+
const relative = path5.relative(worktree.path, resolved);
|
|
14356
|
+
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path5.sep}`) || path5.isAbsolute(relative)) {
|
|
14054
14357
|
return;
|
|
14055
14358
|
}
|
|
14056
14359
|
let stat;
|
|
14057
14360
|
try {
|
|
14058
|
-
stat =
|
|
14361
|
+
stat = fs5.lstatSync(resolved);
|
|
14059
14362
|
} catch (error) {
|
|
14060
14363
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
14061
14364
|
if (code === "ENOENT")
|
|
@@ -14063,14 +14366,14 @@ function removeSyntheticPath(worktree, syntheticPath) {
|
|
|
14063
14366
|
throw error;
|
|
14064
14367
|
}
|
|
14065
14368
|
if (stat.isSymbolicLink()) {
|
|
14066
|
-
|
|
14369
|
+
fs5.unlinkSync(resolved);
|
|
14067
14370
|
return;
|
|
14068
14371
|
}
|
|
14069
14372
|
if (stat.isDirectory()) {
|
|
14070
|
-
|
|
14373
|
+
fs5.rmSync(resolved, { recursive: true, force: true });
|
|
14071
14374
|
return;
|
|
14072
14375
|
}
|
|
14073
|
-
|
|
14376
|
+
fs5.rmSync(resolved, { force: true });
|
|
14074
14377
|
}
|
|
14075
14378
|
function removeSyntheticPathsBeforeDiff(worktree) {
|
|
14076
14379
|
if (worktree.syntheticPaths.length === 0)
|
|
@@ -14119,7 +14422,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
14119
14422
|
const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
|
|
14120
14423
|
const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
|
|
14121
14424
|
const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
|
|
14122
|
-
|
|
14425
|
+
fs5.writeFileSync(patchPath, patch, "utf-8");
|
|
14123
14426
|
if (!patch.trim()) {
|
|
14124
14427
|
return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
|
|
14125
14428
|
}
|
|
@@ -14137,7 +14440,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
14137
14440
|
}
|
|
14138
14441
|
function writeEmptyPatch(patchPath) {
|
|
14139
14442
|
try {
|
|
14140
|
-
|
|
14443
|
+
fs5.writeFileSync(patchPath, "", "utf-8");
|
|
14141
14444
|
} catch {}
|
|
14142
14445
|
}
|
|
14143
14446
|
function hasWorktreeChanges(diff) {
|
|
@@ -14145,7 +14448,7 @@ function hasWorktreeChanges(diff) {
|
|
|
14145
14448
|
}
|
|
14146
14449
|
function diffWorktrees(setup, agents, diffsDir) {
|
|
14147
14450
|
try {
|
|
14148
|
-
|
|
14451
|
+
fs5.mkdirSync(diffsDir, { recursive: true });
|
|
14149
14452
|
} catch {
|
|
14150
14453
|
return [];
|
|
14151
14454
|
}
|
|
@@ -14153,7 +14456,7 @@ function diffWorktrees(setup, agents, diffsDir) {
|
|
|
14153
14456
|
for (let index = 0;index < setup.worktrees.length; index++) {
|
|
14154
14457
|
const worktree = setup.worktrees[index];
|
|
14155
14458
|
const agent = agents[index] ?? `task-${index + 1}`;
|
|
14156
|
-
const patchPath =
|
|
14459
|
+
const patchPath = path5.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
|
|
14157
14460
|
try {
|
|
14158
14461
|
diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
|
|
14159
14462
|
} catch {
|
|
@@ -14175,7 +14478,7 @@ function formatWorktreeDiffSummary(diffs) {
|
|
|
14175
14478
|
}
|
|
14176
14479
|
lines.push("");
|
|
14177
14480
|
}
|
|
14178
|
-
const patchesDir =
|
|
14481
|
+
const patchesDir = path5.dirname(changed[0].patchPath);
|
|
14179
14482
|
lines.push(`Full patches: ${patchesDir}`);
|
|
14180
14483
|
return lines.join(`
|
|
14181
14484
|
`).trimEnd();
|
|
@@ -14185,8 +14488,8 @@ var init_worktree_diff = __esm(() => {
|
|
|
14185
14488
|
});
|
|
14186
14489
|
|
|
14187
14490
|
// dist/builtin/workflows/src/runs/shared/worktree-post-create.ts
|
|
14188
|
-
import * as
|
|
14189
|
-
import * as
|
|
14491
|
+
import * as fs6 from "node:fs";
|
|
14492
|
+
import * as path6 from "node:path";
|
|
14190
14493
|
function tracked(repo, relativePath) {
|
|
14191
14494
|
const result = runGit(repo, ["ls-files", "--error-unmatch", "--", relativePath]);
|
|
14192
14495
|
return result.status === 0;
|
|
@@ -14206,12 +14509,12 @@ function hasTrackedPathComponent(repo, relativePath) {
|
|
|
14206
14509
|
return false;
|
|
14207
14510
|
}
|
|
14208
14511
|
function copyUntrackedFile(mainRoot, worktreeRoot, relativePath) {
|
|
14209
|
-
const source =
|
|
14210
|
-
const destination =
|
|
14211
|
-
if (!
|
|
14512
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14513
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14514
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14212
14515
|
return false;
|
|
14213
|
-
|
|
14214
|
-
|
|
14516
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14517
|
+
fs6.copyFileSync(source, destination);
|
|
14215
14518
|
return true;
|
|
14216
14519
|
}
|
|
14217
14520
|
function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
@@ -14224,14 +14527,14 @@ function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
|
14224
14527
|
return copied;
|
|
14225
14528
|
}
|
|
14226
14529
|
function populatedHooksDirectory(mainRoot) {
|
|
14227
|
-
const husky =
|
|
14530
|
+
const husky = path6.join(mainRoot, ".husky");
|
|
14228
14531
|
try {
|
|
14229
|
-
if (
|
|
14532
|
+
if (fs6.statSync(husky).isDirectory())
|
|
14230
14533
|
return husky;
|
|
14231
14534
|
} catch {}
|
|
14232
|
-
const hooks =
|
|
14535
|
+
const hooks = path6.join(mainRoot, ".git", "hooks");
|
|
14233
14536
|
try {
|
|
14234
|
-
const populated =
|
|
14537
|
+
const populated = fs6.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
|
|
14235
14538
|
return populated ? hooks : undefined;
|
|
14236
14539
|
} catch {
|
|
14237
14540
|
return;
|
|
@@ -14242,7 +14545,7 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
14242
14545
|
if (desired === undefined)
|
|
14243
14546
|
return;
|
|
14244
14547
|
const current = runGitPlain(mainRoot, ["config", "--get", "core.hooksPath"]);
|
|
14245
|
-
if (current.status === 0 &&
|
|
14548
|
+
if (current.status === 0 && path6.resolve(mainRoot, current.stdout.trim()) === desired)
|
|
14246
14549
|
return;
|
|
14247
14550
|
const configured = runGitPlain(mainRoot, ["config", "core.hooksPath", desired]);
|
|
14248
14551
|
if (configured.status !== 0) {
|
|
@@ -14251,10 +14554,10 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
14251
14554
|
}
|
|
14252
14555
|
function normalizeSymlinkDirectory(value2) {
|
|
14253
14556
|
const trimmed = value2.trim();
|
|
14254
|
-
if (!trimmed ||
|
|
14557
|
+
if (!trimmed || path6.isAbsolute(trimmed))
|
|
14255
14558
|
return;
|
|
14256
|
-
const normalized =
|
|
14257
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${
|
|
14559
|
+
const normalized = path6.normalize(trimmed);
|
|
14560
|
+
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path6.sep}`))
|
|
14258
14561
|
return;
|
|
14259
14562
|
return normalized;
|
|
14260
14563
|
}
|
|
@@ -14264,20 +14567,20 @@ function symlinkConfiguredDirectories(mainRoot, worktreeRoot, directories) {
|
|
|
14264
14567
|
const relativePath = normalizeSymlinkDirectory(rawDirectory);
|
|
14265
14568
|
if (relativePath === undefined || synthetic.includes(relativePath))
|
|
14266
14569
|
continue;
|
|
14267
|
-
const source =
|
|
14268
|
-
const destination =
|
|
14269
|
-
if (!
|
|
14570
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14571
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14572
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14270
14573
|
continue;
|
|
14271
|
-
|
|
14574
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14272
14575
|
try {
|
|
14273
|
-
|
|
14576
|
+
fs6.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
|
|
14274
14577
|
synthetic.push(relativePath);
|
|
14275
14578
|
} catch {}
|
|
14276
14579
|
}
|
|
14277
14580
|
return synthetic;
|
|
14278
14581
|
}
|
|
14279
14582
|
function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
14280
|
-
if (!
|
|
14583
|
+
if (!fs6.existsSync(path6.join(mainRoot, ".worktreeinclude")))
|
|
14281
14584
|
return;
|
|
14282
14585
|
const ignored = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-standard"]);
|
|
14283
14586
|
const included = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-from=.worktreeinclude"]);
|
|
@@ -14287,13 +14590,13 @@ function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
|
14287
14590
|
for (const relativePath of included.stdout.split(/\r?\n/).filter(Boolean)) {
|
|
14288
14591
|
if (!ignoredPaths.has(relativePath) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
14289
14592
|
continue;
|
|
14290
|
-
const source =
|
|
14291
|
-
const destination =
|
|
14593
|
+
const source = path6.join(mainRoot, relativePath);
|
|
14594
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
14292
14595
|
try {
|
|
14293
|
-
if (!
|
|
14596
|
+
if (!fs6.statSync(source).isFile() || fs6.existsSync(destination))
|
|
14294
14597
|
continue;
|
|
14295
|
-
|
|
14296
|
-
|
|
14598
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
14599
|
+
fs6.copyFileSync(source, destination);
|
|
14297
14600
|
} catch {}
|
|
14298
14601
|
}
|
|
14299
14602
|
}
|
|
@@ -14310,9 +14613,9 @@ var init_worktree_post_create = __esm(() => {
|
|
|
14310
14613
|
|
|
14311
14614
|
// dist/builtin/workflows/src/runs/shared/worktree-setup.ts
|
|
14312
14615
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
14313
|
-
import * as
|
|
14616
|
+
import * as fs7 from "node:fs";
|
|
14314
14617
|
import * as os from "node:os";
|
|
14315
|
-
import * as
|
|
14618
|
+
import * as path7 from "node:path";
|
|
14316
14619
|
import { createChildProcessEnvironment as createChildProcessEnvironment2 } from "@bastani/atomic";
|
|
14317
14620
|
function originDefaultBranch(mainRoot) {
|
|
14318
14621
|
const symbolic = runGit(mainRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
@@ -14332,7 +14635,7 @@ function originDefaultBranch(mainRoot) {
|
|
|
14332
14635
|
}
|
|
14333
14636
|
function resolveRepoState(cwd, explicitBaseBranch) {
|
|
14334
14637
|
const cwdRelative = resolveRepoCwdRelative(cwd);
|
|
14335
|
-
const toplevel =
|
|
14638
|
+
const toplevel = path7.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
|
|
14336
14639
|
const mainRoot = findCanonicalGitRoot(toplevel);
|
|
14337
14640
|
if (mainRoot === undefined)
|
|
14338
14641
|
throw new Error(`unable to resolve canonical main Git repository root from ${toplevel}`);
|
|
@@ -14345,9 +14648,9 @@ function resolveRepoState(cwd, explicitBaseBranch) {
|
|
|
14345
14648
|
return { toplevel, mainRoot, cwdRelative, baseCommit, baseRef };
|
|
14346
14649
|
}
|
|
14347
14650
|
function normalizeComparableCwd(cwd) {
|
|
14348
|
-
const resolved =
|
|
14651
|
+
const resolved = path7.resolve(cwd);
|
|
14349
14652
|
try {
|
|
14350
|
-
return
|
|
14653
|
+
return fs7.realpathSync(resolved);
|
|
14351
14654
|
} catch {
|
|
14352
14655
|
return resolved;
|
|
14353
14656
|
}
|
|
@@ -14358,7 +14661,7 @@ function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
|
|
|
14358
14661
|
const task = tasks[index];
|
|
14359
14662
|
if (!task.cwd)
|
|
14360
14663
|
continue;
|
|
14361
|
-
const taskCwd =
|
|
14664
|
+
const taskCwd = path7.isAbsolute(task.cwd) ? task.cwd : path7.resolve(sharedCwd, task.cwd);
|
|
14362
14665
|
if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
|
|
14363
14666
|
continue;
|
|
14364
14667
|
return { index, agent: task.agent, cwd: task.cwd };
|
|
@@ -14375,12 +14678,12 @@ function buildWorktreeBranch(runId, index) {
|
|
|
14375
14678
|
return `worktree-${flattenedWorktreeName(runId, index)}`;
|
|
14376
14679
|
}
|
|
14377
14680
|
function buildWorktreePath(mainRoot, runId, index) {
|
|
14378
|
-
return
|
|
14681
|
+
return path7.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
|
|
14379
14682
|
}
|
|
14380
14683
|
function ensureWorktreeIgnore(mainRoot) {
|
|
14381
|
-
const worktreesRoot =
|
|
14382
|
-
|
|
14383
|
-
|
|
14684
|
+
const worktreesRoot = path7.join(mainRoot, ".atomic", "worktrees");
|
|
14685
|
+
fs7.mkdirSync(worktreesRoot, { recursive: true });
|
|
14686
|
+
fs7.writeFileSync(path7.join(worktreesRoot, ".gitignore"), `*
|
|
14384
14687
|
`, "utf8");
|
|
14385
14688
|
}
|
|
14386
14689
|
function resolveRepoCwdRelative(cwd) {
|
|
@@ -14389,7 +14692,7 @@ function resolveRepoCwdRelative(cwd) {
|
|
|
14389
14692
|
throw new Error("worktree isolation requires a git repository");
|
|
14390
14693
|
}
|
|
14391
14694
|
const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
|
|
14392
|
-
const normalizedPrefix = rawPrefix ?
|
|
14695
|
+
const normalizedPrefix = rawPrefix ? path7.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
|
|
14393
14696
|
return normalizedPrefix === "." ? "" : normalizedPrefix;
|
|
14394
14697
|
}
|
|
14395
14698
|
function parseHookTimeout(timeoutMs) {
|
|
@@ -14407,19 +14710,19 @@ function resolveWorktreeSetupHook(repoRoot, config) {
|
|
|
14407
14710
|
if (!hookPath) {
|
|
14408
14711
|
throw new Error("worktree setup hook path cannot be empty");
|
|
14409
14712
|
}
|
|
14410
|
-
const expandedHookPath = hookPath.startsWith("~/") ?
|
|
14713
|
+
const expandedHookPath = hookPath.startsWith("~/") ? path7.join(os.homedir(), hookPath.slice(2)) : hookPath;
|
|
14411
14714
|
let resolvedPath;
|
|
14412
|
-
if (
|
|
14715
|
+
if (path7.isAbsolute(expandedHookPath)) {
|
|
14413
14716
|
resolvedPath = expandedHookPath;
|
|
14414
14717
|
} else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
|
|
14415
|
-
resolvedPath =
|
|
14718
|
+
resolvedPath = path7.resolve(repoRoot, expandedHookPath);
|
|
14416
14719
|
} else {
|
|
14417
14720
|
throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
|
|
14418
14721
|
}
|
|
14419
|
-
if (!
|
|
14722
|
+
if (!fs7.existsSync(resolvedPath)) {
|
|
14420
14723
|
throw new Error(`worktree setup hook not found: ${resolvedPath}`);
|
|
14421
14724
|
}
|
|
14422
|
-
if (
|
|
14725
|
+
if (fs7.statSync(resolvedPath).isDirectory()) {
|
|
14423
14726
|
throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
|
|
14424
14727
|
}
|
|
14425
14728
|
return {
|
|
@@ -14431,17 +14734,17 @@ function normalizeSyntheticPath(worktreePath, rawPath) {
|
|
|
14431
14734
|
const trimmed = rawPath.trim();
|
|
14432
14735
|
if (!trimmed)
|
|
14433
14736
|
throw new Error("synthetic path cannot be empty");
|
|
14434
|
-
if (
|
|
14737
|
+
if (path7.isAbsolute(trimmed))
|
|
14435
14738
|
throw new Error(`synthetic path must be relative: ${rawPath}`);
|
|
14436
|
-
const resolved =
|
|
14437
|
-
const relative =
|
|
14739
|
+
const resolved = path7.resolve(worktreePath, trimmed);
|
|
14740
|
+
const relative = path7.relative(worktreePath, resolved);
|
|
14438
14741
|
if (!relative || relative === ".") {
|
|
14439
14742
|
throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
|
|
14440
14743
|
}
|
|
14441
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
14744
|
+
if (relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative)) {
|
|
14442
14745
|
throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
|
|
14443
14746
|
}
|
|
14444
|
-
return
|
|
14747
|
+
return path7.normalize(relative);
|
|
14445
14748
|
}
|
|
14446
14749
|
function hasTrackedEntries(worktreePath, relativePath) {
|
|
14447
14750
|
const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
|
|
@@ -14513,16 +14816,16 @@ function waitForGitLockRelease() {
|
|
|
14513
14816
|
}
|
|
14514
14817
|
function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
14515
14818
|
for (const relativePath of new Set(relativePaths)) {
|
|
14516
|
-
const target =
|
|
14517
|
-
const relative =
|
|
14518
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
14819
|
+
const target = path7.resolve(worktreePath, relativePath);
|
|
14820
|
+
const relative = path7.relative(worktreePath, target);
|
|
14821
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative))
|
|
14519
14822
|
continue;
|
|
14520
14823
|
let current = worktreePath;
|
|
14521
|
-
for (const component of relative.split(
|
|
14522
|
-
current =
|
|
14824
|
+
for (const component of relative.split(path7.sep)) {
|
|
14825
|
+
current = path7.join(current, component);
|
|
14523
14826
|
let stat;
|
|
14524
14827
|
try {
|
|
14525
|
-
stat =
|
|
14828
|
+
stat = fs7.lstatSync(current);
|
|
14526
14829
|
} catch (error) {
|
|
14527
14830
|
const code = error.code;
|
|
14528
14831
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -14532,7 +14835,7 @@ function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
|
14532
14835
|
if (!stat.isSymbolicLink())
|
|
14533
14836
|
continue;
|
|
14534
14837
|
if (current === target)
|
|
14535
|
-
|
|
14838
|
+
fs7.unlinkSync(current);
|
|
14536
14839
|
break;
|
|
14537
14840
|
}
|
|
14538
14841
|
}
|
|
@@ -14560,7 +14863,7 @@ function createSingleWorktree(mainRoot, cwdRelative, runId, index, baseRef, base
|
|
|
14560
14863
|
cleanupSingleWorktree(mainRoot, { path: worktreePath, branch }, []);
|
|
14561
14864
|
throw new Error(message);
|
|
14562
14865
|
}
|
|
14563
|
-
const agentCwd = cwdRelative ?
|
|
14866
|
+
const agentCwd = cwdRelative ? path7.join(worktreePath, cwdRelative) : worktreePath;
|
|
14564
14867
|
const syntheticPaths = [];
|
|
14565
14868
|
try {
|
|
14566
14869
|
syntheticPaths.push(...performPostCreationSetup(mainRoot, worktreePath, symlinkDirectories));
|
|
@@ -14629,8 +14932,8 @@ var init_worktree = __esm(() => {
|
|
|
14629
14932
|
});
|
|
14630
14933
|
|
|
14631
14934
|
// dist/builtin/workflows/src/runs/shared/worktree-cwd.ts
|
|
14632
|
-
import { lstatSync as
|
|
14633
|
-
import { dirname as
|
|
14935
|
+
import { lstatSync as lstatSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
14936
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve7, sep as sep5 } from "node:path";
|
|
14634
14937
|
function relativePathWithin(root, candidate) {
|
|
14635
14938
|
const path = relative4(root, candidate);
|
|
14636
14939
|
return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path) ? undefined : path;
|
|
@@ -14649,14 +14952,14 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
14649
14952
|
if (cwd === undefined || cwd.length === 0)
|
|
14650
14953
|
return;
|
|
14651
14954
|
const absoluteInput = isAbsolute6(cwd);
|
|
14652
|
-
const candidate = absoluteInput ? cwd :
|
|
14955
|
+
const candidate = absoluteInput ? cwd : resolve7(setup.cwd, cwd);
|
|
14653
14956
|
if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
|
|
14654
14957
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
|
|
14655
14958
|
}
|
|
14656
14959
|
const candidateRealPath = existingRealPath(candidate, "cwd");
|
|
14657
14960
|
const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
|
|
14658
14961
|
if (worktreeRelative !== undefined)
|
|
14659
|
-
return
|
|
14962
|
+
return resolve7(setup.worktreeRoot, worktreeRelative);
|
|
14660
14963
|
if (!isAbsolute6(cwd)) {
|
|
14661
14964
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
|
|
14662
14965
|
}
|
|
@@ -14665,9 +14968,9 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
14665
14968
|
}
|
|
14666
14969
|
const repositoryRelative = absoluteInput ? relativePathWithin(repositoryRoot, candidateRealPath) : undefined;
|
|
14667
14970
|
if (repositoryRelative === undefined) {
|
|
14668
|
-
throw new Error(`atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
|
|
14971
|
+
throw new Error(repositoryRoot === worktreeRoot ? `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}, which belongs to a different repository than the invoking cwd; choose a cwd inside the worktree, or omit cwd.` : `atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
|
|
14669
14972
|
}
|
|
14670
|
-
const mappedCwd =
|
|
14973
|
+
const mappedCwd = resolve7(setup.worktreeRoot, repositoryRelative);
|
|
14671
14974
|
const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
|
|
14672
14975
|
if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
|
|
14673
14976
|
throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
|
|
@@ -14678,7 +14981,7 @@ var init_worktree_cwd = () => {};
|
|
|
14678
14981
|
|
|
14679
14982
|
// dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts
|
|
14680
14983
|
import { existsSync as existsSync3 } from "node:fs";
|
|
14681
|
-
import { isAbsolute as isAbsolute7, resolve as
|
|
14984
|
+
import { isAbsolute as isAbsolute7, resolve as resolve8 } from "node:path";
|
|
14682
14985
|
function normalizeTaskContexts(previous) {
|
|
14683
14986
|
if (previous === undefined)
|
|
14684
14987
|
return [];
|
|
@@ -14731,7 +15034,7 @@ function taskPrevious(options) {
|
|
|
14731
15034
|
function resolveWorkflowPath(filePath, baseDir) {
|
|
14732
15035
|
if (isAbsolute7(filePath))
|
|
14733
15036
|
return filePath;
|
|
14734
|
-
return
|
|
15037
|
+
return resolve8(baseDir ?? process.cwd(), filePath);
|
|
14735
15038
|
}
|
|
14736
15039
|
function taskBaseDir(options) {
|
|
14737
15040
|
if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
|
|
@@ -14886,7 +15189,7 @@ function taskWithSharedDefaults(taskOptions, options) {
|
|
|
14886
15189
|
var init_executor_task_prompts = () => {};
|
|
14887
15190
|
|
|
14888
15191
|
// dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
|
|
14889
|
-
import { isAbsolute as isAbsolute8, join as
|
|
15192
|
+
import { isAbsolute as isAbsolute8, join as join12, resolve as resolve9 } from "node:path";
|
|
14890
15193
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
14891
15194
|
function positiveConcurrency(value2) {
|
|
14892
15195
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < 1)
|
|
@@ -15039,10 +15342,10 @@ function workflowInvocationMetadata(inputDefaults, workflowInvocationCwd, cache,
|
|
|
15039
15342
|
function resolvedTaskCwd(cwd, workflowInvocationCwd) {
|
|
15040
15343
|
if (cwd === undefined)
|
|
15041
15344
|
return;
|
|
15042
|
-
return isAbsolute8(cwd) ? cwd :
|
|
15345
|
+
return isAbsolute8(cwd) ? cwd : resolve9(workflowInvocationCwd, cwd);
|
|
15043
15346
|
}
|
|
15044
15347
|
function taskWorktreeOutputsRoot(runId) {
|
|
15045
|
-
return
|
|
15348
|
+
return join12(workflowArtifactRunPath(runId), "task-outputs");
|
|
15046
15349
|
}
|
|
15047
15350
|
function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCwd = process.cwd(), symlinkDirectories) {
|
|
15048
15351
|
if (options.worktree !== true && !tasks.some((task) => task.worktree === true)) {
|
|
@@ -15052,7 +15355,7 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
15052
15355
|
throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
|
|
15053
15356
|
}
|
|
15054
15357
|
const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
|
|
15055
|
-
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd :
|
|
15358
|
+
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve9(workflowInvocationCwd, explicitCwd);
|
|
15056
15359
|
const conflict = findWorktreeTaskCwdConflict(tasks.map((task) => ({ agent: task.name, cwd: resolvedTaskCwd(task.cwd, workflowInvocationCwd) })), sharedCwd);
|
|
15057
15360
|
if (conflict !== undefined)
|
|
15058
15361
|
throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
|
|
@@ -15067,9 +15370,9 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
15067
15370
|
tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index].agentCwd })),
|
|
15068
15371
|
setup,
|
|
15069
15372
|
agents,
|
|
15070
|
-
diffsDir:
|
|
15373
|
+
diffsDir: join12(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
|
|
15071
15374
|
outputIsolations: tasks.map((_, index) => ({
|
|
15072
|
-
baseDir:
|
|
15375
|
+
baseDir: join12(trustedRoot, runId, scope, String(index)),
|
|
15073
15376
|
trustedRoot
|
|
15074
15377
|
}))
|
|
15075
15378
|
};
|
|
@@ -16796,8 +17099,12 @@ function createStageControlRegistry() {
|
|
|
16796
17099
|
}
|
|
16797
17100
|
await disposeEntries(entries);
|
|
16798
17101
|
},
|
|
16799
|
-
async releaseIdle(runId) {
|
|
16800
|
-
|
|
17102
|
+
async releaseIdle(runId, only) {
|
|
17103
|
+
const runMap = _byRun.get(runId);
|
|
17104
|
+
const entries = only === undefined ? [...runMap ?? []] : [[only, runMap?.get(only)]];
|
|
17105
|
+
for (const [stageId, entry] of entries) {
|
|
17106
|
+
if (entry === undefined)
|
|
17107
|
+
continue;
|
|
16801
17108
|
try {
|
|
16802
17109
|
await releaseIdleEntry(runId, stageId, entry);
|
|
16803
17110
|
} catch (error) {
|
|
@@ -16858,8 +17165,8 @@ var init_possible_stages = __esm(() => {
|
|
|
16858
17165
|
|
|
16859
17166
|
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
16860
17167
|
import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
|
|
16861
|
-
import { existsSync as existsSync4, mkdirSync as
|
|
16862
|
-
import { basename as basename5, dirname as
|
|
17168
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
17169
|
+
import { basename as basename5, dirname as dirname10, join as join13, resolve as resolve10 } from "node:path";
|
|
16863
17170
|
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
16864
17171
|
function encodeOption(value2) {
|
|
16865
17172
|
if (typeof value2 === "bigint")
|
|
@@ -16881,7 +17188,7 @@ function isReopenableSelection(selection) {
|
|
|
16881
17188
|
}
|
|
16882
17189
|
function encodeSelection(selection) {
|
|
16883
17190
|
if (selection.kind === "sqlite")
|
|
16884
|
-
return JSON.stringify({ ...selection, path:
|
|
17191
|
+
return JSON.stringify({ ...selection, path: resolve10(selection.path) });
|
|
16885
17192
|
return JSON.stringify({
|
|
16886
17193
|
...selection,
|
|
16887
17194
|
...selection.options === undefined ? {} : {
|
|
@@ -16913,7 +17220,7 @@ function openDurableJournal(durable) {
|
|
|
16913
17220
|
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
16914
17221
|
}
|
|
16915
17222
|
function poolStateDirectory(agentDir) {
|
|
16916
|
-
return
|
|
17223
|
+
return join13(dirname10(agentDir), "workflows", "pool");
|
|
16917
17224
|
}
|
|
16918
17225
|
function databaseIdentity(selection, agentDir) {
|
|
16919
17226
|
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
@@ -16921,16 +17228,16 @@ function databaseIdentity(selection, agentDir) {
|
|
|
16921
17228
|
function coordinationPath(durable) {
|
|
16922
17229
|
const selection = decodeSelection(durable.selection);
|
|
16923
17230
|
const identity = createHash3("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
16924
|
-
return
|
|
17231
|
+
return join13(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
16925
17232
|
}
|
|
16926
17233
|
function coordinationDatabase(durable) {
|
|
16927
17234
|
return basename5(coordinationPath(durable), ".sqlite");
|
|
16928
17235
|
}
|
|
16929
17236
|
function openCoordinationJournal(path) {
|
|
16930
|
-
const file =
|
|
17237
|
+
const file = resolve10(path);
|
|
16931
17238
|
let opened = coordinationJournals.get(file);
|
|
16932
17239
|
if (opened === undefined) {
|
|
16933
|
-
|
|
17240
|
+
mkdirSync6(dirname10(file), { recursive: true });
|
|
16934
17241
|
opened = resolveRunJournal({ journal: { path: file } });
|
|
16935
17242
|
coordinationJournals.set(file, opened);
|
|
16936
17243
|
opened.catch(() => {
|
|
@@ -16947,20 +17254,20 @@ function poolJournalFor(journal) {
|
|
|
16947
17254
|
return coordinations.get(journal) ?? journal;
|
|
16948
17255
|
}
|
|
16949
17256
|
function poolHostId(agentDir) {
|
|
16950
|
-
const file =
|
|
17257
|
+
const file = join13(poolStateDirectory(agentDir), "host-id");
|
|
16951
17258
|
try {
|
|
16952
|
-
const existing =
|
|
17259
|
+
const existing = readFileSync4(file, "utf8").trim();
|
|
16953
17260
|
if (existing !== "")
|
|
16954
17261
|
return existing;
|
|
16955
17262
|
} catch {}
|
|
16956
|
-
|
|
17263
|
+
mkdirSync6(dirname10(file), { recursive: true });
|
|
16957
17264
|
const id = randomUUID6();
|
|
16958
17265
|
try {
|
|
16959
|
-
|
|
17266
|
+
writeFileSync4(file, `${id}
|
|
16960
17267
|
`, { flag: "wx" });
|
|
16961
17268
|
return id;
|
|
16962
17269
|
} catch {
|
|
16963
|
-
return
|
|
17270
|
+
return readFileSync4(file, "utf8").trim();
|
|
16964
17271
|
}
|
|
16965
17272
|
}
|
|
16966
17273
|
var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
|
|
@@ -16975,7 +17282,7 @@ var init_pool_journal = __esm(() => {
|
|
|
16975
17282
|
|
|
16976
17283
|
// dist/builtin/workflows/src/workers/admission-host.ts
|
|
16977
17284
|
import { execFile, execFileSync } from "node:child_process";
|
|
16978
|
-
import { readdirSync as
|
|
17285
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
16979
17286
|
import { readFile } from "node:fs/promises";
|
|
16980
17287
|
import { hostname } from "node:os";
|
|
16981
17288
|
function admissionBootIdentity() {
|
|
@@ -17006,7 +17313,7 @@ function workerProcessExited(pid, final = false) {
|
|
|
17006
17313
|
return true;
|
|
17007
17314
|
if (process.platform === "linux") {
|
|
17008
17315
|
try {
|
|
17009
|
-
const stat =
|
|
17316
|
+
const stat = readFileSync5(`/proc/${pid}/stat`, "utf8");
|
|
17010
17317
|
return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
|
|
17011
17318
|
} catch {
|
|
17012
17319
|
return admissionProcessStopped(pid);
|
|
@@ -17026,7 +17333,7 @@ function scanProcessGroup(group) {
|
|
|
17026
17333
|
let complete = true;
|
|
17027
17334
|
let entries;
|
|
17028
17335
|
try {
|
|
17029
|
-
entries =
|
|
17336
|
+
entries = readdirSync4("/proc");
|
|
17030
17337
|
} catch {
|
|
17031
17338
|
return { members, complete: false };
|
|
17032
17339
|
}
|
|
@@ -17035,7 +17342,7 @@ function scanProcessGroup(group) {
|
|
|
17035
17342
|
continue;
|
|
17036
17343
|
let stat;
|
|
17037
17344
|
try {
|
|
17038
|
-
stat =
|
|
17345
|
+
stat = readFileSync5(`/proc/${entry}/stat`, "utf8");
|
|
17039
17346
|
} catch {
|
|
17040
17347
|
complete = false;
|
|
17041
17348
|
continue;
|
|
@@ -53774,10 +54081,10 @@ var init_verification_prompts = __esm(() => {
|
|
|
53774
54081
|
// dist/builtin/workflows/builtin/pattern-artifact-root.ts
|
|
53775
54082
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
53776
54083
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
53777
|
-
import { join as
|
|
54084
|
+
import { join as join14 } from "node:path";
|
|
53778
54085
|
async function stableArtifactRoot(ctx, workflowName) {
|
|
53779
54086
|
const cwd = ctx.cwd ?? process.cwd();
|
|
53780
|
-
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () =>
|
|
54087
|
+
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join14(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID9()}`));
|
|
53781
54088
|
await mkdir2(artifactDir, { recursive: true });
|
|
53782
54089
|
return artifactDir;
|
|
53783
54090
|
}
|
|
@@ -53817,7 +54124,7 @@ function fold_usage(results) {
|
|
|
53817
54124
|
|
|
53818
54125
|
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
53819
54126
|
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
53820
|
-
import { join as
|
|
54127
|
+
import { join as join15 } from "node:path";
|
|
53821
54128
|
import { Type as Type4 } from "typebox";
|
|
53822
54129
|
function isRecord3(value2) {
|
|
53823
54130
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -53912,8 +54219,8 @@ async function writeInvalid(path, stage) {
|
|
|
53912
54219
|
}
|
|
53913
54220
|
async function runAdversarialVerification(ctx) {
|
|
53914
54221
|
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
53915
|
-
const criteriaPath =
|
|
53916
|
-
const candidatePath =
|
|
54222
|
+
const criteriaPath = join15(root, "criteria.md");
|
|
54223
|
+
const candidatePath = join15(root, "candidate.md");
|
|
53917
54224
|
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
53918
54225
|
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
53919
54226
|
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
@@ -53945,7 +54252,7 @@ async function runAdversarialVerification(ctx) {
|
|
|
53945
54252
|
criterion,
|
|
53946
54253
|
verifierIndex: index + 1,
|
|
53947
54254
|
name,
|
|
53948
|
-
artifactPath:
|
|
54255
|
+
artifactPath: join15(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
53949
54256
|
});
|
|
53950
54257
|
}
|
|
53951
54258
|
}
|
|
@@ -53998,8 +54305,8 @@ async function runAdversarialVerification(ctx) {
|
|
|
53998
54305
|
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
53999
54306
|
finalDecision = decision;
|
|
54000
54307
|
finalMean = meanScore(scoreReports);
|
|
54001
|
-
scoreTablePath =
|
|
54002
|
-
reviewReportPath =
|
|
54308
|
+
scoreTablePath = join15(root, `verification-summary-${round}.json`);
|
|
54309
|
+
reviewReportPath = join15(root, `review-${round}.json`);
|
|
54003
54310
|
const summary = {
|
|
54004
54311
|
scores: scoreReports,
|
|
54005
54312
|
mean: finalMean,
|
|
@@ -54180,7 +54487,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
|
|
|
54180
54487
|
|
|
54181
54488
|
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
54182
54489
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
54183
|
-
import { join as
|
|
54490
|
+
import { join as join16 } from "node:path";
|
|
54184
54491
|
import { Type as Type6 } from "typebox";
|
|
54185
54492
|
function safeName(value2) {
|
|
54186
54493
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54220,7 +54527,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54220
54527
|
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
54221
54528
|
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
54222
54529
|
const category = fallback?.category ?? exactCategory;
|
|
54223
|
-
const classificationPath =
|
|
54530
|
+
const classificationPath = join16(artifactDir, "classification.json");
|
|
54224
54531
|
await writeFile2(classificationPath, JSON.stringify({
|
|
54225
54532
|
proposed_category: proposedCategory,
|
|
54226
54533
|
selected_category: category,
|
|
@@ -54230,7 +54537,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
54230
54537
|
fallback_used: needsFallback,
|
|
54231
54538
|
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
54232
54539
|
}, null, 2));
|
|
54233
|
-
const actionPath =
|
|
54540
|
+
const actionPath = join16(artifactDir, `action-${safeName(category)}.md`);
|
|
54234
54541
|
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
54235
54542
|
tools: actionTools(category),
|
|
54236
54543
|
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
@@ -54370,7 +54677,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
|
|
|
54370
54677
|
|
|
54371
54678
|
// dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
|
|
54372
54679
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
54373
|
-
import { join as
|
|
54680
|
+
import { join as join17 } from "node:path";
|
|
54374
54681
|
import { Type as Type8 } from "typebox";
|
|
54375
54682
|
function safeName2(value2, index) {
|
|
54376
54683
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54401,9 +54708,9 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54401
54708
|
context: "fresh"
|
|
54402
54709
|
});
|
|
54403
54710
|
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
54404
|
-
const partitionPath =
|
|
54711
|
+
const partitionPath = join17(artifactDir, "partition-plan.json");
|
|
54405
54712
|
await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
54406
|
-
const branchPaths = partitions.map((partition, index) =>
|
|
54713
|
+
const branchPaths = partitions.map((partition, index) => join17(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
|
|
54407
54714
|
const steps = partitions.map((partition, index) => ({
|
|
54408
54715
|
name: `branch-${safeName2(partition.label, index)}`,
|
|
54409
54716
|
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
@@ -54413,13 +54720,13 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54413
54720
|
outputMode: "file-only"
|
|
54414
54721
|
}));
|
|
54415
54722
|
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
54416
|
-
const manifestPath =
|
|
54723
|
+
const manifestPath = join17(artifactDir, "manifest.json");
|
|
54417
54724
|
await writeFile3(manifestPath, JSON.stringify({
|
|
54418
54725
|
task: ctx.inputs.prompt,
|
|
54419
54726
|
partition_plan: partitionPath,
|
|
54420
54727
|
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
|
|
54421
54728
|
}, null, 2));
|
|
54422
|
-
const synthesisPath =
|
|
54729
|
+
const synthesisPath = join17(artifactDir, "synthesis.md");
|
|
54423
54730
|
const synthesis = await ctx.task("synthesize", {
|
|
54424
54731
|
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
54425
54732
|
context: "fresh",
|
|
@@ -54584,7 +54891,7 @@ var init_generate_and_filter_prompts = __esm(() => {
|
|
|
54584
54891
|
|
|
54585
54892
|
// dist/builtin/workflows/builtin/generate-and-filter-runner.ts
|
|
54586
54893
|
import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
54587
|
-
import { join as
|
|
54894
|
+
import { join as join18 } from "node:path";
|
|
54588
54895
|
import { Type as Type10 } from "typebox";
|
|
54589
54896
|
function isRecord4(value2) {
|
|
54590
54897
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -54603,7 +54910,7 @@ function judgeDecision(value2) {
|
|
|
54603
54910
|
}
|
|
54604
54911
|
async function runGenerateAndFilter(ctx) {
|
|
54605
54912
|
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
54606
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) =>
|
|
54913
|
+
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join18(root, `candidate-${index + 1}.md`));
|
|
54607
54914
|
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
54608
54915
|
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
54609
54916
|
name: `generate-${index + 1}`,
|
|
@@ -54612,9 +54919,9 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54612
54919
|
output: path,
|
|
54613
54920
|
outputMode: "file-only"
|
|
54614
54921
|
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
54615
|
-
const manifestPath =
|
|
54922
|
+
const manifestPath = join18(root, "manifest.json");
|
|
54616
54923
|
await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
54617
|
-
const filterPath =
|
|
54924
|
+
const filterPath = join18(root, "filter.json");
|
|
54618
54925
|
const filtered = await ctx.task("dedupe-and-filter", {
|
|
54619
54926
|
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
|
|
54620
54927
|
context: "fresh",
|
|
@@ -54631,7 +54938,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54631
54938
|
let judgePath = null;
|
|
54632
54939
|
let decisionPath = filterPath;
|
|
54633
54940
|
if (ctx.inputs.use_judge) {
|
|
54634
|
-
judgePath =
|
|
54941
|
+
judgePath = join18(root, "judge.json");
|
|
54635
54942
|
const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
|
|
54636
54943
|
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
54637
54944
|
const judged = await ctx.task("judge", {
|
|
@@ -54647,7 +54954,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54647
54954
|
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
54648
54955
|
decisionPath = judgePath;
|
|
54649
54956
|
}
|
|
54650
|
-
const finalPath =
|
|
54957
|
+
const finalPath = join18(root, "shortlist.md");
|
|
54651
54958
|
const finalShortlist = await ctx.task("final-shortlist", {
|
|
54652
54959
|
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
|
|
54653
54960
|
context: "fresh",
|
|
@@ -55176,7 +55483,7 @@ var init_review_convergence = __esm(() => {
|
|
|
55176
55483
|
|
|
55177
55484
|
// dist/builtin/workflows/builtin/goal-artifacts.ts
|
|
55178
55485
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
55179
|
-
import { join as
|
|
55486
|
+
import { join as join19 } from "node:path";
|
|
55180
55487
|
function artifactSafeName(value2) {
|
|
55181
55488
|
const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
55182
55489
|
return safe.length > 0 ? safe : "artifact";
|
|
@@ -55187,7 +55494,7 @@ function withoutTurn(value2) {
|
|
|
55187
55494
|
return copy;
|
|
55188
55495
|
}
|
|
55189
55496
|
async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
|
|
55190
|
-
const artifactPath =
|
|
55497
|
+
const artifactPath = join19(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
55191
55498
|
await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
|
|
55192
55499
|
`, { encoding: "utf8" });
|
|
55193
55500
|
return artifactPath;
|
|
@@ -55196,7 +55503,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
|
|
|
55196
55503
|
reviewer: review.reviewer,
|
|
55197
55504
|
findings: review.findings
|
|
55198
55505
|
}))), reverification = []) {
|
|
55199
|
-
const artifactPath =
|
|
55506
|
+
const artifactPath = join19(artifactDir, "review-round-latest.json");
|
|
55200
55507
|
const visibleReviews = reviews.map(withoutTurn);
|
|
55201
55508
|
await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
|
|
55202
55509
|
`, { encoding: "utf8" });
|
|
@@ -55426,7 +55733,7 @@ var init_goal_review = __esm(() => {
|
|
|
55426
55733
|
// dist/builtin/workflows/builtin/goal-ledger.ts
|
|
55427
55734
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
55428
55735
|
import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
55429
|
-
import { dirname as
|
|
55736
|
+
import { dirname as dirname11, join as join20 } from "node:path";
|
|
55430
55737
|
import { isDeepStrictEqual } from "node:util";
|
|
55431
55738
|
function withoutTurn2(value2) {
|
|
55432
55739
|
const copy = { ...value2 };
|
|
@@ -55451,7 +55758,7 @@ function modelVisibleLedger(ledger) {
|
|
|
55451
55758
|
};
|
|
55452
55759
|
}
|
|
55453
55760
|
function goalLedgerStatePath(ledgerPath) {
|
|
55454
|
-
return
|
|
55761
|
+
return join20(dirname11(ledgerPath), LEDGER_STATE_FILENAME);
|
|
55455
55762
|
}
|
|
55456
55763
|
function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
|
|
55457
55764
|
ledger.lifecycle.push({
|
|
@@ -55527,7 +55834,7 @@ function recoverLegacyExecutionInterruption(ledger) {
|
|
|
55527
55834
|
return true;
|
|
55528
55835
|
}
|
|
55529
55836
|
async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
|
|
55530
|
-
const ledgerPath =
|
|
55837
|
+
const ledgerPath = join20(artifactDir, LEDGER_FILENAME);
|
|
55531
55838
|
const existing = await readExistingGoalLedger(ledgerPath);
|
|
55532
55839
|
if (existing !== undefined) {
|
|
55533
55840
|
if (recoverLegacyExecutionInterruption(existing))
|
|
@@ -56034,7 +56341,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
|
|
|
56034
56341
|
});
|
|
56035
56342
|
|
|
56036
56343
|
// dist/builtin/workflows/builtin/goal-runner.ts
|
|
56037
|
-
import { join as
|
|
56344
|
+
import { join as join21 } from "node:path";
|
|
56038
56345
|
function positiveInteger(value2, fallback) {
|
|
56039
56346
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
|
|
56040
56347
|
return fallback;
|
|
@@ -56085,7 +56392,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
56085
56392
|
appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
|
|
56086
56393
|
await writeGoalLedger(ledgerPath, ledger);
|
|
56087
56394
|
}
|
|
56088
|
-
const orchestratorReceiptPath =
|
|
56395
|
+
const orchestratorReceiptPath = join21(artifactDir, "orchestrator-receipt.md");
|
|
56089
56396
|
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
|
|
56090
56397
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
|
|
56091
56398
|
ledger,
|
|
@@ -56156,7 +56463,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
56156
56463
|
const reviewerName = result.name ?? result.stageName;
|
|
56157
56464
|
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
56158
56465
|
const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
|
|
56159
|
-
const reviewArtifactPath =
|
|
56466
|
+
const reviewArtifactPath = join21(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
|
|
56160
56467
|
const record = reviewDecisionToRecord({
|
|
56161
56468
|
turn,
|
|
56162
56469
|
reviewer: normalizedReviewerName,
|
|
@@ -56359,7 +56666,7 @@ var init_goal = __esm(() => {
|
|
|
56359
56666
|
}),
|
|
56360
56667
|
git_worktree_dir: Type15.String({
|
|
56361
56668
|
default: "",
|
|
56362
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
56669
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
56363
56670
|
}),
|
|
56364
56671
|
create_pr: Type15.Boolean({
|
|
56365
56672
|
default: false,
|
|
@@ -56477,7 +56784,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
|
|
|
56477
56784
|
|
|
56478
56785
|
// dist/builtin/workflows/builtin/loop-until-done-runner.ts
|
|
56479
56786
|
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
56480
|
-
import { join as
|
|
56787
|
+
import { join as join22 } from "node:path";
|
|
56481
56788
|
import { Type as Type16 } from "typebox";
|
|
56482
56789
|
function progressCurve(entries) {
|
|
56483
56790
|
return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
|
|
@@ -56560,18 +56867,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
|
|
|
56560
56867
|
}
|
|
56561
56868
|
async function runLoopUntilDone(ctx) {
|
|
56562
56869
|
const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
|
|
56563
|
-
const iterationsDir =
|
|
56564
|
-
const evaluationsDir =
|
|
56870
|
+
const iterationsDir = join22(artifactDir, "iterations");
|
|
56871
|
+
const evaluationsDir = join22(artifactDir, "evaluations");
|
|
56565
56872
|
await mkdir3(iterationsDir, { recursive: true });
|
|
56566
56873
|
await mkdir3(evaluationsDir, { recursive: true });
|
|
56567
|
-
const ledgerPath =
|
|
56874
|
+
const ledgerPath = join22(artifactDir, "progress-ledger.json");
|
|
56568
56875
|
const entries = [];
|
|
56569
56876
|
const iterationArtifactPaths = [];
|
|
56570
56877
|
const evaluationArtifactPaths = [];
|
|
56571
56878
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
|
|
56572
56879
|
for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
|
|
56573
|
-
const iterationPath =
|
|
56574
|
-
const evaluationPath =
|
|
56880
|
+
const iterationPath = join22(iterationsDir, `iteration-${iteration}.md`);
|
|
56881
|
+
const evaluationPath = join22(evaluationsDir, `evaluation-${iteration}.json`);
|
|
56575
56882
|
iterationArtifactPaths.push(iterationPath);
|
|
56576
56883
|
evaluationArtifactPaths.push(evaluationPath);
|
|
56577
56884
|
await ctx.task(`iteration-${iteration}`, {
|
|
@@ -56620,7 +56927,7 @@ async function runLoopUntilDone(ctx) {
|
|
|
56620
56927
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
|
|
56621
56928
|
if (decision.done) {
|
|
56622
56929
|
const report = progressReport(entries);
|
|
56623
|
-
const resultPath =
|
|
56930
|
+
const resultPath = join22(artifactDir, "result.md");
|
|
56624
56931
|
const final = await ctx.task("completion-summary", {
|
|
56625
56932
|
prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
|
|
56626
56933
|
context: "fresh",
|
|
@@ -56737,9 +57044,9 @@ var init_loop_until_done = __esm(() => {
|
|
|
56737
57044
|
|
|
56738
57045
|
// dist/builtin/workflows/builtin/open-claude-design-utils.ts
|
|
56739
57046
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
56740
|
-
import { mkdirSync as
|
|
57047
|
+
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
56741
57048
|
import { tmpdir, userInfo } from "node:os";
|
|
56742
|
-
import { join as
|
|
57049
|
+
import { join as join23 } from "node:path";
|
|
56743
57050
|
import { Type as Type18 } from "typebox";
|
|
56744
57051
|
import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
|
|
56745
57052
|
function taggedPrompt3(sections) {
|
|
@@ -56782,32 +57089,32 @@ function tmpArtifactBase() {
|
|
|
56782
57089
|
try {
|
|
56783
57090
|
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
56784
57091
|
} catch {}
|
|
56785
|
-
return
|
|
57092
|
+
return join23(tmpdir(), `open-claude-design-${user}`);
|
|
56786
57093
|
}
|
|
56787
57094
|
function prepareArtifactDir(cwd = process.cwd()) {
|
|
56788
57095
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
56789
57096
|
const tmpCandidates = [
|
|
56790
|
-
|
|
56791
|
-
|
|
57097
|
+
join23(tmpArtifactBase(), runId),
|
|
57098
|
+
join23(tmpdir(), "open-claude-design", runId)
|
|
56792
57099
|
];
|
|
56793
|
-
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [
|
|
57100
|
+
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join23(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
56794
57101
|
for (const candidate of candidates) {
|
|
56795
57102
|
try {
|
|
56796
|
-
|
|
57103
|
+
mkdirSync7(candidate, { recursive: true });
|
|
56797
57104
|
return {
|
|
56798
57105
|
runId,
|
|
56799
57106
|
artifactDir: candidate,
|
|
56800
|
-
previewPath:
|
|
56801
|
-
specPath:
|
|
57107
|
+
previewPath: join23(candidate, "preview.html"),
|
|
57108
|
+
specPath: join23(candidate, "spec.html")
|
|
56802
57109
|
};
|
|
56803
57110
|
} catch {}
|
|
56804
57111
|
}
|
|
56805
|
-
const fallback =
|
|
57112
|
+
const fallback = join23(tmpArtifactBase(), runId);
|
|
56806
57113
|
return {
|
|
56807
57114
|
runId,
|
|
56808
57115
|
artifactDir: fallback,
|
|
56809
|
-
previewPath:
|
|
56810
|
-
specPath:
|
|
57116
|
+
previewPath: join23(fallback, "preview.html"),
|
|
57117
|
+
specPath: join23(fallback, "spec.html")
|
|
56811
57118
|
};
|
|
56812
57119
|
}
|
|
56813
57120
|
function ensureAgentBrowser() {
|
|
@@ -57141,8 +57448,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
|
|
|
57141
57448
|
});
|
|
57142
57449
|
|
|
57143
57450
|
// dist/builtin/workflows/builtin/open-claude-design-setup.ts
|
|
57144
|
-
import { mkdirSync as
|
|
57145
|
-
import { join as
|
|
57451
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
57452
|
+
import { join as join24 } from "node:path";
|
|
57146
57453
|
function renderDiscoveryContext(discovery) {
|
|
57147
57454
|
return [
|
|
57148
57455
|
`Confirmed design brief: ${discovery.brief}`,
|
|
@@ -57207,10 +57514,10 @@ async function runDiscoveryAndInit(args) {
|
|
|
57207
57514
|
};
|
|
57208
57515
|
}
|
|
57209
57516
|
function designContextPath(artifactDir) {
|
|
57210
|
-
return
|
|
57517
|
+
return join24(artifactDir, DESIGN_CONTEXT_FILENAME);
|
|
57211
57518
|
}
|
|
57212
57519
|
function referencesBriefPath(artifactDir) {
|
|
57213
|
-
return
|
|
57520
|
+
return join24(artifactDir, REFERENCES_BRIEF_FILENAME);
|
|
57214
57521
|
}
|
|
57215
57522
|
function buildReferenceDiscoveryPrompt(args) {
|
|
57216
57523
|
const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
|
|
@@ -57236,8 +57543,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57236
57543
|
[
|
|
57237
57544
|
"Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
|
|
57238
57545
|
"From each gallery, choose 1-3 fitting designs and CLICK INTO each actual live or project-detail page; do not capture only the grid or thumbnail.",
|
|
57239
|
-
`Capture motion across the entire page: start \`agent-browser record start ${
|
|
57240
|
-
`Also run \`agent-browser screenshot ${
|
|
57546
|
+
`Capture motion across the entire page: start \`agent-browser record start ${join24(args.artifactDir, "ref-<site>-<n>.webm")}\`, scroll smoothly in small increments with waits (using repeated \`agent-browser scroll down 600\` or \`agent-browser mouse wheel 600\`) so animations fire and lazy content loads, then run \`agent-browser record stop\`.`,
|
|
57547
|
+
`Also run \`agent-browser screenshot ${join24(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
|
|
57241
57548
|
"Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
|
|
57242
57549
|
"Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
|
|
57243
57550
|
"Use ask_user_question to ask which reference direction they prefer, offering 2-4 strongest options plus `None of these fit`. If none fit, ask them to provide a reference image, screenshot, URL, or local file path and record the answer.",
|
|
@@ -57262,8 +57569,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
57262
57569
|
}
|
|
57263
57570
|
function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
|
|
57264
57571
|
try {
|
|
57265
|
-
|
|
57266
|
-
|
|
57572
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
57573
|
+
writeFileSync5(filePath, `${content}
|
|
57267
57574
|
`);
|
|
57268
57575
|
} catch (error) {
|
|
57269
57576
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -57814,7 +58121,7 @@ var init_ralph_review_gate = __esm(() => {
|
|
|
57814
58121
|
|
|
57815
58122
|
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
57816
58123
|
import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
|
|
57817
|
-
import { dirname as
|
|
58124
|
+
import { dirname as dirname12, join as join25 } from "node:path";
|
|
57818
58125
|
import { Type as Type20 } from "typebox";
|
|
57819
58126
|
function taggedPrompt4(sections) {
|
|
57820
58127
|
return sections.map(([tag, content]) => {
|
|
@@ -57854,11 +58161,11 @@ function slugifyResearchTopic(prompt) {
|
|
|
57854
58161
|
}
|
|
57855
58162
|
function defaultResearchPath(prompt, now = new Date) {
|
|
57856
58163
|
const date = now.toISOString().slice(0, 10);
|
|
57857
|
-
return
|
|
58164
|
+
return join25(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
57858
58165
|
}
|
|
57859
58166
|
async function createImplementationNotesFile(prompt, runId) {
|
|
57860
58167
|
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
57861
|
-
const notesPath =
|
|
58168
|
+
const notesPath = join25(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
57862
58169
|
const initialNotes = [
|
|
57863
58170
|
"# Implementation Notes",
|
|
57864
58171
|
"",
|
|
@@ -57879,7 +58186,7 @@ async function createImplementationNotesFile(prompt, runId) {
|
|
|
57879
58186
|
}
|
|
57880
58187
|
async function createQaEvidenceVideoPath(runId) {
|
|
57881
58188
|
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
57882
|
-
return
|
|
58189
|
+
return join25(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
57883
58190
|
}
|
|
57884
58191
|
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
57885
58192
|
return [
|
|
@@ -57945,7 +58252,7 @@ function artifactSafeName2(value2) {
|
|
|
57945
58252
|
return safe.length > 0 ? safe : "artifact";
|
|
57946
58253
|
}
|
|
57947
58254
|
async function writeJsonArtifact(path, content) {
|
|
57948
|
-
await mkdir4(
|
|
58255
|
+
await mkdir4(dirname12(path), { recursive: true });
|
|
57949
58256
|
await writeFile8(path, `${JSON.stringify(content, null, 2)}
|
|
57950
58257
|
`, {
|
|
57951
58258
|
encoding: "utf8"
|
|
@@ -58283,7 +58590,7 @@ var init_ralph_models = __esm(() => {
|
|
|
58283
58590
|
|
|
58284
58591
|
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
58285
58592
|
import { existsSync as existsSync5 } from "node:fs";
|
|
58286
|
-
import { join as
|
|
58593
|
+
import { join as join26, resolve as resolve11 } from "node:path";
|
|
58287
58594
|
async function runRalphWorkflow(ctx, options) {
|
|
58288
58595
|
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
58289
58596
|
let latestReviewReportPath;
|
|
@@ -58295,7 +58602,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58295
58602
|
let finalPrReport;
|
|
58296
58603
|
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
58297
58604
|
const workflowPrompt = prompt;
|
|
58298
|
-
const workflowResearchPath =
|
|
58605
|
+
const workflowResearchPath = resolve11(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
58299
58606
|
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
58300
58607
|
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
58301
58608
|
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
@@ -58344,7 +58651,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58344
58651
|
const researchPath = workflowResearchPath;
|
|
58345
58652
|
finalResearchPath = researchPath;
|
|
58346
58653
|
finalPlanPath = researchPath;
|
|
58347
|
-
const orchestratorReportPath =
|
|
58654
|
+
const orchestratorReportPath = join26(artifactDir, "orchestrator-report.md");
|
|
58348
58655
|
const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
|
|
58349
58656
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
|
|
58350
58657
|
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
@@ -58480,7 +58787,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58480
58787
|
diagnostics: parsed.diagnostics,
|
|
58481
58788
|
allowFinalActionRemaining: createPr
|
|
58482
58789
|
});
|
|
58483
|
-
const artifactPath =
|
|
58790
|
+
const artifactPath = join26(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
|
|
58484
58791
|
await writeJsonArtifact(artifactPath, {
|
|
58485
58792
|
reviewer,
|
|
58486
58793
|
decision: parsed.decision,
|
|
@@ -58536,7 +58843,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58536
58843
|
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
58537
58844
|
}));
|
|
58538
58845
|
}
|
|
58539
|
-
latestReviewReportPath = await writeJsonArtifact(
|
|
58846
|
+
latestReviewReportPath = await writeJsonArtifact(join26(artifactDir, "review-round-latest.json"), {
|
|
58540
58847
|
convergence_decision: roundConvergenceDecision,
|
|
58541
58848
|
convergence: convergenceEntries,
|
|
58542
58849
|
consolidated_findings: reverified.batch,
|
|
@@ -58685,7 +58992,7 @@ var init_ralph = __esm(() => {
|
|
|
58685
58992
|
}),
|
|
58686
58993
|
git_worktree_dir: Type21.String({
|
|
58687
58994
|
default: "",
|
|
58688
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
58995
|
+
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own. Absolute paths are used as-is; relative paths resolve from the invoking repo root (or the invoking cwd outside a Git repo). An existing Git worktree root of any repository is reused as-is, even from another repository or a non-Git cwd. Creating a worktree requires starting inside the source Git repo: a missing path or an empty directory becomes a new worktree from base_branch, and a non-empty non-Git directory is treated as a worktree root that gets this run's own <dir>/<4-hex>/<repo-name> checkout, reused on resume."
|
|
58689
58996
|
}),
|
|
58690
58997
|
create_pr: Type21.Boolean({
|
|
58691
58998
|
default: false,
|
|
@@ -58905,7 +59212,7 @@ var init_tournament_prompts = __esm(() => {
|
|
|
58905
59212
|
|
|
58906
59213
|
// dist/builtin/workflows/builtin/tournament-runner.ts
|
|
58907
59214
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
|
|
58908
|
-
import { join as
|
|
59215
|
+
import { join as join27, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve12 } from "node:path";
|
|
58909
59216
|
import { Type as Type22 } from "typebox";
|
|
58910
59217
|
function serializableObject2(value2) {
|
|
58911
59218
|
if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
|
|
@@ -58942,8 +59249,8 @@ function criterionSlug(id) {
|
|
|
58942
59249
|
}
|
|
58943
59250
|
function judgeArtifactPath(judgesDir, job, criterionIndex) {
|
|
58944
59251
|
const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
|
|
58945
|
-
const root =
|
|
58946
|
-
const path =
|
|
59252
|
+
const root = resolve12(judgesDir);
|
|
59253
|
+
const path = resolve12(judgesDir, filename);
|
|
58947
59254
|
const fromRoot = relative5(root, path);
|
|
58948
59255
|
if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
|
|
58949
59256
|
throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
|
|
@@ -58994,16 +59301,16 @@ function combineUsage(totals) {
|
|
|
58994
59301
|
}
|
|
58995
59302
|
async function runTournament(ctx) {
|
|
58996
59303
|
const artifactDir = await stableArtifactRoot(ctx, "tournament");
|
|
58997
|
-
const attemptsDir =
|
|
59304
|
+
const attemptsDir = join27(artifactDir, "attempts");
|
|
58998
59305
|
const numAttempts = ctx.inputs.num_attempts ?? 4;
|
|
58999
59306
|
const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
|
|
59000
59307
|
const nEvaluations = ctx.inputs.n_evaluations ?? 2;
|
|
59001
59308
|
const pivotCount = ctx.inputs.pivots ?? 1;
|
|
59002
59309
|
const seed = ctx.inputs.seed ?? 0;
|
|
59003
|
-
const judgesDir =
|
|
59310
|
+
const judgesDir = join27(artifactDir, "judges");
|
|
59004
59311
|
await mkdir5(attemptsDir, { recursive: true });
|
|
59005
59312
|
await mkdir5(judgesDir, { recursive: true });
|
|
59006
|
-
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
|
|
59313
|
+
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join27(attemptsDir, `attempt-${index + 1}.md`));
|
|
59007
59314
|
const models = ctx.inputs.models;
|
|
59008
59315
|
const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
|
|
59009
59316
|
name: `attempt-${index + 1}`,
|
|
@@ -59168,7 +59475,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59168
59475
|
const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
|
|
59169
59476
|
const budgetPivots = Math.min(pivotCount, entrants.length);
|
|
59170
59477
|
const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
|
|
59171
|
-
const comparisonPath =
|
|
59478
|
+
const comparisonPath = join27(artifactDir, "comparisons.json");
|
|
59172
59479
|
const assignment = modelAssignment(entrants, models);
|
|
59173
59480
|
const phaseUsage = {
|
|
59174
59481
|
attempts: fold_usage(attemptResults),
|
|
@@ -59204,7 +59511,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
59204
59511
|
await writeLedger(fold_usage([]));
|
|
59205
59512
|
const winner = ranking[0];
|
|
59206
59513
|
const winnerEntrant = entrants[winner.index];
|
|
59207
|
-
const resultPath =
|
|
59514
|
+
const resultPath = join27(artifactDir, "winner.md");
|
|
59208
59515
|
const reducer = await ctx.task("comparisons-reducer", {
|
|
59209
59516
|
prompt: renderComparisonsReducerPrompt({
|
|
59210
59517
|
task: ctx.inputs.prompt,
|
|
@@ -60110,7 +60417,7 @@ class SqlPoolQueue {
|
|
|
60110
60417
|
throw new Error("Stale pool coordinator authority", { cause: error });
|
|
60111
60418
|
throw error;
|
|
60112
60419
|
});
|
|
60113
|
-
const row = await this.current(tx, lease, token);
|
|
60420
|
+
const row = await this.current(tx, lease, token, true);
|
|
60114
60421
|
if (row.epoch !== lease.epoch)
|
|
60115
60422
|
throw new Error(STALE_WORK_LEASE);
|
|
60116
60423
|
assertSession();
|
|
@@ -62344,7 +62651,7 @@ function isBrokerStatusReport(value2) {
|
|
|
62344
62651
|
|
|
62345
62652
|
// dist/builtin/intercom/broker/paths.ts
|
|
62346
62653
|
import { homedir as homedir2 } from "os";
|
|
62347
|
-
import { join as
|
|
62654
|
+
import { join as join28 } from "path";
|
|
62348
62655
|
function getHomeDir() {
|
|
62349
62656
|
if (process.platform === "win32") {
|
|
62350
62657
|
if (process.env.USERPROFILE)
|
|
@@ -62361,7 +62668,7 @@ function expandTildePath(path) {
|
|
|
62361
62668
|
if (path === "~")
|
|
62362
62669
|
return getHomeDir();
|
|
62363
62670
|
if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
|
|
62364
|
-
return
|
|
62671
|
+
return join28(getHomeDir(), path.slice(2));
|
|
62365
62672
|
}
|
|
62366
62673
|
return path;
|
|
62367
62674
|
}
|
|
@@ -62372,31 +62679,31 @@ function getAgentDir5() {
|
|
|
62372
62679
|
const piAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
62373
62680
|
if (piAgentDir)
|
|
62374
62681
|
return expandTildePath(piAgentDir);
|
|
62375
|
-
return
|
|
62682
|
+
return join28(getHomeDir(), ".atomic", "agent");
|
|
62376
62683
|
}
|
|
62377
62684
|
function sanitizePipeSegment(value2) {
|
|
62378
62685
|
return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
|
|
62379
62686
|
}
|
|
62380
62687
|
function getIntercomDirPath(agentDir = getAgentDir5()) {
|
|
62381
|
-
return
|
|
62688
|
+
return join28(agentDir, "intercom");
|
|
62382
62689
|
}
|
|
62383
62690
|
function getBrokerPidPath(agentDir = getAgentDir5()) {
|
|
62384
|
-
return
|
|
62691
|
+
return join28(getIntercomDirPath(agentDir), "broker.pid");
|
|
62385
62692
|
}
|
|
62386
62693
|
function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
62387
|
-
return
|
|
62694
|
+
return join28(getIntercomDirPath(agentDir), "broker.spawn.lock");
|
|
62388
62695
|
}
|
|
62389
62696
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
62390
|
-
return
|
|
62697
|
+
return join28(getIntercomDirPath(agentDir), "broker.log");
|
|
62391
62698
|
}
|
|
62392
62699
|
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
62393
|
-
return
|
|
62700
|
+
return join28(getIntercomDirPath(agentDir), "broker.starting");
|
|
62394
62701
|
}
|
|
62395
62702
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
62396
62703
|
if (platform === "win32") {
|
|
62397
62704
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
62398
62705
|
}
|
|
62399
|
-
return
|
|
62706
|
+
return join28(getIntercomDirPath(agentDir), "broker.sock");
|
|
62400
62707
|
}
|
|
62401
62708
|
var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
|
|
62402
62709
|
var init_paths = () => {};
|
|
@@ -64080,11 +64387,11 @@ var init_client = __esm(() => {
|
|
|
64080
64387
|
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
64081
64388
|
|
|
64082
64389
|
// dist/builtin/intercom/broker/start-announcement.ts
|
|
64083
|
-
import { readFileSync as
|
|
64390
|
+
import { readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
64084
64391
|
function readBrokerStartAnnouncement(announcement) {
|
|
64085
64392
|
let text;
|
|
64086
64393
|
try {
|
|
64087
|
-
text =
|
|
64394
|
+
text = readFileSync6(announcement.path, "utf-8");
|
|
64088
64395
|
} catch {
|
|
64089
64396
|
return;
|
|
64090
64397
|
}
|
|
@@ -64103,26 +64410,26 @@ var init_start_announcement = () => {};
|
|
|
64103
64410
|
// dist/builtin/intercom/broker/spawn.ts
|
|
64104
64411
|
import { spawn } from "child_process";
|
|
64105
64412
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
64106
|
-
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync6, mkdirSync as
|
|
64107
|
-
import { join as
|
|
64413
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync9, openSync as openSync3, readFileSync as readFileSync7, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
64414
|
+
import { join as join29, dirname as dirname13 } from "path";
|
|
64108
64415
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
64109
64416
|
import { createRequire as createRequire3 } from "module";
|
|
64110
64417
|
import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
|
|
64111
64418
|
function isIntercomPackageRoot(dir) {
|
|
64112
|
-
return existsSync6(
|
|
64419
|
+
return existsSync6(join29(dir, "package.json")) && existsSync6(join29(dir, "broker"));
|
|
64113
64420
|
}
|
|
64114
64421
|
function resolveIntercomPackageRoot(moduleHref) {
|
|
64115
|
-
const here =
|
|
64422
|
+
const here = dirname13(fileURLToPath4(moduleHref));
|
|
64116
64423
|
if (isIntercomPackageRoot(here))
|
|
64117
64424
|
return here;
|
|
64118
|
-
return
|
|
64425
|
+
return join29(here, "..");
|
|
64119
64426
|
}
|
|
64120
64427
|
function resolveBrokerEntrypoint(packageRoot) {
|
|
64121
|
-
const bundled =
|
|
64122
|
-
return existsSync6(bundled) ? bundled :
|
|
64428
|
+
const bundled = join29(packageRoot, "broker", "broker.bundle.mjs");
|
|
64429
|
+
return existsSync6(bundled) ? bundled : join29(packageRoot, "broker", "broker.ts");
|
|
64123
64430
|
}
|
|
64124
64431
|
function ensurePrivateDirectory(path) {
|
|
64125
|
-
|
|
64432
|
+
mkdirSync9(path, { recursive: true, mode: 448 });
|
|
64126
64433
|
if (process.platform !== "win32")
|
|
64127
64434
|
chmodSync(path, 448);
|
|
64128
64435
|
}
|
|
@@ -64135,14 +64442,14 @@ function getCurrentBrokerRuntime() {
|
|
|
64135
64442
|
return isBunBinary ? "bun-binary" : "bun-source";
|
|
64136
64443
|
}
|
|
64137
64444
|
function requireFromExtensionDir(extensionDir) {
|
|
64138
|
-
return createRequire3(
|
|
64445
|
+
return createRequire3(join29(extensionDir, "package.json"));
|
|
64139
64446
|
}
|
|
64140
64447
|
function getJitiCliPath(extensionDir = EXTENSION_DIR) {
|
|
64141
64448
|
try {
|
|
64142
64449
|
const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
|
|
64143
|
-
return
|
|
64450
|
+
return join29(dirname13(jitiPackage), "lib", "jiti-cli.mjs");
|
|
64144
64451
|
} catch {
|
|
64145
|
-
return
|
|
64452
|
+
return join29(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
|
|
64146
64453
|
}
|
|
64147
64454
|
}
|
|
64148
64455
|
function getDefaultBrokerRunnerPath(extensionDir) {
|
|
@@ -64164,7 +64471,7 @@ function quoteWindowsArg(value2) {
|
|
|
64164
64471
|
return `"${value2.replace(/"/g, '""')}"`;
|
|
64165
64472
|
}
|
|
64166
64473
|
function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
|
|
64167
|
-
return
|
|
64474
|
+
return join29(intercomDir, "broker-launch.vbs");
|
|
64168
64475
|
}
|
|
64169
64476
|
function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
|
|
64170
64477
|
return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
|
|
@@ -64191,8 +64498,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
64191
64498
|
`);
|
|
64192
64499
|
}
|
|
64193
64500
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
64194
|
-
ensurePrivateDirectory(
|
|
64195
|
-
|
|
64501
|
+
ensurePrivateDirectory(dirname13(launcherPath));
|
|
64502
|
+
writeFileSync7(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
64196
64503
|
return launcherPath;
|
|
64197
64504
|
}
|
|
64198
64505
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -64235,14 +64542,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
|
|
|
64235
64542
|
};
|
|
64236
64543
|
}
|
|
64237
64544
|
function resetBrokerLog(logPath = BROKER_LOG) {
|
|
64238
|
-
ensurePrivateDirectory(
|
|
64545
|
+
ensurePrivateDirectory(dirname13(logPath));
|
|
64239
64546
|
try {
|
|
64240
64547
|
const previous = readBrokerLogTail(logPath);
|
|
64241
64548
|
closeSync3(openSync3(logPath, "w"));
|
|
64242
64549
|
if (previous.length > 0) {
|
|
64243
64550
|
try {
|
|
64244
64551
|
const previousPath = `${logPath}.previous`;
|
|
64245
|
-
|
|
64552
|
+
writeFileSync7(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
64246
64553
|
if (process.platform !== "win32")
|
|
64247
64554
|
chmodSync(previousPath, 384);
|
|
64248
64555
|
} catch {}
|
|
@@ -64386,7 +64693,7 @@ async function isBrokerRunning() {
|
|
|
64386
64693
|
if (!existsSync6(BROKER_PID))
|
|
64387
64694
|
return false;
|
|
64388
64695
|
try {
|
|
64389
|
-
const pid = parseInt(
|
|
64696
|
+
const pid = parseInt(readFileSync7(BROKER_PID, "utf-8").trim(), 10);
|
|
64390
64697
|
if (!Number.isFinite(pid))
|
|
64391
64698
|
return false;
|
|
64392
64699
|
process.kill(pid, 0);
|
|
@@ -64411,7 +64718,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
64411
64718
|
}
|
|
64412
64719
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
64413
64720
|
try {
|
|
64414
|
-
return
|
|
64721
|
+
return readFileSync7(lockPath, "utf-8").startsWith(owner);
|
|
64415
64722
|
} catch {
|
|
64416
64723
|
return false;
|
|
64417
64724
|
}
|
|
@@ -64423,7 +64730,7 @@ function acquireSpawnLock() {
|
|
|
64423
64730
|
${Date.now()}
|
|
64424
64731
|
`;
|
|
64425
64732
|
try {
|
|
64426
|
-
|
|
64733
|
+
writeFileSync7(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
64427
64734
|
return owner;
|
|
64428
64735
|
} catch (error) {
|
|
64429
64736
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -64453,7 +64760,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
64453
64760
|
return false;
|
|
64454
64761
|
}
|
|
64455
64762
|
try {
|
|
64456
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
64763
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync7(lockPath, "utf-8").trim().split(`
|
|
64457
64764
|
`);
|
|
64458
64765
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
64459
64766
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -64531,14 +64838,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
64531
64838
|
});
|
|
64532
64839
|
|
|
64533
64840
|
// dist/builtin/intercom/config.ts
|
|
64534
|
-
import { existsSync as existsSync7, readFileSync as
|
|
64841
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
64535
64842
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
64536
64843
|
function loadConfig() {
|
|
64537
64844
|
if (!existsSync7(CONFIG_PATH)) {
|
|
64538
64845
|
return { ...defaults };
|
|
64539
64846
|
}
|
|
64540
64847
|
try {
|
|
64541
|
-
const raw =
|
|
64848
|
+
const raw = readFileSync8(CONFIG_PATH, "utf-8");
|
|
64542
64849
|
const parsed = JSON.parse(raw);
|
|
64543
64850
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
64544
64851
|
throw new Error("Config must be a JSON object");
|
|
@@ -65121,12 +65428,12 @@ var init_sql_pool_usage = __esm(() => {
|
|
|
65121
65428
|
|
|
65122
65429
|
// dist/builtin/workflows/src/workers/pooled-watch-trace.ts
|
|
65123
65430
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
65124
|
-
import { dirname as
|
|
65431
|
+
import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
|
|
65125
65432
|
function configurePooledWatchTrace(journalPath, processRole) {
|
|
65126
65433
|
if (setting === undefined || setting === "" || setting === "0")
|
|
65127
65434
|
return;
|
|
65128
65435
|
role = processRole;
|
|
65129
|
-
file = setting === "1" ?
|
|
65436
|
+
file = setting === "1" ? join30(dirname14(resolve13(journalPath)), "pooled-watch-trace.jsonl") : resolve13(setting);
|
|
65130
65437
|
}
|
|
65131
65438
|
function tracePooledWatch(step, detail) {
|
|
65132
65439
|
if (file === undefined)
|
|
@@ -65320,7 +65627,7 @@ import { fork } from "node:child_process";
|
|
|
65320
65627
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
65321
65628
|
import { createWriteStream } from "node:fs";
|
|
65322
65629
|
import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65323
|
-
import { dirname as
|
|
65630
|
+
import { dirname as dirname15, join as join31, resolve as resolve14 } from "node:path";
|
|
65324
65631
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
65325
65632
|
function isRootLeaseLost(error) {
|
|
65326
65633
|
return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
|
|
@@ -65329,7 +65636,7 @@ function unconfirmedCleanup(groups) {
|
|
|
65329
65636
|
return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
|
|
65330
65637
|
}
|
|
65331
65638
|
function workerLogDirectory(journalPath, root) {
|
|
65332
|
-
return
|
|
65639
|
+
return join31(dirname15(resolve14(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
65333
65640
|
}
|
|
65334
65641
|
function token(work) {
|
|
65335
65642
|
return {
|
|
@@ -65517,6 +65824,7 @@ class PoolCoordinator {
|
|
|
65517
65824
|
cleanups = new Set;
|
|
65518
65825
|
controlAcks = new Map;
|
|
65519
65826
|
lastHeard = new Map;
|
|
65827
|
+
awaiting = new Map;
|
|
65520
65828
|
pendingActivity = new Map;
|
|
65521
65829
|
batches = new Map;
|
|
65522
65830
|
publicationFailures = new Map;
|
|
@@ -66260,7 +66568,7 @@ class PoolCoordinator {
|
|
|
66260
66568
|
this.slots.add(slot);
|
|
66261
66569
|
let ready = false;
|
|
66262
66570
|
let serial = Promise.resolve();
|
|
66263
|
-
const logPath =
|
|
66571
|
+
const logPath = join31(this.logDirectory, `${worker}.log`);
|
|
66264
66572
|
this.logs.set(child, logPath);
|
|
66265
66573
|
let logFailure;
|
|
66266
66574
|
const log = createWriteStream(logPath, { flags: "a" });
|
|
@@ -66316,6 +66624,7 @@ class PoolCoordinator {
|
|
|
66316
66624
|
this.readyWorkers.delete(worker);
|
|
66317
66625
|
this.controlAcks.delete(worker);
|
|
66318
66626
|
this.lastHeard.delete(worker);
|
|
66627
|
+
this.awaiting.delete(worker);
|
|
66319
66628
|
this.slots.delete(slot);
|
|
66320
66629
|
this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
|
|
66321
66630
|
for (const settle of slot.stageCommands.values())
|
|
@@ -66573,8 +66882,19 @@ class PoolCoordinator {
|
|
|
66573
66882
|
await this.sendResult(work.id);
|
|
66574
66883
|
});
|
|
66575
66884
|
const response = handled.then((value2) => routeReady ?? value2);
|
|
66576
|
-
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
66577
|
-
|
|
66885
|
+
if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
|
|
66886
|
+
this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
|
|
66887
|
+
const answered = () => {
|
|
66888
|
+
const left = (this.awaiting.get(worker) ?? 1) - 1;
|
|
66889
|
+
if (left > 0)
|
|
66890
|
+
this.awaiting.set(worker, left);
|
|
66891
|
+
else
|
|
66892
|
+
this.awaiting.delete(worker);
|
|
66893
|
+
if (this.incarnations.get(worker) === child)
|
|
66894
|
+
this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
|
|
66895
|
+
};
|
|
66896
|
+
serial = handled.then(answered, answered);
|
|
66897
|
+
}
|
|
66578
66898
|
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
|
|
66579
66899
|
const rootLeaseLost = isRootLeaseLost(error);
|
|
66580
66900
|
if (rootLeaseLost)
|
|
@@ -66644,7 +66964,10 @@ class PoolCoordinator {
|
|
|
66644
66964
|
if (work.epoch < lease.epoch)
|
|
66645
66965
|
await this.releaseRetained(work);
|
|
66646
66966
|
else
|
|
66647
|
-
await queue.expire(lease, work)
|
|
66967
|
+
await queue.expire(lease, work).catch((error) => {
|
|
66968
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
66969
|
+
throw error;
|
|
66970
|
+
});
|
|
66648
66971
|
}
|
|
66649
66972
|
})().finally(() => {
|
|
66650
66973
|
this.recovering = undefined;
|
|
@@ -66662,7 +66985,7 @@ class PoolCoordinator {
|
|
|
66662
66985
|
isLive(worker, child) {
|
|
66663
66986
|
this.observeResponsiveness();
|
|
66664
66987
|
const heard = this.lastHeard.get(worker);
|
|
66665
|
-
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
|
|
66988
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && ((this.awaiting.get(worker) ?? 0) > 0 || performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs);
|
|
66666
66989
|
}
|
|
66667
66990
|
async stop(child) {
|
|
66668
66991
|
const pid = child.pid;
|
|
@@ -67014,7 +67337,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
67014
67337
|
};
|
|
67015
67338
|
}
|
|
67016
67339
|
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
|
|
67017
|
-
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
|
|
67340
|
+
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
|
|
67018
67341
|
const candidateIds = new Set([
|
|
67019
67342
|
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
67020
67343
|
...activeStore.pendingStageMessagesFor(runId, stageName),
|
|
@@ -67070,7 +67393,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
|
|
|
67070
67393
|
}
|
|
67071
67394
|
}
|
|
67072
67395
|
}
|
|
67073
|
-
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
|
|
67396
|
+
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
|
|
67074
67397
|
const runs = activeStore.runs();
|
|
67075
67398
|
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
67076
67399
|
if (rootRunId === undefined)
|
|
@@ -67079,22 +67402,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
|
|
|
67079
67402
|
if (rootRun === undefined)
|
|
67080
67403
|
return [];
|
|
67081
67404
|
const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
|
|
67082
|
-
|
|
67405
|
+
const ended = stage?.status === "completed" || stage?.status === "skipped";
|
|
67406
|
+
if (ended && receivedByEndedStage.length === 0)
|
|
67083
67407
|
return [];
|
|
67084
67408
|
const hops = workflowBoundaryHops(runs, runId);
|
|
67085
67409
|
if (hops === undefined)
|
|
67086
67410
|
return [];
|
|
67087
67411
|
return (rootRun.pendingStageMessages ?? []).filter((entry) => {
|
|
67088
|
-
if (entry.sticky !== true || entry.status !== "queued")
|
|
67089
|
-
return false;
|
|
67090
|
-
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67091
|
-
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67092
|
-
return false;
|
|
67093
67412
|
if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId && (recipient === undefined || delivery.admission === "context" && delivery.sessionId === recipient.sessionId && (recipient.receivedMessageIds === undefined || recipient.receivedMessageIds.includes(entry.message.id)))))
|
|
67094
67413
|
return false;
|
|
67095
|
-
|
|
67414
|
+
if (ended && !receivedByEndedStage.includes(entry.message.id))
|
|
67415
|
+
return false;
|
|
67416
|
+
return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
|
|
67096
67417
|
});
|
|
67097
67418
|
}
|
|
67419
|
+
function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
|
|
67420
|
+
if (entry.sticky !== true || entry.status !== "queued")
|
|
67421
|
+
return false;
|
|
67422
|
+
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
67423
|
+
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
67424
|
+
return false;
|
|
67425
|
+
return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
|
|
67426
|
+
}
|
|
67098
67427
|
function claimPendingDelivery(store, runId, stageKey, messageId) {
|
|
67099
67428
|
let claims = pendingDeliveryClaims.get(store);
|
|
67100
67429
|
if (claims === undefined) {
|
|
@@ -67158,6 +67487,7 @@ class PoolStageHandoff {
|
|
|
67158
67487
|
owners = new Map;
|
|
67159
67488
|
publications = new Map;
|
|
67160
67489
|
drains = new Map;
|
|
67490
|
+
deliveryIssues = 0;
|
|
67161
67491
|
constructor(backend, store, queue, lease, claimRun) {
|
|
67162
67492
|
this.backend = backend;
|
|
67163
67493
|
this.store = store;
|
|
@@ -67238,11 +67568,23 @@ class PoolStageHandoff {
|
|
|
67238
67568
|
this.drains.set(stage, drain);
|
|
67239
67569
|
try {
|
|
67240
67570
|
await drain;
|
|
67571
|
+
} catch (error) {
|
|
67572
|
+
const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
|
|
67573
|
+
if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
|
|
67574
|
+
this.recordDeliveryIssue(error);
|
|
67575
|
+
throw error;
|
|
67241
67576
|
} finally {
|
|
67242
67577
|
if (this.drains.get(stage) === drain)
|
|
67243
67578
|
this.drains.delete(stage);
|
|
67244
67579
|
}
|
|
67245
67580
|
}
|
|
67581
|
+
recordDeliveryIssue(error) {
|
|
67582
|
+
this.deliveryIssues++;
|
|
67583
|
+
const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
|
|
67584
|
+
this.store.recordRunExecutionState(this.lease.runId, {
|
|
67585
|
+
intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
|
|
67586
|
+
});
|
|
67587
|
+
}
|
|
67246
67588
|
async complete(work) {
|
|
67247
67589
|
const root = this.lease.runId;
|
|
67248
67590
|
const result = await this.queue.result(root, work.id);
|
|
@@ -68598,7 +68940,7 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
68598
68940
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
68599
68941
|
import { fork as fork2 } from "node:child_process";
|
|
68600
68942
|
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
68601
|
-
import { resolve as
|
|
68943
|
+
import { resolve as resolve15 } from "node:path";
|
|
68602
68944
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
68603
68945
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
68604
68946
|
import {
|
|
@@ -68832,7 +69174,7 @@ class LocalWorkerPool {
|
|
|
68832
69174
|
async poolJournal() {
|
|
68833
69175
|
const journal = this.backend.journal;
|
|
68834
69176
|
if (this.options.durable === undefined) {
|
|
68835
|
-
if (!(journal instanceof SqlRunJournal) ||
|
|
69177
|
+
if (!(journal instanceof SqlRunJournal) || resolve15(this.options.journalPath) !== resolve15(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
68836
69178
|
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68837
69179
|
return journal;
|
|
68838
69180
|
}
|
|
@@ -69859,7 +70201,7 @@ var init_local_pool = __esm(() => {
|
|
|
69859
70201
|
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
69860
70202
|
|
|
69861
70203
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
69862
|
-
import { resolve as
|
|
70204
|
+
import { resolve as resolve16 } from "node:path";
|
|
69863
70205
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
69864
70206
|
async function restoreWorkerOptions(backend, options) {
|
|
69865
70207
|
const source = options.continuation?.source.id ?? options.runId;
|
|
@@ -69909,16 +70251,16 @@ async function activatePublicPool(backend, options) {
|
|
|
69909
70251
|
startupTimeoutMs: undefined,
|
|
69910
70252
|
leaseMs: undefined,
|
|
69911
70253
|
maxLoadPerCpu: undefined,
|
|
69912
|
-
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path:
|
|
70254
|
+
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve16(cwd, source.path) }))
|
|
69913
70255
|
};
|
|
69914
70256
|
const admission = options.admission && {
|
|
69915
70257
|
...options.admission,
|
|
69916
|
-
...options.admission.userDatabase ? { userDatabase:
|
|
70258
|
+
...options.admission.userDatabase ? { userDatabase: resolve16(cwd, options.admission.userDatabase) } : {}
|
|
69917
70259
|
};
|
|
69918
70260
|
if (durable !== undefined && admission?.userLimits) {
|
|
69919
|
-
if (admission.userDatabase !== undefined && admission.userDatabase !==
|
|
69920
|
-
throw new Error(`admission.userDatabase must be omitted, or ${
|
|
69921
|
-
admission.userDatabase =
|
|
70261
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve16(poolPath))
|
|
70262
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve16(poolPath)}, for a journal that is not a local SQLite file`);
|
|
70263
|
+
admission.userDatabase = resolve16(poolPath);
|
|
69922
70264
|
}
|
|
69923
70265
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
69924
70266
|
const resources = JSON.parse(JSON.stringify({
|
|
@@ -70524,6 +70866,7 @@ function createTaskPrimitive(runtime) {
|
|
|
70524
70866
|
}
|
|
70525
70867
|
})();
|
|
70526
70868
|
const stageMeta = stage.__modelFallbackMeta();
|
|
70869
|
+
stage.__releaseIfIdle?.();
|
|
70527
70870
|
return {
|
|
70528
70871
|
name,
|
|
70529
70872
|
stageName: name,
|
|
@@ -71322,7 +71665,7 @@ function hasUsableContentBlock(block) {
|
|
|
71322
71665
|
|
|
71323
71666
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
71324
71667
|
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
71325
|
-
import { dirname as
|
|
71668
|
+
import { dirname as dirname16, resolve as resolve17 } from "node:path";
|
|
71326
71669
|
import {
|
|
71327
71670
|
JsonlSessionStore,
|
|
71328
71671
|
resolveSessionStore,
|
|
@@ -71358,11 +71701,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
|
|
|
71358
71701
|
async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
71359
71702
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
71360
71703
|
return;
|
|
71361
|
-
const location =
|
|
71362
|
-
const legacy = await JsonlSessionStore.open(
|
|
71704
|
+
const location = resolve17(sessionFile);
|
|
71705
|
+
const legacy = await JsonlSessionStore.open(dirname16(location), { exactDirectory: true, scanExisting: false });
|
|
71363
71706
|
try {
|
|
71364
71707
|
for await (const file of legacy.scanFiles()) {
|
|
71365
|
-
if (
|
|
71708
|
+
if (resolve17(file.location) !== location || file.header.id !== sessionId)
|
|
71366
71709
|
continue;
|
|
71367
71710
|
const snapshot = await file.read();
|
|
71368
71711
|
if (await store.readHeader(sessionId) === undefined)
|
|
@@ -74188,6 +74531,8 @@ function createTrackedStageCaller(input) {
|
|
|
74188
74531
|
await runtime.releaseLiveHandle().catch(() => {});
|
|
74189
74532
|
}
|
|
74190
74533
|
runtime.state.sessionCheckpointed = finalizationError === undefined;
|
|
74534
|
+
if (runtime.state.contextUnreachable)
|
|
74535
|
+
runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
|
|
74191
74536
|
input.limiter.release();
|
|
74192
74537
|
if (finalizationError !== undefined)
|
|
74193
74538
|
throwFinalizationError(finalizationError.error);
|
|
@@ -74351,7 +74696,8 @@ function createStageContext(input) {
|
|
|
74351
74696
|
recordStageNotice({ kind: "abort", to: "interrupted" });
|
|
74352
74697
|
await innerCtx.abort();
|
|
74353
74698
|
},
|
|
74354
|
-
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
|
|
74699
|
+
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
|
|
74700
|
+
__releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
|
|
74355
74701
|
};
|
|
74356
74702
|
}
|
|
74357
74703
|
|
|
@@ -76040,10 +76386,10 @@ function isRetryableSameCandidateFailure(error) {
|
|
|
76040
76386
|
return isTransientExtensionStartupFailure(error);
|
|
76041
76387
|
return isRetryableSameModelFailure(error);
|
|
76042
76388
|
}
|
|
76043
|
-
function mayAdvanceToNextCandidate(error) {
|
|
76389
|
+
function mayAdvanceToNextCandidate(error, options) {
|
|
76044
76390
|
if (isExtensionStartupFailure(error))
|
|
76045
76391
|
return isTransientExtensionStartupFailure(error);
|
|
76046
|
-
return isRetryableModelFailure(error);
|
|
76392
|
+
return isRetryableModelFailure(error, options);
|
|
76047
76393
|
}
|
|
76048
76394
|
function hasMeaningfulUsage(usage) {
|
|
76049
76395
|
if (usage === undefined)
|
|
@@ -76135,6 +76481,7 @@ class StageSessionController {
|
|
|
76135
76481
|
structuredOutputExecutionFailureValue;
|
|
76136
76482
|
structuredOutputCycleAttemptMark;
|
|
76137
76483
|
unsubscribeTerminateWatcher;
|
|
76484
|
+
unbindAbortSignal;
|
|
76138
76485
|
sessionInternalRetries = 0;
|
|
76139
76486
|
unresolvedContextOverflowMessage;
|
|
76140
76487
|
generationSealed = false;
|
|
@@ -76624,6 +76971,8 @@ class StageSessionController {
|
|
|
76624
76971
|
this.pendingListeners.clear();
|
|
76625
76972
|
this.unsubscribeTerminateWatcher?.();
|
|
76626
76973
|
this.unsubscribeTerminateWatcher = undefined;
|
|
76974
|
+
this.unbindAbortSignal?.();
|
|
76975
|
+
this.unbindAbortSignal = undefined;
|
|
76627
76976
|
this.terminatingToolCallIds.clear();
|
|
76628
76977
|
this.messageAdmission.dispose();
|
|
76629
76978
|
this.deliveryActivity.dispose();
|
|
@@ -76718,8 +77067,10 @@ class StageSessionController {
|
|
|
76718
77067
|
};
|
|
76719
77068
|
if (signal.aborted)
|
|
76720
77069
|
onAbort();
|
|
76721
|
-
else
|
|
77070
|
+
else {
|
|
76722
77071
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
77072
|
+
this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
|
|
77073
|
+
}
|
|
76723
77074
|
}
|
|
76724
77075
|
markAbort(reason) {
|
|
76725
77076
|
this.abortGeneration += 1;
|
|
@@ -76746,6 +77097,9 @@ class StageSessionController {
|
|
|
76746
77097
|
state.controller.abort(reason);
|
|
76747
77098
|
this.thrownErrorRetryStates.clear();
|
|
76748
77099
|
}
|
|
77100
|
+
fallbackFailureOptions() {
|
|
77101
|
+
return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
|
|
77102
|
+
}
|
|
76749
77103
|
retrySettings() {
|
|
76750
77104
|
const managers = [
|
|
76751
77105
|
this.sessionSettingsManager,
|
|
@@ -77020,7 +77374,7 @@ class StageSessionController {
|
|
|
77020
77374
|
const errorSettingsManager = retrySettingsManagerFromError(error);
|
|
77021
77375
|
if (errorSettingsManager !== undefined)
|
|
77022
77376
|
this.sessionSettingsManager = errorSettingsManager;
|
|
77023
|
-
const retryableFailure = isRetryableModelFailure(error);
|
|
77377
|
+
const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
|
|
77024
77378
|
const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
|
|
77025
77379
|
recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
|
|
77026
77380
|
if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
|
|
@@ -77645,7 +77999,7 @@ class StageSessionController {
|
|
|
77645
77999
|
}
|
|
77646
78000
|
throw new WorkflowPromptModelFailure(terminalFailure);
|
|
77647
78001
|
} catch (err) {
|
|
77648
|
-
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
78002
|
+
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77649
78003
|
this.artifactCapture.settleAttempt(true);
|
|
77650
78004
|
const usage = this.takeAttemptUsage(resumedSession);
|
|
77651
78005
|
this.modelAttempts.push({
|
|
@@ -77667,7 +78021,7 @@ class StageSessionController {
|
|
|
77667
78021
|
...usage === undefined ? {} : { usage },
|
|
77668
78022
|
error: message
|
|
77669
78023
|
});
|
|
77670
|
-
if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
|
|
78024
|
+
if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77671
78025
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
77672
78026
|
this.pendingFallbackWarnings.length = 0;
|
|
77673
78027
|
this.notifyModelFallbackMetaChange();
|
|
@@ -77716,7 +78070,7 @@ class StageSessionController {
|
|
|
77716
78070
|
throw err;
|
|
77717
78071
|
const message = errorMessage3(err);
|
|
77718
78072
|
const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
|
|
77719
|
-
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
78073
|
+
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
77720
78074
|
this.recordSuccessfulAttempt(candidate);
|
|
77721
78075
|
return "handled";
|
|
77722
78076
|
}
|
|
@@ -77733,7 +78087,7 @@ class StageSessionController {
|
|
|
77733
78087
|
if (walk !== undefined) {
|
|
77734
78088
|
this.recordCandidateFailure(walk, index, err, candidates);
|
|
77735
78089
|
nextIndex = undefined;
|
|
77736
|
-
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
|
|
78090
|
+
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
|
|
77737
78091
|
try {
|
|
77738
78092
|
nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
|
|
77739
78093
|
} catch (error) {
|
|
@@ -77746,7 +78100,7 @@ class StageSessionController {
|
|
|
77746
78100
|
}
|
|
77747
78101
|
}
|
|
77748
78102
|
}
|
|
77749
|
-
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
|
|
78103
|
+
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
|
|
77750
78104
|
await this.settleFailedCandidate();
|
|
77751
78105
|
return "throw";
|
|
77752
78106
|
}
|
|
@@ -77841,7 +78195,7 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
77841
78195
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
77842
78196
|
import { createHash as createHash6 } from "node:crypto";
|
|
77843
78197
|
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
77844
|
-
import { basename as basename6, dirname as
|
|
78198
|
+
import { basename as basename6, dirname as dirname17, isAbsolute as isAbsolute11, join as join32, resolve as resolve18 } from "node:path";
|
|
77845
78199
|
function normalizeMaxOutput2(maxOutput) {
|
|
77846
78200
|
return {
|
|
77847
78201
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -77904,7 +78258,7 @@ function formatByteSize(bytes) {
|
|
|
77904
78258
|
}
|
|
77905
78259
|
function transcriptPath(runId, outputPath) {
|
|
77906
78260
|
const digest = createHash6("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
77907
|
-
return
|
|
78261
|
+
return join32(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename6(outputPath)}.transcript.md`);
|
|
77908
78262
|
}
|
|
77909
78263
|
function appendContent(lines, content) {
|
|
77910
78264
|
if (typeof content === "string") {
|
|
@@ -77949,7 +78303,7 @@ function renderTranscript(messages, fallbackOutput) {
|
|
|
77949
78303
|
`);
|
|
77950
78304
|
}
|
|
77951
78305
|
function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
|
|
77952
|
-
const absolutePath =
|
|
78306
|
+
const absolutePath = resolve18(outputPath);
|
|
77953
78307
|
const bytes = Buffer.byteLength(fullOutput, "utf8");
|
|
77954
78308
|
const lines = countLines(fullOutput);
|
|
77955
78309
|
const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
|
|
@@ -77964,8 +78318,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
|
|
|
77964
78318
|
return;
|
|
77965
78319
|
if (isAbsolute11(output))
|
|
77966
78320
|
return output;
|
|
77967
|
-
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd :
|
|
77968
|
-
return
|
|
78321
|
+
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve18(runtimeCwd, requestedCwd);
|
|
78322
|
+
return resolve18(baseCwd, output);
|
|
77969
78323
|
}
|
|
77970
78324
|
function degenerateWarning(fullOutput) {
|
|
77971
78325
|
return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
|
|
@@ -78024,7 +78378,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
78024
78378
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
78025
78379
|
const transcript = renderTranscript(messages, fullOutput);
|
|
78026
78380
|
try {
|
|
78027
|
-
await mkdir7(
|
|
78381
|
+
await mkdir7(dirname17(outputPath), { recursive: true });
|
|
78028
78382
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
78029
78383
|
} catch (err) {
|
|
78030
78384
|
return `${displayOutput}
|
|
@@ -78036,7 +78390,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
78036
78390
|
let transcriptError;
|
|
78037
78391
|
try {
|
|
78038
78392
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
78039
|
-
await mkdir7(
|
|
78393
|
+
await mkdir7(dirname17(transcriptFile), { recursive: true });
|
|
78040
78394
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
78041
78395
|
transcriptAvailable = true;
|
|
78042
78396
|
} catch (err) {
|
|
@@ -78547,7 +78901,8 @@ function createWorkflowStageFactory(input) {
|
|
|
78547
78901
|
stageFinalized: false,
|
|
78548
78902
|
sessionCheckpointed: false,
|
|
78549
78903
|
skippedForParallelFailFast: false,
|
|
78550
|
-
stageControlDropped: false
|
|
78904
|
+
stageControlDropped: false,
|
|
78905
|
+
contextUnreachable: false
|
|
78551
78906
|
};
|
|
78552
78907
|
const activeAskUserQuestionCalls = new Set;
|
|
78553
78908
|
const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
|
|
@@ -78793,9 +79148,18 @@ function createWorkflowStageFactory(input) {
|
|
|
78793
79148
|
hasContinuation: input.opts.continuation !== undefined,
|
|
78794
79149
|
hasScopedParents: stageFailFastScope?.parentIds !== undefined
|
|
78795
79150
|
});
|
|
78796
|
-
|
|
79151
|
+
const context = createStageContext({ runtime, runTrackedStageCall });
|
|
79152
|
+
unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
|
|
79153
|
+
return context;
|
|
79154
|
+
};
|
|
79155
|
+
}
|
|
79156
|
+
function releaseWhenUnreachable(state, registry, runId, stageId) {
|
|
79157
|
+
return () => {
|
|
79158
|
+
state.contextUnreachable = true;
|
|
79159
|
+
registry.releaseIdle(runId, stageId);
|
|
78797
79160
|
};
|
|
78798
79161
|
}
|
|
79162
|
+
var unreachableStageContexts;
|
|
78799
79163
|
var init_executor_stage_factory = __esm(() => {
|
|
78800
79164
|
init_intercom_group();
|
|
78801
79165
|
init_pending_stage_route_readiness();
|
|
@@ -78810,6 +79174,7 @@ var init_executor_stage_factory = __esm(() => {
|
|
|
78810
79174
|
init_pending_stage_delivery2();
|
|
78811
79175
|
init_stage_runner();
|
|
78812
79176
|
init_stage_runner_session();
|
|
79177
|
+
unreachableStageContexts = new FinalizationRegistry((release) => release());
|
|
78813
79178
|
});
|
|
78814
79179
|
|
|
78815
79180
|
// dist/builtin/workflows/src/engine/runtime.ts
|
|
@@ -79151,7 +79516,7 @@ async function executeRun(def, resolvedInputs, opts) {
|
|
|
79151
79516
|
const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
|
|
79152
79517
|
const tracker = new GraphFrontierTracker;
|
|
79153
79518
|
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
79154
|
-
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
|
|
79519
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
|
|
79155
79520
|
const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
|
|
79156
79521
|
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
79157
79522
|
let workflowCwd;
|