@bastani/atomic 0.9.40 → 0.9.41-alpha.2

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 (323) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/intercom/CHANGELOG.md +12 -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 +2 -2
  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 +14 -0
  14. package/dist/builtin/subagents/README.md +14 -0
  15. package/dist/builtin/subagents/package.json +3 -3
  16. package/dist/builtin/subagents/src/extension/index.bundle.mjs +99 -19
  17. package/dist/builtin/web-access/package.json +2 -2
  18. package/dist/builtin/workflows/CHANGELOG.md +33 -0
  19. package/dist/builtin/workflows/README.md +2 -0
  20. package/dist/builtin/workflows/builtin/adversarial-verification.js +2 -2
  21. package/dist/builtin/workflows/builtin/{chunk-qjqn389g.js → chunk-2jfst7e4.js} +72 -10
  22. package/dist/builtin/workflows/builtin/{chunk-4bwtzyjq.js → chunk-49kkbdpr.js} +1 -1
  23. package/dist/builtin/workflows/builtin/{chunk-qdd897wm.js → chunk-apagcs4r.js} +1 -1
  24. package/dist/builtin/workflows/builtin/{chunk-454hz1qt.js → chunk-dcxscfnb.js} +1 -1
  25. package/dist/builtin/workflows/builtin/{chunk-bjva9j5k.js → chunk-hx8v4p97.js} +1 -1
  26. package/dist/builtin/workflows/builtin/{chunk-85mx6wcf.js → chunk-k5q3t7je.js} +1 -1
  27. package/dist/builtin/workflows/builtin/{chunk-8kkv04hz.js → chunk-n2gkzkty.js} +1 -1
  28. package/dist/builtin/workflows/builtin/{chunk-y45tkftg.js → chunk-txbc93t6.js} +1 -1
  29. package/dist/builtin/workflows/builtin/{chunk-x0vvjyzg.js → chunk-w4xp1w1f.js} +1 -1
  30. package/dist/builtin/workflows/builtin/{chunk-5eh0brtd.js → chunk-z3pajrfs.js} +1 -1
  31. package/dist/builtin/workflows/builtin/classify-and-act.js +2 -2
  32. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +2 -2
  33. package/dist/builtin/workflows/builtin/generate-and-filter.js +2 -2
  34. package/dist/builtin/workflows/builtin/goal.js +2 -2
  35. package/dist/builtin/workflows/builtin/index.js +10 -10
  36. package/dist/builtin/workflows/builtin/loop-until-done.js +2 -2
  37. package/dist/builtin/workflows/builtin/open-claude-design.js +2 -2
  38. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  39. package/dist/builtin/workflows/builtin/tournament.js +2 -2
  40. package/dist/builtin/workflows/package.json +2 -2
  41. package/dist/builtin/workflows/src/authoring.d.ts +1 -1
  42. package/dist/builtin/workflows/src/durable/journal/internal.d.ts +16 -0
  43. package/dist/builtin/workflows/src/durable/journal/legacy-journal-tables.d.ts +9 -0
  44. package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +6 -0
  45. package/dist/builtin/workflows/src/extension/index.bundle.mjs +950 -116
  46. package/dist/builtin/workflows/src/index.js +806 -131
  47. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +17 -1
  48. package/dist/cli/credential-print.d.ts.map +1 -1
  49. package/dist/cli/credential-print.js +1 -1
  50. package/dist/cli/credential-print.js.map +1 -1
  51. package/dist/config.d.ts +1 -0
  52. package/dist/config.d.ts.map +1 -1
  53. package/dist/config.js +1 -0
  54. package/dist/config.js.map +1 -1
  55. package/dist/core/agent-session-extension-bindings.d.ts +2 -1
  56. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  57. package/dist/core/agent-session-extension-bindings.js +33 -18
  58. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  59. package/dist/core/agent-session-methods.d.ts +2 -1
  60. package/dist/core/agent-session-methods.d.ts.map +1 -1
  61. package/dist/core/agent-session-methods.js.map +1 -1
  62. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  63. package/dist/core/agent-session-prompt.js +114 -21
  64. package/dist/core/agent-session-prompt.js.map +1 -1
  65. package/dist/core/agent-session-runtime.d.ts +1 -1
  66. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  67. package/dist/core/agent-session-runtime.js +6 -0
  68. package/dist/core/agent-session-runtime.js.map +1 -1
  69. package/dist/core/agent-session-state.d.ts +19 -1
  70. package/dist/core/agent-session-state.d.ts.map +1 -1
  71. package/dist/core/agent-session-state.js +41 -6
  72. package/dist/core/agent-session-state.js.map +1 -1
  73. package/dist/core/auth-storage-backends.d.ts +3 -1
  74. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  75. package/dist/core/auth-storage-backends.js +79 -12
  76. package/dist/core/auth-storage-backends.js.map +1 -1
  77. package/dist/core/client-identity.d.ts +8 -0
  78. package/dist/core/client-identity.d.ts.map +1 -0
  79. package/dist/core/client-identity.js +16 -0
  80. package/dist/core/client-identity.js.map +1 -0
  81. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  82. package/dist/core/compaction/planner-outcome.js +2 -1
  83. package/dist/core/compaction/planner-outcome.js.map +1 -1
  84. package/dist/core/execution-model-router.d.ts +18 -0
  85. package/dist/core/execution-model-router.d.ts.map +1 -1
  86. package/dist/core/execution-model-router.js +14 -8
  87. package/dist/core/execution-model-router.js.map +1 -1
  88. package/dist/core/extension-oauth-refresh-rejection.d.ts +12 -0
  89. package/dist/core/extension-oauth-refresh-rejection.d.ts.map +1 -0
  90. package/dist/core/extension-oauth-refresh-rejection.js +70 -0
  91. package/dist/core/extension-oauth-refresh-rejection.js.map +1 -0
  92. package/dist/core/extension-startup-failure.d.ts +30 -0
  93. package/dist/core/extension-startup-failure.d.ts.map +1 -0
  94. package/dist/core/extension-startup-failure.js +62 -0
  95. package/dist/core/extension-startup-failure.js.map +1 -0
  96. package/dist/core/extensions/context-types.d.ts +2 -0
  97. package/dist/core/extensions/context-types.d.ts.map +1 -1
  98. package/dist/core/extensions/context-types.js.map +1 -1
  99. package/dist/core/extensions/provider-types.d.ts +2 -0
  100. package/dist/core/extensions/provider-types.d.ts.map +1 -1
  101. package/dist/core/extensions/provider-types.js.map +1 -1
  102. package/dist/core/extensions/runner-context.d.ts +1 -0
  103. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  104. package/dist/core/extensions/runner-context.js +8 -0
  105. package/dist/core/extensions/runner-context.js.map +1 -1
  106. package/dist/core/extensions/runner.d.ts +1 -0
  107. package/dist/core/extensions/runner.d.ts.map +1 -1
  108. package/dist/core/extensions/runner.js +3 -0
  109. package/dist/core/extensions/runner.js.map +1 -1
  110. package/dist/core/extensions/runtime-types.d.ts +1 -0
  111. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  112. package/dist/core/extensions/runtime-types.js.map +1 -1
  113. package/dist/core/extensions/workflow-run-control-hub.d.ts +1 -0
  114. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  115. package/dist/core/extensions/workflow-run-control-hub.js +3 -0
  116. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  117. package/dist/core/extensions/workflow-run-control.d.ts +8 -0
  118. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  119. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  120. package/dist/core/model-config.d.ts +28 -0
  121. package/dist/core/model-config.d.ts.map +1 -1
  122. package/dist/core/model-fallback-failures.d.ts.map +1 -1
  123. package/dist/core/model-fallback-failures.js +12 -0
  124. package/dist/core/model-fallback-failures.js.map +1 -1
  125. package/dist/core/model-resolver-defaults.js +1 -1
  126. package/dist/core/model-resolver-defaults.js.map +1 -1
  127. package/dist/core/model-runtime-streaming.d.ts.map +1 -1
  128. package/dist/core/model-runtime-streaming.js +9 -3
  129. package/dist/core/model-runtime-streaming.js.map +1 -1
  130. package/dist/core/model-runtime.d.ts +5 -0
  131. package/dist/core/model-runtime.d.ts.map +1 -1
  132. package/dist/core/model-runtime.js +6 -0
  133. package/dist/core/model-runtime.js.map +1 -1
  134. package/dist/core/provider-composer-internal.d.ts +8 -6
  135. package/dist/core/provider-composer-internal.d.ts.map +1 -1
  136. package/dist/core/provider-composer-internal.js +21 -8
  137. package/dist/core/provider-composer-internal.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +12 -4
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/storage/session/sql-session-store.d.ts +35 -0
  142. package/dist/core/storage/session/sql-session-store.d.ts.map +1 -1
  143. package/dist/core/storage/session/sql-session-store.js +158 -42
  144. package/dist/core/storage/session/sql-session-store.js.map +1 -1
  145. package/dist/core/structured-output/deadline.d.ts +40 -0
  146. package/dist/core/structured-output/deadline.d.ts.map +1 -0
  147. package/dist/core/structured-output/deadline.js +110 -0
  148. package/dist/core/structured-output/deadline.js.map +1 -0
  149. package/dist/core/structured-output/index.d.ts.map +1 -1
  150. package/dist/core/structured-output/index.js +103 -47
  151. package/dist/core/structured-output/index.js.map +1 -1
  152. package/dist/core/structured-output/rejection-detail.d.ts +9 -0
  153. package/dist/core/structured-output/rejection-detail.d.ts.map +1 -0
  154. package/dist/core/structured-output/rejection-detail.js +129 -0
  155. package/dist/core/structured-output/rejection-detail.js.map +1 -0
  156. package/dist/core/structured-output/types.d.ts +8 -1
  157. package/dist/core/structured-output/types.d.ts.map +1 -1
  158. package/dist/core/structured-output/types.js.map +1 -1
  159. package/dist/core/tasks/completion.d.ts +7 -1
  160. package/dist/core/tasks/completion.d.ts.map +1 -1
  161. package/dist/core/tasks/completion.js +28 -6
  162. package/dist/core/tasks/completion.js.map +1 -1
  163. package/dist/core/tasks/contracts.d.ts +6 -1
  164. package/dist/core/tasks/contracts.d.ts.map +1 -1
  165. package/dist/core/tasks/contracts.js.map +1 -1
  166. package/dist/core/tasks/pause.d.ts +2 -1
  167. package/dist/core/tasks/pause.d.ts.map +1 -1
  168. package/dist/core/tasks/pause.js +3 -2
  169. package/dist/core/tasks/pause.js.map +1 -1
  170. package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
  171. package/dist/core/tools/bash-pty-native.js +10 -5
  172. package/dist/core/tools/bash-pty-native.js.map +1 -1
  173. package/dist/core/tools/bash.d.ts.map +1 -1
  174. package/dist/core/tools/bash.js +16 -32
  175. package/dist/core/tools/bash.js.map +1 -1
  176. package/dist/core/tools/grep.js +1 -1
  177. package/dist/core/tools/grep.js.map +1 -1
  178. package/dist/core/tools/kill.d.ts.map +1 -1
  179. package/dist/core/tools/kill.js +17 -3
  180. package/dist/core/tools/kill.js.map +1 -1
  181. package/dist/core/tools/shell-task-render.d.ts +55 -0
  182. package/dist/core/tools/shell-task-render.d.ts.map +1 -0
  183. package/dist/core/tools/shell-task-render.js +123 -0
  184. package/dist/core/tools/shell-task-render.js.map +1 -0
  185. package/dist/core/tools/shell-task-status.d.ts +52 -0
  186. package/dist/core/tools/shell-task-status.d.ts.map +1 -0
  187. package/dist/core/tools/shell-task-status.js +184 -0
  188. package/dist/core/tools/shell-task-status.js.map +1 -0
  189. package/dist/core/tools/structured-output.d.ts +5 -0
  190. package/dist/core/tools/structured-output.d.ts.map +1 -1
  191. package/dist/core/tools/structured-output.js +3 -0
  192. package/dist/core/tools/structured-output.js.map +1 -1
  193. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  194. package/dist/extensions/codemode/execute.js +134 -57
  195. package/dist/extensions/codemode/execute.js.map +1 -1
  196. package/dist/extensions/mcp/config.d.ts.map +1 -1
  197. package/dist/extensions/mcp/config.js +3 -2
  198. package/dist/extensions/mcp/config.js.map +1 -1
  199. package/dist/index-extensions.d.ts +1 -0
  200. package/dist/index-extensions.d.ts.map +1 -1
  201. package/dist/index-extensions.js +3 -0
  202. package/dist/index-extensions.js.map +1 -1
  203. package/dist/index.d.ts +3 -1
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +3 -1
  206. package/dist/index.js.map +1 -1
  207. package/dist/main.d.ts.map +1 -1
  208. package/dist/main.js +19 -6
  209. package/dist/main.js.map +1 -1
  210. package/dist/modes/interactive/components/task-row.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/task-row.js +11 -1
  212. package/dist/modes/interactive/components/task-row.js.map +1 -1
  213. package/dist/modes/interactive/interactive-auth-routing.js +12 -10
  214. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
  215. package/dist/modes/interactive/interactive-extension-custom-ui.js +20 -30
  216. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  217. package/dist/modes/interactive/interactive-extension-dialogs.js +23 -96
  218. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  219. package/dist/modes/interactive/interactive-extension-runtime.js +7 -8
  220. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  221. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  222. package/dist/modes/interactive/interactive-input-handling.js +27 -4
  223. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  224. package/dist/modes/interactive/interactive-mode-base.d.ts +20 -10
  225. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  226. package/dist/modes/interactive/interactive-mode-base.js +40 -5
  227. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  228. package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
  229. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  230. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  231. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  232. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -4
  233. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  234. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  235. package/dist/modes/interactive/interactive-mode-types.d.ts +4 -1
  236. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
  238. package/dist/modes/interactive/interactive-prompt-restore.d.ts +3 -0
  239. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  240. package/dist/modes/interactive/interactive-prompt-restore.js +9 -1
  241. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  242. package/dist/modes/interactive/interactive-prompt-turn.js +30 -2
  243. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  244. package/dist/modes/interactive/interactive-queueing.js +43 -8
  245. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  246. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-startup.js +12 -3
  248. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  249. package/dist/modes/interactive/theme/color-utils.d.ts +6 -1
  250. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  251. package/dist/modes/interactive/theme/color-utils.js +39 -17
  252. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  253. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
  254. package/dist/modes/interactive/theme/theme-class.js +2 -2
  255. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  256. package/dist/modes/interactive/theme/theme-tokens.d.ts +6 -0
  257. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -1
  258. package/dist/modes/interactive/theme/theme-tokens.js +7 -3
  259. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -1
  260. package/dist/modes/interactive-engine/isolated-auth.d.ts +3 -0
  261. package/dist/modes/interactive-engine/isolated-auth.d.ts.map +1 -1
  262. package/dist/modes/interactive-engine/isolated-auth.js +13 -1
  263. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  264. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  265. package/dist/modes/interactive-engine/isolated-runtime.js +11 -2
  266. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  267. package/dist/modes/interactive-engine/remote-model-catalog.d.ts +8 -0
  268. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  269. package/dist/modes/interactive-engine/remote-model-catalog.js +54 -0
  270. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  271. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-command-handler.js +4 -13
  273. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  274. package/dist/modes/rpc/rpc-model-catalog.d.ts +9 -0
  275. package/dist/modes/rpc/rpc-model-catalog.d.ts.map +1 -0
  276. package/dist/modes/rpc/rpc-model-catalog.js +19 -0
  277. package/dist/modes/rpc/rpc-model-catalog.js.map +1 -0
  278. package/dist/modes/rpc/rpc-provider-auth.d.ts.map +1 -1
  279. package/dist/modes/rpc/rpc-provider-auth.js +2 -6
  280. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  281. package/dist/modes/rpc/rpc-types.d.ts +6 -0
  282. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  283. package/dist/modes/rpc/rpc-types.js.map +1 -1
  284. package/dist/utils/changelog.d.ts +6 -0
  285. package/dist/utils/changelog.d.ts.map +1 -1
  286. package/dist/utils/changelog.js +11 -0
  287. package/dist/utils/changelog.js.map +1 -1
  288. package/dist/utils/clipboard.d.ts.map +1 -1
  289. package/dist/utils/clipboard.js +4 -0
  290. package/dist/utils/clipboard.js.map +1 -1
  291. package/dist/utils/tools-manager.d.ts.map +1 -1
  292. package/dist/utils/tools-manager.js +3 -2
  293. package/dist/utils/tools-manager.js.map +1 -1
  294. package/docs/background-tasks.md +5 -3
  295. package/docs/codemode.md +2 -2
  296. package/docs/custom-provider/oauth.md +42 -1
  297. package/docs/custom-provider/registration.md +2 -0
  298. package/docs/environment-variables.md +1 -0
  299. package/docs/extensions/api-reference.md +3 -4
  300. package/docs/extensions/authoring.md +1 -1
  301. package/docs/extensions/events.md +1 -1
  302. package/docs/models-configuration.md +9 -0
  303. package/docs/models.md +3 -1
  304. package/docs/providers.md +4 -4
  305. package/docs/rpc/protocol.md +4 -2
  306. package/docs/sdk/reference.md +2 -0
  307. package/docs/sdk/structured-decisions.md +7 -5
  308. package/docs/sdk.md +5 -2
  309. package/docs/settings.md +4 -2
  310. package/docs/subagents/reference.md +1 -1
  311. package/docs/subagents.md +15 -1
  312. package/docs/themes/reference.md +3 -1
  313. package/docs/usage.md +3 -1
  314. package/docs/workflows/api-reference.md +28 -0
  315. package/docs/workflows/authoring.md +1 -1
  316. package/docs/workflows/operations.md +2 -2
  317. package/npm-shrinkwrap.json +67 -54
  318. package/package.json +6 -6
  319. package/schemas/models.schema.json +21 -0
  320. package/dist/core/provider-attribution.d.ts +0 -4
  321. package/dist/core/provider-attribution.d.ts.map +0 -1
  322. package/dist/core/provider-attribution.js +0 -87
  323. 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,
