@bastani/atomic 0.9.8 → 0.9.9-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +6 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  9. package/dist/builtin/subagents/package.json +1 -1
  10. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
  11. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
  12. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
  13. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
  14. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
  15. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
  16. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
  17. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
  18. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  19. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  20. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
  21. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
  22. package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
  23. package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
  24. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  25. package/dist/builtin/web-access/package.json +1 -1
  26. package/dist/builtin/workflows/CHANGELOG.md +22 -0
  27. package/dist/builtin/workflows/README.md +17 -8
  28. package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
  29. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
  30. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
  31. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
  32. package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
  33. package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
  34. package/dist/builtin/workflows/package.json +1 -1
  35. package/dist/builtin/workflows/src/durable/backend.ts +53 -15
  36. package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
  37. package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
  38. package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
  39. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
  40. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
  41. package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
  42. package/dist/builtin/workflows/src/durable/factory.ts +1 -1
  43. package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
  44. package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
  45. package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
  46. package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
  47. package/dist/builtin/workflows/src/durable/index.ts +12 -0
  48. package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
  49. package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
  50. package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
  51. package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
  52. package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
  53. package/dist/builtin/workflows/src/durable/types.ts +3 -0
  54. package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
  55. package/dist/builtin/workflows/src/engine/run.ts +14 -14
  56. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
  57. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
  58. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
  59. package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
  60. package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
  61. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
  62. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
  63. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
  64. package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
  65. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
  66. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
  67. package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
  68. package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
  69. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
  70. package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
  71. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
  72. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
  73. package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
  74. package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
  75. package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
  76. package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
  77. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
  78. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
  79. package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
  80. package/dist/builtin/workflows/src/shared/timing.ts +4 -0
  81. package/dist/builtin/workflows/src/shared/types.ts +5 -3
  82. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
  83. package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
  84. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
  85. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  86. package/dist/core/agent-session-auto-compaction.js +5 -7
  87. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  88. package/dist/core/agent-session-compaction.d.ts +6 -34
  89. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  90. package/dist/core/agent-session-compaction.js +95 -233
  91. package/dist/core/agent-session-compaction.js.map +1 -1
  92. package/dist/core/agent-session-message-queue.d.ts +0 -4
  93. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  94. package/dist/core/agent-session-message-queue.js +1 -5
  95. package/dist/core/agent-session-message-queue.js.map +1 -1
  96. package/dist/core/agent-session-methods.d.ts +5 -6
  97. package/dist/core/agent-session-methods.d.ts.map +1 -1
  98. package/dist/core/agent-session-methods.js.map +1 -1
  99. package/dist/core/agent-session-types.d.ts +2 -12
  100. package/dist/core/agent-session-types.d.ts.map +1 -1
  101. package/dist/core/agent-session-types.js.map +1 -1
  102. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  103. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  104. package/dist/core/compaction/branch-summarization.js +1 -2
  105. package/dist/core/compaction/branch-summarization.js.map +1 -1
  106. package/dist/core/compaction/compaction-boundary.d.ts +9 -0
  107. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
  108. package/dist/core/compaction/compaction-boundary.js +115 -0
  109. package/dist/core/compaction/compaction-boundary.js.map +1 -0
  110. package/dist/core/compaction/compaction-parameters.d.ts +5 -0
  111. package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
  112. package/dist/core/compaction/compaction-parameters.js +27 -0
  113. package/dist/core/compaction/compaction-parameters.js.map +1 -0
  114. package/dist/core/compaction/compaction-runner.d.ts +14 -0
  115. package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
  116. package/dist/core/compaction/compaction-runner.js +29 -0
  117. package/dist/core/compaction/compaction-runner.js.map +1 -0
  118. package/dist/core/compaction/compaction-types.d.ts +79 -0
  119. package/dist/core/compaction/compaction-types.d.ts.map +1 -0
  120. package/dist/core/compaction/compaction-types.js +6 -0
  121. package/dist/core/compaction/compaction-types.js.map +1 -0
  122. package/dist/core/compaction/deleted-ranges.d.ts +6 -0
  123. package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
  124. package/dist/core/compaction/deleted-ranges.js +134 -0
  125. package/dist/core/compaction/deleted-ranges.js.map +1 -0
  126. package/dist/core/compaction/index.d.ts +7 -1
  127. package/dist/core/compaction/index.d.ts.map +1 -1
  128. package/dist/core/compaction/index.js +7 -1
  129. package/dist/core/compaction/index.js.map +1 -1
  130. package/dist/core/compaction/range-planner.d.ts +21 -0
  131. package/dist/core/compaction/range-planner.d.ts.map +1 -0
  132. package/dist/core/compaction/range-planner.js +145 -0
  133. package/dist/core/compaction/range-planner.js.map +1 -0
  134. package/dist/core/compaction/transcript-serialization.d.ts +11 -0
  135. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
  136. package/dist/core/compaction/transcript-serialization.js +104 -0
  137. package/dist/core/compaction/transcript-serialization.js.map +1 -0
  138. package/dist/core/extensions/context-types.d.ts +2 -2
  139. package/dist/core/extensions/context-types.d.ts.map +1 -1
  140. package/dist/core/extensions/context-types.js.map +1 -1
  141. package/dist/core/extensions/event-results.d.ts +2 -2
  142. package/dist/core/extensions/event-results.d.ts.map +1 -1
  143. package/dist/core/extensions/event-results.js.map +1 -1
  144. package/dist/core/extensions/session-events.d.ts +7 -7
  145. package/dist/core/extensions/session-events.d.ts.map +1 -1
  146. package/dist/core/extensions/session-events.js.map +1 -1
  147. package/dist/core/index.d.ts +1 -1
  148. package/dist/core/index.d.ts.map +1 -1
  149. package/dist/core/index.js.map +1 -1
  150. package/dist/core/messages.d.ts +4 -0
  151. package/dist/core/messages.d.ts.map +1 -1
  152. package/dist/core/messages.js +11 -0
  153. package/dist/core/messages.js.map +1 -1
  154. package/dist/core/provider-context-usage.d.ts.map +1 -1
  155. package/dist/core/provider-context-usage.js +1 -2
  156. package/dist/core/provider-context-usage.js.map +1 -1
  157. package/dist/core/session-manager-archive.d.ts +2 -1
  158. package/dist/core/session-manager-archive.d.ts.map +1 -1
  159. package/dist/core/session-manager-archive.js +2 -2
  160. package/dist/core/session-manager-archive.js.map +1 -1
  161. package/dist/core/session-manager-classification.d.ts +9 -0
  162. package/dist/core/session-manager-classification.d.ts.map +1 -0
  163. package/dist/core/session-manager-classification.js +37 -0
  164. package/dist/core/session-manager-classification.js.map +1 -0
  165. package/dist/core/session-manager-core.d.ts +4 -4
  166. package/dist/core/session-manager-core.d.ts.map +1 -1
  167. package/dist/core/session-manager-core.js +13 -8
  168. package/dist/core/session-manager-core.js.map +1 -1
  169. package/dist/core/session-manager-entries.d.ts +4 -3
  170. package/dist/core/session-manager-entries.d.ts.map +1 -1
  171. package/dist/core/session-manager-entries.js +12 -10
  172. package/dist/core/session-manager-entries.js.map +1 -1
  173. package/dist/core/session-manager-history.d.ts +6 -23
  174. package/dist/core/session-manager-history.d.ts.map +1 -1
  175. package/dist/core/session-manager-history.js +23 -256
  176. package/dist/core/session-manager-history.js.map +1 -1
  177. package/dist/core/session-manager-list.d.ts.map +1 -1
  178. package/dist/core/session-manager-list.js +3 -3
  179. package/dist/core/session-manager-list.js.map +1 -1
  180. package/dist/core/session-manager-storage.d.ts +1 -1
  181. package/dist/core/session-manager-storage.d.ts.map +1 -1
  182. package/dist/core/session-manager-storage.js +3 -2
  183. package/dist/core/session-manager-storage.js.map +1 -1
  184. package/dist/core/session-manager-types.d.ts +14 -15
  185. package/dist/core/session-manager-types.d.ts.map +1 -1
  186. package/dist/core/session-manager-types.js.map +1 -1
  187. package/dist/core/session-manager.d.ts +3 -2
  188. package/dist/core/session-manager.d.ts.map +1 -1
  189. package/dist/core/session-manager.js +1 -1
  190. package/dist/core/session-manager.js.map +1 -1
  191. package/dist/core/slash-commands.d.ts.map +1 -1
  192. package/dist/core/slash-commands.js +1 -1
  193. package/dist/core/slash-commands.js.map +1 -1
  194. package/dist/index.d.ts +3 -2
  195. package/dist/index.d.ts.map +1 -1
  196. package/dist/index.js +2 -1
  197. package/dist/index.js.map +1 -1
  198. package/dist/main-session.d.ts +1 -0
  199. package/dist/main-session.d.ts.map +1 -1
  200. package/dist/main-session.js +7 -0
  201. package/dist/main-session.js.map +1 -1
  202. package/dist/main.d.ts.map +1 -1
  203. package/dist/main.js +2 -2
  204. package/dist/main.js.map +1 -1
  205. package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
  206. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
  208. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  209. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/chat-session-host-events.js +5 -11
  211. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  212. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
  214. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  215. package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
  216. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
  218. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  219. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
  221. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
  222. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/chat-session-host.js +1 -0
  224. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  225. package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
  226. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
  227. package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
  228. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
  229. package/dist/modes/interactive/components/index.d.ts +1 -1
  230. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/index.js +1 -1
  232. package/dist/modes/interactive/components/index.js.map +1 -1
  233. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/session-selector-list.js +3 -0
  235. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  236. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-agent-events.js +3 -47
  238. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  239. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  240. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  241. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  242. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  243. package/dist/modes/interactive/interactive-mode-surface.d.ts +5 -3
  244. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  245. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  246. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-render-chat.js +21 -12
  248. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  249. package/dist/modes/rpc/rpc-client.d.ts +3 -5
  250. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  251. package/dist/modes/rpc/rpc-client.js +1 -6
  252. package/dist/modes/rpc/rpc-client.js.map +1 -1
  253. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  254. package/dist/modes/rpc/rpc-command-handler.js +0 -4
  255. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  256. package/dist/modes/rpc/rpc-types.d.ts +2 -11
  257. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  258. package/dist/modes/rpc/rpc-types.js.map +1 -1
  259. package/docs/compaction.md +97 -772
  260. package/docs/extensions.md +25 -29
  261. package/docs/json.md +2 -2
  262. package/docs/rpc.md +32 -24
  263. package/docs/sdk.md +3 -3
  264. package/docs/session-format.md +49 -30
  265. package/docs/sessions.md +5 -3
  266. package/docs/settings.md +14 -4
  267. package/docs/usage.md +1 -1
  268. package/docs/workflows.md +30 -15
  269. package/examples/extensions/custom-compaction.ts +14 -58
  270. package/examples/extensions/handoff.ts +2 -3
  271. package/npm-shrinkwrap.json +23 -23
  272. package/package.json +2 -2
  273. package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
  274. package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
  275. package/dist/core/compaction/context-assistant-turns.js +0 -87
  276. package/dist/core/compaction/context-assistant-turns.js.map +0 -1
  277. package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
  278. package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
  279. package/dist/core/compaction/context-compaction-critical.js +0 -57
  280. package/dist/core/compaction/context-compaction-critical.js.map +0 -1
  281. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
  282. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
  283. package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
  284. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
  285. package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
  286. package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
  287. package/dist/core/compaction/context-compaction-eviction.js +0 -222
  288. package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
  289. package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
  290. package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
  291. package/dist/core/compaction/context-compaction-metrics.js +0 -107
  292. package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
  293. package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
  294. package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
  295. package/dist/core/compaction/context-compaction-prompt.js +0 -163
  296. package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
  297. package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
  298. package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
  299. package/dist/core/compaction/context-compaction-runner.js +0 -273
  300. package/dist/core/compaction/context-compaction-runner.js.map +0 -1
  301. package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
  302. package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
  303. package/dist/core/compaction/context-compaction-strategy.js +0 -27
  304. package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
  305. package/dist/core/compaction/context-compaction-types.d.ts +0 -75
  306. package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
  307. package/dist/core/compaction/context-compaction-types.js +0 -6
  308. package/dist/core/compaction/context-compaction-types.js.map +0 -1
  309. package/dist/core/compaction/context-compaction.d.ts +0 -10
  310. package/dist/core/compaction/context-compaction.d.ts.map +0 -1
  311. package/dist/core/compaction/context-compaction.js +0 -8
  312. package/dist/core/compaction/context-compaction.js.map +0 -1
  313. package/dist/core/compaction/context-deletion-application.d.ts +0 -14
  314. package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
  315. package/dist/core/compaction/context-deletion-application.js +0 -261
  316. package/dist/core/compaction/context-deletion-application.js.map +0 -1
  317. package/dist/core/compaction/context-deletion-store.d.ts +0 -78
  318. package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
  319. package/dist/core/compaction/context-deletion-store.js +0 -162
  320. package/dist/core/compaction/context-deletion-store.js.map +0 -1
  321. package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
  322. package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
  323. package/dist/core/compaction/context-deletion-targets.js +0 -292
  324. package/dist/core/compaction/context-deletion-targets.js.map +0 -1
  325. package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
  326. package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
  327. package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
  328. package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
  329. package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
  330. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
  331. package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
  332. package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
  333. package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
  334. package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
  335. package/dist/core/compaction/context-deletion-tools.js +0 -403
  336. package/dist/core/compaction/context-deletion-tools.js.map +0 -1
  337. package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
  338. package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
  339. package/dist/core/compaction/context-transcript-analysis.js +0 -228
  340. package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
  341. package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
  342. package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
  343. package/dist/core/session-manager-tool-dependencies.js +0 -133
  344. package/dist/core/session-manager-tool-dependencies.js.map +0 -1
  345. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
  346. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
  347. package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
  348. package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
