@bastani/atomic 0.9.13-alpha.2 → 0.9.13-alpha.4

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 (317) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/i-have-adhd/package.json +1 -1
  4. package/dist/builtin/intercom/CHANGELOG.md +14 -0
  5. package/dist/builtin/intercom/README.md +12 -12
  6. package/dist/builtin/intercom/incoming-message-delivery.ts +1 -1
  7. package/dist/builtin/intercom/index.ts +1 -1
  8. package/dist/builtin/intercom/intercom-tool.ts +1 -1
  9. package/dist/builtin/intercom/intercom-utils.ts +3 -6
  10. package/dist/builtin/intercom/package.json +1 -1
  11. package/dist/builtin/intercom/result-renderers.ts +1 -1
  12. package/dist/builtin/intercom/session-target.ts +1 -15
  13. package/dist/builtin/intercom/skills/intercom/SKILL.md +6 -6
  14. package/dist/builtin/intercom/terminal-ordering-barrier.ts +2 -2
  15. package/dist/builtin/intercom/ui/inline-message.ts +7 -5
  16. package/dist/builtin/intercom/ui/session-list.ts +23 -10
  17. package/dist/builtin/mcp/package.json +1 -1
  18. package/dist/builtin/subagents/CHANGELOG.md +19 -0
  19. package/dist/builtin/subagents/README.md +29 -73
  20. package/dist/builtin/subagents/package.json +2 -2
  21. package/dist/builtin/subagents/prompts/parallel-cleanup.md +1 -1
  22. package/dist/builtin/subagents/prompts/parallel-review.md +1 -1
  23. package/dist/builtin/subagents/prompts/review-loop.md +2 -2
  24. package/dist/builtin/subagents/skills/subagent/SKILL.md +23 -59
  25. package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
  26. package/dist/builtin/subagents/src/extension/control-notices.ts +2 -3
  27. package/dist/builtin/subagents/src/extension/doctor.ts +2 -14
  28. package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -17
  29. package/dist/builtin/subagents/src/extension/index.ts +9 -70
  30. package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
  31. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +2 -2
  32. package/dist/builtin/subagents/src/extension/schemas.ts +2 -8
  33. package/dist/builtin/subagents/src/extension/tool-description.ts +2 -3
  34. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -1
  35. package/dist/builtin/subagents/src/intercom/result-intercom.ts +5 -46
  36. package/dist/builtin/subagents/src/runs/{background → foreground}/completion-notification.ts +2 -2
  37. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +25 -88
  38. package/dist/builtin/subagents/src/runs/{background → foreground}/notify.ts +5 -5
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -28
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +3 -0
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +2 -0
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +0 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +30 -20
  44. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +4 -4
  45. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +0 -13
  46. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +104 -48
  47. package/dist/builtin/subagents/src/runs/inprocess/index.ts +1 -1
  48. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +5 -5
  49. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +0 -7
  50. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +0 -10
  51. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +3 -108
  52. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +0 -4
  53. package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
  54. package/dist/builtin/subagents/src/shared/formatters.ts +3 -5
  55. package/dist/builtin/subagents/src/shared/model-resolution.ts +78 -0
  56. package/dist/builtin/subagents/src/shared/status-format.ts +4 -11
  57. package/dist/builtin/subagents/src/shared/types-config.ts +10 -9
  58. package/dist/builtin/subagents/src/shared/types-nested.ts +127 -0
  59. package/dist/builtin/subagents/src/shared/types-results.ts +2 -8
  60. package/dist/builtin/subagents/src/shared/types-runtime.ts +0 -9
  61. package/dist/builtin/subagents/src/shared/types.ts +1 -1
  62. package/dist/builtin/subagents/src/shared/utils.ts +1 -109
  63. package/dist/builtin/subagents/src/slash/slash-commands.ts +7 -17
  64. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -252
  65. package/dist/builtin/subagents/src/tui/render-layout.ts +4 -4
  66. package/dist/builtin/subagents/src/tui/render-result.ts +0 -9
  67. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -34
  68. package/dist/builtin/subagents/src/tui/render.ts +0 -2
  69. package/dist/builtin/web-access/package.json +1 -1
  70. package/dist/builtin/workflows/CHANGELOG.md +23 -0
  71. package/dist/builtin/workflows/README.md +3 -3
  72. package/dist/builtin/workflows/package.json +1 -1
  73. package/dist/builtin/workflows/src/durable/backend.ts +11 -0
  74. package/dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts +63 -25
  75. package/dist/builtin/workflows/src/durable/completed-catalog.ts +166 -25
  76. package/dist/builtin/workflows/src/durable/dbos-backend.ts +42 -24
  77. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +2 -1
  78. package/dist/builtin/workflows/src/durable/run-timing.ts +28 -7
  79. package/dist/builtin/workflows/src/durable/scoped-backend.ts +4 -0
  80. package/dist/builtin/workflows/src/durable/targeted-inspection.ts +110 -0
  81. package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +2 -2
  82. package/dist/builtin/workflows/src/engine/runtime.ts +19 -2
  83. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
  84. package/dist/builtin/workflows/src/extension/index.bundle.mjs +750 -168
  85. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -0
  86. package/dist/builtin/workflows/src/extension/ui-surface.ts +4 -0
  87. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +6 -1
  88. package/dist/builtin/workflows/src/extension/workflow-targets.ts +18 -10
  89. package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +31 -16
  90. package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +75 -3
  91. package/dist/builtin/workflows/src/extension/workflow-tool.ts +53 -6
  92. package/dist/builtin/workflows/src/runs/background/run-inspect.ts +5 -1
  93. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +94 -60
  94. package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +1 -1
  95. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +7 -7
  96. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +25 -4
  97. package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +4 -1
  98. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -0
  99. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +142 -4
  100. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +2 -0
  101. package/dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts +88 -0
  102. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +1 -0
  103. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +1 -0
  104. package/dist/builtin/workflows/src/tui/run-detail.ts +25 -12
  105. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +27 -8
  106. package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +17 -1
  107. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +20 -3
  108. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +10 -1
  109. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +1 -0
  110. package/dist/core/agent-session-events.d.ts.map +1 -1
  111. package/dist/core/agent-session-events.js +22 -5
  112. package/dist/core/agent-session-events.js.map +1 -1
  113. package/dist/core/agent-session-export.d.ts.map +1 -1
  114. package/dist/core/agent-session-export.js +2 -1
  115. package/dist/core/agent-session-export.js.map +1 -1
  116. package/dist/core/agent-session-methods.d.ts +10 -4
  117. package/dist/core/agent-session-methods.d.ts.map +1 -1
  118. package/dist/core/agent-session-methods.js.map +1 -1
  119. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  120. package/dist/core/agent-session-prompt.js +68 -0
  121. package/dist/core/agent-session-prompt.js.map +1 -1
  122. package/dist/core/agent-session-queue-pause.d.ts.map +1 -1
  123. package/dist/core/agent-session-queue-pause.js +6 -0
  124. package/dist/core/agent-session-queue-pause.js.map +1 -1
  125. package/dist/core/agent-session-summary.d.ts +21 -0
  126. package/dist/core/agent-session-summary.d.ts.map +1 -0
  127. package/dist/core/agent-session-summary.js +156 -0
  128. package/dist/core/agent-session-summary.js.map +1 -0
  129. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  130. package/dist/core/agent-session-tool-registry.js +0 -4
  131. package/dist/core/agent-session-tool-registry.js.map +1 -1
  132. package/dist/core/agent-session-transfer.d.ts.map +1 -1
  133. package/dist/core/agent-session-transfer.js +0 -2
  134. package/dist/core/agent-session-transfer.js.map +1 -1
  135. package/dist/core/agent-session-tree.d.ts.map +1 -1
  136. package/dist/core/agent-session-tree.js +6 -0
  137. package/dist/core/agent-session-tree.js.map +1 -1
  138. package/dist/core/agent-session.d.ts +21 -3
  139. package/dist/core/agent-session.d.ts.map +1 -1
  140. package/dist/core/agent-session.js +22 -5
  141. package/dist/core/agent-session.js.map +1 -1
  142. package/dist/core/atomic-guide-command.js +2 -2
  143. package/dist/core/atomic-guide-command.js.map +1 -1
  144. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  145. package/dist/core/compaction/branch-summarization.js +1 -0
  146. package/dist/core/compaction/branch-summarization.js.map +1 -1
  147. package/dist/core/compaction/index.d.ts +1 -0
  148. package/dist/core/compaction/index.d.ts.map +1 -1
  149. package/dist/core/compaction/index.js +1 -0
  150. package/dist/core/compaction/index.js.map +1 -1
  151. package/dist/core/compaction/session-summarization.d.ts +41 -0
  152. package/dist/core/compaction/session-summarization.d.ts.map +1 -0
  153. package/dist/core/compaction/session-summarization.js +97 -0
  154. package/dist/core/compaction/session-summarization.js.map +1 -0
  155. package/dist/core/extensions/ui-types.d.ts +4 -0
  156. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  157. package/dist/core/extensions/ui-types.js.map +1 -1
  158. package/dist/core/keybindings.d.ts +0 -5
  159. package/dist/core/keybindings.d.ts.map +1 -1
  160. package/dist/core/keybindings.js +0 -2
  161. package/dist/core/keybindings.js.map +1 -1
  162. package/dist/core/session-manager-core.d.ts +3 -1
  163. package/dist/core/session-manager-core.d.ts.map +1 -1
  164. package/dist/core/session-manager-core.js +9 -1
  165. package/dist/core/session-manager-core.js.map +1 -1
  166. package/dist/core/session-manager-entries.d.ts +24 -1
  167. package/dist/core/session-manager-entries.d.ts.map +1 -1
  168. package/dist/core/session-manager-entries.js +48 -0
  169. package/dist/core/session-manager-entries.js.map +1 -1
  170. package/dist/core/session-manager-list.d.ts.map +1 -1
  171. package/dist/core/session-manager-list.js +10 -0
  172. package/dist/core/session-manager-list.js.map +1 -1
  173. package/dist/core/session-manager-types.d.ts +10 -1
  174. package/dist/core/session-manager-types.d.ts.map +1 -1
  175. package/dist/core/session-manager-types.js.map +1 -1
  176. package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
  177. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  178. package/dist/core/settings-manager-basic-accessors.js +5 -0
  179. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +1 -1
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js.map +1 -1
  183. package/dist/core/settings-types.d.ts +4 -0
  184. package/dist/core/settings-types.d.ts.map +1 -1
  185. package/dist/core/settings-types.js.map +1 -1
  186. package/dist/core/slash-commands.js +2 -2
  187. package/dist/core/slash-commands.js.map +1 -1
  188. package/dist/core/tools/bash.d.ts +0 -15
  189. package/dist/core/tools/bash.d.ts.map +1 -1
  190. package/dist/core/tools/bash.js +3 -81
  191. package/dist/core/tools/bash.js.map +1 -1
  192. package/dist/core/tools/fetch-url.d.ts +12 -0
  193. package/dist/core/tools/fetch-url.d.ts.map +1 -1
  194. package/dist/core/tools/fetch-url.js +76 -10
  195. package/dist/core/tools/fetch-url.js.map +1 -1
  196. package/dist/core/tools/index.js +4 -4
  197. package/dist/core/tools/index.js.map +1 -1
  198. package/dist/core/tools/session-temp-dir.d.ts +2 -2
  199. package/dist/core/tools/session-temp-dir.d.ts.map +1 -1
  200. package/dist/core/tools/session-temp-dir.js +6 -7
  201. package/dist/core/tools/session-temp-dir.js.map +1 -1
  202. package/dist/core/usage-totals.js +1 -1
  203. package/dist/core/usage-totals.js.map +1 -1
  204. package/dist/index.d.ts +1 -1
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +1 -1
  207. package/dist/index.js.map +1 -1
  208. package/dist/modes/interactive/components/footer.js +1 -1
  209. package/dist/modes/interactive/components/footer.js.map +1 -1
  210. package/dist/modes/interactive/components/host-session-picker.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/host-session-picker.js +1 -0
  212. package/dist/modes/interactive/components/host-session-picker.js.map +1 -1
  213. package/dist/modes/interactive/components/index.d.ts +1 -0
  214. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  215. package/dist/modes/interactive/components/index.js +1 -0
  216. package/dist/modes/interactive/components/index.js.map +1 -1
  217. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  218. package/dist/modes/interactive/components/session-selector-list.js +29 -4
  219. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  220. package/dist/modes/interactive/components/session-selector-search.js +1 -1
  221. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  222. package/dist/modes/interactive/components/transcript-follow-indicator.d.ts +14 -0
  223. package/dist/modes/interactive/components/transcript-follow-indicator.d.ts.map +1 -0
  224. package/dist/modes/interactive/components/transcript-follow-indicator.js +36 -0
  225. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -0
  226. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/tree-selector-content.js +6 -0
  228. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
  229. package/dist/modes/interactive/interactive-extension-custom-ui.js +3 -0
  230. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  231. package/dist/modes/interactive/interactive-input-handling.js +0 -3
  232. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  233. package/dist/modes/interactive/interactive-mode-base.d.ts +1 -0
  234. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  235. package/dist/modes/interactive/interactive-mode-base.js +7 -1
  236. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  237. package/dist/modes/interactive/interactive-mode-surface.d.ts +3 -3
  238. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  239. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  240. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  241. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  242. package/dist/modes/interactive/interactive-mode.js +1 -0
  243. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  244. package/dist/modes/interactive/interactive-slash-commands.js +2 -5
  245. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  246. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-startup.js +6 -0
  248. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  249. package/dist/modes/interactive/interactive-transcript-follow.d.ts +2 -0
  250. package/dist/modes/interactive/interactive-transcript-follow.d.ts.map +1 -0
  251. package/dist/modes/interactive/interactive-transcript-follow.js +6 -0
  252. package/dist/modes/interactive/interactive-transcript-follow.js.map +1 -0
  253. package/dist/modes/interactive/interactive-tui.d.ts +13 -1
  254. package/dist/modes/interactive/interactive-tui.d.ts.map +1 -1
  255. package/dist/modes/interactive/interactive-tui.js +59 -1
  256. package/dist/modes/interactive/interactive-tui.js.map +1 -1
  257. package/dist/modes/interactive-engine/engine-custom-ui.d.ts +2 -0
  258. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  259. package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
  260. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  261. package/dist/modes/interactive-engine/protocol.d.ts +1 -0
  262. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  263. package/dist/modes/interactive-engine/protocol.js +5 -1
  264. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  265. package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
  266. package/dist/modes/interactive-engine/remote-component.js +21 -9
  267. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  268. package/docs/environment-variables.md +1 -1
  269. package/docs/intercom.md +20 -21
  270. package/docs/keybindings.md +2 -5
  271. package/docs/quickstart.md +5 -1
  272. package/docs/sdk.md +1 -1
  273. package/docs/session-format.md +15 -0
  274. package/docs/sessions.md +8 -0
  275. package/docs/settings.md +6 -0
  276. package/docs/subagents.md +19 -31
  277. package/docs/tools.md +3 -5
  278. package/docs/usage.md +3 -1
  279. package/docs/windows.md +1 -1
  280. package/docs/workflows.md +60 -32
  281. package/npm-shrinkwrap.json +29 -29
  282. package/package.json +2 -2
  283. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +0 -331
  284. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +0 -161
  285. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +0 -195
  286. package/dist/builtin/subagents/src/runs/inprocess/background.ts +0 -90
  287. package/dist/builtin/subagents/src/shared/types-async.ts +0 -247
  288. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -217
  289. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -366
  290. package/dist/core/async/format.d.ts +0 -3
  291. package/dist/core/async/format.d.ts.map +0 -1
  292. package/dist/core/async/format.js +0 -52
  293. package/dist/core/async/format.js.map +0 -1
  294. package/dist/core/async/job-manager.d.ts +0 -40
  295. package/dist/core/async/job-manager.d.ts.map +0 -1
  296. package/dist/core/async/job-manager.js +0 -293
  297. package/dist/core/async/job-manager.js.map +0 -1
  298. package/dist/core/async/session-manager.d.ts +0 -16
  299. package/dist/core/async/session-manager.d.ts.map +0 -1
  300. package/dist/core/async/session-manager.js +0 -34
  301. package/dist/core/async/session-manager.js.map +0 -1
  302. package/dist/core/async/types.d.ts +0 -23
  303. package/dist/core/async/types.d.ts.map +0 -1
  304. package/dist/core/async/types.js +0 -2
  305. package/dist/core/async/types.js.map +0 -1
  306. package/dist/core/tools/bash-async-execution.d.ts +0 -27
  307. package/dist/core/tools/bash-async-execution.d.ts.map +0 -1
  308. package/dist/core/tools/bash-async-execution.js +0 -81
  309. package/dist/core/tools/bash-async-execution.js.map +0 -1
  310. package/dist/core/tools/bash-async-jobs.d.ts +0 -30
  311. package/dist/core/tools/bash-async-jobs.d.ts.map +0 -1
  312. package/dist/core/tools/bash-async-jobs.js +0 -87
  313. package/dist/core/tools/bash-async-jobs.js.map +0 -1
  314. package/dist/core/tools/bash-async-output.d.ts +0 -13
  315. package/dist/core/tools/bash-async-output.d.ts.map +0 -1
  316. package/dist/core/tools/bash-async-output.js +0 -122
  317. package/dist/core/tools/bash-async-output.js.map +0 -1
