@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
@@ -0,0 +1,213 @@
1
+ import type { Store } from "../shared/store.js";
2
+ import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
3
+ import { createStageContext, type StageAdapters } from "../runs/foreground/stage-runner.js";
4
+ import {
5
+ stageControlRegistry as defaultStageControlRegistry,
6
+ type AgentSessionEventListener,
7
+ type StageControlHandle,
8
+ type StageControlRegistry,
9
+ } from "../runs/foreground/stage-control-registry.js";
10
+ import type { DurableWorkflowBackend } from "./backend.js";
11
+ import {
12
+ listOpenableCompletedWorkflows,
13
+ resolveCompletedWorkflow,
14
+ } from "./completed-catalog.js";
15
+ import type { ResumableWorkflowEntry } from "./types.js";
16
+
17
+ export type OpenCompletedDurableResult =
18
+ | { readonly ok: true; readonly runId: string; readonly workflowId: string; readonly name: string; readonly message: string }
19
+ | { readonly ok: false; readonly reason: "not_found" | "ambiguous" | "stale" | "active"; readonly message: string };
20
+
21
+ export interface OpenCompletedDurableDeps {
22
+ readonly durableBackend: DurableWorkflowBackend;
23
+ readonly store: Store;
24
+ readonly adapters?: StageAdapters;
25
+ readonly stageControlRegistry?: StageControlRegistry;
26
+ readonly cwd?: string;
27
+ readonly defaultSessionDir?: string;
28
+ }
29
+
30
+ interface CompletedChatRegistration {
31
+ readonly handle: StageControlHandle;
32
+ readonly unregister: () => void;
33
+ }
34
+
35
+ const completedChatRegistrations = new WeakMap<
36
+ StageControlRegistry,
37
+ Map<string, CompletedChatRegistration>
38
+ >();
39
+
40
+ /**
41
+ * Open a completed durable workflow as an immutable run snapshot. The only
42
+ * mutable surface is a lazily reopened stage chat, which appends follow-up
43
+ * conversation to its retained Atomic session without dispatching the workflow.
44
+ */
45
+ export function openCompletedDurableWorkflow(
46
+ workflowIdOrPrefix: string,
47
+ deps: OpenCompletedDurableDeps,
48
+ catalog: readonly ResumableWorkflowEntry[] = listOpenableCompletedWorkflows(deps.durableBackend),
49
+ ): OpenCompletedDurableResult {
50
+ const resolved = resolveCompletedWorkflow(workflowIdOrPrefix, deps.durableBackend, catalog);
51
+ if (resolved.kind === "not_found") {
52
+ return failure("not_found", `No completed durable workflow found for id/prefix: ${workflowIdOrPrefix}`);
53
+ }
54
+ if (resolved.kind === "ambiguous") {
55
+ const matches = resolved.matches.map((entry) => `${entry.name} (${entry.workflowId.slice(0, 8)})`).join(", ");
56
+ return failure("ambiguous", `Ambiguous completed workflow prefix "${workflowIdOrPrefix}" matches: ${matches}`);
57
+ }
58
+ if (resolved.kind === "stale") {
59
+ return failure(
60
+ "stale",
61
+ `Completed workflow ${resolved.entry.workflowId.slice(0, 8)} is stale or missing durable checkpoint/session data and cannot be opened.`,
62
+ );
63
+ }
64
+
65
+ const existing = deps.store.runs().find((run) => run.id === resolved.snapshot.id);
66
+ if (existing !== undefined && existing.status !== "completed") {
67
+ return failure(
68
+ "active",
69
+ `Workflow ${resolved.snapshot.id.slice(0, 8)} is already active in this session; attach with /workflow connect ${resolved.snapshot.id.slice(0, 8)} instead.`,
70
+ );
71
+ }
72
+ const snapshot = resolved.snapshot;
73
+ if (existing !== undefined) deps.store.removeRun(existing.id);
74
+ deps.store.recordRunStart(snapshot);
75
+ registerCompletedChatHandles(snapshot, deps);
76
+ return {
77
+ ok: true,
78
+ runId: snapshot.id,
79
+ workflowId: snapshot.id,
80
+ name: snapshot.name,
81
+ message: `Opened completed durable workflow "${snapshot.name}" (${snapshot.id.slice(0, 8)}) for read-only inspection and follow-up chat.`,
82
+ };
83
+ }
84
+
85
+ function failure(
86
+ reason: "not_found" | "ambiguous" | "stale" | "active",
87
+ message: string,
88
+ ): OpenCompletedDurableResult {
89
+ return { ok: false, reason, message };
90
+ }
91
+
92
+ function registerCompletedChatHandles(
93
+ snapshot: RunSnapshot,
94
+ deps: OpenCompletedDurableDeps,
95
+ ): void {
96
+ if (deps.adapters?.agentSession === undefined) return;
97
+ const registry = deps.stageControlRegistry ?? defaultStageControlRegistry;
98
+ const registrations = completedChatRegistrations.get(registry) ?? new Map();
99
+ completedChatRegistrations.set(registry, registrations);
100
+ const desiredKeys = new Set(
101
+ snapshot.stages
102
+ .filter((stage) => stage.sessionFile !== undefined)
103
+ .map((stage) => completedChatKey(snapshot.id, stage.id)),
104
+ );
105
+ for (const [key, registration] of registrations) {
106
+ if (!key.startsWith(`${snapshot.id}:`) || desiredKeys.has(key)) continue;
107
+ removeCompletedChatRegistration(registrations, key, registration);
108
+ }
109
+ for (const stage of snapshot.stages) {
110
+ if (stage.sessionFile === undefined) continue;
111
+ const key = completedChatKey(snapshot.id, stage.id);
112
+ const registration = registrations.get(key);
113
+ const existing = registry.get(snapshot.id, stage.id);
114
+ if (existing?.sessionFile === stage.sessionFile && !existing.isDisposed) continue;
115
+ if (registration !== undefined) {
116
+ removeCompletedChatRegistration(registrations, key, registration);
117
+ } else if (existing !== undefined) {
118
+ disposeCompletedChatHandle(existing);
119
+ }
120
+ const handle = createCompletedChatHandle(snapshot, stage, stage.sessionFile, deps.adapters, deps.cwd, deps.defaultSessionDir);
121
+ const unregister = registry.register(handle);
122
+ registrations.set(key, { handle, unregister });
123
+ registry.detachControl(snapshot.id, stage.id, handle);
124
+ }
125
+ }
126
+
127
+ function completedChatKey(runId: string, stageId: string): string {
128
+ return `${runId}:${stageId}`;
129
+ }
130
+
131
+ function removeCompletedChatRegistration(
132
+ registrations: Map<string, CompletedChatRegistration>,
133
+ key: string,
134
+ registration: CompletedChatRegistration,
135
+ ): void {
136
+ registration.unregister();
137
+ registrations.delete(key);
138
+ disposeCompletedChatHandle(registration.handle);
139
+ }
140
+
141
+ function disposeCompletedChatHandle(handle: StageControlHandle): void {
142
+ void Promise.resolve(handle.dispose?.()).catch((error: Error) => {
143
+ console.warn("atomic-workflows: completed chat handle dispose failed", error);
144
+ });
145
+ }
146
+
147
+ function createCompletedChatHandle(
148
+ run: RunSnapshot,
149
+ stage: StageSnapshot,
150
+ sessionFile: string,
151
+ adapters: StageAdapters,
152
+ cwd: string | undefined,
153
+ defaultSessionDir: string | undefined,
154
+ ): StageControlHandle {
155
+ const context = createStageContext({
156
+ runId: run.id,
157
+ stageId: stage.id,
158
+ stageName: stage.name,
159
+ adapters,
160
+ stageOptions: {
161
+ resumeFromSessionFile: sessionFile,
162
+ ...(cwd !== undefined ? { cwd } : {}),
163
+ },
164
+ ...(defaultSessionDir !== undefined ? { defaultSessionDir } : {}),
165
+ });
166
+ let disposed = false;
167
+ const ensureAttached = async (): Promise<void> => {
168
+ if (disposed) throw new Error(`Completed stage chat "${stage.name}" is closed.`);
169
+ if (context.__sessionMeta().sessionFile === undefined) {
170
+ await context.__ensureSessionFromFile(sessionFile);
171
+ }
172
+ };
173
+ return {
174
+ runId: run.id,
175
+ stageId: stage.id,
176
+ stageName: stage.name,
177
+ status: "completed",
178
+ get sessionId() { return context.__sessionMeta().sessionId ?? stage.sessionId; },
179
+ get sessionFile() { return context.__sessionMeta().sessionFile ?? sessionFile; },
180
+ get isStreaming() { return context.isStreaming; },
181
+ get isDisposed() { return disposed; },
182
+ get messages() { return context.messages; },
183
+ get agentSession() { return context.__agentSession(); },
184
+ async ensureAttached() { await ensureAttached(); },
185
+ async prompt(text: string) {
186
+ await ensureAttached();
187
+ await context.prompt(text);
188
+ },
189
+ async steer(text: string) {
190
+ await ensureAttached();
191
+ await context.steer(text);
192
+ },
193
+ async followUp(text: string) {
194
+ await ensureAttached();
195
+ await context.followUp(text);
196
+ },
197
+ async pause() {
198
+ throw new Error("Completed workflow snapshots cannot be paused or resumed.");
199
+ },
200
+ async resume(message?: string) {
201
+ if (message !== undefined && message.trim().length > 0) {
202
+ await ensureAttached();
203
+ await context.prompt(message);
204
+ }
205
+ },
206
+ subscribe(listener: AgentSessionEventListener) { return context.subscribe(listener); },
207
+ async dispose() {
208
+ if (disposed) return;
209
+ disposed = true;
210
+ await context.__dispose();
211
+ },
212
+ };
213
+ }
@@ -1,10 +1,12 @@
1
1
  /** DBOS-backed durable backend adapter, loaded only when configured. */