@@ -1,20 +1,17 @@
1
1
  import { cancellationRegistry } from "../runs/background/cancellation-registry.js";
2
2
  import { interruptAllRuns, interruptRun, killAllRuns, killRun, pauseRun, resumeRun } from "../runs/background/status.js";
3
- import type { WorkflowPersistencePort } from "../shared/types.js";
3
+ import { getDurableBackend } from "../durable/factory.js";
4
4
  import { store } from "../shared/store.js";
5
5
  import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
6
6
  import { renderSessionList } from "../tui/session-list.js";
7
7
  import { openKillConfirm, openSessionPicker } from "../tui/session-overlays.js";
8
- import { openWorkflowResumeSelector } from "../tui/workflow-resume-selector.js";
9
8
  import { deriveGraphTheme } from "../tui/graph-theme.js";
9
+ import { openWorkflowResumeSelector } from "../tui/workflow-resume-selector.js";
10
10
  import { emitChatSurface } from "../tui/chat-surface-message.js";
11
- import type { GraphOverlayPort } from "../tui/overlay-adapter.js";
12
- import type { ExtensionRuntime } from "./runtime.js";
13
- import type { ExtensionAPI, PiCommandContext } from "./public-types.js";
11
+ import type { PiCommandContext } from "./public-types.js";
14
12
  import type { WorkflowCommandReporter } from "./workflow-command-utils.js";
