@bastani/atomic 0.9.40-alpha.2 → 0.9.41-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.
Files changed (296) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/intercom/CHANGELOG.md +26 -0
  4. package/dist/builtin/intercom/README.md +1 -1
  5. package/dist/builtin/intercom/broker/broker.ts +24 -21
  6. package/dist/builtin/intercom/broker/client.ts +97 -6
  7. package/dist/builtin/intercom/broker/list-reply.ts +53 -0
  8. package/dist/builtin/intercom/index.bundle.mjs +278 -46
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/recoverable-disconnect.ts +27 -1
  11. package/dist/builtin/intercom/types.ts +8 -1
  12. package/dist/builtin/mcp/package.json +1 -1
  13. package/dist/builtin/subagents/CHANGELOG.md +45 -0
  14. package/dist/builtin/subagents/README.md +14 -0
  15. package/dist/builtin/subagents/package.json +1 -1
  16. package/dist/builtin/subagents/src/extension/index.bundle.mjs +99 -19
  17. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  18. package/dist/builtin/web-access/package.json +1 -1
  19. package/dist/builtin/workflows/CHANGELOG.md +44 -0
  20. package/dist/builtin/workflows/README.md +2 -0
  21. package/dist/builtin/workflows/package.json +1 -1
  22. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  23. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +16 -0
  24. package/dist/builtin/workflows/src/durable/journal/legacy-journal-tables.d.ts +9 -0
  25. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
  26. package/dist/builtin/workflows/src/extension/index.bundle.mjs +441 -90
  27. package/dist/builtin/workflows/src/index.js +226 -34
  28. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +17 -1
  29. package/dist/cli/credential-print.d.ts.map +1 -1
  30. package/dist/cli/credential-print.js +1 -1
  31. package/dist/cli/credential-print.js.map +1 -1
  32. package/dist/config.d.ts +1 -0
  33. package/dist/config.d.ts.map +1 -1
  34. package/dist/config.js +1 -0
  35. package/dist/config.js.map +1 -1
  36. package/dist/core/agent-session-extension-bindings.d.ts +2 -1
  37. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  38. package/dist/core/agent-session-extension-bindings.js +33 -18
  39. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  40. package/dist/core/agent-session-methods.d.ts +2 -1
  41. package/dist/core/agent-session-methods.d.ts.map +1 -1
  42. package/dist/core/agent-session-methods.js.map +1 -1
  43. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  44. package/dist/core/agent-session-prompt.js +114 -21
  45. package/dist/core/agent-session-prompt.js.map +1 -1
  46. package/dist/core/agent-session-runtime.d.ts +1 -1
  47. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  48. package/dist/core/agent-session-runtime.js +6 -0
  49. package/dist/core/agent-session-runtime.js.map +1 -1
  50. package/dist/core/agent-session-state.d.ts +19 -1
  51. package/dist/core/agent-session-state.d.ts.map +1 -1
  52. package/dist/core/agent-session-state.js +41 -6
  53. package/dist/core/agent-session-state.js.map +1 -1
  54. package/dist/core/auth-storage-backends.d.ts +3 -1
  55. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  56. package/dist/core/auth-storage-backends.js +79 -12
  57. package/dist/core/auth-storage-backends.js.map +1 -1
  58. package/dist/core/client-identity.d.ts +8 -0
  59. package/dist/core/client-identity.d.ts.map +1 -0
  60. package/dist/core/client-identity.js +16 -0
  61. package/dist/core/client-identity.js.map +1 -0
  62. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  63. package/dist/core/compaction/planner-outcome.js +2 -1
  64. package/dist/core/compaction/planner-outcome.js.map +1 -1
  65. package/dist/core/execution-model-router.d.ts +18 -0
  66. package/dist/core/execution-model-router.d.ts.map +1 -1
  67. package/dist/core/execution-model-router.js +14 -8
  68. package/dist/core/execution-model-router.js.map +1 -1
  69. package/dist/core/extension-oauth-refresh-rejection.d.ts +12 -0
  70. package/dist/core/extension-oauth-refresh-rejection.d.ts.map +1 -0
  71. package/dist/core/extension-oauth-refresh-rejection.js +70 -0
  72. package/dist/core/extension-oauth-refresh-rejection.js.map +1 -0
  73. package/dist/core/extension-startup-failure.d.ts +30 -0
  74. package/dist/core/extension-startup-failure.d.ts.map +1 -0
  75. package/dist/core/extension-startup-failure.js +62 -0
  76. package/dist/core/extension-startup-failure.js.map +1 -0
  77. package/dist/core/extensions/context-types.d.ts +2 -0
  78. package/dist/core/extensions/context-types.d.ts.map +1 -1
  79. package/dist/core/extensions/context-types.js.map +1 -1
  80. package/dist/core/extensions/provider-types.d.ts +2 -0
  81. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  82. package/dist/core/extensions/provider-types.js.map +1 -1
  83. package/dist/core/extensions/runner-context.d.ts +1 -0
  84. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  85. package/dist/core/extensions/runner-context.js +8 -0
  86. package/dist/core/extensions/runner-context.js.map +1 -1
  87. package/dist/core/extensions/runner.d.ts +1 -0
  88. package/dist/core/extensions/runner.d.ts.map +1 -1
  89. package/dist/core/extensions/runner.js +3 -0
  90. package/dist/core/extensions/runner.js.map +1 -1
  91. package/dist/core/extensions/runtime-types.d.ts +1 -0
  92. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  93. package/dist/core/extensions/runtime-types.js.map +1 -1
  94. package/dist/core/extensions/workflow-run-control-hub.d.ts +1 -0
  95. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  96. package/dist/core/extensions/workflow-run-control-hub.js +3 -0
  97. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  98. package/dist/core/extensions/workflow-run-control.d.ts +8 -0
  99. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  100. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  101. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  102. package/dist/core/model-fallback-failures.js +12 -0
  103. package/dist/core/model-fallback-failures.js.map +1 -1
  104. package/dist/core/model-resolver-defaults.js +1 -1
  105. package/dist/core/model-resolver-defaults.js.map +1 -1
  106. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  107. package/dist/core/model-runtime-streaming.js +9 -3
  108. package/dist/core/model-runtime-streaming.js.map +1 -1
  109. package/dist/core/model-runtime.d.ts +5 -0
  110. package/dist/core/model-runtime.d.ts.map +1 -1
  111. package/dist/core/model-runtime.js +6 -0
  112. package/dist/core/model-runtime.js.map +1 -1
  113. package/dist/core/provider-composer-internal.d.ts +6 -5
  114. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  115. package/dist/core/provider-composer-internal.js +13 -2
  116. package/dist/core/provider-composer-internal.js.map +1 -1
  117. package/dist/core/sdk.d.ts.map +1 -1
  118. package/dist/core/sdk.js +12 -4
  119. package/dist/core/sdk.js.map +1 -1
  120. package/dist/core/storage/session/sql-session-store.d.ts +35 -0
  121. package/dist/core/storage/session/sql-session-store.d.ts.map +1 -1
  122. package/dist/core/storage/session/sql-session-store.js +158 -42
  123. package/dist/core/storage/session/sql-session-store.js.map +1 -1
  124. package/dist/core/structured-output/deadline.d.ts +40 -0
  125. package/dist/core/structured-output/deadline.d.ts.map +1 -0
  126. package/dist/core/structured-output/deadline.js +110 -0
  127. package/dist/core/structured-output/deadline.js.map +1 -0
  128. package/dist/core/structured-output/index.d.ts.map +1 -1
  129. package/dist/core/structured-output/index.js +103 -47
  130. package/dist/core/structured-output/index.js.map +1 -1
  131. package/dist/core/structured-output/rejection-detail.d.ts +9 -0
  132. package/dist/core/structured-output/rejection-detail.d.ts.map +1 -0
  133. package/dist/core/structured-output/rejection-detail.js +129 -0
  134. package/dist/core/structured-output/rejection-detail.js.map +1 -0
  135. package/dist/core/structured-output/types.d.ts +8 -1
  136. package/dist/core/structured-output/types.d.ts.map +1 -1
  137. package/dist/core/structured-output/types.js.map +1 -1
  138. package/dist/core/tasks/completion.d.ts +7 -1
  139. package/dist/core/tasks/completion.d.ts.map +1 -1
  140. package/dist/core/tasks/completion.js +28 -6
  141. package/dist/core/tasks/completion.js.map +1 -1
  142. package/dist/core/tasks/contracts.d.ts +6 -1
  143. package/dist/core/tasks/contracts.d.ts.map +1 -1
  144. package/dist/core/tasks/contracts.js.map +1 -1
  145. package/dist/core/tasks/pause.d.ts +2 -1
  146. package/dist/core/tasks/pause.d.ts.map +1 -1
  147. package/dist/core/tasks/pause.js +3 -2
  148. package/dist/core/tasks/pause.js.map +1 -1
  149. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  150. package/dist/core/tools/bash-pty-native.js +10 -5
  151. package/dist/core/tools/bash-pty-native.js.map +1 -1
  152. package/dist/core/tools/bash.d.ts.map +1 -1
  153. package/dist/core/tools/bash.js +16 -32
  154. package/dist/core/tools/bash.js.map +1 -1
  155. package/dist/core/tools/kill.d.ts.map +1 -1
  156. package/dist/core/tools/kill.js +17 -3
  157. package/dist/core/tools/kill.js.map +1 -1
  158. package/dist/core/tools/shell-task-render.d.ts +55 -0
  159. package/dist/core/tools/shell-task-render.d.ts.map +1 -0
  160. package/dist/core/tools/shell-task-render.js +123 -0
  161. package/dist/core/tools/shell-task-render.js.map +1 -0
  162. package/dist/core/tools/shell-task-status.d.ts +52 -0
  163. package/dist/core/tools/shell-task-status.d.ts.map +1 -0
  164. package/dist/core/tools/shell-task-status.js +184 -0
  165. package/dist/core/tools/shell-task-status.js.map +1 -0
  166. package/dist/core/tools/structured-output.d.ts +5 -0
  167. package/dist/core/tools/structured-output.d.ts.map +1 -1
  168. package/dist/core/tools/structured-output.js +3 -0
  169. package/dist/core/tools/structured-output.js.map +1 -1
  170. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  171. package/dist/extensions/codemode/execute.js +134 -57
  172. package/dist/extensions/codemode/execute.js.map +1 -1
  173. package/dist/extensions/mcp/config.d.ts.map +1 -1
  174. package/dist/extensions/mcp/config.js +3 -2
  175. package/dist/extensions/mcp/config.js.map +1 -1
  176. package/dist/index-extensions.d.ts +1 -0
  177. package/dist/index-extensions.d.ts.map +1 -1
  178. package/dist/index-extensions.js +3 -0
  179. package/dist/index-extensions.js.map +1 -1
  180. package/dist/index.d.ts +3 -1
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +3 -1
  183. package/dist/index.js.map +1 -1
  184. package/dist/main.d.ts.map +1 -1
  185. package/dist/main.js +19 -6
  186. package/dist/main.js.map +1 -1
  187. package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
  188. package/dist/modes/interactive/components/task-row.js +11 -1
  189. package/dist/modes/interactive/components/task-row.js.map +1 -1
  190. package/dist/modes/interactive/interactive-auth-routing.js +12 -10
  191. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
  192. package/dist/modes/interactive/interactive-extension-custom-ui.js +20 -30
  193. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  194. package/dist/modes/interactive/interactive-extension-dialogs.js +23 -96
  195. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  196. package/dist/modes/interactive/interactive-extension-runtime.js +7 -8
  197. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  198. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  199. package/dist/modes/interactive/interactive-input-handling.js +27 -4
  200. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  201. package/dist/modes/interactive/interactive-mode-base.d.ts +20 -10
  202. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  203. package/dist/modes/interactive/interactive-mode-base.js +40 -5
  204. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  205. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  206. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  207. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  208. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  209. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -4
  210. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  211. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  212. package/dist/modes/interactive/interactive-mode-types.d.ts +4 -1
  213. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  214. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  215. package/dist/modes/interactive/interactive-prompt-restore.d.ts +3 -0
  216. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  217. package/dist/modes/interactive/interactive-prompt-restore.js +9 -1
  218. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  219. package/dist/modes/interactive/interactive-prompt-turn.js +30 -2
  220. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  221. package/dist/modes/interactive/interactive-queueing.js +43 -8
  222. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  223. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  224. package/dist/modes/interactive/interactive-startup.js +12 -3
  225. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  226. package/dist/modes/interactive/theme/color-utils.d.ts +6 -1
  227. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  228. package/dist/modes/interactive/theme/color-utils.js +39 -17
  229. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  230. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  231. package/dist/modes/interactive/theme/theme-class.js +2 -2
  232. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  233. package/dist/modes/interactive/theme/theme-tokens.d.ts +6 -0
  234. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -1
  235. package/dist/modes/interactive/theme/theme-tokens.js +7 -3
  236. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -1
  237. package/dist/modes/interactive-engine/isolated-auth.d.ts +3 -0
  238. package/dist/modes/interactive-engine/isolated-auth.d.ts.map +1 -1
  239. package/dist/modes/interactive-engine/isolated-auth.js +13 -1
  240. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  241. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  242. package/dist/modes/interactive-engine/isolated-runtime.js +11 -2
  243. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  244. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +8 -0
  245. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  246. package/dist/modes/interactive-engine/remote-model-catalog.js +54 -0
  247. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  248. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  249. package/dist/modes/rpc/rpc-command-handler.js +4 -13
  250. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  251. package/dist/modes/rpc/rpc-model-catalog.d.ts +9 -0
  252. package/dist/modes/rpc/rpc-model-catalog.d.ts.map +1 -0
  253. package/dist/modes/rpc/rpc-model-catalog.js +19 -0
  254. package/dist/modes/rpc/rpc-model-catalog.js.map +1 -0
  255. package/dist/modes/rpc/rpc-provider-auth.d.ts.map +1 -1
  256. package/dist/modes/rpc/rpc-provider-auth.js +2 -6
  257. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  258. package/dist/modes/rpc/rpc-types.d.ts +6 -0
  259. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  260. package/dist/modes/rpc/rpc-types.js.map +1 -1
  261. package/dist/utils/changelog.d.ts +6 -0
  262. package/dist/utils/changelog.d.ts.map +1 -1
  263. package/dist/utils/changelog.js +11 -0
  264. package/dist/utils/changelog.js.map +1 -1
  265. package/dist/utils/clipboard.d.ts.map +1 -1
  266. package/dist/utils/clipboard.js +4 -0
  267. package/dist/utils/clipboard.js.map +1 -1
  268. package/dist/utils/tools-manager.d.ts.map +1 -1
  269. package/dist/utils/tools-manager.js +3 -2
  270. package/dist/utils/tools-manager.js.map +1 -1
  271. package/docs/background-tasks.md +5 -3
  272. package/docs/codemode.md +2 -2
  273. package/docs/custom-provider/oauth.md +42 -1
  274. package/docs/custom-provider/registration.md +2 -0
  275. package/docs/environment-variables.md +1 -0
  276. package/docs/extensions/api-reference.md +3 -4
  277. package/docs/extensions/authoring.md +1 -1
  278. package/docs/extensions/events.md +1 -1
  279. package/docs/providers.md +3 -3
  280. package/docs/rpc/protocol.md +4 -2
  281. package/docs/sdk/reference.md +2 -0
  282. package/docs/sdk/structured-decisions.md +7 -5
  283. package/docs/sdk.md +5 -2
  284. package/docs/settings.md +4 -2
  285. package/docs/subagents/reference.md +1 -1
  286. package/docs/subagents.md +15 -1
  287. package/docs/themes/reference.md +3 -1
  288. package/docs/usage.md +3 -1
  289. package/docs/workflows/api-reference.md +28 -0
  290. package/docs/workflows/operations.md +2 -2
  291. package/npm-shrinkwrap.json +32 -32
  292. package/package.json +3 -3
  293. package/dist/core/provider-attribution.d.ts +0 -4
  294. package/dist/core/provider-attribution.d.ts.map +0 -1
  295. package/dist/core/provider-attribution.js +0 -87
  296. package/dist/core/provider-attribution.js.map +0 -1
