@bastani/atomic 0.8.13-0 → 0.8.14-0

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 (355) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/host-html-template.ts +1 -1
  4. package/dist/builtin/mcp/init.ts +15 -2
  5. package/dist/builtin/mcp/mcp-callback-server.ts +10 -9
  6. package/dist/builtin/mcp/package.json +1 -1
  7. package/dist/builtin/mcp/ui-session.ts +9 -6
  8. package/dist/builtin/subagents/CHANGELOG.md +8 -1
  9. package/dist/builtin/subagents/README.md +39 -32
  10. package/dist/builtin/subagents/package.json +1 -1
  11. package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
  12. package/dist/builtin/subagents/src/agents/agent-management.ts +6 -1
  13. package/dist/builtin/subagents/src/agents/agent-serializer.ts +2 -0
  14. package/dist/builtin/subagents/src/agents/agents.ts +44 -19
  15. package/dist/builtin/subagents/src/extension/config.ts +16 -0
  16. package/dist/builtin/subagents/src/extension/fanout-child.ts +246 -0
  17. package/dist/builtin/subagents/src/extension/index.ts +466 -603
  18. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +6 -4
  19. package/dist/builtin/subagents/src/intercom/result-intercom.ts +109 -1
  20. package/dist/builtin/subagents/src/runs/background/async-execution.ts +124 -19
  21. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +41 -6
  22. package/dist/builtin/subagents/src/runs/background/async-resume.ts +28 -15
  23. package/dist/builtin/subagents/src/runs/background/async-status.ts +60 -30
  24. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +111 -54
  25. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +83 -0
  26. package/dist/builtin/subagents/src/runs/background/run-status.ts +79 -3
  27. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +46 -1
  28. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +66 -14
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +10 -3
  30. package/dist/builtin/subagents/src/runs/foreground/execution.ts +14 -2
  31. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +320 -23
  32. package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +23 -1
  33. package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +369 -0
  34. package/dist/builtin/subagents/src/runs/shared/nested-events.ts +935 -0
  35. package/dist/builtin/subagents/src/runs/shared/nested-path.ts +52 -0
  36. package/dist/builtin/subagents/src/runs/shared/nested-render.ts +115 -0
  37. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
  38. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +82 -9
  39. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +1 -1
  40. package/dist/builtin/subagents/src/runs/shared/single-output.ts +12 -2
  41. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +32 -10
  42. package/dist/builtin/subagents/src/runs/shared/worktree.ts +3 -2
  43. package/dist/builtin/subagents/src/shared/artifacts.ts +0 -1
  44. package/dist/builtin/subagents/src/shared/types.ts +96 -1
  45. package/dist/builtin/subagents/src/shared/utils.ts +10 -2
  46. package/dist/builtin/subagents/src/slash/slash-commands.ts +468 -625
  47. package/dist/builtin/subagents/src/tui/render.ts +1227 -2093
  48. package/dist/builtin/web-access/package.json +1 -1
  49. package/dist/builtin/workflows/CHANGELOG.md +24 -0
  50. package/dist/builtin/workflows/README.md +28 -11
  51. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +323 -40
  52. package/dist/builtin/workflows/builtin/ralph.ts +362 -176
  53. package/dist/builtin/workflows/package.json +2 -5
  54. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
  55. package/dist/builtin/workflows/skills/skill-creator/LICENSE.txt +202 -0
  56. package/dist/builtin/workflows/skills/skill-creator/SKILL.md +489 -0
  57. package/dist/builtin/workflows/skills/skill-creator/agents/analyzer.md +274 -0
  58. package/dist/builtin/workflows/skills/skill-creator/agents/comparator.md +202 -0
  59. package/dist/builtin/workflows/skills/skill-creator/agents/grader.md +223 -0
  60. package/dist/builtin/workflows/skills/skill-creator/assets/eval_review.html +146 -0
  61. package/dist/builtin/workflows/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  62. package/dist/builtin/workflows/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  63. package/dist/builtin/workflows/skills/skill-creator/references/schemas.md +430 -0
  64. package/dist/builtin/workflows/skills/skill-creator/scripts/__init__.py +0 -0
  65. package/dist/builtin/workflows/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  66. package/dist/builtin/workflows/skills/skill-creator/scripts/generate_report.py +326 -0
  67. package/dist/builtin/workflows/skills/skill-creator/scripts/improve_description.py +247 -0
  68. package/dist/builtin/workflows/skills/skill-creator/scripts/package_skill.py +136 -0
  69. package/dist/builtin/workflows/skills/skill-creator/scripts/quick_validate.py +103 -0
  70. package/dist/builtin/workflows/skills/skill-creator/scripts/run_eval.py +310 -0
  71. package/dist/builtin/workflows/skills/skill-creator/scripts/run_loop.py +328 -0
  72. package/dist/builtin/workflows/skills/skill-creator/scripts/utils.py +47 -0
  73. package/dist/builtin/workflows/src/extension/index.ts +869 -93
  74. package/dist/builtin/workflows/src/extension/render-call.ts +34 -1
  75. package/dist/builtin/workflows/src/extension/render-result.ts +126 -21
  76. package/dist/builtin/workflows/src/extension/runtime.ts +91 -3
  77. package/dist/builtin/workflows/src/extension/wiring.ts +38 -12
  78. package/dist/builtin/workflows/src/extension/workflow-schema.ts +62 -5
  79. package/dist/builtin/workflows/src/runs/background/runner.ts +3 -3
  80. package/dist/builtin/workflows/src/runs/background/status.ts +42 -8
  81. package/dist/builtin/workflows/src/runs/foreground/executor.ts +410 -95
  82. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +5 -2
  83. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +8 -0
  84. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +6 -4
  85. package/dist/builtin/workflows/src/runs/shared/worktree.ts +3 -2
  86. package/dist/builtin/workflows/src/shared/persistence-restore.ts +138 -5
  87. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +30 -0
  88. package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +78 -120
  89. package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +193 -0
  90. package/dist/builtin/workflows/src/shared/store-types.ts +26 -1
  91. package/dist/builtin/workflows/src/shared/store.ts +145 -17
  92. package/dist/builtin/workflows/src/shared/timing.ts +6 -2
  93. package/dist/builtin/workflows/src/shared/workflow-failures.ts +375 -0
  94. package/dist/builtin/workflows/src/tui/chat-surface.ts +68 -17
  95. package/dist/builtin/workflows/src/tui/connectors.ts +2 -2
  96. package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +24 -26
  97. package/dist/builtin/workflows/src/tui/graph-canvas.ts +4 -8
  98. package/dist/builtin/workflows/src/tui/graph-view.ts +17 -14
  99. package/dist/builtin/workflows/src/tui/header.ts +38 -0
  100. package/dist/builtin/workflows/src/tui/inline-form-card.ts +161 -238
  101. package/dist/builtin/workflows/src/tui/inline-form-editor.ts +68 -73
  102. package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +2 -3
  103. package/dist/builtin/workflows/src/tui/inline-form-store.ts +2 -1
  104. package/dist/builtin/workflows/src/tui/inputs-overlay.ts +1 -3
  105. package/dist/builtin/workflows/src/tui/inputs-picker.ts +286 -399
  106. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +11 -0
  107. package/dist/builtin/workflows/src/tui/node-card.ts +2 -1
  108. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -1
  109. package/dist/builtin/workflows/src/tui/prompt-card.ts +46 -19
  110. package/dist/builtin/workflows/src/tui/run-detail.ts +63 -80
  111. package/dist/builtin/workflows/src/tui/session-confirm.ts +9 -3
  112. package/dist/builtin/workflows/src/tui/session-picker.ts +19 -16
  113. package/dist/builtin/workflows/src/tui/stage-chat-layout.ts +88 -0
  114. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +368 -879
  115. package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
  116. package/dist/builtin/workflows/src/tui/status-list.ts +67 -75
  117. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +50 -12
  118. package/dist/builtin/workflows/src/tui/submit-pane.ts +164 -0
  119. package/dist/builtin/workflows/src/tui/switcher.ts +27 -4
  120. package/dist/builtin/workflows/src/tui/text-helpers.ts +98 -4
  121. package/dist/builtin/workflows/src/tui/widget.ts +90 -68
  122. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +23 -2
  123. package/dist/builtin/workflows/src/tui/workflow-list.ts +44 -68
  124. package/dist/cli/file-processor.d.ts.map +1 -1
  125. package/dist/cli/file-processor.js +2 -3
  126. package/dist/cli/file-processor.js.map +1 -1
  127. package/dist/config.d.ts.map +1 -1
  128. package/dist/config.js +3 -10
  129. package/dist/config.js.map +1 -1
  130. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  131. package/dist/core/agent-session-runtime.js +2 -1
  132. package/dist/core/agent-session-runtime.js.map +1 -1
  133. package/dist/core/agent-session-services.d.ts.map +1 -1
  134. package/dist/core/agent-session-services.js +3 -2
  135. package/dist/core/agent-session-services.js.map +1 -1
  136. package/dist/core/agent-session.d.ts +6 -0
  137. package/dist/core/agent-session.d.ts.map +1 -1
  138. package/dist/core/agent-session.js +16 -2
  139. package/dist/core/agent-session.js.map +1 -1
  140. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  141. package/dist/core/atomic-guide-command.js +8 -9
  142. package/dist/core/atomic-guide-command.js.map +1 -1
  143. package/dist/core/auth-storage.d.ts.map +1 -1
  144. package/dist/core/auth-storage.js +3 -2
  145. package/dist/core/auth-storage.js.map +1 -1
  146. package/dist/core/bash-executor.d.ts.map +1 -1
  147. package/dist/core/bash-executor.js +2 -1
  148. package/dist/core/bash-executor.js.map +1 -1
  149. package/dist/core/export-html/index.d.ts.map +1 -1
  150. package/dist/core/export-html/index.js +8 -6
  151. package/dist/core/export-html/index.js.map +1 -1
  152. package/dist/core/export-html/template.js +6 -3
  153. package/dist/core/extensions/loader.d.ts.map +1 -1
  154. package/dist/core/extensions/loader.js +12 -29
  155. package/dist/core/extensions/loader.js.map +1 -1
  156. package/dist/core/model-registry.d.ts.map +1 -1
  157. package/dist/core/model-registry.js +5 -1
  158. package/dist/core/model-registry.js.map +1 -1
  159. package/dist/core/package-manager.d.ts +8 -0
  160. package/dist/core/package-manager.d.ts.map +1 -1
  161. package/dist/core/package-manager.js +145 -58
  162. package/dist/core/package-manager.js.map +1 -1
  163. package/dist/core/prompt-templates.d.ts.map +1 -1
  164. package/dist/core/prompt-templates.js +6 -20
  165. package/dist/core/prompt-templates.js.map +1 -1
  166. package/dist/core/resource-loader.d.ts.map +1 -1
  167. package/dist/core/resource-loader.js +38 -31
  168. package/dist/core/resource-loader.js.map +1 -1
  169. package/dist/core/sdk.d.ts.map +1 -1
  170. package/dist/core/sdk.js +9 -4
  171. package/dist/core/sdk.js.map +1 -1
  172. package/dist/core/session-manager.d.ts.map +1 -1
  173. package/dist/core/session-manager.js +32 -24
  174. package/dist/core/session-manager.js.map +1 -1
  175. package/dist/core/settings-manager.d.ts.map +1 -1
  176. package/dist/core/settings-manager.js +8 -15
  177. package/dist/core/settings-manager.js.map +1 -1
  178. package/dist/core/skills.d.ts.map +1 -1
  179. package/dist/core/skills.js +8 -22
  180. package/dist/core/skills.js.map +1 -1
  181. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +5 -4
  182. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  183. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +34 -11
  184. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  185. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +1 -0
  186. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  187. package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
  188. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  189. package/dist/core/tools/ask-user-question/state/selectors/projections.js +1 -0
  190. package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
  191. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts +1 -2
  192. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  193. package/dist/core/tools/ask-user-question/state/state-reducer.js +26 -9
  194. package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
  195. package/dist/core/tools/ask-user-question/state/state.d.ts +4 -0
  196. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  197. package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
  198. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts +1 -0
  199. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
  200. package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
  201. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  202. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +9 -6
  203. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  204. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +28 -7
  205. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  207. package/dist/core/tools/ask-user-question/view/props-adapter.js +4 -1
  208. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  209. package/dist/core/tools/bash.d.ts.map +1 -1
  210. package/dist/core/tools/bash.js +56 -53
  211. package/dist/core/tools/bash.js.map +1 -1
  212. package/dist/core/tools/edit-diff.d.ts +3 -1
  213. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  214. package/dist/core/tools/edit-diff.js +8 -1
  215. package/dist/core/tools/edit-diff.js.map +1 -1
  216. package/dist/core/tools/edit.d.ts +3 -1
  217. package/dist/core/tools/edit.d.ts.map +1 -1
  218. package/dist/core/tools/edit.js +44 -81
  219. package/dist/core/tools/edit.js.map +1 -1
  220. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  221. package/dist/core/tools/file-mutation-queue.js +27 -12
  222. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  223. package/dist/core/tools/find.d.ts.map +1 -1
  224. package/dist/core/tools/find.js +2 -3
  225. package/dist/core/tools/find.js.map +1 -1
  226. package/dist/core/tools/grep.d.ts.map +1 -1
  227. package/dist/core/tools/grep.js +3 -3
  228. package/dist/core/tools/grep.js.map +1 -1
  229. package/dist/core/tools/ls.d.ts.map +1 -1
  230. package/dist/core/tools/ls.js +5 -5
  231. package/dist/core/tools/ls.js.map +1 -1
  232. package/dist/core/tools/output-accumulator.d.ts +2 -0
  233. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  234. package/dist/core/tools/output-accumulator.js +11 -4
  235. package/dist/core/tools/output-accumulator.js.map +1 -1
  236. package/dist/core/tools/path-utils.d.ts +2 -0
  237. package/dist/core/tools/path-utils.d.ts.map +1 -1
  238. package/dist/core/tools/path-utils.js +39 -21
  239. package/dist/core/tools/path-utils.js.map +1 -1
  240. package/dist/core/tools/read.d.ts.map +1 -1
  241. package/dist/core/tools/read.js +9 -8
  242. package/dist/core/tools/read.js.map +1 -1
  243. package/dist/core/tools/truncate.d.ts.map +1 -1
  244. package/dist/core/tools/truncate.js +12 -2
  245. package/dist/core/tools/truncate.js.map +1 -1
  246. package/dist/core/tools/write.d.ts.map +1 -1
  247. package/dist/core/tools/write.js +20 -35
  248. package/dist/core/tools/write.js.map +1 -1
  249. package/dist/index.d.ts +2 -1
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js +4 -1
  252. package/dist/index.js.map +1 -1
  253. package/dist/main.d.ts.map +1 -1
  254. package/dist/main.js +5 -6
  255. package/dist/main.js.map +1 -1
  256. package/dist/modes/interactive/chat-input-actions.d.ts +24 -0
  257. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -0
  258. package/dist/modes/interactive/chat-input-actions.js +179 -0
  259. package/dist/modes/interactive/chat-input-actions.js.map +1 -0
  260. package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -0
  261. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  262. package/dist/modes/interactive/components/chat-message-renderer.js +14 -3
  263. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  264. package/dist/modes/interactive/components/chat-session-host.d.ts +157 -0
  265. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -0
  266. package/dist/modes/interactive/components/chat-session-host.js +1007 -0
  267. package/dist/modes/interactive/components/chat-session-host.js.map +1 -0
  268. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  269. package/dist/modes/interactive/components/config-selector.js +1 -1
  270. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  271. package/dist/modes/interactive/components/footer.d.ts +1 -0
  272. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/footer.js +14 -5
  274. package/dist/modes/interactive/components/footer.js.map +1 -1
  275. package/dist/modes/interactive/components/index.d.ts +1 -0
  276. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  277. package/dist/modes/interactive/components/index.js +1 -0
  278. package/dist/modes/interactive/components/index.js.map +1 -1
  279. package/dist/modes/interactive/components/login-dialog.d.ts +9 -1
  280. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/login-dialog.js +29 -4
  282. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  283. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  284. package/dist/modes/interactive/interactive-mode.js +18 -67
  285. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  286. package/dist/utils/child-process.d.ts +1 -0
  287. package/dist/utils/child-process.d.ts.map +1 -1
  288. package/dist/utils/child-process.js +8 -0
  289. package/dist/utils/child-process.js.map +1 -1
  290. package/dist/utils/clipboard-native.d.ts +3 -1
  291. package/dist/utils/clipboard-native.d.ts.map +1 -1
  292. package/dist/utils/clipboard-native.js +14 -8
  293. package/dist/utils/clipboard-native.js.map +1 -1
  294. package/dist/utils/image-resize-core.d.ts +30 -0
  295. package/dist/utils/image-resize-core.d.ts.map +1 -0
  296. package/dist/utils/image-resize-core.js +124 -0
  297. package/dist/utils/image-resize-core.js.map +1 -0
  298. package/dist/utils/image-resize-worker.d.ts +2 -0
  299. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  300. package/dist/utils/image-resize-worker.js +31 -0
  301. package/dist/utils/image-resize-worker.js.map +1 -0
  302. package/dist/utils/image-resize.d.ts +7 -27
  303. package/dist/utils/image-resize.d.ts.map +1 -1
  304. package/dist/utils/image-resize.js +75 -115
  305. package/dist/utils/image-resize.js.map +1 -1
  306. package/dist/utils/paths.d.ts +16 -1
  307. package/dist/utils/paths.d.ts.map +1 -1
  308. package/dist/utils/paths.js +49 -7
  309. package/dist/utils/paths.js.map +1 -1
  310. package/docs/changelog.mdx +29 -0
  311. package/docs/compaction.md +1 -1
  312. package/docs/custom-provider.md +2 -2
  313. package/docs/development.md +1 -1
  314. package/docs/docs.json +98 -143
  315. package/docs/extensions.md +29 -16
  316. package/docs/favicon.svg +29 -0
  317. package/docs/images/interactive-mode.png +0 -0
  318. package/docs/images/tree-view.png +0 -0
  319. package/docs/images/workflow-command.png +0 -0
  320. package/docs/images/workflow-graph.png +0 -0
  321. package/docs/images/workflow-input-picker.png +0 -0
  322. package/docs/images/workflow-list.png +0 -0
  323. package/docs/index.md +10 -1
  324. package/docs/logo.svg +59 -0
  325. package/docs/packages.md +3 -3
  326. package/docs/providers.md +1 -1
  327. package/docs/quickstart.md +98 -2
  328. package/docs/rpc.md +8 -8
  329. package/docs/sdk.md +23 -12
  330. package/docs/sessions.md +1 -1
  331. package/docs/skills.md +15 -1
  332. package/docs/termux.md +11 -1
  333. package/docs/themes.md +6 -6
  334. package/docs/tui.md +18 -18
  335. package/docs/usage.md +1 -1
  336. package/docs/workflows.md +172 -2
  337. package/examples/extensions/subagent/index.ts +2 -1
  338. package/package.json +6 -6
  339. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/SKILL.md +0 -0
  340. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/element-attributes.md +0 -0
  341. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/playwright-tests.md +0 -0
  342. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/request-mocking.md +0 -0
  343. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/running-code.md +0 -0
  344. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/session-management.md +0 -0
  345. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/spec-driven-testing.md +0 -0
  346. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/storage-state.md +0 -0
  347. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/test-generation.md +0 -0
  348. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/tracing.md +0 -0
  349. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/video-recording.md +0 -0
  350. /package/dist/builtin/{workflows → subagents}/skills/tdd/SKILL.md +0 -0
  351. /package/dist/builtin/{workflows → subagents}/skills/tdd/deep-modules.md +0 -0
  352. /package/dist/builtin/{workflows → subagents}/skills/tdd/interface-design.md +0 -0
  353. /package/dist/builtin/{workflows → subagents}/skills/tdd/mocking.md +0 -0
  354. /package/dist/builtin/{workflows → subagents}/skills/tdd/refactoring.md +0 -0
  355. /package/dist/builtin/{workflows → subagents}/skills/tdd/tests.md +0 -0
