@duckmind/dm-windows-x64 0.61.4 → 0.61.9

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 (279) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +211 -67
  3. package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
  4. package/extensions/dm-subagents/agents/claude-code.md +15 -0
  5. package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
  6. package/extensions/dm-subagents/agents/codex-exec.md +15 -0
  7. package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
  8. package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
  9. package/extensions/dm-subagents/agents/delegate.md +3 -2
  10. package/extensions/dm-subagents/agents/oracle.md +10 -5
  11. package/extensions/dm-subagents/agents/researcher.md +2 -2
  12. package/extensions/dm-subagents/agents/reviewer.md +17 -7
  13. package/extensions/dm-subagents/agents/scout.md +5 -5
  14. package/extensions/dm-subagents/agents/worker.md +6 -2
  15. package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
  16. package/extensions/dm-subagents/index.js +4 -0
  17. package/extensions/dm-subagents/inspector-runner.mjs +10 -0
  18. package/extensions/dm-subagents/install.mjs +3 -2
  19. package/extensions/dm-subagents/package.json +2 -2
  20. package/extensions/dm-subagents/prompts/council.md +60 -0
  21. package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
  22. package/extensions/dm-subagents/prompts/review-loop.md +13 -7
  23. package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
  24. package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
  25. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
  26. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
  27. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
  28. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
  29. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
  30. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
  31. package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
  32. package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
  33. package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
  34. package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
  35. package/extensions/dm-subagents/src/agents/agents.js +1447 -299
  36. package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
  37. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
  38. package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
  39. package/extensions/dm-subagents/src/agents/identity.js +1 -1
  40. package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
  41. package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
  42. package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
  43. package/extensions/dm-subagents/src/agents/skills.js +52 -35
  44. package/extensions/dm-subagents/src/api/agents.js +6 -0
  45. package/extensions/dm-subagents/src/api/background-work.js +151 -0
  46. package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
  47. package/extensions/dm-subagents/src/api/control-channel.js +3 -0
  48. package/extensions/dm-subagents/src/api/delegation.js +5 -0
  49. package/extensions/dm-subagents/src/api/dm-args.js +3 -0
  50. package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
  51. package/extensions/dm-subagents/src/api/external-runs.js +233 -0
  52. package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
  53. package/extensions/dm-subagents/src/api/preflight.js +322 -0
  54. package/extensions/dm-subagents/src/api/project-panes.js +11 -0
  55. package/extensions/dm-subagents/src/api/shared-types.js +4 -0
  56. package/extensions/dm-subagents/src/extension/config.js +175 -0
  57. package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
  58. package/extensions/dm-subagents/src/extension/doctor.js +71 -17
  59. package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
  60. package/extensions/dm-subagents/src/extension/index.js +711 -265
  61. package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
  62. package/extensions/dm-subagents/src/extension/rpc.js +427 -22
  63. package/extensions/dm-subagents/src/extension/schemas.js +158 -65
  64. package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
  65. package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
  66. package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
  67. package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
  68. package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
  69. package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
  70. package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
  71. package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
  72. package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
  73. package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
  74. package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
  75. package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
  76. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
  77. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
  78. package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
  79. package/extensions/dm-subagents/src/missions/actions.js +394 -0
  80. package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
  81. package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
  82. package/extensions/dm-subagents/src/missions/store.js +548 -0
  83. package/extensions/dm-subagents/src/missions/types.js +9 -0
  84. package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
  85. package/extensions/dm-subagents/src/policy/authority.js +37 -0
  86. package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
  87. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
  88. package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
  89. package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
  90. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
  91. package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
  92. package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
  93. package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
  94. package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
  95. package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
  96. package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
  97. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
  98. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
  99. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
  100. package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
  101. package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
  102. package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
  103. package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
  104. package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
  105. package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
  106. package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
  107. package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
  108. package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
  109. package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
  110. package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
  111. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
  112. package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
  113. package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
  114. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
  115. package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
  116. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
  117. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
  118. package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
  119. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
  120. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
  121. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
  122. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
  123. package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
  124. package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
  125. package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
  126. package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
  127. package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
  128. package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
  129. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
  130. package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
  131. package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
  132. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
  133. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
  134. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
  135. package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
  136. package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
  137. package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
  138. package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
  139. package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
  140. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
  141. package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
  142. package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
  143. package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
  144. package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
  145. package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
  146. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
  147. package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
  148. package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
  149. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
  150. package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
  151. package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
  152. package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
  153. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
  154. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
  155. package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
  156. package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
  157. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
  158. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
  159. package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
  160. package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
  161. package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
  162. package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
  163. package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
  164. package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
  165. package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
  166. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
  167. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
  168. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
  169. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
  170. package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
  171. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
  172. package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
  173. package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
  174. package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
  175. package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
  176. package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
  177. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
  178. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
  179. package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
  180. package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
  181. package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
  182. package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
  183. package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
  184. package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
  185. package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
  186. package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
  187. package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
  188. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
  189. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
  190. package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
  191. package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
  192. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
  193. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
  194. package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
  195. package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
  196. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
  197. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
  198. package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
  199. package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
  200. package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
  201. package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
  202. package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
  203. package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
  204. package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
  205. package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
  206. package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
  207. package/extensions/dm-subagents/src/shared/display-text.js +142 -0
  208. package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
  209. package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
  210. package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
  211. package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
  212. package/extensions/dm-subagents/src/shared/formatters.js +21 -7
  213. package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
  214. package/extensions/dm-subagents/src/shared/model-info.js +10 -5
  215. package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
  216. package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
  217. package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
  218. package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
  219. package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
  220. package/extensions/dm-subagents/src/shared/settings.js +39 -47
  221. package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
  222. package/extensions/dm-subagents/src/shared/status-format.js +9 -2
  223. package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
  224. package/extensions/dm-subagents/src/shared/types.js +47 -7
  225. package/extensions/dm-subagents/src/shared/utf8.js +12 -0
  226. package/extensions/dm-subagents/src/shared/utils.js +151 -131
  227. package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
  228. package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
  229. package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
  230. package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
  231. package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
  232. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
  233. package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
  234. package/extensions/dm-subagents/src/slash/selector.js +101 -0
  235. package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
  236. package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
  237. package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
  238. package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
  239. package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
  240. package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
  241. package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
  242. package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
  243. package/extensions/dm-subagents/src/tui/render.js +1511 -261
  244. package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
  245. package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
  246. package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
  247. package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
  248. package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
  249. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
  250. package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
  251. package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
  252. package/extensions/dm-subagents/src/watchdog/render.js +54 -0
  253. package/extensions/dm-subagents/src/watchdog/review.js +251 -0
  254. package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
  255. package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
  256. package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
  257. package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
  258. package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
  259. package/extensions/dm-subagents/src/watchdog/types.js +29 -0
  260. package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
  261. package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
  262. package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
  263. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
  264. package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
  265. package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
  266. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
  267. package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
  268. package/package.json +4 -3
  269. package/extensions/dm-fff/package.json +0 -21
  270. package/extensions/dm-fff/src/index.js +0 -691
  271. package/extensions/dm-fff/src/query.js +0 -60
  272. package/extensions/dm-subagents/agents/context-builder.md +0 -46
  273. package/extensions/dm-subagents/agents/planner.md +0 -55
  274. package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
  275. package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
  276. package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
  277. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
  278. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
  279. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