@@ -52374,7 +52451,7 @@ function compareDraftSourceOrder(left, right) {
52374
52451
  function runTopologyFor(drafts, tools) {
52375
52452
  return drafts.find((draft) => draft.topology?.run !== undefined)?.topology?.run ?? tools.find((checkpoint) => checkpoint.topology?.run !== undefined)?.topology?.run;
52376
52453
  }
52377
- function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52454
+ function validateRunGroups(grouped, rootRunId, tools, checkpoints, allowPendingChildren = false) {
52378
52455
  const toolsFor = (runId) => tools.filter((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId);
52379
52456
  const owners = new Map;
52380
52457
  const syntheticChildIds = new Set;
@@ -52386,6 +52463,11 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52386
52463
  if (childRunId === parentRunId || owners.has(childRunId))
52387
52464
  return false;
52388
52465
  if (!grouped.has(childRunId)) {
52466
+ if (allowPendingChildren && isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) && !childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId)) {
52467
+ syntheticChildIds.add(childRunId);
52468
+ owners.set(childRunId, draft);
52469
+ continue;
52470
+ }
52389
52471
  if (!isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) || childScopedEvidenceExists(checkpoints, draft.replayKey, childRunId))
52390
52472
  return false;
52391
52473
  syntheticChildIds.add(childRunId);
@@ -52418,6 +52500,10 @@ function validateRunGroups(grouped, rootRunId, tools, checkpoints) {
52418
52500
  }
52419
52501
  return true;
52420
52502
  }