2
2
 
3
- import type { DurableCheckpoint, DurableCheckpointEntry, DurableWorkflowHandle, DurableWorkflowStatus, ResumableWorkflowEntry } from "./types.js";
3
+ import type { DurableCheckpoint, DurableWorkflowHandle, DurableWorkflowStatus, ResumableWorkflowEntry } from "./types.js";
4
4
  import type { WorkflowSerializableValue } from "../shared/types.js";
5
5
  import type { WorkflowSerializableObject as DurableInputs } from "./types.js";
6
6
  import { InMemoryDurableBackend, type DurableWorkflowBackend, type WorkflowRegistrationInput } from "./backend.js";
7
- import { encodeCheckpoint, decodeToCheckpoint } from "./dbos-envelope.js";
7
+ import { encodeCheckpoint, classifyCheckpointPayload } from "./dbos-envelope.js";
8
+ import { classifyLatestMetadata, encodeMetadata, isMetadataStep, metadataStepName } from "./dbos-metadata.js";
9
+ import { DBOS_DELETION_STEP, classifyDbosDeletionTombstone, encodeDbosDeletionTombstone } from "./dbos-tombstone.js";
8
10
 
9
11
  // ---------------------------------------------------------------------------
10
12
  // SDK abstraction
@@ -28,6 +30,8 @@ export interface DbosSdkHandle {
28
30
  readonly listStepRecords: (workflowId: string) => Promise<readonly DbosStepRecord[]>;
29
31
  /** Record a checkpoint step output (envelope) to DBOS. */
30
32
  readonly recordStepOutput: (workflowId: string, stepName: string, output: WorkflowSerializableValue) => Promise<void>;
33
+ /** Permanently delete a root workflow and all prefix checkpoint records. */
34
+ readonly deleteWorkflowData: (workflowId: string) => Promise<void>;
31
35
  }
