@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,278 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { writeAtomicJson } from "../../shared/atomic-json.js";
4
+ import { getSingleResultOutput, readStatus } from "../../shared/utils.js";
5
+ import {
6
+ DIRS,
7
+ SUBAGENT_ASYNC_COMPLETE_EVENT
8
+ } from "../../shared/types.js";
9
+ import { updateActiveRunIndex } from "../background/active-run-index.js";
10
+ import { resultFilePath, writeAsyncResultFile } from "../background/result-files.js";
11
+ import { resolveAsyncResumeTarget } from "../background/async-resume.js";
12
+ import { externalCliReceiptMetadata, normalizeExternalCliRunnerStatus } from "../shared/external-cli-contract.js";
13
+ import { outputPathMappingFromTask } from "../shared/single-output.js";
14
+ import { readWorkflowReceipt, workflowReceiptPath, writeWorkflowReceipt } from "../../workflows/workflow-receipt.js";
15
+ import {
16
+ applyDetachedChildSettlement,
17
+ classifyWorkflowSettlement,
18
+ findWorkflowSettlementStep,
19
+ planWorkflowSettlement,
20
+ promoteSettledPausedWorkflow,
21
+ workflowOutputPathMappingSummary,
22
+ workflowRecoveryActions,
23
+ workflowTerminalOutcomeForResult
24
+ } from "../../workflows/workflow-settlement.js";
25
+ export function applyDetachedChildToPausedWorkflow(status, input) {
26
+ return applyDetachedChildSettlement(status, input);
27
+ }
28
+ export function promotePausedWorkflowIfSettled(status) {
29
+ return promoteSettledPausedWorkflow(status);
30
+ }
31
+ function usageWithValue(usage) {
32
+ return usage && (usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0) ? usage : undefined;
33
+ }
34
+ function workflowResultChildren(status, childRunId, result, existingResults, receipt) {
35
+ const output = getSingleResultOutput(result);
36
+ const outputReference = result.savedOutputPath ?? result.outputReference?.path;
37
+ const outputPathMapping = outputPathMappingFromTask(result.task, outputReference);
38
+ const terminalOutcome = workflowTerminalOutcomeForResult(result);
39
+ const usage = usageWithValue(result.usage);
40
+ if (Array.isArray(existingResults)) {
41
+ return existingResults.map((entry) => {
42
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
43
+ return entry;
44
+ const child = entry;
45
+ if (child.runId !== childRunId)
46
+ return child;
47
+ return {
48
+ ...child,
49
+ success: result.exitCode === 0 && !result.error && !result.interrupted,
50
+ output,
51
+ outputState: output.trim() ? "present" : "absent",
52
+ detached: undefined,
53
+ ...usage ? { usage } : {},
54
+ ...outputReference ? { outputReference } : {},
55
+ ...outputPathMapping ? { outputPathMapping } : {},
56
+ ...result.interrupted || result.stopped ? { interrupted: true } : {},
57
+ ...result.stopped ? { stopped: true } : {},
58
+ ...terminalOutcome ? { terminalOutcome } : {},
59
+ ...result.sessionName ? { sessionName: result.sessionName } : {},
60
+ ...result.sessionFile ? { sessionFile: result.sessionFile } : {},
61
+ ...result.error ? { error: result.error } : {}
62
+ };
63
+ });
64
+ }
65
+ return status.steps?.map((step) => ({
66
+ workflowKey: step.workflowKey,
67
+ agent: step.agent,
68
+ ...step.sessionName ? { sessionName: step.sessionName } : {},
69
+ runId: step.runId,
70
+ success: step.status === "completed" || step.status === "complete",
71
+ output: step.runId === childRunId ? output : "",
72
+ outputState: step.runId === childRunId && output.trim() ? "present" : "absent",
73
+ ...step.runId === childRunId ? { ...usage ? { usage } : {}, ...result.sessionFile ? { sessionFile: result.sessionFile } : {} } : {},
74
+ ...step.runId === childRunId && outputReference ? { outputReference } : step.workflowKey && receipt?.entries[step.workflowKey]?.outputReference ? { outputReference: receipt.entries[step.workflowKey].outputReference } : {},
75
+ ...step.runId === childRunId && outputPathMapping ? { outputPathMapping } : step.outputPathMapping ? { outputPathMapping: step.outputPathMapping } : {},
76
+ ...step.interrupted ? { interrupted: true } : {},
77
+ ...step.runId === childRunId && terminalOutcome ? { terminalOutcome } : step.workflowKey && receipt?.entries[step.workflowKey]?.terminalOutcome ? { terminalOutcome: receipt.entries[step.workflowKey].terminalOutcome } : {},
78
+ ...step.stopped ? { stopped: true } : {},
79
+ ...step.error ? { error: step.error } : {}
80
+ }));
81
+ }
82
+ function reconcileWorkflowReceipt(status, childRunId, result, asyncDir, resolution) {
83
+ const receiptRoot = path.dirname(asyncDir);
84
+ const receiptPath = workflowReceiptPath(receiptRoot, status.runId);
85
+ if (!fs.existsSync(receiptPath))
86
+ return;
87
+ const receipt = readWorkflowReceipt(receiptRoot, status.runId);
88
+ const step = status.steps?.find((candidate) => candidate.runId === childRunId);
89
+ const key = step?.workflowKey;
90
+ if (!key)
91
+ throw new Error(`Workflow receipt '${status.runId}' cannot identify detached child '${childRunId}' by stable key.`);
92
+ const entry = receipt.entries[key];
93
+ if (!entry)
94
+ throw new Error(`Workflow receipt '${status.runId}' has no detached child key '${key}'.`);
95
+ let resumability;
96
+ try {
97
+ const target = resolveAsyncResumeTarget({ id: childRunId, dir: path.join(DIRS.async, childRunId) }, {}, { requireSessionFile: true, sessionId: status.sessionId });
98
+ resumability = target.kind === "revive" ? { state: "resumable" } : { state: "not-resumable", reason: "child is still running" };
99
+ } catch (error) {
100
+ resumability = { state: "not-resumable", reason: error instanceof Error ? error.message : String(error) };
101
+ }
102
+ const outputReference = result.savedOutputPath ?? result.outputReference?.path ?? entry.outputReference;
103
+ const childStatus = readStatus(path.join(DIRS.async, childRunId));
104
+ const externalStep = childStatus?.steps?.length === 1 && childStatus.steps[0]?.runner?.type === "external-cli" ? childStatus.steps[0] : undefined;
105
+ const externalRunner = normalizeExternalCliRunnerStatus(result.runner?.type === "external-cli" ? result.runner : externalStep?.runner);
106
+ const externalProcess = result.externalProcess ?? externalStep?.externalProcess;
107
+ const externalAdapter = externalRunner ? externalCliReceiptMetadata({ runner: externalRunner, externalProcess, outputReference }) : entry.externalAdapter;
108
+ const childTerminalOutcome = workflowTerminalOutcomeForResult(result) ?? entry.terminalOutcome;
109
+ if (externalAdapter)
110
+ resumability = { state: "not-resumable", reason: externalAdapter.nonResumableReason };
111
+ const updatedEntry = resumability.state === "resumable" ? {
112
+ ...entry,
113
+ ...step.agent ? { agent: step.agent } : {},
114
+ ...step.context ? { resolvedContext: step.context } : {},
115
+ latestRunId: entry.latestRunId ?? childRunId,
116
+ resumability,
117
+ ...outputReference ? { outputReference } : {},
118
+ ...childTerminalOutcome ? { terminalOutcome: childTerminalOutcome } : {},
119
+ ...externalAdapter ? { externalAdapter } : {}
120
+ } : {
121
+ ...entry,
122
+ ...step.agent ? { agent: step.agent } : {},
123
+ ...step.context ? { resolvedContext: step.context } : {},
124
+ resumability,
125
+ ...outputReference ? { outputReference } : {},
126
+ ...childTerminalOutcome ? { terminalOutcome: childTerminalOutcome } : {},
127
+ ...externalAdapter ? { externalAdapter } : {}
128
+ };
129
+ const next = {
130
+ ...receipt,
131
+ state: status.state === "complete" ? "complete" : status.state === "stopped" ? "stopped" : status.state === "paused" ? "paused" : "failed",
132
+ entries: {
133
+ ...receipt.entries,
134
+ [key]: updatedEntry
135
+ },
136
+ workflowChildren: status.workflowChildren,
137
+ ...receipt.terminalOutcome ? { terminalOutcome: receipt.terminalOutcome } : {},
138
+ ...resolution ? { workflowResolution: resolution } : {}
139
+ };
140
+ if (resolution)
141
+ next.recovery = workflowRecoveryActions(next);
142
+ else {
143
+ delete next.workflowResolution;
144
+ delete next.recovery;
145
+ }
146
+ writeWorkflowReceipt(asyncDir, next);
147
+ return next;
148
+ }
149
+ function appendDetachedWorkflowEvent(asyncDir, event) {
150
+ const eventsPath = path.join(asyncDir, "events.jsonl");
151
+ try {
152
+ fs.appendFileSync(eventsPath, `${JSON.stringify(event)}
153
+ `, "utf-8");
154
+ } catch (error) {
155
+ console.error(`Failed to append detached workflow event '${eventsPath}':`, error);
156
+ }
157
+ }
158
+ export function reconcileDetachedWorkflowChildCompletion(input) {
159
+ const job = input.state.asyncJobs.get(input.workflowRunId);
160
+ const asyncDir = job?.asyncDir ?? path.join(DIRS.async, input.workflowRunId);
161
+ const status = readStatus(asyncDir);
162
+ if (!status)
163
+ return false;
164
+ const matchingControls = input.workflowKey === undefined ? [] : [...input.state.foregroundControls?.values() ?? []].filter((control) => control.parentWorkflowRunId === input.workflowRunId && control.workflowKey === input.workflowKey);
165
+ const confirmedLiveIdentity = matchingControls.length === 1 && matchingControls[0]?.runId === input.childRunId;
166
+ if (confirmedLiveIdentity) {
167
+ const candidates = status.steps?.filter((candidate) => candidate.workflowKey === input.workflowKey) ?? [];
168
+ const candidate = candidates.length === 1 ? candidates[0] : undefined;
169
+ if (candidate && candidate.runId === undefined && candidate.sessionFile === undefined && candidate.status === "paused" && candidate.activityState === "needs_attention")
170
+ candidate.runId = input.childRunId;
171
+ }
172
+ const next = applyDetachedChildToPausedWorkflow(status, {
173
+ childRunId: input.childRunId,
174
+ result: input.result,
175
+ workflowKey: input.workflowKey
176
+ });
177
+ if (!next)
178
+ return false;
179
+ const outputReference = input.result.savedOutputPath ?? input.result.outputReference?.path;
180
+ const outputPathMapping = outputPathMappingFromTask(input.result.task, outputReference);
181
+ const settledStep = findWorkflowSettlementStep(next, input.childRunId);
182
+ if (settledStep && outputPathMapping)
183
+ settledStep.outputPathMapping = outputPathMapping;
184
+ const resultPath = resultFilePath(DIRS.results, input.workflowRunId);
185
+ let existing;
186
+ try {
187
+ const parsed = JSON.parse(fs.readFileSync(resultPath, "utf-8"));
188
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
189
+ existing = parsed;
190
+ } catch (error) {
191
+ if (error.code !== "ENOENT")
192
+ throw error;
193
+ }
194
+ let receipt;
195
+ let receiptError;
196
+ const resolution = classifyWorkflowSettlement(next, input.result.interrupted);
197
+ try {
198
+ receipt = reconcileWorkflowReceipt(next, input.childRunId, input.result, asyncDir, resolution);
199
+ } catch (error) {
200
+ receiptError = `Failed to reconcile async workflow receipt: ${error instanceof Error ? error.message : String(error)}`;
201
+ }
202
+ const results = workflowResultChildren(next, input.childRunId, input.result, existing?.results, receipt);
203
+ const recovery = workflowRecoveryActions(receipt);
204
+ const summary = `${resolution === "settled-awaiting-resume" ? `Workflow lanes settled after detached child ${input.childRunId} finished. JavaScript workflow continuation was not persisted.${recovery.length ? " Use the listed keyed recovery action to continue a child." : " No retained child is resumable."}` : next.state === "complete" ? `Workflow completed after detached child ${input.childRunId} finished.` : next.error ?? (typeof existing?.summary === "string" ? existing.summary : "Workflow failed.")}${workflowOutputPathMappingSummary(results)}`;
205
+ const plan = planWorkflowSettlement({
206
+ status: next,
207
+ summary,
208
+ children: results,
209
+ baseResult: {
210
+ ...existing ?? {},
211
+ id: next.runId,
212
+ runId: next.runId,
213
+ toolCallId: next.toolCallId,
214
+ agent: "workflow",
215
+ mode: "workflow",
216
+ endedAt: next.endedAt,
217
+ workflow: next.workflow,
218
+ reconciledFromDetachedChild: input.childRunId,
219
+ asyncDir,
220
+ cwd: next.cwd,
221
+ sessionId: next.sessionId ?? (typeof existing?.sessionId === "string" ? existing.sessionId : undefined),
222
+ completionOwnerId: next.completionOwnerId
223
+ },
224
+ receipt,
225
+ receiptPath: path.join(asyncDir, "workflow-receipt.json"),
226
+ receiptPersistenceError: receiptError,
227
+ resolution,
228
+ terminalOutcome: receipt?.terminalOutcome,
229
+ eventMetadata: { reconciledFromDetachedChild: input.childRunId }
230
+ });
231
+ writeAtomicJson(path.join(asyncDir, "status.json"), plan.status);
232
+ updateActiveRunIndex(asyncDir, plan.status.state, plan.status.toolCallId);
233
+ if (job) {
234
+ job.status = plan.status.state;
235
+ job.updatedAt = plan.status.lastUpdate;
236
+ job.activityState = plan.status.activityState;
237
+ job.steps = plan.status.steps?.map((step, index) => ({ ...step, index }));
238
+ job.workflow = plan.status.workflow;
239
+ }
240
+ writeAsyncResultFile(resultPath, plan.publicResult);
241
+ if (receiptError) {
242
+ appendDetachedWorkflowEvent(asyncDir, {
243
+ ts: Date.now(),
244
+ runId: input.workflowRunId,
245
+ type: "subagent.workflow.receipt_write_failed",
246
+ error: receiptError,
247
+ reconciledFromDetachedChild: input.childRunId
248
+ });
249
+ }
250
+ if (plan.completionEvent) {
251
+ appendDetachedWorkflowEvent(asyncDir, {
252
+ ts: Date.now(),
253
+ runId: input.workflowRunId,
254
+ ...plan.completionEvent,
255
+ recovery: plan.recovery
256
+ });
257
+ input.events?.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
258
+ id: input.workflowRunId,
259
+ runId: input.workflowRunId,
260
+ source: "async",
261
+ mode: "workflow",
262
+ agent: "workflow",
263
+ success: plan.status.state === "complete",
264
+ state: plan.status.state,
265
+ ...resolution ? { workflowResolution: resolution } : {},
266
+ ...plan.receipt?.terminalOutcome ? { terminalOutcome: plan.receipt.terminalOutcome } : {},
267
+ recovery: plan.recovery,
268
+ summary: typeof plan.publicResult.summary === "string" ? plan.publicResult.summary : plan.status.error,
269
+ reconciledFromDetachedChild: input.childRunId,
270
+ results,
271
+ sessionId: plan.status.sessionId,
272
+ completionOwnerId: plan.status.completionOwnerId,
273
+ timestamp: Date.now(),
274
+ triggerTurn: true
275
+ });
276
+ }
277
+ return true;
278
+ }
@@ -0,0 +1,155 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { readStatus } from "../../shared/utils.js";
5
+ import { steeringReceipt } from "../background/steering.js";
6
+ import {
7
+ consumeSteerAckFromDir,
8
+ readSteerCapability,
9
+ steerAcksDir,
10
+ steerCapabilityPath,
11
+ stepSteerInboxDir,
12
+ writeSteerRequestToExistingDir
13
+ } from "../background/control-channel.js";
14
+ function activeWorkflowError(state, workflowRunId, asyncDirRoot) {
15
+ if (!state.currentSessionId)
16
+ return "Workflow steering requires an active parent session.";
17
+ if (!state.workflowControllers?.has(workflowRunId))
18
+ return `Workflow '${workflowRunId}' has no live foreground child.`;
19
+ const status = readStatus(path.join(asyncDirRoot, workflowRunId));
20
+ if (!status || status.mode !== "workflow" || status.state !== "running" && status.state !== "queued") {
21
+ return `Workflow '${workflowRunId}' has no live foreground child.`;
22
+ }
23
+ if (status.sessionId !== state.currentSessionId)
24
+ return `Workflow '${workflowRunId}' was not found in the active session.`;
25
+ return;
26
+ }
27
+ function controlIsLiveInWorkflow(control, workflowRunId, sessionId) {
28
+ return control.parentWorkflowRunId === workflowRunId && control.sessionId === sessionId && Boolean(control.workflowSteeringDir) && (control.activeChildren?.size ?? 0) > 0;
29
+ }
30
+ export function resolveWorkflowForegroundSteeringTarget(input) {
31
+ const { state, childRunId, asyncDirRoot } = input;
32
+ if (childRunId) {
33
+ const control = state.foregroundControls.get(childRunId);
34
+ if (!control?.parentWorkflowRunId)
35
+ return { ok: false, message: `Foreground run '${childRunId}' is not a live workflow-owned child.` };
36
+ const workflowRunId = control.parentWorkflowRunId;
37
+ const workflowError = activeWorkflowError(state, workflowRunId, asyncDirRoot);
38
+ if (workflowError)
39
+ return { ok: false, message: workflowError };
40
+ if (!controlIsLiveInWorkflow(control, workflowRunId, state.currentSessionId)) {
41
+ return { ok: false, message: `Foreground run '${childRunId}' is not a live workflow-owned child in the active session.` };
42
+ }
43
+ return { ok: true, target: { control, workflowRunId, sourceRunId: childRunId } };
44
+ }
45
+ const workflowRunId = input.workflowRunId;
46
+ if (!workflowRunId)
47
+ return { ok: false, message: "Workflow steering requires a workflow or child run id." };
48
+ const workflowError = activeWorkflowError(state, workflowRunId, asyncDirRoot);
49
+ if (workflowError)
50
+ return { ok: false, message: workflowError };
51
+ const controls = [...state.foregroundControls.values()].filter((control) => controlIsLiveInWorkflow(control, workflowRunId, state.currentSessionId));
52
+ if (controls.length === 0)
53
+ return { ok: false, message: `Workflow '${workflowRunId}' has no live foreground child.` };
54
+ if (controls.length > 1)
55
+ return { ok: false, message: `Workflow '${workflowRunId}' has ${controls.length} live foreground children; steer a child run id instead.` };
56
+ return { ok: true, target: { control: controls[0], workflowRunId, sourceRunId: workflowRunId } };
57
+ }
58
+ function managementError(message) {
59
+ return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
60
+ }
61
+ export async function steerWorkflowForegroundTarget(input) {
62
+ const { control, sourceRunId } = input.target;
63
+ const routeDir = control.workflowSteeringDir;
64
+ if (!routeDir || !fs.existsSync(routeDir))
65
+ return managementError(`Foreground run '${control.runId}' has no live workflow steering route.`);
66
+ const activeIndexes = [...control.activeChildren?.keys() ?? []].sort((left, right) => left - right);
67
+ const index = input.index ?? (activeIndexes.length === 1 ? activeIndexes[0] : undefined);
68
+ if (index === undefined) {
69
+ return managementError(activeIndexes.length === 0 ? `Foreground run '${control.runId}' has no live child session.` : `Foreground run '${control.runId}' has ${activeIndexes.length} live child sessions; provide index.`);
70
+ }
71
+ if (!activeIndexes.includes(index))
72
+ return managementError(`Foreground run '${control.runId}' child ${index} is not live.`);
73
+ const capability = readSteerCapability(routeDir, index);
74
+ if (capability?.supported === false)
75
+ return managementError(`Foreground run '${control.runId}' child ${index} does not support steering.`);
76
+ const request = {
77
+ type: "steer",
78
+ id: randomUUID(),
79
+ ts: Date.now(),
80
+ message: input.message.trim(),
81
+ ...input.mode && input.mode !== "steer" ? { mode: input.mode } : {},
82
+ targetIndex: index,
83
+ source: "steer-action"
84
+ };
85
+ try {
86
+ writeSteerRequestToExistingDir(stepSteerInboxDir(routeDir, index), request);
87
+ } catch (error) {
88
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
89
+ return managementError(`Foreground run '${control.runId}' has no live workflow steering route.`);
90
+ }
91
+ return managementError(`Failed to queue steering for foreground run ${control.runId}: ${error instanceof Error ? error.message : String(error)}`);
92
+ }
93
+ const deadline = Date.now() + (input.ackTimeoutMs ?? 3000);
94
+ let ack;
95
+ let routeRemoved = false;
96
+ while (Date.now() <= deadline) {
97
+ ack = consumeSteerAckFromDir(steerAcksDir(routeDir, index), request.id);
98
+ if (ack || input.signal?.aborted)
99
+ break;
100
+ if (!fs.existsSync(routeDir)) {
101
+ routeRemoved = true;
102
+ break;
103
+ }
104
+ await new Promise((resolve) => setTimeout(resolve, Math.min(50, Math.max(1, deadline - Date.now()))));
105
+ }
106
+ if (routeRemoved || !ack && !input.signal?.aborted && !fs.existsSync(routeDir)) {
107
+ return managementError(`Foreground run '${control.runId}' has no live child session.`);
108
+ }
109
+ const target = ack?.state === "delivered" ? { index, state: "delivered", deliveredAt: ack.ts } : ack?.state === "queued" ? { index, state: "queued" } : ack?.state === "failed" ? { index, state: "failed", reason: ack.message } : { index, state: "pending" };
110
+ const steering = {
111
+ requestId: request.id,
112
+ state: ack?.state === "delivered" ? "delivered" : ack?.state === "failed" ? "failed" : "pending",
113
+ deliveryStatus: ack?.state === "delivered" ? "delivered" : "queued",
114
+ sourceRunId,
115
+ targets: [target]
116
+ };
117
+ if (input.signal?.aborted) {
118
+ return { content: [{ type: "text", text: steeringReceipt(request.message, `Steering pending for foreground run ${control.runId} (request ${request.id}); caller aborted before acknowledgment.`) }], details: { mode: "management", results: [], steering } };
119
+ }
120
+ if (ack?.state === "delivered") {
121
+ return { content: [{ type: "text", text: steeringReceipt(request.message, `Steering delivered for foreground run ${control.runId} (request ${request.id}).`) }], details: { mode: "management", results: [], steering } };
122
+ }
123
+ if (ack?.state === "queued") {
124
+ return { content: [{ type: "text", text: steeringReceipt(request.message, `Steering queued for foreground run ${control.runId} (request ${request.id}).`) }], details: { mode: "management", results: [], steering } };
125
+ }
126
+ if (ack?.state === "failed") {
127
+ return { content: [{ type: "text", text: steeringReceipt(request.message, `Steering failed for foreground run ${control.runId} (request ${request.id}): ${ack.message}`) }], isError: true, details: { mode: "management", results: [], steering } };
128
+ }
129
+ return { content: [{ type: "text", text: steeringReceipt(request.message, `Steering pending for foreground run ${control.runId} (request ${request.id}); no acknowledgment was received.`) }], details: { mode: "management", results: [], steering } };
130
+ }
131
+ export function workflowForegroundSteeringDir(asyncDirRoot, workflowRunId, childRunId) {
132
+ return path.join(asyncDirRoot, workflowRunId, "control", "workflow-foreground", childRunId);
133
+ }
134
+ export function removeWorkflowForegroundSteeringRoute(control) {
135
+ if (!control.workflowSteeringDir)
136
+ return;
137
+ try {
138
+ fs.rmSync(control.workflowSteeringDir, { recursive: true, force: true });
139
+ } catch (error) {
140
+ console.warn(`[dm-subagents] Failed to remove workflow foreground steering route '${control.workflowSteeringDir}': ${error instanceof Error ? error.message : String(error)}`);
141
+ }
142
+ }
143
+ export function workflowForegroundSteeringLaunchOptions(control, index) {
144
+ if (!control?.workflowSteeringDir)
145
+ return {};
146
+ const steerInboxDir = stepSteerInboxDir(control.workflowSteeringDir, index);
147
+ const steerAckDir = steerAcksDir(control.workflowSteeringDir, index);
148
+ fs.mkdirSync(steerInboxDir, { recursive: true });
149
+ fs.mkdirSync(steerAckDir, { recursive: true });
150
+ return {
151
+ steerInboxDir,
152
+ steerCapabilityPath: steerCapabilityPath(control.workflowSteeringDir, index),
153
+ steerAckDir
154
+ };
155
+ }
@@ -0,0 +1,97 @@
1
+ export const ABORT_RECOVERY_PROMPT = "The prior run ended from a provider/transport abort after useful progress. Continue from the current files and transcript. Do not restart. Fix any validation failure or write the required report. Finish with final output.";
2
+ const PROVIDER_ABORT_PATTERN = /(?:provider|transport|connection|stream|socket|request).*(?:abort|closed|reset|ended|terminated|error|fail)|(?:abort|closed|reset|ended|terminated|error|fail).*(?:provider|transport|connection|stream|socket|request)/i;
3
+ const ABORT_ERROR_PATTERN = /\b(?:operation|request|response|stream|connection|transport|provider)?\s*(?:was\s+)?aborted\b/i;
4
+ const TOOL_FAILURE_PREFIX = /^[\w.:@/-]+ failed (?:(?:\(exit \d+\):)|(?:with exit code \d+))(?:\s|$)/i;
5
+ function isProviderAbortError(error) {
6
+ return !TOOL_FAILURE_PREFIX.test(error.trim()) && (PROVIDER_ABORT_PATTERN.test(error) || ABORT_ERROR_PATTERN.test(error));
7
+ }
8
+ function record(value) {
9
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
10
+ }
11
+ function contentParts(message) {
12
+ return Array.isArray(message.content) ? message.content : [];
13
+ }
14
+ function terminalAssistant(messages) {
15
+ for (let index = messages.length - 1;index >= 0; index--) {
16
+ const message = record(messages[index]);
17
+ if (message?.role === "assistant")
18
+ return { message, index };
19
+ }
20
+ return { index: messages.length };
21
+ }
22
+ function zeroOutputUsage(message) {
23
+ const usage = record(message.usage);
24
+ return usage !== undefined && (usage.output ?? usage.outputTokens ?? 0) === 0;
25
+ }
26
+ function hasUsefulProgress(messages, terminalIndex) {
27
+ for (let index = 0;index < terminalIndex; index++) {
28
+ const message = record(messages[index]);
29
+ if (!message)
30
+ continue;
31
+ if (message.role === "assistant" && contentParts(message).length > 0)
32
+ return true;
33
+ if (message.role === "toolResult" && message.isError !== true)
34
+ return true;
35
+ }
36
+ return false;
37
+ }
38
+ function hasUnresolvedToolCall(messages) {
39
+ const pending = new Set;
40
+ for (const rawMessage of messages) {
41
+ const message = record(rawMessage);
42
+ if (!message)
43
+ continue;
44
+ if (message.role === "assistant") {
45
+ for (const rawPart of contentParts(message)) {
46
+ const part = record(rawPart);
47
+ if (part?.type === "toolCall" && typeof part.id === "string" && part.id)
48
+ pending.add(part.id);
49
+ }
50
+ } else if (message.role === "toolResult" && typeof message.toolCallId === "string") {
51
+ pending.delete(message.toolCallId);
52
+ }
53
+ }
54
+ return pending.size > 0;
55
+ }
56
+ export function planAbortRecovery(input) {
57
+ const terminal = terminalAssistant(input.messages);
58
+ const message = terminal.message;
59
+ const terminalError = typeof message?.errorMessage === "string" ? message.errorMessage : undefined;
60
+ const emptyZeroUsageTerminal = message !== undefined && contentParts(message).length === 0 && zeroOutputUsage(message);
61
+ const terminalAssistantAbort = message?.stopReason === "aborted" || message?.stopReason === "error" && terminalError !== undefined && isProviderAbortError(terminalError);
62
+ const abortCandidate = emptyZeroUsageTerminal && terminalAssistantAbort;
63
+ const compactionAbortCandidate = input.afterCompactionSettlement === true && abortCandidate;
64
+ const settle = (reason) => ({
65
+ action: "settle",
66
+ reason,
67
+ ...compactionAbortCandidate ? { diagnostic: `Compaction-induced child abort could not be resumed safely: ${reason}.` } : {}
68
+ });
69
+ if (input.alreadyResumed)
70
+ return settle("resume already attempted");
71
+ if (!input.sessionAvailable)
72
+ return settle("retained session unavailable");
73
+ if (input.stopped || input.interrupted)
74
+ return settle("explicit stop or interrupt");
75
+ if (input.processSignal && !compactionAbortCandidate)
76
+ return settle("process terminated by signal");
77
+ if (input.timedOut)
78
+ return settle("elapsed timeout");
79
+ if (input.toolBudgetExhausted || input.usageBudgetExhausted)
80
+ return settle("budget exhausted");
81
+ if (input.structuredOutputFailed)
82
+ return settle("structured output failure");
83
+ if (input.acceptanceFailed)
84
+ return settle("acceptance failure");
85
+ if (input.currentTool)
86
+ return settle(`active tool '${input.currentTool.slice(0, 128)}' remains in flight`);
87
+ if (hasUnresolvedToolCall(input.messages))
88
+ return settle("unresolved tool call remains in transcript");
89
+ if (!input.afterCompactionSettlement)
90
+ return settle("compaction settlement not verified");
91
+ if (!abortCandidate)
92
+ return settle("terminal assistant abort evidence not verified");
93
+ const progressLimit = emptyZeroUsageTerminal ? terminal.index : input.messages.length;
94
+ if (!hasUsefulProgress(input.messages, progressLimit))
95
+ return settle("no useful prior progress");
96
+ return { action: "resume", prompt: ABORT_RECOVERY_PROMPT };
97
+ }