@@ -5,10 +5,25 @@
5
5
 
6
6
  import { truncateToWidth } from "../tui/text-helpers.js";
7
7
 
8
+ /** Renderer-only subset of the canonical WorkflowToolArgs from index.ts. */
8
9
  export interface WorkflowToolArgs {
9
10
  workflow?: string;
10
11
  inputs?: Record<string, unknown>;
11
- action?: "run" | "list" | "get" | "status" | "interrupt" | "kill" | "resume" | "inputs";
12
+ action?:
13
+ | "run"
14
+ | "list"
15
+ | "get"
16
+ | "status"
17
+ | "stages"
18
+ | "stage"
19
+ | "transcript"
20
+ | "send"
21
+ | "pause"
22
+ | "interrupt"
23
+ | "kill"
24
+ | "resume"
25
+ | "reload"
26
+ | "inputs";
12
27
  runId?: string;
13
28
  task?: { name?: string; prompt?: string; task?: string } | string;
14
29
  tasks?: readonly unknown[];
@@ -62,6 +77,24 @@ export function renderCall(args: WorkflowToolArgs, opts: RenderCallOpts = {}): s
62
77
  case "run":
63
78
  line = name === undefined ? "workflow: run" : `workflow: run ${quoted(name)}`;
64
79
  break;
80
+ case "stages":
81
+ line = name === undefined ? "workflow: list stages" : `workflow: list stages for ${quoted(name)}`;
82
+ break;
83
+ case "stage":
84
+ line = name === undefined ? "workflow: inspect stage" : `workflow: inspect stage in ${quoted(name)}`;
85
+ break;
86
+ case "transcript":
87
+ line = name === undefined ? "workflow: read stage transcript" : `workflow: read stage transcript in ${quoted(name)}`;
88
+ break;
89
+ case "send":
90
+ line = name === undefined ? "workflow: send to stage" : `workflow: send to stage in ${quoted(name)}`;
91
+ break;
92
+ case "pause":
93
+ line = name === undefined ? "workflow: pause run" : `workflow: pause run ${quoted(name)}`;
94
+ break;
95
+ case "reload":
96
+ line = "workflow: reload runtime";
97
+ break;
65
98
  case "interrupt":
66
99
  line = name === undefined
67
100
  ? "workflow: interrupt run"
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Render the workflow tool result for chat / LLM-tool surfaces.
3
3
  *
4
- * Rich background-workflow surfaces (status list, per-run detail) delegate
5
- * to the canonical Catppuccin renderers in `src/tui/`. Compact one-liners
6
- * (list/run/interrupt/resume) stay inline here.
4
+ * Workflow surfaces delegate to the canonical rounded renderers in `src/tui/`.
5
+ * Compact status/error/control responses are wrapped in the same rounded
6
+ * notice panel vocabulary so tool output stays visually consistent.
7
7
  *
8
8
  * cross-ref:
9
9
  * - src/tui/status-list.ts band-header status list
@@ -11,7 +11,7 @@
11
11
  * - pi-subagents src/extension/index.ts renderResult slot
12
12
  */
13
13
 
14
- import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
14
+ import type { PendingPrompt, RunSnapshot, StageSnapshot, StageStatus } from "../shared/store-types.js";
15
15
  import type { WorkflowDetails } from "../shared/types.js";
16
16
  import type { RunDetail } from "../runs/background/status.js";
17
17
  import { renderInputsSchema } from "../shared/render-inputs-schema.js";
@@ -20,6 +20,7 @@ import { renderRunDetail } from "../tui/run-detail.js";
20
20
  import { renderWorkflowList } from "../tui/workflow-list.js";
21
21
  import { deriveGraphTheme } from "../tui/graph-theme.js";
22
22
  import { renderDispatchConfirm } from "../tui/dispatch-confirm.js";
23
+ import { renderRoundedBox } from "../tui/chat-surface.js";
23
24
  import { truncateToWidth } from "../tui/text-helpers.js";
24
25
 
25
26
  // ---------------------------------------------------------------------------
@@ -97,6 +98,32 @@ type RunResult = {
97
98
  */
98
99
  message?: string;
99
100
  };
101
+ type StageListItem = {
102
+ id: string;
103
+ name: string;
104
+ status: StageStatus;
105
+ sessionId?: string;
106
+ sessionFile?: string;
107
+ error?: string;
108
+ awaitingInputSince?: number;
109
+ pendingPrompt?: PendingPrompt;
110
+ };
111
+ type StageListResult = { action: "stages"; runId: string; filter: string; stages: StageListItem[]; error?: string };
112
+ type StageDetailResult = { action: "stage"; runId: string; stage?: StageSnapshot; error?: string };
113
+ type TranscriptEntry = { role: string; text?: string; toolName?: string; output?: string; timestamp?: number };
114
+ type TranscriptResult = {
115
+ action: "transcript";
116
+ runId: string;
117
+ stageId: string;
118
+ source: "live" | "snapshot" | "error";
119
+ entries: TranscriptEntry[];
120
+ truncated: boolean;
121
+ sessionId?: string;
122
+ sessionFile?: string;
123
+ };
124
+ type SendResult = { action: "send"; runId: string; stageId: string; delivery: string; status: "ok" | "noop"; message: string };
125
+ type PauseResult = { action: "pause"; runId: string; status: string; message: string };
126
+ type ReloadResult = { action: "reload"; status: "ok" | "noop"; message: string };
100
127
  type InterruptResult = { action: "interrupt"; runId: string; status: string; message: string };
101
128
  type KillResult = { action: "kill"; runId: string; status: string; message: string };
102
129
  type ResumeResult = { action: "resume"; runId: string; status: string; message: string };
@@ -108,6 +135,12 @@ export type WorkflowToolResult =
108
135
  | InputsResult
109
136
  | GetResult
110
137
  | RunResult
138
+ | StageListResult
139
+ | StageDetailResult
140
+ | TranscriptResult
141
+ | SendResult
142
+ | PauseResult
143
+ | ReloadResult
111
144
  | InterruptResult
112
145
  | KillResult
113
146
  | ResumeResult;
@@ -144,6 +177,38 @@ function fitLine(line: string, width?: number): string {
144
177
  return truncateToWidth(line, width, "…");
145
178
  }
146
179
 
180
+ function renderNotice(
181
+ title: string,
182
+ message: string,
183
+ opts: RenderResultOpts | undefined,
184
+ themed: boolean,
185
+ ): string {
186
+ const theme = themed ? deriveGraphTheme({}) : undefined;
187
+ const width = opts?.width;
188
+ const contentWidth = width && width > 0 ? Math.max(1, width - 4) : undefined;
189
+ return renderRoundedBox({
190
+ title,
191
+ bodyLines: [` ${fitLine(message, contentWidth)} `],
192
+ theme,
193
+ width,
194
+ });
195
+ }
196
+
197
+ const TRANSCRIPT_NOTICE_ENTRY_LIMIT = 5;
198
+ const TRANSCRIPT_NOTICE_CHAR_LIMIT = 240;
199
+
200
+ function transcriptNoticeText(entries: readonly TranscriptEntry[]): string {
201
+ if (entries.length === 0) return "no transcript entries";
202
+ const shown = entries.slice(0, TRANSCRIPT_NOTICE_ENTRY_LIMIT);
203
+ const text = shown
204
+ .map((entry) => `${entry.role}: ${entry.text ?? entry.output ?? entry.toolName ?? "(no body)"}`)
205
+ .join(" | ");
206
+ const entrySuffix = entries.length > shown.length
207
+ ? ` … (+${entries.length - shown.length} more)`
208
+ : "";
209
+ return fitLine(`${text}${entrySuffix}`, TRANSCRIPT_NOTICE_CHAR_LIMIT);
210
+ }
211
+
147
212
  export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts): string {
148
213
  const partial = opts?.isPartial === true;
149
214
  const themed = opts?.plain !== true;
@@ -168,7 +233,7 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
168
233
  case "statusDetail": {
169
234
  if ("error" in result) {
170
235
  const r = result as Extract<StatusDetailResult, { error: string }>;
171
- return fitLine(`workflow status id=${r.runId}: ${r.error}`, opts?.width);
236
+ return renderNotice("WORKFLOW STATUS", `id=${r.runId}: ${r.error}`, opts, themed);
172
237
  }
173
238
  const r = result as Extract<StatusDetailResult, { detail: RunDetail }>;
174
239
  return renderRunDetail(r.detail, {
@@ -187,34 +252,36 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
187
252
 
188
253
  case "get": {
189
254
  const r = result as GetResult;
190
- if (r.error) return fitLine(`workflow get (${r.workflow}): ${r.error}`, opts?.width);
255
+ if (r.error) return renderNotice("WORKFLOW GET", `${r.workflow}: ${r.error}`, opts, themed);
191
256
  const output = r.details?.output;
192
257
  const description = typeof output?.["description"] === "string" ? ` — ${output["description"]}` : "";
193
- return fitLine(
194
- `workflow get (${r.workflow}): ${r.details?.status ?? "completed"}${description}`,
195
- opts?.width,
258
+ return renderNotice(
259
+ "WORKFLOW GET",
260
+ `${r.workflow}: ${r.details?.status ?? "completed"}${description}`,
261
+ opts,
262
+ themed,
196
263
  );
197
264
  }
198
265
 
199
266
  case "run": {
200
267
  const r = result as RunResult;
201
- if (partial) return fitLine(`workflow run ${r.runId}: ${r.status} (in progress…)`, opts?.width);
268
+ if (partial) return renderNotice("WORKFLOW RUN", `${r.runId}: ${r.status} (in progress…)`, opts, themed);
202
269
  if (r.status === "failed" && !r.runId) {
203
270
  // Not-found path — render the error verbatim, no fake runId banner.
204
271
  const label = r.name ? ` (${r.name})` : "";
205
- return fitLine(`workflow run${label}: ${r.error ?? "workflow not found"}`, opts?.width);
272
+ return renderNotice("WORKFLOW RUN", `${label || "workflow"}: ${r.error ?? "workflow not found"}`, opts, themed);
206
273
  }
207
274
  if (r.error) {
208
275
  const label = r.name ? ` (${r.name})` : "";
209
- return fitLine(`workflow run ${r.runId}${label}: ${r.status} — ${r.error}`, opts?.width);
276
+ return renderNotice("WORKFLOW RUN", `${r.runId}${label}: ${r.status} — ${r.error}`, opts, themed);
210
277
  }
211
278
  if (r.details) {
212
279
  const label = r.name ? ` (${r.name})` : "";
213
- return fitLine(`workflow run ${r.runId}${label}: ${r.details.mode} ${r.details.status}`, opts?.width);
280
+ return renderNotice("WORKFLOW RUN", `${r.runId}${label}: ${r.details.mode} ${r.details.status}`, opts, themed);
214
281
  }
215
282
  if (r.status === "completed" || r.status === "killed") {
216
283
  const label = r.name ? ` (${r.name})` : "";
217
- return fitLine(`workflow run ${r.runId}${label}: ${r.status}`, opts?.width);
284
+ return renderNotice("WORKFLOW RUN", `${r.runId}${label}: ${r.status}`, opts, themed);
218
285
  }
219
286
  // Background dispatch — reuse the same confirmation card rendered by
220
287
  // `/workflow <name> ...` when we have the workflow name and run id.
@@ -228,31 +295,69 @@ export function renderResult(result: WorkflowToolResult, opts?: RenderResultOpts
228
295
  });
229
296
  }
230
297
  const label = r.name ? ` (${r.name})` : "";
231
- return fitLine(
232
- `workflow run ${r.runId}${label}: started in background — ${r.message ?? r.status}`,
233
- opts?.width,
298
+ return renderNotice(
299
+ "WORKFLOW RUN",
300
+ `${r.runId}${label}: started in background — ${r.message ?? r.status}`,
301
+ opts,
302
+ themed,
234
303
  );
235
304
  }
236
305
 
306
+ case "stages": {
307
+ const r = result as StageListResult;
308
+ if (r.error) return renderNotice("WORKFLOW STAGES", `${r.runId || "(none)"}: ${r.error}`, opts, themed);
309
+ const counts = r.stages.map((s) => `${s.name} (${s.id.slice(0, 12)}): ${s.status}`).join("; ");
310
+ return renderNotice("WORKFLOW STAGES", `${r.runId}: ${r.filter} — ${counts || "no stages"}`, opts, themed);
311
+ }
312
+
313
+ case "stage": {
314
+ const r = result as StageDetailResult;
315
+ if (r.error || !r.stage) return renderNotice("WORKFLOW STAGE", `${r.runId}: ${r.error ?? "stage not found"}`, opts, themed);
316
+ const extra = r.stage.error ? ` — ${r.stage.error}` : r.stage.result ? ` — ${r.stage.result}` : "";
317
+ return renderNotice("WORKFLOW STAGE", `${r.runId}: ${r.stage.name} (${r.stage.id.slice(0, 12)}) ${r.stage.status}${extra}`, opts, themed);
318
+ }
319
+
320
+ case "transcript": {
321
+ const r = result as TranscriptResult;
322
+ const text = transcriptNoticeText(r.entries);
323
+ const suffix = r.truncated ? " (truncated)" : "";
324
+ return renderNotice("WORKFLOW TRANSCRIPT", `${r.runId}/${r.stageId.slice(0, 12)} ${r.source}: ${text}${suffix}`, opts, themed);
325
+ }
326
+
327
+ case "send": {
328
+ const r = result as SendResult;
329
+ return renderNotice("WORKFLOW SEND", `${r.runId}/${r.stageId.slice(0, 12)} ${r.delivery}: ${r.message}`, opts, themed);
330
+ }
331
+
332
+ case "pause": {
333
+ const r = result as PauseResult;
334
+ return renderNotice("WORKFLOW PAUSE", `${r.runId}: ${r.message}`, opts, themed);
335
+ }
336
+
337
+ case "reload": {
338
+ const r = result as ReloadResult;
339
+ return renderNotice("WORKFLOW RELOAD", r.message, opts, themed);
340
+ }
341
+
237
342
  case "interrupt": {
238
343
  const r = result as InterruptResult;
239
- return fitLine(`workflow interrupt ${r.runId}: ${r.message}`, opts?.width);
344
+ return renderNotice("WORKFLOW INTERRUPT", `${r.runId}: ${r.message}`, opts, themed);
240
345
  }
241
346
 
242
347
  case "kill": {
243
348
  const r = result as KillResult;
244
- return fitLine(`workflow kill ${r.runId}: ${r.message}`, opts?.width);
349
+ return renderNotice("WORKFLOW KILL", `${r.runId}: ${r.message}`, opts, themed);
245
350
  }
246
351
 
247
352
  case "resume": {
248
353
  const r = result as ResumeResult;
249
- return fitLine(`workflow resume ${r.runId}: ${r.message}`, opts?.width);
354
+ return renderNotice("WORKFLOW RESUME", `${r.runId}: ${r.message}`, opts, themed);
250
355
  }
251
356
 
252
357
  default: {
253
358
  // Runtime guard — handles values coerced from external sources.
254
359
  const fallback = result as { action: string; message?: string };
255
- return fitLine(`workflow: ${fallback.message ?? JSON.stringify(result)}`, opts?.width);
360
+ return renderNotice("WORKFLOW", fallback.message ?? JSON.stringify(result), opts, themed);
256
361
  }
257
362
  }
258
363
  }
@@ -24,8 +24,9 @@ import type {
24
24
  WorkflowModelCatalogPort,
25
25
  } from "../shared/types.js";
26
26
  import type { StageAdapters } from "../runs/foreground/stage-runner.js";
27
- import { runChain, runParallel, runTask, type RunOpts } from "../runs/foreground/executor.js";
27
+ import { resolveInputs, runChain, runParallel, runTask, type RunOpts } from "../runs/foreground/executor.js";
28
28
  import type { Store } from "../shared/store.js";
29
+ import type { RunSnapshot } from "../shared/store-types.js";
29
30
  import type { CancellationRegistry } from "../runs/background/cancellation-registry.js";
30
31
  import { store as defaultStore } from "../shared/store.js";
31
32
  import { dispatch } from "./dispatcher.js";
@@ -39,6 +40,8 @@ import {
39
40
  type WorkflowResultIntercomPort,
40
41
  } from "../intercom/result-intercom.js";
41
42
  import { validateWorkflowModels } from "../runs/shared/model-fallback.js";
43
+ import { runDetached } from "../runs/background/runner.js";
44
+ import { classifyWorkflowFailure } from "../shared/workflow-failures.js";
42
45
 
43
46
  // ---------------------------------------------------------------------------
44
47
  // Options
@@ -81,6 +84,10 @@ export interface ExtensionRuntimeOpts {
81
84
  // Public interface
82
85
  // ---------------------------------------------------------------------------
83
86
 
87
+ export type ResumeFailedRunResult =
88
+ | { ok: true; runId: string; sourceRunId: string; resumeFromStageId: string; message: string }
89
+ | { ok: false; reason: "run_not_found" | "not_resumable" | "workflow_not_found" | "insufficient_state"; message: string };
90
+
84
91
  export interface ExtensionRuntime {
85
92
  /**
86
93
  * Live registry — read-only reference.
@@ -96,6 +103,9 @@ export interface ExtensionRuntime {
96
103
 
97
104
  /** Execute direct single/parallel/chain workflow tool modes. */
98
105
  runDirect(args: WorkflowToolArgs): Promise<WorkflowDetails>;
106
+
107
+ /** Start a linked continuation for a failed resumable named workflow run. */
108
+ resumeFailedRun(sourceRunId: string, stageId?: string): ResumeFailedRunResult;
99
109
  }
100
110
 
101
111
  // ---------------------------------------------------------------------------
@@ -312,6 +322,82 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
312
322
  throw new Error("WorkflowRuntime.runDirect: no direct execution mode supplied");
313
323
  }
314
324
 
325
+ function matchesResumeStageIdentifier(stage: RunSnapshot["stages"][number], identifier: string): boolean {
326
+ return stage.id === identifier || stage.name === identifier || stage.id.startsWith(identifier);
327
+ }
328
+
329
+ function stageLabel(stage: RunSnapshot["stages"][number]): string {
330
+ return `${stage.name} (${stage.id.slice(0, 12)})`;
331
+ }
332
+
333
+ function resolveUniqueResumeStage(source: RunSnapshot, identifier: string): { ok: true; stage: RunSnapshot["stages"][number] } | { ok: false; message: string } {
334
+ const exactId = source.stages.find((stage) => stage.id === identifier);
335
+ if (exactId !== undefined) return { ok: true, stage: exactId };
336
+
337
+ const exactNames = source.stages.filter((stage) => stage.name === identifier);
338
+ if (exactNames.length === 1) return { ok: true, stage: exactNames[0]! };
339
+ if (exactNames.length > 1) {
340
+ return { ok: false, message: `insufficient_state: ambiguous stage identifier "${identifier}" matches: ${exactNames.map(stageLabel).join(", ")}` };
341
+ }
342
+
343
+ const matches = source.stages.filter((stage) => matchesResumeStageIdentifier(stage, identifier));
344
+ if (matches.length === 0) return { ok: false, message: `insufficient_state: stage not found in source run ${source.id}: ${identifier}` };
345
+ if (matches.length > 1) {
346
+ return { ok: false, message: `insufficient_state: ambiguous stage identifier "${identifier}" matches: ${matches.map(stageLabel).join(", ")}` };
347
+ }
348
+ return { ok: true, stage: matches[0]! };
349
+ }
350
+
351
+ function resolveResumeStage(source: RunSnapshot, stageId?: string): { ok: true; stageId: string } | { ok: false; message: string } {
352
+ if (stageId !== undefined) {
353
+ const resolved = resolveUniqueResumeStage(source, stageId);
354
+ if (!resolved.ok) return { ok: false, message: resolved.message };
355
+ const stage = resolved.stage;
356
+ if (stage.status !== "failed") return { ok: false, message: `insufficient_state: stage ${stage.name} is ${stage.status}, not failed` };
357
+ return { ok: true, stageId: stage.id };
358
+ }
359
+ const failedStageId = source.failedStageId ?? source.stages.find((stage) => stage.status === "failed")?.id;
360
+ if (failedStageId === undefined) {
361
+ return { ok: false, message: `insufficient_state: failed run ${source.id} does not identify a failed stage` };
362
+ }
363
+ return { ok: true, stageId: failedStageId };
364
+ }
365
+
366
+ function resumeFailedRun(sourceRunId: string, stageId?: string): ResumeFailedRunResult {
367
+ const source = activeStore.runs().find((run) => run.id === sourceRunId);
368
+ if (source === undefined) {
369
+ return { ok: false, reason: "run_not_found", message: `run not found: ${sourceRunId}` };
370
+ }
371
+ if (source.status !== "failed" || source.endedAt === undefined || source.resumable === false) {
372
+ return { ok: false, reason: "not_resumable", message: `run ${sourceRunId} is not a failed resumable workflow run` };
373
+ }
374
+ const def = registry.get(source.name);
375
+ if (def === undefined) {
376
+ return { ok: false, reason: "workflow_not_found", message: `workflow_not_found: ${source.name}` };
377
+ }
378
+ const resolvedStage = resolveResumeStage(source, stageId);
379
+ if (!resolvedStage.ok) {
380
+ return { ok: false, reason: "insufficient_state", message: resolvedStage.message };
381
+ }
382
+ const sourceInputs = { ...source.inputs };
383
+ try {
384
+ resolveInputs(def.inputs, sourceInputs);
385
+ } catch (err) {
386
+ return { ok: false, reason: "insufficient_state", message: `insufficient_state: ${err instanceof Error ? err.message : String(err)}` };
387
+ }
388
+ const accepted = runDetached(def, sourceInputs, {
389
+ ...runOptions({ workflow: def.name, inputs: sourceInputs }),
390
+ continuation: { source, resumeFromStageId: resolvedStage.stageId },
391
+ });
392
+ return {
393
+ ok: true,
394
+ runId: accepted.runId,
395
+ sourceRunId: source.id,
396
+ resumeFromStageId: resolvedStage.stageId,
397
+ message: `Resuming failed workflow "${def.name}" from run ${source.id.slice(0, 8)} at stage ${resolvedStage.stageId.slice(0, 8)} (new run ${accepted.runId}).`,
398
+ };
399
+ }
400
+
315
401
  async function runDirectAsync(args: WorkflowToolArgs): Promise<WorkflowDetails> {
316
402
  const runId = crypto.randomUUID();
317
403
  const mode = directMode(args);
@@ -330,7 +416,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
330
416
  runId,
331
417
  status: "failed",
332
418
  progress: { completed: 0, total: directProgressTotal(args) },
333
- error: error instanceof Error ? error.message : String(error),
419
+ error: classifyWorkflowFailure(error).userMessage,
334
420
  }, delivery, parentSession);
335
421
  }
