@bastani/atomic 0.8.28-alpha.1 → 0.8.28-alpha.3

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 (428) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +120 -118
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/package.json +1 -1
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/web-access/package.json +1 -1
  7. package/dist/builtin/workflows/CHANGELOG.md +26 -0
  8. package/dist/builtin/workflows/README.md +1 -1
  9. package/dist/builtin/workflows/builtin/open-claude-design.ts +150 -13
  10. package/dist/builtin/workflows/package.json +1 -1
  11. package/dist/builtin/workflows/src/authoring.d.ts +5 -2
  12. package/dist/builtin/workflows/src/extension/dispatcher.ts +2 -0
  13. package/dist/builtin/workflows/src/extension/index.ts +8 -0
  14. package/dist/builtin/workflows/src/extension/render-result.ts +5 -2
  15. package/dist/builtin/workflows/src/extension/workflow-schema.ts +18 -0
  16. package/dist/builtin/workflows/src/runs/background/status.ts +4 -0
  17. package/dist/builtin/workflows/src/runs/foreground/executor.ts +1251 -110
  18. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +34 -10
  19. package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +10 -2
  20. package/dist/builtin/workflows/src/shared/persistence-restore.ts +28 -9
  21. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +9 -3
  22. package/dist/builtin/workflows/src/shared/store-types.ts +10 -3
  23. package/dist/builtin/workflows/src/shared/store.ts +29 -7
  24. package/dist/builtin/workflows/src/shared/types.ts +12 -10
  25. package/dist/builtin/workflows/src/tui/chat-surface.ts +32 -33
  26. package/dist/builtin/workflows/src/tui/run-detail.ts +23 -4
  27. package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
  28. package/dist/builtin/workflows/src/tui/status-list.ts +47 -3
  29. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +1 -1
  30. package/dist/builtin/workflows/src/tui/widget.ts +12 -3
  31. package/dist/builtin/workflows/src/workflows/define-workflow.ts +3 -3
  32. package/dist/cli/args.d.ts +4 -0
  33. package/dist/cli/args.d.ts.map +1 -1
  34. package/dist/cli/args.js +35 -0
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/cli/project-trust.d.ts +10 -0
  37. package/dist/cli/project-trust.d.ts.map +1 -0
  38. package/dist/cli/project-trust.js +36 -0
  39. package/dist/cli/project-trust.js.map +1 -0
  40. package/dist/cli/startup-ui.d.ts +7 -0
  41. package/dist/cli/startup-ui.d.ts.map +1 -0
  42. package/dist/cli/startup-ui.js +57 -0
  43. package/dist/cli/startup-ui.js.map +1 -0
  44. package/dist/config.d.ts.map +1 -1
  45. package/dist/config.js +24 -3
  46. package/dist/config.js.map +1 -1
  47. package/dist/core/agent-session-runtime.d.ts +3 -1
  48. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  49. package/dist/core/agent-session-runtime.js +1 -0
  50. package/dist/core/agent-session-runtime.js.map +1 -1
  51. package/dist/core/agent-session-services.d.ts +3 -1
  52. package/dist/core/agent-session-services.d.ts.map +1 -1
  53. package/dist/core/agent-session-services.js +3 -2
  54. package/dist/core/agent-session-services.js.map +1 -1
  55. package/dist/core/agent-session.d.ts +9 -1
  56. package/dist/core/agent-session.d.ts.map +1 -1
  57. package/dist/core/agent-session.js +70 -21
  58. package/dist/core/agent-session.js.map +1 -1
  59. package/dist/core/auth-storage.d.ts.map +1 -1
  60. package/dist/core/auth-storage.js +4 -3
  61. package/dist/core/auth-storage.js.map +1 -1
  62. package/dist/core/compaction/branch-summarization.d.ts +3 -1
  63. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  64. package/dist/core/compaction/branch-summarization.js +9 -3
  65. package/dist/core/compaction/branch-summarization.js.map +1 -1
  66. package/dist/core/compaction/compaction.d.ts.map +1 -1
  67. package/dist/core/compaction/compaction.js +18 -24
  68. package/dist/core/compaction/compaction.js.map +1 -1
  69. package/dist/core/compaction/utils.d.ts +1 -1
  70. package/dist/core/compaction/utils.d.ts.map +1 -1
  71. package/dist/core/compaction/utils.js +1 -1
  72. package/dist/core/compaction/utils.js.map +1 -1
  73. package/dist/core/experimental.d.ts +2 -0
  74. package/dist/core/experimental.d.ts.map +1 -0
  75. package/dist/core/experimental.js +5 -0
  76. package/dist/core/experimental.js.map +1 -0
  77. package/dist/core/export-html/template.js +19 -6
  78. package/dist/core/extensions/index.d.ts +1 -1
  79. package/dist/core/extensions/index.d.ts.map +1 -1
  80. package/dist/core/extensions/index.js.map +1 -1
  81. package/dist/core/extensions/loader.d.ts +1 -1
  82. package/dist/core/extensions/loader.d.ts.map +1 -1
  83. package/dist/core/extensions/loader.js +6 -4
  84. package/dist/core/extensions/loader.js.map +1 -1
  85. package/dist/core/extensions/runner.d.ts +11 -4
  86. package/dist/core/extensions/runner.d.ts.map +1 -1
  87. package/dist/core/extensions/runner.js +53 -3
  88. package/dist/core/extensions/runner.js.map +1 -1
  89. package/dist/core/extensions/types.d.ts +34 -4
  90. package/dist/core/extensions/types.d.ts.map +1 -1
  91. package/dist/core/extensions/types.js.map +1 -1
  92. package/dist/core/footer-data-provider.d.ts +2 -0
  93. package/dist/core/footer-data-provider.d.ts.map +1 -1
  94. package/dist/core/footer-data-provider.js +27 -1
  95. package/dist/core/footer-data-provider.js.map +1 -1
  96. package/dist/core/index.d.ts +2 -0
  97. package/dist/core/index.d.ts.map +1 -1
  98. package/dist/core/index.js +2 -0
  99. package/dist/core/index.js.map +1 -1
  100. package/dist/core/model-registry.d.ts.map +1 -1
  101. package/dist/core/model-registry.js +64 -7
  102. package/dist/core/model-registry.js.map +1 -1
  103. package/dist/core/model-resolver.d.ts.map +1 -1
  104. package/dist/core/model-resolver.js +1 -0
  105. package/dist/core/model-resolver.js.map +1 -1
  106. package/dist/core/output-guard.d.ts +1 -0
  107. package/dist/core/output-guard.d.ts.map +1 -1
  108. package/dist/core/output-guard.js +52 -22
  109. package/dist/core/output-guard.js.map +1 -1
  110. package/dist/core/package-manager.d.ts +1 -0
  111. package/dist/core/package-manager.d.ts.map +1 -1
  112. package/dist/core/package-manager.js +20 -8
  113. package/dist/core/package-manager.js.map +1 -1
  114. package/dist/core/project-trust.d.ts +15 -0
  115. package/dist/core/project-trust.d.ts.map +1 -0
  116. package/dist/core/project-trust.js +58 -0
  117. package/dist/core/project-trust.js.map +1 -0
  118. package/dist/core/prompt-templates.d.ts +5 -4
  119. package/dist/core/prompt-templates.d.ts.map +1 -1
  120. package/dist/core/prompt-templates.js +30 -29
  121. package/dist/core/prompt-templates.js.map +1 -1
  122. package/dist/core/provider-attribution.d.ts +4 -0
  123. package/dist/core/provider-attribution.d.ts.map +1 -0
  124. package/dist/core/provider-attribution.js +73 -0
  125. package/dist/core/provider-attribution.js.map +1 -0
  126. package/dist/core/provider-display-names.d.ts.map +1 -1
  127. package/dist/core/provider-display-names.js +3 -0
  128. package/dist/core/provider-display-names.js.map +1 -1
  129. package/dist/core/resolve-config-value.d.ts +9 -1
  130. package/dist/core/resolve-config-value.d.ts.map +1 -1
  131. package/dist/core/resolve-config-value.js +134 -11
  132. package/dist/core/resolve-config-value.js.map +1 -1
  133. package/dist/core/resource-loader.d.ts +12 -2
  134. package/dist/core/resource-loader.d.ts.map +1 -1
  135. package/dist/core/resource-loader.js +108 -18
  136. package/dist/core/resource-loader.js.map +1 -1
  137. package/dist/core/sdk.d.ts +4 -2
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +13 -42
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +6 -7
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +99 -35
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts +15 -2
  146. package/dist/core/settings-manager.d.ts.map +1 -1
  147. package/dist/core/settings-manager.js +69 -10
  148. package/dist/core/settings-manager.js.map +1 -1
  149. package/dist/core/slash-commands.d.ts.map +1 -1
  150. package/dist/core/slash-commands.js +1 -0
  151. package/dist/core/slash-commands.js.map +1 -1
  152. package/dist/core/system-prompt.d.ts.map +1 -1
  153. package/dist/core/system-prompt.js +0 -3
  154. package/dist/core/system-prompt.js.map +1 -1
  155. package/dist/core/tools/ask-user-question/state/inline-input.d.ts +28 -0
  156. package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -0
  157. package/dist/core/tools/ask-user-question/state/inline-input.js +56 -0
  158. package/dist/core/tools/ask-user-question/state/inline-input.js.map +1 -0
  159. package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
  160. package/dist/core/tools/ask-user-question/state/key-router.js +30 -4
  161. package/dist/core/tools/ask-user-question/state/key-router.js.map +1 -1
  162. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  163. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +9 -8
  164. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  165. package/dist/core/tools/ask-user-question/state/row-intent.d.ts +3 -2
  166. package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
  167. package/dist/core/tools/ask-user-question/state/row-intent.js +1 -1
  168. package/dist/core/tools/ask-user-question/state/row-intent.js.map +1 -1
  169. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +2 -0
  170. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  171. package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
  172. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  173. package/dist/core/tools/ask-user-question/state/selectors/projections.js +2 -0
  174. package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
  175. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  176. package/dist/core/tools/ask-user-question/state/state-reducer.js +36 -24
  177. package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
  178. package/dist/core/tools/ask-user-question/state/state.d.ts +8 -0
  179. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  180. package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
  181. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts +6 -0
  182. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  183. package/dist/core/tools/ask-user-question/tool/format-answer.js +19 -1
  184. package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
  185. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +3 -2
  186. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  187. package/dist/core/tools/ask-user-question/tool/response-envelope.js +15 -3
  188. package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
  189. package/dist/core/tools/ask-user-question/tool/types.d.ts +2 -1
  190. package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
  191. package/dist/core/tools/ask-user-question/tool/types.js.map +1 -1
  192. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts +5 -2
  193. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
  194. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +2 -0
  195. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  196. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +1 -0
  197. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  198. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +2 -1
  199. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  200. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts +3 -3
  201. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  202. package/dist/core/tools/ask-user-question/view/props-adapter.js +11 -4
  203. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  204. package/dist/core/tools/bash-policy.d.ts +62 -0
  205. package/dist/core/tools/bash-policy.d.ts.map +1 -0
  206. package/dist/core/tools/bash-policy.js +1069 -0
  207. package/dist/core/tools/bash-policy.js.map +1 -0
  208. package/dist/core/tools/bash.d.ts +5 -0
  209. package/dist/core/tools/bash.d.ts.map +1 -1
  210. package/dist/core/tools/bash.js +9 -1
  211. package/dist/core/tools/bash.js.map +1 -1
  212. package/dist/core/tools/edit.d.ts.map +1 -1
  213. package/dist/core/tools/edit.js +7 -10
  214. package/dist/core/tools/edit.js.map +1 -1
  215. package/dist/core/tools/find.d.ts.map +1 -1
  216. package/dist/core/tools/find.js +1 -1
  217. package/dist/core/tools/find.js.map +1 -1
  218. package/dist/core/tools/grep.d.ts.map +1 -1
  219. package/dist/core/tools/grep.js +1 -1
  220. package/dist/core/tools/grep.js.map +1 -1
  221. package/dist/core/tools/index.d.ts +1 -0
  222. package/dist/core/tools/index.d.ts.map +1 -1
  223. package/dist/core/tools/index.js +1 -0
  224. package/dist/core/tools/index.js.map +1 -1
  225. package/dist/core/tools/ls.d.ts.map +1 -1
  226. package/dist/core/tools/ls.js +1 -1
  227. package/dist/core/tools/ls.js.map +1 -1
  228. package/dist/core/tools/oversized-tool-result.d.ts +53 -0
  229. package/dist/core/tools/oversized-tool-result.d.ts.map +1 -0
  230. package/dist/core/tools/oversized-tool-result.js +206 -0
  231. package/dist/core/tools/oversized-tool-result.js.map +1 -0
  232. package/dist/core/tools/read.d.ts +12 -0
  233. package/dist/core/tools/read.d.ts.map +1 -1
  234. package/dist/core/tools/read.js +99 -34
  235. package/dist/core/tools/read.js.map +1 -1
  236. package/dist/core/tools/render-utils.d.ts +6 -0
  237. package/dist/core/tools/render-utils.d.ts.map +1 -1
  238. package/dist/core/tools/render-utils.js +17 -1
  239. package/dist/core/tools/render-utils.js.map +1 -1
  240. package/dist/core/tools/tool-definition-wrapper.d.ts +6 -0
  241. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  242. package/dist/core/tools/tool-definition-wrapper.js +2 -0
  243. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  244. package/dist/core/tools/tool-limits.d.ts +25 -0
  245. package/dist/core/tools/tool-limits.d.ts.map +1 -0
  246. package/dist/core/tools/tool-limits.js +25 -0
  247. package/dist/core/tools/tool-limits.js.map +1 -0
  248. package/dist/core/tools/write.d.ts.map +1 -1
  249. package/dist/core/tools/write.js +1 -1
  250. package/dist/core/tools/write.js.map +1 -1
  251. package/dist/core/trust-manager.d.ts +31 -0
  252. package/dist/core/trust-manager.d.ts.map +1 -0
  253. package/dist/core/trust-manager.js +196 -0
  254. package/dist/core/trust-manager.js.map +1 -0
  255. package/dist/index.d.ts +11 -6
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +6 -2
  258. package/dist/index.js.map +1 -1
  259. package/dist/main.d.ts.map +1 -1
  260. package/dist/main.js +142 -30
  261. package/dist/main.js.map +1 -1
  262. package/dist/migrations.d.ts +3 -1
  263. package/dist/migrations.d.ts.map +1 -1
  264. package/dist/migrations.js +325 -7
  265. package/dist/migrations.js.map +1 -1
  266. package/dist/modes/index.d.ts +1 -1
  267. package/dist/modes/index.d.ts.map +1 -1
  268. package/dist/modes/index.js.map +1 -1
  269. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  270. package/dist/modes/interactive/components/bash-execution.js +2 -2
  271. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  272. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/footer.js +6 -0
  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 +1 -1
  280. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/login-dialog.js +9 -16
  282. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  283. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  284. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  285. package/dist/modes/interactive/components/settings-selector.js +20 -0
  286. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  287. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  288. package/dist/modes/interactive/components/tool-execution.js +22 -0
  289. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  290. package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  291. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  292. package/dist/modes/interactive/components/trust-selector.js +85 -0
  293. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  294. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  295. package/dist/modes/interactive/components/user-message.js +1 -1
  296. package/dist/modes/interactive/components/user-message.js.map +1 -1
  297. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  298. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  299. package/dist/modes/interactive/interactive-mode.js +130 -9
  300. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  301. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  302. package/dist/modes/interactive/theme/theme.js +10 -0
  303. package/dist/modes/interactive/theme/theme.js.map +1 -1
  304. package/dist/modes/print-mode.d.ts.map +1 -1
  305. package/dist/modes/print-mode.js +1 -0
  306. package/dist/modes/print-mode.js.map +1 -1
  307. package/dist/modes/rpc/rpc-client.d.ts +3 -0
  308. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  309. package/dist/modes/rpc/rpc-client.js +50 -6
  310. package/dist/modes/rpc/rpc-client.js.map +1 -1
  311. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  312. package/dist/modes/rpc/rpc-mode.js +23 -4
  313. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  314. package/dist/modes/rpc/rpc-types.d.ts +1 -0
  315. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  316. package/dist/modes/rpc/rpc-types.js.map +1 -1
  317. package/dist/package-manager-cli.d.ts +6 -2
  318. package/dist/package-manager-cli.d.ts.map +1 -1
  319. package/dist/package-manager-cli.js +104 -10
  320. package/dist/package-manager-cli.js.map +1 -1
  321. package/dist/utils/changelog.d.ts +1 -0
  322. package/dist/utils/changelog.d.ts.map +1 -1
  323. package/dist/utils/changelog.js +72 -0
  324. package/dist/utils/changelog.js.map +1 -1
  325. package/dist/utils/deprecation.d.ts +4 -0
  326. package/dist/utils/deprecation.d.ts.map +1 -0
  327. package/dist/utils/deprecation.js +13 -0
  328. package/dist/utils/deprecation.js.map +1 -0
  329. package/dist/utils/git.d.ts.map +1 -1
  330. package/dist/utils/git.js +54 -22
  331. package/dist/utils/git.js.map +1 -1
  332. package/dist/utils/json.d.ts +3 -0
  333. package/dist/utils/json.d.ts.map +1 -0
  334. package/dist/utils/json.js +7 -0
  335. package/dist/utils/json.js.map +1 -0
  336. package/dist/utils/open-browser.d.ts +9 -0
  337. package/dist/utils/open-browser.d.ts.map +1 -0
  338. package/dist/utils/open-browser.js +22 -0
  339. package/dist/utils/open-browser.js.map +1 -0
  340. package/docs/containerization.md +111 -0
  341. package/docs/custom-provider.md +9 -9
  342. package/docs/development.md +1 -1
  343. package/docs/docs.json +2 -0
  344. package/docs/extensions.md +40 -4
  345. package/docs/index.md +2 -0
  346. package/docs/models.md +10 -10
  347. package/docs/packages.md +1 -1
  348. package/docs/prompt-templates.md +9 -2
  349. package/docs/providers.md +18 -5
  350. package/docs/quickstart.md +1 -0
  351. package/docs/rpc.md +3 -2
  352. package/docs/sdk.md +47 -0
  353. package/docs/security.md +58 -0
  354. package/docs/session-format.md +2 -2
  355. package/docs/sessions.md +8 -0
  356. package/docs/settings.md +21 -4
  357. package/docs/skills.md +1 -1
  358. package/docs/terminal-setup.md +44 -2
  359. package/docs/themes.md +1 -1
  360. package/docs/tmux.md +4 -2
  361. package/docs/tui.md +14 -5
  362. package/docs/usage.md +17 -3
  363. package/docs/workflows.md +127 -15
  364. package/examples/README.md +1 -1
  365. package/examples/extensions/README.md +8 -5
  366. package/examples/extensions/bash-spawn-hook.ts +1 -1
  367. package/examples/extensions/built-in-tool-renderer.ts +1 -1
  368. package/examples/extensions/claude-rules.ts +1 -1
  369. package/examples/extensions/commands.ts +1 -1
  370. package/examples/extensions/custom-header.ts +1 -1
  371. package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
  372. package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
  373. package/examples/extensions/custom-provider-anthropic/package.json +6 -6
  374. package/examples/extensions/custom-provider-gitlab-duo/index.ts +55 -4
  375. package/examples/extensions/custom-provider-gitlab-duo/package.json +3 -3
  376. package/examples/extensions/doom-overlay/README.md +1 -1
  377. package/examples/extensions/doom-overlay/index.ts +2 -2
  378. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  379. package/examples/extensions/gondolin/index.ts +523 -0
  380. package/examples/extensions/gondolin/package-lock.json +185 -0
  381. package/examples/extensions/gondolin/package.json +19 -0
  382. package/examples/extensions/handoff.ts +1 -1
  383. package/examples/extensions/hidden-thinking-label.ts +1 -1
  384. package/examples/extensions/inline-bash.ts +2 -2
  385. package/examples/extensions/input-transform-streaming.ts +39 -0
  386. package/examples/extensions/input-transform.ts +3 -3
  387. package/examples/extensions/interactive-shell.ts +2 -2
  388. package/examples/extensions/mac-system-theme.ts +2 -2
  389. package/examples/extensions/minimal-mode.ts +1 -1
  390. package/examples/extensions/modal-editor.ts +1 -1
  391. package/examples/extensions/model-status.ts +1 -1
  392. package/examples/extensions/overlay-qa-tests.ts +198 -179
  393. package/examples/extensions/overlay-test.ts +1 -1
  394. package/examples/extensions/pirate.ts +1 -1
  395. package/examples/extensions/preset.ts +14 -12
  396. package/examples/extensions/project-trust.ts +64 -0
  397. package/examples/extensions/prompt-customizer.ts +1 -1
  398. package/examples/extensions/qna.ts +1 -1
  399. package/examples/extensions/question.ts +1 -1
  400. package/examples/extensions/questionnaire.ts +1 -1
  401. package/examples/extensions/rainbow-editor.ts +1 -1
  402. package/examples/extensions/sandbox/index.ts +16 -14
  403. package/examples/extensions/sandbox/package-lock.json +90 -90
  404. package/examples/extensions/sandbox/package.json +17 -17
  405. package/examples/extensions/snake.ts +1 -1
  406. package/examples/extensions/space-invaders.ts +1 -1
  407. package/examples/extensions/ssh.ts +2 -2
  408. package/examples/extensions/subagent/README.md +13 -13
  409. package/examples/extensions/subagent/agents.ts +4 -2
  410. package/examples/extensions/subagent/index.ts +6 -6
  411. package/examples/extensions/summarize.ts +1 -1
  412. package/examples/extensions/tic-tac-toe.ts +1 -1
  413. package/examples/extensions/titlebar-spinner.ts +1 -1
  414. package/examples/extensions/todo.ts +1 -1
  415. package/examples/extensions/tool-override.ts +1 -1
  416. package/examples/extensions/tools.ts +6 -1
  417. package/examples/extensions/with-deps/package-lock.json +4 -4
  418. package/examples/extensions/with-deps/package.json +7 -7
  419. package/examples/extensions/working-indicator.ts +4 -4
  420. package/examples/extensions/working-message-test.ts +1 -1
  421. package/examples/sdk/01-minimal.ts +1 -1
  422. package/examples/sdk/03-custom-prompt.ts +1 -1
  423. package/examples/sdk/04-skills.ts +1 -1
  424. package/examples/sdk/06-extensions.ts +2 -2
  425. package/examples/sdk/08-prompt-templates.ts +1 -1
  426. package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
  427. package/examples/sdk/README.md +2 -2
  428. package/package.json +4 -4