@@ -37555,6 +37555,8 @@ function summaryRows(detail, now) {
37555
37555
  rows.push(["error", detail.error.split(`
37556
37556
  `)[0] ?? ""]);
37557
37557
  }
37558
+ if (detail.resumeGuidance)
37559
+ rows.push(["guidance", detail.resumeGuidance]);
37558
37560
  return rows;
37559
37561
  }
37560
37562
  function artifactRowsFor(detail) {
@@ -37668,6 +37670,8 @@ function stateBadges(detail, theme) {
37668
37670
  switch (detail.status) {
37669
37671
  case "running":
37670
37672
  return [{ text: "● running", fg: theme.warning }];
37673
+ case "crashed":
37674
+ return [{ text: detail.resumable === true ? "✗ crashed · resumable" : "✗ crashed", fg: theme.error }];
37671
37675
  case "paused":
37672
37676
  return [{ text: "❚❚ paused", fg: theme.warning }];
37673
37677
  case "completed":
@@ -37690,6 +37694,8 @@ function stateLabel(detail) {
37690
37694
  switch (detail.status) {
37691
37695
  case "running":
37692
37696
  return "● running";
37697
+ case "crashed":
37698
+ return detail.resumable === true ? "✗ crashed · resumable" : "✗ crashed";
37693
37699
  case "paused":
37694
37700
  return "❚❚ paused";
37695
37701
  case "completed":
@@ -37729,8 +37735,10 @@ function renderIdentifierRows2(id, width, theme) {
37729
37735
  });
37730
37736
  }
37731
37737
  function renderDetailHintRows(detail, width, theme) {
37732
- const prefix = detail.endedAt === undefined ? detail.status === "paused" ? " workflow resume id=" : " workflow interrupt id=" : " workflow resume id=";
37733
- const suffix = detail.endedAt === undefined ? detail.status === "paused" ? " continue workflow " : " cancel " : " reopen graph ";
37738
+ const resumable = detail.status === "paused" && detail.resumable !== false || detail.resumable === true && (detail.status === "crashed" || detail.status === "failed" || detail.status === "blocked");
37739
+ const inspectOnly = detail.ownerActiveElsewhere === true || detail.status === "crashed" && !resumable || detail.endedAt !== undefined && !resumable;
37740
+ const prefix = inspectOnly ? " ▸ workflow status id=" : resumable ? " ▸ workflow resume id=" : " ▸ workflow interrupt id=";
37741
+ const suffix = inspectOnly ? detail.ownerActiveElsewhere === true ? " inspect; owner active elsewhere " : " inspect retained state " : resumable ? " continue workflow " : " cancel ";
37734
37742
  const continuation = " ";
37735
37743
  const rows = wrapIdentifierLines(detail.runId, width, prefix, continuation);
37736
37744
  const last = rows[rows.length - 1];
@@ -38943,6 +38951,7 @@ var APP_ACTION = {
38943
38951
  thinkingToggle: "app.thinking.toggle"
38944
38952
  };
38945
38953
  var TUI_ACTION = {
38954
+ altScreenBottom: "tui.altScreen.bottom",
38946
38955
  editorCursorUp: "tui.editor.cursorUp",
38947
38956
  editorCursorDown: "tui.editor.cursorDown",
38948
38957
  editorCursorLeft: "tui.editor.cursorLeft",
@@ -40598,6 +40607,11 @@ function remoteTerminalControlFrom(tui) {
40598
40607
  return { setAutowrap: terminal.setAutowrap.bind(terminal) };
40599
40608
  }
40600
40609
 
40610
+ // dist/builtin/workflows/src/tui/workflow-attach-pane.ts
40611
+ import {
40612
+ TRANSCRIPT_JUMP_TO_END_URL as TRANSCRIPT_JUMP_TO_END_URL2
40613
+ } from "@bastani/atomic";
40614
+
40601
40615
  // dist/builtin/workflows/src/runs/foreground/stage-queued-user-messages.ts
40602
40616
  var EMPTY_STAGE_QUEUED_USER_MESSAGES = Object.freeze({
40603
40617
  steering: Object.freeze([]),
@@ -43788,6 +43802,9 @@ class StageChatComposerDrafts {
43788
43802
  }
43789
43803
  }
43790
43804
 
43805
+ // dist/builtin/workflows/src/tui/stage-chat-view.ts
43806
+ import { keyText as keyText2, TranscriptFollowIndicator } from "@bastani/atomic";
43807
+
43791
43808
  // dist/builtin/workflows/src/tui/stage-chat-layout.ts
43792
43809
  function resolveStageChatViewportRows(reported, fallbackRows) {
43793
43810
  if (typeof reported !== "number" || !Number.isFinite(reported)) {
@@ -44122,7 +44139,7 @@ function postMortemUnavailableMessage(reason) {
44122
44139
  return;
44123
44140
  }
44124
44141
  }
44125
- function renderReadOnlyArchiveBody(ctx, width, budget, stage) {
44142
+ function renderReadOnlyArchiveBody(ctx, width, budget, stage, indicatorLines = [], renderIndicator = () => indicatorLines) {
44126
44143
  if (stage?.promptFootprint) {
44127
44144
  return renderReadOnlyPromptArchiveBody(ctx, width, budget, stage);
44128
44145
  }
@@ -44133,8 +44150,13 @@ function renderReadOnlyArchiveBody(ctx, width, budget, stage) {
44133
44150
  callout.push(...bannerLines(ctx, width, unavailableMessage === undefined ? "info" : "warning", unavailableMessage === undefined ? "◌" : "!", unavailableMessage === undefined ? "READ-ONLY SESSION" : "SESSION UNAVAILABLE", unavailableMessage === undefined ? stage?.sessionFile ? "archived transcript" : "no live chat session" : "post-mortem chat cannot be reopened"));
44134
44151
  callout.push(...new Text2(paint2(unavailableMessage ?? "This node is no longer attached to a live chat session.", t.textMuted), 2, 0).render(width));
44135
44152
  const transcriptBudget = Math.max(0, budget - callout.length);
44136
- const lines = transcriptBudget > 0 ? ctx.chatHost.renderBody(width, transcriptBudget) : [];
44137
- lines.push(...callout);
44153
+ const reservedIndicatorRows = indicatorLines.length > 0 && transcriptBudget > indicatorLines.length ? indicatorLines.length : 0;
44154
+ const transcriptRows = transcriptBudget - reservedIndicatorRows;
44155
+ const lines = transcriptRows > 0 ? ctx.chatHost.renderBody(width, transcriptRows) : [];
44156
+ const visibleIndicatorLines = reservedIndicatorRows > 0 ? [...renderIndicator().slice(0, reservedIndicatorRows)] : [];
44157
+ while (visibleIndicatorLines.length < reservedIndicatorRows)
44158
+ visibleIndicatorLines.push(blankLine(width));
44159
+ lines.push(...visibleIndicatorLines, ...callout);
44138
44160
  while (lines.length < budget)
44139
44161
  lines.push(blankLine(width));
44140
44162
  if (lines.length > budget)
@@ -44210,16 +44232,21 @@ function formatReadOnlyPromptAnswer(value2, kind) {
44210
44232
  return String(value2);
44211
44233
  }
44212
44234
  }
44213
- function renderPausedBody(ctx, width, budget) {
44235
+ function renderPausedBody(ctx, width, budget, indicatorLines = [], renderIndicator = () => indicatorLines) {
44214
44236
  const t = ctx.theme;
44215
44237
  const callout = [];
44216
44238
  callout.push(blankLine(width));
44217
44239
  callout.push(...bannerLines(ctx, width, "warning", "❚❚", "PAUSED", "enter resumes · ctrl+x return to graph"));
44218
44240
  callout.push(...new Text2(paint2("This workflow stage is paused. Type a message below and press Enter to resume.", t.textMuted), 2, 0).render(width));
44219
- const calloutRows = Math.min(callout.length, Math.max(0, budget - 1));
44220
- const transcriptBudget = Math.max(1, budget - calloutRows);
44221
- const lines = ctx.chatHost.renderBody(width, transcriptBudget);
44222
- lines.push(...callout.slice(0, calloutRows));
44241
+ const calloutRows = Math.min(callout.length, Math.max(0, budget));
44242
+ const transcriptBudget = Math.max(0, budget - calloutRows);
44243
+ const reservedIndicatorRows = indicatorLines.length > 0 && transcriptBudget > indicatorLines.length ? indicatorLines.length : 0;
44244
+ const transcriptRows = transcriptBudget - reservedIndicatorRows;
44245
+ const lines = transcriptRows > 0 ? ctx.chatHost.renderBody(width, transcriptRows) : [];
44246
+ const visibleIndicatorLines = reservedIndicatorRows > 0 ? [...renderIndicator().slice(0, reservedIndicatorRows)] : [];
44247
+ while (visibleIndicatorLines.length < reservedIndicatorRows)
44248
+ visibleIndicatorLines.push(blankLine(width));
44249
+ lines.push(...visibleIndicatorLines, ...callout.slice(0, calloutRows));
44223
44250
  while (lines.length < budget)
44224
44251
  lines.push(blankLine(width));
44225
44252
  if (lines.length > budget)
@@ -44662,6 +44689,9 @@ function canSubmitPrompt(ctx, promptId) {
44662
44689
  return ctx.canSubmitPrompt?.(ctx.runId, ctx.stageId, promptId) ?? true;
44663
44690
  }
44664
44691
 
44692
+ // dist/builtin/workflows/src/tui/stage-chat-view-input.ts
44693
+ import { TRANSCRIPT_JUMP_TO_END_URL } from "@bastani/atomic";
44694
+
44665
44695
  // dist/builtin/workflows/src/tui/stage-chat-view-state.ts
44666
44696
  import { ChatSessionHost } from "@bastani/atomic";
44667
44697
  import { Editor } from "@earendil-works/pi-tui";
@@ -45636,6 +45666,8 @@ function promptPageSize(ctx) {
45636
45666
 
45637
45667
  // dist/builtin/workflows/src/tui/stage-chat-view-input.ts
45638
45668
  function handleStageChatInput(ctx, data) {
45669
+ if (data === TRANSCRIPT_JUMP_TO_END_URL)
45670
+ return handleStageChatJumpToBottom(ctx, data);
45639
45671
  const keybindings = isKeybindingsLike(ctx.piKeybindings) ? ctx.piKeybindings : undefined;
45640
45672
  if (matchesKey(data, Key.ctrl("t")) && matchesAction(keybindings, data, APP_ACTION.thinkingToggle)) {
45641
45673
  return false;
@@ -45669,6 +45701,8 @@ function handleStageChatInput(ctx, data) {
45669
45701
  if (readOnlyPromptArchive && handlePromptScrollInput(ctx, data, true)) {
45670
45702
  return true;
45671
45703
  }
45704
+ if (handleStageChatJumpToBottom(ctx, data))
45705
+ return true;
45672
45706
  if (ctx.chatHost.handleScrollInput(data))
45673
45707
  return true;
45674
45708
  if (matchesKey(data, Key.escape)) {
@@ -45699,6 +45733,13 @@ function handleStageChatInput(ctx, data) {
45699
45733
  return true;
45700
45734
  return ctx.chatHost.handleInput(data);
45701
45735
  }
45736
+ function handleStageChatJumpToBottom(ctx, data) {
45737
+ const keybindings = isKeybindingsLike(ctx.piKeybindings) ? ctx.piKeybindings : undefined;
45738
+ if (data !== TRANSCRIPT_JUMP_TO_END_URL && !matchesAction(keybindings, data, TUI_ACTION.altScreenBottom))
45739
+ return false;
45740
+ ctx.chatHost.scrollToBottom();
45741
+ return true;
45742
+ }
45702
45743
  function handleToolsExpandInput(ctx, data) {
45703
45744
  const keybindings = isKeybindingsLike(ctx.piKeybindings) ? ctx.piKeybindings : undefined;
45704
45745
  if (!matchesAction(keybindings, data, APP_ACTION.toolsExpand))
@@ -45722,6 +45763,10 @@ function handleMountedCustomUiInput(ctx, data) {
45722
45763
  ctx.onClose();
45723
45764
  return true;
45724
45765
  }
45766
+ if (handleStageChatJumpToBottom(ctx, data)) {
45767
+ ctx.requestRender?.();
45768
+ return true;
45769
+ }
45725
45770
  if (ctx.chatHost.handleScrollInput(data)) {
45726
45771
  ctx.requestRender?.();
45727
45772
  return true;
@@ -45896,6 +45941,12 @@ class StageChatView {
45896
45941
  if (blocked)
45897
45942
  this.chatHost.scrollToBottom();
45898
45943
  let bodyLines;
45944
+ let transcriptBodyActive = false;
45945
+ let reservedIndicatorLines = [];
45946
+ const indicator = new TranscriptFollowIndicator({
45947
+ isFollowing: () => this.chatHost.bodyScrollFromBottom() === 0,
45948
+ keyLabel: () => keyText2("tui.altScreen.bottom")
45949
+ });
45899
45950
  if (bodyBudget <= 0) {
45900
45951
  bodyLines = [];
45901
45952
  } else if (promptActive) {
@@ -45903,16 +45954,24 @@ class StageChatView {
45903
45954
  } else if (blocked) {
45904
45955
  bodyLines = renderBlockedBody(ctx, w, bodyBudget, stage);
45905
45956
  } else if (!readOnlyArchive && isPaused(ctx, stage)) {
45906
- bodyLines = renderPausedBody(ctx, w, bodyBudget);
45957
+ reservedIndicatorLines = bodyBudget > 1 ? indicator.render(w) : [];
45958
+ bodyLines = renderPausedBody(ctx, w, bodyBudget, reservedIndicatorLines, () => indicator.render(w));
45907
45959
  } else if (readOnlyArchive) {
45908
- bodyLines = renderReadOnlyArchiveBody(ctx, w, bodyBudget, stage);
45960
+ reservedIndicatorLines = bodyBudget > 1 ? indicator.render(w) : [];
45961
+ bodyLines = renderReadOnlyArchiveBody(ctx, w, bodyBudget, stage, reservedIndicatorLines, () => indicator.render(w));
45909
45962
  } else {
45963
+ transcriptBodyActive = true;
45910
45964
  bodyLines = this.chatHost.renderBody(w, bodyBudget);
45911
45965
  }
45966
+ const indicatorLines = transcriptBodyActive && bodyBudget > 1 ? indicator.render(w) : [];
45967
+ const indicatorVisible = indicatorLines.length > 0;
45968
+ const dropBodyRow = transcriptBodyActive && indicatorVisible && bodyLines.length >= bodyBudget;
45969
+ const visibleBodyLines = bodyLines.slice(dropBodyRow ? 1 : 0, bodyBudget);
45912
45970
  const lines = [
45913
45971
  ...headerLines,
45914
45972
  ...sepLines,
45915
- ...bodyLines,
45973
+ ...visibleBodyLines,
45974
+ ...indicatorLines,
45916
45975
  ...visiblePendingLines,
45917
45976
  ...visibleWorkingLines,
45918
45977
  ...visibleUsageLines,
@@ -46280,6 +46339,8 @@ class WorkflowAttachPane {
46280
46339
  return true;
46281
46340
  return this.chatView.handleInput(data);
46282
46341
  }
46342
+ if (data === TRANSCRIPT_JUMP_TO_END_URL2)
46343
+ return false;
46283
46344
  if (this._shouldQuarantineGraphEnter(data))
46284
46345
  return true;
46285
46346
  return this.graphView.handleInput(data);
@@ -46647,6 +46708,7 @@ function buildGraphOverlayAdapter(pi, store2, buildOpts = {}) {
46647
46708
  overlay: true,
46648
46709
  deferInlineCustomUiFocus: true,
46649
46710
  handlesCtrlC: true,
46711
+ handlesInternalUiAction: true,
46650
46712
  overlayOptions: FULLSCREEN_OVERLAY_OPTIONS,
46651
46713
  onHandle: (handle) => {
46652
46714
  currentHandle = handle;
@@ -47839,7 +47901,7 @@ function isModelUsage(value2) {
47839
47901
  if (typeof value2 !== "object" || value2 === null || Array.isArray(value2))
47840
47902
  return false;
47841
47903
  const usage = value2;
47842
- return ["input", "output", "cacheRead", "cacheWrite", "cost", "turns"].every((key2) => usage[key2] === undefined || typeof usage[key2] === "number" && Number.isFinite(usage[key2]));
47904
+ return ["input", "output", "cacheRead", "cacheWrite", "cost", "turns"].every((key2) => usage[key2] === undefined || typeof usage[key2] === "number" && Number.isFinite(usage[key2]) && usage[key2] >= 0);
47843
47905
  }
47844
47906
  function isUiPromptKind(value2) {
47845
47907
  return value2 === "input" || value2 === "confirm" || value2 === "select" || value2 === "editor" || value2 === "custom";
@@ -48165,6 +48227,12 @@ class InMemoryDurableBackend {
48165
48227
  return this.getWorkflow(workflowId);
48166
48228
  }
48167
48229
  async hydrateWorkflow(_workflowId) {}
48230
+ async hydrateWorkflowForInspection(workflowId) {
48231
+ const handle = this.getLoadableWorkflow(workflowId);
48232
+ if (handle !== undefined)
48233
+ return { kind: "current", handle };
48234
+ return { kind: this.deletedWorkflowIds.has(workflowId) ? "deleted" : "absent" };
48235
+ }
48168
48236
  async hydrateResumableWorkflows() {}
48169
48237
  async prepareWorkflowCatalog() {
48170
48238
  return { resumable: this.listResumableWorkflows(), completed: this.listCompletedWorkflows() };
@@ -50300,17 +50368,24 @@ class DbosDurableBackend {
50300
50368
  throw first;
50301
50369
  }
50302
50370
  async hydrateWorkflow(workflowId) {
50303
- if (this.locallyRegistered.has(workflowId))
50304
- return;
50305
- const info = await this.sdk.retrieveWorkflow(workflowId);
50306
- if (info !== undefined) {
50307
- await this.hydrateInfo(info);
50308
- return;
50371
+ await this.hydrateWorkflowForInspection(workflowId);
50372
+ }
50373
+ async hydrateWorkflowForInspection(workflowId) {
50374
+ if (this.locallyRegistered.has(workflowId)) {
50375
+ const handle = this.getLoadableWorkflow(workflowId);
50376
+ return handle === undefined ? { kind: "malformed" } : { kind: "current", handle };
50309
50377
  }
50378
+ const info = await this.sdk.retrieveWorkflow(workflowId);
50379
+ if (info !== undefined)
50380
+ return await this.hydrateInfo(info);
50310
50381
  const records = await this.sdk.listStepRecords(workflowId);
50311
50382
  const deletion = classifyDbosDeletionTombstone(records, workflowId);
50312
- if (deletion !== "absent")
50313
- await this.suppressWorkflow(workflowId);
50383
+ if (deletion === "absent" && records.length === 0)
50384
+ return { kind: "absent" };
50385
+ await this.suppressWorkflow(workflowId);
50386
+ if (deletion === "absent")
50387
+ return { kind: "malformed" };
50388
+ return { kind: deletion === "current" ? "deleted" : "malformed" };
50314
50389
  }
50315
50390
  async hydrateResumableWorkflows() {
50316
50391
  const all = await this.sdk.listAllWorkflows();
@@ -50322,10 +50397,15 @@ class DbosDurableBackend {
50322
50397
  }
50323
50398
  async hydrateInfo(info) {
50324
50399
  const records = await this.sdk.listStepRecords(info.workflowId);
50400
+ const deletion = classifyDbosDeletionTombstone(records, info.workflowId);
50401
+ if (deletion !== "absent") {
50402
+ await this.suppressWorkflow(info.workflowId);
50403
+ return { kind: deletion === "current" ? "deleted" : "malformed" };
50404
+ }
50325
50405
  const metadata = classifyLatestMetadata(records, info.workflowId);
50326
50406
  if (metadata.kind !== "current") {
50327
50407
  await this.suppressWorkflow(info.workflowId);
50328
- return;
50408
+ return { kind: "malformed" };
50329
50409
  }
50330
50410
  const checkpoints = [];
50331
50411
  for (const record of records) {
@@ -50334,7 +50414,7 @@ class DbosDurableBackend {
50334
50414
  const classified = classifyCheckpointPayload(info.workflowId, record.stepName, record.output);
50335
50415
  if (classified.kind === "unknown") {
50336
50416
  await this.suppressWorkflow(info.workflowId);
50337
- return;
50417
+ return { kind: "malformed" };
50338
50418
  }
50339
50419
  checkpoints.push(classified.checkpoint);
50340
50420
  }
@@ -50345,14 +50425,21 @@ class DbosDurableBackend {
50345
50425
  for (const checkpoint of checkpoints)
50346
50426
  this.mem.recordCheckpoint(checkpoint);
50347
50427
  const current = this.mem.getWorkflow(info.workflowId);
50348
- if (current !== undefined) {
50349
- const pendingPrompts2 = this.promptReservations.hydrate(info.workflowId, metadata.metadata.pendingPrompts, records, metadata.metadata.promptReservationEpoch);
50350
- this.applyMetadata(info.workflowId, {
50351
- ...metadata.metadata,
50352
- pendingPrompts: pendingPrompts2,
50353
- completedCheckpoints: current.completedCheckpoints
50354
- });
50428
+ if (current === undefined) {
50429
+ await this.suppressWorkflow(info.workflowId);
50430
+ return { kind: "malformed" };
50355
50431
  }
50432
+ const pendingPrompts2 = this.promptReservations.hydrate(info.workflowId, metadata.metadata.pendingPrompts, records, metadata.metadata.promptReservationEpoch);
50433
+ this.applyMetadata(info.workflowId, {
50434
+ ...metadata.metadata,
50435
+ pendingPrompts: pendingPrompts2,
50436
+ completedCheckpoints: current.completedCheckpoints
50437
+ });
50438
+ const handle = this.getLoadableWorkflow(info.workflowId);
50439
+ if (handle !== undefined)
50440
+ return { kind: "current", handle };
50441
+ await this.suppressWorkflow(info.workflowId);
50442
+ return { kind: "malformed" };
50356
50443
  }
50357
50444
  async suppressWorkflow(workflowId) {
50358
50445
  this.invalid.add(workflowId);
@@ -51066,20 +51153,34 @@ function priorRunElapsedMs(backend, workflowId) {
51066
51153
  return elapsedMs;
51067
51154
  }
51068
51155
  function recordRunTimingCheckpoint(backend, run, options) {
51156
+ const checkpoint = runTimingCheckpoint(backend, run, options);
51157
+ if (checkpoint === undefined)
51158
+ return false;
51159
+ backend.recordCheckpoint(checkpoint);
51160
+ return true;
51161
+ }
51162
+ async function recordRunTimingCheckpointAsync(backend, run, options) {
51163
+ const checkpoint = runTimingCheckpoint(backend, run, options);
51164
+ if (checkpoint === undefined)
51165
+ return false;
51166
+ await backend.recordCheckpointAsync(checkpoint);
51167
+ return true;
51168
+ }
51169
+ function runTimingCheckpoint(backend, run, options) {
51069
51170
  const now = options?.now ?? Date.now();
51070
51171
  const elapsedMs = elapsedRunMs(run, now);
51071
51172
  if (elapsedMs <= 0)
51072
- return false;
51173
+ return;
51073
51174
  if (backend.listCheckpoints(run.id).length === 0)
51074
- return false;
51175
+ return;
51075
51176
  const recorded = priorRunElapsedMs(backend, run.id);
51076
51177
  if (recorded !== undefined) {
51077
51178
  if (elapsedMs <= recorded)
51078
- return false;
51179
+ return;
51079
51180
  if (options?.debounce === true && timingBucket(elapsedMs) === timingBucket(recorded))
51080
- return false;
51181
+ return;
51081
51182
  }
51082
- const checkpoint = {
51183
+ return {
51083
51184
  kind: "tool",
51084
51185
  workflowId: run.id,
51085
51186
  checkpointId: `run-timing:${elapsedMs}`,
@@ -51088,8 +51189,6 @@ function recordRunTimingCheckpoint(backend, run, options) {
51088
51189
  output: { elapsedMs },
51089
51190
  completedAt: now
51090
51191
  };
51091
- backend.recordCheckpoint(checkpoint);
51092
- return true;
51093
51192
  }
51094
51193
  function inheritedRunElapsedMs(input) {
51095
51194
  const now = input.now ?? Date.now();
@@ -52992,33 +53091,33 @@ function isRunStatus(value2) {
52992
53091
  return false;
52993
53092
  }
52994
53093
  }
52995
- function resolveRunId(target) {
53094
+ function resolveRunId(target, activeStore = store) {
52996
53095
  if (!isFullRunId(target))
52997
53096
  return { kind: "malformed", message: malformedRunIdMessage(target) };
52998
- const exact = store.runs().find((r) => r.id === target);
53097
+ const exact = activeStore.runs().find((r) => r.id === target);
52999
53098
  if (exact)
53000
53099
  return { kind: "exact", runId: exact.id };
53001
53100
  return { kind: "not_found" };
53002
53101
  }
53003
- function resolveToolRunTarget(args, emptyMessage) {
53102
+ function resolveToolRunTarget(args, emptyMessage, activeStore = store) {
53004
53103
  const rawTarget = args.runId?.trim() ?? "";
53005
53104
  if (args.all === true || rawTarget === "--all")
53006
53105
  return { kind: "all" };
53007
- const target = rawTarget || store.activeRunId() || "";
53106
+ const target = rawTarget || activeStore.activeRunId() || "";
53008
53107
  if (!target)
53009
53108
  return { kind: "not_found", target: rawTarget, message: emptyMessage };
53010
- const resolved = resolveRunId(target);
53109
+ const resolved = resolveRunId(target, activeStore);
53011
53110
  if (resolved.kind === "exact")
53012
53111
  return { kind: "run", runId: resolved.runId };
53013
53112
  if (resolved.kind === "malformed")
53014
53113
  return { kind: "malformed", target, message: resolved.message };
53015
53114
  return { kind: "not_found", target, message: `Run not found: ${target}` };
53016
53115
  }
53017
- function resolveStageTarget(runId, stageTarget) {
53116
+ function resolveStageTarget(runId, stageTarget, activeStore = store) {
53018
53117
  const target = stageTarget?.trim();
53019
53118
  if (!target)
53020
53119
  return { ok: true, runId };
53021
- const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
53120
+ const graph = expandWorkflowGraph(readGraphStoreSnapshot(activeStore), runId);
53022
53121
  const exactVirtualIds = graph.stages.filter((stage) => stage.id === target);
53023
53122
  if (exactVirtualIds.length === 1)
53024
53123
  return resolvedStageTarget(exactVirtualIds[0]);
@@ -53054,8 +53153,8 @@ function ambiguousStageTarget(target, stages) {
53054
53153
  message: `Ambiguous stage identifier "${target}" matches: ${stages.map(expandedStageLabel).join(", ")}`
53055
53154
  };
53056
53155
  }
53057
- function resolveToolStageTarget(runId, stageTarget) {
53058
- return resolveStageTarget(runId, stageTarget);
53156
+ function resolveToolStageTarget(runId, stageTarget, activeStore = store) {
53157
+ return resolveStageTarget(runId, stageTarget, activeStore);
53059
53158
  }
53060
53159
  function resolveControlNodeTarget(runId, stageTarget) {
53061
53160
  const target = stageTarget?.trim();
@@ -61101,6 +61200,9 @@ class ScopedDurableBackend {
61101
61200
  hydrateWorkflow(_workflowId) {
61102
61201
  return Promise.resolve();
61103
61202
  }
61203
+ hydrateWorkflowForInspection(_workflowId) {
61204
+ return Promise.resolve({ kind: "absent" });
61205
+ }
61104
61206
  hydrateResumableWorkflows() {
61105
61207
  return Promise.resolve();
61106
61208
  }
@@ -64784,7 +64886,7 @@ function createDurableStageSessionRecorder(input) {
64784
64886
  if (stageRunId === input.runId) {
64785
64887
  await recordStageSessionCheckpoint(input.deps, snapshot, { force: options?.forceDurable === true });
64786
64888
  if (input.runSnapshot !== undefined) {
64787
- recordRunTimingCheckpoint(input.deps.backend, input.runSnapshot, {
64889
+ await recordRunTimingCheckpointAsync(input.deps.backend, input.runSnapshot, {
64788
64890
  debounce: options?.forceDurable !== true
64789
64891
  });
64790
64892
  }
@@ -64833,7 +64935,7 @@ function hasUsableContentBlock(block) {
64833
64935
  }
64834
64936
 
64835
64937
  // dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts
64836
- function validBoundaryRecordSet(checkpoints, strict) {
64938
+ function validBoundaryRecordSet(checkpoints, strict, requireActiveFingerprint = false) {
64837
64939
  const stages = checkpoints.filter((item) => item.kind === "stage");
64838
64940
  const boundaries = stages.filter((item) => item.topology?.boundary !== undefined);
64839
64941
  const startsByReplay = new Map;
@@ -64848,42 +64950,59 @@ function validBoundaryRecordSet(checkpoints, strict) {
64848
64950
  return false;
64849
64951
  if (boundaries.some((checkpoint) => checkpoint.topology.boundary.event === "terminal" && startsByReplay.get(checkpoint.replayKey)?.length !== 1))
64850
64952
  return false;
64851
- return [...startsByReplay.values()].every((starts) => boundaryTransitionError(starts[0], stages, strict) === undefined);
64953
+ return [...startsByReplay.values()].every((starts) => {
64954
+ const start = starts[0];
64955
+ if (boundaryTransitionError(start, stages, strict) !== undefined)
64956
+ return false;
64957
+ if (!requireActiveFingerprint || start.topology.boundary.invocationFingerprint !== undefined)
64958
+ return true;
64959
+ return stages.some((stage) => stage.replayKey === start.replayKey && stage.topology?.boundary?.event === "terminal" && stage.topology.boundary.status === "completed") && boundaryTransitionError(start, stages, true) === undefined;
64960
+ });
64852
64961
  }
64853
- function validStageGroup(drafts, runId, allowedNodeIds = new Set) {
64962
+ function validStageGroup(drafts, runId, rootRunId, tools = []) {
64854
64963
  if (drafts.some((draft) => draft.topology.stageId.length === 0))
64855
64964
  return false;
64856
- const stageIds = new Set(drafts.map((draft) => draft.topology.stageId));
64857
- if (stageIds.size !== drafts.length)
64965
+ if (tools.some((tool) => tool.topology !== undefined && (tool.topology.version !== DURABLE_TOOL_TOPOLOGY_VERSION || tool.topology.nodeId.length === 0)))
64858
64966
  return false;
64859
- const ids = new Set([...allowedNodeIds, ...stageIds]);
64860
- if (ids.size !== allowedNodeIds.size + stageIds.size)
64967
+ const stageIds = drafts.map((draft) => draft.topology.stageId);
64968
+ const toolIds = tools.map((tool) => tool.topology?.nodeId ?? tool.checkpointId);
64969
+ const ids = new Set([...stageIds, ...toolIds]);
64970
+ if (ids.size !== stageIds.length + toolIds.length)
64861
64971
  return false;
64862
64972
  const orders = drafts.flatMap((draft) => draft.topology.sourceOrder === undefined ? [] : [draft.topology.sourceOrder]);
64863
64973
  if (new Set(orders).size !== orders.length)
64864
64974
  return false;
64865
- if (drafts.some((draft) => draft.topology.parentIds.some((parentId) => !ids.has(parentId))))
64975
+ const parentEntries = [
64976
+ ...drafts.map((draft) => [draft.topology.stageId, draft.topology.parentIds]),
64977
+ ...tools.map((tool) => [tool.topology?.nodeId ?? tool.checkpointId, tool.topology?.parentIds ?? []])
64978
+ ];
64979
+ if (parentEntries.some(([, parentIds]) => parentIds.some((parentId) => !ids.has(parentId))))
64866
64980
  return false;
64867
- const runs = drafts.flatMap((draft) => draft.topology?.run === undefined ? [] : [draft.topology.run]);
64981
+ const runs = [
64982
+ ...drafts.flatMap((draft) => draft.topology?.run === undefined ? [] : [draft.topology.run]),
64983
+ ...tools.flatMap((tool) => tool.topology?.run === undefined ? [] : [tool.topology.run])
64984
+ ];
64868
64985
  const first = runs[0];
64869
64986
  if (runs.some((run) => run.runId !== runId || first !== undefined && (run.runName !== first.runName || run.parentRunId !== first.parentRunId || run.parentStageId !== first.parentStageId || run.rootRunId !== first.rootRunId)))
64870
64987
  return false;
64871
- const parents = new Map(drafts.map((draft) => [draft.topology.stageId, draft.topology.parentIds]));
64988
+ if (runId === rootRunId && runs.some((run) => run.parentRunId !== undefined || run.parentStageId !== undefined || run.rootRunId !== undefined))
64989
+ return false;
64990
+ const parents = new Map(parentEntries);
64872
64991
  const visiting = new Set;
64873
64992
  const visited = new Set;
64874
- const cyclic = (stageId) => {
64875
- if (visiting.has(stageId))
64993
+ const cyclic = (nodeId) => {
64994
+ if (visiting.has(nodeId))
64876
64995
  return true;
64877
- if (visited.has(stageId))
64996
+ if (visited.has(nodeId))
64878
64997
  return false;
64879
- visiting.add(stageId);
64880
- if ((parents.get(stageId) ?? []).some(cyclic))
64998
+ visiting.add(nodeId);
64999
+ if ((parents.get(nodeId) ?? []).some(cyclic))
64881
65000
  return true;
64882
- visiting.delete(stageId);
64883
- visited.add(stageId);
65001
+ visiting.delete(nodeId);
65002
+ visited.add(nodeId);
64884
65003
  return false;
64885
65004
  };
64886
- return ![...stageIds].some(cyclic);
65005
+ return ![...ids].some(cyclic);
64887
65006
  }
64888
65007
  function compareDraftSourceOrder(left, right) {
64889
65008
  const leftOrder = left.topology?.sourceOrder;
@@ -65425,7 +65544,7 @@ function completedWorkflowRunSnapshots(backend, entry) {
65425
65544
  const checkpoints = backend.listCheckpoints(entry.workflowId);
65426
65545
  if (checkpoints.length === 0)
65427
65546
  return [];
65428
- const runs = runSnapshotsFromCheckpoints(checkpoints, handle.workflowId, handle.name, handle.updatedAt).map((run2) => ({ ...run2, stages: run2.stages.map(validatedStageTranscript) }));
65547
+ const runs = runSnapshotsFromCheckpoints(checkpoints, handle.workflowId, handle.name, handle.updatedAt, COMPLETED_RECONSTRUCTION).map((run2) => ({ ...run2, stages: run2.stages.map(validatedStageTranscript) }));
65429
65548
  const rootIndex = runs.findIndex((run2) => run2.id === handle.workflowId);
65430
65549
  if (rootIndex < 0)
65431
65550
  return [];
@@ -65449,11 +65568,45 @@ function completedWorkflowRunSnapshots(backend, entry) {
65449
65568
  };
65450
65569
  return [root, ...runs.filter((_, index) => index !== rootIndex)];
65451
65570
  }
65571
+ function durableWorkflowRunSnapshots(backend, handle) {
65572
+ const checkpoints = backend.listCheckpoints(handle.workflowId);
65573
+ if (checkpoints.length === 0) {
65574
+ return [rootSnapshot(backend, handle, { stages: [], toolNodes: [] })];
65575
+ }
65576
+ const requiresTerminalTopology = handle.status === "completed" || handle.status === "failed";
65577
+ const runs = runSnapshotsFromCheckpoints(checkpoints, handle.workflowId, handle.name, handle.updatedAt, requiresTerminalTopology ? COMPLETED_RECONSTRUCTION : ACTIVE_INSPECTION_RECONSTRUCTION);
65578
+ const rootIndex = runs.findIndex((run2) => run2.id === handle.workflowId);
65579
+ if (rootIndex < 0)
65580
+ return [];
65581
+ return [rootSnapshot(backend, handle, runs[rootIndex]), ...runs.filter((_, index) => index !== rootIndex)];
65582
+ }
65583
+ function rootSnapshot(backend, handle, graph) {
65584
+ const terminal = handle.status === "completed" || handle.status === "failed" || handle.status === "cancelled";
65585
+ const priorDurationMs = priorRunElapsedMs(backend, handle.workflowId);
65586
+ const terminalDurationMs = priorDurationMs ?? Math.max(0, handle.updatedAt - handle.createdAt);
65587
+ return {
65588
+ id: handle.workflowId,
65589
+ name: handle.name,
65590
+ inputs: { ...handle.inputs },
65591
+ status: handle.status,
65592
+ stages: graph.stages,
65593
+ toolNodes: graph.toolNodes,
65594
+ startedAt: handle.createdAt,
65595
+ ...terminal ? { endedAt: handle.updatedAt, durationMs: terminalDurationMs } : priorDurationMs === undefined ? {} : { accumulatedDurationMs: priorDurationMs },
65596
+ ...handle.error !== undefined ? { error: handle.error } : {},
65597
+ ...handle.failureKind !== undefined ? { failureKind: handle.failureKind } : {},
65598
+ ...handle.failureCode !== undefined ? { failureCode: handle.failureCode } : {},
65599
+ ...handle.failureRecoverability !== undefined ? { failureRecoverability: handle.failureRecoverability } : {},
65600
+ ...handle.failureDisposition !== undefined ? { failureDisposition: handle.failureDisposition } : {},
65601
+ ...handle.failedToolNodeId !== undefined ? { failedToolNodeId: handle.failedToolNodeId } : {},
65602
+ resumable: isDurableWorkflowResumable(handle)
65603
+ };
65604
+ }
65452
65605
  function durableNestedRunSnapshots(backend, rootWorkflowId) {
65453
65606
  const handle = backend.getWorkflow(rootWorkflowId);
65454
65607
  if (handle === undefined)
65455
65608
  return [];
65456
- return runSnapshotsFromCheckpoints(backend.listCheckpoints(rootWorkflowId), rootWorkflowId, handle.name, handle.updatedAt, false).filter((run2) => run2.id !== rootWorkflowId);
65609
+ return runSnapshotsFromCheckpoints(backend.listCheckpoints(rootWorkflowId), rootWorkflowId, handle.name, handle.updatedAt, LEGACY_ACTIVE_RECONSTRUCTION).filter((run2) => run2.id !== rootWorkflowId);
65457
65610
  }
65458
65611
  function validatedStageTranscript(stage) {
65459
65612
  if (stage.sessionFile === undefined || isReopenableSessionTranscript(stage.sessionFile))
@@ -65523,15 +65676,36 @@ function summarizeCompletedToolResult(value2) {
65523
65676
  return flattenTruncatedString(String(value2).slice(0, 240));
65524
65677
  return serialized.length <= 240 ? serialized : `${flattenTruncatedString(serialized.slice(0, 237))}...`;
65525
65678
  }
65526
- function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallbackCompletedAt, strict = true) {
65527
- if (!validBoundaryRecordSet(checkpoints, strict))
65679
+ var COMPLETED_RECONSTRUCTION = {
65680
+ requireTerminal: true,
65681
+ failClosed: true,
65682
+ retainActive: false,
65683
+ failOnUnreachable: false,
65684
+ requireActiveBoundaryFingerprint: false
65685
+ };
65686
+ var ACTIVE_INSPECTION_RECONSTRUCTION = {
65687
+ requireTerminal: false,
65688
+ failClosed: true,
65689
+ retainActive: true,
65690
+ failOnUnreachable: true,
65691
+ requireActiveBoundaryFingerprint: true
65692
+ };
65693
+ var LEGACY_ACTIVE_RECONSTRUCTION = {
65694
+ requireTerminal: false,
65695
+ failClosed: false,
65696
+ retainActive: true,
65697
+ failOnUnreachable: false,
65698
+ requireActiveBoundaryFingerprint: false
65699
+ };
65700
+ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallbackCompletedAt, policy = COMPLETED_RECONSTRUCTION) {
65701
+ if (!validBoundaryRecordSet(checkpoints, policy.requireTerminal, policy.requireActiveBoundaryFingerprint))
65528
65702
  return [];
65529
65703
  const stageRecords = checkpoints.filter((checkpoint) => checkpoint.kind === "stage");
65530
65704
  const identityRecords = stageRecords.filter((stage) => stage.topology?.sourceOrder !== undefined || stage.topology?.status !== undefined || stage.topology?.occurrenceKey !== undefined || stage.topology?.boundary !== undefined);
65531
65705
  if (immutableStageGroupError(identityRecords) !== undefined)
65532
65706
  return [];
65533
65707
  const recordsByGroup = groupByDurableStageKey(stageRecords);
65534
- const candidates = [...recordsByGroup.values()].map((records) => mergeStageGroup(records, stageRecords, checkpoints)).filter((draft) => !strict || draft.topology?.run === undefined || draft.endedAt !== undefined || draft.output !== undefined).map((draft) => draft.topology !== undefined ? draft : {
65708
+ const candidates = [...recordsByGroup.values()].map((records) => mergeStageGroup(records, stageRecords, checkpoints)).filter((draft) => policy.retainActive || draft.topology?.run === undefined || draft.endedAt !== undefined || draft.output !== undefined).map((draft) => draft.topology !== undefined ? draft : {
65535
65709
  ...draft,
65536
65710
  topology: {
65537
65711
  version: DURABLE_STAGE_TOPOLOGY_VERSION,
@@ -65542,13 +65716,36 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65542
65716
  }).sort(compareDraftSourceOrder);
65543
65717
  const drafts = checkpointDrafts(checkpoints);
65544
65718
  const toolCheckpoints = drafts.tools;
65719
+ if (policy.failClosed) {
65720
+ for (const draft of candidates) {
65721
+ const boundary = draft.topology?.boundary;
65722
+ if (boundary === undefined || childRunIdFromDraft(draft) === undefined)
65723
+ continue;
65724
+ if (boundary.replayScope !== draft.replayKey)
65725
+ return [];
65726
+ const expectedChildRun = {
65727
+ runId: boundary.child.runId,
65728
+ runName: boundary.child.runName,
65729
+ parentRunId: boundary.child.parentRunId,
65730
+ parentStageId: boundary.child.parentStageId,
65731
+ rootRunId: boundary.child.rootRunId
65732
+ };
65733
+ const childToolIds = new Set(toolCheckpoints.flatMap((checkpoint) => checkpoint.topology?.run?.runId === expectedChildRun.runId ? [checkpoint.topology.nodeId] : []));
65734
+ if (directChildTopologyError(stageRecords, boundary.replayScope, expectedChildRun, true, childToolIds) !== undefined)
65735
+ return [];
65736
+ }
65737
+ }
65545
65738
  if (candidates.length === 0 && toolCheckpoints.length === 0) {
65546
- return strict ? [] : [syntheticRun(rootRunId, rootRunName, checkpoints.length, fallbackCompletedAt)];
65739
+ const supportedNonGraphState = checkpoints.every((checkpoint) => checkpoint.kind === "ui" || checkpoint.kind === "tool" && checkpoint.argsHash === RUN_TIMING_CHECKPOINT_NAME);
65740
+ if (policy.failClosed && supportedNonGraphState) {
65741
+ return [emptyGraphRun(rootRunId, rootRunName, fallbackCompletedAt)];
65742
+ }
65743
+ return policy.failClosed ? [] : [syntheticRun(rootRunId, rootRunName, checkpoints.length, fallbackCompletedAt)];
65547
65744
  }
65548
65745
  const grouped = new Map;
65549
65746
  for (const draft of candidates) {
65550
65747
  if (draft.topology?.version !== DURABLE_STAGE_TOPOLOGY_VERSION) {
65551
- if (strict)
65748
+ if (policy.failClosed)
65552
65749
  return [];
65553
65750
  continue;
65554
65751
  }
@@ -65564,7 +65761,10 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65564
65761
  }
65565
65762
  for (const group of grouped.values())
65566
65763
  group.sort(compareDraftSourceOrder);
65764
+ const groupedCount = grouped.size;
65567
65765
  retainReachableRunGroups(grouped, rootRunId);
65766
+ if (policy.failOnUnreachable && grouped.size !== groupedCount)
65767
+ return [];
65568
65768
  if (!validateRunGroups(grouped, rootRunId, toolCheckpoints, checkpoints))
65569
65769
  return [];
65570
65770
  const syntheticChildren = [];
@@ -65574,7 +65774,7 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65574
65774
  if (child?.exited !== true || grouped.has(child.runId))
65575
65775
  continue;
65576
65776
  if (!isSyntheticExitedChild(draft, parentRunId, child.runId, rootRunId) || childScopedEvidenceExists(checkpoints, draft.replayKey, child.runId)) {
65577
- if (strict)
65777
+ if (policy.failClosed)
65578
65778
  return [];
65579
65779
  continue;
65580
65780
  }
@@ -65583,8 +65783,8 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65583
65783
  }
65584
65784
  const idMaps = new Map;
65585
65785
  for (const [runId, runDrafts] of grouped) {
65586
- const ownedToolIds = new Set(toolCheckpoints.flatMap((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId ? [checkpoint.topology?.nodeId ?? checkpoint.checkpointId] : []));
65587
- if (!validStageGroup(runDrafts, runId, ownedToolIds))
65786
+ const ownedTools = toolCheckpoints.filter((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId);
65787
+ if (!validStageGroup(runDrafts, runId, rootRunId, ownedTools))
65588
65788
  return [];
65589
65789
  const ids = new Map;
65590
65790
  let hasIdentityConflict = false;
@@ -65600,7 +65800,7 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65600
65800
  }
65601
65801
  });
65602
65802
  if (hasIdentityConflict) {
65603
- if (strict)
65803
+ if (policy.failClosed)
65604
65804
  return [];
65605
65805
  grouped.delete(runId);
65606
65806
  continue;
@@ -65620,7 +65820,7 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65620
65820
  const ownedTools = toolCheckpoints.filter((checkpoint) => (checkpoint.topology?.run?.runId ?? rootRunId) === runId);
65621
65821
  const hasUnknownParents = runDrafts.some((draft) => draft.topology.parentIds.some((parentId) => !ids.has(parentId))) || ownedTools.some((checkpoint) => checkpoint.topology?.parentIds.some((parentId) => !ids.has(parentId)) === true);
65622
65822
  if (hasUnknownParents) {
65623
- if (strict)
65823
+ if (policy.failClosed)
65624
65824
  return [];
65625
65825
  continue;
65626
65826
  }
@@ -65630,6 +65830,8 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65630
65830
  const startedAt = Math.min(...stages.map((stage) => stage.startedAt ?? fallbackCompletedAt), ...toolNodes.map((tool) => tool.startedAt ?? tool.endedAt ?? fallbackCompletedAt));
65631
65831
  const endedAt = Math.max(...stages.map((stage) => stage.endedAt ?? fallbackCompletedAt), ...toolNodes.map((tool) => tool.endedAt ?? fallbackCompletedAt));
65632
65832
  const owner = runId === rootRunId ? undefined : boundaryOwner(grouped, runId);
65833
+ const status = owner === undefined ? "completed" : childRunStatus(owner);
65834
+ const terminal = status !== "running" && status !== "pending" && status !== "paused" && status !== "blocked";
65633
65835
  const parentRunId = run2?.parentRunId ?? rootRunId;
65634
65836
  const boundarySourceId = grouped.get(parentRunId)?.find((draft) => childRunIdFromDraft(draft) === runId)?.topology?.stageId;
65635
65837
  const declaredParentStageId = run2?.parentStageId === undefined ? undefined : idMaps.get(parentRunId)?.get(run2.parentStageId);
@@ -65639,12 +65841,11 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65639
65841
  id: runId,
65640
65842
  name: run2?.runName ?? rootRunName,
65641
65843
  inputs: {},
65642
- status: owner === undefined ? "completed" : childRunStatus(owner),
65844
+ status,
65643
65845
  stages,
65644
65846
  toolNodes,
65645
65847
  startedAt,
65646
- endedAt,
65647
- durationMs: Math.max(0, endedAt - startedAt),
65848
+ ...terminal ? { endedAt, durationMs: Math.max(0, endedAt - startedAt) } : {},
65648
65849
  ...run2?.parentRunId !== undefined ? { parentRunId: run2.parentRunId } : {},
65649
65850
  ...parentStageId !== undefined ? { parentStageId } : {},
65650
65851
  ...run2?.rootRunId !== undefined ? { rootRunId: run2.rootRunId } : {},
@@ -65659,7 +65860,7 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65659
65860
  }
65660
65861
  for (const { parentRunId, owner, child } of syntheticChildren) {
65661
65862
  if (!emittedRunIds.has(parentRunId)) {
65662
- if (strict)
65863
+ if (policy.failClosed)
65663
65864
  return [];
65664
65865
  continue;
65665
65866
  }
@@ -65667,7 +65868,7 @@ function runSnapshotsFromCheckpoints(checkpoints, rootRunId, rootRunName, fallba
65667
65868
  const boundary = topology.boundary;
65668
65869
  const parentStageId = idMaps.get(parentRunId)?.get(topology.stageId);
65669
65870
  if (parentStageId === undefined) {
65670
- if (strict)
65871
+ if (policy.failClosed)
65671
65872
  return [];
65672
65873
  continue;
65673
65874
  }
@@ -65736,6 +65937,20 @@ function stageResult(draft) {
65736
65937
  return;
65737
65938
  return typeof draft.output === "string" ? draft.output : JSON.stringify(draft.output);
65738
65939
  }
65940
+ function emptyGraphRun(runId, runName, completedAt) {
65941
+ return {
65942
+ id: runId,
65943
+ name: runName,
65944
+ inputs: {},
65945
+ status: "completed",
65946
+ stages: [],
65947
+ toolNodes: [],
65948
+ startedAt: completedAt,
65949
+ endedAt: completedAt,
65950
+ durationMs: 0,
65951
+ resumable: false
65952
+ };
65953
+ }
65739
65954
  function syntheticRun(runId, runName, checkpointCount, completedAt) {
65740
65955
  return {
65741
65956
  id: runId,
@@ -66619,7 +66834,7 @@ function createTrackedStageCaller(input) {
66619
66834
  if (suppressQueuedContinuation)
66620
66835
  runtime.state.suppressQueuedUserMessageContinuation = true;
66621
66836
  try {
66622
- result = await raceAbort(runtime.innerCtx.prompt(RESUME_CONTINUATION_PROMPT), runtime.signal);
66837
+ result = await runtime.raceStageSessionHeartbeat(raceAbort(runtime.innerCtx.prompt(RESUME_CONTINUATION_PROMPT), runtime.signal));
66623
66838
  } finally {
66624
66839
  if (suppressQueuedContinuation)
66625
66840
  runtime.state.suppressQueuedUserMessageContinuation = false;
@@ -66646,46 +66861,51 @@ function createTrackedStageCaller(input) {
66646
66861
  throw err;
66647
66862
  }
66648
66863
  const trackStageLifecycle = !runtime.state.stageFinalized;
66649
- let refreshedParentIds;
66650
- if (trackStageLifecycle && !input.hasContinuation && runtime.stageSnapshot.startedAt === undefined && !input.hasScopedParents) {
66651
- const actualParentIds = runtime.scheduler.tracker.currentParents();
66652
- const sameParents = actualParentIds.length === runtime.stageSnapshot.parentIds.length && actualParentIds.every((value2) => runtime.stageSnapshot.parentIds.includes(value2));
66653
- if (!sameParents) {
66654
- runtime.scheduler.tracker.replaceParents(runtime.stageId, actualParentIds);
66655
- refreshedParentIds = actualParentIds;
66656
- }
66657
- }
66658
- if (trackStageLifecycle) {
66659
- const now = Date.now();
66660
- const hasNoExplicitModelConfig = input.options?.model === undefined && input.options?.fallbackModels === undefined;
66661
- const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
66662
- if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && (hasNoExplicitModelConfig || await hasExplicitFastModeCandidate({
66663
- model: input.options?.model,
66664
- fallbackModels: input.options?.fallbackModels,
66665
- models: runtime.opts.models
66666
- }))) {
66667
- try {
66668
- await runtime.innerCtx.__ensureSession();
66669
- runtime.captureStageSessionMeta();
66670
- } catch (err) {
66671
- if (!(err instanceof Error && err.message.includes("prompt adapter not configured")))
66672
- throw err;
66864
+ let applyTerminalStageState;
66865
+ let terminalStateIsSuccess = false;
66866
+ try {
66867
+ let refreshedParentIds;
66868
+ if (trackStageLifecycle && !input.hasContinuation && runtime.stageSnapshot.startedAt === undefined && !input.hasScopedParents) {
66869
+ const actualParentIds = runtime.scheduler.tracker.currentParents();
66870
+ const sameParents = actualParentIds.length === runtime.stageSnapshot.parentIds.length && actualParentIds.every((value2) => runtime.stageSnapshot.parentIds.includes(value2));
66871
+ if (!sameParents) {
66872
+ runtime.scheduler.tracker.replaceParents(runtime.stageId, actualParentIds);
66873
+ refreshedParentIds = actualParentIds;
66673
66874
  }
66674
66875
  }
66675
- if (refreshedParentIds !== undefined) {
66676
- runtime.scheduler.setStageParentIds(runtime.stageSnapshot, refreshedParentIds);
66876
+ if (trackStageLifecycle) {
66877
+ const now = Date.now();
66878
+ const hasNoExplicitModelConfig = input.options?.model === undefined && input.options?.fallbackModels === undefined;
66879
+ const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
66880
+ if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && (hasNoExplicitModelConfig || await hasExplicitFastModeCandidate({
66881
+ model: input.options?.model,
66882
+ fallbackModels: input.options?.fallbackModels,
66883
+ models: runtime.opts.models
66884
+ }))) {
66885
+ try {
66886
+ await runtime.innerCtx.__ensureSession();
66887
+ } catch (err) {
66888
+ if (!(err instanceof Error && err.message.includes("prompt adapter not configured")))
66889
+ throw err;
66890
+ }
66891
+ }
66892
+ if (refreshedParentIds !== undefined) {
66893
+ runtime.scheduler.setStageParentIds(runtime.stageSnapshot, refreshedParentIds);
66894
+ }
66895
+ runtime.stageSnapshot.status = "running";
66896
+ runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
66897
+ runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
66898
+ runtime.activeStore.recordStageStart(runtime.runId, runtime.stageSnapshot);
66899
+ runtime.appendStageStartOnce();
66900
+ const sessionMeta = runtime.innerCtx.__sessionMeta();
66901
+ if (sessionMeta.sessionId !== undefined || sessionMeta.sessionFile !== undefined) {
66902
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
66903
+ }
66904
+ runtime.startStageSessionHeartbeat();
66905
+ } else {
66906
+ runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
66677
66907
  }
66678
- runtime.stageSnapshot.status = "running";
66679
- runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
66680
- runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
66681
- runtime.activeStore.recordStageStart(runtime.runId, runtime.stageSnapshot);
66682
- runtime.appendStageStartOnce();
66683
- } else {
66684
- runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
66685
- }
66686
- runtime.mcpScope.apply();
66687
- let applyTerminalStageState;
66688
- try {
66908
+ runtime.mcpScope.apply();
66689
66909
  const abortSession = () => {
66690
66910
  runtime.innerCtx.abort().catch(() => {});
66691
66911
  };
@@ -66697,7 +66917,7 @@ function createTrackedStageCaller(input) {
66697
66917
  try {
66698
66918
  runtime.state.askUserQuestionObservedThisTurn = false;
66699
66919
  runtime.state.chatAnswerObservedThisTurn = false;
66700
- result = await raceAbort(call(), runtime.signal);
66920
+ result = await runtime.raceStageSessionHeartbeat(raceAbort(call(), runtime.signal));
66701
66921
  const initialDrain = await drainResumeContinuations(result);
66702
66922
  result = initialDrain.result;
66703
66923
  let repeatReadinessAfterChatTurn = initialDrain.chatAnswerObserved;
@@ -66721,10 +66941,10 @@ function createTrackedStageCaller(input) {
66721
66941
  runtime.state.chatAnswerObservedThisTurn = false;
66722
66942
  runtime.state.waitingForStageChatTurn = true;
66723
66943
  try {
66724
- await raceAbort(new Promise((resolve12) => {
66944
+ await runtime.raceStageSessionHeartbeat(raceAbort(new Promise((resolve12) => {
66725
66945
  resolveNextTurnEnd = resolve12;
66726
66946
  runtime.state.wakeWaitingForStageChatTurn = resolve12;
66727
- }), runtime.signal);
66947
+ }), runtime.signal));
66728
66948
  } finally {
66729
66949
  runtime.state.wakeWaitingForStageChatTurn = undefined;
66730
66950
  runtime.state.waitingForStageChatTurn = false;
@@ -66748,7 +66968,7 @@ function createTrackedStageCaller(input) {
66748
66968
  runtime.signal.removeEventListener("abort", abortSession);
66749
66969
  }
66750
66970
  await runtime.innerCtx.__closeGeneration();
66751
- runtime.captureStageSessionMeta();
66971
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
66752
66972
  runtime.applyModelFallbackMeta(runtime.innerCtx.__modelFallbackMeta());
66753
66973
  if (trackStageLifecycle && runtime.stageFailFastScope?.failed === true && runtime.stageFailFastScope.activeStages.has(runtime.stageId)) {
66754
66974
  runtime.markSkippedForParallelFailFast();
@@ -66758,6 +66978,7 @@ function createTrackedStageCaller(input) {
66758
66978
  throw runtime.parallelFailFastError();
66759
66979
  if (trackStageLifecycle) {
66760
66980
  const assistantText = runtime.innerCtx.__getLastAssistantText();
66981
+ terminalStateIsSuccess = true;
66761
66982
  applyTerminalStageState = () => {
66762
66983
  runtime.stageSnapshot.status = "completed";
66763
66984
  if (assistantText !== undefined)
@@ -66782,15 +67003,30 @@ function createTrackedStageCaller(input) {
66782
67003
  }
66783
67004
  throw err;
66784
67005
  } finally {
66785
- runtime.mcpScope.clear();
66786
67006
  let finalizationError;
67007
+ let durableCheckpointError;
66787
67008
  try {
66788
- await runtime.innerCtx.__closeGeneration();
66789
- runtime.captureStageSessionMeta();
67009
+ runtime.mcpScope.clear();
66790
67010
  } catch (err) {
66791
67011
  finalizationError = { thrown: true, error: err };
66792
67012
  }
67013
+ try {
67014
+ await runtime.drainStageSessionHeartbeat();
67015
+ } catch (err) {
67016
+ durableCheckpointError = { thrown: true, error: err };
67017
+ }
67018
+ try {
67019
+ await runtime.innerCtx.__closeGeneration();
67020
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
67021
+ } catch (err) {
67022
+ durableCheckpointError ??= { thrown: true, error: err };
67023
+ }
67024
+ finalizationError ??= durableCheckpointError;
66793
67025
  if (trackStageLifecycle) {
67026
+ if (durableCheckpointError !== undefined && terminalStateIsSuccess) {
67027
+ const failure3 = runtime.classifyExecutorFailure(durableCheckpointError.error);
67028
+ applyTerminalStageState = () => applyFailureToStage(runtime.stageSnapshot, failure3);
67029
+ }
66794
67030
  if (!runtime.state.stageFinalized)
66795
67031
  applyTerminalStageState?.();
66796
67032
  try {
@@ -67027,7 +67263,7 @@ function createStageControlHandle(runtime) {
67027
67263
  if (sessionFile === undefined)
67028
67264
  return;
67029
67265
  await runtime.innerCtx.__ensureSessionFromFile(sessionFile);
67030
- runtime.captureStageSessionMeta();
67266
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
67031
67267
  };
67032
67268
  const toolExecutions = new StageToolExecutionBuffer;
67033
67269
  const queuedUserMessages = new StageQueuedUserMessageBuffer;
@@ -67071,7 +67307,7 @@ function createStageControlHandle(runtime) {
67071
67307
  await ensureMessagingSession();
67072
67308
  await runtime.innerCtx.__ensureSession();
67073
67309
  runtime.throwIfStageMutationBlocked();
67074
- runtime.captureStageSessionMeta();
67310
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
67075
67311
  },
67076
67312
  async sendUserMessage(text, options, beforeDelivery) {
67077
67313
  runtime.throwIfStageMutationBlocked();
@@ -68229,6 +68465,28 @@ function terminatingToolCallId(event) {
68229
68465
  }
68230
68466
 
68231
68467
  // dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts
68468
+ function hasMeaningfulUsage(usage) {
68469
+ if (usage === undefined)
68470
+ return false;
68471
+ const values = [usage.input, usage.output, usage.cacheRead, usage.cacheWrite, usage.totalTokens, usage.cost.total];
68472
+ return values.every((value2) => Number.isFinite(value2) && value2 >= 0) && values.some((value2) => value2 > 0);
68473
+ }
68474
+ function usageForAttempt(messages, start, discarded) {
68475
+ const totals = { ...discarded };
68476
+ let meaningful = totals.turns > 0;
68477
+ for (const message of messages.slice(start)) {
68478
+ if (message.role !== "assistant" || !hasMeaningfulUsage(message.usage))
68479
+ continue;
68480
+ totals.input += message.usage.input;
68481
+ totals.output += message.usage.output;
68482
+ totals.cacheRead += message.usage.cacheRead;
68483
+ totals.cacheWrite += message.usage.cacheWrite;
68484
+ totals.cost += message.usage.cost.total;
68485
+ totals.turns += 1;
68486
+ meaningful = true;
68487
+ }
68488
+ return meaningful ? totals : undefined;
68489
+ }
68232
68490
  function isSessionCreationPauseResult(value2) {
68233
68491
  return "kind" in value2 && value2.kind === "paused";
68234
68492
  }
@@ -68291,6 +68549,15 @@ class StageSessionController {
68291
68549
  sessionPromise;
68292
68550
  reattachSessionFile;
68293
68551
  lastPromptStartIndex;
68552
+ attemptUsageStartIndex;
68553
+ discardedAttemptUsage = {
68554
+ input: 0,
68555
+ output: 0,
68556
+ cacheRead: 0,
68557
+ cacheWrite: 0,
68558
+ cost: 0,
68559
+ turns: 0
68560
+ };
68294
68561
  terminatingToolCallIds = new Set;
68295
68562
  latestStructuredOutputToolErrorValue;
68296
68563
  unsubscribeTerminateWatcher;
@@ -68490,6 +68757,7 @@ class StageSessionController {
68490
68757
  this.activeCandidateIndex = index;
68491
68758
  this.selectedModel = candidate.id;
68492
68759
  this.notifyModelFallbackMetaChange();
68760
+ this.beginAttemptUsage(activeSession);
68493
68761
  const { terminalScanStartIndex } = await this.promptWithThrownErrorRetry(activeSession, promptText, sdkOptions);
68494
68762
  const terminalFailure = latestTerminalAssistantFailureSince(activeSession.messages, terminalScanStartIndex);
68495
68763
  if (terminalFailure !== undefined) {
@@ -68628,9 +68896,38 @@ class StageSessionController {
68628
68896
  }
68629
68897
  return;
68630
68898
  }
68899
+ beginAttemptUsage(session) {
68900
+ this.attemptUsageStartIndex = session.messages.length;
68901
+ this.discardedAttemptUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
68902
+ }
68903
+ takeAttemptUsage(session) {
68904
+ const start = this.attemptUsageStartIndex;
68905
+ const usage = session === undefined || start === undefined ? undefined : usageForAttempt(session.messages, start, this.discardedAttemptUsage);
68906
+ this.clearAttemptUsage();
68907
+ return usage;
68908
+ }
68909
+ clearAttemptUsage() {
68910
+ this.attemptUsageStartIndex = undefined;
68911
+ this.discardedAttemptUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
68912
+ }
68913
+ accrueDiscardedAttemptUsage(message) {
68914
+ if (!hasMeaningfulUsage(message.usage))
68915
+ return;
68916
+ this.discardedAttemptUsage.input += message.usage.input;
68917
+ this.discardedAttemptUsage.output += message.usage.output;
68918
+ this.discardedAttemptUsage.cacheRead += message.usage.cacheRead;
68919
+ this.discardedAttemptUsage.cacheWrite += message.usage.cacheWrite;
68920
+ this.discardedAttemptUsage.cost += message.usage.cost.total;
68921
+ this.discardedAttemptUsage.turns += 1;
68922
+ }
68631
68923
  restoreSessionMessages(session, snapshot, promptText, keepPrompt) {
68632
68924
  const snapshotMessages = new Set(snapshot);
68633
68925
  const admitted = session.messages.filter((message) => !snapshotMessages.has(message));
68926
+ for (const message of admitted) {
68927
+ if (message.role !== "assistant" || message.stopReason !== "error")
68928
+ continue;
68929
+ this.accrueDiscardedAttemptUsage(message);
68930
+ }
68634
68931
  const failedAssistantIndex = admitted.findLastIndex((message) => message.role === "assistant" && message.stopReason === "error");
68635
68932
  const promptUser = admitted.slice(0, failedAssistantIndex < 0 ? admitted.length : failedAssistantIndex).findLast((message) => message.role === "user" && stageUserMessageText(message) === promptText);
68636
68933
  const retainedMessages = admitted.filter((message) => {
@@ -68979,7 +69276,11 @@ class StageSessionController {
68979
69276
  throw new Error(`atomic-workflows: stage "${this.opts.stageName}" session has been disposed`);
68980
69277
  throw this.staleCreationReason(startGeneration);
68981
69278
  }
68982
- return attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
69279
+ const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
69280
+ if (session instanceof Promise)
69281
+ return await session;
69282
+ await this.opts.onSessionReady?.();
69283
+ return session;
68983
69284
  }
68984
69285
  attachSession(created) {
68985
69286
  const result = normalizeSessionCreateResult(created);
@@ -69087,11 +69388,17 @@ class StageSessionController {
69087
69388
  const resumedSession = this.session;
69088
69389
  const resumedLabel = this.selectedModel ?? workflowModelId(resumedSession.model) ?? candidates[0].id;
69089
69390
  this.notifyModelFallbackMetaChange();
69391
+ this.beginAttemptUsage(resumedSession);
69090
69392
  try {
69091
69393
  const { terminalScanStartIndex } = await this.promptWithThrownErrorRetry(resumedSession, text, sdkOptions);
69092
69394
  const terminalFailure = latestTerminalAssistantFailureSince(resumedSession.messages, terminalScanStartIndex);
69093
69395
  if (terminalFailure === undefined || this.capturedStructuredOutputForAttempt()) {
69094
- this.modelAttempts.push({ model: resumedLabel, success: true });
69396
+ const usage = this.takeAttemptUsage(resumedSession);
69397
+ this.modelAttempts.push({
69398
+ model: resumedLabel,
69399
+ success: true,
69400
+ ...usage === undefined ? {} : { usage }
69401
+ });
69095
69402
  this.pendingFallbackWarnings.length = 0;
69096
69403
  this.resumeCurrentSession = true;
69097
69404
  return true;
@@ -69099,13 +69406,24 @@ class StageSessionController {
69099
69406
  throw new WorkflowPromptModelFailure(terminalFailure);
69100
69407
  } catch (err) {
69101
69408
  if (this.capturedStructuredOutputForAttempt() && isRetryableModelFailure(err)) {
69102
- this.modelAttempts.push({ model: resumedLabel, success: true });
69409
+ const usage2 = this.takeAttemptUsage(resumedSession);
69410
+ this.modelAttempts.push({
69411
+ model: resumedLabel,
69412
+ success: true,
69413
+ ...usage2 === undefined ? {} : { usage: usage2 }
69414
+ });
69103
69415
  this.pendingFallbackWarnings.length = 0;
69104
69416
  this.resumeCurrentSession = true;
69105
69417
  return true;
69106
69418
  }
69107
69419
  const message = errorMessage3(err);
69108
- this.modelAttempts.push({ model: resumedLabel, success: false, error: message });
69420
+ const usage = this.takeAttemptUsage(resumedSession);
69421
+ this.modelAttempts.push({
69422
+ model: resumedLabel,
69423
+ success: false,
69424
+ ...usage === undefined ? {} : { usage },
69425
+ error: message
69426
+ });
69109
69427
  if (this.opts.signal?.aborted || !isRetryableModelFailure(err)) {
69110
69428
  this.modelWarnings.push(...this.pendingFallbackWarnings);
69111
69429
  this.pendingFallbackWarnings.length = 0;
@@ -69131,10 +69449,12 @@ class StageSessionController {
69131
69449
  this.recordSuccessfulAttempt(candidate);
69132
69450
  return "handled";
69133
69451
  }
69452
+ const usage = this.takeAttemptUsage(this.session);
69134
69453
  this.modelAttempts.push({
69135
69454
  model: candidate.id,
69136
69455
  success: false,
69137
69456
  ...modelAttemptReasoning(candidate, this.effectiveStageOptions?.thinkingLevel),
69457
+ ...usage === undefined ? {} : { usage },
69138
69458
  error: message
69139
69459
  });
69140
69460
  if (this.opts.signal?.aborted || !isRetryableModelFailure(err) || index === candidates.length - 1) {
@@ -69152,10 +69472,12 @@ class StageSessionController {
69152
69472
  return this.structuredOutputCapture?.called === true && this.opts.signal?.aborted !== true;
69153
69473
  }
69154
69474
  recordSuccessfulAttempt(candidate) {
69475
+ const usage = this.takeAttemptUsage(this.session);
69155
69476
  this.modelAttempts.push({
69156
69477
  model: candidate.id,
69157
69478
  success: true,
69158
- ...modelAttemptReasoning(candidate, this.effectiveStageOptions?.thinkingLevel)
69479
+ ...modelAttemptReasoning(candidate, this.effectiveStageOptions?.thinkingLevel),
69480
+ ...usage === undefined ? {} : { usage }
69159
69481
  });
69160
69482
  this.pendingFallbackWarnings.length = 0;
69161
69483
  this.resumeCurrentSession = true;
@@ -69592,6 +69914,81 @@ function createStageContext2(opts) {
69592
69914
  }
69593
69915
  };
69594
69916
  }
69917
+ // dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts
69918
+ var STAGE_SESSION_HEARTBEAT_INTERVAL_MS = 30000;
69919
+ function createStageSessionHeartbeat(checkpoint, intervalMs = STAGE_SESSION_HEARTBEAT_INTERVAL_MS) {
69920
+ let active2 = false;
69921
+ let timer;
69922
+ let generation = 0;
69923
+ let nextDeadline = 0;
69924
+ let failure3;
69925
+ let inFlight;
69926
+ let rejectFailure;
69927
+ const failureSignal = new Promise((_resolve, reject) => {
69928
+ rejectFailure = reject;
69929
+ });
69930
+ failureSignal.catch(() => {
69931
+ return;
69932
+ });
69933
+ const stopScheduling = () => {
69934
+ active2 = false;
69935
+ generation += 1;
69936
+ if (timer !== undefined)
69937
+ clearTimeout(timer);
69938
+ timer = undefined;
69939
+ };
69940
+ const fail = (error) => {
69941
+ if (failure3 !== undefined)
69942
+ return;
69943
+ failure3 = error;
69944
+ stopScheduling();
69945
+ rejectFailure(error);
69946
+ };
69947
+ const schedule = (scheduledGeneration) => {
69948
+ if (!active2 || failure3 !== undefined || scheduledGeneration !== generation)
69949
+ return;
69950
+ const delayMs = Math.max(0, nextDeadline - Date.now());
69951
+ timer = setTimeout(() => {
69952
+ timer = undefined;
69953
+ const startedAt = Date.now();
69954
+ do
69955
+ nextDeadline += intervalMs;
69956
+ while (nextDeadline <= startedAt);
69957
+ const running = checkpoint().catch(fail).finally(() => {
69958
+ if (inFlight === running)
69959
+ inFlight = undefined;
69960
+ schedule(scheduledGeneration);
69961
+ });
69962
+ inFlight = running;
69963
+ }, delayMs);
69964
+ timer.unref?.();
69965
+ };
69966
+ const drain = async () => {
69967
+ stopScheduling();
69968
+ await inFlight;
69969
+ if (failure3 !== undefined)
69970
+ throw failure3;
69971
+ };
69972
+ return {
69973
+ start() {
69974
+ if (active2 || failure3 !== undefined)
69975
+ return;
69976
+ active2 = true;
69977
+ generation += 1;
69978
+ nextDeadline = Date.now() + intervalMs;
69979
+ schedule(generation);
69980
+ },
69981
+ stop: stopScheduling,
69982
+ drain,
69983
+ fail,
69984
+ race(work) {
69985
+ if (failure3 !== undefined)
69986
+ return Promise.reject(failure3);
69987
+ return Promise.race([work, failureSignal]);
69988
+ }
69989
+ };
69990
+ }
69991
+
69595
69992
  // dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts
69596
69993
  function createWorkflowStageFactory(input) {
69597
69994
  return (name, options, stageFailFastScope) => {
@@ -69672,6 +70069,15 @@ function createWorkflowStageFactory(input) {
69672
70069
  if (meta2.modelAttempts !== undefined)
69673
70070
  stageSnapshot.modelAttempts = meta2.modelAttempts;
69674
70071
  };
70072
+ let runtime;
70073
+ const stageSessionHeartbeat = createStageSessionHeartbeat(async () => {
70074
+ try {
70075
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
70076
+ } catch (error) {
70077
+ await runtime.innerCtx.abort().catch(() => {});
70078
+ throw error;
70079
+ }
70080
+ });
69675
70081
  const innerCtx = createStageContext2({
69676
70082
  stageId,
69677
70083
  stageName: name,
@@ -69687,6 +70093,12 @@ function createWorkflowStageFactory(input) {
69687
70093
  applyModelFallbackMeta(meta2);
69688
70094
  if (stageSnapshot.status === "running")
69689
70095
  input.activeStore.recordStageStart(input.runId, stageSnapshot);
70096
+ },
70097
+ async onSessionReady() {
70098
+ if (stageSnapshot.status !== "running")
70099
+ return;
70100
+ await runtime.captureStageSessionMeta({ awaitDurable: true });
70101
+ runtime.startStageSessionHeartbeat();
69690
70102
  }
69691
70103
  });
69692
70104
  const state2 = {
@@ -69749,8 +70161,7 @@ function createWorkflowStageFactory(input) {
69749
70161
  stageUiBroker.clearStagePrompt(input.runId, stageId);
69750
70162
  await innerCtx.__dispose();
69751
70163
  };
69752
- let runtime;
69753
- const captureStageSessionMeta = (checkpointOptions) => {
70164
+ const captureStageSessionMeta = async (checkpointOptions) => {
69754
70165
  const meta2 = innerCtx.__sessionMeta();
69755
70166
  if (meta2.sessionId !== undefined)
69756
70167
  stageSnapshot.sessionId = meta2.sessionId;
@@ -69759,15 +70170,17 @@ function createWorkflowStageFactory(input) {
69759
70170
  if (meta2.sessionId !== undefined || meta2.sessionFile !== undefined)
69760
70171
  input.activeStore.recordStageSession(input.runId, stageId, meta2);
69761
70172
  const pending = input.opts.onStageSession?.(input.runId, stageSnapshot, checkpointOptions);
69762
- if (checkpointOptions?.forceDurable === true)
69763
- return pending;
70173
+ if (checkpointOptions?.forceDurable === true || checkpointOptions?.awaitDurable === true) {
70174
+ await pending;
70175
+ return;
70176
+ }
69764
70177
  Promise.resolve(pending).catch(() => {});
69765
- return;
69766
70178
  };
69767
70179
  const releaseLiveHandle = async () => {
69768
70180
  if (state2.liveHandleReleased)
69769
70181
  return;
69770
70182
  state2.liveHandleReleased = true;
70183
+ stageSessionHeartbeat.stop();
69771
70184
  runtime.dropStageControlHandle();
69772
70185
  runtime.unregisterStageHandle();
69773
70186
  await disposeInnerContext();
@@ -69800,6 +70213,7 @@ function createWorkflowStageFactory(input) {
69800
70213
  });
69801
70214
  };
69802
70215
  const finalizeStageSnapshot = async () => {
70216
+ stageSessionHeartbeat.stop();
69803
70217
  if (state2.stageFinalized)
69804
70218
  return false;
69805
70219
  if (stageSnapshot.endedAt !== undefined && isTerminalStage(stageSnapshot)) {
@@ -69872,6 +70286,9 @@ function createWorkflowStageFactory(input) {
69872
70286
  dropStageControlHandle: () => {},
69873
70287
  unregisterWorkflowExitCleanup: () => {},
69874
70288
  captureStageSessionMeta,
70289
+ startStageSessionHeartbeat: stageSessionHeartbeat.start,
70290
+ drainStageSessionHeartbeat: stageSessionHeartbeat.drain,
70291
+ raceStageSessionHeartbeat: stageSessionHeartbeat.race,
69875
70292
  applyModelFallbackMeta,
69876
70293
  appendStageStartOnce,
69877
70294
  finalizeStageSnapshot,
@@ -70024,9 +70441,22 @@ class EngineRuntime {
70024
70441
  apply: () => {
70025
70442
  if (!this.childRunOptions.mcp || !hasScope)
70026
70443
  return;
70027
- if (depth === 0)
70444
+ if (depth > 0) {
70445
+ depth += 1;
70446
+ return;
70447
+ }
70448
+ depth = 1;
70449
+ try {
70028
70450
  this.childRunOptions.mcp.setScope(stageId, allow, deny);
70029
- depth += 1;
70451
+ } catch (error) {
70452
+ depth = 0;
70453
+ try {
70454
+ this.childRunOptions.mcp.clearScope(stageId);
70455
+ } catch (cleanupError) {
70456
+ throw new AggregateError([error, cleanupError], "MCP scope setup failed and compensating cleanup failed");
70457
+ }
70458
+ throw error;
70459
+ }
70030
70460
  },
70031
70461
  clear: () => {
70032
70462
  if (!this.childRunOptions.mcp || !hasScope)
@@ -71369,6 +71799,72 @@ function disposeCompletedChatHandle(handle) {
71369
71799
  });
71370
71800
  }
71371
71801
 
71802
+ // dist/builtin/workflows/src/durable/targeted-inspection.ts
71803
+ async function inspectTargetedDurableWorkflow(backend, workflowId, now = Date.now()) {
71804
+ const hydrated = backend.hydrateWorkflowForInspection ? await backend.hydrateWorkflowForInspection(workflowId) : await hydrateWithoutClassification(backend, workflowId);
71805
+ if (hydrated.kind !== "current")
71806
+ return hydrationFailure(workflowId, hydrated.kind);
71807
+ const handle = hydrated.handle;
71808
+ if (handle.rootWorkflowId !== undefined && handle.rootWorkflowId !== handle.workflowId) {
71809
+ return malformed(workflowId, "the requested id belongs to a nested workflow rather than a durable root");
71810
+ }
71811
+ const reconstructed = durableWorkflowRunSnapshots(backend, handle);
71812
+ if (reconstructed.length === 0)
71813
+ return malformed(workflowId, "durable checkpoint topology is malformed or incomplete");
71814
+ const runs = structuredClone(reconstructed);
71815
+ const inspectionStore = createStore();
71816
+ for (const run2 of runs)
71817
+ inspectionStore.recordRunStart(structuredClone(run2));
71818
+ const inspected = inspectRun(workflowId, { store: inspectionStore });
71819
+ if (!inspected.ok)
71820
+ return malformed(workflowId, "the durable checkpoint graph has no reciprocal root");
71821
+ const foreignLive = isForeignLiveWorkflow(handle, getAtomicExecutorId(), now);
71822
+ const live = isLiveRunningWorkflow(handle, now);
71823
+ const crashed = handle.status === "running" && !live;
71824
+ const resumeGuidance = crashed ? inspected.detail.resumable === true ? `This workflow appears to have crashed and is resumable. Resume it explicitly with /workflow resume ${workflowId}.` : "This workflow appears to have crashed, but its retained state is not resumable." : foreignLive ? "This workflow is actively running in another Atomic session. Inspect it here, but control it from its owner session." : live ? "This workflow still has a fresh durable heartbeat. Inspect it here without starting another executor." : terminalGuidance(handle.status, workflowId, inspected.detail.resumable === true);
71825
+ return {
71826
+ kind: "found",
71827
+ runs,
71828
+ store: inspectionStore,
71829
+ detail: {
71830
+ ...inspected.detail,
71831
+ ...crashed ? { status: "crashed" } : {},
71832
+ ...live ? { resumable: false } : {},
71833
+ ...foreignLive ? { ownerActiveElsewhere: true } : {},
71834
+ resumeGuidance
71835
+ }
71836
+ };
71837
+ }
71838
+ function terminalGuidance(status, workflowId, resumable) {
71839
+ if (resumable)
71840
+ return `This retained workflow is ${status} and resumable. Resume it explicitly with /workflow resume ${workflowId}.`;
71841
+ return `This retained workflow is ${status} and available for read-only inspection.`;
71842
+ }
71843
+ async function hydrateWithoutClassification(backend, workflowId) {
71844
+ await backend.hydrateWorkflow(workflowId);
71845
+ const handle = backend.getLoadableWorkflow(workflowId);
71846
+ return handle === undefined ? { kind: "absent" } : { kind: "current", handle };
71847
+ }
71848
+ function hydrationFailure(workflowId, kind) {
71849
+ switch (kind) {
71850
+ case "absent":
71851
+ return {
71852
+ kind,
71853
+ message: `Run not found: ${workflowId} (not present in the current session or durable store).`
71854
+ };
71855
+ case "deleted":
71856
+ return { kind, message: `Durable workflow was deleted: ${workflowId}` };
71857
+ case "malformed":
71858
+ return malformed(workflowId, "current DBOS metadata or checkpoints are malformed");
71859
+ }
71860
+ }
71861
+ function malformed(workflowId, reason) {
71862
+ return {
71863
+ kind: "malformed",
71864
+ message: `Durable workflow ${workflowId} cannot be inspected safely: ${reason}.`
71865
+ };
71866
+ }
71867
+
71372
71868
  // dist/builtin/workflows/src/extension/runtime-durable-resume.ts
71373
71869
  function createDurableResumeRuntime(deps) {
71374
71870
  const hydrateStoredWorkflowCandidates = async (backend, target) => {
@@ -71378,6 +71874,10 @@ function createDurableResumeRuntime(deps) {
71378
71874
  };
71379
71875
  let preparedCatalog = [];
71380
71876
  return {
71877
+ async inspectDurableWorkflow(workflowId) {
71878
+ await deps.ensureReady();
71879
+ return await inspectTargetedDurableWorkflow(getDurableBackend(), workflowId);
71880
+ },
71381
71881
  async resumeDurableWorkflow(workflowId, options) {
71382
71882
  await deps.ensureReady();
71383
71883
  const backend = getDurableBackend();
@@ -72052,6 +72552,9 @@ function createWorkflowExtensionRuntimeState(pi, adapters, resolveCwd = () => pi
72052
72552
  resumeDurableWorkflow(workflowId, options) {
72053
72553
  return runtimeRef.current.resumeDurableWorkflow(workflowId, options);
72054
72554
  },
72555
+ inspectDurableWorkflow(workflowId) {
72556
+ return runtimeRef.current.inspectDurableWorkflow(workflowId);
72557
+ },
72055
72558
  listDurableResumable() {
72056
72559
  return runtimeRef.current.listDurableResumable();
72057
72560
  },
@@ -72986,7 +73489,7 @@ function openInputsPicker(ui, opts) {
72986
73489
  }
72987
73490
 
72988
73491
  // dist/builtin/workflows/src/tui/session-picker.ts
72989
- import { keyText as keyText2 } from "@bastani/atomic";
73492
+ import { keyText as keyText3 } from "@bastani/atomic";
72990
73493
  var ESCAPE_CODE = 27;
72991
73494
  function isQuitRun3(run2) {
72992
73495
  return run2.endedAt === undefined && run2.status === "paused" && run2.exitReason === "quit";
@@ -73079,12 +73582,12 @@ function renderHintsRow(width, theme, state2) {
73079
73582
  const muted = hexToAnsi(theme.textMuted);
73080
73583
  const sep7 = `${dim} · ${RESET}`;
73081
73584
  const hint = (key2, label) => `${text}${key2}${RESET} ${muted}${label}${RESET}`;
73082
- const parts = state2.filterFocused ? [hint(keyText2("tui.select.confirm"), "Submit"), hint(keyText2("tui.select.cancel"), "Exit Filter")] : [
73083
- hint(`${keyText2("tui.select.up")}/${keyText2("tui.select.down")}`, "Navigate"),
73084
- hint(keyText2("tui.select.confirm"), "Connect"),
73585
+ const parts = state2.filterFocused ? [hint(keyText3("tui.select.confirm"), "Submit"), hint(keyText3("tui.select.cancel"), "Exit Filter")] : [
73586
+ hint(`${keyText3("tui.select.up")}/${keyText3("tui.select.down")}`, "Navigate"),
73587
+ hint(keyText3("tui.select.confirm"), "Connect"),
73085
73588
  hint("a", state2.includeAll ? "Active Only" : "All"),
73086
73589
  hint("/", "Filter"),
73087
- hint(keyText2("tui.select.cancel"), "Close")
73590
+ hint(keyText3("tui.select.cancel"), "Close")
73088
73591
  ];
73089
73592
  const line = ` ${parts.join(sep7)}`;
73090
73593
  const clipped = truncateToWidth(line, width, "…");
@@ -73721,6 +74224,7 @@ function toPickerRow(session) {
73721
74224
  modifiedAt: session.modified.getTime(),
73722
74225
  messageCount: session.messageCount,
73723
74226
  firstMessage: session.firstMessage,
74227
+ ...session.summary !== undefined ? { summary: session.summary } : {},
73724
74228
  allMessagesText: session.allMessagesText,
73725
74229
  ...session.name !== undefined ? { name: session.name } : {},
73726
74230
  ...session.messageColor !== undefined ? { messageColor: session.messageColor } : {}
@@ -74570,8 +75074,13 @@ Available: ${formatAvailableWorkflowNames(deps.runtimeProxy.registry.names())}`)
74570
75074
  const resolved = resolveRunId(target);
74571
75075
  if (resolved.kind === "malformed")
74572
75076
  return fail(resolved.message);
74573
- if (resolved.kind === "not_found")
74574
- return fail(`Run not found: ${target}`);
75077
+ if (resolved.kind === "not_found") {
75078
+ const durable = await deps.runtimeForContext(ctx).inspectDurableWorkflow(target);
75079
+ if (durable.kind !== "found")
75080
+ return fail(durable.message);
75081
+ emitChatSurface(pi, { kind: "detail", detail: durable.detail });
75082
+ return;
75083
+ }
74575
75084
  const inspected = inspectRun(resolved.runId);
74576
75085
  if (!inspected.ok)
74577
75086
  return fail(`Run not found: ${target}`);
@@ -75645,8 +76154,9 @@ function snapshotTranscriptEntryCount(snapshot) {
75645
76154
  }
75646
76155
 
75647
76156
  // dist/builtin/workflows/src/extension/workflow-tool-inspection.ts
75648
- function workflowStagesResult(args) {
75649
- const target = resolveToolRunTarget(args, "No active run to inspect.");
76157
+ function workflowStagesResult(args, source) {
76158
+ const activeStore = source?.store ?? store;
76159
+ const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
75650
76160
  const filter = args.statusFilter ?? "all";
75651
76161
  if (target.kind === "all") {
75652
76162
  return {
@@ -75666,19 +76176,20 @@ function workflowStagesResult(args) {
75666
76176
  error: target.message
75667
76177
  };
75668
76178
  }
75669
- const run2 = store.runs().find((r) => r.id === target.runId);
75670
- const stages = (run2?.stages ?? []).filter((stage) => filter === "all" || stage.status === filter).map(summarizeStage);
76179
+ const stageSnapshots = source?.store === undefined ? activeStore.runs().find((run2) => run2.id === target.runId)?.stages ?? [] : expandWorkflowGraph(readGraphStoreSnapshot(activeStore), target.runId).stages;
76180
+ const stages = stageSnapshots.filter((stage) => filter === "all" || stage.status === filter).map(summarizeStage);
75671
76181
  return { action: "stages", runId: target.runId, filter, stages };
75672
76182
  }
75673
- function workflowStageResult(args) {
75674
- const target = resolveToolRunTarget(args, "No active run to inspect.");
76183
+ function workflowStageResult(args, source) {
76184
+ const activeStore = source?.store ?? store;
76185
+ const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
75675
76186
  if (target.kind === "all") {
75676
76187
  return { action: "stage", runId: "--all", error: "Stage inspection requires a single run." };
75677
76188
  }
75678
76189
  if (target.kind === "malformed" || target.kind === "not_found") {
75679
76190
  return { action: "stage", runId: target.target, error: target.message };
75680
76191
  }
75681
- const stage = resolveToolStageTarget(target.runId, args.stageId);
76192
+ const stage = resolveToolStageTarget(target.runId, args.stageId, activeStore);
75682
76193
  if (!stage.ok || stage.stageId === undefined) {
75683
76194
  return {
75684
76195
  action: "stage",
@@ -75687,7 +76198,7 @@ function workflowStageResult(args) {
75687
76198
  };
75688
76199
  }
75689
76200
  const stageRunId = stage.runId ?? target.runId;
75690
- const run2 = store.runs().find((r) => r.id === stageRunId);
76201
+ const run2 = activeStore.runs().find((r) => r.id === stageRunId);
75691
76202
  const snapshot = run2?.stages.find((s) => s.id === stage.stageId);
75692
76203
  return snapshot ? { action: "stage", runId: stageRunId, stage: cloneStage(snapshot) } : {
75693
76204
  action: "stage",
@@ -75695,8 +76206,9 @@ function workflowStageResult(args) {
75695
76206
  error: `Stage not found in run ${stageRunId}: ${stage.stageId}`
75696
76207
  };
75697
76208
  }
75698
- function workflowTranscriptResult(args) {
75699
- const target = resolveToolRunTarget(args, "No active run to inspect.");
76209
+ function workflowTranscriptResult(args, source) {
76210
+ const activeStore = source?.store ?? store;
76211
+ const target = resolveToolRunTarget(args, "No active run to inspect.", activeStore);
75700
76212
  if (target.kind === "all") {
75701
76213
  return {
75702
76214
  action: "transcript",
@@ -75717,7 +76229,7 @@ function workflowTranscriptResult(args) {
75717
76229
  truncated: false
75718
76230
  };
75719
76231
  }
75720
- const stage = resolveToolStageTarget(target.runId, args.stageId);
76232
+ const stage = resolveToolStageTarget(target.runId, args.stageId, activeStore);
75721
76233
  if (!stage.ok || stage.stageId === undefined) {
75722
76234
  return {
75723
76235
  action: "transcript",
@@ -75729,9 +76241,9 @@ function workflowTranscriptResult(args) {
75729
76241
  };
75730
76242
  }
75731
76243
  const stageRunId = stage.runId ?? target.runId;
75732
- const run2 = store.runs().find((r) => r.id === stageRunId);
76244
+ const run2 = activeStore.runs().find((r) => r.id === stageRunId);
75733
76245
  const snapshot = run2?.stages.find((s) => s.id === stage.stageId);
75734
- const liveHandle2 = stageControlRegistry.get(stageRunId, stage.stageId);
76246
+ const liveHandle2 = source?.allowLiveHandles === false ? undefined : stageControlRegistry.get(stageRunId, stage.stageId);
75735
76247
  if (liveHandle2 !== undefined) {
75736
76248
  const sessionFile = liveHandle2.sessionFile ?? snapshot?.sessionFile;
75737
76249
  const sessionId = liveHandle2.sessionId ?? snapshot?.sessionId;
@@ -75791,6 +76303,41 @@ function brokerAnswerFromArgs(args) {
75791
76303
  const text = textPayloadFromArgs(args);
75792
76304
  return text !== undefined ? { text } : {};
75793
76305
  }
76306
+ function answersPendingPrompt(delivery, promptId) {
76307
+ return delivery === "answer" || delivery === "auto" || promptId !== undefined;
76308
+ }
76309
+ function answerablePromptIds(stage) {
76310
+ const target = stage.workflowGraphTarget;
76311
+ const ids = [];
76312
+ const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
76313
+ if (brokered !== undefined)
76314
+ ids.push(brokered.id);
76315
+ if (stage.pendingPrompt !== undefined)
76316
+ ids.push(stage.pendingPrompt.id);
76317
+ if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom") {
76318
+ ids.push(stage.promptFootprint.id);
76319
+ }
76320
+ return ids;
76321
+ }
76322
+ function inferPromptStageTarget(runId, delivery, promptId) {
76323
+ if (!answersPendingPrompt(delivery, promptId))
76324
+ return { ok: true, runId };
76325
+ const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
76326
+ const ids = answerablePromptIds(stage);
76327
+ return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
76328
+ });
76329
+ const only = pending[0];
76330
+ if (pending.length === 1 && only !== undefined) {
76331
+ return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
76332
+ }
76333
+ if (pending.length === 0) {
76334
+ return promptId === undefined ? { ok: true, runId } : { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
76335
+ }
76336
+ return {
76337
+ ok: false,
76338
+ message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`
76339
+ };
76340
+ }
75794
76341
  function workflowSendResult(runId, stageId, delivery, status, message) {
75795
76342
  return { action: "send", runId, stageId, delivery, status, message };
75796
76343
  }
@@ -75851,7 +76398,8 @@ async function workflowSendAction(args, deps = {}) {
75851
76398
  if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
75852
76399
  return terminalWorkflowSendResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
75853
76400
  }
75854
- const stage = resolveToolStageTarget(target.runId, args.stageId);
76401
+ const requested = resolveToolStageTarget(target.runId, args.stageId);
76402
+ const stage = requested.ok && requested.stageId === undefined ? inferPromptStageTarget(target.runId, requestedDelivery, args.promptId) : requested;
75855
76403
  if (!stage.ok || stage.stageId === undefined) {
75856
76404
  return workflowSendResult(target.runId, "", requestedDelivery, "noop", stage.ok ? "Stage id or name is required." : stage.message);
75857
76405
  }
@@ -75992,6 +76540,32 @@ async function workflowSendAction(args, deps = {}) {
75992
76540
  }
75993
76541
 
75994
76542
  // dist/builtin/workflows/src/extension/workflow-tool.ts
76543
+ async function resolveDurableInspectionSource(args, runtime) {
76544
+ const target = args.runId?.trim();
76545
+ if (args.all === true || target === undefined || target.length === 0 || target === "--all")
76546
+ return { kind: "local" };
76547
+ const local = resolveRunId(target);
76548
+ if (local.kind !== "not_found")
76549
+ return { kind: "local" };
76550
+ const durable = await runtime.inspectDurableWorkflow(target);
76551
+ if (durable.kind !== "found")
76552
+ return { kind: "error", message: durable.message };
76553
+ return { kind: "durable", source: { store: durable.store, allowLiveHandles: false } };
76554
+ }
76555
+ function durableInspectionError(action, runId, message) {
76556
+ if (action === "stages")
76557
+ return { action, runId, filter: "all", stages: [], error: message };
76558
+ if (action === "stage")
76559
+ return { action, runId, error: message };
76560
+ return {
76561
+ action,
76562
+ runId,
76563
+ stageId: "",
76564
+ source: "error",
76565
+ entries: [{ role: "notice", text: message }],
76566
+ truncated: false
76567
+ };
76568
+ }
75995
76569
  function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflowResourcesLoaded = () => {}, sendDeps = {}) {
75996
76570
  return async function executeWorkflowTool(args, ctx) {
75997
76571
  const action = args.action ?? "run";
@@ -76047,7 +76621,8 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
76047
76621
  return { action: "statusDetail", runId: target, error: resolved.message };
76048
76622
  }
76049
76623
  if (resolved.kind === "not_found") {
76050
- return { action: "statusDetail", runId: target, error: `run not found: ${target}` };
76624
+ const durable = await getRuntime().inspectDurableWorkflow(target);
76625
+ return durable.kind === "found" ? { action: "statusDetail", runId: target, detail: durable.detail } : { action: "statusDetail", runId: target, error: durable.message };
76051
76626
  }
76052
76627
  const result2 = inspectRun(resolved.runId);
76053
76628
  return result2.ok ? { action: "statusDetail", runId: result2.runId, detail: result2.detail } : { action: "statusDetail", runId: target, error: `run not found: ${target}` };
@@ -76063,11 +76638,18 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
76063
76638
  return result;
76064
76639
  }
76065
76640
  case "stages":
76066
- return workflowStagesResult(args);
76067
76641
  case "stage":
76068
- return workflowStageResult(args);
76069
- case "transcript":
76070
- return workflowTranscriptResult(args);
76642
+ case "transcript": {
76643
+ const resolved = await resolveDurableInspectionSource(args, getRuntime());
76644
+ if (resolved.kind === "error")
76645
+ return durableInspectionError(action, args.runId ?? "", resolved.message);
76646
+ const source = resolved.kind === "durable" ? resolved.source : undefined;
76647
+ if (action === "stages")
76648
+ return workflowStagesResult(args, source);
76649
+ if (action === "stage")
76650
+ return workflowStageResult(args, source);
76651
+ return workflowTranscriptResult(args, source);
76652
+ }
76071
76653
  case "send":
76072
76654
  return workflowSendAction(args, sendDeps);
76073
76655
  case "pause":