336
422
  const background = runDirectForeground(args, runId);
@@ -345,7 +431,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
345
431
  runId,
346
432
  status: "failed",
347
433
  progress: { completed: 0, total: directProgressTotal(args) },
348
- error: error instanceof Error ? error.message : String(error),
434
+ error: classifyWorkflowFailure(error).userMessage,
349
435
  }, delivery, parentSession);
350
436
  emitDirectIntercom(details, delivery, parentSession);
351
437
  },
@@ -382,5 +468,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
382
468
  return summarized;
383
469
  });
384
470
  },
471
+
472
+ resumeFailedRun,
385
473
  };
386
474
  }
@@ -21,10 +21,12 @@
21
21
  * pi docs/sdk.md createAgentSession
22
22
  */
23
23
 
24
+ import { basename } from "node:path";
24
25
  import type { CreateAgentSessionOptions } from "@bastani/atomic";
25
26
  import type { ChatMessageRenderOptions } from "@bastani/atomic";
26
27
  import type { StageAdapters, StageSessionRuntime } from "../runs/foreground/stage-runner.js";
27
28
  import type { StageExecutionMeta, StageOptions } from "../shared/types.js";
29
+ import { stageUiBroker, type StageUiBroker } from "../shared/stage-ui-broker.js";
28
30
 