@@ -6,7 +6,7 @@
6
6
  * modules here. Public custom-TUI types are type-only imports from the same
7
7
  * extension-compatible surfaces used by Atomic extension UI.
8
8
  */
9
- import type { KeybindingsManager, Theme } from "@bastani/atomic";
9
+ import type { BashCommandPolicy, KeybindingsManager, Theme } from "@bastani/atomic";
10
10
  import type { Component, OverlayHandle, OverlayOptions, TUI } from "@earendil-works/pi-tui";
11
11
  import type { Static, TOptional, TSchema } from "typebox";
12
12
  export type { Static, TSchema };
@@ -31,10 +31,16 @@ export type WorkflowOutputMode = "inline" | "file-only";
31
31
  export type WorkflowContextMode = "fresh" | "fork";
32
32
  export type WorkflowThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
33
33
  export type WorkflowExecutionMode = "interactive" | "non_interactive";
34
- export type RunStatus = "pending" | "running" | "paused" | "completed" | "failed" | "killed";
34
+ export type WorkflowExitStatus = "completed" | "skipped" | "cancelled" | "blocked";
35
+ export type RunStatus = "pending" | "running" | "paused" | WorkflowExitStatus | "failed" | "killed";
35
36
  export type WorkflowDetailsMode = "named" | "single" | "parallel" | "chain" | "inspection" | "control";
