@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
@@ -13,6 +13,7 @@ import type { RunOpts } from "./executor-types.js";
13
13
  import { run } from "./executor-run.js";
14
14
  import {
15
15
  cleanupPreparedWorktrees,
16
+ createGitWorktreeSetupCache,
16
17
  collectWorktreeDiffs,
17
18
  defineDirectWorkflow,
18
19
  directModelRequestsFromChain,
@@ -23,8 +24,9 @@ import {
23
24
  prepareDirectWorktrees,
24
25
  validateDirectModels,
25
26
  workflowDetailsFromRun,
26
- writeDirectOutput,
27
+ type GitWorktreeSetupCache,
27
28
  } from "./executor-direct-helpers.js";
29
+ import { writeDirectOutput } from "./executor-direct-output.js";
28
30
  import {
29
31
  directTaskPrompt,
30
32
  directTaskToStep,
@@ -57,27 +59,36 @@ export async function runTask(
57
59
  } catch (err) {
58
60
  return failedDirectDetails("single", runId, 1, err, options);
59
61
  }
60
- const prepared = prepareDirectWorktrees([taskWithDefaults], options, runId, "single");
62
+ const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
63
+ const prepared = prepareDirectWorktrees([taskWithDefaults], options, runId, "single", workflowInvocationCwd);
61
64
  const preparedTask = prepared.tasks[0]!;
65
+ const gitWorktreeSetupCache = createGitWorktreeSetupCache();
62
66
  const direct = defineDirectWorkflow("direct-task", async (ctx) => {
67
+ const rawResult = await ctx.task(preparedTask.name, directTaskToStep(preparedTask));
68
+ const { result, artifact } = await writeDirectOutput(
69
+ preparedTask, rawResult, workflowInvocationCwd, prepared.outputIsolations?.[0], gitWorktreeSetupCache,
70
+ );
71
+ const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
72
+ return {
73
+ results: [result],
74
+ text: result.text,
75
+ artifacts: [
76
+ ...worktreeDiffs.artifacts,
77
+ ...(artifact === undefined ? [] : [artifact]),
78
+ ],
79
+ ...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
80
+ };
81
+ });
82
+ let runResult;
83
+ try {
84
+ runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
85
+ } finally {
63
86
  try {
64
- const rawResult = await ctx.task(preparedTask.name, directTaskToStep(preparedTask));
65
- const { result, artifact } = await writeDirectOutput(preparedTask, rawResult);
66
- const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
67
- return {
68
- results: [result],
69
- text: result.text,
70
- artifacts: [
71
- ...worktreeDiffs.artifacts,
72
- ...(artifact === undefined ? [] : [artifact]),
73
- ],
74
- ...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
75
- };
87
+ gitWorktreeSetupCache.dispose();
76
88
  } finally {
77
89
  cleanupPreparedWorktrees(prepared);
78
90
  }
79
- });
80
- const runResult = await run(direct, {}, { ...runOptions, runId });
91
+ }
81
92
  const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
82
93
  return workflowDetailsFromRun("single", runResult, results, options, validationWarnings);
83
94
  }
@@ -96,35 +107,44 @@ export async function runParallel(
96
107
  } catch (err) {
97
108
  return failedDirectDetails("parallel", runId, expanded.length, err, options);
98
109
  }
