@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
|
@@ -3824,10 +3824,16 @@ function selectRunJournal(options = {}) {
|
|
|
3824
3824
|
async function resolveRunJournal(options = {}) {
|
|
3825
3825
|
return openSelectedRunJournal(selectRunJournal(options), options.agentDir);
|
|
3826
3826
|
}
|
|
3827
|
+
function runJournalOrigin(journal) {
|
|
3828
|
+
return journalOrigins.get(journal);
|
|
3829
|
+
}
|
|
3827
3830
|
async function openSelectedRunJournal(selection, agentDir = getAgentDir()) {
|
|
3828
3831
|
if ("createRun" in selection)
|
|
3829
3832
|
return selection;
|
|
3830
|
-
|
|
3833
|
+
const journal = await withRunJournalConfigSource(selection, () => provider.openRunJournal(selection, { agentDir, domain: "journal" }));
|
|
3834
|
+
if (!journalOrigins.has(journal))
|
|
3835
|
+
journalOrigins.set(journal, { selection, agentDir });
|
|
3836
|
+
return journal;
|
|
3831
3837
|
}
|
|
3832
3838
|
async function withRunJournalConfigSource(selection, open) {
|
|
3833
3839
|
if ("createRun" in selection)
|
|
@@ -3845,7 +3851,7 @@ async function withRunJournalConfigSource(selection, open) {
|
|
|
3845
3851
|
throw error;
|
|
3846
3852
|
}
|
|
3847
3853
|
}
|
|
3848
|
-
var hostModules, provider, origins;
|
|
3854
|
+
var hostModules, provider, origins, journalOrigins;
|
|
3849
3855
|
var init_resolution = __esm(() => {
|
|
3850
3856
|
init_memory_run_journal();
|
|
3851
3857
|
init_sql_run_journal();
|
|
@@ -3858,6 +3864,7 @@ var init_resolution = __esm(() => {
|
|
|
3858
3864
|
}
|
|
3859
3865
|
});
|
|
3860
3866
|
origins = new WeakMap;
|
|
3867
|
+
journalOrigins = new WeakMap;
|
|
3861
3868
|
});
|
|
3862
3869
|
|
|
3863
3870
|
// dist/builtin/workflows/src/authoring/keep-context.ts
|
|
@@ -17283,7 +17290,7 @@ async function admitWorkflowSessions(backend, opts, callback) {
|
|
|
17283
17290
|
return callback(opts);
|
|
17284
17291
|
if (!(rootBackend instanceof JournalDurableBackend))
|
|
17285
17292
|
throw new Error("Resource admission requires a journal backend");
|
|
17286
|
-
const admission = await SqlResourceAdmission.open(rootBackend.journal, {
|
|
17293
|
+
const admission = await SqlResourceAdmission.open(poolJournalFor(rootBackend.journal), {
|
|
17287
17294
|
...config,
|
|
17288
17295
|
root: opts.parentRun?.rootRunId ?? opts.runId,
|
|
17289
17296
|
holder: randomUUID7()
|
|
@@ -17301,6 +17308,7 @@ var init_admission_binding = __esm(() => {
|
|
|
17301
17308
|
init_journal_backend();
|
|
17302
17309
|
init_wiring();
|
|
17303
17310
|
init_stage_runner_session_options();
|
|
17311
|
+
init_pool_journal();
|
|
17304
17312
|
init_resource_admission();
|
|
17305
17313
|
workflowResourceAdmission = new WeakMap;
|
|
17306
17314
|
});
|
|
@@ -59185,6 +59193,84 @@ var init_host_options = __esm(() => {
|
|
|
59185
59193
|
hostWorkerBindings = Symbol("host-worker-bindings");
|
|
59186
59194
|
});
|
|
59187
59195
|
|
|
59196
|
+
// dist/builtin/workflows/src/durable/journal/pool-remote-journal.ts
|
|
59197
|
+
class PoolRemoteJournal {
|
|
59198
|
+
journal;
|
|
59199
|
+
storage;
|
|
59200
|
+
mirrored;
|
|
59201
|
+
mirroring;
|
|
59202
|
+
constructor(journal, storage) {
|
|
59203
|
+
this.journal = journal;
|
|
59204
|
+
this.storage = storage;
|
|
59205
|
+
}
|
|
59206
|
+
async mirror(lease) {
|
|
59207
|
+
const root = lease.runId;
|
|
59208
|
+
const sampledAt = performance.now();
|
|
59209
|
+
const [run, state] = await Promise.all([this.journal.getRun(root), this.journal.leaseState(root)]);
|
|
59210
|
+
if (run === undefined)
|
|
59211
|
+
throw new RunNotFoundError(root);
|
|
59212
|
+
const { runs, leases } = this.storage.tables;
|
|
59213
|
+
await this.storage.transaction(async (tx) => {
|
|
59214
|
+
await tx.run(`INSERT INTO ${runs}(run_id, name, cwd, created_at, status, header_json) VALUES (?, ?, ?, ?, ?, ?)
|
|
59215
|
+
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 }));
|
|
59216
|
+
if (state === undefined)
|
|
59217
|
+
await tx.run(`DELETE FROM ${leases} WHERE run_id = ?`, root);
|
|
59218
|
+
else
|
|
59219
|
+
await tx.run(`INSERT INTO ${leases}(run_id, holder_id, epoch, renewed_at) VALUES (?, ?, ?, CAST(unixepoch('subsec') * 1000 AS INTEGER) - ?)
|
|
59220
|
+
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)));
|
|
59221
|
+
});
|
|
59222
|
+
if (state === undefined || state.holderId !== lease.holderId || state.epoch !== lease.epoch)
|
|
59223
|
+
throw new StaleLeaseError(root, lease.epoch, state?.epoch ?? 0);
|
|
59224
|
+
this.mirrored = { lease, at: sampledAt };
|
|
59225
|
+
}
|
|
59226
|
+
async fresh(lease, maxAgeMs = MIRROR_FRESH_MS) {
|
|
59227
|
+
const known = this.mirrored;
|
|
59228
|
+
if (known !== undefined && known.lease.holderId === lease.holderId && known.lease.epoch === lease.epoch && performance.now() - known.at < maxAgeMs)
|
|
59229
|
+
return;
|
|
59230
|
+
this.mirroring ??= this.mirror(lease).finally(() => {
|
|
59231
|
+
this.mirroring = undefined;
|
|
59232
|
+
});
|
|
59233
|
+
try {
|
|
59234
|
+
await this.mirroring;
|
|
59235
|
+
} catch (error) {
|
|
59236
|
+
if (error instanceof StaleLeaseError || error instanceof RunNotFoundError)
|
|
59237
|
+
throw error;
|
|
59238
|
+
}
|
|
59239
|
+
}
|
|
59240
|
+
entry(root, key) {
|
|
59241
|
+
return this.journal.readKey(root, key);
|
|
59242
|
+
}
|
|
59243
|
+
append(lease, key, checkpoint) {
|
|
59244
|
+
const event = { type: RUN_EVENT_TYPES.checkpointRecorded, payload: checkpoint };
|
|
59245
|
+
return this.journal.append(lease, event, { key });
|
|
59246
|
+
}
|
|
59247
|
+
events(root) {
|
|
59248
|
+
return (fromSeq) => this.journal.read(root, fromSeq);
|
|
59249
|
+
}
|
|
59250
|
+
}
|
|
59251
|
+
function isSameCheckpointValue(stored, next) {
|
|
59252
|
+
const hash = (value2) => durableHash(value2);
|
|
59253
|
+
return hash(stored) === hash(next);
|
|
59254
|
+
}
|
|
59255
|
+
function isRecordedCheckpointValue(stored, next) {
|
|
59256
|
+
const recorded = stored;
|
|
59257
|
+
if (isSameCheckpointValue(recorded, next))
|
|
59258
|
+
return true;
|
|
59259
|
+
const { completedAt, startedAt } = recorded;
|
|
59260
|
+
if (typeof completedAt !== "number")
|
|
59261
|
+
return false;
|
|
59262
|
+
const later = next;
|
|
59263
|
+
if (startedAt === undefined !== (later.startedAt === undefined))
|
|
59264
|
+
return false;
|
|
59265
|
+
return isSameCheckpointValue({ ...later, completedAt, ...startedAt === undefined ? {} : { startedAt } }, recorded);
|
|
59266
|
+
}
|
|
59267
|
+
var MIRROR_FRESH_MS = 2000;
|
|
59268
|
+
var init_pool_remote_journal = __esm(() => {
|
|
59269
|
+
init_durable_hash();
|
|
59270
|
+
init_types();
|
|
59271
|
+
init_values();
|
|
59272
|
+
});
|
|
59273
|
+
|
|
59188
59274
|
// dist/builtin/workflows/src/durable/journal/pool-checkpoint-index.ts
|
|
59189
59275
|
function push(map, key, value2) {
|
|
59190
59276
|
if (key === undefined)
|
|
@@ -59252,6 +59338,11 @@ class PoolCheckpointRead {
|
|
|
59252
59338
|
this.pending = apply;
|
|
59253
59339
|
});
|
|
59254
59340
|
}
|
|
59341
|
+
readEntries(stream) {
|
|
59342
|
+
return this.index.readEntries(this.root, stream, (apply) => {
|
|
59343
|
+
this.pending = apply;
|
|
59344
|
+
});
|
|
59345
|
+
}
|
|
59255
59346
|
commit() {
|
|
59256
59347
|
this.pending?.();
|
|
59257
59348
|
this.pending = undefined;
|
|
@@ -59274,7 +59365,6 @@ class PoolCheckpointIndex {
|
|
|
59274
59365
|
}
|
|
59275
59366
|
const from = base?.seq ?? 0;
|
|
59276
59367
|
const to = head ? Number(head.seq) : 0;
|
|
59277
|
-
const delta = new Partitions;
|
|
59278
59368
|
const added = [];
|
|
59279
59369
|
if (to > from) {
|
|
59280
59370
|
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);
|
|
@@ -59282,15 +59372,57 @@ class PoolCheckpointIndex {
|
|
|
59282
59372
|
const checkpoint = JSON.parse(String(row.payload));
|
|
59283
59373
|
if (checkpoint.kind === "ui")
|
|
59284
59374
|
continue;
|
|
59285
|
-
|
|
59375
|
+
added.push({
|
|
59286
59376
|
seq: Number(row.seq),
|
|
59287
59377
|
order: row.key === null ? Buffer.alloc(0) : Buffer.from(row.key, "utf8"),
|
|
59288
59378
|
checkpoint
|
|
59289
|
-
};
|
|
59290
|
-
delta.add(entry);
|
|
59291
|
-
added.push(entry);
|
|
59379
|
+
});
|
|
59292
59380
|
}
|
|
59293
59381
|
}
|
|
59382
|
+
return this.view(root, current, base, from, to, head, added, onCommit);
|
|
59383
|
+
}
|
|
59384
|
+
async readEntries(root, stream, onCommit) {
|
|
59385
|
+
const current = this.roots.get(root);
|
|
59386
|
+
let base = current;
|
|
59387
|
+
for (;; ) {
|
|
59388
|
+
const mark = base !== undefined && base.seq > 0 ? { seq: base.seq, key: base.key, at: base.at } : undefined;
|
|
59389
|
+
let verified = mark === undefined;
|
|
59390
|
+
let mismatch = false;
|
|
59391
|
+
let head;
|
|
59392
|
+
const added = [];
|
|
59393
|
+
for await (const entry of stream(mark === undefined ? 1 : mark.seq)) {
|
|
59394
|
+
if (mark !== undefined && entry.seq === mark.seq) {
|
|
59395
|
+
if ((entry.key ?? null) !== mark.key || entry.at !== mark.at) {
|
|
59396
|
+
mismatch = true;
|
|
59397
|
+
break;
|
|
59398
|
+
}
|
|
59399
|
+
verified = true;
|
|
59400
|
+
head = { seq: entry.seq, key: entry.key ?? null, at: entry.at };
|
|
59401
|
+
continue;
|
|
59402
|
+
}
|
|
59403
|
+
head = { seq: entry.seq, key: entry.key ?? null, at: entry.at };
|
|
59404
|
+
if (entry.event.type !== RUN_EVENT_TYPES.checkpointRecorded)
|
|
59405
|
+
continue;
|
|
59406
|
+
const checkpoint = entry.event.payload;
|
|
59407
|
+
if (checkpoint.kind === "ui")
|
|
59408
|
+
continue;
|
|
59409
|
+
added.push({
|
|
59410
|
+
seq: entry.seq,
|
|
59411
|
+
order: entry.key === undefined ? Buffer.alloc(0) : Buffer.from(entry.key, "utf8"),
|
|
59412
|
+
checkpoint
|
|
59413
|
+
});
|
|
59414
|
+
}
|
|
59415
|
+
if (mark !== undefined && (mismatch || !verified)) {
|
|
59416
|
+
base = undefined;
|
|
59417
|
+
continue;
|
|
59418
|
+
}
|
|
59419
|
+
return this.view(root, current, base, mark?.seq ?? 0, head?.seq ?? 0, head, added, onCommit);
|
|
59420
|
+
}
|
|
59421
|
+
}
|
|
59422
|
+
view(root, current, base, from, to, head, added, onCommit) {
|
|
59423
|
+
const delta = new Partitions;
|
|
59424
|
+
for (const entry of added)
|
|
59425
|
+
delta.add(entry);
|
|
59294
59426
|
onCommit(() => {
|
|
59295
59427
|
const latest = this.roots.get(root);
|
|
59296
59428
|
if (!base) {
|
|
@@ -59553,15 +59685,21 @@ function expiry(now, duration) {
|
|
|
59553
59685
|
|
|
59554
59686
|
class SqlPoolQueue {
|
|
59555
59687
|
storage;
|
|
59688
|
+
remote;
|
|
59556
59689
|
meta;
|
|
59557
59690
|
roots;
|
|
59558
59691
|
work;
|
|
59559
59692
|
operations;
|
|
59693
|
+
outbox;
|
|
59560
59694
|
transaction;
|
|
59561
59695
|
journal;
|
|
59562
59696
|
checkpoints = new PoolCheckpointIndex;
|
|
59563
|
-
|
|
59697
|
+
committing = new Map;
|
|
59698
|
+
draining;
|
|
59699
|
+
outboxPending = false;
|
|
59700
|
+
constructor(storage, remote) {
|
|
59564
59701
|
this.storage = storage;
|
|
59702
|
+
this.remote = remote;
|
|
59565
59703
|
const { transaction, tables: journal } = storage;
|
|
59566
59704
|
this.transaction = transaction;
|
|
59567
59705
|
this.journal = journal;
|
|
@@ -59569,10 +59707,11 @@ class SqlPoolQueue {
|
|
|
59569
59707
|
this.roots = `${journal.runs}_pool`;
|
|
59570
59708
|
this.work = `${journal.runs}_work`;
|
|
59571
59709
|
this.operations = `${journal.runs}_pool_operations`;
|
|
59710
|
+
this.outbox = `${journal.runs}_pool_outbox`;
|
|
59572
59711
|
}
|
|
59573
|
-
static async open(storage) {
|
|
59712
|
+
static async open(storage, remote) {
|
|
59574
59713
|
const journal = storage.tables;
|
|
59575
|
-
const pool = new SqlPoolQueue(storage);
|
|
59714
|
+
const pool = new SqlPoolQueue(storage, remote);
|
|
59576
59715
|
await storage.transaction(async (tx) => {
|
|
59577
59716
|
if ((await tx.get("PRAGMA foreign_keys"))?.foreign_keys !== 1)
|
|
59578
59717
|
throw new Error("Pool requires SQLite foreign keys");
|
|
@@ -59615,6 +59754,15 @@ class SqlPoolQueue {
|
|
|
59615
59754
|
state TEXT NOT NULL DEFAULT 'running', revision INTEGER NOT NULL DEFAULT 0
|
|
59616
59755
|
)`);
|
|
59617
59756
|
await tx.exec(poolUsageSchema(journal.runs));
|
|
59757
|
+
if (remote)
|
|
59758
|
+
await tx.exec(`CREATE TABLE IF NOT EXISTS ${pool.outbox}(
|
|
59759
|
+
work TEXT NOT NULL REFERENCES ${pool.work}(id) ON DELETE CASCADE,
|
|
59760
|
+
generation INTEGER NOT NULL, operation TEXT NOT NULL, request TEXT NOT NULL,
|
|
59761
|
+
event_key TEXT NOT NULL, payload TEXT NOT NULL, last_seq INTEGER,
|
|
59762
|
+
PRIMARY KEY(work, generation, operation)
|
|
59763
|
+
)`);
|
|
59764
|
+
if (remote)
|
|
59765
|
+
pool.outboxPending = await tx.get(`SELECT 1 AS held FROM ${pool.outbox} LIMIT 1`) !== undefined;
|
|
59618
59766
|
if (version === 1)
|
|
59619
59767
|
await pool.migrateFromVersion1(tx);
|
|
59620
59768
|
});
|
|
@@ -59659,6 +59807,7 @@ class SqlPoolQueue {
|
|
|
59659
59807
|
});
|
|
59660
59808
|
}
|
|
59661
59809
|
async setControl(lease, state) {
|
|
59810
|
+
await this.remote?.fresh(lease);
|
|
59662
59811
|
return this.transaction(async (tx) => {
|
|
59663
59812
|
await this.authority(tx, lease);
|
|
59664
59813
|
await tx.run(`INSERT INTO ${this.roots}_control(root, state, revision) VALUES (?, ?, 1)
|
|
@@ -59670,7 +59819,7 @@ class SqlPoolQueue {
|
|
|
59670
59819
|
withCurrentAppend(lease, token, assertSession, action) {
|
|
59671
59820
|
lease = snapshotLease(lease);
|
|
59672
59821
|
token = { ...token };
|
|
59673
|
-
|
|
59822
|
+
const guard = async (tx, runId) => {
|
|
59674
59823
|
try {
|
|
59675
59824
|
if (runId !== lease.runId)
|
|
59676
59825
|
throw new Error("Pool delivery cannot write another root");
|
|
@@ -59688,7 +59837,10 @@ class SqlPoolQueue {
|
|
|
59688
59837
|
throw error;
|
|
59689
59838
|
throw new PoolAppendRefusedError(error.message, { cause: error });
|
|
59690
59839
|
}
|
|
59691
|
-
}
|
|
59840
|
+
};
|
|
59841
|
+
if (this.remote)
|
|
59842
|
+
return this.transaction((tx) => guard(tx, lease.runId)).then(action);
|
|
59843
|
+
return this.storage.withAppendGuard(guard, action);
|
|
59692
59844
|
}
|
|
59693
59845
|
async assertCurrent(lease, token) {
|
|
59694
59846
|
await this.transaction(async (tx) => {
|
|
@@ -59721,6 +59873,8 @@ class SqlPoolQueue {
|
|
|
59721
59873
|
const payload = serializeJson(boundary);
|
|
59722
59874
|
const fingerprint = durableHash({ descriptor: JSON.parse(json), boundary: JSON.parse(payload) });
|
|
59723
59875
|
const key = JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, boundary.kind, boundary.checkpointId]);
|
|
59876
|
+
if (this.remote)
|
|
59877
|
+
await this.recordBoundaryStart(lease, key, boundary);
|
|
59724
59878
|
return this.transaction(async (tx) => {
|
|
59725
59879
|
const { now } = await this.authority(tx, lease);
|
|
59726
59880
|
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);
|
|
@@ -59737,21 +59891,47 @@ class SqlPoolQueue {
|
|
|
59737
59891
|
throw new Error("Pool work scopes overlap");
|
|
59738
59892
|
const id = randomUUID10();
|
|
59739
59893
|
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);
|
|
59740
|
-
|
|
59741
|
-
|
|
59742
|
-
|
|
59743
|
-
|
|
59744
|
-
|
|
59745
|
-
|
|
59894
|
+
if (!this.remote) {
|
|
59895
|
+
const seq = await tx.get(`SELECT COALESCE(MAX(seq), 0) AS seq FROM ${this.journal.events} WHERE run_id = ?`, lease.runId);
|
|
59896
|
+
const existing = await tx.get(`SELECT payload FROM ${this.journal.events} WHERE run_id = ? AND key = ?`, lease.runId, key);
|
|
59897
|
+
if (existing && existing.payload !== payload)
|
|
59898
|
+
throw new Error("Pool boundary identity conflict");
|
|
59899
|
+
if (!existing)
|
|
59900
|
+
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);
|
|
59901
|
+
}
|
|
59746
59902
|
return fromRow(await tx.get(`SELECT * FROM ${this.work} WHERE id = ?`, id));
|
|
59747
59903
|
});
|
|
59748
59904
|
}
|
|
59905
|
+
async recordBoundaryStart(lease, key, boundary) {
|
|
59906
|
+
const remote = this.remote;
|
|
59907
|
+
await remote.fresh(lease);
|
|
59908
|
+
const existing = await remote.entry(lease.runId, key);
|
|
59909
|
+
if (existing) {
|
|
59910
|
+
if (!isSameCheckpointValue(existing.event.payload, boundary))
|
|
59911
|
+
throw new Error("Pool boundary identity conflict");
|
|
59912
|
+
return;
|
|
59913
|
+
}
|
|
59914
|
+
const outcome = await remote.append(lease, key, boundary);
|
|
59915
|
+
if (outcome.status === "exists" && !isSameCheckpointValue(outcome.entry.event.payload, boundary))
|
|
59916
|
+
throw new Error("Pool boundary identity conflict");
|
|
59917
|
+
}
|
|
59749
59918
|
async claim(lease, worker, definitions, durationMs) {
|
|
59750
59919
|
positive(durationMs);
|
|
59751
59920
|
lease = snapshotLease(lease);
|
|
59752
59921
|
const compatibleDefinitions = definitions.flatMap((d) => [d.definition, d.digest]);
|
|
59753
59922
|
validateText("holderId", worker);
|
|
59754
59923
|
const compatible = definitions.map(() => "(json_extract(descriptor, '$.definition') = ? AND json_extract(descriptor, '$.digest') = ?)").join(" OR ");
|
|
59924
|
+
if (this.remote) {
|
|
59925
|
+
await this.remote.fresh(lease);
|
|
59926
|
+
try {
|
|
59927
|
+
while (this.outboxPending || this.draining !== undefined)
|
|
59928
|
+
await this.drainOutbox(lease);
|
|
59929
|
+
} catch (error) {
|
|
59930
|
+
if (error instanceof StaleLeaseError)
|
|
59931
|
+
throw error;
|
|
59932
|
+
return;
|
|
59933
|
+
}
|
|
59934
|
+
}
|
|
59755
59935
|
return this.transaction(async (tx) => {
|
|
59756
59936
|
const { now, status } = await this.authority(tx, lease);
|
|
59757
59937
|
const control = await tx.get(`SELECT state FROM ${this.roots}_control WHERE root = ?`, lease.runId);
|
|
@@ -59785,6 +59965,7 @@ class SqlPoolQueue {
|
|
|
59785
59965
|
positive(durationMs);
|
|
59786
59966
|
lease = snapshotLease(lease);
|
|
59787
59967
|
token = { ...token };
|
|
59968
|
+
await this.remote?.fresh(lease);
|
|
59788
59969
|
return this.transaction(async (tx) => {
|
|
59789
59970
|
const { now } = await this.authority(tx, lease);
|
|
59790
59971
|
const row = await this.current(tx, lease, token);
|
|
@@ -59803,6 +59984,8 @@ class SqlPoolQueue {
|
|
|
59803
59984
|
const request = serializeJson({ epoch: token.epoch, worker: token.worker, mutation });
|
|
59804
59985
|
const identity = requestIdentity(request);
|
|
59805
59986
|
mutation = JSON.parse(request).mutation;
|
|
59987
|
+
if (this.remote && mutation.kind !== "session-append")
|
|
59988
|
+
return this.commitRemote(lease, token, operationId, mutation, identity);
|
|
59806
59989
|
const checkpoints = this.checkpoints.begin(lease.runId);
|
|
59807
59990
|
const receipt = await this.transaction(async (tx) => {
|
|
59808
59991
|
const { now, status } = await this.authority(tx, lease);
|
|
@@ -59826,6 +60009,127 @@ class SqlPoolQueue {
|
|
|
59826
60009
|
checkpoints.commit();
|
|
59827
60010
|
return receipt;
|
|
59828
60011
|
}
|
|
60012
|
+
commitRemote(lease, token, operationId, mutation, identity) {
|
|
60013
|
+
const flight = JSON.stringify([token.id, token.generation, operationId]);
|
|
60014
|
+
const running = this.committing.get(flight);
|
|
60015
|
+
if (running)
|
|
60016
|
+
return running;
|
|
60017
|
+
const commit = this.stageAndDeliver(lease, token, operationId, mutation, identity).finally(() => {
|
|
60018
|
+
this.committing.delete(flight);
|
|
60019
|
+
});
|
|
60020
|
+
this.committing.set(flight, commit);
|
|
60021
|
+
return commit;
|
|
60022
|
+
}
|
|
60023
|
+
async stageAndDeliver(lease, token, operationId, mutation, identity) {
|
|
60024
|
+
const remote = this.remote;
|
|
60025
|
+
await remote.fresh(lease);
|
|
60026
|
+
const checkpoint = mutation.checkpoint;
|
|
60027
|
+
const key = JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, checkpoint.kind, checkpoint.checkpointId]);
|
|
60028
|
+
const reads = this.checkpoints.begin(lease.runId);
|
|
60029
|
+
const [existing, view] = await Promise.all([
|
|
60030
|
+
remote.entry(lease.runId, key),
|
|
60031
|
+
checkpoint.kind === "ui" ? undefined : reads.readEntries(remote.events(lease.runId))
|
|
60032
|
+
]);
|
|
60033
|
+
reads.commit();
|
|
60034
|
+
const source = {
|
|
60035
|
+
read: async () => view ?? Promise.reject(new Error("Pool checkpoint view is unavailable"))
|
|
60036
|
+
};
|
|
60037
|
+
const staged = await this.transaction(async (tx) => {
|
|
60038
|
+
const { now, status } = await this.authority(tx, lease);
|
|
60039
|
+
const row = await this.current(tx, lease, token);
|
|
60040
|
+
if (row.epoch !== lease.epoch)
|
|
60041
|
+
throw new Error(STALE_WORK_LEASE);
|
|
60042
|
+
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
60043
|
+
if (previous) {
|
|
60044
|
+
if (previous.request !== identity)
|
|
60045
|
+
throw new Error("Pool operation identity conflict");
|
|
60046
|
+
return { receipt: JSON.parse(previous.receipt) };
|
|
60047
|
+
}
|
|
60048
|
+
const held = await tx.get(`SELECT * FROM ${this.outbox} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
60049
|
+
if (held) {
|
|
60050
|
+
if (held.request !== identity)
|
|
60051
|
+
throw new Error("Pool operation identity conflict");
|
|
60052
|
+
return { held };
|
|
60053
|
+
}
|
|
60054
|
+
if (row.expires_at < now)
|
|
60055
|
+
throw new Error(STALE_WORK_LEASE);
|
|
60056
|
+
if (!await this.admitsAttemptWrites(tx, lease, status))
|
|
60057
|
+
throw new Error("Pool root is not running");
|
|
60058
|
+
await validatePoolMutation(tx, this.journal, lease.runId, fromRow(row), mutation, source);
|
|
60059
|
+
if (checkpoint.completedAt > Math.max(now, Date.now()) + MAX_WORKER_CLOCK_SKEW_MS)
|
|
60060
|
+
throw new Error("Pool checkpoint timestamp is in the future");
|
|
60061
|
+
assertWorkflowSerializableObject(checkpoint, "Pool checkpoint");
|
|
60062
|
+
if (existing && !isRecordedCheckpointValue(existing.event.payload, checkpoint))
|
|
60063
|
+
throw new Error("Pool checkpoint identity conflict");
|
|
60064
|
+
if (existing && mutation.kind !== "checkpoint")
|
|
60065
|
+
throw new Error("Pool session checkpoint identity conflict");
|
|
60066
|
+
const lastSeq = mutation.kind === "checkpoint" ? undefined : await applyPoolSession(tx, `${this.journal.runs}_pool_`, row.id, mutation);
|
|
60067
|
+
const billed = poolCheckpointUsage(checkpoint);
|
|
60068
|
+
if (billed && !existing)
|
|
60069
|
+
await upsertPoolUsage(tx, this.journal.runs, row.id, token.generation, billed.key, billed.usage);
|
|
60070
|
+
if (existing) {
|
|
60071
|
+
const receipt = { seq: existing.seq, at: existing.at };
|
|
60072
|
+
await tx.run(`INSERT INTO ${this.operations} VALUES (?, ?, ?, ?, ?)`, token.id, token.generation, operationId, identity, JSON.stringify(receipt));
|
|
60073
|
+
return { receipt };
|
|
60074
|
+
}
|
|
60075
|
+
const entry = {
|
|
60076
|
+
work: token.id,
|
|
60077
|
+
generation: token.generation,
|
|
60078
|
+
operation: operationId,
|
|
60079
|
+
request: identity,
|
|
60080
|
+
event_key: key,
|
|
60081
|
+
payload: serializeJson(checkpoint),
|
|
60082
|
+
last_seq: lastSeq ?? null
|
|
60083
|
+
};
|
|
60084
|
+
await tx.run(`INSERT INTO ${this.outbox} VALUES (?, ?, ?, ?, ?, ?, ?)`, entry.work, entry.generation, entry.operation, entry.request, entry.event_key, entry.payload, entry.last_seq);
|
|
60085
|
+
return { held: entry };
|
|
60086
|
+
});
|
|
60087
|
+
if (staged.receipt !== undefined)
|
|
60088
|
+
return staged.receipt;
|
|
60089
|
+
this.outboxPending = true;
|
|
60090
|
+
return this.deliver(lease, staged.held);
|
|
60091
|
+
}
|
|
60092
|
+
async deliver(lease, held) {
|
|
60093
|
+
const remote = this.remote;
|
|
60094
|
+
const checkpoint = JSON.parse(held.payload);
|
|
60095
|
+
const outcome = await remote.append(lease, held.event_key, checkpoint);
|
|
60096
|
+
const forget = (tx) => tx.run(`DELETE FROM ${this.outbox} WHERE work = ? AND generation = ? AND operation = ?`, held.work, held.generation, held.operation);
|
|
60097
|
+
if (outcome.status === "exists" && !isRecordedCheckpointValue(outcome.entry.event.payload, checkpoint)) {
|
|
60098
|
+
await this.transaction(forget);
|
|
60099
|
+
throw new Error("Pool checkpoint identity conflict");
|
|
60100
|
+
}
|
|
60101
|
+
const receipt = {
|
|
60102
|
+
seq: outcome.entry.seq,
|
|
60103
|
+
at: outcome.entry.at,
|
|
60104
|
+
...held.last_seq === null ? {} : { lastSeq: Number(held.last_seq) }
|
|
60105
|
+
};
|
|
60106
|
+
await this.transaction(async (tx) => {
|
|
60107
|
+
await tx.run(`INSERT OR IGNORE INTO ${this.operations} VALUES (?, ?, ?, ?, ?)`, held.work, held.generation, held.operation, held.request, JSON.stringify(receipt));
|
|
60108
|
+
await forget(tx);
|
|
60109
|
+
});
|
|
60110
|
+
return receipt;
|
|
60111
|
+
}
|
|
60112
|
+
drainOutbox(lease) {
|
|
60113
|
+
if (!this.remote)
|
|
60114
|
+
return Promise.resolve(0);
|
|
60115
|
+
lease = snapshotLease(lease);
|
|
60116
|
+
this.draining ??= this.deliverAll(lease).finally(() => {
|
|
60117
|
+
this.draining = undefined;
|
|
60118
|
+
});
|
|
60119
|
+
return this.draining;
|
|
60120
|
+
}
|
|
60121
|
+
async deliverAll(lease) {
|
|
60122
|
+
this.outboxPending = false;
|
|
60123
|
+
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));
|
|
60124
|
+
try {
|
|
60125
|
+
for (const row of rows)
|
|
60126
|
+
await this.deliver(lease, row);
|
|
60127
|
+
} catch (error) {
|
|
60128
|
+
this.outboxPending = true;
|
|
60129
|
+
throw error;
|
|
60130
|
+
}
|
|
60131
|
+
return rows.length;
|
|
60132
|
+
}
|
|
59829
60133
|
async appendSession(tx, row, mutation, now) {
|
|
59830
60134
|
return { at: now, lastSeq: await applyPoolSession(tx, `${this.journal.runs}_pool_`, row.id, mutation) };
|
|
59831
60135
|
}
|
|
@@ -59861,6 +60165,7 @@ class SqlPoolQueue {
|
|
|
59861
60165
|
token = { ...token };
|
|
59862
60166
|
assertWorkflowSerializableObject(result, "Pool result");
|
|
59863
60167
|
const payload = serializeJson(result);
|
|
60168
|
+
await this.remote?.fresh(lease);
|
|
59864
60169
|
await this.transaction(async (tx) => {
|
|
59865
60170
|
const { now, status } = await this.authority(tx, lease);
|
|
59866
60171
|
const row = await this.current(tx, lease, token, true);
|
|
@@ -59876,6 +60181,8 @@ class SqlPoolQueue {
|
|
|
59876
60181
|
throw new Error(STALE_WORK_LEASE);
|
|
59877
60182
|
if (JSON.parse(payload).runId !== fromRow(row).childRunId)
|
|
59878
60183
|
throw new Error("Pool result identity mismatch");
|
|
60184
|
+
if (this.remote && await tx.get(`SELECT 1 AS held FROM ${this.outbox} WHERE work = ? LIMIT 1`, token.id))
|
|
60185
|
+
throw new Error("Pool work has journal events not yet recorded");
|
|
59879
60186
|
await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
|
|
59880
60187
|
await tx.run(`UPDATE ${this.work} SET state = 'completed' WHERE id = ?`, token.id);
|
|
59881
60188
|
});
|
|
@@ -59902,6 +60209,7 @@ class SqlPoolQueue {
|
|
|
59902
60209
|
positive(durationMs);
|
|
59903
60210
|
lease = snapshotLease(lease);
|
|
59904
60211
|
token = { ...token };
|
|
60212
|
+
await this.remote?.fresh(lease);
|
|
59905
60213
|
return this.transaction(async (tx) => {
|
|
59906
60214
|
const { now } = await this.authority(tx, lease);
|
|
59907
60215
|
const row = await this.current(tx, lease, token);
|
|
@@ -59973,11 +60281,11 @@ function isRecordedCheckpoint(stored, payload) {
|
|
|
59973
60281
|
return false;
|
|
59974
60282
|
return serializeJson({ ...next, completedAt, ...startedAt === undefined ? {} : { startedAt } }) === stored;
|
|
59975
60283
|
}
|
|
59976
|
-
function openSqlPoolQueue(journal) {
|
|
60284
|
+
function openSqlPoolQueue(journal, remote) {
|
|
59977
60285
|
const storage = sqlPoolStorage(journal);
|
|
59978
60286
|
if (!storage)
|
|
59979
60287
|
return Promise.reject(new Error("Worker pool requires a SQL run journal"));
|
|
59980
|
-
return SqlPoolQueue.open(storage);
|
|
60288
|
+
return SqlPoolQueue.open(storage, remote);
|
|
59981
60289
|
}
|
|
59982
60290
|
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;
|
|
59983
60291
|
var init_sql_pool_queue = __esm(() => {
|
|
@@ -59987,6 +60295,7 @@ var init_sql_pool_queue = __esm(() => {
|
|
|
59987
60295
|
init_internal();
|
|
59988
60296
|
init_pool_checkpoint_index();
|
|
59989
60297
|
init_pool_mutations();
|
|
60298
|
+
init_pool_remote_journal();
|
|
59990
60299
|
init_pool_stage_usage();
|
|
59991
60300
|
init_types();
|
|
59992
60301
|
init_values();
|
|
@@ -61791,6 +62100,9 @@ function getBrokerSpawnLockPath(agentDir = getAgentDir5()) {
|
|
|
61791
62100
|
function getBrokerLogPath(agentDir = getAgentDir5()) {
|
|
61792
62101
|
return join26(getIntercomDirPath(agentDir), "broker.log");
|
|
61793
62102
|
}
|
|
62103
|
+
function getBrokerStartAnnouncementPath(agentDir = getAgentDir5()) {
|
|
62104
|
+
return join26(getIntercomDirPath(agentDir), "broker.starting");
|
|
62105
|
+
}
|
|
61794
62106
|
function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDir5()) {
|
|
61795
62107
|
if (platform === "win32") {
|
|
61796
62108
|
return `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}`;
|
|
@@ -62097,7 +62409,7 @@ var init_live_route_refusal = __esm(() => {
|
|
|
62097
62409
|
});
|
|
62098
62410
|
|
|
62099
62411
|
// dist/builtin/intercom/recoverable-disconnect.ts
|
|
62100
|
-
var RECOVERABLE_DISCONNECT_MESSAGE = "Client disconnected", IntercomClientDisconnectedError, IntercomBrokerTimeoutError;
|
|
62412
|
+
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;
|
|
62101
62413
|
var init_recoverable_disconnect = __esm(() => {
|
|
62102
62414
|
init_live_route_refusal();
|
|
62103
62415
|
IntercomClientDisconnectedError = class IntercomClientDisconnectedError extends Error {
|
|
@@ -62114,8 +62426,46 @@ var init_recoverable_disconnect = __esm(() => {
|
|
|
62114
62426
|
this.name = "IntercomBrokerTimeoutError";
|
|
62115
62427
|
}
|
|
62116
62428
|
};
|
|
62429
|
+
IntercomBrokerRetiringError = class IntercomBrokerRetiringError extends Error {
|
|
62430
|
+
intercomRecoverableDisconnect = true;
|
|
62431
|
+
constructor(message = BROKER_RETIRING_REASON, options) {
|
|
62432
|
+
super(message, options);
|
|
62433
|
+
this.name = "IntercomBrokerRetiringError";
|
|
62434
|
+
}
|
|
62435
|
+
};
|
|
62117
62436
|
});
|
|
62118
62437
|
|
|
62438
|
+
// dist/builtin/intercom/broker/socket-liveness.ts
|
|
62439
|
+
import net from "net";
|
|
62440
|
+
function isSocketAnswering(socketPath, timeoutMs = SOCKET_PROBE_TIMEOUT_MS) {
|
|
62441
|
+
return new Promise((resolve) => {
|
|
62442
|
+
const socket = net.connect(socketPath);
|
|
62443
|
+
const finish = (isConnected) => {
|
|
62444
|
+
clearTimeout(timeout);
|
|
62445
|
+
socket.off("connect", onConnect);
|
|
62446
|
+
socket.off("error", onError);
|
|
62447
|
+
resolve(isConnected);
|
|
62448
|
+
};
|
|
62449
|
+
const onConnect = () => {
|
|
62450
|
+
socket.on("error", () => {});
|
|
62451
|
+
socket.end();
|
|
62452
|
+
finish(true);
|
|
62453
|
+
};
|
|
62454
|
+
const onError = () => {
|
|
62455
|
+
socket.destroy();
|
|
62456
|
+
finish(false);
|
|
62457
|
+
};
|
|
62458
|
+
socket.on("connect", onConnect);
|
|
62459
|
+
socket.on("error", onError);
|
|
62460
|
+
const timeout = setTimeout(() => {
|
|
62461
|
+
socket.destroy();
|
|
62462
|
+
finish(false);
|
|
62463
|
+
}, timeoutMs);
|
|
62464
|
+
});
|
|
62465
|
+
}
|
|
62466
|
+
var SOCKET_PROBE_TIMEOUT_MS = 1000;
|
|
62467
|
+
var init_socket_liveness = () => {};
|
|
62468
|
+
|
|
62119
62469
|
// dist/builtin/intercom/retry-policy.ts
|
|
62120
62470
|
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;
|
|
62121
62471
|
var init_retry_policy = __esm(() => {
|
|
@@ -62128,7 +62478,7 @@ var init_retry_policy = __esm(() => {
|
|
|
62128
62478
|
|
|
62129
62479
|
// dist/builtin/intercom/broker/client.ts
|
|
62130
62480
|
import { EventEmitter } from "events";
|
|
62131
|
-
import
|
|
62481
|
+
import net2 from "net";
|
|
62132
62482
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
62133
62483
|
function connectAborted() {
|
|
62134
62484
|
return new IntercomClientDisconnectedError({ cause: new Error("Disconnected before the broker connection registered") });
|
|
@@ -62153,6 +62503,19 @@ function isBacklogRefusal(error) {
|
|
|
62153
62503
|
const code = error.code;
|
|
62154
62504
|
return code === "ECONNREFUSED" || code === "EAGAIN";
|
|
62155
62505
|
}
|
|
62506
|
+
function isLostBrokerSignature(error) {
|
|
62507
|
+
if (error instanceof ConnectionClosedBeforeRegistrationError)
|
|
62508
|
+
return true;
|
|
62509
|
+
const code = error.code;
|
|
62510
|
+
return code === "ENOENT" || code === "ECONNRESET" || code === "EPIPE";
|
|
62511
|
+
}
|
|
62512
|
+
async function classifyRegistrationFailure(error) {
|
|
62513
|
+
if (!isLostBrokerSignature(error) || await isSocketAnswering(BROKER_SOCKET))
|
|
62514
|
+
return error;
|
|
62515
|
+
return new IntercomBrokerRetiringError(`Intercom broker went away before it registered this session: ${error.message}`, {
|
|
62516
|
+
cause: error
|
|
62517
|
+
});
|
|
62518
|
+
}
|
|
62156
62519
|
function toError(error) {
|
|
62157
62520
|
return error instanceof Error ? error : new Error(String(error));
|
|
62158
62521
|
}
|
|
@@ -62162,15 +62525,22 @@ function isWorkflowFutureStageRosterEntries(value2) {
|
|
|
62162
62525
|
function isWorkflowStageRosterEntries(value2) {
|
|
62163
62526
|
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"));
|
|
62164
62527
|
}
|
|
62165
|
-
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;
|
|
62528
|
+
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;
|
|
62166
62529
|
var init_client = __esm(() => {
|
|
62167
62530
|
init_paths();
|
|
62168
62531
|
init_pending_send_registry();
|
|
62169
62532
|
init_group();
|
|
62170
62533
|
init_recoverable_disconnect();
|
|
62534
|
+
init_socket_liveness();
|
|
62171
62535
|
init_live_route_refusal();
|
|
62172
62536
|
init_retry_policy();
|
|
62173
62537
|
BROKER_SOCKET = getBrokerSocketPath();
|
|
62538
|
+
ConnectionClosedBeforeRegistrationError = class ConnectionClosedBeforeRegistrationError extends Error {
|
|
62539
|
+
constructor() {
|
|
62540
|
+
super("Connection closed before registration");
|
|
62541
|
+
this.name = "ConnectionClosedBeforeRegistrationError";
|
|
62542
|
+
}
|
|
62543
|
+
};
|
|
62174
62544
|
IntercomPendingStageRouteRefusedError = class IntercomPendingStageRouteRefusedError extends Error {
|
|
62175
62545
|
connectionKept;
|
|
62176
62546
|
code;
|
|
@@ -62338,8 +62708,14 @@ var init_client = __esm(() => {
|
|
|
62338
62708
|
} catch (error) {
|
|
62339
62709
|
if (attempt.signal.aborted)
|
|
62340
62710
|
throw connectAborted();
|
|
62341
|
-
if (!(error instanceof Error)
|
|
62711
|
+
if (!(error instanceof Error))
|
|
62342
62712
|
throw error;
|
|
62713
|
+
if (!isBacklogRefusal(error) || retry >= BROKER_BACKLOG_RETRIES) {
|
|
62714
|
+
const classified = await classifyRegistrationFailure(error);
|
|
62715
|
+
if (attempt.signal.aborted)
|
|
62716
|
+
throw connectAborted();
|
|
62717
|
+
throw classified;
|
|
62718
|
+
}
|
|
62343
62719
|
const backoff = BROKER_BACKLOG_RETRY_BASE_MS * 2 ** retry;
|
|
62344
62720
|
await abortableDelay(backoff * (0.5 + Math.random() / 2), attempt.signal);
|
|
62345
62721
|
}
|
|
@@ -62356,7 +62732,7 @@ var init_client = __esm(() => {
|
|
|
62356
62732
|
this._messageSource = messageSource ?? readSubagentMessageSource();
|
|
62357
62733
|
this._groups = normalizeGroups(session.groups, session.group);
|
|
62358
62734
|
return new Promise((resolve, reject) => {
|
|
62359
|
-
const socket =
|
|
62735
|
+
const socket = net2.connect(BROKER_SOCKET);
|
|
62360
62736
|
this.socket = socket;
|
|
62361
62737
|
this.disconnectError = null;
|
|
62362
62738
|
let settled = false;
|
|
@@ -62414,7 +62790,7 @@ var init_client = __esm(() => {
|
|
|
62414
62790
|
this.emit("disconnected", disconnectError);
|
|
62415
62791
|
}
|
|
62416
62792
|
if (wasConnecting) {
|
|
62417
|
-
reject(new
|
|
62793
|
+
reject(new ConnectionClosedBeforeRegistrationError);
|
|
62418
62794
|
}
|
|
62419
62795
|
};
|
|
62420
62796
|
const onSocketError = (err) => {
|
|
@@ -62516,7 +62892,7 @@ var init_client = __esm(() => {
|
|
|
62516
62892
|
case "registration_failed": {
|
|
62517
62893
|
if (typeof brokerMessage.reason !== "string")
|
|
62518
62894
|
throw new Error("Invalid registration_failed message");
|
|
62519
|
-
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
62895
|
+
const refusal = isLiveWorkflowStageRouteRefusalCode(brokerMessage.code) ? new IntercomLiveRouteRefusedError(brokerMessage.code, brokerMessage.reason) : brokerMessage.code === BROKER_RETIRING_CODE ? new IntercomBrokerRetiringError(brokerMessage.reason) : new Error(brokerMessage.reason);
|
|
62520
62896
|
if (this._sessionId === null) {
|
|
62521
62897
|
this.emit("_registration_failed", refusal);
|
|
62522
62898
|
break;
|
|
@@ -63411,40 +63787,34 @@ var init_client = __esm(() => {
|
|
|
63411
63787
|
};
|
|
63412
63788
|
});
|
|
63413
63789
|
|
|
63414
|
-
// dist/builtin/intercom/broker/
|
|
63415
|
-
|
|
63416
|
-
|
|
63417
|
-
|
|
63418
|
-
|
|
63419
|
-
|
|
63420
|
-
|
|
63421
|
-
|
|
63422
|
-
|
|
63423
|
-
|
|
63424
|
-
|
|
63425
|
-
|
|
63426
|
-
|
|
63427
|
-
|
|
63428
|
-
|
|
63429
|
-
|
|
63430
|
-
|
|
63431
|
-
|
|
63432
|
-
|
|
63433
|
-
|
|
63434
|
-
socket.on("connect", onConnect);
|
|
63435
|
-
socket.on("error", onError);
|
|
63436
|
-
const timeout = setTimeout(() => {
|
|
63437
|
-
socket.destroy();
|
|
63438
|
-
finish(false);
|
|
63439
|
-
}, timeoutMs);
|
|
63440
|
-
});
|
|
63790
|
+
// dist/builtin/intercom/broker/startup-timeout.ts
|
|
63791
|
+
var BROKER_READY_TIMEOUT_MS = 30000, MIN_BROKER_STARTUP_TIMEOUT_MS = 1000;
|
|
63792
|
+
|
|
63793
|
+
// dist/builtin/intercom/broker/start-announcement.ts
|
|
63794
|
+
import { readFileSync as readFileSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
63795
|
+
function readBrokerStartAnnouncement(announcement) {
|
|
63796
|
+
let text;
|
|
63797
|
+
try {
|
|
63798
|
+
text = readFileSync3(announcement.path, "utf-8");
|
|
63799
|
+
} catch {
|
|
63800
|
+
return;
|
|
63801
|
+
}
|
|
63802
|
+
if (!text.endsWith(`
|
|
63803
|
+
`))
|
|
63804
|
+
return;
|
|
63805
|
+
const [token, pid, ...rest] = text.trim().split(/\s+/u);
|
|
63806
|
+
if (token !== announcement.token || rest.length > 0)
|
|
63807
|
+
return;
|
|
63808
|
+
const parsed = Number(pid);
|
|
63809
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
63441
63810
|
}
|
|
63442
|
-
var
|
|
63443
|
-
var
|
|
63811
|
+
var BROKER_ANNOUNCE_PATH_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_PATH", BROKER_ANNOUNCE_TOKEN_ENV = "ATOMIC_INTERCOM_BROKER_ANNOUNCE_TOKEN";
|
|
63812
|
+
var init_start_announcement = () => {};
|
|
63444
63813
|
|
|
63445
63814
|
// dist/builtin/intercom/broker/spawn.ts
|
|
63446
63815
|
import { spawn } from "child_process";
|
|
63447
|
-
import {
|
|
63816
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
63817
|
+
import { appendFileSync, chmodSync, closeSync as closeSync3, existsSync as existsSync5, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync4, readSync as readSync2, statSync as statSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
63448
63818
|
import { join as join27, dirname as dirname11 } from "path";
|
|
63449
63819
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
63450
63820
|
import { createRequire as createRequire3 } from "module";
|
|
@@ -63533,7 +63903,7 @@ function getWindowsHiddenLauncherScript(commandLine) {
|
|
|
63533
63903
|
}
|
|
63534
63904
|
function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
|
|
63535
63905
|
ensurePrivateDirectory(dirname11(launcherPath));
|
|
63536
|
-
|
|
63906
|
+
writeFileSync5(launcherPath, getWindowsHiddenLauncherScript(commandLine), "utf-8");
|
|
63537
63907
|
return launcherPath;
|
|
63538
63908
|
}
|
|
63539
63909
|
function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath, runtime = getCurrentBrokerRuntime(), logPath = BROKER_LOG) {
|
|
@@ -63561,7 +63931,7 @@ function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir
|
|
|
63561
63931
|
args: [...brokerArgs, brokerPath]
|
|
63562
63932
|
};
|
|
63563
63933
|
}
|
|
63564
|
-
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore") {
|
|
63934
|
+
function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore", announcement) {
|
|
63565
63935
|
const storage = processSharedStorageSelection();
|
|
63566
63936
|
return {
|
|
63567
63937
|
detached: true,
|
|
@@ -63569,7 +63939,8 @@ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, stderr = "ignore")
|
|
|
63569
63939
|
cwd: extensionDir,
|
|
63570
63940
|
env: createChildProcessEnvironment4({
|
|
63571
63941
|
NODE_NO_WARNINGS: "1",
|
|
63572
|
-
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage }
|
|
63942
|
+
...storage === undefined ? {} : { [BROKER_STORAGE_ENV]: storage },
|
|
63943
|
+
...announcement === undefined ? {} : { [BROKER_ANNOUNCE_PATH_ENV]: announcement.path, [BROKER_ANNOUNCE_TOKEN_ENV]: announcement.token }
|
|
63573
63944
|
}),
|
|
63574
63945
|
windowsHide: true
|
|
63575
63946
|
};
|
|
@@ -63582,7 +63953,7 @@ function resetBrokerLog(logPath = BROKER_LOG) {
|
|
|
63582
63953
|
if (previous.length > 0) {
|
|
63583
63954
|
try {
|
|
63584
63955
|
const previousPath = `${logPath}.previous`;
|
|
63585
|
-
|
|
63956
|
+
writeFileSync5(previousPath, Buffer.from(previous).subarray(-BROKER_LOG_TAIL_BYTES), { mode: 384 });
|
|
63586
63957
|
if (process.platform !== "win32")
|
|
63587
63958
|
chmodSync(previousPath, 384);
|
|
63588
63959
|
} catch {}
|
|
@@ -63644,6 +64015,12 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
63644
64015
|
}
|
|
63645
64016
|
const brokerPath = resolveBrokerEntrypoint(extensionDir);
|
|
63646
64017
|
const launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir);
|
|
64018
|
+
const announcement = launch.kind === "windows-launcher" ? { path: BROKER_START_ANNOUNCEMENT, token: randomUUID14() } : undefined;
|
|
64019
|
+
if (announcement !== undefined) {
|
|
64020
|
+
try {
|
|
64021
|
+
unlinkSync4(announcement.path);
|
|
64022
|
+
} catch {}
|
|
64023
|
+
}
|
|
63647
64024
|
if (launch.kind === "windows-launcher") {
|
|
63648
64025
|
writeWindowsHiddenLauncher(launch.launcherCommandLine, launch.launcherPath);
|
|
63649
64026
|
}
|
|
@@ -63654,7 +64031,7 @@ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs, readyTimeoutMs = B
|
|
|
63654
64031
|
const logFd = launch.kind === "direct" ? openSync3(BROKER_LOG, "a") : undefined;
|
|
63655
64032
|
let child;
|
|
63656
64033
|
try {
|
|
63657
|
-
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore"));
|
|
64034
|
+
child = spawn(launch.command, launch.args, getBrokerSpawnOptions(extensionDir, logFd ?? "ignore", announcement));
|
|
63658
64035
|
} finally {
|
|
63659
64036
|
if (logFd !== undefined)
|
|
63660
64037
|
closeSync3(logFd);
|
|
@@ -63690,7 +64067,7 @@ ${describeBrokerLog()}`);
|
|
|
63690
64067
|
};
|
|
63691
64068
|
child.once("error", onError);
|
|
63692
64069
|
child.once("exit", onExit);
|
|
63693
|
-
waitForBroker(readyTimeoutMs).then(() => {
|
|
64070
|
+
waitForBroker(readyTimeoutMs, announcement === undefined ? undefined : () => readBrokerStartAnnouncement(announcement)).then(() => {
|
|
63694
64071
|
cleanup();
|
|
63695
64072
|
resolve();
|
|
63696
64073
|
}, (error) => {
|
|
@@ -63711,7 +64088,7 @@ async function isBrokerRunning() {
|
|
|
63711
64088
|
if (!existsSync5(BROKER_PID))
|
|
63712
64089
|
return false;
|
|
63713
64090
|
try {
|
|
63714
|
-
const pid = parseInt(
|
|
64091
|
+
const pid = parseInt(readFileSync4(BROKER_PID, "utf-8").trim(), 10);
|
|
63715
64092
|
if (!Number.isFinite(pid))
|
|
63716
64093
|
return false;
|
|
63717
64094
|
process.kill(pid, 0);
|
|
@@ -63736,7 +64113,7 @@ function handSpawnLockToBroker(pid, owner) {
|
|
|
63736
64113
|
}
|
|
63737
64114
|
function ownsSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
63738
64115
|
try {
|
|
63739
|
-
return
|
|
64116
|
+
return readFileSync4(lockPath, "utf-8").startsWith(owner);
|
|
63740
64117
|
} catch {
|
|
63741
64118
|
return false;
|
|
63742
64119
|
}
|
|
@@ -63748,7 +64125,7 @@ function acquireSpawnLock() {
|
|
|
63748
64125
|
${Date.now()}
|
|
63749
64126
|
`;
|
|
63750
64127
|
try {
|
|
63751
|
-
|
|
64128
|
+
writeFileSync5(BROKER_SPAWN_LOCK, owner, { flag: "wx" });
|
|
63752
64129
|
return owner;
|
|
63753
64130
|
} catch (error) {
|
|
63754
64131
|
if (!(error instanceof Error) || error.code !== "EEXIST") {
|
|
@@ -63756,7 +64133,7 @@ ${Date.now()}
|
|
|
63756
64133
|
}
|
|
63757
64134
|
if (isSpawnLockStale()) {
|
|
63758
64135
|
try {
|
|
63759
|
-
|
|
64136
|
+
unlinkSync4(BROKER_SPAWN_LOCK);
|
|
63760
64137
|
} catch {}
|
|
63761
64138
|
continue;
|
|
63762
64139
|
}
|
|
@@ -63778,7 +64155,7 @@ function isSpawnLockStale(lockPath = BROKER_SPAWN_LOCK, nowMs = Date.now()) {
|
|
|
63778
64155
|
return false;
|
|
63779
64156
|
}
|
|
63780
64157
|
try {
|
|
63781
|
-
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] =
|
|
64158
|
+
const [spawnerLine = "", createdAtLine = "", brokerLine = ""] = readFileSync4(lockPath, "utf-8").trim().split(`
|
|
63782
64159
|
`);
|
|
63783
64160
|
const spawnerPid = Number.parseInt(spawnerLine, 10);
|
|
63784
64161
|
const createdAt = Number.parseInt(createdAtLine, 10);
|
|
@@ -63796,25 +64173,34 @@ function releaseSpawnLock(owner, lockPath = BROKER_SPAWN_LOCK) {
|
|
|
63796
64173
|
if (!ownsSpawnLock(owner, lockPath))
|
|
63797
64174
|
return;
|
|
63798
64175
|
try {
|
|
63799
|
-
|
|
64176
|
+
unlinkSync4(lockPath);
|
|
63800
64177
|
} catch {}
|
|
63801
64178
|
}
|
|
63802
|
-
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS) {
|
|
64179
|
+
async function waitForBroker(timeoutMs = BROKER_READY_TIMEOUT_MS, announcedPid) {
|
|
63803
64180
|
const start = Date.now();
|
|
63804
64181
|
let interval = BROKER_POLL_INITIAL_INTERVAL_MS;
|
|
63805
64182
|
while (Date.now() - start < timeoutMs) {
|
|
63806
64183
|
if (await checkSocketConnectable()) {
|
|
63807
64184
|
return;
|
|
63808
64185
|
}
|
|
64186
|
+
const pid = announcedPid?.();
|
|
64187
|
+
if (pid !== undefined && !isProcessAlive(pid)) {
|
|
64188
|
+
if (await checkSocketConnectable())
|
|
64189
|
+
return;
|
|
64190
|
+
throw new Error(`Intercom broker exited before startup (pid ${pid})
|
|
64191
|
+
${describeBrokerLog()}`);
|
|
64192
|
+
}
|
|
63809
64193
|
await sleep(interval);
|
|
63810
64194
|
interval = Math.min(interval * 2, BROKER_POLL_MAX_INTERVAL_MS);
|
|
63811
64195
|
}
|
|
63812
|
-
throw new Error(`Broker failed to start within timeout
|
|
64196
|
+
throw new Error(`Broker failed to start within timeout (${timeoutMs} ms)
|
|
64197
|
+
` + "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).
|
|
63813
64198
|
${describeBrokerLog()}`);
|
|
63814
64199
|
}
|
|
63815
|
-
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,
|
|
64200
|
+
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";
|
|
63816
64201
|
var init_spawn = __esm(() => {
|
|
63817
64202
|
init_socket_liveness();
|
|
64203
|
+
init_start_announcement();
|
|
63818
64204
|
init_paths();
|
|
63819
64205
|
INTERCOM_DIR = getIntercomDirPath();
|
|
63820
64206
|
EXTENSION_DIR = resolveIntercomPackageRoot(import.meta.url);
|
|
@@ -63822,6 +64208,7 @@ var init_spawn = __esm(() => {
|
|
|
63822
64208
|
BROKER_PID = getBrokerPidPath();
|
|
63823
64209
|
BROKER_SPAWN_LOCK = getBrokerSpawnLockPath();
|
|
63824
64210
|
BROKER_LOG = getBrokerLogPath();
|
|
64211
|
+
BROKER_START_ANNOUNCEMENT = getBrokerStartAnnouncementPath();
|
|
63825
64212
|
BROKER_LOG_TAIL_BYTES = 8 * 1024;
|
|
63826
64213
|
});
|
|
63827
64214
|
|
|
@@ -63846,14 +64233,14 @@ var init_reply_waiter = __esm(() => {
|
|
|
63846
64233
|
});
|
|
63847
64234
|
|
|
63848
64235
|
// dist/builtin/intercom/config.ts
|
|
63849
|
-
import { existsSync as existsSync6, readFileSync as
|
|
64236
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
63850
64237
|
import { getAgentConfigPaths } from "@bastani/atomic";
|
|
63851
64238
|
function loadConfig() {
|
|
63852
64239
|
if (!existsSync6(CONFIG_PATH)) {
|
|
63853
64240
|
return { ...defaults };
|
|
63854
64241
|
}
|
|
63855
64242
|
try {
|
|
63856
|
-
const raw =
|
|
64243
|
+
const raw = readFileSync5(CONFIG_PATH, "utf-8");
|
|
63857
64244
|
const parsed = JSON.parse(raw);
|
|
63858
64245
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
63859
64246
|
throw new Error("Config must be a JSON object");
|
|
@@ -63883,6 +64270,12 @@ function loadConfig() {
|
|
|
63883
64270
|
}
|
|
63884
64271
|
config.brokerArgs = brokerArgs;
|
|
63885
64272
|
}
|
|
64273
|
+
if (Object.hasOwn(parsedConfig, "brokerStartupTimeoutMs")) {
|
|
64274
|
+
if (!Number.isInteger(parsedConfig.brokerStartupTimeoutMs) || Number(parsedConfig.brokerStartupTimeoutMs) < MIN_BROKER_STARTUP_TIMEOUT_MS) {
|
|
64275
|
+
throw new Error(`"brokerStartupTimeoutMs" must be an integer of at least ${MIN_BROKER_STARTUP_TIMEOUT_MS}`);
|
|
64276
|
+
}
|
|
64277
|
+
config.brokerStartupTimeoutMs = Number(parsedConfig.brokerStartupTimeoutMs);
|
|
64278
|
+
}
|
|
63886
64279
|
if (Object.hasOwn(parsedConfig, "confirmSend")) {
|
|
63887
64280
|
if (typeof parsedConfig.confirmSend !== "boolean") {
|
|
63888
64281
|
throw new Error(`"confirmSend" must be a boolean`);
|
|
@@ -63930,6 +64323,7 @@ var init_config = __esm(() => {
|
|
|
63930
64323
|
defaults = {
|
|
63931
64324
|
brokerCommand: DEFAULT_BROKER_COMMAND,
|
|
63932
64325
|
brokerArgs: [...DEFAULT_BROKER_ARGS],
|
|
64326
|
+
brokerStartupTimeoutMs: BROKER_READY_TIMEOUT_MS,
|
|
63933
64327
|
confirmSend: false,
|
|
63934
64328
|
maxPendingAsks: DEFAULT_MAX_PENDING_REPLY_WAITS,
|
|
63935
64329
|
replyHint: true
|
|
@@ -63950,7 +64344,7 @@ var init_reconnect_backoff = __esm(() => {
|
|
|
63950
64344
|
});
|
|
63951
64345
|
|
|
63952
64346
|
// dist/builtin/intercom/workflow-route-owner.ts
|
|
63953
|
-
import { randomUUID as
|
|
64347
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
63954
64348
|
import { createEventBus, getBuiltinPackagePaths } from "@bastani/atomic";
|
|
63955
64349
|
function closedError() {
|
|
63956
64350
|
return new Error("Workflow Intercom route owner closed");
|
|
@@ -63958,7 +64352,7 @@ function closedError() {
|
|
|
63958
64352
|
function createWorkflowRouteOwner(cwd) {
|
|
63959
64353
|
const events = createEventBus();
|
|
63960
64354
|
const config = loadConfig();
|
|
63961
|
-
const id =
|
|
64355
|
+
const id = randomUUID15();
|
|
63962
64356
|
const routes = new Map;
|
|
63963
64357
|
const connections = new Map;
|
|
63964
64358
|
const isCurrent = (state) => routes.get(state.route.runId) === state;
|
|
@@ -64022,7 +64416,7 @@ function createWorkflowRouteOwner(cwd) {
|
|
|
64022
64416
|
});
|
|
64023
64417
|
if (extensionDir === undefined)
|
|
64024
64418
|
throw new Error("Intercom builtin package is unavailable");
|
|
64025
|
-
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs,
|
|
64419
|
+
await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs, config.brokerStartupTimeoutMs, extensionDir);
|
|
64026
64420
|
if (connections.get(connection.key) !== connection)
|
|
64027
64421
|
throw closedError();
|
|
64028
64422
|
const client = new IntercomClient(`${id}:pending-stage-route:${connection.key}`, {
|
|
@@ -64666,7 +65060,7 @@ var init_startup_timeout = () => {};
|
|
|
64666
65060
|
|
|
64667
65061
|
// dist/builtin/workflows/src/workers/pool-coordinator.ts
|
|
64668
65062
|
import { fork } from "node:child_process";
|
|
64669
|
-
import { randomUUID as
|
|
65063
|
+
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
64670
65064
|
import { createWriteStream } from "node:fs";
|
|
64671
65065
|
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
64672
65066
|
import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
|
|
@@ -64891,6 +65285,9 @@ class PoolCoordinator {
|
|
|
64891
65285
|
lease;
|
|
64892
65286
|
options;
|
|
64893
65287
|
journal;
|
|
65288
|
+
durable;
|
|
65289
|
+
remote;
|
|
65290
|
+
mirrorTimer;
|
|
64894
65291
|
queue;
|
|
64895
65292
|
usageLedger;
|
|
64896
65293
|
usageTotal;
|
|
@@ -64923,6 +65320,7 @@ class PoolCoordinator {
|
|
|
64923
65320
|
while (this.inflight.size > 0)
|
|
64924
65321
|
await Promise.allSettled([...this.inflight]);
|
|
64925
65322
|
await this.journal?.close().catch(() => {});
|
|
65323
|
+
await this.durable?.close().catch(() => {});
|
|
64926
65324
|
}
|
|
64927
65325
|
receive(message) {
|
|
64928
65326
|
if (message.kind === "request-reply") {
|
|
@@ -65012,11 +65410,21 @@ class PoolCoordinator {
|
|
|
65012
65410
|
this.desiredControl ??= control;
|
|
65013
65411
|
configurePooledWatchTrace(options.journalPath, "coordinator");
|
|
65014
65412
|
this.journal ??= await resolveRunJournal({ journal: { path: options.journalPath } });
|
|
65413
|
+
if (options.durable !== undefined && this.remote === undefined) {
|
|
65414
|
+
this.durable = await openDurableJournal(options.durable);
|
|
65415
|
+
this.remote = new PoolRemoteJournal(this.durable, sqlPoolStorage(this.journal));
|
|
65416
|
+
}
|
|
65417
|
+
await this.remote?.mirror(lease);
|
|
65015
65418
|
this.usageLedger ??= await openSqlPoolUsage(this.journal);
|
|
65016
65419
|
this.usageTotal = await this.usageLedger.total(root);
|
|
65017
65420
|
this.lease = lease;
|
|
65018
|
-
const queue = await openSqlPoolQueue(this.journal);
|
|
65421
|
+
const queue = await openSqlPoolQueue(this.journal, this.remote);
|
|
65019
65422
|
await queue.initialize(lease, COORDINATOR_LEASE_MS);
|
|
65423
|
+
await queue.drainOutbox(lease);
|
|
65424
|
+
if (this.remote !== undefined) {
|
|
65425
|
+
const remote = this.remote;
|
|
65426
|
+
this.mirrorTimer = setInterval(() => void remote.fresh(lease, 0).catch(() => {}), MIRROR_INTERVAL_MS).unref();
|
|
65427
|
+
}
|
|
65020
65428
|
const retained = [];
|
|
65021
65429
|
for (const work of await queue.inspect(root))
|
|
65022
65430
|
if (work.state === "leased" && work.epoch < lease.epoch && (await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
|
|
@@ -65149,7 +65557,7 @@ class PoolCoordinator {
|
|
|
65149
65557
|
throw new Error("Worker exited before delivery acknowledgement");
|
|
65150
65558
|
const { slot, workerRequest } = target;
|
|
65151
65559
|
await new Promise((resolve, reject) => {
|
|
65152
|
-
const id =
|
|
65560
|
+
const id = randomUUID16();
|
|
65153
65561
|
slot.deliveries.set(id, { resolve, reject });
|
|
65154
65562
|
slot.child.send({ id: workerRequest, delivery: { id, from: payload.from, message: payload.message } }, (error) => {
|
|
65155
65563
|
if (error) {
|
|
@@ -65490,12 +65898,16 @@ class PoolCoordinator {
|
|
|
65490
65898
|
admission: options.admission,
|
|
65491
65899
|
...this.promptNodes ? { promptNodes: true } : {}
|
|
65492
65900
|
})
|
|
65493
|
-
], {
|
|
65901
|
+
], {
|
|
65902
|
+
stdio: ["ignore", "ignore", "pipe", "ipc"],
|
|
65903
|
+
execArgv: [],
|
|
65904
|
+
...options.durable === undefined ? {} : { env: { ...process.env, [POOL_DURABLE_JOURNAL_ENV]: JSON.stringify(options.durable) } }
|
|
65905
|
+
});
|
|
65494
65906
|
const disconnected = new Promise((resolve) => child.once("disconnect", () => resolve()));
|
|
65495
65907
|
this.children.add(child);
|
|
65496
65908
|
if (child.pid !== undefined)
|
|
65497
65909
|
this.port.send({ kind: "spawned", pid: child.pid });
|
|
65498
|
-
const worker =
|
|
65910
|
+
const worker = randomUUID16();
|
|
65499
65911
|
this.incarnations.set(worker, child);
|
|
65500
65912
|
const slot = { worker, child, deliveries: new Map, runs: new Set, stageCommands: new Map };
|
|
65501
65913
|
this.slots.add(slot);
|
|
@@ -65896,6 +66308,7 @@ class PoolCoordinator {
|
|
|
65896
66308
|
this.closed = true;
|
|
65897
66309
|
clearInterval(this.ticker);
|
|
65898
66310
|
clearInterval(this.recoveryTimer);
|
|
66311
|
+
clearInterval(this.mirrorTimer);
|
|
65899
66312
|
this.rateLimitOutbox.close();
|
|
65900
66313
|
let failure;
|
|
65901
66314
|
let stopping = [];
|
|
@@ -65974,8 +66387,10 @@ function runPoolCoordinator() {
|
|
|
65974
66387
|
port.onClose(() => process.exit(0));
|
|
65975
66388
|
return coordinator;
|
|
65976
66389
|
}
|
|
65977
|
-
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;
|
|
66390
|
+
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;
|
|
65978
66391
|
var init_pool_coordinator = __esm(() => {
|
|
66392
|
+
init_internal();
|
|
66393
|
+
init_pool_remote_journal();
|
|
65979
66394
|
init_resolution();
|
|
65980
66395
|
init_workflows_host_module();
|
|
65981
66396
|
init_sql_pool_queue();
|
|
@@ -65986,6 +66401,7 @@ var init_pool_coordinator = __esm(() => {
|
|
|
65986
66401
|
init_pending_stage_route_capability();
|
|
65987
66402
|
init_pending_stage_route_readiness();
|
|
65988
66403
|
init_store();
|
|
66404
|
+
init_pool_journal();
|
|
65989
66405
|
init_pooled_watch_trace();
|
|
65990
66406
|
init_resource_admission();
|
|
65991
66407
|
init_stage_watch_coalesce();
|
|
@@ -66800,7 +67216,7 @@ class StageToolExecutionBuffer {
|
|
|
66800
67216
|
}
|
|
66801
67217
|
|
|
66802
67218
|
// dist/builtin/workflows/src/workers/pooled-stage-handle.ts
|
|
66803
|
-
import { randomUUID as
|
|
67219
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
66804
67220
|
|
|
66805
67221
|
class PooledStageHandle {
|
|
66806
67222
|
runId;
|
|
@@ -67118,7 +67534,7 @@ class PooledStageHandle {
|
|
|
67118
67534
|
return Promise.reject(new PooledStageDeliveryError("StageNotLive", this.stageName));
|
|
67119
67535
|
const outcome = Promise.withResolvers();
|
|
67120
67536
|
const entry = {
|
|
67121
|
-
op:
|
|
67537
|
+
op: randomUUID17(),
|
|
67122
67538
|
text,
|
|
67123
67539
|
intent,
|
|
67124
67540
|
...options === undefined ? {} : { options },
|
|
@@ -67576,7 +67992,7 @@ var init_pooled_stage_registry = __esm(() => {
|
|
|
67576
67992
|
|
|
67577
67993
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
67578
67994
|
import { fork as fork2 } from "node:child_process";
|
|
67579
|
-
import { randomUUID as
|
|
67995
|
+
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
67580
67996
|
import { resolve as resolve13 } from "node:path";
|
|
67581
67997
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
67582
67998
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
@@ -67761,8 +68177,7 @@ class LocalWorkerPool {
|
|
|
67761
68177
|
async prepare(root, store) {
|
|
67762
68178
|
if (this.closed)
|
|
67763
68179
|
throw new Error("Local worker pool is closed");
|
|
67764
|
-
|
|
67765
|
-
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68180
|
+
const poolJournal = await this.poolJournal();
|
|
67766
68181
|
if (this.root !== undefined && this.root !== root)
|
|
67767
68182
|
throw new Error("Local worker pool belongs to another root");
|
|
67768
68183
|
this.root = root;
|
|
@@ -67779,6 +68194,7 @@ class LocalWorkerPool {
|
|
|
67779
68194
|
lease: this.lease,
|
|
67780
68195
|
options: {
|
|
67781
68196
|
journalPath: this.options.journalPath,
|
|
68197
|
+
...this.options.durable === undefined ? {} : { durable: this.options.durable },
|
|
67782
68198
|
workers: this.options.workers,
|
|
67783
68199
|
leaseMs: this.leaseMs,
|
|
67784
68200
|
startupTimeoutMs: this.options.startupTimeoutMs ?? defaultStartupTimeoutMs(this.options.workers),
|
|
@@ -67787,7 +68203,20 @@ class LocalWorkerPool {
|
|
|
67787
68203
|
},
|
|
67788
68204
|
...this.desiredControl === undefined ? {} : { control: this.desiredControl }
|
|
67789
68205
|
});
|
|
67790
|
-
this.queue ??= await openSqlPoolQueue(this.backend.journal);
|
|
68206
|
+
this.queue ??= await openSqlPoolQueue(poolJournal, this.options.durable === undefined ? undefined : new PoolRemoteJournal(this.backend.journal, sqlPoolStorage(poolJournal)));
|
|
68207
|
+
}
|
|
68208
|
+
async poolJournal() {
|
|
68209
|
+
const journal = this.backend.journal;
|
|
68210
|
+
if (this.options.durable === undefined) {
|
|
68211
|
+
if (!(journal instanceof SqlRunJournal) || resolve13(this.options.journalPath) !== resolve13(journal.path) || sqlPoolStorage(journal)?.tables.runs !== "wf_runs")
|
|
68212
|
+
throw new Error("Local workers require the same default-prefix SQLite journal");
|
|
68213
|
+
return journal;
|
|
68214
|
+
}
|
|
68215
|
+
if (isLocalPoolJournal(journal))
|
|
68216
|
+
throw new Error("Local workers share a local SQLite journal as it is; a durable journal selection does not apply");
|
|
68217
|
+
const coordination = await openCoordinationJournal(this.options.journalPath);
|
|
68218
|
+
registerPoolJournal(journal, coordination);
|
|
68219
|
+
return coordination;
|
|
67791
68220
|
}
|
|
67792
68221
|
async control(state) {
|
|
67793
68222
|
this.desiredControl = state;
|
|
@@ -67870,7 +68299,7 @@ class LocalWorkerPool {
|
|
|
67870
68299
|
return { ok: false, refusal: "PoolClosed" };
|
|
67871
68300
|
if (this.coordinator === undefined)
|
|
67872
68301
|
return { ok: false, refusal: "StageNotOnWorker" };
|
|
67873
|
-
const watch =
|
|
68302
|
+
const watch = randomUUID18();
|
|
67874
68303
|
this.stageWatches.set(watch, listener);
|
|
67875
68304
|
try {
|
|
67876
68305
|
const result = await this.command({ kind: "stage-watch", watch, ...ref });
|
|
@@ -68754,6 +69183,7 @@ var RECONNECT_ATTEMPT_PUBLICATIONS = 40, INTERNAL_WORKFLOW_WORKER_ARG = "--inter
|
|
|
68754
69183
|
var init_local_pool = __esm(() => {
|
|
68755
69184
|
init_internal();
|
|
68756
69185
|
init_journal_backend();
|
|
69186
|
+
init_pool_remote_journal();
|
|
68757
69187
|
init_sql_pool_queue();
|
|
68758
69188
|
init_sql_run_journal();
|
|
68759
69189
|
init_workflow_tool_abort();
|
|
@@ -68768,6 +69198,7 @@ var init_local_pool = __esm(() => {
|
|
|
68768
69198
|
init_held_prompt_answers();
|
|
68769
69199
|
init_host_options();
|
|
68770
69200
|
init_pool_coordinator();
|
|
69201
|
+
init_pool_journal();
|
|
68771
69202
|
init_pooled_stage_sources();
|
|
68772
69203
|
init_pooled_watch_trace();
|
|
68773
69204
|
init_stage_handoff();
|
|
@@ -68809,8 +69240,18 @@ async function activatePublicPool(backend, options) {
|
|
|
68809
69240
|
throw new Error("Local worker containment is unavailable on Windows; pooled tool processes cannot be enabled");
|
|
68810
69241
|
if (process.platform !== "linux" && process.platform !== "darwin" || !await hasNativeProcessIdentity() || !await admissionBootIdentity())
|
|
68811
69242
|
throw new Error("Local worker containment requires native process identity support");
|
|
68812
|
-
if (!(backend instanceof JournalDurableBackend)
|
|
68813
|
-
throw new Error("Local workers require a
|
|
69243
|
+
if (!(backend instanceof JournalDurableBackend))
|
|
69244
|
+
throw new Error("Local workers require a journal backend");
|
|
69245
|
+
const local = isLocalPoolJournal(backend.journal);
|
|
69246
|
+
let durable;
|
|
69247
|
+
let poolJournal = backend.journal;
|
|
69248
|
+
let poolPath = local ? backend.journal.path : "";
|
|
69249
|
+
if (!local) {
|
|
69250
|
+
durable = poolDurableJournal(backend.journal);
|
|
69251
|
+
poolPath = coordinationPath(durable);
|
|
69252
|
+
poolJournal = await openCoordinationJournal(poolPath);
|
|
69253
|
+
registerPoolJournal(backend.journal, poolJournal);
|
|
69254
|
+
}
|
|
68814
69255
|
const cwd = options.cwd ?? process.cwd();
|
|
68815
69256
|
const localWorkers = options.localWorkers && {
|
|
68816
69257
|
...options.localWorkers,
|
|
@@ -68822,16 +69263,27 @@ async function activatePublicPool(backend, options) {
|
|
|
68822
69263
|
...options.admission,
|
|
68823
69264
|
...options.admission.userDatabase ? { userDatabase: resolve14(cwd, options.admission.userDatabase) } : {}
|
|
68824
69265
|
};
|
|
69266
|
+
if (durable !== undefined && admission?.userLimits) {
|
|
69267
|
+
if (admission.userDatabase !== undefined && admission.userDatabase !== resolve14(poolPath))
|
|
69268
|
+
throw new Error(`admission.userDatabase must be omitted, or ${resolve14(poolPath)}, for a journal that is not a local SQLite file`);
|
|
69269
|
+
admission.userDatabase = resolve14(poolPath);
|
|
69270
|
+
}
|
|
68825
69271
|
const sources = localWorkers && await Promise.all(localWorkers.definitions.map(async (source) => ({ ...source, digest: await definitionDigest(source.path) })));
|
|
68826
69272
|
const resources = JSON.parse(JSON.stringify({
|
|
68827
69273
|
...localWorkers ? { localWorkers, definitions: sources } : {},
|
|
68828
|
-
...admission ? { admission } : {}
|
|
69274
|
+
...admission ? { admission } : {},
|
|
69275
|
+
...durable !== undefined && localWorkers ? { coordinator: { host: poolHostId(durable.agentDir), database: coordinationDatabase(durable) } } : {}
|
|
68829
69276
|
}));
|
|
69277
|
+
const saved = options.effectiveResources?.coordinator;
|
|
69278
|
+
if (saved !== undefined && resources.coordinator !== undefined && saved.host !== resources.coordinator.host)
|
|
69279
|
+
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.`);
|
|
69280
|
+
if (saved !== undefined && resources.coordinator !== undefined && saved.host === resources.coordinator.host && saved.database !== resources.coordinator.database)
|
|
69281
|
+
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.`);
|
|
68830
69282
|
if (options.effectiveResources && !isDeepStrictEqual2(options.effectiveResources, resources))
|
|
68831
69283
|
throw new Error("Worker definition compatibility or immutable resource configuration changed");
|
|
68832
69284
|
options.effectiveResources = resources;
|
|
68833
69285
|
if (resources.admission)
|
|
68834
|
-
await SqlResourceAdmission.open(
|
|
69286
|
+
await SqlResourceAdmission.open(poolJournal, {
|
|
68835
69287
|
...resources.admission,
|
|
68836
69288
|
root: options.runId,
|
|
68837
69289
|
holder: "preflight"
|
|
@@ -68841,7 +69293,8 @@ async function activatePublicPool(backend, options) {
|
|
|
68841
69293
|
const definitions = await Promise.all((sources ?? []).map(async (source) => ({ ...source, definition: await loadWorkerDefinition(source) })));
|
|
68842
69294
|
const pool = new LocalWorkerPool(backend, {
|
|
68843
69295
|
rootId: options.runId,
|
|
68844
|
-
journalPath:
|
|
69296
|
+
journalPath: poolPath,
|
|
69297
|
+
...durable === undefined ? {} : { durable },
|
|
68845
69298
|
workers: localWorkers.count,
|
|
68846
69299
|
definitions,
|
|
68847
69300
|
admission: resources.admission ?? {},
|
|
@@ -68858,13 +69311,12 @@ async function activatePublicPool(backend, options) {
|
|
|
68858
69311
|
}
|
|
68859
69312
|
}
|
|
68860
69313
|
var init_public_pool = __esm(() => {
|
|
68861
|
-
init_internal();
|
|
68862
69314
|
init_journal_backend();
|
|
68863
|
-
init_sql_run_journal();
|
|
68864
69315
|
init_admission_host();
|
|
68865
69316
|
init_definitions();
|
|
68866
69317
|
init_host_options();
|
|
68867
69318
|
init_local_pool();
|
|
69319
|
+
init_pool_journal();
|
|
68868
69320
|
init_resource_admission();
|
|
68869
69321
|
});
|
|
68870
69322
|
|
|
@@ -69324,7 +69776,7 @@ var init_run_budget = __esm(() => {
|
|
|
69324
69776
|
});
|
|
69325
69777
|
|
|
69326
69778
|
// dist/builtin/workflows/src/engine/primitives/parallel.ts
|
|
69327
|
-
import { randomUUID as
|
|
69779
|
+
import { randomUUID as randomUUID19 } from "node:crypto";
|
|
69328
69780
|
function createParallelPrimitive(input) {
|
|
69329
69781
|
return async (steps, options = {}) => {
|
|
69330
69782
|
input.runtime.exit.throwIfWorkflowExitSelected();
|
|
@@ -69332,7 +69784,7 @@ function createParallelPrimitive(input) {
|
|
|
69332
69784
|
const normalizedOptions = normalizeGroup(options);
|
|
69333
69785
|
const normalizedSteps = steps.map(normalizeGroup);
|
|
69334
69786
|
const needsAutoGroup = normalizedOptions.group === true || normalizedSteps.some((step) => step.group === true);
|
|
69335
|
-
const autoGroup = needsAutoGroup ?
|
|
69787
|
+
const autoGroup = needsAutoGroup ? randomUUID19() : undefined;
|
|
69336
69788
|
const resolveAutoGroup = (value2) => value2.group === true && autoGroup ? { ...value2, group: autoGroup } : value2;
|
|
69337
69789
|
const resolvedOptions = resolveAutoGroup(normalizedOptions);
|
|
69338
69790
|
const resolvedSteps = normalizedSteps.map(resolveAutoGroup);
|
|
@@ -70216,7 +70668,7 @@ function hasUsableContentBlock(block) {
|
|
|
70216
70668
|
}
|
|
70217
70669
|
|
|
70218
70670
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
70219
|
-
import { randomUUID as
|
|
70671
|
+
import { randomUUID as randomUUID20 } from "node:crypto";
|
|
70220
70672
|
import { dirname as dirname14, resolve as resolve15 } from "node:path";
|
|
70221
70673
|
import {
|
|
70222
70674
|
JsonlSessionStore,
|
|
@@ -70238,7 +70690,7 @@ async function stageSessionStore(options, defaultSessionDir) {
|
|
|
70238
70690
|
}
|
|
70239
70691
|
async function forkStageSession(store, sessionId, cwd, options, destination = store) {
|
|
70240
70692
|
const source = await store.load(sessionId);
|
|
70241
|
-
const id =
|
|
70693
|
+
const id = randomUUID20();
|
|
70242
70694
|
await destination.create({
|
|
70243
70695
|
id,
|
|
70244
70696
|
version: 4,
|
|
@@ -70273,6 +70725,7 @@ var init_stage_session_store = () => {};
|
|
|
70273
70725
|
// dist/builtin/workflows/src/workers/pool-session-store.ts
|
|
70274
70726
|
var init_pool_session_store = __esm(() => {
|
|
70275
70727
|
init_internal();
|
|
70728
|
+
init_pool_journal();
|
|
70276
70729
|
});
|
|
70277
70730
|
|
|
70278
70731
|
// dist/builtin/workflows/src/durable/completed-catalog-index.ts
|
|
@@ -78961,7 +79414,7 @@ var init_executor = __esm(() => {
|
|
|
78961
79414
|
});
|
|
78962
79415
|
|
|
78963
79416
|
// dist/builtin/workflows/src/runs/foreground/sdk-run.ts
|
|
78964
|
-
import { randomUUID as
|
|
79417
|
+
import { randomUUID as randomUUID21 } from "node:crypto";
|
|
78965
79418
|
async function run2(def, inputs, callerOpts = {}) {
|
|
78966
79419
|
let opts = callerOpts;
|
|
78967
79420
|
const store2 = opts.store === undefined || opts.store === store ? currentWorkflowStore() : opts.store;
|
|
@@ -78972,7 +79425,7 @@ async function run2(def, inputs, callerOpts = {}) {
|
|
|
78972
79425
|
if (opts.journal === undefined && opts.durableBackend === undefined && ownedBackend === undefined) {
|
|
78973
79426
|
bindStoreDurableBackend(store2, backend);
|
|
78974
79427
|
}
|
|
78975
|
-
const runId = opts.runId ??
|
|
79428
|
+
const runId = opts.runId ?? randomUUID21();
|
|
78976
79429
|
if (sourceRunId !== undefined || opts.localWorkers || opts.admission) {
|
|
78977
79430
|
opts = await restoreWorkerOptions(backend, { ...opts, runId });
|
|
78978
79431
|
}
|
|
@@ -79142,10 +79595,128 @@ var init_workflows_host_module = __esm(() => {
|
|
|
79142
79595
|
provideRunJournalHostModules({ "@bastani/atomic/workflows": exports_sdk_surface });
|
|
79143
79596
|
});
|
|
79144
79597
|
|
|
79598
|
+
// dist/builtin/workflows/src/workers/pool-journal.ts
|
|
79599
|
+
import { createHash as createHash6, randomUUID as randomUUID22 } from "node:crypto";
|
|
79600
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
79601
|
+
import { basename as basename6, dirname as dirname16, join as join31, resolve as resolve17 } from "node:path";
|
|
79602
|
+
import { storageSelectionKey as storageSelectionKey2 } from "@bastani/atomic/storage";
|
|
79603
|
+
function encodeOption(value2) {
|
|
79604
|
+
if (typeof value2 === "bigint")
|
|
79605
|
+
return { $bigint: value2.toString() };
|
|
79606
|
+
if (value2 instanceof Uint8Array)
|
|
79607
|
+
return { $bytes: Buffer.from(value2).toString("base64") };
|
|
79608
|
+
return value2;
|
|
79609
|
+
}
|
|
79610
|
+
function decodeOption(value2) {
|
|
79611
|
+
if (value2 !== null && typeof value2 === "object") {
|
|
79612
|
+
if ("$bigint" in value2)
|
|
79613
|
+
return BigInt(value2.$bigint);
|
|
79614
|
+
return new Uint8Array(Buffer.from(value2.$bytes, "base64"));
|
|
79615
|
+
}
|
|
79616
|
+
return value2;
|
|
79617
|
+
}
|
|
79618
|
+
function isReopenableSelection(selection) {
|
|
79619
|
+
return selection.kind === "sqlite" || selection.kind === "adapter";
|
|
79620
|
+
}
|
|
79621
|
+
function encodeSelection(selection) {
|
|
79622
|
+
if (selection.kind === "sqlite")
|
|
79623
|
+
return JSON.stringify({ ...selection, path: resolve17(selection.path) });
|
|
79624
|
+
return JSON.stringify({
|
|
79625
|
+
...selection,
|
|
79626
|
+
...selection.options === undefined ? {} : {
|
|
79627
|
+
options: Object.fromEntries(Object.entries(selection.options).map(([key, value2]) => [key, encodeOption(value2)]))
|
|
79628
|
+
}
|
|
79629
|
+
});
|
|
79630
|
+
}
|
|
79631
|
+
function decodeSelection(text) {
|
|
79632
|
+
const value2 = JSON.parse(text);
|
|
79633
|
+
if (value2.kind === "sqlite" || value2.options === undefined)
|
|
79634
|
+
return value2;
|
|
79635
|
+
return {
|
|
79636
|
+
...value2,
|
|
79637
|
+
options: Object.fromEntries(Object.entries(value2.options).map(([key, option]) => [key, decodeOption(option)]))
|
|
79638
|
+
};
|
|
79639
|
+
}
|
|
79640
|
+
function isLocalPoolJournal(journal) {
|
|
79641
|
+
return journal instanceof SqlRunJournal && journal.descriptor.adapter === "node-sqlite" && journal.path !== ":memory:" && sqlPoolStorage(journal)?.tables.runs === "wf_runs";
|
|
79642
|
+
}
|
|
79643
|
+
function poolDurableJournal(journal) {
|
|
79644
|
+
const origin = runJournalOrigin(journal);
|
|
79645
|
+
if (origin === undefined)
|
|
79646
|
+
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");
|
|
79647
|
+
if (!isReopenableSelection(origin.selection))
|
|
79648
|
+
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}`);
|
|
79649
|
+
return { selection: encodeSelection(origin.selection), agentDir: origin.agentDir };
|
|
79650
|
+
}
|
|
79651
|
+
function openDurableJournal(durable) {
|
|
79652
|
+
return openSelectedRunJournal(decodeSelection(durable.selection), durable.agentDir);
|
|
79653
|
+
}
|
|
79654
|
+
function poolStateDirectory(agentDir) {
|
|
79655
|
+
return join31(dirname16(agentDir), "workflows", "pool");
|
|
79656
|
+
}
|
|
79657
|
+
function databaseIdentity(selection, agentDir) {
|
|
79658
|
+
return storageSelectionKey2(selection.kind === "adapter" ? { ...selection, secrets: undefined } : selection, agentDir);
|
|
79659
|
+
}
|
|
79660
|
+
function coordinationPath(durable) {
|
|
79661
|
+
const selection = decodeSelection(durable.selection);
|
|
79662
|
+
const identity = createHash6("sha256").update(databaseIdentity(selection, durable.agentDir)).digest("hex");
|
|
79663
|
+
return join31(poolStateDirectory(durable.agentDir), `${identity.slice(0, 24)}.sqlite`);
|
|
79664
|
+
}
|
|
79665
|
+
function coordinationDatabase(durable) {
|
|
79666
|
+
return basename6(coordinationPath(durable), ".sqlite");
|
|
79667
|
+
}
|
|
79668
|
+
function openCoordinationJournal(path) {
|
|
79669
|
+
const file = resolve17(path);
|
|
79670
|
+
let opened = coordinationJournals.get(file);
|
|
79671
|
+
if (opened === undefined) {
|
|
79672
|
+
mkdirSync8(dirname16(file), { recursive: true });
|
|
79673
|
+
opened = resolveRunJournal({ journal: { path: file } });
|
|
79674
|
+
coordinationJournals.set(file, opened);
|
|
79675
|
+
opened.catch(() => {
|
|
79676
|
+
if (coordinationJournals.get(file) === opened)
|
|
79677
|
+
coordinationJournals.delete(file);
|
|
79678
|
+
});
|
|
79679
|
+
}
|
|
79680
|
+
return opened;
|
|
79681
|
+
}
|
|
79682
|
+
function registerPoolJournal(durable, coordination) {
|
|
79683
|
+
coordinations.set(durable, coordination);
|
|
79684
|
+
}
|
|
79685
|
+
function poolJournalFor(journal) {
|
|
79686
|
+
return coordinations.get(journal) ?? journal;
|
|
79687
|
+
}
|
|
79688
|
+
function poolHostId(agentDir) {
|
|
79689
|
+
const file = join31(poolStateDirectory(agentDir), "host-id");
|
|
79690
|
+
try {
|
|
79691
|
+
const existing = readFileSync6(file, "utf8").trim();
|
|
79692
|
+
if (existing !== "")
|
|
79693
|
+
return existing;
|
|
79694
|
+
} catch {}
|
|
79695
|
+
mkdirSync8(dirname16(file), { recursive: true });
|
|
79696
|
+
const id = randomUUID22();
|
|
79697
|
+
try {
|
|
79698
|
+
writeFileSync6(file, `${id}
|
|
79699
|
+
`, { flag: "wx" });
|
|
79700
|
+
return id;
|
|
79701
|
+
} catch {
|
|
79702
|
+
return readFileSync6(file, "utf8").trim();
|
|
79703
|
+
}
|
|
79704
|
+
}
|
|
79705
|
+
var POOL_DURABLE_JOURNAL_ENV = "ATOMIC_POOL_DURABLE_JOURNAL", coordinationJournals, coordinations;
|
|
79706
|
+
var init_pool_journal = __esm(() => {
|
|
79707
|
+
init_internal();
|
|
79708
|
+
init_workflows_host_module();
|
|
79709
|
+
init_resolution();
|
|
79710
|
+
init_sql_run_journal();
|
|
79711
|
+
coordinationJournals = new Map;
|
|
79712
|
+
coordinations = new WeakMap;
|
|
79713
|
+
});
|
|
79714
|
+
|
|
79145
79715
|
// dist/builtin/workflows/src/workers/local-worker.ts
|
|
79146
79716
|
init_internal();
|
|
79147
79717
|
init_journal_backend();
|
|
79148
79718
|
init_resolution();
|
|
79719
|
+
init_pool_journal();
|
|
79149
79720
|
init_workflows_host_module();
|
|
79150
79721
|
init_run();
|
|
79151
79722
|
init_run_tool_control_registry();
|
|
@@ -79157,7 +79728,7 @@ init_stage_ui_broker();
|
|
|
79157
79728
|
init_store();
|
|
79158
79729
|
init_admission_binding();
|
|
79159
79730
|
init_definitions();
|
|
79160
|
-
import { randomUUID as
|
|
79731
|
+
import { randomUUID as randomUUID24 } from "node:crypto";
|
|
79161
79732
|
import { setTimeout as delay4 } from "node:timers/promises";
|
|
79162
79733
|
import {
|
|
79163
79734
|
applyProviderRateLimitObservation as applyProviderRateLimitObservation2,
|
|
@@ -79183,7 +79754,7 @@ init_resource_admission();
|
|
|
79183
79754
|
// dist/builtin/workflows/src/workers/session-store.ts
|
|
79184
79755
|
init_stage_topology();
|
|
79185
79756
|
init_run_durable_topology();
|
|
79186
|
-
import { randomUUID as
|
|
79757
|
+
import { randomUUID as randomUUID23 } from "node:crypto";
|
|
79187
79758
|
function workerSessionStore(input) {
|
|
79188
79759
|
const checkpoint = (id, header) => {
|
|
79189
79760
|
const owner = header.workflow;
|
|
@@ -79199,7 +79770,7 @@ function workerSessionStore(input) {
|
|
|
79199
79770
|
...durableStageCheckpointMetadata(stage, durableRunTopology(run), run.stages.indexOf(stage)),
|
|
79200
79771
|
kind: "stage",
|
|
79201
79772
|
workflowId: input.root,
|
|
79202
|
-
checkpointId: `${prefix}:session:${id}:${
|
|
79773
|
+
checkpointId: `${prefix}:session:${id}:${randomUUID23()}`,
|
|
79203
79774
|
replayKey: `${prefix}:${stage.replayKey}`,
|
|
79204
79775
|
name: stage.name,
|
|
79205
79776
|
sessionId: id,
|
|
@@ -79863,7 +80434,10 @@ async function runWorker(start) {
|
|
|
79863
80434
|
});
|
|
79864
80435
|
});
|
|
79865
80436
|
const definitions = await Promise.all(start.definitions.map(loadWorkerDefinition));
|
|
79866
|
-
const
|
|
80437
|
+
const poolJournal = await resolveRunJournal({ journal: { path: start.journalPath } });
|
|
80438
|
+
const durableSelection = process.env[POOL_DURABLE_JOURNAL_ENV];
|
|
80439
|
+
delete process.env[POOL_DURABLE_JOURNAL_ENV];
|
|
80440
|
+
const journal = durableSelection === undefined ? poolJournal : await openDurableJournal(JSON.parse(durableSelection));
|
|
79867
80441
|
const journalReads = new Set(["descriptor", "getRun", "listRuns", "read", "readKey", "leaseState", "close"]);
|
|
79868
80442
|
const readOnlyJournal = new Proxy(journal, {
|
|
79869
80443
|
get(target, key) {
|
|
@@ -79877,9 +80451,9 @@ async function runWorker(start) {
|
|
|
79877
80451
|
});
|
|
79878
80452
|
const reader = await JournalDurableBackend.open(readOnlyJournal, { runs: [] });
|
|
79879
80453
|
configurePooledWatchTrace(start.journalPath, `worker:${process.pid}`);
|
|
79880
|
-
const sessions = await new StorageProvider3().openSessionStore({ kind: "sqlite", path: start.journalPath, prefix: `${sqlPoolStorage(
|
|
80454
|
+
const sessions = await new StorageProvider3().openSessionStore({ kind: "sqlite", path: start.journalPath, prefix: `${sqlPoolStorage(poolJournal).tables.runs}_pool_` }, { agentDir: "", domain: "sessions" });
|
|
79881
80455
|
const commit = poolWorkerCommit({
|
|
79882
|
-
send: async (mutation) => await request({ kind: "commit", operation:
|
|
80456
|
+
send: async (mutation) => await request({ kind: "commit", operation: randomUUID24(), mutation }),
|
|
79883
80457
|
catchUp: () => reader.catchUpWorkflow(start.root)
|
|
79884
80458
|
});
|
|
79885
80459
|
const reads = new Set([
|
|
@@ -80024,7 +80598,7 @@ async function runWorker(start) {
|
|
|
80024
80598
|
});
|
|
80025
80599
|
};
|
|
80026
80600
|
const unsubscribe = store.subscribeInvalidation(publish);
|
|
80027
|
-
const admission = start.admission ? await SqlResourceAdmission.open(
|
|
80601
|
+
const admission = start.admission ? await SqlResourceAdmission.open(poolJournal, {
|
|
80028
80602
|
...start.admission,
|
|
80029
80603
|
root: start.root,
|
|
80030
80604
|
holder: work.worker,
|
|
@@ -80173,6 +80747,8 @@ async function runWorker(start) {
|
|
|
80173
80747
|
} finally {
|
|
80174
80748
|
await reader.close();
|
|
80175
80749
|
await sessions.close();
|
|
80750
|
+
if (poolJournal !== journal)
|
|
80751
|
+
await poolJournal.close().catch(() => {});
|
|
80176
80752
|
}
|
|
80177
80753
|
if (rootLeaseLost)
|
|
80178
80754
|
process.disconnect?.();
|