@bastani/atomic 0.9.42 → 0.9.43-alpha.1

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.
@@ -989,8 +989,14 @@ function registerSqlPoolStorage(journal, storage) {
989
989
  function sqlPoolStorage(journal) {
990
990
  return poolStorage.get(journal);
991
991
  }
992
- var JOURNAL_READ_PAGE_SIZE = 256, versionReaders, poolStorage;
992
+ var JOURNAL_READ_PAGE_SIZE = 256, NON_SNAPSHOT_EVENT_TYPES, versionReaders, poolStorage;
993
993
  var init_internal = __esm(() => {
994
+ init_types();
995
+ NON_SNAPSHOT_EVENT_TYPES = [
996
+ RUN_EVENT_TYPES.checkpointRecorded,
997
+ RUN_EVENT_TYPES.messageSettled,
998
+ RUN_EVENT_TYPES.messageDelivered
999
+ ];
994
1000
  versionReaders = new WeakMap;
995
1001
  poolStorage = new WeakMap;
996
1002
  });
@@ -1372,7 +1378,8 @@ class SqlRunJournal {
1372
1378
  this.legacy = legacy;
1373
1379
  registerRunJournalVersions(this, {
1374
1380
  changeToken: () => this.changeToken(),
1375
- runVersions: () => this.runVersions()
1381
+ runVersions: () => this.runVersions(),
1382
+ snapshotTail: (runId) => this.snapshotTail(runId)
1376
1383
  });
1377
1384
  registerSqlPoolStorage(this, {
1378
1385
  transaction: (body) => this.operation(() => this.database.transaction(body)),
@@ -1498,6 +1505,28 @@ class SqlRunJournal {
1498
1505
  ]));
1499
1506
  });
1500
1507
  }
1508
+ async snapshotTail(runId) {
1509
+ this.assertOpen();
1510
+ validateText("runId", runId);
1511
+ return this.operation(async () => {
1512
+ const events = await this.isUnconvertedLegacyRun(runId) ? JOURNAL_TABLES.events : this.tables.events;
1513
+ const later = `FROM ${events} AS later WHERE later.${JOURNAL_COLUMNS.runId} = snapshot.${JOURNAL_COLUMNS.runId} AND later.${JOURNAL_COLUMNS.seq} > snapshot.${JOURNAL_COLUMNS.seq} AND later.${JOURNAL_COLUMNS.type} = ?`;
1514
+ const row = await this.database.get(`SELECT ${EVENT_COLUMNS.map((column) => `snapshot.${column}`).join(", ")},
1515
+ latest.${JOURNAL_COLUMNS.seq} AS latest_seq, latest.${JOURNAL_COLUMNS.at} AS latest_at,
1516
+ (SELECT count(*) ${later}) AS later_checkpoints,
1517
+ (SELECT json_extract(later.${JOURNAL_COLUMNS.payload}, '$.completedAt') ${later} ORDER BY later.${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS last_checkpoint_at
1518
+ FROM (SELECT ${JOURNAL_COLUMNS.seq}, ${JOURNAL_COLUMNS.at} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS latest,
1519
+ (SELECT ${EVENT_COLUMNS.join(", ")} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.type} NOT IN (${NON_SNAPSHOT_EVENT_TYPES.map(() => "?").join(", ")}) ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS snapshot`, RUN_EVENT_TYPES.checkpointRecorded, RUN_EVENT_TYPES.checkpointRecorded, runId, runId, ...NON_SNAPSHOT_EVENT_TYPES);
1520
+ if (row === undefined)
1521
+ return;
1522
+ return {
1523
+ version: { seq: journalCounter(runId, "seq", row.latest_seq), at: Number(row.latest_at) },
1524
+ snapshot: entryFromRow(row),
1525
+ laterCheckpoints: Number(row.later_checkpoints),
1526
+ ...row.last_checkpoint_at === null ? {} : { lastCheckpointAt: Number(row.last_checkpoint_at) }
1527
+ };
1528
+ });
1529
+ }
1501
1530
  async requireRun(tx, runId) {
1502
1531
  if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
1503
1532
  return;
@@ -1715,13 +1744,14 @@ class SqlRunJournal {
1715
1744
  return this.closePromise;
1716
1745
  }
1717
1746
  }
1718
- var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)";
1747
+ var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", EVENT_COLUMNS;
1719
1748
  var init_sql_run_journal = __esm(() => {
1720
1749
  init_internal();
1721
1750
  init_legacy_journal_tables();
1722
1751
  init_types();
1723
1752
  init_values();
1724
1753
  init_internal();
1754
+ EVENT_COLUMNS = [JOURNAL_COLUMNS.runId, JOURNAL_COLUMNS.seq, JOURNAL_COLUMNS.epoch, JOURNAL_COLUMNS.key, JOURNAL_COLUMNS.type, JOURNAL_COLUMNS.payload, JOURNAL_COLUMNS.at];
1725
1755
  });
1726
1756
 
1727
1757
  // dist/builtin/workflows/src/durable/journal/resolution.ts
