@bastani/atomic 0.9.26-alpha.3 → 0.9.26-alpha.5

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.
Files changed (118) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/broker/broker.ts +9 -1
  4. package/dist/builtin/intercom/index.bundle.mjs +11 -2
  5. package/dist/builtin/intercom/package.json +2 -2
  6. package/dist/builtin/intercom/types.ts +13 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/package.json +3 -3
  9. package/dist/builtin/web-access/package.json +2 -2
  10. package/dist/builtin/workflows/CHANGELOG.md +16 -0
  11. package/dist/builtin/workflows/builtin/{chunk-kfsnh3w7.js → chunk-613yaa53.js} +128 -45
  12. package/dist/builtin/workflows/builtin/{chunk-rqmasd3d.js → chunk-6kqrk0pf.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-wz783pvd.js → chunk-ea6nrbn3.js} +1 -1
  14. package/dist/builtin/workflows/builtin/goal.js +2 -2
  15. package/dist/builtin/workflows/builtin/index.js +3 -3
  16. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  17. package/dist/builtin/workflows/package.json +2 -2
  18. package/dist/builtin/workflows/src/extension/index.bundle.mjs +653 -303
  19. package/dist/builtin/workflows/src/index.js +201 -77
  20. package/dist/core/agent-session-export.js +1 -1
  21. package/dist/core/agent-session-export.js.map +1 -1
  22. package/dist/core/export-html/tool-renderer.d.ts +3 -3
  23. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  24. package/dist/core/export-html/tool-renderer.js +3 -3
  25. package/dist/core/export-html/tool-renderer.js.map +1 -1
  26. package/dist/core/extensions/api-types.d.ts +3 -1
  27. package/dist/core/extensions/api-types.d.ts.map +1 -1
  28. package/dist/core/extensions/api-types.js.map +1 -1
  29. package/dist/core/extensions/context-types.d.ts +5 -2
  30. package/dist/core/extensions/context-types.d.ts.map +1 -1
  31. package/dist/core/extensions/context-types.js.map +1 -1
  32. package/dist/core/extensions/index.d.ts +1 -1
  33. package/dist/core/extensions/index.d.ts.map +1 -1
  34. package/dist/core/extensions/index.js.map +1 -1
  35. package/dist/core/extensions/loader-api.d.ts.map +1 -1
  36. package/dist/core/extensions/loader-api.js +5 -0
  37. package/dist/core/extensions/loader-api.js.map +1 -1
  38. package/dist/core/extensions/loader-bindings.d.ts +1 -1
  39. package/dist/core/extensions/loader-bindings.d.ts.map +1 -1
  40. package/dist/core/extensions/loader-bindings.js +1 -0
  41. package/dist/core/extensions/loader-bindings.js.map +1 -1
  42. package/dist/core/extensions/runner.d.ts +3 -1
  43. package/dist/core/extensions/runner.d.ts.map +1 -1
  44. package/dist/core/extensions/runner.js +6 -0
  45. package/dist/core/extensions/runner.js.map +1 -1
  46. package/dist/core/extensions/runtime-types.d.ts +2 -1
  47. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  48. package/dist/core/extensions/runtime-types.js.map +1 -1
  49. package/dist/core/extensions/tool-types.d.ts +3 -0
  50. package/dist/core/extensions/tool-types.d.ts.map +1 -1
  51. package/dist/core/extensions/tool-types.js.map +1 -1
  52. package/dist/core/extensions/ui-types.d.ts +2 -2
  53. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  54. package/dist/core/extensions/ui-types.js.map +1 -1
  55. package/dist/core/model-resolver-defaults.js +1 -1
  56. package/dist/core/model-resolver-defaults.js.map +1 -1
  57. package/dist/core/package-manager-auto-resources.d.ts.map +1 -1
  58. package/dist/core/package-manager-auto-resources.js +6 -2
  59. package/dist/core/package-manager-auto-resources.js.map +1 -1
  60. package/dist/core/package-manager-resolver.d.ts.map +1 -1
  61. package/dist/core/package-manager-resolver.js +4 -2
  62. package/dist/core/package-manager-resolver.js.map +1 -1
  63. package/dist/core/settings-manager-resource-accessors.js +7 -3
  64. package/dist/core/settings-manager-resource-accessors.js.map +1 -1
  65. package/dist/core/settings-merge.d.ts.map +1 -1
  66. package/dist/core/settings-merge.js +10 -0
  67. package/dist/core/settings-merge.js.map +1 -1
  68. package/dist/core/settings-types.d.ts +7 -1
  69. package/dist/core/settings-types.d.ts.map +1 -1
  70. package/dist/core/settings-types.js.map +1 -1
  71. package/dist/extensions/mcp/index.d.ts.map +1 -1
  72. package/dist/extensions/mcp/index.js +20 -1
  73. package/dist/extensions/mcp/index.js.map +1 -1
  74. package/dist/extensions/mcp/tools.d.ts +3 -1
  75. package/dist/extensions/mcp/tools.d.ts.map +1 -1
  76. package/dist/extensions/mcp/tools.js +19 -13
  77. package/dist/extensions/mcp/tools.js.map +1 -1
  78. package/dist/index.d.ts +2 -2
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js.map +1 -1
  81. package/dist/modes/interactive/components/chat-message-renderer.d.ts +2 -3
  82. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  83. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  84. package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -1
  85. package/dist/modes/interactive/components/config-selector-list.js +3 -1
  86. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  87. package/dist/modes/interactive/components/config-selector-project-scope.d.ts.map +1 -1
  88. package/dist/modes/interactive/components/config-selector-project-scope.js +2 -1
  89. package/dist/modes/interactive/components/config-selector-project-scope.js.map +1 -1
  90. package/dist/modes/interactive/components/tool-execution.d.ts +2 -5
  91. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  92. package/dist/modes/interactive/components/tool-execution.js +14 -40
  93. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  94. package/dist/modes/interactive/interactive-mode-surface.d.ts +3 -3
  95. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  96. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  97. package/dist/modes/interactive/interactive-session-runtime.js +6 -1
  98. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  99. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  100. package/dist/modes/interactive/interactive-startup.js +5 -0
  101. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  102. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  103. package/dist/modes/interactive-engine/engine-custom-ui.js +9 -0
  104. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  105. package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
  106. package/dist/modes/interactive-engine/engine-render-service.js +10 -1
  107. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  108. package/dist/utils/image-convert.d.ts +5 -0
  109. package/dist/utils/image-convert.d.ts.map +1 -1
  110. package/dist/utils/image-convert.js +36 -6
  111. package/dist/utils/image-convert.js.map +1 -1
  112. package/docs/extensions.md +6 -0
  113. package/docs/intercom/reference.md +13 -1
  114. package/docs/providers.md +10 -0
  115. package/docs/settings.md +28 -1
  116. package/docs/workflows/operations.md +27 -3
  117. package/npm-shrinkwrap.json +71 -92
  118. package/package.json +9 -9
@@ -76,6 +76,92 @@ function raceAbort(operation, signal) {
76
76
  });
77
77
  }
78
78
 
79
+ // dist/builtin/workflows/src/durable/dbos-database-diagnostics.ts
80
+ function redactedDatabaseEndpoint(url) {
81
+ try {
82
+ const parsed = new URL(url);
83
+ parsed.username = "";
84
+ parsed.password = "";
85
+ parsed.search = "";
86
+ parsed.hash = "";
87
+ return parsed.toString();
88
+ } catch {
89
+ return "unparseable PostgreSQL endpoint";
90
+ }
91
+ }
92
+ function redactedDatabaseMessage(message, url) {
93
+ let safe = message.replace(/postgres(?:ql)?:\/\/[^\s"'<>]+/gi, (value2) => redactedDatabaseEndpoint(value2));
94
+ let configuredSecrets = [];
95
+ if (url !== undefined) {
96
+ try {
97
+ const parsed = new URL(url);
98
+ configuredSecrets = [parsed.username, parsed.password, ...parsed.searchParams.values()].flatMap((secret) => {
99
+ try {
100
+ return [secret, decodeURIComponent(secret)];
101
+ } catch {
102
+ return [secret];
103
+ }
104
+ }).filter((secret) => secret.length > 0);
105
+ } catch {
106
+ return "PostgreSQL diagnostic could not be safely redacted; check the configured endpoint.";
107
+ }
108
+ }
109
+ safe = safe.replace(/\b(password|passwd|token|secret|sslpassword|user(?:name)?)\s*(?:([=:])\s*|((?:is|was)\s+)|\s+)(?:"([^"]*)"|'([^']*)'|([^\s,;]+))/gi, (match, key, separator, filler, doubleQuoted, singleQuoted, bare) => {
110
+ const value2 = doubleQuoted ?? singleQuoted ?? bare ?? "";
111
+ const isUserContext = /^user(?:name)?$/i.test(key);
112
+ if (separator === undefined && !isUserContext && !configuredSecrets.includes(value2))
113
+ return match;
114
+ const rendered = doubleQuoted !== undefined ? '"[redacted]"' : singleQuoted !== undefined ? "'[redacted]'" : "[redacted]";
115
+ return `${key}${separator ?? " "}${filler ?? ""}${rendered}`;
116
+ });
117
+ for (const secret of new Set(configuredSecrets)) {
118
+ if (secret.length < 4)
119
+ continue;
120
+ const escaped = secret.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
121
+ const expression = new RegExp(`(?<![\\p{L}\\p{N}_\\[])${escaped}(?![\\p{L}\\p{N}_\\]])`, "gu");
122
+ safe = safe.replace(expression, "[redacted]");
123
+ }
124
+ return safe;
125
+ }
126
+ function databaseDependencyMessage(message, diagnostics) {
127
+ const safe = redactedDatabaseMessage(message, diagnostics?.url);
128
+ if (diagnostics === undefined)
129
+ return safe;
130
+ const failure = diagnostics.failure === undefined ? "" : ` Last probe/recovery failure: ${redactedDatabaseMessage(diagnostics.failure, diagnostics.url)}`;
131
+ return `${safe} Provider: ${diagnostics.provider}; endpoint: ${redactedDatabaseEndpoint(diagnostics.url)}.${failure}`;
132
+ }
133
+
134
+ // dist/builtin/workflows/src/durable/dbos-process-owner.ts
135
+ function emptyOwner2() {
136
+ return {
137
+ version: 1,
138
+ state: "uninitialized",
139
+ configured: undefined,
140
+ active: undefined,
141
+ launchPromise: undefined,
142
+ shutdownPromise: undefined,
143
+ failure: undefined,
144
+ wrappers: undefined,
145
+ leases: new Set
146
+ };
147
+ }
148
+ function ownerBag2() {
149
+ return globalThis;
150
+ }
151
+ function getDbosProcessOwner() {
152
+ const bag = ownerBag2();
153
+ const existing = bag[DBOS_PROCESS_OWNER_KEY];
154
+ if (existing !== undefined && existing.version === 1)
155
+ return existing;
156
+ const created = emptyOwner2();
157
+ bag[DBOS_PROCESS_OWNER_KEY] = created;
158
+ return created;
159
+ }
160
+ var DBOS_PROCESS_OWNER_KEY;
161
+ var init_dbos_process_owner = __esm(() => {
162
+ DBOS_PROCESS_OWNER_KEY = Symbol.for("atomic-workflows/dbos-process-owner@1");
163
+ });
164
+
79
165
  // dist/builtin/workflows/src/durable/dbos-admission.ts