32
36
 
33
37
  export interface DbosWorkflowInfo {
@@ -81,6 +85,7 @@ interface DbosStatic {
81
85
  resumeWorkflow(workflowId: string): Promise<DbosWorkflowHandle>;
82
86
  cancelWorkflow(workflowId: string, options?: { readonly cancelChildren?: boolean }): Promise<void>;
83
87
  listWorkflows(input: Record<string, WorkflowSerializableValue>): Promise<readonly DbosStatus[]>;
88
+ deleteWorkflows(workflowIds: string[], deleteChildren?: boolean): Promise<void>;
84
89
  }
85
90
 
86
91
  export function isDbosConfigured(): boolean {
@@ -158,6 +163,17 @@ function createRealDbosHandle(
158
163
  async recordStepOutput(workflowId, stepName, output) {
159
164
  await dbos.startWorkflow(checkpointWorkflow, { workflowID: checkpointId(workflowId, stepName) })(workflowId, stepName, output);
160
165
  },
166
+ async deleteWorkflowData(workflowId) {
167
+ const prefix = `${workflowId}:checkpoint:`;
168
+ const checkpointIds: string[] = [];
169
+ const pageSize = 1_000;
170
+ for (let offset = 0;; offset += pageSize) {
171
+ const page = await dbos.listWorkflows({ workflow_id_prefix: prefix, limit: pageSize, offset });
172
+ checkpointIds.push(...page.map((status) => status.workflowID ?? status.workflowId ?? "").filter((id) => id.length > 0));
173
+ if (page.length < pageSize) break;
174
+ }
175
+ await dbos.deleteWorkflows([...new Set([workflowId, ...checkpointIds])], true);
176
+ },
161
177
  };
162
178
  }
163
179
 
@@ -202,6 +218,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
202
218
  private readonly mem = new InMemoryDurableBackend();
203
219
  private readonly sdk: DbosSdkHandle;
204
220
  private readonly hydrated = new Set<string>();
221
+ private readonly incompatible = new Set<string>();
222
+ private readonly compatible = new Set<string>();
223
+ private readonly locallyRegistered = new Set<string>();
205
224
  private writeQueue: Promise<void> = Promise.resolve();
206
225
  private writeErrors: Error[] = [];
207
226
 
@@ -210,6 +229,9 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
210
229
  }
