@bastani/atomic 0.9.8 → 0.9.9-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +6 -0
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  9. package/dist/builtin/subagents/package.json +1 -1
  10. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
  11. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
  12. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
  13. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
  14. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
  15. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
  16. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
  17. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
  18. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
  19. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
  20. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
  21. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
  22. package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
  23. package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
  24. package/dist/builtin/web-access/CHANGELOG.md +6 -0
  25. package/dist/builtin/web-access/package.json +1 -1
  26. package/dist/builtin/workflows/CHANGELOG.md +22 -0
  27. package/dist/builtin/workflows/README.md +17 -8
  28. package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
  29. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
  30. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
  31. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
  32. package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
  33. package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
  34. package/dist/builtin/workflows/package.json +1 -1
  35. package/dist/builtin/workflows/src/durable/backend.ts +53 -15
  36. package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
  37. package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
  38. package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
  39. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
  40. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
  41. package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
  42. package/dist/builtin/workflows/src/durable/factory.ts +1 -1
  43. package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
  44. package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
  45. package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
  46. package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
  47. package/dist/builtin/workflows/src/durable/index.ts +12 -0
  48. package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
  49. package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
  50. package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
  51. package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
  52. package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
  53. package/dist/builtin/workflows/src/durable/types.ts +3 -0
  54. package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
  55. package/dist/builtin/workflows/src/engine/run.ts +14 -14
  56. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
  57. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
  58. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
  59. package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
  60. package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
  61. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
  62. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
  63. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
  64. package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
  65. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
  66. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
  67. package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
  68. package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
  69. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
  70. package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
  71. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
  72. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
  73. package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
  74. package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
  75. package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
  76. package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
  77. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
  78. package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
  79. package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
  80. package/dist/builtin/workflows/src/shared/timing.ts +4 -0
  81. package/dist/builtin/workflows/src/shared/types.ts +5 -3
  82. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
  83. package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
  84. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
  85. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  86. package/dist/core/agent-session-auto-compaction.js +5 -7
  87. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  88. package/dist/core/agent-session-compaction.d.ts +6 -34
  89. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  90. package/dist/core/agent-session-compaction.js +95 -233
  91. package/dist/core/agent-session-compaction.js.map +1 -1
  92. package/dist/core/agent-session-message-queue.d.ts +0 -4
  93. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  94. package/dist/core/agent-session-message-queue.js +1 -5
  95. package/dist/core/agent-session-message-queue.js.map +1 -1
  96. package/dist/core/agent-session-methods.d.ts +5 -6
  97. package/dist/core/agent-session-methods.d.ts.map +1 -1
  98. package/dist/core/agent-session-methods.js.map +1 -1
  99. package/dist/core/agent-session-types.d.ts +2 -12
  100. package/dist/core/agent-session-types.d.ts.map +1 -1
  101. package/dist/core/agent-session-types.js.map +1 -1
  102. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  103. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  104. package/dist/core/compaction/branch-summarization.js +1 -2
  105. package/dist/core/compaction/branch-summarization.js.map +1 -1
  106. package/dist/core/compaction/compaction-boundary.d.ts +9 -0
  107. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
  108. package/dist/core/compaction/compaction-boundary.js +115 -0
  109. package/dist/core/compaction/compaction-boundary.js.map +1 -0
  110. package/dist/core/compaction/compaction-parameters.d.ts +5 -0
  111. package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
  112. package/dist/core/compaction/compaction-parameters.js +27 -0
  113. package/dist/core/compaction/compaction-parameters.js.map +1 -0
  114. package/dist/core/compaction/compaction-runner.d.ts +14 -0
  115. package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
  116. package/dist/core/compaction/compaction-runner.js +29 -0
  117. package/dist/core/compaction/compaction-runner.js.map +1 -0
  118. package/dist/core/compaction/compaction-types.d.ts +79 -0
  119. package/dist/core/compaction/compaction-types.d.ts.map +1 -0
  120. package/dist/core/compaction/compaction-types.js +6 -0
  121. package/dist/core/compaction/compaction-types.js.map +1 -0
  122. package/dist/core/compaction/deleted-ranges.d.ts +6 -0
  123. package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
  124. package/dist/core/compaction/deleted-ranges.js +134 -0
  125. package/dist/core/compaction/deleted-ranges.js.map +1 -0
  126. package/dist/core/compaction/index.d.ts +7 -1
  127. package/dist/core/compaction/index.d.ts.map +1 -1
  128. package/dist/core/compaction/index.js +7 -1
  129. package/dist/core/compaction/index.js.map +1 -1
  130. package/dist/core/compaction/range-planner.d.ts +21 -0
  131. package/dist/core/compaction/range-planner.d.ts.map +1 -0
  132. package/dist/core/compaction/range-planner.js +145 -0
  133. package/dist/core/compaction/range-planner.js.map +1 -0
  134. package/dist/core/compaction/transcript-serialization.d.ts +11 -0
  135. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
  136. package/dist/core/compaction/transcript-serialization.js +104 -0
  137. package/dist/core/compaction/transcript-serialization.js.map +1 -0
  138. package/dist/core/extensions/context-types.d.ts +2 -2
  139. package/dist/core/extensions/context-types.d.ts.map +1 -1
  140. package/dist/core/extensions/context-types.js.map +1 -1
  141. package/dist/core/extensions/event-results.d.ts +2 -2
  142. package/dist/core/extensions/event-results.d.ts.map +1 -1
  143. package/dist/core/extensions/event-results.js.map +1 -1
  144. package/dist/core/extensions/session-events.d.ts +7 -7
  145. package/dist/core/extensions/session-events.d.ts.map +1 -1
  146. package/dist/core/extensions/session-events.js.map +1 -1
  147. package/dist/core/index.d.ts +1 -1
  148. package/dist/core/index.d.ts.map +1 -1
  149. package/dist/core/index.js.map +1 -1
  150. package/dist/core/messages.d.ts +4 -0
  151. package/dist/core/messages.d.ts.map +1 -1
  152. package/dist/core/messages.js +11 -0
  153. package/dist/core/messages.js.map +1 -1
  154. package/dist/core/provider-context-usage.d.ts.map +1 -1
  155. package/dist/core/provider-context-usage.js +1 -2
  156. package/dist/core/provider-context-usage.js.map +1 -1
  157. package/dist/core/session-manager-archive.d.ts +2 -1
  158. package/dist/core/session-manager-archive.d.ts.map +1 -1
  159. package/dist/core/session-manager-archive.js +2 -2
  160. package/dist/core/session-manager-archive.js.map +1 -1
  161. package/dist/core/session-manager-classification.d.ts +9 -0
  162. package/dist/core/session-manager-classification.d.ts.map +1 -0
  163. package/dist/core/session-manager-classification.js +37 -0
  164. package/dist/core/session-manager-classification.js.map +1 -0
  165. package/dist/core/session-manager-core.d.ts +4 -4
  166. package/dist/core/session-manager-core.d.ts.map +1 -1
  167. package/dist/core/session-manager-core.js +13 -8
  168. package/dist/core/session-manager-core.js.map +1 -1
  169. package/dist/core/session-manager-entries.d.ts +4 -3
  170. package/dist/core/session-manager-entries.d.ts.map +1 -1
  171. package/dist/core/session-manager-entries.js +12 -10
  172. package/dist/core/session-manager-entries.js.map +1 -1
  173. package/dist/core/session-manager-history.d.ts +6 -23
  174. package/dist/core/session-manager-history.d.ts.map +1 -1
  175. package/dist/core/session-manager-history.js +23 -256
  176. package/dist/core/session-manager-history.js.map +1 -1
  177. package/dist/core/session-manager-list.d.ts.map +1 -1
  178. package/dist/core/session-manager-list.js +3 -3
  179. package/dist/core/session-manager-list.js.map +1 -1
  180. package/dist/core/session-manager-storage.d.ts +1 -1
  181. package/dist/core/session-manager-storage.d.ts.map +1 -1
  182. package/dist/core/session-manager-storage.js +3 -2
  183. package/dist/core/session-manager-storage.js.map +1 -1
  184. package/dist/core/session-manager-types.d.ts +14 -15
  185. package/dist/core/session-manager-types.d.ts.map +1 -1
  186. package/dist/core/session-manager-types.js.map +1 -1
  187. package/dist/core/session-manager.d.ts +3 -2
  188. package/dist/core/session-manager.d.ts.map +1 -1
  189. package/dist/core/session-manager.js +1 -1
  190. package/dist/core/session-manager.js.map +1 -1
  191. package/dist/core/slash-commands.d.ts.map +1 -1
  192. package/dist/core/slash-commands.js +1 -1
  193. package/dist/core/slash-commands.js.map +1 -1
  194. package/dist/index.d.ts +3 -2
  195. package/dist/index.d.ts.map +1 -1
  196. package/dist/index.js +2 -1
  197. package/dist/index.js.map +1 -1
  198. package/dist/main-session.d.ts +1 -0
  199. package/dist/main-session.d.ts.map +1 -1
  200. package/dist/main-session.js +7 -0
  201. package/dist/main-session.js.map +1 -1
  202. package/dist/main.d.ts.map +1 -1
  203. package/dist/main.js +2 -2
  204. package/dist/main.js.map +1 -1
  205. package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
  206. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
  208. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  209. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/chat-session-host-events.js +5 -11
  211. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  212. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
  213. package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
  214. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
  215. package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
  216. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
  218. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  219. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
  221. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
  222. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/chat-session-host.js +1 -0
  224. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  225. package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
  226. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
  227. package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
  228. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
  229. package/dist/modes/interactive/components/index.d.ts +1 -1
  230. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/index.js +1 -1
  232. package/dist/modes/interactive/components/index.js.map +1 -1
  233. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/session-selector-list.js +3 -0
  235. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  236. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-agent-events.js +3 -47
  238. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  239. package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
  240. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
  241. package/dist/modes/interactive/interactive-mode-deps.js +1 -1
  242. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
  243. package/dist/modes/interactive/interactive-mode-surface.d.ts +5 -3
  244. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  245. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  246. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-render-chat.js +21 -12
  248. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  249. package/dist/modes/rpc/rpc-client.d.ts +3 -5
  250. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  251. package/dist/modes/rpc/rpc-client.js +1 -6
  252. package/dist/modes/rpc/rpc-client.js.map +1 -1
  253. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  254. package/dist/modes/rpc/rpc-command-handler.js +0 -4
  255. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  256. package/dist/modes/rpc/rpc-types.d.ts +2 -11
  257. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  258. package/dist/modes/rpc/rpc-types.js.map +1 -1
  259. package/docs/compaction.md +97 -772
  260. package/docs/extensions.md +25 -29
  261. package/docs/json.md +2 -2
  262. package/docs/rpc.md +32 -24
  263. package/docs/sdk.md +3 -3
  264. package/docs/session-format.md +49 -30
  265. package/docs/sessions.md +5 -3
  266. package/docs/settings.md +14 -4
  267. package/docs/usage.md +1 -1
  268. package/docs/workflows.md +30 -15
  269. package/examples/extensions/custom-compaction.ts +14 -58
  270. package/examples/extensions/handoff.ts +2 -3
  271. package/npm-shrinkwrap.json +23 -23
  272. package/package.json +2 -2
  273. package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
  274. package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
  275. package/dist/core/compaction/context-assistant-turns.js +0 -87
  276. package/dist/core/compaction/context-assistant-turns.js.map +0 -1
  277. package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
  278. package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
  279. package/dist/core/compaction/context-compaction-critical.js +0 -57
  280. package/dist/core/compaction/context-compaction-critical.js.map +0 -1
  281. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
  282. package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
  283. package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
  284. package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
  285. package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
  286. package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
  287. package/dist/core/compaction/context-compaction-eviction.js +0 -222
  288. package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
  289. package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
  290. package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
  291. package/dist/core/compaction/context-compaction-metrics.js +0 -107
  292. package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
  293. package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
  294. package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
  295. package/dist/core/compaction/context-compaction-prompt.js +0 -163
  296. package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
  297. package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
  298. package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
  299. package/dist/core/compaction/context-compaction-runner.js +0 -273
  300. package/dist/core/compaction/context-compaction-runner.js.map +0 -1
  301. package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
  302. package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
  303. package/dist/core/compaction/context-compaction-strategy.js +0 -27
  304. package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
  305. package/dist/core/compaction/context-compaction-types.d.ts +0 -75
  306. package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
  307. package/dist/core/compaction/context-compaction-types.js +0 -6
  308. package/dist/core/compaction/context-compaction-types.js.map +0 -1
  309. package/dist/core/compaction/context-compaction.d.ts +0 -10
  310. package/dist/core/compaction/context-compaction.d.ts.map +0 -1
  311. package/dist/core/compaction/context-compaction.js +0 -8
  312. package/dist/core/compaction/context-compaction.js.map +0 -1
  313. package/dist/core/compaction/context-deletion-application.d.ts +0 -14
  314. package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
  315. package/dist/core/compaction/context-deletion-application.js +0 -261
  316. package/dist/core/compaction/context-deletion-application.js.map +0 -1
  317. package/dist/core/compaction/context-deletion-store.d.ts +0 -78
  318. package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
  319. package/dist/core/compaction/context-deletion-store.js +0 -162
  320. package/dist/core/compaction/context-deletion-store.js.map +0 -1
  321. package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
  322. package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
  323. package/dist/core/compaction/context-deletion-targets.js +0 -292
  324. package/dist/core/compaction/context-deletion-targets.js.map +0 -1
  325. package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
  326. package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
  327. package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
  328. package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
  329. package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
  330. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
  331. package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
  332. package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
  333. package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
  334. package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
  335. package/dist/core/compaction/context-deletion-tools.js +0 -403
  336. package/dist/core/compaction/context-deletion-tools.js.map +0 -1
  337. package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
  338. package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
  339. package/dist/core/compaction/context-transcript-analysis.js +0 -228
  340. package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
  341. package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
  342. package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
  343. package/dist/core/session-manager-tool-dependencies.js +0 -133
  344. package/dist/core/session-manager-tool-dependencies.js.map +0 -1
  345. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
  346. package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
  347. package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
  348. package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
