@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,50 @@
1
+ import { formatProcessSignalError } from "./process-signal.js";
2
+ export const SUBAGENT_STARTUP_RETRY_DELAYS_MS = [250, 750, 1500];
3
+ export const MAX_SUBAGENT_STARTUP_FAILURE_DURATION_MS = 2000;
4
+ const SIGKILL_PROCESS_SIGNAL_ERROR = formatProcessSignalError("SIGKILL");
5
+ const EXTENSION_REGISTRATION_CONFLICT_PATTERN = /Failed to load extension\b[^\n]*:\s*(?:Tool|Flag)\s+"[^"]+"\s+conflicts with\b/i;
6
+ export function formatSubagentExtensionConflictError(error, input) {
7
+ if (!error || !input.ambientExtensionsEnabled || !EXTENSION_REGISTRATION_CONFLICT_PATTERN.test(error))
8
+ return error;
9
+ const settings = JSON.stringify({
10
+ subagents: { agentOverrides: { [input.agent]: { extensions: [] } } }
11
+ });
12
+ return `${error}
13
+
14
+ Subagent startup loaded conflicting ambient DM extensions. Retry this run after disabling ambient extension discovery for agent ${JSON.stringify(input.agent)} in project .dm/settings.json: ${settings}. Replace the empty array with only the required extension entry paths when this agent needs extension tools.`;
15
+ }
16
+ function hasUsage(usage) {
17
+ return usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0;
18
+ }
19
+ export function isRetryableSubagentStartupFailure(evidence) {
20
+ return evidence.exitCode !== undefined && evidence.exitCode !== null && evidence.exitCode !== 0 && (!evidence.error?.trim() || evidence.error === SIGKILL_PROCESS_SIGNAL_ERROR) && !evidence.finalOutput?.trim() && evidence.messageCount === 0 && evidence.toolCount === 0 && !hasUsage(evidence.usage) && evidence.durationMs >= 0 && evidence.durationMs <= MAX_SUBAGENT_STARTUP_FAILURE_DURATION_MS && evidence.protocolError === undefined && (evidence.processSignal === undefined || evidence.processSignal === null || evidence.processSignal === "SIGKILL") && evidence.observedMutationAttempt !== true && evidence.detached !== true && evidence.interrupted !== true && evidence.timedOut !== true && evidence.stopped !== true && evidence.turnBudgetExceeded !== true;
21
+ }
22
+ export function formatSubagentStartupRetryNote(input) {
23
+ return `[startup-retry] ${input.model} exited before model or tool activity (attempt ${input.attempt}/${input.maxAttempts}). Retrying the same model in ${input.delayMs}ms.`;
24
+ }
25
+ export function formatSubagentStartupRetryExhaustedError(input) {
26
+ return `Subagent failed to start after ${input.attempts} attempts on ${input.model}; no model, tool, output, usage, or diagnostic activity was observed. This may be a concurrent DM startup race. Retry the run or temporarily lower subagent concurrency.`;
27
+ }
28
+ export async function waitForSubagentStartupRetry(delayMs, signals) {
29
+ const activeSignals = signals.filter((signal) => Boolean(signal));
30
+ if (activeSignals.some((signal) => signal.aborted))
31
+ return false;
32
+ if (delayMs <= 0)
33
+ return true;
34
+ return await new Promise((resolve) => {
35
+ let settled = false;
36
+ const finish = (shouldRetry) => {
37
+ if (settled)
38
+ return;
39
+ settled = true;
40
+ clearTimeout(timer);
41
+ for (const signal of activeSignals)
42
+ signal.removeEventListener("abort", abort);
43
+ resolve(shouldRetry);
44
+ };
45
+ const abort = () => finish(false);
46
+ const timer = setTimeout(() => finish(true), delayMs);
47
+ for (const signal of activeSignals)
48
+ signal.addEventListener("abort", abort, { once: true });
49
+ });
50
+ }
@@ -0,0 +1,130 @@
1
+ const REVIEW_ONLY_PATTERNS = [
2
+ /\breview only\b/i,
3
+ /\bsuggest fixes only\b/i,
4
+ /\bonly return findings\b/i,
5
+ /\breturn findings only\b/i
6
+ ];
7
+ const REVIEWER_REQUIRED_EDIT_PATTERNS = [
8
+ /\bmust\s+(?:edit|modify|change|fix|patch|apply|implement)\b/i,
9
+ /\brequired\s+to\s+(?:edit|modify|change|fix|patch|apply|implement)\b/i,
10
+ /(?:^|[.!?\n]\s*)implement\s+(?:the\s+)?(?:approved|requested|specified|file|code|source|fix(?:es)?|changes?)\b/i,
11
+ /\bregardless\s+of\s+findings\b/i,
12
+ /\balways\s+(?:edit|modify|change|fix|patch|apply|implement)\b/i,
13
+ /\bapply\s+(?:the\s+)?fix(?:es)?\s+directly\b/i,
14
+ /\bmake\s+(?:the\s+)?code\s+changes\b/i
15
+ ];
16
+ const NO_EDIT_PROHIBITION_PATTERN = /\b(?:do not|don't|must not)\s+(?:edit|modify|write(?:\s+to)?|touch|change)\b((?:(?!\b(?:but|and|then)\b)[^.;,:!?\n–—-])*)/gi;
17
+ const GENERIC_PROHIBITION_OBJECT = /^\s*(?:(?:any|all|the|these|those|your|our|existing|project|product|source|sources|config|configs|repo|repository)[\s/,-]*)*(?:files?|code|codebase|sources?|anything|repo(?:sitory)?)?\s*$/i;
18
+ const SCOPED_NO_EDIT_CONSTRAINT_PATTERNS = [
19
+ /\bdo not edit files?\s+outside\b/i,
20
+ /\bdo not edit\s+outside\b/i,
21
+ /\bdo not edit\s+unrelated files?\b/i,
22
+ /\bdo not change\s+unrelated files?\b/i,
23
+ /\bdo not modify\s+unrelated files?\b/i
24
+ ];
25
+ const NO_TOOL_INTENT_PATTERNS = [
26
+ /\bno tools? needed\b/i,
27
+ /\bno tools? required\b/i,
28
+ /\bwithout using tools\b/i,
29
+ /\bdo not use tools\b/i,
30
+ /\bdon't use tools\b/i
31
+ ];
32
+ const READ_ONLY_DELIVERABLE_PATTERNS = [
33
+ /\b(?:draft|write|compose|prepare|produce)\s+(?:(?:a|an|the)\s+)?(?:github\s+)?(?:issue|bug report|issue draft|issue body|proposal|plan|report|summary|findings?|analysis|recommendations?)\b/i,
34
+ /\b(?:issue|bug report)\s+(?:draft|body|template)\b/i,
35
+ /\b(?:return|provide|produce)\s+(?:text|markdown|answer|findings?|recommendations?)\s+only\b/i
36
+ ];
37
+ const RESEARCH_AGENT_PATTERNS = [
38
+ /\binvestigate\b/i,
39
+ /\bscout\b/i,
40
+ /\bresearch(?:er)?\b/i
41
+ ];
42
+ const SEVERITY_COMPOUND_PATTERN = /\b(?:must|should|needs)[\-\u2010-\u2015](?:fix|edit|update|add|remove|replace|create|apply|make|do|implement|modify|delete|patch)\b/gi;
43
+ function stripSeverityCompounds(task) {
44
+ return task.replace(SEVERITY_COMPOUND_PATTERN, " ");
45
+ }
46
+
47
+ export { stripSeverityCompounds };
48
+ const FIX_OR_PATCH_IMPLEMENTATION_PATTERN = /\b(?:fix|patch)\s+(?:(?:it|this|that|them|each|any|all|these|those)\b|(?:(?:a|an|the|any|all)\s+)?(?:(?:failing|failed|broken|flaky|red|cold|start|current|existing|reported|approved|known|regression|unit|integration|e2e|source|typescript|type-?script|ts|type-?check|compiler)\s+)*(?:bug|defect|issues?|problems?|failures?|regressions?|tests?|errors?|items?|typos?|code|source|implementation|component|function|module|class|method|logic|file|files|readme|docs?|changelog|package\.json|config|manifest|extension|prompt|command|lint(?:ing)?|build|ci|type-?check|type\s+checking)\b)/i;
49
+ const WORKER_IMPLEMENTATION_PATTERNS = [
50
+ /\b(?:implement|edit|modify|refactor|delete)\b/i,
51
+ FIX_OR_PATCH_IMPLEMENTATION_PATTERN,
52
+ /\b(?:update|add|remove|replace|create)\b(?!\s+(?:(?:a|an|the)\s+)?(?:report|summary|findings?)(?:\b|$))/i,
53
+ /\bapply\s+(?:the\s+)?(?:(?:suggested|proposed|recommended)\s+)?(?:changes?|fix(?:es)?|patch)\b/i,
54
+ /\bmake\s+(?:the\s+)?changes\b/i,
55
+ /\bdo those fixes\b/i
56
+ ];
57
+ const GENERAL_IMPLEMENTATION_PATTERNS = [
58
+ /\b(?:implement|edit|modify|refactor)\b/i,
59
+ FIX_OR_PATCH_IMPLEMENTATION_PATTERN,
60
+ /\bapply\s+(?:the\s+)?(?:(?:suggested|proposed|recommended)\s+)?(?:changes?|fix(?:es)?|patch)\b/i,
61
+ /\bmake\s+(?:the\s+)?changes\b/i,
62
+ /\bdo those fixes\b/i,
63
+ /\b(?:update|add|remove|replace|delete|create)\s+(?:the\s+)?(?:file|files|code|source|implementation|test|tests|component|function|module|class|method|logic|import|imports|readme|docs?|changelog|package\.json|config|manifest|extension|prompt|command)\b/i
64
+ ];
65
+ function stripFrameworkInstructions(task) {
66
+ return task.split(`
67
+ `).filter((line) => !/^\s*\[(?:Write to|Read from):/i.test(line)).filter((line) => !/^\s*(?:Create and maintain progress at:|Update progress at:|\*\*Output:\*\*|Write your findings to(?: exactly this path)?:|Return the complete artifact in your final response\.|The runtime will persist it to exactly this path:|Do not call contact_supervisor merely because no write-capable tool is available\.|This path is authoritative for this run\.|Ignore any other output filename or output path mentioned elsewhere)/i.test(line)).join(`
68
+ `);
69
+ }
70
+ function stripPatterns(task, patterns) {
71
+ let stripped = task;
72
+ for (const pattern of patterns) {
73
+ const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
74
+ stripped = stripped.replace(new RegExp(pattern.source, flags), " ");
75
+ }
76
+ return stripped;
77
+ }
78
+ function analyzeNoEditProhibitions(taskText) {
79
+ let present = REVIEW_ONLY_PATTERNS.some((pattern) => pattern.test(taskText)) || NO_TOOL_INTENT_PATTERNS.some((pattern) => pattern.test(taskText));
80
+ let blanket = present;
81
+ let strippedText = stripPatterns(taskText, [...REVIEW_ONLY_PATTERNS, ...NO_TOOL_INTENT_PATTERNS]);
82
+ strippedText = strippedText.replace(new RegExp(NO_EDIT_PROHIBITION_PATTERN.source, NO_EDIT_PROHIBITION_PATTERN.flags), (_match, object) => {
83
+ present = true;
84
+ if (GENERIC_PROHIBITION_OBJECT.test(object))
85
+ blanket = true;
86
+ return " ";
87
+ });
88
+ return { present, blanket, strippedText };
89
+ }
90
+ function taskHasReadOnlyDeliverable(taskText) {
91
+ return READ_ONLY_DELIVERABLE_PATTERNS.some((pattern) => pattern.test(taskText));
92
+ }
93
+ function isReviewerStyleAgent(agent) {
94
+ return /\b(?:advisor|reviewer|oracle)\b/i.test(agent);
95
+ }
96
+ function hasImplementationIntent(agent, taskText) {
97
+ if (isReviewerStyleAgent(agent))
98
+ return REVIEWER_REQUIRED_EDIT_PATTERNS.some((pattern) => pattern.test(taskText));
99
+ if (agent === "worker")
100
+ return WORKER_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));
101
+ return GENERAL_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));
102
+ }
103
+ export function classifyTaskMutationIntent(agent, task) {
104
+ const taskText = stripSeverityCompounds(stripFrameworkInstructions(task));
105
+ const taskTextWithoutScopedConstraints = stripPatterns(taskText, SCOPED_NO_EDIT_CONSTRAINT_PATTERNS);
106
+ const prohibitions = analyzeNoEditProhibitions(taskTextWithoutScopedConstraints);
107
+ if (prohibitions.present) {
108
+ if (prohibitions.blanket)
109
+ return { kind: "read-only" };
110
+ return hasImplementationIntent(agent, prohibitions.strippedText) ? { kind: "implementation" } : { kind: "read-only" };
111
+ }
112
+ if (RESEARCH_AGENT_PATTERNS.some((pattern) => pattern.test(agent)))
113
+ return { kind: "read-only" };
114
+ if (hasImplementationIntent(agent, taskText))
115
+ return { kind: "implementation" };
116
+ if (isReviewerStyleAgent(agent))
117
+ return { kind: "read-only" };
118
+ return taskHasReadOnlyDeliverable(taskTextWithoutScopedConstraints) ? { kind: "read-only" } : { kind: "unknown" };
119
+ }
120
+ export function expectsImplementationMutation(agent, task) {
121
+ return classifyTaskMutationIntent(agent, task).kind === "implementation";
122
+ }
123
+ const MAY_MUTATE_VERB_PATTERN = /\b(?:fix|implement|update|write|edit|modify|migrate|delete|remove|refactor|commit)\b/i;
124
+ export function taskMayMutate(task) {
125
+ const taskText = stripPatterns(stripSeverityCompounds(stripFrameworkInstructions(task)), SCOPED_NO_EDIT_CONSTRAINT_PATTERNS);
126
+ const prohibitions = analyzeNoEditProhibitions(taskText);
127
+ if (prohibitions.blanket)
128
+ return false;
129
+ return MAY_MUTATE_VERB_PATTERN.test(stripPatterns(prohibitions.strippedText, READ_ONLY_DELIVERABLE_PATTERNS));
130
+ }
@@ -0,0 +1,59 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ export const REQUIRED_CHILD_TOOLS_ENV = "DM_SUBAGENT_REQUIRED_TOOLS";
4
+ export const MCP_DIRECT_CHILD_TOOLS_ENV = "DM_SUBAGENT_MCP_DIRECT_TOOLS";
5
+ export const CHILD_TOOL_DIAGNOSTIC_PATH_ENV = "DM_SUBAGENT_TOOL_DIAGNOSTIC_PATH";
6
+ export function writeChildToolDiagnostic(filePath, required, available, agent, mcpDirectTools) {
7
+ const availableNames = new Set(available);
8
+ const missing = required.filter((name) => !availableNames.has(name));
9
+ if (missing.length === 0) {
10
+ fs.rmSync(filePath, { force: true });
11
+ return;
12
+ }
13
+ const missingMcpDirectTools = mcpDirectTools?.length ? missing.filter((name) => mcpDirectTools.includes(name)) : [];
14
+ const diagnostic = {
15
+ agent,
16
+ required,
17
+ available,
18
+ missing,
19
+ ...missingMcpDirectTools.length > 0 ? { missingMcpDirectTools } : {}
20
+ };
21
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
22
+ fs.writeFileSync(filePath, JSON.stringify(diagnostic), { mode: 384 });
23
+ return diagnostic;
24
+ }
25
+ export function readChildToolDiagnostic(filePath) {
26
+ if (!filePath || !fs.existsSync(filePath))
27
+ return;
28
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
29
+ const stringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0);
30
+ if (!stringArray(parsed.required) || !stringArray(parsed.available) || !stringArray(parsed.missing) || parsed.agent !== undefined && typeof parsed.agent !== "string" || parsed.missingMcpDirectTools !== undefined && !stringArray(parsed.missingMcpDirectTools)) {
31
+ throw new Error(`Malformed child tool diagnostic at '${filePath}'.`);
32
+ }
33
+ return {
34
+ ...parsed.agent ? { agent: parsed.agent } : {},
35
+ required: parsed.required,
36
+ available: parsed.available,
37
+ missing: parsed.missing,
38
+ ...parsed.missingMcpDirectTools ? { missingMcpDirectTools: parsed.missingMcpDirectTools } : {}
39
+ };
40
+ }
41
+ export function formatChildToolDiagnostic(diagnostic) {
42
+ const subject = diagnostic.agent ? `Agent '${diagnostic.agent}'` : "Subagent";
43
+ return [
44
+ `${subject} requested unavailable child tools: ${diagnostic.missing.join(", ")}.`,
45
+ "The `tools` field is a strict allowlist; it does not load extension code.",
46
+ ...diagnostic.missingMcpDirectTools?.length ? [`Resolved MCP direct tools missing from the child registry: ${diagnostic.missingMcpDirectTools.join(", ")}. This indicates a host/dm-mcp-adapter registration problem, not a tool-call failure.`] : [],
47
+ "For extension tools, add the provider path to `subagentOnlyExtensions` (child-only), `extensions`, or as a path-like entry in `tools`, while keeping each registered tool name in `tools`.",
48
+ "For MCP tools, verify the MCP adapter configuration and selected tool names. For builtin tools, verify the name against the installed DM version."
49
+ ].join(`
50
+ `);
51
+ }
52
+ export function readChildToolDiagnosticError(filePath) {
53
+ try {
54
+ const diagnostic = readChildToolDiagnostic(filePath);
55
+ return diagnostic ? formatChildToolDiagnostic(diagnostic) : undefined;
56
+ } catch (error) {
57
+ return `Failed to read child tool availability diagnostic: ${error instanceof Error ? error.message : String(error)}`;
58
+ }
59
+ }
@@ -1,5 +1,6 @@
1
1
  export const DEFAULT_TOOL_BUDGET_BLOCK = ["read", "grep", "find", "ls"];