29
31
  // ---------------------------------------------------------------------------
30
32
  // Minimal pi surface
@@ -61,6 +63,8 @@ export interface RuntimeWiringSurface {
61
63
  export interface RuntimeAdapterBuildOptions {
62
64
  /** Test seam for SDK session creation. */
63
65
  createAgentSession?: (options?: CreateAgentSessionOptions) => Promise<{ session: StageSessionRuntime }>;
66
+ /** Broker that routes stage-local custom UI into attached workflow nodes. */
67
+ stageUiBroker?: StageUiBroker;
64
68
  }
65
69
 
66
70
  type BindableStageSession = StageSessionRuntime & {
@@ -149,7 +153,7 @@ export async function prepareAtomicStageSessionOptions(
149
153
  cwd,
150
154
  agentDir,
151
155
  settingsManager,
152
- builtinPackagePaths: sdk.getBuiltinPackagePaths?.() ?? [],
156
+ builtinPackagePaths: stageBuiltinPackagePaths(sdk.getBuiltinPackagePaths?.() ?? []),
153
157
  });
154
158
  await resourceLoader.reload();
155
159
 
@@ -162,6 +166,15 @@ export async function prepareAtomicStageSessionOptions(
162
166
  };
163
167
  }
164
168
 
169
+ function stageBuiltinPackagePaths(paths: readonly string[]): string[] {
170
+ // Workflow stages are child AgentSessions owned by the workflow extension.
171
+ // Loading the workflows extension again inside that child session replays its
172
+ // `session_start` lifecycle and clears/kills the parent workflow store. Keep
173
+ // the other builtin packages (subagents, mcp, web-access, intercom), but do
174
+ // not recursively install workflows into workflow stage sessions.
175
+ return paths.filter((path) => basename(path) !== "workflows");
176
+ }
177
+
165
178
  async function createPiSdkAgentSession(
166
179
  options?: CreateAgentSessionOptions,
167
180
  ): Promise<{ session: StageSessionRuntime }> {
@@ -224,7 +237,11 @@ function stripWorkflowOnlyOptions(options: (StageOptions | CreateAgentSessionOpt
224
237
  return sessionOptions as CreateAgentSessionOptions;
225
238
  }
226
239
 
227
- function makeStageExtensionUiContext(ui: PiUISurface) {
240
+ function makeStageExtensionUiContext(
241
+ ui: PiUISurface,
242
+ meta: StageExecutionMeta | undefined,
243
+ broker: StageUiBroker,
244
+ ) {
228
245
  return {
229
246
  select: ui.select ?? (async () => undefined),
230
247
  confirm: ui.confirm ?? (async () => false),
@@ -240,14 +257,22 @@ function makeStageExtensionUiContext(ui: PiUISurface) {
240
257
  setFooter: ui.setFooter ?? (() => undefined),
241
258
  setHeader: ui.setHeader ?? (() => undefined),
242
259
  setTitle: ui.setTitle ?? (() => undefined),
243
- custom: ui.custom
244
- ? async <T = undefined>(factory: PiCustomOverlayFactory<T>, options?: PiCustomOverlayOptions): Promise<T> => {
245
- const result = await ui.custom!(factory as PiCustomOverlayFactory, options ?? { overlay: true });
260
+ custom: async <T = undefined>(factory: PiCustomOverlayFactory<T>, options?: PiCustomOverlayOptions): Promise<T> => {
261
+ if (meta !== undefined) {
262
+ return broker.requestCustomUi(
263
+ meta.runId,
264
+ meta.stageId,
265
+ factory,
266
+ options,
267
+ meta.signal,
268
+ );
269
+ }
270
+ if (ui.custom) {
271
+ const result = await ui.custom(factory as PiCustomOverlayFactory, options ?? { overlay: true });
246
272
  return result as T;
247
273
  }
248
- : async () => {
249
- throw new Error("pi-workflows: ask_user_question UI is unavailable");
250
- },
274
+ throw new Error("pi-workflows: ask_user_question UI is unavailable");
275
+ },
251
276
  pasteToEditor: ui.pasteToEditor ?? (() => undefined),
252
277
  setEditorText: ui.setEditorText ?? (() => undefined),
253
278
  getEditorText: ui.getEditorText ?? (() => ""),
@@ -289,9 +314,10 @@ export function buildRuntimeAdapters(
289
314
  options.createAgentSession ??
290
315
  pi.createAgentSession ??
291
316
  (isTestContext() ? createTestAgentSession : createPiSdkAgentSession);
317
+ const broker = options.stageUiBroker ?? stageUiBroker;
292
318
  const adapters: StageAdapters = {
293
319
  agentSession: {
294
- async create(stageOptions: CreateAgentSessionOptions & Pick<StageOptions, "mcp" | "fallbackModels">, _meta?: StageExecutionMeta): Promise<StageSessionRuntime> {
320
+ async create(stageOptions: CreateAgentSessionOptions & Pick<StageOptions, "mcp" | "fallbackModels">, meta?: StageExecutionMeta): Promise<StageSessionRuntime> {
295
321
  // Atomic's SDK handles extension / skills / prompt-template /
296
322
  // slash-command discovery via the SettingsManager / ResourceLoader.
297
323
  // The production default deliberately uses normal DefaultResourceLoader
@@ -302,9 +328,9 @@ export function buildRuntimeAdapters(
302
328
  const sessionOptions: CreateAgentSessionOptions = stripWorkflowOnlyOptions(stageOptions) ?? {};
303
329
  const result = await createSession(sessionOptions);
304
330
  const bindable = result.session as BindableStageSession;
305
- if (typeof pi.ui?.custom === "function" && typeof bindable.bindExtensions === "function") {
331
+ if ((pi.ui !== undefined || meta !== undefined) && typeof bindable.bindExtensions === "function") {
306
332
  await bindable.bindExtensions({
307
- uiContext: makeStageExtensionUiContext(pi.ui),
333
+ uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta, broker),
308
334
  });
309
335
  }
310
336
  return result.session;
@@ -568,7 +594,7 @@ export interface PiUISurface {
568
594
  setTheme?: (theme: string | unknown) => { success: boolean; error?: string };
569
595
  getToolsExpanded?: () => boolean;
570
596
  setToolsExpanded?: (expanded: boolean) => void;
571
- getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd" | "markdownTheme">> | undefined;
597
+ getChatRenderSettings?: () => Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd">> | undefined;
572
598
  }
573
599
 
574
600
  /**
@@ -99,21 +99,78 @@ export const WorkflowParametersSchema = Type.Object({
99
99
  Type.Literal("get"),
100
100
  Type.Literal("inputs"),
101
101
  Type.Literal("status"),
102
+ Type.Literal("stages"),
103
+ Type.Literal("stage"),
104
+ Type.Literal("transcript"),
105
+ Type.Literal("send"),
106
+ Type.Literal("pause"),
102
107
  Type.Literal("interrupt"),
103
108
  Type.Literal("kill"),
104
109
  Type.Literal("resume"),
105
- ])),
110
+ Type.Literal("reload"),
111
+ ], {
112
+ description: "Workflow action: run/list/get/inputs/status, inspect stages/transcripts, send messages or prompt answers, pause/resume/interrupt/kill runs, or reload workflow resources.",
113
+ })),
106
114
  runId: Type.Optional(Type.String({
107
- description: "Run identifier or unique prefix for status/interrupt/kill/resume. Use '--all' for interrupt/kill all.",
115
+ description: "Run identifier or unique prefix for status/stages/stage/transcript/send/pause/resume/interrupt/kill. Use '--all' or all:true for supported bulk run-control actions.",
108
116
  })),
109
117
  all: Type.Optional(Type.Boolean({
110
- description: "Apply supported run-control actions (interrupt/kill) to all in-flight runs.",
118
+ description: "Apply supported run-control actions (pause/interrupt/kill) to all in-flight runs instead of one run; cannot be combined with stageId.",
111
119
  })),
112
120
  stageId: Type.Optional(Type.String({
113
- description: "Stage id, unique prefix, or stage name for stage-scoped resume.",
121
+ description: "Stage id, unique prefix, or stage name for stage-scoped inspection, transcript, send, pause, or resume.",
114
122
  })),
115
123
  message: Type.Optional(Type.String({
116
- description: "Optional message forwarded when resuming paused work.",
124
+ description: "Message payload for send/follow-up/prompt/steer/resume, or optional text forwarded when resuming paused work.",
125
+ })),
126
+ statusFilter: Type.Optional(Type.Union([
127
+ Type.Literal("pending"),
128
+ Type.Literal("running"),
129
+ Type.Literal("awaiting_input"),
130
+ Type.Literal("paused"),
131
+ Type.Literal("blocked"),
132
+ Type.Literal("completed"),
133
+ Type.Literal("failed"),
134
+ Type.Literal("skipped"),
135
+ Type.Literal("all"),
136
+ ], {
137
+ description: "Filter stages by status for the stages action; use 'all' to include every stage.",
138
+ })),
139
+ format: Type.Optional(Type.Union([Type.Literal("text"), Type.Literal("json")], {
140
+ description: "Agent-visible output format for data-bearing inspection actions.",
141
+ })),
142
+ limit: Type.Optional(Type.Integer({
143
+ minimum: 0,
144
+ description: "Transcript-only: maximum number of most recent transcript entries to return; applied before tool output is serialized.",
145
+ })),
146
+ tail: Type.Optional(Type.Integer({
147
+ minimum: 0,
148
+ description: "Transcript-only: return only the last N transcript entries; overrides limit when both are provided.",
149
+ })),
150
+ includeToolOutput: Type.Optional(Type.Boolean({
151
+ description: "Transcript-only: include captured tool output entries when building results from stage snapshots; live session transcripts may not expose tool output.",
152
+ })),
153
+ text: Type.Optional(Type.String({
154
+ description: "Text to send to a stage for prompt answers, steering, follow-ups, or resume messages.",
155
+ })),
156
+ response: Type.Optional(Type.Unknown({
157
+ description: "Structured response payload for answering a pending stage prompt.",
158
+ })),
159
+ delivery: Type.Optional(Type.Union([
160
+ Type.Literal("auto"),
161
+ Type.Literal("answer"),
162
+ Type.Literal("prompt"),
163
+ Type.Literal("steer"),
164
+ Type.Literal("followUp"),
165
+ Type.Literal("resume"),
166
+ ], {
167
+ description: "Delivery mode for the send action: auto answers pending prompts first, then resumes paused stages, steers streaming stages, or queues a follow-up.",
168
+ })),
169
+ promptId: Type.Optional(Type.String({
170
+ description: "Pending prompt identifier to answer when using the send action.",
171
+ })),
172
+ reason: Type.Optional(Type.String({
173
+ description: "Human-readable reason for the reload action, echoed in the reload result.",
117
174
  })),
118
175
  task: Type.Optional(Type.Union([
119
176
  DirectTaskSchema,