99
- const prepared = prepareDirectWorktrees(expanded, options, runId, "parallel");
110
+ const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
111
+ const prepared = prepareDirectWorktrees(expanded, options, runId, "parallel", workflowInvocationCwd);
112
+ const gitWorktreeSetupCache = createGitWorktreeSetupCache();
100
113
  const direct = defineDirectWorkflow("direct-parallel", async (ctx) => {
114
+ const steps = prepared.tasks.map((task) => directTaskToStep(task));
115
+ const rawResults = await ctx.parallel(steps, {
116
+ task: options.task,
117
+ concurrency: options.concurrency,
118
+ failFast: options.failFast,
119
+ });
120
+ const persisted = await Promise.all(
121
+ rawResults.map((result, index) => writeDirectOutput(
122
+ prepared.tasks[index]!, result, workflowInvocationCwd, prepared.outputIsolations?.[index], gitWorktreeSetupCache,
123
+ )),
124
+ );
125
+ const results = persisted.map((item) => item.result);
126
+ const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
127
+ const artifacts = [
128
+ ...worktreeDiffs.artifacts,
129
+ ...persisted.flatMap((item) => item.artifact === undefined ? [] : [item.artifact]),
130
+ ];
131
+ return {
132
+ results,
133
+ count: results.length,
134
+ artifacts,
135
+ ...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
136
+ };
137
+ });
138
+ let runResult;
139
+ try {
140
+ runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
141
+ } finally {
101
142
  try {
102
- const steps = prepared.tasks.map((task) => directTaskToStep(task));
103
- const rawResults = await ctx.parallel(steps, {
104
- task: options.task,
105
- concurrency: options.concurrency,
106
- failFast: options.failFast,
107
- });
108
- const persisted = await Promise.all(
109
- rawResults.map((result, index) => writeDirectOutput(prepared.tasks[index]!, result)),
110
- );
111
- const results = persisted.map((item) => item.result);
112
- const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
113
- const artifacts = [
114
- ...worktreeDiffs.artifacts,
115
- ...persisted.flatMap((item) => item.artifact === undefined ? [] : [item.artifact]),
116
- ];
117
- return {
118
- results,
119
- count: results.length,
120
- artifacts,
121
- ...(worktreeDiffs.summary === undefined ? {} : { worktreeSummary: worktreeDiffs.summary }),
122
- };
143
+ gitWorktreeSetupCache.dispose();
123
144
  } finally {
124
145
  cleanupPreparedWorktrees(prepared);
125
146
  }
126
- });
127
- const runResult = await run(direct, {}, { ...runOptions, runId });
147
+ }
128
148
  const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
129
149
  return workflowDetailsFromRun("parallel", runResult, results, options, validationWarnings);
130
150
  }