52503
+ function isPendingChildBoundary(draft, parentRunId, childRunId, rootRunId) {
52504
+ const boundary = draft.topology?.boundary;
52505
+ return workflowChildFromDraft(draft) === undefined && boundary?.event === "start" && boundary.status === "running" && boundary.child.runId === childRunId && boundary.child.parentRunId === parentRunId && boundary.child.parentStageId === draft.topology?.stageId && boundary.child.rootRunId === rootRunId;
52506
+ }
52421
52507
  function isSyntheticExitedChild(draft, parentRunId, childRunId, rootRunId) {
52422
52508
  const child = workflowChildFromDraft(draft);
52423
52509
  const boundary = draft.topology?.boundary;
@@ -53060,6 +53146,13 @@ class PromptReservationState {
53060
53146
 
53061
53147
  // dist/builtin/workflows/src/durable/journal/internal.ts
53062
53148
  var JOURNAL_READ_PAGE_SIZE = 256;
53149
+ var versionReaders = new WeakMap;
53150
+ function registerRunJournalVersions(journal, versions) {
53151
+ versionReaders.set(journal, versions);
53152
+ }
53153
+ function runJournalVersions(journal) {
53154
+ return versionReaders.get(journal);
53155
+ }
53063
53156
 
53064
53157
  // dist/builtin/workflows/src/durable/journal/values.ts
53065
53158
  function validateText(field, value2) {
@@ -53405,6 +53498,8 @@ class JournalDurableBackend {
53405
53498
  persistent;
53406
53499
  projection = createJournalProjection();
53407
53500
  sequences = new Map;
53501
+ foldedAt = new Map;
53502
+ catalogToken;
53408
53503
  leases = new Map;
53409
53504
  executions = new Map;
53410
53505
  executionContext = new AsyncLocalStorage;
@@ -53448,7 +53543,7 @@ class JournalDurableBackend {
53448
53543
  try {
53449
53544
  this.ensureOpen();
53450
53545
  if (requiresActiveExecution)
53451
- this.assertExecutionActive(runId);
53546
+ this.assertExecutionActive();
53452
53547
  } catch (error) {
53453
53548
  return Promise.reject(error);
53454
53549
  }
@@ -53501,6 +53596,7 @@ class JournalDurableBackend {
53501
53596
  this.projection.applyWorkflowSnapshot({ ...handle, pendingStageMessages: messages });
53502
53597
  }
53503
53598
  this.sequences.set(entry.runId, entry.seq);
53599
+ this.foldedAt.set(entry.runId, entry.at);
53504
53600
  }
53505
53601
  *entries(runId, fromSeq) {
53506
53602
  return yield* invoke(async () => {
@@ -53514,6 +53610,7 @@ class JournalDurableBackend {
53514
53610
  const entries = yield* this.entries(runId);
53515
53611
  this.projection.deleteWorkflow(runId);
53516
53612
  this.sequences.delete(runId);
53613
+ this.foldedAt.delete(runId);
53517
53614
  this.prompts.delete(runId);
53518
53615
  for (const entry of entries)
53519
53616
  this.fold(entry);
@@ -53526,7 +53623,7 @@ class JournalDurableBackend {
53526
53623
  }
53527
53624
  *current(runId) {
53528
53625
  this.ensureOpen();
53529
- this.assertExecutionActive(runId, true);
53626
+ this.assertExecutionActive(true);
53530
53627
  yield* this.refresh(runId);
53531
53628
  if (this.projection.getWorkflow(runId) === undefined)
53532
53629
  return;
@@ -53545,14 +53642,14 @@ class JournalDurableBackend {
53545
53642
  if (this.state === "closed" || this.state === "closing" && !this.mutationContext.getStore())
53546
53643
  throw new JournalBackendClosedError;
53547
53644
  }
53548
- assertExecutionActive(runId, admitted = false) {
53645
+ assertExecutionActive(admitted = false) {
53549
53646
  for (const [executionRunId, execution] of this.executionContext.getStore() ?? [])
53550
53647
  if (execution.retired && !(admitted && this.mutationContext.getStore()?.has(execution)))
53551
- throw new JournalExecutionRetiredError(typeof runId === "string" ? runId : executionRunId);
53648
+ throw new JournalExecutionRetiredError(executionRunId);
53552
53649
  }
53553
53650
  *ownership(runId) {
53554
53651
  this.ensureOpen();
53555
- this.assertExecutionActive(runId, true);
53652
+ this.assertExecutionActive(true);
53556
53653
  const lost = this.lost.get(runId);
53557
53654
  if (lost)
53558
53655
  throw lost;
@@ -53612,7 +53709,7 @@ class JournalDurableBackend {
53612
53709
  return this.serialize(input.workflowId, () => this.register(input));
53613
53710
  }
53614
53711
  *register(input) {
53615
- this.assertExecutionActive(input.workflowId, true);
53712
+ this.assertExecutionActive(true);
53616
53713
  this.ensureOpen();
53617
53714
  const header = {
53618
53715
  runId: input.workflowId,
@@ -53836,11 +53933,36 @@ class JournalDurableBackend {
53836
53933
  }
53837
53934
  hydrateResumableWorkflows() {
53838
53935
  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);
53936
+ const journal = runJournalVersions(this.journal);
53937
+ if (journal === undefined) {
53938
+ const runs = await this.journal.listRuns();
53939
+ for (const runId of new Set([...this.sequences.keys(), ...runs.map((run) => run.runId)]))
53940
+ await this.hydrateWorkflow(runId);
53941
+ return;
53942
+ }
53943
+ const token = await journal.changeToken();
53944
+ if (token === this.catalogToken)
53945
+ return;
53946
+ const versions = await journal.runVersions();
53947
+ for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
53948
+ await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
53949
+ this.catalogToken = token;
53842
53950
  }));
53843
53951
  }
53952
+ *catchUp(runId, version) {
53953
+ const folded = this.sequences.get(runId) ?? 0;
53954
+ if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
53955
+ return;
53956
+ if (version !== undefined && folded > 0 && version.seq > folded) {
53957
+ const entries = yield* this.entries(runId, folded);
53958
+ if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
53959
+ for (const entry of entries)
53960
+ this.fold(entry);
53961
+ return;
53962
+ }
53963
+ }
53964
+ yield* this.rebuild(runId);
53965
+ }
53844
53966
  async prepareWorkflowCatalog() {
53845
53967
  await this.hydrateResumableWorkflows();
53846
53968
  return this.projection.prepareWorkflowCatalog();
@@ -53858,6 +53980,7 @@ class JournalDurableBackend {
53858
53980
  }
53859
53981
  this.leases.delete(runId);
53860
53982
  this.sequences.delete(runId);
53983
+ this.foldedAt.delete(runId);
53861
53984
  this.prompts.delete(runId);
53862
53985
  this.projection.deleteWorkflow(runId);
53863
53986
  }
@@ -53950,7 +54073,7 @@ class JournalDurableBackend {
53950
54073
  }
53951
54074
  async withWorkflowLease(runId, action) {
53952
54075
  this.ensureOpen();
53953
- this.assertExecutionActive(runId);
54076
+ this.assertExecutionActive();
53954
54077
  const context = this.executionContext.getStore();
53955
54078
  const active = this.executions.get(runId);
53956
54079
  if (active !== undefined && context?.get(runId) !== active)
@@ -53985,7 +54108,7 @@ class JournalDurableBackend {
53985
54108
  return this.serialize(runId, () => this.release(runId, execution), false);
53986
54109
  }
53987
54110
  releaseWorkflow(runId) {
53988
- this.assertExecutionActive(runId);
54111
+ this.assertExecutionActive();
53989
54112
  return this.serialize(runId, () => this.release(runId));
53990
54113
  }
53991
54114
  *release(runId, execution) {
@@ -54078,6 +54201,10 @@ var LEGACY_COLUMNS = {
54078
54201
  var PENDING_LEGACY_RUNS = `SELECT ${JOURNAL_COLUMNS.runId}, ${JOURNAL_COLUMNS.headerJson}, ${JOURNAL_COLUMNS.status} FROM ${JOURNAL_TABLES.runs}
54079
54202
  WHERE ${JOURNAL_COLUMNS.runId} NOT IN (SELECT ${JOURNAL_COLUMNS.runId} FROM ${CURRENT.runs})
54080
54203
  AND ${JOURNAL_COLUMNS.runId} NOT IN (SELECT ${JOURNAL_COLUMNS.runId} FROM ${CURRENT.legacyDeleted})`;
54204
+ function latestEventColumns(events, runs) {
54205
+ 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}`;
54206
+ return `${latest(JOURNAL_COLUMNS.seq)}, ${latest(JOURNAL_COLUMNS.at)}`;
54207
+ }
54081
54208
  async function hasLegacyTable(tx, table) {
54082
54209
  const columns = await tx.all("SELECT name FROM pragma_table_info(?)", JOURNAL_TABLES[table]);
54083
54210
  const names = new Set(columns.map((column) => column.name));
@@ -54111,6 +54238,9 @@ class LegacyJournalRuns {
54111
54238
  async find(executor, runId) {
54112
54239
  return executor.get(`${PENDING_LEGACY_RUNS} AND ${JOURNAL_COLUMNS.runId} = ?`, runId);
54113
54240
  }
54241
+ async versions(executor) {
54242
+ return executor.all(`SELECT pending.${JOURNAL_COLUMNS.runId}, ${latestEventColumns(JOURNAL_TABLES.events, "pending")} FROM (${PENDING_LEGACY_RUNS}) AS pending`);
54243
+ }
54114
54244
  async events(executor, runId, fromSeq, limit) {
54115
54245
  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
54246
  }
@@ -54161,6 +54291,10 @@ class SqlRunJournal {
54161
54291
  this.database = database;
54162
54292
  this.tables = tables;
54163
54293
  this.legacy = legacy;
54294
+ registerRunJournalVersions(this, {
54295
+ changeToken: () => this.changeToken(),
54296
+ runVersions: () => this.runVersions()
54297
+ });
54164
54298
  }
54165
54299
  static async open(database, options = {}) {
54166
54300
  const t = renderStorageIdentifiers2("journal", JOURNAL_TABLES, options.prefix);
@@ -54259,6 +54393,27 @@ class SqlRunJournal {
54259
54393
  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
54394
  });
54261
54395
  }
54396
+ async changeToken() {
54397
+ this.assertOpen();
54398
+ return this.operation(async () => {
54399
+ const row = await this.database.get(`SELECT data_version, total_changes() AS changes,
54400
+ (SELECT count(*) FROM ${this.tables.runs}) AS runs,
54401
+ (SELECT max(rowid) FROM ${this.tables.events}) AS last_event
54402
+ FROM pragma_data_version`);
54403
+ return JSON.stringify(Object.values(row ?? {}).map(String));
54404
+ });
54405
+ }
54406
+ async runVersions() {
54407
+ this.assertOpen();
54408
+ return this.operation(async () => {
54409
+ const rows = await this.database.all(`SELECT runs.${JOURNAL_COLUMNS.runId}, ${latestEventColumns(this.tables.events, "runs")} FROM ${this.tables.runs} AS runs`);
54410
+ const legacy = await this.legacy?.versions(this.database) ?? [];
54411
+ return new Map([...rows, ...legacy].map((row) => [
54412
+ row[JOURNAL_COLUMNS.runId],
54413
+ { seq: journalCounter(row[JOURNAL_COLUMNS.runId], "seq", row[JOURNAL_COLUMNS.seq]), at: Number(row[JOURNAL_COLUMNS.at]) }
54414
+ ]));
54415
+ });
54416
+ }
54262
54417
  async requireRun(tx, runId) {
54263
54418
  if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
54264
54419
  return;
@@ -55656,6 +55811,10 @@ function deriveInputFields(schema) {
55656
55811
 
55657
55812
  // dist/builtin/workflows/src/runs/shared/validate-inputs.ts
55658
55813
  import { Value as Value2 } from "typebox/value";
55814
+ function firstSchemaError(def, value2, kind) {
55815
+ const first = [...Value2.Errors(def, value2)][0];
55816
+ return first === undefined ? `does not match ${kind} schema` : first.message;
55817
+ }
55659
55818
  function validateInputs(schema, inputs) {
55660
55819
  const errors = [];
55661
55820
  for (const key of Object.keys(inputs)) {
@@ -55684,12 +55843,16 @@ function validateInputs(schema, inputs) {
55684
55843
  if (typeof value2 !== "number" || !Number.isFinite(value2)) {
55685
55844
  errors.push({ key, reason: `expected finite number, got ${workflowSerializableTypeName(value2)}` });
55686
55845
  hasTypeError = true;
55846
+ } else if (!Value2.Check(def, value2)) {
55847
+ errors.push({ key, reason: firstSchemaError(def, value2, kind) });
55687
55848
  }
55688
55849
  break;
55689
55850
  case "integer":
55690
55851
  if (typeof value2 !== "number" || !Number.isInteger(value2)) {
55691
55852
  errors.push({ key, reason: `expected integer, got ${workflowSerializableTypeName(value2)}` });
55692
55853
  hasTypeError = true;
55854
+ } else if (!Value2.Check(def, value2)) {
55855
+ errors.push({ key, reason: firstSchemaError(def, value2, kind) });
55693
55856
  }
55694
55857
  break;
55695
55858
  case "boolean":
@@ -55860,6 +56023,20 @@ function resolve_budget(layers) {
55860
56023
  var DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES = 15;
55861
56024
  var WORKFLOW_HEARTBEAT_CUSTOM_TYPE = "workflows:workflow-heartbeat";
55862
56025
 
56026
+ // dist/builtin/workflows/src/shared/workflow-source.ts
56027
+ var WORKFLOW_SOURCES = new WeakMap;
56028
+ var OWN_MODULE_PATH = normalizeStackPath(import.meta.url);
56029
+ function isWorkflowRuntimeModule(path) {
56030
+ const normalized = normalizeStackPath(path);
56031
+ return normalized === OWN_MODULE_PATH || isWorkflowRuntimeFrame(normalized);
56032
+ }
56033
+ function recordWorkflowSource(definition, path) {
56034
+ WORKFLOW_SOURCES.set(definition, path);
56035
+ }
56036
+ function workflowSource(definition) {
56037
+ return WORKFLOW_SOURCES.get(definition);
56038
+ }
56039
+
55863
56040
  // dist/builtin/workflows/src/workflows/identity.ts
55864
56041
  function normalizeWorkflowName(name) {
55865
56042
  if (!name || typeof name !== "string") {
@@ -55907,8 +56084,10 @@ function isWorkflowAuthoringImplementationFrame(filePath) {
55907
56084
  return false;
55908
56085
  return normalized.includes("/packages/workflows/") || normalized.includes("/dist/builtin/workflows/") || normalized.includes("/.atomic/agent/extensions/workflows/");
55909
56086
  }
55910
- function workflowNameFromCaller() {
55911
- const stack = new Error().stack;
56087
+ function callerSourcePath(entry) {
56088
+ const capture = new Error;
56089
+ Error.captureStackTrace(capture, entry);
56090
+ const stack = capture.stack;
55912
56091
  if (stack === undefined)
55913
56092
  return;
55914
56093
  for (const line of stack.split(`
@@ -55918,14 +56097,18 @@ function workflowNameFromCaller() {
55918
56097
  continue;
55919
56098
  if (isWorkflowAuthoringImplementationFrame(filePath))
55920
56099
  continue;
55921
- const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
55922
- if (base.length > 0)
55923
- return base;
56100
+ return isWorkflowRuntimeModule(filePath) ? undefined : filePath;
55924
56101
  }
55925
56102
  return;
55926
56103
  }
55927
- function resolveWorkflowName(name) {
55928
- const resolved = name ?? workflowNameFromCaller();
56104
+ function workflowNameFromSourcePath(filePath) {
56105
+ if (filePath === undefined)
56106
+ return;
56107
+ const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
56108
+ return base.length > 0 ? base : undefined;
56109
+ }
56110
+ function resolveWorkflowName(name, sourcePath) {
56111
+ const resolved = name ?? workflowNameFromSourcePath(sourcePath);
55929
56112
  if (resolved === undefined) {
55930
56113
  throw new TypeError("workflow: name must be provided when caller filename cannot be inferred");
55931
56114
  }
@@ -55961,7 +56144,8 @@ function workflow(spec) {
55961
56144
  throw new TypeError("workflow: heartbeatIntervalMinutes must be a non-negative finite number");
55962
56145
  }
55963
56146
  assertWorkflowBudget(spec.budget, "workflow: budget");
55964
- const name = resolveWorkflowName(spec.name);
56147
+ const source = callerSourcePath(workflow);
56148
+ const name = resolveWorkflowName(spec.name, source);
55965
56149
  const normalizedName = normalizeWorkflowName(name);
55966
56150
  requireNonEmptyString(normalizedName, "normalized name");
55967
56151
  const frozenInputs = freezeSchemaMap(spec.inputs ?? {});
@@ -55983,6 +56167,8 @@ function workflow(spec) {
55983
56167
  run
55984
56168
  };
55985
56169
  const branded = stampWorkflowDefinition(definition);
56170
+ if (source !== undefined)
56171
+ recordWorkflowSource(branded, source);
55986
56172
  return Object.freeze(branded);
55987
56173
  }
55988
56174
 
@@ -60197,7 +60383,12 @@ async function mapParallelSteps(steps, concurrency, failFast, mapper, onFirstFai
60197
60383
  if (selectedFailure !== undefined)
60198
60384
  throw selectedFailure;
60199
60385
  }
60200
- throw new AggregateError(failures.map((failure) => failure.error), `atomic-workflows: ${failures.length} parallel ${failures.length === 1 ? "step" : "steps"} failed`);
60386
+ const aggregate = new AggregateError(failures.map((failure) => failure.error), `atomic-workflows: ${failures.length} parallel ${failures.length === 1 ? "step" : "steps"} failed`);
60387
+ if (failFastEnabled)
60388
+ throw aggregate;
60389
+ const failedIndexes = new Set(failures.map((failure) => failure.index));
60390
+ const partialResults = Array.from({ length: steps.length }, (_, index) => failedIndexes.has(index) ? undefined : results[index]);
60391
+ throw Object.assign(aggregate, { partialResults });
60201
60392
  }
60202
60393
  return results;
60203
60394
  }
@@ -61672,13 +61863,24 @@ class ConcurrencyLimiter {
61672
61863
  get queued() {
61673
61864
  return this._queue.length;
61674
61865
  }
61675
- acquire() {
61866
+ acquire(signal) {
61867
+ if (signal?.aborted)
61868
+ return Promise.reject(signal.reason);
61676
61869
  if (this._running < this.limit) {
61677
61870
  this._running++;
61678
61871
  return Promise.resolve();
61679
61872
  }
61680
- return new Promise((resolve) => {
61681
- this._queue.push(resolve);
61873
+ return new Promise((resolve, reject) => {
61874
+ const grant = () => {
61875
+ signal?.removeEventListener("abort", onAbort);
61876
+ resolve();
61877
+ };
61878
+ const onAbort = () => {
61879
+ this._queue.splice(this._queue.indexOf(grant), 1);
61880
+ reject(signal?.reason);
61881
+ };
61882
+ this._queue.push(grant);
61883
+ signal?.addEventListener("abort", onAbort, { once: true });
61682
61884
  });
61683
61885
  }
61684
61886
  release() {
@@ -61689,8 +61891,8 @@ class ConcurrencyLimiter {
61689
61891
  this._running--;
61690
61892
  }
61691
61893
  }
61692
- async run(fn) {
61693
- await this.acquire();
61894
+ async run(fn, signal) {
61895
+ await this.acquire(signal);
61694
61896
  try {
61695
61897
  return await fn();
61696
61898
  } finally {
@@ -63415,6 +63617,7 @@ function createWorkflowExitManager(input) {
63415
63617
  ...outputSnapshot !== undefined ? { outputSnapshot } : {},
63416
63618
  ...validationError !== undefined ? { validationError } : {}
63417
63619
  }));
63620
+ input.onExitSelected?.(selectedExit);
63418
63621
  input.controller.abort(selectedExit);
63419
63622
  runWorkflowExitCleanups(reason);
63420
63623
  throw selectedExit;
@@ -64226,14 +64429,40 @@ function createChildWorkflowRunner(input) {
64226
64429
  }
64227
64430
  };
64228
64431
  }
64432
+ // dist/builtin/workflows/src/shared/error-with-causes.ts
64433
+ var MAX_CAUSE_DEPTH = 5;
64434
+ function describeErrorWithCauses(error) {
64435
+ const messages = [];
64436
+ const visited = new Set;
64437
+ let current = error;
64438
+ for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH && !visited.has(current); depth++) {
64439
+ visited.add(current);
64440
+ const message = current instanceof Error ? current.message : String(current);
64441
+ if (!messages.includes(message))
64442
+ messages.push(message);
64443
+ current = current instanceof Error ? current.cause : undefined;
64444
+ }
64445
+ return messages.join(": ");
64446
+ }
64447
+
64229
64448
  // dist/builtin/workflows/src/engine/run-durable-finalize.ts
64230
64449
  async function finalizeDurableTerminalStatus(input) {
64450
+ try {
64451
+ await commitDurableTerminalStatus(input);
64452
+ } catch (error) {
64453
+ if (input.store !== undefined)
64454
+ recordDurableEndingFailure(input.store, input.runSnapshot, error);
64455
+ throw error;
64456
+ }
64457
+ }
64458
+ async function commitDurableTerminalStatus(input) {
64231
64459
  if (!input.isRoot)
64232
64460
  return;
64233
64461
  const status = effectiveRunStatus(input.runSnapshot);
64234
64462
  const isExitTerminal = input.runSnapshot.exited === true && status !== "running";
64235
64463
  const isBlocked = status === "blocked" && (input.runSnapshot.endedAt !== undefined || input.runSnapshot.blockedAt !== undefined);
64236
- if (status !== "failed" && status !== "killed" && !isExitTerminal && !isBlocked)
64464
+ const isUncommittedCompletion = status === "completed" && input.terminalStatusCommitted === false;
64465
+ if (status !== "failed" && status !== "killed" && !isExitTerminal && !isBlocked && !isUncommittedCompletion)
64237
64466
  return;
64238
64467
  const durableStatus = toDurableStatus(status);
64239
64468
  if (durableStatus !== undefined) {
@@ -64243,7 +64472,7 @@ async function finalizeDurableTerminalStatus(input) {
64243
64472
  if (input.runSnapshot.result !== undefined)
64244
64473
  throw error;
64245
64474
  }
64246
- if (durableStatus === "failed" || durableStatus === "blocked") {
64475
+ if (durableStatus === "failed" || durableStatus === "blocked" || isUncommittedCompletion) {
64247
64476
  await recordRunTimingCheckpointAsync(input.durableBackend, input.runSnapshot);
64248
64477
  }
64249
64478
  const failure = durableStatus === "failed" ? {
@@ -64261,6 +64490,16 @@ async function finalizeDurableTerminalStatus(input) {
64261
64490
  await input.durableBackend.commitWorkflowStatus(input.runId, durableStatus, undefined, input.runSnapshot.resumable, failure);
64262
64491
  }
64263
64492
  }
64493
+ function recordDurableEndingFailure(store, runSnapshot, error) {
64494
+ const detail = describeErrorWithCauses(error);
64495
+ store.recordNotice({
64496
+ id: `workflow-durable-ending-failed:${runSnapshot.id}`,
64497
+ runId: runSnapshot.id,
64498
+ level: "error",
64499
+ 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.`,
64500
+ createdAt: Date.now()
64501
+ });
64502
+ }
64264
64503
  function toDurableStatus(status) {
64265
64504
  switch (status) {
64266
64505
  case "completed":
@@ -64648,6 +64887,402 @@ function deferStageUntilRunRelease(input) {
64648
64887
  };
64649
64888
  }
64650
64889
 
64890
+ // dist/builtin/workflows/src/engine/run-rejection-boundary.ts
64891
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
64892
+ import { inspect } from "node:util";
64893
+ var EVENT = "unhandledRejection";
64894
+ var BOUNDARY_KEY = Symbol.for("atomic-workflows/run-rejection-boundary@5");
64895
+ var FLAG = "--unhandled-rejections";
64896
+ var MAX_CAUSE_DEPTH2 = 8;
64897
+ var MAX_PRIMITIVES_PER_RUN = 64;
64898
+ var MAX_STOP_STRINGS = 64;
64899
+ var ENDED_RUN_GRACE_MS = 30000;
64900
+ var NATIVE_REPORTING_MODES = new Set(["throw", "warn-with-error-code"]);
64901
+ function boundaryBag() {
64902
+ return globalThis;
64903
+ }
64904
+ function sharedBoundary() {
64905
+ const bag = boundaryBag();
64906
+ const existing = bag[BOUNDARY_KEY];
64907
+ if (existing !== undefined && existing.version === 5)
64908
+ return existing;
64909
+ const created = {
64910
+ version: 5,
64911
+ store: new AsyncLocalStorage3,
64912
+ owners: new WeakMap,
64913
+ promises: new WeakMap,
64914
+ scopes: new Set,
64915
+ runs: new Map,
64916
+ ended: new Map,
64917
+ stops: new Set,
64918
+ listener: undefined
64919
+ };
64920
+ bag[BOUNDARY_KEY] = created;
64921
+ return created;
64922
+ }
64923
+ function isObject(value2) {
64924
+ return typeof value2 === "object" && value2 !== null || typeof value2 === "function";
64925
+ }
64926
+ function isPrimitive(value2) {
64927
+ return !isObject(value2);
64928
+ }
64929
+ function safeField3(value2, key) {
64930
+ try {
64931
+ return value2[key];
64932
+ } catch {
64933
+ return;
64934
+ }
64935
+ }
64936
+ function strongerEffect(left, right) {
64937
+ return left === "fail-run" || right === "fail-run" ? "fail-run" : "ignore";
64938
+ }
64939
+ function addAttribution(into, scope, effect) {
64940
+ into.set(scope, strongerEffect(into.get(scope), effect));
64941
+ }
64942
+ function recordedOwners(boundary, reason) {
64943
+ const owners = new Map;
64944
+ let stopped = false;
64945
+ const seen = new Set;
64946
+ const pending = [{ value: reason, depth: 0 }];
64947
+ while (pending.length > 0) {
64948
+ const { value: value2, depth } = pending.pop();
64949
+ if (depth > MAX_CAUSE_DEPTH2)
64950
+ continue;
64951
+ if (isPrimitive(value2)) {
64952
+ if (depth === 0 || value2 !== undefined && value2 !== null) {
64953
+ for (const scope of boundary.scopes) {
64954
+ const entry = scope.primitives.get(value2);
64955
+ if (entry !== undefined)
64956
+ addAttribution(owners, scope, entry.effect);
64957
+ }
64958
+ if (typeof value2 === "string" && boundary.stops.has(value2))
64959
+ stopped = true;
64960
+ }
64961
+ continue;
64962
+ }
64963
+ if (seen.has(value2))
64964
+ continue;
64965
+ seen.add(value2);
64966
+ for (const [scope, effect] of boundary.owners.get(value2) ?? [])
64967
+ addAttribution(owners, scope, effect);
64968
+ pending.push({ value: safeField3(value2, "cause"), depth: depth + 1 });
64969
+ const errors = safeField3(value2, "errors");
64970
+ if (Array.isArray(errors))
64971
+ for (const entry of errors)
64972
+ pending.push({ value: entry, depth: depth + 1 });
64973
+ }
64974
+ return { owners, stopped };
64975
+ }
64976
+ function pruneEndedSources(boundary) {
64977
+ const now = Date.now();
64978
+ for (const [source, trees] of boundary.ended) {
64979
+ for (const [rootRunId, endedAt] of trees)
64980
+ if (now - endedAt > ENDED_RUN_GRACE_MS)
64981
+ trees.delete(rootRunId);
64982
+ if (trees.size === 0)
64983
+ boundary.ended.delete(source);
64984
+ }
64985
+ }
64986
+ function recordEndedRun(boundary, scope) {
64987
+ if (scope.source === undefined)
64988
+ return;
64989
+ const trees = boundary.ended.get(scope.source) ?? new Map;
64990
+ trees.set(scope.rootRunId, Date.now());
64991
+ boundary.ended.set(scope.source, trees);
64992
+ }
64993
+ function endedInAnotherRunTree(boundary, source, live) {
64994
+ for (const endedRoot of boundary.ended.get(source)?.keys() ?? [])
64995
+ if (endedRoot !== live.rootRunId)
64996
+ return true;
64997
+ return false;
64998
+ }
64999
+ function recognizedSources(boundary) {
65000
+ pruneEndedSources(boundary);
65001
+ const sources = new Set(boundary.ended.keys());
65002
+ for (const scope of boundary.scopes)
65003
+ if (scope.live && scope.source !== undefined)
65004
+ sources.add(scope.source);
65005
+ return sources;
65006
+ }
65007
+ function authoringSource(reason, sources) {
65008
+ if (sources.size === 0 || !isObject(reason))
65009
+ return;
65010
+ const stack = safeField3(reason, "stack");
65011
+ if (typeof stack !== "string")
65012
+ return;
65013
+ for (const line of stack.split(`
65014
+ `)) {
65015
+ if (!line.trimStart().startsWith("at "))
65016
+ continue;
65017
+ const path = parsePromptStackFrame(line)?.normalizedPath;
65018
+ if (path === undefined)
65019
+ continue;
65020
+ if (isWorkflowRuntimeModule(path))
65021
+ return;
65022
+ if (/\/node_modules\//.test(path))
65023
+ continue;
65024
+ if (sources.has(path))
65025
+ return path;
65026
+ }
65027
+ return;
65028
+ }
65029
+ function hasAncestorIn(scope, candidates) {
65030
+ for (let ancestor = scope.parent;ancestor !== undefined; ancestor = ancestor.parent) {
65031
+ if (candidates.has(ancestor))
65032
+ return true;
65033
+ }
65034
+ return false;
65035
+ }
65036
+ function outermostLiveRuns(boundary, source) {
65037
+ const matching = new Set;
65038
+ for (const scope of boundary.scopes)
65039
+ if (scope.live && scope.source === source)
65040
+ matching.add(scope);
65041
+ const outermost = new Set;
65042
+ for (const scope of matching)
65043
+ if (!hasAncestorIn(scope, matching))
65044
+ outermost.add(scope);
65045
+ return outermost;
65046
+ }
65047
+ function runOfSource(boundary, source) {
65048
+ const [only, ...others] = outermostLiveRuns(boundary, source);
65049
+ if (only === undefined)
65050
+ return new Map;
65051
+ if (others.length > 0 || only.sharedSource)
65052
+ return;
65053
+ if (endedInAnotherRunTree(boundary, source, only))
65054
+ return;
65055
+ return new Map([[only, "fail-run"]]);
65056
+ }
65057
+ function markSharedSource(boundary, source) {
65058
+ const runs = outermostLiveRuns(boundary, source);
65059
+ if (runs.size > 1)
65060
+ for (const run of runs)
65061
+ run.sharedSource = true;
65062
+ }
65063
+ function rejectingRun(boundary, recorded, promise, scoped) {
65064
+ const tracked = promise === undefined ? undefined : boundary.promises.get(promise);
65065
+ if (tracked !== undefined && recorded.has(tracked))
65066
+ return tracked;
65067
+ if (scoped !== undefined && recorded.has(scoped))
65068
+ return scoped;
65069
+ return;
65070
+ }
65071
+ function attribute(boundary, reason, promise) {
65072
+ const { owners: recorded, stopped } = recordedOwners(boundary, reason);
65073
+ const scoped = boundary.store.getStore();
65074
+ if (recorded.size > 1) {
65075
+ const rejecting = rejectingRun(boundary, recorded, promise, scoped);
65076
+ if (rejecting !== undefined)
65077
+ return new Map([[rejecting, recorded.get(rejecting) ?? "fail-run"]]);
65078
+ }
65079
+ if (recorded.size > 0)
65080
+ return recorded;
65081
+ if (stopped)
65082
+ return new Map;
65083
+ if (scoped !== undefined && boundary.scopes.has(scoped))
65084
+ return new Map([[scoped, "fail-run"]]);
65085
+ const origin = authoringSource(reason, recognizedSources(boundary));
65086
+ if (origin === undefined)
65087
+ return;
65088
+ if (scoped !== undefined)
65089
+ return new Map([[scoped, "ignore"]]);
65090
+ return runOfSource(boundary, origin);
65091
+ }
65092
+ function unhandledRejectionError(reason) {
65093
+ return Object.assign(new Error("This error originated either by throwing inside of an async function without a catch block, " + `or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "${inspect(reason)}".`), { code: "ERR_UNHANDLED_REJECTION" });
65094
+ }
65095
+ function unhandledRejectionsMode() {
65096
+ const args = [...(process.env.NODE_OPTIONS ?? "").split(/\s+/), ...process.execArgv];
65097
+ let mode = "throw";
65098
+ for (let index = 0;index < args.length; index += 1) {
65099
+ const arg = args[index] ?? "";
65100
+ if (arg.startsWith(`${FLAG}=`))
65101
+ mode = arg.slice(FLAG.length + 1);
65102
+ else if (arg === FLAG && args[index + 1] !== undefined)
65103
+ mode = args[index + 1] ?? mode;
65104
+ }
65105
+ return mode;
65106
+ }
65107
+ function surfaceNatively(boundary, reason) {
65108
+ const listener = boundary.listener;
65109
+ if (listener === undefined || process.listenerCount(EVENT) > 1)
65110
+ return;
65111
+ if (!NATIVE_REPORTING_MODES.has(unhandledRejectionsMode()))
65112
+ return;
65113
+ process.nextTick(() => {
65114
+ process.removeListener(EVENT, listener);
65115
+ Promise.reject(reason);
65116
+ setImmediate(() => {
65117
+ if (!process.listeners(EVENT).includes(listener))
65118
+ process.on(EVENT, listener);
65119
+ });
65120
+ });
65121
+ }
65122
+ function onUnhandledRejection(reason, promise) {
65123
+ const boundary = sharedBoundary();
65124
+ const owners = attribute(boundary, reason, promise);
65125
+ if (owners === undefined) {
65126
+ surfaceNatively(boundary, reason);
65127
+ return;
65128
+ }
65129
+ const error = isObject(reason) ? reason : unhandledRejectionError(reason);
65130
+ for (const [scope, effect] of owners) {
65131
+ if (effect !== "fail-run" || !scope.live)
65132
+ continue;
65133
+ try {
65134
+ scope.fail(error);
65135
+ } catch {}
65136
+ }
65137
+ }
65138
+ function ensureInstalled(boundary) {
65139
+ if (boundary.listener !== undefined)
65140
+ return;
65141
+ boundary.listener = onUnhandledRejection;
65142
+ process.on(EVENT, onUnhandledRejection);
65143
+ }
65144
+ function record(boundary, scope, reason, effect) {
65145
+ if (isPrimitive(reason)) {
65146
+ recordPrimitive(scope, reason, effect);
65147
+ return;
65148
+ }
65149
+ const owners = boundary.owners.get(reason);
65150
+ if (owners === undefined)
65151
+ boundary.owners.set(reason, new Map([[scope, effect]]));
65152
+ else
65153
+ addAttribution(owners, scope, effect);
65154
+ }
65155
+ function recordStop(boundary, reason) {
65156
+ boundary.stops.delete(reason);
65157
+ boundary.stops.add(reason);
65158
+ if (boundary.stops.size <= MAX_STOP_STRINGS)
65159
+ return;
65160
+ const oldest = boundary.stops.values().next();
65161
+ if (!oldest.done)
65162
+ boundary.stops.delete(oldest.value);
65163
+ }
65164
+ function recordPrimitive(scope, reason, effect) {
65165
+ if (!scope.live)
65166
+ return;
65167
+ if (scope.primitives.size >= MAX_PRIMITIVES_PER_RUN && !scope.primitives.has(reason)) {
65168
+ const oldest = scope.primitives.keys().next();
65169
+ if (!oldest.done)
65170
+ scope.primitives.delete(oldest.value);
65171
+ }
65172
+ scope.generation += 1;
65173
+ const generation = scope.generation;
65174
+ scope.primitives.set(reason, { effect: strongerEffect(scope.primitives.get(reason)?.effect, effect), generation });
65175
+ afterPendingRejectionReports().then(() => {
65176
+ if (scope.primitives.get(reason)?.generation === generation)
65177
+ scope.primitives.delete(reason);
65178
+ });
65179
+ }
65180
+ function discardFailure() {}
65181
+ function afterPendingRejectionReports() {
65182
+ return new Promise((resolve) => {
65183
+ const { port1, port2 } = new MessageChannel;
65184
+ port1.onmessage = () => {
65185
+ port1.close();
65186
+ port2.close();
65187
+ resolve();
65188
+ };
65189
+ port2.postMessage(undefined);
65190
+ });
65191
+ }
65192
+ function openRunRejectionScope(options) {
65193
+ const boundary = sharedBoundary();
65194
+ ensureInstalled(boundary);
65195
+ pruneEndedSources(boundary);
65196
+ const parent = options.parentRunId === undefined ? undefined : boundary.runs.get(options.parentRunId);
65197
+ const scope = {
65198
+ runId: options.runId,
65199
+ rootRunId: parent?.rootRunId ?? options.runId,
65200
+ source: options.source === undefined ? undefined : normalizeStackPath(options.source),
65201
+ parent,
65202
+ fail: options.fail,
65203
+ primitives: new Map,
65204
+ generation: 0,
65205
+ live: true,
65206
+ sharedSource: false
65207
+ };
65208
+ boundary.scopes.add(scope);
65209
+ boundary.runs.set(scope.runId, scope);
65210
+ if (scope.source !== undefined)
65211
+ markSharedSource(boundary, scope.source);
65212
+ return {
65213
+ run: (callback) => boundary.store.run(scope, callback),
65214
+ contain: (promise, effect = "fail-run") => {
65215
+ boundary.promises.set(promise, scope);
65216
+ promise.then(undefined, (reason) => record(boundary, scope, reason, effect));
65217
+ return promise;
65218
+ },
65219
+ watch: (promise) => {
65220
+ const watched = promise.then(undefined, (reason) => {
65221
+ record(boundary, scope, reason, "fail-run");
65222
+ throw reason;
65223
+ });
65224
+ boundary.promises.set(watched, scope);
65225
+ return watched;
65226
+ },
65227
+ ignore: (reason) => {
65228
+ if (typeof reason === "string")
65229
+ recordStop(boundary, reason);
65230
+ else
65231
+ record(boundary, scope, reason, "ignore");
65232
+ },
65233
+ settle: afterPendingRejectionReports,
65234
+ close: () => {
65235
+ scope.live = false;
65236
+ scope.fail = discardFailure;
65237
+ recordEndedRun(boundary, scope);
65238
+ afterPendingRejectionReports().then(() => {
65239
+ scope.primitives.clear();
65240
+ scope.parent = undefined;
65241
+ boundary.scopes.delete(scope);
65242
+ if (boundary.runs.get(scope.runId) === scope)
65243
+ boundary.runs.delete(scope.runId);
65244
+ });
65245
+ }
65246
+ };
65247
+ }
65248
+ var WATCHED_STAGE_METHODS = [
65249
+ "prompt",
65250
+ "complete",
65251
+ "sendUserMessage",
65252
+ "steer",
65253
+ "followUp",
65254
+ "setModel",
65255
+ "setThinkingLevel",
65256
+ "cycleModel",
65257
+ "cycleThinkingLevel",
65258
+ "navigateTree",
65259
+ "compact",
65260
+ "abort"
65261
+ ];
65262
+ function containStageRejections(stage, scope) {
65263
+ const contained = Object.create(stage);
65264
+ const descriptors = {};
65265
+ for (const name of WATCHED_STAGE_METHODS) {
65266
+ descriptors[name] = {
65267
+ value: (...args) => {
65268
+ const result = Reflect.apply(stage[name], stage, args);
65269
+ return result instanceof Promise ? scope.watch(result) : result;
65270
+ }
65271
+ };
65272
+ }
65273
+ Object.defineProperties(contained, descriptors);
65274
+ return contained;
65275
+ }
65276
+ function containUiRejections(ui, scope) {
65277
+ return {
65278
+ input: (prompt) => scope.watch(ui.input(prompt)),
65279
+ confirm: (message) => scope.watch(ui.confirm(message)),
65280
+ select: (message, options) => scope.watch(ui.select(message, options)),
65281
+ editor: (initial) => scope.watch(ui.editor(initial)),
65282
+ custom: (factory, options) => scope.watch(ui.custom(factory, options))
65283
+ };
65284
+ }
65285
+
64651
65286
  // dist/builtin/workflows/src/engine/run-returned-status.ts
64652
65287
  function classifyReturnedRunStatus(result, runSnapshot) {
64653
65288
  const structuredFailure = runSnapshot !== undefined ? structuredRecoverableWorkflowFailure(runSnapshot) : undefined;
@@ -66638,7 +67273,9 @@ import { createStructuredOutputCapture, runCallback as runCallback2 } from "@bas
66638
67273
  import {
66639
67274
  AutoRoutingInferenceError,
66640
67275
  convertToLlm,
67276
+ isExtensionStartupFailure,
66641
67277
  isModelRoutingDebugEnabled,
67278
+ isTransientExtensionStartupFailure,
66642
67279
  parseModelConstraints,
66643
67280
  setsProviders
66644
67281
  } from "@bastani/atomic";
@@ -66909,6 +67546,23 @@ class StageDeliveryActivity {
66909
67546
  }
66910
67547
  }
66911
67548
 
67549
+ // dist/builtin/workflows/src/runs/foreground/stage-routing.ts
67550
+ var STAGE_ROUTING_CONCURRENCY = 8;
67551
+ var STAGE_ROUTING_DEADLINE_MS = 300000;
67552
+ var routingLimiter = new ConcurrencyLimiter(STAGE_ROUTING_CONCURRENCY);
67553
+ async function routeStageModel(route, input) {
67554
+ const deadline = new AbortController;
67555
+ const timer = setTimeout(() => deadline.abort(new Error("stage routing deadline")), STAGE_ROUTING_DEADLINE_MS);
67556
+ try {
67557
+ return await route({
67558
+ ...input,
67559
+ inference: { deadline: deadline.signal, limit: (run, signal) => routingLimiter.run(run, signal) }
67560
+ });
67561
+ } finally {
67562
+ clearTimeout(timer);
67563
+ }
67564
+ }
67565
+
66912
67566
  // dist/builtin/workflows/src/runs/foreground/stage-runner-artifact-capture.ts
66913
67567
  class StageArtifactCapture {
66914
67568
  session;
@@ -67399,6 +68053,7 @@ async function stripWorkflowOnlyOptions(options, defaultSessionDir, meta, pendin
67399
68053
  }
67400
68054
  const {
67401
68055
  schema: _schema,
68056
+ schemaTimeoutMs: _schemaTimeoutMs,
67402
68057
  mcp: _mcp,
67403
68058
  fallbackModels,
67404
68059
  modelConstraints: _modelConstraints,
@@ -67732,6 +68387,15 @@ class StageSessionReplacement {
67732
68387
  this.previous = undefined;
67733
68388
  await Promise.allSettled([...previous ? [disposeStageSession(previous)] : [], ...this.cleanups]);
67734
68389
  }
68390
+ async disposeRetired() {
68391
+ const previous = this.previous;
68392
+ this.previous = undefined;
68393
+ if (!previous)
68394
+ return;
68395
+ await disposeStageSession(previous).catch((error) => {
68396
+ console.error("atomic-workflows: retired stage session disposal failed", error);
68397
+ });
68398
+ }
67735
68399
  async disposeAfterIdle(session) {
67736
68400
  const agent = session.agent;
67737
68401
  if (typeof agent?.waitForIdle === "function")
@@ -67895,7 +68559,7 @@ function isWorkflowStructuredOutputContractError(error) {
67895
68559
  return error instanceof Error && "code" in error && error.code === "ATOMIC_WORKFLOW_STRUCTURED_OUTPUT_CONTRACT";
67896
68560
  }
67897
68561
  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.";
68562
+ 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
68563
  }
67900
68564
  var STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
67901
68565
  function toolResultText(content) {
@@ -67947,7 +68611,8 @@ function stageOptionsWithStructuredOutput(options, capture, executionCapture) {
67947
68611
  return options;
67948
68612
  const structuredOutputTool = createStructuredOutputTool({
67949
68613
  schema: options.schema,
67950
- capture
68614
+ capture,
68615
+ ...options.schemaTimeoutMs === undefined ? {} : { timeoutMs: options.schemaTimeoutMs }
67951
68616
  });
67952
68617
  const executeStructuredOutput = structuredOutputTool.execute;
67953
68618
  const capturedStructuredOutputTool = {
@@ -68037,6 +68702,16 @@ function waitForStageStartup(operation, signal) {
68037
68702
  // dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
68038
68703
  var WORKFLOW_STAGE_CLOSED_FOR_GOOD_STATE = "atomic:workflow-stage-closed-for-good";
68039
68704
  var WORKFLOW_STAGE_END_CHILDREN_STATE = "atomic:workflow-stage-end-children";
68705
+ function isRetryableSameCandidateFailure(error) {
68706
+ if (isExtensionStartupFailure(error))
68707
+ return isTransientExtensionStartupFailure(error);
68708
+ return isRetryableSameModelFailure(error);
68709
+ }
68710
+ function mayAdvanceToNextCandidate(error) {
68711
+ if (isExtensionStartupFailure(error))
68712
+ return isTransientExtensionStartupFailure(error);
68713
+ return isRetryableModelFailure(error);
68714
+ }
68040
68715
  function hasMeaningfulUsage(usage) {
68041
68716
  if (usage === undefined)
68042
68717
  return false;
@@ -68288,7 +68963,7 @@ class StageSessionController {
68288
68963
  return;
68289
68964
  if (!this.routingPromise) {
68290
68965
  this.beginStartup();
68291
- this.routingPromise = (async () => {
68966
+ const routing = (async () => {
68292
68967
  const route = this.modelCatalog?.routeModel;
68293
68968
  if (!route)
68294
68969
  throw new Error("Workflow stage auto routing requires a routing-capable model catalog.");
@@ -68300,7 +68975,7 @@ class StageSessionController {
68300
68975
  ...thinking === undefined ? [] : [{ allowedEfforts: [thinking] }]
68301
68976
  ].filter((c) => c !== undefined);
68302
68977
  try {
68303
- this.modelRoute = await route({
68978
+ this.modelRoute = await routeStageModel(route, {
68304
68979
  task: text,
68305
68980
  stageName: this.opts.stageName,
68306
68981
  constraints,
@@ -68321,7 +68996,17 @@ class StageSessionController {
68321
68996
  this.modelRoute.assertCurrent();
68322
68997
  this.meta.stageOptions = { ...options, model: this.modelRoute.modelOverride };
68323
68998
  this.opts.onModelFallbackMetaChange?.(this.currentModelFallbackMeta());
68324
- })();
68999
+ })().catch((error) => {
69000
+ if (this.routingPromise === routing) {
69001
+ this.routingPromise = undefined;
69002
+ this.modelRoute = undefined;
69003
+ }
69004
+ if (this.startupWait.signal.aborted || this.opts.signal?.aborted)
69005
+ throw error;
69006
+ this.settleStartup(true);
69007
+ throw new Error(`atomic-workflows: stage "${this.opts.stageName}" failed during startup phase model-resolution: ${errorMessage3(error)}`);
69008
+ });
69009
+ this.routingPromise = routing;
68325
69010
  }
68326
69011
  await this.routingPromise;
68327
69012
  }
@@ -69076,7 +69761,7 @@ class StageSessionController {
69076
69761
  const errorSettingsManager = retrySettingsManagerFromError(error);
69077
69762
  if (errorSettingsManager !== undefined)
69078
69763
  this.sessionSettingsManager = errorSettingsManager;
69079
- const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameModelFailure(error));
69764
+ const decision = isWorkflowPendingStageDeliveryFailure(error) ? undefined : nextRetryDecision(this.retrySettings(), retryAttempt, isRetryableSameCandidateFailure(error));
69080
69765
  if (decision === undefined || this.disposed || this.opts.signal?.aborted === true || this.startupWait.signal.aborted || this.capturedStructuredOutputForAttempt()) {
69081
69766
  throw error;
69082
69767
  }
@@ -69488,10 +70173,11 @@ class StageSessionController {
69488
70173
  ...usage === undefined ? {} : { usage },
69489
70174
  error: message
69490
70175
  });
69491
- if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !isRetryableModelFailure(err) || index === candidates.length - 1) {
70176
+ if (this.opts.signal?.aborted || this.startupWait.signal.aborted || terminalStageDelivery || !mayAdvanceToNextCandidate(err) || index === candidates.length - 1) {
69492
70177
  this.modelWarnings.push(...this.pendingFallbackWarnings);
69493
70178
  this.pendingFallbackWarnings.length = 0;
69494
70179
  this.notifyModelFallbackMetaChange();
70180
+ await this.replacement.disposeRetired();
69495
70181
  return "throw";
69496
70182
  }
69497
70183
  const nextCandidate = candidates[index + 1];
@@ -70613,13 +71299,13 @@ class EngineRuntime {
70613
71299
 
70614
71300
  // dist/builtin/workflows/src/engine/session-closed-error.ts
70615
71301
  import { isStaleExtensionContextError as isStaleExtensionContextError5 } from "@bastani/atomic";
70616
- var MAX_CAUSE_DEPTH = 8;
71302
+ var MAX_CAUSE_DEPTH3 = 8;
70617
71303
  function reportsClosedSession(error) {
70618
71304
  return "code" in error && error.code === "SessionClosed" || isStaleExtensionContextError5(error);
70619
71305
  }
70620
71306
  function isSessionClosedError(error) {
70621
71307
  let current = error;
70622
- for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined; depth++) {
71308
+ for (let depth = 0;depth < MAX_CAUSE_DEPTH3 && current !== undefined; depth++) {
70623
71309
  try {
70624
71310
  if (reportsClosedSession(current))
70625
71311
  return true;
@@ -70691,7 +71377,12 @@ async function executeRun(def, resolvedInputs, opts) {
70691
71377
  workflowObservationRuntime(activeStore).control(runId, "kill");
70692
71378
  ownController.abort(callerSignal?.reason);
70693
71379
  };
70694
- const exit = createWorkflowExitManager({ runId, exitScope, controller: ownController });
71380
+ const exit = createWorkflowExitManager({
71381
+ runId,
71382
+ exitScope,
71383
+ controller: ownController,
71384
+ onExitSelected: (signal) => rejectionScope.ignore(signal)
71385
+ });
70695
71386
  const sourceBackend = opts.durableBackend;
70696
71387
  const backendView = sourceBackend;
70697
71388
  const rootBackend = opts.durableRootBackend ?? backendView;
@@ -71205,6 +71896,22 @@ async function executeRun(def, resolvedInputs, opts) {
71205
71896
  baseFromPromptNodes: getPromptNodeUi
71206
71897
  });
71207
71898
  let pausedExit;
71899
+ const authoredIn = workflowSource(def);
71900
+ const rejectionScope = openRunRejectionScope({
71901
+ runId,
71902
+ ...opts.parentRun !== undefined ? { parentRunId: opts.parentRun.runId } : {},
71903
+ ...authoredIn !== undefined ? { source: authoredIn } : {},
71904
+ fail: (error) => {
71905
+ if (findWorkflowGracefulQuit(error) !== undefined)
71906
+ return;
71907
+ const selected = terminalEvents.selectFailure(error);
71908
+ if (selected.kind === "failure" && !ownController.signal.aborted)
71909
+ ownController.abort(selected.error);
71910
+ }
71911
+ });
71912
+ ownController.signal.addEventListener("abort", () => rejectionScope.ignore(ownController.signal.reason), {
71913
+ once: true
71914
+ });
71208
71915
  const ctx = {
71209
71916
  inputs: resolvedInputs,
71210
71917
  runId,
@@ -71215,28 +71922,30 @@ async function executeRun(def, resolvedInputs, opts) {
71215
71922
  if (scheduler.isRunPaused()) {
71216
71923
  pausedExit ??= whenRunning(async () => exit.exit(options));
71217
71924
  pausedExit.catch(() => {});
71218
- throw new Error("Workflow exit is waiting for explicit resume");
71925
+ const waiting = new Error("Workflow exit is waiting for explicit resume");
71926
+ rejectionScope.ignore(waiting);
71927
+ throw waiting;
71219
71928
  }
71220
71929
  return exit.exit(options);
71221
71930
  },
71222
- ui,
71931
+ ui: containUiRejections(ui, rejectionScope),
71223
71932
  stage: (name, options) => {
71224
71933
  ownController.signal.throwIfAborted();
71225
71934
  if (!scheduler.isRunPaused())
71226
- return durableStage(name, options);
71935
+ return containStageRejections(durableStage(name, options), rejectionScope);
71227
71936
  const replayKey = stageReplayKeyGenerator(name);
71228
- return deferStageUntilRunRelease({
71937
+ return containStageRejections(deferStageUntilRunRelease({
71229
71938
  name,
71230
71939
  create: () => durableStage(name, options, replayKey),
71231
71940
  isPaused: scheduler.isRunPaused,
71232
71941
  waitForRelease: waitForRunRelease,
71233
71942
  signal: ownController.signal
71234
- });
71943
+ }), rejectionScope);
71235
71944
  },
71236
- task: gatedTask,
71237
- chain: (...args) => whenRunning(() => chain(...args)),
71238
- parallel: (...args) => whenRunning(() => parallel(...args)),
71239
- workflow: (...args) => whenRunning(() => {
71945
+ task: (...args) => rejectionScope.watch(gatedTask(...args)),
71946
+ chain: (...args) => rejectionScope.watch(whenRunning(() => chain(...args))),
71947
+ parallel: (...args) => rejectionScope.watch(whenRunning(() => parallel(...args))),
71948
+ workflow: (...args) => rejectionScope.watch(whenRunning(() => {
71240
71949
  const pending = durableWorkflow(...args);
71241
71950
  pendingChildWorkflows.add(pending);
71242
71951
  const settled = () => {
@@ -71244,18 +71953,17 @@ async function executeRun(def, resolvedInputs, opts) {
71244
71953
  };
71245
71954
  pending.then(settled, settled);
71246
71955
  return pending;
71247
- }),
71956
+ })),
71248
71957
  tool: (...args) => {
71249
71958
  if (admittedTools.closed)
71250
- return tool(...args);
71251
- const pending = whenRunning(() => tool(...args));
71252
- pending.catch(() => {});
71253
- return pending;
71959
+ return rejectionScope.contain(tool(...args), "ignore");
71960
+ return rejectionScope.contain(whenRunning(() => tool(...args)));
71254
71961
  },
71255
71962
  ...opts.models !== undefined ? { models: opts.models } : {}
71256
71963
  };
71257
71964
  const runtimeSettled = Promise.withResolvers();
71258
71965
  let durableRootAdmitted = false;
71966
+ let terminalStatusCommitted = false;
71259
71967
  let pausePersistence;
71260
71968
  let resumePersistence;
71261
71969
  let controlSettlements = Promise.resolve();
@@ -71401,7 +72109,7 @@ async function executeRun(def, resolvedInputs, opts) {
71401
72109
  while (scheduler.isRunPaused())
71402
72110
  await waitForRunRelease();
71403
72111
  ownController.signal.throwIfAborted();
71404
- const rawResult = await raceAbort(runWorkflowDefinitionCallback(def.name, runId, () => def.run(ctx)), ownController.signal);
72112
+ const rawResult = await raceAbort(runWorkflowDefinitionCallback(def.name, runId, () => rejectionScope.run(() => def.run(ctx))), ownController.signal);
71405
72113
  await drainCachedStagePersistence();
71406
72114
  while (scheduler.isRunPaused())
71407
72115
  await waitForRunRelease();
@@ -71411,6 +72119,7 @@ async function executeRun(def, resolvedInputs, opts) {
71411
72119
  if (pausedExit !== undefined)
71412
72120
  await pausedExit;
71413
72121
  budget.rethrowIfSystemOwnedStop(runSnapshot.stages.at(-1)?.name ?? startupFrontierStage);
72122
+ await rejectionScope.settle();
71414
72123
  const normalTerminalEvent = terminalEvents.winner();
71415
72124
  if (normalTerminalEvent?.kind === "cancellation") {
71416
72125
  const gracefulQuit = findWorkflowGracefulQuit(normalTerminalEvent.reason);
@@ -71445,6 +72154,7 @@ async function executeRun(def, resolvedInputs, opts) {
71445
72154
  await recordRunResultCheckpointAsync(durableBackend, runSnapshot);
71446
72155
  }
71447
72156
  await durableBackend.commitWorkflowStatus(runId, returned.status, undefined, returned.metadata?.resumable);
72157
+ terminalStatusCommitted = true;
71448
72158
  await appendRunEndWhenRecorded(opts.persistence, recorded, {
71449
72159
  runId,
71450
72160
  status: returned.status,
@@ -71479,6 +72189,9 @@ async function executeRun(def, resolvedInputs, opts) {
71479
72189
  }
71480
72190
  if (ownerClosing && err instanceof Error && isSessionClosedError(err))
71481
72191
  return await suspendForClosedSession(err);
72192
+ if (selectedTerminalEvent.kind === "failure" && pendingChildWorkflows.size > 0 && !ownController.signal.aborted) {
72193
+ ownController.abort(err);
72194
+ }
71482
72195
  await admittedTools.closeAndDrain();
71483
72196
  if (ownController.signal.aborted)
71484
72197
  await Promise.allSettled([...pendingChildWorkflows]);
@@ -71553,6 +72266,7 @@ async function executeRun(def, resolvedInputs, opts) {
71553
72266
  });
71554
72267
  return failed;
71555
72268
  } finally {
72269
+ rejectionScope.close();
71556
72270
  callerSignal?.removeEventListener("abort", onCallerAbort);
71557
72271
  workflowObservationRuntime(activeStore).finishRun(runId);
71558
72272
  runtimeSettled.resolve();
@@ -71566,7 +72280,9 @@ async function executeRun(def, resolvedInputs, opts) {
71566
72280
  runId,
71567
72281
  runSnapshot,
71568
72282
  isRoot: opts.parentRun === undefined,
71569
- durableBackend
72283
+ durableBackend,
72284
+ terminalStatusCommitted,
72285
+ store: activeStore
71570
72286
  });
71571
72287
  }
71572
72288
  } finally {
@@ -71645,11 +72361,17 @@ function runDetached(def, inputs, opts = {}) {
71645
72361
  opts.onWorkflowStartReady?.();
71646
72362
  }
71647
72363
  };
71648
- let settleJob = () => {};
71649
- const voidPromise = new Promise((resolve) => {
71650
- settleJob = resolve;
71651
- });
71652
- const jobEntry = { runId, controller, promise: voidPromise };
72364
+ const jobSettled = Promise.withResolvers();
72365
+ const jobOutcome = Promise.withResolvers();
72366
+ jobOutcome.promise.catch(() => {});
72367
+ const settleJob = (failure) => {
72368
+ jobSettled.resolve();
72369
+ if (failure === undefined)
72370
+ jobOutcome.resolve();
72371
+ else
72372
+ jobOutcome.reject(failure.error);
72373
+ };
72374
+ const jobEntry = { runId, controller, promise: jobSettled.promise, outcome: jobOutcome.promise };
71653
72375
  try {
71654
72376
  opts.startupSignal?.addEventListener("abort", cancelStartup, { once: true });
71655
72377
  registry.register(runId, controller);
@@ -71697,6 +72419,7 @@ function runDetached(def, inputs, opts = {}) {
71697
72419
  throw error;
71698
72420
  }
71699
72421
  const settle = async (...args) => {
72422
+ const [ok, , error] = args;
71700
72423
  try {
71701
72424
  if (!observed)
71702
72425
  await observe(...args);
@@ -71704,7 +72427,7 @@ function runDetached(def, inputs, opts = {}) {
71704
72427
  detachStartup();
71705
72428
  registry.unregister(runId, controller);
71706
72429
  tracker.unregister(runId, jobEntry);
71707
- settleJob();
72430
+ settleJob(ok ? undefined : { error });
71708
72431
  }
71709
72432
  };
71710
72433
  backgroundPromise.then((result) => {
@@ -72658,11 +73381,17 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
72658
73381
  retainReachableRunGroups(grouped, rootRunId);
72659
73382
  if (policy.failOnUnreachable && grouped.size !== groupedCount)
72660
73383
  return [];
72661
- if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints))
73384
+ if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints, policy.retainActive))
72662
73385
  return [];
72663
73386
  const syntheticChildren = [];
73387
+ const pendingChildren = [];
72664
73388
  for (const [parentRunId, runDrafts] of grouped) {
72665
73389
  for (const draft of runDrafts) {
73390
+ const pendingChildRunId = childRunIdFromDraft(draft);
73391
+ if (policy.retainActive && pendingChildRunId !== undefined && !grouped.has(pendingChildRunId) && isPendingChildBoundary(draft, parentRunId, pendingChildRunId, rootRunId)) {
73392
+ pendingChildren.push({ parentRunId, owner: draft });
73393
+ continue;
73394
+ }
72666
73395
  const child = workflowChildFromDraft(draft);
72667
73396
  if (child?.exited !== true || grouped.has(child.runId))
72668
73397
  continue;
@@ -72771,6 +73500,28 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
72771
73500
  resumable: false
72772
73501
  });
72773
73502
  }
73503
+ for (const { parentRunId, owner } of pendingChildren) {
73504
+ if (!emittedRunIds.has(parentRunId))
73505
+ return [];
73506
+ const topology = owner.topology;
73507
+ const boundary = topology.boundary;
73508
+ const parentStageId = idMaps.get(parentRunId)?.get(topology.stageId);
73509
+ if (parentStageId === undefined)
73510
+ return [];
73511
+ runs.push({
73512
+ id: boundary.child.runId,
73513
+ name: boundary.child.runName,
73514
+ inputs: {},
73515
+ status: "running",
73516
+ stages: [],
73517
+ toolNodes: [],
73518
+ startedAt: owner.startedAt ?? owner.firstCompletedAt,
73519
+ parentRunId,
73520
+ parentStageId,
73521
+ rootRunId: boundary.child.rootRunId,
73522
+ resumable: false
73523
+ });
73524
+ }
72774
73525
  return runs;
72775
73526
  }
72776
73527
  function stageSnapshotFromDraft(draft, id, parentIds) {
@@ -73285,6 +74036,43 @@ function isDormantMessageEvent(value2) {
73285
74036
  // dist/builtin/workflows/src/extension/extension-lifecycle.ts
73286
74037
  import { registerExtensionContextRetirementEffect, sessionScopedExtensionState as sessionScopedExtensionState2 } from "@bastani/atomic";
73287
74038
 
74039
+ // dist/builtin/workflows/src/runs/background/ended-run-settlement.ts
74040
+ var ENDED_RUN_SETTLEMENT_TIMEOUT_MS = 1e4;
74041
+ function awaitJobSettlement(job) {
74042
+ return job.outcome ?? job.promise;
74043
+ }
74044
+ async function settleEndedRuns(opts) {
74045
+ const timeoutMs = opts.timeoutMs ?? ENDED_RUN_SETTLEMENT_TIMEOUT_MS;
74046
+ const ending = topLevelWorkflowRuns(opts.store.runs()).flatMap((run) => {
74047
+ const job = run.endedAt === undefined ? undefined : opts.jobs.get(run.id);
74048
+ return job === undefined ? [] : [{ runId: run.id, job }];
74049
+ });
74050
+ if (ending.length === 0)
74051
+ return [];
74052
+ const deadline = Promise.withResolvers();
74053
+ const timer = setTimeout(deadline.resolve, timeoutMs);
74054
+ timer.unref?.();
74055
+ try {
74056
+ const settled = await Promise.all(ending.map(({ runId, job }) => Promise.race([
74057
+ awaitJobSettlement(job).then(() => {
74058
+ return;
74059
+ }, (error) => ({
74060
+ runId,
74061
+ reason: "failed",
74062
+ message: describeErrorWithCauses(error)
74063
+ })),
74064
+ deadline.promise.then(() => ({
74065
+ runId,
74066
+ reason: "timed_out",
74067
+ message: `still recording its ending after ${timeoutMs} ms`
74068
+ }))
74069
+ ])));
74070
+ return settled.filter((failure) => failure !== undefined);
74071
+ } finally {
74072
+ clearTimeout(timer);
74073
+ }
74074
+ }
74075
+
73288
74076
  // dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts
73289
74077
  function expandedControlRunIds(store, runId) {
73290
74078
  const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
@@ -76545,6 +77333,13 @@ function registerWorkflowLifecycleHandlers(pi, deps) {
76545
77333
  if (failures.length > 0)
76546
77334
  throw new Error(failures.map((result) => `${result.runId}: ${result.reason}${"message" in result ? ` (${result.message})` : ""}`).join("; "));
76547
77335
  },
77336
+ async () => {
77337
+ if (boundary !== "quit")
77338
+ return;
77339
+ const failures = await settleEndedRuns({ store, jobs });
77340
+ if (failures.length > 0)
77341
+ throw new Error(failures.map((failure) => `${failure.runId}: ended but its ending was not recorded (${failure.message})`).join("; "));
77342
+ },
76548
77343
  () => stageControlRegistry.clear()
76549
77344
  ]);
76550
77345
  lifetime.generations.add(quitAndCheckpointRuns);
@@ -83295,6 +84090,7 @@ import { join as join28 } from "node:path";
83295
84090
  import {
83296
84091
  isStaleExtensionContextError as isStaleExtensionContextError6,
83297
84092
  ModelRuntime,
84093
+ noOpUIContext,
83298
84094
  resolveRestoredModelReference
83299
84095
  } from "@bastani/atomic";
83300
84096
 
@@ -83621,7 +84417,14 @@ function stripWorkflowOnlyOptions2(options) {
83621
84417
  if (!options)
83622
84418
  return options;
83623
84419
  const maybeWorkflowOptions = options;
83624
- const { schema: _schema, mcp: _mcp, fallbackModels, group: _group, ...sessionOptions } = maybeWorkflowOptions;
84420
+ const {
84421
+ schema: _schema,
84422
+ schemaTimeoutMs: _schemaTimeoutMs,
84423
+ mcp: _mcp,
84424
+ fallbackModels,
84425
+ group: _group,
84426
+ ...sessionOptions
84427
+ } = maybeWorkflowOptions;
83625
84428
  return fallbackModels?.length === 0 ? { ...sessionOptions, fallbackModels: [] } : sessionOptions;
83626
84429
  }
83627
84430
  function emitLateIntercomRoute(pi, meta, messages, options, batch) {
@@ -83738,6 +84541,7 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83738
84541
  notify: ui.notify ?? (() => {
83739
84542
  return;
83740
84543
  }),
84544
+ requestRender: noOpUIContext.requestRender,
83741
84545
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
83742
84546
  return;
83743
84547
  }),
@@ -83797,7 +84601,7 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83797
84601
  getEditorComponent: ui.getEditorComponent ?? (() => {
83798
84602
  return;
83799
84603
  }),
83800
- theme: ui.theme,
84604
+ theme: ui.theme ?? noOpUIContext.theme,
83801
84605
  getAllThemes: ui.getAllThemes ?? (() => []),
83802
84606
  getTheme: ui.getTheme ?? (() => {
83803
84607
  return;
@@ -83807,9 +84611,8 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
83807
84611
  setToolsExpanded: ui.setToolsExpanded ?? (() => {
83808
84612
  return;
83809
84613
  }),
83810
- getChatRenderSettings: ui.getChatRenderSettings ?? (() => {
83811
- return;
83812
- })
84614
+ getFooterDataProvider: noOpUIContext.getFooterDataProvider,
84615
+ getChatRenderSettings: ui.getChatRenderSettings ?? noOpUIContext.getChatRenderSettings
83813
84616
  };
83814
84617
  }
83815
84618
  function findStageModel(runtime, reference) {
@@ -85912,6 +86715,7 @@ function workflowModelCatalogFromContext(ctx, resolveLiveContext) {
85912
86715
  model: current.model,
85913
86716
  getRouterModel: () => current.getRouterModel(),
85914
86717
  ...current.getModelRouting ? { getModelRouting: () => current.getModelRouting() } : {},
86718
+ ...current.getHttpIdleTimeoutMs ? { getHttpIdleTimeoutMs: () => current.getHttpIdleTimeoutMs() } : {},
85915
86719
  modelRegistry: {
85916
86720
  getAvailable: () => registry.getAvailable(),
85917
86721
  getAll: () => registry.getAll(),
@@ -85929,7 +86733,8 @@ function workflowModelCatalogFromContext(ctx, resolveLiveContext) {
85929
86733
  signal: input.signal,
85930
86734
  selection: input.selection,
85931
86735
  ...input.taskNeeds ? { taskNeeds: input.taskNeeds } : {},
85932
- ...input.overrideProviderSettings ? { overrideProviderSettings: true } : {}
86736
+ ...input.overrideProviderSettings ? { overrideProviderSettings: true } : {},
86737
+ ...input.inference ? { inference: input.inference } : {}
85933
86738
  });
85934
86739
  },
85935
86740
  listModels: async () => {
@@ -86708,7 +87513,7 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86708
87513
  const entry = { signature };
86709
87514
  announcedRoutes.set(run.id, entry);
86710
87515
  try {
86711
- pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT2, announcement);
87516
+ outsideWorkflowExecutions(() => pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT2, announcement));
86712
87517
  } catch (error) {
86713
87518
  if (announcedRoutes.get(run.id) === entry)
86714
87519
  announcedRoutes.delete(run.id);
@@ -86747,7 +87552,7 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86747
87552
  announcedRoutes.clear();
86748
87553
  announceRoutes();
86749
87554
  });
86750
- const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT2, (payload) => {
87555
+ const routePendingStageMessage = (payload) => {
86751
87556
  if (disposed || !isPendingStageMessageEvent(payload) || payload.handled)
86752
87557
  return;
86753
87558
  const runs = activeStore.runs();
@@ -86810,12 +87615,13 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
86810
87615
  }
86811
87616
  payload.handled = true;
86812
87617
  payload.completion = queueAndPersist(activeStore, resolvedEvent, workflowInvocationIntercomGroup(rootRunId), stage.pendingStageDeliveryAvailable === true);
86813
- });
87618
+ };
87619
+ const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT2, (payload) => outsideWorkflowExecutions(() => routePendingStageMessage(payload)));
86814
87620
  const stickySubscription = pi.events?.on?.(STICKY_LIVE_DELIVERED_EVENT, (payload) => {
86815
87621
  if (disposed || !isStickyLiveDeliveredEvent(payload) || payload.handled)
86816
87622
  return;
86817
87623
  payload.handled = true;
86818
- payload.completion = recordConfirmedStickyDeliveries(activeStore, payload);
87624
+ payload.completion = outsideWorkflowExecutions(() => recordConfirmedStickyDeliveries(activeStore, payload));
86819
87625
  });
86820
87626
  const dispose = () => {
86821
87627
  disposed = true;
@@ -87595,7 +88401,7 @@ function openInputsPicker(ui, opts) {
87595
88401
  // dist/builtin/workflows/src/tui/session-picker.ts
87596
88402
  import { keyText as keyText3 } from "@bastani/atomic";
87597
88403
  var ESCAPE_CODE = 27;
87598
- function isQuitRun4(run) {
88404
+ function isQuitRun5(run) {
87599
88405
  return run.endedAt === undefined && run.status === "paused" && run.exitReason === "quit";
87600
88406
  }
87601
88407
  var DOUBLE_ESCAPE_SEQUENCE = String.fromCharCode(ESCAPE_CODE, ESCAPE_CODE);
@@ -87632,8 +88438,7 @@ function selectRunsForPicker(runs, query, includeAll, now = Date.now(), intent =
87632
88438
  return true;
87633
88439
  return r.name.toLowerCase().includes(q) || r.id.startsWith(q);
87634
88440
  };
87635
- const active = [];
87636
- const terminal = [];
88441
+ const rows = [];
87637
88442
  for (const r of runs) {
87638
88443
  if (!isTopLevelWorkflowRun(r))
87639
88444
  continue;
@@ -87646,16 +88451,30 @@ function selectRunsForPicker(runs, query, includeAll, now = Date.now(), intent =
87646
88451
  }
87647
88452
  const endedAt = r.endedAt;
87648
88453
  if (endedAt === undefined) {
87649
- active.push({ run: r, bucket: "active" });
88454
+ rows.push({ run: r, bucket: "active" });
87650
88455
  continue;
87651
88456
  }
87652
88457
  if (includeAll || now - endedAt <= RECENT_WINDOW_MS) {
87653
- terminal.push({ run: r, bucket: "terminal" });
88458
+ rows.push({ run: r, bucket: "terminal" });
87654
88459
  }
87655
88460
  }
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];
88461
+ return sortRunsByStatus(rows, (row) => row.run, createRunIndicatorStatusResolver(runs));
88462
+ }
88463
+ function syncSessionPickerSelection(state, rows) {
88464
+ if (state.selectedRunId !== undefined) {
88465
+ const index = rows.findIndex((row) => row.run.id === state.selectedRunId);
88466
+ if (index >= 0)
88467
+ state.selectedIndex = index;
88468
+ }
88469
+ state.selectedRunId = rows[state.selectedIndex]?.run.id;
88470
+ }
88471
+ function selectIndex2(state, rows, index) {
88472
+ state.selectedIndex = index;
88473
+ state.selectedRunId = rows[index]?.run.id;
88474
+ }
88475
+ function resetSelection(state) {
88476
+ state.selectedIndex = 0;
88477
+ state.selectedRunId = undefined;
87659
88478
  }
87660
88479
  var TITLE = "Connect to workflow run";
87661
88480
  function renderHeader3(width, theme) {
@@ -87736,7 +88555,7 @@ function renderRunRow(row, isSelected, inner, theme, now, allRuns) {
87736
88555
  const border = hexToAnsi(theme.border);
87737
88556
  const panelBg = hexBg(theme.bg);
87738
88557
  const run = row.run;
87739
- const indicatorStatus = isQuitRun4(run) ? run.status : runIndicatorStatus(run, allRuns);
88558
+ const indicatorStatus = isQuitRun5(run) ? run.status : runIndicatorStatus(run, allRuns);
87740
88559
  const icon = statusIcon(indicatorStatus);
87741
88560
  const iconColor = hexToAnsi(statusColor(indicatorStatus, theme));
87742
88561
  const dim = hexToAnsi(theme.dim);
@@ -87828,12 +88647,12 @@ function handleSessionPickerInput(data, state, rows) {
87828
88647
  }
87829
88648
  if (matchesKey(data, Key.backspace)) {
87830
88649
  state.query = state.query.slice(0, -1);
87831
- state.selectedIndex = 0;
88650
+ resetSelection(state);
87832
88651
  return { kind: "noop" };
87833
88652
  }
87834
88653
  if (data.length === 1 && data >= " " && data <= "~") {
87835
88654
  state.query += data;
87836
- state.selectedIndex = 0;
88655
+ resetSelection(state);
87837
88656
  return { kind: "noop" };
87838
88657
  }
87839
88658
  return { kind: "noop" };
@@ -87848,17 +88667,17 @@ function handleSessionPickerInput(data, state, rows) {
87848
88667
  return { kind: "close" };
87849
88668
  if (matchesKey(data, "a") || matchesKey(data, Key.shift("a"))) {
87850
88669
  state.includeAll = !state.includeAll;
87851
- state.selectedIndex = 0;
88670
+ resetSelection(state);
87852
88671
  return { kind: "noop" };
87853
88672
  }
87854
88673
  if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
87855
- state.selectedIndex = Math.min(state.selectedIndex + 1, Math.max(0, rows.length - 1));
88674
+ selectIndex2(state, rows, Math.min(state.selectedIndex + 1, Math.max(0, rows.length - 1)));
87856
88675
  return { kind: "noop" };
87857
88676
  }
87858
88677
  if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
87859
88678
  if (rows.length > 0 && state.selectedIndex === 0)
87860
88679
  return { kind: "noop" };
87861
- state.selectedIndex = Math.max(state.selectedIndex - 1, 0);
88680
+ selectIndex2(state, rows, Math.max(state.selectedIndex - 1, 0));
87862
88681
  return { kind: "noop" };
87863
88682
  }
87864
88683
  if (matchesKey(data, Key.enter)) {
@@ -88185,10 +89004,12 @@ function openSessionPicker(ui, store, theme, intent = "connect") {
88185
89004
  return {
88186
89005
  render: (width) => {
88187
89006
  const rows = selectRows();
89007
+ syncSessionPickerSelection(state, rows);
88188
89008
  return renderSessionPicker({ width, theme, rows, state, allRuns: store.runs() });
88189
89009
  },
88190
89010
  handleInput: (data) => {
88191
89011
  const rows = selectRows();
89012
+ syncSessionPickerSelection(state, rows);
88192
89013
  const consumed = isSessionPickerKey(data, state, rows);
88193
89014
  const action = handleSessionPickerInput(data, state, rows);
88194
89015
  if (action.kind === "noop") {
@@ -89221,6 +90042,18 @@ function createSessionRunControl(host) {
89221
90042
  async quit(runId) {
89222
90043
  return controlOutcome(await request({ action: "quit", ...target(runId) }));
89223
90044
  },
90045
+ async waitForSettled(runId) {
90046
+ const job = (host.jobs ?? currentJobTracker()).get(runId);
90047
+ if (job === undefined)
90048
+ return;
90049
+ try {
90050
+ await awaitJobSettlement(job);
90051
+ } catch (error) {
90052
+ const cause = error instanceof Error ? error : new Error(String(error));
90053
+ const code = error instanceof JournalError ? "storage_unavailable" : classifyControlError(error);
90054
+ throw failure3(code, `Run ${runId} did not settle cleanly: ${describeErrorWithCauses(error)}`, runId, cause);
90055
+ }
90056
+ },
89224
90057
  async resume(runId, options) {
89225
90058
  return controlOutcome(await request({
89226
90059
  action: "resume",
@@ -91664,6 +92497,7 @@ function factory(pi) {
91664
92497
  execute: executeWorkflowTool,
91665
92498
  context: () => sessionContext,
91666
92499
  store: owner.store,
92500
+ jobs: runState.jobs,
91667
92501
  catalog: async () => {
91668
92502
  const runtime = runtimeState.runtimeForContext(sessionContext);
91669
92503
  return await runtime.prepareDurableCatalog?.() ?? { resumable: [], completed: [] };