80
166
  import { AsyncLocalStorage } from "node:async_hooks";
81
167
  function isDbosDependencyError(error) {
@@ -94,6 +180,8 @@ async function boundedAdmission(operation, signal, timeoutMs = DBOS_ADMISSION_TI
94
180
  return await raceAbort(operation(controller.signal), controller.signal);
95
181
  } catch (error) {
96
182
  controller.abort(error);
183
+ if (isDbosDependencyError(error) && error.admissionDetail !== undefined)
184
+ throw new DbosDependencyError(error.admissionDetail, null);
97
185
  throw error;
98
186
  } finally {
99
187
  clearTimeout(timer);
@@ -102,10 +190,13 @@ async function boundedAdmission(operation, signal, timeoutMs = DBOS_ADMISSION_TI
102
190
  }
103
191
  var DBOS_ADMISSION_TIMEOUT_MS = 1e4, DbosDependencyError, key2, bag, dbosAdmissionContext;
104
192
  var init_dbos_admission = __esm(() => {
193
+ init_dbos_process_owner();
105
194
  DbosDependencyError = class DbosDependencyError extends Error {
106
195
  code = "ATOMIC_DBOS_DEPENDENCY";
107
- constructor(message = "Workflow database unavailable during admission. Restore PostgreSQL before retrying.") {
108
- super(message);
196
+ admissionDetail;
197
+ constructor(message = "Workflow database unavailable during admission. Restore PostgreSQL before retrying.", diagnostics = getDbosProcessOwner().databaseDiagnostics?.(), admissionDetail) {
198
+ super(databaseDependencyMessage(message, diagnostics ?? undefined));
199
+ this.admissionDetail = admissionDetail === undefined ? undefined : redactedDatabaseMessage(admissionDetail);
109
200
  this.name = "DbosDependencyError";
110
201
  }
111
202
  };
@@ -30276,11 +30367,11 @@ function fenceDbosAdmissionPool(pool) {
30276
30367
  const connect = pool.connect.bind(pool);
30277
30368
  async function acquire(signal) {
30278
30369
  if (signal.aborted)
30279
- throw new DbosDependencyError;
30370
+ throw sdkDependencyError();
30280
30371
  const pending = connect().then((client) => {
30281
30372
  if (signal.aborted) {
30282
30373
  client.release(true);
30283
- throw new DbosDependencyError;
30374
+ throw sdkDependencyError();
30284
30375
  }
30285
30376
  return fencedClient(client, signal);
30286
30377
  });
@@ -30324,7 +30415,7 @@ function fencedClient(client, signal) {
30324
30415
  const callback = typeof last === "function" ? values.pop() : undefined;
30325
30416
  const pending = (async () => {
30326
30417
  if (signal.aborted || released)
30327
- throw new DbosDependencyError;
30418
+ throw sdkDependencyError();
30328
30419
  try {
30329
30420
  return await raceAbort(new Promise((resolve, reject) => {
30330
30421
  Reflect.apply(target, client, [
@@ -30356,9 +30447,15 @@ function fencedClient(client, signal) {
30356
30447
  }
30357
30448
  });
30358
30449
  }
30450
+ function sdkDependencyError(message) {
30451
+ const reported = message === undefined ? new DbosDependencyError : new DbosDependencyError(message, null);
30452
+ return new DbosDependencyError(undefined, null, reported.message);
30453
+ }
30359
30454
  function databaseError(error, signal) {
30360
30455
  if (signal.aborted)
30361
- return new DbosDependencyError;
30456
+ return sdkDependencyError();
30457
+ if (isDbosDependencyError(error))
30458
+ return sdkDependencyError(error.admissionDetail ?? error.message);
30362
30459
  const pending = [error];
30363
30460
  const seen = new Set;
30364
30461
  while (pending.length > 0) {
@@ -30375,7 +30472,7 @@ function databaseError(error, signal) {
30375
30472
  const code = "code" in value2 && typeof value2.code === "string" ? value2.code : undefined;
30376
30473
  const message = value2 instanceof Error ? value2.message : "";
30377
30474
  if (code !== undefined && (/^(?:08|53|57)[0-9A-Z]{3}$|^40003$/.test(code) || connectionErrnos.has(code)) || code === undefined && connectionMessages.has(message)) {
30378
- return new DbosDependencyError;
30475
+ return sdkDependencyError();
30379
30476
  }
30380
30477
  }
30381
30478
  return error;
@@ -30398,7 +30495,9 @@ var init_dbos_admission_pool = __esm(() => {
30398
30495
  "Connection terminated unexpectedly",
30399
30496
  "Connection terminated due to connection timeout",
30400
30497
  "Client has encountered a connection error and is not queryable",
30401
- "timeout exceeded when trying to connect"
30498
+ "timeout exceeded when trying to connect",
30499
+ "Client was closed and is not queryable",
30500
+ "Postgres connection pool changed while acquiring a connection"
30402
30501
  ]);
30403
30502
  });
30404
30503
 
@@ -30686,6 +30785,11 @@ function defaultDatabaseUrl(name) {
30686
30785
  function configureAdmissionDatabase(sdk, config, launchLock = withDbosLaunchLock) {
30687
30786
  const systemDatabaseUrl = config.systemDatabaseUrl ?? defaultDatabaseUrl(config.name);
30688
30787
  const health = resolvedPostgresHealth(systemDatabaseUrl);
30788
+ getDbosProcessOwner().databaseDiagnostics = () => ({
30789
+ provider: health === undefined ? config.systemDatabaseUrl === undefined ? "docker" : "configured" : "managed",
30790
+ url: health?.endpoint ?? systemDatabaseUrl,
30791
+ failure: health?.lastFailure?.message
30792
+ });
30689
30793
  const createPool = () => {
30690
30794
  let unsubscribe;
30691
30795
  const managed = createRecoverablePostgresPool(systemDatabaseUrl, {
@@ -30723,6 +30827,7 @@ var import_datasource2;
30723
30827
  var init_dbos_admission_config = __esm(() => {
30724
30828
  init_dbos_admission_pool();
30725
30829
  init_dbos_launch_lock();
30830
+ init_dbos_process_owner();
30726
30831
  init_dbos_recoverable_pool();
30727
30832
  import_datasource2 = __toESM(require_datasource(), 1);
30728
30833
  });
@@ -67501,10 +67606,10 @@ function recordPendingStageMessageDeliveries(messages, runId, messageId, records
67501
67606
  if (index < 0)
67502
67607
  return messages;
67503
67608
  const entry = messages[index];
67504
- const recorded = new Set((entry.deliveries ?? []).map((delivery) => `${delivery.runId}\x00${delivery.stageId}`));
67609
+ const recorded = new Set((entry.deliveries ?? []).map((delivery) => JSON.stringify([delivery.runId, delivery.stageId, delivery.sessionId, delivery.admission])));
67505
67610
  const additions = [];
67506
67611
  for (const record of records) {
67507
- const key = `${record.runId}\x00${record.stageId}`;
67612
+ const key = JSON.stringify([record.runId, record.stageId, record.sessionId, record.admission]);
67508
67613
  if (recorded.has(key))
67509
67614
  continue;
67510
67615
  recorded.add(key);
@@ -67512,6 +67617,8 @@ function recordPendingStageMessageDeliveries(messages, runId, messageId, records
67512
67617
  runId: record.runId,
67513
67618
  stageId: record.stageId,
67514
67619
  ...record.stageName === undefined ? {} : { stageName: record.stageName },
67620
+ ...record.sessionId === undefined ? {} : { sessionId: record.sessionId },
67621
+ ...record.admission === undefined ? {} : { admission: record.admission },
67515
67622
  deliveredAt
67516
67623
  });
67517
67624
  }
@@ -85894,33 +86001,8 @@ function classifyDbosDeletionTombstone(records, workflowId) {
85894
86001
  return isCurrentDurableFormat(raw.version) ? "current" : "unknown";
85895
86002
  }
85896
86003
 
85897
- // dist/builtin/workflows/src/durable/dbos-process-owner.ts
85898
- var DBOS_PROCESS_OWNER_KEY = Symbol.for("atomic-workflows/dbos-process-owner@1");
85899
- function emptyOwner2() {
85900
- return {
85901
- version: 1,
85902
- state: "uninitialized",
85903
- configured: undefined,
85904
- active: undefined,
85905
- launchPromise: undefined,
85906
- shutdownPromise: undefined,
85907
- failure: undefined,
85908
- wrappers: undefined,
85909
- leases: new Set
85910
- };
85911
- }
85912
- function ownerBag2() {
85913
- return globalThis;
85914
- }
85915
- function getDbosProcessOwner() {
85916
- const bag = ownerBag2();
85917
- const existing = bag[DBOS_PROCESS_OWNER_KEY];
85918
- if (existing !== undefined && existing.version === 1)
85919
- return existing;
85920
- const created = emptyOwner2();
85921
- bag[DBOS_PROCESS_OWNER_KEY] = created;
85922
- return created;
85923
- }
86004
+ // dist/builtin/workflows/src/durable/dbos-backend.ts
86005
+ init_dbos_process_owner();
85924
86006
 
85925
86007
  // dist/builtin/workflows/src/durable/dbos-sdk-handle.ts
85926
86008
  var ATOMIC_EXECUTOR_ID = `atomic-${process.pid.toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
@@ -86041,6 +86123,7 @@ function statusToInfo(status, fallbackId) {
86041
86123
  }
86042
86124
 
86043
86125
  // dist/builtin/workflows/src/durable/dbos-system-database-url.ts
86126
+ init_dbos_process_owner();
86044
86127
  function nonEmptyTrimmed(value2) {
86045
86128
  const trimmed = value2?.trim();
86046
86129
  return trimmed === undefined || trimmed.length === 0 ? undefined : trimmed;
@@ -86055,9 +86138,7 @@ class DbosSystemDatabaseConflictError extends Error {
86055
86138
  function redactDatabaseUrl(url) {
86056
86139
  try {
86057
86140
  const parsed = new URL(url);
86058
- if (parsed.password !== "")
86059
- parsed.password = "***";
86060
- return parsed.toString();
86141
+ return parsed.host;
86061
86142
  } catch {
86062
86143
  return "the requested database";
86063
86144
  }
@@ -87774,6 +87855,7 @@ class PostgresHealth {
87774
87855
  attempts = 0;
87775
87856
  nextRecoveryAt = 0;
87776
87857
  failure;
87858
+ healthySinceFailure = false;
87777
87859
  revision = 0;
87778
87860
  listeners = new Set;
87779
87861
  constructor(operations) {
@@ -87782,6 +87864,18 @@ class PostgresHealth {
87782
87864
  get lastFailure() {
87783
87865
  return this.failure;
87784
87866
  }
87867
+ get endpoint() {
87868
+ return this.operations.url?.();
87869
+ }
87870
+ retainFailure(error) {
87871
+ const message = error instanceof Error ? error.message : String(error);
87872
+ const safe = redactedDatabaseMessage(message, this.endpoint);
87873
+ this.failure = new Error(safe);
87874
+ this.healthySinceFailure = false;
87875
+ }
87876
+ dependencyFailure(message) {
87877
+ return new DbosDependencyError(message, this.endpoint === undefined ? undefined : { provider: "managed", url: this.endpoint, failure: this.failure?.message });
87878
+ }
87785
87879
  subscribe(listener) {
87786
87880
  this.listeners.add(listener);
87787
87881
  return () => this.listeners.delete(listener);
@@ -87804,12 +87898,15 @@ class PostgresHealth {
87804
87898
  await this.operations.validate?.(client);
87805
87899
  }
87806
87900
  } catch (error) {
87807
- this.failure = error instanceof Error ? error : new Error(String(error));
87901
+ this.retainFailure(error);
87808
87902
  if (!isQueryReadTimeout(error)) {
87809
87903
  this.invalidate();
87810
- throw error;
87904
+ if (this.endpoint === undefined)
87905
+ throw error;
87906
+ const failure = this.dependencyFailure("Managed PostgreSQL connection validation refused. Preserve its data and ownership records.");
87907
+ throw error instanceof DbosDependencyError ? failure : new Error(failure.message);
87811
87908
  }
87812
- throw new DbosDependencyError("Managed PostgreSQL did not answer a connection identity check in time.");
87909
+ throw this.dependencyFailure("Managed PostgreSQL did not answer a connection identity check in time.");
87813
87910
  }
87814
87911
  }
87815
87912
  check() {
@@ -87850,7 +87947,7 @@ class PostgresHealth {
87850
87947
  } catch (retryError) {
87851
87948
  if (!isMonitoringConnectionFailure(retryError))
87852
87949
  throw retryError;
87853
- this.failure = retryError;
87950
+ this.retainFailure(retryError);
87854
87951
  return;
87855
87952
  }
87856
87953
  }
@@ -87865,6 +87962,7 @@ class PostgresHealth {
87865
87962
  this.available = identity;
87866
87963
  this.attempts = 0;
87867
87964
  this.nextRecoveryAt = 0;
87965
+ this.healthySinceFailure = true;
87868
87966
  return identity.url;
87869
87967
  }
87870
87968
  async refresh() {
@@ -87874,19 +87972,21 @@ class PostgresHealth {
87874
87972
  return ready;
87875
87973
  } catch (error) {
87876
87974
  if (isQueryReadTimeout(error)) {
87877
- this.failure = new DbosDependencyError("Managed PostgreSQL did not answer a health check in time.");
87878
- throw this.failure;
87975
+ this.retainFailure(new Error("Managed PostgreSQL did not answer a health check in time."));
87976
+ throw this.dependencyFailure("Managed PostgreSQL did not answer a health check in time.");
87879
87977
  }
87880
- this.failure = error instanceof Error ? error : new Error(String(error));
87978
+ this.retainFailure(error);
87881
87979
  if (!(error instanceof Error && ("code" in error) && error.code === "53300"))
87882
87980
  this.invalidate();
87883
- throw error;
87981
+ throw this.endpoint === undefined ? error : this.dependencyFailure("Managed PostgreSQL recovery refused after a health probe failure. Preserve its data and ownership records.");
87982
+ }
87983
+ if (this.attempts === 0 && (this.failure === undefined || this.healthySinceFailure)) {
87984
+ this.retainFailure(new Error("Managed PostgreSQL failed its live health check."));
87985
+ this.healthySinceFailure = false;
87884
87986
  }
87885
- if (this.attempts === 0)
87886
- this.failure = new DbosDependencyError("Managed PostgreSQL failed its live health check.");
87887
87987
  this.invalidate();
87888
87988
  if ((this.operations.now ?? Date.now)() < this.nextRecoveryAt)
87889
- throw new DbosDependencyError("Managed Postgres recovery is cooling down after bounded attempts.");
87989
+ throw this.dependencyFailure("Managed Postgres recovery is cooling down after bounded attempts.");
87890
87990
  while (!this.stopped && this.attempts < RECOVERY_ATTEMPTS) {
87891
87991
  const attempt = this.attempts++;
87892
87992
  if (attempt > 0)
@@ -87899,12 +87999,12 @@ class PostgresHealth {
87899
87999
  if (ready !== undefined)
87900
88000
  return ready;
87901
88001
  } catch (error) {
87902
- this.failure = error instanceof Error ? error : new Error(String(error));
88002
+ this.retainFailure(error);
87903
88003
  }
87904
88004
  }
87905
88005
  this.attempts = 0;
87906
88006
  this.nextRecoveryAt = (this.operations.now ?? Date.now)() + HEALTH_INTERVAL_MS;
87907
- throw new DbosDependencyError("Managed Postgres is unavailable after bounded recovery. Preserve its data and ownership records.");
88007
+ throw this.dependencyFailure("Managed Postgres is unavailable after bounded recovery. Preserve its data and ownership records.");
87908
88008
  }
87909
88009
  }
87910
88010
 
@@ -88560,6 +88660,8 @@ async function ensureCluster(options = {}) {
88560
88660
  const server = current.server;
88561
88661
  if (!server)
88562
88662
  throw new Error("Managed Postgres published identity is missing.");
88663
+ if (managedPostmaster(current) === undefined)
88664
+ return;
88563
88665
  if (!managedPostgresRuntimeHealthy(current, server.port)) {
88564
88666
  verifyManagedPostmasterProcess(current, server);
88565
88667
  return;
@@ -88576,6 +88678,7 @@ async function ensureCluster(options = {}) {
88576
88678
  };
88577
88679
  health = new PostgresHealth({
88578
88680
  probe: () => inspect(),
88681
+ url: embeddedDbosSystemDatabaseUrl,
88579
88682
  validate: async (client) => {
88580
88683
  const identity = await inspect(async () => {
88581
88684
  const query = { text: POSTGRES_IDENTITY_SQL, query_timeout: POSTGRES_HEALTH_QUERY_TIMEOUT_MS };
@@ -89663,6 +89766,9 @@ async function requireDockerSuccess(action, args) {
89663
89766
  throw new Error(`Could not ${action}: ${commandFailureDetail(result)}`);
89664
89767
  }
89665
89768
 
89769
+ // dist/builtin/workflows/src/durable/dbos-lifecycle.ts
89770
+ init_dbos_process_owner();
89771
+
89666
89772
  // dist/builtin/workflows/src/durable/dbos-registration-diagnostics.ts
89667
89773
  var cachedErrorModule;
89668
89774
  var errorModuleLoad;
@@ -92282,6 +92388,292 @@ function observeRunExecution(run, now = Date.now()) {
92282
92388
  };
92283
92389
  }
92284
92390
 
92391
+ // dist/builtin/workflows/src/durable/prompt-reservations.ts
92392
+ function durablePromptScope(backend, workflowId) {
92393
+ return backend.promptReservationScope(workflowId);
92394
+ }
92395
+ function claimDurablePromptToken(backend, workflowId, reservationId) {
92396
+ return backend.pendingPromptToken(workflowId, reservationId);
92397
+ }
92398
+ function reserveDurablePrompt(backend, workflowId, reservationId) {
92399
+ return backend.reservePendingPrompt(workflowId, reservationId);
92400
+ }
92401
+ function releaseDurablePrompt(backend, workflowId, reservationId, token) {
92402
+ backend.releasePendingPrompt(workflowId, reservationId, token);
92403
+ }
92404
+
92405
+ // dist/builtin/workflows/src/durable/scoped-backend.ts
92406
+ class ScopedDurableBackend {
92407
+ persistent;
92408
+ inner;
92409
+ scope;
92410
+ constructor(inner, scope) {
92411
+ this.inner = inner;
92412
+ this.scope = scope;
92413
+ this.persistent = inner.persistent;
92414
+ }
92415
+ registerWorkflow(_handle) {}
92416
+ persistPendingStageMessages(workflowId, messages, logicalRunId = workflowId) {
92417
+ return this.inner.persistPendingStageMessages(this.scope.rootWorkflowId, messages, logicalRunId);
92418
+ }
92419
+ recordCheckpoint(checkpoint) {
92420
+ this.inner.recordCheckpoint(this.remap(checkpoint));
92421
+ }
92422
+ async recordCheckpointAsync(checkpoint, options) {
92423
+ await this.inner.recordCheckpointAsync(this.remap(checkpoint), options);
92424
+ }
92425
+ async recordAdditiveCheckpointBestEffort(checkpoint) {
92426
+ return await this.inner.recordAdditiveCheckpointBestEffort(this.remap(checkpoint));
92427
+ }
92428
+ flush(workflowId) {
92429
+ return workflowId === undefined ? this.inner.flush() : this.inner.flush(this.scope.rootWorkflowId);
92430
+ }
92431
+ getToolOutput(_workflowId, argsHash) {
92432
+ return this.inner.getToolOutput(this.scope.rootWorkflowId, this.scopeKey(argsHash));
92433
+ }
92434
+ getToolCheckpoint(_workflowId, argsHash) {
92435
+ return this.inner.getToolCheckpoint(this.scope.rootWorkflowId, this.scopeKey(argsHash));
92436
+ }
92437
+ getUiResponse(_workflowId, promptHash) {
92438
+ return this.inner.getUiResponse(this.scope.rootWorkflowId, this.scopeKey(promptHash));
92439
+ }
92440
+ getStageOutput(_workflowId, replayKey) {
92441
+ return this.inner.getStageOutput(this.scope.rootWorkflowId, this.scopeKey(replayKey));
92442
+ }
92443
+ getStageSession(_workflowId, replayKey) {
92444
+ return this.inner.getStageSession(this.scope.rootWorkflowId, this.scopeKey(replayKey));
92445
+ }
92446
+ listCheckpoints(workflowId) {
92447
+ const prefix = `${this.scope.scopePrefix}:`;
92448
+ return this.inner.listCheckpoints(this.scope.rootWorkflowId).filter((checkpoint) => checkpointHasPrefix(checkpoint, prefix)).map((checkpoint) => localCheckpoint(checkpoint, workflowId, prefix));
92449
+ }
92450
+ getWorkflow(_workflowId) {
92451
+ return;
92452
+ }
92453
+ getLoadableWorkflow(_workflowId) {
92454
+ return;
92455
+ }
92456
+ setWorkflowStatus(_workflowId, _status, _pendingPrompts, _resumable) {}
92457
+ async transitionWorkflowStatus(_workflowId, _expectedStatuses, _status, _pendingPrompts, _resumable) {
92458
+ return false;
92459
+ }
92460
+ adjustPendingPrompts(_workflowId, delta) {
92461
+ this.inner.adjustPendingPrompts(this.scope.rootWorkflowId, delta);
92462
+ }
92463
+ promptReservationScope(_workflowId) {
92464
+ return this.effectivePromptScope();
92465
+ }
92466
+ pendingPromptToken(_workflowId, reservationId) {
92467
+ return claimDurablePromptToken(this.inner, this.scope.rootWorkflowId, reservationId);
92468
+ }
92469
+ reservePendingPrompt(_workflowId, reservationId) {
92470
+ return reserveDurablePrompt(this.inner, this.scope.rootWorkflowId, reservationId);
92471
+ }
92472
+ releasePendingPrompt(_workflowId, reservationId, token) {
92473
+ releaseDurablePrompt(this.inner, this.scope.rootWorkflowId, reservationId, token);
92474
+ }
92475
+ listResumableWorkflows() {
92476
+ return [];
92477
+ }
92478
+ listCompletedWorkflows() {
92479
+ return [];
92480
+ }
92481
+ async prepareWorkflowCatalog() {
92482
+ return { resumable: [], completed: [] };
92483
+ }
92484
+ toMetadata(_workflowId) {
92485
+ return;
92486
+ }
92487
+ async deleteWorkflow(_workflowId) {}
92488
+ async deleteWorkflowIfInactive(_workflowId) {
92489
+ return { ok: false, reason: "not_found" };
92490
+ }
92491
+ isWorkflowLoadable(_workflowId) {
92492
+ return false;
92493
+ }
92494
+ reset() {}
92495
+ hydrateWorkflow(_workflowId) {
92496
+ return Promise.resolve();
92497
+ }
92498
+ hydrateWorkflowForInspection(_workflowId) {
92499
+ return Promise.resolve({ kind: "absent" });
92500
+ }
92501
+ hydrateResumableWorkflows() {
92502
+ return Promise.resolve();
92503
+ }
92504
+ effectivePromptScope() {
92505
+ const parent = durablePromptScope(this.inner, this.scope.rootWorkflowId);
92506
+ const scope = parent.scope === "root" ? this.scope.scopePrefix : `${parent.scope}:${this.scope.scopePrefix}`;
92507
+ return {
92508
+ rootWorkflowId: parent.rootWorkflowId,
92509
+ scope
92510
+ };
92511
+ }
92512
+ scopeKey(key) {
92513
+ return `${this.scope.scopePrefix}:${key}`;
92514
+ }
92515
+ remap(checkpoint) {
92516
+ const workflowId = this.scope.rootWorkflowId;
92517
+ if (checkpoint.kind === "tool") {
92518
+ return {
92519
+ ...checkpoint,
92520
+ workflowId,
92521
+ checkpointId: this.scopeKey(checkpoint.checkpointId),
92522
+ argsHash: this.scopeKey(checkpoint.argsHash)
92523
+ };
92524
+ }
92525
+ if (checkpoint.kind === "ui") {
92526
+ return {
92527
+ ...checkpoint,
92528
+ workflowId,
92529
+ checkpointId: this.scopeKey(checkpoint.checkpointId),
92530
+ promptHash: this.scopeKey(checkpoint.promptHash)
92531
+ };
92532
+ }
92533
+ return {
92534
+ ...checkpoint,
92535
+ workflowId,
92536
+ checkpointId: this.scopeKey(checkpoint.checkpointId),
92537
+ replayKey: this.scopeKey(checkpoint.replayKey),
92538
+ ...remappedBoundaryScope(checkpoint, this.scopeKey(checkpoint.topology?.boundary?.replayScope ?? ""))
92539
+ };
92540
+ }
92541
+ }
92542
+ function checkpointHasPrefix(checkpoint, prefix) {
92543
+ if (!checkpoint.checkpointId.startsWith(prefix))
92544
+ return false;
92545
+ if (checkpoint.kind === "tool")
92546
+ return checkpoint.argsHash.startsWith(prefix);
92547
+ if (checkpoint.kind === "ui")
92548
+ return checkpoint.promptHash.startsWith(prefix);
92549
+ return checkpoint.replayKey.startsWith(prefix);
92550
+ }
92551
+ function localCheckpoint(checkpoint, workflowId, prefix) {
92552
+ const checkpointId = checkpoint.checkpointId.slice(prefix.length);
92553
+ if (checkpoint.kind === "tool") {
92554
+ return { ...checkpoint, workflowId, checkpointId, argsHash: checkpoint.argsHash.slice(prefix.length) };
92555
+ }
92556
+ if (checkpoint.kind === "ui") {
92557
+ return { ...checkpoint, workflowId, checkpointId, promptHash: checkpoint.promptHash.slice(prefix.length) };
92558
+ }
92559
+ const replayKey = checkpoint.replayKey.slice(prefix.length);
92560
+ const replayScope = stripOnePrefix(checkpoint.topology?.boundary?.replayScope, prefix);
92561
+ return {
92562
+ ...checkpoint,
92563
+ workflowId,
92564
+ checkpointId,
92565
+ replayKey,
92566
+ ...remappedBoundaryScope(checkpoint, replayScope)
92567
+ };
92568
+ }
92569
+ function remappedBoundaryScope(checkpoint, replayScope) {
92570
+ const topology = checkpoint.topology;
92571
+ if (topology?.boundary === undefined || replayScope === undefined)
92572
+ return {};
92573
+ return {
92574
+ topology: {
92575
+ ...topology,
92576
+ boundary: { ...topology.boundary, replayScope }
92577
+ }
92578
+ };
92579
+ }
92580
+ function stripOnePrefix(value2, prefix) {
92581
+ if (value2 === undefined || !value2.startsWith(prefix))
92582
+ return value2;
92583
+ return value2.slice(prefix.length);
92584
+ }
92585
+
92586
+ // dist/builtin/workflows/src/durable/run-owner-backend.ts
92587
+ function durableRootRunIdForRun(runs, runId) {
92588
+ return reciprocalWorkflowRootRunId(new Map(runs.map((run) => [run.id, run])), runId);
92589
+ }
92590
+ function durableBackendForRun(backend, runs, runId) {
92591
+ const rootRunId = durableRootRunIdForRun(runs, runId);
92592
+ if (rootRunId === undefined)
92593
+ return;
92594
+ const runById = new Map(runs.map((run) => [run.id, run]));
92595
+ if (rootRunId === runId)
92596
+ return backend;
92597
+ const scopes = [];
92598
+ let current = runById.get(runId);
92599
+ while (current !== undefined && current.id !== rootRunId) {
92600
+ const parent = current.parentRunId === undefined ? undefined : runById.get(current.parentRunId);
92601
+ const boundary = parent?.stages.find((stage) => stage.id === current?.parentStageId);
92602
+ if (parent === undefined || boundary?.replayKey === undefined)
92603
+ return;
92604
+ scopes.push(boundary.replayKey);
92605
+ current = parent;
92606
+ }
92607
+ if (current?.id !== rootRunId)
92608
+ return;
92609
+ let view = backend;
92610
+ for (const scopePrefix of scopes.reverse()) {
92611
+ view = new ScopedDurableBackend(view, { rootWorkflowId: rootRunId, scopePrefix });
92612
+ }
92613
+ return view;
92614
+ }
92615
+
92616
+ // dist/builtin/workflows/src/shared/sticky-stage-delivery-status.ts
92617
+ function stickyStageDeliveryStatuses(runs, rootRunId) {
92618
+ const root = runs.find((run) => run.id === rootRunId);
92619
+ const entries = (root?.pendingStageMessages ?? []).filter((entry) => entry.sticky === true);
92620
+ const result = [];
92621
+ for (const run of runs) {
92622
+ if (run.id !== rootRunId && run.rootRunId !== rootRunId && durableRootRunIdForRun(runs, run.id) !== rootRunId)
92623
+ continue;
92624
+ const resolved = durableRootRunIdForRun(runs, run.id) === rootRunId;
92625
+ const hops = workflowBoundaryHops(runs, run.id);
92626
+ for (const stage of run.stages) {
92627
+ if (stage.nodeKind === "tool" || stage.replayKey?.startsWith("prompt:") === true || stage.replayKey?.startsWith("workflow:") === true || stage.workflowChildRun !== undefined || stage.workflowChild !== undefined)
92628
+ continue;
92629
+ for (const entry of entries) {
92630
+ const target = entry.targetPath ?? entry.stageKey;
92631
+ const parsed = parseWorkflowStageTarget(target);
92632
+ if (!parsed || parsed.rootRunId !== rootRunId)
92633
+ continue;
92634
+ if (resolved && hops && !stageMatchesPathPattern(parsed.segments, hops, [stage.id, stage.name]))
92635
+ continue;
92636
+ const receipts = (entry.deliveries ?? []).filter((delivery) => delivery.runId === run.id && delivery.stageId === stage.id);
92637
+ const delivered = receipts.some((delivery) => delivery.admission === "context" && delivery.sessionId !== undefined && (stage.sessionId === undefined || delivery.sessionId === stage.sessionId));
92638
+ let state;
92639
+ let reason;
92640
+ if (!resolved || !hops) {
92641
+ state = "root-unresolved";
92642
+ reason = "Repair reciprocal parent/boundary ownership before startup";
92643
+ } else if (delivered) {
92644
+ state = "delivered";
92645
+ reason = "Startup context admission confirmed; sticky subscription remains for future stages";
92646
+ } else if (["completed", "failed", "skipped"].includes(stage.status)) {
92647
+ state = "stage-terminal";
92648
+ reason = `${stage.error ? `${stage.error}; ` : ""}Stage ended without confirmed context admission; steer a live stage or start a new stage`;
92649
+ } else if (receipts.some((delivery) => delivery.admission !== "context" && (delivery.sessionId === undefined || stage.sessionId === undefined || delivery.sessionId === stage.sessionId))) {
92650
+ state = "receipt-unverified";
92651
+ reason = "Legacy or live transport receipt only; inspect the session transcript to confirm context admission";
92652
+ } else if (stage.pendingStageDeliveryAvailable !== true) {
92653
+ state = "delivery-unavailable";
92654
+ reason = "Stage has no pre-start Intercom helper; enable Intercom in the invocation group";
92655
+ } else if (receipts.length > 0) {
92656
+ state = "session-replaced";
92657
+ reason = "Only a previous session has a receipt; replacement must drain before its first turn";
92658
+ } else {
92659
+ state = "queued";
92660
+ reason = "No delivery receipt; stage startup must drain before its first turn";
92661
+ }
92662
+ result.push({
92663
+ messageId: entry.message.id,
92664
+ target,
92665
+ runId: run.id,
92666
+ stageId: stage.id,
92667
+ ...stage.sessionId === undefined ? {} : { sessionId: stage.sessionId },
92668
+ state,
92669
+ reason
92670
+ });
92671
+ }
92672
+ }
92673
+ }
92674
+ return result;
92675
+ }
92676
+
92285
92677
  // dist/builtin/workflows/src/runs/background/run-inspect.ts
92286
92678
  function inspectRun(runId, opts) {
92287
92679
  const activeStore = opts?.store ?? store;
@@ -92312,6 +92704,7 @@ function inspectRun(runId, opts) {
92312
92704
  inputs: copy.inputs,
92313
92705
  stages: expandedStages.map((stage) => structuredClone(stage)),
92314
92706
  tools: expandedGraph.tools.map((tool) => structuredClone(tool)),
92707
+ deliveryStates: stickyStageDeliveryStatuses(activeStore.runs(), copy.rootRunId ?? copy.id).filter((delivery) => copy.id === (copy.rootRunId ?? copy.id) || delivery.runId === copy.id),
92315
92708
  result: copy.result,
92316
92709
  error: copy.error ?? (strandedRoot ? IMPOSSIBLE_ROOT_LIVENESS_MESSAGE : effectiveRunStatus(copy) === copy.status ? undefined : structuredRecoverableWorkflowFailureText(copy) ?? actionableReturnedStatusText(copy.result)),
92317
92710
  exited: copy.exited,
@@ -94096,6 +94489,9 @@ function registerWorkflowLifecycleHandlers(pi, deps) {
94096
94489
  });
94097
94490
  }
94098
94491
 
94492
+ // dist/builtin/workflows/src/extension/extension-runtime-state.ts
94493
+ init_dbos_process_owner();
94494
+
94099
94495
  // dist/builtin/workflows/src/durable/workflow-heartbeat-anchor.ts
94100
94496
  var WORKFLOW_HEARTBEAT_ANCHOR_CHECKPOINT_NAME = "workflow-heartbeat-anchor";
94101
94497
  function asPersistedAnchorOutput(output) {
@@ -102243,201 +102639,7 @@ function hasInvocationData(checkpoints, replayKey) {
102243
102639
 
102244
102640
  // dist/builtin/workflows/src/engine/run.ts
102245
102641
  init_dbos_admission();
102246
-
102247
- // dist/builtin/workflows/src/durable/prompt-reservations.ts
102248
- function durablePromptScope(backend, workflowId) {
102249
- return backend.promptReservationScope(workflowId);
102250
- }
102251
- function claimDurablePromptToken(backend, workflowId, reservationId) {
102252
- return backend.pendingPromptToken(workflowId, reservationId);
102253
- }
102254
- function reserveDurablePrompt(backend, workflowId, reservationId) {
102255
- return backend.reservePendingPrompt(workflowId, reservationId);
102256
- }
102257
- function releaseDurablePrompt(backend, workflowId, reservationId, token) {
102258
- backend.releasePendingPrompt(workflowId, reservationId, token);
102259
- }
102260
-
102261
- // dist/builtin/workflows/src/durable/scoped-backend.ts
102262
- class ScopedDurableBackend {
102263
- persistent;
102264
- inner;
102265
- scope;
102266
- constructor(inner, scope) {
102267
- this.inner = inner;
102268
- this.scope = scope;
102269
- this.persistent = inner.persistent;
102270
- }
102271
- registerWorkflow(_handle) {}
102272
- persistPendingStageMessages(workflowId, messages, logicalRunId = workflowId) {
102273
- return this.inner.persistPendingStageMessages(this.scope.rootWorkflowId, messages, logicalRunId);
102274
- }
102275
- recordCheckpoint(checkpoint) {
102276
- this.inner.recordCheckpoint(this.remap(checkpoint));
102277
- }
102278
- async recordCheckpointAsync(checkpoint, options) {
102279
- await this.inner.recordCheckpointAsync(this.remap(checkpoint), options);
102280
- }
102281
- async recordAdditiveCheckpointBestEffort(checkpoint) {
102282
- return await this.inner.recordAdditiveCheckpointBestEffort(this.remap(checkpoint));
102283
- }
102284
- flush(workflowId) {
102285
- return workflowId === undefined ? this.inner.flush() : this.inner.flush(this.scope.rootWorkflowId);
102286
- }
102287
- getToolOutput(_workflowId, argsHash) {
102288
- return this.inner.getToolOutput(this.scope.rootWorkflowId, this.scopeKey(argsHash));
102289
- }
102290
- getToolCheckpoint(_workflowId, argsHash) {
102291
- return this.inner.getToolCheckpoint(this.scope.rootWorkflowId, this.scopeKey(argsHash));
102292
- }
102293
- getUiResponse(_workflowId, promptHash) {
102294
- return this.inner.getUiResponse(this.scope.rootWorkflowId, this.scopeKey(promptHash));
102295
- }
102296
- getStageOutput(_workflowId, replayKey) {
102297
- return this.inner.getStageOutput(this.scope.rootWorkflowId, this.scopeKey(replayKey));
102298
- }
102299
- getStageSession(_workflowId, replayKey) {
102300
- return this.inner.getStageSession(this.scope.rootWorkflowId, this.scopeKey(replayKey));
102301
- }
102302
- listCheckpoints(workflowId) {
102303
- const prefix = `${this.scope.scopePrefix}:`;
102304
- return this.inner.listCheckpoints(this.scope.rootWorkflowId).filter((checkpoint) => checkpointHasPrefix(checkpoint, prefix)).map((checkpoint) => localCheckpoint(checkpoint, workflowId, prefix));
102305
- }
102306
- getWorkflow(_workflowId) {
102307
- return;
102308
- }
102309
- getLoadableWorkflow(_workflowId) {
102310
- return;
102311
- }
102312
- setWorkflowStatus(_workflowId, _status, _pendingPrompts, _resumable) {}
102313
- async transitionWorkflowStatus(_workflowId, _expectedStatuses, _status, _pendingPrompts, _resumable) {
102314
- return false;
102315
- }
102316
- adjustPendingPrompts(_workflowId, delta) {
102317
- this.inner.adjustPendingPrompts(this.scope.rootWorkflowId, delta);
102318
- }
102319
- promptReservationScope(_workflowId) {
102320
- return this.effectivePromptScope();
102321
- }
102322
- pendingPromptToken(_workflowId, reservationId) {
102323
- return claimDurablePromptToken(this.inner, this.scope.rootWorkflowId, reservationId);
102324
- }
102325
- reservePendingPrompt(_workflowId, reservationId) {
102326
- return reserveDurablePrompt(this.inner, this.scope.rootWorkflowId, reservationId);
102327
- }
102328
- releasePendingPrompt(_workflowId, reservationId, token) {
102329
- releaseDurablePrompt(this.inner, this.scope.rootWorkflowId, reservationId, token);
102330
- }
102331
- listResumableWorkflows() {
102332
- return [];
102333
- }
102334
- listCompletedWorkflows() {
102335
- return [];
102336
- }
102337
- async prepareWorkflowCatalog() {
102338
- return { resumable: [], completed: [] };
102339
- }
102340
- toMetadata(_workflowId) {
102341
- return;
102342
- }
102343
- async deleteWorkflow(_workflowId) {}
102344
- async deleteWorkflowIfInactive(_workflowId) {
102345
- return { ok: false, reason: "not_found" };
102346
- }
102347
- isWorkflowLoadable(_workflowId) {
102348
- return false;
102349
- }
102350
- reset() {}
102351
- hydrateWorkflow(_workflowId) {
102352
- return Promise.resolve();
102353
- }
102354
- hydrateWorkflowForInspection(_workflowId) {
102355
- return Promise.resolve({ kind: "absent" });
102356
- }
102357
- hydrateResumableWorkflows() {
102358
- return Promise.resolve();
102359
- }
102360
- effectivePromptScope() {
102361
- const parent = durablePromptScope(this.inner, this.scope.rootWorkflowId);
102362
- const scope = parent.scope === "root" ? this.scope.scopePrefix : `${parent.scope}:${this.scope.scopePrefix}`;
102363
- return {
102364
- rootWorkflowId: parent.rootWorkflowId,
102365
- scope
102366
- };
102367
- }
102368
- scopeKey(key) {
102369
- return `${this.scope.scopePrefix}:${key}`;
102370
- }
102371
- remap(checkpoint) {
102372
- const workflowId = this.scope.rootWorkflowId;
102373
- if (checkpoint.kind === "tool") {
102374
- return {
102375
- ...checkpoint,
102376
- workflowId,
102377
- checkpointId: this.scopeKey(checkpoint.checkpointId),
102378
- argsHash: this.scopeKey(checkpoint.argsHash)
102379
- };
102380
- }
102381
- if (checkpoint.kind === "ui") {
102382
- return {
102383
- ...checkpoint,
102384
- workflowId,
102385
- checkpointId: this.scopeKey(checkpoint.checkpointId),
102386
- promptHash: this.scopeKey(checkpoint.promptHash)
102387
- };
102388
- }
102389
- return {
102390
- ...checkpoint,
102391
- workflowId,
102392
- checkpointId: this.scopeKey(checkpoint.checkpointId),
102393
- replayKey: this.scopeKey(checkpoint.replayKey),
102394
- ...remappedBoundaryScope(checkpoint, this.scopeKey(checkpoint.topology?.boundary?.replayScope ?? ""))
102395
- };
102396
- }
102397
- }
102398
- function checkpointHasPrefix(checkpoint, prefix) {
102399
- if (!checkpoint.checkpointId.startsWith(prefix))
102400
- return false;
102401
- if (checkpoint.kind === "tool")
102402
- return checkpoint.argsHash.startsWith(prefix);
102403
- if (checkpoint.kind === "ui")
102404
- return checkpoint.promptHash.startsWith(prefix);
102405
- return checkpoint.replayKey.startsWith(prefix);
102406
- }
102407
- function localCheckpoint(checkpoint, workflowId, prefix) {
102408
- const checkpointId = checkpoint.checkpointId.slice(prefix.length);
102409
- if (checkpoint.kind === "tool") {
102410
- return { ...checkpoint, workflowId, checkpointId, argsHash: checkpoint.argsHash.slice(prefix.length) };
102411
- }
102412
- if (checkpoint.kind === "ui") {
102413
- return { ...checkpoint, workflowId, checkpointId, promptHash: checkpoint.promptHash.slice(prefix.length) };
102414
- }
102415
- const replayKey = checkpoint.replayKey.slice(prefix.length);
102416
- const replayScope = stripOnePrefix(checkpoint.topology?.boundary?.replayScope, prefix);
102417
- return {
102418
- ...checkpoint,
102419
- workflowId,
102420
- checkpointId,
102421
- replayKey,
102422
- ...remappedBoundaryScope(checkpoint, replayScope)
102423
- };
102424
- }
102425
- function remappedBoundaryScope(checkpoint, replayScope) {
102426
- const topology = checkpoint.topology;
102427
- if (topology?.boundary === undefined || replayScope === undefined)
102428
- return {};
102429
- return {
102430
- topology: {
102431
- ...topology,
102432
- boundary: { ...topology.boundary, replayScope }
102433
- }
102434
- };
102435
- }
102436
- function stripOnePrefix(value2, prefix) {
102437
- if (value2 === undefined || !value2.startsWith(prefix))
102438
- return value2;
102439
- return value2.slice(prefix.length);
102440
- }
102642
+ init_dbos_process_owner();
102441
102643
 
102442
102644
  // dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts
102443
102645
  import { isAbsolute as isAbsolute12, join as join28, resolve as resolve12 } from "node:path";
@@ -109433,36 +109635,6 @@ function createReplayStageContext(input) {
109433
109635
  };
109434
109636
  }
109435
109637
 
109436
- // dist/builtin/workflows/src/durable/run-owner-backend.ts
109437
- function durableRootRunIdForRun(runs, runId) {
109438
- return reciprocalWorkflowRootRunId(new Map(runs.map((run) => [run.id, run])), runId);
109439
- }
109440
- function durableBackendForRun(backend, runs, runId) {
109441
- const rootRunId = durableRootRunIdForRun(runs, runId);
109442
- if (rootRunId === undefined)
109443
- return;
109444
- const runById = new Map(runs.map((run) => [run.id, run]));
109445
- if (rootRunId === runId)
109446
- return backend;
109447
- const scopes = [];
109448
- let current = runById.get(runId);
109449
- while (current !== undefined && current.id !== rootRunId) {
109450
- const parent = current.parentRunId === undefined ? undefined : runById.get(current.parentRunId);
109451
- const boundary = parent?.stages.find((stage) => stage.id === current?.parentStageId);
109452
- if (parent === undefined || boundary?.replayKey === undefined)
109453
- return;
109454
- scopes.push(boundary.replayKey);
109455
- current = parent;
109456
- }
109457
- if (current?.id !== rootRunId)
109458
- return;
109459
- let view = backend;
109460
- for (const scopePrefix of scopes.reverse()) {
109461
- view = new ScopedDurableBackend(view, { rootWorkflowId: rootRunId, scopePrefix });
109462
- }
109463
- return view;
109464
- }
109465
-
109466
109638
  // dist/builtin/workflows/src/shared/pending-stage-route-capability.ts
109467
109639
  import { randomUUID as randomUUID9 } from "node:crypto";
109468
109640
  var routeCapabilities = new WeakMap;
@@ -109521,14 +109693,21 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
109521
109693
  };
109522
109694
  return {
109523
109695
  routeCapability: workflowPendingStageRouteCapability(activeStore, runId),
109524
- deliverPending(deliver) {
109696
+ deliverPending(deliver, recipient) {
109525
109697
  if (drainPromise !== undefined)
109526
109698
  return drainPromise;
109527
109699
  if (terminalError !== undefined)
109528
109700
  return Promise.resolve();
109529
109701
  drainError = undefined;
109530
- const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver);
109531
- const drain = attempt.then(() => resolveReady?.(), (error) => {
109702
+ const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, recipient);
109703
+ const drain = attempt.then(() => {
109704
+ resolveReady?.();
109705
+ readyPromise = undefined;
109706
+ resolveReady = undefined;
109707
+ rejectReady = undefined;
109708
+ if (drainPromise === drain)
109709
+ drainPromise = undefined;
109710
+ }, (error) => {
109532
109711
  drainError = error;
109533
109712
  rejectReady?.(error);
109534
109713
  readyPromise = undefined;
@@ -109541,8 +109720,8 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
109541
109720
  drainPromise = drain;
109542
109721
  return drainPromise;
109543
109722
  },
109544
- ready() {
109545
- if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName || activeStore.pendingStageMessagesFor(runId, stageName).length === 0) && stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName).length === 0) {
109723
+ ready(sessionId) {
109724
+ if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName || activeStore.pendingStageMessagesFor(runId, stageName).length === 0) && stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, sessionId === undefined ? undefined : { sessionId }).length === 0) {
109546
109725
  return;
109547
109726
  }
109548
109727
  if (terminalError !== undefined)
@@ -109560,8 +109739,8 @@ function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageNa
109560
109739
  }
109561
109740
  };
109562
109741
  }
109563
- async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver) {
109564
- const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName);
109742
+ async function deliverPendingStageMessages(activeStore, runId, stageId, stageName, deliver, recipient) {
109743
+ const stickyEntries = stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient);
109565
109744
  const candidateIds = new Set([
109566
109745
  ...activeStore.pendingStageMessagesFor(runId, stageId),
109567
109746
  ...activeStore.pendingStageMessagesFor(runId, stageName),
@@ -109583,7 +109762,8 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
109583
109762
  if (releaseClaim === undefined)
109584
109763
  continue;
109585
109764
  try {
109586
- await deliver(toPendingStageSender(entry), entry.message);
109765
+ if (!recipient?.receivedMessageIds.includes(entry.message.id))
109766
+ await deliver(toPendingStageSender(entry), entry.message);
109587
109767
  if (entry.sticky === true) {
109588
109768
  const entryBackend = durableBackendForRun(rootBackend, activeStore.runs(), entry.runId);
109589
109769
  if (entryBackend === undefined) {
@@ -109593,7 +109773,8 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
109593
109773
  {
109594
109774
  runId,
109595
109775
  stageId,
109596
- ...stageName === stageId ? {} : { stageName }
109776
+ ...stageName === stageId ? {} : { stageName },
109777
+ ...recipient === undefined ? {} : { sessionId: recipient.sessionId, admission: "context" }
109597
109778
  }
109598
109779
  ], new Date().toISOString(), entryBackend)) {
109599
109780
  throw new Error(`atomic-workflows: pending-stage message ${entry.id} changed during delivery`);
@@ -109608,7 +109789,7 @@ async function deliverPendingStageMessages(activeStore, runId, stageId, stageNam
109608
109789
  }
109609
109790
  }
109610
109791
  }
109611
- function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName) {
109792
+ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageName, recipient) {
109612
109793
  const runs = activeStore.runs();
109613
109794
  const rootRunId = durableRootRunIdForRun(runs, runId);
109614
109795
  if (rootRunId === undefined)
@@ -109625,9 +109806,8 @@ function stickyPendingStageEntriesForStage(activeStore, runId, stageId, stageNam
109625
109806
  const parsed = entry.targetPath === undefined ? undefined : parseWorkflowStageTarget(entry.targetPath);
109626
109807
  if (parsed === undefined || parsed.rootRunId !== rootRunId)
109627
109808
  return false;
109628
- if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId)) {
109809
+ if ((entry.deliveries ?? []).some((delivery) => delivery.runId === runId && delivery.stageId === stageId && (recipient === undefined || delivery.admission === "context" && delivery.sessionId === recipient.sessionId && (recipient.receivedMessageIds === undefined || recipient.receivedMessageIds.includes(entry.message.id)))))
109629
109810
  return false;
109630
- }
109631
109811
  return stageMatchesPathPattern(parsed.segments, hops, [stageId, stageName]);
109632
109812
  });
109633
109813
  }
@@ -112155,7 +112335,7 @@ class StageSessionController {
112155
112335
  const attachedSession = session instanceof Promise ? await session : session;
112156
112336
  this.reportStartupPhase("delivery-readiness");
112157
112337
  try {
112158
- await this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
112338
+ await this.sharedOrchestrationContext?.pendingStageDelivery?.ready(attachedSession.sessionId);
112159
112339
  await this.opts.onSessionReady?.();
112160
112340
  if (this.disposed || this.opts.signal?.aborted || this.abortGeneration !== startGeneration)
112161
112341
  throw this.staleCreationReason(startGeneration);
@@ -114130,7 +114310,7 @@ async function run(def, inputs, opts = {}) {
114130
114310
  if (control === latestControl && !ownController.signal.aborted && isDbosDependencyError(error)) {
114131
114311
  activeStore.recordRunExecutionState(runId, {
114132
114312
  phase: "blocked_dependency",
114133
- dependencyError: `Workflow database unavailable during ${status === "paused" ? "pause" : "resume"}; persistence not confirmed.`
114313
+ dependencyError: `Workflow database unavailable during ${status === "paused" ? "pause" : "resume"}; persistence not confirmed. ${error.message}`
114134
114314
  });
114135
114315
  if (status === "paused")
114136
114316
  return;
@@ -114177,7 +114357,7 @@ async function run(def, inputs, opts = {}) {
114177
114357
  if (!admission.admitting)
114178
114358
  return pausePersistence;
114179
114359
  backgroundAdmissionControl(durableBackend, runId, pausePersistence, (error, resumable) => {
114180
- admissionControlError = unknownErrorMessage(error);
114360
+ admissionControlError = databaseDependencyMessage(unknownErrorMessage(error), getDbosProcessOwner().databaseDiagnostics?.());
114181
114361
  runSnapshot.error = admissionControlError;
114182
114362
  activeStore.recordRunPaused(runId, undefined, { resumable });
114183
114363
  return runSnapshot.error;
@@ -114194,7 +114374,7 @@ async function run(def, inputs, opts = {}) {
114194
114374
  } catch (error) {
114195
114375
  if (admission.failed) {
114196
114376
  scheduler.releaseRun();
114197
- throw error;
114377
+ throw new Error(admissionControlError ?? databaseDependencyMessage(unknownErrorMessage(error), getDbosProcessOwner().databaseDiagnostics?.()));
114198
114378
  }
114199
114379
  }
114200
114380
  if (generation !== pauseGeneration)
@@ -114267,12 +114447,21 @@ async function run(def, inputs, opts = {}) {
114267
114447
  }).catch((error) => {
114268
114448
  const isTopologyError = typeof error === "object" && error !== null && "name" in error && error.name === "DurableNestedTopologyError";
114269
114449
  if (!isDbosDependencyError(error) && !isTopologyError) {
114270
- durableAdmissionFailure = { error };
114271
- classifiedFailures.set(error, classifyWorkflowFailure({
114450
+ const admissionDetail = unknownErrorMessage(error);
114451
+ const diagnostics = getDbosProcessOwner().databaseDiagnostics?.();
114452
+ const safeMessage = databaseDependencyMessage(admissionDetail, diagnostics);
114453
+ activeStore.recordRunExecutionState(runId, {
114454
+ phase: "blocked_dependency",
114455
+ dependencyError: safeMessage
114456
+ });
114457
+ const safeError = new Error(safeMessage);
114458
+ durableAdmissionFailure = { error: safeError };
114459
+ classifiedFailures.set(safeError, classifyWorkflowFailure({
114272
114460
  code: "ATOMIC_DURABLE_ADMISSION_REJECTED",
114273
- message: unknownErrorMessage(error),
114274
- cause: error
114461
+ message: safeMessage,
114462
+ cause: safeError
114275
114463
  }));
114464
+ throw safeError;
114276
114465
  }
114277
114466
  throw error;
114278
114467
  }), ownController.signal);
@@ -115582,7 +115771,11 @@ function createExtensionRuntime(opts = {}) {
115582
115771
  const resolvePossibleStageEntry = opts.resolvePossibleStageEntry;
115583
115772
  const beforeRestoreCompleted = opts.beforeRestoreCompleted;
115584
115773
  const ensureDbosReady = async () => {
115585
- return await initializeDurableBackend(durabilityWarningSink);
115774
+ if (opts.prepareDatabase !== undefined)
115775
+ await opts.prepareDatabase();
115776
+ const backend = await initializeDurableBackend(durabilityWarningSink);
115777
+ opts.databaseReady?.();
115778
+ return backend;
115586
115779
  };
115587
115780
  function runOptions(policy) {
115588
115781
  const defaultSessionDir = resolveDefaultStageSessionDir?.();
@@ -115853,6 +116046,95 @@ function createStatusWriter(store, config, opts = {}) {
115853
116046
  };
115854
116047
  }
115855
116048
 
116049
+ // dist/builtin/workflows/src/extension/workflow-database-settings.ts
116050
+ import { readFileSync as readFileSync7 } from "node:fs";
116051
+ import { readFile as readFile6 } from "node:fs/promises";
116052
+ import { homedir as homedir3 } from "node:os";
116053
+ import { join as join33, resolve as resolve15 } from "node:path";
116054
+ import { getAgentDir as getAgentDir3, getAgentDirs as getAgentDirs3, getProjectConfigDirs, SettingsManager } from "@bastani/atomic";
116055
+ var DATABASE_SETTING_KEYS = new Set(["systemDatabaseUrl", "systemDatabaseUrlFile"]);
116056
+ function databaseSettings(settings) {
116057
+ const workflows = settings.workflows;
116058
+ if (workflows === undefined || workflows === null || Array.isArray(workflows))
116059
+ return;
116060
+ if (typeof workflows !== "object")
116061
+ throw new TypeError("workflows must be an array of paths or an object");
116062
+ return workflows.durability;
116063
+ }
116064
+ function readSettingsFile(directory) {
116065
+ let parsed;
116066
+ try {
116067
+ parsed = JSON.parse(readFileSync7(join33(directory, "settings.json"), "utf8").replace(/^\uFEFF/, ""));
116068
+ } catch {
116069
+ return;
116070
+ }
116071
+ return parsed !== null && typeof parsed === "object" ? parsed : undefined;
116072
+ }
116073
+ function settingsDirectoryDeclaringDatabase(directories) {
116074
+ let declaring;
116075
+ for (const directory of directories) {
116076
+ const settings = readSettingsFile(directory);
116077
+ if (settings !== undefined && databaseSettings(settings) !== undefined)
116078
+ declaring ??= directory;
116079
+ }
116080
+ return declaring ?? directories[0];
116081
+ }
116082
+ async function resolveWorkflowDatabaseSettings(global2, project, directories) {
116083
+ const projectDatabase = databaseSettings(project);
116084
+ const database = projectDatabase !== undefined ? projectDatabase : databaseSettings(global2);
116085
+ if (database === undefined)
116086
+ return;
116087
+ if (database === null || typeof database !== "object" || Array.isArray(database)) {
116088
+ throw new TypeError("workflows.durability must be an object");
116089
+ }
116090
+ if (Object.keys(database).some((key) => !DATABASE_SETTING_KEYS.has(key))) {
116091
+ throw new TypeError("workflows.durability supports only systemDatabaseUrl or systemDatabaseUrlFile");
116092
+ }
116093
+ const { systemDatabaseUrl: url, systemDatabaseUrlFile: file } = database;
116094
+ if (url !== undefined && file !== undefined) {
116095
+ throw new TypeError("Set only one of workflows.durability.systemDatabaseUrl and systemDatabaseUrlFile");
116096
+ }
116097
+ let value2 = url;
116098
+ if (file !== undefined) {
116099
+ if (typeof file !== "string" || file.trim() === "") {
116100
+ throw new TypeError("workflows.durability.systemDatabaseUrlFile must be a non-empty path");
116101
+ }
116102
+ const path = file.startsWith("~/") || file.startsWith("~\\") ? join33(homedir3(), file.slice(2)) : resolve15(projectDatabase === undefined ? directories.global : directories.project, file);
116103
+ try {
116104
+ value2 = await readFile6(path, "utf8");
116105
+ } catch {
116106
+ throw new Error("Cannot read workflows.durability.systemDatabaseUrlFile; check its path and permissions");
116107
+ }
116108
+ }
116109
+ if (value2 === undefined)
116110
+ return;
116111
+ if (typeof value2 !== "string" || value2.trim() === "") {
116112
+ throw new TypeError("Workflow database selection must contain a non-empty Postgres URL");
116113
+ }
116114
+ try {
116115
+ const parsed = new URL(value2.trim());
116116
+ if (!["postgres:", "postgresql:"].includes(parsed.protocol) || parsed.hostname === "")
116117
+ throw new Error;
116118
+ } catch {
116119
+ throw new TypeError("Workflow database selection must contain a valid Postgres URL");
116120
+ }
116121
+ return value2.trim();
116122
+ }
116123
+ async function prepareWorkflowDatabaseSettings(cwd, projectTrusted) {
116124
+ if (process.env.DBOS_SYSTEM_DATABASE_URL?.trim())
116125
+ return;
116126
+ const manager = SettingsManager.create(cwd, getAgentDir3(), { projectTrusted });
116127
+ if (manager.drainErrors().length > 0)
116128
+ throw new Error("Cannot read workflow database settings; repair settings.json");
116129
+ const projectDirectories = getProjectConfigDirs(cwd);
116130
+ const url = await resolveWorkflowDatabaseSettings(manager.getGlobalSettings(), manager.getProjectSettings(), {
116131
+ global: settingsDirectoryDeclaringDatabase(getAgentDirs3()),
116132
+ project: projectTrusted ? settingsDirectoryDeclaringDatabase(projectDirectories) : projectDirectories[0]
116133
+ });
116134
+ if (url !== undefined)
116135
+ requestDbosSystemDatabaseUrl(url);
116136
+ }
116137
+
115856
116138
  // dist/builtin/workflows/src/extension/workflow-heartbeat-notice.ts
115857
116139
  var WORKFLOW_HEARTBEAT_TITLE = "WORKFLOW HEARTBEAT";
115858
116140
  var WORKFLOW_HEARTBEAT_GLYPH = "♥";
@@ -117004,6 +117286,45 @@ function createWorkflowExtensionRuntimeState(pi, adapters, options = {}) {
117004
117286
  const resolveDefaultStageSessionDir = () => hostStageSessionDir.current;
117005
117287
  const discoveryRef = { current: null };
117006
117288
  const resolvePossibleStageEntry = (normalizedName) => discoveryRef.current?.sources.find((source) => source.id === normalizedName)?.filePath ?? resolveBuiltinDefinitionSource(normalizedName);
117289
+ let databasePreparation;
117290
+ const prepareDatabase = () => {
117291
+ const cwd = resolveCwd();
117292
+ const trusted = pi.getResourceLoaderInheritanceSnapshot?.()?.projectTrusted ?? false;
117293
+ const key = JSON.stringify([cwd, trusted]);
117294
+ if (databasePreparation?.key === key)
117295
+ return databasePreparation.promise;
117296
+ const promise = prepareWorkflowDatabaseSettings(cwd, trusted).catch((error) => {
117297
+ if (databasePreparation?.promise === promise)
117298
+ databasePreparation = undefined;
117299
+ throw error;
117300
+ });
117301
+ databasePreparation = { key, promise };
117302
+ return promise;
117303
+ };
117304
+ const databaseReady = (ctx) => {
117305
+ const owner = getDbosProcessOwner();
117306
+ const describeDatabase = owner.databaseDiagnostics;
117307
+ if (owner.state !== "ready" || describeDatabase === undefined)
117308
+ return;
117309
+ if (owner.announcedDatabaseDiagnostics === describeDatabase)
117310
+ return;
117311
+ const diagnostics = describeDatabase();
117312
+ const dockerFallback = diagnostics.provider === "docker";
117313
+ let host = "unknown host";
117314
+ try {
117315
+ host = new URL(diagnostics.url).host;
117316
+ } catch {}
117317
+ const message = `Workflow database: ${dockerFallback ? "Docker fallback" : diagnostics.provider} (${host})`;
117318
+ if (ctx?.hasUI && ctx.ui?.notify) {
117319
+ try {
117320
+ ctx.ui.notify(message, "info");
117321
+ owner.announcedDatabaseDiagnostics = describeDatabase;
117322
+ } catch {}
117323
+ } else if (dockerFallback) {
117324
+ owner.announcedDatabaseDiagnostics = describeDatabase;
117325
+ console.error(message);
117326
+ }
117327
+ };
117007
117328
  const startupDiscovery = discoverStartupWorkflowsSync();
117008
117329
  const runtimeRef = {
117009
117330
  current: createExtensionRuntime({
@@ -117017,7 +117338,9 @@ function createWorkflowExtensionRuntimeState(pi, adapters, options = {}) {
117017
117338
  config: runtimeConfigRef.current,
117018
117339
  resolvePossibleStageEntry,
117019
117340
  resolveDefaultStageSessionDir,
117020
- beforeRestoreCompleted
117341
+ beforeRestoreCompleted,
117342
+ prepareDatabase,
117343
+ databaseReady
117021
117344
  })
117022
117345
  };
117023
117346
  const configLoadRef = { current: null };
@@ -117082,7 +117405,9 @@ function createWorkflowExtensionRuntimeState(pi, adapters, options = {}) {
117082
117405
  ...models === undefined ? {} : { models },
117083
117406
  ...durabilityWarningSink === undefined ? {} : { durabilityWarningSink },
117084
117407
  resolveDefaultStageSessionDir,
117085
- beforeRestoreCompleted
117408
+ beforeRestoreCompleted,
117409
+ prepareDatabase,
117410
+ databaseReady: () => databaseReady(ctx)
117086
117411
  });
117087
117412
  }
117088
117413
  let lazyDiscoveryPromise = null;
@@ -117121,7 +117446,9 @@ function createWorkflowExtensionRuntimeState(pi, adapters, options = {}) {
117121
117446
  config: runtimeConfigRef.current,
117122
117447
  resolvePossibleStageEntry,
117123
117448
  resolveDefaultStageSessionDir,
117124
- beforeRestoreCompleted
117449
+ beforeRestoreCompleted,
117450
+ prepareDatabase,
117451
+ databaseReady
117125
117452
  });
117126
117453
  }
117127
117454
  function isWorkflowDiscoveryCurrent(generation) {
@@ -117623,6 +117950,22 @@ function possibleStageRows(runs, rootRunId, rootRun) {
117623
117950
  return segments !== undefined && segments.length === 1 && segments[0] === "**";
117624
117951
  }).length
117625
117952
  });
117953
+ const statuses = stickyStageDeliveryStatuses(runs, rootRunId);
117954
+ for (const target of new Set(statuses.map((status) => status.target))) {
117955
+ if (rows.some((row) => row.target === target))
117956
+ continue;
117957
+ rows.push({
117958
+ target,
117959
+ queuedCount: stickyQueued.filter((entry) => (entry.targetPath ?? entry.stageKey) === target).length,
117960
+ deliveryOnly: true
117961
+ });
117962
+ }
117963
+ for (let index = 0;index < rows.length; index++) {
117964
+ const row = rows[index];
117965
+ const deliveryStates = statuses.filter((status) => status.target === row.target);
117966
+ if (deliveryStates.length > 0)
117967
+ rows[index] = { ...row, deliveryStates };
117968
+ }
117626
117969
  return rows;
117627
117970
  }
117628
117971
  function materializedStageMatches(runs, rootRunId, entrySegments) {
@@ -117863,7 +118206,9 @@ async function recordConfirmedStickyDeliveries(activeStore, event) {
117863
118206
  const records = matchingLiveStages(runs, rootRunId, parsedTarget.segments).filter((match) => delivered.has(match.target)).map((match) => ({
117864
118207
  runId: match.run.id,
117865
118208
  stageId: match.stage.id,
117866
- ...match.stage.name === match.stage.id ? {} : { stageName: match.stage.name }
118209
+ ...match.stage.name === match.stage.id ? {} : { stageName: match.stage.name },
118210
+ ...match.stage.sessionId === undefined ? {} : { sessionId: match.stage.sessionId },
118211
+ admission: "transport"
117867
118212
  }));
117868
118213
  if (records.length === 0)
117869
118214
  return false;
@@ -120870,6 +121215,7 @@ function summarizeRunSnapshot(run, now = Date.now(), options) {
120870
121215
  status: stage.status
120871
121216
  })),
120872
121217
  pendingStages: pendingWorkflowStageStatuses(run, options?.owningRunStatus, options?.resolveBoundarySegments),
121218
+ deliveryStates: stickyStageDeliveryStatuses(options?.allRuns ?? [run], run.id),
120873
121219
  tools: (run.toolNodes ?? []).map((tool) => {
120874
121220
  const owner = tool;
120875
121221
  return {
@@ -121158,6 +121504,9 @@ function renderStatusToolContent(result) {
121158
121504
  }
121159
121505
  for (const entry of run.awaitingInput)
121160
121506
  lines.push(statusAwaitingInputLine(entry));
121507
+ for (const delivery of run.deliveryStates ?? stickyStageDeliveryStatuses(allRuns, run.runId)) {
121508
+ lines.push(` Intercom delivery ${delivery.messageId} target=${delivery.target} stage=${delivery.runId}/${delivery.stageId}${delivery.sessionId === undefined ? "" : ` session=${delivery.sessionId}`} state=${delivery.state} — ${delivery.reason}`);
121509
+ }
121161
121510
  for (const stage of run.pendingStages.slice(0, STATUS_PENDING_STAGE_LIMIT)) {
121162
121511
  lines.push(statusPendingStageLine(stage));
121163
121512
  }
@@ -122334,6 +122683,7 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
122334
122683
  const statusByRunId = new Map(capturedRuns.map((run) => [run.id, run.status]));
122335
122684
  const listing = buildWorkflowStatusListing(topLevelExpandedSnapshots(store), args.statusFilter ?? "all", Date.now(), {
122336
122685
  toolControlRegistry,
122686
+ allRuns: capturedRuns,
122337
122687
  owningRunStatus: (owningRunId) => statusByRunId.get(owningRunId),
122338
122688
  resolveBoundarySegments: (runId) => workflowBoundarySegments(capturedRuns, runId)
122339
122689
  });