@@ -38933,10 +38933,23 @@ function runIndicatorStatus(run, allRuns = [run]) {
38933
38933
  }
38934
38934
  return status;
38935
38935
  }
38936
+ function createRunIndicatorStatusResolver(allRuns) {
38937
+ let runsWithPendingDescendants;
38938
+ return (run) => {
38939
+ const status = effectiveRunStatus(run);
38940
+ if (TERMINAL_OR_BLOCKED.has(status))
38941
+ return status;
38942
+ if (runHasPendingInput(run))
38943
+ return "awaiting_input";
38944
+ runsWithPendingDescendants ??= ancestorsOfPendingInputRuns(allRuns);
38945
+ return runsWithPendingDescendants.has(run.id) ? "awaiting_input" : status;
38946
+ };
38947
+ }
38936
38948
  function resolveRunIndicatorStatuses(runs, allRuns) {
38949
+ const statusOf = createRunIndicatorStatusResolver(allRuns);
38937
38950
  const statuses = {};
38938
38951
  for (const run of runs)
38939
- statuses[run.id] = runIndicatorStatus(run, allRuns);
38952
+ statuses[run.id] = statusOf(run);
38940
38953
  return statuses;
38941
38954
  }
38942
38955
  function runHasPendingInput(run) {
@@ -38944,6 +38957,30 @@ function runHasPendingInput(run) {
38944
38957
  return true;
38945
38958
  return run.stages.some((stage) => stage.status === "awaiting_input" || stage.awaitingInputSince !== undefined || stage.pendingPrompt !== undefined || stage.inputRequest !== undefined);
38946
38959
  }
38960
+ function ancestorsOfPendingInputRuns(allRuns) {
38961
+ const runsById = new Map(allRuns.map((candidate) => [candidate.id, candidate]));
38962
+ const ancestors = new Set;
38963
+ for (const candidate of allRuns) {
38964
+ if (TERMINAL_OR_BLOCKED.has(effectiveRunStatus(candidate)) || !runHasPendingInput(candidate))
38965
+ continue;
38966
+ const mark = (ancestorId) => {
38967
+ if (ancestorId !== candidate.id)
38968
+ ancestors.add(ancestorId);
38969
+ };
38970
+ if (candidate.rootRunId !== undefined)
38971
+ mark(candidate.rootRunId);
38972
+ const visited = new Set;
38973
+ let current = candidate;
38974
+ while (current !== undefined && current.parentRunId !== undefined) {
38975
+ mark(current.parentRunId);
38976
+ if (visited.has(current.id))
38977
+ break;
38978
+ visited.add(current.id);
38979
+ current = runsById.get(current.parentRunId);
38980
+ }
38981
+ }
38982
+ return ancestors;
38983
+ }
38947
38984
  function runBelongsTo(candidate, ancestor, runsById) {
38948
38985
  if (candidate.rootRunId === ancestor.id)
38949
38986
  return true;
@@ -38960,16 +38997,58 @@ function runBelongsTo(candidate, ancestor, runsById) {
38960
38997
  return false;
38961
38998
  }
38962
38999
 
39000
+ // dist/builtin/workflows/src/shared/run-order.ts
39001
+ var ACTIVE_RANK = {
39002
+ awaiting_input: 0,
39003
+ blocked: 0,
39004
+ running: 1,
39005
+ paused: 2
39006
+ };
39007
+ var OTHER_ACTIVE_RANK = 3;
39008
+ var TERMINAL_RANK = {
39009
+ blocked: 0,
39010
+ failed: 1,
39011
+ killed: 1,
39012
+ cancelled: 2,
39013
+ skipped: 3,
39014
+ completed: 4
39015
+ };
39016
+ var OTHER_TERMINAL_RANK = 5;
39017
+ function isQuitRun(run) {
39018
+ return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
39019
+ }
39020
+ function statusRank(run, statusOf) {
39021
+ if (run.endedAt !== undefined)
39022
+ return TERMINAL_RANK[statusOf(run)] ?? OTHER_TERMINAL_RANK;
39023
+ if (isQuitRun(run))
39024
+ return ACTIVE_RANK.paused ?? OTHER_ACTIVE_RANK;
39025
+ return ACTIVE_RANK[statusOf(run)] ?? OTHER_ACTIVE_RANK;
39026
+ }
39027
+ function sortRunsByStatus(items, runOf, statusOf) {
39028
+ return items.map((item) => {
39029
+ const run = runOf(item);
39030
+ return { item, run, rank: statusRank(run, statusOf) };
39031
+ }).sort((a, b) => {
39032
+ const aEnded = a.run.endedAt !== undefined;
39033
+ if (aEnded !== (b.run.endedAt !== undefined))
39034
+ return aEnded ? 1 : -1;
39035
+ const rankDelta = a.rank - b.rank;
39036
+ if (rankDelta !== 0)
39037
+ return rankDelta;
39038
+ return aEnded ? (b.run.endedAt ?? 0) - (a.run.endedAt ?? 0) : b.run.startedAt - a.run.startedAt;
39039
+ }).map((entry) => entry.item);
39040
+ }
39041
+
38963
39042
  // dist/builtin/workflows/src/tui/status-list.ts
38964
39043
  var STAGE_LABEL_BUDGET = 24;
38965
- function isQuitRun(run) {
39044
+ function isQuitRun2(run) {
38966
39045
  return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
38967
39046
  }
38968
39047
  function renderStatusList(runs, opts = {}) {
38969
39048
  const now = opts.now ?? Date.now();
38970
39049
  const width = effectiveWidth2(opts.width);
38971
39050
  const cardWidth = Math.max(20, width - 4);
38972
- const sorted = sortRuns(runs);
39051
+ const sorted = sortRuns(runs, opts);
38973
39052
  const resolveBoundarySegments = opts.resolveBoundarySegments ?? ((runId) => workflowBoundarySegments(runs, runId));
38974
39053
  const counts = countBuckets(runs);
38975
39054
  const subtitle = `${sorted.length} run${sorted.length === 1 ? "" : "s"}`;
@@ -39094,12 +39173,12 @@ function pendingStageLine(line, width, theme) {
39094
39173
  function runAccent(run, theme, indicatorStatus) {
39095
39174
  if (!theme)
39096
39175
  return "#000000";
39097
- if (isQuitRun(run))
39176
+ if (isQuitRun2(run))
39098
39177
  return theme.warning;
39099
39178
  return statusColor(indicatorStatus, theme);
39100
39179
  }
39101
39180
  function runTrailing(run, theme) {
39102
- if (isQuitRun(run))
39181
+ if (isQuitRun2(run))
39103
39182
  return { text: "○ quit", fg: theme?.warning };
39104
39183
  switch (effectiveRunStatus(run)) {
39105
39184
  case "completed":
@@ -39128,7 +39207,7 @@ function runCardMeta(run, now) {
39128
39207
  const total = run.stages.length;
39129
39208
  const done = run.stages.filter((s) => s.status === "completed" || s.status === "failed" || s.status === "skipped").length;
39130
39209
  const ago = run.endedAt !== undefined ? `${fmtDuration(now - run.endedAt)} ago` : run.startedAt != null ? fmtDuration(elapsedRunMs(run, now)) : undefined;
39131
- if (isQuitRun(run))
39210
+ if (isQuitRun2(run))
39132
39211
  return run.resumable === false ? "not resumable" : "resumable via /workflow resume";
39133
39212
  if (effectiveRunStatus(run) === "running") {
39134
39213
  if (isChain)
@@ -39242,7 +39321,7 @@ function countBuckets(runs) {
39242
39321
  const c = { active: 0, paused: 0, quit: 0, completed: 0, blocked: 0, failed: 0, pending: 0 };
39243
39322
  for (const r of runs) {
39244
39323
  const status = effectiveRunStatus(r);
39245
- if (isQuitRun(r))
39324
+ if (isQuitRun2(r))
39246
39325
  c.quit++;
39247
39326
  else if (r.endedAt === undefined) {
39248
39327
  if (status === "pending")
@@ -39304,11 +39383,9 @@ function plainBadges(c) {
39304
39383
  out.push({ text: `⊘ ${c.failed}` });
39305
39384
  return out;
39306
39385
  }
39307
- function sortRuns(runs) {
39308
- const active = runs.filter((r) => r.endedAt === undefined);
39309
- const ended = runs.filter((r) => r.endedAt !== undefined);
39310
- const byStart = (a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0);
39311
- return [...[...active].sort(byStart), ...[...ended].sort(byStart)];
39386
+ function sortRuns(runs, opts) {
39387
+ const statusOf = createRunIndicatorStatusResolver(opts.allRuns ?? runs);
39388
+ return sortRunsByStatus(runs, (run) => run, (run) => opts.indicatorStatuses?.[run.id] ?? statusOf(run));
39312
39389
  }
39313
39390
  function renderStatusHintRows(id, theme, width) {
39314
39391
  const budget = Math.max(1, width - 4);
@@ -39350,7 +39427,7 @@ function emptyStateLine(theme) {
39350
39427
  return ` ${hexToAnsi(theme.dim)}no workflow runs in current session${RESET}`;
39351
39428
  }
39352
39429
  function statusIconForRun(run, indicatorStatus) {
39353
- if (isQuitRun(run))
39430
+ if (isQuitRun2(run))
39354
39431
  return statusIcon("pending");
39355
39432
  return statusIcon(indicatorStatus);
39356
39433
  }
@@ -50249,7 +50326,7 @@ function isDisplayablePrompt(message) {
50249
50326
  function isTerminalOrBlockedRun(run) {
50250
50327
  return TERMINAL_OR_BLOCKED2.has(effectiveRunStatus(run)) || run.endedAt !== undefined;
50251
50328
  }
50252
- function isQuitRun2(run) {
50329
+ function isQuitRun3(run) {
50253
50330
  return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
50254
50331
  }
50255
50332
  function hasLiveAncestry(candidate, visibleRun, runsById) {
@@ -50265,7 +50342,7 @@ function hasLiveAncestry(candidate, visibleRun, runsById) {
50265
50342
  return false;
50266
50343
  const parent = runsById.get(parentRunId);
50267
50344
  const boundary = parent?.stages.find((stage) => stage.id === parentStageId);
50268
- if (parent === undefined || isTerminalOrBlockedRun(parent) || isQuitRun2(parent) || boundary === undefined || boundary.status !== "running" && boundary.status !== "awaiting_input") {
50345
+ if (parent === undefined || isTerminalOrBlockedRun(parent) || isQuitRun3(parent) || boundary === undefined || boundary.status !== "running" && boundary.status !== "awaiting_input") {
50269
50346
  return false;
50270
50347
  }
50271
50348
  current = parent;
@@ -50273,12 +50350,12 @@ function hasLiveAncestry(candidate, visibleRun, runsById) {
50273
50350
  return true;
50274
50351
  }
50275
50352
  function visibleRunTreeMembers(visibleRun, allRuns) {
50276
- if (isTerminalOrBlockedRun(visibleRun) || isQuitRun2(visibleRun))
50353
+ if (isTerminalOrBlockedRun(visibleRun) || isQuitRun3(visibleRun))
50277
50354
  return [];
50278
50355
  const runsById = new Map;
50279
50356
  const ambiguousRunIds = new Set;
50280
50357
  for (const candidate of allRuns) {
50281
- if (isTerminalOrBlockedRun(candidate) || isQuitRun2(candidate))
50358
+ if (isTerminalOrBlockedRun(candidate) || isQuitRun3(candidate))
50282
50359
  continue;
50283
50360
  if (runsById.has(candidate.id))
50284
50361
  ambiguousRunIds.add(candidate.id);
@@ -50291,7 +50368,7 @@ function visibleRunTreeMembers(visibleRun, allRuns) {
50291
50368
  return [];
50292
50369
  const members = [visibleRun];
50293
50370
  for (const candidate of allRuns) {
50294
- if (isTerminalOrBlockedRun(candidate) || isQuitRun2(candidate))
50371
+ if (isTerminalOrBlockedRun(candidate) || isQuitRun3(candidate))
50295
50372
  continue;
50296
50373
  if (candidate.id === visibleRun.id || ambiguousRunIds.has(candidate.id))
50297
50374
  continue;
@@ -50361,7 +50438,7 @@ function runPromptOccurrenceForStage(run, stage, prompt) {
50361
50438
  return descriptorOccurrence(run, stage.id, prompt.id, message, isDisplayablePrompt(message));
50362
50439
  }
50363
50440
  function pendingInputOccurrences(run) {
50364
- if (isTerminalOrBlockedRun(run) || isQuitRun2(run))
50441
+ if (isTerminalOrBlockedRun(run) || isQuitRun3(run))
50365
50442
  return [];
50366
50443
  const occurrences = run.pendingPrompt === undefined ? [] : [runPromptOccurrence(run, run.pendingPrompt)];
50367
50444
  return occurrences.concat(stagePromptOccurrences(run));
@@ -50404,17 +50481,17 @@ function formatDuration(ms) {
50404
50481
  const rmin = minutes % 60;
50405
50482
  return `${hours}h${rmin > 0 ? ` ${rmin}m` : ""}`;
50406
50483
  }
50407
- function isQuitRun3(run) {
50484
+ function isQuitRun4(run) {
50408
50485
  return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
50409
50486
  }
50410
50487
  function isActive(run) {
50411
- return run.endedAt === undefined && !isQuitRun3(run);
50488
+ return run.endedAt === undefined && !isQuitRun4(run);
50412
50489
  }
50413
50490
  function recentlyEnded(run, now) {
50414
50491
  return run.endedAt !== undefined && now - run.endedAt <= RECENT_ENDED_WINDOW_MS;
50415
50492
  }
50416
50493
  function recentlyQuit(run, now) {
50417
- return isQuitRun3(run) && run.quitAt !== undefined && now - run.quitAt <= RECENT_ENDED_WINDOW_MS;
50494
+ return isQuitRun4(run) && run.quitAt !== undefined && now - run.quitAt <= RECENT_ENDED_WINDOW_MS;
50418
50495
  }
50419
50496
  function subtreeAwaitsInput(root, allRuns) {
50420
50497
  return runIndicatorStatus(root, allRuns) === "awaiting_input";
@@ -50423,7 +50500,7 @@ function countRuns(runs, allRuns = runs) {
50423
50500
  const counts = { active: 0, paused: 0, quit: 0, done: 0, blocked: 0, failed: 0, awaiting: 0 };
50424
50501
  for (const r of runs) {
50425
50502
  const status = effectiveRunStatus(r);
50426
- if (isQuitRun3(r))
50503
+ if (isQuitRun4(r))
50427
50504
  counts.quit++;
50428
50505
  else if (status === "blocked")
50429
50506
  counts.blocked++;
@@ -50435,7 +50512,7 @@ function countRuns(runs, allRuns = runs) {
50435
50512
  counts.done++;
50436
50513
  else if (status === "failed" || status === "killed")
50437
50514
  counts.failed++;
50438
- if (r.endedAt === undefined && !isQuitRun3(r) && subtreeAwaitsInput(r, allRuns))
50515
+ if (r.endedAt === undefined && !isQuitRun4(r) && subtreeAwaitsInput(r, allRuns))
50439
50516
  counts.awaiting++;
50440
50517
  }
50441
50518
  return counts;
@@ -50448,7 +50525,7 @@ function nextWidgetRefreshDelayMs(snap, now = Date.now()) {
50448
50525
  for (const run of display) {
50449
50526
  if (run.endedAt !== undefined) {
50450
50527
  delays.push(Math.max(1, run.endedAt + RECENT_ENDED_WINDOW_MS - now + 1));
50451
- } else if (isQuitRun3(run) && run.quitAt !== undefined) {
50528
+ } else if (isQuitRun4(run) && run.quitAt !== undefined) {
50452
50529
  delays.push(Math.max(1, run.quitAt + RECENT_ENDED_WINDOW_MS - now + 1));
50453
50530
  }
50454
50531
  }
@@ -50468,12 +50545,12 @@ function selectDisplayRuns(snap, now) {
50468
50545
  return [...sort(active), ...sort(recent)];
50469
50546
  }
50470
50547
  function statusGlyph2(run, allRuns) {
50471
- if (isQuitRun3(run))
50548
+ if (isQuitRun4(run))
50472
50549
  return statusIcon("pending");
50473
50550
  return statusIcon(runIndicatorStatus(run, allRuns));
50474
50551
  }
50475
50552
  function statusFg(run, theme, allRuns) {
50476
- if (isQuitRun3(run))
50553
+ if (isQuitRun4(run))
50477
50554
  return theme.warning;
50478
50555
  const indicatorStatus = runIndicatorStatus(run, allRuns);
50479
50556
  if (indicatorStatus === "awaiting_input")
@@ -50559,7 +50636,7 @@ function metaLine(run, expandGraph, now, width = Number.POSITIVE_INFINITY, resol
50559
50636
  if (run.endedAt !== undefined) {
50560
50637
  return elapsedLabel(run, now);
50561
50638
  }
50562
- if (isQuitRun3(run))
50639
+ if (isQuitRun4(run))
50563
50640
  return run.resumable === false ? "quit · not resumable" : "quit · resumable via /workflow resume";
50564
50641
  if (effectiveRunStatus(run) === "blocked")
50565
50642
  return "blocked · resumable via /workflow resume";
@@ -50708,8 +50785,8 @@ function buildThemedWidgetLines(snap, piTheme, width = 120, now = Date.now(), la
50708
50785
  const displayCounts = countRuns(display, snap.runs);
50709
50786
  const visibleCounts = {
50710
50787
  active: display.filter((r) => r.endedAt === undefined && effectiveRunStatus(r) === "running").length,
50711
- paused: display.filter((r) => r.endedAt === undefined && effectiveRunStatus(r) === "paused" && !isQuitRun3(r)).length,
50712
- quit: display.filter(isQuitRun3).length,
50788
+ paused: display.filter((r) => r.endedAt === undefined && effectiveRunStatus(r) === "paused" && !isQuitRun4(r)).length,
50789
+ quit: display.filter(isQuitRun4).length,
50713
50790
  done: display.filter((r) => r.endedAt !== undefined && ["completed", "skipped", "cancelled"].includes(effectiveRunStatus(r))).length,
50714
50791
  blocked: display.filter((r) => effectiveRunStatus(r) === "blocked").length,
50715
50792
  failed: display.filter((r) => r.endedAt !== undefined && ["failed", "killed"].includes(effectiveRunStatus(r))).length,
@@ -50734,7 +50811,7 @@ function buildThemedWidgetLines(snap, piTheme, width = 120, now = Date.now(), la
50734
50811
  for (let i = 0;i < display.length; i++) {
50735
50812
  const run = display[i];
50736
50813
  const affordance = pendingInputAffordance(run, snap.runs);
50737
- const runLines = !isQuitRun3(run) && affordance !== undefined ? awaitingRunLines(run, now, themed ? graphTheme : undefined, snap.runs, affordance, bodyWidth, expandGraph) : themed ? themedRunLines(run, now, graphTheme, snap.runs, width, expandGraph) : plainRunLines(run, now, snap.runs, width, expandGraph);
50814
+ const runLines = !isQuitRun4(run) && affordance !== undefined ? awaitingRunLines(run, now, themed ? graphTheme : undefined, snap.runs, affordance, bodyWidth, expandGraph) : themed ? themedRunLines(run, now, graphTheme, snap.runs, width, expandGraph) : plainRunLines(run, now, snap.runs, width, expandGraph);
50738
50815
  body.push(...runLines);
50739
50816
  layout?.runs.push({
50740
50817
  id: run.id,
@@ -53060,6 +53137,13 @@ class PromptReservationState {
53060
53137
 
53061
53138
  // dist/builtin/workflows/src/durable/journal/internal.ts
53062
53139
  var JOURNAL_READ_PAGE_SIZE = 256;
53140
+ var versionReaders = new WeakMap;
53141
+ function registerRunJournalVersions(journal, versions) {
53142
+ versionReaders.set(journal, versions);
53143
+ }
53144
+ function runJournalVersions(journal) {
53145
+ return versionReaders.get(journal);
53146
+ }
53063
53147
 
53064
53148
  // dist/builtin/workflows/src/durable/journal/values.ts
53065
53149
  function validateText(field, value2) {
@@ -53405,6 +53489,8 @@ class JournalDurableBackend {
53405
53489
  persistent;
53406
53490
  projection = createJournalProjection();
53407
53491
  sequences = new Map;
53492
+ foldedAt = new Map;
53493
+ catalogToken;
53408
53494
  leases = new Map;
53409
53495
  executions = new Map;
53410
53496
  executionContext = new AsyncLocalStorage;
@@ -53448,7 +53534,7 @@ class JournalDurableBackend {
53448
53534
  try {
53449
53535
  this.ensureOpen();
53450
53536
  if (requiresActiveExecution)
53451
- this.assertExecutionActive(runId);
53537
+ this.assertExecutionActive();
53452
53538
  } catch (error) {
53453
53539
  return Promise.reject(error);
53454
53540
  }
@@ -53501,6 +53587,7 @@ class JournalDurableBackend {
53501
53587
  this.projection.applyWorkflowSnapshot({ ...handle, pendingStageMessages: messages });
53502
53588
  }
53503
53589
  this.sequences.set(entry.runId, entry.seq);
53590
+ this.foldedAt.set(entry.runId, entry.at);
53504
53591
  }
53505
53592
  *entries(runId, fromSeq) {
53506
53593
  return yield* invoke(async () => {
@@ -53514,6 +53601,7 @@ class JournalDurableBackend {
53514
53601
  const entries = yield* this.entries(runId);
53515
53602
  this.projection.deleteWorkflow(runId);
53516
53603
  this.sequences.delete(runId);
53604
+ this.foldedAt.delete(runId);
53517
53605
  this.prompts.delete(runId);
53518
53606
  for (const entry of entries)
53519
53607
  this.fold(entry);
@@ -53526,7 +53614,7 @@ class JournalDurableBackend {
53526
53614
  }
53527
53615
  *current(runId) {
53528
53616
  this.ensureOpen();
53529
- this.assertExecutionActive(runId, true);
53617
+ this.assertExecutionActive(true);
53530
53618
  yield* this.refresh(runId);
53531
53619
  if (this.projection.getWorkflow(runId) === undefined)
53532
53620
  return;
@@ -53545,14 +53633,14 @@ class JournalDurableBackend {
53545
53633
  if (this.state === "closed" || this.state === "closing" && !this.mutationContext.getStore())
53546
53634
  throw new JournalBackendClosedError;
53547
53635
  }
53548
- assertExecutionActive(runId, admitted = false) {
53636
+ assertExecutionActive(admitted = false) {
53549
53637
  for (const [executionRunId, execution] of this.executionContext.getStore() ?? [])
53550
53638
  if (execution.retired && !(admitted && this.mutationContext.getStore()?.has(execution)))
53551
- throw new JournalExecutionRetiredError(typeof runId === "string" ? runId : executionRunId);
53639
+ throw new JournalExecutionRetiredError(executionRunId);
53552
53640
  }
53553
53641
  *ownership(runId) {
53554
53642
  this.ensureOpen();
53555
- this.assertExecutionActive(runId, true);
53643
+ this.assertExecutionActive(true);
53556
53644
  const lost = this.lost.get(runId);
53557
53645
  if (lost)
53558
53646
  throw lost;
@@ -53612,7 +53700,7 @@ class JournalDurableBackend {
53612
53700
  return this.serialize(input.workflowId, () => this.register(input));
53613
53701
  }
53614
53702
  *register(input) {
53615
- this.assertExecutionActive(input.workflowId, true);
53703
+ this.assertExecutionActive(true);
53616
53704
  this.ensureOpen();
53617
53705
  const header = {
53618
53706
  runId: input.workflowId,
@@ -53836,11 +53924,36 @@ class JournalDurableBackend {
53836
53924
  }
53837
53925
  hydrateResumableWorkflows() {
53838
53926
  return this.serialize(this.catalogQueue, () => invoke(async () => {
53839
- const runs = await this.journal.listRuns();
53840
- for (const runId of new Set([...this.sequences.keys(), ...runs.map((run) => run.runId)]))
53841
- await this.hydrateWorkflow(runId);
53927
+ const journal = runJournalVersions(this.journal);
53928
+ if (journal === undefined) {
53929
+ const runs = await this.journal.listRuns();
53930
+ for (const runId of new Set([...this.sequences.keys(), ...runs.map((run) => run.runId)]))
53931
+ await this.hydrateWorkflow(runId);
53932
+ return;
53933
+ }
53934
+ const token = await journal.changeToken();
53935
+ if (token === this.catalogToken)
53936
+ return;
53937
+ const versions = await journal.runVersions();
53938
+ for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
53939
+ await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
53940
+ this.catalogToken = token;
53842
53941
  }));
53843
53942
  }
53943
+ *catchUp(runId, version) {
53944
+ const folded = this.sequences.get(runId) ?? 0;
53945
+ if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
53946
+ return;
53947
+ if (version !== undefined && folded > 0 && version.seq > folded) {
53948
+ const entries = yield* this.entries(runId, folded);
53949
+ if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
53950
+ for (const entry of entries)
53951
+ this.fold(entry);
53952
+ return;
53953
+ }
53954
+ }
53955
+ yield* this.rebuild(runId);
53956
+ }
53844
53957
  async prepareWorkflowCatalog() {
53845
53958
  await this.hydrateResumableWorkflows();
53846
53959
  return this.projection.prepareWorkflowCatalog();
@@ -53858,6 +53971,7 @@ class JournalDurableBackend {
53858
53971
  }
53859
53972
  this.leases.delete(runId);
53860
53973
  this.sequences.delete(runId);
53974
+ this.foldedAt.delete(runId);
53861
53975
  this.prompts.delete(runId);
53862
53976
  this.projection.deleteWorkflow(runId);
53863
53977
  }
@@ -53950,7 +54064,7 @@ class JournalDurableBackend {
53950
54064
  }
53951
54065
  async withWorkflowLease(runId, action) {
53952
54066
  this.ensureOpen();
53953
- this.assertExecutionActive(runId);
54067
+ this.assertExecutionActive();
53954
54068
  const context = this.executionContext.getStore();
53955
54069
  const active = this.executions.get(runId);
53956
54070
  if (active !== undefined && context?.get(runId) !== active)
@@ -53985,7 +54099,7 @@ class JournalDurableBackend {
53985
54099
  return this.serialize(runId, () => this.release(runId, execution), false);
53986
54100
  }
53987
54101
  releaseWorkflow(runId) {
53988
- this.assertExecutionActive(runId);
54102
+ this.assertExecutionActive();
53989
54103
  return this.serialize(runId, () => this.release(runId));
53990
54104
  }
53991
54105
  *release(runId, execution) {
@@ -54078,6 +54192,10 @@ var LEGACY_COLUMNS = {
54078
54192
  var PENDING_LEGACY_RUNS = `SELECT ${JOURNAL_COLUMNS.runId}, ${JOURNAL_COLUMNS.headerJson}, ${JOURNAL_COLUMNS.status} FROM ${JOURNAL_TABLES.runs}
54079
54193
  WHERE ${JOURNAL_COLUMNS.runId} NOT IN (SELECT ${JOURNAL_COLUMNS.runId} FROM ${CURRENT.runs})
54080
54194
  AND ${JOURNAL_COLUMNS.runId} NOT IN (SELECT ${JOURNAL_COLUMNS.runId} FROM ${CURRENT.legacyDeleted})`;
54195
+ function latestEventColumns(events, runs) {
54196
+ const latest = (column) => `COALESCE((SELECT ${column} FROM ${events} AS latest WHERE latest.${JOURNAL_COLUMNS.runId} = ${runs}.${JOURNAL_COLUMNS.runId} ORDER BY latest.${JOURNAL_COLUMNS.seq} DESC LIMIT 1), 0) AS ${column}`;
54197
+ return `${latest(JOURNAL_COLUMNS.seq)}, ${latest(JOURNAL_COLUMNS.at)}`;
54198
+ }
54081
54199
  async function hasLegacyTable(tx, table) {
54082
54200
  const columns = await tx.all("SELECT name FROM pragma_table_info(?)", JOURNAL_TABLES[table]);
54083
54201
  const names = new Set(columns.map((column) => column.name));
@@ -54111,6 +54229,9 @@ class LegacyJournalRuns {
54111
54229
  async find(executor, runId) {
54112
54230
  return executor.get(`${PENDING_LEGACY_RUNS} AND ${JOURNAL_COLUMNS.runId} = ?`, runId);
54113
54231
  }
54232
+ async versions(executor) {
54233
+ return executor.all(`SELECT pending.${JOURNAL_COLUMNS.runId}, ${latestEventColumns(JOURNAL_TABLES.events, "pending")} FROM (${PENDING_LEGACY_RUNS}) AS pending`);
54234
+ }
54114
54235
  async events(executor, runId, fromSeq, limit) {
54115
54236
  return executor.all(`SELECT ${LEGACY_COLUMNS.events.join(", ")} FROM ${JOURNAL_TABLES.events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.seq} >= ? ORDER BY ${JOURNAL_COLUMNS.seq} LIMIT ?`, runId, fromSeq, limit);
54116
54237
  }
@@ -54161,6 +54282,10 @@ class SqlRunJournal {
54161
54282
  this.database = database;
54162
54283
  this.tables = tables;
54163
54284
  this.legacy = legacy;
54285
+ registerRunJournalVersions(this, {
54286
+ changeToken: () => this.changeToken(),
54287
+ runVersions: () => this.runVersions()
54288
+ });
54164
54289
  }
54165
54290
  static async open(database, options = {}) {
54166
54291
  const t = renderStorageIdentifiers2("journal", JOURNAL_TABLES, options.prefix);
@@ -54259,6 +54384,27 @@ class SqlRunJournal {
54259
54384
  return [...rows, ...legacy].map((row) => ({ ...JSON.parse(row[JOURNAL_COLUMNS.headerJson]), status: row[JOURNAL_COLUMNS.status] })).sort((left, right) => left.runId < right.runId ? -1 : left.runId > right.runId ? 1 : 0);
54260
54385
  });
54261
54386
  }
54387
+ async changeToken() {
54388
+ this.assertOpen();
54389
+ return this.operation(async () => {
54390
+ const row = await this.database.get(`SELECT data_version, total_changes() AS changes,
54391
+ (SELECT count(*) FROM ${this.tables.runs}) AS runs,
54392
+ (SELECT max(rowid) FROM ${this.tables.events}) AS last_event
54393
+ FROM pragma_data_version`);
54394
+ return JSON.stringify(Object.values(row ?? {}).map(String));
54395
+ });
54396
+ }
54397
+ async runVersions() {
54398
+ this.assertOpen();
54399
+ return this.operation(async () => {
54400
+ const rows = await this.database.all(`SELECT runs.${JOURNAL_COLUMNS.runId}, ${latestEventColumns(this.tables.events, "runs")} FROM ${this.tables.runs} AS runs`);
54401
+ const legacy = await this.legacy?.versions(this.database) ?? [];
54402
+ return new Map([...rows, ...legacy].map((row) => [
54403
+ row[JOURNAL_COLUMNS.runId],
54404
+ { seq: journalCounter(row[JOURNAL_COLUMNS.runId], "seq", row[JOURNAL_COLUMNS.seq]), at: Number(row[JOURNAL_COLUMNS.at]) }
54405
+ ]));
54406
+ });
54407
+ }
54262
54408
  async requireRun(tx, runId) {
54263
54409
  if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
54264
54410
  return;
@@ -55656,6 +55802,10 @@ function deriveInputFields(schema) {
55656
55802
 
55657
55803
  // dist/builtin/workflows/src/runs/shared/validate-inputs.ts
55658
55804
  import { Value as Value2 } from "typebox/value";
55805
+ function firstSchemaError(def, value2, kind) {
55806
+ const first = [...Value2.Errors(def, value2)][0];
55807
+ return first === undefined ? `does not match ${kind} schema` : first.message;
55808
+ }
55659
55809
  function validateInputs(schema, inputs) {
55660
55810
  const errors = [];
55661
55811
  for (const key of Object.keys(inputs)) {
@@ -55684,12 +55834,16 @@ function validateInputs(schema, inputs) {
55684
55834
  if (typeof value2 !== "number" || !Number.isFinite(value2)) {
55685
55835
  errors.push({ key, reason: `expected finite number, got ${workflowSerializableTypeName(value2)}` });
55686
55836
  hasTypeError = true;
55837
+ } else if (!Value2.Check(def, value2)) {
55838
+ errors.push({ key, reason: firstSchemaError(def, value2, kind) });
55687
55839
  }
55688
55840
  break;
55689
55841
  case "integer":
55690
55842
  if (typeof value2 !== "number" || !Number.isInteger(value2)) {
55691
55843
  errors.push({ key, reason: `expected integer, got ${workflowSerializableTypeName(value2)}` });
55692
55844
  hasTypeError = true;
55845
+ } else if (!Value2.Check(def, value2)) {
55846
+ errors.push({ key, reason: firstSchemaError(def, value2, kind) });
55693
55847
  }
55694
55848
  break;
55695
55849
  case "boolean":
@@ -60197,7 +60351,12 @@ async function mapParallelSteps(steps, concurrency, failFast, mapper, onFirstFai
60197
60351
  if (selectedFailure !== undefined)
60198
60352
  throw selectedFailure;
60199
60353
  }
60200
- throw new AggregateError(failures.map((failure) => failure.error), `atomic-workflows: ${failures.length} parallel ${failures.length === 1 ? "step" : "steps"} failed`);
60354
+ const aggregate = new AggregateError(failures.map((failure) => failure.error), `atomic-workflows: ${failures.length} parallel ${failures.length === 1 ? "step" : "steps"} failed`);
60355
+ if (failFastEnabled)
60356
+ throw aggregate;
60357
+ const failedIndexes = new Set(failures.map((failure) => failure.index));
60358
+ const partialResults = Array.from({ length: steps.length }, (_, index) => failedIndexes.has(index) ? undefined : results[index]);
60359
+ throw Object.assign(aggregate, { partialResults });
60201
60360
  }
60202
60361
  return results;
60203
60362
  }
@@ -61672,13 +61831,24 @@ class ConcurrencyLimiter {
61672
61831
  get queued() {
61673
61832
  return this._queue.length;
61674
61833
  }
61675
- acquire() {
61834
+ acquire(signal) {
61835
+ if (signal?.aborted)
61836
+ return Promise.reject(signal.reason);
61676
61837
  if (this._running < this.limit) {
61677
61838
  this._running++;
61678
61839
  return Promise.resolve();
61679
61840
  }
61680
- return new Promise((resolve) => {
61681
- this._queue.push(resolve);
61841
+ return new Promise((resolve, reject) => {
61842
+ const grant = () => {
61843
+ signal?.removeEventListener("abort", onAbort);
61844
+ resolve();
61845
+ };
61846
+ const onAbort = () => {
61847
+ this._queue.splice(this._queue.indexOf(grant), 1);
61848
+ reject(signal?.reason);
61849
+ };
61850
+ this._queue.push(grant);
61851
+ signal?.addEventListener("abort", onAbort, { once: true });
61682
61852
  });
61683
61853
  }
61684
61854
  release() {
@@ -61689,8 +61859,8 @@ class ConcurrencyLimiter {
61689
61859
  this._running--;
61690
61860
  }
61691
61861
  }
61692
- async run(fn) {
61693
- await this.acquire();
61862
+ async run(fn, signal) {
61863
+ await this.acquire(signal);
61694
61864
  try {
61695
61865
  return await fn();
61696
61866
  } finally {
@@ -64226,14 +64396,40 @@ function createChildWorkflowRunner(input) {
64226
64396
  }
64227
64397
  };
64228
64398
  }
64399
+ // dist/builtin/workflows/src/shared/error-with-causes.ts
64400
+ var MAX_CAUSE_DEPTH = 5;
64401
+ function describeErrorWithCauses(error) {
64402
+ const messages = [];
64403
+ const visited = new Set;
64404
+ let current = error;
64405
+ for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH && !visited.has(current); depth++) {
64406
+ visited.add(current);
64407
+ const message = current instanceof Error ? current.message : String(current);
64408
+ if (!messages.includes(message))
64409
+ messages.push(message);
64410
+ current = current instanceof Error ? current.cause : undefined;
64411
+ }
64412
+ return messages.join(": ");
64413
+ }
64414
+
64229
64415
  // dist/builtin/workflows/src/engine/run-durable-finalize.ts
64230
64416
  async function finalizeDurableTerminalStatus(input) {
64417
+ try {
64418
+ await commitDurableTerminalStatus(input);
64419
+ } catch (error) {
64420
+ if (input.store !== undefined)
64421
+ recordDurableEndingFailure(input.store, input.runSnapshot, error);
64422
+ throw error;
64423
+ }
64424
+ }
64425
+ async function commitDurableTerminalStatus(input) {
64231
64426
  if (!input.isRoot)
64232
64427
  return;
64233
64428
  const status = effectiveRunStatus(input.runSnapshot);
64234
64429
  const isExitTerminal = input.runSnapshot.exited === true && status !== "running";
64235
64430
  const isBlocked = status === "blocked" && (input.runSnapshot.endedAt !== undefined || input.runSnapshot.blockedAt !== undefined);
64236
- if (status !== "failed" && status !== "killed" && !isExitTerminal && !isBlocked)
64431
+ const isUncommittedCompletion = status === "completed" && input.terminalStatusCommitted === false;
64432
+ if (status !== "failed" && status !== "killed" && !isExitTerminal && !isBlocked && !isUncommittedCompletion)
64237
64433
  return;
64238
64434
  const durableStatus = toDurableStatus(status);
64239
64435
  if (durableStatus !== undefined) {
@@ -64243,7 +64439,7 @@ async function finalizeDurableTerminalStatus(input) {
64243
64439
  if (input.runSnapshot.result !== undefined)
64244
64440
  throw error;
64245
64441
  }
64246
- if (durableStatus === "failed" || durableStatus === "blocked") {
64442
+ if (durableStatus === "failed" || durableStatus === "blocked" || isUncommittedCompletion) {
64247
64443
  await recordRunTimingCheckpointAsync(input.durableBackend, input.runSnapshot);
64248
64444
  }
64249
64445
  const failure = durableStatus === "failed" ? {
@@ -64261,6 +64457,16 @@ async function finalizeDurableTerminalStatus(input) {
64261
64457
  await input.durableBackend.commitWorkflowStatus(input.runId, durableStatus, undefined, input.runSnapshot.resumable, failure);
64262
64458
  }
64263
64459
  }
64460
+ function recordDurableEndingFailure(store, runSnapshot, error) {
64461
+ const detail = describeErrorWithCauses(error);
64462
+ store.recordNotice({
64463
+ id: `workflow-durable-ending-failed:${runSnapshot.id}`,
64464
+ runId: runSnapshot.id,
64465
+ level: "error",
64466
+ message: `Workflow "${runSnapshot.name}" ended ${runSnapshot.status}, but its final state could not be saved to the workflow journal: ${detail}. Readers of the journal may report it as crashed.`,
64467
+ createdAt: Date.now()
64468
+ });
64469
+ }
64264
64470
  function toDurableStatus(status) {
64265
64471
  switch (status) {
64266
64472
  case "completed":
@@ -66638,7 +66844,9 @@ import { createStructuredOutputCapture, runCallback as runCallback2 } from "@bas
66638
66844
  import {
66639
66845
  AutoRoutingInferenceError,
66640
66846
  convertToLlm,
66847
+ isExtensionStartupFailure,
66641
66848
  isModelRoutingDebugEnabled,
66849
+ isTransientExtensionStartupFailure,
66642
66850
  parseModelConstraints,
66643
66851
  setsProviders
66644
66852
  } from "@bastani/atomic";
@@ -66909,6 +67117,23 @@ class StageDeliveryActivity {
66909
67117
  }
66910
67118
  }
66911
67119
 
67120
+ // dist/builtin/workflows/src/runs/foreground/stage-routing.ts
67121
+ var STAGE_ROUTING_CONCURRENCY = 8;
67122
+ var STAGE_ROUTING_DEADLINE_MS = 300000;
67123
+ var routingLimiter = new ConcurrencyLimiter(STAGE_ROUTING_CONCURRENCY);
67124
+ async function routeStageModel(route, input) {
67125
+ const deadline = new AbortController;
67126
+ const timer = setTimeout(() => deadline.abort(new Error("stage routing deadline")), STAGE_ROUTING_DEADLINE_MS);
67127
+ try {
67128
+ return await route({
67129
+ ...input,
67130
+ inference: { deadline: deadline.signal, limit: (run, signal) => routingLimiter.run(run, signal) }
67131
+ });
67132
+ } finally {
67133
+ clearTimeout(timer);
67134
+ }
67135
+ }
67136
+
66912
67137
  // dist/builtin/workflows/src/runs/foreground/stage-runner-artifact-capture.ts
66913
67138
  class StageArtifactCapture {
66914
67139
  session;
@@ -67399,6 +67624,7 @@ async function stripWorkflowOnlyOptions(options, defaultSessionDir, meta, pendin
67399
67624
  }
67400
67625
  const {
67401
67626
  schema: _schema,
67627
+ schemaTimeoutMs: _schemaTimeoutMs,
67402
67628
  mcp: _mcp,
67403
67629
  fallbackModels,
67404
67630
  modelConstraints: _modelConstraints,
@@ -67732,6 +67958,15 @@ class StageSessionReplacement {
67732
67958
  this.previous = undefined;
67733
67959
  await Promise.allSettled([...previous ? [disposeStageSession(previous)] : [], ...this.cleanups]);
67734
67960
  }
67961
+ async disposeRetired() {
67962
+ const previous = this.previous;
67963
+ this.previous = undefined;
67964
+ if (!previous)
67965
+ return;
67966
+ await disposeStageSession(previous).catch((error) => {
67967
+ console.error("atomic-workflows: retired stage session disposal failed", error);
67968
+ });
67969
+ }
67735
67970
  async disposeAfterIdle(session) {
67736
67971
  const agent = session.agent;
67737
67972
  if (typeof agent?.waitForIdle === "function")
@@ -67895,7 +68130,7 @@ function isWorkflowStructuredOutputContractError(error) {
67895
68130
  return error instanceof Error && "code" in error && error.code === "ATOMIC_WORKFLOW_STRUCTURED_OUTPUT_CONTRACT";
67896
68131
  }
67897
68132
  function isStructuredOutputContractFailure(message) {
67898
- return message.startsWith(STRUCTURED_OUTPUT_MISSING_ERROR) || message.startsWith('Validation failed for tool "structured_output":') || message.startsWith("Invalid structured output: response does not match the decision schema.") || message.startsWith("Invalid structured output: non-JSON decision.") || message.startsWith("Structured output requires one structured_output call.") || message.startsWith("Structured output requires exactly one structured_output call and no provider fallback.") || message === "Structured output requires complete judgment instructions." || message === "Structured output requires a nonempty named state object containing the task and relevant context text." || message === "Structured output inputs must be finite, acyclic JSON data." || message === "Structured output inputs must be plain JSON objects." || message === "structured_output tool call failed schema validation.";
68133
+ return message.startsWith(STRUCTURED_OUTPUT_MISSING_ERROR) || message.startsWith('Validation failed for tool "structured_output":') || message.startsWith("Invalid structured output: response does not match the decision schema.") || message.startsWith("Invalid structured output: non-JSON decision.") || message.startsWith("Invalid structured output: tool call arguments were not valid JSON.") || message.startsWith("Structured output requires one structured_output call.") || message.startsWith("Structured output requires exactly one structured_output call and no provider fallback.") || message === "Structured output requires complete judgment instructions." || message === "Structured output requires a nonempty named state object containing the task and relevant context text." || message === "Structured output inputs must be finite, acyclic JSON data." || message === "Structured output inputs must be plain JSON objects." || message === "structured_output tool call failed schema validation.";
67899
68134
  }
67900
68135
  var STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
67901
68136
  function toolResultText(content) {
@@ -67947,7 +68182,8 @@ function stageOptionsWithStructuredOutput(options, capture, executionCapture) {
67947
68182
  return options;
67948
68183
  const structuredOutputTool = createStructuredOutputTool({
67949
68184
  schema: options.schema,
67950
- capture
68185
+ capture,
68186
+ ...options.schemaTimeoutMs === undefined ? {} : { timeoutMs: options.schemaTimeoutMs }
67951
68187
  });
67952
68188
  const executeStructuredOutput = structuredOutputTool.execute;
67953
68189
  const capturedStructuredOutputTool = {
@@ -68037,6 +68273,16 @@ function waitForStageStartup(operation, signal) {
68037
68273
  // dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
68038
68274
  var WORKFLOW_STAGE_CLOSED_FOR_GOOD_STATE = "atomic:workflow-stage-closed-for-good";
68039
68275
  var WORKFLOW_STAGE_END_CHILDREN_STATE = "atomic:workflow-stage-end-children";
68276
+ function isRetryableSameCandidateFailure(error) {
68277
+ if (isExtensionStartupFailure(error))
68278
+ return isTransientExtensionStartupFailure(error);
68279
+ return isRetryableSameModelFailure(error);
68280
+ }
68281
+ function mayAdvanceToNextCandidate(error) {
68282
+ if (isExtensionStartupFailure(error))
68283
+ return isTransientExtensionStartupFailure(error);
68284
+ return isRetryableModelFailure(error);
68285
+ }
68040
68286
  function hasMeaningfulUsage(usage) {
68041
68287
  if (usage === undefined)
68042
68288
  return false;
@@ -68288,7 +68534,7 @@ class StageSessionController {
68288
68534
  return;
68289
68535
  if (!this.routingPromise) {
68290
68536
  this.beginStartup();
68291
- this.routingPromise = (async () => {
68537
+ const routing = (async () => {
68292
68538
  const route = this.modelCatalog?.routeModel;
68293
68539
  if (!route)
68294
68540
  throw new Error("Workflow stage auto routing requires a routing-capable model catalog.");
@@ -68300,7 +68546,7 @@ class StageSessionController {
68300
68546
  ...thinking === undefined ? [] : [{ allowedEfforts: [thinking] }]
68301
68547
  ].filter((c) => c !== undefined);
68302
68548
  try {
68303
- this.modelRoute = await route({
68549
+ this.modelRoute = await routeStageModel(route, {
68304
68550
  task: text,
68305
68551
  stageName: this.opts.stageName,
68306
68552
  constraints,
@@ -68321,7 +68567,17 @@ class StageSessionController {
68321
68567
  this.modelRoute.assertCurrent();
68322
68568
  this.meta.stageOptions = { ...options, model: this.modelRoute.modelOverride };
68323
68569
  this.opts.onModelFallbackMetaChange?.(this.currentModelFallbackMeta());
68324
- })();
68570
+ })().catch((error) => {
68571
+ if (this.routingPromise === routing) {
68572
+ this.routingPromise = undefined;
68573
+ this.modelRoute = undefined;
68574
+ }
68575
+ if (this.startupWait.signal.aborted || this.opts.signal?.aborted)
68576
+ throw error;
68577
+ this.settleStartup(true);
68578
+ throw new Error(`atomic-workflows: stage "${this.opts.stageName}" failed during startup phase model-resolution: ${errorMessage3(error)}`);
68579
+ });
68580
+ this.routingPromise = routing;
68325
68581
  }
68326
68582
  await this.routingPromise;
68327
68583
  }
@@ -69076,7 +69332,7 @@ class StageSessionController {
69076
69332
  const errorSettingsManager = retrySettingsManagerFromError(error);
69077
69333
  if (errorSettingsManager !== undefined)
69078
69334
  this.sessionSettingsManager = errorSettingsManager;
69079
- const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
69335
+ const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameCandidateFailure(error));
69080
69336
  if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.startupWait.signal.aborted || this.capturedStructuredOutputForAttempt()) {
69081
69337
  throw error;
69082
69338
  }
@@ -69488,10 +69744,11 @@ class StageSessionController {
69488
69744
  ...usage === undefined ? {} : { usage },
69489
69745
  error: message
69490
69746
  });
69491
- if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
69747
+ if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || index === candidates.length - 1) {
69492
69748
  this.modelWarnings.push(...this.pendingFallbackWarnings);
69493
69749
  this.pendingFallbackWarnings.length = 0;
69494
69750
  this.notifyModelFallbackMetaChange();
69751
+ await this.replacement.disposeRetired();
69495
69752
  return "throw";
69496
69753
  }
69497
69754
  const nextCandidate = candidates[index + 1];
@@ -70613,13 +70870,13 @@ class EngineRuntime {
70613
70870
 
70614
70871
  // dist/builtin/workflows/src/engine/session-closed-error.ts
70615
70872
  import { isStaleExtensionContextError as isStaleExtensionContextError5 } from "@bastani/atomic";
70616
- var MAX_CAUSE_DEPTH = 8;
70873
+ var MAX_CAUSE_DEPTH2 = 8;
70617
70874
  function reportsClosedSession(error) {
70618
70875
  return "code" in error && error.code === "SessionClosed" || isStaleExtensionContextError5(error);
70619
70876
  }
70620
70877
  function isSessionClosedError(error) {
70621
70878
  let current = error;
70622
- for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined; depth++) {
70879
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH2 && current !== undefined; depth++) {
70623
70880
  try {
70624
70881
  if (reportsClosedSession(current))
70625
70882
  return true;
@@ -71256,6 +71513,7 @@ async function executeRun(def, resolvedInputs, opts) {
71256
71513
  };
71257
71514
  const runtimeSettled = Promise.withResolvers();
71258
71515
  let durableRootAdmitted = false;
71516
+ let terminalStatusCommitted = false;
71259
71517
  let pausePersistence;
71260
71518
  let resumePersistence;
71261
71519
  let controlSettlements = Promise.resolve();
@@ -71445,6 +71703,7 @@ async function executeRun(def, resolvedInputs, opts) {
71445
71703
  await recordRunResultCheckpointAsync(durableBackend, runSnapshot);
71446
71704
  }
71447
71705
  await durableBackend.commitWorkflowStatus(runId, returned.status, undefined, returned.metadata?.resumable);
71706
+ terminalStatusCommitted = true;
71448
71707
  await appendRunEndWhenRecorded(opts.persistence, recorded, {
71449
71708
  runId,
71450
71709
  status: returned.status,
@@ -71566,7 +71825,9 @@ async function executeRun(def, resolvedInputs, opts) {
71566
71825
  runId,
71567
71826
  runSnapshot,
71568
71827
  isRoot: opts.parentRun === undefined,
71569
- durableBackend
71828
+ durableBackend,
71829
+ terminalStatusCommitted,
71830
+ store: activeStore
71570
71831
  });
71571
71832
  }
71572
71833
  } finally {
@@ -71645,11 +71906,17 @@ function runDetached(def, inputs, opts = {}) {
71645
71906
  opts.onWorkflowStartReady?.();
71646
71907
  }
71647
71908
  };
71648
- let settleJob = () => {};
71649
- const voidPromise = new Promise((resolve) => {
71650
- settleJob = resolve;
71651
- });
71652
- const jobEntry = { runId, controller, promise: voidPromise };
71909
+ const jobSettled = Promise.withResolvers();
71910
+ const jobOutcome = Promise.withResolvers();
71911
+ jobOutcome.promise.catch(() => {});
71912
+ const settleJob = (failure) => {
71913
+ jobSettled.resolve();
71914
+ if (failure === undefined)
71915
+ jobOutcome.resolve();
71916
+ else
71917
+ jobOutcome.reject(failure.error);
71918
+ };
71919
+ const jobEntry = { runId, controller, promise: jobSettled.promise, outcome: jobOutcome.promise };
71653
71920
  try {
71654
71921
  opts.startupSignal?.addEventListener("abort", cancelStartup, { once: true });
71655
71922
  registry.register(runId, controller);
@@ -71697,6 +71964,7 @@ function runDetached(def, inputs, opts = {}) {
71697
71964
  throw error;
71698
71965
  }
71699
71966
  const settle = async (...args) => {
71967
+ const [ok, , error] = args;
71700
71968
  try {
71701
71969
  if (!observed)
71702
71970
  await observe(...args);
@@ -71704,7 +71972,7 @@ function runDetached(def, inputs, opts = {}) {
71704
71972
  detachStartup();
71705
71973
  registry.unregister(runId, controller);
71706
71974
  tracker.unregister(runId, jobEntry);
71707
- settleJob();
71975
+ settleJob(ok ? undefined : { error });
71708
71976
  }
71709
71977
  };
71710
71978
  backgroundPromise.then((result) => {
@@ -73285,6 +73553,43 @@ function isDormantMessageEvent(value2) {
73285
73553
  // dist/builtin/workflows/src/extension/extension-lifecycle.ts
73286
73554
  import { registerExtensionContextRetirementEffect, sessionScopedExtensionState as sessionScopedExtensionState2 } from "@bastani/atomic";
73287
73555
 
73556
+ // dist/builtin/workflows/src/runs/background/ended-run-settlement.ts
73557
+ var ENDED_RUN_SETTLEMENT_TIMEOUT_MS = 1e4;
73558
+ function awaitJobSettlement(job) {
73559
+ return job.outcome ?? job.promise;
73560
+ }
73561
+ async function settleEndedRuns(opts) {
73562
+ const timeoutMs = opts.timeoutMs ?? ENDED_RUN_SETTLEMENT_TIMEOUT_MS;
73563
+ const ending = topLevelWorkflowRuns(opts.store.runs()).flatMap((run) => {
73564
+ const job = run.endedAt === undefined ? undefined : opts.jobs.get(run.id);
73565
+ return job === undefined ? [] : [{ runId: run.id, job }];
73566
+ });
73567
+ if (ending.length === 0)
73568
+ return [];
73569
+ const deadline = Promise.withResolvers();
73570
+ const timer = setTimeout(deadline.resolve, timeoutMs);
73571
+ timer.unref?.();
73572
+ try {
73573
+ const settled = await Promise.all(ending.map(({ runId, job }) => Promise.race([
73574
+ awaitJobSettlement(job).then(() => {
73575
+ return;
73576
+ }, (error) => ({
73577
+ runId,
73578
+ reason: "failed",
73579
+ message: describeErrorWithCauses(error)
73580
+ })),
73581
+ deadline.promise.then(() => ({
73582
+ runId,
73583
+ reason: "timed_out",
73584
+ message: `still recording its ending after ${timeoutMs} ms`
73585
+ }))
73586
+ ])));
73587
+ return settled.filter((failure) => failure !== undefined);
73588
+ } finally {
73589
+ clearTimeout(timer);
73590
+ }
73591
+ }
73592
+
73288
73593
  // dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts
73289
73594
  function expandedControlRunIds(store, runId) {
73290
73595
  const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
@@ -76545,6 +76850,13 @@ function registerWorkflowLifecycleHandlers(pi, deps) {
76545
76850
  if (failures.length > 0)
76546
76851
  throw new Error(failures.map((result) => `${result.runId}: ${result.reason}${"message" in result ? ` (${result.message})` : ""}`).join("; "));
76547
76852
  },
76853
+ async () => {
76854
+ if (boundary !== "quit")
76855
+ return;
76856
+ const failures = await settleEndedRuns({ store, jobs });
76857
+ if (failures.length > 0)
76858
+ throw new Error(failures.map((failure) => `${failure.runId}: ended but its ending was not recorded (${failure.message})`).join("; "));
76859
+ },
76548
76860
  () => stageControlRegistry.clear()
76549
76861
  ]);
76550
76862
  lifetime.generations.add(quitAndCheckpointRuns);
@@ -83295,6 +83607,7 @@ import { join as join28 } from "node:path";
83295
83607
  import {
83296
83608
  isStaleExtensionContextError as isStaleExtensionContextError6,
83297
83609
  ModelRuntime,
83610
+ noOpUIContext,
83298
83611
  resolveRestoredModelReference
83299
83612
  } from "@bastani/atomic";
83300
83613
 
@@ -83621,7 +83934,14 @@ function stripWorkflowOnlyOptions2(options) {
83621
83934
  if (!options)
83622
83935
  return options;
83623
83936
  const maybeWorkflowOptions = options;
83624
- const { schema: _schema, mcp: _mcp, fallbackModels, group: _group, ...sessionOptions } = maybeWorkflowOptions;
83937
+ const {
83938
+ schema: _schema,
83939
+ schemaTimeoutMs: _schemaTimeoutMs,
83940
+ mcp: _mcp,
83941
+ fallbackModels,
83942
+ group: _group,
83943
+ ...sessionOptions
83944
+ } = maybeWorkflowOptions;
83625
83945
  return fallbackModels?.length === 0 ? { ...sessionOptions, fallbackModels: [] } : sessionOptions;
83626
83946
  }
83627
83947
  function emitLateIntercomRoute(pi, meta, messages, options, batch) {
@@ -83738,6 +84058,7 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83738
84058
  notify: ui.notify ?? (() => {
83739
84059
  return;
83740
84060
  }),
84061
+ requestRender: noOpUIContext.requestRender,
83741
84062
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
83742
84063
  return;
83743
84064
  }),
@@ -83797,7 +84118,7 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83797
84118
  getEditorComponent: ui.getEditorComponent ?? (() => {
83798
84119
  return;
83799
84120
  }),
83800
- theme: ui.theme,
84121
+ theme: ui.theme ?? noOpUIContext.theme,
83801
84122
  getAllThemes: ui.getAllThemes ?? (() => []),
83802
84123
  getTheme: ui.getTheme ?? (() => {
83803
84124
  return;
@@ -83807,9 +84128,8 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83807
84128
  setToolsExpanded: ui.setToolsExpanded ?? (() => {
83808
84129
  return;
83809
84130
  }),
83810
- getChatRenderSettings: ui.getChatRenderSettings ?? (() => {
83811
- return;
83812
- })
84131
+ getFooterDataProvider: noOpUIContext.getFooterDataProvider,
84132
+ getChatRenderSettings: ui.getChatRenderSettings ?? noOpUIContext.getChatRenderSettings
83813
84133
  };
83814
84134
  }
83815
84135
  function findStageModel(runtime, reference) {
@@ -85912,6 +86232,7 @@ function workflowModelCatalogFromContext(ctx, resolveLiveContext) {
85912
86232
  model: current.model,
85913
86233
  getRouterModel: () => current.getRouterModel(),
85914
86234
  ...current.getModelRouting ? { getModelRouting: () => current.getModelRouting() } : {},
86235
+ ...current.getHttpIdleTimeoutMs ? { getHttpIdleTimeoutMs: () => current.getHttpIdleTimeoutMs() } : {},
85915
86236
  modelRegistry: {
85916
86237
  getAvailable: () => registry.getAvailable(),
85917
86238
  getAll: () => registry.getAll(),
@@ -85929,7 +86250,8 @@ function workflowModelCatalogFromContext(ctx, resolveLiveContext) {
85929
86250
  signal: input.signal,
85930
86251
  selection: input.selection,
85931
86252
  ...input.taskNeeds ? { taskNeeds: input.taskNeeds } : {},
85932
- ...input.overrideProviderSettings ? { overrideProviderSettings: true } : {}
86253
+ ...input.overrideProviderSettings ? { overrideProviderSettings: true } : {},
86254
+ ...input.inference ? { inference: input.inference } : {}
85933
86255
  });
85934
86256
  },
85935
86257
  listModels: async () => {
@@ -86708,7 +87030,7 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86708
87030
  const entry = { signature };
86709
87031
  announcedRoutes.set(run.id, entry);
86710
87032
  try {
86711
- pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT2, announcement);
87033
+ outsideWorkflowExecutions(() => pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT2, announcement));
86712
87034
  } catch (error) {
86713
87035
  if (announcedRoutes.get(run.id) === entry)
86714
87036
  announcedRoutes.delete(run.id);
@@ -86747,7 +87069,7 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86747
87069
  announcedRoutes.clear();
86748
87070
  announceRoutes();
86749
87071
  });
86750
- const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT2, (payload) => {
87072
+ const routePendingStageMessage = (payload) => {
86751
87073
  if (disposed || !isPendingStageMessageEvent(payload) || payload.handled)
86752
87074
  return;
86753
87075
  const runs = activeStore.runs();
@@ -86810,12 +87132,13 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86810
87132
  }
86811
87133
  payload.handled = true;
86812
87134
  payload.completion = queueAndPersist(activeStore, resolvedEvent, workflowInvocationIntercomGroup(rootRunId), stage.pendingStageDeliveryAvailable === true);
86813
- });
87135
+ };
87136
+ const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT2, (payload) => outsideWorkflowExecutions(() => routePendingStageMessage(payload)));
86814
87137
  const stickySubscription = pi.events?.on?.(STICKY_LIVE_DELIVERED_EVENT, (payload) => {
86815
87138
  if (disposed || !isStickyLiveDeliveredEvent(payload) || payload.handled)
86816
87139
  return;
86817
87140
  payload.handled = true;
86818
- payload.completion = recordConfirmedStickyDeliveries(activeStore, payload);
87141
+ payload.completion = outsideWorkflowExecutions(() => recordConfirmedStickyDeliveries(activeStore, payload));
86819
87142
  });
86820
87143
  const dispose = () => {
86821
87144
  disposed = true;
@@ -87595,7 +87918,7 @@ function openInputsPicker(ui, opts) {
87595
87918
  // dist/builtin/workflows/src/tui/session-picker.ts
87596
87919
  import { keyText as keyText3 } from "@bastani/atomic";
87597
87920
  var ESCAPE_CODE = 27;
87598
- function isQuitRun4(run) {
87921
+ function isQuitRun5(run) {
87599
87922
  return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
87600
87923
  }
87601
87924
  var DOUBLE_ESCAPE_SEQUENCE = String.fromCharCode(ESCAPE_CODE, ESCAPE_CODE);
@@ -87632,8 +87955,7 @@ function selectRunsForPicker(runs, query, includeAll, now = Date.now(), intent =
87632
87955
  return true;
87633
87956
  return r.name.toLowerCase().includes(q) || r.id.startsWith(q);
87634
87957
  };
87635
- const active = [];
87636
- const terminal = [];
87958
+ const rows = [];
87637
87959
  for (const r of runs) {
87638
87960
  if (!isTopLevelWorkflowRun(r))
87639
87961
  continue;
@@ -87646,16 +87968,30 @@ function selectRunsForPicker(runs, query, includeAll, now = Date.now(), intent =
87646
87968
  }
87647
87969
  const endedAt = r.endedAt;
87648
87970
  if (endedAt === undefined) {
87649
- active.push({ run: r, bucket: "active" });
87971
+ rows.push({ run: r, bucket: "active" });
87650
87972
  continue;
87651
87973
  }
87652
87974
  if (includeAll || now - endedAt <= RECENT_WINDOW_MS) {
87653
- terminal.push({ run: r, bucket: "terminal" });
87975
+ rows.push({ run: r, bucket: "terminal" });
87654
87976
  }
87655
87977
  }
87656
- active.sort((a, b) => a.run.startedAt - b.run.startedAt);
87657
- terminal.sort((a, b) => (b.run.endedAt ?? 0) - (a.run.endedAt ?? 0));
87658
- return [...active, ...terminal];
87978
+ return sortRunsByStatus(rows, (row) => row.run, createRunIndicatorStatusResolver(runs));
87979
+ }
87980
+ function syncSessionPickerSelection(state, rows) {
87981
+ if (state.selectedRunId !== undefined) {
87982
+ const index = rows.findIndex((row) => row.run.id === state.selectedRunId);
87983
+ if (index >= 0)
87984
+ state.selectedIndex = index;
87985
+ }
87986
+ state.selectedRunId = rows[state.selectedIndex]?.run.id;
87987
+ }
87988
+ function selectIndex2(state, rows, index) {
87989
+ state.selectedIndex = index;
87990
+ state.selectedRunId = rows[index]?.run.id;
87991
+ }
87992
+ function resetSelection(state) {
87993
+ state.selectedIndex = 0;
87994
+ state.selectedRunId = undefined;
87659
87995
  }
87660
87996
  var TITLE = "Connect to workflow run";
87661
87997
  function renderHeader3(width, theme) {
@@ -87736,7 +88072,7 @@ function renderRunRow(row, isSelected, inner, theme, now, allRuns) {
87736
88072
  const border = hexToAnsi(theme.border);
87737
88073
  const panelBg = hexBg(theme.bg);
87738
88074
  const run = row.run;
87739
- const indicatorStatus = isQuitRun4(run) ? run.status : runIndicatorStatus(run, allRuns);
88075
+ const indicatorStatus = isQuitRun5(run) ? run.status : runIndicatorStatus(run, allRuns);
87740
88076
  const icon = statusIcon(indicatorStatus);
87741
88077
  const iconColor = hexToAnsi(statusColor(indicatorStatus, theme));
87742
88078
  const dim = hexToAnsi(theme.dim);
@@ -87828,12 +88164,12 @@ function handleSessionPickerInput(data, state, rows) {
87828
88164
  }
87829
88165
  if (matchesKey(data, Key.backspace)) {
87830
88166
  state.query = state.query.slice(0, -1);
87831
- state.selectedIndex = 0;
88167
+ resetSelection(state);
87832
88168
  return { kind: "noop" };
87833
88169
  }
87834
88170
  if (data.length === 1 && data >= " " && data <= "~") {
87835
88171
  state.query += data;
87836
- state.selectedIndex = 0;
88172
+ resetSelection(state);
87837
88173
  return { kind: "noop" };
87838
88174
  }
87839
88175
  return { kind: "noop" };
@@ -87848,17 +88184,17 @@ function handleSessionPickerInput(data, state, rows) {
87848
88184
  return { kind: "close" };
87849
88185
  if (matchesKey(data, "a") || matchesKey(data, Key.shift("a"))) {
87850
88186
  state.includeAll = !state.includeAll;
87851
- state.selectedIndex = 0;
88187
+ resetSelection(state);
87852
88188
  return { kind: "noop" };
87853
88189
  }
87854
88190
  if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
87855
- state.selectedIndex = Math.min(state.selectedIndex + 1, Math.max(0, rows.length - 1));
88191
+ selectIndex2(state, rows, Math.min(state.selectedIndex + 1, Math.max(0, rows.length - 1)));
87856
88192
  return { kind: "noop" };
87857
88193
  }
87858
88194
  if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
87859
88195
  if (rows.length > 0 && state.selectedIndex === 0)
87860
88196
  return { kind: "noop" };
87861
- state.selectedIndex = Math.max(state.selectedIndex - 1, 0);
88197
+ selectIndex2(state, rows, Math.max(state.selectedIndex - 1, 0));
87862
88198
  return { kind: "noop" };
87863
88199
  }
87864
88200
  if (matchesKey(data, Key.enter)) {
@@ -88185,10 +88521,12 @@ function openSessionPicker(ui, store, theme, intent = "connect") {
88185
88521
  return {
88186
88522
  render: (width) => {
88187
88523
  const rows = selectRows();
88524
+ syncSessionPickerSelection(state, rows);
88188
88525
  return renderSessionPicker({ width, theme, rows, state, allRuns: store.runs() });
88189
88526
  },
88190
88527
  handleInput: (data) => {
88191
88528
  const rows = selectRows();
88529
+ syncSessionPickerSelection(state, rows);
88192
88530
  const consumed = isSessionPickerKey(data, state, rows);
88193
88531
  const action = handleSessionPickerInput(data, state, rows);
88194
88532
  if (action.kind === "noop") {
@@ -89221,6 +89559,18 @@ function createSessionRunControl(host) {
89221
89559
  async quit(runId) {
89222
89560
  return controlOutcome(await request({ action: "quit", ...target(runId) }));
89223
89561
  },
89562
+ async waitForSettled(runId) {
89563
+ const job = (host.jobs ?? currentJobTracker()).get(runId);
89564
+ if (job === undefined)
89565
+ return;
89566
+ try {
89567
+ await awaitJobSettlement(job);
89568
+ } catch (error) {
89569
+ const cause = error instanceof Error ? error : new Error(String(error));
89570
+ const code = error instanceof JournalError ? "storage_unavailable" : classifyControlError(error);
89571
+ throw failure3(code, `Run ${runId} did not settle cleanly: ${describeErrorWithCauses(error)}`, runId, cause);
89572
+ }
89573
+ },
89224
89574
  async resume(runId, options) {
89225
89575
  return controlOutcome(await request({
89226
89576
  action: "resume",
@@ -91664,6 +92014,7 @@ function factory(pi) {
91664
92014
  execute: executeWorkflowTool,
91665
92015
  context: () => sessionContext,
91666
92016
  store: owner.store,
92017
+ jobs: runState.jobs,
91667
92018
  catalog: async () => {
91668
92019
  const runtime = runtimeState.runtimeForContext(sessionContext);
91669
92020
  return await runtime.prepareDurableCatalog?.() ?? { resumable: [], completed: [] };