@bastani/atomic 0.9.54 → 0.9.55
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 +12 -0
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/README.md +2 -1
- package/dist/builtin/intercom/broker/announce-on-import.ts +5 -0
- package/dist/builtin/intercom/broker/broker.ts +28 -0
- package/dist/builtin/intercom/broker/client.ts +48 -3
- package/dist/builtin/intercom/broker/paths.ts +9 -0
- package/dist/builtin/intercom/broker/socket-writes.ts +5 -0
- package/dist/builtin/intercom/broker/spawn.ts +58 -6
- package/dist/builtin/intercom/broker/start-announcement.ts +77 -0
- package/dist/builtin/intercom/broker/startup-timeout.ts +23 -0
- package/dist/builtin/intercom/index.bundle.mjs +184 -73
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/recoverable-disconnect.ts +38 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +26 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +8458 -7874
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +687 -111
- package/dist/builtin/workflows/src/index.js +834 -264
- package/dist/builtin/workflows/src/local-worker-entry.mjs +687 -111
- package/dist/builtin/workflows/src/workers/public-options.d.ts +8 -0
- package/dist/core/extension-startup-failure.d.ts.map +1 -1
- package/dist/core/extension-startup-failure.js +1 -0
- package/dist/core/extension-startup-failure.js.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.d.ts +27 -0
- package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.js +99 -7
- package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
- package/docs/settings.md +2 -2
- package/docs/storage.md +2 -0
- package/docs/workflows/api-reference.md +3 -3
- package/docs/workflows/operations.md +3 -3
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
|
@@ -1996,10 +1996,16 @@ function selectRunJournal(options = {}) {
|
|
|
1996
1996
|
async function resolveRunJournal(options = {}) {
|
|
1997
1997
|
return openSelectedRunJournal(selectRunJournal(options), options.agentDir);
|
|
1998
1998
|
}
|
|
1999
|
+
function runJournalOrigin(journal) {
|
|
2000
|
+
return journalOrigins.get(journal);
|
|
2001
|
+
}
|
|
1999
2002
|
async function openSelectedRunJournal(selection, agentDir = getAgentDir()) {
|
|
2000
2003
|
if ("createRun" in selection)
|
|
2001
2004
|
return selection;
|
|
2002
|
-
|
|
2005
|
+
const journal = await withRunJournalConfigSource(selection, () => provider.openRunJournal(selection, { agentDir, domain: "journal" }));
|
|
2006
|
+
if (!journalOrigins.has(journal))
|
|
2007
|
+
journalOrigins.set(journal, { selection, agentDir });
|
|
2008
|
+
return journal;
|
|
2003
2009
|
}
|
|
2004
2010
|
async function withRunJournalConfigSource(selection, open) {
|
|
2005
2011
|
if ("createRun" in selection)
|
|
@@ -2017,7 +2023,7 @@ async function withRunJournalConfigSource(selection, open) {
|
|
|
2017
2023
|
throw error;
|
|
2018
2024
|
}
|
|
2019
2025
|
}
|
|
2020
|
-
var hostModules, provider, origins;
|
|
2026
|
+
var hostModules, provider, origins, journalOrigins;
|
|
2021
2027
|
var init_resolution = __esm(() => {
|
|
2022
2028
|
init_memory_run_journal();
|
|
2023
2029
|
init_sql_run_journal();
|
|
@@ -2030,6 +2036,7 @@ var init_resolution = __esm(() => {
|
|
|
2030
2036
|
}
|
|
2031
2037
|
});
|
|
2032
2038
|
origins = new WeakMap;
|
|
2039
|
+
journalOrigins = new WeakMap;
|
|
2033
2040
|
});
|
|
2034
2041
|
|
|
2035
2042
|
// dist/builtin/workflows/src/durable/journal/sqlite-run-journal.ts
|
|
@@ -16762,9 +16769,126 @@ var init_possible_stages = __esm(() => {
|
|
|
16762
16769
|
TRACKED_NODE_METHODS = new Set(["stage", "task", "chain", "parallel", "workflow", "tool"]);
|
|
16763
16770
|
});
|
|
16764
16771
|
|
|
16772
|
+
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
16773
|
+
import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
|
|
16774
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16775
|
+
import { basename as basename5, dirname as dirname9, join as join12, resolve as resolve9 } from "node:path";
|
|
16776
|
+
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
16777
|
+
function encodeOption(value2) {
|
|
16778
|
+
if (typeof value2 === "bigint")
|
|
16779
|
+
return { $bigint: value2.toString() };
|
|
16780
|
+
if (value2 instanceof Uint8Array)
|
|
16781
|
+
return { $bytes: Buffer.from(value2).toString("base64") };
|
|
16782
|
+
return value2;
|
|
16783
|
+
}
|
|
16784
|
+
function decodeOption(value2) {
|
|
16785
|
+
if (value2 !== null && typeof value2 === "object") {
|
|
16786
|
+
if ("$bigint" in value2)
|
|
16787
|
+
return BigInt(value2.$bigint);
|
|
16788
|
+
return new Uint8Array(Buffer.from(value2.$bytes, "base64"));
|
|
16789
|
+
}
|
|
16790
|
+
return value2;
|
|
16791
|
+
}
|
|
16792
|
+
function isReopenableSelection(selection) {
|
|
16793
|
+
return selection.kind === "sqlite" || selection.kind === "adapter";
|
|
16794
|
+
}
|
|
16795
|
+
function encodeSelection(selection) {
|
|
16796
|
+
if (selection.kind === "sqlite")
|
|
16797
|
+
return JSON.stringify({ ...selection, path: resolve9(selection.path) });
|
|
16798
|
+
return JSON.stringify({
|
|
16799
|
+
...selection,
|
|
16800
|
+
...selection.options === undefined ? {} : {
|
|
16801
|
+
options: Object.fromEntries(Object.entries(selection.options).map(([key, value2]) => [key, encodeOption(value2)]))
|
|
16802
|
+
}
|
|
16803
|
+
});
|
|
16804
|
+
}
|
|
16805
|
+
function decodeSelection(text) {
|
|
16806
|
+
const value2 = JSON.parse(text);
|
|
16807
|
+
if (value2.kind === "sqlite" || value2.options === undefined)
|
|
16808
|
+
return value2;
|
|
16809
|
+
return {
|
|
16810
|
+
...value2,
|
|
16811
|
+
options: Object.fromEntries(Object.entries(value2.options).map(([key, option]) => [key, decodeOption(option)]))
|
|
16812
|
+
};
|
|
16813
|
+
}
|
|
16814
|
+
function isLocalPoolJournal(journal) {
|
|
16815
|
+
return journal instanceof SqlRunJournal && journal.descriptor.adapter === "node-sqlite" && journal.path !== ":memory:" && sqlPoolStorage(journal)?.tables.runs === "wf_runs";
|
|
16816
|
+
}
|
|
16817
|
+
function poolDurableJournal(journal) {
|
|
16818
|
+
const origin = runJournalOrigin(journal);
|
|
16819
|
+
if (origin === undefined)
|
|
16820
|
+
throw new Error("Local workers cannot reopen a journal passed as an object; select the journal with workflows.journal, --storage or ATOMIC_WORKFLOWS_JOURNAL so every worker process can open it");
|
|
16821
|
+
if (!isReopenableSelection(origin.selection))
|
|
16822
|
+
throw new Error(`Local workers need a journal their processes can open by selection, a SQLite file or a storage adapter, not ${origin.selection.kind}`);
|
|
16823
|
+
return { selection: encodeSelection(origin.selection), agentDir: origin.agentDir };
|
|
16824
|
+
}
|
|
16825
|
+
function openDurableJournal(durable) {
|
|
16826
|
+
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
16827
|
+
}
|
|
16828
|
+
function poolStateDirectory(agentDir) {
|
|
16829
|
+
return join12(dirname9(agentDir), "workflows", "pool");
|
|
16830
|
+
}
|
|
16831
|
+
function databaseIdentity(selection, agentDir) {
|
|
16832
|
+
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
16833
|
+
}
|
|
16834
|
+
function coordinationPath(durable) {
|
|
16835
|
+
const selection = decodeSelection(durable.selection);
|
|
16836
|
+
const identity = createHash3("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
16837
|
+
return join12(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
16838
|
+
}
|
|
16839
|
+
function coordinationDatabase(durable) {
|
|
16840
|
+
return basename5(coordinationPath(durable), ".sqlite");
|
|
16841
|
+
}
|
|
16842
|
+
function openCoordinationJournal(path) {
|
|
16843
|
+
const file = resolve9(path);
|
|
16844
|
+
let opened = coordinationJournals.get(file);
|
|
16845
|
+
if (opened === undefined) {
|
|
16846
|
+
mkdirSync5(dirname9(file), { recursive: true });
|
|
16847
|
+
opened = resolveRunJournal({ journal: { path: file } });
|
|
16848
|
+
coordinationJournals.set(file, opened);
|
|
16849
|
+
opened.catch(() => {
|
|
16850
|
+
if (coordinationJournals.get(file) === opened)
|
|
16851
|
+
coordinationJournals.delete(file);
|
|
16852
|
+
});
|
|
16853
|
+
}
|
|
16854
|
+
return opened;
|
|
16855
|
+
}
|
|
16856
|
+
function registerPoolJournal(durable, coordination) {
|
|
16857
|
+
coordinations.set(durable, coordination);
|
|
16858
|
+
}
|
|
16859
|
+
function poolJournalFor(journal) {
|
|
16860
|
+
return coordinations.get(journal) ?? journal;
|
|
16861
|
+
}
|
|
16862
|
+
function poolHostId(agentDir) {
|
|
16863
|
+
const file = join12(poolStateDirectory(agentDir), "host-id");
|
|
16864
|
+
try {
|
|
16865
|
+
const existing = readFileSync2(file, "utf8").trim();
|
|
16866
|
+
if (existing !== "")
|
|
16867
|
+
return existing;
|
|
16868
|
+
} catch {}
|
|
16869
|
+
mkdirSync5(dirname9(file), { recursive: true });
|
|
16870
|
+
const id = randomUUID6();
|
|
16871
|
+
try {
|
|
16872
|
+
writeFileSync3(file, `${id}
|
|
16873
|
+
`, { flag: "wx" });
|
|
16874
|
+
return id;
|
|
16875
|
+
} catch {
|
|
16876
|
+
return readFileSync2(file, "utf8").trim();
|
|
16877
|
+
}
|
|
16878
|
+
}
|
|
16879
|
+
var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
|
|
16880
|
+
var init_pool_journal = __esm(() => {
|
|
16881
|
+
init_internal();
|
|
16882
|
+
init_workflows_host_module();
|
|
16883
|
+
init_resolution();
|
|
16884
|
+
init_sql_run_journal();
|
|
16885
|
+
coordinationJournals = new Map;
|
|
16886
|
+
coordinations = new WeakMap;
|
|
16887
|
+
});
|
|
16888
|
+
|
|
16765
16889
|
// dist/builtin/workflows/src/workers/admission-host.ts
|
|
16766
16890
|
import { execFile, execFileSync } from "node:child_process";
|
|
16767
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
16891
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
16768
16892
|
import { readFile } from "node:fs/promises";
|
|
16769
16893
|
import { hostname } from "node:os";
|
|
16770
16894
|
function admissionBootIdentity() {
|
|
@@ -16805,7 +16929,7 @@ function scanProcessGroup(group) {
|
|
|
16805
16929
|
continue;
|
|
16806
16930
|
let stat;
|
|
16807
16931
|
try {
|
|
16808
|
-
stat =
|
|
16932
|
+
stat = readFileSync3(`/proc/${entry}/stat`, "utf8");
|
|
16809
16933
|
} catch {
|
|
16810
16934
|
complete = false;
|
|
16811
16935
|
continue;
|
|
@@ -16869,7 +16993,7 @@ var init_admission_host = __esm(() => {
|
|
|
16869
16993
|
});
|
|
16870
16994
|
|
|
16871
16995
|
// dist/builtin/workflows/src/workers/resource-admission.ts
|
|
16872
|
-
import { randomUUID as
|
|
16996
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
16873
16997
|
import { realpath } from "node:fs/promises";
|
|
16874
16998
|
import { cpus, freemem, loadavg } from "node:os";
|
|
16875
16999
|
import { setTimeout as delay } from "node:timers/promises";
|
|
@@ -16884,7 +17008,7 @@ class SqlResourceAdmission {
|
|
|
16884
17008
|
permits;
|
|
16885
17009
|
configuration;
|
|
16886
17010
|
owners;
|
|
16887
|
-
owner =
|
|
17011
|
+
owner = randomUUID7();
|
|
16888
17012
|
nextReconciliation = 0;
|
|
16889
17013
|
constructor(storage, options) {
|
|
16890
17014
|
this.storage = storage;
|
|
@@ -16991,7 +17115,7 @@ class SqlResourceAdmission {
|
|
|
16991
17115
|
}
|
|
16992
17116
|
async acquire(kind, signal, request) {
|
|
16993
17117
|
signal?.throwIfAborted();
|
|
16994
|
-
const operation =
|
|
17118
|
+
const operation = randomUUID7();
|
|
16995
17119
|
const release = (reason = "resource cleanup confirmed") => this.storage.transaction(async (tx) => {
|
|
16996
17120
|
await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = ? WHERE operation = ? AND state != 'released'`, reason, operation);
|
|
16997
17121
|
});
|
|
@@ -17214,7 +17338,7 @@ var init_resource_admission = __esm(() => {
|
|
|
17214
17338
|
});
|
|
17215
17339
|
|
|
17216
17340
|
// dist/builtin/workflows/src/workers/admission-binding.ts
|
|
17217
|
-
import { randomUUID as
|
|
17341
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
17218
17342
|
import { withResourceAdmission } from "@bastani/atomic";
|
|
17219
17343
|
|
|
17220
17344
|
class SessionCapacitySlot {
|
|
@@ -17289,10 +17413,10 @@ async function admitWorkflowSessions(backend, opts, callback) {
|
|
|
17289
17413
|
return callback(opts);
|
|
17290
17414
|
if (!(rootBackend instanceof JournalDurableBackend))
|
|
17291
17415
|
throw new Error("Resource admission requires a journal backend");
|
|
17292
|
-
const admission = await SqlResourceAdmission.open(rootBackend.journal, {
|
|
17416
|
+
const admission = await SqlResourceAdmission.open(poolJournalFor(rootBackend.journal), {
|
|
17293
17417
|
...config,
|
|
17294
17418
|
root: opts.parentRun?.rootRunId ?? opts.runId,
|
|
17295
|
-
holder:
|
|
17419
|
+
holder: randomUUID8()
|
|
17296
17420
|
});
|
|
17297
17421
|
return withResourceAdmission(admission, () => callback({
|
|
17298
17422
|
...opts,
|
|
@@ -17307,6 +17431,7 @@ var init_admission_binding = __esm(() => {
|
|
|
17307
17431
|
init_journal_backend();
|
|
17308
17432
|
init_wiring();
|
|
17309
17433
|
init_stage_runner_session_options();
|
|
17434
|
+
init_pool_journal();
|
|
17310
17435
|
init_resource_admission();
|
|
17311
17436
|
workflowResourceAdmission = new WeakMap;
|
|
17312
17437
|
});
|
|
@@ -53509,12 +53634,12 @@ var init_verification_prompts = __esm(() => {
|
|
|
53509
53634
|
});
|
|
53510
53635
|
|
|
53511
53636
|
// dist/builtin/workflows/builtin/pattern-artifact-root.ts
|
|
53512
|
-
import { randomUUID as
|
|
53637
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
53513
53638
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
53514
|
-
import { join as
|
|
53639
|
+
import { join as join13 } from "node:path";
|
|
53515
53640
|
async function stableArtifactRoot(ctx, workflowName) {
|
|
53516
53641
|
const cwd = ctx.cwd ?? process.cwd();
|
|
53517
|
-
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () =>
|
|
53642
|
+
const artifactDir = await ctx.tool("artifact-root", { workflow: workflowName }, async () => join13(cwd, ".atomic", "workflows", "runs", `${workflowName}-${randomUUID9()}`));
|
|
53518
53643
|
await mkdir2(artifactDir, { recursive: true });
|
|
53519
53644
|
return artifactDir;
|
|
53520
53645
|
}
|
|
@@ -53554,7 +53679,7 @@ function fold_usage(results) {
|
|
|
53554
53679
|
|
|
53555
53680
|
// dist/builtin/workflows/builtin/adversarial-verification-runner.ts
|
|
53556
53681
|
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
53557
|
-
import { join as
|
|
53682
|
+
import { join as join14 } from "node:path";
|
|
53558
53683
|
import { Type as Type4 } from "typebox";
|
|
53559
53684
|
function isRecord3(value2) {
|
|
53560
53685
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -53649,8 +53774,8 @@ async function writeInvalid(path, stage) {
|
|
|
53649
53774
|
}
|
|
53650
53775
|
async function runAdversarialVerification(ctx) {
|
|
53651
53776
|
const root = await stableArtifactRoot(ctx, "adversarial-verification");
|
|
53652
|
-
const criteriaPath =
|
|
53653
|
-
const candidatePath =
|
|
53777
|
+
const criteriaPath = join14(root, "criteria.md");
|
|
53778
|
+
const candidatePath = join14(root, "candidate.md");
|
|
53654
53779
|
const resolvedCriteria = resolveCriteria(ctx.inputs.criteria);
|
|
53655
53780
|
await writeFile(criteriaPath, renderCriteriaMarkdown(resolvedCriteria));
|
|
53656
53781
|
await ctx.task("worker", { prompt: renderWorkerPrompt(ctx.inputs.task), context: "fresh", output: candidatePath, outputMode: "file-only" });
|
|
@@ -53682,7 +53807,7 @@ async function runAdversarialVerification(ctx) {
|
|
|
53682
53807
|
criterion,
|
|
53683
53808
|
verifierIndex: index + 1,
|
|
53684
53809
|
name,
|
|
53685
|
-
artifactPath:
|
|
53810
|
+
artifactPath: join14(root, `verification-${round}-${criterion.id}-${index + 1}.json`)
|
|
53686
53811
|
});
|
|
53687
53812
|
}
|
|
53688
53813
|
}
|
|
@@ -53735,8 +53860,8 @@ async function runAdversarialVerification(ctx) {
|
|
|
53735
53860
|
const decision = decide_verification(roundResult, { acceptMean, quorumFraction: QUORUM_FRACTION });
|
|
53736
53861
|
finalDecision = decision;
|
|
53737
53862
|
finalMean = meanScore(scoreReports);
|
|
53738
|
-
scoreTablePath =
|
|
53739
|
-
reviewReportPath =
|
|
53863
|
+
scoreTablePath = join14(root, `verification-summary-${round}.json`);
|
|
53864
|
+
reviewReportPath = join14(root, `review-${round}.json`);
|
|
53740
53865
|
const summary = {
|
|
53741
53866
|
scores: scoreReports,
|
|
53742
53867
|
mean: finalMean,
|
|
@@ -53917,7 +54042,7 @@ var GROUNDED_REPORTING2 = "Before reporting progress, audit each claim against a
|
|
|
53917
54042
|
|
|
53918
54043
|
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
53919
54044
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
53920
|
-
import { join as
|
|
54045
|
+
import { join as join15 } from "node:path";
|
|
53921
54046
|
import { Type as Type6 } from "typebox";
|
|
53922
54047
|
function safeName(value2) {
|
|
53923
54048
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -53957,7 +54082,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
53957
54082
|
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
53958
54083
|
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
53959
54084
|
const category = fallback?.category ?? exactCategory;
|
|
53960
|
-
const classificationPath =
|
|
54085
|
+
const classificationPath = join15(artifactDir, "classification.json");
|
|
53961
54086
|
await writeFile2(classificationPath, JSON.stringify({
|
|
53962
54087
|
proposed_category: proposedCategory,
|
|
53963
54088
|
selected_category: category,
|
|
@@ -53967,7 +54092,7 @@ async function runClassifyAndAct(ctx) {
|
|
|
53967
54092
|
fallback_used: needsFallback,
|
|
53968
54093
|
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
53969
54094
|
}, null, 2));
|
|
53970
|
-
const actionPath =
|
|
54095
|
+
const actionPath = join15(artifactDir, `action-${safeName(category)}.md`);
|
|
53971
54096
|
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
53972
54097
|
tools: actionTools(category),
|
|
53973
54098
|
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
@@ -54107,7 +54232,7 @@ var GROUNDED_REPORTING3 = "Before reporting progress, audit each claim against a
|
|
|
54107
54232
|
|
|
54108
54233
|
// dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts
|
|
54109
54234
|
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
54110
|
-
import { join as
|
|
54235
|
+
import { join as join16 } from "node:path";
|
|
54111
54236
|
import { Type as Type8 } from "typebox";
|
|
54112
54237
|
function safeName2(value2, index) {
|
|
54113
54238
|
const normalized = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
@@ -54138,9 +54263,9 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54138
54263
|
context: "fresh"
|
|
54139
54264
|
});
|
|
54140
54265
|
const partitions = parsedPartitions(plan.structured, ctx.inputs.max_branches, ctx.inputs.prompt);
|
|
54141
|
-
const partitionPath =
|
|
54266
|
+
const partitionPath = join16(artifactDir, "partition-plan.json");
|
|
54142
54267
|
await writeFile3(partitionPath, JSON.stringify({ task: ctx.inputs.prompt, partitions }, null, 2));
|
|
54143
|
-
const branchPaths = partitions.map((partition, index) =>
|
|
54268
|
+
const branchPaths = partitions.map((partition, index) => join16(artifactDir, `branch-${safeName2(partition.label, index)}.md`));
|
|
54144
54269
|
const steps = partitions.map((partition, index) => ({
|
|
54145
54270
|
name: `branch-${safeName2(partition.label, index)}`,
|
|
54146
54271
|
prompt: branchPrompt({ prompt: ctx.inputs.prompt, ...partition }),
|
|
@@ -54150,13 +54275,13 @@ async function runFanOutAndSynthesize(ctx) {
|
|
|
54150
54275
|
outputMode: "file-only"
|
|
54151
54276
|
}));
|
|
54152
54277
|
await ctx.parallel(steps, { concurrency: Math.min(ctx.inputs.max_concurrency, partitions.length), failFast: false });
|
|
54153
|
-
const manifestPath =
|
|
54278
|
+
const manifestPath = join16(artifactDir, "manifest.json");
|
|
54154
54279
|
await writeFile3(manifestPath, JSON.stringify({
|
|
54155
54280
|
task: ctx.inputs.prompt,
|
|
54156
54281
|
partition_plan: partitionPath,
|
|
54157
54282
|
branches: partitions.map((partition, index) => ({ ...partition, artifact_path: branchPaths[index] }))
|
|
54158
54283
|
}, null, 2));
|
|
54159
|
-
const synthesisPath =
|
|
54284
|
+
const synthesisPath = join16(artifactDir, "synthesis.md");
|
|
54160
54285
|
const synthesis = await ctx.task("synthesize", {
|
|
54161
54286
|
prompt: synthesisPrompt(ctx.inputs.prompt, manifestPath),
|
|
54162
54287
|
context: "fresh",
|
|
@@ -54321,7 +54446,7 @@ var init_generate_and_filter_prompts = __esm(() => {
|
|
|
54321
54446
|
|
|
54322
54447
|
// dist/builtin/workflows/builtin/generate-and-filter-runner.ts
|
|
54323
54448
|
import { readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
54324
|
-
import { join as
|
|
54449
|
+
import { join as join17 } from "node:path";
|
|
54325
54450
|
import { Type as Type10 } from "typebox";
|
|
54326
54451
|
function isRecord4(value2) {
|
|
54327
54452
|
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
@@ -54340,7 +54465,7 @@ function judgeDecision(value2) {
|
|
|
54340
54465
|
}
|
|
54341
54466
|
async function runGenerateAndFilter(ctx) {
|
|
54342
54467
|
const root = await stableArtifactRoot(ctx, "generate-and-filter");
|
|
54343
|
-
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) =>
|
|
54468
|
+
const candidatePaths = Array.from({ length: ctx.inputs.num_candidates }, (_, index) => join17(root, `candidate-${index + 1}.md`));
|
|
54344
54469
|
const shortlistLimit = Math.min(ctx.inputs.shortlist_size, ctx.inputs.num_candidates);
|
|
54345
54470
|
await ctx.parallel(candidatePaths.map((path, index) => ({
|
|
54346
54471
|
name: `generate-${index + 1}`,
|
|
@@ -54349,9 +54474,9 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54349
54474
|
output: path,
|
|
54350
54475
|
outputMode: "file-only"
|
|
54351
54476
|
})), { concurrency: ctx.inputs.max_concurrency, failFast: false });
|
|
54352
|
-
const manifestPath =
|
|
54477
|
+
const manifestPath = join17(root, "manifest.json");
|
|
54353
54478
|
await writeFile4(manifestPath, JSON.stringify({ task: ctx.inputs.prompt, candidate_artifact_paths: candidatePaths }, null, 2));
|
|
54354
|
-
const filterPath =
|
|
54479
|
+
const filterPath = join17(root, "filter.json");
|
|
54355
54480
|
const filtered = await ctx.task("dedupe-and-filter", {
|
|
54356
54481
|
prompt: renderFilterPrompt(ctx.inputs.prompt, candidatePaths, shortlistLimit),
|
|
54357
54482
|
context: "fresh",
|
|
@@ -54368,7 +54493,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54368
54493
|
let judgePath = null;
|
|
54369
54494
|
let decisionPath = filterPath;
|
|
54370
54495
|
if (ctx.inputs.use_judge) {
|
|
54371
|
-
judgePath =
|
|
54496
|
+
judgePath = join17(root, "judge.json");
|
|
54372
54497
|
const judgeCandidates = await Promise.all(shortlist.map(async (path) => ({ path, body: await readFile3(path, "utf8") })));
|
|
54373
54498
|
const judgePrompt = renderJudgePrompt(ctx.inputs.prompt, filterPath, shortlistLimit, judgeCandidates);
|
|
54374
54499
|
const judged = await ctx.task("judge", {
|
|
@@ -54384,7 +54509,7 @@ async function runGenerateAndFilter(ctx) {
|
|
|
54384
54509
|
shortlist = judgedShortlist.length > 0 ? judgedShortlist : shortlist;
|
|
54385
54510
|
decisionPath = judgePath;
|
|
54386
54511
|
}
|
|
54387
|
-
const finalPath =
|
|
54512
|
+
const finalPath = join17(root, "shortlist.md");
|
|
54388
54513
|
const finalShortlist = await ctx.task("final-shortlist", {
|
|
54389
54514
|
prompt: renderFinalShortlistPrompt(ctx.inputs.prompt, decisionPath),
|
|
54390
54515
|
context: "fresh",
|
|
@@ -54913,7 +55038,7 @@ var init_review_convergence = __esm(() => {
|
|
|
54913
55038
|
|
|
54914
55039
|
// dist/builtin/workflows/builtin/goal-artifacts.ts
|
|
54915
55040
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
54916
|
-
import { join as
|
|
55041
|
+
import { join as join18 } from "node:path";
|
|
54917
55042
|
function artifactSafeName(value2) {
|
|
54918
55043
|
const safe = value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
54919
55044
|
return safe.length > 0 ? safe : "artifact";
|
|
@@ -54924,7 +55049,7 @@ function withoutTurn(value2) {
|
|
|
54924
55049
|
return copy;
|
|
54925
55050
|
}
|
|
54926
55051
|
async function writeReviewArtifact(artifactDir, reviewer, decision, rawText, convergenceDecision) {
|
|
54927
|
-
const artifactPath =
|
|
55052
|
+
const artifactPath = join18(artifactDir, `review-${artifactSafeName(reviewer)}.json`);
|
|
54928
55053
|
await writeFile5(artifactPath, `${JSON.stringify({ reviewer, decision, convergence_decision: convergenceDecision, raw_text: rawText }, null, 2)}
|
|
54929
55054
|
`, { encoding: "utf8" });
|
|
54930
55055
|
return artifactPath;
|
|
@@ -54933,7 +55058,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
|
|
|
54933
55058
|
reviewer: review.reviewer,
|
|
54934
55059
|
findings: review.findings
|
|
54935
55060
|
}))), reverification = []) {
|
|
54936
|
-
const artifactPath =
|
|
55061
|
+
const artifactPath = join18(artifactDir, "review-round-latest.json");
|
|
54937
55062
|
const visibleReviews = reviews.map(withoutTurn);
|
|
54938
55063
|
await writeFile5(artifactPath, `${JSON.stringify({ reviews: visibleReviews, consolidated_findings: consolidatedFindings, reverification }, null, 2)}
|
|
54939
55064
|
`, { encoding: "utf8" });
|
|
@@ -55161,9 +55286,9 @@ var init_goal_review = __esm(() => {
|
|
|
55161
55286
|
});
|
|
55162
55287
|
|
|
55163
55288
|
// dist/builtin/workflows/builtin/goal-ledger.ts
|
|
55164
|
-
import { randomUUID as
|
|
55289
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
55165
55290
|
import { readFile as readFile4, rename, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
55166
|
-
import { dirname as
|
|
55291
|
+
import { dirname as dirname10, join as join19 } from "node:path";
|
|
55167
55292
|
import { isDeepStrictEqual } from "node:util";
|
|
55168
55293
|
function withoutTurn2(value2) {
|
|
55169
55294
|
const copy = { ...value2 };
|
|
@@ -55188,7 +55313,7 @@ function modelVisibleLedger(ledger) {
|
|
|
55188
55313
|
};
|
|
55189
55314
|
}
|
|
55190
55315
|
function goalLedgerStatePath(ledgerPath) {
|
|
55191
|
-
return
|
|
55316
|
+
return join19(dirname10(ledgerPath), LEDGER_STATE_FILENAME);
|
|
55192
55317
|
}
|
|
55193
55318
|
function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
|
|
55194
55319
|
ledger.lifecycle.push({
|
|
@@ -55264,14 +55389,14 @@ function recoverLegacyExecutionInterruption(ledger) {
|
|
|
55264
55389
|
return true;
|
|
55265
55390
|
}
|
|
55266
55391
|
async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
|
|
55267
|
-
const ledgerPath =
|
|
55392
|
+
const ledgerPath = join19(artifactDir, LEDGER_FILENAME);
|
|
55268
55393
|
const existing = await readExistingGoalLedger(ledgerPath);
|
|
55269
55394
|
if (existing !== undefined) {
|
|
55270
55395
|
if (recoverLegacyExecutionInterruption(existing))
|
|
55271
55396
|
await writeGoalLedger(ledgerPath, existing);
|
|
55272
55397
|
return { ledger: existing, ledgerPath, artifactDir };
|
|
55273
55398
|
}
|
|
55274
|
-
const goalId =
|
|
55399
|
+
const goalId = randomUUID10();
|
|
55275
55400
|
const now = new Date().toISOString();
|
|
55276
55401
|
const ledger = {
|
|
55277
55402
|
goal_id: goalId,
|
|
@@ -55300,7 +55425,7 @@ async function writeGoalLedger(ledgerPath, ledger) {
|
|
|
55300
55425
|
const stateContents = `${JSON.stringify(ledger, null, 2)}
|
|
55301
55426
|
`;
|
|
55302
55427
|
const statePath = goalLedgerStatePath(ledgerPath);
|
|
55303
|
-
const pendingStatePath = `${statePath}.${
|
|
55428
|
+
const pendingStatePath = `${statePath}.${randomUUID10()}.tmp`;
|
|
55304
55429
|
await writeFile6(pendingStatePath, stateContents, { encoding: "utf8" });
|
|
55305
55430
|
try {
|
|
55306
55431
|
await rename(pendingStatePath, statePath);
|
|
@@ -55771,7 +55896,7 @@ var init_goal_orchestrator_prompts = __esm(() => {
|
|
|
55771
55896
|
});
|
|
55772
55897
|
|
|
55773
55898
|
// dist/builtin/workflows/builtin/goal-runner.ts
|
|
55774
|
-
import { join as
|
|
55899
|
+
import { join as join20 } from "node:path";
|
|
55775
55900
|
function positiveInteger(value2, fallback) {
|
|
55776
55901
|
if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 <= 0) {
|
|
55777
55902
|
return fallback;
|
|
@@ -55822,7 +55947,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
55822
55947
|
appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
|
|
55823
55948
|
await writeGoalLedger(ledgerPath, ledger);
|
|
55824
55949
|
}
|
|
55825
|
-
const orchestratorReceiptPath =
|
|
55950
|
+
const orchestratorReceiptPath = join20(artifactDir, "orchestrator-receipt.md");
|
|
55826
55951
|
const orchestratorForkOptions = forkContinuationOptions(previousOrchestratorSessionId);
|
|
55827
55952
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? renderGoalOrchestratorPrompt({
|
|
55828
55953
|
ledger,
|
|
@@ -55893,7 +56018,7 @@ async function runGoalWorkflow(ctx, options) {
|
|
|
55893
56018
|
const reviewerName = result.name ?? result.stageName;
|
|
55894
56019
|
const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
|
|
55895
56020
|
const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
|
|
55896
|
-
const reviewArtifactPath =
|
|
56021
|
+
const reviewArtifactPath = join20(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
|
|
55897
56022
|
const record = reviewDecisionToRecord({
|
|
55898
56023
|
turn,
|
|
55899
56024
|
reviewer: normalizedReviewerName,
|
|
@@ -56214,7 +56339,7 @@ var GROUNDED_REPORTING5 = "Before reporting progress, audit each claim against a
|
|
|
56214
56339
|
|
|
56215
56340
|
// dist/builtin/workflows/builtin/loop-until-done-runner.ts
|
|
56216
56341
|
import { mkdir as mkdir3, writeFile as writeFile7 } from "node:fs/promises";
|
|
56217
|
-
import { join as
|
|
56342
|
+
import { join as join21 } from "node:path";
|
|
56218
56343
|
import { Type as Type16 } from "typebox";
|
|
56219
56344
|
function progressCurve(entries) {
|
|
56220
56345
|
return entries.flatMap((entry) => entry.progress === undefined ? [] : [entry.progress.score]);
|
|
@@ -56297,18 +56422,18 @@ async function writeLedger(path, task, maxIterations, status, entries) {
|
|
|
56297
56422
|
}
|
|
56298
56423
|
async function runLoopUntilDone(ctx) {
|
|
56299
56424
|
const artifactDir = await stableArtifactRoot(ctx, "loop-until-done");
|
|
56300
|
-
const iterationsDir =
|
|
56301
|
-
const evaluationsDir =
|
|
56425
|
+
const iterationsDir = join21(artifactDir, "iterations");
|
|
56426
|
+
const evaluationsDir = join21(artifactDir, "evaluations");
|
|
56302
56427
|
await mkdir3(iterationsDir, { recursive: true });
|
|
56303
56428
|
await mkdir3(evaluationsDir, { recursive: true });
|
|
56304
|
-
const ledgerPath =
|
|
56429
|
+
const ledgerPath = join21(artifactDir, "progress-ledger.json");
|
|
56305
56430
|
const entries = [];
|
|
56306
56431
|
const iterationArtifactPaths = [];
|
|
56307
56432
|
const evaluationArtifactPaths = [];
|
|
56308
56433
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, "active", entries);
|
|
56309
56434
|
for (let iteration = 1;iteration <= ctx.inputs.max_iterations; iteration += 1) {
|
|
56310
|
-
const iterationPath =
|
|
56311
|
-
const evaluationPath =
|
|
56435
|
+
const iterationPath = join21(iterationsDir, `iteration-${iteration}.md`);
|
|
56436
|
+
const evaluationPath = join21(evaluationsDir, `evaluation-${iteration}.json`);
|
|
56312
56437
|
iterationArtifactPaths.push(iterationPath);
|
|
56313
56438
|
evaluationArtifactPaths.push(evaluationPath);
|
|
56314
56439
|
await ctx.task(`iteration-${iteration}`, {
|
|
@@ -56357,7 +56482,7 @@ async function runLoopUntilDone(ctx) {
|
|
|
56357
56482
|
await writeLedger(ledgerPath, ctx.inputs.prompt, ctx.inputs.max_iterations, decision.done ? "complete" : "active", entries);
|
|
56358
56483
|
if (decision.done) {
|
|
56359
56484
|
const report = progressReport(entries);
|
|
56360
|
-
const resultPath =
|
|
56485
|
+
const resultPath = join21(artifactDir, "result.md");
|
|
56361
56486
|
const final = await ctx.task("completion-summary", {
|
|
56362
56487
|
prompt: renderCompletionPrompt({ task: ctx.inputs.prompt, ledgerPath, iterationPath }),
|
|
56363
56488
|
context: "fresh",
|
|
@@ -56474,9 +56599,9 @@ var init_loop_until_done = __esm(() => {
|
|
|
56474
56599
|
|
|
56475
56600
|
// dist/builtin/workflows/builtin/open-claude-design-utils.ts
|
|
56476
56601
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
56477
|
-
import { mkdirSync as
|
|
56602
|
+
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
56478
56603
|
import { tmpdir, userInfo } from "node:os";
|
|
56479
|
-
import { join as
|
|
56604
|
+
import { join as join22 } from "node:path";
|
|
56480
56605
|
import { Type as Type18 } from "typebox";
|
|
56481
56606
|
import { createChildProcessEnvironment as createChildProcessEnvironment3 } from "@bastani/atomic";
|
|
56482
56607
|
function taggedPrompt3(sections) {
|
|
@@ -56519,32 +56644,32 @@ function tmpArtifactBase() {
|
|
|
56519
56644
|
try {
|
|
56520
56645
|
user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
|
|
56521
56646
|
} catch {}
|
|
56522
|
-
return
|
|
56647
|
+
return join22(tmpdir(), `open-claude-design-${user}`);
|
|
56523
56648
|
}
|
|
56524
56649
|
function prepareArtifactDir(cwd = process.cwd()) {
|
|
56525
56650
|
const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
56526
56651
|
const tmpCandidates = [
|
|
56527
|
-
|
|
56528
|
-
|
|
56652
|
+
join22(tmpArtifactBase(), runId),
|
|
56653
|
+
join22(tmpdir(), "open-claude-design", runId)
|
|
56529
56654
|
];
|
|
56530
|
-
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [
|
|
56655
|
+
const candidates = process.env.NODE_ENV === "test" ? tmpCandidates : [join22(cwd, "specs", "design", runId), ...tmpCandidates];
|
|
56531
56656
|
for (const candidate of candidates) {
|
|
56532
56657
|
try {
|
|
56533
|
-
|
|
56658
|
+
mkdirSync6(candidate, { recursive: true });
|
|
56534
56659
|
return {
|
|
56535
56660
|
runId,
|
|
56536
56661
|
artifactDir: candidate,
|
|
56537
|
-
previewPath:
|
|
56538
|
-
specPath:
|
|
56662
|
+
previewPath: join22(candidate, "preview.html"),
|
|
56663
|
+
specPath: join22(candidate, "spec.html")
|
|
56539
56664
|
};
|
|
56540
56665
|
} catch {}
|
|
56541
56666
|
}
|
|
56542
|
-
const fallback =
|
|
56667
|
+
const fallback = join22(tmpArtifactBase(), runId);
|
|
56543
56668
|
return {
|
|
56544
56669
|
runId,
|
|
56545
56670
|
artifactDir: fallback,
|
|
56546
|
-
previewPath:
|
|
56547
|
-
specPath:
|
|
56671
|
+
previewPath: join22(fallback, "preview.html"),
|
|
56672
|
+
specPath: join22(fallback, "spec.html")
|
|
56548
56673
|
};
|
|
56549
56674
|
}
|
|
56550
56675
|
function ensureAgentBrowser() {
|
|
@@ -56878,8 +57003,8 @@ var init_open_claude_design_live_protocol = __esm(() => {
|
|
|
56878
57003
|
});
|
|
56879
57004
|
|
|
56880
57005
|
// dist/builtin/workflows/builtin/open-claude-design-setup.ts
|
|
56881
|
-
import { mkdirSync as
|
|
56882
|
-
import { join as
|
|
57006
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
57007
|
+
import { join as join23 } from "node:path";
|
|
56883
57008
|
function renderDiscoveryContext(discovery) {
|
|
56884
57009
|
return [
|
|
56885
57010
|
`Confirmed design brief: ${discovery.brief}`,
|
|
@@ -56944,10 +57069,10 @@ async function runDiscoveryAndInit(args) {
|
|
|
56944
57069
|
};
|
|
56945
57070
|
}
|
|
56946
57071
|
function designContextPath(artifactDir) {
|
|
56947
|
-
return
|
|
57072
|
+
return join23(artifactDir, DESIGN_CONTEXT_FILENAME);
|
|
56948
57073
|
}
|
|
56949
57074
|
function referencesBriefPath(artifactDir) {
|
|
56950
|
-
return
|
|
57075
|
+
return join23(artifactDir, REFERENCES_BRIEF_FILENAME);
|
|
56951
57076
|
}
|
|
56952
57077
|
function buildReferenceDiscoveryPrompt(args) {
|
|
56953
57078
|
const siteList = REFERENCE_DESIGN_SITES.map((site, index) => `${index + 1}. ${site.name} — ${site.url}`).join(`
|
|
@@ -56973,8 +57098,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
56973
57098
|
[
|
|
56974
57099
|
"Use the agent-browser skill to open each gallery; if `agent-browser` reports a missing browser executable, follow the bootstrap rules and retry once.",
|
|
56975
57100
|
"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.",
|
|
56976
|
-
`Capture motion across the entire page: start \`agent-browser record start ${
|
|
56977
|
-
`Also run \`agent-browser screenshot ${
|
|
57101
|
+
`Capture motion across the entire page: start \`agent-browser record start ${join23(args.artifactDir, "ref-<site>-<n>.webm")}\`, scroll smoothly in small increments with waits (using repeated \`agent-browser scroll down 600\` or \`agent-browser mouse wheel 600\`) so animations fire and lazy content loads, then run \`agent-browser record stop\`.`,
|
|
57102
|
+
`Also run \`agent-browser screenshot ${join23(args.artifactDir, "ref-<site>-<n>.png")} --full\`; this still is the minimum when video is unavailable.`,
|
|
56978
57103
|
"Record the actual destination URL, title, and author. For each reference, cite observed layout, typography, color, spacing, and motion traits rather than inferred traits.",
|
|
56979
57104
|
"Assess fit against DESIGN.md, PRODUCT.md, and the ds-* discovery evidence in the design-context file; prefer on-brand references and flag departures.",
|
|
56980
57105
|
"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.",
|
|
@@ -56999,8 +57124,8 @@ function buildReferenceDiscoveryPrompt(args) {
|
|
|
56999
57124
|
}
|
|
57000
57125
|
function writeRequiredContextArtifact(artifactDir, filePath, content, label) {
|
|
57001
57126
|
try {
|
|
57002
|
-
|
|
57003
|
-
|
|
57127
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
57128
|
+
writeFileSync4(filePath, `${content}
|
|
57004
57129
|
`);
|
|
57005
57130
|
} catch (error) {
|
|
57006
57131
|
const detail = error instanceof Error ? error.message : String(error);
|
|
@@ -57551,7 +57676,7 @@ var init_ralph_review_gate = __esm(() => {
|
|
|
57551
57676
|
|
|
57552
57677
|
// dist/builtin/workflows/builtin/ralph-core.ts
|
|
57553
57678
|
import { mkdir as mkdir4, writeFile as writeFile8 } from "node:fs/promises";
|
|
57554
|
-
import { dirname as
|
|
57679
|
+
import { dirname as dirname11, join as join24 } from "node:path";
|
|
57555
57680
|
import { Type as Type20 } from "typebox";
|
|
57556
57681
|
function taggedPrompt4(sections) {
|
|
57557
57682
|
return sections.map(([tag, content]) => {
|
|
@@ -57591,11 +57716,11 @@ function slugifyResearchTopic(prompt) {
|
|
|
57591
57716
|
}
|
|
57592
57717
|
function defaultResearchPath(prompt, now = new Date) {
|
|
57593
57718
|
const date = now.toISOString().slice(0, 10);
|
|
57594
|
-
return
|
|
57719
|
+
return join24(DEFAULT_RESEARCH_DIR, `${date}-${slugifyResearchTopic(prompt)}.md`);
|
|
57595
57720
|
}
|
|
57596
57721
|
async function createImplementationNotesFile(prompt, runId) {
|
|
57597
57722
|
const notesDir = await createWorkflowArtifactDirectory(runId);
|
|
57598
|
-
const notesPath =
|
|
57723
|
+
const notesPath = join24(notesDir, IMPLEMENTATION_NOTES_FILENAME);
|
|
57599
57724
|
const initialNotes = [
|
|
57600
57725
|
"# Implementation Notes",
|
|
57601
57726
|
"",
|
|
@@ -57616,7 +57741,7 @@ async function createImplementationNotesFile(prompt, runId) {
|
|
|
57616
57741
|
}
|
|
57617
57742
|
async function createQaEvidenceVideoPath(runId) {
|
|
57618
57743
|
const qaDir = await createWorkflowArtifactDirectory(runId);
|
|
57619
|
-
return
|
|
57744
|
+
return join24(qaDir, QA_E2E_VIDEO_FILENAME);
|
|
57620
57745
|
}
|
|
57621
57746
|
function renderQaE2eVideoGuidance(qaVideoPath) {
|
|
57622
57747
|
return [
|
|
@@ -57682,7 +57807,7 @@ function artifactSafeName2(value2) {
|
|
|
57682
57807
|
return safe.length > 0 ? safe : "artifact";
|
|
57683
57808
|
}
|
|
57684
57809
|
async function writeJsonArtifact(path, content) {
|
|
57685
|
-
await mkdir4(
|
|
57810
|
+
await mkdir4(dirname11(path), { recursive: true });
|
|
57686
57811
|
await writeFile8(path, `${JSON.stringify(content, null, 2)}
|
|
57687
57812
|
`, {
|
|
57688
57813
|
encoding: "utf8"
|
|
@@ -58019,8 +58144,8 @@ var init_ralph_models = __esm(() => {
|
|
|
58019
58144
|
});
|
|
58020
58145
|
|
|
58021
58146
|
// dist/builtin/workflows/builtin/ralph-runner.ts
|
|
58022
|
-
import { existsSync as
|
|
58023
|
-
import { join as
|
|
58147
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
58148
|
+
import { join as join25, resolve as resolve10 } from "node:path";
|
|
58024
58149
|
async function runRalphWorkflow(ctx, options) {
|
|
58025
58150
|
const { prompt, acceptanceCriteria, maxLoops, comparisonBaseBranch, workflowStartCwd, createPr, runId } = options;
|
|
58026
58151
|
let latestReviewReportPath;
|
|
@@ -58032,7 +58157,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58032
58157
|
let finalPrReport;
|
|
58033
58158
|
const workflowCwdContext = workflowCwdContextSection(workflowStartCwd);
|
|
58034
58159
|
const workflowPrompt = prompt;
|
|
58035
|
-
const workflowResearchPath =
|
|
58160
|
+
const workflowResearchPath = resolve10(workflowStartCwd, defaultResearchPath(workflowPrompt));
|
|
58036
58161
|
const implementationNotesPath = await createImplementationNotesFile(workflowPrompt, runId);
|
|
58037
58162
|
const qaVideoPath = await createQaEvidenceVideoPath(runId);
|
|
58038
58163
|
const artifactDir = await createWorkflowArtifactDirectory(runId);
|
|
@@ -58081,7 +58206,7 @@ async function runRalphWorkflow(ctx, options) {
|
|
|
58081
58206
|
const researchPath = workflowResearchPath;
|
|
58082
58207
|
finalResearchPath = researchPath;
|
|
58083
58208
|
finalPlanPath = researchPath;
|
|
58084
|
-
const orchestratorReportPath =
|
|
58209
|
+
const orchestratorReportPath = join25(artifactDir, "orchestrator-report.md");
|
|
58085
58210
|
const orchestratorForkOptions = forkContinuationOptions3(previousOrchestratorSessionId);
|
|
58086
58211
|
const orchestratorPrompt = orchestratorForkOptions.forkFromSessionId === undefined ? taggedPrompt4([
|
|
58087
58212
|
["acceptance_criteria", keepContext(acceptanceCriteria)],
|
|
@@ -58217,7 +58342,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58217
58342
|
diagnostics: parsed.diagnostics,
|
|
58218
58343
|
allowFinalActionRemaining: createPr
|
|
58219
58344
|
});
|
|
58220
|
-
const artifactPath =
|
|
58345
|
+
const artifactPath = join25(artifactDir, `review-${artifactSafeName2(reviewer)}.json`);
|
|
58221
58346
|
await writeJsonArtifact(artifactPath, {
|
|
58222
58347
|
reviewer,
|
|
58223
58348
|
decision: parsed.decision,
|
|
@@ -58273,7 +58398,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58273
58398
|
usage: fold_usage([orchestrator, ...reviews, ...reverifyResults])
|
|
58274
58399
|
}));
|
|
58275
58400
|
}
|
|
58276
|
-
latestReviewReportPath = await writeJsonArtifact(
|
|
58401
|
+
latestReviewReportPath = await writeJsonArtifact(join25(artifactDir, "review-round-latest.json"), {
|
|
58277
58402
|
convergence_decision: roundConvergenceDecision,
|
|
58278
58403
|
convergence: convergenceEntries,
|
|
58279
58404
|
consolidated_findings: reverified.batch,
|
|
@@ -58283,7 +58408,7 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
58283
58408
|
if (approved)
|
|
58284
58409
|
break;
|
|
58285
58410
|
}
|
|
58286
|
-
const qaVideoAvailable =
|
|
58411
|
+
const qaVideoAvailable = existsSync5(qaVideoPath);
|
|
58287
58412
|
const unapprovedHandoff = createPr === true && !approved;
|
|
58288
58413
|
const escalationEvidence = unapprovedHandoff ? convergence_escalation_evidence(convergenceEntries) : [];
|
|
58289
58414
|
if (createPr === true) {
|
|
@@ -58642,7 +58767,7 @@ var init_tournament_prompts = __esm(() => {
|
|
|
58642
58767
|
|
|
58643
58768
|
// dist/builtin/workflows/builtin/tournament-runner.ts
|
|
58644
58769
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile9 } from "node:fs/promises";
|
|
58645
|
-
import { join as
|
|
58770
|
+
import { join as join26, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve11 } from "node:path";
|
|
58646
58771
|
import { Type as Type22 } from "typebox";
|
|
58647
58772
|
function serializableObject2(value2) {
|
|
58648
58773
|
if (value2 === null || Array.isArray(value2) || typeof value2 !== "object")
|
|
@@ -58679,8 +58804,8 @@ function criterionSlug(id) {
|
|
|
58679
58804
|
}
|
|
58680
58805
|
function judgeArtifactPath(judgesDir, job, criterionIndex) {
|
|
58681
58806
|
const filename = `judge-${job.a}-${job.b}-c${criterionIndex}-${criterionSlug(job.criterionId)}-r${job.rep}.json`;
|
|
58682
|
-
const root =
|
|
58683
|
-
const path =
|
|
58807
|
+
const root = resolve11(judgesDir);
|
|
58808
|
+
const path = resolve11(judgesDir, filename);
|
|
58684
58809
|
const fromRoot = relative5(root, path);
|
|
58685
58810
|
if (fromRoot.startsWith("..") || isAbsolute9(fromRoot)) {
|
|
58686
58811
|
throw new Error(`tournament: judge artifact escaped its directory: ${path}`);
|
|
@@ -58731,16 +58856,16 @@ function combineUsage(totals) {
|
|
|
58731
58856
|
}
|
|
58732
58857
|
async function runTournament(ctx) {
|
|
58733
58858
|
const artifactDir = await stableArtifactRoot(ctx, "tournament");
|
|
58734
|
-
const attemptsDir =
|
|
58859
|
+
const attemptsDir = join26(artifactDir, "attempts");
|
|
58735
58860
|
const numAttempts = ctx.inputs.num_attempts ?? 4;
|
|
58736
58861
|
const maxConcurrency = ctx.inputs.max_concurrency ?? 4;
|
|
58737
58862
|
const nEvaluations = ctx.inputs.n_evaluations ?? 2;
|
|
58738
58863
|
const pivotCount = ctx.inputs.pivots ?? 1;
|
|
58739
58864
|
const seed = ctx.inputs.seed ?? 0;
|
|
58740
|
-
const judgesDir =
|
|
58865
|
+
const judgesDir = join26(artifactDir, "judges");
|
|
58741
58866
|
await mkdir5(attemptsDir, { recursive: true });
|
|
58742
58867
|
await mkdir5(judgesDir, { recursive: true });
|
|
58743
|
-
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) =>
|
|
58868
|
+
const attemptArtifactPaths = Array.from({ length: numAttempts }, (_, index) => join26(attemptsDir, `attempt-${index + 1}.md`));
|
|
58744
58869
|
const models = ctx.inputs.models;
|
|
58745
58870
|
const attemptResults = await ctx.parallel(attemptArtifactPaths.map((path, index) => ({
|
|
58746
58871
|
name: `attempt-${index + 1}`,
|
|
@@ -58905,7 +59030,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
58905
59030
|
const outputRanking = ranking.map(({ label, meanPreference }) => ({ label, meanPreference }));
|
|
58906
59031
|
const budgetPivots = Math.min(pivotCount, entrants.length);
|
|
58907
59032
|
const comparisonBudget = (entrants.length + budgetPivots * (entrants.length - budgetPivots) + budgetPivots * (budgetPivots - 1) / 2) * criteria.length * nEvaluations;
|
|
58908
|
-
const comparisonPath =
|
|
59033
|
+
const comparisonPath = join26(artifactDir, "comparisons.json");
|
|
58909
59034
|
const assignment = modelAssignment(entrants, models);
|
|
58910
59035
|
const phaseUsage = {
|
|
58911
59036
|
attempts: fold_usage(attemptResults),
|
|
@@ -58941,7 +59066,7 @@ The previous report was invalid. Return the required JSON schema exactly once.`,
|
|
|
58941
59066
|
await writeLedger(fold_usage([]));
|
|
58942
59067
|
const winner = ranking[0];
|
|
58943
59068
|
const winnerEntrant = entrants[winner.index];
|
|
58944
|
-
const resultPath =
|
|
59069
|
+
const resultPath = join26(artifactDir, "winner.md");
|
|
58945
59070
|
const reducer = await ctx.task("comparisons-reducer", {
|
|
58946
59071
|
prompt: renderComparisonsReducerPrompt({
|
|
58947
59072
|
task: ctx.inputs.prompt,
|
|
@@ -59159,7 +59284,7 @@ var init_workflow_module_loader = __esm(() => {
|
|
|
59159
59284
|
});
|
|
59160
59285
|
|
|
59161
59286
|
// dist/builtin/workflows/src/workers/definitions.ts
|
|
59162
|
-
import { createHash as
|
|
59287
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
59163
59288
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
59164
59289
|
import { isAbsolute as isAbsolute10 } from "node:path";
|
|
59165
59290
|
async function loadWorkerDefinition(source) {
|
|
@@ -59177,7 +59302,7 @@ async function loadWorkerWorkflow(path, exportName = "default") {
|
|
|
59177
59302
|
return loadWorkerDefinition({ path, exportName, digest: await definitionDigest(path) });
|
|
59178
59303
|
}
|
|
59179
59304
|
async function definitionDigest(path) {
|
|
59180
|
-
return
|
|
59305
|
+
return createHash4("sha256").update(await readFile6(path)).digest("hex");
|
|
59181
59306
|
}
|
|
59182
59307
|
var workerDefinitionSources;
|
|
59183
59308
|
var init_definitions = __esm(() => {
|
|
@@ -59191,6 +59316,84 @@ var init_host_options = __esm(() => {
|
|
|
59191
59316
|
hostWorkerBindings = Symbol("host-worker-bindings");
|
|
59192
59317
|
});
|
|
59193
59318
|
|
|
59319
|
+
// dist/builtin/workflows/src/durable/journal/pool-remote-journal.ts
|
|
59320
|
+
class PoolRemoteJournal {
|
|
59321
|
+
journal;
|
|
59322
|
+
storage;
|
|
59323
|
+
mirrored;
|
|
59324
|
+
mirroring;
|
|
59325
|
+
constructor(journal, storage) {
|
|
59326
|
+
this.journal = journal;
|
|
59327
|
+
this.storage = storage;
|
|
59328
|
+
}
|
|
59329
|
+
async mirror(lease) {
|
|
59330
|
+
const root = lease.runId;
|
|
59331
|
+
const sampledAt = performance.now();
|
|
59332
|
+
const [run, state] = await Promise.all([this.journal.getRun(root), this.journal.leaseState(root)]);
|
|
59333
|
+
if (run === undefined)
|
|
59334
|
+
throw new RunNotFoundError(root);
|
|
59335
|
+
const { runs, leases } = this.storage.tables;
|
|
59336
|
+
await this.storage.transaction(async (tx) => {
|
|
59337
|
+
await tx.run(`INSERT INTO ${runs}(run_id, name, cwd, created_at, status, header_json) VALUES (?, ?, ?, ?, ?, ?)
|
|
59338
|
+
ON CONFLICT(run_id) DO UPDATE SET status = excluded.status`, root, run.name, run.cwd, run.createdAt, run.status, serializeJson({ runId: root, name: run.name, cwd: run.cwd, createdAt: run.createdAt, status: run.status }));
|
|
59339
|
+
if (state === undefined)
|
|
59340
|
+
await tx.run(`DELETE FROM ${leases} WHERE run_id = ?`, root);
|
|
59341
|
+
else
|
|
59342
|
+
await tx.run(`INSERT INTO ${leases}(run_id, holder_id, epoch, renewed_at) VALUES (?, ?, ?, CAST(unixepoch('subsec') * 1000 AS INTEGER) - ?)
|
|
59343
|
+
ON CONFLICT(run_id) DO UPDATE SET holder_id = excluded.holder_id, epoch = excluded.epoch, renewed_at = excluded.renewed_at`, root, state.holderId, state.epoch, Math.ceil(Math.max(0, state.ageMs) + (performance.now() - sampledAt)));
|
|
59344
|
+
});
|
|
59345
|
+
if (state === undefined || state.holderId !== lease.holderId || state.epoch !== lease.epoch)
|
|
59346
|
+
throw new StaleLeaseError(root, lease.epoch, state?.epoch ?? 0);
|
|
59347
|
+
this.mirrored = { lease, at: sampledAt };
|
|
59348
|
+
}
|
|
59349
|
+
async fresh(lease, maxAgeMs = MIRROR_FRESH_MS) {
|
|
59350
|
+
const known = this.mirrored;
|
|
59351
|
+
if (known !== undefined && known.lease.holderId === lease.holderId && known.lease.epoch === lease.epoch && performance.now() - known.at < maxAgeMs)
|
|
59352
|
+
return;
|
|
59353
|
+
this.mirroring ??= this.mirror(lease).finally(() => {
|
|
59354
|
+
this.mirroring = undefined;
|
|
59355
|
+
});
|
|
59356
|
+
try {
|
|
59357
|
+
await this.mirroring;
|
|
59358
|
+
} catch (error) {
|
|
59359
|
+
if (error instanceof StaleLeaseError || error instanceof RunNotFoundError)
|
|
59360
|
+
throw error;
|
|
59361
|
+
}
|
|
59362
|
+
}
|
|
59363
|
+
entry(root, key) {
|
|
59364
|
+
return this.journal.readKey(root, key);
|
|
59365
|
+
}
|
|
59366
|
+
append(lease, key, checkpoint) {
|
|
59367
|
+
const event = { type: RUN_EVENT_TYPES.checkpointRecorded, payload: checkpoint };
|
|
59368
|
+
return this.journal.append(lease, event, { key });
|
|
59369
|
+
}
|
|
59370
|
+
events(root) {
|
|
59371
|
+
return (fromSeq) => this.journal.read(root, fromSeq);
|
|
59372
|
+
}
|
|
59373
|
+
}
|
|
59374
|
+
function isSameCheckpointValue(stored, next) {
|
|
59375
|
+
const hash = (value2) => durableHash(value2);
|
|
59376
|
+
return hash(stored) === hash(next);
|
|
59377
|
+
}
|
|
59378
|
+
function isRecordedCheckpointValue(stored, next) {
|
|
59379
|
+
const recorded = stored;
|
|
59380
|
+
if (isSameCheckpointValue(recorded, next))
|
|
59381
|
+
return true;
|
|
59382
|
+
const { completedAt, startedAt } = recorded;
|
|
59383
|
+
if (typeof completedAt !== "number")
|
|
59384
|
+
return false;
|
|
59385
|
+
const later = next;
|
|
59386
|
+
if (startedAt === undefined !== (later.startedAt === undefined))
|
|
59387
|
+
return false;
|
|
59388
|
+
return isSameCheckpointValue({ ...later, completedAt, ...startedAt === undefined ? {} : { startedAt } }, recorded);
|
|
59389
|
+
}
|
|
59390
|
+
var MIRROR_FRESH_MS = 2000;
|
|
59391
|
+
var init_pool_remote_journal = __esm(() => {
|
|
59392
|
+
init_durable_hash();
|
|
59393
|
+
init_types();
|
|
59394
|
+
init_values();
|
|
59395
|
+
});
|
|
59396
|
+
|
|
59194
59397
|
// dist/builtin/workflows/src/durable/journal/pool-checkpoint-index.ts
|
|
59195
59398
|
function push(map, key, value2) {
|
|
59196
59399
|
if (key === undefined)
|
|
@@ -59258,6 +59461,11 @@ class PoolCheckpointRead {
|
|
|
59258
59461
|
this.pending = apply;
|
|
59259
59462
|
});
|
|
59260
59463
|
}
|
|
59464
|
+
readEntries(stream) {
|
|
59465
|
+
return this.index.readEntries(this.root, stream, (apply) => {
|
|
59466
|
+
this.pending = apply;
|
|
59467
|
+
});
|
|
59468
|
+
}
|
|
59261
59469
|
commit() {
|
|
59262
59470
|
this.pending?.();
|
|
59263
59471
|
this.pending = undefined;
|
|
@@ -59280,7 +59488,6 @@ class PoolCheckpointIndex {
|
|
|
59280
59488
|
}
|
|
59281
59489
|
const from = base?.seq ?? 0;
|
|
59282
59490
|
const to = head ? Number(head.seq) : 0;
|
|
59283
|
-
const delta = new Partitions;
|
|
59284
59491
|
const added = [];
|
|
59285
59492
|
if (to > from) {
|
|
59286
59493
|
const rows = await tx.all(`SELECT seq, key, payload FROM ${events} WHERE run_id = ? AND seq > ? AND seq <= ? AND type = ? ORDER BY seq`, root, from, to, RUN_EVENT_TYPES.checkpointRecorded);
|
|
@@ -59288,15 +59495,57 @@ class PoolCheckpointIndex {
|
|
|
59288
59495
|
const checkpoint = JSON.parse(String(row.payload));
|
|
59289
59496
|
if (checkpoint.kind === "ui")
|
|
59290
59497
|
continue;
|
|
59291
|
-
|
|
59498
|
+
added.push({
|
|
59292
59499
|
seq: Number(row.seq),
|
|
59293
59500
|
order: row.key === null ? Buffer.alloc(0) : Buffer.from(row.key, "utf8"),
|
|
59294
59501
|
checkpoint
|
|
59295
|
-
};
|
|
59296
|
-
delta.add(entry);
|
|
59297
|
-
added.push(entry);
|
|
59502
|
+
});
|
|
59298
59503
|
}
|
|
59299
59504
|
}
|
|
59505
|
+
return this.view(root, current, base, from, to, head, added, onCommit);
|
|
59506
|
+
}
|
|
59507
|
+
async readEntries(root, stream, onCommit) {
|
|
59508
|
+
const current = this.roots.get(root);
|
|
59509
|
+
let base = current;
|
|
59510
|
+
for (;; ) {
|
|
59511
|
+
const mark = base !== undefined && base.seq > 0 ? { seq: base.seq, key: base.key, at: base.at } : undefined;
|
|
59512
|
+
let verified = mark === undefined;
|
|
59513
|
+
let mismatch = false;
|
|
59514
|
+
let head;
|
|
59515
|
+
const added = [];
|
|
59516
|
+
for await (const entry of stream(mark === undefined ? 1 : mark.seq)) {
|
|
59517
|
+
if (mark !== undefined && entry.seq === mark.seq) {
|
|
59518
|
+
if ((entry.key ?? null) !== mark.key || entry.at !== mark.at) {
|
|
59519
|
+
mismatch = true;
|
|
59520
|
+
break;
|
|
59521
|
+
}
|
|
59522
|
+
verified = true;
|
|
59523
|
+
head = { seq: entry.seq, key: entry.key ?? null, at: entry.at };
|
|
59524
|
+
continue;
|
|
59525
|
+
}
|
|
59526
|
+
head = { seq: entry.seq, key: entry.key ?? null, at: entry.at };
|
|
59527
|
+
if (entry.event.type !== RUN_EVENT_TYPES.checkpointRecorded)
|
|
59528
|
+
continue;
|
|
59529
|
+
const checkpoint = entry.event.payload;
|
|
59530
|
+
if (checkpoint.kind === "ui")
|
|
59531
|
+
continue;
|
|
59532
|
+
added.push({
|
|
59533
|
+
seq: entry.seq,
|
|
59534
|
+
order: entry.key === undefined ? Buffer.alloc(0) : Buffer.from(entry.key, "utf8"),
|
|
59535
|
+
checkpoint
|
|
59536
|
+
});
|
|
59537
|
+
}
|
|
59538
|
+
if (mark !== undefined && (mismatch || !verified)) {
|
|
59539
|
+
base = undefined;
|
|
59540
|
+
continue;
|
|
59541
|
+
}
|
|
59542
|
+
return this.view(root, current, base, mark?.seq ?? 0, head?.seq ?? 0, head, added, onCommit);
|
|
59543
|
+
}
|
|
59544
|
+
}
|
|
59545
|
+
view(root, current, base, from, to, head, added, onCommit) {
|
|
59546
|
+
const delta = new Partitions;
|
|
59547
|
+
for (const entry of added)
|
|
59548
|
+
delta.add(entry);
|
|
59300
59549
|
onCommit(() => {
|
|
59301
59550
|
const latest = this.roots.get(root);
|
|
59302
59551
|
if (!base) {
|
|
@@ -59525,10 +59774,10 @@ var init_pool_stage_usage = __esm(() => {
|
|
|
59525
59774
|
});
|
|
59526
59775
|
|
|
59527
59776
|
// dist/builtin/workflows/src/durable/journal/sql-pool-queue.ts
|
|
59528
|
-
import { createHash as
|
|
59777
|
+
import { createHash as createHash5, randomUUID as randomUUID11 } from "node:crypto";
|
|
59529
59778
|
import { assertStorageSchemaVersion as assertStorageSchemaVersion2, StorageError as StorageError2 } from "@bastani/atomic/storage";
|
|
59530
59779
|
function requestIdentity(request) {
|
|
59531
|
-
return
|
|
59780
|
+
return createHash5("sha256").update(request).digest("hex");
|
|
59532
59781
|
}
|
|
59533
59782
|
function fromRow(row) {
|
|
59534
59783
|
return {
|
|
@@ -59559,15 +59808,21 @@ function expiry(now, duration) {
|
|
|
59559
59808
|
|
|
59560
59809
|
class SqlPoolQueue {
|
|
59561
59810
|
storage;
|
|
59811
|
+
remote;
|
|
59562
59812
|
meta;
|
|
59563
59813
|
roots;
|
|
59564
59814
|
work;
|
|
59565
59815
|
operations;
|
|
59816
|
+
outbox;
|
|
59566
59817
|
transaction;
|
|
59567
59818
|
journal;
|
|
59568
59819
|
checkpoints = new PoolCheckpointIndex;
|
|
59569
|
-
|
|
59820
|
+
committing = new Map;
|
|
59821
|
+
draining;
|
|
59822
|
+
outboxPending = false;
|
|
59823
|
+
constructor(storage, remote) {
|
|
59570
59824
|
this.storage = storage;
|
|
59825
|
+
this.remote = remote;
|
|
59571
59826
|
const { transaction, tables: journal } = storage;
|
|
59572
59827
|
this.transaction = transaction;
|
|
59573
59828
|
this.journal = journal;
|
|
@@ -59575,10 +59830,11 @@ class SqlPoolQueue {
|
|
|
59575
59830
|
this.roots = `${journal.runs}_pool`;
|
|
59576
59831
|
this.work = `${journal.runs}_work`;
|
|
59577
59832
|
this.operations = `${journal.runs}_pool_operations`;
|
|
59833
|
+
this.outbox = `${journal.runs}_pool_outbox`;
|
|
59578
59834
|
}
|
|
59579
|
-
static async open(storage) {
|
|
59835
|
+
static async open(storage, remote) {
|
|
59580
59836
|
const journal = storage.tables;
|
|
59581
|
-
const pool = new SqlPoolQueue(storage);
|
|
59837
|
+
const pool = new SqlPoolQueue(storage, remote);
|
|
59582
59838
|
await storage.transaction(async (tx) => {
|
|
59583
59839
|
if ((await tx.get("PRAGMA foreign_keys"))?.foreign_keys !== 1)
|
|
59584
59840
|
throw new Error("Pool requires SQLite foreign keys");
|
|
@@ -59621,6 +59877,15 @@ class SqlPoolQueue {
|
|
|
59621
59877
|
state TEXT NOT NULL DEFAULT 'running', revision INTEGER NOT NULL DEFAULT 0
|
|
59622
59878
|
)`);
|
|
59623
59879
|
await tx.exec(poolUsageSchema(journal.runs));
|
|
59880
|
+
if (remote)
|
|
59881
|
+
await tx.exec(`CREATE TABLE IF NOT EXISTS ${pool.outbox}(
|
|
59882
|
+
work TEXT NOT NULL REFERENCES ${pool.work}(id) ON DELETE CASCADE,
|
|
59883
|
+
generation INTEGER NOT NULL, operation TEXT NOT NULL, request TEXT NOT NULL,
|
|
59884
|
+
event_key TEXT NOT NULL, payload TEXT NOT NULL, last_seq INTEGER,
|
|
59885
|
+
PRIMARY KEY(work, generation, operation)
|
|
59886
|
+
)`);
|
|
59887
|
+
if (remote)
|
|
59888
|
+
pool.outboxPending = await tx.get(`SELECT 1 AS held FROM ${pool.outbox} LIMIT 1`) !== undefined;
|
|
59624
59889
|
if (version === 1)
|
|
59625
59890
|
await pool.migrateFromVersion1(tx);
|
|
59626
59891
|
});
|
|
@@ -59665,6 +59930,7 @@ class SqlPoolQueue {
|
|
|
59665
59930
|
});
|
|
59666
59931
|
}
|
|
59667
59932
|
async setControl(lease, state) {
|
|
59933
|
+
await this.remote?.fresh(lease);
|
|
59668
59934
|
return this.transaction(async (tx) => {
|
|
59669
59935
|
await this.authority(tx, lease);
|
|
59670
59936
|
await tx.run(`INSERT INTO ${this.roots}_control(root, state, revision) VALUES (?, ?, 1)
|
|
@@ -59676,7 +59942,7 @@ class SqlPoolQueue {
|
|
|
59676
59942
|
withCurrentAppend(lease, token, assertSession, action) {
|
|
59677
59943
|
lease = snapshotLease(lease);
|
|
59678
59944
|
token = { ...token };
|
|
59679
|
-
|
|
59945
|
+
const guard = async (tx, runId) => {
|
|
59680
59946
|
try {
|
|
59681
59947
|
if (runId !== lease.runId)
|
|
59682
59948
|
throw new Error("Pool delivery cannot write another root");
|
|
@@ -59694,7 +59960,10 @@ class SqlPoolQueue {
|
|
|
59694
59960
|
throw error;
|
|
59695
59961
|
throw new PoolAppendRefusedError(error.message, { cause: error });
|
|
59696
59962
|
}
|
|
59697
|
-
}
|
|
59963
|
+
};
|
|
59964
|
+
if (this.remote)
|
|
59965
|
+
return this.transaction((tx) => guard(tx, lease.runId)).then(action);
|
|
59966
|
+
return this.storage.withAppendGuard(guard, action);
|
|
59698
59967
|
}
|
|
59699
59968
|
async assertCurrent(lease, token) {
|
|
59700
59969
|
await this.transaction(async (tx) => {
|
|
@@ -59727,6 +59996,8 @@ class SqlPoolQueue {
|
|
|
59727
59996
|
const payload = serializeJson(boundary);
|
|
59728
59997
|
const fingerprint = durableHash({ descriptor: JSON.parse(json), boundary: JSON.parse(payload) });
|
|
59729
59998
|
const key = JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, boundary.kind, boundary.checkpointId]);
|
|
59999
|
+
if (this.remote)
|
|
60000
|
+
await this.recordBoundaryStart(lease, key, boundary);
|
|
59730
60001
|
return this.transaction(async (tx) => {
|
|
59731
60002
|
const { now } = await this.authority(tx, lease);
|
|
59732
60003
|
const previous = await tx.get(`SELECT * FROM ${this.work} WHERE root = ? AND (boundary = ? OR json_extract(descriptor, '$.scope') = ? OR json_extract(descriptor, '$.childRunId') = ?)`, lease.runId, boundaryId, scope, childRunId);
|
|
@@ -59741,23 +60012,49 @@ class SqlPoolQueue {
|
|
|
59741
60012
|
const siblings = await tx.all(`SELECT json_extract(descriptor, '$.scope') AS scope FROM ${this.work} WHERE root = ?`, lease.runId);
|
|
59742
60013
|
if (siblings.some((item) => scope.startsWith(`${item.scope}:`) || item.scope.startsWith(`${scope}:`)))
|
|
59743
60014
|
throw new Error("Pool work scopes overlap");
|
|
59744
|
-
const id =
|
|
60015
|
+
const id = randomUUID11();
|
|
59745
60016
|
await tx.run(`INSERT INTO ${this.work}(id, root, boundary, descriptor, fingerprint, epoch, ready_at) VALUES (?, ?, ?, ?, ?, ?, ?)`, id, lease.runId, boundaryId, json, fingerprint, lease.epoch, now);
|
|
59746
|
-
|
|
59747
|
-
|
|
59748
|
-
|
|
59749
|
-
|
|
59750
|
-
|
|
59751
|
-
|
|
60017
|
+
if (!this.remote) {
|
|
60018
|
+
const seq = await tx.get(`SELECT COALESCE(MAX(seq), 0) AS seq FROM ${this.journal.events} WHERE run_id = ?`, lease.runId);
|
|
60019
|
+
const existing = await tx.get(`SELECT payload FROM ${this.journal.events} WHERE run_id = ? AND key = ?`, lease.runId, key);
|
|
60020
|
+
if (existing && existing.payload !== payload)
|
|
60021
|
+
throw new Error("Pool boundary identity conflict");
|
|
60022
|
+
if (!existing)
|
|
60023
|
+
await tx.run(`INSERT INTO ${this.journal.events} VALUES (?, ?, ?, ?, ?, ?, ?)`, lease.runId, journalCounter(lease.runId, "seq", Number(seq.seq) + 1, "overflow"), lease.epoch, key, RUN_EVENT_TYPES.checkpointRecorded, payload, now);
|
|
60024
|
+
}
|
|
59752
60025
|
return fromRow(await tx.get(`SELECT * FROM ${this.work} WHERE id = ?`, id));
|
|
59753
60026
|
});
|
|
59754
60027
|
}
|
|
60028
|
+
async recordBoundaryStart(lease, key, boundary) {
|
|
60029
|
+
const remote = this.remote;
|
|
60030
|
+
await remote.fresh(lease);
|
|
60031
|
+
const existing = await remote.entry(lease.runId, key);
|
|
60032
|
+
if (existing) {
|
|
60033
|
+
if (!isSameCheckpointValue(existing.event.payload, boundary))
|
|
60034
|
+
throw new Error("Pool boundary identity conflict");
|
|
60035
|
+
return;
|
|
60036
|
+
}
|
|
60037
|
+
const outcome = await remote.append(lease, key, boundary);
|
|
60038
|
+
if (outcome.status === "exists" && !isSameCheckpointValue(outcome.entry.event.payload, boundary))
|
|
60039
|
+
throw new Error("Pool boundary identity conflict");
|
|
60040
|
+
}
|
|
59755
60041
|
async claim(lease, worker, definitions, durationMs) {
|
|
59756
60042
|
positive(durationMs);
|
|
59757
60043
|
lease = snapshotLease(lease);
|
|
59758
60044
|
const compatibleDefinitions = definitions.flatMap((d) => [d.definition, d.digest]);
|
|
59759
60045
|
validateText("holderId", worker);
|
|
59760
60046
|
const compatible = definitions.map(() => "(json_extract(descriptor, '$.definition') = ? AND json_extract(descriptor, '$.digest') = ?)").join(" OR ");
|
|
60047
|
+
if (this.remote) {
|
|
60048
|
+
await this.remote.fresh(lease);
|
|
60049
|
+
try {
|
|
60050
|
+
while (this.outboxPending || this.draining !== undefined)
|
|
60051
|
+
await this.drainOutbox(lease);
|
|
60052
|
+
} catch (error) {
|
|
60053
|
+
if (error instanceof StaleLeaseError)
|
|
60054
|
+
throw error;
|
|
60055
|
+
return;
|
|
60056
|
+
}
|
|
60057
|
+
}
|
|
59761
60058
|
return this.transaction(async (tx) => {
|
|
59762
60059
|
const { now, status } = await this.authority(tx, lease);
|
|
59763
60060
|
const control = await tx.get(`SELECT state FROM ${this.roots}_control WHERE root = ?`, lease.runId);
|
|
@@ -59791,6 +60088,7 @@ class SqlPoolQueue {
|
|
|
59791
60088
|
positive(durationMs);
|
|
59792
60089
|
lease = snapshotLease(lease);
|
|
59793
60090
|
token = { ...token };
|
|
60091
|
+
await this.remote?.fresh(lease);
|
|
59794
60092
|
return this.transaction(async (tx) => {
|
|
59795
60093
|
const { now } = await this.authority(tx, lease);
|
|
59796
60094
|
const row = await this.current(tx, lease, token);
|
|
@@ -59809,6 +60107,8 @@ class SqlPoolQueue {
|
|
|
59809
60107
|
const request = serializeJson({ epoch: token.epoch, worker: token.worker, mutation });
|
|
59810
60108
|
const identity = requestIdentity(request);
|
|
59811
60109
|
mutation = JSON.parse(request).mutation;
|
|
60110
|
+
if (this.remote && mutation.kind !== "session-append")
|
|
60111
|
+
return this.commitRemote(lease, token, operationId, mutation, identity);
|
|
59812
60112
|
const checkpoints = this.checkpoints.begin(lease.runId);
|
|
59813
60113
|
const receipt = await this.transaction(async (tx) => {
|
|
59814
60114
|
const { now, status } = await this.authority(tx, lease);
|
|
@@ -59832,6 +60132,127 @@ class SqlPoolQueue {
|
|
|
59832
60132
|
checkpoints.commit();
|
|
59833
60133
|
return receipt;
|
|
59834
60134
|
}
|
|
60135
|
+
commitRemote(lease, token, operationId, mutation, identity) {
|
|
60136
|
+
const flight = JSON.stringify([token.id, token.generation, operationId]);
|
|
60137
|
+
const running = this.committing.get(flight);
|
|
60138
|
+
if (running)
|
|
60139
|
+
return running;
|
|
60140
|
+
const commit = this.stageAndDeliver(lease, token, operationId, mutation, identity).finally(() => {
|
|
60141
|
+
this.committing.delete(flight);
|
|
60142
|
+
});
|
|
60143
|
+
this.committing.set(flight, commit);
|
|
60144
|
+
return commit;
|
|
60145
|
+
}
|
|
60146
|
+
async stageAndDeliver(lease, token, operationId, mutation, identity) {
|
|
60147
|
+
const remote = this.remote;
|
|
60148
|
+
await remote.fresh(lease);
|
|
60149
|
+
const checkpoint = mutation.checkpoint;
|
|
60150
|
+
const key = JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, checkpoint.kind, checkpoint.checkpointId]);
|
|
60151
|
+
const reads = this.checkpoints.begin(lease.runId);
|
|
60152
|
+
const [existing, view] = await Promise.all([
|
|
60153
|
+
remote.entry(lease.runId, key),
|
|
60154
|
+
checkpoint.kind === "ui" ? undefined : reads.readEntries(remote.events(lease.runId))
|
|
60155
|
+
]);
|
|
60156
|
+
reads.commit();
|
|
60157
|
+
const source = {
|
|
60158
|
+
read: async () => view ?? Promise.reject(new Error("Pool checkpoint view is unavailable"))
|
|
60159
|
+
};
|
|
60160
|
+
const staged = await this.transaction(async (tx) => {
|
|
60161
|
+
const { now, status } = await this.authority(tx, lease);
|
|
60162
|
+
const row = await this.current(tx, lease, token);
|
|
60163
|
+
if (row.epoch !== lease.epoch)
|
|
60164
|
+
throw new Error(STALE_WORK_LEASE);
|
|
60165
|
+
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
60166
|
+
if (previous) {
|
|
60167
|
+
if (previous.request !== identity)
|
|
60168
|
+
throw new Error("Pool operation identity conflict");
|
|
60169
|
+
return { receipt: JSON.parse(previous.receipt) };
|
|
60170
|
+
}
|
|
60171
|
+
const held = await tx.get(`SELECT * FROM ${this.outbox} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
60172
|
+
if (held) {
|
|
60173
|
+
if (held.request !== identity)
|
|
60174
|
+
throw new Error("Pool operation identity conflict");
|
|
60175
|
+
return { held };
|
|
60176
|
+
}
|
|
60177
|
+
if (row.expires_at < now)
|
|
60178
|
+
throw new Error(STALE_WORK_LEASE);
|
|
60179
|
+
if (!await this.admitsAttemptWrites(tx, lease, status))
|
|
60180
|
+
throw new Error("Pool root is not running");
|
|
60181
|
+
await validatePoolMutation(tx, this.journal, lease.runId, fromRow(row), mutation, source);
|
|
60182
|
+
if (checkpoint.completedAt > Math.max(now, Date.now()) + MAX_WORKER_CLOCK_SKEW_MS)
|
|
60183
|
+
throw new Error("Pool checkpoint timestamp is in the future");
|
|
60184
|
+
assertWorkflowSerializableObject(checkpoint, "Pool checkpoint");
|
|
60185
|
+
if (existing && !isRecordedCheckpointValue(existing.event.payload, checkpoint))
|
|
60186
|
+
throw new Error("Pool checkpoint identity conflict");
|
|
60187
|
+
if (existing && mutation.kind !== "checkpoint")
|
|
60188
|
+
throw new Error("Pool session checkpoint identity conflict");
|
|
60189
|
+
const lastSeq = mutation.kind === "checkpoint" ? undefined : await applyPoolSession(tx, `${this.journal.runs}_pool_`, row.id, mutation);
|
|
60190
|
+
const billed = poolCheckpointUsage(checkpoint);
|
|
60191
|
+
if (billed && !existing)
|
|
60192
|
+
await upsertPoolUsage(tx, this.journal.runs, row.id, token.generation, billed.key, billed.usage);
|
|
60193
|
+
if (existing) {
|
|
60194
|
+
const receipt = { seq: existing.seq, at: existing.at };
|
|
60195
|
+
await tx.run(`INSERT INTO ${this.operations} VALUES (?, ?, ?, ?, ?)`, token.id, token.generation, operationId, identity, JSON.stringify(receipt));
|
|
60196
|
+
return { receipt };
|
|
60197
|
+
}
|
|
60198
|
+
const entry = {
|
|
60199
|
+
work: token.id,
|
|
60200
|
+
generation: token.generation,
|
|
60201
|
+
operation: operationId,
|
|
60202
|
+
request: identity,
|
|
60203
|
+
event_key: key,
|
|
60204
|
+
payload: serializeJson(checkpoint),
|
|
60205
|
+
last_seq: lastSeq ?? null
|
|
60206
|
+
};
|
|
60207
|
+
await tx.run(`INSERT INTO ${this.outbox} VALUES (?, ?, ?, ?, ?, ?, ?)`, entry.work, entry.generation, entry.operation, entry.request, entry.event_key, entry.payload, entry.last_seq);
|
|
60208
|
+
return { held: entry };
|
|
60209
|
+
});
|
|
60210
|
+
if (staged.receipt !== undefined)
|
|
60211
|
+
return staged.receipt;
|
|
60212
|
+
this.outboxPending = true;
|
|
60213
|
+
return this.deliver(lease, staged.held);
|
|
60214
|
+
}
|
|
60215
|
+
async deliver(lease, held) {
|
|
60216
|
+
const remote = this.remote;
|
|
60217
|
+
const checkpoint = JSON.parse(held.payload);
|
|
60218
|
+
const outcome = await remote.append(lease, held.event_key, checkpoint);
|
|
60219
|
+
const forget = (tx) => tx.run(`DELETE FROM ${this.outbox} WHERE work = ? AND generation = ? AND operation = ?`, held.work, held.generation, held.operation);
|
|
60220
|
+
if (outcome.status === "exists" && !isRecordedCheckpointValue(outcome.entry.event.payload, checkpoint)) {
|
|
60221
|
+
await this.transaction(forget);
|
|
60222
|
+
throw new Error("Pool checkpoint identity conflict");
|
|
60223
|
+
}
|
|
60224
|
+
const receipt = {
|
|
60225
|
+
seq: outcome.entry.seq,
|
|
60226
|
+
at: outcome.entry.at,
|
|
60227
|
+
...held.last_seq === null ? {} : { lastSeq: Number(held.last_seq) }
|
|
60228
|
+
};
|
|
60229
|
+
await this.transaction(async (tx) => {
|
|
60230
|
+
await tx.run(`INSERT OR IGNORE INTO ${this.operations} VALUES (?, ?, ?, ?, ?)`, held.work, held.generation, held.operation, held.request, JSON.stringify(receipt));
|
|
60231
|
+
await forget(tx);
|
|
60232
|
+
});
|
|
60233
|
+
return receipt;
|
|
60234
|
+
}
|
|
60235
|
+
drainOutbox(lease) {
|
|
60236
|
+
if (!this.remote)
|
|
60237
|
+
return Promise.resolve(0);
|
|
60238
|
+
lease = snapshotLease(lease);
|
|
60239
|
+
this.draining ??= this.deliverAll(lease).finally(() => {
|
|
60240
|
+
this.draining = undefined;
|
|
60241
|
+
});
|
|
60242
|
+
return this.draining;
|
|
60243
|
+
}
|
|
60244
|
+
async deliverAll(lease) {
|
|
60245
|
+
this.outboxPending = false;
|
|
60246
|
+
const rows = await this.transaction((tx) => tx.all(`SELECT o.* FROM ${this.outbox} o JOIN ${this.work} w ON w.id = o.work WHERE w.root = ? ORDER BY o.rowid`, lease.runId));
|
|
60247
|
+
try {
|
|
60248
|
+
for (const row of rows)
|
|
60249
|
+
await this.deliver(lease, row);
|
|
60250
|
+
} catch (error) {
|
|
60251
|
+
this.outboxPending = true;
|
|
60252
|
+
throw error;
|
|
60253
|
+
}
|
|
60254
|
+
return rows.length;
|
|
60255
|
+
}
|
|
59835
60256
|
async appendSession(tx, row, mutation, now) {
|
|
59836
60257
|
return { at: now, lastSeq: await applyPoolSession(tx, `${this.journal.runs}_pool_`, row.id, mutation) };
|
|
59837
60258
|
}
|
|
@@ -59867,6 +60288,7 @@ class SqlPoolQueue {
|
|
|
59867
60288
|
token = { ...token };
|
|
59868
60289
|
assertWorkflowSerializableObject(result, "Pool result");
|
|
59869
60290
|
const payload = serializeJson(result);
|
|
60291
|
+
await this.remote?.fresh(lease);
|
|
59870
60292
|
await this.transaction(async (tx) => {
|
|
59871
60293
|
const { now, status } = await this.authority(tx, lease);
|
|
59872
60294
|
const row = await this.current(tx, lease, token, true);
|
|
@@ -59882,6 +60304,8 @@ class SqlPoolQueue {
|
|
|
59882
60304
|
throw new Error(STALE_WORK_LEASE);
|
|
59883
60305
|
if (JSON.parse(payload).runId !== fromRow(row).childRunId)
|
|
59884
60306
|
throw new Error("Pool result identity mismatch");
|
|
60307
|
+
if (this.remote && await tx.get(`SELECT 1 AS held FROM ${this.outbox} WHERE work = ? LIMIT 1`, token.id))
|
|
60308
|
+
throw new Error("Pool work has journal events not yet recorded");
|
|
59885
60309
|
await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
|
|
59886
60310
|
await tx.run(`UPDATE ${this.work} SET state = 'completed' WHERE id = ?`, token.id);
|
|
59887
60311
|
});
|
|
@@ -59908,6 +60332,7 @@ class SqlPoolQueue {
|
|
|
59908
60332
|
positive(durationMs);
|
|
59909
60333
|
lease = snapshotLease(lease);
|
|
59910
60334
|
token = { ...token };
|
|
60335
|
+
await this.remote?.fresh(lease);
|
|
59911
60336
|
return this.transaction(async (tx) => {
|
|
59912
60337
|
const { now } = await this.authority(tx, lease);
|
|
59913
60338
|
const row = await this.current(tx, lease, token);
|
|
@@ -59979,11 +60404,11 @@ function isRecordedCheckpoint(stored, payload) {
|
|
|
59979
60404
|
return false;
|
|
59980
60405
|
return serializeJson({ ...next, completedAt, ...startedAt === undefined ? {} : { startedAt } }) === stored;
|
|
59981
60406
|
}
|
|
59982
|
-
function openSqlPoolQueue(journal) {
|
|
60407
|
+
function openSqlPoolQueue(journal, remote) {
|
|
59983
60408
|
const storage = sqlPoolStorage(journal);
|
|
59984
60409
|
if (!storage)
|
|
59985
60410
|
return Promise.reject(new Error("Worker pool requires a SQL run journal"));
|
|
59986
|
-
return SqlPoolQueue.open(storage);
|
|
60411
|
+
return SqlPoolQueue.open(storage, remote);
|
|
59987
60412
|
}
|
|
59988
60413
|
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000, POOL_SCHEMA_VERSION = 2, STALE_WORK_LEASE = "Stale work lease", PoolAppendRefusedError;
|
|
59989
60414
|
var init_sql_pool_queue = __esm(() => {
|
|
@@ -59993,6 +60418,7 @@ var init_sql_pool_queue = __esm(() => {
|
|
|
59993
60418
|
init_internal();
|
|
59994
60419
|
init_pool_checkpoint_index();
|
|
59995
60420
|
init_pool_mutations();
|
|
60421
|
+
init_pool_remote_journal();
|
|
59996
60422
|
init_pool_stage_usage();
|
|
59997
60423
|
init_types();
|
|
59998
60424
|
init_values();
|
|
@@ -60064,7 +60490,7 @@ var init_external_run_routes = __esm(() => {
|
|
|
60064
60490
|
});
|
|
60065
60491
|
|
|
60066
60492
|
// dist/builtin/workflows/src/shared/pending-stage-route-capability.ts
|
|
60067
|
-
import { randomUUID as
|
|
60493
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
60068
60494
|
function capabilitiesFor(store) {
|
|
60069
60495
|
let capabilities = routeCapabilities.get(store);
|
|
60070
60496
|
if (capabilities === undefined) {
|
|
@@ -60077,13 +60503,13 @@ function workflowPendingStageRouteCapability(store, runId) {
|
|
|
60077
60503
|
const capabilities = capabilitiesFor(store);
|
|
60078
60504
|
let capability = capabilities.get(runId);
|
|
60079
60505
|
if (capability === undefined) {
|
|
60080
|
-
capability =
|
|
60506
|
+
capability = randomUUID12();
|
|
60081
60507
|
capabilities.set(runId, capability);
|
|
60082
60508
|
}
|
|
60083
60509
|
return capability;
|
|
60084
60510
|
}
|
|
60085
60511
|
function rotateWorkflowPendingStageRouteCapability(store, runId) {
|
|
60086
|
-
const capability =
|
|
60512
|
+
const capability = randomUUID12();
|
|
60087
60513
|
capabilitiesFor(store).set(runId, capability);
|
|
60088
60514
|
return capability;
|
|
60089
60515
|
}
|
|
@@ -61752,7 +62178,7 @@ function isBrokerStatusReport(value2) {
|
|
|
61752
62178
|
|
|
61753
62179
|
// dist/builtin/intercom/broker/paths.ts
|
|
61754
62180
|
import { homedir as homedir2 } from "os";
|
|
61755
|
-
import { join as
|
|
62181
|
+
import { join as join27 } from "path";
|
|
61756
62182
|
function getHomeDir() {
|
|
61757
62183
|
if (process.platform === "win32") {
|
|
61758
62184
|
if (process.env.USERPROFILE)
|
|
@@ -61769,7 +62195,7 @@ function expandTildePath(path) {
|
|
|
61769
62195
|
if (path === "~")
|
|
61770
62196
|
return getHomeDir();
|
|
61771
62197
|
if (path.startsWith("~/") || process.platform === "win32" && path.startsWith("~\\")) {
|
|
61772
|
-
return
|
|
62198
|
+
return join27(getHomeDir(), path.slice(2));
|
|
61773
62199
|
}
|
|
61774
62200
|
return path;
|
|
61775
62201
|
}
|
|
@@ -61780,28 +62206,31 @@ function getAgentDir5() {
|
|
|
61780
62206
|
const piAgentDir = process.env.PI_CODING_AGENT_DIR;
|
|
61781
62207
|
if (piAgentDir)
|
|
61782
62208
|
return expandTildePath(piAgentDir);
|
|
61783
|
-
return
|
|
62209
|
+
return join27(getHomeDir(), ".atomic", "agent");
|
|
61784
62210
|
}
|
|
61785
62211
|
function sanitizePipeSegment(value2) {
|
|
61786
62212
|
return value2.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
|
|
61787
62213
|
}
|
|
61788
62214
|
function getIntercomDirPath(agentDir = getAgentDir5()) {
|
|
61789
|
-
return
|
|
62215
|
+
return join27(agentDir, "intercom");
|
|
61790
62216
|
}
|
|
61791
62217
|
function getBrokerPidPath(agentDir = getAgentDir5()) {
|
|
61792
|
-
return
|
|
62218
|
+
return join27(getIntercomDirPath(agentDir), "broker.pid");
|
|
61793
62219
|
}
|
|
61794
62220
|
function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
61795
|
-
return
|
|
62221
|
+
return join27(getIntercomDirPath(agentDir), "broker.spawn.lock");
|
|
61796
62222
|
}
|
|
61797
62223
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
61798
|
-
return
|
|
62224
|
+
return join27(getIntercomDirPath(agentDir), "broker.log");
|
|
62225
|
+
}
|
|
62226
|
+
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
62227
|
+
return join27(getIntercomDirPath(agentDir), "broker.starting");
|
|
61799
62228
|
}
|
|
61800
62229
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
61801
62230
|
if (platform === "win32") {
|
|
61802
62231
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
61803
62232
|
}
|
|
61804
|
-
return
|
|
62233
|
+
return join27(getIntercomDirPath(agentDir), "broker.sock");
|
|
61805
62234
|
}
|
|
61806
62235
|
var BROKER_STORAGE_ENV = "ATOMIC_STORAGE";
|
|
61807
62236
|
var init_paths = () => {};
|
|
@@ -61828,7 +62257,7 @@ function buildSendSignature(to, options) {
|
|
|
61828
62257
|
}
|
|
61829
62258
|
|
|
61830
62259
|
// dist/builtin/intercom/broker/pending-send-registry.ts
|
|
61831
|
-
import { randomUUID as
|
|
62260
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
61832
62261
|
|
|
61833
62262
|
class PendingSendRegistry {
|
|
61834
62263
|
generationTtlMs;
|
|
@@ -61887,7 +62316,7 @@ class PendingSendRegistry {
|
|
|
61887
62316
|
const generation = this.nextGeneration(messageId);
|
|
61888
62317
|
const attempt = {
|
|
61889
62318
|
messageId,
|
|
61890
|
-
attemptId:
|
|
62319
|
+
attemptId: randomUUID13(),
|
|
61891
62320
|
signature,
|
|
61892
62321
|
promise,
|
|
61893
62322
|
resolve: resolvePromise,
|
|
@@ -62103,7 +62532,7 @@ var init_live_route_refusal = __esm(() => {
|
|
|
62103
62532
|
});
|
|
62104
62533
|
|
|
62105
62534
|
// dist/builtin/intercom/recoverable-disconnect.ts
|
|
62106
|
-
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", IntercomClientDisconnectedError, IntercomBrokerTimeoutError;
|
|
62535
|
+
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", IntercomClientDisconnectedError, IntercomBrokerTimeoutError, BROKER_RETIRING_CODE = "broker_retiring", BROKER_RETIRING_REASON = "Intercom broker is retiring; connect to its replacement", IntercomBrokerRetiringError;
|
|
62107
62536
|
var init_recoverable_disconnect = __esm(() => {
|
|
62108
62537
|
init_live_route_refusal();
|
|
62109
62538
|
IntercomClientDisconnectedError = class IntercomClientDisconnectedError extends Error {
|
|
@@ -62120,8 +62549,46 @@ var init_recoverable_disconnect = __esm(() => {
|
|
|
62120
62549
|
this.name = "IntercomBrokerTimeoutError";
|
|
62121
62550
|
}
|
|
62122
62551
|
};
|
|
62552
|
+
IntercomBrokerRetiringError = class IntercomBrokerRetiringError extends Error {
|
|
62553
|
+
intercomRecoverableDisconnect = true;
|
|
62554
|
+
constructor(message = BROKER_RETIRING_REASON, options) {
|
|
62555
|
+
super(message, options);
|
|
62556
|
+
this.name = "IntercomBrokerRetiringError";
|
|
62557
|
+
}
|
|
62558
|
+
};
|
|
62123
62559
|
});
|
|
62124
62560
|
|
|
62561
|
+
// dist/builtin/intercom/broker/socket-liveness.ts
|
|
62562
|
+
import net from "net";
|
|
62563
|
+
function isSocketAnswering(socketPath, timeoutMs = SOCKET_PROBE_TIMEOUT_MS) {
|
|
62564
|
+
return new Promise((resolve) => {
|
|
62565
|
+
const socket = net.connect(socketPath);
|
|
62566
|
+
const finish = (isConnected) => {
|
|
62567
|
+
clearTimeout(timeout);
|
|
62568
|
+
socket.off("connect", onConnect);
|
|
62569
|
+
socket.off("error", onError);
|
|
62570
|
+
resolve(isConnected);
|
|
62571
|
+
};
|
|
62572
|
+
const onConnect = () => {
|
|
62573
|
+
socket.on("error", () => {});
|
|
62574
|
+
socket.end();
|
|
62575
|
+
finish(true);
|
|
62576
|
+
};
|
|
62577
|
+
const onError = () => {
|
|
62578
|
+
socket.destroy();
|
|
62579
|
+
finish(false);
|
|
62580
|
+
};
|
|
62581
|
+
socket.on("connect", onConnect);
|
|
62582
|
+
socket.on("error", onError);
|
|
62583
|
+
const timeout = setTimeout(() => {
|
|
62584
|
+
socket.destroy();
|
|
62585
|
+
finish(false);
|
|
62586
|
+
}, timeoutMs);
|
|
62587
|
+
});
|
|
62588
|
+
}
|
|
62589
|
+
var SOCKET_PROBE_TIMEOUT_MS = 1000;
|
|
62590
|
+
var init_socket_liveness = () => {};
|
|
62591
|
+
|
|
62125
62592
|
// dist/builtin/intercom/retry-policy.ts
|
|
62126
62593
|
var ASK_REPLY_TIMEOUT_MS, RETRY_IDENTITY_RETRY_OPPORTUNITY_MS, RETRY_IDENTITY_TTL_MS, DELIVERED_MESSAGE_TTL_MS, SEND_RESPONSE_TIMEOUT_MS = 1e4, RECIPIENT_RECEIPT_TIMEOUT_MS = 8000, RECIPIENT_SAVING_REPORT_INTERVAL_MS;
|
|
62127
62594
|
var init_retry_policy = __esm(() => {
|
|
@@ -62134,8 +62601,8 @@ var init_retry_policy = __esm(() => {
|
|
|
62134
62601
|
|
|
62135
62602
|
// dist/builtin/intercom/broker/client.ts
|
|
62136
62603
|
import { EventEmitter } from "events";
|
|
62137
|
-
import
|
|
62138
|
-
import { randomUUID as
|
|
62604
|
+
import net2 from "net";
|
|
62605
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
62139
62606
|
function connectAborted() {
|
|
62140
62607
|
return new IntercomClientDisconnectedError({ cause: new Error("Disconnected before the broker connection registered") });
|
|
62141
62608
|
}
|
|
@@ -62159,6 +62626,19 @@ function isBacklogRefusal(error) {
|
|
|
62159
62626
|
const code = error.code;
|
|
62160
62627
|
return code === "ECONNREFUSED" || code === "EAGAIN";
|
|
62161
62628
|
}
|
|
62629
|
+
function isLostBrokerSignature(error) {
|
|
62630
|
+
if (error instanceof ConnectionClosedBeforeRegistrationError)
|
|
62631
|
+
return true;
|
|
62632
|
+
const code = error.code;
|
|
62633
|
+
return code === "ENOENT" || code === "ECONNRESET" || code === "EPIPE";
|
|
62634
|
+
}
|
|
62635
|
+
async function classifyRegistrationFailure(error) {
|
|
62636
|
+
if (!isLostBrokerSignature(error) || await isSocketAnswering(BROKER_SOCKET))
|
|
62637
|
+
return error;
|
|
62638
|
+
return new IntercomBrokerRetiringError(`Intercom broker went away before it registered this session: ${error.message}`, {
|
|
62639
|
+
cause: error
|
|
62640
|
+
});
|
|
62641
|
+
}
|
|
62162
62642
|
function toError(error) {
|
|
62163
62643
|
return error instanceof Error ? error : new Error(String(error));
|
|
62164
62644
|
}
|
|
@@ -62168,15 +62648,22 @@ function isWorkflowFutureStageRosterEntries(value2) {
|
|
|
62168
62648
|
function isWorkflowStageRosterEntries(value2) {
|
|
62169
62649
|
return Array.isArray(value2) && value2.every((entry) => typeof entry === "object" && entry !== null && entry.kind === "workflow-stage" && typeof entry.runId === "string" && typeof entry.stageId === "string" && typeof entry.stageName === "string" && typeof entry.target === "string" && (entry.lifecycle === "pending" || entry.lifecycle === "running") && typeof entry.group === "string" && (entry.sessionId === undefined || typeof entry.sessionId === "string"));
|
|
62170
62650
|
}
|
|
62171
|
-
var BROKER_SOCKET, BROKER_CONNECT_TIMEOUT_MS = 1e4, PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS = 1e4, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000, BROKER_BACKLOG_RETRIES = 6, BROKER_BACKLOG_RETRY_BASE_MS = 25, HELD_SEND_GRACE_MS = 5000, IntercomPendingStageRouteRefusedError, PENDING_STAGE_ROUTE_REFUSAL_CODES, IntercomClient;
|
|
62651
|
+
var BROKER_SOCKET, BROKER_CONNECT_TIMEOUT_MS = 1e4, PENDING_STAGE_ROUTE_ACK_TIMEOUT_MS = 1e4, GROUP_REQUEST_TIMEOUT_MS = 5000, PRESENCE_ACK_TIMEOUT_MS = 5000, RESTORING_RECIPIENT_REQUEST_TIMEOUT_MS = 5000, BROKER_BACKLOG_RETRIES = 6, BROKER_BACKLOG_RETRY_BASE_MS = 25, ConnectionClosedBeforeRegistrationError, HELD_SEND_GRACE_MS = 5000, IntercomPendingStageRouteRefusedError, PENDING_STAGE_ROUTE_REFUSAL_CODES, IntercomClient;
|
|
62172
62652
|
var init_client = __esm(() => {
|
|
62173
62653
|
init_paths();
|
|
62174
62654
|
init_pending_send_registry();
|
|
62175
62655
|
init_group();
|
|
62176
62656
|
init_recoverable_disconnect();
|
|
62657
|
+
init_socket_liveness();
|
|
62177
62658
|
init_live_route_refusal();
|
|
62178
62659
|
init_retry_policy();
|
|
62179
62660
|
BROKER_SOCKET = getBrokerSocketPath();
|
|
62661
|
+
ConnectionClosedBeforeRegistrationError = class ConnectionClosedBeforeRegistrationError extends Error {
|
|
62662
|
+
constructor() {
|
|
62663
|
+
super("Connection closed before registration");
|
|
62664
|
+
this.name = "ConnectionClosedBeforeRegistrationError";
|
|
62665
|
+
}
|
|
62666
|
+
};
|
|
62180
62667
|
IntercomPendingStageRouteRefusedError = class IntercomPendingStageRouteRefusedError extends Error {
|
|
62181
62668
|
connectionKept;
|
|
62182
62669
|
code;
|
|
@@ -62230,7 +62717,7 @@ var init_client = __esm(() => {
|
|
|
62230
62717
|
if (this.socket !== socket || socket.destroyed)
|
|
62231
62718
|
return this.disconnectError ?? new IntercomClientDisconnectedError;
|
|
62232
62719
|
if (this.healthCheck?.socket !== socket) {
|
|
62233
|
-
const requestId =
|
|
62720
|
+
const requestId = randomUUID14();
|
|
62234
62721
|
const result = new Promise((resolve) => {
|
|
62235
62722
|
const finish = (failure) => {
|
|
62236
62723
|
clearTimeout(timer);
|
|
@@ -62262,7 +62749,7 @@ var init_client = __esm(() => {
|
|
|
62262
62749
|
}
|
|
62263
62750
|
return reported;
|
|
62264
62751
|
}
|
|
62265
|
-
constructor(returnAddress =
|
|
62752
|
+
constructor(returnAddress = randomUUID14(), options = {}) {
|
|
62266
62753
|
super();
|
|
62267
62754
|
if (returnAddress.length === 0)
|
|
62268
62755
|
throw new Error("Intercom return address must not be empty");
|
|
@@ -62344,8 +62831,14 @@ var init_client = __esm(() => {
|
|
|
62344
62831
|
} catch (error) {
|
|
62345
62832
|
if (attempt.signal.aborted)
|
|
62346
62833
|
throw connectAborted();
|
|
62347
|
-
if (!(error instanceof Error)
|
|
62834
|
+
if (!(error instanceof Error))
|
|
62348
62835
|
throw error;
|
|
62836
|
+
if (!isBacklogRefusal(error) || retry >= BROKER_BACKLOG_RETRIES) {
|
|
62837
|
+
const classified = await classifyRegistrationFailure(error);
|
|
62838
|
+
if (attempt.signal.aborted)
|
|
62839
|
+
throw connectAborted();
|
|
62840
|
+
throw classified;
|
|
62841
|
+
}
|
|
62349
62842
|
const backoff = BROKER_BACKLOG_RETRY_BASE_MS * 2 ** retry;
|
|
62350
62843
|
await abortableDelay(backoff * (0.5 + Math.random() / 2), attempt.signal);
|
|
62351
62844
|
}
|
|
@@ -62362,7 +62855,7 @@ var init_client = __esm(() => {
|
|
|
62362
62855
|
this._messageSource = messageSource ?? readSubagentMessageSource();
|
|
62363
62856
|
this._groups = normalizeGroups(session.groups, session.group);
|
|
62364
62857
|
return new Promise((resolve, reject) => {
|
|
62365
|
-
const socket =
|
|
62858
|
+
const socket = net2.connect(BROKER_SOCKET);
|
|
62366
62859
|
this.socket = socket;
|
|
62367
62860
|
this.disconnectError = null;
|
|
62368
62861
|
let settled = false;
|
|
@@ -62420,7 +62913,7 @@ var init_client = __esm(() => {
|
|
|
62420
62913
|
this.emit("disconnected", disconnectError);
|
|
62421
62914
|
}
|
|
62422
62915
|
if (wasConnecting) {
|
|
62423
|
-
reject(new
|
|
62916
|
+
reject(new ConnectionClosedBeforeRegistrationError);
|
|
62424
62917
|
}
|
|
62425
62918
|
};
|
|
62426
62919
|
const onSocketError = (err) => {
|
|
@@ -62522,7 +63015,7 @@ var init_client = __esm(() => {
|
|
|
62522
63015
|
case "registration_failed": {
|
|
62523
63016
|
if (typeof brokerMessage.reason !== "string")
|
|
62524
63017
|
throw new Error("Invalid registration_failed message");
|
|
62525
|
-
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
63018
|
+
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : brokerMessage.code === BROKER_RETIRING_CODE ? new IntercomBrokerRetiringError(brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
62526
63019
|
if (this._sessionId === null) {
|
|
62527
63020
|
this.emit("_registration_failed", refusal);
|
|
62528
63021
|
break;
|
|
@@ -62917,7 +63410,7 @@ var init_client = __esm(() => {
|
|
|
62917
63410
|
return Promise.reject(toError(error));
|
|
62918
63411
|
}
|
|
62919
63412
|
return new Promise((resolve, reject) => {
|
|
62920
|
-
const requestId =
|
|
63413
|
+
const requestId = randomUUID14();
|
|
62921
63414
|
const timeout = setTimeout(() => {
|
|
62922
63415
|
if (!this.pendingLists.delete(requestId))
|
|
62923
63416
|
return;
|
|
@@ -62949,7 +63442,7 @@ var init_client = __esm(() => {
|
|
|
62949
63442
|
} catch (error) {
|
|
62950
63443
|
return Promise.reject(toError(error));
|
|
62951
63444
|
}
|
|
62952
|
-
const requestId =
|
|
63445
|
+
const requestId = randomUUID14();
|
|
62953
63446
|
return new Promise((resolve, reject) => {
|
|
62954
63447
|
const timeout = setTimeout(() => {
|
|
62955
63448
|
if (!this.pendingGroupLists.delete(requestId))
|
|
@@ -62984,7 +63477,7 @@ var init_client = __esm(() => {
|
|
|
62984
63477
|
}
|
|
62985
63478
|
if (!this.brokerAnswersStatus)
|
|
62986
63479
|
return Promise.resolve(undefined);
|
|
62987
|
-
const requestId =
|
|
63480
|
+
const requestId = randomUUID14();
|
|
62988
63481
|
return new Promise((resolve, reject) => {
|
|
62989
63482
|
const timeout = setTimeout(() => {
|
|
62990
63483
|
if (!this.pendingBrokerStatus.delete(requestId))
|
|
@@ -63023,7 +63516,7 @@ var init_client = __esm(() => {
|
|
|
63023
63516
|
} catch (error) {
|
|
63024
63517
|
return Promise.reject(toError(error));
|
|
63025
63518
|
}
|
|
63026
|
-
const requestId =
|
|
63519
|
+
const requestId = randomUUID14();
|
|
63027
63520
|
return new Promise((resolve, reject) => {
|
|
63028
63521
|
const timeout = setTimeout(() => {
|
|
63029
63522
|
if (!this.pendingMemberships.delete(requestId))
|
|
@@ -63060,7 +63553,7 @@ var init_client = __esm(() => {
|
|
|
63060
63553
|
if (!normalizedChildName)
|
|
63061
63554
|
return Promise.reject(new Error("Child session name is required"));
|
|
63062
63555
|
return new Promise((resolve, reject) => {
|
|
63063
|
-
const requestId =
|
|
63556
|
+
const requestId = randomUUID14();
|
|
63064
63557
|
const timeout = setTimeout(() => {
|
|
63065
63558
|
if (!this.pendingSupervisorAuthorizations.delete(requestId))
|
|
63066
63559
|
return;
|
|
@@ -63110,7 +63603,7 @@ var init_client = __esm(() => {
|
|
|
63110
63603
|
} catch (error) {
|
|
63111
63604
|
return Promise.reject(toError(error));
|
|
63112
63605
|
}
|
|
63113
|
-
const requestId =
|
|
63606
|
+
const requestId = randomUUID14();
|
|
63114
63607
|
return new Promise((resolve, reject) => {
|
|
63115
63608
|
const timeout = setTimeout(() => {
|
|
63116
63609
|
if (!this.pendingRestoringRecipientRequests.delete(requestId))
|
|
@@ -63167,7 +63660,7 @@ var init_client = __esm(() => {
|
|
|
63167
63660
|
});
|
|
63168
63661
|
}
|
|
63169
63662
|
return new Promise((resolve, reject) => {
|
|
63170
|
-
const requestId =
|
|
63663
|
+
const requestId = randomUUID14();
|
|
63171
63664
|
const timeout = setTimeout(() => {
|
|
63172
63665
|
if (!this.pendingStageRouteRegistrations.delete(requestId))
|
|
63173
63666
|
return;
|
|
@@ -63213,7 +63706,7 @@ var init_client = __esm(() => {
|
|
|
63213
63706
|
}
|
|
63214
63707
|
if (!this.brokerClaimsWorkflowInvocations)
|
|
63215
63708
|
return Promise.resolve(false);
|
|
63216
|
-
const requestId =
|
|
63709
|
+
const requestId = randomUUID14();
|
|
63217
63710
|
return new Promise((resolve, reject) => {
|
|
63218
63711
|
this.pendingWorkflowInvocationClaims.set(requestId, { resolve, reject });
|
|
63219
63712
|
try {
|
|
@@ -63231,7 +63724,7 @@ var init_client = __esm(() => {
|
|
|
63231
63724
|
} catch (error) {
|
|
63232
63725
|
return Promise.reject(toError(error));
|
|
63233
63726
|
}
|
|
63234
|
-
const requestId =
|
|
63727
|
+
const requestId = randomUUID14();
|
|
63235
63728
|
return new Promise((resolve, reject) => {
|
|
63236
63729
|
this.pendingLiveWorkflowStageRoutes.set(requestId, { resolve, reject });
|
|
63237
63730
|
try {
|
|
@@ -63299,7 +63792,7 @@ var init_client = __esm(() => {
|
|
|
63299
63792
|
} catch (error) {
|
|
63300
63793
|
return Promise.reject(toError(error));
|
|
63301
63794
|
}
|
|
63302
|
-
const messageId = options.messageId ??
|
|
63795
|
+
const messageId = options.messageId ?? randomUUID14();
|
|
63303
63796
|
let acquired;
|
|
63304
63797
|
try {
|
|
63305
63798
|
const pendingSignature = JSON.stringify({
|
|
@@ -63385,7 +63878,7 @@ var init_client = __esm(() => {
|
|
|
63385
63878
|
} catch (error) {
|
|
63386
63879
|
return Promise.reject(toError(error));
|
|
63387
63880
|
}
|
|
63388
|
-
const requestId =
|
|
63881
|
+
const requestId = randomUUID14();
|
|
63389
63882
|
return new Promise((resolve, reject) => {
|
|
63390
63883
|
const wrappedResolve = (group) => {
|
|
63391
63884
|
clearTimeout(timeout);
|
|
@@ -63417,59 +63910,53 @@ var init_client = __esm(() => {
|
|
|
63417
63910
|
};
|
|
63418
63911
|
});
|
|
63419
63912
|
|
|
63420
|
-
// dist/builtin/intercom/broker/
|
|
63421
|
-
|
|
63422
|
-
|
|
63423
|
-
|
|
63424
|
-
|
|
63425
|
-
|
|
63426
|
-
|
|
63427
|
-
|
|
63428
|
-
|
|
63429
|
-
|
|
63430
|
-
|
|
63431
|
-
|
|
63432
|
-
|
|
63433
|
-
|
|
63434
|
-
|
|
63435
|
-
|
|
63436
|
-
|
|
63437
|
-
|
|
63438
|
-
|
|
63439
|
-
|
|
63440
|
-
socket.on("connect", onConnect);
|
|
63441
|
-
socket.on("error", onError);
|
|
63442
|
-
const timeout = setTimeout(() => {
|
|
63443
|
-
socket.destroy();
|
|
63444
|
-
finish(false);
|
|
63445
|
-
}, timeoutMs);
|
|
63446
|
-
});
|
|
63913
|
+
// dist/builtin/intercom/broker/startup-timeout.ts
|
|
63914
|
+
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
63915
|
+
|
|
63916
|
+
// dist/builtin/intercom/broker/start-announcement.ts
|
|
63917
|
+
import { readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
63918
|
+
function readBrokerStartAnnouncement(announcement) {
|
|
63919
|
+
let text;
|
|
63920
|
+
try {
|
|
63921
|
+
text = readFileSync4(announcement.path, "utf-8");
|
|
63922
|
+
} catch {
|
|
63923
|
+
return;
|
|
63924
|
+
}
|
|
63925
|
+
if (!text.endsWith(`
|
|
63926
|
+
`))
|
|
63927
|
+
return;
|
|
63928
|
+
const [token, pid, ...rest] = text.trim().split(/\s+/u);
|
|
63929
|
+
if (token !== announcement.token || rest.length > 0)
|
|
63930
|
+
return;
|
|
63931
|
+
const parsed = Number(pid);
|
|
63932
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
63447
63933
|
}
|
|
63448
|
-
var
|
|
63449
|
-
var
|
|
63934
|
+
var BROKER_ANNOUNCE_PATH_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_PATH", BROKER_ANNOUNCE_TOKEN_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_TOKEN";
|
|
63935
|
+
var init_start_announcement = () => {};
|
|
63450
63936
|
|
|
63451
63937
|
// dist/builtin/intercom/broker/spawn.ts
|
|
63452
63938
|
import { spawn } from "child_process";
|
|
63453
|
-
import {
|
|
63454
|
-
import {
|
|
63939
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
63940
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync8, openSync as openSync3, readFileSync as readFileSync5, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
63941
|
+
import { join as join28, dirname as dirname12 } from "path";
|
|
63455
63942
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
63456
63943
|
import { createRequire as createRequire3 } from "module";
|
|
63457
63944
|
import { createChildProcessEnvironment as createChildProcessEnvironment4, isBunBinary, processSharedStorageSelection } from "@bastani/atomic";
|
|
63458
63945
|
function isIntercomPackageRoot(dir) {
|
|
63459
|
-
return
|
|
63946
|
+
return existsSync6(join28(dir, "package.json")) && existsSync6(join28(dir, "broker"));
|
|
63460
63947
|
}
|
|
63461
63948
|
function resolveIntercomPackageRoot(moduleHref) {
|
|
63462
|
-
const here =
|
|
63949
|
+
const here = dirname12(fileURLToPath4(moduleHref));
|
|
63463
63950
|
if (isIntercomPackageRoot(here))
|
|
63464
63951
|
return here;
|
|
63465
|
-
return
|
|
63952
|
+
return join28(here, "..");
|
|
63466
63953
|
}
|
|
63467
63954
|
function resolveBrokerEntrypoint(packageRoot) {
|
|
63468
|
-
const bundled =
|
|
63469
|
-
return
|
|
63955
|
+
const bundled = join28(packageRoot, "broker", "broker.bundle.mjs");
|
|
63956
|
+
return existsSync6(bundled) ? bundled : join28(packageRoot, "broker", "broker.ts");
|
|
63470
63957
|
}
|
|
63471
63958
|
function ensurePrivateDirectory(path) {
|
|
63472
|
-
|
|
63959
|
+
mkdirSync8(path, { recursive: true, mode: 448 });
|
|
63473
63960
|
if (process.platform !== "win32")
|
|
63474
63961
|
chmodSync(path, 448);
|
|
63475
63962
|
}
|
|
@@ -63482,14 +63969,14 @@ function getCurrentBrokerRuntime() {
|
|
|
63482
63969
|
return isBunBinary ? "bun-binary" : "bun-source";
|
|
63483
63970
|
}
|
|
63484
63971
|
function requireFromExtensionDir(extensionDir) {
|
|
63485
|
-
return createRequire3(
|
|
63972
|
+
return createRequire3(join28(extensionDir, "package.json"));
|
|
63486
63973
|
}
|
|
63487
63974
|
function getJitiCliPath(extensionDir = EXTENSION_DIR) {
|
|
63488
63975
|
try {
|
|
63489
63976
|
const jitiPackage = requireFromExtensionDir(extensionDir).resolve("jiti/package.json");
|
|
63490
|
-
return
|
|
63977
|
+
return join28(dirname12(jitiPackage), "lib", "jiti-cli.mjs");
|
|
63491
63978
|
} catch {
|
|
63492
|
-
return
|
|
63979
|
+
return join28(extensionDir, "node_modules", "jiti", "lib", "jiti-cli.mjs");
|
|
63493
63980
|
}
|
|
63494
63981
|
}
|
|
63495
63982
|
function getDefaultBrokerRunnerPath(extensionDir) {
|
|
@@ -63511,7 +63998,7 @@ function quoteWindowsArg(value2) {
|
|
|
63511
63998
|
return `"${value2.replace(/"/g, '""')}"`;
|
|
63512
63999
|
}
|
|
63513
64000
|
function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
|
|
63514
|
-
return
|
|
64001
|
+
return join28(intercomDir, "broker-launch.vbs");
|
|
63515
64002
|
}
|
|
63516
64003
|
function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
|
|
63517
64004
|
return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
|
|
@@ -63538,8 +64025,8 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
63538
64025
|
`);
|
|
63539
64026
|
}
|
|
63540
64027
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
63541
|
-
ensurePrivateDirectory(
|
|
63542
|
-
|
|
64028
|
+
ensurePrivateDirectory(dirname12(launcherPath));
|
|
64029
|
+
writeFileSync6(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
63543
64030
|
return launcherPath;
|
|
63544
64031
|
}
|
|
63545
64032
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -63567,7 +64054,7 @@ function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir
|
|
|
63567
64054
|
args: [...brokerArgs, brokerPath]
|
|
63568
64055
|
};
|
|
63569
64056
|
}
|
|
63570
|
-
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore") {
|
|
64057
|
+
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore", announcement) {
|
|
63571
64058
|
const storage = processSharedStorageSelection();
|
|
63572
64059
|
return {
|
|
63573
64060
|
detached: true,
|
|
@@ -63575,20 +64062,21 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore")
|
|
|
63575
64062
|
cwd: extensionDir,
|
|
63576
64063
|
env: createChildProcessEnvironment4({
|
|
63577
64064
|
NODE_NO_WARNINGS: "1",
|
|
63578
|
-
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage }
|
|
64065
|
+
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage },
|
|
64066
|
+
...announcement === undefined ? {} : { [BROKER_ANNOUNCE_PATH_ENV]: announcement.path, [BROKER_ANNOUNCE_TOKEN_ENV]: announcement.token }
|
|
63579
64067
|
}),
|
|
63580
64068
|
windowsHide: true
|
|
63581
64069
|
};
|
|
63582
64070
|
}
|
|
63583
64071
|
function resetBrokerLog(logPath = BROKER_LOG) {
|
|
63584
|
-
ensurePrivateDirectory(
|
|
64072
|
+
ensurePrivateDirectory(dirname12(logPath));
|
|
63585
64073
|
try {
|
|
63586
64074
|
const previous = readBrokerLogTail(logPath);
|
|
63587
64075
|
closeSync3(openSync3(logPath, "w"));
|
|
63588
64076
|
if (previous.length > 0) {
|
|
63589
64077
|
try {
|
|
63590
64078
|
const previousPath = `${logPath}.previous`;
|
|
63591
|
-
|
|
64079
|
+
writeFileSync6(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
63592
64080
|
if (process.platform !== "win32")
|
|
63593
64081
|
chmodSync(previousPath, 384);
|
|
63594
64082
|
} catch {}
|
|
@@ -63650,6 +64138,12 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
63650
64138
|
}
|
|
63651
64139
|
const brokerPath = resolveBrokerEntrypoint(extensionDir);
|
|
63652
64140
|
const launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir);
|
|
64141
|
+
const announcement = launch.kind === "windows-launcher" ? { path: BROKER_START_ANNOUNCEMENT, token: randomUUID15() } : undefined;
|
|
64142
|
+
if (announcement !== undefined) {
|
|
64143
|
+
try {
|
|
64144
|
+
unlinkSync4(announcement.path);
|
|
64145
|
+
} catch {}
|
|
64146
|
+
}
|
|
63653
64147
|
if (launch.kind === "windows-launcher") {
|
|
63654
64148
|
writeWindowsHiddenLauncher(launch.launcherCommandLine, launch.launcherPath);
|
|
63655
64149
|
}
|
|
@@ -63660,7 +64154,7 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
63660
64154
|
const logFd = launch.kind === "direct" ? openSync3(BROKER_LOG, "a") : undefined;
|
|
63661
64155
|
let child;
|
|
63662
64156
|
try {
|
|
63663
|
-
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore"));
|
|
64157
|
+
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore", announcement));
|
|
63664
64158
|
} finally {
|
|
63665
64159
|
if (logFd !== undefined)
|
|
63666
64160
|
closeSync3(logFd);
|
|
@@ -63696,7 +64190,7 @@ ${describeBrokerLog()}`);
|
|
|
63696
64190
|
};
|
|
63697
64191
|
child.once("error", onError);
|
|
63698
64192
|
child.once("exit", onExit);
|
|
63699
|
-
waitForBroker(readyTimeoutMs).then(() => {
|
|
64193
|
+
waitForBroker(readyTimeoutMs, announcement === undefined ? undefined : () => readBrokerStartAnnouncement(announcement)).then(() => {
|
|
63700
64194
|
cleanup();
|
|
63701
64195
|
resolve();
|
|
63702
64196
|
}, (error) => {
|
|
@@ -63714,10 +64208,10 @@ async function isBrokerRunning() {
|
|
|
63714
64208
|
if (await checkSocketConnectable()) {
|
|
63715
64209
|
return true;
|
|
63716
64210
|
}
|
|
63717
|
-
if (!
|
|
64211
|
+
if (!existsSync6(BROKER_PID))
|
|
63718
64212
|
return false;
|
|
63719
64213
|
try {
|
|
63720
|
-
const pid = parseInt(
|
|
64214
|
+
const pid = parseInt(readFileSync5(BROKER_PID, "utf-8").trim(), 10);
|
|
63721
64215
|
if (!Number.isFinite(pid))
|
|
63722
64216
|
return false;
|
|
63723
64217
|
process.kill(pid, 0);
|
|
@@ -63742,7 +64236,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
63742
64236
|
}
|
|
63743
64237
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
63744
64238
|
try {
|
|
63745
|
-
return
|
|
64239
|
+
return readFileSync5(lockPath, "utf-8").startsWith(owner);
|
|
63746
64240
|
} catch {
|
|
63747
64241
|
return false;
|
|
63748
64242
|
}
|
|
@@ -63754,7 +64248,7 @@ function acquireSpawnLock() {
|
|
|
63754
64248
|
${Date.now()}
|
|
63755
64249
|
`;
|
|
63756
64250
|
try {
|
|
63757
|
-
|
|
64251
|
+
writeFileSync6(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
63758
64252
|
return owner;
|
|
63759
64253
|
} catch (error) {
|
|
63760
64254
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -63762,7 +64256,7 @@ ${Date.now()}
|
|
|
63762
64256
|
}
|
|
63763
64257
|
if (isSpawnLockStale()) {
|
|
63764
64258
|
try {
|
|
63765
|
-
|
|
64259
|
+
unlinkSync4(BROKER_SPAWN_LOCK);
|
|
63766
64260
|
} catch {}
|
|
63767
64261
|
continue;
|
|
63768
64262
|
}
|
|
@@ -63780,11 +64274,11 @@ function isProcessAlive(pid) {
|
|
|
63780
64274
|
}
|
|
63781
64275
|
}
|
|
63782
64276
|
function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
63783
|
-
if (!
|
|
64277
|
+
if (!existsSync6(lockPath)) {
|
|
63784
64278
|
return false;
|
|
63785
64279
|
}
|
|
63786
64280
|
try {
|
|
63787
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
64281
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync5(lockPath, "utf-8").trim().split(`
|
|
63788
64282
|
`);
|
|
63789
64283
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
63790
64284
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -63802,25 +64296,34 @@ function releaseSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
|
63802
64296
|
if (!ownsSpawnLock(owner, lockPath))
|
|
63803
64297
|
return;
|
|
63804
64298
|
try {
|
|
63805
|
-
|
|
64299
|
+
unlinkSync4(lockPath);
|
|
63806
64300
|
} catch {}
|
|
63807
64301
|
}
|
|
63808
|
-
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS) {
|
|
64302
|
+
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS, announcedPid) {
|
|
63809
64303
|
const start = Date.now();
|
|
63810
64304
|
let interval = BROKER_POLL_INITIAL_INTERVAL_MS;
|
|
63811
64305
|
while (Date.now() - start < timeoutMs) {
|
|
63812
64306
|
if (await checkSocketConnectable()) {
|
|
63813
64307
|
return;
|
|
63814
64308
|
}
|
|
64309
|
+
const pid = announcedPid?.();
|
|
64310
|
+
if (pid !== undefined && !isProcessAlive(pid)) {
|
|
64311
|
+
if (await checkSocketConnectable())
|
|
64312
|
+
return;
|
|
64313
|
+
throw new Error(`Intercom broker exited before startup (pid ${pid})
|
|
64314
|
+
${describeBrokerLog()}`);
|
|
64315
|
+
}
|
|
63815
64316
|
await sleep(interval);
|
|
63816
64317
|
interval = Math.min(interval * 2, BROKER_POLL_MAX_INTERVAL_MS);
|
|
63817
64318
|
}
|
|
63818
|
-
throw new Error(`Broker failed to start within timeout
|
|
64319
|
+
throw new Error(`Broker failed to start within timeout (${timeoutMs} ms)
|
|
64320
|
+
` + "The broker did not answer on its socket in time; it may still be starting, which a busy machine or an empty jiti " + "cache slows. Try again, or raise `brokerStartupTimeoutMs` in the Intercom config.json (default " + `${BROKER_READY_TIMEOUT_MS} ms).
|
|
63819
64321
|
${describeBrokerLog()}`);
|
|
63820
64322
|
}
|
|
63821
|
-
var INTERCOM_DIR, EXTENSION_DIR, BROKER_SOCKET2, BROKER_PID, BROKER_SPAWN_LOCK, BROKER_LOG, BROKER_LOG_TAIL_BYTES, BROKER_POLL_INITIAL_INTERVAL_MS = 10, BROKER_POLL_MAX_INTERVAL_MS = 100,
|
|
64323
|
+
var INTERCOM_DIR, EXTENSION_DIR, BROKER_SOCKET2, BROKER_PID, BROKER_SPAWN_LOCK, BROKER_LOG, BROKER_START_ANNOUNCEMENT, BROKER_LOG_TAIL_BYTES, BROKER_POLL_INITIAL_INTERVAL_MS = 10, BROKER_POLL_MAX_INTERVAL_MS = 100, BROKER_SPAWN_LOCK_MAX_AGE_MS = 60000, INTERNAL_INTERCOM_BROKER_ARG = "--atomic-internal-intercom-broker";
|
|
63822
64324
|
var init_spawn = __esm(() => {
|
|
63823
64325
|
init_socket_liveness();
|
|
64326
|
+
init_start_announcement();
|
|
63824
64327
|
init_paths();
|
|
63825
64328
|
INTERCOM_DIR = getIntercomDirPath();
|
|
63826
64329
|
EXTENSION_DIR = resolveIntercomPackageRoot(import.meta.url);
|
|
@@ -63828,6 +64331,7 @@ var init_spawn = __esm(() => {
|
|
|
63828
64331
|
BROKER_PID = getBrokerPidPath();
|
|
63829
64332
|
BROKER_SPAWN_LOCK = getBrokerSpawnLockPath();
|
|
63830
64333
|
BROKER_LOG = getBrokerLogPath();
|
|
64334
|
+
BROKER_START_ANNOUNCEMENT = getBrokerStartAnnouncementPath();
|
|
63831
64335
|
BROKER_LOG_TAIL_BYTES = 8 * 1024;
|
|
63832
64336
|
});
|
|
63833
64337
|
|
|
@@ -63852,14 +64356,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
63852
64356
|
});
|
|
63853
64357
|
|
|
63854
64358
|
// dist/builtin/intercom/config.ts
|
|
63855
|
-
import { existsSync as
|
|
64359
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
63856
64360
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
63857
64361
|
function loadConfig() {
|
|
63858
|
-
if (!
|
|
64362
|
+
if (!existsSync7(CONFIG_PATH)) {
|
|
63859
64363
|
return { ...defaults };
|
|
63860
64364
|
}
|
|
63861
64365
|
try {
|
|
63862
|
-
const raw =
|
|
64366
|
+
const raw = readFileSync6(CONFIG_PATH, "utf-8");
|
|
63863
64367
|
const parsed = JSON.parse(raw);
|
|
63864
64368
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
63865
64369
|
throw new Error("Config must be a JSON object");
|
|
@@ -63889,6 +64393,12 @@ function loadConfig() {
|
|
|
63889
64393
|
}
|
|
63890
64394
|
config.brokerArgs = brokerArgs;
|
|
63891
64395
|
}
|
|
64396
|
+
if (Object.hasOwn(parsedConfig, "brokerStartupTimeoutMs")) {
|
|
64397
|
+
if (!Number.isInteger(parsedConfig.brokerStartupTimeoutMs) || Number(parsedConfig.brokerStartupTimeoutMs) < MIN_BROKER_STARTUP_TIMEOUT_MS) {
|
|
64398
|
+
throw new Error(`"brokerStartupTimeoutMs" must be an integer of at least ${MIN_BROKER_STARTUP_TIMEOUT_MS}`);
|
|
64399
|
+
}
|
|
64400
|
+
config.brokerStartupTimeoutMs = Number(parsedConfig.brokerStartupTimeoutMs);
|
|
64401
|
+
}
|
|
63892
64402
|
if (Object.hasOwn(parsedConfig, "confirmSend")) {
|
|
63893
64403
|
if (typeof parsedConfig.confirmSend !== "boolean") {
|
|
63894
64404
|
throw new Error(`"confirmSend" must be a boolean`);
|
|
@@ -63931,11 +64441,12 @@ var init_config = __esm(() => {
|
|
|
63931
64441
|
init_diagnostics();
|
|
63932
64442
|
init_reply_waiter();
|
|
63933
64443
|
CONFIG_PATHS = getAgentConfigPaths("intercom", "config.json");
|
|
63934
|
-
CONFIG_PATH = CONFIG_PATHS.find((path) =>
|
|
64444
|
+
CONFIG_PATH = CONFIG_PATHS.find((path) => existsSync7(path)) ?? CONFIG_PATHS[0];
|
|
63935
64445
|
DEFAULT_BROKER_ARGS = ["--no-install", "tsx"];
|
|
63936
64446
|
defaults = {
|
|
63937
64447
|
brokerCommand: DEFAULT_BROKER_COMMAND,
|
|
63938
64448
|
brokerArgs: [...DEFAULT_BROKER_ARGS],
|
|
64449
|
+
brokerStartupTimeoutMs: BROKER_READY_TIMEOUT_MS,
|
|
63939
64450
|
confirmSend: false,
|
|
63940
64451
|
maxPendingAsks: DEFAULT_MAX_PENDING_REPLY_WAITS,
|
|
63941
64452
|
replyHint: true
|
|
@@ -63956,7 +64467,7 @@ var init_reconnect_backoff = __esm(() => {
|
|
|
63956
64467
|
});
|
|
63957
64468
|
|
|
63958
64469
|
// dist/builtin/intercom/workflow-route-owner.ts
|
|
63959
|
-
import { randomUUID as
|
|
64470
|
+
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
63960
64471
|
import { createEventBus, getBuiltinPackagePaths } from "@bastani/atomic";
|
|
63961
64472
|
function closedError() {
|
|
63962
64473
|
return new Error("Workflow Intercom route owner closed");
|
|
@@ -63964,7 +64475,7 @@ function closedError() {
|
|
|
63964
64475
|
function createWorkflowRouteOwner(cwd) {
|
|
63965
64476
|
const events = createEventBus();
|
|
63966
64477
|
const config = loadConfig();
|
|
63967
|
-
const id =
|
|
64478
|
+
const id = randomUUID16();
|
|
63968
64479
|
const routes = new Map;
|
|
63969
64480
|
const connections = new Map;
|
|
63970
64481
|
const isCurrent = (state) => routes.get(state.route.runId) === state;
|
|
@@ -64028,7 +64539,7 @@ function createWorkflowRouteOwner(cwd) {
|
|
|
64028
64539
|
});
|
|
64029
64540
|
if (extensionDir === undefined)
|
|
64030
64541
|
throw new Error("Intercom builtin package is unavailable");
|
|
64031
|
-
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs,
|
|
64542
|
+
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs, config.brokerStartupTimeoutMs, extensionDir);
|
|
64032
64543
|
if (connections.get(connection.key) !== connection)
|
|
64033
64544
|
throw closedError();
|
|
64034
64545
|
const client = new IntercomClient(`${id}:pending-stage-route:${connection.key}`, {
|
|
@@ -64486,12 +64997,12 @@ var init_sql_pool_usage = __esm(() => {
|
|
|
64486
64997
|
|
|
64487
64998
|
// dist/builtin/workflows/src/workers/pooled-watch-trace.ts
|
|
64488
64999
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
64489
|
-
import { dirname as
|
|
65000
|
+
import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
|
|
64490
65001
|
function configurePooledWatchTrace(journalPath, processRole) {
|
|
64491
65002
|
if (setting === undefined || setting === "" || setting === "0")
|
|
64492
65003
|
return;
|
|
64493
65004
|
role = processRole;
|
|
64494
|
-
file = setting === "1" ?
|
|
65005
|
+
file = setting === "1" ? join29(dirname13(resolve12(journalPath)), "pooled-watch-trace.jsonl") : resolve12(setting);
|
|
64495
65006
|
}
|
|
64496
65007
|
function tracePooledWatch(step, detail) {
|
|
64497
65008
|
if (file === undefined)
|
|
@@ -64672,10 +65183,10 @@ var init_startup_timeout = () => {};
|
|
|
64672
65183
|
|
|
64673
65184
|
// dist/builtin/workflows/src/workers/pool-coordinator.ts
|
|
64674
65185
|
import { fork } from "node:child_process";
|
|
64675
|
-
import { randomUUID as
|
|
65186
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
64676
65187
|
import { createWriteStream } from "node:fs";
|
|
64677
65188
|
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
64678
|
-
import { dirname as
|
|
65189
|
+
import { dirname as dirname14, join as join30, resolve as resolve13 } from "node:path";
|
|
64679
65190
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
64680
65191
|
function isRootLeaseLost(error) {
|
|
64681
65192
|
return error instanceof StaleLeaseError || error.message.startsWith("Stale lease for run ");
|
|
@@ -64684,7 +65195,7 @@ function unconfirmedCleanup(groups) {
|
|
|
64684
65195
|
return new Error(`Local worker process cleanup unconfirmed; ${groups.length > 0 ? `process groups ${groups.join(", ")} still running after SIGKILL; ` : ""}permits quarantined`);
|
|
64685
65196
|
}
|
|
64686
65197
|
function workerLogDirectory(journalPath, root) {
|
|
64687
|
-
return
|
|
65198
|
+
return join30(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
64688
65199
|
}
|
|
64689
65200
|
function token(work) {
|
|
64690
65201
|
return {
|
|
@@ -64897,6 +65408,9 @@ class PoolCoordinator {
|
|
|
64897
65408
|
lease;
|
|
64898
65409
|
options;
|
|
64899
65410
|
journal;
|
|
65411
|
+
durable;
|
|
65412
|
+
remote;
|
|
65413
|
+
mirrorTimer;
|
|
64900
65414
|
queue;
|
|
64901
65415
|
usageLedger;
|
|
64902
65416
|
usageTotal;
|
|
@@ -64929,6 +65443,7 @@ class PoolCoordinator {
|
|
|
64929
65443
|
while (this.inflight.size > 0)
|
|
64930
65444
|
await Promise.allSettled([...this.inflight]);
|
|
64931
65445
|
await this.journal?.close().catch(() => {});
|
|
65446
|
+
await this.durable?.close().catch(() => {});
|
|
64932
65447
|
}
|
|
64933
65448
|
receive(message) {
|
|
64934
65449
|
if (message.kind === "request-reply") {
|
|
@@ -65018,11 +65533,21 @@ class PoolCoordinator {
|
|
|
65018
65533
|
this.desiredControl ??= control;
|
|
65019
65534
|
configurePooledWatchTrace(options.journalPath, "coordinator");
|
|
65020
65535
|
this.journal ??= await resolveRunJournal({ journal: { path: options.journalPath } });
|
|
65536
|
+
if (options.durable !== undefined && this.remote === undefined) {
|
|
65537
|
+
this.durable = await openDurableJournal(options.durable);
|
|
65538
|
+
this.remote = new PoolRemoteJournal(this.durable, sqlPoolStorage(this.journal));
|
|
65539
|
+
}
|
|
65540
|
+
await this.remote?.mirror(lease);
|
|
65021
65541
|
this.usageLedger ??= await openSqlPoolUsage(this.journal);
|
|
65022
65542
|
this.usageTotal = await this.usageLedger.total(root);
|
|
65023
65543
|
this.lease = lease;
|
|
65024
|
-
const queue = await openSqlPoolQueue(this.journal);
|
|
65544
|
+
const queue = await openSqlPoolQueue(this.journal, this.remote);
|
|
65025
65545
|
await queue.initialize(lease, COORDINATOR_LEASE_MS);
|
|
65546
|
+
await queue.drainOutbox(lease);
|
|
65547
|
+
if (this.remote !== undefined) {
|
|
65548
|
+
const remote = this.remote;
|
|
65549
|
+
this.mirrorTimer = setInterval(() => void remote.fresh(lease, 0).catch(() => {}), MIRROR_INTERVAL_MS).unref();
|
|
65550
|
+
}
|
|
65026
65551
|
const retained = [];
|
|
65027
65552
|
for (const work of await queue.inspect(root))
|
|
65028
65553
|
if (work.state === "leased" && work.epoch < lease.epoch && (await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
|
|
@@ -65155,7 +65680,7 @@ class PoolCoordinator {
|
|
|
65155
65680
|
throw new Error("Worker exited before delivery acknowledgement");
|
|
65156
65681
|
const { slot, workerRequest } = target;
|
|
65157
65682
|
await new Promise((resolve, reject) => {
|
|
65158
|
-
const id =
|
|
65683
|
+
const id = randomUUID17();
|
|
65159
65684
|
slot.deliveries.set(id, { resolve, reject });
|
|
65160
65685
|
slot.child.send({ id: workerRequest, delivery: { id, from: payload.from, message: payload.message } }, (error) => {
|
|
65161
65686
|
if (error) {
|
|
@@ -65496,18 +66021,22 @@ class PoolCoordinator {
|
|
|
65496
66021
|
admission: options.admission,
|
|
65497
66022
|
...this.promptNodes ? { promptNodes: true } : {}
|
|
65498
66023
|
})
|
|
65499
|
-
], {
|
|
66024
|
+
], {
|
|
66025
|
+
stdio: ["ignore", "ignore", "pipe", "ipc"],
|
|
66026
|
+
execArgv: [],
|
|
66027
|
+
...options.durable === undefined ? {} : { env: { ...process.env, [POOL_DURABLE_JOURNAL_ENV]: JSON.stringify(options.durable) } }
|
|
66028
|
+
});
|
|
65500
66029
|
const disconnected = new Promise((resolve) => child.once("disconnect", () => resolve()));
|
|
65501
66030
|
this.children.add(child);
|
|
65502
66031
|
if (child.pid !== undefined)
|
|
65503
66032
|
this.port.send({ kind: "spawned", pid: child.pid });
|
|
65504
|
-
const worker =
|
|
66033
|
+
const worker = randomUUID17();
|
|
65505
66034
|
this.incarnations.set(worker, child);
|
|
65506
66035
|
const slot = { worker, child, deliveries: new Map, runs: new Set, stageCommands: new Map };
|
|
65507
66036
|
this.slots.add(slot);
|
|
65508
66037
|
let ready = false;
|
|
65509
66038
|
let serial = Promise.resolve();
|
|
65510
|
-
const logPath =
|
|
66039
|
+
const logPath = join30(this.logDirectory, `${worker}.log`);
|
|
65511
66040
|
this.logs.set(child, logPath);
|
|
65512
66041
|
let logFailure;
|
|
65513
66042
|
const log = createWriteStream(logPath, { flags: "a" });
|
|
@@ -65902,6 +66431,7 @@ class PoolCoordinator {
|
|
|
65902
66431
|
this.closed = true;
|
|
65903
66432
|
clearInterval(this.ticker);
|
|
65904
66433
|
clearInterval(this.recoveryTimer);
|
|
66434
|
+
clearInterval(this.mirrorTimer);
|
|
65905
66435
|
this.rateLimitOutbox.close();
|
|
65906
66436
|
let failure;
|
|
65907
66437
|
let stopping = [];
|
|
@@ -65954,8 +66484,10 @@ function childRetryLimit(work, reason) {
|
|
|
65954
66484
|
const exportName = work.definition.slice(work.definition.lastIndexOf("#") + 1);
|
|
65955
66485
|
return `Local worker retry limit: child ${work.childRunId} (${exportName}) ${reason} ${MAX_CHILD_ATTEMPTS} times`;
|
|
65956
66486
|
}
|
|
65957
|
-
var CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
|
|
66487
|
+
var CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
|
|
65958
66488
|
var init_pool_coordinator = __esm(() => {
|
|
66489
|
+
init_internal();
|
|
66490
|
+
init_pool_remote_journal();
|
|
65959
66491
|
init_resolution();
|
|
65960
66492
|
init_workflows_host_module();
|
|
65961
66493
|
init_sql_pool_queue();
|
|
@@ -65966,6 +66498,7 @@ var init_pool_coordinator = __esm(() => {
|
|
|
65966
66498
|
init_pending_stage_route_capability();
|
|
65967
66499
|
init_pending_stage_route_readiness();
|
|
65968
66500
|
init_store();
|
|
66501
|
+
init_pool_journal();
|
|
65969
66502
|
init_pooled_watch_trace();
|
|
65970
66503
|
init_resource_admission();
|
|
65971
66504
|
init_stage_watch_coalesce();
|
|
@@ -66780,7 +67313,7 @@ class StageToolExecutionBuffer {
|
|
|
66780
67313
|
}
|
|
66781
67314
|
|
|
66782
67315
|
// dist/builtin/workflows/src/workers/pooled-stage-handle.ts
|
|
66783
|
-
import { randomUUID as
|
|
67316
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
66784
67317
|
|
|
66785
67318
|
class PooledStageHandle {
|
|
66786
67319
|
runId;
|
|
@@ -67098,7 +67631,7 @@ class PooledStageHandle {
|
|
|
67098
67631
|
return Promise.reject(new PooledStageDeliveryError("StageNotLive", this.stageName));
|
|
67099
67632
|
const outcome = Promise.withResolvers();
|
|
67100
67633
|
const entry = {
|
|
67101
|
-
op:
|
|
67634
|
+
op: randomUUID18(),
|
|
67102
67635
|
text,
|
|
67103
67636
|
intent,
|
|
67104
67637
|
...options === undefined ? {} : { options },
|
|
@@ -67556,8 +68089,8 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
67556
68089
|
|
|
67557
68090
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
67558
68091
|
import { fork as fork2 } from "node:child_process";
|
|
67559
|
-
import { randomUUID as
|
|
67560
|
-
import { resolve as
|
|
68092
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
68093
|
+
import { resolve as resolve14 } from "node:path";
|
|
67561
68094
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
67562
68095
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
67563
68096
|
import {
|
|
@@ -67741,8 +68274,7 @@ class LocalWorkerPool {
|
|
|
67741
68274
|
async prepare(root, store) {
|
|
67742
68275
|
if (this.closed)
|
|
67743
68276
|
throw new Error("Local worker pool is closed");
|
|
67744
|
-
|
|
67745
|
-
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68277
|
+
const poolJournal = await this.poolJournal();
|
|
67746
68278
|
if (this.root !== undefined && this.root !== root)
|
|
67747
68279
|
throw new Error("Local worker pool belongs to another root");
|
|
67748
68280
|
this.root = root;
|
|
@@ -67759,6 +68291,7 @@ class LocalWorkerPool {
|
|
|
67759
68291
|
lease: this.lease,
|
|
67760
68292
|
options: {
|
|
67761
68293
|
journalPath: this.options.journalPath,
|
|
68294
|
+
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
67762
68295
|
workers: this.options.workers,
|
|
67763
68296
|
leaseMs: this.leaseMs,
|
|
67764
68297
|
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
@@ -67767,7 +68300,20 @@ class LocalWorkerPool {
|
|
|
67767
68300
|
},
|
|
67768
68301
|
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
67769
68302
|
});
|
|
67770
|
-
this.queue ??= await openSqlPoolQueue(this.backend.journal);
|
|
68303
|
+
this.queue ??= await openSqlPoolQueue(poolJournal, this.options.durable === undefined ? undefined : new PoolRemoteJournal(this.backend.journal, sqlPoolStorage(poolJournal)));
|
|
68304
|
+
}
|
|
68305
|
+
async poolJournal() {
|
|
68306
|
+
const journal = this.backend.journal;
|
|
68307
|
+
if (this.options.durable === undefined) {
|
|
68308
|
+
if (!(journal instanceof SqlRunJournal) || resolve14(this.options.journalPath) !== resolve14(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
68309
|
+
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68310
|
+
return journal;
|
|
68311
|
+
}
|
|
68312
|
+
if (isLocalPoolJournal(journal))
|
|
68313
|
+
throw new Error("Local workers share a local SQLite journal as it is; a durable journal selection does not apply");
|
|
68314
|
+
const coordination = await openCoordinationJournal(this.options.journalPath);
|
|
68315
|
+
registerPoolJournal(journal, coordination);
|
|
68316
|
+
return coordination;
|
|
67771
68317
|
}
|
|
67772
68318
|
async control(state) {
|
|
67773
68319
|
this.desiredControl = state;
|
|
@@ -67850,7 +68396,7 @@ class LocalWorkerPool {
|
|
|
67850
68396
|
return { ok: false, refusal: "PoolClosed" };
|
|
67851
68397
|
if (this.coordinator === undefined)
|
|
67852
68398
|
return { ok: false, refusal: "StageNotOnWorker" };
|
|
67853
|
-
const watch =
|
|
68399
|
+
const watch = randomUUID19();
|
|
67854
68400
|
this.stageWatches.set(watch, listener);
|
|
67855
68401
|
try {
|
|
67856
68402
|
const result = await this.command({ kind: "stage-watch", watch, ...ref });
|
|
@@ -68734,6 +69280,7 @@ var RECONNECT_ATTEMPT_PUBLICATIONS = 40, INTERNAL_WORKFLOW_WORKER_ARG = "--inter
|
|
|
68734
69280
|
var init_local_pool = __esm(() => {
|
|
68735
69281
|
init_internal();
|
|
68736
69282
|
init_journal_backend();
|
|
69283
|
+
init_pool_remote_journal();
|
|
68737
69284
|
init_sql_pool_queue();
|
|
68738
69285
|
init_sql_run_journal();
|
|
68739
69286
|
init_workflow_tool_abort();
|
|
@@ -68748,6 +69295,7 @@ var init_local_pool = __esm(() => {
|
|
|
68748
69295
|
init_held_prompt_answers();
|
|
68749
69296
|
init_host_options();
|
|
68750
69297
|
init_pool_coordinator();
|
|
69298
|
+
init_pool_journal();
|
|
68751
69299
|
init_pooled_stage_sources();
|
|
68752
69300
|
init_pooled_watch_trace();
|
|
68753
69301
|
init_stage_handoff();
|
|
@@ -68757,7 +69305,7 @@ var init_local_pool = __esm(() => {
|
|
|
68757
69305
|
});
|
|
68758
69306
|
|
|
68759
69307
|
// dist/builtin/workflows/src/workers/public-pool.ts
|
|
68760
|
-
import { resolve as
|
|
69308
|
+
import { resolve as resolve15 } from "node:path";
|
|
68761
69309
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
68762
69310
|
async function restoreWorkerOptions(backend, options) {
|
|
68763
69311
|
const source = options.continuation?.source.id ?? options.runId;
|
|
@@ -68789,29 +69337,50 @@ async function activatePublicPool(backend, options) {
|
|
|
68789
69337
|
throw new Error("Local worker containment is unavailable on Windows; pooled tool processes cannot be enabled");
|
|
68790
69338
|
if (process.platform !== "linux" && process.platform !== "darwin" || !await hasNativeProcessIdentity() || !await admissionBootIdentity())
|
|
68791
69339
|
throw new Error("Local worker containment requires native process identity support");
|
|
68792
|
-
if (!(backend instanceof JournalDurableBackend)
|
|
68793
|
-
throw new Error("Local workers require a
|
|
69340
|
+
if (!(backend instanceof JournalDurableBackend))
|
|
69341
|
+
throw new Error("Local workers require a journal backend");
|
|
69342
|
+
const local = isLocalPoolJournal(backend.journal);
|
|
69343
|
+
let durable;
|
|
69344
|
+
let poolJournal = backend.journal;
|
|
69345
|
+
let poolPath = local ? backend.journal.path : "";
|
|
69346
|
+
if (!local) {
|
|
69347
|
+
durable = poolDurableJournal(backend.journal);
|
|
69348
|
+
poolPath = coordinationPath(durable);
|
|
69349
|
+
poolJournal = await openCoordinationJournal(poolPath);
|
|
69350
|
+
registerPoolJournal(backend.journal, poolJournal);
|
|
69351
|
+
}
|
|
68794
69352
|
const cwd = options.cwd ?? process.cwd();
|
|
68795
69353
|
const localWorkers = options.localWorkers && {
|
|
68796
69354
|
...options.localWorkers,
|
|
68797
69355
|
startupTimeoutMs: undefined,
|
|
68798
69356
|
leaseMs: undefined,
|
|
68799
|
-
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path:
|
|
69357
|
+
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve15(cwd, source.path) }))
|
|
68800
69358
|
};
|
|
68801
69359
|
const admission = options.admission && {
|
|
68802
69360
|
...options.admission,
|
|
68803
|
-
...options.admission.userDatabase ? { userDatabase:
|
|
69361
|
+
...options.admission.userDatabase ? { userDatabase: resolve15(cwd, options.admission.userDatabase) } : {}
|
|
68804
69362
|
};
|
|
69363
|
+
if (durable !== undefined && admission?.userLimits) {
|
|
69364
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve15(poolPath))
|
|
69365
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve15(poolPath)}, for a journal that is not a local SQLite file`);
|
|
69366
|
+
admission.userDatabase = resolve15(poolPath);
|
|
69367
|
+
}
|
|
68805
69368
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
68806
69369
|
const resources = JSON.parse(JSON.stringify({
|
|
68807
69370
|
...localWorkers ? { localWorkers, definitions: sources } : {},
|
|
68808
|
-
...admission ? { admission } : {}
|
|
69371
|
+
...admission ? { admission } : {},
|
|
69372
|
+
...durable !== undefined && localWorkers ? { coordinator: { host: poolHostId(durable.agentDir), database: coordinationDatabase(durable) } } : {}
|
|
68809
69373
|
}));
|
|
69374
|
+
const saved = options.effectiveResources?.coordinator;
|
|
69375
|
+
if (saved !== undefined && resources.coordinator !== undefined && saved.host !== resources.coordinator.host)
|
|
69376
|
+
throw new Error(`This root's local workers ran on another machine (${saved.host}). Their work queue and leases are in that machine's pool database, which this machine cannot see, and its workers may still be running children. Resume the root on that machine.`);
|
|
69377
|
+
if (saved !== undefined && resources.coordinator !== undefined && saved.host === resources.coordinator.host && saved.database !== resources.coordinator.database)
|
|
69378
|
+
throw new Error(`This root's local workers keep their work queue and leases in the pool database ${saved.database} on this machine, but the journal is now selected in a way that uses ${resources.coordinator.database}: its adapter, options, prefix or the agent directory changed. Resume the root with the journal selected as it was when the root started.`);
|
|
68810
69379
|
if (options.effectiveResources && !isDeepStrictEqual2(options.effectiveResources, resources))
|
|
68811
69380
|
throw new Error("Worker definition compatibility or immutable resource configuration changed");
|
|
68812
69381
|
options.effectiveResources = resources;
|
|
68813
69382
|
if (resources.admission)
|
|
68814
|
-
await SqlResourceAdmission.open(
|
|
69383
|
+
await SqlResourceAdmission.open(poolJournal, {
|
|
68815
69384
|
...resources.admission,
|
|
68816
69385
|
root: options.runId,
|
|
68817
69386
|
holder: "preflight"
|
|
@@ -68821,7 +69390,8 @@ async function activatePublicPool(backend, options) {
|
|
|
68821
69390
|
const definitions = await Promise.all((sources ?? []).map(async (source) => ({ ...source, definition: await loadWorkerDefinition(source) })));
|
|
68822
69391
|
const pool = new LocalWorkerPool(backend, {
|
|
68823
69392
|
rootId: options.runId,
|
|
68824
|
-
journalPath:
|
|
69393
|
+
journalPath: poolPath,
|
|
69394
|
+
...durable === undefined ? {} : { durable },
|
|
68825
69395
|
workers: localWorkers.count,
|
|
68826
69396
|
definitions,
|
|
68827
69397
|
admission: resources.admission ?? {},
|
|
@@ -68838,13 +69408,12 @@ async function activatePublicPool(backend, options) {
|
|
|
68838
69408
|
}
|
|
68839
69409
|
}
|
|
68840
69410
|
var init_public_pool = __esm(() => {
|
|
68841
|
-
init_internal();
|
|
68842
69411
|
init_journal_backend();
|
|
68843
|
-
init_sql_run_journal();
|
|
68844
69412
|
init_admission_host();
|
|
68845
69413
|
init_definitions();
|
|
68846
69414
|
init_host_options();
|
|
68847
69415
|
init_local_pool();
|
|
69416
|
+
init_pool_journal();
|
|
68848
69417
|
init_resource_admission();
|
|
68849
69418
|
});
|
|
68850
69419
|
|
|
@@ -69304,7 +69873,7 @@ var init_run_budget = __esm(() => {
|
|
|
69304
69873
|
});
|
|
69305
69874
|
|
|
69306
69875
|
// dist/builtin/workflows/src/engine/primitives/parallel.ts
|
|
69307
|
-
import { randomUUID as
|
|
69876
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
69308
69877
|
function createParallelPrimitive(input) {
|
|
69309
69878
|
return async (steps, options = {}) => {
|
|
69310
69879
|
input.runtime.exit.throwIfWorkflowExitSelected();
|
|
@@ -69312,7 +69881,7 @@ function createParallelPrimitive(input) {
|
|
|
69312
69881
|
const normalizedOptions = normalizeGroup(options);
|
|
69313
69882
|
const normalizedSteps = steps.map(normalizeGroup);
|
|
69314
69883
|
const needsAutoGroup = normalizedOptions.group === true || normalizedSteps.some((step) => step.group === true);
|
|
69315
|
-
const autoGroup = needsAutoGroup ?
|
|
69884
|
+
const autoGroup = needsAutoGroup ? randomUUID20() : undefined;
|
|
69316
69885
|
const resolveAutoGroup = (value2) => value2.group === true && autoGroup ? { ...value2, group: autoGroup } : value2;
|
|
69317
69886
|
const resolvedOptions = resolveAutoGroup(normalizedOptions);
|
|
69318
69887
|
const resolvedSteps = normalizedSteps.map(resolveAutoGroup);
|
|
@@ -70196,8 +70765,8 @@ function hasUsableContentBlock(block) {
|
|
|
70196
70765
|
}
|
|
70197
70766
|
|
|
70198
70767
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
70199
|
-
import { randomUUID as
|
|
70200
|
-
import { dirname as
|
|
70768
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
70769
|
+
import { dirname as dirname15, resolve as resolve16 } from "node:path";
|
|
70201
70770
|
import {
|
|
70202
70771
|
JsonlSessionStore,
|
|
70203
70772
|
resolveSessionStore,
|
|
@@ -70218,7 +70787,7 @@ async function stageSessionStore(options, defaultSessionDir) {
|
|
|
70218
70787
|
}
|
|
70219
70788
|
async function forkStageSession(store, sessionId, cwd, options, destination = store) {
|
|
70220
70789
|
const source = await store.load(sessionId);
|
|
70221
|
-
const id =
|
|
70790
|
+
const id = randomUUID21();
|
|
70222
70791
|
await destination.create({
|
|
70223
70792
|
id,
|
|
70224
70793
|
version: 4,
|
|
@@ -70233,11 +70802,11 @@ async function forkStageSession(store, sessionId, cwd, options, destination = st
|
|
|
70233
70802
|
async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
70234
70803
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
70235
70804
|
return;
|
|
70236
|
-
const location =
|
|
70237
|
-
const legacy = await JsonlSessionStore.open(
|
|
70805
|
+
const location = resolve16(sessionFile);
|
|
70806
|
+
const legacy = await JsonlSessionStore.open(dirname15(location), { exactDirectory: true, scanExisting: false });
|
|
70238
70807
|
try {
|
|
70239
70808
|
for await (const file of legacy.scanFiles()) {
|
|
70240
|
-
if (
|
|
70809
|
+
if (resolve16(file.location) !== location || file.header.id !== sessionId)
|
|
70241
70810
|
continue;
|
|
70242
70811
|
const snapshot = await file.read();
|
|
70243
70812
|
if (await store.readHeader(sessionId) === undefined)
|
|
@@ -70253,6 +70822,7 @@ var init_stage_session_store = () => {};
|
|
|
70253
70822
|
// dist/builtin/workflows/src/workers/pool-session-store.ts
|
|
70254
70823
|
var init_pool_session_store = __esm(() => {
|
|
70255
70824
|
init_internal();
|
|
70825
|
+
init_pool_journal();
|
|
70256
70826
|
});
|
|
70257
70827
|
|
|
70258
70828
|
// dist/builtin/workflows/src/durable/completed-catalog-index.ts
|
|
@@ -76713,9 +77283,9 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
76713
77283
|
});
|
|
76714
77284
|
|
|
76715
77285
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
76716
|
-
import { createHash as
|
|
77286
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
76717
77287
|
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
76718
|
-
import { basename as
|
|
77288
|
+
import { basename as basename6, dirname as dirname16, isAbsolute as isAbsolute11, join as join31, resolve as resolve17 } from "node:path";
|
|
76719
77289
|
function normalizeMaxOutput2(maxOutput) {
|
|
76720
77290
|
return {
|
|
76721
77291
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -76777,8 +77347,8 @@ function formatByteSize(bytes) {
|
|
|
76777
77347
|
return `${value2.toFixed(1)} ${units[unitIndex]}`;
|
|
76778
77348
|
}
|
|
76779
77349
|
function transcriptPath(runId, outputPath) {
|
|
76780
|
-
const digest =
|
|
76781
|
-
return
|
|
77350
|
+
const digest = createHash6("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
77351
|
+
return join31(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename6(outputPath)}.transcript.md`);
|
|
76782
77352
|
}
|
|
76783
77353
|
function appendContent(lines, content) {
|
|
76784
77354
|
if (typeof content === "string") {
|
|
@@ -76823,7 +77393,7 @@ function renderTranscript(messages, fallbackOutput) {
|
|
|
76823
77393
|
`);
|
|
76824
77394
|
}
|
|
76825
77395
|
function savedOutputReference(outputPath, fullOutput, transcriptPathValue, transcriptText, transcriptAvailable, warning) {
|
|
76826
|
-
const absolutePath =
|
|
77396
|
+
const absolutePath = resolve17(outputPath);
|
|
76827
77397
|
const bytes = Buffer.byteLength(fullOutput, "utf8");
|
|
76828
77398
|
const lines = countLines(fullOutput);
|
|
76829
77399
|
const transcriptBytes = Buffer.byteLength(transcriptText, "utf8");
|
|
@@ -76838,8 +77408,8 @@ function resolveOutputPath(output, runtimeCwd, requestedCwd) {
|
|
|
76838
77408
|
return;
|
|
76839
77409
|
if (isAbsolute11(output))
|
|
76840
77410
|
return output;
|
|
76841
|
-
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd :
|
|
76842
|
-
return
|
|
77411
|
+
const baseCwd = requestedCwd === undefined ? runtimeCwd : isAbsolute11(requestedCwd) ? requestedCwd : resolve17(runtimeCwd, requestedCwd);
|
|
77412
|
+
return resolve17(baseCwd, output);
|
|
76843
77413
|
}
|
|
76844
77414
|
function degenerateWarning(fullOutput) {
|
|
76845
77415
|
return fullOutput.trim().length === 0 ? "WARNING: the stage artifact is empty; search the companion transcript for this stage's work." : undefined;
|
|
@@ -76898,7 +77468,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
76898
77468
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
76899
77469
|
const transcript = renderTranscript(messages, fullOutput);
|
|
76900
77470
|
try {
|
|
76901
|
-
await mkdir7(
|
|
77471
|
+
await mkdir7(dirname16(outputPath), { recursive: true });
|
|
76902
77472
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
76903
77473
|
} catch (err) {
|
|
76904
77474
|
return `${displayOutput}
|
|
@@ -76910,7 +77480,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
76910
77480
|
let transcriptError;
|
|
76911
77481
|
try {
|
|
76912
77482
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
76913
|
-
await mkdir7(
|
|
77483
|
+
await mkdir7(dirname16(transcriptFile), { recursive: true });
|
|
76914
77484
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
76915
77485
|
transcriptAvailable = true;
|
|
76916
77486
|
} catch (err) {
|
|
@@ -78941,7 +79511,7 @@ var init_executor = __esm(() => {
|
|
|
78941
79511
|
});
|
|
78942
79512
|
|
|
78943
79513
|
// dist/builtin/workflows/src/runs/foreground/sdk-run.ts
|
|
78944
|
-
import { randomUUID as
|
|
79514
|
+
import { randomUUID as randomUUID22 } from "node:crypto";
|
|
78945
79515
|
async function run2(def, inputs, callerOpts = {}) {
|
|
78946
79516
|
let opts = callerOpts;
|
|
78947
79517
|
const store2 = opts.store === undefined || opts.store === store ? currentWorkflowStore() : opts.store;
|
|
@@ -78952,7 +79522,7 @@ async function run2(def, inputs, callerOpts = {}) {
|
|
|
78952
79522
|
if (opts.journal === undefined && opts.durableBackend === undefined && ownedBackend === undefined) {
|
|
78953
79523
|
bindStoreDurableBackend(store2, backend);
|
|
78954
79524
|
}
|
|
78955
|
-
const runId = opts.runId ??
|
|
79525
|
+
const runId = opts.runId ?? randomUUID22();
|
|
78956
79526
|
if (sourceRunId !== undefined || opts.localWorkers || opts.admission) {
|
|
78957
79527
|
opts = await restoreWorkerOptions(backend, { ...opts, runId });
|
|
78958
79528
|
}
|