@@ -0,0 +1,387 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { writePrivateAtomicJson } from "../shared/atomic-json.js";
4
+ import { parseWorkflowChildSummary } from "./workflow-child-summary.js";
5
+ import { HOST_STEP_MAX_COUNT, assertUniqueHostStepIds, parseHostStepNode } from "../runs/shared/host-step-status.js";
6
+ import { assertWorkflowLaneKey, normalizeWorkflowLaneMetadata } from "../runs/shared/lane-metadata.js";
7
+ export const WORKFLOW_RECEIPT_VERSION = 1;
8
+ export const WORKFLOW_RECEIPT_FILE = "workflow-receipt.json";
9
+ const MAX_WORKFLOW_RECEIPT_BYTES = 2 * 1024 * 1024;
10
+ const KEY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
11
+ function assertSafeRunId(value, label) {
12
+ const normalized = value.trim();
13
+ if (!normalized || path.basename(normalized) !== normalized || normalized === "." || normalized === "..") {
14
+ throw new Error(`${label} must be an exact workflow run id, not a path or prefix.`);
15
+ }
16
+ return normalized;
17
+ }
18
+ function assertKey(value, label) {
19
+ if (!KEY_PATTERN.test(value))
20
+ throw new Error(`${label} is invalid.`);
21
+ return value;
22
+ }
23
+ export function workflowReceiptPath(asyncDirRoot, workflowRunId) {
24
+ return path.join(asyncDirRoot, assertSafeRunId(workflowRunId, "workflowRunId"), WORKFLOW_RECEIPT_FILE);
25
+ }
26
+ export function buildWorkflowReceipt(input) {
27
+ const workflowRunId = assertSafeRunId(input.workflowRunId, "workflowRunId");
28
+ if (input.workflowChildren?.workflowRunId !== undefined && input.workflowChildren.workflowRunId !== workflowRunId)
29
+ throw new Error("workflowChildren workflowRunId does not match its receipt.");
30
+ const entries = Object.create(null);
31
+ for (const child of input.children) {
32
+ const key = assertKey(child.key, "workflow receipt child key");
33
+ if (entries[key])
34
+ throw new Error(`Workflow receipt has duplicate child key '${key}'.`);
35
+ const lane = normalizeWorkflowLaneMetadata(child.lane, `workflow receipt child '${key}'.lane`);
36
+ assertWorkflowLaneKey(lane, key, `workflow receipt child '${key}'.lane`);
37
+ const runIds = [...new Set((child.continuation?.runIds ?? (child.runId ? [child.runId] : [])).filter((runId) => typeof runId === "string" && runId.trim()).map((runId) => runId.trim()))];
38
+ const latestRunId = runIds.at(-1);
39
+ const resumability = child.resumability ?? { state: "not-resumable", reason: child.runId ? "resumability was not recorded" : "child produced no run id" };
40
+ if (resumability.state === "resumable" && !latestRunId)
41
+ throw new Error(`Workflow receipt child '${key}' is resumable but has no retained run id.`);
42
+ const base = {
43
+ key,
44
+ ...lane ? { lane } : {},
45
+ ...child.terminalOutcome ? { terminalOutcome: child.terminalOutcome } : {},
46
+ ...child.agent ? { agent: child.agent } : {},
47
+ ...child.requestedContext ? { requestedContext: child.requestedContext } : {},
48
+ ...child.resolvedContext ? { resolvedContext: child.resolvedContext } : {},
49
+ ...child.outputReference ? { outputReference: child.outputReference } : {},
50
+ ...child.recovery ? { acceptanceRecovery: child.recovery } : {},
51
+ ...child.externalAdapter ? { externalAdapter: child.externalAdapter } : {},
52
+ continuation: { runIds }
53
+ };
54
+ entries[key] = resumability.state === "resumable" ? { ...base, latestRunId, resumability } : { ...base, ...latestRunId ? { latestRunId } : {}, resumability };
55
+ }
56
+ if (input.hostSteps && input.hostSteps.length > HOST_STEP_MAX_COUNT)
57
+ throw new Error(`Workflow receipt has more than ${HOST_STEP_MAX_COUNT} host steps.`);
58
+ const hostSteps = input.hostSteps?.map((hostStep, index) => parseHostStepNode(hostStep, `workflow receipt hostSteps[${index}]`));
59
+ if (hostSteps)
60
+ assertUniqueHostStepIds(hostSteps, "workflow receipt");
61
+ return { version: WORKFLOW_RECEIPT_VERSION, workflowRunId, state: input.state, createdAt: input.createdAt ?? Date.now(), entries, ...hostSteps?.length ? { hostSteps } : {}, ...input.workflowChildren ? { workflowChildren: input.workflowChildren } : {}, ...input.terminalOutcome ? { terminalOutcome: input.terminalOutcome } : {} };
62
+ }
63
+ export function writeWorkflowReceipt(asyncDir, receipt) {
64
+ const receiptPath = path.join(asyncDir, WORKFLOW_RECEIPT_FILE);
65
+ writePrivateAtomicJson(receiptPath, receipt);
66
+ return receiptPath;
67
+ }
68
+ function readWorkflowReceiptFile(receiptPath) {
69
+ let fd;
70
+ try {
71
+ fd = fs.openSync(receiptPath, "r");
72
+ const stat = fs.fstatSync(fd);
73
+ if (!stat.isFile())
74
+ throw new Error("workflow receipt is not a regular file.");
75
+ if (stat.size > MAX_WORKFLOW_RECEIPT_BYTES)
76
+ throw new Error(`workflow receipt exceeds the ${MAX_WORKFLOW_RECEIPT_BYTES}-byte limit.`);
77
+ const buffer = Buffer.allocUnsafe(stat.size);
78
+ let offset = 0;
79
+ while (offset < buffer.length) {
80
+ const bytesRead = fs.readSync(fd, buffer, offset, buffer.length - offset, null);
81
+ if (bytesRead <= 0)
82
+ throw new Error("workflow receipt ended before its declared size.");
83
+ offset += bytesRead;
84
+ }
85
+ return JSON.parse(buffer.toString("utf-8"));
86
+ } finally {
87
+ if (fd !== undefined)
88
+ fs.closeSync(fd);
89
+ }
90
+ }
91
+ const EXTERNAL_CLI_CAPABILITIES = {
92
+ stop: true,
93
+ steer: false,
94
+ resume: false,
95
+ structuredOutput: false,
96
+ toolEvents: false,
97
+ supervisor: "unsupported",
98
+ forkContext: false,
99
+ extensionBindings: false
100
+ };
101
+ function parseExternalCliReceiptMetadata(value, key, source) {
102
+ if (value === undefined)
103
+ return;
104
+ const label = `Invalid workflow receipt '${source}': entry '${key}' externalAdapter`;
105
+ if (!value || typeof value !== "object" || Array.isArray(value))
106
+ throw new Error(`${label} must be an object.`);
107
+ const metadata = value;
108
+ const unknownMetadata = Object.keys(metadata).filter((field) => !["adapter", "capabilities", "safety", "outputArtifacts", "handoff", "supervisor", "nonResumableReason"].includes(field));
109
+ if (unknownMetadata.length > 0)
110
+ throw new Error(`${label} has unsupported fields: ${unknownMetadata.join(", ")}.`);
111
+ const adapter = metadata.adapter;
112
+ if (!adapter || typeof adapter !== "object" || Array.isArray(adapter))
113
+ throw new Error(`${label}.adapter must be an object.`);
114
+ const adapterRecord = adapter;
115
+ const unknownAdapter = Object.keys(adapterRecord).filter((field) => !["id", "version", "executionMode"].includes(field));
116
+ if (unknownAdapter.length > 0)
117
+ throw new Error(`${label}.adapter has unsupported fields: ${unknownAdapter.join(", ")}.`);
118
+ if (adapterRecord.id !== "external-cli" && adapterRecord.id !== "codex-exec" && adapterRecord.id !== "codex-exec-writer" && adapterRecord.id !== "claude-code" && adapterRecord.id !== "claude-code-writer" && adapterRecord.id !== "cursor-agent" && adapterRecord.id !== "cursor-agent-writer" && adapterRecord.id !== "grok-build" || adapterRecord.version !== 1 || adapterRecord.executionMode !== (adapterRecord.id === "cursor-agent" || adapterRecord.id === "cursor-agent-writer" || adapterRecord.id === "grok-build" ? "one-shot-prompt-file" : "one-shot-stdin"))
119
+ throw new Error(`${label}.adapter is invalid.`);
120
+ const capabilities = metadata.capabilities;
121
+ if (!capabilities || typeof capabilities !== "object" || Array.isArray(capabilities))
122
+ throw new Error(`${label}.capabilities must be an object.`);
123
+ const capabilityRecord = capabilities;
124
+ const unknownCapabilities = Object.keys(capabilityRecord).filter((field) => !(field in EXTERNAL_CLI_CAPABILITIES));
125
+ if (unknownCapabilities.length > 0)
126
+ throw new Error(`${label}.capabilities has unsupported fields: ${unknownCapabilities.join(", ")}.`);
127
+ for (const [capability, expected] of Object.entries(EXTERNAL_CLI_CAPABILITIES)) {
128
+ if (capabilityRecord[capability] !== expected)
129
+ throw new Error(`${label}.capabilities.${capability} is invalid.`);
130
+ }
131
+ const safety = metadata.safety;
132
+ if (adapterRecord.id === "codex-exec") {
133
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
134
+ throw new Error(`${label}.safety is missing.`);
135
+ const safetyRecord = safety;
136
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !["sandbox", "approvalPolicy", "ephemeral"].includes(field));
137
+ if (unknownSafety.length > 0)
138
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
139
+ if (safetyRecord.sandbox !== "read-only" || safetyRecord.approvalPolicy !== "never" || safetyRecord.ephemeral !== true)
140
+ throw new Error(`${label}.safety is invalid.`);
141
+ } else if (adapterRecord.id === "codex-exec-writer") {
142
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
143
+ throw new Error(`${label}.safety is missing.`);
144
+ const safetyRecord = safety;
145
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !["access", "sandbox", "approvalPolicy", "ephemeral"].includes(field));
146
+ if (unknownSafety.length > 0)
147
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
148
+ if (safetyRecord.access !== "workspace-write" || safetyRecord.sandbox !== "workspace-write" || safetyRecord.approvalPolicy !== "never" || safetyRecord.ephemeral !== true)
149
+ throw new Error(`${label}.safety is invalid.`);
150
+ } else if (adapterRecord.id === "claude-code") {
151
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
152
+ throw new Error(`${label}.safety is missing.`);
153
+ const safetyRecord = safety;
154
+ const legacy = safetyRecord.authentication === undefined;
155
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !(legacy ? ["permissionMode", "tools", "mcp", "settingSources", "sessionPersistence"] : ["access", "authentication", "permissionMode", "tools", "mcp", "settingSources", "userSettingsTrust", "sessionPersistence"]).includes(field));
156
+ if (unknownSafety.length > 0)
157
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
158
+ if (legacy) {
159
+ if (safetyRecord.permissionMode !== "plan" || safetyRecord.tools !== "none" || safetyRecord.mcp !== "empty-strict" || safetyRecord.settingSources !== "none" || safetyRecord.sessionPersistence !== false)
160
+ throw new Error(`${label}.safety is invalid.`);
161
+ } else if (safetyRecord.access !== "read-only" || safetyRecord.authentication !== "existing-cli-required" || safetyRecord.permissionMode !== "plan" || safetyRecord.tools !== "none" || safetyRecord.mcp !== "empty-strict" || safetyRecord.settingSources !== "user" || safetyRecord.userSettingsTrust !== "required" || safetyRecord.sessionPersistence !== false)
162
+ throw new Error(`${label}.safety is invalid.`);
163
+ } else if (adapterRecord.id === "claude-code-writer") {
164
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
165
+ throw new Error(`${label}.safety is missing.`);
166
+ const safetyRecord = safety;
167
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !["access", "authentication", "permissionMode", "tools", "mcp", "settingSources", "userSettingsTrust", "sessionPersistence"].includes(field));
168
+ if (unknownSafety.length > 0)
169
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
170
+ if (safetyRecord.access !== "workspace-write" || safetyRecord.authentication !== "existing-cli-required" || safetyRecord.permissionMode !== "acceptEdits" || safetyRecord.tools !== "Read,Write,Edit,Glob,Grep" || safetyRecord.mcp !== "empty-strict" || safetyRecord.settingSources !== "user" || safetyRecord.userSettingsTrust !== "required" || safetyRecord.sessionPersistence !== false)
171
+ throw new Error(`${label}.safety is invalid.`);
172
+ } else if (adapterRecord.id === "cursor-agent" || adapterRecord.id === "cursor-agent-writer") {
173
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
174
+ throw new Error(`${label}.safety is missing.`);
175
+ const safetyRecord = safety;
176
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !["access", "authentication", "mode", "sandbox", "workspaceTrust", "sessionReuse"].includes(field));
177
+ if (unknownSafety.length > 0)
178
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
179
+ const writer = adapterRecord.id === "cursor-agent-writer";
180
+ if (safetyRecord.access !== (writer ? "workspace-write" : "read-only") || safetyRecord.authentication !== "cursor-api-key-or-existing-login" || safetyRecord.mode !== (writer ? "print" : "ask") || safetyRecord.sandbox !== "enabled" || safetyRecord.workspaceTrust !== "existing-required" || safetyRecord.sessionReuse !== false)
181
+ throw new Error(`${label}.safety is invalid.`);
182
+ } else if (adapterRecord.id === "grok-build") {
183
+ if (!safety || typeof safety !== "object" || Array.isArray(safety))
184
+ throw new Error(`${label}.safety is missing.`);
185
+ const safetyRecord = safety;
186
+ const unknownSafety = Object.keys(safetyRecord).filter((field) => !["access", "authentication", "permissionMode", "tools", "deniedTools", "sandbox", "webSearch", "subagents", "config", "updates", "sessionPersistence"].includes(field));
187
+ if (unknownSafety.length > 0)
188
+ throw new Error(`${label}.safety has unsupported fields: ${unknownSafety.join(", ")}.`);
189
+ if (safetyRecord.access !== "read-only" || safetyRecord.authentication !== "xai-api-key-required" || safetyRecord.permissionMode !== "plan" || safetyRecord.tools !== "read_file,grep,list_dir" || safetyRecord.deniedTools !== "run_terminal_cmd,search_replace,Agent,Bash,Edit,Write,MCPTool" || safetyRecord.sandbox !== "read-only" || safetyRecord.webSearch !== false || safetyRecord.subagents !== false || safetyRecord.config !== "temporary-home" || safetyRecord.updates !== "disabled" || safetyRecord.sessionPersistence !== false)
190
+ throw new Error(`${label}.safety is invalid.`);
191
+ } else if (safety !== undefined)
192
+ throw new Error(`${label}.safety is invalid for the generic adapter.`);
193
+ const handoff = metadata.handoff;
194
+ if (!handoff || typeof handoff !== "object" || Array.isArray(handoff))
195
+ throw new Error(`${label}.handoff must be an object.`);
196
+ const handoffRecord = handoff;
197
+ const unknownHandoff = Object.keys(handoffRecord).filter((field) => field !== "mode");
198
+ if (unknownHandoff.length > 0)
199
+ throw new Error(`${label}.handoff has unsupported fields: ${unknownHandoff.join(", ")}.`);
200
+ if (handoffRecord.mode !== "fresh")
201
+ throw new Error(`${label}.handoff is invalid.`);
202
+ const supervisor = metadata.supervisor;
203
+ if (!supervisor || typeof supervisor !== "object" || Array.isArray(supervisor))
204
+ throw new Error(`${label}.supervisor must be an object.`);
205
+ const supervisorRecord = supervisor;
206
+ const unknownSupervisor = Object.keys(supervisorRecord).filter((field) => !["mode", "reason"].includes(field));
207
+ if (unknownSupervisor.length > 0)
208
+ throw new Error(`${label}.supervisor has unsupported fields: ${unknownSupervisor.join(", ")}.`);
209
+ if (supervisorRecord.mode !== "unsupported" || typeof supervisorRecord.reason !== "string" || !supervisorRecord.reason.trim())
210
+ throw new Error(`${label}.supervisor is invalid.`);
211
+ if (typeof metadata.nonResumableReason !== "string" || !metadata.nonResumableReason.trim())
212
+ throw new Error(`${label}.nonResumableReason is missing.`);
213
+ const outputArtifacts = metadata.outputArtifacts;
214
+ if (outputArtifacts !== undefined) {
215
+ if (!outputArtifacts || typeof outputArtifacts !== "object" || Array.isArray(outputArtifacts))
216
+ throw new Error(`${label}.outputArtifacts must be an object.`);
217
+ const unknownArtifacts = Object.keys(outputArtifacts).filter((field) => !["stdoutPath", "stderrPath", "finalOutputPath"].includes(field));
218
+ if (unknownArtifacts.length > 0)
219
+ throw new Error(`${label}.outputArtifacts has unsupported fields: ${unknownArtifacts.join(", ")}.`);
220
+ for (const field of ["stdoutPath", "stderrPath", "finalOutputPath"]) {
221
+ const artifactPath = outputArtifacts[field];
222
+ if (artifactPath !== undefined && (typeof artifactPath !== "string" || !artifactPath.trim()))
223
+ throw new Error(`${label}.outputArtifacts.${field} must be a non-empty string.`);
224
+ }
225
+ }
226
+ return value;
227
+ }
228
+ function parseTerminalOutcome(value, label) {
229
+ if (value === undefined)
230
+ return;
231
+ if (!value || typeof value !== "object" || Array.isArray(value))
232
+ throw new Error(`${label} must be an object.`);
233
+ const outcome = value;
234
+ if (outcome.state !== "partial" || outcome.reason !== "budget_exhausted" && outcome.reason !== "timeout")
235
+ throw new Error(`${label} is invalid.`);
236
+ return { state: "partial", reason: outcome.reason };
237
+ }
238
+ function parseAcceptanceRecoveryMetadata(value, label) {
239
+ if (value === undefined)
240
+ return;
241
+ if (!value || typeof value !== "object" || Array.isArray(value))
242
+ throw new Error(`${label} must be an object.`);
243
+ const recovery = value;
244
+ if (recovery.status !== "available-for-review" || recovery.reason !== "acceptance-metadata-rejected")
245
+ throw new Error(`${label} is invalid.`);
246
+ if (typeof recovery.reportPath !== "string" || !recovery.reportPath.trim() || typeof recovery.reportHash !== "string" || !/^[a-f0-9]{64}$/u.test(recovery.reportHash))
247
+ throw new Error(`${label} is invalid.`);
248
+ return {
249
+ status: "available-for-review",
250
+ reason: "acceptance-metadata-rejected",
251
+ reportPath: recovery.reportPath,
252
+ reportHash: recovery.reportHash
253
+ };
254
+ }
255
+ function parseEntry(value, key, source) {
256
+ if (!value || typeof value !== "object" || Array.isArray(value))
257
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' must be an object.`);
258
+ const entry = value;
259
+ if (entry.key !== key)
260
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' has a mismatched key.`);
261
+ const latestRunId = entry.latestRunId;
262
+ if (latestRunId !== undefined && (typeof latestRunId !== "string" || !latestRunId.trim()))
263
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' latestRunId must be non-empty.`);
264
+ const continuation = entry.continuation;
265
+ if (!continuation || typeof continuation !== "object" || Array.isArray(continuation) || !Array.isArray(continuation.runIds)) {
266
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' continuation is missing.`);
267
+ }
268
+ const runIds = continuation.runIds;
269
+ if (runIds.some((runId) => typeof runId !== "string" || !runId.trim()))
270
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' continuation contains an invalid run id.`);
271
+ if (latestRunId !== undefined && runIds.at(-1) !== latestRunId)
272
+ throw new Error(`Workflow receipt '${source}' entry '${key}' is stale: latestRunId does not match its continuation lineage.`);
273
+ const resumability = entry.resumability;
274
+ if (!resumability || typeof resumability !== "object" || Array.isArray(resumability))
275
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' resumability is missing.`);
276
+ const state = resumability.state;
277
+ if (state !== "resumable" && state !== "not-resumable")
278
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' resumability state is invalid.`);
279
+ const reason = resumability.reason;
280
+ if (state === "resumable" && latestRunId === undefined)
281
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' resumable entry has no retained run id.`);
282
+ if (state === "not-resumable" && (typeof reason !== "string" || !reason.trim()))
283
+ throw new Error(`Invalid workflow receipt '${source}': entry '${key}' non-resumable reason is missing.`);
284
+ const terminalOutcome = parseTerminalOutcome(entry.terminalOutcome, `Invalid workflow receipt '${source}': entry '${key}' terminalOutcome`);
285
+ const acceptanceRecovery = parseAcceptanceRecoveryMetadata(entry.acceptanceRecovery, `Invalid workflow receipt '${source}': entry '${key}' acceptanceRecovery`);
286
+ parseExternalCliReceiptMetadata(entry.externalAdapter, key, source);
287
+ const lane = normalizeWorkflowLaneMetadata(entry.lane, `Invalid workflow receipt '${source}': entry '${key}'.lane`);
288
+ assertWorkflowLaneKey(lane, key, `Invalid workflow receipt '${source}': entry '${key}'.lane`);
289
+ return { ...value, ...lane ? { lane } : {}, ...terminalOutcome ? { terminalOutcome } : {}, ...acceptanceRecovery ? { acceptanceRecovery } : {} };
290
+ }
291
+ function parseWorkflowResolution(value, source) {
292
+ if (value === undefined)
293
+ return;
294
+ if (value !== "settled-awaiting-resume" && value !== "failed-child" && value !== "interrupted-child")
295
+ throw new Error(`Invalid workflow receipt '${source}': workflowResolution is invalid.`);
296
+ return value;
297
+ }
298
+ function parseRecovery(value, workflowRunId, entries, source) {
299
+ if (value === undefined)
300
+ return;
301
+ if (!Array.isArray(value))
302
+ throw new Error(`Invalid workflow receipt '${source}': recovery must be an array.`);
303
+ return value.map((item, index) => {
304
+ if (!item || typeof item !== "object" || Array.isArray(item))
305
+ throw new Error(`Invalid workflow receipt '${source}': recovery[${index}] must be an object.`);
306
+ const action = item;
307
+ const key = action.key;
308
+ const resume = action.resume;
309
+ if (typeof key !== "string" || !entries[key] || action.call !== "runs.run" || action.taskRequired !== true || !resume || typeof resume !== "object" || Array.isArray(resume))
310
+ throw new Error(`Invalid workflow receipt '${source}': recovery[${index}] is invalid.`);
311
+ const reference = resume;
312
+ if (reference.workflowRunId !== workflowRunId || reference.key !== key || reference.latest !== true || entries[key].resumability.state !== "resumable")
313
+ throw new Error(`Invalid workflow receipt '${source}': recovery[${index}] does not identify a resumable entry.`);
314
+ return { key, call: "runs.run", resume: { workflowRunId, key, latest: true }, taskRequired: true };
315
+ });
316
+ }
317
+ export function readWorkflowReceipt(asyncDirRoot, workflowRunId) {
318
+ const receiptPath = workflowReceiptPath(asyncDirRoot, workflowRunId);
319
+ let value;
320
+ try {
321
+ value = readWorkflowReceiptFile(receiptPath);
322
+ } catch (error) {
323
+ if (error.code === "ENOENT") {
324
+ const workflowDir = path.dirname(receiptPath);
325
+ if (fs.existsSync(path.join(workflowDir, "status.json")) || fs.existsSync(path.join(workflowDir, "events.jsonl"))) {
326
+ throw new Error(`Workflow receipt '${workflowRunId}' is not available because the workflow may still be active or terminal receipt writing failed. Use direct child run IDs from status/events for direct resume after the normal retained-child checks.`);
327
+ }
328
+ throw new Error(`Workflow receipt '${workflowRunId}' was not found.`);
329
+ }
330
+ throw new Error(`Workflow receipt '${workflowRunId}' could not be read: ${error instanceof Error ? error.message : String(error)}`, { cause: error instanceof Error ? error : undefined });
331
+ }
332
+ if (!value || typeof value !== "object" || Array.isArray(value))
333
+ throw new Error(`Invalid workflow receipt '${receiptPath}': expected an object.`);
334
+ const receipt = value;
335
+ if (receipt.version !== WORKFLOW_RECEIPT_VERSION)
336
+ throw new Error(`Invalid workflow receipt '${receiptPath}': unsupported version.`);
337
+ if (receipt.workflowRunId !== workflowRunId)
338
+ throw new Error(`Workflow receipt '${receiptPath}' is stale: workflowRunId does not match.`);
339
+ if (receipt.state !== "complete" && receipt.state !== "failed" && receipt.state !== "paused" && receipt.state !== "stopped") {
340
+ throw new Error(`Workflow receipt '${receiptPath}' is stale: workflow is not terminal.`);
341
+ }
342
+ if (typeof receipt.createdAt !== "number" || !Number.isFinite(receipt.createdAt))
343
+ throw new Error(`Invalid workflow receipt '${receiptPath}': createdAt is invalid.`);
344
+ if (!receipt.entries || typeof receipt.entries !== "object" || Array.isArray(receipt.entries))
345
+ throw new Error(`Invalid workflow receipt '${receiptPath}': entries must be an object.`);
346
+ const entries = Object.create(null);
347
+ for (const [key, entry] of Object.entries(receipt.entries))
348
+ entries[assertKey(key, "workflow receipt key")] = parseEntry(entry, key, receiptPath);
349
+ const workflowChildren = parseWorkflowChildSummary(receipt.workflowChildren);
350
+ if (workflowChildren && workflowChildren.workflowRunId !== workflowRunId)
351
+ throw new Error(`Workflow receipt '${receiptPath}' is stale: workflowChildren.workflowRunId does not match.`);
352
+ let hostSteps;
353
+ if (receipt.hostSteps !== undefined) {
354
+ if (!Array.isArray(receipt.hostSteps))
355
+ throw new Error(`Invalid workflow receipt '${receiptPath}': hostSteps must be an array.`);
356
+ if (receipt.hostSteps.length > HOST_STEP_MAX_COUNT)
357
+ throw new Error(`Invalid workflow receipt '${receiptPath}': hostSteps exceeds ${HOST_STEP_MAX_COUNT} entries.`);
358
+ hostSteps = receipt.hostSteps.map((hostStep, index) => parseHostStepNode(hostStep, `${receiptPath} hostSteps[${index}]`));
359
+ assertUniqueHostStepIds(hostSteps, receiptPath);
360
+ }
361
+ const workflowResolution = parseWorkflowResolution(receipt.workflowResolution, receiptPath);
362
+ const terminalOutcome = parseTerminalOutcome(receipt.terminalOutcome, `Invalid workflow receipt '${receiptPath}': terminalOutcome`);
363
+ const recovery = parseRecovery(receipt.recovery, workflowRunId, entries, receiptPath);
364
+ return { version: 1, workflowRunId, state: receipt.state, createdAt: receipt.createdAt, entries, ...hostSteps?.length ? { hostSteps } : {}, ...workflowChildren ? { workflowChildren } : {}, ...workflowResolution ? { workflowResolution } : {}, ...terminalOutcome ? { terminalOutcome } : {}, ...recovery ? { recovery } : {} };
365
+ }
366
+ export function resolveWorkflowReceiptResumeEntry(input) {
367
+ if (input.reference.latest !== true)
368
+ throw new Error("Keyed workflow receipt resume requires latest: true.");
369
+ const key = assertKey(input.reference.key, "keyed resume key");
370
+ const receipt = readWorkflowReceipt(input.asyncDirRoot, input.reference.workflowRunId.trim());
371
+ const entry = receipt.entries[key];
372
+ if (!entry)
373
+ throw new Error(`Workflow receipt '${receipt.workflowRunId}' has no child key '${key}'.`);
374
+ assertResumableEntry(entry, receipt.workflowRunId, key);
375
+ input.assertResumable?.(entry.latestRunId);
376
+ return entry;
377
+ }
378
+ function assertResumableEntry(entry, workflowRunId, key) {
379
+ if (entry.resumability.state !== "resumable")
380
+ throw new Error(`Workflow receipt '${workflowRunId}' child '${key}' is not resumable: ${entry.resumability.reason}.`);
381
+ if (!entry.latestRunId)
382
+ throw new Error(`Workflow receipt '${workflowRunId}' child '${key}' has no retained run id.`);
383
+ }
384
+ export function resolveWorkflowReceiptResume(input) {
385
+ const entry = resolveWorkflowReceiptResumeEntry(input);
386
+ return entry.latestRunId;
387
+ }
@@ -0,0 +1,189 @@
1
+ import { workflowChildSummary } from "./workflow-child-summary.js";
2
+ export const UNSUPPORTED_DETACHED_WORKFLOW_CONTINUATION = "unsupported-continuation: detached workflow child settled, but JavaScript workflow continuation was not persisted. Resume the workflow explicitly instead of treating the completed child as top-level workflow completion.";
3
+ export const INTERRUPTED_DETACHED_CHILD = "Interrupted. Waiting for explicit next action.";
4
+ export const EVIDENCE_PERSISTENCE_FAILED = "evidence-persistence-failed";
5
+ function cloneWorkflowStatus(status) {
6
+ return {
7
+ ...status,
8
+ steps: status.steps?.map((step) => ({ ...step })),
9
+ workflow: status.workflow ? { ...status.workflow, trace: [...status.workflow.trace ?? []] } : status.workflow
10
+ };
11
+ }
12
+ function workflowState(status) {
13
+ return status.state === "complete" ? "completed" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed";
14
+ }
15
+ function withWorkflowChildren(status) {
16
+ return {
17
+ ...status,
18
+ workflowChildren: workflowChildSummary({
19
+ parentToolCallId: status.toolCallId ?? status.runId,
20
+ workflowRunId: status.runId,
21
+ workflowState: workflowState(status),
22
+ inventoryComplete: true,
23
+ trace: status.workflow?.trace,
24
+ steps: status.steps
25
+ })
26
+ };
27
+ }
28
+ export function findWorkflowSettlementStep(status, childRunId, workflowKey, sessionFile) {
29
+ const exact = status.steps?.find((candidate) => candidate.runId === childRunId);
30
+ if (exact || !workflowKey || !sessionFile)
31
+ return exact;
32
+ const candidates = status.steps?.filter((candidate) => candidate.runId === undefined && candidate.workflowKey === workflowKey && candidate.sessionFile === sessionFile) ?? [];
33
+ return candidates.length === 1 ? candidates[0] : undefined;
34
+ }
35
+ export function promoteSettledPausedWorkflow(status, now = Date.now()) {
36
+ if (status.mode !== "workflow" || status.state !== "paused")
37
+ return;
38
+ const next = cloneWorkflowStatus(status);
39
+ const stillOpen = next.steps?.some((candidate) => candidate.status === "running" || candidate.status === "paused" && candidate.activityState === "needs_attention") === true;
40
+ if (stillOpen || !next.steps?.length)
41
+ return;
42
+ const failed = next.steps.some((candidate) => candidate.status === "failed");
43
+ next.lastUpdate = now;
44
+ next.state = "failed";
45
+ next.endedAt = now;
46
+ delete next.activityState;
47
+ if (!failed)
48
+ next.error = UNSUPPORTED_DETACHED_WORKFLOW_CONTINUATION;
49
+ return withWorkflowChildren(next);
50
+ }
51
+ export function applyDetachedChildSettlement(status, input) {
52
+ if (status.mode !== "workflow" || status.state !== "paused")
53
+ return;
54
+ const next = cloneWorkflowStatus(status);
55
+ const step = findWorkflowSettlementStep(next, input.childRunId, input.workflowKey, input.result.sessionFile);
56
+ if (!step)
57
+ return;
58
+ step.runId ??= input.childRunId;
59
+ const succeeded = input.result.exitCode === 0 && !input.result.error && !input.result.interrupted;
60
+ const failedSiblingError = next.steps?.find((candidate) => {
61
+ const candidateStep = candidate;
62
+ return candidateStep !== step && candidateStep.status === "failed" && !candidateStep.interrupted && candidateStep.error;
63
+ })?.error;
64
+ const interruptedChildError = next.steps?.find((candidate) => {
65
+ const candidateStep = candidate;
66
+ return candidateStep.status === "failed" && candidateStep.interrupted && candidateStep.error;
67
+ })?.error;
68
+ const now = input.now ?? Date.now();
69
+ step.status = succeeded ? "completed" : "failed";
70
+ step.endedAt = now;
71
+ delete step.activityState;
72
+ delete step.currentTool;
73
+ delete step.currentToolStartedAt;
74
+ if (input.result.sessionFile)
75
+ step.sessionFile = input.result.sessionFile;
76
+ if (input.result.sessionName)
77
+ step.sessionName = input.result.sessionName;
78
+ if (succeeded) {
79
+ delete step.error;
80
+ delete step.interrupted;
81
+ } else if (input.result.interrupted || input.result.stopped) {
82
+ step.error = input.result.error ?? INTERRUPTED_DETACHED_CHILD;
83
+ step.interrupted = true;
84
+ if (input.result.stopped)
85
+ step.stopped = true;
86
+ } else {
87
+ delete step.interrupted;
88
+ delete step.stopped;
89
+ if (input.result.error)
90
+ step.error = input.result.error;
91
+ }
92
+ next.lastUpdate = now;
93
+ const promoted = promoteSettledPausedWorkflow(next, now);
94
+ if (promoted?.state === "failed" && failedSiblingError)
95
+ promoted.error = failedSiblingError;
96
+ else if (promoted?.state === "failed" && (input.result.interrupted || input.result.stopped))
97
+ promoted.error = input.result.error ?? INTERRUPTED_DETACHED_CHILD;
98
+ else if (promoted?.state === "failed" && input.result.error)
99
+ promoted.error = input.result.error;
100
+ else if (promoted?.state === "failed" && interruptedChildError)
101
+ promoted.error = interruptedChildError;
102
+ return withWorkflowChildren(promoted ?? next);
103
+ }
104
+ export function classifyWorkflowSettlement(status, interrupted = false) {
105
+ if (status.state !== "complete" && status.state !== "failed")
106
+ return;
107
+ if (status.steps?.some((step) => {
108
+ const candidate = step;
109
+ return candidate.status === "failed" && !candidate.interrupted;
110
+ }))
111
+ return "failed-child";
112
+ if (interrupted || status.steps?.some((step) => {
113
+ const candidate = step;
114
+ return candidate.status === "stopped" || candidate.stopped || candidate.interrupted || candidate.error === INTERRUPTED_DETACHED_CHILD;
115
+ }))
116
+ return "interrupted-child";
117
+ return "settled-awaiting-resume";
118
+ }
119
+ export function workflowRecoveryActions(receipt) {
120
+ if (!receipt)
121
+ return [];
122
+ return Object.values(receipt.entries).flatMap((entry) => entry.resumability.state === "resumable" ? [{ key: entry.key, call: "runs.run", resume: { workflowRunId: receipt.workflowRunId, key: entry.key, latest: true }, taskRequired: true }] : []);
123
+ }
124
+ export function workflowTerminalOutcomeForResult(result) {
125
+ if (result.timedOut)
126
+ return { state: "partial", reason: "timeout" };
127
+ if (result.turnBudgetExceeded || result.toolBudgetBlocked)
128
+ return { state: "partial", reason: "budget_exhausted" };
129
+ return;
130
+ }
131
+ export function workflowOutputPathMappingSummary(children) {
132
+ const mappings = children.flatMap((entry) => {
133
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
134
+ return [];
135
+ const child = entry;
136
+ return child.outputPathMapping ? [`'${child.workflowKey ?? "child"}': requested ${child.outputPathMapping.requestedPath} -> saved ${child.outputPathMapping.savedPath}`] : [];
137
+ });
138
+ return mappings.length > 0 ? ` Output path mappings: ${mappings.join("; ")}.` : "";
139
+ }
140
+ export function planWorkflowSettlement(input) {
141
+ const now = input.now ?? Date.now();
142
+ let status = withWorkflowChildren(cloneWorkflowStatus(input.status));
143
+ let summary = input.summary;
144
+ let receipt = input.receipt;
145
+ let resolution = input.resolution;
146
+ if (input.receiptPersistenceError) {
147
+ const diagnostic = `${EVIDENCE_PERSISTENCE_FAILED}: ${input.receiptPersistenceError}`;
148
+ status = withWorkflowChildren({ ...status, state: "failed", error: diagnostic, activityState: undefined, endedAt: now, lastUpdate: now });
149
+ summary = `${diagnostic} Available child evidence was preserved, but workflow completion was not accepted.`;
150
+ receipt = undefined;
151
+ if (!resolution)
152
+ resolution = classifyWorkflowSettlement(status);
153
+ }
154
+ const recovery = workflowRecoveryActions(receipt);
155
+ if (receipt) {
156
+ receipt = {
157
+ ...receipt,
158
+ state: status.state === "complete" ? "complete" : status.state === "paused" ? "paused" : status.state === "stopped" ? "stopped" : "failed",
159
+ workflowChildren: status.workflowChildren,
160
+ ...resolution ? { workflowResolution: resolution, recovery } : {}
161
+ };
162
+ }
163
+ const publicResult = {
164
+ ...input.baseResult,
165
+ success: status.state === "complete",
166
+ state: status.state,
167
+ summary,
168
+ error: status.state === "complete" ? undefined : status.error ?? summary,
169
+ stopped: status.stopped ? true : undefined,
170
+ activityState: status.activityState,
171
+ workflowChildren: status.workflowChildren,
172
+ results: input.children,
173
+ ...input.terminalOutcome ? { terminalOutcome: input.terminalOutcome } : {},
174
+ ...resolution ? { workflowResolution: resolution, recovery } : {},
175
+ ...receipt && input.receiptPath ? { workflowReceipt: { path: input.receiptPath, receipt } } : {},
176
+ timestamp: now
177
+ };
178
+ const terminal = status.state === "complete" || status.state === "failed" || status.state === "partial" || status.state === "stopped";
179
+ const completionEvent = terminal ? {
180
+ type: "subagent.workflow.completed",
181
+ state: status.state,
182
+ ...resolution ? { workflowResolution: resolution } : {},
183
+ ...input.terminalOutcome ? { terminalOutcome: input.terminalOutcome } : {},
184
+ ...status.error ? { error: status.error } : {},
185
+ ...status.activityState ? { activityState: status.activityState } : {},
186
+ ...input.eventMetadata
187
+ } : undefined;
188
+ return { status, publicResult, receipt, recovery, completionEvent };
189
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckmind/dm-windows-x64",
3
- "version": "0.61.4",
3
+ "version": "0.61.9",
4
4
  "description": "DuckMind (dm) binary payload for windows x64",
5
5
  "license": "MIT",
6
6
  "os": [
@@ -27,11 +27,12 @@
27
27
  "node": ">=20.0.0"
28
28
  },
29
29
  "dependencies": {
30
+ "acorn": "8.18.0",
30
31
  "jiti": "2.7.0",
31
32
  "typebox": "^1.1.34",
32
- "@ff-labs/fff-node": "*",
33
- "@sinclair/typebox": "^0.34.48",
33
+ "yaml": "2.8.3",
34
34
  "@mozilla/readability": "^0.6.0",
35
+ "@sinclair/typebox": "^0.34.48",
35
36
  "jsdom": "^29.1.1",
36
37
  "pdf-parse": "^2.4.5",
37
38
  "turndown": "^7.1.2"
@@ -1,21 +0,0 @@
1
- {
2
- "name": "dm-fff",
3
- "version": "0.6.0",
4
- "description": "DM extension: FFF-powered fuzzy file and content search",
5
- "type": "module",
6
- "license": "MIT",
7
- "keywords": [
8
- "duckmind",
9
- "dm",
10
- "fff",
11
- "search",
12
- "grep",
13
- "fuzzy-search",
14
- "ai-agent"
15
- ],
16
- "dm": {
17
- "extensions": [
18
- "./src/index.js"
19
- ]
20
- }
21
- }