15
13
  import { stripYesFlag } from "./workflow-command-utils.js";
16
14
  import { workflowPolicyFromContext } from "./workflow-policy.js";
17
- import { formatResumableWorkflowList } from "../durable/resume-catalog.js";
18
15
  import type { ResumableWorkflowEntry } from "../durable/types.js";
19
16
  import {
20
17
  formatAlreadyEndedRetainedMessage,
@@ -23,14 +20,14 @@ import {
23
20
  resolveStageTarget,
24
21
  } from "./workflow-targets.js";
25
22
  import { formatWorkflowResourceLoadWarning } from "./workflow-command-surfaces.js";
23
+ import {
24
+ handleDurableResume,
25
+ prepareWorkflowResumeCatalog,
26
+ resolveWorkflowResumeTarget,
27
+ type WorkflowRunControlDeps,
28
+ } from "./workflow-durable-resume-command.js";
26
29
 
27
- export interface WorkflowRunControlDeps {
28
- pi: ExtensionAPI;
29
- overlay: GraphOverlayPort;
30
- getPersistence: () => WorkflowPersistencePort | undefined;
31
- runtimeForContext: (ctx?: PiCommandContext) => ExtensionRuntime;
32
- ensureWorkflowResourcesLoaded: () => Promise<void> | void;
33
- }
30
+ export type { WorkflowRunControlDeps } from "./workflow-durable-resume-command.js";
34
31
 
35
32
  function resolveAttachStageId(runId: string, stageTarget: string | undefined): string | undefined | false {
36
33
  if (!stageTarget) return undefined;
@@ -42,79 +39,6 @@ function resolveAttachStageId(runId: string, stageTarget: string | undefined): s
42
39
  return byName?.id ?? false;
43
40
  }
44
41
 
45
- function filterSelectorDurableEntries(
46
- runtime: ExtensionRuntime,
47
- entries: readonly ResumableWorkflowEntry[],
48
- ): readonly ResumableWorkflowEntry[] {
49
- const registry = runtime.registry as { has(name: string): boolean } | undefined;
50
- if (registry === undefined) return entries;
51
- return entries.filter((entry) => {
52
- const requiresCurrentDefinition = entry.status === "running" || entry.status === "failed" || entry.status === "blocked";
53
- return !requiresCurrentDefinition || registry.has(entry.name);
54
- });
55
- }
56
-
57
-
58
- async function handleDurableResume(
59
- target: string | undefined,
60
- ctx: PiCommandContext,
61
- reporter: WorkflowCommandReporter,
62
- deps: WorkflowRunControlDeps,
63
- ): Promise<boolean> {
64
- const print = (msg: string): void => reporter.info(msg);
65
- const fail = (msg: string): void => reporter.error(msg);
66
- try {
67
- await deps.ensureWorkflowResourcesLoaded();
68
- } catch (error) {
69
- ctx.ui?.notify(formatWorkflowResourceLoadWarning(error), "warning");
70
- }
71
- const runtime = deps.runtimeForContext(ctx);
72
- const policy = workflowPolicyFromContext(ctx);
73
- // Hydrate the durable backend from DBOS (if configured) before listing so a
74
- // fresh process discovers workflows persisted by a prior session.
75
- const prepared = await runtime.prepareDurableResumable(target);
76
- const durable = filterSelectorDurableEntries(runtime, prepared);
77
- if (target !== undefined) {
78
- // Attempt resume by id/prefix against the durable catalog.
79
- const result = runtime.resumeDurableWorkflow(target, { policy });
80
- if (result.ok) {
81
- print(result.message);
82
- // Open/connect the overlay to the resumed run, analogous to live resume.
83
- if (policy.allowInputPicker) deps.overlay.open(result.runId, overlaySurfaceFromContext(ctx));
84
- return true;
85
- }
86
- // Not a durable workflow either — surface the catalog for discovery.
87
- if (durable.length > 0) {
88
- fail(`${result.message}\n\n${formatResumableWorkflowList(durable)}`);
89
- } else {
90
- fail(result.message);
91
- }
92
- return true;
93
- }
94
- // No target: show the durable selector when interactive, otherwise print.
95
- if (durable.length === 0) {
96
- fail("No resumable durable workflows found. Usage: /workflow resume <id> (or /resume for Atomic sessions).");
97
- return true;
98
- }
99
- if (!policy.allowInputPicker) {
100
- print(`${formatResumableWorkflowList(durable)}\n\nResume with: /workflow resume <id>`);
101
- return true;
102
- }
103
- const picked = await openWorkflowResumeSelector(ctx.ui, [], durable);
104
- if (picked.kind === "durable") {
105
- const result = runtime.resumeDurableWorkflow(picked.workflowId, { policy });
106
- if (result.ok) {
107
- print(result.message);
108
- if (policy.allowInputPicker) deps.overlay.open(result.runId, overlaySurfaceFromContext(ctx));
109
- } else {
110
- fail(result.message);
111
- }
112
- }
113
- if (picked.kind !== "durable") {
114
- print(`${formatResumableWorkflowList(durable)}\n\nResume with: /workflow resume <id>`);
115
- }
116
- return true;
117
- }
118
42
 
119
43
  export async function handleRunControlCommand(
120
44
  action: "connect" | "interrupt" | "kill" | "attach" | "pause" | "resume",
@@ -304,33 +228,35 @@ export async function handleRunControlCommand(
304
228
  // Only inactive workflows belong in the resume selector. Live runs:
305
229
  // show paused (quit) or recoverably-failed runs; actively-running live
306
230
  // runs are hidden (resuming one that is executing would double-dispatch).
307
- const liveRuns = topLevelWorkflowRuns(store.runs()).filter((run) =>
231
+ let liveRuns = topLevelWorkflowRuns(store.runs()).filter((run) =>
308
232
  run.status === "paused" || (run.status === "failed" && run.resumable !== false),
309
233
  );
234
+ const activeLiveIds = new Set(
235
+ topLevelWorkflowRuns(store.runs())
236
+ .filter((run) => run.endedAt === undefined && run.status === "running" && run.exitReason !== "quit")
237
+ .map((run) => run.id),
238
+ );
239
+ await ensureWorkflowResourcesVisible();
240
+ const runtime = deps.runtimeForContext(ctx);
310
241
  let durableEntries: readonly ResumableWorkflowEntry[] = [];
311
- if (liveRuns.length === 0) {
312
- // Durable entries: a `running` durable handle may be a crashed process
313
- // (cross-session crash recovery), so it stays selectable UNLESS it
314
- // matches an actively-executing live run in this session.
315
- const activeLiveIds = new Set(
316
- topLevelWorkflowRuns(store.runs())
317
- .filter((run) => run.endedAt === undefined && run.status === "running" && run.exitReason !== "quit")
318
- .map((run) => run.id),
319
- );
320
- await ensureWorkflowResourcesVisible();
321
- const runtime = deps.runtimeForContext(ctx);
322
- try {
323
- const prepared = await runtime.prepareDurableResumable(undefined);
324
- durableEntries = filterSelectorDurableEntries(runtime, prepared)
325
- .filter((entry) => !activeLiveIds.has(entry.workflowId));
326
- } catch (error) {
327
- const message = error instanceof Error ? error.message : String(error);
328
- fail(`Failed to list resumable workflows: ${message}`);
242
+ let completedEntries: readonly ResumableWorkflowEntry[] = [];
243
+ try {
244
+ const catalog = await prepareWorkflowResumeCatalog(runtime, activeLiveIds);
245
+ durableEntries = catalog.resumable;
246
+ completedEntries = catalog.completed;
247
+ } catch (error) {
248
+ liveRuns = liveRuns.filter((run) => getDurableBackend().isWorkflowLoadable(run.id));
249
+ const errorMessage = error instanceof Error ? error.message : String(error);
250
+ if (liveRuns.length === 0) {
251
+ fail(`Failed to list workflow resume targets: ${errorMessage}`);
329
252
  return true;
330
253
  }
331
254
  }
332
- const picked = await openWorkflowResumeSelector(ctx.ui, liveRuns, durableEntries);
333
- if (picked.kind === "durable") return await handleDurableResume(picked.workflowId, ctx, reporter, deps);
255
+ liveRuns = liveRuns.filter((run) => getDurableBackend().isWorkflowLoadable(run.id));
256
+ const picked = await openWorkflowResumeSelector(ctx.ui, liveRuns, durableEntries, completedEntries);
257
+ if (picked.kind === "durable" || picked.kind === "completed") {
258
+ return await handleDurableResume(picked.workflowId, ctx, reporter, deps);
259
+ }
334
260
  if (picked.kind === "live") {
335
261
  const resolved = resolveRunIdPrefix(picked.runId);
336
262
  if (resolved.kind !== "exact") {
@@ -359,14 +285,42 @@ export async function handleRunControlCommand(
359
285
  if (action === "attach" && picked.kind === "kill") return handleRunControlCommand("kill", [picked.runId, "-y"], ctx, reporter, deps);
360
286
  if (picked.kind !== (action === "attach" ? "connect" : action)) return true;
361
287
  runId = picked.runId;
288
+ } else if (action === "resume") {
289
+ const backend = getDurableBackend();
290
+ const exactBeforePreparation = store.runs().find((run) => run.id === target);
291
+ let durable: readonly ResumableWorkflowEntry[] = [];
292
+ let preparationError: string | undefined;
293
+ const needsDurablePreparation = exactBeforePreparation === undefined
294
+ || !backend.isWorkflowLoadable(exactBeforePreparation.id);
295
+ if (needsDurablePreparation) {
296
+ await ensureWorkflowResourcesVisible();
297
+ const runtime = deps.runtimeForContext(ctx);
298
+ try {
299
+ durable = await runtime.prepareDurableResumable(target);
300
+ } catch (error) {
301
+ preparationError = error instanceof Error ? error.message : String(error);
302
+ }
303
+ }
304
+ const loadableRuns = topLevelWorkflowRuns(store.runs()).filter((run) => backend.isWorkflowLoadable(run.id));
305
+ const combined = resolveWorkflowResumeTarget(target, loadableRuns, durable, backend.listCompletedWorkflows());
306
+ if (combined.kind === "ambiguous") {
307
+ fail(`Ambiguous workflow prefix "${target}" matches: ${combined.matches.map((match) => `${match.name} (${match.workflowId.slice(0, 8)})`).join(", ")}`);
308
+ return true;
309
+ }
310
+ if (combined.kind === "completed" || combined.kind === "durable") {
311
+ return await handleDurableResume(combined.workflowId, ctx, reporter, deps);
312
+ }
313
+ if (combined.kind === "live") runId = combined.workflowId;
314
+ else {
315
+ if (preparationError !== undefined) {
316
+ fail(`Failed to resolve workflow resume target: ${preparationError}`);
317
+ return true;
318
+ }
319
+ return await handleDurableResume(target, ctx, reporter, deps);
320
+ }
362
321
  } else {
363
322
  const resolved = resolveRunIdPrefix(target);
364
323
  if (resolved.kind === "not_found") {
365
- // Not a live run — fall back to the cross-session durable resume catalog.
366
- // cross-ref: issue #1498 — /workflow resume by top-level workflow id.
367
- if (action === "resume") {
368
- return await handleDurableResume(target, ctx, reporter, deps);
369
- }
370
324
  fail(`Run not found: ${target}`);
371
325
  return true;
372
326
  }
@@ -45,7 +45,7 @@ const JsonSchemaObject = Type.Unsafe<Record<string, unknown>>({
45
45
 
46
46
  const StageSessionOptionProperties = {
47
47
  schema: Type.Optional(JsonSchemaObject),
48
- cwd: Type.Optional(Type.String()),
48
+ cwd: Type.Optional(Type.String({ description: "Starting directory only; does not provide worktree isolation." })),
49
49
  agentDir: Type.Optional(Type.String()),
50
50
  authStorage: Type.Optional(SdkSessionOptionSchema("authStorage")),
51
51
  modelRegistry: Type.Optional(SdkSessionOptionSchema("modelRegistry")),
@@ -88,8 +88,8 @@ const WorkflowTaskOptionProperties = {
88
88
  output: Type.Optional(WorkflowOutputSchema),
89
89
  outputMode: Type.Optional(Type.Union([Type.Literal("inline"), Type.Literal("file-only")])),
90
90
  reads: Type.Optional(Type.Union([Type.Array(Type.String()), Type.Literal(false)])),
91
- worktree: Type.Optional(Type.Boolean()),
92
- gitWorktreeDir: Type.Optional(Type.String()),
91
+ worktree: Type.Optional(Type.Boolean({ description: "Runner-managed temporary per-task worktree isolation for direct runs." })),
92
+ gitWorktreeDir: Type.Optional(Type.String({ description: "Runner-managed reusable worktree; natural-language worktree instructions do not set this option." })),
93
93
  baseBranch: Type.Optional(Type.String()),
94
94
  maxOutput: Type.Optional(MaxOutputSchema),
95
95
  artifacts: Type.Optional(Type.Boolean()),
@@ -107,8 +107,8 @@ const ParallelChainStepSchema = Type.Object({
107
107
  parallel: Type.Array(DirectTaskSchema),
108
108
  concurrency: Type.Optional(Type.Number()),
109
109
  failFast: Type.Optional(Type.Boolean()),
110
- worktree: Type.Optional(Type.Boolean()),
111
- gitWorktreeDir: Type.Optional(Type.String()),
110
+ worktree: Type.Optional(Type.Boolean({ description: "Runner-managed temporary per-task worktree isolation for direct runs." })),
111
+ gitWorktreeDir: Type.Optional(Type.String({ description: "Runner-managed reusable worktree; natural-language worktree instructions do not set this option." })),
112
112
  baseBranch: Type.Optional(Type.String()),
113
113
  });
114
114
 
@@ -9,6 +9,7 @@ import {
9
9
  } from "../runs/background/status.js";
10
10
  import { cancellationRegistry } from "../runs/background/cancellation-registry.js";
11
11
  import { store } from "../shared/store.js";
12
+ import { getDurableBackend } from "../durable/factory.js";
12
13
  import type { WorkflowExecutionPolicy, WorkflowPersistencePort } from "../shared/types.js";
13
14
  import type { ExtensionRuntime } from "./runtime.js";
14
15
  import type { WorkflowToolResult } from "./render-result.js";
@@ -176,6 +177,21 @@ export async function workflowResumeAction(
176
177
  if (target.kind === "all") return { action: "resume", runId: "--all", status: "noop", message: "Resume does not support --all." };
177
178
  if (target.kind === "ambiguous") return { action: "resume", runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
178
179
  if (target.kind === "not_found") return { action: "resume", runId: target.target, status: "noop", message: target.message };
180
+ const backend = getDurableBackend();
181
+ if (!backend.isWorkflowLoadable(target.runId)) {
182
+ try {
183
+ await deps.ensureWorkflowResourcesLoaded();
184
+ await deps.getRuntime().prepareDurableResumable(target.runId);
185
+ } catch {
186
+ // Durable compatibility preparation failures fall through to the
187
+ // authoritative loadability check below; workflow resume remains best-effort.
188
+ }
189
+ if (!backend.isWorkflowLoadable(target.runId)) {
190
+ store.removeRun(target.runId);
191
+ return { action: "resume", runId: target.runId, status: "noop", message: `Run not found: ${target.runId}` };
192
+ }
193
+ }
194
+ let warning: string | undefined;
179
195
  const stage = resolveToolStageTarget(target.runId, args.stageId);
180
196
  if (!stage.ok) return { action: "resume", runId: target.runId, status: "noop", message: stage.message };
181
197
  const stageRunId = stage.runId ?? target.runId;
@@ -188,7 +204,6 @@ export async function workflowResumeAction(
188
204
  (run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable")
189
205
  );
190
206
  if (isResumableContinuation) {
191
- let warning: string | undefined;
192
207
  try {
193
208
  await deps.ensureWorkflowResourcesLoaded();
194
209
  } catch (error) {
@@ -1,6 +1,6 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import { tmpdir } from "node:os";
2
2
  import { basename, dirname, extname, isAbsolute, join, resolve } from "node:path";
3
- import { CONFIG_DIR_NAME, isCodexFastModeCandidateModelId } from "@bastani/atomic";
3
+ import { APP_NAME, CONFIG_DIR_NAME, isCodexFastModeCandidateModelId } from "@bastani/atomic";
4
4
  import { Type } from "typebox";
5
5
  import type {
6
6
  StageOptions,
@@ -10,7 +10,6 @@ import type {
10
10
  WorkflowDetails,
11
11
  WorkflowDirectOptions,
12
12
  WorkflowDirectTaskItem,
13
- WorkflowOutputMode,
14
13
  WorkflowOutputSchema,
15
14
  WorkflowTaskResult,
16
15
  WorkflowTaskStep,
@@ -30,10 +29,11 @@ import {
30
29
  type GitWorktreeSetupResult,
31
30
  type WorktreeSetup,
32
31
  } from "../shared/worktree.js";
32
+ import { resolveWorktreeStageCwd } from "../shared/worktree-cwd.js";
33
33
  import type { RunOpts, RunResult } from "./executor-types.js";
34
34
  import { isWorkflowExitStatus } from "./executor-abort.js";
35
- import { directTaskWithDefaults, resolveWorkflowPath, taskBaseDir, withoutUndefinedProperties } from "./executor-task-prompts.js";
36
- export { createGitWorktreeSetupCache } from "../shared/worktree.js";
35
+ import { directTaskWithDefaults, withoutUndefinedProperties } from "./executor-task-prompts.js";
36
+ export { createGitWorktreeSetupCache, createGitWorktreeSetupCacheOwner } from "../shared/worktree.js";
37
37
  export type { GitWorktreeSetupCache } from "../shared/worktree.js";
38
38
 
39
39
  export function directModelRequestsFromChain(
@@ -190,11 +190,17 @@ function namespaceRepeatedOutput(output: WorkflowDirectTaskItem["output"], index
190
190
  return join(dirname(output), `${base}-${index + 1}${ext}`);
191
191
  }
192
192
 
193
+ export interface DirectOutputIsolation {
194
+ readonly baseDir: string;
195
+ readonly trustedRoot: string;
196
+ }
197
+
193
198
  export interface PreparedDirectWorktrees {
194
199
  readonly tasks: WorkflowDirectTaskItem[];
195
200
  readonly setup?: WorktreeSetup;
196
201
  readonly agents: string[];
197
202
  readonly diffsDir?: string;
203
+ readonly outputIsolations?: readonly DirectOutputIsolation[];
198
204
  }
199
205
 
200
206
  export function directRunId(runOptions: RunOpts): string {
@@ -205,20 +211,18 @@ function hasDirectWorktreeIsolation(tasks: readonly WorkflowDirectTaskItem[], op
205
211
  return options.worktree === true || tasks.some((task) => task.worktree === true);
206
212
  }
207
213
 
208
- function resolveSharedDirectWorktreeCwd(tasks: readonly WorkflowDirectTaskItem[]): string {
214
+ function resolveSharedDirectWorktreeCwd(
215
+ tasks: readonly WorkflowDirectTaskItem[],
216
+ workflowInvocationCwd: string,
217
+ ): string {
209
218
  const explicitCwd = tasks.find((task) => typeof task.cwd === "string")?.cwd;
210
- if (explicitCwd === undefined) return process.cwd();
211
- return isAbsolute(explicitCwd) ? explicitCwd : resolve(process.cwd(), explicitCwd);
219
+ if (explicitCwd === undefined) return workflowInvocationCwd;
220
+ return isAbsolute(explicitCwd) ? explicitCwd : resolve(workflowInvocationCwd, explicitCwd);
212
221
  }
213
222
 
214
- function normalizeDirectTaskCwd(cwd: string | undefined): string | undefined {
223
+ function normalizeDirectTaskCwd(cwd: string | undefined, workflowInvocationCwd: string): string | undefined {
215
224
  if (cwd === undefined) return undefined;
216
- return isAbsolute(cwd) ? cwd : resolve(process.cwd(), cwd);
217
- }
218
-
219
- export function resolveWorktreeCwdOverride(cwd: string | undefined, worktreeCwd: string): string | undefined {
220
- if (cwd === undefined || cwd.length === 0) return undefined;
221
- return isAbsolute(cwd) ? cwd : resolve(worktreeCwd, cwd);
225
+ return isAbsolute(cwd) ? cwd : resolve(workflowInvocationCwd, cwd);
222
226
  }
223
227
 
224
228
  export function stageOptionsWithInputDefaults<T extends StageOptions>(options: T | undefined, inputDefaults: Partial<StageOptions>): T | undefined {
@@ -229,13 +233,16 @@ export function stageOptionsWithInputDefaults<T extends StageOptions>(options: T
229
233
 
230
234
  export function stageOptionsWithGitWorktree<T extends StageOptions>(options: T | undefined, workflowInvocationCwd: string, cache?: GitWorktreeSetupCache): T | undefined {
231
235
  if (options === undefined) return undefined;
232
- if (typeof options.gitWorktreeDir !== "string" || options.gitWorktreeDir.trim().length === 0) return options;
236
+ if (typeof options.gitWorktreeDir !== "string") return options;
237
+ if (options.gitWorktreeDir.trim().length === 0) {
238
+ throw new Error("atomic-workflows: gitWorktreeDir cannot be empty; provide a reusable worktree path or omit gitWorktreeDir for a non-worktree run.");
239
+ }
233
240
  const setup = setupGitWorktreeCached({
234
241
  gitWorktreeDir: options.gitWorktreeDir,
235
242
  baseBranch: options.baseBranch,
236
243
  cwd: workflowInvocationCwd,
237
244
  }, cache);
238
- const explicitCwd = resolveWorktreeCwdOverride(options.cwd, setup.cwd);
245
+ const explicitCwd = resolveWorktreeStageCwd(options.cwd, setup);
239
246
  return { ...options, gitWorktreeDir: undefined, baseBranch: undefined, cwd: explicitCwd ?? setup.cwd };
240
247
  }
241
248
 
@@ -267,9 +274,24 @@ export function workflowInvocationMetadata(inputDefaults: Partial<StageOptions>,
267
274
  };
268
275
  }
269
276
 
277
+ function nonBlankChainDir(chainDir: string | undefined): string | undefined {
278
+ return typeof chainDir === "string" && chainDir.trim().length > 0 ? chainDir : undefined;
279
+ }
280
+
281
+ function directWorktreeArtifactBase(options: WorkflowDirectOptions, setup: WorktreeSetup): string {
282
+ return nonBlankChainDir(options.chainDir) ?? join(setup.cwd, CONFIG_DIR_NAME, "workflows");
283
+ }
284
+
270
285
  function directWorktreeDiffsDir(options: WorkflowDirectOptions, setup: WorktreeSetup, runId: string, scope: string): string {
271
- const baseDir = options.chainDir ?? join(setup.cwd, CONFIG_DIR_NAME, "workflows");
272
- return join(baseDir, "worktree-diffs", runId, scope);
286
+ return join(directWorktreeArtifactBase(options, setup), "worktree-diffs", runId, scope);
287
+ }
288
+
289
+ function directWorktreeOutputsRoot(): string {
290
+ return join(tmpdir(), `${APP_NAME}-workflow-outputs`);
291
+ }
292
+
293
+ function directWorktreeOutputsDir(runId: string, scope: string, index: number): string {
294
+ return join(directWorktreeOutputsRoot(), runId, scope, String(index));
273
295
  }
274
296
 
275
297
  export function prepareDirectWorktrees(
@@ -277,6 +299,7 @@ export function prepareDirectWorktrees(
277
299
  options: WorkflowDirectOptions,
278
300
  runId: string,
279
301
  scope: string,
302
+ workflowInvocationCwd: string = process.cwd(),
280
303
  ): PreparedDirectWorktrees {
281
304
  if (!hasDirectWorktreeIsolation(tasks, options)) {
282
305
  return {
@@ -289,9 +312,9 @@ export function prepareDirectWorktrees(
289
312
  throw new Error("atomic-workflows: worktree and gitWorktreeDir are mutually exclusive; use gitWorktreeDir for a reusable worktree or worktree:true for temporary isolated worktrees.");
290
313
  }
291
314
 
292
- const sharedCwd = resolveSharedDirectWorktreeCwd(tasks);
315
+ const sharedCwd = resolveSharedDirectWorktreeCwd(tasks, workflowInvocationCwd);
293
316
  const conflict = findWorktreeTaskCwdConflict(
294
- tasks.map((task) => ({ agent: task.name, cwd: normalizeDirectTaskCwd(task.cwd) })),
317
+ tasks.map((task) => ({ agent: task.name, cwd: normalizeDirectTaskCwd(task.cwd, workflowInvocationCwd) })),
295
318
  sharedCwd,
296
319
  );
297
320
  if (conflict !== undefined) throw new Error(formatWorktreeTaskCwdConflict(conflict, sharedCwd));
@@ -306,6 +329,10 @@ export function prepareDirectWorktrees(
306
329
  setup,
307
330
  agents,
308
331
  diffsDir: directWorktreeDiffsDir(options, setup, runId, scope),
332
+ outputIsolations: tasks.map((_, index) => ({
333
+ baseDir: directWorktreeOutputsDir(runId, scope, index),
334
+ trustedRoot: directWorktreeOutputsRoot(),
335
+ })),
309
336
  };
310
337
  }
311
338
 
@@ -343,31 +370,11 @@ export function isRunOpts(value: WorkflowDirectOptions | RunOpts | undefined): v
343
370
  "adapters" in value || "ui" in value || "store" in value || "persistence" in value ||
344
371
  "mcp" in value || "cancellation" in value || "overlay" in value || "signal" in value ||
345
372
  "config" in value || "depth" in value || "stageControlRegistry" in value || "runId" in value ||
346
- "onRunStart" in value || "onStageStart" in value || "onStageEnd" in value || "onRunEnd" in value ||
347
- "models" in value
373
+ "gitWorktreeSetupCache" in value || "onRunStart" in value || "onStageStart" in value ||
374
+ "onStageEnd" in value || "onRunEnd" in value || "models" in value
348
375
  );
349
376
  }
350
377
 
351
- export async function writeDirectOutput(
352
- item: { readonly chainDir?: string; readonly cwd?: string; readonly output?: string | false; readonly outputMode?: WorkflowOutputMode },
353
- result: WorkflowTaskResult,
354
- ): Promise<{ result: WorkflowTaskResult; artifact?: WorkflowArtifact }> {
355
- if (typeof item.output !== "string") return { result };
356
-
357
- const outputPath = resolveWorkflowPath(item.output, taskBaseDir(item));
358
- await mkdir(dirname(outputPath), { recursive: true });
359
- await writeFile(outputPath, result.text, "utf8");
360
-
361
- const visibleResult = item.outputMode === "file-only" ? { ...result, text: "" } : result;
362
- return {
363
- result: visibleResult,
364
- artifact: {
365
- kind: "output",
366
- path: outputPath,
367
- taskName: result.name,
368
- },
369
- };
370
- }
371
378
 
372
379
  function directFailureMessage(error: unknown): string {
373
380
  return classifyWorkflowFailure(error).userMessage;
@@ -0,0 +1,91 @@
1
+ import { lstat, mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, isAbsolute, relative } from "node:path";
3
+ import type {
4
+ WorkflowArtifact,
5
+ WorkflowDirectTaskItem,
6
+ WorkflowTaskResult,
7
+ } from "../../shared/types.js";
8
+ import { setupGitWorktreeCached, type GitWorktreeSetupCache } from "../shared/worktree.js";
9
+ import { resolveContainedRelativePath, resolveWorktreeStageCwd } from "../shared/worktree-cwd.js";
10
+ import type { DirectOutputIsolation } from "./executor-direct-helpers.js";
11
+ import { resolveWorkflowPath, taskBaseDir } from "./executor-task-prompts.js";
12
+
13
+ function nonBlankChainDir(chainDir: string | undefined): string | undefined {
14
+ return typeof chainDir === "string" && chainDir.trim().length > 0 ? chainDir : undefined;
15
+ }
16
+ async function ensureTrustedArtifactRoot(root: string): Promise<void> {
17
+ await mkdir(root, { recursive: true });
18
+ const entry = await lstat(root);
19
+ if (entry.isSymbolicLink() || !entry.isDirectory()) {
20
+ throw new Error(
21
+ `atomic-workflows: runner artifact root ${root} must be a real directory, not a symlink or junction.`,
22
+ );
23
+ }
24
+ }
25
+
26
+ export async function writeDirectOutput(
27
+ item: Pick<WorkflowDirectTaskItem, "cwd" | "output" | "outputMode" | "gitWorktreeDir" | "baseBranch"> & { readonly chainDir?: string },
28
+ result: WorkflowTaskResult,
29
+ workflowInvocationCwd: string = process.cwd(),
30
+ outputIsolation?: DirectOutputIsolation,
31
+ gitWorktreeSetupCache?: GitWorktreeSetupCache,
32
+ ): Promise<{ result: WorkflowTaskResult; artifact?: WorkflowArtifact }> {
33
+ if (typeof item.output !== "string") return { result };
34
+
35
+ const explicitChainDir = nonBlankChainDir(item.chainDir);
36
+ let outputPath: string;
37
+ let trustedArtifactRoot: string | undefined;
38
+ let containment: { readonly root: string; readonly baseDir: string; readonly description: string } | undefined;
39
+ if (isAbsolute(item.output)) {
40
+ outputPath = item.output;
41
+ } else if (explicitChainDir !== undefined) {
42
+ outputPath = resolveWorkflowPath(item.output, resolveWorkflowPath(explicitChainDir, process.cwd()));
43
+ } else if (outputIsolation !== undefined) {
44
+ await ensureTrustedArtifactRoot(outputIsolation.trustedRoot);
45
+ trustedArtifactRoot = outputIsolation.trustedRoot;
46
+ const baseRelative = relative(outputIsolation.trustedRoot, outputIsolation.baseDir);
47
+ const baseDir = resolveContainedRelativePath(
48
+ outputIsolation.trustedRoot,
49
+ outputIsolation.trustedRoot,
50
+ baseRelative,
51
+ "runner artifact root",
52
+ );
53
+ await mkdir(baseDir, { recursive: true });
54
+ containment = { root: baseDir, baseDir, description: "runner output root" };
55
+ outputPath = resolveContainedRelativePath(baseDir, baseDir, item.output, containment.description);
56
+ } else if (typeof item.gitWorktreeDir === "string") {
57
+ const setup = setupGitWorktreeCached({
58
+ gitWorktreeDir: item.gitWorktreeDir,
59
+ baseBranch: item.baseBranch,
60
+ cwd: workflowInvocationCwd,
61
+ }, gitWorktreeSetupCache);
62
+ const baseDir = resolveWorktreeStageCwd(item.cwd, setup) ?? setup.cwd;
63
+ containment = { root: setup.worktreeRoot, baseDir, description: "gitWorktreeDir" };
64
+ outputPath = resolveContainedRelativePath(setup.worktreeRoot, baseDir, item.output, containment.description);
65
+ } else {
66
+ outputPath = resolveWorkflowPath(item.output, taskBaseDir(item));
67
+ }
68
+
69
+ await mkdir(dirname(outputPath), { recursive: true });
70
+ if (trustedArtifactRoot !== undefined) await ensureTrustedArtifactRoot(trustedArtifactRoot);
71
+
72
+ if (containment !== undefined) {
73
+ outputPath = resolveContainedRelativePath(
74
+ containment.root,
75
+ containment.baseDir,
76
+ item.output,
77
+ containment.description,
78
+ );
79
+ }
80
+ await writeFile(outputPath, result.text, "utf8");
81
+
82
+ const visibleResult = item.outputMode === "file-only" ? { ...result, text: "" } : result;
83
+ return {
84
+ result: visibleResult,
85
+ artifact: {
86
+ kind: "output",
87
+ path: outputPath,
88
+ taskName: result.name,
89
+ },
90
+ };
91
+ }