@@ -9853,6 +9883,7 @@ class JournalDurableBackend {
9853
9883
  projection = createJournalProjection();
9854
9884
  sequences = new Map;
9855
9885
  foldedAt = new Map;
9886
+ summarized = new Map;
9856
9887
  catalogToken;
9857
9888
  leases = new Map;
9858
9889
  executions = new Map;
@@ -9878,8 +9909,8 @@ class JournalDurableBackend {
9878
9909
  let backend;
9879
9910
  try {
9880
9911
  backend = new JournalDurableBackend(journal, undefined, options.ownsJournal ?? true);
9881
- for (const run of await journal.listRuns())
9882
- for await (const entry of journal.read(run.runId))
9912
+ for (const runId of options.runs ?? (await journal.listRuns()).map((run) => run.runId))
9913
+ for await (const entry of journal.read(runId))
9883
9914
  backend.fold(entry);
9884
9915
  return backend;
9885
9916
  } catch (error) {
@@ -9952,6 +9983,18 @@ class JournalDurableBackend {
9952
9983
  this.sequences.set(entry.runId, entry.seq);
9953
9984
  this.foldedAt.set(entry.runId, entry.at);
9954
9985
  }
9986
+ summarize(runId, tail) {
9987
+ const event = tail.snapshot.event;
9988
+ const handle = event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased ? event.payload.handle : event.payload;
9989
+ this.projection.deleteWorkflow(runId);
9990
+ this.prompts.delete(runId);
9991
+ this.projection.applyWorkflowSnapshot({
9992
+ ...handle,
9993
+ completedCheckpoints: handle.completedCheckpoints + tail.laterCheckpoints,
9994
+ ...tail.lastCheckpointAt === undefined ? {} : { updatedAt: tail.lastCheckpointAt }
9995
+ });
9996
+ this.summarized.set(runId, tail.version);
9997
+ }
9955
9998
  *entries(runId, fromSeq) {
9956
9999
  return yield* invoke(async () => {
9957
10000
  const entries = [];
@@ -9965,6 +10008,7 @@ class JournalDurableBackend {
9965
10008
  this.projection.deleteWorkflow(runId);
9966
10009
  this.sequences.delete(runId);
9967
10010
  this.foldedAt.delete(runId);
10011
+ this.summarized.delete(runId);
9968
10012
  this.prompts.delete(runId);
9969
10013
  for (const entry of entries)
9970
10014
  this.fold(entry);
@@ -10286,6 +10330,9 @@ class JournalDurableBackend {
10286
10330
  async hydrateWorkflow(runId) {
10287
10331
  await this.serialize(runId, () => this.rebuild(runId), false);
10288
10332
  }
10333
+ async catchUpWorkflow(runId) {
10334
+ await this.serialize(runId, () => this.extend(runId), false);
10335
+ }
10289
10336
  hydrateResumableWorkflows() {
10290
10337
  return this.serialize(this.catalogQueue, () => invoke(async () => {
10291
10338
  const journal = runJournalVersions(this.journal);
@@ -10299,16 +10346,33 @@ class JournalDurableBackend {
10299
10346
  if (token === this.catalogToken)
10300
10347
  return;
10301
10348
  const versions = await journal.runVersions();
10302
- for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
10303
- await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
10349
+ for (const runId of new Set([...this.sequences.keys(), ...this.summarized.keys(), ...versions.keys()]))
10350
+ await this.serialize(runId, () => this.catchUp(runId, versions.get(runId), journal), false);
10304
10351
  this.catalogToken = token;
10305
10352
  }));
10306
10353
  }
10307
- *catchUp(runId, version) {
10354
+ *catchUp(runId, version, journal) {
10308
10355
  const folded = this.sequences.get(runId) ?? 0;
10356
+ if (folded === 0 && version !== undefined) {
10357
+ const summarized = this.summarized.get(runId);
10358
+ if (summarized !== undefined && summarized.seq === version.seq && summarized.at === version.at)
10359
+ return;
10360
+ const tail = yield* invoke(() => journal.snapshotTail(runId));
10361
+ if (tail !== undefined)
10362
+ return this.summarize(runId, tail);
10363
+ if (summarized === undefined && version.seq === 0)
10364
+ return;
10365
+ return yield* this.rebuild(runId);
10366
+ }
10309
10367
  if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
10310
10368
  return;
10311
- if (version !== undefined && folded > 0 && version.seq > folded) {
10369
+ if (version !== undefined && folded > 0 && version.seq > folded)
10370
+ return yield* this.extend(runId);
10371
+ yield* this.rebuild(runId);
10372
+ }
10373
+ *extend(runId) {
10374
+ const folded = this.sequences.get(runId) ?? 0;
10375
+ if (folded > 0) {
10312
10376
  const entries = yield* this.entries(runId, folded);
10313
10377
  if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
10314
10378
  for (const entry of entries)
@@ -10336,6 +10400,7 @@ class JournalDurableBackend {
10336
10400
  this.leases.delete(runId);
10337
10401
  this.sequences.delete(runId);
10338
10402
  this.foldedAt.delete(runId);
10403
+ this.summarized.delete(runId);
10339
10404
  this.prompts.delete(runId);
10340
10405
  this.projection.deleteWorkflow(runId);
10341
10406
  }
@@ -10600,7 +10665,13 @@ async function initializeDurableBackend(options = {}) {
10600
10665
  const selected = owner.selectedBackends;
10601
10666
  const existing = selected.get(key);
10602
10667
  const entry = existing ?? {
10603
- ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal })).then((opened) => {
10668
+ ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal, runs: [] })).then(async (opened) => {
10669
+ try {
10670
+ await opened.hydrateResumableWorkflows();
10671
+ } catch (error) {
10672
+ await opened.close();
10673
+ throw error;
10674
+ }
10604
10675
  if (ownsJournal)
10605
10676
  opened.closeOnProcessExit();
10606
10677
  entry.close = () => opened.close();
@@ -57495,7 +57566,7 @@ class SqlPoolQueue {
57495
57566
  });
57496
57567
  const row = await this.current(tx, lease, token);
57497
57568
  if (row.epoch !== lease.epoch || row.expires_at < now)
57498
- throw new Error("Stale work lease");
57569
+ throw new Error(STALE_WORK_LEASE);
57499
57570
  assertSession();
57500
57571
  }, action);
57501
57572
  }
@@ -57504,7 +57575,7 @@ class SqlPoolQueue {
57504
57575
  const { now } = await this.authority(tx, lease);
57505
57576
  const row = await this.current(tx, lease, token);
57506
57577
  if (row.epoch !== lease.epoch || row.expires_at < now)
57507
- throw new Error("Stale work lease");
57578
+ throw new Error(STALE_WORK_LEASE);
57508
57579
  });
57509
57580
  }
57510
57581
  async enqueue(lease, descriptor, boundary) {
@@ -57584,7 +57655,7 @@ class SqlPoolQueue {
57584
57655
  async current(tx, lease, token, allowCompleted = false) {
57585
57656
  const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
57586
57657
  if (row?.state !== "leased" && !(allowCompleted && row?.state === "completed") || row.epoch !== token.epoch || row.generation !== token.generation || row.worker !== token.worker)
57587
- throw new Error("Stale work lease");
57658
+ throw new Error(STALE_WORK_LEASE);
57588
57659
  return row;
57589
57660
  }
57590
57661
  async renew(lease, token, operationId, durationMs) {
@@ -57597,7 +57668,7 @@ class SqlPoolQueue {
57597
57668
  const { now } = await this.authority(tx, lease);
57598
57669
  const row = await this.current(tx, lease, token);
57599
57670
  if (row.epoch !== lease.epoch || row.expires_at < now)
57600
- throw new Error("Stale work lease");
57671
+ throw new Error(STALE_WORK_LEASE);
57601
57672
  const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
57602
57673
  if (previous) {
57603
57674
  if (previous.request !== request)
@@ -57625,7 +57696,7 @@ class SqlPoolQueue {
57625
57696
  const { now, status } = await this.authority(tx, lease);
57626
57697
  const row = await this.current(tx, lease, token);
57627
57698
  if (row.epoch !== lease.epoch)
57628
- throw new Error("Stale work lease");
57699
+ throw new Error(STALE_WORK_LEASE);
57629
57700
  const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
57630
57701
  if (previous) {
57631
57702
  if (previous.request !== request)
@@ -57633,7 +57704,7 @@ class SqlPoolQueue {
57633
57704
  return JSON.parse(previous.receipt);
57634
57705
  }
57635
57706
  if (row.expires_at < now)
57636
- throw new Error("Stale work lease");
57707
+ throw new Error(STALE_WORK_LEASE);
57637
57708
  if (!await this.admitsAttemptWrites(tx, lease, status))
57638
57709
  throw new Error("Pool root is not running");
57639
57710
  const checkpoint = mutation.checkpoint;
@@ -57673,7 +57744,7 @@ class SqlPoolQueue {
57673
57744
  const { now, status } = await this.authority(tx, lease);
57674
57745
  const row = await this.current(tx, lease, token, true);
57675
57746
  if (row.epoch !== lease.epoch)
57676
- throw new Error("Stale work lease");
57747
+ throw new Error(STALE_WORK_LEASE);
57677
57748
  if (row.state === "completed") {
57678
57749
  const previous = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, token.id);
57679
57750
  if (previous?.result !== payload)
@@ -57681,7 +57752,7 @@ class SqlPoolQueue {
57681
57752
  return;
57682
57753
  }
57683
57754
  if (row.expires_at < now || !await this.admitsAttemptWrites(tx, lease, status))
57684
- throw new Error("Stale work lease");
57755
+ throw new Error(STALE_WORK_LEASE);
57685
57756
  if (JSON.parse(payload).runId !== fromRow(row).childRunId)
57686
57757
  throw new Error("Pool result identity mismatch");
57687
57758
  await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
@@ -57706,6 +57777,40 @@ class SqlPoolQueue {
57706
57777
  return true;
57707
57778
  });
57708
57779
  }
57780
+ async extend(lease, token, durationMs) {
57781
+ positive(durationMs);
57782
+ lease = snapshotLease(lease);
57783
+ token = { ...token };
57784
+ return this.transaction(async (tx) => {
57785
+ const { now } = await this.authority(tx, lease);
57786
+ const row = await this.current(tx, lease, token);
57787
+ if (row.epoch !== lease.epoch)
57788
+ throw new Error(STALE_WORK_LEASE);
57789
+ const expiresAt = Math.max(Number(row.expires_at), expiry(now, durationMs));
57790
+ await tx.run(`UPDATE ${this.work} SET expires_at = ?, renewed_at = ? WHERE id = ?`, expiresAt, now, row.id);
57791
+ return { ...fromRow(row), expiresAt, renewedAt: now };
57792
+ });
57793
+ }
57794
+ async releaseExited(lease, token) {
57795
+ lease = snapshotLease(lease);
57796
+ token = { ...token };
57797
+ return this.transaction(async (tx) => {
57798
+ await this.authority(tx, lease);
57799
+ const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
57800
+ if (row?.state !== "leased" || row.generation !== token.generation || row.worker !== token.worker || row.epoch !== token.epoch)
57801
+ return false;
57802
+ await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE id = ?`, row.id);
57803
+ return true;
57804
+ });
57805
+ }
57806
+ async releasePreviousIncarnations(lease) {
57807
+ lease = snapshotLease(lease);
57808
+ return this.transaction(async (tx) => {
57809
+ await this.authority(tx, lease);
57810
+ const released = await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE root = ? AND state = 'leased' AND epoch < ?`, lease.runId, lease.epoch);
57811
+ return released.changes;
57812
+ });
57813
+ }
57709
57814
  async inspect(root) {
57710
57815
  return this.transaction(async (tx) => (await tx.all(`SELECT * FROM ${this.work} WHERE root = ? ORDER BY ready_at, rowid`, root)).map(fromRow));
57711
57816
  }
@@ -57716,7 +57821,7 @@ function openSqlPoolQueue(journal) {
57716
57821
  return Promise.reject(new Error("Worker pool requires a SQL run journal"));
57717
57822
  return SqlPoolQueue.open(storage);
57718
57823
  }
57719
- var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000;
57824
+ var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000, STALE_WORK_LEASE = "Stale work lease";
57720
57825
  var init_sql_pool_queue = __esm(() => {
57721
57826
  init_serializable();
57722
57827
  init_boundary_topology();
@@ -61157,12 +61262,66 @@ var init_sdk_intercom = __esm(() => {
61157
61262
  owners2 = new WeakMap;
61158
61263
  });
61159
61264
 
61265
+ // dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
61266
+ function isInfrastructureError(value2) {
61267
+ if (value2 instanceof WorkflowInfrastructureError)
61268
+ return true;
61269
+ if (typeof value2 !== "object" || value2 === null)
61270
+ return false;
61271
+ const candidate = value2;
61272
+ return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
61273
+ }
61274
+ function isRetryableWorkflowError(error) {
61275
+ let current = error;
61276
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
61277
+ if (isInfrastructureError(current))
61278
+ return true;
61279
+ current = current instanceof Error ? current.cause : undefined;
61280
+ }
61281
+ return false;
61282
+ }
61283
+ function workflowInfrastructureFault(message) {
61284
+ return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
61285
+ }
61286
+ function asWorkflowInfrastructureError(error) {
61287
+ if (isInfrastructureError(error))
61288
+ return error;
61289
+ if (!(error instanceof Error))
61290
+ return;
61291
+ const code = workflowInfrastructureFault(error.message);
61292
+ return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
61293
+ }
61294
+ var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
61295
+ var init_workflow_infrastructure_error = __esm(() => {
61296
+ FAULT_PATTERNS = [
61297
+ [/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
61298
+ [/Local worker retry limit/, "worker_retry_limit"],
61299
+ [/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
61300
+ [/Worker exited before delivery acknowledgement/, "worker_lost"],
61301
+ [/Stale work lease/, "stale_work_lease"],
61302
+ [/Intercom runtime no longer active/, "intercom_unavailable"],
61303
+ [/Storage unavailable/, "storage_unavailable"]
61304
+ ];
61305
+ WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
61306
+ name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
61307
+ retryable = true;
61308
+ code;
61309
+ constructor(code, message, options) {
61310
+ super(message, options);
61311
+ this.code = code;
61312
+ }
61313
+ };
61314
+ });
61315
+
61160
61316
  // dist/builtin/workflows/src/workers/host-options.ts
61161
61317
  var hostWorkerBindings;
61162
61318
  var init_host_options = __esm(() => {
61163
61319
  hostWorkerBindings = Symbol("host-worker-bindings");
61164
61320
  });
61165
61321
 
61322
+ // dist/builtin/workflows/src/workers/protocol.ts
61323
+ var WORKER_HEARTBEAT_INTERVAL_MS = 1000;
61324
+
61166
61325
  // dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
61167
61326
  function isWorkflowPendingStageDeliveryFailure(error) {
61168
61327
  if (error instanceof WorkflowPendingStageDeliveryFailedError)
@@ -61702,20 +61861,33 @@ var init_stage_handoff = __esm(() => {
61702
61861
  // dist/builtin/workflows/src/workers/local-pool.ts
61703
61862
  import { fork } from "node:child_process";
61704
61863
  import { randomUUID as randomUUID15 } from "node:crypto";
61705
- import { resolve as resolve11 } from "node:path";
61864
+ import { createWriteStream } from "node:fs";
61865
+ import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
61866
+ import { dirname as dirname12, join as join28, resolve as resolve11 } from "node:path";
61706
61867
  import { setTimeout as delay2 } from "node:timers/promises";
61707
61868
  import { fileURLToPath as fileURLToPath5 } from "node:url";
61708
61869
  import { isBunBinary as isBunBinary2 } from "@bastani/atomic";
61870
+ function workerLogDirectory(journalPath, root) {
61871
+ return join28(dirname12(resolve11(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
61872
+ }
61709
61873
 
61710
61874
  class LocalWorkerPool {
61711
61875
  backend;
61712
61876
  options;
61713
61877
  children = new Set;
61714
61878
  incarnations = new Map;
61879
+ readyWorkers = new Set;
61880
+ logs = new Map;
61881
+ logDirectory;
61715
61882
  cleanups = new Set;
61716
61883
  recovering;
61717
61884
  nextRecoveryAt = 0;
61718
61885
  controlAcks = new Map;
61886
+ lastHeard = new Map;
61887
+ lastTick = performance.now();
61888
+ rootStalledMs = 0;
61889
+ ticker;
61890
+ leaseMs;
61719
61891
  desiredControl;
61720
61892
  root;
61721
61893
  store;
@@ -61739,9 +61911,15 @@ class LocalWorkerPool {
61739
61911
  this.options = options;
61740
61912
  if (!Number.isSafeInteger(options.workers) || options.workers < 1)
61741
61913
  throw new Error("Invalid local worker count");
61914
+ if (options.startupTimeoutMs !== undefined && (!Number.isSafeInteger(options.startupTimeoutMs) || options.startupTimeoutMs < 1 || options.startupTimeoutMs > MAX_TIMER_DELAY_MS))
61915
+ throw new Error("Invalid local worker startup timeout");
61916
+ if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
61917
+ throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
61918
+ this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
61742
61919
  this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
61743
61920
  if (options.admission && options.rootId === undefined)
61744
61921
  workflowResourceAdmission.set(backend, options.admission);
61922
+ this.ticker = setInterval(() => this.observeResponsiveness(), ROOT_TICK_INTERVAL_MS).unref();
61745
61923
  }
61746
61924
  get workerPids() {
61747
61925
  return [...this.children].flatMap((child) => child.pid === undefined ? [] : [child.pid]);
@@ -61767,6 +61945,7 @@ class LocalWorkerPool {
61767
61945
  this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
61768
61946
  const queue = await openSqlPoolQueue(this.backend.journal);
61769
61947
  await queue.initialize(this.lease, COORDINATOR_LEASE_MS);
61948
+ await queue.releasePreviousIncarnations(this.lease);
61770
61949
  for (;; ) {
61771
61950
  const intended = this.desiredControl ?? "running";
61772
61951
  await queue.setControl(this.lease, intended);
@@ -61781,8 +61960,8 @@ class LocalWorkerPool {
61781
61960
  if (!this.queue || !this.lease)
61782
61961
  return;
61783
61962
  const control = await this.queue.setControl(this.lease, state);
61784
- const deadline = Date.now() + WORK_LEASE_MS;
61785
- while ([...this.incarnations.keys()].some((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision)) {
61963
+ const deadline = Date.now() + CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS;
61964
+ while ([...this.readyWorkers].some((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision)) {
61786
61965
  if (this.desiredControl !== state)
61787
61966
  return;
61788
61967
  if (Date.now() >= deadline) {
@@ -61852,7 +62031,16 @@ class LocalWorkerPool {
61852
62031
  root,
61853
62032
  holder: "coordinator"
61854
62033
  });
61855
- await Promise.all(Array.from({ length: this.options.workers }, () => this.spawn(root)));
62034
+ this.logDirectory = workerLogDirectory(this.options.journalPath, root);
62035
+ await mkdir6(this.logDirectory, { recursive: true }).catch(() => {
62036
+ return;
62037
+ });
62038
+ const workers = Array.from({ length: this.options.workers }, () => this.spawn(root));
62039
+ try {
62040
+ await Promise.any(workers);
62041
+ } catch (error) {
62042
+ throw error.errors[0];
62043
+ }
61856
62044
  }
61857
62045
  spawn(root) {
61858
62046
  if (this.closed)
@@ -61873,26 +62061,56 @@ class LocalWorkerPool {
61873
62061
  let serial = Promise.resolve();
61874
62062
  let work;
61875
62063
  const deliveries = new Map;
62064
+ const logPath = join28(this.logDirectory, `${worker}.log`);
62065
+ this.logs.set(child, logPath);
62066
+ let logFailure;
62067
+ const log = createWriteStream(logPath, { flags: "a" });
62068
+ log.on("error", (error) => {
62069
+ logFailure = error.message;
62070
+ });
61876
62071
  let stderr = "";
61877
62072
  child.stderr?.on("data", (chunk) => {
61878
- stderr = (stderr + chunk.toString()).slice(-8192);
62073
+ stderr = (stderr + chunk.toString()).slice(-STDERR_TAIL_CHARACTERS);
61879
62074
  });
62075
+ child.stderr?.on("error", (error) => {
62076
+ logFailure ??= error.message;
62077
+ log.end();
62078
+ });
62079
+ child.stderr?.pipe(log);
62080
+ const diagnosed = (summary) => new Error(`${summary} (worker stderr log: ${logFailure === undefined ? logPath : `unavailable, ${logFailure}`})${stderr ? `: ${stderr}` : ""}`);
62081
+ const startupTimeoutMs = this.options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
62082
+ let timedOut = false;
62083
+ let terminated = false;
62084
+ const terminate = () => {
62085
+ if (terminated)
62086
+ return;
62087
+ terminated = true;
62088
+ child.kill("SIGKILL");
62089
+ };
62090
+ const replied = (error) => {
62091
+ if (error)
62092
+ terminate();
62093
+ };
61880
62094
  return new Promise((resolve, reject) => {
61881
62095
  const startup = setTimeout(() => {
61882
- this.failure = new Error("Local worker startup timed out");
61883
- reject(this.failure);
61884
- child.kill("SIGKILL");
61885
- }, 30000);
61886
- child.once("error", (error) => {
62096
+ timedOut = true;
62097
+ terminate();
62098
+ }, startupTimeoutMs);
62099
+ child.on("error", (error) => {
61887
62100
  clearTimeout(startup);
61888
62101
  reject(error);
62102
+ terminate();
61889
62103
  });
62104
+ const closed = new Promise((resolve) => child.once("close", () => resolve()));
61890
62105
  child.once("exit", () => {
62106
+ Promise.race([closed, delay2(STDERR_DRAIN_GRACE_MS)]).then(() => reject(diagnosed(timedOut ? `Local worker startup timed out after ${startupTimeoutMs} ms` : "Local worker exited before readiness")));
61891
62107
  this.children.delete(child);
62108
+ this.logs.delete(child);
61892
62109
  clearTimeout(startup);
61893
62110
  this.incarnations.delete(worker);
61894
- reject(new Error(`Local worker exited before readiness: ${stderr}`));
62111
+ this.readyWorkers.delete(worker);
61895
62112
  this.controlAcks.delete(worker);
62113
+ this.lastHeard.delete(worker);
61896
62114
  if (work)
61897
62115
  this.handoff?.fence(work);
61898
62116
  for (const delivery of deliveries.values())
@@ -61915,9 +62133,11 @@ class LocalWorkerPool {
61915
62133
  }
61916
62134
  if (this.closed)
61917
62135
  return;
62136
+ if (work)
62137
+ await this.queue.releaseExited(this.lease, work);
61918
62138
  const exhausted = work ? work.generation >= 3 : ++this.replacements > 3;
61919
62139
  if (exhausted)
61920
- this.failure = new Error(`Local worker retry limit: ${stderr}`);
62140
+ this.failure = diagnosed("Local worker retry limit");
61921
62141
  else
61922
62142
  await this.spawn(root);
61923
62143
  }).catch((error) => {
@@ -61927,6 +62147,8 @@ class LocalWorkerPool {
61927
62147
  cleanup.finally(() => this.cleanups.delete(cleanup));
61928
62148
  });
61929
62149
  child.on("message", (message) => {
62150
+ this.observeResponsiveness();
62151
+ this.lastHeard.set(worker, { at: performance.now(), rootStalled: this.rootStalledMs });
61930
62152
  if (message.kind === "delivery-ack") {
61931
62153
  const pending = deliveries.get(message.deliveryId);
61932
62154
  deliveries.delete(message.deliveryId);
@@ -61938,7 +62160,10 @@ class LocalWorkerPool {
61938
62160
  }
61939
62161
  const response = serial.then(async () => {
61940
62162
  if (message.kind === "ready") {
62163
+ if (terminated)
62164
+ return;
61941
62165
  ready = true;
62166
+ this.readyWorkers.add(worker);
61942
62167
  clearTimeout(startup);
61943
62168
  resolve();
61944
62169
  return;
@@ -61965,11 +62190,13 @@ class LocalWorkerPool {
61965
62190
  work = await queue.claim(lease, worker, this.sources.map((source) => ({
61966
62191
  definition: `${source.path}#${source.exportName}`,
61967
62192
  digest: source.digest
61968
- })), WORK_LEASE_MS);
62193
+ })), this.leaseMs);
61969
62194
  return work;
61970
62195
  }
61971
62196
  if (!work)
61972
62197
  throw new Error("Worker has no active attempt");
62198
+ if (message.kind === "renew" || work.expiresAt - Date.now() < this.leaseMs / 2)
62199
+ work = await queue.extend(lease, work, this.leaseMs);
61973
62200
  if (message.kind === "activity")
61974
62201
  return this.handoff?.publish(work, message.runs);
61975
62202
  if (message.kind === "route")
@@ -61990,10 +62217,8 @@ class LocalWorkerPool {
61990
62217
  });
61991
62218
  }));
61992
62219
  }
61993
- if (message.kind === "renew") {
61994
- work = await queue.renew(lease, work, randomUUID15(), WORK_LEASE_MS);
62220
+ if (message.kind === "renew")
61995
62221
  return;
61996
- }
61997
62222
  if (message.kind === "commit") {
61998
62223
  const receipt = await queue.commit(lease, work, message.operation, message.mutation);
61999
62224
  this.usageTotal = await this.usageLedger.total(root);
@@ -62018,13 +62243,7 @@ class LocalWorkerPool {
62018
62243
  });
62019
62244
  if (message.kind !== "delivery" && message.kind !== "delivery-ready")
62020
62245
  serial = response.then(() => {}, () => {});
62021
- response.then((value2) => {
62022
- if (child.connected)
62023
- child.send({ id: message.id, value: value2 });
62024
- }, (error) => {
62025
- if (child.connected)
62026
- child.send({ id: message.id, error: error.message });
62027
- });
62246
+ response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => child.send({ id: message.id, error: error.message }, replied));
62028
62247
  });
62029
62248
  });
62030
62249
  }
@@ -62034,14 +62253,22 @@ class LocalWorkerPool {
62034
62253
  if (this.closed || performance.now() < this.nextRecoveryAt)
62035
62254
  return Promise.resolve();
62036
62255
  this.recovering = (async () => {
62256
+ await new Promise((resolve) => setImmediate(resolve));
62037
62257
  await this.admission?.reconcile();
62038
62258
  const expiredBefore = Date.now();
62039
62259
  for (const work of await this.queue.inspect(root)) {
62040
62260
  if (work.state !== "leased" || work.expiresAt >= expiredBefore)
62041
62261
  continue;
62042
62262
  const child = work.worker === null ? undefined : this.incarnations.get(work.worker);
62043
- if (child)
62044
- await this.stop(child);
62263
+ if (child && work.worker !== null && this.isLive(work.worker, child)) {
62264
+ await this.queue.extend(this.lease, work, this.leaseMs).catch((error) => {
62265
+ if (error.message !== STALE_WORK_LEASE)
62266
+ throw error;
62267
+ });
62268
+ continue;
62269
+ }
62270
+ if (child && !await this.stop(child).then(() => true, () => false))
62271
+ continue;
62045
62272
  await this.queue.expire(this.lease, work);
62046
62273
  }
62047
62274
  })().finally(() => {
@@ -62050,6 +62277,18 @@ class LocalWorkerPool {
62050
62277
  });
62051
62278
  return this.recovering;
62052
62279
  }
62280
+ observeResponsiveness() {
62281
+ const now = performance.now();
62282
+ const gap = now - this.lastTick;
62283
+ if (gap > ROOT_STALL_THRESHOLD_MS)
62284
+ this.rootStalledMs += gap - ROOT_TICK_INTERVAL_MS;
62285
+ this.lastTick = now;
62286
+ }
62287
+ isLive(worker, child) {
62288
+ this.observeResponsiveness();
62289
+ const heard = this.lastHeard.get(worker);
62290
+ return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.rootStalledMs - heard.rootStalled) < this.leaseMs;
62291
+ }
62053
62292
  stop(child) {
62054
62293
  if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
62055
62294
  return Promise.resolve();
@@ -62066,9 +62305,13 @@ class LocalWorkerPool {
62066
62305
  try {
62067
62306
  return await this.dispatch(definition, inputs, options);
62068
62307
  } catch (error) {
62069
- if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
62070
- await this.close();
62071
- throw error;
62308
+ try {
62309
+ if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
62310
+ await this.close();
62311
+ } catch (closeError) {
62312
+ throw asWorkflowInfrastructureError(closeError) ?? closeError;
62313
+ }
62314
+ throw asWorkflowInfrastructureError(error) ?? error;
62072
62315
  }
62073
62316
  }
62074
62317
  async dispatch(definition, inputs, options) {
@@ -62112,6 +62355,8 @@ class LocalWorkerPool {
62112
62355
  for (;; ) {
62113
62356
  options.signal?.throwIfAborted();
62114
62357
  if (this.closed) {
62358
+ if (this.failure)
62359
+ throw this.failure;
62115
62360
  if (this.desiredControl === "quit")
62116
62361
  throw new WorkflowGracefulQuitError(root, "worker pool teardown");
62117
62362
  throw new Error("Local worker pool is closed");
@@ -62138,19 +62383,28 @@ class LocalWorkerPool {
62138
62383
  }
62139
62384
  async dispose() {
62140
62385
  this.closed = true;
62386
+ clearInterval(this.ticker);
62141
62387
  this.releaseBinding();
62142
62388
  if (this.options.rootId === undefined)
62143
62389
  workflowResourceAdmission.delete(this.backend);
62144
62390
  let failure;
62391
+ let stopping = [];
62145
62392
  try {
62146
62393
  await this.recovering?.catch(() => {});
62147
- await Promise.all([...this.children].map((child) => this.stop(child)));
62394
+ stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
62395
+ await Promise.all(stopping.map(({ child }) => this.stop(child)));
62148
62396
  await Promise.all([...this.cleanups]);
62149
62397
  if (this.cleanupFailure)
62150
62398
  throw this.cleanupFailure;
62151
62399
  } catch (error) {
62152
62400
  failure = error;
62153
62401
  }
62402
+ if (failure === undefined) {
62403
+ const stopped = stopping.flatMap(({ child, log }) => log !== undefined && (child.exitCode !== null || child.signalCode !== null) ? [log] : []);
62404
+ await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
62405
+ if (this.logDirectory !== undefined)
62406
+ await rmdir(this.logDirectory).catch(() => {});
62407
+ }
62154
62408
  try {
62155
62409
  await this.releaseRoutes?.();
62156
62410
  } catch (error) {
@@ -62160,7 +62414,7 @@ class LocalWorkerPool {
62160
62414
  throw failure;
62161
62415
  }
62162
62416
  }
62163
- var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker", WORK_LEASE_MS = 5000, RECOVERY_INTERVAL_MS = 500, COORDINATOR_LEASE_MS;
62417
+ var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker", DEFAULT_WORK_LEASE_MS = 30000, MINIMUM_WORK_LEASE_MS, CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS = 5000, RECOVERY_INTERVAL_MS = 500, ROOT_TICK_INTERVAL_MS = 100, ROOT_STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, DEFAULT_STARTUP_TIMEOUT_MS = 30000, MAX_TIMER_DELAY_MS = 2147483647, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000;
62164
62418
  var init_local_pool = __esm(() => {
62165
62419
  init_internal();
62166
62420
  init_sql_pool_queue();
@@ -62168,12 +62422,14 @@ var init_local_pool = __esm(() => {
62168
62422
  init_sql_run_journal();
62169
62423
  init_workflow_tool_abort();
62170
62424
  init_sdk_intercom();
62425
+ init_workflow_infrastructure_error();
62171
62426
  init_admission_binding();
62172
62427
  init_definitions();
62173
62428
  init_dispatch();
62174
62429
  init_host_options();
62175
62430
  init_resource_admission();
62176
62431
  init_stage_handoff();
62432
+ MINIMUM_WORK_LEASE_MS = 2 * WORKER_HEARTBEAT_INTERVAL_MS;
62177
62433
  COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
62178
62434
  });
62179
62435
 
@@ -62215,6 +62471,8 @@ async function activatePublicPool(backend, options) {
62215
62471
  const cwd = options.cwd ?? process.cwd();
62216
62472
  const localWorkers = options.localWorkers && {
62217
62473
  ...options.localWorkers,
62474
+ startupTimeoutMs: undefined,
62475
+ leaseMs: undefined,
62218
62476
  definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve12(cwd, source.path) }))
62219
62477
  };
62220
62478
  const admission = options.admission && {
@@ -62243,7 +62501,9 @@ async function activatePublicPool(backend, options) {
62243
62501
  journalPath: backend.journal.path,
62244
62502
  workers: localWorkers.count,
62245
62503
  definitions,
62246
- admission: resources.admission ?? {}
62504
+ admission: resources.admission ?? {},
62505
+ startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
62506
+ leaseMs: options.localWorkers?.leaseMs
62247
62507
  });
62248
62508
  try {
62249
62509
  pool.validateOptions(options);
@@ -63161,12 +63421,12 @@ function createChildWorkflowRunner(input) {
63161
63421
  const childExitStatus = isWorkflowExitStatus(childRun.status) ? childRun.status : "blocked";
63162
63422
  if (!isWorkflowExitStatus(childRun.status) && !childBudgetExceeded || childRun.status === "failed" && childRun.exited !== true) {
63163
63423
  const failedChildStage = childRun.stages.find((stage) => stage.failureKind !== undefined);
63164
- throw new Error(`atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`, {
63165
- cause: {
63166
- ...failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {},
63167
- ...failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}
63168
- }
63169
- });
63424
+ const message = `atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`;
63425
+ const cause = {
63426
+ ...failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {},
63427
+ ...failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}
63428
+ };
63429
+ throw new Error(message, { cause });
63170
63430
  }
63171
63431
  const outputs = selectWorkflowOutputs(child, childRun.result);
63172
63432
  const childExited = childBudgetExceeded || childRun.exited === true || childRun.status !== "completed";
@@ -63227,7 +63487,7 @@ function describeErrorWithCauses(error) {
63227
63487
  const messages = [];
63228
63488
  const visited = new Set;
63229
63489
  let current = error;
63230
- for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH && !visited.has(current); depth++) {
63490
+ for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH2 && !visited.has(current); depth++) {
63231
63491
  visited.add(current);
63232
63492
  const message = current instanceof Error ? current.message : String(current);
63233
63493
  if (!messages.includes(message))
@@ -63236,7 +63496,7 @@ function describeErrorWithCauses(error) {
63236
63496
  }
63237
63497
  return messages.join(": ");
63238
63498
  }
63239
- var MAX_CAUSE_DEPTH = 5;
63499
+ var MAX_CAUSE_DEPTH2 = 5;
63240
63500
 
63241
63501
  // dist/builtin/workflows/src/shared/returned-run-status.ts
63242
63502
  function normalizeReturnedWorkflowStatus(status) {
@@ -63563,7 +63823,7 @@ function hasUsableContentBlock(block) {
63563
63823
 
63564
63824
  // dist/builtin/workflows/src/shared/stage-session-store.ts
63565
63825
  import { randomUUID as randomUUID17 } from "node:crypto";
63566
- import { dirname as dirname12, resolve as resolve13 } from "node:path";
63826
+ import { dirname as dirname13, resolve as resolve13 } from "node:path";
63567
63827
  import {
63568
63828
  JsonlSessionStore,
63569
63829
  resolveSessionStore,
@@ -63600,7 +63860,7 @@ async function migrateLegacyStageSession(store, sessionId, sessionFile) {
63600
63860
  if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
63601
63861
  return;
63602
63862
  const location = resolve13(sessionFile);
63603
- const legacy = await JsonlSessionStore.open(dirname12(location), { exactDirectory: true, scanExisting: false });
63863
+ const legacy = await JsonlSessionStore.open(dirname13(location), { exactDirectory: true, scanExisting: false });
63604
63864
  try {
63605
63865
  for await (const file of legacy.scanFiles()) {
63606
63866
  if (resolve13(file.location) !== location || file.header.id !== sessionId)
@@ -64748,7 +65008,7 @@ function recordedOwners(boundary, reason) {
64748
65008
  const pending = [{ value: reason, depth: 0 }];
64749
65009
  while (pending.length > 0) {
64750
65010
  const { value: value2, depth } = pending.pop();
64751
- if (depth > MAX_CAUSE_DEPTH2)
65011
+ if (depth > MAX_CAUSE_DEPTH3)
64752
65012
  continue;
64753
65013
  if (isPrimitive(value2)) {
64754
65014
  if (depth === 0 || value2 !== undefined && value2 !== null) {
@@ -65070,7 +65330,7 @@ function containUiRejections(ui, scope) {
65070
65330
  custom: (factory, options) => scope.watch(ui.custom(factory, options))
65071
65331
  };
65072
65332
  }
65073
- var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections", MAX_CAUSE_DEPTH2 = 8, MAX_PRIMITIVES_PER_RUN = 64, MAX_STOP_STRINGS = 64, ENDED_RUN_GRACE_MS = 30000, NATIVE_REPORTING_MODES, WATCHED_STAGE_METHODS;
65333
+ var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections", MAX_CAUSE_DEPTH3 = 8, MAX_PRIMITIVES_PER_RUN = 64, MAX_STOP_STRINGS = 64, ENDED_RUN_GRACE_MS = 30000, NATIVE_REPORTING_MODES, WATCHED_STAGE_METHODS;
65074
65334
  var init_run_rejection_boundary = __esm(() => {
65075
65335
  init_prompt_callsite();
65076
65336
  init_workflow_source();
@@ -69863,8 +70123,8 @@ var init_stage_runner_controller = __esm(() => {
69863
70123
 
69864
70124
  // dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
69865
70125
  import { createHash as createHash4 } from "node:crypto";
69866
- import { mkdir as mkdir6, writeFile as writeFile10 } from "node:fs/promises";
69867
- import { basename as basename5, dirname as dirname13, isAbsolute as isAbsolute11, join as join28, resolve as resolve14 } from "node:path";
70126
+ import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
70127
+ import { basename as basename5, dirname as dirname14, isAbsolute as isAbsolute11, join as join29, resolve as resolve14 } from "node:path";
69868
70128
  function normalizeMaxOutput2(maxOutput) {
69869
70129
  return {
69870
70130
  bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
@@ -69927,7 +70187,7 @@ function formatByteSize(bytes) {
69927
70187
  }
69928
70188
  function transcriptPath(runId, outputPath) {
69929
70189
  const digest = createHash4("sha256").update(outputPath).digest("hex").slice(0, 16);
69930
- return join28(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
70190
+ return join29(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
69931
70191
  }
69932
70192
  function appendContent(lines, content) {
69933
70193
  if (typeof content === "string") {
@@ -70047,7 +70307,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
70047
70307
  const transcriptFile = transcriptPath(runId, outputPath);
70048
70308
  const transcript = renderTranscript(messages, fullOutput);
70049
70309
  try {
70050
- await mkdir6(dirname13(outputPath), { recursive: true });
70310
+ await mkdir7(dirname14(outputPath), { recursive: true });
70051
70311
  await writeFile10(outputPath, fullOutput, "utf8");
70052
70312
  } catch (err) {
70053
70313
  return `${displayOutput}
@@ -70059,7 +70319,7 @@ ${err instanceof Error ? err.message : String(err)}`;
70059
70319
  let transcriptError;
70060
70320
  try {
70061
70321
  await ensureWorkflowArtifactRunDirectory(runId);
70062
- await mkdir6(dirname13(transcriptFile), { recursive: true });
70322
+ await mkdir7(dirname14(transcriptFile), { recursive: true });
70063
70323
  await writeFile10(transcriptFile, transcript, "utf8");
70064
70324
  transcriptAvailable = true;
70065
70325
  } catch (err) {
@@ -70968,7 +71228,7 @@ function reportsClosedSession(error) {
70968
71228
  }
70969
71229
  function isSessionClosedError(error) {
70970
71230
  let current = error;
70971
- for (let depth = 0;depth < MAX_CAUSE_DEPTH3 && current !== undefined; depth++) {
71231
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH4 && current !== undefined; depth++) {
70972
71232
  try {
70973
71233
  if (reportsClosedSession(current))
70974
71234
  return true;
@@ -70979,7 +71239,7 @@ function isSessionClosedError(error) {
70979
71239
  }
70980
71240
  return false;
70981
71241
  }
70982
- var MAX_CAUSE_DEPTH3 = 8;
71242
+ var MAX_CAUSE_DEPTH4 = 8;
70983
71243
  var init_session_closed_error = () => {};
70984
71244
 
70985
71245
  // dist/builtin/workflows/src/engine/workflow-activity.ts
@@ -72220,11 +72480,13 @@ __export(exports_sdk_surface, {
72220
72480
  StaleLeaseError: () => StaleLeaseError,
72221
72481
  StorageUnavailableError: () => StorageUnavailableError,
72222
72482
  WORKFLOW_HEARTBEAT_CUSTOM_TYPE: () => WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
72483
+ WorkflowInfrastructureError: () => WorkflowInfrastructureError,
72223
72484
  cancellationRegistry: () => cancellationRegistry,
72224
72485
  createAgentSessionAdapter: () => createAgentSessionAdapter,
72225
72486
  createCancellationRegistry: () => createCancellationRegistry,
72226
72487
  createRegistry: () => createRegistry,
72227
72488
  createStore: () => createStore,
72489
+ isRetryableWorkflowError: () => isRetryableWorkflowError,
72228
72490
  keepContext: () => keepContext,
72229
72491
  loadWorkerWorkflow: () => loadWorkerWorkflow,
72230
72492
  normalizeWorkflowName: () => normalizeWorkflowName,
@@ -72251,6 +72513,7 @@ var init_sdk_surface = __esm(() => {
72251
72513
  init_worktree();
72252
72514
  init_store();
72253
72515
  init_types2();
72516
+ init_workflow_infrastructure_error();
72254
72517
  init_definitions();
72255
72518
  init_registry();
72256
72519
  init_types();
@@ -72284,11 +72547,13 @@ export {
72284
72547
  StaleLeaseError,
72285
72548
  StorageUnavailableError,
72286
72549
  WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
72550
+ WorkflowInfrastructureError,
72287
72551
  cancellationRegistry,
72288
72552
  createAgentSessionAdapter,
72289
72553
  createCancellationRegistry,
72290
72554
  createRegistry,
72291
72555
  createStore,
72556
+ isRetryableWorkflowError,
72292
72557
  keepContext,
72293
72558
  loadWorkerWorkflow,
72294
72559
  normalizeWorkflowName,