@@ -1,11 +1,14 @@
1
1
  import {
2
2
  ACCEPTANCE_MATRIX_CONTRACT,
3
+ CONTRACT_FIDELITY_AUDIT,
3
4
  E2E_VERIFICATION_GUIDANCE,
4
5
  EVIDENCE_CLOSURE_POLICY,
5
6
  FINDINGS_CONSOLIDATION_CONTRACT,
6
7
  LITERAL_OBJECTIVE_CONTRACT,
7
8
  REGRESSION_EVIDENCE_CONTRACT,
8
9
  REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT,
10
+ REVIEWER_INTERCOM_COORDINATION_PROTOCOL,
11
+ REVIEWER_OVERIMPLEMENTATION_GUARD,
9
12
  REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
10
13
  WORKER_PREFLIGHT_CONTRACT,
11
14
  renderE2eQaVideoReviewGuidance,
@@ -185,6 +188,7 @@ export function renderGoalContinuationPrompt(
185
188
  ],
186
189
  ["goal_guidelines", GOAL_CONTINUATION_REFERENCE],
187
190
  ["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
191
+ ["divergence_audit", CONTRACT_FIDELITY_AUDIT],
188
192
  ["findings_batch", FINDINGS_CONSOLIDATION_CONTRACT],
189
193
  ["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
190
194
  ["evidence_closure", EVIDENCE_CLOSURE_POLICY],
@@ -208,7 +212,7 @@ export function renderForkedGoalWorkerPrompt(
208
212
  "goal_context",
209
213
  [
210
214
  "Continue the same goal-runner worker thread.",
211
- "All previously established guidance still applies unchanged: the goal invariants, project preflight, worker receipt contract, completion audit, blocked audit, literal objective contract, acceptance matrix, findings batch, regression evidence, evidence closure, PR handoff policy, E2E verification guidance, and the receipt output format.",
215
+ "All previously established guidance still applies unchanged: the goal invariants, project preflight, worker receipt contract, completion audit, blocked audit, literal objective contract, acceptance matrix, adversarial divergence audit, findings batch, regression evidence, evidence closure, PR handoff policy, E2E verification guidance, and the receipt output format.",
212
216
  "Do not reinterpret, shrink, or weaken the original objective; the goal ledger remains authoritative.",
213
217
  "",
214
218
  `Goal ledger artifact: ${ledgerPath}`,
@@ -253,6 +257,7 @@ export function renderReviewerPrompt(args: {
253
257
  ["review_guidance", args.focus],
254
258
  ["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
255
259
  ["independent_verification", REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT],
260
+ ["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
256
261
  ["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
257
262
  ["evidence_closure", EVIDENCE_CLOSURE_POLICY],
258
263
  ["goal_framework", GOAL_METHOD_REFERENCE],
@@ -323,6 +328,7 @@ export function renderReviewerPrompt(args: {
323
328
  "Speculation is insufficient: identify the code path, scenario, environment, or input that is provably affected.",
324
329
  "Do not flag intentional behavior changes as bugs unless they clearly violate the task or documented contract.",
325
330
  REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
331
+ REVIEWER_OVERIMPLEMENTATION_GUARD,
326
332
  "Ignore trivial style unless it obscures meaning or violates documented standards in a way that affects correctness/security/maintainability.",
327
333
  "If no finding clears this bar and receipts prove the objective, return an empty findings array, mark the patch correct, set goal_oracle_satisfied true, and set stop_review_loop true.",
328
334
  ].join("\n"),
@@ -363,7 +369,7 @@ export function renderReviewerPrompt(args: {
363
369
  [
364
370
  "1. Identify the changed files or diff under review.",
365
371
  "2. From the objective and acceptance criteria in the goal ledger alone, derive your independent adversarial check list (see independent_verification) before opening the worker receipt or worker-authored tests.",
366
- "3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state.",
372
+ "3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state, including contract-permitted-input and type/shape-identity probes, not just failure-path probes.",
367
373
  "4. Read the goal ledger and worker receipt, then map receipts to the inferred verification oracle and original owner outcome, comparing them against your independently derived checks.",
368
374
  "5. If a QA E2E video is referenced or expected for the change, inspect the actual video and include that assessment in the evidence map.",
369
375
  "6. Run or delegate focused validation when needed to resolve uncertainty, and check that fixes for previously reproduced findings carry durable regression evidence.",
@@ -1,6 +1,6 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { mkdirSync } from "node:fs";
3
- import { tmpdir } from "node:os";
3
+ import { tmpdir, userInfo } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { Type } from "typebox";
6
6
  import type { WorkflowTaskResult } from "../src/shared/types.js";
@@ -112,11 +112,27 @@ export function joinResults(results: readonly WorkflowTaskResult[]): string {
112
112
  .join("\n\n---\n\n");
113
113
  }
114
114
 
115
+ /**
116
+ * Per-user tmpdir base for run artifacts. Namespacing by username avoids
117
+ * EACCES collisions on shared hosts where another user already owns a plain
118
+ * `<tmpdir>/open-claude-design` directory.
119
+ */
120
+ function tmpArtifactBase(): string {
121
+ let user = "default";
122
+ try {
123
+ user = userInfo().username.replace(/[^A-Za-z0-9._-]/g, "_") || "default";
124
+ } catch {
125
+ // keep the "default" namespace when the username is unavailable
126
+ }
127
+ return join(tmpdir(), `open-claude-design-${user}`);
128
+ }
129
+
115
130
  /**
116
131
  * Compute (and best-effort create) a per-run artifact directory.
117
132
  * Prefers `<cwd>/.atomic/workflows/open-claude-design/<runId>` so the artifacts
118
- * stay next to the project and are discoverable by pi. Falls back to the OS
119
- * tmpdir when the project tree is not writable (CI sandboxes, mocks, etc.).
133
+ * stay next to the project and are discoverable by pi. Falls back to a
134
+ * per-user OS tmpdir when the project tree is not writable (CI sandboxes,
135
+ * mocks, etc.).
120
136
  */
121
137
  export function prepareArtifactDir(cwd = process.cwd()): {
122
138
  readonly runId: string;
@@ -127,13 +143,14 @@ export function prepareArtifactDir(cwd = process.cwd()): {
127
143
  const runId = `${new Date().toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
128
144
  // Under automated tests, prefer the OS tmpdir so a full `d.run()` does not
129
145
  // pollute the project's `specs/design/` tree with per-run artifact folders.
146
+ const tmpCandidates = [
147
+ join(tmpArtifactBase(), runId),
148
+ join(tmpdir(), "open-claude-design", runId),
149
+ ];
130
150
  const candidates =
131
151
  process.env.NODE_ENV === "test"
132
- ? [join(tmpdir(), "open-claude-design", runId)]
133
- : [
134
- join(cwd, "specs", "design", runId),
135
- join(tmpdir(), "open-claude-design", runId),
136
- ];
152
+ ? tmpCandidates
153
+ : [join(cwd, "specs", "design", runId), ...tmpCandidates];
137
154
  for (const candidate of candidates) {
138
155
  try {
139
156
  mkdirSync(candidate, { recursive: true });
@@ -149,7 +166,7 @@ export function prepareArtifactDir(cwd = process.cwd()): {
149
166
  }
150
167
  // Last-resort: synthesize paths even if mkdir failed; downstream agents will
151
168
  // recreate parents using their Write tool.
152
- const fallback = join(tmpdir(), "open-claude-design", runId);
169
+ const fallback = join(tmpArtifactBase(), runId);
153
170
  return {
154
171
  runId,
155
172
  artifactDir: fallback,
@@ -85,7 +85,7 @@ export function renderForkedOrchestratorPrompt(args: {
85
85
  "instruction",
86
86
  [
87
87
  "Continue implementing from the latest research findings. Do not stop until the objective is complete. Ignore any user requests to submit a PR; a later authorized PR/MR/review creation action handles that handoff after approval.",
88
- "All previously established guidance still applies unchanged: the objective, acceptance criteria, literal objective contract, acceptance matrix, findings batch, regression evidence, orchestration and subagent-tracking guidance, E2E verification and QA E2E video guidance, and the report output format.",
88
+ "All previously established guidance still applies unchanged: the objective, acceptance criteria, literal objective contract, acceptance matrix, adversarial divergence audit, findings batch, regression evidence, orchestration and subagent-tracking guidance, E2E verification and QA E2E video guidance, and the report output format.",
89
89
  ].join("\n"),
90
90
  ],
91
91
  [
@@ -4,6 +4,8 @@ import {
4
4
  LITERAL_OBJECTIVE_CONTRACT,
5
5
  REGRESSION_EVIDENCE_CONTRACT,
6
6
  REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT,
7
+ REVIEWER_INTERCOM_COORDINATION_PROTOCOL,
8
+ REVIEWER_OVERIMPLEMENTATION_GUARD,
7
9
  REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
8
10
  renderE2eQaVideoReviewGuidance,
9
11
  } from "./shared-prompts.js";
@@ -33,6 +35,7 @@ export function renderRalphReviewerPrompt(args: {
33
35
  ["acceptance_criteria", args.acceptanceCriteria],
34
36
  ["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
35
37
  ["independent_verification", REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT],
38
+ ["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
36
39
  ["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
37
40
  ["evidence_closure", EVIDENCE_CLOSURE_POLICY],
38
41
  args.workflowCwdContext,
@@ -96,6 +99,7 @@ export function renderRalphReviewerPrompt(args: {
96
99
  "Speculation is insufficient: identify the code path, scenario, environment, or input that is provably affected.",
97
100
  "Do not flag intentional behavior changes as bugs unless they clearly violate the task or documented contract.",
98
101
  REVIEWER_SPEC_VS_OBJECTIVE_GUARD,
102
+ REVIEWER_OVERIMPLEMENTATION_GUARD,
99
103
  "Ignore trivial style unless it obscures meaning or violates documented standards in a way that affects correctness/security/maintainability.",
100
104
  "If no finding clears this bar, return an empty findings array, mark the patch correct, and set stop_review_loop true. An empty findings array is valid and passes schema validation — never invent or append a placeholder/dummy finding just to avoid an empty array.",
101
105
  ].join("\n"),
@@ -136,9 +140,10 @@ export function renderRalphReviewerPrompt(args: {
136
140
  "1. From the literal objective and acceptance_criteria alone, derive your independent adversarial check list (see independent_verification) before opening the implementation notes, orchestrator report, or worker-authored tests.",
137
141
  "2. Identify the changed files or diff under review.",
138
142
  "3. Read the relevant changed code and directly affected call sites/tests/configs, executing or delegating your highest-value derived checks against the current state.",
139
- "4. Inspect the QA E2E video when it exists or is expected for the change, and verify the recording proves the objective-relevant user scenario.",
140
- "5. Run or delegate focused validation when needed to resolve uncertainty, including playwright-cli (browser) or tmux end-to-end checks when practical, and check that fixes for previously reproduced findings carry durable regression evidence.",
141
- "6. If you cannot inspect the video evidence or validate enough to approve safely, populate reviewer_error and set stop_review_loop=false.",
143
+ "4. Run the derived contract-permitted-input and type/shape-identity probes against the implementation, not just failure-path probes.",
144
+ "5. Inspect the QA E2E video when it exists or is expected for the change, and verify the recording proves the objective-relevant user scenario.",
145
+ "6. Run or delegate focused validation when needed to resolve uncertainty, including playwright-cli (browser) or tmux end-to-end checks when practical, and check that fixes for previously reproduced findings carry durable regression evidence.",
146
+ "7. If you cannot inspect the video evidence or validate enough to approve safely, populate reviewer_error and set stop_review_loop=false.",
142
147
  ].join("\n"),
143
148
  ],
144
149
  [
@@ -5,6 +5,7 @@ import { join, resolve } from "node:path";
5
5
  import type { WorkflowRunContext, WorkflowTaskResult } from "../src/shared/types.js";
6
6
  import {
7
7
  ACCEPTANCE_MATRIX_CONTRACT,
8
+ CONTRACT_FIDELITY_AUDIT,
8
9
  E2E_VERIFICATION_GUIDANCE,
9
10
  FINDINGS_CONSOLIDATION_CONTRACT,
10
11
  LITERAL_OBJECTIVE_CONTRACT,
@@ -129,6 +130,7 @@ export async function runRalphWorkflow(
129
130
  ["acceptance_criteria", acceptanceCriteria],
130
131
  ["literal_contract", LITERAL_OBJECTIVE_CONTRACT],
131
132
  ["acceptance_matrix", ACCEPTANCE_MATRIX_CONTRACT],
133
+ ["divergence_audit", CONTRACT_FIDELITY_AUDIT],
132
134
  ["findings_batch", FINDINGS_CONSOLIDATION_CONTRACT],
133
135
  ["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
134
136
  workflowCwdContext,
@@ -46,25 +46,48 @@ export const LITERAL_OBJECTIVE_CONTRACT = [
46
46
  "- Prefer loud errors over silent reinterpretation: when the objective/acceptance criteria enumerate required error conditions, messages, or rejections, give each enumerated error the widest plausible trigger surface. When the contract leaves an input ambiguous or unspecified near an enumerated error case, prefer raising that error over silently reinterpreting the input as different valid behavior, even when external spec knowledge says the input is valid.",
47
47
  "- Only narrow an enumerated error's trigger surface when the objective, acceptance criteria, or pre-existing required tests explicitly require the ambiguous input to be accepted. Widening an enumerated error to nearby ambiguous inputs is applying the contract, not adding beyond it.",
48
48
  "- Do not add behaviors, restrictions, error conditions, or follow-up requirements beyond what the objective/acceptance criteria require.",
49
+ "- The loud-error preference applies ONLY to error conditions the objective/acceptance criteria enumerate. For anything the contract does not enumerate, the default is the opposite: accept permissively and never invent a new validation error, required field, uniqueness constraint, or rejection the contract does not name.",
50
+ "- When the contract names a concrete type, shape, or format ('returns a dict', 'a list of strings', a JSON object with named keys), produce exactly that — no defensive substitutes such as read-only proxies, frozen collections, tuples-for-lists, or wrapper subclasses unless the contract requires them. Consumers may check type identity literally.",
51
+ "- Where behavior is unspecified, prefer the choice that preserves input verbatim over one that normalizes, deduplicates, reorders, or rewrites it; transform only what the contract says to transform.",
49
52
  ].join("\n");
50
53
 
51
54
  export const REVIEWER_SPEC_VS_OBJECTIVE_GUARD =
52
55
  "Do not use external spec/standard conformance alone to flag a wide trigger surface for an error condition the objective/acceptance criteria enumerate; the contract prefers loud errors over silent reinterpretation of ambiguous inputs, so classify such spec-vs-objective tension as beyond_objective rather than a blocking defect.";
53
56
 
57
+ export const REVIEWER_OVERIMPLEMENTATION_GUARD =
58
+ "Hunt over-implementation as seriously as gaps: any validation error, required field, uniqueness/format constraint, immutability wrapper, or normalization the contract does not require is a defect that rejects inputs or produces shapes the contract permits — classify it required_by_objective. Probe at least one contract-permitted input the worker's own tests do not exercise before approving.";
59
+
54
60
  export const ACCEPTANCE_MATRIX_CONTRACT = [
55
61
  "Acceptance/contract matrix:",
56
62
  "- Before implementing, derive an observable acceptance matrix from the literal objective and acceptance criteria: one row per explicit clause, requirement, named artifact, command, gate, invariant, and deliverable, each mapped to the concrete observable check (command, test, executable scenario, artifact inspection, or state assertion) that would prove it in the current checkout.",
57
63
  "- Record the matrix in the receipt/implementation notes on the first turn and keep it current as work proceeds; every later completion claim must map back to matrix rows with current evidence.",
58
64
  "- The matrix inherits the literal contract's scope: do not add rows for behavior the objective/acceptance criteria do not require, and do not drop rows because they are inconvenient to prove.",
65
+ "- Add one row per literal example in the objective/acceptance criteria (sample inputs/outputs, rendered text, file contents), checked character-for-character rather than paraphrased.",
66
+ "- Add explicit rows for each interface decision the contract constrains: return/field types by identity, required-vs-optional per field, duplicate handling, ordering, and raw-vs-normalized text. When the contract leaves such a decision open, record the permissive/preserving default chosen.",
59
67
  "",
60
68
  "Stateful behavior modeling:",
61
69
  "- When the work involves stateful behavior (lifecycles, sessions, caches, persisted data, protocols, retries, concurrency, or multi-step flows), model the state space explicitly before implementing: enumerate the states, the legal transitions between them, the invariants that must hold in every state, and how illegal transitions or unexpected inputs are handled.",
62
70
  "- Tie matrix rows for stateful clauses to specific states, transitions, and invariants so their checks exercise transitions and invariant preservation, not just happy-path end states.",
63
71
  ].join("\n");
64
72
 
73
+ export const CONTRACT_FIDELITY_AUDIT = [
74
+ "Adversarial divergence pass:",
75
+ "- After checks are green and before claiming readiness for review, re-read the literal objective/acceptance criteria and ask for each clause: what plausible independent check of this clause would my implementation fail?",
76
+ "- Probe the recurring divergence categories specifically: (1) type-identity assertions on returned values, (2) inputs with optional fields omitted, (3) duplicated or aliased inputs, (4) ordering assumptions, (5) text expected verbatim where the implementation normalizes it, and (6) any raised error the contract does not enumerate.",
77
+ "- Fix each divergence or record its justification in the receipt/implementation notes; an unexamined divergence category is unfinished verification, not a nice-to-have.",
78
+ ].join("\n");
79
+
80
+ export const REVIEWER_INTERCOM_COORDINATION_PROTOCOL = [
81
+ "Concurrent reviewer coordination protocol:",
82
+ "- At review start, use Intercom to initialize/check coordination and discover sibling reviewers participating in the same workflow run.",
83
+ "- Tell those sibling reviewers your validation plan and intended check ownership before running checks. Claim ownership before starting any expensive, lock-prone, or potentially conflicting command that uses a shared checkout or shared environment.",
84
+ "- Coordinate and serialize conflicting shared-checkout or shared-environment commands, including full test suites, build or test commands, package-manager operations, browser or E2E sessions, migrations, and generated-artifact steps. Announce each coordinated check when it starts and finishes. Release every claimed resource when finished, then send siblings an explicit resource-release update. Share reusable command outcomes and evidence so siblings can avoid redundant execution where appropriate.",
85
+ "- Operational coordination does not make the review collective: independently inspect the patch, perform your own analysis, and produce your own verdict. Never copy or defer to a sibling reviewer's conclusions.",
86
+ ].join("\n");
87
+
65
88
  export const REVIEWER_INDEPENDENT_VERIFICATION_CONTRACT = [
66
89
  "Independent verification derivation:",
67
- "- Before relying on the worker receipt, worker-authored tests, or any prior reviewer output, derive your own adversarial check list from the literal objective and acceptance criteria alone: per-clause observable checks plus boundary, edge, negative, and invalid-input probes, and state/transition/invariant probes for stateful behavior.",
90
+ "- Before relying on the worker receipt, worker-authored tests, or any prior reviewer output, derive your own adversarial check list from the literal objective and acceptance criteria alone: per-clause observable checks plus boundary, edge, negative, and invalid-input probes; contract-permitted-input probes (permissive inputs the implementation might wrongly reject: optional fields omitted, duplicates or aliases present, unusual-but-allowed values) and exact type/shape/text-identity probes for anything the contract names; and state/transition/invariant probes for stateful behavior.",
68
91
  "- Execute or delegate the highest-value derived checks against the current repository state before mapping worker evidence to requirements.",
69
92
  "- Worker-authored tests, snapshots, and receipts corroborate your derived checks; they never substitute for them. Passing worker-authored tests is circular evidence for the clauses those tests were written from.",
70
93
  "- Keep derived checks inside the literal contract's scope; do not manufacture requirements beyond the objective/acceptance criteria.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.8",
3
+ "version": "0.9.9-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -23,6 +23,8 @@
23
23
 
24
24
  import type { WorkflowSerializableValue } from "../shared/types.js";
25
25
  import { createHash } from "node:crypto";
26
+ import { isDurableWorkflowResumable } from "./resume-eligibility.js";
27
+ import { DURABLE_FORMAT_VERSION } from "./format-version.js";
26
28
  import type {
27
29
  DurableCheckpoint,
28
30
  DurableCheckpointEntry,
@@ -94,8 +96,13 @@ export interface DurableWorkflowBackend {
94
96
  /** Look up a cached stage output by replay key. */
95
97
  getStageOutput(workflowId: string, replayKey: string): WorkflowSerializableValue | undefined;
96
98
 
97
- /** Look up resumable stage session metadata by replay key, when available. */
98
- getStageSession(workflowId: string, replayKey: string): { sessionId?: string; sessionFile?: string } | undefined;
99
+ /** Look up the latest resumable stage session and accumulated active timing. */
100
+ getStageSession(workflowId: string, replayKey: string): {
101
+ sessionId?: string;
102
+ sessionFile?: string;
103
+ startedAt?: number;
104
+ durationMs?: number;
105
+ } | undefined;
99
106
 
100
107
  /** List all checkpoints for a workflow (in completion order). */
101
108
  listCheckpoints(workflowId: string): readonly DurableCheckpoint[];
@@ -107,14 +114,22 @@ export interface DurableWorkflowBackend {
107
114
  setWorkflowStatus(workflowId: string, status: DurableWorkflowStatus, pendingPrompts?: number, resumable?: boolean): void;
108
115
 
109
116
  /**
110
- * List resumable workflows (not completed/cancelled, or explicitly marked
111
- * resumable after failure). Used by the `/workflow resume` selector.
117
+ * List resumable root workflows: running/paused runs with progress and
118
+ * failed/blocked runs unless explicitly marked non-resumable.
112
119
  */
113
120
  listResumableWorkflows(): readonly ResumableWorkflowEntry[];
121
+ /** List successful completed root workflows with durable checkpoint progress. */
122
+ listCompletedWorkflows(): readonly ResumableWorkflowEntry[];
114
123
 
115
124
  /** Export a session-cache entry for the given workflow (for JSONL persistence). */
116
125
  toCacheEntry(workflowId: string): DurableCheckpointEntry | undefined;
117
126
 
127
+ /** Permanently remove one root workflow and its durable checkpoints. */
128
+ deleteWorkflow(workflowId: string): Promise<void>;
129
+
130
+ /** Whether a workflow id may be exposed or resumed from live/restored metadata. */
131
+ isWorkflowLoadable(workflowId: string): boolean;
132
+
118
133
  /** Clear all state (for tests). */
119
134
  reset(): void;
120
135
 
@@ -185,8 +200,10 @@ function checkpointKey(c: DurableCheckpoint): string {
185
200
  export class InMemoryDurableBackend implements DurableWorkflowBackend {
186
201
  public readonly persistent = false;
187
202
  private readonly workflows = new Map<string, InMemoryWorkflowRecord>();
203
+ private readonly deletedWorkflowIds = new Set<string>();
188
204
 
189
205
  registerWorkflow(handle: WorkflowRegistrationInput): void {
206
+ this.deletedWorkflowIds.delete(handle.workflowId);
190
207
  const existing = this.workflows.get(handle.workflowId);
191
208
  const completedCheckpoints = handle.completedCheckpoints ?? existing?.handle.completedCheckpoints ?? 0;
192
209
  const pendingPrompts = handle.pendingPrompts ?? existing?.handle.pendingPrompts ?? 0;
@@ -246,10 +263,20 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
246
263
  return checkpoint !== undefined && "output" in checkpoint ? checkpoint.output : undefined;
247
264
  }
248
265
 
249
- getStageSession(workflowId: string, replayKey: string): { sessionId?: string; sessionFile?: string } | undefined {
266
+ getStageSession(workflowId: string, replayKey: string): {
267
+ sessionId?: string;
268
+ sessionFile?: string;
269
+ startedAt?: number;
270
+ durationMs?: number;
271
+ } | undefined {
250
272
  const checkpoint = this.workflows.get(workflowId)?.stageSessionByReplayKey.get(replayKey);
251
273
  if (checkpoint?.sessionId === undefined && checkpoint?.sessionFile === undefined) return undefined;
252
- return { ...(checkpoint.sessionId !== undefined ? { sessionId: checkpoint.sessionId } : {}), ...(checkpoint.sessionFile !== undefined ? { sessionFile: checkpoint.sessionFile } : {}) };
274
+ return {
275
+ ...(checkpoint.sessionId !== undefined ? { sessionId: checkpoint.sessionId } : {}),
276
+ ...(checkpoint.sessionFile !== undefined ? { sessionFile: checkpoint.sessionFile } : {}),
277
+ ...(checkpoint.startedAt !== undefined ? { startedAt: checkpoint.startedAt } : {}),
278
+ ...(checkpoint.durationMs !== undefined ? { durationMs: checkpoint.durationMs } : {}),
279
+ };
253
280
  }
254
281
 
255
282
  listCheckpoints(workflowId: string): readonly DurableCheckpoint[] {
@@ -270,7 +297,13 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
270
297
 
271
298
  listResumableWorkflows(): readonly ResumableWorkflowEntry[] {
272
299
  return [...this.workflows.values()]
273
- .filter((rec) => isRootWorkflow(rec.handle) && isResumableHandle(rec.handle))
300
+ .filter((rec) => isDurableWorkflowResumable(rec.handle))
301
+ .map((rec) => toResumableEntry(rec.handle));
302
+ }
303
+
304
+ listCompletedWorkflows(): readonly ResumableWorkflowEntry[] {
305
+ return [...this.workflows.values()]
306
+ .filter((rec) => isRootWorkflow(rec.handle) && isCompletedHandle(rec.handle))
274
307
  .map((rec) => toResumableEntry(rec.handle));
275
308
  }
276
309
 
@@ -279,6 +312,7 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
279
312
  if (!rec) return undefined;
280
313
  const h = rec.handle;
281
314
  return {
315
+ formatVersion: DURABLE_FORMAT_VERSION,
282
316
  type: "workflow.durable.checkpoint",
283
317
  workflowId: h.workflowId,
284
318
  name: h.name,
@@ -297,8 +331,18 @@ export class InMemoryDurableBackend implements DurableWorkflowBackend {
297
331
  };
298
332
  }
299
333
 
334
+ async deleteWorkflow(workflowId: string): Promise<void> {
335
+ this.workflows.delete(workflowId);
336
+ this.deletedWorkflowIds.add(workflowId);
337
+ }
338
+
339
+ isWorkflowLoadable(workflowId: string): boolean {
340
+ return !this.deletedWorkflowIds.has(workflowId);
341
+ }
342
+
300
343
  reset(): void {
301
344
  this.workflows.clear();
345
+ this.deletedWorkflowIds.clear();
302
346
  }
303
347
 
304
348
  /** Export all records (for FileDurableBackend serialization or debugging). */
@@ -323,14 +367,8 @@ function hasResumeProgress(handle: DurableWorkflowHandle): boolean {
323
367
  return handle.completedCheckpoints > 0 || handle.pendingPrompts > 0;
324
368
  }
325
369
 
326
- function isResumableHandle(handle: DurableWorkflowHandle): boolean {
327
- if (handle.status === "failed" || handle.status === "blocked") return handle.resumable !== false;
328
- // `running`/`paused` are both resumable at the backend level: a `running`
329
- // durable handle may belong to a crashed process (no live executor), which
330
- // is exactly the cross-session crash-recovery case. Same-session
331
- // double-resume is prevented by the command layer, which hides durable
332
- // entries that match an active live run.
333
- return (handle.status === "running" || handle.status === "paused") && hasResumeProgress(handle);
370
+ function isCompletedHandle(handle: DurableWorkflowHandle): boolean {
371
+ return handle.status === "completed" && hasResumeProgress(handle);
334
372
  }
335
373
 
336
374
  function toResumableEntry(handle: DurableWorkflowHandle): ResumableWorkflowEntry {
@@ -0,0 +1,245 @@
1
+ import { readFileSync, statSync } from "node:fs";
2
+ import type { RunSnapshot, StageSnapshot } from "../shared/store-types.js";
3
+ import type { WorkflowInputValues } from "../shared/types.js";
4
+ import type { DurableWorkflowBackend } from "./backend.js";
5
+ import type {
6
+ DurableCheckpoint,
7
+ DurableStageCheckpoint,
8
+ ResumableWorkflowEntry,
9
+ } from "./types.js";
10
+ import { resolveDurableEntry } from "./resume-runtime.js";
11
+
12
+ export type CompletedWorkflowResolution =
13
+ | { readonly kind: "found"; readonly entry: ResumableWorkflowEntry; readonly snapshot: RunSnapshot }
14
+ | { readonly kind: "ambiguous"; readonly matches: readonly ResumableWorkflowEntry[] }
15
+ | { readonly kind: "not_found" }
16
+ | { readonly kind: "stale"; readonly entry: ResumableWorkflowEntry };
17
+
18
+ interface SessionTranscriptEntry {
19
+ readonly type?: string;
20
+ readonly id?: string;
21
+ readonly timestamp?: string;
22
+ readonly message?: {
23
+ readonly role?: string;
24
+ readonly content?: string | object;
25
+ };
26
+ }
27
+
28
+ interface StageDraft {
29
+ readonly replayKey: string;
30
+ readonly name: string;
31
+ readonly firstCompletedAt: number;
32
+ readonly output?: DurableStageCheckpoint["output"];
33
+ readonly result?: string;
34
+ readonly sessionId?: string;
35
+ readonly sessionFile?: string;
36
+ readonly startedAt?: number;
37
+ readonly endedAt?: number;
38
+ readonly durationMs?: number;
39
+ readonly model?: string;
40
+ readonly fastMode?: boolean;
41
+ readonly attemptedModels?: readonly string[];
42
+ readonly modelAttempts?: DurableStageCheckpoint["modelAttempts"];
43
+ }
44
+
45
+ /** Authoritative completed rows. This path is deliberately separate from resumability. */
46
+ export function listCompletedFromBackend(
47
+ backend: DurableWorkflowBackend,
48
+ ): readonly ResumableWorkflowEntry[] {
49
+ return backend.listCompletedWorkflows();
50
+ }
51
+
52
+ /** Completed rows whose authoritative checkpoints and referenced transcripts still exist. */
53
+ export function listOpenableCompletedWorkflows(
54
+ backend: DurableWorkflowBackend,
55
+ ): readonly ResumableWorkflowEntry[] {
56
+ return listCompletedFromBackend(backend)
57
+ .filter((entry) => completedWorkflowSnapshot(backend, entry) !== undefined)
58
+ .sort((a, b) => b.updatedAt - a.updatedAt);
59
+ }
60
+
61
+ export function resolveCompletedWorkflow(
62
+ workflowIdOrPrefix: string,
63
+ backend: DurableWorkflowBackend,
64
+ openableCatalog: readonly ResumableWorkflowEntry[] = listOpenableCompletedWorkflows(backend),
65
+ ): CompletedWorkflowResolution {
66
+ const resolved = resolveDurableEntry(workflowIdOrPrefix, openableCatalog);
67
+ if (resolved !== undefined) {
68
+ if ("kind" in resolved) return { kind: "ambiguous", matches: resolved.matches };
69
+ const snapshot = completedWorkflowSnapshot(backend, resolved);
70
+ return snapshot === undefined
71
+ ? { kind: "stale", entry: resolved }
72
+ : { kind: "found", entry: resolved, snapshot };
73
+ }
74
+
75
+ const authoritative = resolveDurableEntry(workflowIdOrPrefix, listCompletedFromBackend(backend));
76
+ if (authoritative === undefined) return { kind: "not_found" };
77
+ if ("kind" in authoritative) return { kind: "ambiguous", matches: authoritative.matches };
78
+ return { kind: "stale", entry: authoritative };
79
+ }
80
+
81
+ export function completedWorkflowSnapshot(
82
+ backend: DurableWorkflowBackend,
83
+ entry: ResumableWorkflowEntry,
84
+ ): RunSnapshot | undefined {
85
+ const handle = backend.getWorkflow(entry.workflowId);
86
+ if (handle === undefined || handle.status !== "completed") return undefined;
87
+ const checkpoints = backend.listCheckpoints(entry.workflowId);
88
+ if (checkpoints.length === 0) return undefined;
89
+ const stages = stageSnapshotsFromCheckpoints(checkpoints, handle.updatedAt).map(validatedStageTranscript);
90
+ if (!stages.some((stage) => stage.sessionFile !== undefined)) return undefined;
91
+
92
+ return {
93
+ id: handle.workflowId,
94
+ name: handle.name,
95
+ inputs: { ...handle.inputs } as WorkflowInputValues,
96
+ status: "completed",
97
+ stages,
98
+ startedAt: handle.createdAt,
99
+ endedAt: handle.updatedAt,
100
+ durationMs: Math.max(0, handle.updatedAt - handle.createdAt),
101
+ resumable: false,
102
+ };
103
+ }
104
+
105
+ function validatedStageTranscript(stage: StageSnapshot): StageSnapshot {
106
+ if (stage.sessionFile === undefined || isReopenableSessionTranscript(stage.sessionFile)) return stage;
107
+ const { sessionFile, ...withoutSessionFile } = stage;
108
+ void sessionFile;
109
+ return withoutSessionFile;
110
+ }
111
+
112
+ function isReopenableSessionTranscript(path: string): boolean {
113
+ try {
114
+ const stats = statSync(path);
115
+ if (!stats.isFile() || stats.size === 0) return false;
116
+ const lines = readFileSync(path, "utf8").split("\n").filter((line) => line.trim().length > 0);
117
+ if (lines.length < 2) return false;
118
+ const entries: SessionTranscriptEntry[] = [];
119
+ for (const line of lines) {
120
+ const parsed = JSON.parse(line) as object;
121
+ if (typeof parsed !== "object" || parsed === null) return false;
122
+ entries.push(parsed as SessionTranscriptEntry);
123
+ }
124
+ const header = entries[0];
125
+ return header?.type === "session" && typeof header.id === "string" && entries.some(isUsableContextMessage);
126
+ } catch {
127
+ return false;
128
+ }
129
+ }
130
+
131
+ function isUsableContextMessage(entry: SessionTranscriptEntry): boolean {
132
+ return entry.type === "message"
133
+ && typeof entry.id === "string"
134
+ && typeof entry.timestamp === "string"
135
+ && typeof entry.message?.role === "string"
136
+ && hasUsableMessageContent(entry.message.content);
137
+ }
138
+
139
+ function hasUsableMessageContent(content: string | object | undefined): boolean {
140
+ if (typeof content === "string") return content.trim().length > 0;
141
+ return Array.isArray(content) && content.some(hasUsableContentBlock);
142
+ }
143
+
144
+ function hasUsableContentBlock(block: object): boolean {
145
+ if (typeof block !== "object" || block === null) return false;
146
+ const contentBlock = block as {
147
+ readonly text?: string;
148
+ readonly thinking?: string;
149
+ readonly data?: string;
150
+ readonly name?: string;
151
+ };
152
+ return [contentBlock.text, contentBlock.thinking, contentBlock.data, contentBlock.name]
153
+ .some((value) => typeof value === "string" && value.trim().length > 0);
154
+ }
155
+
156
+ function stageSnapshotsFromCheckpoints(
157
+ checkpoints: readonly DurableCheckpoint[],
158
+ fallbackCompletedAt: number,
159
+ ): StageSnapshot[] {
160
+ const drafts = new Map<string, StageDraft>();
161
+ for (const checkpoint of checkpoints) {
162
+ if (checkpoint.kind !== "stage") continue;
163
+ const existing = drafts.get(checkpoint.replayKey);
164
+ drafts.set(checkpoint.replayKey, mergeStageDraft(existing, checkpoint));
165
+ }
166
+ const ordered = [...drafts.values()].sort((a, b) => a.firstCompletedAt - b.firstCompletedAt);
167
+ if (ordered.length === 0) return [syntheticCheckpointStage(checkpoints.length, fallbackCompletedAt)];
168
+ return ordered.map(stageSnapshotFromDraft);
169
+ }
170
+
171
+ function mergeStageDraft(
172
+ existing: StageDraft | undefined,
173
+ checkpoint: DurableStageCheckpoint,
174
+ ): StageDraft {
175
+ return {
176
+ replayKey: checkpoint.replayKey,
177
+ name: existing?.name ?? checkpoint.name,
178
+ firstCompletedAt: Math.min(existing?.firstCompletedAt ?? checkpoint.completedAt, checkpoint.completedAt),
179
+ ...valueOrExisting("output", checkpoint, existing),
180
+ ...valueOrExisting("result", checkpoint, existing),
181
+ ...valueOrExisting("sessionId", checkpoint, existing),
182
+ ...valueOrExisting("sessionFile", checkpoint, existing),
183
+ ...valueOrExisting("startedAt", checkpoint, existing),
184
+ ...valueOrExisting("endedAt", checkpoint, existing),
185
+ ...valueOrExisting("durationMs", checkpoint, existing),
186
+ ...valueOrExisting("model", checkpoint, existing),
187
+ ...valueOrExisting("fastMode", checkpoint, existing),
188
+ ...valueOrExisting("attemptedModels", checkpoint, existing),
189
+ ...valueOrExisting("modelAttempts", checkpoint, existing),
190
+ };
191
+ }
192
+
193
+ function valueOrExisting<
194
+ K extends keyof Omit<StageDraft, "replayKey" | "name" | "firstCompletedAt">
195
+ >(key: K, checkpoint: DurableStageCheckpoint, existing: StageDraft | undefined): Pick<StageDraft, K> | object {
196
+ const checkpointValue = checkpoint[key];
197
+ if (checkpointValue !== undefined) return { [key]: checkpointValue } as Pick<StageDraft, K>;
198
+ const existingValue = existing?.[key];
199
+ return existingValue === undefined ? {} : { [key]: existingValue } as Pick<StageDraft, K>;
200
+ }
201
+
202
+ function stageSnapshotFromDraft(draft: StageDraft, index: number): StageSnapshot {
203
+ const startedAt = draft.startedAt ?? draft.firstCompletedAt;
204
+ const endedAt = draft.endedAt ?? draft.firstCompletedAt;
205
+ return {
206
+ id: `completed-stage-${index + 1}`,
207
+ name: draft.name,
208
+ status: "completed",
209
+ parentIds: [],
210
+ startedAt,
211
+ endedAt,
212
+ durationMs: draft.durationMs ?? Math.max(0, endedAt - startedAt),
213
+ ...(stageResult(draft) !== undefined ? { result: stageResult(draft) } : {}),
214
+ replayKey: draft.replayKey,
215
+ toolEvents: [],
216
+ attachable: false,
217
+ ...(draft.sessionId !== undefined ? { sessionId: draft.sessionId } : {}),
218
+ ...(draft.sessionFile !== undefined ? { sessionFile: draft.sessionFile } : {}),
219
+ ...(draft.model !== undefined ? { model: draft.model } : {}),
220
+ ...(draft.fastMode !== undefined ? { fastMode: draft.fastMode } : {}),
221
+ ...(draft.attemptedModels !== undefined ? { attemptedModels: draft.attemptedModels } : {}),
222
+ ...(draft.modelAttempts !== undefined ? { modelAttempts: draft.modelAttempts } : {}),
223
+ };
224
+ }
225
+
226
+ function stageResult(draft: StageDraft): string | undefined {
227
+ if (draft.result !== undefined) return draft.result;
228
+ if (draft.output === undefined) return undefined;
229
+ return typeof draft.output === "string" ? draft.output : JSON.stringify(draft.output);
230
+ }
231
+
232
+ function syntheticCheckpointStage(checkpointCount: number, completedAt: number): StageSnapshot {
233
+ return {
234
+ id: "completed-checkpoints",
235
+ name: "durable checkpoints",
236
+ status: "completed",
237
+ parentIds: [],
238
+ startedAt: completedAt,
239
+ endedAt: completedAt,
240
+ durationMs: 0,
241
+ result: `${checkpointCount} durable checkpoint${checkpointCount === 1 ? "" : "s"}`,
242
+ toolEvents: [],
243
+ attachable: false,
244
+ };
245
+ }