211
230
 
212
231
  registerWorkflow(handle: WorkflowRegistrationInput): void {
232
+ this.incompatible.delete(handle.workflowId);
233
+ this.compatible.add(handle.workflowId);
234
+ this.locallyRegistered.add(handle.workflowId);
213
235
  this.mem.registerWorkflow(handle);
214
236
  this.enqueueWrite(async () => {
215
237
  await this.sdk.startWorkflow(handle.workflowId, handle.name, handle.inputs);
@@ -218,12 +240,15 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
218
240
  }
219
241
 
220
242
  recordCheckpoint(checkpoint: DurableCheckpoint): void {
243
+ if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
221
244
  this.mem.recordCheckpoint(checkpoint);
222
245
  this.enqueueWrite(() => this.persistCheckpoint(checkpoint));
223
246
  }
224
247
 
225
248
  async recordCheckpointAsync(checkpoint: DurableCheckpoint): Promise<void> {
249
+ if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
226
250
  await this.enqueueWrite(async () => {
251
+ if (!this.isWorkflowLoadable(checkpoint.workflowId)) return;
227
252
  await this.persistCheckpointRecord(checkpoint);
228
253
  this.mem.recordCheckpoint(checkpoint);
229
254
  await this.writeMetadata(checkpoint.workflowId);
@@ -247,17 +272,48 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
247
272
  getWorkflow(workflowId: string): DurableWorkflowHandle | undefined { return this.mem.getWorkflow(workflowId); }
248
273
 
249
274
  setWorkflowStatus(workflowId: string, status: DurableWorkflowStatus, pendingPrompts?: number, resumable?: boolean): void {
275
+ if (!this.isWorkflowLoadable(workflowId)) return;
250
276
  this.mem.setWorkflowStatus(workflowId, status, pendingPrompts, resumable);
251
277
  this.enqueueWrite(async () => {
278
+ if (!this.isWorkflowLoadable(workflowId)) return;
252
279
  if (status === "cancelled") await this.sdk.cancelWorkflow(workflowId);
253
280
  else if (status === "running") await this.sdk.resumeWorkflow(workflowId);
254
281
  await this.writeMetadata(workflowId);
255
282
  });
256
283
  }
257
284
 
258
- listResumableWorkflows(): readonly ResumableWorkflowEntry[] { return this.mem.listResumableWorkflows(); }
259
- toCacheEntry(workflowId: string) { return this.mem.toCacheEntry(workflowId); }
260
- reset(): void { this.mem.reset(); this.hydrated.clear(); this.writeQueue = Promise.resolve(); this.writeErrors = []; }
285
+ listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
286
+ return this.mem.listResumableWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
287
+ }
288
+ listCompletedWorkflows(): readonly ResumableWorkflowEntry[] {
289
+ return this.mem.listCompletedWorkflows().filter((entry) => !this.incompatible.has(entry.workflowId));
290
+ }
291
+ toCacheEntry(workflowId: string) { return this.incompatible.has(workflowId) ? undefined : this.mem.toCacheEntry(workflowId); }
292
+ async deleteWorkflow(workflowId: string): Promise<void> {
293
+ this.incompatible.add(workflowId);
294
+ this.compatible.delete(workflowId);
295
+ this.locallyRegistered.delete(workflowId);
296
+ this.hydrated.delete(workflowId);
297
+ await this.mem.deleteWorkflow(workflowId);
298
+ await this.enqueueWrite(async () => {
299
+ await this.sdk.deleteWorkflowData(workflowId);
300
+ await this.sdk.recordStepOutput(workflowId, DBOS_DELETION_STEP, encodeDbosDeletionTombstone(workflowId));
301
+ });
302
+ }
303
+ isWorkflowLoadable(workflowId: string): boolean {
304
+ return !this.incompatible.has(workflowId)
305
+ && (this.locallyRegistered.has(workflowId) || this.compatible.has(workflowId));
306
+ }
307
+ reset(): void {
308
+ this.mem.reset();
309
+ this.hydrated.clear();
310
+ this.incompatible.clear();
311
+ this.compatible.clear();
312
+ this.locallyRegistered.clear();
313
+ this.writeQueue = Promise.resolve();
314
+ this.writeErrors = [];
315
+ }
316
+
261
317
  async flush(): Promise<void> {
262
318
  await this.writeQueue;
263
319
  if (this.writeErrors.length === 0) return;
@@ -266,63 +322,76 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
266
322
  throw first;
267
323
  }
268
324
 
269
- /**
270
- * Hydrate a single workflow's handle and checkpoints from DBOS into the
271
- * in-memory mirror. Idempotent: skips workflows already hydrated with
272
- * checkpoints. Safe to call before synchronous replay reads.
273
- */
274
325
  async hydrateWorkflow(workflowId: string): Promise<void> {
275
- if (this.hydrated.has(workflowId) && this.mem.getWorkflow(workflowId) !== undefined) return;
326
+ if (this.locallyRegistered.has(workflowId)) return;
276
327
  const info = await this.sdk.retrieveWorkflow(workflowId);
277
- if (info !== undefined && this.mem.getWorkflow(workflowId) === undefined) {
278
- this.mem.registerWorkflow({
279
- workflowId: info.workflowId,
280
- name: info.name,
281
- inputs: info.inputs ?? {},
282
- createdAt: info.createdAt,
283
- status: dbosStatusToDurable(info.status),
284
- });
328
+ if (info !== undefined) {
329
+ await this.hydrateInfo(info);
330
+ return;
285
331
  }
286
- const stepRecords = await this.sdk.listStepRecords(workflowId);
287
- this.applyMetadata(workflowId, stepRecords);
288
- for (const rec of stepRecords) {
289
- if (isMetadataStep(rec.stepName)) continue;
290
- const cp = decodeToCheckpoint(workflowId, rec.stepName, rec.output);
291
- if (cp !== undefined) this.mem.recordCheckpoint(cp);
292
- }
293
- this.hydrated.add(workflowId);
332
+ const records = await this.sdk.listStepRecords(workflowId);
333
+ const deletion = classifyDbosDeletionTombstone(records, workflowId);
334
+ if (deletion !== "absent") await this.suppressWorkflow(workflowId);
294
335
  }
295
336
 
296
- /**
297
- * Hydrate all resumable workflows from DBOS into the in-memory mirror.
298
- * Called by the resume/list path before enumerating resumable entries so
299
- * a fresh process discovers workflows persisted by a prior session.
300
- */
301
337
  async hydrateResumableWorkflows(): Promise<void> {
302
338
  const all = await this.sdk.listAllWorkflows();
303
339
  for (const info of all) {
304
- if (this.mem.getWorkflow(info.workflowId) === undefined) {
305
- this.mem.registerWorkflow({
306
- workflowId: info.workflowId,
307
- name: info.name,
308
- inputs: info.inputs ?? {},
309
- createdAt: info.createdAt,
310
- status: dbosStatusToDurable(info.status),
311
- });
340
+ if (this.locallyRegistered.has(info.workflowId)) continue;
341
+ await this.hydrateInfo(info);
342
+ }
343
+ }
344
+
345
+ private async hydrateInfo(info: DbosWorkflowInfo): Promise<void> {
346
+ const records = await this.sdk.listStepRecords(info.workflowId);
347
+ const metadata = classifyLatestMetadata(records, info.workflowId);
348
+ if (metadata.kind === "legacy") {
349
+ await this.cleanupLegacyWorkflow(info.workflowId);
350
+ return;
351
+ }
352
+ if (metadata.kind !== "current") {
353
+ await this.suppressWorkflow(info.workflowId);
354
+ return;
355
+ }
356
+ const checkpoints: DurableCheckpoint[] = [];
357
+ for (const record of records) {
358
+ if (isMetadataStep(record.stepName) || record.stepName === DBOS_DELETION_STEP) continue;
359
+ const classified = classifyCheckpointPayload(info.workflowId, record.stepName, record.output);
360
+ if (classified.kind === "legacy") {
361
+ await this.cleanupLegacyWorkflow(info.workflowId);
362
+ return;
312
363
  }
313
- if (!this.hydrated.has(info.workflowId)) {
314
- const stepRecords = await this.sdk.listStepRecords(info.workflowId);
315
- this.applyMetadata(info.workflowId, stepRecords);
316
- for (const rec of stepRecords) {
317
- if (isMetadataStep(rec.stepName)) continue;
318
- const cp = decodeToCheckpoint(info.workflowId, rec.stepName, rec.output);
319
- if (cp !== undefined) this.mem.recordCheckpoint(cp);
320
- }
321
- this.hydrated.add(info.workflowId);
364
+ if (classified.kind === "unknown") {
365
+ await this.suppressWorkflow(info.workflowId);
366
+ return;
322
367
  }
368
+ checkpoints.push(classified.checkpoint);
369
+ }
370
+ await this.mem.deleteWorkflow(info.workflowId);
371
+ this.incompatible.delete(info.workflowId);
372
+ this.compatible.add(info.workflowId);
373
+ this.applyMetadata(info.workflowId, metadata.entry);
374
+ checkpoints.forEach((checkpoint) => this.mem.recordCheckpoint(checkpoint));
375
+ this.hydrated.add(info.workflowId);
376
+ }
377
+
378
+ private async cleanupLegacyWorkflow(workflowId: string): Promise<void> {
379
+ try {
380
+ await this.deleteWorkflow(workflowId);
381
+ } catch {
382
+ // deleteWorkflow marks the in-memory mirror incompatible before durable
383
+ // cleanup. Its write queue records/logs the error, while hydration must
384
+ // still return a filtered catalog and allow later discovery to retry.
323
385
  }
324
386
  }
325
387
 
388
+ private async suppressWorkflow(workflowId: string): Promise<void> {
389
+ this.incompatible.add(workflowId);
390
+ this.compatible.delete(workflowId);
391
+ this.hydrated.delete(workflowId);
392
+ await this.mem.deleteWorkflow(workflowId);
393
+ }
394
+
326
395
  private enqueueWrite(fn: () => Promise<void>): Promise<void> {
327
396
  const next = this.writeQueue.then(fn, fn);
328
397
  this.writeQueue = next.catch((err) => {
@@ -339,14 +408,7 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
339
408
  await this.sdk.recordStepOutput(workflowId, metadataStepName(entry.ts), encodeMetadata(entry));
340
409
  }
341
410
 
342
- private applyMetadata(workflowId: string, records: readonly DbosStepRecord[]): void {
343
- const entries = records
344
- .filter((r) => isMetadataStep(r.stepName))
345
- .map((r) => decodeMetadata(r.output))
346
- .filter((entry): entry is DurableCheckpointEntry => entry !== undefined)
347
- .sort((a, b) => a.ts - b.ts);
348
- const entry = entries.at(-1);
349
- if (entry === undefined) return;
411
+ private applyMetadata(workflowId: string, entry: import("./types.js").DurableCheckpointEntry): void {
350
412
  this.mem.registerWorkflow({
351
413
  workflowId,
352
414
  name: entry.name,
@@ -367,116 +429,4 @@ export class DbosDurableBackend implements DurableWorkflowBackend {
367
429
  }
368
430
  }
369
431
 
370
- const METADATA_STEP_PREFIX = "__atomic_metadata";
371
- const METADATA_VERSION = 1;
372
-
373
- function metadataStepName(ts: number): string {
374
- return `${METADATA_STEP_PREFIX}:${ts}:${crypto.randomUUID()}`;
375
- }
376
-
377
- function isMetadataStep(stepName: string): boolean {
378
- return stepName === METADATA_STEP_PREFIX || stepName.startsWith(`${METADATA_STEP_PREFIX}:`);
379
- }
380
-
381
- interface DbosMetadataEnvelope {
382
- readonly __atomicDurableMetadata: true;
383
- readonly version: 1;
384
- readonly entry: WorkflowSerializableValue;
385
- }
386
-
387
- function encodeMetadata(entry: DurableCheckpointEntry): WorkflowSerializableValue {
388
- return {
389
- __atomicDurableMetadata: true,
390
- version: METADATA_VERSION,
391
- entry: {
392
- type: entry.type,
393
- workflowId: entry.workflowId,
394
- name: entry.name,
395
- inputs: entry.inputs,
396
- status: entry.status,
397
- completedCheckpoints: entry.completedCheckpoints,
398
- pendingPrompts: entry.pendingPrompts,
399
- ...(entry.label !== undefined ? { label: entry.label } : {}),
400
- ...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
401
- ...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
402
- ...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
403
- ...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
404
- ...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
405
- ...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
406
- ts: entry.ts,
407
- },
408
- };
409
- }
410
-
411
- function decodeMetadata(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
412
- if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
413
- const raw = value as Partial<DbosMetadataEnvelope>;
414
- if (raw.__atomicDurableMetadata !== true || raw.version !== METADATA_VERSION) return undefined;
415
- const entry = raw.entry;
416
- if (entry === undefined) return undefined;
417
- return parseDurableCheckpointEntry(entry);
418
- }
419
-
420
- function parseDurableCheckpointEntry(value: WorkflowSerializableValue): DurableCheckpointEntry | undefined {
421
- if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined;
422
- const entry = value as Partial<DurableCheckpointEntry>;
423
- if (entry.type !== "workflow.durable.checkpoint"
424
- || typeof entry.workflowId !== "string"
425
- || typeof entry.name !== "string"
426
- || typeof entry.inputs !== "object"
427
- || entry.inputs === null
428
- || Array.isArray(entry.inputs)
429
- || typeof entry.status !== "string"
430
- || !isDurableWorkflowStatus(entry.status)
431
- || typeof entry.completedCheckpoints !== "number"
432
- || typeof entry.pendingPrompts !== "number"
433
- || typeof entry.ts !== "number"
434
- || (entry.label !== undefined && typeof entry.label !== "string")
435
- || (entry.rootWorkflowId !== undefined && typeof entry.rootWorkflowId !== "string")
436
- || (entry.resumable !== undefined && typeof entry.resumable !== "boolean")
437
- || (entry.invocationCwd !== undefined && typeof entry.invocationCwd !== "string")
438
- || (entry.workflowCwd !== undefined && typeof entry.workflowCwd !== "string")
439
- || (entry.repositoryRoot !== undefined && typeof entry.repositoryRoot !== "string")
440
- || (entry.gitWorktreeRoot !== undefined && typeof entry.gitWorktreeRoot !== "string")) {
441
- return undefined;
442
- }
443
- return {
444
- type: "workflow.durable.checkpoint",
445
- workflowId: entry.workflowId,
446
- name: entry.name,
447
- inputs: entry.inputs,
448
- status: entry.status,
449
- completedCheckpoints: entry.completedCheckpoints,
450
- pendingPrompts: entry.pendingPrompts,
451
- ts: entry.ts,
452
- ...(entry.label !== undefined ? { label: entry.label } : {}),
453
- ...(entry.rootWorkflowId !== undefined ? { rootWorkflowId: entry.rootWorkflowId } : {}),
454
- ...(entry.resumable !== undefined ? { resumable: entry.resumable } : {}),
455
- ...(entry.invocationCwd !== undefined ? { invocationCwd: entry.invocationCwd } : {}),
456
- ...(entry.workflowCwd !== undefined ? { workflowCwd: entry.workflowCwd } : {}),
457
- ...(entry.repositoryRoot !== undefined ? { repositoryRoot: entry.repositoryRoot } : {}),
458
- ...(entry.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: entry.gitWorktreeRoot } : {}),
459
- };
460
- }
461
-
462
- function isDurableWorkflowStatus(value: string): value is DurableWorkflowStatus {
463
- return value === "running"
464
- || value === "paused"
465
- || value === "completed"
466
- || value === "failed"
467
- || value === "cancelled"
468
- || value === "blocked";
469
- }
470
-
471
- function dbosStatusToDurable(status: string): DurableWorkflowStatus {
472
- switch (status) {
473
- case "SUCCESS": return "completed";
474
- case "ERROR": return "failed";
475
- case "CANCELLED": return "cancelled";
476
- case "PENDING":
477
- case "ENQUEUED":
478
- case "DELAYED":
479
- return "running";
480
- default: return "running";
481
- }
482
- }
432
+ // Metadata encoding/classification lives in dbos-metadata.ts to keep this adapter focused.