2
2
  export const TOOL_BUDGET_ENV = "DM_SUBAGENT_TOOL_BUDGET";
3
+ export const TOOL_BUDGET_ZERO_AUTH_ENV = "DM_SUBAGENT_TOOL_BUDGET_ZERO_AUTH";
3
4
  export function normalizeToolBudgetBlock(block) {
4
5
  if (block === "*")
5
6
  return "*";
@@ -7,14 +8,15 @@ export function normalizeToolBudgetBlock(block) {
7
8
  return [...DEFAULT_TOOL_BUDGET_BLOCK];
8
9
  return [...new Set(block.map((tool) => tool.trim()).filter(Boolean))];
9
10
  }
10
- export function validateToolBudgetConfig(raw, label = "toolBudget") {
11
+ export function validateToolBudgetConfig(raw, label = "toolBudget", options = {}) {
11
12
  if (raw === undefined)
12
13
  return {};
13
14
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
14
15
  return { error: `${label} must be an object with hard and optional soft/block.` };
15
16
  const value = raw;
16
- if (typeof value.hard !== "number" || !Number.isInteger(value.hard) || value.hard < 1) {
17
- return { error: `${label}.hard must be an integer >= 1.` };
17
+ const minimumHard = options.minimumHard ?? 1;
18
+ if (typeof value.hard !== "number" || !Number.isInteger(value.hard) || value.hard < minimumHard) {
19
+ return { error: `${label}.hard must be an integer >= ${minimumHard}.` };
18
20
  }
19
21
  if (value.soft !== undefined && (typeof value.soft !== "number" || !Number.isInteger(value.soft) || value.soft < 1)) {
20
22
  return { error: `${label}.soft must be an integer >= 1 when provided.` };
@@ -62,11 +64,11 @@ export function toolBudgetBlockedMessage(budget, toolName, toolCount) {
62
64
  export function encodeToolBudgetEnv(budget) {
63
65
  return budget ? JSON.stringify(budget) : undefined;
64
66
  }
65
- export function decodeToolBudgetEnv(value) {
67
+ export function decodeToolBudgetEnv(value, options = {}) {
66
68
  if (!value?.trim())
67
69
  return;
68
70
  const parsed = JSON.parse(value);
69
- const normalized = validateToolBudgetConfig(parsed, TOOL_BUDGET_ENV);
71
+ const normalized = validateToolBudgetConfig(parsed, TOOL_BUDGET_ENV, options.allowZero ? { minimumHard: 0 } : undefined);
70
72
  if (normalized.error)
71
73
  throw new Error(normalized.error);
72
74
  return normalized.budget;
@@ -0,0 +1,64 @@
1
+ export const TOOL_TIMEOUT_ENV = "DM_SUBAGENT_TOOL_TIMEOUT_MS";
2
+ const MAX_TIMER_DELAY_MS = 2147483647;
3
+ export const DEFAULT_FAST_TOOL_TIMEOUT_MS = 300000;
4
+ export const DEFAULT_FAST_TOOL_TIMEOUT_TOOLS = new Set([
5
+ "read",
6
+ "grep",
7
+ "find",
8
+ "ls",
9
+ "edit",
10
+ "write",
11
+ "structured_output"
12
+ ]);
13
+ export const TOOL_TIMEOUT_EXEMPT_TOOLS = new Set(["contact_supervisor", "intercom", "bg_wait", "subagent_wait"]);
14
+ export const TOOL_TIMEOUT_ALLOWLIST = TOOL_TIMEOUT_EXEMPT_TOOLS;
15
+ export function isToolTimeoutExempt(toolName) {
16
+ return toolName !== undefined && TOOL_TIMEOUT_EXEMPT_TOOLS.has(toolName);
17
+ }
18
+ export function defaultToolTimeoutMs(toolName) {
19
+ return toolName !== undefined && DEFAULT_FAST_TOOL_TIMEOUT_TOOLS.has(toolName) ? DEFAULT_FAST_TOOL_TIMEOUT_MS : undefined;
20
+ }
21
+ export function effectiveToolTimeoutMs(toolName, configuredToolTimeoutMs) {
22
+ if (isToolTimeoutExempt(toolName))
23
+ return;
24
+ return configuredToolTimeoutMs ?? defaultToolTimeoutMs(toolName);
25
+ }
26
+ export function formatToolTimeoutMessage(toolName, timeoutMs) {
27
+ return `Tool '${toolName}' exceeded its timeout of ${timeoutMs}ms.`;
28
+ }
29
+ export function toolTimeoutCallKey(event, fallbackId) {
30
+ return typeof event.toolCallId === "string" && event.toolCallId.length > 0 ? `id:${event.toolCallId}` : `anon:${String(event.toolName ?? "tool")}:${fallbackId}`;
31
+ }
32
+ export function resolveToolTimeoutMs(input) {
33
+ const candidates = [
34
+ { label: "toolTimeoutMs", value: input.callValue },
35
+ { label: "agent.toolTimeoutMs", value: input.agentValue },
36
+ { label: "config.toolTimeoutMs", value: input.configValue }
37
+ ];
38
+ let winner;
39
+ for (const candidate of candidates) {
40
+ if (candidate.value === undefined)
41
+ continue;
42
+ winner = candidate;
43
+ break;
44
+ }
45
+ if (winner === undefined && input.envValue !== undefined && input.envValue.trim() !== "") {
46
+ winner = { label: TOOL_TIMEOUT_ENV, value: input.envValue };
47
+ }
48
+ if (winner === undefined)
49
+ return {};
50
+ let raw = winner.value;
51
+ let parsed;
52
+ if (winner.label === TOOL_TIMEOUT_ENV && typeof raw === "string") {
53
+ parsed = Number(raw);
54
+ if (raw.trim() !== "" && !Number.isNaN(parsed))
55
+ raw = parsed;
56
+ }
57
+ if (typeof raw !== "number" || !Number.isInteger(raw) || raw <= 0 || raw > MAX_TIMER_DELAY_MS) {
58
+ return { error: `${winner.label} must be a positive integer no larger than ${MAX_TIMER_DELAY_MS}.` };
59
+ }
60
+ return { toolTimeoutMs: raw };
61
+ }
62
+ export function toolTimeoutFromEnv(env = process.env) {
63
+ return env[TOOL_TIMEOUT_ENV];
64
+ }
@@ -0,0 +1,74 @@
1
+ function validateLimit(value, label) {
2
+ if (!value || typeof value !== "object" || Array.isArray(value))
3
+ return { error: `${label} must be an object.` };
4
+ const raw = value;
5
+ const unknown = Object.keys(raw).find((key) => key !== "soft" && key !== "hard");
6
+ if (unknown)
7
+ return { error: `${label}.${unknown} is not supported.` };
8
+ if (typeof raw.hard !== "number" || !Number.isFinite(raw.hard) || raw.hard <= 0)
9
+ return { error: `${label}.hard must be a positive number.` };
10
+ if (raw.soft !== undefined && (typeof raw.soft !== "number" || !Number.isFinite(raw.soft) || raw.soft <= 0))
11
+ return { error: `${label}.soft must be a positive number.` };
12
+ if (typeof raw.soft === "number" && raw.soft > raw.hard)
13
+ return { error: `${label}.soft must be less than or equal to ${label}.hard.` };
14
+ return { limit: { ...typeof raw.soft === "number" ? { soft: raw.soft } : {}, hard: raw.hard } };
15
+ }
16
+ export function validateUsageBudgetConfig(value, label = "usageBudget") {
17
+ if (value === undefined)
18
+ return {};
19
+ if (!value || typeof value !== "object" || Array.isArray(value))
20
+ return { error: `${label} must be an object.` };
21
+ const raw = value;
22
+ const unknown = Object.keys(raw).find((key) => key !== "tokens" && key !== "costUsd");
23
+ if (unknown)
24
+ return { error: `${label}.${unknown} is not supported.` };
25
+ const budget = {};
26
+ if (raw.tokens !== undefined) {
27
+ const tokens = validateLimit(raw.tokens, `${label}.tokens`);
28
+ if (tokens.error)
29
+ return { error: tokens.error };
30
+ budget.tokens = tokens.limit;
31
+ }
32
+ if (raw.costUsd !== undefined) {
33
+ const costUsd = validateLimit(raw.costUsd, `${label}.costUsd`);
34
+ if (costUsd.error)
35
+ return { error: costUsd.error };
36
+ budget.costUsd = costUsd.limit;
37
+ }
38
+ if (!budget.tokens && !budget.costUsd)
39
+ return { error: `${label} must include tokens or costUsd.` };
40
+ return { budget };
41
+ }
42
+ function metricState(limit, used) {
43
+ if (!limit)
44
+ return;
45
+ return {
46
+ ...limit,
47
+ used,
48
+ outcome: used >= limit.hard ? "hard-exceeded" : limit.soft !== undefined && used >= limit.soft ? "soft-exceeded" : "within-budget"
49
+ };
50
+ }
51
+ export function usageBudgetState(config, totals) {
52
+ if (!config)
53
+ return;
54
+ const inputTokens = totals?.inputTokens ?? 0;
55
+ const outputTokens = totals?.outputTokens ?? 0;
56
+ const tokens = metricState(config.tokens, inputTokens + outputTokens);
57
+ const costUsd = metricState(config.costUsd, totals?.costUsd ?? 0);
58
+ const reason = tokens?.outcome === "hard-exceeded" ? "tokens" : costUsd?.outcome === "hard-exceeded" ? "costUsd" : undefined;
59
+ return {
60
+ version: 1,
61
+ source: "reported",
62
+ ...tokens ? { tokens } : {},
63
+ ...costUsd ? { costUsd } : {},
64
+ exhausted: reason !== undefined,
65
+ ...reason ? { reason } : {}
66
+ };
67
+ }
68
+ export function usageBudgetExceededMessage(state) {
69
+ if (state.reason === "tokens" && state.tokens)
70
+ return `Usage budget exhausted: reported tokens ${state.tokens.used} reached hard limit ${state.tokens.hard}.`;
71
+ if (state.reason === "costUsd" && state.costUsd)
72
+ return `Usage budget exhausted: reported cost $${state.costUsd.used.toFixed(6)} reached hard limit $${state.costUsd.hard.toFixed(6)}.`;
73
+ return "Usage budget exhausted.";
74
+ }
@@ -1,4 +1,22 @@
1
1
  import { isDynamicParallelStep, isParallelStep } from "../../shared/settings.js";
2
+ export function workflowGraphStageNodes(graph) {
3
+ const nodes = graph?.nodes;
4
+ if (!nodes?.length)
5
+ return [];
6
+ const stages = [];
7
+ const visit = (node) => {
8
+ if (node.kind === "parallel-group" || node.kind === "dynamic-parallel-group") {
9
+ for (const child of node.children ?? [])
10
+ visit(child);
11
+ return;
12
+ }
13
+ if (node.kind !== "host-step")
14
+ stages.push(node);
15
+ };
16
+ for (const node of nodes)
17
+ visit(node);
18
+ return stages;
19
+ }
2
20
  function normalizeStatus(status) {
3
21
  switch (status) {
4
22
  case "complete":
@@ -12,6 +30,8 @@ function normalizeStatus(status) {
12
30
  return "paused";
13
31
  case "detached":
14
32
  return "detached";
33
+ case "rejected":
34
+ return "rejected";
15
35
  case "pending":
16
36
  return "pending";
17
37
  default:
@@ -46,6 +66,8 @@ function seqLabel(step, stepIndex) {
46
66
  function summarizeParallelStatuses(statuses) {
47
67
  if (statuses.some((status) => status === "running"))
48
68
  return "running";
69
+ if (statuses.some((status) => status === "rejected"))
70
+ return "rejected";
49
71
  if (statuses.some((status) => status === "failed"))
50
72
  return "failed";
51
73
  if (statuses.some((status) => status === "paused"))