@bastani/atomic 0.9.61-alpha.1 → 0.9.61-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -4
- package/dist/builtin/intercom/index.bundle.mjs +3 -3
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +12 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +14 -0
- package/dist/builtin/workflows/README.md +9 -7
- package/dist/builtin/workflows/builtin/{chunk-h6bt0r0g.js → chunk-a2j0x1a6.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-g3b2zf8r.js → chunk-vzbec50q.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +1 -1
- package/dist/builtin/workflows/builtin/index.js +2 -2
- package/dist/builtin/workflows/builtin/ralph.js +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +828 -418
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +905 -429
- package/dist/builtin/workflows/src/index.js +798 -393
- package/dist/builtin/workflows/src/local-worker-entry.mjs +905 -429
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-retry.js +12 -3
- package/dist/core/agent-session-retry.js.map +1 -1
- package/dist/core/model-fallback-failures.d.ts +14 -4
- package/dist/core/model-fallback-failures.d.ts.map +1 -1
- package/dist/core/model-fallback-failures.js +43 -15
- package/dist/core/model-fallback-failures.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +1 -0
- package/dist/core/settings-defaults.d.ts.map +1 -1
- package/dist/core/settings-defaults.js +1 -0
- package/dist/core/settings-defaults.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +2 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-schema.d.ts +2 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +4 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-startup-chat-container.d.ts +2 -0
- package/dist/modes/interactive/interactive-startup-chat-container.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup-chat-container.js +6 -0
- package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.d.ts +8 -0
- package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +28 -6
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.d.ts +33 -5
- package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +91 -17
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/rpc/queued-writer.d.ts +2 -0
- package/dist/modes/rpc/queued-writer.d.ts.map +1 -1
- package/dist/modes/rpc/queued-writer.js +8 -0
- package/dist/modes/rpc/queued-writer.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +4 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/docs/intercom/reference.md +1 -1
- package/docs/models/evals.md +30 -2
- package/docs/settings.md +3 -0
- package/docs/subagents/reference.md +3 -1
- package/docs/workflows/api-reference.md +9 -6
- package/docs/workflows/builtins.md +1 -1
- package/docs/workflows/operations.md +4 -4
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +5 -0
|
@@ -3058,8 +3058,12 @@ function createStageControlRegistry() {
|
|
|
3058
3058
|
}
|
|
3059
3059
|
await disposeEntries(entries);
|
|
3060
3060
|
},
|
|
3061
|
-
async releaseIdle(runId) {
|
|
3062
|
-
|
|
3061
|
+
async releaseIdle(runId, only) {
|
|
3062
|
+
const runMap = _byRun.get(runId);
|
|
3063
|
+
const entries = only === undefined ? [...runMap ?? []] : [[only, runMap?.get(only)]];
|
|
3064
|
+
for (const [stageId, entry] of entries) {
|
|
3065
|
+
if (entry === undefined)
|
|
3066
|
+
continue;
|
|
3063
3067
|
try {
|
|
3064
3068
|
await releaseIdleEntry(runId, stageId, entry);
|
|
3065
3069
|
} catch (error) {
|
|
@@ -15573,9 +15577,104 @@ var init_workflow_artifacts = __esm(() => {
|
|
|
15573
15577
|
pendingArtifactPrunes = new Map;
|
|
15574
15578
|
});
|
|
15575
15579
|
|
|
15576
|
-
// dist/builtin/workflows/src/runs/shared/worktree-
|
|
15580
|
+
// dist/builtin/workflows/src/runs/shared/worktree-allocation.ts
|
|
15581
|
+
import { randomBytes } from "node:crypto";
|
|
15577
15582
|
import * as fs from "node:fs";
|
|
15578
15583
|
import * as path from "node:path";
|
|
15584
|
+
function nextBucketId() {
|
|
15585
|
+
return nextBucketIdOverride?.() ?? randomBytes(2).toString("hex");
|
|
15586
|
+
}
|
|
15587
|
+
function errorCode(error) {
|
|
15588
|
+
return error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
15589
|
+
}
|
|
15590
|
+
function allocateWorktreeCheckoutPath(root, repositoryName) {
|
|
15591
|
+
for (let attempt = 0;attempt < MAX_BUCKET_ATTEMPTS; attempt++) {
|
|
15592
|
+
const bucket = path.join(root, nextBucketId());
|
|
15593
|
+
try {
|
|
15594
|
+
fs.mkdirSync(bucket);
|
|
15595
|
+
return path.join(bucket, repositoryName);
|
|
15596
|
+
} catch (error) {
|
|
15597
|
+
if (errorCode(error) === "EEXIST")
|
|
15598
|
+
continue;
|
|
15599
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15600
|
+
throw new Error(`Failed to create worktree bucket ${bucket} under gitWorktreeDir ${root}: ${message}`);
|
|
15601
|
+
}
|
|
15602
|
+
}
|
|
15603
|
+
throw new Error(`Every worktree bucket identifier under gitWorktreeDir ${root} is already in use.`);
|
|
15604
|
+
}
|
|
15605
|
+
function removeEmptyWorktreeBucket(checkout) {
|
|
15606
|
+
try {
|
|
15607
|
+
fs.rmdirSync(path.dirname(checkout));
|
|
15608
|
+
} catch {}
|
|
15609
|
+
}
|
|
15610
|
+
function linkedGitDirectory(checkout) {
|
|
15611
|
+
let pointer;
|
|
15612
|
+
try {
|
|
15613
|
+
if (!fs.lstatSync(path.join(checkout, ".git")).isFile())
|
|
15614
|
+
return;
|
|
15615
|
+
pointer = fs.readFileSync(path.join(checkout, ".git"), "utf8");
|
|
15616
|
+
} catch {
|
|
15617
|
+
return;
|
|
15618
|
+
}
|
|
15619
|
+
if (!pointer.startsWith("gitdir:"))
|
|
15620
|
+
return;
|
|
15621
|
+
const gitDir = pointer.slice("gitdir:".length).trim();
|
|
15622
|
+
return gitDir ? path.resolve(checkout, gitDir) : undefined;
|
|
15623
|
+
}
|
|
15624
|
+
function readWorktreeOwner(gitDir) {
|
|
15625
|
+
let contents;
|
|
15626
|
+
try {
|
|
15627
|
+
contents = fs.readFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), "utf8");
|
|
15628
|
+
} catch {
|
|
15629
|
+
return;
|
|
15630
|
+
}
|
|
15631
|
+
try {
|
|
15632
|
+
const record = JSON.parse(contents);
|
|
15633
|
+
return record.version === WORKTREE_OWNER_VERSION && typeof record.ownerRunId === "string" && record.ownerRunId ? record.ownerRunId : undefined;
|
|
15634
|
+
} catch {
|
|
15635
|
+
return;
|
|
15636
|
+
}
|
|
15637
|
+
}
|
|
15638
|
+
function findOwnedWorktreeCheckouts(root, repositoryName, ownerRunId) {
|
|
15639
|
+
let entries;
|
|
15640
|
+
try {
|
|
15641
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
15642
|
+
} catch {
|
|
15643
|
+
return [];
|
|
15644
|
+
}
|
|
15645
|
+
const owned = [];
|
|
15646
|
+
for (const entry of entries) {
|
|
15647
|
+
if (!entry.isDirectory() || !BUCKET_PATTERN.test(entry.name))
|
|
15648
|
+
continue;
|
|
15649
|
+
const checkout = path.join(root, entry.name, repositoryName);
|
|
15650
|
+
try {
|
|
15651
|
+
if (!fs.lstatSync(checkout).isDirectory())
|
|
15652
|
+
continue;
|
|
15653
|
+
} catch {
|
|
15654
|
+
continue;
|
|
15655
|
+
}
|
|
15656
|
+
const gitDir = linkedGitDirectory(checkout);
|
|
15657
|
+
if (gitDir !== undefined && readWorktreeOwner(gitDir) === ownerRunId)
|
|
15658
|
+
owned.push(checkout);
|
|
15659
|
+
}
|
|
15660
|
+
return owned.sort();
|
|
15661
|
+
}
|
|
15662
|
+
function bindWorktreeOwner(gitDir, ownerRunId) {
|
|
15663
|
+
const record = { version: WORKTREE_OWNER_VERSION, ownerRunId };
|
|
15664
|
+
fs.writeFileSync(path.join(gitDir, WORKTREE_OWNER_FILENAME), `${JSON.stringify(record)}
|
|
15665
|
+
`, {
|
|
15666
|
+
encoding: "utf8",
|
|
15667
|
+
flag: "wx"
|
|
15668
|
+
});
|
|
15669
|
+
}
|
|
15670
|
+
var WORKTREE_OWNER_FILENAME = "atomic-workflow-run.json", WORKTREE_OWNER_VERSION = 1, BUCKET_PATTERN, MAX_BUCKET_ATTEMPTS = 65536, nextBucketIdOverride;
|
|
15671
|
+
var init_worktree_allocation = __esm(() => {
|
|
15672
|
+
BUCKET_PATTERN = /^[0-9a-f]{4}$/;
|
|
15673
|
+
});
|
|
15674
|
+
|
|
15675
|
+
// dist/builtin/workflows/src/runs/shared/worktree-generation.ts
|
|
15676
|
+
import * as fs2 from "node:fs";
|
|
15677
|
+
import * as path2 from "node:path";
|
|
15579
15678
|
function sameFileIdentity(left, right) {
|
|
15580
15679
|
return left.dev === right.dev && left.ino === right.ino;
|
|
15581
15680
|
}
|
|
@@ -15585,7 +15684,7 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
15585
15684
|
assertCurrent() {
|
|
15586
15685
|
if (disposed)
|
|
15587
15686
|
throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
|
|
15588
|
-
if (!
|
|
15687
|
+
if (!fs2.lstatSync(gitDir).isDirectory()) {
|
|
15589
15688
|
throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
|
|
15590
15689
|
}
|
|
15591
15690
|
},
|
|
@@ -15595,17 +15694,17 @@ function openMainCheckoutAnchor(gitDir) {
|
|
|
15595
15694
|
};
|
|
15596
15695
|
}
|
|
15597
15696
|
function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
15598
|
-
const gitFile =
|
|
15599
|
-
if (
|
|
15697
|
+
const gitFile = path2.join(worktreeRoot, ".git");
|
|
15698
|
+
if (fs2.lstatSync(gitFile).isDirectory())
|
|
15600
15699
|
return openMainCheckoutAnchor(gitFile);
|
|
15601
|
-
const descriptor =
|
|
15700
|
+
const descriptor = fs2.openSync(gitFile, "r");
|
|
15602
15701
|
let disposed = false;
|
|
15603
15702
|
const anchor = {
|
|
15604
15703
|
assertCurrent() {
|
|
15605
15704
|
if (disposed)
|
|
15606
15705
|
throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
|
|
15607
|
-
const held =
|
|
15608
|
-
const current =
|
|
15706
|
+
const held = fs2.fstatSync(descriptor, { bigint: true });
|
|
15707
|
+
const current = fs2.lstatSync(gitFile, { bigint: true });
|
|
15609
15708
|
if (!current.isFile() || !sameFileIdentity(held, current)) {
|
|
15610
15709
|
throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
|
|
15611
15710
|
}
|
|
@@ -15614,7 +15713,7 @@ function openGitWorktreeGenerationAnchor(worktreeRoot) {
|
|
|
15614
15713
|
if (disposed)
|
|
15615
15714
|
return;
|
|
15616
15715
|
disposed = true;
|
|
15617
|
-
|
|
15716
|
+
fs2.closeSync(descriptor);
|
|
15618
15717
|
}
|
|
15619
15718
|
};
|
|
15620
15719
|
try {
|
|
@@ -15728,84 +15827,84 @@ var init_worktree_git_runner = __esm(() => {
|
|
|
15728
15827
|
});
|
|
15729
15828
|
|
|
15730
15829
|
// dist/builtin/workflows/src/runs/shared/worktree-root.ts
|
|
15731
|
-
import * as
|
|
15732
|
-
import * as
|
|
15830
|
+
import * as fs3 from "node:fs";
|
|
15831
|
+
import * as path3 from "node:path";
|
|
15733
15832
|
function pathFromPointer(contents, prefix, base) {
|
|
15734
15833
|
if (!contents.startsWith(prefix))
|
|
15735
15834
|
return;
|
|
15736
15835
|
const value2 = contents.slice(prefix.length).trim();
|
|
15737
15836
|
if (!value2)
|
|
15738
15837
|
return;
|
|
15739
|
-
return
|
|
15838
|
+
return path3.resolve(base, value2);
|
|
15740
15839
|
}
|
|
15741
15840
|
function readText(file) {
|
|
15742
15841
|
try {
|
|
15743
|
-
return
|
|
15842
|
+
return fs3.readFileSync(file, "utf8");
|
|
15744
15843
|
} catch {
|
|
15745
15844
|
return;
|
|
15746
15845
|
}
|
|
15747
15846
|
}
|
|
15748
15847
|
function samePath(left, right) {
|
|
15749
15848
|
try {
|
|
15750
|
-
const a =
|
|
15751
|
-
const b =
|
|
15849
|
+
const a = fs3.realpathSync.native(left);
|
|
15850
|
+
const b = fs3.realpathSync.native(right);
|
|
15752
15851
|
return process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
15753
15852
|
} catch {
|
|
15754
15853
|
return false;
|
|
15755
15854
|
}
|
|
15756
15855
|
}
|
|
15757
15856
|
function findGitRoot(cwd) {
|
|
15758
|
-
let current =
|
|
15857
|
+
let current = path3.resolve(cwd);
|
|
15759
15858
|
try {
|
|
15760
|
-
if (!
|
|
15761
|
-
current =
|
|
15859
|
+
if (!fs3.statSync(current).isDirectory())
|
|
15860
|
+
current = path3.dirname(current);
|
|
15762
15861
|
} catch {
|
|
15763
15862
|
return;
|
|
15764
15863
|
}
|
|
15765
15864
|
while (true) {
|
|
15766
15865
|
try {
|
|
15767
|
-
const entry =
|
|
15866
|
+
const entry = fs3.statSync(path3.join(current, ".git"));
|
|
15768
15867
|
if (entry.isDirectory() || entry.isFile())
|
|
15769
15868
|
return current;
|
|
15770
15869
|
} catch {}
|
|
15771
|
-
const parent =
|
|
15870
|
+
const parent = path3.dirname(current);
|
|
15772
15871
|
if (parent === current)
|
|
15773
15872
|
return;
|
|
15774
15873
|
current = parent;
|
|
15775
15874
|
}
|
|
15776
15875
|
}
|
|
15777
15876
|
function resolveMainRepoRoot(repoRoot) {
|
|
15778
|
-
const gitEntry =
|
|
15877
|
+
const gitEntry = path3.join(repoRoot, ".git");
|
|
15779
15878
|
let stats;
|
|
15780
15879
|
try {
|
|
15781
|
-
stats =
|
|
15880
|
+
stats = fs3.statSync(gitEntry);
|
|
15782
15881
|
} catch {
|
|
15783
15882
|
return;
|
|
15784
15883
|
}
|
|
15785
15884
|
if (stats.isDirectory())
|
|
15786
|
-
return
|
|
15885
|
+
return path3.resolve(repoRoot);
|
|
15787
15886
|
if (!stats.isFile())
|
|
15788
15887
|
return;
|
|
15789
15888
|
const pointer = readText(gitEntry);
|
|
15790
15889
|
if (pointer === undefined)
|
|
15791
15890
|
return;
|
|
15792
15891
|
const gitDir = pathFromPointer(pointer, "gitdir:", repoRoot);
|
|
15793
|
-
if (gitDir === undefined ||
|
|
15892
|
+
if (gitDir === undefined || path3.basename(path3.dirname(gitDir)) !== "worktrees")
|
|
15794
15893
|
return;
|
|
15795
|
-
const commonGitDir =
|
|
15796
|
-
if (
|
|
15894
|
+
const commonGitDir = path3.dirname(path3.dirname(gitDir));
|
|
15895
|
+
if (path3.basename(commonGitDir) !== ".git")
|
|
15797
15896
|
return;
|
|
15798
|
-
const backPointer = readText(
|
|
15799
|
-
const commonPointer = readText(
|
|
15897
|
+
const backPointer = readText(path3.join(gitDir, "gitdir"));
|
|
15898
|
+
const commonPointer = readText(path3.join(gitDir, "commondir"));
|
|
15800
15899
|
if (backPointer === undefined || commonPointer === undefined)
|
|
15801
15900
|
return;
|
|
15802
|
-
const linkedGitEntry =
|
|
15803
|
-
const declaredCommonDir =
|
|
15901
|
+
const linkedGitEntry = path3.resolve(gitDir, backPointer.trim());
|
|
15902
|
+
const declaredCommonDir = path3.resolve(gitDir, commonPointer.trim());
|
|
15804
15903
|
if (!backPointer.trim() || !commonPointer.trim())
|
|
15805
15904
|
return;
|
|
15806
15905
|
if (!samePath(linkedGitEntry, gitEntry) || !samePath(declaredCommonDir, commonGitDir))
|
|
15807
15906
|
return;
|
|
15808
|
-
return
|
|
15907
|
+
return path3.dirname(commonGitDir);
|
|
15809
15908
|
}
|
|
15810
15909
|
function findCanonicalGitRoot(cwd) {
|
|
15811
15910
|
const repoRoot = findGitRoot(cwd);
|
|
@@ -15814,33 +15913,31 @@ function findCanonicalGitRoot(cwd) {
|
|
|
15814
15913
|
var init_worktree_root = () => {};
|
|
15815
15914
|
|
|
15816
15915
|
// dist/builtin/workflows/src/runs/shared/worktree-git.ts
|
|
15817
|
-
import * as
|
|
15818
|
-
import * as
|
|
15819
|
-
function gitWorktreeSetupCacheKey(
|
|
15820
|
-
const repoRoot = repositoryRootForGitWorktree(options.cwd);
|
|
15821
|
-
const { logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
15822
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
15916
|
+
import * as fs4 from "node:fs";
|
|
15917
|
+
import * as path4 from "node:path";
|
|
15918
|
+
function gitWorktreeSetupCacheKey(request) {
|
|
15823
15919
|
return JSON.stringify([
|
|
15824
|
-
|
|
15825
|
-
comparablePathThroughExistingAncestor(
|
|
15920
|
+
comparablePathThroughExistingAncestor(request.options.cwd),
|
|
15921
|
+
comparablePathThroughExistingAncestor(request.target)
|
|
15826
15922
|
]);
|
|
15827
15923
|
}
|
|
15828
|
-
function createGitWorktreeSetupCache() {
|
|
15924
|
+
function createGitWorktreeSetupCache(ownerRunId) {
|
|
15829
15925
|
const results = new Map;
|
|
15830
15926
|
let disposed = false;
|
|
15831
15927
|
return {
|
|
15832
15928
|
get(options) {
|
|
15833
15929
|
if (disposed)
|
|
15834
15930
|
throw new Error("Git worktree setup cache is already disposed");
|
|
15835
|
-
const
|
|
15931
|
+
const request = resolveGitWorktreeSetupRequest(options);
|
|
15932
|
+
const key = gitWorktreeSetupCacheKey(request);
|
|
15836
15933
|
const cached = results.get(key);
|
|
15837
15934
|
if (cached !== undefined) {
|
|
15838
15935
|
assertCachedGitWorktreeIdentity(cached, options);
|
|
15839
15936
|
return cached.result;
|
|
15840
15937
|
}
|
|
15841
|
-
const
|
|
15842
|
-
results.set(key, {
|
|
15843
|
-
return result;
|
|
15938
|
+
const setup = setupGitWorktreeFromRequest(request, ownerRunId);
|
|
15939
|
+
results.set(key, { ...setup, identity: captureGitWorktreeIdentity(setup) });
|
|
15940
|
+
return setup.result;
|
|
15844
15941
|
},
|
|
15845
15942
|
dispose() {
|
|
15846
15943
|
if (disposed)
|
|
@@ -15872,10 +15969,10 @@ function worktreeRecoveryCommand(repositoryRoot, worktreeDir) {
|
|
|
15872
15969
|
return `git -C ${quoteShellArg(repositoryRoot)} worktree remove --force ${quoteShellArg(worktreeDir)}`;
|
|
15873
15970
|
}
|
|
15874
15971
|
function hasGrandparent(value2) {
|
|
15875
|
-
const parent =
|
|
15972
|
+
const parent = path4.dirname(value2);
|
|
15876
15973
|
if (parent === value2)
|
|
15877
15974
|
return false;
|
|
15878
|
-
const grandparent =
|
|
15975
|
+
const grandparent = path4.dirname(parent);
|
|
15879
15976
|
return grandparent !== parent;
|
|
15880
15977
|
}
|
|
15881
15978
|
function pathAncestors(value2) {
|
|
@@ -15883,7 +15980,7 @@ function pathAncestors(value2) {
|
|
|
15883
15980
|
let current = value2;
|
|
15884
15981
|
while (true) {
|
|
15885
15982
|
ancestors.push(current);
|
|
15886
|
-
const parent =
|
|
15983
|
+
const parent = path4.dirname(current);
|
|
15887
15984
|
if (parent === current)
|
|
15888
15985
|
return ancestors;
|
|
15889
15986
|
current = parent;
|
|
@@ -15892,89 +15989,167 @@ function pathAncestors(value2) {
|
|
|
15892
15989
|
function shouldPreserveLogicalPath(logicalPath) {
|
|
15893
15990
|
return pathAncestors(logicalPath).some((ancestor) => {
|
|
15894
15991
|
try {
|
|
15895
|
-
return
|
|
15992
|
+
return fs4.lstatSync(ancestor).isSymbolicLink() && hasGrandparent(ancestor);
|
|
15896
15993
|
} catch {
|
|
15897
15994
|
return false;
|
|
15898
15995
|
}
|
|
15899
15996
|
});
|
|
15900
15997
|
}
|
|
15901
15998
|
function canonicalizePreservingSymlinks(value2) {
|
|
15902
|
-
const logicalPath =
|
|
15999
|
+
const logicalPath = path4.resolve(value2);
|
|
15903
16000
|
const preserveLogicalPath = shouldPreserveLogicalPath(logicalPath);
|
|
15904
16001
|
try {
|
|
15905
|
-
const canonical =
|
|
16002
|
+
const canonical = fs4.realpathSync.native(logicalPath);
|
|
15906
16003
|
return preserveLogicalPath && canonical !== logicalPath ? logicalPath : canonical;
|
|
15907
16004
|
} catch {
|
|
15908
16005
|
return logicalPath;
|
|
15909
16006
|
}
|
|
15910
16007
|
}
|
|
15911
|
-
function resolveGitWorktreePath(value2,
|
|
16008
|
+
function resolveGitWorktreePath(value2, baseDir) {
|
|
15912
16009
|
const trimmed = value2.trim();
|
|
15913
16010
|
if (!trimmed)
|
|
15914
16011
|
throw new Error("gitWorktreeDir cannot be empty");
|
|
15915
16012
|
if (trimmed.includes("\x00")) {
|
|
15916
16013
|
throw new Error("gitWorktreeDir contains an unusable null byte; provide a valid path or omit gitWorktreeDir.");
|
|
15917
16014
|
}
|
|
15918
|
-
return canonicalizePreservingSymlinks(
|
|
16015
|
+
return canonicalizePreservingSymlinks(path4.isAbsolute(trimmed) ? trimmed : path4.resolve(baseDir, trimmed));
|
|
15919
16016
|
}
|
|
15920
16017
|
function comparableRealPath(value2) {
|
|
15921
|
-
const realpath =
|
|
16018
|
+
const realpath = fs4.realpathSync.native(value2).replace(/\\/g, "/");
|
|
15922
16019
|
return process.platform === "win32" ? realpath.toLowerCase() : realpath;
|
|
15923
16020
|
}
|
|
15924
|
-
function
|
|
15925
|
-
let existing =
|
|
16021
|
+
function nearestExistingAncestor(value2) {
|
|
16022
|
+
let existing = path4.resolve(value2);
|
|
15926
16023
|
const missing = [];
|
|
15927
16024
|
while (!pathExistsSync(existing)) {
|
|
15928
|
-
const parent =
|
|
16025
|
+
const parent = path4.dirname(existing);
|
|
15929
16026
|
if (parent === existing)
|
|
15930
16027
|
break;
|
|
15931
|
-
missing.unshift(
|
|
16028
|
+
missing.unshift(path4.basename(existing));
|
|
15932
16029
|
existing = parent;
|
|
15933
16030
|
}
|
|
15934
|
-
|
|
16031
|
+
return { existing, missing };
|
|
16032
|
+
}
|
|
16033
|
+
function comparablePathThroughExistingAncestor(value2) {
|
|
16034
|
+
const { existing, missing } = nearestExistingAncestor(value2);
|
|
16035
|
+
const resolved = path4.resolve(comparableRealPath(existing), ...missing).replace(/\\/g, "/");
|
|
15935
16036
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
15936
16037
|
}
|
|
16038
|
+
function isFileOrLink(value2) {
|
|
16039
|
+
try {
|
|
16040
|
+
const entry = fs4.lstatSync(value2);
|
|
16041
|
+
return entry.isFile() || entry.isSymbolicLink();
|
|
16042
|
+
} catch {
|
|
16043
|
+
return false;
|
|
16044
|
+
}
|
|
16045
|
+
}
|
|
16046
|
+
function isDirectory(value2) {
|
|
16047
|
+
try {
|
|
16048
|
+
return fs4.statSync(value2).isDirectory();
|
|
16049
|
+
} catch {
|
|
16050
|
+
return false;
|
|
16051
|
+
}
|
|
16052
|
+
}
|
|
16053
|
+
function looksLikeGitDirectory(directory) {
|
|
16054
|
+
if (!isDirectory(directory))
|
|
16055
|
+
return false;
|
|
16056
|
+
if (path4.basename(directory) === ".git")
|
|
16057
|
+
return true;
|
|
16058
|
+
if (!isFileOrLink(path4.join(directory, "HEAD")))
|
|
16059
|
+
return false;
|
|
16060
|
+
if (isFileOrLink(path4.join(directory, "commondir")))
|
|
16061
|
+
return true;
|
|
16062
|
+
return isDirectory(path4.join(directory, "objects")) && isDirectory(path4.join(directory, "refs"));
|
|
16063
|
+
}
|
|
16064
|
+
function enclosingGitMetadataDirectory(target) {
|
|
16065
|
+
const { existing } = nearestExistingAncestor(target);
|
|
16066
|
+
let realExisting = existing;
|
|
16067
|
+
try {
|
|
16068
|
+
realExisting = fs4.realpathSync.native(existing);
|
|
16069
|
+
} catch {}
|
|
16070
|
+
for (const candidate of new Set([...pathAncestors(existing), ...pathAncestors(realExisting)])) {
|
|
16071
|
+
if (looksLikeGitDirectory(candidate))
|
|
16072
|
+
return candidate;
|
|
16073
|
+
}
|
|
16074
|
+
const insideGitDir = runGitReadOnlyProbe(existing, ["rev-parse", "--is-inside-git-dir"]);
|
|
16075
|
+
if (insideGitDir.status !== 0 && isGitTimeoutResult(insideGitDir)) {
|
|
16076
|
+
throw new Error(`Timed out while validating gitWorktreeDir ${target}. Git reported: ${gitFailureMessage(insideGitDir)}`);
|
|
16077
|
+
}
|
|
16078
|
+
return insideGitDir.status === 0 && insideGitDir.stdout.trim() === "true" ? existing : undefined;
|
|
16079
|
+
}
|
|
16080
|
+
function assertSafeGitWorktreeTarget(target, invokingRoot) {
|
|
16081
|
+
const gitDirectory = enclosingGitMetadataDirectory(target);
|
|
16082
|
+
if (gitDirectory !== undefined) {
|
|
16083
|
+
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.`);
|
|
16084
|
+
}
|
|
16085
|
+
if (invokingRoot !== undefined)
|
|
16086
|
+
validateWorktreeOutsideInvokingCheckout(target, invokingRoot);
|
|
16087
|
+
const { existing, missing } = nearestExistingAncestor(target);
|
|
16088
|
+
const workingTree = gitTopLevel(existing);
|
|
16089
|
+
if (workingTree === undefined)
|
|
16090
|
+
return;
|
|
16091
|
+
if (missing.length === 0 && comparableRealPath(target) === comparableRealPath(workingTree))
|
|
16092
|
+
return;
|
|
16093
|
+
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.`);
|
|
16094
|
+
}
|
|
15937
16095
|
function validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot) {
|
|
15938
16096
|
const repository = comparableRealPath(repoRoot);
|
|
15939
16097
|
const candidate = comparablePathThroughExistingAncestor(worktreeRoot);
|
|
15940
|
-
const relativePath =
|
|
16098
|
+
const relativePath = path4.relative(repository, candidate);
|
|
15941
16099
|
if (relativePath === "") {
|
|
15942
|
-
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate
|
|
16100
|
+
throw new Error("gitWorktreeDir must not resolve to the invoking checkout; provide a separate worktree path outside it.");
|
|
15943
16101
|
}
|
|
15944
|
-
if (!relativePath.startsWith(`..${
|
|
15945
|
-
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate
|
|
16102
|
+
if (!relativePath.startsWith(`..${path4.sep}`) && relativePath !== ".." && !path4.isAbsolute(relativePath)) {
|
|
16103
|
+
throw new Error("gitWorktreeDir must be outside the invoking checkout; provide a separate worktree path outside it.");
|
|
15946
16104
|
}
|
|
15947
16105
|
}
|
|
15948
16106
|
function gitPathFromOutput(value2, cwd) {
|
|
15949
16107
|
const trimmed = value2.trim();
|
|
15950
16108
|
if (!trimmed)
|
|
15951
16109
|
return;
|
|
15952
|
-
return
|
|
16110
|
+
return path4.isAbsolute(trimmed) ? path4.resolve(trimmed) : path4.resolve(cwd, trimmed);
|
|
15953
16111
|
}
|
|
15954
16112
|
function pathExistsSync(value2) {
|
|
16113
|
+
return pathStatSync(value2) !== undefined;
|
|
16114
|
+
}
|
|
16115
|
+
function pathStatSync(value2) {
|
|
15955
16116
|
try {
|
|
15956
|
-
|
|
15957
|
-
return true;
|
|
16117
|
+
return fs4.statSync(value2);
|
|
15958
16118
|
} catch (error) {
|
|
15959
16119
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
15960
16120
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
15961
|
-
return
|
|
16121
|
+
return;
|
|
15962
16122
|
throw error;
|
|
15963
16123
|
}
|
|
15964
16124
|
}
|
|
15965
|
-
function
|
|
16125
|
+
function probeInvokingRepository(cwd) {
|
|
15966
16126
|
const result = runGitReadOnlyProbe(cwd, ["rev-parse", "--show-toplevel"]);
|
|
15967
16127
|
if (result.status !== 0) {
|
|
15968
16128
|
if (isGitTimeoutResult(result)) {
|
|
15969
16129
|
throw new Error(`Timed out while checking the Git repository for gitWorktreeDir from ${cwd}. Git reported: ${gitFailureMessage(result)}`);
|
|
15970
16130
|
}
|
|
15971
|
-
|
|
16131
|
+
return { failure: gitFailureMessage(result) };
|
|
15972
16132
|
}
|
|
15973
|
-
const
|
|
15974
|
-
if (
|
|
16133
|
+
const root = gitPathFromOutput(result.stdout, cwd);
|
|
16134
|
+
if (root === undefined) {
|
|
15975
16135
|
throw new Error(`gitWorktreeDir could not resolve the repository top level from ${cwd}: git returned an empty path.`);
|
|
15976
16136
|
}
|
|
15977
|
-
return
|
|
16137
|
+
return { repository: { root, ...cwdWithinGitRepository(cwd, root) } };
|
|
16138
|
+
}
|
|
16139
|
+
function resolveGitWorktreeSetupRequest(options) {
|
|
16140
|
+
const probe = probeInvokingRepository(options.cwd);
|
|
16141
|
+
if ("repository" in probe) {
|
|
16142
|
+
return {
|
|
16143
|
+
options,
|
|
16144
|
+
repository: probe.repository,
|
|
16145
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, probe.repository.logicalRoot)
|
|
16146
|
+
};
|
|
16147
|
+
}
|
|
16148
|
+
return {
|
|
16149
|
+
options,
|
|
16150
|
+
repositoryProbeFailure: probe.failure,
|
|
16151
|
+
target: resolveGitWorktreePath(options.gitWorktreeDir, canonicalizePreservingSymlinks(options.cwd))
|
|
16152
|
+
};
|
|
15978
16153
|
}
|
|
15979
16154
|
function gitTopLevelFromResult(result, cwd, description) {
|
|
15980
16155
|
if (result.status !== 0) {
|
|
@@ -16010,25 +16185,25 @@ function dirnameForEachRelativeComponent(base, relativePath) {
|
|
|
16010
16185
|
continue;
|
|
16011
16186
|
if (component === "..")
|
|
16012
16187
|
return;
|
|
16013
|
-
current =
|
|
16188
|
+
current = path4.dirname(current);
|
|
16014
16189
|
}
|
|
16015
16190
|
return current;
|
|
16016
16191
|
}
|
|
16017
16192
|
function cwdWithinGitRepository(cwd, repoRoot) {
|
|
16018
|
-
const sourceCwd =
|
|
16019
|
-
const sourceRepoRoot =
|
|
16020
|
-
const relativeCwd =
|
|
16021
|
-
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") ||
|
|
16193
|
+
const sourceCwd = fs4.realpathSync.native(cwd);
|
|
16194
|
+
const sourceRepoRoot = fs4.realpathSync.native(repoRoot);
|
|
16195
|
+
const relativeCwd = path4.relative(sourceRepoRoot, sourceCwd);
|
|
16196
|
+
const safeRelativeCwd = relativeCwd === "" || relativeCwd.startsWith("..") || path4.isAbsolute(relativeCwd) ? "" : relativeCwd;
|
|
16022
16197
|
const logicalCwd = canonicalizePreservingSymlinks(cwd);
|
|
16023
16198
|
return {
|
|
16024
16199
|
relativeCwd: safeRelativeCwd,
|
|
16025
|
-
|
|
16200
|
+
logicalRoot: dirnameForEachRelativeComponent(logicalCwd, safeRelativeCwd) ?? repoRoot
|
|
16026
16201
|
};
|
|
16027
16202
|
}
|
|
16028
16203
|
function workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd) {
|
|
16029
|
-
return relativeCwd === "" ? worktreeRoot :
|
|
16204
|
+
return relativeCwd === "" ? worktreeRoot : path4.join(worktreeRoot, relativeCwd);
|
|
16030
16205
|
}
|
|
16031
|
-
function
|
|
16206
|
+
function validateGitWorktreeRoot(worktreeRoot) {
|
|
16032
16207
|
const topLevel = gitTopLevel(worktreeRoot);
|
|
16033
16208
|
if (topLevel === undefined) {
|
|
16034
16209
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree: ${worktreeRoot}`);
|
|
@@ -16036,8 +16211,18 @@ function validateExistingGitWorktreeRoot(worktreeRoot, repoRoot) {
|
|
|
16036
16211
|
if (comparableRealPath(worktreeRoot) !== comparableRealPath(topLevel)) {
|
|
16037
16212
|
throw new Error(`gitWorktreeDir already exists but is not a Git worktree root: ${worktreeRoot}. Git top-level checkout is ${topLevel}`);
|
|
16038
16213
|
}
|
|
16039
|
-
|
|
16040
|
-
|
|
16214
|
+
return gitCommonDirForWorktree(topLevel);
|
|
16215
|
+
}
|
|
16216
|
+
function existingGitWorktreeCommonDir(directory) {
|
|
16217
|
+
return gitTopLevel(directory) === undefined ? undefined : validateGitWorktreeRoot(directory);
|
|
16218
|
+
}
|
|
16219
|
+
function sameGitCommonDir(left, right) {
|
|
16220
|
+
return comparableRealPath(left) === comparableRealPath(right);
|
|
16221
|
+
}
|
|
16222
|
+
function validateCreatedGitWorktree(worktreeRoot, repository) {
|
|
16223
|
+
assertSafeGitWorktreeTarget(worktreeRoot, repository.root);
|
|
16224
|
+
if (!sameGitCommonDir(validateGitWorktreeRoot(worktreeRoot), gitCommonDirForWorktree(repository.root))) {
|
|
16225
|
+
throw new Error(`gitWorktreeDir does not belong to the invoking Git repository: ${worktreeRoot}`);
|
|
16041
16226
|
}
|
|
16042
16227
|
}
|
|
16043
16228
|
function gitDirectoryForWorktree(cwd) {
|
|
@@ -16051,26 +16236,27 @@ function gitDirectoryForWorktree(cwd) {
|
|
|
16051
16236
|
return gitDir;
|
|
16052
16237
|
}
|
|
16053
16238
|
function captureGitWorktreeIdentitySnapshot(setup) {
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
const
|
|
16239
|
+
const { worktreeRoot, repositoryRoot } = setup.result;
|
|
16240
|
+
assertSafeGitWorktreeTarget(worktreeRoot, setup.invokingRoot);
|
|
16241
|
+
const commonDir = validateGitWorktreeRoot(worktreeRoot);
|
|
16242
|
+
const stats = fs4.statSync(worktreeRoot);
|
|
16057
16243
|
return {
|
|
16058
|
-
worktreeRealPath: comparableRealPath(
|
|
16059
|
-
repositoryRealPath: comparableRealPath(
|
|
16060
|
-
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(
|
|
16061
|
-
commonDirRealPath: comparableRealPath(
|
|
16244
|
+
worktreeRealPath: comparableRealPath(worktreeRoot),
|
|
16245
|
+
repositoryRealPath: comparableRealPath(repositoryRoot),
|
|
16246
|
+
gitDirRealPath: comparableRealPath(gitDirectoryForWorktree(worktreeRoot)),
|
|
16247
|
+
commonDirRealPath: comparableRealPath(commonDir),
|
|
16062
16248
|
device: stats.dev,
|
|
16063
16249
|
inode: stats.ino
|
|
16064
16250
|
};
|
|
16065
16251
|
}
|
|
16066
16252
|
function captureGitWorktreeIdentity(setup) {
|
|
16067
16253
|
const snapshot = captureGitWorktreeIdentitySnapshot(setup);
|
|
16068
|
-
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.worktreeRoot) };
|
|
16254
|
+
return { ...snapshot, generation: openGitWorktreeGenerationAnchor(setup.result.worktreeRoot) };
|
|
16069
16255
|
}
|
|
16070
16256
|
function assertCachedGitWorktreeIdentity(cached, options) {
|
|
16071
16257
|
let current;
|
|
16072
16258
|
try {
|
|
16073
|
-
current = captureGitWorktreeIdentitySnapshot(cached
|
|
16259
|
+
current = captureGitWorktreeIdentitySnapshot(cached);
|
|
16074
16260
|
cached.identity.generation.assertCurrent();
|
|
16075
16261
|
} catch (error) {
|
|
16076
16262
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -16078,34 +16264,58 @@ function assertCachedGitWorktreeIdentity(cached, options) {
|
|
|
16078
16264
|
}
|
|
16079
16265
|
const expected = cached.identity;
|
|
16080
16266
|
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) {
|
|
16081
|
-
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended
|
|
16082
|
-
}
|
|
16267
|
+
throw new Error(`Cached gitWorktreeDir changed before reuse: ${options.gitWorktreeDir}. Start a new run with the intended worktree.`);
|
|
16268
|
+
}
|
|
16269
|
+
}
|
|
16270
|
+
function requireInvokingRepository(request, action) {
|
|
16271
|
+
if (request.repository !== undefined)
|
|
16272
|
+
return request.repository;
|
|
16273
|
+
throw new Error([
|
|
16274
|
+
`gitWorktreeDir requires the workflow to be invoked from inside a Git repository to ${action}.`,
|
|
16275
|
+
"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.",
|
|
16276
|
+
`Git reported: ${request.repositoryProbeFailure ?? "no repository"}`
|
|
16277
|
+
].join(" "));
|
|
16278
|
+
}
|
|
16279
|
+
function setupGitWorktreeFromRequest(request, ownerRunId) {
|
|
16280
|
+
const { repository, target } = request;
|
|
16281
|
+
assertSafeGitWorktreeTarget(target, repository?.root);
|
|
16282
|
+
const entry = pathStatSync(target);
|
|
16283
|
+
if (entry === undefined)
|
|
16284
|
+
return createGitWorktreeAtPath(request, false);
|
|
16285
|
+
if (!entry.isDirectory())
|
|
16286
|
+
throw new Error(`gitWorktreeDir already exists but is not a directory: ${target}`);
|
|
16287
|
+
if (fs4.readdirSync(target).length === 0)
|
|
16288
|
+
return createGitWorktreeAtPath(request, true);
|
|
16289
|
+
const commonDir = existingGitWorktreeCommonDir(target);
|
|
16290
|
+
if (commonDir === undefined)
|
|
16291
|
+
return allocateGitWorktree(request, ownerRunId);
|
|
16292
|
+
const sameRepository = repository !== undefined && sameGitCommonDir(commonDir, gitCommonDirForWorktree(repository.root));
|
|
16293
|
+
return {
|
|
16294
|
+
result: {
|
|
16295
|
+
worktreeRoot: target,
|
|
16296
|
+
cwd: sameRepository ? workspaceCwdForGitWorktreeRoot(target, repository.relativeCwd) : target,
|
|
16297
|
+
repositoryRoot: sameRepository ? repository.root : target,
|
|
16298
|
+
created: false
|
|
16299
|
+
},
|
|
16300
|
+
...repository !== undefined ? { invokingRoot: repository.root } : {}
|
|
16301
|
+
};
|
|
16083
16302
|
}
|
|
16084
|
-
function
|
|
16085
|
-
const
|
|
16086
|
-
const
|
|
16303
|
+
function createGitWorktreeAtPath(request, existingEmptyDirectory) {
|
|
16304
|
+
const { target: worktreeRoot } = request;
|
|
16305
|
+
const repository = requireInvokingRepository(request, `create a new worktree at ${worktreeRoot}`);
|
|
16306
|
+
const mainRoot = findCanonicalGitRoot(repository.root);
|
|
16087
16307
|
if (mainRoot === undefined) {
|
|
16088
|
-
throw new Error(`Unable to resolve the canonical main Git repository root from ${
|
|
16089
|
-
}
|
|
16090
|
-
const { relativeCwd, logicalRepoRoot } = cwdWithinGitRepository(options.cwd, repoRoot);
|
|
16091
|
-
const worktreeRoot = resolveGitWorktreePath(options.gitWorktreeDir, logicalRepoRoot);
|
|
16092
|
-
validateWorktreeOutsideInvokingCheckout(worktreeRoot, repoRoot);
|
|
16093
|
-
if (pathExistsSync(worktreeRoot)) {
|
|
16094
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
16095
|
-
return {
|
|
16096
|
-
worktreeRoot,
|
|
16097
|
-
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, relativeCwd),
|
|
16098
|
-
repositoryRoot: repoRoot,
|
|
16099
|
-
created: false
|
|
16100
|
-
};
|
|
16308
|
+
throw new Error(`Unable to resolve the canonical main Git repository root from ${repository.root}.`);
|
|
16101
16309
|
}
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16310
|
+
if (!existingEmptyDirectory) {
|
|
16311
|
+
try {
|
|
16312
|
+
fs4.mkdirSync(path4.dirname(worktreeRoot), { recursive: true });
|
|
16313
|
+
} catch (error) {
|
|
16314
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16315
|
+
throw new Error(`Failed to create parent directory for requested gitWorktreeDir ${worktreeRoot}: ${message}`);
|
|
16316
|
+
}
|
|
16107
16317
|
}
|
|
16108
|
-
const baseRef = options.baseBranch?.trim() || "HEAD";
|
|
16318
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
16109
16319
|
const result = runGit(mainRoot, ["worktree", "add", "--detach", worktreeRoot, baseRef]);
|
|
16110
16320
|
if (result.status !== 0) {
|
|
16111
16321
|
throw new Error([
|
|
@@ -16115,30 +16325,127 @@ function setupGitWorktree(options) {
|
|
|
16115
16325
|
`));
|
|
16116
16326
|
}
|
|
16117
16327
|
try {
|
|
16118
|
-
|
|
16119
|
-
validateExistingGitWorktreeRoot(worktreeRoot, repoRoot);
|
|
16328
|
+
validateCreatedGitWorktree(worktreeRoot, repository);
|
|
16120
16329
|
} catch (error) {
|
|
16121
16330
|
runGit(mainRoot, ["worktree", "remove", "--force", worktreeRoot]);
|
|
16122
16331
|
const message = error instanceof Error ? error.message : String(error);
|
|
16123
16332
|
throw new Error(`Created gitWorktreeDir failed post-creation validation: ${message}`);
|
|
16124
16333
|
}
|
|
16125
16334
|
return {
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16335
|
+
result: {
|
|
16336
|
+
worktreeRoot,
|
|
16337
|
+
cwd: workspaceCwdForGitWorktreeRoot(worktreeRoot, repository.relativeCwd),
|
|
16338
|
+
repositoryRoot: repository.root,
|
|
16339
|
+
created: true
|
|
16340
|
+
},
|
|
16341
|
+
invokingRoot: repository.root
|
|
16342
|
+
};
|
|
16343
|
+
}
|
|
16344
|
+
function containedWorktreeCwd(checkout, relativeCwd) {
|
|
16345
|
+
const cwd = workspaceCwdForGitWorktreeRoot(checkout, relativeCwd);
|
|
16346
|
+
let resolved;
|
|
16347
|
+
try {
|
|
16348
|
+
resolved = fs4.realpathSync.native(cwd);
|
|
16349
|
+
} catch {
|
|
16350
|
+
resolved = "";
|
|
16351
|
+
}
|
|
16352
|
+
const relative2 = resolved === "" ? undefined : path4.relative(fs4.realpathSync.native(checkout), resolved);
|
|
16353
|
+
if (relative2 === undefined || relative2 === ".." || relative2.startsWith(`..${path4.sep}`) || path4.isAbsolute(relative2) || !fs4.statSync(resolved).isDirectory()) {
|
|
16354
|
+
throw new Error(`The selected base does not contain a working directory ${relativeCwd || "."} inside the worktree ${checkout}.`);
|
|
16355
|
+
}
|
|
16356
|
+
return cwd;
|
|
16357
|
+
}
|
|
16358
|
+
function allocatedGitWorktreeSetup(checkout, repository, created) {
|
|
16359
|
+
return {
|
|
16360
|
+
result: {
|
|
16361
|
+
worktreeRoot: checkout,
|
|
16362
|
+
cwd: containedWorktreeCwd(checkout, repository.relativeCwd),
|
|
16363
|
+
repositoryRoot: repository.root,
|
|
16364
|
+
created
|
|
16365
|
+
},
|
|
16366
|
+
invokingRoot: repository.root
|
|
16130
16367
|
};
|
|
16131
16368
|
}
|
|
16369
|
+
function validateOwnedGitWorktree(checkout, repository) {
|
|
16370
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
16371
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
16372
|
+
if (sameGitCommonDir(gitDir, gitCommonDirForWorktree(checkout))) {
|
|
16373
|
+
throw new Error(`${checkout} is not a linked worktree`);
|
|
16374
|
+
}
|
|
16375
|
+
const backlink = fs4.readFileSync(path4.join(gitDir, "gitdir"), "utf8").trim();
|
|
16376
|
+
if (!backlink || comparableRealPath(path4.resolve(gitDir, backlink)) !== comparableRealPath(path4.join(checkout, ".git"))) {
|
|
16377
|
+
throw new Error(`the Git directory of ${checkout} belongs to another checkout`);
|
|
16378
|
+
}
|
|
16379
|
+
}
|
|
16380
|
+
function findOwnedGitWorktree(root, repository, ownerRunId) {
|
|
16381
|
+
const [checkout] = findOwnedWorktreeCheckouts(root, path4.basename(repository.root), ownerRunId);
|
|
16382
|
+
if (checkout === undefined)
|
|
16383
|
+
return;
|
|
16384
|
+
try {
|
|
16385
|
+
validateOwnedGitWorktree(checkout, repository);
|
|
16386
|
+
return allocatedGitWorktreeSetup(checkout, repository, false);
|
|
16387
|
+
} catch (error) {
|
|
16388
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16389
|
+
throw new Error(`The worktree this workflow run allocated under gitWorktreeDir ${root} can no longer be reused: ${checkout}. ${message}`);
|
|
16390
|
+
}
|
|
16391
|
+
}
|
|
16392
|
+
function allocateGitWorktree(request, ownerRunId) {
|
|
16393
|
+
const { target: root } = request;
|
|
16394
|
+
const repository = requireInvokingRepository(request, `create a new worktree under ${root}`);
|
|
16395
|
+
if (ownerRunId !== undefined) {
|
|
16396
|
+
const owned = findOwnedGitWorktree(root, repository, ownerRunId);
|
|
16397
|
+
if (owned !== undefined)
|
|
16398
|
+
return owned;
|
|
16399
|
+
}
|
|
16400
|
+
const baseRef = request.options.baseBranch?.trim() || "HEAD";
|
|
16401
|
+
const revision = runGit(repository.root, ["rev-parse", "--verify", "--end-of-options", `${baseRef}^{commit}`]);
|
|
16402
|
+
const commit = revision.status === 0 ? revision.stdout.trim() : "";
|
|
16403
|
+
if (commit === "") {
|
|
16404
|
+
throw new Error(`Failed to resolve ${baseRef} to a commit for gitWorktreeDir ${root}. Git reported: ${gitFailureMessage(revision)}`);
|
|
16405
|
+
}
|
|
16406
|
+
const checkout = allocateWorktreeCheckoutPath(root, path4.basename(repository.root));
|
|
16407
|
+
const add = runGit(repository.root, ["worktree", "add", "--detach", "--no-checkout", checkout, commit]);
|
|
16408
|
+
if (add.status !== 0) {
|
|
16409
|
+
removeEmptyWorktreeBucket(checkout);
|
|
16410
|
+
throw new Error(`Failed to create git worktree at ${checkout} under gitWorktreeDir ${root} from ${baseRef}. Git reported: ${gitFailureMessage(add)}`);
|
|
16411
|
+
}
|
|
16412
|
+
try {
|
|
16413
|
+
const gitDir = gitDirectoryForWorktree(checkout);
|
|
16414
|
+
runGitOrThrow(checkout, ["config", "--file", path4.join(gitDir, "config.worktree"), "core.worktree", checkout]);
|
|
16415
|
+
runGitOrThrow(checkout, ["--work-tree=.", "reset", "--hard", "--no-recurse-submodules", commit]);
|
|
16416
|
+
validateCreatedGitWorktree(checkout, repository);
|
|
16417
|
+
const setup = allocatedGitWorktreeSetup(checkout, repository, true);
|
|
16418
|
+
if (ownerRunId !== undefined)
|
|
16419
|
+
bindWorktreeOwner(gitDir, ownerRunId);
|
|
16420
|
+
return setup;
|
|
16421
|
+
} catch (error) {
|
|
16422
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16423
|
+
const removal = runGit(repository.root, ["worktree", "remove", "--force", checkout]);
|
|
16424
|
+
removeEmptyWorktreeBucket(checkout);
|
|
16425
|
+
const rollback = removal.status === 0 ? "" : ` Rolling back the incomplete worktree also failed; remove it with: ${worktreeRecoveryCommand(repository.root, checkout)}`;
|
|
16426
|
+
throw new Error(`Failed to set up git worktree at ${checkout} under gitWorktreeDir ${root}: ${message}${rollback}`);
|
|
16427
|
+
}
|
|
16428
|
+
}
|
|
16429
|
+
function runGitOrThrow(cwd, args) {
|
|
16430
|
+
const result = runGit(cwd, args);
|
|
16431
|
+
if (result.status !== 0)
|
|
16432
|
+
throw new Error(gitFailureMessage(result));
|
|
16433
|
+
}
|
|
16434
|
+
function setupGitWorktree(options) {
|
|
16435
|
+
return setupGitWorktreeFromRequest(resolveGitWorktreeSetupRequest(options)).result;
|
|
16436
|
+
}
|
|
16132
16437
|
var init_worktree_git = __esm(() => {
|
|
16438
|
+
init_worktree_allocation();
|
|
16133
16439
|
init_worktree_generation();
|
|
16134
16440
|
init_worktree_git_runner();
|
|
16135
16441
|
init_worktree_root();
|
|
16442
|
+
init_worktree_allocation();
|
|
16136
16443
|
init_worktree_git_runner();
|
|
16137
16444
|
});
|
|
16138
16445
|
|
|
16139
16446
|
// dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts
|
|
16140
|
-
function createGitWorktreeSetupCacheOwner(suppliedCache) {
|
|
16141
|
-
const cache = suppliedCache ?? createGitWorktreeSetupCache();
|
|
16447
|
+
function createGitWorktreeSetupCacheOwner(suppliedCache, ownerRunId) {
|
|
16448
|
+
const cache = suppliedCache ?? createGitWorktreeSetupCache(ownerRunId);
|
|
16142
16449
|
const ownsCache = suppliedCache === undefined;
|
|
16143
16450
|
let released = false;
|
|
16144
16451
|
return {
|
|
@@ -16159,20 +16466,20 @@ var init_worktree_cache_lifecycle = __esm(() => {
|
|
|
16159
16466
|
});
|
|
16160
16467
|
|
|
16161
16468
|
// dist/builtin/workflows/src/runs/shared/worktree-diff.ts
|
|
16162
|
-
import * as
|
|
16163
|
-
import * as
|
|
16469
|
+
import * as fs5 from "node:fs";
|
|
16470
|
+
import * as path5 from "node:path";
|
|
16164
16471
|
function safePatchAgentName(agent) {
|
|
16165
16472
|
return agent.replace(/[^\w.-]/g, "_");
|
|
16166
16473
|
}
|
|
16167
16474
|
function removeSyntheticPath(worktree, syntheticPath) {
|
|
16168
|
-
const resolved =
|
|
16169
|
-
const relative =
|
|
16170
|
-
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${
|
|
16475
|
+
const resolved = path5.resolve(worktree.path, syntheticPath);
|
|
16476
|
+
const relative = path5.relative(worktree.path, resolved);
|
|
16477
|
+
if (!relative || relative === "." || relative === ".." || relative.startsWith(`..${path5.sep}`) || path5.isAbsolute(relative)) {
|
|
16171
16478
|
return;
|
|
16172
16479
|
}
|
|
16173
16480
|
let stat;
|
|
16174
16481
|
try {
|
|
16175
|
-
stat =
|
|
16482
|
+
stat = fs5.lstatSync(resolved);
|
|
16176
16483
|
} catch (error) {
|
|
16177
16484
|
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
16178
16485
|
if (code === "ENOENT")
|
|
@@ -16180,14 +16487,14 @@ function removeSyntheticPath(worktree, syntheticPath) {
|
|
|
16180
16487
|
throw error;
|
|
16181
16488
|
}
|
|
16182
16489
|
if (stat.isSymbolicLink()) {
|
|
16183
|
-
|
|
16490
|
+
fs5.unlinkSync(resolved);
|
|
16184
16491
|
return;
|
|
16185
16492
|
}
|
|
16186
16493
|
if (stat.isDirectory()) {
|
|
16187
|
-
|
|
16494
|
+
fs5.rmSync(resolved, { recursive: true, force: true });
|
|
16188
16495
|
return;
|
|
16189
16496
|
}
|
|
16190
|
-
|
|
16497
|
+
fs5.rmSync(resolved, { force: true });
|
|
16191
16498
|
}
|
|
16192
16499
|
function removeSyntheticPathsBeforeDiff(worktree) {
|
|
16193
16500
|
if (worktree.syntheticPaths.length === 0)
|
|
@@ -16236,7 +16543,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
16236
16543
|
const diffStat = runGitChecked(worktree.path, ["diff", "--cached", "--stat", setup.baseCommit]).trim();
|
|
16237
16544
|
const patch = runGitChecked(worktree.path, ["diff", "--cached", setup.baseCommit]);
|
|
16238
16545
|
const numstat = runGitChecked(worktree.path, ["diff", "--cached", "--numstat", setup.baseCommit]);
|
|
16239
|
-
|
|
16546
|
+
fs5.writeFileSync(patchPath, patch, "utf-8");
|
|
16240
16547
|
if (!patch.trim()) {
|
|
16241
16548
|
return emptyDiff(worktree.index, agent, worktree.branch, patchPath);
|
|
16242
16549
|
}
|
|
@@ -16254,7 +16561,7 @@ function captureWorktreeDiff(setup, worktree, agent, patchPath) {
|
|
|
16254
16561
|
}
|
|
16255
16562
|
function writeEmptyPatch(patchPath) {
|
|
16256
16563
|
try {
|
|
16257
|
-
|
|
16564
|
+
fs5.writeFileSync(patchPath, "", "utf-8");
|
|
16258
16565
|
} catch {}
|
|
16259
16566
|
}
|
|
16260
16567
|
function hasWorktreeChanges(diff) {
|
|
@@ -16262,7 +16569,7 @@ function hasWorktreeChanges(diff) {
|
|
|
16262
16569
|
}
|
|
16263
16570
|
function diffWorktrees(setup, agents, diffsDir) {
|
|
16264
16571
|
try {
|
|
16265
|
-
|
|
16572
|
+
fs5.mkdirSync(diffsDir, { recursive: true });
|
|
16266
16573
|
} catch {
|
|
16267
16574
|
return [];
|
|
16268
16575
|
}
|
|
@@ -16270,7 +16577,7 @@ function diffWorktrees(setup, agents, diffsDir) {
|
|
|
16270
16577
|
for (let index = 0;index < setup.worktrees.length; index++) {
|
|
16271
16578
|
const worktree = setup.worktrees[index];
|
|
16272
16579
|
const agent = agents[index] ?? `task-${index + 1}`;
|
|
16273
|
-
const patchPath =
|
|
16580
|
+
const patchPath = path5.join(diffsDir, `task-${index}-${safePatchAgentName(agent)}.patch`);
|
|
16274
16581
|
try {
|
|
16275
16582
|
diffs.push(captureWorktreeDiff(setup, worktree, agent, patchPath));
|
|
16276
16583
|
} catch {
|
|
@@ -16292,7 +16599,7 @@ function formatWorktreeDiffSummary(diffs) {
|
|
|
16292
16599
|
}
|
|
16293
16600
|
lines.push("");
|
|
16294
16601
|
}
|
|
16295
|
-
const patchesDir =
|
|
16602
|
+
const patchesDir = path5.dirname(changed[0].patchPath);
|
|
16296
16603
|
lines.push(`Full patches: ${patchesDir}`);
|
|
16297
16604
|
return lines.join(`
|
|
16298
16605
|
`).trimEnd();
|
|
@@ -16302,8 +16609,8 @@ var init_worktree_diff = __esm(() => {
|
|
|
16302
16609
|
});
|
|
16303
16610
|
|
|
16304
16611
|
// dist/builtin/workflows/src/runs/shared/worktree-post-create.ts
|
|
16305
|
-
import * as
|
|
16306
|
-
import * as
|
|
16612
|
+
import * as fs6 from "node:fs";
|
|
16613
|
+
import * as path6 from "node:path";
|
|
16307
16614
|
function tracked(repo, relativePath) {
|
|
16308
16615
|
const result = runGit(repo, ["ls-files", "--error-unmatch", "--", relativePath]);
|
|
16309
16616
|
return result.status === 0;
|
|
@@ -16323,12 +16630,12 @@ function hasTrackedPathComponent(repo, relativePath) {
|
|
|
16323
16630
|
return false;
|
|
16324
16631
|
}
|
|
16325
16632
|
function copyUntrackedFile(mainRoot, worktreeRoot, relativePath) {
|
|
16326
|
-
const source =
|
|
16327
|
-
const destination =
|
|
16328
|
-
if (!
|
|
16633
|
+
const source = path6.join(mainRoot, relativePath);
|
|
16634
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
16635
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
16329
16636
|
return false;
|
|
16330
|
-
|
|
16331
|
-
|
|
16637
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
16638
|
+
fs6.copyFileSync(source, destination);
|
|
16332
16639
|
return true;
|
|
16333
16640
|
}
|
|
16334
16641
|
function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
@@ -16341,14 +16648,14 @@ function propagateLocalSettings(mainRoot, worktreeRoot) {
|
|
|
16341
16648
|
return copied;
|
|
16342
16649
|
}
|
|
16343
16650
|
function populatedHooksDirectory(mainRoot) {
|
|
16344
|
-
const husky =
|
|
16651
|
+
const husky = path6.join(mainRoot, ".husky");
|
|
16345
16652
|
try {
|
|
16346
|
-
if (
|
|
16653
|
+
if (fs6.statSync(husky).isDirectory())
|
|
16347
16654
|
return husky;
|
|
16348
16655
|
} catch {}
|
|
16349
|
-
const hooks =
|
|
16656
|
+
const hooks = path6.join(mainRoot, ".git", "hooks");
|
|
16350
16657
|
try {
|
|
16351
|
-
const populated =
|
|
16658
|
+
const populated = fs6.readdirSync(hooks, { withFileTypes: true }).some((entry) => entry.isFile() && !entry.name.endsWith(".sample"));
|
|
16352
16659
|
return populated ? hooks : undefined;
|
|
16353
16660
|
} catch {
|
|
16354
16661
|
return;
|
|
@@ -16359,7 +16666,7 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
16359
16666
|
if (desired === undefined)
|
|
16360
16667
|
return;
|
|
16361
16668
|
const current = runGitPlain(mainRoot, ["config", "--get", "core.hooksPath"]);
|
|
16362
|
-
if (current.status === 0 &&
|
|
16669
|
+
if (current.status === 0 && path6.resolve(mainRoot, current.stdout.trim()) === desired)
|
|
16363
16670
|
return;
|
|
16364
16671
|
const configured = runGitPlain(mainRoot, ["config", "core.hooksPath", desired]);
|
|
16365
16672
|
if (configured.status !== 0) {
|
|
@@ -16368,10 +16675,10 @@ function configureSharedHooksPath(mainRoot) {
|
|
|
16368
16675
|
}
|
|
16369
16676
|
function normalizeSymlinkDirectory(value2) {
|
|
16370
16677
|
const trimmed = value2.trim();
|
|
16371
|
-
if (!trimmed ||
|
|
16678
|
+
if (!trimmed || path6.isAbsolute(trimmed))
|
|
16372
16679
|
return;
|
|
16373
|
-
const normalized =
|
|
16374
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${
|
|
16680
|
+
const normalized = path6.normalize(trimmed);
|
|
16681
|
+
if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path6.sep}`))
|
|
16375
16682
|
return;
|
|
16376
16683
|
return normalized;
|
|
16377
16684
|
}
|
|
@@ -16381,20 +16688,20 @@ function symlinkConfiguredDirectories(mainRoot, worktreeRoot, directories) {
|
|
|
16381
16688
|
const relativePath = normalizeSymlinkDirectory(rawDirectory);
|
|
16382
16689
|
if (relativePath === undefined || synthetic.includes(relativePath))
|
|
16383
16690
|
continue;
|
|
16384
|
-
const source =
|
|
16385
|
-
const destination =
|
|
16386
|
-
if (!
|
|
16691
|
+
const source = path6.join(mainRoot, relativePath);
|
|
16692
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
16693
|
+
if (!fs6.existsSync(source) || fs6.existsSync(destination) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
16387
16694
|
continue;
|
|
16388
|
-
|
|
16695
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
16389
16696
|
try {
|
|
16390
|
-
|
|
16697
|
+
fs6.symlinkSync(source, destination, process.platform === "win32" ? "junction" : undefined);
|
|
16391
16698
|
synthetic.push(relativePath);
|
|
16392
16699
|
} catch {}
|
|
16393
16700
|
}
|
|
16394
16701
|
return synthetic;
|
|
16395
16702
|
}
|
|
16396
16703
|
function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
16397
|
-
if (!
|
|
16704
|
+
if (!fs6.existsSync(path6.join(mainRoot, ".worktreeinclude")))
|
|
16398
16705
|
return;
|
|
16399
16706
|
const ignored = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-standard"]);
|
|
16400
16707
|
const included = runGit(mainRoot, ["ls-files", "--others", "--ignored", "--exclude-from=.worktreeinclude"]);
|
|
@@ -16404,13 +16711,13 @@ function copyWorktreeIncludes(mainRoot, worktreeRoot) {
|
|
|
16404
16711
|
for (const relativePath of included.stdout.split(/\r?\n/).filter(Boolean)) {
|
|
16405
16712
|
if (!ignoredPaths.has(relativePath) || hasTrackedPathComponent(worktreeRoot, relativePath))
|
|
16406
16713
|
continue;
|
|
16407
|
-
const source =
|
|
16408
|
-
const destination =
|
|
16714
|
+
const source = path6.join(mainRoot, relativePath);
|
|
16715
|
+
const destination = path6.join(worktreeRoot, relativePath);
|
|
16409
16716
|
try {
|
|
16410
|
-
if (!
|
|
16717
|
+
if (!fs6.statSync(source).isFile() || fs6.existsSync(destination))
|
|
16411
16718
|
continue;
|
|
16412
|
-
|
|
16413
|
-
|
|
16719
|
+
fs6.mkdirSync(path6.dirname(destination), { recursive: true });
|
|
16720
|
+
fs6.copyFileSync(source, destination);
|
|
16414
16721
|
} catch {}
|
|
16415
16722
|
}
|
|
16416
16723
|
}
|
|
@@ -16427,9 +16734,9 @@ var init_worktree_post_create = __esm(() => {
|
|
|
16427
16734
|
|
|
16428
16735
|
// dist/builtin/workflows/src/runs/shared/worktree-setup.ts
|
|
16429
16736
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
16430
|
-
import * as
|
|
16737
|
+
import * as fs7 from "node:fs";
|
|
16431
16738
|
import * as os from "node:os";
|
|
16432
|
-
import * as
|
|
16739
|
+
import * as path7 from "node:path";
|
|
16433
16740
|
import { createChildProcessEnvironment as createChildProcessEnvironment2 } from "@bastani/atomic";
|
|
16434
16741
|
function originDefaultBranch(mainRoot) {
|
|
16435
16742
|
const symbolic = runGit(mainRoot, ["symbolic-ref", "--short", "refs/remotes/origin/HEAD"]);
|
|
@@ -16449,7 +16756,7 @@ function originDefaultBranch(mainRoot) {
|
|
|
16449
16756
|
}
|
|
16450
16757
|
function resolveRepoState(cwd, explicitBaseBranch) {
|
|
16451
16758
|
const cwdRelative = resolveRepoCwdRelative(cwd);
|
|
16452
|
-
const toplevel =
|
|
16759
|
+
const toplevel = path7.resolve(runGitChecked(cwd, ["rev-parse", "--show-toplevel"]).trim());
|
|
16453
16760
|
const mainRoot = findCanonicalGitRoot(toplevel);
|
|
16454
16761
|
if (mainRoot === undefined)
|
|
16455
16762
|
throw new Error(`unable to resolve canonical main Git repository root from ${toplevel}`);
|
|
@@ -16462,9 +16769,9 @@ function resolveRepoState(cwd, explicitBaseBranch) {
|
|
|
16462
16769
|
return { toplevel, mainRoot, cwdRelative, baseCommit, baseRef };
|
|
16463
16770
|
}
|
|
16464
16771
|
function normalizeComparableCwd(cwd) {
|
|
16465
|
-
const resolved =
|
|
16772
|
+
const resolved = path7.resolve(cwd);
|
|
16466
16773
|
try {
|
|
16467
|
-
return
|
|
16774
|
+
return fs7.realpathSync(resolved);
|
|
16468
16775
|
} catch {
|
|
16469
16776
|
return resolved;
|
|
16470
16777
|
}
|
|
@@ -16475,7 +16782,7 @@ function findWorktreeTaskCwdConflict(tasks, sharedCwd) {
|
|
|
16475
16782
|
const task = tasks[index];
|
|
16476
16783
|
if (!task.cwd)
|
|
16477
16784
|
continue;
|
|
16478
|
-
const taskCwd =
|
|
16785
|
+
const taskCwd = path7.isAbsolute(task.cwd) ? task.cwd : path7.resolve(sharedCwd, task.cwd);
|
|
16479
16786
|
if (normalizeComparableCwd(taskCwd) === normalizedSharedCwd)
|
|
16480
16787
|
continue;
|
|
16481
16788
|
return { index, agent: task.agent, cwd: task.cwd };
|
|
@@ -16492,12 +16799,12 @@ function buildWorktreeBranch(runId, index) {
|
|
|
16492
16799
|
return `worktree-${flattenedWorktreeName(runId, index)}`;
|
|
16493
16800
|
}
|
|
16494
16801
|
function buildWorktreePath(mainRoot, runId, index) {
|
|
16495
|
-
return
|
|
16802
|
+
return path7.join(mainRoot, ".atomic", "worktrees", flattenedWorktreeName(runId, index));
|
|
16496
16803
|
}
|
|
16497
16804
|
function ensureWorktreeIgnore(mainRoot) {
|
|
16498
|
-
const worktreesRoot =
|
|
16499
|
-
|
|
16500
|
-
|
|
16805
|
+
const worktreesRoot = path7.join(mainRoot, ".atomic", "worktrees");
|
|
16806
|
+
fs7.mkdirSync(worktreesRoot, { recursive: true });
|
|
16807
|
+
fs7.writeFileSync(path7.join(worktreesRoot, ".gitignore"), `*
|
|
16501
16808
|
`, "utf8");
|
|
16502
16809
|
}
|
|
16503
16810
|
function resolveRepoCwdRelative(cwd) {
|
|
@@ -16506,7 +16813,7 @@ function resolveRepoCwdRelative(cwd) {
|
|
|
16506
16813
|
throw new Error("worktree isolation requires a git repository");
|
|
16507
16814
|
}
|
|
16508
16815
|
const rawPrefix = runGitChecked(cwd, ["rev-parse", "--show-prefix"]).trim();
|
|
16509
|
-
const normalizedPrefix = rawPrefix ?
|
|
16816
|
+
const normalizedPrefix = rawPrefix ? path7.normalize(rawPrefix.replace(/[\\/]+$/, "")) : "";
|
|
16510
16817
|
return normalizedPrefix === "." ? "" : normalizedPrefix;
|
|
16511
16818
|
}
|
|
16512
16819
|
function parseHookTimeout(timeoutMs) {
|
|
@@ -16524,19 +16831,19 @@ function resolveWorktreeSetupHook(repoRoot, config) {
|
|
|
16524
16831
|
if (!hookPath) {
|
|
16525
16832
|
throw new Error("worktree setup hook path cannot be empty");
|
|
16526
16833
|
}
|
|
16527
|
-
const expandedHookPath = hookPath.startsWith("~/") ?
|
|
16834
|
+
const expandedHookPath = hookPath.startsWith("~/") ? path7.join(os.homedir(), hookPath.slice(2)) : hookPath;
|
|
16528
16835
|
let resolvedPath;
|
|
16529
|
-
if (
|
|
16836
|
+
if (path7.isAbsolute(expandedHookPath)) {
|
|
16530
16837
|
resolvedPath = expandedHookPath;
|
|
16531
16838
|
} else if (expandedHookPath.includes("/") || expandedHookPath.includes("\\")) {
|
|
16532
|
-
resolvedPath =
|
|
16839
|
+
resolvedPath = path7.resolve(repoRoot, expandedHookPath);
|
|
16533
16840
|
} else {
|
|
16534
16841
|
throw new Error("worktree setup hook must be an absolute path or a repo-relative path");
|
|
16535
16842
|
}
|
|
16536
|
-
if (!
|
|
16843
|
+
if (!fs7.existsSync(resolvedPath)) {
|
|
16537
16844
|
throw new Error(`worktree setup hook not found: ${resolvedPath}`);
|
|
16538
16845
|
}
|
|
16539
|
-
if (
|
|
16846
|
+
if (fs7.statSync(resolvedPath).isDirectory()) {
|
|
16540
16847
|
throw new Error(`worktree setup hook must be a file, got directory: ${resolvedPath}`);
|
|
16541
16848
|
}
|
|
16542
16849
|
return {
|
|
@@ -16548,17 +16855,17 @@ function normalizeSyntheticPath(worktreePath, rawPath) {
|
|
|
16548
16855
|
const trimmed = rawPath.trim();
|
|
16549
16856
|
if (!trimmed)
|
|
16550
16857
|
throw new Error("synthetic path cannot be empty");
|
|
16551
|
-
if (
|
|
16858
|
+
if (path7.isAbsolute(trimmed))
|
|
16552
16859
|
throw new Error(`synthetic path must be relative: ${rawPath}`);
|
|
16553
|
-
const resolved =
|
|
16554
|
-
const relative =
|
|
16860
|
+
const resolved = path7.resolve(worktreePath, trimmed);
|
|
16861
|
+
const relative = path7.relative(worktreePath, resolved);
|
|
16555
16862
|
if (!relative || relative === ".") {
|
|
16556
16863
|
throw new Error(`synthetic path cannot target the worktree root: ${rawPath}`);
|
|
16557
16864
|
}
|
|
16558
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
16865
|
+
if (relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative)) {
|
|
16559
16866
|
throw new Error(`synthetic path escapes the worktree root: ${rawPath}`);
|
|
16560
16867
|
}
|
|
16561
|
-
return
|
|
16868
|
+
return path7.normalize(relative);
|
|
16562
16869
|
}
|
|
16563
16870
|
function hasTrackedEntries(worktreePath, relativePath) {
|
|
16564
16871
|
const result = runGit(worktreePath, ["ls-files", "--", relativePath]);
|
|
@@ -16630,16 +16937,16 @@ function waitForGitLockRelease() {
|
|
|
16630
16937
|
}
|
|
16631
16938
|
function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
16632
16939
|
for (const relativePath of new Set(relativePaths)) {
|
|
16633
|
-
const target =
|
|
16634
|
-
const relative =
|
|
16635
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
16940
|
+
const target = path7.resolve(worktreePath, relativePath);
|
|
16941
|
+
const relative = path7.relative(worktreePath, target);
|
|
16942
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path7.sep}`) || path7.isAbsolute(relative))
|
|
16636
16943
|
continue;
|
|
16637
16944
|
let current = worktreePath;
|
|
16638
|
-
for (const component of relative.split(
|
|
16639
|
-
current =
|
|
16945
|
+
for (const component of relative.split(path7.sep)) {
|
|
16946
|
+
current = path7.join(current, component);
|
|
16640
16947
|
let stat;
|
|
16641
16948
|
try {
|
|
16642
|
-
stat =
|
|
16949
|
+
stat = fs7.lstatSync(current);
|
|
16643
16950
|
} catch (error) {
|
|
16644
16951
|
const code = error.code;
|
|
16645
16952
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -16649,7 +16956,7 @@ function unlinkWorktreeLinks(worktreePath, relativePaths) {
|
|
|
16649
16956
|
if (!stat.isSymbolicLink())
|
|
16650
16957
|
continue;
|
|
16651
16958
|
if (current === target)
|
|
16652
|
-
|
|
16959
|
+
fs7.unlinkSync(current);
|
|
16653
16960
|
break;
|
|
16654
16961
|
}
|
|
16655
16962
|
}
|
|
@@ -16677,7 +16984,7 @@ function createSingleWorktree(mainRoot, cwdRelative, runId, index, baseRef, base
|
|
|
16677
16984
|
cleanupSingleWorktree(mainRoot, { path: worktreePath, branch }, []);
|
|
16678
16985
|
throw new Error(message);
|
|
16679
16986
|
}
|
|
16680
|
-
const agentCwd = cwdRelative ?
|
|
16987
|
+
const agentCwd = cwdRelative ? path7.join(worktreePath, cwdRelative) : worktreePath;
|
|
16681
16988
|
const syntheticPaths = [];
|
|
16682
16989
|
try {
|
|
16683
16990
|
syntheticPaths.push(...performPostCreationSetup(mainRoot, worktreePath, symlinkDirectories));
|
|
@@ -16746,8 +17053,8 @@ var init_worktree = __esm(() => {
|
|
|
16746
17053
|
});
|
|
16747
17054
|
|
|
16748
17055
|
// dist/builtin/workflows/src/runs/shared/worktree-cwd.ts
|
|
16749
|
-
import { lstatSync as
|
|
16750
|
-
import { dirname as
|
|
17056
|
+
import { lstatSync as lstatSync6, realpathSync as realpathSync4 } from "node:fs";
|
|
17057
|
+
import { dirname as dirname10, isAbsolute as isAbsolute6, relative as relative4, resolve as resolve8, sep as sep5 } from "node:path";
|
|
16751
17058
|
function relativePathWithin(root, candidate) {
|
|
16752
17059
|
const path = relative4(root, candidate);
|
|
16753
17060
|
return path === ".." || path.startsWith(`..${sep5}`) || isAbsolute6(path) ? undefined : path;
|
|
@@ -16766,14 +17073,14 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
16766
17073
|
if (cwd === undefined || cwd.length === 0)
|
|
16767
17074
|
return;
|
|
16768
17075
|
const absoluteInput = isAbsolute6(cwd);
|
|
16769
|
-
const candidate = absoluteInput ? cwd :
|
|
17076
|
+
const candidate = absoluteInput ? cwd : resolve8(setup.cwd, cwd);
|
|
16770
17077
|
if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
|
|
16771
17078
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
|
|
16772
17079
|
}
|
|
16773
17080
|
const candidateRealPath = existingRealPath(candidate, "cwd");
|
|
16774
17081
|
const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
|
|
16775
17082
|
if (worktreeRelative !== undefined)
|
|
16776
|
-
return
|
|
17083
|
+
return resolve8(setup.worktreeRoot, worktreeRelative);
|
|
16777
17084
|
if (!isAbsolute6(cwd)) {
|
|
16778
17085
|
throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
|
|
16779
17086
|
}
|
|
@@ -16782,9 +17089,9 @@ function resolveWorktreeStageCwd(cwd, setup) {
|
|
|
16782
17089
|
}
|
|
16783
17090
|
const repositoryRelative = absoluteInput ? relativePathWithin(repositoryRoot, candidateRealPath) : undefined;
|
|
16784
17091
|
if (repositoryRelative === undefined) {
|
|
16785
|
-
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.`);
|
|
17092
|
+
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.`);
|
|
16786
17093
|
}
|
|
16787
|
-
const mappedCwd =
|
|
17094
|
+
const mappedCwd = resolve8(setup.worktreeRoot, repositoryRelative);
|
|
16788
17095
|
const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
|
|
16789
17096
|
if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
|
|
16790
17097
|
throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
|
|
@@ -16795,7 +17102,7 @@ var init_worktree_cwd = () => {};
|
|
|
16795
17102
|
|
|
16796
17103
|
// dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts
|
|
16797
17104
|
import { existsSync as existsSync4 } from "node:fs";
|
|
16798
|
-
import { isAbsolute as isAbsolute7, resolve as
|
|
17105
|
+
import { isAbsolute as isAbsolute7, resolve as resolve9 } from "node:path";
|
|
16799
17106
|
function normalizeTaskContexts(previous) {
|
|
16800
17107
|
if (previous === undefined)
|
|
16801
17108
|
return [];
|
|
@@ -16848,7 +17155,7 @@ function taskPrevious(options) {
|
|
|
16848
17155
|
function resolveWorkflowPath(filePath, baseDir) {
|
|
16849
17156
|
if (isAbsolute7(filePath))
|
|
16850
17157
|
return filePath;
|
|
16851
|
-
return
|
|
17158
|
+
return resolve9(baseDir ?? process.cwd(), filePath);
|
|
16852
17159
|
}
|
|
16853
17160
|
function taskBaseDir(options) {
|
|
16854
17161
|
if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
|
|
@@ -17003,7 +17310,7 @@ function taskWithSharedDefaults(taskOptions, options) {
|
|
|
17003
17310
|
var init_executor_task_prompts = () => {};
|
|
17004
17311
|
|
|
17005
17312
|
// dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
|
|
17006
|
-
import { isAbsolute as isAbsolute8, join as
|
|
17313
|
+
import { isAbsolute as isAbsolute8, join as join12, resolve as resolve10 } from "node:path";
|
|
17007
17314
|
import { CONFIG_DIR_NAME } from "@bastani/atomic";
|
|
17008
17315
|
function positiveConcurrency(value2) {
|
|
17009
17316
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < 1)
|
|
@@ -17156,10 +17463,10 @@ function workflowInvocationMetadata(inputDefaults, workflowInvocationCwd, cache,
|
|
|
17156
17463
|
function resolvedTaskCwd(cwd, workflowInvocationCwd) {
|
|
17157
17464
|
if (cwd === undefined)
|
|
17158
17465
|
return;
|
|
17159
|
-
return isAbsolute8(cwd) ? cwd :
|
|
17466
|
+
return isAbsolute8(cwd) ? cwd : resolve10(workflowInvocationCwd, cwd);
|
|
17160
17467
|
}
|
|
17161
17468
|
function taskWorktreeOutputsRoot(runId) {
|
|
17162
|
-
return
|
|
17469
|
+
return join12(workflowArtifactRunPath(runId), "task-outputs");
|
|
17163
17470
|
}
|
|
17164
17471
|
function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCwd = process.cwd(), symlinkDirectories) {
|
|
17165
17472
|
if (options.worktree !== true && !tasks.some((task) => task.worktree === true)) {
|
|
@@ -17169,7 +17476,7 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
17169
17476
|
throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
|
|
17170
17477
|
}
|
|
17171
17478
|
const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
|
|
17172
|
-
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd :
|
|
17479
|
+
const sharedCwd = explicitCwd === undefined ? workflowInvocationCwd : isAbsolute8(explicitCwd) ? explicitCwd : resolve10(workflowInvocationCwd, explicitCwd);
|
|
17173
17480
|
const conflict = findWorktreeTaskCwdConflict(tasks.map((task) => ({ agent: task.name, cwd: resolvedTaskCwd(task.cwd, workflowInvocationCwd) })), sharedCwd);
|
|
17174
17481
|
if (conflict !== undefined)
|
|
17175
17482
|
throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
|
|
@@ -17184,9 +17491,9 @@ function prepareTaskWorktrees(tasks, options, runId, scope, workflowInvocationCw
|
|
|
17184
17491
|
tasks: tasks.map((task, index) => ({ ...task, cwd: setup.worktrees[index].agentCwd })),
|
|
17185
17492
|
setup,
|
|
17186
17493
|
agents,
|
|
17187
|
-
diffsDir:
|
|
17494
|
+
diffsDir: join12(setup.cwd, CONFIG_DIR_NAME, "workflows", "worktree-diffs", runId, scope),
|
|
17188
17495
|
outputIsolations: tasks.map((_, index) => ({
|
|
17189
|
-
baseDir:
|
|
17496
|
+
baseDir: join12(trustedRoot, runId, scope, String(index)),
|
|
17190
17497
|
trustedRoot
|
|
17191
17498
|
}))
|
|
17192
17499
|
};
|
|
@@ -18628,13 +18935,13 @@ function raceAbort2(operation, signal) {
|
|
|
18628
18935
|
}
|
|
18629
18936
|
|
|
18630
18937
|
// dist/builtin/workflows/src/shared/possible-stages.ts
|
|
18631
|
-
import { existsSync as existsSync5, readFileSync as
|
|
18632
|
-
import { dirname as
|
|
18938
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
|
|
18939
|
+
import { dirname as dirname11, join as join13, resolve as resolve11 } from "node:path";
|
|
18633
18940
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
18634
18941
|
function scanPossibleStagesFromSource(entrySourcePath, options = {}) {
|
|
18635
18942
|
const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
18636
18943
|
const scanner = new PossibleStagesScanner(maxDepth);
|
|
18637
|
-
scanner.scanSubtree(
|
|
18944
|
+
scanner.scanSubtree(resolve11(entrySourcePath), "", 0, [resolve11(entrySourcePath)]);
|
|
18638
18945
|
return {
|
|
18639
18946
|
hasTrackedNodes: scanner.hasTrackedNodes,
|
|
18640
18947
|
stages: [...scanner.stages].sort(),
|
|
@@ -18645,7 +18952,7 @@ function resolveBuiltinDefinitionSource(name) {
|
|
|
18645
18952
|
const builtinDir = fileURLToPath3(new URL("../../builtin/", import.meta.url));
|
|
18646
18953
|
for (const stem of [name, kebabCase(name)]) {
|
|
18647
18954
|
for (const extension of [".ts", ".js"]) {
|
|
18648
|
-
const candidate =
|
|
18955
|
+
const candidate = join13(builtinDir, `${stem}${extension}`);
|
|
18649
18956
|
if (isFileSync(candidate))
|
|
18650
18957
|
return candidate;
|
|
18651
18958
|
}
|
|
@@ -18884,7 +19191,7 @@ function templateToPattern(raw) {
|
|
|
18884
19191
|
function buildFileUnit(path, warnings) {
|
|
18885
19192
|
let source;
|
|
18886
19193
|
try {
|
|
18887
|
-
source =
|
|
19194
|
+
source = readFileSync4(path, "utf-8");
|
|
18888
19195
|
} catch (error) {
|
|
18889
19196
|
warnings.push(`possible-stages: failed to read ${path}: ${errorMessage2(error)}`);
|
|
18890
19197
|
return;
|
|
@@ -20088,16 +20395,16 @@ function resolveRelativeSpecifier(specifier, importingFile) {
|
|
|
20088
20395
|
return;
|
|
20089
20396
|
const candidates = [];
|
|
20090
20397
|
if (specifier.endsWith(".js")) {
|
|
20091
|
-
candidates.push(
|
|
20398
|
+
candidates.push(join13(dirname11(importingFile), `${specifier.slice(0, -3)}.ts`));
|
|
20092
20399
|
}
|
|
20093
|
-
candidates.push(
|
|
20400
|
+
candidates.push(join13(dirname11(importingFile), specifier), join13(dirname11(importingFile), `${specifier}.ts`), join13(dirname11(importingFile), `${specifier}.js`), join13(dirname11(importingFile), specifier, "index.ts"), join13(dirname11(importingFile), specifier, "index.js"));
|
|
20094
20401
|
return candidates.find((candidate) => isFileSync(candidate));
|
|
20095
20402
|
}
|
|
20096
20403
|
function isFileSync(path) {
|
|
20097
20404
|
if (!existsSync5(path))
|
|
20098
20405
|
return false;
|
|
20099
20406
|
try {
|
|
20100
|
-
|
|
20407
|
+
readFileSync4(path, { flag: "r" });
|
|
20101
20408
|
return true;
|
|
20102
20409
|
} catch {
|
|
20103
20410
|
return false;
|
|
@@ -20125,7 +20432,7 @@ var init_possible_stages = __esm(() => {
|
|
|
20125
20432
|
|
|
20126
20433
|
// dist/builtin/workflows/src/workers/admission-host.ts
|
|
20127
20434
|
import { execFile, execFileSync } from "node:child_process";
|
|
20128
|
-
import { readdirSync as
|
|
20435
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
20129
20436
|
import { readFile } from "node:fs/promises";
|
|
20130
20437
|
import { hostname } from "node:os";
|
|
20131
20438
|
function admissionBootIdentity() {
|
|
@@ -20156,7 +20463,7 @@ function workerProcessExited(pid, final = false) {
|
|
|
20156
20463
|
return true;
|
|
20157
20464
|
if (process.platform === "linux") {
|
|
20158
20465
|
try {
|
|
20159
|
-
const stat =
|
|
20466
|
+
const stat = readFileSync5(`/proc/${pid}/stat`, "utf8");
|
|
20160
20467
|
return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
|
|
20161
20468
|
} catch {
|
|
20162
20469
|
return admissionProcessStopped(pid);
|
|
@@ -20176,7 +20483,7 @@ function scanProcessGroup(group) {
|
|
|
20176
20483
|
let complete = true;
|
|
20177
20484
|
let entries;
|
|
20178
20485
|
try {
|
|
20179
|
-
entries =
|
|
20486
|
+
entries = readdirSync4("/proc");
|
|
20180
20487
|
} catch {
|
|
20181
20488
|
return { members, complete: false };
|
|
20182
20489
|
}
|
|
@@ -20185,7 +20492,7 @@ function scanProcessGroup(group) {
|
|
|
20185
20492
|
continue;
|
|
20186
20493
|
let stat;
|
|
20187
20494
|
try {
|
|
20188
|
-
stat =
|
|
20495
|
+
stat = readFileSync5(`/proc/${entry}/stat`, "utf8");
|
|
20189
20496
|
} catch {
|
|
20190
20497
|
complete = false;
|
|
20191
20498
|
continue;
|
|
@@ -20416,6 +20723,7 @@ class SqlResourceAdmission {
|
|
|
20416
20723
|
epoch: this.options.attempt.epoch
|
|
20417
20724
|
}) : null);
|
|
20418
20725
|
});
|
|
20726
|
+
let quarantinedSince;
|
|
20419
20727
|
try {
|
|
20420
20728
|
for (;; ) {
|
|
20421
20729
|
signal?.throwIfAborted();
|
|
@@ -20425,7 +20733,9 @@ class SqlResourceAdmission {
|
|
|
20425
20733
|
}
|
|
20426
20734
|
const hostReason = this.hostReason();
|
|
20427
20735
|
const pressure = this.stageStartPressure(kind, request?.delegated);
|
|
20736
|
+
let quarantined = undefined;
|
|
20428
20737
|
const granted = await this.storage.transaction(async (tx) => {
|
|
20738
|
+
quarantined = undefined;
|
|
20429
20739
|
await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
|
|
20430
20740
|
const { root } = this.options;
|
|
20431
20741
|
if (!await this.assertCurrentAttempt(tx)) {
|
|
@@ -20443,6 +20753,8 @@ class SqlResourceAdmission {
|
|
|
20443
20753
|
if (control && control.state !== "running")
|
|
20444
20754
|
reason ??= `root ${control.state}`;
|
|
20445
20755
|
}
|
|
20756
|
+
const held = [];
|
|
20757
|
+
let blockedOtherwise = reason !== undefined;
|
|
20446
20758
|
for (const scope of [`root:${root}`, "user"]) {
|
|
20447
20759
|
const row = await tx.get(`SELECT config FROM ${this.configuration} WHERE scope = ?`, scope);
|
|
20448
20760
|
const limit = row ? JSON.parse(String(row.config))[kind] : undefined;
|
|
@@ -20452,9 +20764,21 @@ class SqlResourceAdmission {
|
|
|
20452
20764
|
const args = scope === "user" ? [kind] : [kind, root];
|
|
20453
20765
|
const count = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted'`, ...args);
|
|
20454
20766
|
const older = await tx.get(`SELECT 1 AS waiting FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'waiting' AND reason IS NOT ? AND ticket < (SELECT ticket FROM ${this.permits} WHERE operation = ?) LIMIT 1`, ...args, STAGE_START_PRESSURE_REASON, operation);
|
|
20455
|
-
|
|
20456
|
-
|
|
20767
|
+
const used = Number(count?.count);
|
|
20768
|
+
if (used < limit && !older)
|
|
20769
|
+
continue;
|
|
20770
|
+
reason ??= `${scope} ${kind}`;
|
|
20771
|
+
const quarantinedPermits = kind === "process" && used >= limit ? await tx.all(`SELECT process_identity FROM ${this.permits} WHERE kind = ? ${rootClause} AND state = 'granted' AND reason = ?`, ...args, QUARANTINED_REASON) : [];
|
|
20772
|
+
if (quarantinedPermits.length > 0 && used - quarantinedPermits.length < limit)
|
|
20773
|
+
held.push({
|
|
20774
|
+
limit: `${scope === "user" ? "admission.userLimits" : "admission.limits"}.${kind} (${limit})`,
|
|
20775
|
+
groups: quarantinedPermits.flatMap(({ process_identity }) => process_identity === null ? [] : [JSON.parse(process_identity).id])
|
|
20776
|
+
});
|
|
20777
|
+
else
|
|
20778
|
+
blockedOtherwise = true;
|
|
20457
20779
|
}
|
|
20780
|
+
if (!blockedOtherwise && held.length > 0)
|
|
20781
|
+
quarantined = held;
|
|
20458
20782
|
if (reason && request?.delegated)
|
|
20459
20783
|
throw new Error(`Delegated session cannot be admitted without capacity headroom: ${reason}`);
|
|
20460
20784
|
const stageStart = kind === "session" && request?.delegated !== true;
|
|
@@ -20467,6 +20791,14 @@ class SqlResourceAdmission {
|
|
|
20467
20791
|
signal?.throwIfAborted();
|
|
20468
20792
|
return release;
|
|
20469
20793
|
}
|
|
20794
|
+
if (quarantined === undefined)
|
|
20795
|
+
quarantinedSince = undefined;
|
|
20796
|
+
else {
|
|
20797
|
+
const now = performance.now();
|
|
20798
|
+
quarantinedSince ??= now;
|
|
20799
|
+
if (now - quarantinedSince >= QUARANTINED_CAPACITY_WAIT_MS)
|
|
20800
|
+
throw new QuarantinedCapacityError(quarantined, now - quarantinedSince);
|
|
20801
|
+
}
|
|
20470
20802
|
await delay(50 + Math.floor(Math.random() * 25), undefined, { signal });
|
|
20471
20803
|
}
|
|
20472
20804
|
} catch (error) {
|
|
@@ -20508,9 +20840,9 @@ class SqlResourceAdmission {
|
|
|
20508
20840
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'host reboot confirmed' WHERE owner = ? AND state = 'granted'`, owner.id);
|
|
20509
20841
|
} else if (stopped) {
|
|
20510
20842
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'owner death confirmed' WHERE owner = ? AND kind = 'session' AND state = 'granted'`, owner.id);
|
|
20511
|
-
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ?`, UNCONFIRMED_REASON, owner.id, UNCONFIRMED_REASON);
|
|
20843
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ? AND reason IS NOT ?`, UNCONFIRMED_REASON, owner.id, UNCONFIRMED_REASON, QUARANTINED_REASON);
|
|
20512
20844
|
} else {
|
|
20513
|
-
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND state = 'granted' AND reason IS NOT ? AND EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS})`, EXPIRED_REASON, owner.id, EXPIRED_REASON, owner.id);
|
|
20845
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner = ? AND state = 'granted' AND reason IS NOT ? AND reason IS NOT ? AND EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS})`, EXPIRED_REASON, owner.id, EXPIRED_REASON, QUARANTINED_REASON, owner.id);
|
|
20514
20846
|
}
|
|
20515
20847
|
if (owner.host === admissionHost && process.platform !== "win32") {
|
|
20516
20848
|
const processes = await tx.all(`SELECT * FROM ${this.permits} WHERE owner = ? AND state = 'granted' AND kind = 'process' AND process_identity IS NOT NULL`, owner.id);
|
|
@@ -20538,9 +20870,10 @@ class SqlResourceAdmission {
|
|
|
20538
20870
|
return true;
|
|
20539
20871
|
if (permit.state === "waiting")
|
|
20540
20872
|
return stopped || !!permit.expired;
|
|
20541
|
-
|
|
20873
|
+
const quarantined = permit.reason === QUARANTINED_REASON;
|
|
20874
|
+
if (stopped && (permit.kind === "session" || permit.reason !== UNCONFIRMED_REASON && !quarantined))
|
|
20542
20875
|
return true;
|
|
20543
|
-
if (!stopped && permit.expired && permit.reason !== EXPIRED_REASON)
|
|
20876
|
+
if (!stopped && permit.expired && permit.reason !== EXPIRED_REASON && !quarantined)
|
|
20544
20877
|
return true;
|
|
20545
20878
|
return permit.kind === "process" && permit.host === admissionHost && process.platform !== "win32" && permit.process_identity !== null && processGroupStopped(permit.process_identity);
|
|
20546
20879
|
}
|
|
@@ -20551,7 +20884,9 @@ class SqlResourceAdmission {
|
|
|
20551
20884
|
await this.reconcile();
|
|
20552
20885
|
return this.storage.transaction(async (tx) => {
|
|
20553
20886
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'worker exit confirmed' WHERE root = ? AND holder = ? AND state IN ('waiting', 'granted') AND (kind = 'session' OR state = 'waiting')`, this.options.root, holder);
|
|
20554
|
-
|
|
20887
|
+
await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ?`, UNCONFIRMED_REASON, this.options.root, holder, QUARANTINED_REASON);
|
|
20888
|
+
const held = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted'`, this.options.root, holder);
|
|
20889
|
+
return Number(held?.count);
|
|
20555
20890
|
});
|
|
20556
20891
|
}
|
|
20557
20892
|
async reapStoppedProcesses(holder) {
|
|
@@ -20598,10 +20933,13 @@ async function settleProcessGroups(storage, root, scope, reap) {
|
|
|
20598
20933
|
survivors = await settle(REAP_KILL_GRACE_MS);
|
|
20599
20934
|
}
|
|
20600
20935
|
const confirmed = [...groups].flatMap(([group, operations]) => survivors.includes(group) ? [] : operations);
|
|
20601
|
-
|
|
20936
|
+
const quarantined = reap ? survivors.flatMap((group) => groups.get(group) ?? []) : [];
|
|
20937
|
+
if (confirmed.length > 0 || quarantined.length > 0)
|
|
20602
20938
|
await storage.transaction(async (tx) => {
|
|
20603
20939
|
for (const operation of confirmed)
|
|
20604
20940
|
await tx.run(`UPDATE ${permits} SET state = 'released', reason = 'process group cleanup confirmed' WHERE operation = ? AND state = 'granted'`, operation);
|
|
20941
|
+
for (const operation of quarantined)
|
|
20942
|
+
await tx.run(`UPDATE ${permits} SET reason = ? WHERE operation = ? AND state = 'granted'`, QUARANTINED_REASON, operation);
|
|
20605
20943
|
});
|
|
20606
20944
|
return { survivors, unprobeable };
|
|
20607
20945
|
}
|
|
@@ -20618,11 +20956,20 @@ async function reapProcessGroups(journal, root, scope) {
|
|
|
20618
20956
|
return { survivors: [], unprobeable: [] };
|
|
20619
20957
|
return settleProcessGroups(storage, root, scope, true);
|
|
20620
20958
|
}
|
|
20621
|
-
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
|
|
20959
|
+
var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", QUARANTINED_REASON = "cleanup unconfirmed; permit quarantined", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", QUARANTINED_CAPACITY_WAIT_MS, QuarantinedCapacityError, NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
|
|
20622
20960
|
var init_resource_admission = __esm(() => {
|
|
20623
20961
|
init_internal();
|
|
20624
20962
|
init_sql_run_journal();
|
|
20963
|
+
init_workflow_infrastructure_error();
|
|
20625
20964
|
init_admission_host();
|
|
20965
|
+
QUARANTINED_CAPACITY_WAIT_MS = REAP_TERM_GRACE_MS + REAP_KILL_GRACE_MS;
|
|
20966
|
+
QuarantinedCapacityError = class QuarantinedCapacityError extends WorkflowInfrastructureError {
|
|
20967
|
+
constructor(capacity, waitedMs) {
|
|
20968
|
+
const limits = capacity.map(({ limit }) => limit).join(" and ");
|
|
20969
|
+
const groups = [...new Set(capacity.flatMap(({ groups }) => groups))].join(", ");
|
|
20970
|
+
super("worker_cleanup_unconfirmed", `Local worker process cleanup unconfirmed; process permit refused after ${Math.round(waitedMs)} ms: ${limits} ${capacity.length === 1 ? "is" : "are"} held by quarantined permits of process groups ${groups} that survived SIGKILL`);
|
|
20971
|
+
}
|
|
20972
|
+
};
|
|
20626
20973
|
});
|
|
20627
20974
|
|
|
20628
20975
|
// dist/builtin/workflows/src/workers/admission-binding.ts
|
|
@@ -56924,10 +57271,10 @@ var init_verification_prompts = __esm(() => {
|
|
|
56924
57271
|
// dist/builtin/workflows/builtin/pattern-artifact-root.ts
|
|
56925
57272
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
56926
57273
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
56927
|
-
import { join as
|
|
57274
|
+
import { join as join14 } from "node:path";
|
|
56928
57275
|
async function stableArtifactRoot(ctx, workflowName) {
|
|
56929
57276
|
const cwd = ctx.cwd ?? process.cwd();
|
|
56930
|
-
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () =>
|
|
57277
|
+
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join14(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID9()}`));
|
|
56931
57278
|
await mkdir2(artifactDir, { recursive: true });
|
|
56932
57279
|
return artifactDir;
|
|
56933
57280
|
}
|
|
@@ -56967,7 +57314,7 @@ function fold_usage(results) {
|
|
|
56967
57314
|
|
|
56968
57315
|
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
56969
57316
|
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
56970
|
-
import { join as
|
|
57317
|
+
import { join as join15 } from "node:path";
|
|
56971
57318
|
import { Type as Type4 } from "typebox";
|
|
56972
57319
|
function isRecord3(value2) {
|
|
56973
57320
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -57062,8 +57409,8 @@ async function writeInvalid(path, stage) {
|
|
|
57062
57409
|
}
|
|
57063
57410
|
async function runAdversarialVerification(ctx) {
|
|
57064
57411
|
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
57065
|
-
const criteriaPath =
|
|
57066
|
-
const candidatePath =
|
|
57412
|
+
const criteriaPath = join15(root, "criteria.md");
|
|
57413
|
+
const candidatePath = join15(root, "candidate.md");
|
|
57067
57414
|
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
57068
57415
|
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
57069
57416
|
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
@@ -57095,7 +57442,7 @@ async function runAdversarialVerification(ctx) {
|
|
|
57095
57442
|
criterion,
|
|
57096
57443
|
verifierIndex: index + 1,
|
|
57097
57444
|
name,
|
|
57098
|
-
artifactPath:
|
|
57445
|
+
artifactPath: join15(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
57099
57446
|
});
|
|
57100
57447
|
}
|
|
57101
57448
|
}
|
|
@@ -57148,8 +57495,8 @@ async function runAdversarialVerification(ctx) {
|
|
|
57148
57495
|
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
57149
57496
|
finalDecision = decision;
|
|
57150
57497
|
finalMean = meanScore(scoreReports);
|
|
57151
|
-
scoreTablePath =
|
|
57152
|
-
reviewReportPath =
|
|
57498
|
+
scoreTablePath = join15(root, `verification-summary-${round}.json`);
|
|
57499
|
+
reviewReportPath = join15(root, `review-${round}.json`);
|
|
57153
57500
|
const summary = {
|
|
57154
57501
|
scores: scoreReports,
|
|
57155
57502
|
mean: finalMean,
|
|
@@ -57330,7 +57677,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
|
|
|
57330
57677
|
|
|
57331
57678
|
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
57332
57679
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
57333
|
-
import { join as
|
|
57680
|
+
import { join as join16 } from "node:path";
|
|
57334
57681
|
import { Type as Type6 } from "typebox";
|
|
57335
57682
|
function safeName(value2) {
|
|
57336
57683
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -57370,7 +57717,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
57370
57717
|
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
57371
57718
|
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
57372
57719
|
const category = fallback?.category ?? exactCategory;
|
|
57373
|
-
const classificationPath =
|
|
57720
|
+
const classificationPath = join16(artifactDir, "classification.json");
|
|
57374
57721
|
await writeFile2(classificationPath, JSON.stringify({
|
|
57375
57722
|
proposed_category: proposedCategory,
|
|
57376
57723
|
selected_category: category,
|
|
@@ -57380,7 +57727,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
57380
57727
|
fallback_used: needsFallback,
|
|
57381
57728
|
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
57382
57729
|
}, null, 2));
|
|
57383
|
-
const actionPath =
|
|
57730
|
+
const actionPath = join16(artifactDir, `action-${safeName(category)}.md`);
|
|
57384
57731
|
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
57385
57732
|
tools: actionTools(category),
|
|
57386
57733
|
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
@@ -57520,7 +57867,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
|
|
|
57520
57867
|
|
|
57521
57868
|
// dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
|
|
57522
57869
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
57523
|
-
import { join as
|
|
57870
|
+
import { join as join17 } from "node:path";
|
|
57524
57871
|
import { Type as Type8 } from "typebox";
|
|
57525
57872
|
function safeName2(value2, index) {
|
|
57526
57873
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -57551,9 +57898,9 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
57551
57898
|
context: "fresh"
|
|
57552
57899
|
});
|
|
57553
57900
|
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
57554
|
-
const partitionPath =
|
|
57901
|
+
const partitionPath = join17(artifactDir, "partition-plan.json");
|
|
57555
57902
|
await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
57556
|
-
const branchPaths = partitions.map((partition, index) =>
|
|
57903
|
+
const branchPaths = partitions.map((partition, index) => join17(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
|
|
57557
57904
|
const steps = partitions.map((partition, index) => ({
|
|
57558
57905
|
name: `branch-${safeName2(partition.label, index)}`,
|
|
57559
57906
|
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
@@ -57563,13 +57910,13 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
57563
57910
|
outputMode: "file-only"
|
|
57564
57911
|
}));
|
|
57565
57912
|
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
57566
|
-
const manifestPath =
|
|
57913
|
+
const manifestPath = join17(artifactDir, "manifest.json");
|
|
57567
57914
|
await writeFile3(manifestPath, JSON.stringify({
|
|
57568
57915
|
task: ctx.inputs.prompt,
|
|
57569
57916
|
partition_plan: partitionPath,
|
|
57570
57917
|
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
|
|
57571
57918
|
}, null, 2));
|
|
57572
|
-
const synthesisPath =
|
|
57919
|
+
const synthesisPath = join17(artifactDir, "synthesis.md");
|
|
57573
57920
|
const synthesis = await ctx.task("synthesize", {
|
|
57574
57921
|
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
57575
57922
|
context: "fresh",
|
|
@@ -57734,7 +58081,7 @@ var init_generate_and_filter_prompts = __esm(() => {
|
|
|
57734
58081
|
|
|
57735
58082
|
// dist/builtin/workflows/builtin/generate-and-filter-runner.ts
|
|
57736
58083
|
import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
57737
|
-
import { join as
|
|
58084
|
+
import { join as join18 } from "node:path";
|
|
57738
58085
|
import { Type as Type10 } from "typebox";
|
|
57739
58086
|
function isRecord4(value2) {
|
|
57740
58087
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -57753,7 +58100,7 @@ function judgeDecision(value2) {
|
|
|
57753
58100
|
}
|
|
57754
58101
|
async function runGenerateAndFilter(ctx) {
|
|
57755
58102
|
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
57756
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) =>
|
|
58103
|
+
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join18(root, `candidate-${index + 1}.md`));
|
|
57757
58104
|
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
57758
58105
|
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
57759
58106
|
name: `generate-${index + 1}`,
|
|
@@ -57762,9 +58109,9 @@ async function runGenerateAndFilter(ctx) {
|
|
|
57762
58109
|
output: path,
|
|
57763
58110
|
outputMode: "file-only"
|
|
57764
58111
|
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
57765
|
-
const manifestPath =
|
|
58112
|
+
const manifestPath = join18(root, "manifest.json");
|
|
57766
58113
|
await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
57767
|
-
const filterPath =
|
|
58114
|
+
const filterPath = join18(root, "filter.json");
|
|
57768
58115
|
const filtered = await ctx.task("dedupe-and-filter", {
|
|
57769
58116
|
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
|
|
57770
58117
|
context: "fresh",
|
|
@@ -57781,7 +58128,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
57781
58128
|
let judgePath = null;
|
|
57782
58129
|
let decisionPath = filterPath;
|
|
57783
58130
|
if (ctx.inputs.use_judge) {
|
|
57784
|
-
judgePath =
|
|
58131
|
+
judgePath = join18(root, "judge.json");
|
|
57785
58132
|
const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
|
|
57786
58133
|
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
57787
58134
|
const judged = await ctx.task("judge", {
|
|
@@ -57797,7 +58144,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
57797
58144
|
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
57798
58145
|
decisionPath = judgePath;
|
|
57799
58146
|
}
|
|
57800
|
-
const finalPath =
|
|
58147
|
+
const finalPath = join18(root, "shortlist.md");
|
|
57801
58148
|
const finalShortlist = await ctx.task("final-shortlist", {
|
|
57802
58149
|
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
|
|
57803
58150
|
context: "fresh",
|
|
@@ -58326,7 +58673,7 @@ var init_review_convergence = __esm(() => {
|
|
|
58326
58673
|
|
|
58327
58674
|
// dist/builtin/workflows/builtin/goal-artifacts.ts
|
|
58328
58675
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
58329
|
-
import { join as
|
|
58676
|
+
import { join as join19 } from "node:path";
|
|
58330
58677
|
function artifactSafeName(value2) {
|
|
58331
58678
|
const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
58332
58679
|
return safe.length > 0 ? safe : "artifact";
|
|
@@ -58337,7 +58684,7 @@ function withoutTurn(value2) {
|
|
|
58337
58684
|
return copy;
|
|
58338
58685
|
}
|
|
58339
58686
|
async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
|
|
58340
|
-
const artifactPath =
|
|
58687
|
+
const artifactPath = join19(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
58341
58688
|
await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
|
|
58342
58689
|
`, { encoding: "utf8" });
|
|
58343
58690
|
return artifactPath;
|
|
@@ -58346,7 +58693,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
|
|
|
58346
58693
|
reviewer: review.reviewer,
|
|
58347
58694
|
findings: review.findings
|
|
58348
58695
|
}))), reverification = []) {
|
|
58349
|
-
const artifactPath =
|
|
58696
|
+
const artifactPath = join19(artifactDir, "review-round-latest.json");
|
|
58350
58697
|
const visibleReviews = reviews.map(withoutTurn);
|
|
58351
58698
|
await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
|
|
58352
58699
|
`, { encoding: "utf8" });
|
|
@@ -58576,7 +58923,7 @@ var init_goal_review = __esm(() => {
|
|
|
58576
58923
|
// dist/builtin/workflows/builtin/goal-ledger.ts
|
|
58577
58924
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
58578
58925
|
import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
58579
|
-
import { dirname as
|
|
58926
|
+
import { dirname as dirname12, join as join20 } from "node:path";
|
|
58580
58927
|
import { isDeepStrictEqual } from "node:util";
|
|
58581
58928
|
function withoutTurn2(value2) {
|
|
58582
58929
|
const copy = { ...value2 };
|
|
@@ -58601,7 +58948,7 @@ function modelVisibleLedger(ledger) {
|
|
|
58601
58948
|
};
|
|
58602
58949
|
}
|
|
58603
58950
|
function goalLedgerStatePath(ledgerPath) {
|
|
58604
|
-
return
|
|
58951
|
+
return join20(dirname12(ledgerPath), LEDGER_STATE_FILENAME);
|
|
58605
58952
|
}
|
|
58606
58953
|
function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
|
|
58607
58954
|
ledger.lifecycle.push({
|
|
@@ -58677,7 +59024,7 @@ function recoverLegacyExecutionInterruption(ledger) {
|
|
|
58677
59024
|
return true;
|
|
58678
59025
|
}
|
|
58679
59026
|
async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
|
|
58680
|
-
const ledgerPath =
|
|
59027
|
+
const ledgerPath = join20(artifactDir, LEDGER_FILENAME);
|
|
58681
59028
|
const existing = await readExistingGoalLedger(ledgerPath);
|
|
58682
59029
|
if (existing !== undefined) {
|
|
58683
59030
|
if (recoverLegacyExecutionInterruption(existing))
|
|
@@ -59184,7 +59531,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
|
|
|
59184
59531
|
});
|
|
59185
59532
|
|
|
59186
59533
|
// dist/builtin/workflows/builtin/goal-runner.ts
|
|
59187
|
-
import { join as
|
|
59534
|
+
import { join as join21 } from "node:path";
|
|
59188
59535
|
function positiveInteger(value2, fallback) {
|
|
59189
59536
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
|
|
59190
59537
|
return fallback;
|
|
@@ -59235,7 +59582,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
59235
59582
|
appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
|
|
59236
59583
|
await writeGoalLedger(ledgerPath, ledger);
|
|
59237
59584
|
}
|
|
59238
|
-
const orchestratorReceiptPath =
|
|
59585
|
+
const orchestratorReceiptPath = join21(artifactDir, "orchestrator-receipt.md");
|
|
59239
59586
|
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
|
|
59240
59587
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
|
|
59241
59588
|
ledger,
|
|
@@ -59306,7 +59653,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
59306
59653
|
const reviewerName = result.name ?? result.stageName;
|
|
59307
59654
|
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
59308
59655
|
const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
|
|
59309
|
-
const reviewArtifactPath =
|
|
59656
|
+
const reviewArtifactPath = join21(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
|
|
59310
59657
|
const record = reviewDecisionToRecord({
|
|
59311
59658
|
turn,
|
|
59312
59659
|
reviewer: normalizedReviewerName,
|
|
@@ -59509,7 +59856,7 @@ var init_goal = __esm(() => {
|
|
|
59509
59856
|
}),
|
|
59510
59857
|
git_worktree_dir: Type15.String({
|
|
59511
59858
|
default: "",
|
|
59512
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
59859
|
+
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."
|
|
59513
59860
|
}),
|
|
59514
59861
|
create_pr: Type15.Boolean({
|
|
59515
59862
|
default: false,
|
|
@@ -59627,7 +59974,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
|
|
|
59627
59974
|
|
|
59628
59975
|
// dist/builtin/workflows/builtin/loop-until-done-runner.ts
|
|
59629
59976
|
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
59630
|
-
import { join as
|
|
59977
|
+
import { join as join22 } from "node:path";
|
|
59631
59978
|
import { Type as Type16 } from "typebox";
|
|
59632
59979
|
function progressCurve(entries) {
|
|
59633
59980
|
return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
|
|
@@ -59710,18 +60057,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
|
|
|
59710
60057
|
}
|
|
59711
60058
|
async function runLoopUntilDone(ctx) {
|
|
59712
60059
|
const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
|
|
59713
|
-
const iterationsDir =
|
|
59714
|
-
const evaluationsDir =
|
|
60060
|
+
const iterationsDir = join22(artifactDir, "iterations");
|
|
60061
|
+
const evaluationsDir = join22(artifactDir, "evaluations");
|
|
59715
60062
|
await mkdir3(iterationsDir, { recursive: true });
|
|
59716
60063
|
await mkdir3(evaluationsDir, { recursive: true });
|
|
59717
|
-
const ledgerPath =
|
|
60064
|
+
const ledgerPath = join22(artifactDir, "progress-ledger.json");
|
|
59718
60065
|
const entries = [];
|
|
59719
60066
|
const iterationArtifactPaths = [];
|
|
59720
60067
|
const evaluationArtifactPaths = [];
|
|
59721
60068
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
|
|
59722
60069
|
for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
|
|
59723
|
-
const iterationPath =
|
|
59724
|
-
const evaluationPath =
|
|
60070
|
+
const iterationPath = join22(iterationsDir, `iteration-${iteration}.md`);
|
|
60071
|
+
const evaluationPath = join22(evaluationsDir, `evaluation-${iteration}.json`);
|
|
59725
60072
|
iterationArtifactPaths.push(iterationPath);
|
|
59726
60073
|
evaluationArtifactPaths.push(evaluationPath);
|
|
59727
60074
|
await ctx.task(`iteration-${iteration}`, {
|
|
@@ -59770,7 +60117,7 @@ async function runLoopUntilDone(ctx) {
|
|
|
59770
60117
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
|
|
59771
60118
|
if (decision.done) {
|
|
59772
60119
|
const report = progressReport(entries);
|
|
59773
|
-
const resultPath =
|
|
60120
|
+
const resultPath = join22(artifactDir, "result.md");
|
|
59774
60121
|
const final = await ctx.task("completion-summary", {
|
|
59775
60122
|
prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
|
|
59776
60123
|
context: "fresh",
|
|
@@ -59887,9 +60234,9 @@ var init_loop_until_done = __esm(() => {
|
|
|
59887
60234
|
|
|
59888
60235
|
// dist/builtin/workflows/builtin/open-claude-design-utils.ts
|
|
59889
60236
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
59890
|
-
import { mkdirSync as
|
|
60237
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
59891
60238
|
import { tmpdir, userInfo } from "node:os";
|
|
59892
|
-
import { join as
|
|
60239
|
+
import { join as join23 } from "node:path";
|
|
59893
60240
|
import { Type as Type18 } from "typebox";
|
|
59894
60241
|
import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
|
|
59895
60242
|
function taggedPrompt3(sections) {
|
|
@@ -59932,32 +60279,32 @@ function tmpArtifactBase() {
|
|
|
59932
60279
|
try {
|
|
59933
60280
|
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
59934
60281
|
} catch {}
|
|
59935
|
-
return
|
|
60282
|
+
return join23(tmpdir(), `open-claude-design-${user}`);
|
|
59936
60283
|
}
|
|
59937
60284
|
function prepareArtifactDir(cwd = process.cwd()) {
|
|
59938
60285
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
59939
60286
|
const tmpCandidates = [
|
|
59940
|
-
|
|
59941
|
-
|
|
60287
|
+
join23(tmpArtifactBase(), runId),
|
|
60288
|
+
join23(tmpdir(), "open-claude-design", runId)
|
|
59942
60289
|
];
|
|
59943
|
-
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [
|
|
60290
|
+
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join23(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
59944
60291
|
for (const candidate of candidates) {
|
|
59945
60292
|
try {
|
|
59946
|
-
|
|
60293
|
+
mkdirSync6(candidate, { recursive: true });
|
|
59947
60294
|
return {
|
|
59948
60295
|
runId,
|
|
59949
60296
|
artifactDir: candidate,
|
|
59950
|
-
previewPath:
|
|
59951
|
-
specPath:
|
|
60297
|
+
previewPath: join23(candidate, "preview.html"),
|
|
60298
|
+
specPath: join23(candidate, "spec.html")
|
|
59952
60299
|
};
|
|
59953
60300
|
} catch {}
|
|
59954
60301
|
}
|
|
59955
|
-
const fallback =
|
|
60302
|
+
const fallback = join23(tmpArtifactBase(), runId);
|
|
59956
60303
|
return {
|
|
59957
60304
|
runId,
|
|
59958
60305
|
artifactDir: fallback,
|
|
59959
|
-
previewPath:
|
|
59960
|
-
specPath:
|
|
60306
|
+
previewPath: join23(fallback, "preview.html"),
|
|
60307
|
+
specPath: join23(fallback, "spec.html")
|
|
59961
60308
|
};
|
|
59962
60309
|
}
|
|
59963
60310
|
function ensureAgentBrowser() {
|
|
@@ -60291,8 +60638,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
|
|
|
60291
60638
|
});
|
|
60292
60639
|
|
|
60293
60640
|
// dist/builtin/workflows/builtin/open-claude-design-setup.ts
|
|
60294
|
-
import { mkdirSync as
|
|
60295
|
-
import { join as
|
|
60641
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
60642
|
+
import { join as join24 } from "node:path";
|
|
60296
60643
|
function renderDiscoveryContext(discovery) {
|
|
60297
60644
|
return [
|
|
60298
60645
|
`Confirmed design brief: ${discovery.brief}`,
|
|
@@ -60357,10 +60704,10 @@ async function runDiscoveryAndInit(args) {
|
|
|
60357
60704
|
};
|
|
60358
60705
|
}
|
|
60359
60706
|
function designContextPath(artifactDir) {
|
|
60360
|
-
return
|
|
60707
|
+
return join24(artifactDir, DESIGN_CONTEXT_FILENAME);
|
|
60361
60708
|
}
|
|
60362
60709
|
function referencesBriefPath(artifactDir) {
|
|
60363
|
-
return
|
|
60710
|
+
return join24(artifactDir, REFERENCES_BRIEF_FILENAME);
|
|
60364
60711
|
}
|
|
60365
60712
|
function buildReferenceDiscoveryPrompt(args) {
|
|
60366
60713
|
const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
|
|
@@ -60386,8 +60733,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
60386
60733
|
[
|
|
60387
60734
|
"Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
|
|
60388
60735
|
"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.",
|
|
60389
|
-
`Capture motion across the entire page: start \`agent-browser record start ${
|
|
60390
|
-
`Also run \`agent-browser screenshot ${
|
|
60736
|
+
`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\`.`,
|
|
60737
|
+
`Also run \`agent-browser screenshot ${join24(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
|
|
60391
60738
|
"Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
|
|
60392
60739
|
"Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
|
|
60393
60740
|
"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.",
|
|
@@ -60412,8 +60759,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
60412
60759
|
}
|
|
60413
60760
|
function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
|
|
60414
60761
|
try {
|
|
60415
|
-
|
|
60416
|
-
|
|
60762
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
60763
|
+
writeFileSync4(filePath, `${content}
|
|
60417
60764
|
`);
|
|
60418
60765
|
} catch (error) {
|
|
60419
60766
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -60964,7 +61311,7 @@ var init_ralph_review_gate = __esm(() => {
|
|
|
60964
61311
|
|
|
60965
61312
|
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
60966
61313
|
import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
|
|
60967
|
-
import { dirname as
|
|
61314
|
+
import { dirname as dirname13, join as join25 } from "node:path";
|
|
60968
61315
|
import { Type as Type20 } from "typebox";
|
|
60969
61316
|
function taggedPrompt4(sections) {
|
|
60970
61317
|
return sections.map(([tag, content]) => {
|
|
@@ -61004,11 +61351,11 @@ function slugifyResearchTopic(prompt) {
|
|
|
61004
61351
|
}
|
|
61005
61352
|
function defaultResearchPath(prompt, now = new Date) {
|
|
61006
61353
|
const date = now.toISOString().slice(0, 10);
|
|
61007
|
-
return
|
|
61354
|
+
return join25(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
61008
61355
|
}
|
|
61009
61356
|
async function createImplementationNotesFile(prompt, runId) {
|
|
61010
61357
|
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
61011
|
-
const notesPath =
|
|
61358
|
+
const notesPath = join25(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
61012
61359
|
const initialNotes = [
|
|
61013
61360
|
"# Implementation Notes",
|
|
61014
61361
|
"",
|
|
@@ -61029,7 +61376,7 @@ async function createImplementationNotesFile(prompt, runId) {
|
|
|
61029
61376
|
}
|
|
61030
61377
|
async function createQaEvidenceVideoPath(runId) {
|
|
61031
61378
|
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
61032
|
-
return
|
|
61379
|
+
return join25(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
61033
61380
|
}
|
|
61034
61381
|
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
61035
61382
|
return [
|
|
@@ -61095,7 +61442,7 @@ function artifactSafeName2(value2) {
|
|
|
61095
61442
|
return safe.length > 0 ? safe : "artifact";
|
|
61096
61443
|
}
|
|
61097
61444
|
async function writeJsonArtifact(path, content) {
|
|
61098
|
-
await mkdir4(
|
|
61445
|
+
await mkdir4(dirname13(path), { recursive: true });
|
|
61099
61446
|
await writeFile8(path, `${JSON.stringify(content, null, 2)}
|
|
61100
61447
|
`, {
|
|
61101
61448
|
encoding: "utf8"
|
|
@@ -61433,7 +61780,7 @@ var init_ralph_models = __esm(() => {
|
|
|
61433
61780
|
|
|
61434
61781
|
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
61435
61782
|
import { existsSync as existsSync6 } from "node:fs";
|
|
61436
|
-
import { join as
|
|
61783
|
+
import { join as join26, resolve as resolve12 } from "node:path";
|
|
61437
61784
|
async function runRalphWorkflow(ctx, options) {
|
|
61438
61785
|
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
61439
61786
|
let latestReviewReportPath;
|
|
@@ -61445,7 +61792,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
61445
61792
|
let finalPrReport;
|
|
61446
61793
|
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
61447
61794
|
const workflowPrompt = prompt;
|
|
61448
|
-
const workflowResearchPath =
|
|
61795
|
+
const workflowResearchPath = resolve12(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
61449
61796
|
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
61450
61797
|
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
61451
61798
|
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
@@ -61494,7 +61841,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
61494
61841
|
const researchPath = workflowResearchPath;
|
|
61495
61842
|
finalResearchPath = researchPath;
|
|
61496
61843
|
finalPlanPath = researchPath;
|
|
61497
|
-
const orchestratorReportPath =
|
|
61844
|
+
const orchestratorReportPath = join26(artifactDir, "orchestrator-report.md");
|
|
61498
61845
|
const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
|
|
61499
61846
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
|
|
61500
61847
|
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
@@ -61630,7 +61977,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
61630
61977
|
diagnostics: parsed.diagnostics,
|
|
61631
61978
|
allowFinalActionRemaining: createPr
|
|
61632
61979
|
});
|
|
61633
|
-
const artifactPath =
|
|
61980
|
+
const artifactPath = join26(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
|
|
61634
61981
|
await writeJsonArtifact(artifactPath, {
|
|
61635
61982
|
reviewer,
|
|
61636
61983
|
decision: parsed.decision,
|
|
@@ -61686,7 +62033,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
61686
62033
|
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
61687
62034
|
}));
|
|
61688
62035
|
}
|
|
61689
|
-
latestReviewReportPath = await writeJsonArtifact(
|
|
62036
|
+
latestReviewReportPath = await writeJsonArtifact(join26(artifactDir, "review-round-latest.json"), {
|
|
61690
62037
|
convergence_decision: roundConvergenceDecision,
|
|
61691
62038
|
convergence: convergenceEntries,
|
|
61692
62039
|
consolidated_findings: reverified.batch,
|
|
@@ -61835,7 +62182,7 @@ var init_ralph = __esm(() => {
|
|
|
61835
62182
|
}),
|
|
61836
62183
|
git_worktree_dir: Type21.String({
|
|
61837
62184
|
default: "",
|
|
61838
|
-
description: "Optional Git worktree path. Leave at the default unless the user explicitly requested worktree isolation — stages never create git worktrees on their own.
|
|
62185
|
+
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."
|
|
61839
62186
|
}),
|
|
61840
62187
|
create_pr: Type21.Boolean({
|
|
61841
62188
|
default: false,
|
|
@@ -62055,7 +62402,7 @@ var init_tournament_prompts = __esm(() => {
|
|
|
62055
62402
|
|
|
62056
62403
|
// dist/builtin/workflows/builtin/tournament-runner.ts
|
|
62057
62404
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
|
|
62058
|
-
import { join as
|
|
62405
|
+
import { join as join27, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve13 } from "node:path";
|
|
62059
62406
|
import { Type as Type22 } from "typebox";
|
|
62060
62407
|
function serializableObject3(value2) {
|
|
62061
62408
|
if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
|
|
@@ -62092,8 +62439,8 @@ function criterionSlug(id) {
|
|
|
62092
62439
|
}
|
|
62093
62440
|
function judgeArtifactPath(judgesDir, job, criterionIndex) {
|
|
62094
62441
|
const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
|
|
62095
|
-
const root =
|
|
62096
|
-
const path =
|
|
62442
|
+
const root = resolve13(judgesDir);
|
|
62443
|
+
const path = resolve13(judgesDir, filename);
|
|
62097
62444
|
const fromRoot = relative5(root, path);
|
|
62098
62445
|
if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
|
|
62099
62446
|
throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
|
|
@@ -62144,16 +62491,16 @@ function combineUsage(totals) {
|
|
|
62144
62491
|
}
|
|
62145
62492
|
async function runTournament(ctx) {
|
|
62146
62493
|
const artifactDir = await stableArtifactRoot(ctx, "tournament");
|
|
62147
|
-
const attemptsDir =
|
|
62494
|
+
const attemptsDir = join27(artifactDir, "attempts");
|
|
62148
62495
|
const numAttempts = ctx.inputs.num_attempts ?? 4;
|
|
62149
62496
|
const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
|
|
62150
62497
|
const nEvaluations = ctx.inputs.n_evaluations ?? 2;
|
|
62151
62498
|
const pivotCount = ctx.inputs.pivots ?? 1;
|
|
62152
62499
|
const seed = ctx.inputs.seed ?? 0;
|
|
62153
|
-
const judgesDir =
|
|
62500
|
+
const judgesDir = join27(artifactDir, "judges");
|
|
62154
62501
|
await mkdir5(attemptsDir, { recursive: true });
|
|
62155
62502
|
await mkdir5(judgesDir, { recursive: true });
|
|
62156
|
-
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
|
|
62503
|
+
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join27(attemptsDir, `attempt-${index + 1}.md`));
|
|
62157
62504
|
const models = ctx.inputs.models;
|
|
62158
62505
|
const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
|
|
62159
62506
|
name: `attempt-${index + 1}`,
|
|
@@ -62318,7 +62665,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
62318
62665
|
const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
|
|
62319
62666
|
const budgetPivots = Math.min(pivotCount, entrants.length);
|
|
62320
62667
|
const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
|
|
62321
|
-
const comparisonPath =
|
|
62668
|
+
const comparisonPath = join27(artifactDir, "comparisons.json");
|
|
62322
62669
|
const assignment = modelAssignment(entrants, models);
|
|
62323
62670
|
const phaseUsage = {
|
|
62324
62671
|
attempts: fold_usage(attemptResults),
|
|
@@ -62354,7 +62701,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
62354
62701
|
await writeLedger(fold_usage([]));
|
|
62355
62702
|
const winner = ranking[0];
|
|
62356
62703
|
const winnerEntrant = entrants[winner.index];
|
|
62357
|
-
const resultPath =
|
|
62704
|
+
const resultPath = join27(artifactDir, "winner.md");
|
|
62358
62705
|
const reducer = await ctx.task("comparisons-reducer", {
|
|
62359
62706
|
prompt: renderComparisonsReducerPrompt({
|
|
62360
62707
|
task: ctx.inputs.prompt,
|
|
@@ -63301,7 +63648,7 @@ class SqlPoolQueue {
|
|
|
63301
63648
|
throw new Error("Stale pool coordinator authority", { cause: error });
|
|
63302
63649
|
throw error;
|
|
63303
63650
|
});
|
|
63304
|
-
const row = await this.current(tx, lease, token);
|
|
63651
|
+
const row = await this.current(tx, lease, token, true);
|
|
63305
63652
|
if (row.epoch !== lease.epoch)
|
|
63306
63653
|
throw new Error(STALE_WORK_LEASE);
|
|
63307
63654
|
assertSession();
|
|
@@ -65313,7 +65660,7 @@ function isBrokerStatusReport(value2) {
|
|
|
65313
65660
|
|
|
65314
65661
|
// dist/builtin/intercom/broker/paths.ts
|
|
65315
65662
|
import { homedir as homedir2 } from "os";
|
|
65316
|
-
import { join as
|
|
65663
|
+
import { join as join28 } from "path";
|
|
65317
65664
|
function getHomeDir() {
|
|
65318
65665
|
if (process.platform === "win32") {
|
|
65319
65666
|
if (process.env.USERPROFILE)
|
|
@@ -65330,7 +65677,7 @@ function expandTildePath(path) {
|
|
|
65330
65677
|
if (path === "~")
|
|
65331
65678
|
return getHomeDir();
|
|
65332
65679
|
if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
|
|
65333
|
-
return
|
|
65680
|
+
return join28(getHomeDir(), path.slice(2));
|
|
65334
65681
|
}
|
|
65335
65682
|
return path;
|
|
65336
65683
|
}
|
|
@@ -65341,31 +65688,31 @@ function getAgentDir5() {
|
|
|
65341
65688
|
const piAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
65342
65689
|
if (piAgentDir)
|
|
65343
65690
|
return expandTildePath(piAgentDir);
|
|
65344
|
-
return
|
|
65691
|
+
return join28(getHomeDir(), ".atomic", "agent");
|
|
65345
65692
|
}
|
|
65346
65693
|
function sanitizePipeSegment(value2) {
|
|
65347
65694
|
return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
|
|
65348
65695
|
}
|
|
65349
65696
|
function getIntercomDirPath(agentDir = getAgentDir5()) {
|
|
65350
|
-
return
|
|
65697
|
+
return join28(agentDir, "intercom");
|
|
65351
65698
|
}
|
|
65352
65699
|
function getBrokerPidPath(agentDir = getAgentDir5()) {
|
|
65353
|
-
return
|
|
65700
|
+
return join28(getIntercomDirPath(agentDir), "broker.pid");
|
|
65354
65701
|
}
|
|
65355
65702
|
function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
65356
|
-
return
|
|
65703
|
+
return join28(getIntercomDirPath(agentDir), "broker.spawn.lock");
|
|
65357
65704
|
}
|
|
65358
65705
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
65359
|
-
return
|
|
65706
|
+
return join28(getIntercomDirPath(agentDir), "broker.log");
|
|
65360
65707
|
}
|
|
65361
65708
|
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
65362
|
-
return
|
|
65709
|
+
return join28(getIntercomDirPath(agentDir), "broker.starting");
|
|
65363
65710
|
}
|
|
65364
65711
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
65365
65712
|
if (platform === "win32") {
|
|
65366
65713
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
65367
65714
|
}
|
|
65368
|
-
return
|
|
65715
|
+
return join28(getIntercomDirPath(agentDir), "broker.sock");
|
|
65369
65716
|
}
|
|
65370
65717
|
var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
|
|
65371
65718
|
var init_paths = () => {};
|
|
@@ -67049,11 +67396,11 @@ var init_client = __esm(() => {
|
|
|
67049
67396
|
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
67050
67397
|
|
|
67051
67398
|
// dist/builtin/intercom/broker/start-announcement.ts
|
|
67052
|
-
import { readFileSync as
|
|
67399
|
+
import { readFileSync as readFileSync6, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
67053
67400
|
function readBrokerStartAnnouncement(announcement) {
|
|
67054
67401
|
let text;
|
|
67055
67402
|
try {
|
|
67056
|
-
text =
|
|
67403
|
+
text = readFileSync6(announcement.path, "utf-8");
|
|
67057
67404
|
} catch {
|
|
67058
67405
|
return;
|
|
67059
67406
|
}
|
|
@@ -67072,26 +67419,26 @@ var init_start_announcement = () => {};
|
|
|
67072
67419
|
// dist/builtin/intercom/broker/spawn.ts
|
|
67073
67420
|
import { spawn } from "child_process";
|
|
67074
67421
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
67075
|
-
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync7, mkdirSync as
|
|
67076
|
-
import { join as
|
|
67422
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync7, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync7, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
67423
|
+
import { join as join29, dirname as dirname14 } from "path";
|
|
67077
67424
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
67078
67425
|
import { createRequire as createRequire3 } from "module";
|
|
67079
67426
|
import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
|
|
67080
67427
|
function isIntercomPackageRoot(dir) {
|
|
67081
|
-
return existsSync7(
|
|
67428
|
+
return existsSync7(join29(dir, "package.json")) && existsSync7(join29(dir, "broker"));
|
|
67082
67429
|
}
|
|
67083
67430
|
function resolveIntercomPackageRoot(moduleHref) {
|
|
67084
|
-
const here =
|
|
67431
|
+
const here = dirname14(fileURLToPath5(moduleHref));
|
|
67085
67432
|
if (isIntercomPackageRoot(here))
|
|
67086
67433
|
return here;
|
|
67087
|
-
return
|
|
67434
|
+
return join29(here, "..");
|
|
67088
67435
|
}
|
|
67089
67436
|
function resolveBrokerEntrypoint(packageRoot) {
|
|
67090
|
-
const bundled =
|
|
67091
|
-
return existsSync7(bundled) ? bundled :
|
|
67437
|
+
const bundled = join29(packageRoot, "broker", "broker.bundle.mjs");
|
|
67438
|
+
return existsSync7(bundled) ? bundled : join29(packageRoot, "broker", "broker.ts");
|
|
67092
67439
|
}
|
|
67093
67440
|
function ensurePrivateDirectory(path) {
|
|
67094
|
-
|
|
67441
|
+
mkdirSync8(path, { recursive: true, mode: 448 });
|
|
67095
67442
|
if (process.platform !== "win32")
|
|
67096
67443
|
chmodSync(path, 448);
|
|
67097
67444
|
}
|
|
@@ -67104,14 +67451,14 @@ function getCurrentBrokerRuntime() {
|
|
|
67104
67451
|
return isBunBinary ? "bun-binary" : "bun-source";
|
|
67105
67452
|
}
|
|
67106
67453
|
function requireFromExtensionDir(extensionDir) {
|
|
67107
|
-
return createRequire3(
|
|
67454
|
+
return createRequire3(join29(extensionDir, "package.json"));
|
|
67108
67455
|
}
|
|
67109
67456
|
function getJitiCliPath(extensionDir = EXTENSION_DIR) {
|
|
67110
67457
|
try {
|
|
67111
67458
|
const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
|
|
67112
|
-
return
|
|
67459
|
+
return join29(dirname14(jitiPackage), "lib", "jiti-cli.mjs");
|
|
67113
67460
|
} catch {
|
|
67114
|
-
return
|
|
67461
|
+
return join29(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
|
|
67115
67462
|
}
|
|
67116
67463
|
}
|
|
67117
67464
|
function getDefaultBrokerRunnerPath(extensionDir) {
|
|
@@ -67133,7 +67480,7 @@ function quoteWindowsArg(value2) {
|
|
|
67133
67480
|
return `"${value2.replace(/"/g, '""')}"`;
|
|
67134
67481
|
}
|
|
67135
67482
|
function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
|
|
67136
|
-
return
|
|
67483
|
+
return join29(intercomDir, "broker-launch.vbs");
|
|
67137
67484
|
}
|
|
67138
67485
|
function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
|
|
67139
67486
|
return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
|
|
@@ -67160,8 +67507,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
67160
67507
|
`);
|
|
67161
67508
|
}
|
|
67162
67509
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
67163
|
-
ensurePrivateDirectory(
|
|
67164
|
-
|
|
67510
|
+
ensurePrivateDirectory(dirname14(launcherPath));
|
|
67511
|
+
writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
67165
67512
|
return launcherPath;
|
|
67166
67513
|
}
|
|
67167
67514
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -67204,14 +67551,14 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore",
|
|
|
67204
67551
|
};
|
|
67205
67552
|
}
|
|
67206
67553
|
function resetBrokerLog(logPath = BROKER_LOG) {
|
|
67207
|
-
ensurePrivateDirectory(
|
|
67554
|
+
ensurePrivateDirectory(dirname14(logPath));
|
|
67208
67555
|
try {
|
|
67209
67556
|
const previous = readBrokerLogTail(logPath);
|
|
67210
67557
|
closeSync3(openSync3(logPath, "w"));
|
|
67211
67558
|
if (previous.length > 0) {
|
|
67212
67559
|
try {
|
|
67213
67560
|
const previousPath = `${logPath}.previous`;
|
|
67214
|
-
|
|
67561
|
+
writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
67215
67562
|
if (process.platform !== "win32")
|
|
67216
67563
|
chmodSync(previousPath, 384);
|
|
67217
67564
|
} catch {}
|
|
@@ -67355,7 +67702,7 @@ async function isBrokerRunning() {
|
|
|
67355
67702
|
if (!existsSync7(BROKER_PID))
|
|
67356
67703
|
return false;
|
|
67357
67704
|
try {
|
|
67358
|
-
const pid = parseInt(
|
|
67705
|
+
const pid = parseInt(readFileSync7(BROKER_PID, "utf-8").trim(), 10);
|
|
67359
67706
|
if (!Number.isFinite(pid))
|
|
67360
67707
|
return false;
|
|
67361
67708
|
process.kill(pid, 0);
|
|
@@ -67380,7 +67727,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
67380
67727
|
}
|
|
67381
67728
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
67382
67729
|
try {
|
|
67383
|
-
return
|
|
67730
|
+
return readFileSync7(lockPath, "utf-8").startsWith(owner);
|
|
67384
67731
|
} catch {
|
|
67385
67732
|
return false;
|
|
67386
67733
|
}
|
|
@@ -67392,7 +67739,7 @@ function acquireSpawnLock() {
|
|
|
67392
67739
|
${Date.now()}
|
|
67393
67740
|
`;
|
|
67394
67741
|
try {
|
|
67395
|
-
|
|
67742
|
+
writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
67396
67743
|
return owner;
|
|
67397
67744
|
} catch (error) {
|
|
67398
67745
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -67422,7 +67769,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
67422
67769
|
return false;
|
|
67423
67770
|
}
|
|
67424
67771
|
try {
|
|
67425
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
67772
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync7(lockPath, "utf-8").trim().split(`
|
|
67426
67773
|
`);
|
|
67427
67774
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
67428
67775
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -67500,14 +67847,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
67500
67847
|
});
|
|
67501
67848
|
|
|
67502
67849
|
// dist/builtin/intercom/config.ts
|
|
67503
|
-
import { existsSync as existsSync8, readFileSync as
|
|
67850
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
|
|
67504
67851
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
67505
67852
|
function loadConfig() {
|
|
67506
67853
|
if (!existsSync8(CONFIG_PATH)) {
|
|
67507
67854
|
return { ...defaults };
|
|
67508
67855
|
}
|
|
67509
67856
|
try {
|
|
67510
|
-
const raw =
|
|
67857
|
+
const raw = readFileSync8(CONFIG_PATH, "utf-8");
|
|
67511
67858
|
const parsed = JSON.parse(raw);
|
|
67512
67859
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
67513
67860
|
throw new Error("Config must be a JSON object");
|
|
@@ -68090,12 +68437,12 @@ var init_sql_pool_usage = __esm(() => {
|
|
|
68090
68437
|
|
|
68091
68438
|
// dist/builtin/workflows/src/workers/pooled-watch-trace.ts
|
|
68092
68439
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
68093
|
-
import { dirname as
|
|
68440
|
+
import { dirname as dirname15, join as join30, resolve as resolve14 } from "node:path";
|
|
68094
68441
|
function configurePooledWatchTrace(journalPath, processRole) {
|
|
68095
68442
|
if (setting === undefined || setting === "" || setting === "0")
|
|
68096
68443
|
return;
|
|
68097
68444
|
role = processRole;
|
|
68098
|
-
file = setting === "1" ?
|
|
68445
|
+
file = setting === "1" ? join30(dirname15(resolve14(journalPath)), "pooled-watch-trace.jsonl") : resolve14(setting);
|
|
68099
68446
|
}
|
|
68100
68447
|
function tracePooledWatch(step, detail) {
|
|
68101
68448
|
if (file === undefined)
|
|
@@ -68289,7 +68636,7 @@ import { fork } from "node:child_process";
|
|
|
68289
68636
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
68290
68637
|
import { createWriteStream } from "node:fs";
|
|
68291
68638
|
import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
68292
|
-
import { dirname as
|
|
68639
|
+
import { dirname as dirname16, join as join31, resolve as resolve15 } from "node:path";
|
|
68293
68640
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
68294
68641
|
function isRootLeaseLost(error) {
|
|
68295
68642
|
return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
|
|
@@ -68298,7 +68645,7 @@ function unconfirmedCleanup(groups) {
|
|
|
68298
68645
|
return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
|
|
68299
68646
|
}
|
|
68300
68647
|
function workerLogDirectory(journalPath, root) {
|
|
68301
|
-
return
|
|
68648
|
+
return join31(dirname16(resolve15(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
68302
68649
|
}
|
|
68303
68650
|
function token(work) {
|
|
68304
68651
|
return {
|
|
@@ -68486,6 +68833,7 @@ class PoolCoordinator {
|
|
|
68486
68833
|
cleanups = new Set;
|
|
68487
68834
|
controlAcks = new Map;
|
|
68488
68835
|
lastHeard = new Map;
|
|
68836
|
+
awaiting = new Map;
|
|
68489
68837
|
pendingActivity = new Map;
|
|
68490
68838
|
batches = new Map;
|
|
68491
68839
|
publicationFailures = new Map;
|
|
@@ -69229,7 +69577,7 @@ class PoolCoordinator {
|
|
|
69229
69577
|
this.slots.add(slot);
|
|
69230
69578
|
let ready = false;
|
|
69231
69579
|
let serial = Promise.resolve();
|
|
69232
|
-
const logPath =
|
|
69580
|
+
const logPath = join31(this.logDirectory, `${worker}.log`);
|
|
69233
69581
|
this.logs.set(child, logPath);
|
|
69234
69582
|
let logFailure;
|
|
69235
69583
|
const log = createWriteStream(logPath, { flags: "a" });
|
|
@@ -69285,6 +69633,7 @@ class PoolCoordinator {
|
|
|
69285
69633
|
this.readyWorkers.delete(worker);
|
|
69286
69634
|
this.controlAcks.delete(worker);
|
|
69287
69635
|
this.lastHeard.delete(worker);
|
|
69636
|
+
this.awaiting.delete(worker);
|
|
69288
69637
|
this.slots.delete(slot);
|
|
69289
69638
|
this.endStageWatches((watch) => watch.slot === slot, "worker_exited");
|
|
69290
69639
|
for (const settle of slot.stageCommands.values())
|
|
@@ -69542,8 +69891,19 @@ class PoolCoordinator {
|
|
|
69542
69891
|
await this.sendResult(work.id);
|
|
69543
69892
|
});
|
|
69544
69893
|
const response = handled.then((value2) => routeReady ?? value2);
|
|
69545
|
-
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
69546
|
-
|
|
69894
|
+
if (message.kind !== "delivery" && message.kind !== "delivery-ready") {
|
|
69895
|
+
this.awaiting.set(worker, (this.awaiting.get(worker) ?? 0) + 1);
|
|
69896
|
+
const answered = () => {
|
|
69897
|
+
const left = (this.awaiting.get(worker) ?? 1) - 1;
|
|
69898
|
+
if (left > 0)
|
|
69899
|
+
this.awaiting.set(worker, left);
|
|
69900
|
+
else
|
|
69901
|
+
this.awaiting.delete(worker);
|
|
69902
|
+
if (this.incarnations.get(worker) === child)
|
|
69903
|
+
this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
|
|
69904
|
+
};
|
|
69905
|
+
serial = handled.then(answered, answered);
|
|
69906
|
+
}
|
|
69547
69907
|
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => {
|
|
69548
69908
|
const rootLeaseLost = isRootLeaseLost(error);
|
|
69549
69909
|
if (rootLeaseLost)
|
|
@@ -69613,7 +69973,10 @@ class PoolCoordinator {
|
|
|
69613
69973
|
if (work.epoch < lease.epoch)
|
|
69614
69974
|
await this.releaseRetained(work);
|
|
69615
69975
|
else
|
|
69616
|
-
await queue.expire(lease, work)
|
|
69976
|
+
await queue.expire(lease, work).catch((error) => {
|
|
69977
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
69978
|
+
throw error;
|
|
69979
|
+
});
|
|
69617
69980
|
}
|
|
69618
69981
|
})().finally(() => {
|
|
69619
69982
|
this.recovering = undefined;
|
|
@@ -69631,7 +69994,7 @@ class PoolCoordinator {
|
|
|
69631
69994
|
isLive(worker, child) {
|
|
69632
69995
|
this.observeResponsiveness();
|
|
69633
69996
|
const heard = this.lastHeard.get(worker);
|
|
69634
|
-
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
|
|
69997
|
+
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);
|
|
69635
69998
|
}
|
|
69636
69999
|
async stop(child) {
|
|
69637
70000
|
const pid = child.pid;
|
|
@@ -69966,7 +70329,7 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
|
|
|
69966
70329
|
};
|
|
69967
70330
|
}
|
|
69968
70331
|
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, commit, recipient) {
|
|
69969
|
-
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
|
|
70332
|
+
const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, recipient?.receivedMessageIds);
|
|
69970
70333
|
const candidateIds = new Set([
|
|
69971
70334
|
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
69972
70335
|
...activeStore.pendingStageMessagesFor(runId, stageName),
|
|
@@ -70022,7 +70385,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
|
|
|
70022
70385
|
}
|
|
70023
70386
|
}
|
|
70024
70387
|
}
|
|
70025
|
-
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
|
|
70388
|
+
function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient, receivedByEndedStage = []) {
|
|
70026
70389
|
const runs = activeStore.runs();
|
|
70027
70390
|
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
70028
70391
|
if (rootRunId === undefined)
|
|
@@ -70031,22 +70394,28 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
|
|
|
70031
70394
|
if (rootRun === undefined)
|
|
70032
70395
|
return [];
|
|
70033
70396
|
const stage = runs.find((run) => run.id === runId)?.stages.find((candidate) => candidate.id === stageId);
|
|
70034
|
-
|
|
70397
|
+
const ended = stage?.status === "completed" || stage?.status === "skipped";
|
|
70398
|
+
if (ended && receivedByEndedStage.length === 0)
|
|
70035
70399
|
return [];
|
|
70036
70400
|
const hops = workflowBoundaryHops(runs, runId);
|
|
70037
70401
|
if (hops === undefined)
|
|
70038
70402
|
return [];
|
|
70039
70403
|
return (rootRun.pendingStageMessages ?? []).filter((entry) => {
|
|
70040
|
-
if (entry.sticky !== true || entry.status !== "queued")
|
|
70041
|
-
return false;
|
|
70042
|
-
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
70043
|
-
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
70044
|
-
return false;
|
|
70045
70404
|
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)))))
|
|
70046
70405
|
return false;
|
|
70047
|
-
|
|
70406
|
+
if (ended && !receivedByEndedStage.includes(entry.message.id))
|
|
70407
|
+
return false;
|
|
70408
|
+
return stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName);
|
|
70048
70409
|
});
|
|
70049
70410
|
}
|
|
70411
|
+
function stickyEntryTargetsStage(entry, rootRunId, hops, stageId, stageName) {
|
|
70412
|
+
if (entry.sticky !== true || entry.status !== "queued")
|
|
70413
|
+
return false;
|
|
70414
|
+
const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
|
|
70415
|
+
if (parsed === undefined || parsed.rootRunId !== rootRunId)
|
|
70416
|
+
return false;
|
|
70417
|
+
return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
|
|
70418
|
+
}
|
|
70050
70419
|
function claimPendingDelivery(store, runId, stageKey, messageId) {
|
|
70051
70420
|
let claims = pendingDeliveryClaims.get(store);
|
|
70052
70421
|
if (claims === undefined) {
|
|
@@ -70110,6 +70479,7 @@ class PoolStageHandoff {
|
|
|
70110
70479
|
owners = new Map;
|
|
70111
70480
|
publications = new Map;
|
|
70112
70481
|
drains = new Map;
|
|
70482
|
+
deliveryIssues = 0;
|
|
70113
70483
|
constructor(backend, store, queue, lease, claimRun) {
|
|
70114
70484
|
this.backend = backend;
|
|
70115
70485
|
this.store = store;
|
|
@@ -70190,11 +70560,23 @@ class PoolStageHandoff {
|
|
|
70190
70560
|
this.drains.set(stage, drain);
|
|
70191
70561
|
try {
|
|
70192
70562
|
await drain;
|
|
70563
|
+
} catch (error) {
|
|
70564
|
+
const current = this.attempts.get(work.id) === attempt && !attempt.fenced;
|
|
70565
|
+
if (current && attempt.sessions.get(stage) === recipient.sessionId && error.message !== STALE)
|
|
70566
|
+
this.recordDeliveryIssue(error);
|
|
70567
|
+
throw error;
|
|
70193
70568
|
} finally {
|
|
70194
70569
|
if (this.drains.get(stage) === drain)
|
|
70195
70570
|
this.drains.delete(stage);
|
|
70196
70571
|
}
|
|
70197
70572
|
}
|
|
70573
|
+
recordDeliveryIssue(error) {
|
|
70574
|
+
this.deliveryIssues++;
|
|
70575
|
+
const drains = this.deliveryIssues === 1 ? "1 stage drain" : `${this.deliveryIssues} stage drains`;
|
|
70576
|
+
this.store.recordRunExecutionState(this.lease.runId, {
|
|
70577
|
+
intercomDeliveryIssue: `${drains} on local workers failed; undelivered messages stay queued and arrive live or on the stage's next drain (last: ${error.message})`
|
|
70578
|
+
});
|
|
70579
|
+
}
|
|
70198
70580
|
async complete(work) {
|
|
70199
70581
|
const root = this.lease.runId;
|
|
70200
70582
|
const result = await this.queue.result(root, work.id);
|
|
@@ -71502,7 +71884,7 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
71502
71884
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
71503
71885
|
import { fork as fork2 } from "node:child_process";
|
|
71504
71886
|
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
71505
|
-
import { resolve as
|
|
71887
|
+
import { resolve as resolve16 } from "node:path";
|
|
71506
71888
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
71507
71889
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
71508
71890
|
import {
|
|
@@ -71736,7 +72118,7 @@ class LocalWorkerPool {
|
|
|
71736
72118
|
async poolJournal() {
|
|
71737
72119
|
const journal = this.backend.journal;
|
|
71738
72120
|
if (this.options.durable === undefined) {
|
|
71739
|
-
if (!(journal instanceof SqlRunJournal) ||
|
|
72121
|
+
if (!(journal instanceof SqlRunJournal) || resolve16(this.options.journalPath) !== resolve16(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
71740
72122
|
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
71741
72123
|
return journal;
|
|
71742
72124
|
}
|
|
@@ -72763,7 +73145,7 @@ var init_local_pool = __esm(() => {
|
|
|
72763
73145
|
var DEFAULT_POOLED_STAGE_START_MAX_LOAD_PER_CPU = 3;
|
|
72764
73146
|
|
|
72765
73147
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
72766
|
-
import { resolve as
|
|
73148
|
+
import { resolve as resolve17 } from "node:path";
|
|
72767
73149
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
72768
73150
|
function withWorkerSettings(options, settings) {
|
|
72769
73151
|
const configured = settings?.workflows;
|
|
@@ -72823,16 +73205,16 @@ async function activatePublicPool(backend, options) {
|
|
|
72823
73205
|
startupTimeoutMs: undefined,
|
|
72824
73206
|
leaseMs: undefined,
|
|
72825
73207
|
maxLoadPerCpu: undefined,
|
|
72826
|
-
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path:
|
|
73208
|
+
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve17(cwd, source.path) }))
|
|
72827
73209
|
};
|
|
72828
73210
|
const admission = options.admission && {
|
|
72829
73211
|
...options.admission,
|
|
72830
|
-
...options.admission.userDatabase ? { userDatabase:
|
|
73212
|
+
...options.admission.userDatabase ? { userDatabase: resolve17(cwd, options.admission.userDatabase) } : {}
|
|
72831
73213
|
};
|
|
72832
73214
|
if (durable !== undefined && admission?.userLimits) {
|
|
72833
|
-
if (admission.userDatabase !== undefined && admission.userDatabase !==
|
|
72834
|
-
throw new Error(`admission.userDatabase must be omitted, or ${
|
|
72835
|
-
admission.userDatabase =
|
|
73215
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve17(poolPath))
|
|
73216
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve17(poolPath)}, for a journal that is not a local SQLite file`);
|
|
73217
|
+
admission.userDatabase = resolve17(poolPath);
|
|
72836
73218
|
}
|
|
72837
73219
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
72838
73220
|
const resources = JSON.parse(JSON.stringify({
|
|
@@ -73438,6 +73820,7 @@ function createTaskPrimitive(runtime) {
|
|
|
73438
73820
|
}
|
|
73439
73821
|
})();
|
|
73440
73822
|
const stageMeta = stage.__modelFallbackMeta();
|
|
73823
|
+
stage.__releaseIfIdle?.();
|
|
73441
73824
|
return {
|
|
73442
73825
|
name,
|
|
73443
73826
|
stageName: name,
|
|
@@ -75908,6 +76291,8 @@ function createTrackedStageCaller(input) {
|
|
|
75908
76291
|
await runtime.releaseLiveHandle().catch(() => {});
|
|
75909
76292
|
}
|
|
75910
76293
|
runtime.state.sessionCheckpointed = finalizationError === undefined;
|
|
76294
|
+
if (runtime.state.contextUnreachable)
|
|
76295
|
+
runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId);
|
|
75911
76296
|
input.limiter.release();
|
|
75912
76297
|
if (finalizationError !== undefined)
|
|
75913
76298
|
throwFinalizationError(finalizationError.error);
|
|
@@ -76071,7 +76456,8 @@ function createStageContext(input) {
|
|
|
76071
76456
|
recordStageNotice({ kind: "abort", to: "interrupted" });
|
|
76072
76457
|
await innerCtx.abort();
|
|
76073
76458
|
},
|
|
76074
|
-
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta()
|
|
76459
|
+
__modelFallbackMeta: () => innerCtx.__modelFallbackMeta(),
|
|
76460
|
+
__releaseIfIdle: () => runtime.stageRegistry.releaseIdle(runtime.runId, runtime.stageId)
|
|
76075
76461
|
};
|
|
76076
76462
|
}
|
|
76077
76463
|
|
|
@@ -77760,10 +78146,10 @@ function isRetryableSameCandidateFailure(error) {
|
|
|
77760
78146
|
return isTransientExtensionStartupFailure(error);
|
|
77761
78147
|
return isRetryableSameModelFailure(error);
|
|
77762
78148
|
}
|
|
77763
|
-
function mayAdvanceToNextCandidate(error) {
|
|
78149
|
+
function mayAdvanceToNextCandidate(error, options) {
|
|
77764
78150
|
if (isExtensionStartupFailure(error))
|
|
77765
78151
|
return isTransientExtensionStartupFailure(error);
|
|
77766
|
-
return isRetryableModelFailure(error);
|
|
78152
|
+
return isRetryableModelFailure(error, options);
|
|
77767
78153
|
}
|
|
77768
78154
|
function hasMeaningfulUsage(usage) {
|
|
77769
78155
|
if (usage === undefined)
|
|
@@ -77855,6 +78241,7 @@ class StageSessionController {
|
|
|
77855
78241
|
structuredOutputExecutionFailureValue;
|
|
77856
78242
|
structuredOutputCycleAttemptMark;
|
|
77857
78243
|
unsubscribeTerminateWatcher;
|
|
78244
|
+
unbindAbortSignal;
|
|
77858
78245
|
sessionInternalRetries = 0;
|
|
77859
78246
|
unresolvedContextOverflowMessage;
|
|
77860
78247
|
generationSealed = false;
|
|
@@ -78344,6 +78731,8 @@ class StageSessionController {
|
|
|
78344
78731
|
this.pendingListeners.clear();
|
|
78345
78732
|
this.unsubscribeTerminateWatcher?.();
|
|
78346
78733
|
this.unsubscribeTerminateWatcher = undefined;
|
|
78734
|
+
this.unbindAbortSignal?.();
|
|
78735
|
+
this.unbindAbortSignal = undefined;
|
|
78347
78736
|
this.terminatingToolCallIds.clear();
|
|
78348
78737
|
this.messageAdmission.dispose();
|
|
78349
78738
|
this.deliveryActivity.dispose();
|
|
@@ -78438,8 +78827,10 @@ class StageSessionController {
|
|
|
78438
78827
|
};
|
|
78439
78828
|
if (signal.aborted)
|
|
78440
78829
|
onAbort();
|
|
78441
|
-
else
|
|
78830
|
+
else {
|
|
78442
78831
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
78832
|
+
this.unbindAbortSignal = () => signal.removeEventListener("abort", onAbort);
|
|
78833
|
+
}
|
|
78443
78834
|
}
|
|
78444
78835
|
markAbort(reason) {
|
|
78445
78836
|
this.abortGeneration += 1;
|
|
@@ -78466,6 +78857,9 @@ class StageSessionController {
|
|
|
78466
78857
|
state.controller.abort(reason);
|
|
78467
78858
|
this.thrownErrorRetryStates.clear();
|
|
78468
78859
|
}
|
|
78860
|
+
fallbackFailureOptions() {
|
|
78861
|
+
return { fallbackOnContentFilter: this.retrySettings()?.fallbackOnContentFilter !== false };
|
|
78862
|
+
}
|
|
78469
78863
|
retrySettings() {
|
|
78470
78864
|
const managers = [
|
|
78471
78865
|
this.sessionSettingsManager,
|
|
@@ -78740,7 +79134,7 @@ class StageSessionController {
|
|
|
78740
79134
|
const errorSettingsManager = retrySettingsManagerFromError(error);
|
|
78741
79135
|
if (errorSettingsManager !== undefined)
|
|
78742
79136
|
this.sessionSettingsManager = errorSettingsManager;
|
|
78743
|
-
const retryableFailure = isRetryableModelFailure(error);
|
|
79137
|
+
const retryableFailure = isRetryableModelFailure(error, this.fallbackFailureOptions());
|
|
78744
79138
|
const sameCandidateRetryable = isRetryableSameModelFailure(error) && !isUnresolvedContextOverflowFailure(error);
|
|
78745
79139
|
recordProviderRateLimit(this.currentProvider(), error, modelIdForModel(this.currentModelValue()));
|
|
78746
79140
|
if (this.hasExplicitModelFallbackConfig && isProviderRateLimit(error)) {
|
|
@@ -79365,7 +79759,7 @@ class StageSessionController {
|
|
|
79365
79759
|
}
|
|
79366
79760
|
throw new WorkflowPromptModelFailure(terminalFailure);
|
|
79367
79761
|
} catch (err) {
|
|
79368
|
-
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
79762
|
+
if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
79369
79763
|
this.artifactCapture.settleAttempt(true);
|
|
79370
79764
|
const usage = this.takeAttemptUsage(resumedSession);
|
|
79371
79765
|
this.modelAttempts.push({
|
|
@@ -79387,7 +79781,7 @@ class StageSessionController {
|
|
|
79387
79781
|
...usage === undefined ? {} : { usage },
|
|
79388
79782
|
error: message
|
|
79389
79783
|
});
|
|
79390
|
-
if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
|
|
79784
|
+
if (this.opts.signal?.aborted || !isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
79391
79785
|
this.modelWarnings.push(...this.pendingFallbackWarnings);
|
|
79392
79786
|
this.pendingFallbackWarnings.length = 0;
|
|
79393
79787
|
this.notifyModelFallbackMetaChange();
|
|
@@ -79436,7 +79830,7 @@ class StageSessionController {
|
|
|
79436
79830
|
throw err;
|
|
79437
79831
|
const message = errorMessage4(err);
|
|
79438
79832
|
const terminalStageDelivery = isWorkflowPendingStageDeliveryFailure(err);
|
|
79439
|
-
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
|
|
79833
|
+
if (!terminalStageDelivery && this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err, this.fallbackFailureOptions())) {
|
|
79440
79834
|
this.recordSuccessfulAttempt(candidate);
|
|
79441
79835
|
return "handled";
|
|
79442
79836
|
}
|
|
@@ -79453,7 +79847,7 @@ class StageSessionController {
|
|
|
79453
79847
|
if (walk !== undefined) {
|
|
79454
79848
|
this.recordCandidateFailure(walk, index, err, candidates);
|
|
79455
79849
|
nextIndex = undefined;
|
|
79456
|
-
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err)) {
|
|
79850
|
+
if (!this.opts.signal?.aborted && !this.startupWait.signal.aborted && !terminalStageDelivery && mayAdvanceToNextCandidate(err, this.fallbackFailureOptions())) {
|
|
79457
79851
|
try {
|
|
79458
79852
|
nextIndex = await this.selectReadyCandidate(candidates, walk, index + 1);
|
|
79459
79853
|
} catch (error) {
|
|
@@ -79466,7 +79860,7 @@ class StageSessionController {
|
|
|
79466
79860
|
}
|
|
79467
79861
|
}
|
|
79468
79862
|
}
|
|
79469
|
-
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || nextIndex === undefined) {
|
|
79863
|
+
if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err, this.fallbackFailureOptions()) || nextIndex === undefined) {
|
|
79470
79864
|
await this.settleFailedCandidate();
|
|
79471
79865
|
return "throw";
|
|
79472
79866
|
}
|
|
@@ -79561,7 +79955,7 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
79561
79955
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
79562
79956
|
import { createHash as createHash5 } from "node:crypto";
|
|
79563
79957
|
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
79564
|
-
import { basename as basename5, dirname as
|
|
79958
|
+
import { basename as basename5, dirname as dirname17, isAbsolute as isAbsolute11, join as join32, resolve as resolve18 } from "node:path";
|
|
79565
79959
|
function normalizeMaxOutput2(maxOutput) {
|
|
79566
79960
|
return {
|
|
79567
79961
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -79624,7 +80018,7 @@ function formatByteSize(bytes) {
|
|
|
79624
80018
|
}
|
|
79625
80019
|
function transcriptPath(runId, outputPath) {
|
|
79626
80020
|
const digest = createHash5("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
79627
|
-
return
|
|
80021
|
+
return join32(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
79628
80022
|
}
|
|
79629
80023
|
function appendContent(lines, content) {
|
|
79630
80024
|
if (typeof content === "string") {
|
|
@@ -79669,7 +80063,7 @@ function renderTranscript(messages, fallbackOutput) {
|
|
|
79669
80063
|
`);
|
|
79670
80064
|
}
|
|
79671
80065
|
function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
|
|
79672
|
-
const absolutePath =
|
|
80066
|
+
const absolutePath = resolve18(outputPath);
|
|
79673
80067
|
const bytes = Buffer.byteLength(fullOutput, "utf8");
|
|
79674
80068
|
const lines = countLines(fullOutput);
|
|
79675
80069
|
const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
|
|
@@ -79684,8 +80078,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
|
|
|
79684
80078
|
return;
|
|
79685
80079
|
if (isAbsolute11(output))
|
|
79686
80080
|
return output;
|
|
79687
|
-
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd :
|
|
79688
|
-
return
|
|
80081
|
+
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve18(runtimeCwd, requestedCwd);
|
|
80082
|
+
return resolve18(baseCwd, output);
|
|
79689
80083
|
}
|
|
79690
80084
|
function degenerateWarning(fullOutput) {
|
|
79691
80085
|
return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
|
|
@@ -79744,7 +80138,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
79744
80138
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
79745
80139
|
const transcript = renderTranscript(messages, fullOutput);
|
|
79746
80140
|
try {
|
|
79747
|
-
await mkdir7(
|
|
80141
|
+
await mkdir7(dirname17(outputPath), { recursive: true });
|
|
79748
80142
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
79749
80143
|
} catch (err) {
|
|
79750
80144
|
return `${displayOutput}
|
|
@@ -79756,7 +80150,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
79756
80150
|
let transcriptError;
|
|
79757
80151
|
try {
|
|
79758
80152
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
79759
|
-
await mkdir7(
|
|
80153
|
+
await mkdir7(dirname17(transcriptFile), { recursive: true });
|
|
79760
80154
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
79761
80155
|
transcriptAvailable = true;
|
|
79762
80156
|
} catch (err) {
|
|
@@ -80267,7 +80661,8 @@ function createWorkflowStageFactory(input) {
|
|
|
80267
80661
|
stageFinalized: false,
|
|
80268
80662
|
sessionCheckpointed: false,
|
|
80269
80663
|
skippedForParallelFailFast: false,
|
|
80270
|
-
stageControlDropped: false
|
|
80664
|
+
stageControlDropped: false,
|
|
80665
|
+
contextUnreachable: false
|
|
80271
80666
|
};
|
|
80272
80667
|
const activeAskUserQuestionCalls = new Set;
|
|
80273
80668
|
const hasActiveAskUserQuestion = () => activeAskUserQuestionCalls.size > 0 || state.activeAskUserQuestionAnonymousCalls > 0;
|
|
@@ -80513,9 +80908,18 @@ function createWorkflowStageFactory(input) {
|
|
|
80513
80908
|
hasContinuation: input.opts.continuation !== undefined,
|
|
80514
80909
|
hasScopedParents: stageFailFastScope?.parentIds !== undefined
|
|
80515
80910
|
});
|
|
80516
|
-
|
|
80911
|
+
const context = createStageContext({ runtime, runTrackedStageCall });
|
|
80912
|
+
unreachableStageContexts.register(context, releaseWhenUnreachable(state, input.stageRegistry, input.runId, stageId));
|
|
80913
|
+
return context;
|
|
80914
|
+
};
|
|
80915
|
+
}
|
|
80916
|
+
function releaseWhenUnreachable(state, registry, runId, stageId) {
|
|
80917
|
+
return () => {
|
|
80918
|
+
state.contextUnreachable = true;
|
|
80919
|
+
registry.releaseIdle(runId, stageId);
|
|
80517
80920
|
};
|
|
80518
80921
|
}
|
|
80922
|
+
var unreachableStageContexts;
|
|
80519
80923
|
var init_executor_stage_factory = __esm(() => {
|
|
80520
80924
|
init_intercom_group();
|
|
80521
80925
|
init_pending_stage_route_readiness();
|
|
@@ -80530,6 +80934,7 @@ var init_executor_stage_factory = __esm(() => {
|
|
|
80530
80934
|
init_pending_stage_delivery2();
|
|
80531
80935
|
init_stage_runner();
|
|
80532
80936
|
init_stage_runner_session();
|
|
80937
|
+
unreachableStageContexts = new FinalizationRegistry((release) => release());
|
|
80533
80938
|
});
|
|
80534
80939
|
|
|
80535
80940
|
// dist/builtin/workflows/src/engine/runtime.ts
|
|
@@ -80871,7 +81276,7 @@ async function executeRun(def, resolvedInputs, opts) {
|
|
|
80871
81276
|
const ownsCancellationRegistration = opts.signal === undefined && opts.cancellation !== undefined;
|
|
80872
81277
|
const tracker = new GraphFrontierTracker;
|
|
80873
81278
|
const inputConcurrency = resolveInputConcurrency(def.inputs, resolvedInputs);
|
|
80874
|
-
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache);
|
|
81279
|
+
const inputRuntimeDefaults = resolveInputRuntimeDefaults(def, resolvedInputs), gitWorktreeSetupCacheOwner = createGitWorktreeSetupCacheOwner(opts.gitWorktreeSetupCache, runId);
|
|
80875
81280
|
const gitWorktreeSetupCache = gitWorktreeSetupCacheOwner.cache;
|
|
80876
81281
|
const workflowInvocationCwd = opts.cwd ?? process.cwd();
|
|
80877
81282
|
let workflowCwd;
|
|
@@ -81970,8 +82375,8 @@ var init_workflows_host_module = __esm(() => {
|
|
|
81970
82375
|
|
|
81971
82376
|
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
81972
82377
|
import { createHash as createHash6, randomUUID as randomUUID22 } from "node:crypto";
|
|
81973
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
81974
|
-
import { basename as basename6, dirname as
|
|
82378
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
|
|
82379
|
+
import { basename as basename6, dirname as dirname18, join as join33, resolve as resolve19 } from "node:path";
|
|
81975
82380
|
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
81976
82381
|
function encodeOption(value2) {
|
|
81977
82382
|
if (typeof value2 === "bigint")
|
|
@@ -81993,7 +82398,7 @@ function isReopenableSelection(selection) {
|
|
|
81993
82398
|
}
|
|
81994
82399
|
function encodeSelection(selection) {
|
|
81995
82400
|
if (selection.kind === "sqlite")
|
|
81996
|
-
return JSON.stringify({ ...selection, path:
|
|
82401
|
+
return JSON.stringify({ ...selection, path: resolve19(selection.path) });
|
|
81997
82402
|
return JSON.stringify({
|
|
81998
82403
|
...selection,
|
|
81999
82404
|
...selection.options === undefined ? {} : {
|
|
@@ -82025,7 +82430,7 @@ function openDurableJournal(durable) {
|
|
|
82025
82430
|
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
82026
82431
|
}
|
|
82027
82432
|
function poolStateDirectory(agentDir) {
|
|
82028
|
-
return
|
|
82433
|
+
return join33(dirname18(agentDir), "workflows", "pool");
|
|
82029
82434
|
}
|
|
82030
82435
|
function databaseIdentity(selection, agentDir) {
|
|
82031
82436
|
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
@@ -82033,16 +82438,16 @@ function databaseIdentity(selection, agentDir) {
|
|
|
82033
82438
|
function coordinationPath(durable) {
|
|
82034
82439
|
const selection = decodeSelection(durable.selection);
|
|
82035
82440
|
const identity = createHash6("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
82036
|
-
return
|
|
82441
|
+
return join33(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
82037
82442
|
}
|
|
82038
82443
|
function coordinationDatabase(durable) {
|
|
82039
82444
|
return basename6(coordinationPath(durable), ".sqlite");
|
|
82040
82445
|
}
|
|
82041
82446
|
function openCoordinationJournal(path) {
|
|
82042
|
-
const file =
|
|
82447
|
+
const file = resolve19(path);
|
|
82043
82448
|
let opened = coordinationJournals.get(file);
|
|
82044
82449
|
if (opened === undefined) {
|
|
82045
|
-
|
|
82450
|
+
mkdirSync9(dirname18(file), { recursive: true });
|
|
82046
82451
|
opened = resolveRunJournal({ journal: { path: file } });
|
|
82047
82452
|
coordinationJournals.set(file, opened);
|
|
82048
82453
|
opened.catch(() => {
|
|
@@ -82059,20 +82464,20 @@ function poolJournalFor(journal) {
|
|
|
82059
82464
|
return coordinations.get(journal) ?? journal;
|
|
82060
82465
|
}
|
|
82061
82466
|
function poolHostId(agentDir) {
|
|
82062
|
-
const file =
|
|
82467
|
+
const file = join33(poolStateDirectory(agentDir), "host-id");
|
|
82063
82468
|
try {
|
|
82064
|
-
const existing =
|
|
82469
|
+
const existing = readFileSync9(file, "utf8").trim();
|
|
82065
82470
|
if (existing !== "")
|
|
82066
82471
|
return existing;
|
|
82067
82472
|
} catch {}
|
|
82068
|
-
|
|
82473
|
+
mkdirSync9(dirname18(file), { recursive: true });
|
|
82069
82474
|
const id = randomUUID22();
|
|
82070
82475
|
try {
|
|
82071
|
-
|
|
82476
|
+
writeFileSync7(file, `${id}
|
|
82072
82477
|
`, { flag: "wx" });
|
|
82073
82478
|
return id;
|
|
82074
82479
|
} catch {
|
|
82075
|
-
return
|
|
82480
|
+
return readFileSync9(file, "utf8").trim();
|
|
82076
82481
|
}
|
|
82077
82482
|
}
|
|
82078
82483
|
async function poolJournalOf(journal) {
|
|
@@ -82873,9 +83278,9 @@ var init_sdk_owner_release = __esm(() => {
|
|
|
82873
83278
|
|
|
82874
83279
|
// dist/builtin/workflows/src/durable/sdk-recovery-scope.ts
|
|
82875
83280
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
82876
|
-
import { resolve as
|
|
83281
|
+
import { resolve as resolve20 } from "node:path";
|
|
82877
83282
|
function canonicalDirectory(path) {
|
|
82878
|
-
const absolute =
|
|
83283
|
+
const absolute = resolve20(path);
|
|
82879
83284
|
try {
|
|
82880
83285
|
const canonical = realpathSync5.native(absolute);
|
|
82881
83286
|
return process.platform === "win32" ? canonical.toLowerCase() : canonical;
|
|
@@ -84821,6 +85226,8 @@ function summaryRows(detail, now) {
|
|
|
84821
85226
|
rows.push(["last progress", formatTime(detail.lastProgressAt)]);
|
|
84822
85227
|
if (detail.dependencyError !== undefined)
|
|
84823
85228
|
rows.push(["dependency", detail.dependencyError]);
|
|
85229
|
+
if (detail.intercomDeliveryIssue !== undefined)
|
|
85230
|
+
rows.push(["intercom", detail.intercomDeliveryIssue]);
|
|
84824
85231
|
if (detail.controlPersistence !== undefined) {
|
|
84825
85232
|
rows.push(["control", `${detail.controlRequestedStatus} (${detail.controlPersistence})`]);
|
|
84826
85233
|
}
|
|
@@ -96559,7 +96966,8 @@ function observeRunExecution(run, now = Date.now()) {
|
|
|
96559
96966
|
dependencyError: run.dependencyError,
|
|
96560
96967
|
lastProgressAt,
|
|
96561
96968
|
controlPersistence: run.controlPersistence,
|
|
96562
|
-
controlRequestedStatus: run.controlRequestedStatus
|
|
96969
|
+
controlRequestedStatus: run.controlRequestedStatus,
|
|
96970
|
+
...run.intercomDeliveryIssue === undefined ? {} : { intercomDeliveryIssue: run.intercomDeliveryIssue }
|
|
96563
96971
|
};
|
|
96564
96972
|
}
|
|
96565
96973
|
|
|
@@ -97143,7 +97551,7 @@ function installCompactionHook(api, store) {
|
|
|
97143
97551
|
});
|
|
97144
97552
|
}
|
|
97145
97553
|
// dist/builtin/workflows/src/extension/config-loader.ts
|
|
97146
|
-
import { isAbsolute as isAbsolute12, join as
|
|
97554
|
+
import { isAbsolute as isAbsolute12, join as join34 } from "node:path";
|
|
97147
97555
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2, getAgentDir as getAgentDir6 } from "@bastani/atomic";
|
|
97148
97556
|
// dist/builtin/workflows/src/extension/lifecycle-notifications.ts
|
|
97149
97557
|
init_returned_run_status();
|
|
@@ -98060,7 +98468,7 @@ function resolveWorkflowPaths(workflows, baseDir) {
|
|
|
98060
98468
|
}
|
|
98061
98469
|
return Object.fromEntries(Object.entries(workflows).map(([name, entry]) => [
|
|
98062
98470
|
name,
|
|
98063
|
-
isAbsolute12(entry.path) ? entry.path :
|
|
98471
|
+
isAbsolute12(entry.path) ? entry.path : join34(baseDir, entry.path)
|
|
98064
98472
|
]));
|
|
98065
98473
|
}
|
|
98066
98474
|
function workflowAgentDirs(opts) {
|
|
@@ -98068,12 +98476,12 @@ function workflowAgentDirs(opts) {
|
|
|
98068
98476
|
return opts.agentDirs;
|
|
98069
98477
|
if (opts.homeDir !== undefined) {
|
|
98070
98478
|
const homeDir = opts.homeDir;
|
|
98071
|
-
return [
|
|
98479
|
+
return [join34(homeDir, CONFIG_DIR_NAME2, "agent")];
|
|
98072
98480
|
}
|
|
98073
98481
|
return [getAgentDir6()];
|
|
98074
98482
|
}
|
|
98075
98483
|
function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
98076
|
-
const globalBase = opts.agentDir ?? (opts.homeDir === undefined ? getAgentDir6() :
|
|
98484
|
+
const globalBase = opts.agentDir ?? (opts.homeDir === undefined ? getAgentDir6() : join34(opts.homeDir, CONFIG_DIR_NAME2, "agent"));
|
|
98077
98485
|
const projectBase = opts.projectRoot;
|
|
98078
98486
|
const result = {};
|
|
98079
98487
|
const projectWorkflows = resolveWorkflowPaths(projectConfig?.workflows, projectBase);
|
|
@@ -98083,7 +98491,7 @@ function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
|
98083
98491
|
if (hasWorkflows(globalConfig)) {
|
|
98084
98492
|
const projectKeys = new Set(Object.keys(projectWorkflows ?? {}));
|
|
98085
98493
|
const globalEntries = Object.entries(globalConfig.workflows).filter(([name]) => !projectKeys.has(name)).map(([name, entry]) => {
|
|
98086
|
-
return [name, isAbsolute12(entry.path) ? entry.path :
|
|
98494
|
+
return [name, isAbsolute12(entry.path) ? entry.path : join34(globalBase, entry.path)];
|
|
98087
98495
|
});
|
|
98088
98496
|
if (globalEntries.length > 0) {
|
|
98089
98497
|
result.globalWorkflows = Object.fromEntries(globalEntries);
|
|
@@ -98094,8 +98502,8 @@ function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
|
98094
98502
|
async function loadWorkflowConfig(opts = {}) {
|
|
98095
98503
|
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
98096
98504
|
const diagnostics = [];
|
|
98097
|
-
const globalCandidates = workflowAgentDirs(opts).map((agentDir) =>
|
|
98098
|
-
const projectCandidates = [
|
|
98505
|
+
const globalCandidates = workflowAgentDirs(opts).map((agentDir) => join34(agentDir, "extensions", "workflow", "config.json"));
|
|
98506
|
+
const projectCandidates = [join34(projectRoot, CONFIG_DIR_NAME2, "extensions", "workflow", "config.json")];
|
|
98099
98507
|
let globalConfig = null;
|
|
98100
98508
|
for (let i = globalCandidates.length - 1;i >= 0; i--) {
|
|
98101
98509
|
const globalPath = globalCandidates[i];
|
|
@@ -99787,7 +100195,7 @@ init_possible_stages();
|
|
|
99787
100195
|
import { registerExtensionContextRetirementEffect as registerExtensionContextRetirementEffect2 } from "@bastani/atomic";
|
|
99788
100196
|
|
|
99789
100197
|
// dist/builtin/workflows/src/extension/discovery.ts
|
|
99790
|
-
import { join as
|
|
100198
|
+
import { join as join36 } from "node:path";
|
|
99791
100199
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3, getAgentDir as getAgentDir7 } from "@bastani/atomic";
|
|
99792
100200
|
|
|
99793
100201
|
// dist/builtin/workflows/builtin/index.ts
|
|
@@ -99808,12 +100216,12 @@ init_registry();
|
|
|
99808
100216
|
// dist/builtin/workflows/src/extension/discovery-loaders.ts
|
|
99809
100217
|
init_workflow_module_loader();
|
|
99810
100218
|
import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
99811
|
-
import { extname, isAbsolute as isAbsolute13, join as
|
|
100219
|
+
import { extname, isAbsolute as isAbsolute13, join as join35, resolve as resolve21 } from "node:path";
|
|
99812
100220
|
async function scanWorkflowDir(dir) {
|
|
99813
100221
|
try {
|
|
99814
100222
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
99815
100223
|
const WORKFLOW_EXTS = new Set([".ts", ".js", ".mjs", ".cjs"]);
|
|
99816
|
-
return entries.filter((e) => e.isFile() && WORKFLOW_EXTS.has(extname(e.name))).map((e) =>
|
|
100224
|
+
return entries.filter((e) => e.isFile() && WORKFLOW_EXTS.has(extname(e.name))).map((e) => join35(dir, e.name)).sort();
|
|
99817
100225
|
} catch {
|
|
99818
100226
|
return null;
|
|
99819
100227
|
}
|
|
@@ -99852,7 +100260,7 @@ async function loadFromPaths(pathsOrMap, kind, baseCwd, diagnostics, getWorkflow
|
|
|
99852
100260
|
const all = [];
|
|
99853
100261
|
const entries = Array.isArray(pathsOrMap) ? pathsOrMap.map((p) => ({ rawPath: p })) : Object.entries(pathsOrMap).map(([name, p]) => ({ rawPath: p, configuredName: name }));
|
|
99854
100262
|
for (const { rawPath, configuredName } of entries) {
|
|
99855
|
-
const absPath = isAbsolute13(rawPath) ? rawPath :
|
|
100263
|
+
const absPath = isAbsolute13(rawPath) ? rawPath : resolve21(baseCwd, rawPath);
|
|
99856
100264
|
let pathStats;
|
|
99857
100265
|
try {
|
|
99858
100266
|
pathStats = await stat2(absPath);
|
|
@@ -99883,7 +100291,7 @@ function workflowAgentDirs2(options) {
|
|
|
99883
100291
|
return options.agentDirs;
|
|
99884
100292
|
if (options?.homeDir !== undefined) {
|
|
99885
100293
|
const homeDir = options.homeDir;
|
|
99886
|
-
return [
|
|
100294
|
+
return [join36(homeDir, CONFIG_DIR_NAME3, "agent")];
|
|
99887
100295
|
}
|
|
99888
100296
|
return [getAgentDir7()];
|
|
99889
100297
|
}
|
|
@@ -100039,7 +100447,7 @@ async function discoverWorkflows(options) {
|
|
|
100039
100447
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
100040
100448
|
}
|
|
100041
100449
|
}
|
|
100042
|
-
for (const dir of [
|
|
100450
|
+
for (const dir of [join36(cwd, CONFIG_DIR_NAME3, "workflows")]) {
|
|
100043
100451
|
const candidates = await loadFromDir(dir, "project-local", diagnostics, getWorkflowHostModules);
|
|
100044
100452
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
100045
100453
|
}
|
|
@@ -100051,7 +100459,7 @@ async function discoverWorkflows(options) {
|
|
|
100051
100459
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
100052
100460
|
}
|
|
100053
100461
|
}
|
|
100054
|
-
for (const dir of agentDirs.map((agentDir) =>
|
|
100462
|
+
for (const dir of agentDirs.map((agentDir) => join36(agentDir, "workflows")).reverse()) {
|
|
100055
100463
|
const candidates = await loadFromDir(dir, "user-global", diagnostics, getWorkflowHostModules);
|
|
100056
100464
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
100057
100465
|
}
|
|
@@ -100926,17 +101334,17 @@ function createExtensionRuntime(opts = {}) {
|
|
|
100926
101334
|
|
|
100927
101335
|
// dist/builtin/workflows/src/extension/status-writer.ts
|
|
100928
101336
|
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile11 } from "node:fs/promises";
|
|
100929
|
-
import { dirname as
|
|
101337
|
+
import { dirname as dirname19, join as join37 } from "node:path";
|
|
100930
101338
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME4 } from "@bastani/atomic";
|
|
100931
|
-
var DEFAULT_STATUS_SUBPATH =
|
|
101339
|
+
var DEFAULT_STATUS_SUBPATH = join37(CONFIG_DIR_NAME4, "workflows", "status.json");
|
|
100932
101340
|
function resolveStatusFilePath(config, opts = {}) {
|
|
100933
101341
|
if (config.statusFilePath)
|
|
100934
101342
|
return config.statusFilePath;
|
|
100935
101343
|
const root = opts.projectRoot ?? process.cwd();
|
|
100936
|
-
return
|
|
101344
|
+
return join37(root, DEFAULT_STATUS_SUBPATH);
|
|
100937
101345
|
}
|
|
100938
101346
|
async function atomicWriteJson(path, content) {
|
|
100939
|
-
const dir =
|
|
101347
|
+
const dir = dirname19(path);
|
|
100940
101348
|
await mkdir8(dir, { recursive: true });
|
|
100941
101349
|
const tmpPath = `${path}.tmp`;
|
|
100942
101350
|
await writeFile11(tmpPath, content, "utf8");
|
|
@@ -105078,6 +105486,8 @@ function renderStatusToolContent(result) {
|
|
|
105078
105486
|
}
|
|
105079
105487
|
if (run.dependencyError !== undefined)
|
|
105080
105488
|
lines.push(` dependency: ${run.dependencyError}`);
|
|
105489
|
+
if (run.intercomDeliveryIssue !== undefined)
|
|
105490
|
+
lines.push(` Intercom delivery: ${run.intercomDeliveryIssue}`);
|
|
105081
105491
|
if (run.controlPersistence !== undefined) {
|
|
105082
105492
|
lines.push(` control: ${run.controlRequestedStatus} (${run.controlPersistence})`);
|
|
105083
105493
|
}
|