@@ -137,6 +157,8 @@ async function runDirectChainStep(
137
157
  prior: WorkflowTaskResult | readonly WorkflowTaskResult[] | undefined,
138
158
  options: WorkflowDirectOptions,
139
159
  runId: string,
160
+ workflowInvocationCwd: string,
161
+ gitWorktreeSetupCache: GitWorktreeSetupCache,
140
162
  ): Promise<{ results: WorkflowTaskResult[]; artifacts: WorkflowArtifact[] }> {
141
163
  if ("parallel" in step) {
142
164
  const stepOptions = {
@@ -146,7 +168,9 @@ async function runDirectChainStep(
146
168
  ...(step.baseBranch !== undefined ? { baseBranch: step.baseBranch } : {}),
147
169
  };
148
170
  const expanded = expandedParallelTasks(step.parallel.map((item) => directTaskWithDefaults(item, stepOptions)));
149
- const prepared = prepareDirectWorktrees(expanded, stepOptions, `${runId}-s${index}`, `step-${index}`);
171
+ const prepared = prepareDirectWorktrees(
172
+ expanded, stepOptions, `${runId}-s${index}`, `step-${index}`, workflowInvocationCwd,
173
+ );
150
174
  try {
151
175
  const steps = prepared.tasks.map((item) =>
152
176
  directTaskToStep(item, directTaskPrompt(item) ?? "{previous}", item.previous ?? prior),
@@ -159,7 +183,10 @@ async function runDirectChainStep(
159
183
  } as WorkflowParallelOptions);
160
184
  const persisted = await Promise.all(
161
185
  rawResults.map((result, taskIndex) =>
162
- writeDirectOutput({ ...prepared.tasks[taskIndex]!, chainDir: options.chainDir }, result),
186
+ writeDirectOutput(
187
+ { ...prepared.tasks[taskIndex]!, chainDir: options.chainDir }, result, workflowInvocationCwd,
188
+ prepared.outputIsolations?.[taskIndex], gitWorktreeSetupCache,
189
+ ),
163
190
  ),
164
191
  );
165
192
  const worktreeDiffs = collectWorktreeDiffs(prepared, stepOptions.artifacts !== false);
@@ -176,7 +203,9 @@ async function runDirectChainStep(
176
203
  }
177
204
 
178
205
  const prompt = directTaskPrompt(step) ?? (index === 0 ? "{task}" : "{previous}");
179
- const prepared = prepareDirectWorktrees([directTaskWithDefaults(step, options)], options, `${runId}-s${index}`, `step-${index}`);
206
+ const prepared = prepareDirectWorktrees(
207
+ [directTaskWithDefaults(step, options)], options, `${runId}-s${index}`, `step-${index}`, workflowInvocationCwd,
208
+ );
180
209
  const preparedStep = prepared.tasks[0]!;
181
210
  try {
182
211
  const rawResult = await ctx.task(
@@ -186,7 +215,10 @@ async function runDirectChainStep(
186
215
  ...(typeof options.chainDir === "string" ? { chainDir: options.chainDir } : {}),
187
216
  } as WorkflowTaskOptions,
188
217
  );
189
- const { result, artifact } = await writeDirectOutput({ ...preparedStep, chainDir: options.chainDir }, rawResult);
218
+ const { result, artifact } = await writeDirectOutput(
219
+ { ...preparedStep, chainDir: options.chainDir }, rawResult, workflowInvocationCwd,
220
+ prepared.outputIsolations?.[0], gitWorktreeSetupCache,
221
+ );
190
222
  const worktreeDiffs = collectWorktreeDiffs(prepared, options.artifacts !== false);
191
223
  return {
192
224
  results: [result],
@@ -215,19 +247,36 @@ export async function runChain(
215
247
  } catch (err) {
216
248
  return failedDirectDetails("chain", runId, chain.length, err, options);
217
249
  }
250
+ const workflowInvocationCwd = runOptions.cwd ?? process.cwd();
251
+ const gitWorktreeSetupCache = createGitWorktreeSetupCache();
218
252
  const direct = defineDirectWorkflow("direct-chain", async (ctx) => {
219
253
  const results: WorkflowTaskResult[] = [];
220
254
  const artifacts: WorkflowArtifact[] = [];
221
255
  let prior: WorkflowTaskResult | readonly WorkflowTaskResult[] | undefined;
222
256
  for (let index = 0; index < chain.length; index += 1) {
223
- const step = await runDirectChainStep(ctx, chain[index]!, index, options.task ?? "", prior, options, runId);
257
+ const step = await runDirectChainStep(
258
+ ctx,
259
+ chain[index]!,
260
+ index,
261
+ options.task ?? "",
262
+ prior,
263
+ options,
264
+ runId,
265
+ workflowInvocationCwd,
266
+ gitWorktreeSetupCache,
267
+ );
224
268
  results.push(...step.results);
225
269
  artifacts.push(...step.artifacts);
226
270
  prior = step.results.length === 1 ? step.results[0] : step.results;
227
271
  }
228
272
  return { results, count: results.length, artifacts };
229
273
  });
230
- const runResult = await run(direct, {}, { ...runOptions, runId });
274
+ let runResult;
275
+ try {
276
+ runResult = await run(direct, {}, { ...runOptions, runId, gitWorktreeSetupCache });
277
+ } finally {
278
+ gitWorktreeSetupCache.dispose();
279
+ }
231
280
  const results = (runResult.result?.["results"] ?? []) as WorkflowTaskResult[];
232
281
  return workflowDetailsFromRun("chain", runResult, results, options, validationWarnings);
233
282
  }
@@ -7,6 +7,7 @@ import { raceAbort } from "./executor-abort.js";
7
7
  import { hasExplicitFastModeCandidate } from "./executor-direct-helpers.js";
8
8
  import { applyFailureToStage } from "./executor-lifecycle.js";
9
9
  import { isTerminalStage } from "./executor-scheduler.js";
10
+ import { rebasedStageStartedAt } from "../../shared/timing.js";
10
11
 
11
12
  export interface TrackedStageCallOptions {
12
13
  readonly eagerSession?: boolean;
@@ -110,8 +111,9 @@ export function createTrackedStageCaller(input: {
110
111
  }
111
112
  }
112
113
  if (trackStageLifecycle) {
114
+ const now = Date.now();
113
115
  runtime.stageSnapshot.status = "running";
114
- runtime.stageSnapshot.startedAt = Date.now();
116
+ runtime.stageSnapshot.startedAt ??= rebasedStageStartedAt(input.options?.durableAccumulatedDurationMs, now);
115
117
  const hasNoExplicitModelConfig = input.options?.model === undefined && input.options?.fallbackModels === undefined;
116
118
  const promptAdapterHandlesInitialPrompt = input.adapters.prompt !== undefined;
117
119
  if (callOptions.eagerSession && !promptAdapterHandlesInitialPrompt && (hasNoExplicitModelConfig || await hasExplicitFastModeCandidate({
@@ -69,7 +69,7 @@ export function resolveWorkflowPath(filePath: string, baseDir: string | undefine
69
69
  }
70
70
 
71
71
  export function taskBaseDir(options: Pick<WorkflowTaskExecutionOptions, "chainDir" | "cwd">): string | undefined {
72
- if (typeof options.chainDir === "string" && options.chainDir.length > 0) {
72
+ if (typeof options.chainDir === "string" && options.chainDir.trim().length > 0) {
73
73
  return resolveWorkflowPath(options.chainDir, process.cwd());
74
74
  }
75
75
  if (typeof options.cwd === "string" && options.cwd.length > 0) {
@@ -15,6 +15,7 @@ import type { WorkflowRegistry } from "../../workflows/registry.js";
15
15
  import type { CancellationRegistry } from "../background/cancellation-registry.js";
16
16
  import type { StageAdapters } from "./stage-runner.js";
17
17
  import type { StageControlRegistry } from "./stage-control-registry.js";
18
+ import type { GitWorktreeSetupCache } from "../shared/worktree.js";
18
19
 
19
20
  export interface ResolvedInputs extends WorkflowInputValues {}
20
21
 
@@ -68,6 +69,8 @@ export interface RunOpts extends Omit<AuthoringContract.RunOpts, "adapters" | "s
68
69
  stageControlRegistry?: StageControlRegistry;
69
70
  /** Pre-allocated runId. */
70
71
  runId?: string;
72
+ /** Internal reusable-worktree cache shared with direct output persistence. */
73
+ gitWorktreeSetupCache?: GitWorktreeSetupCache;
71
74
  /** Replay completed stages from a failed source run, then resume at this stage. */
72
75
  continuation?: RunContinuationOpts;
73
76
  /**
@@ -306,7 +306,7 @@ export class StageSessionController {
306
306
  const stageOptions = this.stageOptionsForCandidate(candidate, resumeOptions);
307
307
  const created = this.opts.adapters.agentSession
308
308
  ? await this.opts.adapters.agentSession.create(
309
- stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir) as StageSessionCreateOptions,
309
+ stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta) as StageSessionCreateOptions,
310
310
  { ...this.meta, stageOptions },
311
311
  )
312
312
  : missingAdapter(consumer);
@@ -1,15 +1,38 @@
1
1
  import { SessionManager, type CreateAgentSessionOptions } from "@bastani/atomic";
2
- import type { StageOptions } from "../../shared/types.js";
2
+ import type { StageExecutionMeta, StageOptions } from "../../shared/types.js";
3
3
  import type { AgentSessionConsumer } from "./stage-runner-types.js";
4
4
 
5
+ function workflowSessionOptions(meta: StageExecutionMeta) {
6
+ return {
7
+ internal: true as const,
8
+ workflow: { runId: meta.runId, stageId: meta.stageId, stageName: meta.stageName },
9
+ };
10
+ }
11
+
12
+ function workflowOrchestrationContext(meta: StageExecutionMeta): NonNullable<CreateAgentSessionOptions["orchestrationContext"]> {
13
+ return {
14
+ kind: "workflow-stage",
15
+ workflowRunId: meta.runId,
16
+ workflowStageId: meta.stageId,
17
+ workflowStageName: meta.stageName,
18
+ constraints: { disableWorkflowTool: true, maxSubagentDepth: 5 },
19
+ };
20
+ }
21
+
5
22
  export function stripWorkflowOnlyOptions(
6
23
  options: StageOptions | undefined,
7
- defaultSessionDir?: string,
24
+ defaultSessionDir: string | undefined,
25
+ meta: StageExecutionMeta,
8
26
  ): CreateAgentSessionOptions {
27
+ const classification = workflowSessionOptions(meta);
28
+ const orchestrationContext = workflowOrchestrationContext(meta);
9
29
  if (!options) {
10
30
  return defaultSessionDir === undefined
11
- ? {}
12
- : { sessionManager: SessionManager.create(process.cwd(), defaultSessionDir) };
31
+ ? { orchestrationContext }
32
+ : {
33
+ orchestrationContext,
34
+ sessionManager: SessionManager.create(process.cwd(), defaultSessionDir, classification),
35
+ };
13
36
  }
14
37
  const {
15
38
  schema: _schema,
@@ -20,6 +43,7 @@ export function stripWorkflowOnlyOptions(
20
43
  forkFromSessionFile,
21
44
  resumeFromSessionFile,
22
45
  durableReplayKey: _durableReplayKey,
46
+ durableAccumulatedDurationMs: _durableAccumulatedDurationMs,
23
47
  sessionDir,
24
48
  gitWorktreeDir: _gitWorktreeDir,
25
49
  baseBranch: _baseBranch,
@@ -31,12 +55,17 @@ export function stripWorkflowOnlyOptions(
31
55
  if (resumeFromSessionFile !== undefined) {
32
56
  sessionOptions.sessionManager = SessionManager.open(resumeFromSessionFile, effectiveSessionDir, cwd);
33
57
  } else if (context === "fork" && forkFromSessionFile !== undefined) {
34
- sessionOptions.sessionManager = SessionManager.forkFrom(forkFromSessionFile, cwd, effectiveSessionDir);
58
+ sessionOptions.sessionManager = SessionManager.forkFrom(
59
+ forkFromSessionFile,
60
+ cwd,
61
+ effectiveSessionDir,
62
+ classification,
63
+ );
35
64
  } else if (effectiveSessionDir !== undefined) {
36
- sessionOptions.sessionManager = SessionManager.create(cwd, effectiveSessionDir);
65
+ sessionOptions.sessionManager = SessionManager.create(cwd, effectiveSessionDir, classification);
37
66
  }
38
67
  }
39
- return sessionOptions as CreateAgentSessionOptions;
68
+ return { ...sessionOptions, orchestrationContext } as CreateAgentSessionOptions;
40
69
  }
41
70
 
42
71
  export function missingAdapter(consumer: AgentSessionConsumer): never {
@@ -0,0 +1,25 @@
1
+ import { createGitWorktreeSetupCache, type GitWorktreeSetupCache } from "./worktree-git.js";
2
+
3
+ export interface GitWorktreeSetupCacheOwner {
4
+ readonly cache: GitWorktreeSetupCache;
5
+ release(finalizer: () => void): void;
6
+ }
7
+
8
+ export function createGitWorktreeSetupCacheOwner(
9
+ suppliedCache?: GitWorktreeSetupCache,
10
+ ): GitWorktreeSetupCacheOwner {
11
+ const cache = suppliedCache ?? createGitWorktreeSetupCache();
12
+ const ownsCache = suppliedCache === undefined;
13
+ let released = false;
14
+ return {
15
+ cache,
16
+ release(finalizer) {
17
+ try {
18
+ if (!released && ownsCache) cache.dispose();
19
+ released = true;
20
+ } finally {
21
+ finalizer();
22
+ }
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,103 @@
1
+ import { lstatSync, realpathSync } from "node:fs";
2
+ import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
3
+ import type { GitWorktreeSetupResult } from "./worktree-types.js";
4
+
5
+ function relativePathWithin(root: string, candidate: string): string | undefined {
6
+ const path = relative(root, candidate);
7
+ return path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path) ? undefined : path;
8
+ }
9
+
10
+ function existingRealPathThroughAncestor(path: string, description: string): string {
11
+ let existing = resolve(path);
12
+ const missing: string[] = [];
13
+ while (true) {
14
+ try {
15
+ return resolve(realpathSync.native(existing), ...missing);
16
+ } catch (error) {
17
+ let existingEntry: ReturnType<typeof lstatSync> | undefined;
18
+ try {
19
+ existingEntry = lstatSync(existing);
20
+ } catch {
21
+ // Missing components are resolved through their nearest existing ancestor.
22
+ }
23
+ const code = error && typeof error === "object" && "code" in error
24
+ ? String((error as { readonly code?: unknown }).code)
25
+ : undefined;
26
+ const parent = dirname(existing);
27
+ if (existingEntry?.isSymbolicLink() === true || (code !== "ENOENT" && code !== "ENOTDIR") || parent === existing) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ throw new Error(`atomic-workflows: cannot resolve ${description} ${path}: ${message}`);
30
+ }
31
+ missing.unshift(existing.slice(parent.length + (parent.endsWith(sep) ? 0 : 1)));
32
+ existing = parent;
33
+ }
34
+ }
35
+ }
36
+
37
+ function existingRealPath(path: string, description: string): string {
38
+ try {
39
+ return realpathSync.native(path);
40
+ } catch (error) {
41
+ const message = error instanceof Error ? error.message : String(error);
42
+ throw new Error(`atomic-workflows: cannot resolve ${description} ${path}: ${message}`);
43
+ }
44
+ }
45
+
46
+ export function resolveWorktreeStageCwd(
47
+ cwd: string | undefined,
48
+ setup: GitWorktreeSetupResult,
49
+ ): string | undefined {
50
+ const worktreeRoot = existingRealPath(setup.worktreeRoot, "gitWorktreeDir");
51
+ const repositoryRoot = existingRealPath(setup.repositoryRoot, "invoking checkout");
52
+ if (cwd === undefined || cwd.length === 0) return undefined;
53
+
54
+ const absoluteInput = isAbsolute(cwd);
55
+ const candidate = absoluteInput ? cwd : resolve(setup.cwd, cwd);
56
+ if (!absoluteInput && relativePathWithin(setup.worktreeRoot, candidate) === undefined) {
57
+ throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a cwd inside the worktree.`);
58
+ }
59
+ const candidateRealPath = existingRealPath(candidate, "cwd");
60
+ const worktreeRelative = relativePathWithin(worktreeRoot, candidateRealPath);
61
+ if (worktreeRelative !== undefined) return resolve(setup.worktreeRoot, worktreeRelative);
62
+ if (!isAbsolute(cwd)) {
63
+ throw new Error(`atomic-workflows: relative cwd ${cwd} escapes gitWorktreeDir ${setup.worktreeRoot}; choose a path that remains inside the selected worktree.`);
64
+ }
65
+ if (relativePathWithin(setup.worktreeRoot, candidate) !== undefined) {
66
+ throw new Error(`atomic-workflows: cwd ${cwd} resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or choose a cwd inside the worktree.`);
67
+ }
68
+
69
+ const repositoryRelative = absoluteInput
70
+ ? relativePathWithin(repositoryRoot, candidateRealPath)
71
+ : undefined;
72
+ if (repositoryRelative === undefined) {
73
+ throw new Error(`atomic-workflows: cwd ${cwd} is outside gitWorktreeDir ${setup.worktreeRoot}; use a cwd inside the invoking repository so Atomic can remap it, or omit cwd.`);
74
+ }
75
+ const mappedCwd = resolve(setup.worktreeRoot, repositoryRelative);
76
+ const mappedRealPath = existingRealPath(mappedCwd, "remapped worktree cwd");
77
+ if (relativePathWithin(worktreeRoot, mappedRealPath) === undefined) {
78
+ throw new Error(`atomic-workflows: cwd ${cwd} remaps through a path that resolves outside gitWorktreeDir ${setup.worktreeRoot}; remove the escaping symlink or omit cwd.`);
79
+ }
80
+ return mappedCwd;
81
+ }
82
+
83
+
84
+ export function resolveContainedRelativePath(
85
+ root: string,
86
+ baseDir: string,
87
+ relativePath: string,
88
+ description: string,
89
+ ): string {
90
+ if (isAbsolute(relativePath) || relativePath.split(/[\\/]+/).includes("..")) {
91
+ throw new Error(`atomic-workflows: relative output ${relativePath} escapes ${description} ${root}; use a path without parent traversal.`);
92
+ }
93
+ const candidate = resolve(baseDir, relativePath);
94
+ if (relativePathWithin(resolve(root), candidate) === undefined) {
95
+ throw new Error(`atomic-workflows: relative output ${relativePath} escapes ${description} ${root}.`);
96
+ }
97
+ const realRoot = existingRealPath(root, description);
98
+ const realCandidate = existingRealPathThroughAncestor(candidate, "relative output");
99
+ if (relativePathWithin(realRoot, realCandidate) === undefined) {
100
+ throw new Error(`atomic-workflows: relative output ${relativePath} resolves outside ${description} ${root} through a symlink.`);
101
+ }
102
+ return candidate;
103
+ }
@@ -0,0 +1,57 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ export interface GitWorktreeGenerationAnchor {
5
+ assertCurrent(): void;
6
+ dispose(): void;
7
+ }
8
+
9
+ function sameFileIdentity(left: fs.BigIntStats, right: fs.BigIntStats): boolean {
10
+ return left.dev === right.dev && left.ino === right.ino;
11
+ }
12
+
13
+ function openMainCheckoutAnchor(gitDir: string): GitWorktreeGenerationAnchor {
14
+ let disposed = false;
15
+ return {
16
+ assertCurrent() {
17
+ if (disposed) throw new Error(`cached .git identity anchor is already disposed: ${gitDir}`);
18
+ if (!fs.lstatSync(gitDir).isDirectory()) {
19
+ throw new Error(`cached main-checkout .git directory is no longer current: ${gitDir}`);
20
+ }
21
+ },
22
+ dispose() {
23
+ disposed = true;
24
+ },
25
+ };
26
+ }
27
+
28
+ export function openGitWorktreeGenerationAnchor(worktreeRoot: string): GitWorktreeGenerationAnchor {
29
+ const gitFile = path.join(worktreeRoot, ".git");
30
+ if (fs.lstatSync(gitFile).isDirectory()) return openMainCheckoutAnchor(gitFile);
31
+ const descriptor = fs.openSync(gitFile, "r");
32
+ let disposed = false;
33
+
34
+ const anchor: GitWorktreeGenerationAnchor = {
35
+ assertCurrent() {
36
+ if (disposed) throw new Error(`cached .git identity anchor is already disposed: ${gitFile}`);
37
+ const held = fs.fstatSync(descriptor, { bigint: true });
38
+ const current = fs.lstatSync(gitFile, { bigint: true });
39
+ if (!current.isFile() || !sameFileIdentity(held, current)) {
40
+ throw new Error(`cached .git identity anchor no longer matches the selected checkout: ${gitFile}`);
41
+ }
42
+ },
43
+ dispose() {
44
+ if (disposed) return;
45
+ disposed = true;
46
+ fs.closeSync(descriptor);
47
+ },
48
+ };
49
+
50
+ try {
51
+ anchor.assertCurrent();
52
+ return anchor;
53
+ } catch (error) {
54
+ anchor.dispose();
55
+ throw error;
56
+ }
57
+ }