36
- export type WorkflowDetailsStatus = "accepted" | "running" | "completed" | "failed" | "killed" | "noop";
37
+ export type WorkflowDetailsStatus = "accepted" | "running" | WorkflowExitStatus | "failed" | "killed" | "noop";
37
38
  export type WorkflowAction = "list" | "get" | "inputs" | "run" | "status" | "interrupt" | "resume";
39
+ export interface WorkflowExitOptions<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> {
40
+ readonly status?: WorkflowExitStatus;
41
+ readonly reason?: string;
42
+ readonly outputs?: Partial<TOutputs>;
43
+ }
38
44
  export interface WorkflowModelFallbackFields {
39
45
  /** Ordered model IDs to try after `model` fails; entries may use `:off|minimal|low|medium|high|xhigh` reasoning suffixes. */
40
46
  readonly fallbackModels?: readonly string[];
@@ -112,6 +118,7 @@ export interface StageOptions extends WorkflowModelFallbackFields {
112
118
  readonly noTools?: "all" | "builtin";
113
119
  readonly excludedTools?: readonly string[];
114
120
  readonly customTools?: readonly WorkflowCustomToolDefinition[];
121
+ readonly bashPolicy?: BashCommandPolicy;
115
122
  readonly cwd?: string;
116
123
  readonly agentDir?: string;
117
124
  readonly scopedModels?: readonly WorkflowScopedModel[];
@@ -332,12 +339,22 @@ export interface WorkflowRunChildOptions<TInputs extends WorkflowInputValues = W
332
339
  readonly inputs?: TInputs;
333
340
  readonly stageName?: string;
334
341
  }
335
- export interface WorkflowChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> extends WorkflowSerializableObject {
342
+ export interface WorkflowCompletedChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> extends WorkflowSerializableObject {
336
343
  readonly workflow: string;
337
344
  readonly runId: string;
338
345
  readonly status: "completed";
346
+ readonly exited: false;
339
347
  readonly outputs: TOutputs;
340
348
  }
349
+ export interface WorkflowExitedChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> extends WorkflowSerializableObject {
350
+ readonly workflow: string;
351
+ readonly runId: string;
352
+ readonly status: WorkflowExitStatus;
353
+ readonly exited: true;
354
+ readonly outputs: Partial<TOutputs>;
355
+ readonly exitReason?: string;
356
+ }
357
+ export type WorkflowChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> = WorkflowCompletedChildResult<TOutputs> | WorkflowExitedChildResult<TOutputs>;
341
358
  export type WorkflowCustomUiComponent = Component & {
342
359
  dispose?(): void;
343
360
  };
@@ -379,9 +396,10 @@ export interface WorkflowUIAdapter {
379
396
  editor(initial?: string): Promise<string>;
380
397
  custom?<T>(factory: WorkflowCustomUiFactory<T>, options?: WorkflowCustomUiOptions): Promise<T>;
381
398
  }
382
- export interface WorkflowRunContext<TInputs extends WorkflowInputValues = WorkflowInputValues, TDefinitionBrand extends object = {}> {
399
+ export interface WorkflowRunContext<TInputs extends WorkflowInputValues = WorkflowInputValues, TDefinitionBrand extends object = {}, TOutputs extends WorkflowOutputValues = WorkflowOutputValues> {
383
400
  readonly inputs: Readonly<TInputs>;
384
401
  readonly cwd?: string;
402
+ exit(options?: WorkflowExitOptions<TOutputs>): never;
385
403
  stage(name: string, options?: StageOptions): StageContext;
386
404
  task(name: string, options: WorkflowTaskOptions): Promise<WorkflowTaskResult>;
387
405
  chain(steps: readonly WorkflowTaskStep[], options?: WorkflowChainOptions): Promise<WorkflowTaskResult[]>;
@@ -389,7 +407,7 @@ export interface WorkflowRunContext<TInputs extends WorkflowInputValues = Workfl
389
407
  workflow<TChildInputs extends WorkflowInputValues, TChildOutputs extends WorkflowOutputValues>(definition: WorkflowDefinition<TChildInputs, TChildOutputs> & TDefinitionBrand, options?: WorkflowRunChildOptions<TChildInputs>): Promise<WorkflowChildResult<TChildOutputs>>;
390
408
  readonly ui: WorkflowUIContext;
391
409
  }
392
- export type WorkflowRunFn<TInputs extends WorkflowInputValues = WorkflowInputValues, TOutputs extends WorkflowOutputValues = WorkflowOutputValues, TDefinitionBrand extends object = {}> = (ctx: WorkflowRunContext<TInputs, TDefinitionBrand>) => Promise<TOutputs> | TOutputs;
410
+ export type WorkflowRunFn<TInputs extends WorkflowInputValues = WorkflowInputValues, TOutputs extends WorkflowOutputValues = WorkflowOutputValues, TDefinitionBrand extends object = {}> = (ctx: WorkflowRunContext<TInputs, TDefinitionBrand, TOutputs>) => Promise<TOutputs> | TOutputs;
393
411
  export interface WorkflowRuntimeConfig {
394
412
  readonly maxDepth: number;
395
413
  readonly defaultConcurrency: number;
@@ -414,7 +432,7 @@ export interface WorkflowDefinition<TInputs extends WorkflowInputValues = Workfl
414
432
  readonly inputs: WorkflowInputSchemaMap;
415
433
  readonly outputs?: WorkflowOutputSchemaMap;
416
434
  readonly inputBindings?: WorkflowInputBindings;
417
- run(ctx: WorkflowRunContext<TInputs, TDefinitionBrand>): Promise<TOutputs> | TOutputs;
435
+ run(ctx: WorkflowRunContext<TInputs, TDefinitionBrand, TOutputs>): Promise<TOutputs> | TOutputs;
418
436
  }
419
437
  type DeclaredResolvedEntry<K extends string, S extends TSchema> = S extends TOptional<TSchema> ? {
420
438
  readonly [P in K]?: Static<S>;
@@ -437,7 +455,7 @@ export interface WorkflowBuilder<TInputs extends WorkflowInputValues = {}, TOutp
437
455
  input<K extends string, S extends TSchema>(key: K, schema: S): WorkflowBuilder<Simplify<TInputs & DeclaredResolvedEntry<K, S>>, TOutputs, Simplify<TRunInputs & DeclaredProvidedEntry<K, S>>, TDefinitionBrand, WorkflowDefinition<Simplify<TInputs & DeclaredResolvedEntry<K, S>>, TOutputs, Simplify<TRunInputs & DeclaredProvidedEntry<K, S>>, TDefinitionBrand> & TDefinitionBrand>;
438
456
  output<K extends string, S extends TSchema>(key: K, schema: S): WorkflowBuilder<TInputs, Simplify<TOutputs & (DeclaredResolvedEntry<K, S> & WorkflowOutputValues)>, TRunInputs, TDefinitionBrand, WorkflowDefinition<TInputs, Simplify<TOutputs & (DeclaredResolvedEntry<K, S> & WorkflowOutputValues)>, TRunInputs, TDefinitionBrand> & TDefinitionBrand>;
439
457
  worktreeFromInputs(binding: WorkflowWorktreeInputBinding): WorkflowBuilder<TInputs, TOutputs, TRunInputs, TDefinitionBrand, TCompiledDefinition>;
440
- run<TActualOutputs extends TOutputs>(fn: (ctx: WorkflowRunContext<TInputs, TDefinitionBrand>) => Promise<NoExtraOutputs<TOutputs, TActualOutputs>> | NoExtraOutputs<TOutputs, TActualOutputs>): CompletedWorkflowBuilder<TInputs, TOutputs, TRunInputs, TDefinitionBrand, TCompiledDefinition>;
458
+ run<TActualOutputs extends TOutputs>(fn: (ctx: WorkflowRunContext<TInputs, TDefinitionBrand, TOutputs>) => Promise<NoExtraOutputs<TOutputs, TActualOutputs>> | NoExtraOutputs<TOutputs, TActualOutputs>): CompletedWorkflowBuilder<TInputs, TOutputs, TRunInputs, TDefinitionBrand, TCompiledDefinition>;
441
459
  }
442
460
  export interface CompletedWorkflowBuilder<TInputs extends WorkflowInputValues = {}, TOutputs extends WorkflowOutputValues = {}, TRunInputs extends WorkflowInputValues = TInputs, TDefinitionBrand extends object = {}, TCompiledDefinition extends WorkflowDefinition<TInputs, TOutputs, TRunInputs, TDefinitionBrand> = WorkflowDefinition<TInputs, TOutputs, TRunInputs, TDefinitionBrand>> extends WorkflowBuilder<TInputs, TOutputs, TRunInputs, TDefinitionBrand, TCompiledDefinition> {
443
461
  description(text: string): CompletedWorkflowBuilder<TInputs, TOutputs, TRunInputs, TDefinitionBrand, TCompiledDefinition>;
@@ -501,7 +519,7 @@ export interface RunOpts {
501
519
  readonly onRunStart?: (snapshot: RunSnapshot) => void;
502
520
  readonly onStageStart?: (runId: string, snapshot: StageSnapshot) => void;
503
521
  readonly onStageEnd?: (runId: string, snapshot: StageSnapshot) => void;
504
- readonly onRunEnd?: (runId: string, status: RunStatus, result?: WorkflowOutputValues, error?: string) => void;
522
+ readonly onRunEnd?: (runId: string, status: RunStatus, result?: WorkflowOutputValues, error?: string, exitReason?: string) => void;
505
523
  }
506
524
  export interface WorkflowProgressSummary extends WorkflowSerializableObject {
507
525
  readonly completed?: number;
@@ -530,6 +548,9 @@ export interface WorkflowDetails extends WorkflowSerializableObject {
530
548
  readonly intercom?: WorkflowIntercomSummary;
531
549
  readonly warnings?: readonly string[];
532
550
  readonly error?: string;
551
+ /** True when the run reached its terminal status through ctx.exit(). */
552
+ readonly exited?: boolean;
553
+ readonly exitReason?: string;
533
554
  }
534
555
  export type StageStatus = RunStatus | "skipped" | "awaiting_input" | "blocked";
535
556
  export interface StageSnapshot extends WorkflowSerializableObject {
@@ -542,8 +563,11 @@ export interface StageSnapshot extends WorkflowSerializableObject {
542
563
  export interface RunResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> extends WorkflowSerializableObject {
543
564
  readonly runId: string;
544
565
  readonly status: RunStatus;
545
- readonly result?: TOutputs;
566
+ readonly result?: Partial<TOutputs>;
546
567
  readonly error?: string;
568
+ /** True when the run reached its terminal status through ctx.exit(). */
569
+ readonly exited?: boolean;
570
+ readonly exitReason?: string;
547
571
  readonly stages: readonly StageSnapshot[];
548
572
  }
549
573
  export type ResolvedInputs<TInputs extends WorkflowInputValues = WorkflowInputValues> = Readonly<TInputs> & WorkflowSerializableObject;
@@ -29,12 +29,20 @@ function virtualStageId(runId: string, stageId: string, isRootRun: boolean): str
29
29
  return isRootRun ? stageId : `${runId}:${stageId}`;
30
30
  }
31
31
 
32
+ function isTerminalNonCompletedBoundary(stage: StageSnapshot): boolean {
33
+ return stage.status === "failed" || stage.status === "skipped";
34
+ }
35
+
32
36
  function childRunIdFor(stage: StageSnapshot): string | undefined {
33
- return stage.workflowChildRun?.runId ?? stage.workflowChild?.runId;
37
+ if (isTerminalNonCompletedBoundary(stage)) return undefined;
38
+ if (stage.status === "completed") return stage.workflowChild?.runId ?? stage.workflowChildRun?.runId;
39
+ return stage.workflowChildRun?.runId;
34
40
  }
35
41
 
36
42
  function childAliasFor(stage: StageSnapshot): string | undefined {
37
- return stage.workflowChildRun?.alias ?? stage.workflowChild?.alias;
43
+ if (isTerminalNonCompletedBoundary(stage)) return undefined;
44
+ if (stage.status === "completed") return stage.workflowChild?.alias ?? stage.workflowChildRun?.alias;
45
+ return stage.workflowChildRun?.alias;
38
46
  }
39
47
 
40
48
  function localTerminalStageIds(stages: readonly StageSnapshot[]): readonly string[] {
@@ -9,14 +9,14 @@
9
9
  import type { Store } from "./store.js";
10
10
  import type {
11
11
  RunSnapshot,
12
+ RunStatus,
12
13
  StageSnapshot,
13
14
  StageStatus,
14
- WorkflowChildReplaySnapshot,
15
15
  WorkflowFailureCode,
16
16
  WorkflowFailureDisposition,
17
17
  WorkflowFailureKind,
18
18
  } from "./store-types.js";
19
- import type { WorkflowInputValues, WorkflowOutputValues } from "./types.js";
19
+ import type { WorkflowExitStatus, WorkflowInputValues, WorkflowOutputValues } from "./types.js";
20
20
  import { workflowSerializableObjectSchema } from "./serializable.js";
21
21
  import { Value } from "typebox/value";
22
22
  import {
@@ -429,11 +429,12 @@ function serializableObjectOrEmpty(value: unknown): WorkflowOutputValues {
429
429
  return serializableObject(value) ?? {};
430
430
  }
431
431
 
432
- function isWorkflowChildReplayStatus(status: unknown): status is WorkflowChildReplaySnapshot["status"] {
433
- return status === "completed";
432
+ function isWorkflowChildReplayStatus(status: unknown): status is WorkflowExitStatus {
433
+ return status === "completed" || status === "skipped" || status === "cancelled" || status === "blocked";
434
434
  }
435
435
 
436
436
  function workflowChildMetadata(payload: Record<string, unknown>): Pick<StageSnapshot, "workflowChild"> {
437
+ if (payload["status"] !== "completed") return {};
437
438
  const workflowChild = payload["workflowChild"];
438
439
  if (!isRecord(workflowChild)) return {};
439
440
  const alias = workflowChild["alias"];
@@ -441,6 +442,8 @@ function workflowChildMetadata(payload: Record<string, unknown>): Pick<StageSnap
441
442
  const childRunId = workflowChild["runId"];
442
443
  const status = workflowChild["status"];
443
444
  const outputs = workflowChild["outputs"];
445
+ const exited = workflowChild["exited"];
446
+ const exitReason = workflowChild["exitReason"];
444
447
  if (
445
448
  typeof alias !== "string" ||
446
449
  typeof workflow !== "string" ||
@@ -470,7 +473,9 @@ function workflowChildMetadata(payload: Record<string, unknown>): Pick<StageSnap
470
473
  workflow,
471
474
  runId: childRunId,
472
475
  status,
476
+ ...(typeof exited === "boolean" ? { exited } : status !== "completed" || typeof exitReason === "string" ? { exited: true } : {}),
473
477
  outputs: clonedOutputs,
478
+ ...(typeof exitReason === "string" ? { exitReason } : {}),
474
479
  },
475
480
  };
476
481
  }
@@ -567,7 +572,12 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
567
572
 
568
573
  const runMeta = findRunStartMetadata(entries, runId);
569
574
  const stages = _buildStageSnapshots(entries, runId);
570
- if (status === "completed" && stages.some((stage) => stage.status !== "completed")) continue;
575
+ const exited = end["exited"];
576
+ const exitReason = end["exitReason"];
577
+ const resumable = end["resumable"];
578
+ const restoredAuthorExit = isWorkflowExitTerminalStatus(status) &&
579
+ (exited === true || status !== "completed" || typeof exitReason === "string" || resumable === false);
580
+ if (status === "completed" && !restoredAuthorExit && stages.some((stage) => stage.status !== "completed")) continue;
571
581
  store.recordRunStart({
572
582
  id: runId,
573
583
  name: start.name,
@@ -583,6 +593,7 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
583
593
  });
584
594
 
585
595
  const error = end["error"];
596
+ const result = serializableObject(end["result"]);
586
597
  const failureKind = end["failureKind"];
587
598
  const failureCode = end["failureCode"];
588
599
  const failureRecoverability = end["failureRecoverability"];
@@ -590,11 +601,10 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
590
601
  const retryAfterMs = numericRetryAfterMs(end["retryAfterMs"]);
591
602
  const failureMessage = end["failureMessage"];
592
603
  const failedStageId = end["failedStageId"];
593
- const resumable = end["resumable"];
594
604
  store.recordRunEnd(
595
605
  runId,
596
606
  status,
597
- undefined,
607
+ result,
598
608
  typeof error === "string" ? error : undefined,
599
609
  {
600
610
  ...(typeof failureKind === "string" && isWorkflowFailureKind(failureKind) ? { failureKind } : {}),
@@ -604,15 +614,24 @@ function restoreTerminalRuns(entries: readonly SessionEntry[], store: Store): vo
604
614
  ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
605
615
  ...(typeof failureMessage === "string" ? { failureMessage } : {}),
606
616
  ...(typeof failedStageId === "string" ? { failedStageId } : {}),
607
- ...(typeof resumable === "boolean" ? { resumable } : {}),
617
+ ...(typeof resumable === "boolean" ? { resumable } : isWorkflowExitTerminalStatus(status) && restoredAuthorExit ? { resumable: false } : {}),
618
+ ...(restoredAuthorExit && isWorkflowExitTerminalStatus(status) ? { exited: true } : {}),
619
+ ...(typeof exitReason === "string" ? { exitReason } : {}),
608
620
  },
609
621
  );
610
622
  }
611
623
  }
612
624
 
613
- function restoreTerminalRunStatus(status: unknown): "completed" | "failed" | "killed" | undefined {
625
+ function isWorkflowExitTerminalStatus(status: RunStatus): status is WorkflowExitStatus {
626
+ return status === "completed" || status === "skipped" || status === "cancelled" || status === "blocked";
627
+ }
628
+
629
+ function restoreTerminalRunStatus(status: unknown): RunStatus | undefined {
614
630
  switch (status) {
615
631
  case "completed":
632
+ case "skipped":
633
+ case "cancelled":
634
+ case "blocked":
616
635
  case "failed":
617
636
  case "killed":
618
637
  return status;
@@ -6,7 +6,7 @@
6
6
  * through gracefully when the runtime doesn't support the method.
7
7
  */
8
8
 
9
- import type { WorkflowInputValues, WorkflowOutputValues } from "./types.js";
9
+ import type { WorkflowExitStatus, WorkflowInputValues, WorkflowOutputValues } from "./types.js";
10
10
  import type {
11
11
  WorkflowFailureCode,
12
12
  WorkflowFailureDisposition,
@@ -69,8 +69,10 @@ export interface WorkflowChildReplayPayload {
69
69
  readonly alias: string;
70
70
  readonly workflow: string;
71
71
  readonly runId: string;
72
- readonly status: "completed";
72
+ readonly status: WorkflowExitStatus;
73
+ readonly exited?: boolean;
73
74
  readonly outputs: WorkflowOutputValues;
75
+ readonly exitReason?: string;
74
76
  }
75
77
 
76
78
  export interface StageEndPayload {
@@ -98,6 +100,8 @@ export interface RunEndPayload {
98
100
  readonly status: string;
99
101
  readonly result?: WorkflowOutputValues;
100
102
  readonly error?: string;
103
+ readonly exited?: boolean;
104
+ readonly exitReason?: string;
101
105
  readonly failureKind?: string;
102
106
  readonly failureCode?: string;
103
107
  readonly failureRecoverability?: string;
@@ -201,7 +205,7 @@ export function appendStageEnd(
201
205
  ...(payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {}),
202
206
  ...(payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {}),
203
207
  ...(payload.replayed !== undefined ? { replayed: payload.replayed } : {}),
204
- ...(payload.workflowChild !== undefined ? { workflowChild: payload.workflowChild } : {}),
208
+ ...(payload.status === "completed" && payload.workflowChild !== undefined ? { workflowChild: payload.workflowChild } : {}),
205
209
  });
206
210
  if (opts?.emitMessage === true && payload.summary && typeof api.appendCustomMessageEntry === "function") {
207
211
  api.appendCustomMessageEntry(
@@ -236,6 +240,8 @@ export function appendRunEnd(api: PersistenceAPI, payload: RunEndPayload): void
236
240
  status: terminalPayload.status,
237
241
  ...(terminalPayload.result !== undefined ? { result: terminalPayload.result } : {}),
238
242
  ...(terminalPayload.error !== undefined ? { error: terminalPayload.error } : {}),
243
+ ...(terminalPayload.exited !== undefined ? { exited: terminalPayload.exited } : {}),
244
+ ...(terminalPayload.exitReason !== undefined ? { exitReason: terminalPayload.exitReason } : {}),
239
245
  ...(terminalPayload.failureKind !== undefined ? { failureKind: terminalPayload.failureKind } : {}),
240
246
  ...(terminalPayload.failureCode !== undefined ? { failureCode: terminalPayload.failureCode } : {}),
241
247
  ...(terminalPayload.failureRecoverability !== undefined ? { failureRecoverability: terminalPayload.failureRecoverability } : {}),
@@ -3,9 +3,9 @@
3
3
  * cross-ref: spec §5.5
4
4
  */
5
5
 
6
- import type { WorkflowInputValues, WorkflowOutputValues } from "./types.js";
6
+ import type { WorkflowExitStatus, WorkflowInputValues, WorkflowOutputValues } from "./types.js";
7
7
 
8
- export type RunStatus = "pending" | "running" | "paused" | "completed" | "failed" | "killed";
8
+ export type RunStatus = "pending" | "running" | "paused" | WorkflowExitStatus | "failed" | "killed";
9
9
  export type StageStatus =
10
10
  | "pending"
11
11
  | "running"
@@ -125,8 +125,11 @@ export interface WorkflowChildReplaySnapshot {
125
125
  readonly alias: string;
126
126
  readonly workflow: string;
127
127
  readonly runId: string;
128
- readonly status: "completed";
128
+ readonly status: WorkflowExitStatus;
129
+ /** True when the child reached this terminal status through ctx.exit(). */
130
+ readonly exited?: boolean;
129
131
  readonly outputs: WorkflowOutputValues;
132
+ readonly exitReason?: string;
130
133
  }
131
134
 
132
135
  export interface StageSnapshot {
@@ -243,6 +246,10 @@ export interface RunSnapshot {
243
246
  resumedAt?: number;
244
247
  result?: WorkflowOutputValues;
245
248
  error?: string;
249
+ /** True when the run reached its terminal status through ctx.exit(). */
250
+ exited?: boolean;
251
+ /** Optional author-supplied reason from ctx.exit(). */
252
+ exitReason?: string;
246
253
  /** Structured workflow failure category for failed runs. */
247
254
  failureKind?: WorkflowFailureKind;
248
255
  /** Specific additive workflow failure code within `failureKind`. */
@@ -25,8 +25,16 @@ import type {
25
25
  import { accumulatePausedDurationMs, elapsedRunMs } from "./timing.js";
26
26
  import { isTopLevelWorkflowRun } from "./run-visibility.js";
27
27
 
28
- /** Statuses that represent a terminal run state — cannot be overwritten. */
29
- const TERMINAL_STATUSES: ReadonlySet<RunStatus> = new Set(["completed", "failed", "killed"]);
28
+ /**
29
+ * Statuses that represent a terminal run state — cannot be overwritten.
30
+ *
31
+ * Note on `"blocked"`: here it is an author-selected `ctx.exit({ status: "blocked" })`
32
+ * outcome — terminal and non-resumable. This is deliberately distinct from retry-blocking,
33
+ * which does NOT use this run status: `recordRunBlocked()` keeps `run.status = "running"`
34
+ * and records the block via `blockedAt` / `failureDisposition: "active_blocked"` (resumable).
35
+ * The two never collide despite the shared word.
36
+ */
37
+ const TERMINAL_STATUSES: ReadonlySet<RunStatus> = new Set(["completed", "failed", "killed", "skipped", "cancelled", "blocked"]);
30
38
 
31
39
  function isTerminalStageStatus(status: StageStatus): boolean {
32
40
  return status === "completed" || status === "failed" || status === "skipped";
@@ -53,6 +61,8 @@ export interface RunEndMetadata {
53
61
  readonly failedStageId?: string;
54
62
  readonly resumable?: boolean;
55
63
  readonly retryAfterMs?: number;
64
+ readonly exited?: boolean;
65
+ readonly exitReason?: string;
56
66
  }
57
67
 
58
68
  export interface RunBlockedMetadata extends RunEndMetadata {
@@ -73,6 +83,8 @@ function clearRunFailureMetadata(run: RunSnapshot): void {
73
83
  delete run.resumable;
74
84
  delete run.retryAfterMs;
75
85
  delete run.blockedAt;
86
+ delete run.exited;
87
+ delete run.exitReason;
76
88
  }
77
89
 
78
90
  function clearStaleBlockedRunMetadata(run: RunSnapshot, metadata: RunEndMetadata | undefined): void {
@@ -84,6 +96,8 @@ function clearStaleBlockedRunMetadata(run: RunSnapshot, metadata: RunEndMetadata
84
96
  if (metadata?.failedStageId === undefined) delete run.failedStageId;
85
97
  if (metadata?.resumable === undefined) delete run.resumable;
86
98
  if (metadata?.retryAfterMs === undefined) delete run.retryAfterMs;
99
+ if (metadata?.exited === undefined) delete run.exited;
100
+ if (metadata?.exitReason === undefined) delete run.exitReason;
87
101
  }
88
102
 
89
103
  function applyRunEndMetadata(run: RunSnapshot, metadata: RunEndMetadata): void {
@@ -95,6 +109,8 @@ function applyRunEndMetadata(run: RunSnapshot, metadata: RunEndMetadata): void {
95
109
  if (metadata.failureMessage !== undefined) run.failureMessage = metadata.failureMessage;
96
110
  if (metadata.failedStageId !== undefined) run.failedStageId = metadata.failedStageId;
97
111
  if (metadata.resumable !== undefined) run.resumable = metadata.resumable;
112
+ if (metadata.exited !== undefined) run.exited = metadata.exited;
113
+ if (metadata.exitReason !== undefined) run.exitReason = metadata.exitReason;
98
114
  }
99
115
 
100
116
  export type StagePromptAnswerSource = "workflow_ui" | "workflow_tool";
@@ -138,8 +154,8 @@ export interface Store {
138
154
  /**
139
155
  * Records the end of a run.
140
156
  * Returns `true` if state changed, `false` if the run was not found or
141
- * already in a terminal state (completed | failed | killed).
142
- * `result` is only applied for status "completed".
157
+ * already in a terminal state (completed | failed | killed | skipped | cancelled | blocked).
158
+ * `result` is applied for intentional success/exit statuses (completed | skipped | cancelled | blocked).
143
159
  * `error` is only applied for status "failed" | "killed".
144
160
  */
145
161
  recordRunEnd(
@@ -531,8 +547,13 @@ export function createStore(): Store {
531
547
  if (stage.promptAnswerState !== undefined) existing.promptAnswerState = stage.promptAnswerState;
532
548
  if (stage.replayedFromStageId !== undefined) existing.replayedFromStageId = stage.replayedFromStageId;
533
549
  if (stage.replayed !== undefined) existing.replayed = stage.replayed;
534
- if (stage.workflowChildRun !== undefined) existing.workflowChildRun = { ...stage.workflowChildRun };
535
- if (stage.workflowChild !== undefined) existing.workflowChild = structuredClone(stage.workflowChild);
550
+ if (stage.status === "completed") {
551
+ if (stage.workflowChildRun !== undefined) existing.workflowChildRun = { ...stage.workflowChildRun };
552
+ if (stage.workflowChild !== undefined) existing.workflowChild = structuredClone(stage.workflowChild);
553
+ } else {
554
+ delete existing.workflowChildRun;
555
+ delete existing.workflowChild;
556
+ }
536
557
  delete existing.awaitingInputSince;
537
558
  delete existing.inputRequest;
538
559
  rejectStagePrompt(runId, existing, `atomic-workflows: stage ${stage.id} ended before prompt resolved`);
@@ -564,11 +585,12 @@ export function createStore(): Store {
564
585
  run.durationMs = elapsedRunMs(run, run.endedAt);
565
586
  const wasBlocked = run.blockedAt !== undefined || run.failureDisposition === "active_blocked";
566
587
  delete run.blockedAt;
567
- if (status === "completed") {
588
+ if (status === "completed" || status === "skipped" || status === "cancelled" || status === "blocked") {
568
589
  if (result !== undefined) {
569
590
  run.result = result;
570
591
  }
571
592
  clearRunFailureMetadata(run);
593
+ if (metadata !== undefined) applyRunEndMetadata(run, metadata);
572
594
  } else {
573
595
  if (wasBlocked && error === undefined) delete run.error;
574
596
  if ((status === "failed" || status === "killed") && error !== undefined) {
@@ -47,6 +47,8 @@ export type WorkflowSerializableValue = AuthoringContract.WorkflowSerializableVa
47
47
  export type WorkflowInputValues = AuthoringContract.WorkflowInputValues;
48
48
  export type WorkflowOutputValues = AuthoringContract.WorkflowOutputValues;
49
49
  export type WorkflowRunOutput = AuthoringContract.WorkflowRunOutput;
50
+ export type WorkflowExitStatus = AuthoringContract.WorkflowExitStatus;
51
+ export type WorkflowExitOptions<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> = AuthoringContract.WorkflowExitOptions<TOutputs>;
50
52
 
51
53
  // ---------------------------------------------------------------------------
52
54
  // Workflow input / output schemas
@@ -98,14 +100,9 @@ export interface WorkflowRunChildOptions<TInputs extends WorkflowInputValues = W
98
100
  readonly stageName?: string;
99
101
  }
100
102
 
101
- export interface WorkflowChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues>
102
- extends WorkflowSerializableObject {
103
- readonly workflow: string;
104
- readonly runId: string;
105
- readonly status: "completed";
106
- /** Child outputs, typed from the child workflow's declared `.output(...)` contract. */
107
- readonly outputs: TOutputs;
108
- }
103
+ export type WorkflowCompletedChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> = AuthoringContract.WorkflowCompletedChildResult<TOutputs>;
104
+ export type WorkflowExitedChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> = AuthoringContract.WorkflowExitedChildResult<TOutputs>;
105
+ export type WorkflowChildResult<TOutputs extends WorkflowOutputValues = WorkflowOutputValues> = AuthoringContract.WorkflowChildResult<TOutputs>;
109
106
 
110
107
  // ---------------------------------------------------------------------------
111
108
  // HIL (human-in-the-loop) primitives available inside run functions
@@ -329,11 +326,16 @@ export interface StageContext {
329
326
  // Workflow run context (top-level ctx passed to the run function)
330
327
  // ---------------------------------------------------------------------------
331
328
 
332
- export interface WorkflowRunContext<TInputs extends WorkflowInputValues = WorkflowInputValues> {
329
+ export interface WorkflowRunContext<
330
+ TInputs extends WorkflowInputValues = WorkflowInputValues,
331
+ TOutputs extends WorkflowOutputValues = WorkflowOutputValues,
332
+ > {
333
333
  /** Typed inputs provided by the caller, validated against the input schema. */
334
334
  readonly inputs: TInputs;
335
335
  /** Invocation working directory for workflow-owned artifacts. Defaults to the host process cwd when omitted. */
336
336
  readonly cwd?: string;
337
+ /** Intentionally end this workflow run from any call depth. */
338
+ exit(options?: WorkflowExitOptions<TOutputs>): never;
337
339
  /**
338
340
  * Create and register a named stage synchronously. Stage work starts when
339
341
  * a stage method such as prompt() or complete() is awaited; the executor
@@ -383,7 +385,7 @@ export type WorkflowRuntimeConfig = AuthoringContract.WorkflowRuntimeConfig;
383
385
  export type WorkflowRunFn<
384
386
  TInputs extends WorkflowInputValues = WorkflowInputValues,
385
387
  TOutputs extends WorkflowOutputValues = WorkflowOutputValues,
386
- > = (ctx: WorkflowRunContext<TInputs>) => ReturnType<AuthoringContract.WorkflowRunFn<TInputs, TOutputs>>;
388
+ > = (ctx: WorkflowRunContext<TInputs, TOutputs>) => ReturnType<AuthoringContract.WorkflowRunFn<TInputs, TOutputs>>;
387
389
 
388
390
  // ---------------------------------------------------------------------------
389
391
  // Compiled workflow definition
@@ -11,9 +11,11 @@
11
11
  * left, a `surface0` tag carrying the runId / workflow name, a
12
12
  * bolded title beside it, and one optional second row indented past
13
13
  * the stripe.
14
- * - **Progress strip**: bracketed `[✓]` / `[●]` / `[]` / `[]` cells,
15
- * coloured by stage status. Truncates with a trailing `…` when the
16
- * rendered cells exceed the available budget.
14
+ * - **Progress strip**: bracketed status cells such as `[]`, `[]`,
15
+ * `[○]`, `[✗]`, and `[❚❚]`, coloured by stage status. Cells are
16
+ * measured by visible width per rendered glyph rather than assumed to
17
+ * be a fixed 3 columns, and the strip truncates with a trailing `…`
18
+ * when the rendered cells exceed the available budget.
17
19
  * - **Hint rows**: a single grammar — `▸ /slash command verb-phrase
18
20
  * hint`.
19
21
  *
@@ -440,7 +442,7 @@ function renderTaggedCardPlain(opts: RenderTaggedCardOpts, width: number): strin
440
442
  }
441
443
 
442
444
  // ---------------------------------------------------------------------------
443
- // Progress strip — `[✓][●][○][✗]` cells, coloured by stage status
445
+ // Progress strip — variable-width bracketed cells, coloured by stage status
444
446
  // ---------------------------------------------------------------------------
445
447
 
446
448
  export interface ProgressCell {
@@ -449,45 +451,40 @@ export interface ProgressCell {
449
451
 
450
452
  /**
451
453
  * Render a progress strip whose visible width is at most `budget` cells.
452
- * Each cell renders as a 3-character bracket-glyph-bracket sequence
453
- * (`[✓]`). When the strip would exceed the budget, the rendered output
454
- * is truncated and a trailing `…` is appended.
454
+ * Each cell renders as a bracketed status glyph whose visible width can
455
+ * vary by status (`[✓]` is 3 cells, `[❚❚]` is 4 cells). Truncation uses
456
+ * the measured width of each rendered cell and appends a trailing `…`
457
+ * when the next whole cell would exceed the budget.
455
458
  *
456
459
  * Themed mode colours the glyphs by status; plain mode emits the same
457
- * ASCII shape so logs remain readable.
460
+ * bracketed shape so logs remain readable.
458
461
  */
459
462
  export function progressStrip(
460
463
  cells: readonly ProgressCell[],
461
464
  budget: number,
462
465
  theme?: GraphTheme,
463
466
  ): string {
464
- const CELL_WIDTH = 3;
465
467
  const usable = Math.max(0, Math.floor(budget));
466
- const maxCells = Math.max(0, Math.floor(usable / CELL_WIDTH));
467
- if (maxCells === 0 || cells.length === 0) return "";
468
-
469
- const truncated = cells.length > maxCells;
470
- // Reserve 1 cell of width for the trailing ellipsis if truncating, so the
471
- // rendered output still fits.
472
- const visibleCount = truncated
473
- ? Math.max(0, Math.floor((usable - 1) / CELL_WIDTH))
474
- : cells.length;
475
- const slice = cells.slice(0, visibleCount);
476
-
477
- let out = "";
478
- if (theme) {
479
- for (const cell of slice) {
480
- out += renderCellThemed(cell.status, theme);
481
- }
482
- } else {
483
- for (const cell of slice) {
484
- out += renderCellPlain(cell.status);
485
- }
468
+ if (usable < 3 || cells.length === 0) return "";
469
+
470
+ const ellipsisWidth = visibleWidth(ELLIPSIS);
471
+ const out: string[] = [];
472
+ let used = 0;
473
+
474
+ for (let i = 0; i < cells.length; i++) {
475
+ const rendered = theme ? renderCellThemed(cells[i]!.status, theme) : renderCellPlain(cells[i]!.status);
476
+ const renderedWidth = visibleWidth(rendered);
477
+ const isLast = i === cells.length - 1;
478
+ const reserved = isLast ? 0 : ellipsisWidth;
479
+ if (used + renderedWidth + reserved > usable) break;
480
+ out.push(rendered);
481
+ used += renderedWidth;
482
+ if (isLast) return out.join("");
486
483
  }
487
- if (truncated) {
488
- out += theme ? `${hexToAnsi(theme.dim)}${ELLIPSIS}${RESET}` : ELLIPSIS;
489
- }
490
- return out;
484
+
485
+ if (out.length === 0 && ellipsisWidth > usable) return "";
486
+ const suffix = theme ? `${hexToAnsi(theme.dim)}${ELLIPSIS}${RESET}` : ELLIPSIS;
487
+ return `${out.join("")}${suffix}`;
491
488
  }
492
489
 
493
490
  function renderCellThemed(status: StageStatus, theme: GraphTheme): string {
@@ -506,6 +503,7 @@ function stageGlyph(status: StageStatus): string {
506
503
  switch (status) {
507
504
  case "completed": return "✓";
508
505
  case "running": return "●";
506
+ case "paused": return "❚❚";
509
507
  case "failed": return "✗";
510
508
  case "awaiting_input": return "?";
511
509
  case "skipped": return "⊘";
@@ -518,6 +516,7 @@ function stageColor(status: StageStatus, theme: GraphTheme): string {
518
516
  switch (status) {
519
517
  case "completed": return hexToAnsi(theme.success);
520
518
  case "running": return hexToAnsi(theme.warning);
519
+ case "paused": return hexToAnsi(theme.warning);
521
520
  case "failed": return hexToAnsi(theme.error);
522
521
  case "awaiting_input": return hexToAnsi(theme.info);
523
522
  case "skipped": return hexToAnsi(theme.dim);