@duckmind/dm-darwin-x64 0.43.2 → 0.43.8

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 (256) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +242 -49
  3. package/extensions/dm-9router-ext/package.json +2 -19
  4. package/extensions/dm-9router-ext/src/index.js +5 -0
  5. package/extensions/dm-ask-user/index.js +10 -0
  6. package/extensions/dm-ask-user/package.json +1 -21
  7. package/extensions/dm-cli-anything/package.json +0 -6
  8. package/extensions/dm-context/package.json +2 -12
  9. package/extensions/dm-context/src/context.js +1 -0
  10. package/extensions/dm-context/src/index.js +7 -0
  11. package/extensions/dm-context/src/utils.js +1 -0
  12. package/extensions/dm-cua/package.json +0 -7
  13. package/extensions/dm-fff/package.json +1 -28
  14. package/extensions/dm-fff/src/index.js +15 -0
  15. package/extensions/dm-fff/src/query.js +1 -0
  16. package/extensions/dm-goal/package.json +2 -31
  17. package/extensions/dm-goal/src/goal.js +43 -0
  18. package/extensions/dm-grill-me/index.js +174 -0
  19. package/extensions/dm-grill-me/package.json +1 -26
  20. package/extensions/dm-image2/package.json +0 -7
  21. package/extensions/dm-subagents/package.json +1 -32
  22. package/extensions/dm-subagents/src/agents/agent-management.js +37 -0
  23. package/extensions/dm-subagents/src/agents/agent-memory.js +6 -0
  24. package/extensions/dm-subagents/src/agents/agent-scope.js +1 -0
  25. package/extensions/dm-subagents/src/agents/agent-selection.js +1 -0
  26. package/extensions/dm-subagents/src/agents/agent-serializer.js +7 -0
  27. package/extensions/dm-subagents/src/agents/agents.js +11 -0
  28. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -0
  29. package/extensions/dm-subagents/src/agents/frontmatter.js +6 -0
  30. package/extensions/dm-subagents/src/agents/identity.js +1 -0
  31. package/extensions/dm-subagents/src/agents/proactive-skills.js +1 -0
  32. package/extensions/dm-subagents/src/agents/skills.js +6 -0
  33. package/extensions/dm-subagents/src/extension/config.js +2 -0
  34. package/extensions/dm-subagents/src/extension/control-notices.js +4 -0
  35. package/extensions/dm-subagents/src/extension/doctor.js +16 -0
  36. package/extensions/dm-subagents/src/extension/fanout-child.js +231 -0
  37. package/extensions/dm-subagents/src/extension/index.js +367 -0
  38. package/extensions/dm-subagents/src/extension/rpc.js +8 -0
  39. package/extensions/dm-subagents/src/extension/schemas.js +1 -0
  40. package/extensions/dm-subagents/src/extension/{tool-description.ts → tool-description.js} +6 -126
  41. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +13 -0
  42. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -0
  43. package/extensions/dm-subagents/src/intercom/result-intercom.js +3 -0
  44. package/extensions/dm-subagents/src/profiles/profiles.js +3 -0
  45. package/extensions/dm-subagents/src/runs/background/async-execution.js +46 -0
  46. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +14 -0
  47. package/extensions/dm-subagents/src/runs/background/async-resume.js +8 -0
  48. package/extensions/dm-subagents/src/runs/background/async-status.js +12 -0
  49. package/extensions/dm-subagents/src/runs/background/chain-append.js +2 -0
  50. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +1 -0
  51. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +1 -0
  52. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +1 -0
  53. package/extensions/dm-subagents/src/runs/background/control-channel.js +1 -0
  54. package/extensions/dm-subagents/src/runs/background/fleet-view.js +17 -0
  55. package/extensions/dm-subagents/src/runs/background/notify.js +3 -0
  56. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +1 -0
  57. package/extensions/dm-subagents/src/runs/background/result-watcher.js +8 -0
  58. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +4 -0
  59. package/extensions/dm-subagents/src/runs/background/run-status.js +23 -0
  60. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +4 -0
  61. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +11 -0
  62. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +78 -0
  63. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -0
  64. package/extensions/dm-subagents/src/runs/background/wait.js +11 -0
  65. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +12 -0
  66. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +102 -0
  67. package/extensions/dm-subagents/src/runs/foreground/execution.js +51 -0
  68. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +228 -0
  69. package/extensions/dm-subagents/src/runs/shared/acceptance.js +3 -0
  70. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +1 -0
  71. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +3 -0
  72. package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -0
  73. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +1 -0
  74. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +1 -0
  75. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +1 -0
  76. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +1 -0
  77. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +1 -0
  78. package/extensions/dm-subagents/src/runs/shared/model-scope.js +1 -0
  79. package/extensions/dm-subagents/src/runs/shared/nested-events.js +8 -0
  80. package/extensions/dm-subagents/src/runs/shared/nested-path.js +1 -0
  81. package/extensions/dm-subagents/src/runs/shared/nested-render.js +1 -0
  82. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +5 -0
  83. package/extensions/dm-subagents/src/runs/shared/run-history.js +5 -0
  84. package/extensions/dm-subagents/src/runs/shared/single-output.js +14 -0
  85. package/extensions/dm-subagents/src/runs/shared/structured-output.js +1 -0
  86. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +5 -0
  87. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +22 -0
  88. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +1 -0
  89. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +7 -0
  90. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +1 -0
  91. package/extensions/dm-subagents/src/runs/shared/worktree.js +3 -0
  92. package/extensions/dm-subagents/src/shared/artifacts.js +2 -0
  93. package/extensions/dm-subagents/src/shared/atomic-json.js +1 -0
  94. package/extensions/dm-subagents/src/shared/child-transcript.js +5 -0
  95. package/extensions/dm-subagents/src/shared/file-coalescer.js +1 -0
  96. package/extensions/dm-subagents/src/shared/fork-context.js +6 -0
  97. package/extensions/dm-subagents/src/shared/formatters.js +9 -0
  98. package/extensions/dm-subagents/src/shared/jsonl-writer.js +2 -0
  99. package/extensions/dm-subagents/src/shared/model-info.js +1 -0
  100. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +1 -0
  101. package/extensions/dm-subagents/src/shared/session-identity.js +1 -0
  102. package/extensions/dm-subagents/src/shared/session-tokens.js +2 -0
  103. package/extensions/dm-subagents/src/shared/settings.js +23 -0
  104. package/extensions/dm-subagents/src/shared/status-format.js +1 -0
  105. package/extensions/dm-subagents/src/shared/types.js +8 -0
  106. package/extensions/dm-subagents/src/shared/utils.js +2 -0
  107. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +1 -0
  108. package/extensions/dm-subagents/src/slash/prompt-workflows.js +7 -0
  109. package/extensions/dm-subagents/src/slash/slash-bridge.js +1 -0
  110. package/extensions/dm-subagents/src/slash/slash-commands.js +38 -0
  111. package/extensions/dm-subagents/src/slash/slash-live-state.js +6 -0
  112. package/extensions/dm-subagents/src/tui/render-helpers.js +1 -0
  113. package/extensions/dm-subagents/src/tui/render.js +4 -0
  114. package/extensions/dm-tasks/package.json +1 -30
  115. package/extensions/dm-tasks/src/auto-clear.js +1 -0
  116. package/extensions/dm-tasks/src/index.js +212 -0
  117. package/extensions/dm-tasks/src/process-tracker.js +1 -0
  118. package/extensions/dm-tasks/src/task-store.js +1 -0
  119. package/extensions/dm-tasks/src/tasks-config.js +1 -0
  120. package/extensions/dm-tasks/src/types.js +0 -0
  121. package/extensions/dm-tasks/src/ui/settings-menu.js +1 -0
  122. package/extensions/dm-tasks/src/ui/task-widget.js +1 -0
  123. package/extensions/dm-usage/index.js +9 -0
  124. package/extensions/dm-usage/package.json +1 -18
  125. package/extensions/greedysearch-dm/bin/search.mjs +135 -135
  126. package/extensions/greedysearch-dm/index.js +20 -0
  127. package/extensions/greedysearch-dm/package.json +1 -22
  128. package/extensions/greedysearch-dm/src/formatters/results.js +8 -0
  129. package/extensions/greedysearch-dm/src/formatters/sources.js +1 -0
  130. package/extensions/greedysearch-dm/src/formatters/synthesis.js +1 -0
  131. package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
  132. package/extensions/greedysearch-dm/src/search/paths.mjs +1 -0
  133. package/extensions/greedysearch-dm/src/search/research.mjs +100 -100
  134. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +10 -10
  135. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
  136. package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
  137. package/extensions/greedysearch-dm/src/types.js +0 -0
  138. package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
  139. package/package.json +1 -1
  140. package/extensions/dm-9router-ext/src/index.ts +0 -541
  141. package/extensions/dm-ask-user/index.ts +0 -857
  142. package/extensions/dm-context/src/context.ts +0 -158
  143. package/extensions/dm-context/src/index.ts +0 -439
  144. package/extensions/dm-context/src/utils.ts +0 -6
  145. package/extensions/dm-fff/src/index.ts +0 -1023
  146. package/extensions/dm-fff/src/query.ts +0 -87
  147. package/extensions/dm-goal/src/goal.ts +0 -1073
  148. package/extensions/dm-grill-me/index.ts +0 -1085
  149. package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
  150. package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
  151. package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
  152. package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
  153. package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
  154. package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
  155. package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
  156. package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
  157. package/extensions/dm-subagents/src/agents/identity.ts +0 -30
  158. package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
  159. package/extensions/dm-subagents/src/agents/skills.ts +0 -729
  160. package/extensions/dm-subagents/src/extension/config.ts +0 -39
  161. package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
  162. package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
  163. package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
  164. package/extensions/dm-subagents/src/extension/index.ts +0 -656
  165. package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
  166. package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
  167. package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
  168. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
  169. package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
  170. package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
  171. package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
  172. package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
  173. package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
  174. package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
  175. package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
  176. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
  177. package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
  178. package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
  179. package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
  180. package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
  181. package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
  182. package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
  183. package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
  184. package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
  185. package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
  186. package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
  187. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
  188. package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
  189. package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
  190. package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
  191. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
  192. package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
  193. package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
  194. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
  195. package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
  196. package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
  197. package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
  198. package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
  199. package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
  200. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
  201. package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
  202. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
  203. package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
  204. package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
  205. package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
  206. package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
  207. package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
  208. package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
  209. package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
  210. package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
  211. package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
  212. package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
  213. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
  214. package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
  215. package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
  216. package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
  217. package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
  218. package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
  219. package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
  220. package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
  221. package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
  222. package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
  223. package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
  224. package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
  225. package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
  226. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  227. package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
  228. package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
  229. package/extensions/dm-subagents/src/shared/settings.ts +0 -450
  230. package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
  231. package/extensions/dm-subagents/src/shared/types.ts +0 -1257
  232. package/extensions/dm-subagents/src/shared/utils.ts +0 -554
  233. package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
  234. package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
  235. package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
  236. package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
  237. package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
  238. package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
  239. package/extensions/dm-subagents/src/tui/render.ts +0 -1748
  240. package/extensions/dm-tasks/src/auto-clear.ts +0 -91
  241. package/extensions/dm-tasks/src/index.ts +0 -1145
  242. package/extensions/dm-tasks/src/process-tracker.ts +0 -140
  243. package/extensions/dm-tasks/src/task-store.ts +0 -305
  244. package/extensions/dm-tasks/src/tasks-config.ts +0 -23
  245. package/extensions/dm-tasks/src/types.ts +0 -40
  246. package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
  247. package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
  248. package/extensions/dm-usage/index.ts +0 -1718
  249. package/extensions/greedysearch-dm/index.ts +0 -177
  250. package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
  251. package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
  252. package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
  253. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
  254. package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
  255. package/extensions/greedysearch-dm/src/types.ts +0 -110
  256. package/extensions/greedysearch-dm/src/utils/helpers.ts +0 -40
@@ -1,1065 +0,0 @@
1
- /**
2
- * Async execution logic for subagent tool
3
- */
4
-
5
- import { spawn } from "node:child_process";
6
- import * as fs from "node:fs";
7
- import * as os from "node:os";
8
- import * as path from "node:path";
9
- import { fileURLToPath } from "node:url";
10
- import { createRequire } from "node:module";
11
- import type { ExtensionAPI } from "@duckmind/dm-coding-agent";
12
- import type { AgentConfig } from "../../agents/agents.ts";
13
- import { applyThinkingSuffix } from "../shared/dm-args.ts";
14
- import { injectOutputPathSystemPrompt, injectSingleOutputInstruction, normalizeSingleOutputOverride, resolveSingleOutputPath, validateFileOnlyOutputMode } from "../shared/single-output.ts";
15
- import { buildChainInstructions, isDynamicParallelStep, isParallelStep, resolveStepBehavior, suppressProgressForReadOnlyTask, writeInitialProgressFile, type ChainStep, type ResolvedStepBehavior, type SequentialStep, type StepOverrides } from "../../shared/settings.ts";
16
- import type { RunnerStep } from "../shared/parallel-utils.ts";
17
- import { resolvePiPackageRoot } from "../shared/dm-spawn.ts";
18
- import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "../../agents/skills.ts";
19
- import { buildAgentMemoryInjection } from "../../agents/agent-memory.ts";
20
- import { PI_CODING_AGENT_PACKAGE_ROOT_ENV, resolveChildCwd } from "../../shared/utils.ts";
21
- import { buildModelCandidates, resolveModelCandidate, resolveSubagentModelOverride, type AvailableModelInfo, type ParentModel } from "../shared/model-fallback.ts";
22
- import type { ModelScopeConfig } from "../shared/model-scope.ts";
23
- import { resolveEffectiveThinking } from "../../shared/model-info.ts";
24
- import { resolveExpectedWorktreeAgentCwd } from "../shared/worktree.ts";
25
- import { buildWorkflowGraphSnapshot } from "../shared/workflow-graph.ts";
26
- import { ChainOutputValidationError, validateChainOutputBindings } from "../shared/chain-outputs.ts";
27
- import { createStructuredOutputRuntime } from "../shared/structured-output.ts";
28
- import { resolveEffectiveAcceptance } from "../shared/acceptance.ts";
29
- import {
30
- type AcceptanceInput,
31
- type ArtifactConfig,
32
- type Details,
33
- type MaxOutputConfig,
34
- type NestedRouteInfo,
35
- type ResolvedControlConfig,
36
- type ResolvedTurnBudget,
37
- type ResolvedToolBudget,
38
- type SubagentRunMode,
39
- ASYNC_DIR,
40
- RESULTS_DIR,
41
- SUBAGENT_ASYNC_STARTED_EVENT,
42
- SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
43
- TEMP_ROOT_DIR,
44
- getAsyncConfigPath,
45
- resolveChildMaxSubagentDepth,
46
- } from "../../shared/types.ts";
47
- import { nestedResultsPath, resolveInheritedNestedRouteFromEnv, resolveNestedParentAddressFromEnv, writeNestedEvent } from "../shared/nested-events.ts";
48
- import { initialTurnBudgetState } from "../shared/turn-budget.ts";
49
- import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
50
- import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
51
-
52
- const require = createRequire(import.meta.url);
53
- const piPackageRoot = resolvePiPackageRoot();
54
-
55
- function resolveJitiCliFromPackageJson(packageJsonPath: string): string | undefined {
56
- if (!fs.existsSync(packageJsonPath)) return undefined;
57
- const packageRoot = path.dirname(packageJsonPath);
58
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
59
- bin?: string | Record<string, string>;
60
- };
61
- const binField = pkg.bin;
62
- const binPath = typeof binField === "string"
63
- ? binField
64
- : binField?.jiti ?? Object.values(binField ?? {})[0];
65
- const candidates = [binPath, "lib/jiti-cli.mjs"].filter((candidate): candidate is string => Boolean(candidate));
66
- for (const candidate of candidates) {
67
- const cliPath = path.resolve(packageRoot, candidate);
68
- if (fs.existsSync(cliPath)) return cliPath;
69
- }
70
- return undefined;
71
- }
72
-
73
- function resolveJitiCliPath(): string | undefined {
74
- const candidates: Array<() => string | undefined> = [
75
- () => require.resolve("jiti/package.json"),
76
- () => piPackageRoot
77
- ? createRequire(path.join(piPackageRoot, "package.json")).resolve("jiti/package.json")
78
- : undefined,
79
- () => {
80
- if (!process.argv[1]) return undefined;
81
- const piEntry = fs.realpathSync(process.argv[1]);
82
- return createRequire(piEntry).resolve("jiti/package.json");
83
- },
84
- () => piPackageRoot ? path.join(piPackageRoot, "node_modules", "jiti", "package.json") : undefined,
85
- ];
86
- for (const candidate of candidates) {
87
- try {
88
- const packageJsonPath = candidate();
89
- if (!packageJsonPath) continue;
90
- const cliPath = resolveJitiCliFromPackageJson(packageJsonPath);
91
- if (cliPath) return cliPath;
92
- } catch {
93
- // Candidate not available in this install, continue probing.
94
- }
95
- }
96
- return undefined;
97
- }
98
-
99
- const jitiCliPath = resolveJitiCliPath();
100
-
101
- interface AsyncExecutionContext {
102
- pi: ExtensionAPI;
103
- cwd: string;
104
- currentSessionId: string;
105
- /** Parent session id used by permission-system ask forwarding. */
106
- parentSessionId?: string;
107
- currentModelProvider?: string;
108
- currentModel?: ParentModel;
109
- /** Optional model-scope enforcement resolved from subagent settings. */
110
- modelScope?: ModelScopeConfig;
111
- }
112
-
113
- interface AsyncChainParams {
114
- chain: ChainStep[];
115
- task?: string;
116
- attachRoot?: ImportedAsyncRoot & { agent: string; outputName?: string; label?: string };
117
- resultMode?: Exclude<SubagentRunMode, "single">;
118
- agents: AgentConfig[];
119
- ctx: AsyncExecutionContext;
120
- availableModels?: AvailableModelInfo[];
121
- cwd?: string;
122
- maxOutput?: MaxOutputConfig;
123
- artifactsDir?: string;
124
- artifactConfig: ArtifactConfig;
125
- shareEnabled: boolean;
126
- sessionRoot?: string;
127
- chainSkills?: string[];
128
- sessionFilesByFlatIndex?: (string | undefined)[];
129
- thinkingOverridesByFlatIndex?: (AgentConfig["thinking"] | undefined)[];
130
- progressDir?: string;
131
- dynamicFanoutMaxItems?: number;
132
- maxSubagentDepth: number;
133
- worktreeSetupHook?: string;
134
- worktreeSetupHookTimeoutMs?: number;
135
- worktreeBaseDir?: string;
136
- controlConfig?: ResolvedControlConfig;
137
- controlIntercomTarget?: string;
138
- childIntercomTarget?: (agent: string, index: number) => string | undefined;
139
- nestedRoute?: NestedRouteInfo;
140
- acceptance?: AcceptanceInput;
141
- timeoutMs?: number;
142
- turnBudget?: ResolvedTurnBudget;
143
- toolBudget?: ResolvedToolBudget;
144
- configToolBudget?: ResolvedToolBudget;
145
- /** Global cap on simultaneously-running subagent tasks within the async run. */
146
- globalConcurrencyLimit?: number;
147
- }
148
-
149
- interface AsyncSingleParams {
150
- agent: string;
151
- task?: string;
152
- agentConfig: AgentConfig;
153
- ctx: AsyncExecutionContext;
154
- cwd?: string;
155
- maxOutput?: MaxOutputConfig;
156
- artifactsDir?: string;
157
- artifactConfig: ArtifactConfig;
158
- shareEnabled: boolean;
159
- sessionRoot?: string;
160
- sessionFile?: string;
161
- skills?: string[];
162
- output?: string | boolean;
163
- outputMode?: "inline" | "file-only";
164
- outputBaseDir?: string;
165
- modelOverride?: string;
166
- thinkingOverride?: AgentConfig["thinking"];
167
- availableModels?: AvailableModelInfo[];
168
- maxSubagentDepth: number;
169
- worktreeSetupHook?: string;
170
- worktreeSetupHookTimeoutMs?: number;
171
- worktreeBaseDir?: string;
172
- controlConfig?: ResolvedControlConfig;
173
- controlIntercomTarget?: string;
174
- childIntercomTarget?: (agent: string, index: number) => string | undefined;
175
- nestedRoute?: NestedRouteInfo;
176
- acceptance?: AcceptanceInput;
177
- timeoutMs?: number;
178
- turnBudget?: ResolvedTurnBudget;
179
- toolBudget?: ResolvedToolBudget;
180
- configToolBudget?: ResolvedToolBudget;
181
- }
182
-
183
- interface AsyncExecutionResult {
184
- content: Array<{ type: "text"; text: string }>;
185
- details: Details;
186
- isError?: boolean;
187
- }
188
-
189
- export interface AsyncRunnerStepBuildParams {
190
- chain: ChainStep[];
191
- task?: string;
192
- attachRoot?: ImportedAsyncRoot & { agent: string; outputName?: string; label?: string };
193
- resultMode?: SubagentRunMode;
194
- agents: AgentConfig[];
195
- ctx: AsyncExecutionContext;
196
- availableModels?: AvailableModelInfo[];
197
- cwd?: string;
198
- chainSkills?: string[];
199
- sessionFilesByFlatIndex?: (string | undefined)[];
200
- thinkingOverridesByFlatIndex?: (AgentConfig["thinking"] | undefined)[];
201
- progressDir?: string;
202
- dynamicFanoutMaxItems?: number;
203
- maxSubagentDepth: number;
204
- worktreeBaseDir?: string;
205
- asyncDir: string;
206
- outputBaseDir?: string;
207
- validateOutputBindings?: boolean;
208
- toolBudget?: ResolvedToolBudget;
209
- configToolBudget?: ResolvedToolBudget;
210
- }
211
-
212
- export type AsyncRunnerStepBuildResult =
213
- | {
214
- steps: RunnerStep[];
215
- runnerCwd: string;
216
- workflowGraph: ReturnType<typeof buildWorkflowGraphSnapshot>;
217
- eventChain: ChainStep[];
218
- originalTask?: string;
219
- }
220
- | { error: string };
221
-
222
- export function formatAsyncStartedMessage(headline: string): string {
223
- return [
224
- headline,
225
- "",
226
- "The async run is detached. Do not run sleep timers or polling loops just to wait for it.",
227
- "If you have independent work, continue that work. When you have nothing left to do until the async result arrives, call wait() — it blocks until the run finishes and delivers the completion here. Only if you are certain you will get another turn (an interactive session where the user will prompt you again) can you instead stop and let DM wake you; inside a skill that must run to completion, or in a non-interactive run, there is no next turn, so use wait().",
228
- "Use subagent({ action: \"status\", id: \"...\" }) when you need a one-shot status/result or to inspect a blocked/stale run. To block until completion, prefer wait(). Do not poll in a loop just to wait.",
229
- ].join("\n");
230
- }
231
-
232
- /**
233
- * Check if jiti is available for async execution
234
- */
235
- export function isAsyncAvailable(): boolean {
236
- return jitiCliPath !== undefined;
237
- }
238
-
239
- function isNodeExecutableName(execPath: string): boolean {
240
- const basename = path.basename(execPath).toLowerCase();
241
- return basename === "node" || basename === "node.exe" || basename === "nodejs" || basename === "nodejs.exe";
242
- }
243
-
244
- function canUseCurrentNodeExecutable(execPath: string): boolean {
245
- try {
246
- fs.accessSync(execPath, process.platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
247
- return true;
248
- } catch {
249
- return false;
250
- }
251
- }
252
-
253
- function resolveAsyncRunnerNodeCommand(): string {
254
- if (isNodeExecutableName(process.execPath) && canUseCurrentNodeExecutable(process.execPath)) {
255
- return process.execPath;
256
- }
257
- return process.platform === "win32" ? "node.exe" : "node";
258
- }
259
-
260
- export function resolveAsyncRunnerLogPaths(cfg: object): { stdoutPath: string; stderrPath: string } | undefined {
261
- const asyncDir = typeof (cfg as { asyncDir?: unknown }).asyncDir === "string"
262
- ? (cfg as { asyncDir: string }).asyncDir
263
- : undefined;
264
- if (!asyncDir) return undefined;
265
- return {
266
- stdoutPath: path.join(asyncDir, "runner.stdout.log"),
267
- stderrPath: path.join(asyncDir, "runner.stderr.log"),
268
- };
269
- }
270
-
271
- function closeFd(fd: number | undefined): void {
272
- if (fd === undefined) return;
273
- try {
274
- fs.closeSync(fd);
275
- } catch {
276
- // Best-effort cleanup; child process already owns its duplicated stdio fd.
277
- }
278
- }
279
-
280
- /**
281
- * Spawn the async runner process
282
- */
283
- function spawnRunner(cfg: object, suffix: string, cwd: string): { pid?: number; error?: string } {
284
- if (!jitiCliPath) {
285
- return { error: "upstream jiti for TypeScript execution could not be found; ensure package dependencies are installed" };
286
- }
287
-
288
- try {
289
- const cwdStats = fs.statSync(cwd);
290
- if (!cwdStats.isDirectory()) {
291
- return { error: `cwd is not a directory: ${cwd}` };
292
- }
293
- } catch {
294
- return { error: `cwd does not exist: ${cwd}` };
295
- }
296
-
297
- fs.mkdirSync(TEMP_ROOT_DIR, { recursive: true });
298
- const cfgPath = getAsyncConfigPath(suffix);
299
- fs.writeFileSync(cfgPath, JSON.stringify(cfg));
300
- const runner = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-runner.ts");
301
- const nodeCommand = resolveAsyncRunnerNodeCommand();
302
-
303
- const logPaths = resolveAsyncRunnerLogPaths(cfg);
304
- let stdoutFd: number | undefined;
305
- let stderrFd: number | undefined;
306
- try {
307
- if (logPaths) {
308
- fs.mkdirSync(path.dirname(logPaths.stdoutPath), { recursive: true });
309
- stdoutFd = fs.openSync(logPaths.stdoutPath, "a");
310
- stderrFd = fs.openSync(logPaths.stderrPath, "a");
311
- }
312
- const proc = spawn(nodeCommand, [jitiCliPath, runner, cfgPath], {
313
- cwd,
314
- detached: true,
315
- stdio: ["ignore", stdoutFd ?? "ignore", stderrFd ?? "ignore"],
316
- windowsHide: true,
317
- env: {
318
- ...process.env,
319
- ...(piPackageRoot ? { [PI_CODING_AGENT_PACKAGE_ROOT_ENV]: piPackageRoot } : {}),
320
- },
321
- });
322
- closeFd(stdoutFd);
323
- closeFd(stderrFd);
324
- proc.on("error", (error) => {
325
- console.error(`[dm-subagents] async spawn failed: ${error.message}`);
326
- });
327
- if (typeof proc.pid !== "number") {
328
- return { error: `async runner did not produce a pid for cwd: ${cwd}` };
329
- }
330
- proc.unref();
331
- return { pid: proc.pid };
332
- } catch (error) {
333
- closeFd(stdoutFd);
334
- closeFd(stderrFd);
335
- return { error: error instanceof Error ? error.message : String(error) };
336
- }
337
- }
338
-
339
- function formatAsyncStartError(mode: SubagentRunMode, message: string): AsyncExecutionResult {
340
- return {
341
- content: [{ type: "text", text: message }],
342
- isError: true,
343
- details: { mode, results: [] },
344
- };
345
- }
346
-
347
- const UNAVAILABLE_SUBAGENT_SKILL_ERROR = "Skills not found: dm-subagents";
348
-
349
- class UnavailableSubagentSkillError extends Error {}
350
- class AsyncStartValidationError extends Error {}
351
-
352
- export function buildAsyncRunnerSteps(id: string, params: AsyncRunnerStepBuildParams): AsyncRunnerStepBuildResult {
353
- const {
354
- chain,
355
- agents,
356
- ctx,
357
- cwd,
358
- sessionFilesByFlatIndex,
359
- thinkingOverridesByFlatIndex,
360
- maxSubagentDepth,
361
- worktreeBaseDir,
362
- asyncDir,
363
- } = params;
364
- const outputBaseDir = params.outputBaseDir;
365
- const resultMode = params.resultMode ?? "chain";
366
- const chainSkills = params.chainSkills ?? [];
367
- const availableModels = params.availableModels;
368
- const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
369
- const progressDir = params.progressDir ?? runnerCwd;
370
- const graphChain: ChainStep[] = params.attachRoot
371
- ? [{
372
- agent: params.attachRoot.agent,
373
- task: `Attach async root ${params.attachRoot.runId}`,
374
- label: params.attachRoot.label ?? `Attached root ${params.attachRoot.runId}`,
375
- ...(params.attachRoot.outputName ? { as: params.attachRoot.outputName } : {}),
376
- }, ...chain]
377
- : chain;
378
- const firstStep = chain[0];
379
- const originalTask = params.task ?? (firstStep
380
- ? (isParallelStep(firstStep)
381
- ? firstStep.parallel[0]?.task
382
- : isDynamicParallelStep(firstStep)
383
- ? firstStep.parallel.task
384
- : (firstStep as SequentialStep).task)
385
- : undefined);
386
- try {
387
- if (params.validateOutputBindings !== false) {
388
- validateChainOutputBindings(chain, { maxItems: params.dynamicFanoutMaxItems });
389
- }
390
- } catch (error) {
391
- if (error instanceof ChainOutputValidationError) return { error: error.message };
392
- throw error;
393
- }
394
- const workflowGraph = buildWorkflowGraphSnapshot({ runId: id, mode: resultMode, steps: graphChain });
395
-
396
- for (const s of chain) {
397
- const stepAgents = isParallelStep(s)
398
- ? s.parallel.map((t) => t.agent)
399
- : isDynamicParallelStep(s)
400
- ? [s.parallel.agent]
401
- : [(s as SequentialStep).agent];
402
- for (const agentName of stepAgents) {
403
- if (!agents.find((x) => x.name === agentName)) {
404
- return { error: `Unknown agent: ${agentName}` };
405
- }
406
- }
407
- }
408
-
409
- let progressInstructionCreated = false;
410
- const buildStepOverrides = (s: SequentialStep): StepOverrides => {
411
- const stepSkillInput = normalizeSkillInput(s.skill);
412
- return {
413
- ...(s.output !== undefined ? { output: s.output } : {}),
414
- ...(s.outputMode !== undefined ? { outputMode: s.outputMode } : {}),
415
- ...(s.reads !== undefined ? { reads: s.reads } : {}),
416
- ...(s.progress !== undefined ? { progress: s.progress } : {}),
417
- ...(stepSkillInput !== undefined ? { skills: stepSkillInput } : {}),
418
- ...(s.model ? { model: s.model } : {}),
419
- };
420
- };
421
- const buildSeqStep = (s: SequentialStep, sessionFile?: string, behaviorCwd?: string, progressPrecreated = false, resolvedBehavior?: ResolvedStepBehavior, flatIndex?: number) => {
422
- const a = agents.find((x) => x.name === s.agent)!;
423
- const toolBudgetInput = s.toolBudget ?? params.toolBudget ?? a.toolBudget ?? params.configToolBudget;
424
- const resolvedToolBudget = validateToolBudgetConfig(toolBudgetInput, s.toolBudget ? "toolBudget" : a.toolBudget ? "agent.toolBudget" : "config.toolBudget");
425
- if (resolvedToolBudget.error) throw new AsyncStartValidationError(resolvedToolBudget.error);
426
- const stepCwd = resolveChildCwd(runnerCwd, s.cwd);
427
- const instructionCwd = behaviorCwd ?? stepCwd;
428
- const behavior = suppressProgressForReadOnlyTask(resolvedBehavior ?? resolveStepBehavior(a, buildStepOverrides(s), chainSkills), s.task, originalTask);
429
- const skillNames = behavior.skills === false ? [] : behavior.skills;
430
- const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, stepCwd, ctx.cwd);
431
- if (missingSkills.includes("dm-subagents")) throw new UnavailableSubagentSkillError(UNAVAILABLE_SUBAGENT_SKILL_ERROR);
432
-
433
- let systemPrompt = a.systemPrompt?.trim() ?? "";
434
- if (resolvedSkills.length > 0) {
435
- const injection = buildSkillInjection(resolvedSkills);
436
- systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
437
- }
438
- const memoryInjection = buildAgentMemoryInjection(a, stepCwd);
439
- if (memoryInjection) {
440
- systemPrompt = systemPrompt ? `${systemPrompt}\n\n${memoryInjection}` : memoryInjection;
441
- }
442
-
443
- const readInstructions = buildChainInstructions({ ...behavior, output: false, progress: false }, instructionCwd, false);
444
- const isFirstProgressAgent = behavior.progress && !progressPrecreated && !progressInstructionCreated;
445
- if (behavior.progress) progressInstructionCreated = true;
446
- const progressInstructions = buildChainInstructions({ ...behavior, output: false, reads: false }, progressDir, isFirstProgressAgent);
447
- const outputPath = resolveSingleOutputPath(behavior.output, ctx.cwd, instructionCwd, outputBaseDir);
448
- systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath);
449
- const validationError = validateFileOnlyOutputMode(behavior.outputMode, outputPath, `Async step (${s.agent})`);
450
- if (validationError) throw new AsyncStartValidationError(validationError);
451
- let taskTemplate = s.task ?? "{previous}";
452
- taskTemplate = taskTemplate.replace(/\{task\}/g, originalTask ?? "");
453
- taskTemplate = taskTemplate.replace(/\{chain_dir\}/g, runnerCwd);
454
- const task = injectSingleOutputInstruction(`${readInstructions.prefix}${taskTemplate}${progressInstructions.suffix}`, outputPath);
455
-
456
- const requestedModel = behavior.model ?? a.model;
457
- const primaryModel = resolveSubagentModelOverride(requestedModel, ctx.currentModel, availableModels, ctx.currentModelProvider, { scope: ctx.modelScope, source: behavior.model ? "explicit" : "inherited" });
458
- const thinkingOverride = flatIndex === undefined ? undefined : thinkingOverridesByFlatIndex?.[flatIndex];
459
- const effectiveThinking = thinkingOverride ?? a.thinking;
460
- const model = applyThinkingSuffix(primaryModel, effectiveThinking, thinkingOverride !== undefined);
461
- return {
462
- parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
463
- agent: s.agent,
464
- task,
465
- phase: s.phase,
466
- label: s.label,
467
- outputName: s.as,
468
- structured: Boolean(s.outputSchema),
469
- cwd: stepCwd,
470
- model,
471
- thinking: resolveEffectiveThinking(model, effectiveThinking),
472
- modelCandidates: buildModelCandidates(primaryModel, a.fallbackModels, availableModels, ctx.currentModelProvider, { scope: ctx.modelScope }).map((candidate) =>
473
- applyThinkingSuffix(candidate, effectiveThinking, thinkingOverride !== undefined),
474
- ),
475
- tools: a.tools,
476
- extensions: a.extensions,
477
- subagentOnlyExtensions: a.subagentOnlyExtensions,
478
- mcpDirectTools: a.mcpDirectTools,
479
- completionGuard: a.completionGuard,
480
- systemPrompt,
481
- systemPromptMode: a.systemPromptMode,
482
- inheritProjectContext: a.inheritProjectContext,
483
- inheritSkills: a.inheritSkills,
484
- skills: resolvedSkills.map((r) => r.name),
485
- outputPath,
486
- outputMode: behavior.outputMode,
487
- sessionFile,
488
- maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, a.maxSubagentDepth),
489
- effectiveAcceptance: resolveEffectiveAcceptance({
490
- explicit: s.acceptance,
491
- agentName: s.agent,
492
- task: s.task,
493
- mode: resultMode,
494
- async: true,
495
- dynamic: false,
496
- }),
497
- ...(s.outputSchema ? { structuredOutputSchema: s.outputSchema } : {}),
498
- ...(s.outputSchema ? { structuredOutput: createStructuredOutputRuntime(s.outputSchema, path.join(asyncDir, "structured-output")) } : {}),
499
- ...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
500
- };
501
- };
502
-
503
- let flatStepIndex = 0;
504
- const nextFlatStep = (): { index: number; sessionFile?: string; thinkingOverride?: AgentConfig["thinking"] } => {
505
- const index = flatStepIndex;
506
- const sessionFile = sessionFilesByFlatIndex?.[flatStepIndex];
507
- const thinkingOverride = thinkingOverridesByFlatIndex?.[flatStepIndex];
508
- flatStepIndex++;
509
- return {
510
- index,
511
- ...(sessionFile ? { sessionFile } : {}),
512
- ...(thinkingOverride ? { thinkingOverride } : {}),
513
- };
514
- };
515
-
516
- try {
517
- const builtSteps = chain.map((s, stepIndex) => {
518
- if (isParallelStep(s)) {
519
- const parallelBehaviors = s.parallel.map((task) => {
520
- const agent = agents.find((candidate) => candidate.name === task.agent)!;
521
- return suppressProgressForReadOnlyTask(resolveStepBehavior(agent, buildStepOverrides(task), chainSkills), task.task, originalTask);
522
- });
523
- const progressPrecreated = parallelBehaviors.some((behavior) => behavior.progress);
524
- if (progressPrecreated) {
525
- if (!s.worktree || params.progressDir) writeInitialProgressFile(progressDir);
526
- progressInstructionCreated = true;
527
- }
528
- return {
529
- parallel: s.parallel.map((t, taskIndex) => {
530
- let behaviorCwd: string | undefined;
531
- if (s.worktree) {
532
- try {
533
- behaviorCwd = resolveExpectedWorktreeAgentCwd(runnerCwd, `${id}-s${stepIndex}`, taskIndex, worktreeBaseDir);
534
- } catch {
535
- behaviorCwd = undefined;
536
- }
537
- }
538
- const staticStep = nextFlatStep();
539
- return buildSeqStep(t, staticStep.sessionFile, behaviorCwd, progressPrecreated, parallelBehaviors[taskIndex], staticStep.index);
540
- }),
541
- concurrency: s.concurrency,
542
- failFast: s.failFast,
543
- worktree: s.worktree,
544
- };
545
- }
546
- if (isDynamicParallelStep(s)) {
547
- const agent = agents.find((candidate) => candidate.name === s.parallel.agent)!;
548
- const behavior = suppressProgressForReadOnlyTask(resolveStepBehavior(agent, buildStepOverrides(s.parallel), chainSkills), s.parallel.task, originalTask);
549
- const progressPrecreated = behavior.progress;
550
- if (progressPrecreated) {
551
- writeInitialProgressFile(progressDir);
552
- progressInstructionCreated = true;
553
- }
554
- const maxItems = s.expand.maxItems ?? params.dynamicFanoutMaxItems ?? 0;
555
- const dynamicFlatSteps = Array.from({ length: maxItems }, () => nextFlatStep());
556
- return {
557
- expand: s.expand,
558
- parallel: buildSeqStep(s.parallel as SequentialStep, undefined, undefined, progressPrecreated, behavior),
559
- collect: s.collect,
560
- concurrency: s.concurrency,
561
- failFast: s.failFast,
562
- phase: s.phase,
563
- label: s.label,
564
- sessionFiles: dynamicFlatSteps.map((step) => step.sessionFile),
565
- thinkingOverrides: dynamicFlatSteps.map((step) => step.thinkingOverride),
566
- effectiveAcceptance: resolveEffectiveAcceptance({
567
- explicit: s.acceptance,
568
- agentName: s.parallel.agent,
569
- task: s.parallel.task,
570
- mode: resultMode,
571
- async: true,
572
- dynamicGroup: true,
573
- }),
574
- };
575
- }
576
- const staticStep = nextFlatStep();
577
- return buildSeqStep(s as SequentialStep, staticStep.sessionFile, undefined, false, undefined, staticStep.index);
578
- });
579
- const steps = params.attachRoot
580
- ? [{
581
- agent: params.attachRoot.agent,
582
- task: "",
583
- label: params.attachRoot.label ?? `Attached root ${params.attachRoot.runId}`,
584
- outputName: params.attachRoot.outputName,
585
- importAsyncRoot: {
586
- runId: params.attachRoot.runId,
587
- asyncDir: params.attachRoot.asyncDir,
588
- resultPath: params.attachRoot.resultPath,
589
- index: params.attachRoot.index,
590
- },
591
- inheritProjectContext: false,
592
- inheritSkills: false,
593
- }, ...builtSteps]
594
- : builtSteps;
595
- return { steps, runnerCwd, workflowGraph, eventChain: graphChain, ...(originalTask !== undefined ? { originalTask } : {}) };
596
- } catch (error) {
597
- if (error instanceof UnavailableSubagentSkillError || error instanceof AsyncStartValidationError) return { error: error.message };
598
- throw error;
599
- }
600
- }
601
-
602
- /**
603
- * Execute a chain asynchronously
604
- */
605
- export function executeAsyncChain(
606
- id: string,
607
- params: AsyncChainParams,
608
- ): AsyncExecutionResult {
609
- const {
610
- chain,
611
- agents,
612
- ctx,
613
- cwd,
614
- maxOutput,
615
- artifactsDir,
616
- artifactConfig,
617
- shareEnabled,
618
- sessionRoot,
619
- sessionFilesByFlatIndex,
620
- thinkingOverridesByFlatIndex,
621
- maxSubagentDepth,
622
- worktreeSetupHook,
623
- worktreeSetupHookTimeoutMs,
624
- worktreeBaseDir,
625
- controlConfig,
626
- controlIntercomTarget,
627
- childIntercomTarget,
628
- nestedRoute,
629
- } = params;
630
- const resultMode = params.resultMode ?? "chain";
631
- const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
632
- const nestedAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
633
- const asyncDir = inheritedNestedRoute
634
- ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id)
635
- : path.join(ASYNC_DIR, id);
636
- try {
637
- fs.mkdirSync(asyncDir, { recursive: true });
638
- } catch (error) {
639
- const message = error instanceof Error ? error.message : String(error);
640
- return {
641
- content: [{ type: "text", text: `Failed to create async run directory '${asyncDir}': ${message}` }],
642
- isError: true,
643
- details: { mode: resultMode, results: [] },
644
- };
645
- }
646
-
647
- const built = buildAsyncRunnerSteps(id, {
648
- chain,
649
- task: params.task,
650
- attachRoot: params.attachRoot,
651
- resultMode,
652
- agents,
653
- ctx,
654
- availableModels: params.availableModels,
655
- cwd,
656
- chainSkills: params.chainSkills,
657
- sessionFilesByFlatIndex,
658
- thinkingOverridesByFlatIndex,
659
- progressDir: params.progressDir ?? (artifactsDir ? path.join(artifactsDir, "progress", id) : resultMode === "parallel" ? path.join(asyncDir, "progress") : undefined),
660
- outputBaseDir: artifactsDir ? path.join(artifactsDir, "outputs", id) : undefined,
661
- dynamicFanoutMaxItems: params.dynamicFanoutMaxItems,
662
- maxSubagentDepth,
663
- worktreeBaseDir,
664
- asyncDir,
665
- toolBudget: params.toolBudget,
666
- configToolBudget: params.configToolBudget,
667
- });
668
- if ("error" in built) {
669
- try {
670
- fs.rmSync(asyncDir, { recursive: true, force: true });
671
- } catch {
672
- // Best-effort cleanup for validation failures before the runner is spawned.
673
- }
674
- return formatAsyncStartError(resultMode, built.error);
675
- }
676
- const { steps, runnerCwd, workflowGraph, eventChain } = built;
677
- const deadlineAt = params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined;
678
- const initialTurnBudget = params.turnBudget ? initialTurnBudgetState(params.turnBudget) : undefined;
679
- let childTargetIndex = 0;
680
- const childIntercomTargets = childIntercomTarget ? steps.flatMap((step) => {
681
- if (!("parallel" in step) && step.importAsyncRoot) {
682
- childTargetIndex++;
683
- return [undefined];
684
- }
685
- if ("parallel" in step) {
686
- if (!Array.isArray(step.parallel)) {
687
- childTargetIndex++;
688
- return [undefined];
689
- }
690
- return step.parallel.map((task) => childIntercomTarget(task.agent, childTargetIndex++));
691
- }
692
- return [childIntercomTarget(step.agent, childTargetIndex++)];
693
- }) : undefined;
694
-
695
- let spawnResult: { pid?: number; error?: string } = {};
696
- try {
697
- spawnResult = spawnRunner(
698
- {
699
- id,
700
- steps,
701
- resultPath: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) : path.join(RESULTS_DIR, `${id}.json`),
702
- cwd: runnerCwd,
703
- placeholder: "{previous}",
704
- maxOutput,
705
- artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
706
- artifactConfig,
707
- share: shareEnabled,
708
- sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
709
- asyncDir,
710
- sessionId: ctx.currentSessionId,
711
- piPackageRoot,
712
- piArgv1: process.argv[1],
713
- worktreeSetupHook,
714
- worktreeSetupHookTimeoutMs,
715
- worktreeBaseDir,
716
- controlConfig,
717
- turnBudget: params.turnBudget,
718
- toolBudget: params.toolBudget,
719
- controlIntercomTarget,
720
- childIntercomTargets,
721
- resultMode,
722
- dynamicFanoutMaxItems: params.dynamicFanoutMaxItems,
723
- timeoutMs: params.timeoutMs,
724
- deadlineAt,
725
- globalConcurrencyLimit: params.globalConcurrencyLimit,
726
- workflowGraph,
727
- nestedRoute: nestedRoute ?? inheritedNestedRoute,
728
- nestedSelf: inheritedNestedRoute && nestedAddress ? {
729
- parentRunId: nestedAddress.parentRunId,
730
- parentStepIndex: nestedAddress.parentStepIndex,
731
- depth: nestedAddress.depth,
732
- path: nestedAddress.path,
733
- } : undefined,
734
- },
735
- id,
736
- runnerCwd,
737
- );
738
- } catch (error) {
739
- const message = error instanceof Error ? error.message : String(error);
740
- return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': ${message}`);
741
- }
742
-
743
- if (spawnResult.error) {
744
- return formatAsyncStartError(resultMode, `Failed to start async ${resultMode} '${id}': ${spawnResult.error}`);
745
- }
746
-
747
- if (spawnResult.pid) {
748
- const eventFirstStep = eventChain[0];
749
- const firstAgents = isParallelStep(eventFirstStep)
750
- ? eventFirstStep.parallel.map((t) => t.agent)
751
- : isDynamicParallelStep(eventFirstStep)
752
- ? [eventFirstStep.parallel.agent]
753
- : [(eventFirstStep as SequentialStep).agent];
754
- const parallelGroups: Array<{ start: number; count: number; stepIndex: number }> = [];
755
- const flatAgents: string[] = [];
756
- let flatStepStart = 0;
757
- for (let stepIndex = 0; stepIndex < eventChain.length; stepIndex++) {
758
- const step = eventChain[stepIndex]!;
759
- if (isParallelStep(step)) {
760
- parallelGroups.push({ start: flatStepStart, count: step.parallel.length, stepIndex });
761
- flatAgents.push(...step.parallel.map((task) => task.agent));
762
- flatStepStart += step.parallel.length;
763
- } else if (isDynamicParallelStep(step)) {
764
- parallelGroups.push({ start: flatStepStart, count: 1, stepIndex });
765
- flatAgents.push(step.parallel.agent);
766
- flatStepStart++;
767
- } else {
768
- flatAgents.push((step as SequentialStep).agent);
769
- flatStepStart++;
770
- }
771
- }
772
- if (inheritedNestedRoute && nestedAddress) {
773
- const now = Date.now();
774
- try {
775
- writeNestedEvent(inheritedNestedRoute, {
776
- type: "subagent.nested.started",
777
- ts: now,
778
- parentRunId: nestedAddress.parentRunId,
779
- parentStepIndex: nestedAddress.parentStepIndex,
780
- child: {
781
- id,
782
- parentRunId: nestedAddress.parentRunId,
783
- parentStepIndex: nestedAddress.parentStepIndex,
784
- depth: nestedAddress.depth,
785
- path: nestedAddress.path,
786
- asyncDir,
787
- pid: spawnResult.pid,
788
- ownerIntercomTarget: process.env.DM_SUBAGENT_INTERCOM_SESSION_NAME,
789
- leafIntercomTarget: childIntercomTargets?.[0],
790
- intercomTarget: childIntercomTargets?.[0],
791
- ownerState: "live",
792
- mode: resultMode,
793
- state: "running",
794
- agent: firstAgents[0],
795
- agents: flatAgents,
796
- chainStepCount: eventChain.length,
797
- parallelGroups,
798
- ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
799
- ...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
800
- startedAt: now,
801
- lastUpdate: now,
802
- },
803
- });
804
- } catch (error) {
805
- console.error("Failed to emit nested async start event:", error);
806
- }
807
- }
808
- ctx.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
809
- lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
810
- id,
811
- pid: spawnResult.pid,
812
- sessionId: ctx.currentSessionId,
813
- mode: resultMode,
814
- agent: firstAgents[0],
815
- agents: flatAgents,
816
- task: isParallelStep(eventFirstStep)
817
- ? eventFirstStep.parallel[0]?.task?.slice(0, 50)
818
- : isDynamicParallelStep(eventFirstStep)
819
- ? eventFirstStep.parallel.task?.slice(0, 50)
820
- : (eventFirstStep as SequentialStep).task?.slice(0, 50),
821
- chain: eventChain.map((s) =>
822
- isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : isDynamicParallelStep(s) ? `expand:${s.parallel.agent}` : (s as SequentialStep).agent,
823
- ),
824
- chainStepCount: eventChain.length,
825
- parallelGroups,
826
- workflowGraph,
827
- cwd: runnerCwd,
828
- asyncDir,
829
- ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
830
- ...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
831
- nestedRoute,
832
- });
833
- }
834
-
835
- const chainDesc = chain
836
- .map((s) =>
837
- isParallelStep(s) ? `[${s.parallel.map((t) => t.agent).join("+")}]` : isDynamicParallelStep(s) ? `expand:${s.parallel.agent}` : (s as SequentialStep).agent,
838
- )
839
- .join(" -> ");
840
-
841
- return {
842
- content: [{ type: "text", text: formatAsyncStartedMessage(`Async ${resultMode}: ${chainDesc} [${id}]`) }],
843
- details: { mode: resultMode, runId: id, results: [], asyncId: id, asyncDir, workflowGraph, ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
844
- };
845
- }
846
-
847
- /**
848
- * Execute a single agent asynchronously
849
- */
850
- export function executeAsyncSingle(
851
- id: string,
852
- params: AsyncSingleParams,
853
- ): AsyncExecutionResult {
854
- const {
855
- agent,
856
- agentConfig,
857
- ctx,
858
- cwd,
859
- maxOutput,
860
- artifactsDir,
861
- artifactConfig,
862
- shareEnabled,
863
- sessionRoot,
864
- sessionFile,
865
- maxSubagentDepth,
866
- worktreeSetupHook,
867
- worktreeSetupHookTimeoutMs,
868
- worktreeBaseDir,
869
- controlConfig,
870
- controlIntercomTarget,
871
- childIntercomTarget,
872
- nestedRoute,
873
- } = params;
874
- const task = params.task ?? "";
875
- const runnerCwd = resolveChildCwd(ctx.cwd, cwd);
876
- const skillNames = params.skills ?? agentConfig.skills ?? [];
877
- const availableModels = params.availableModels;
878
- const { resolved: resolvedSkills, missing: missingSkills } = resolveSkillsWithFallback(skillNames, runnerCwd, ctx.cwd);
879
- if (missingSkills.includes("dm-subagents")) return formatAsyncStartError("single", UNAVAILABLE_SUBAGENT_SKILL_ERROR);
880
- let systemPrompt = agentConfig.systemPrompt?.trim() ?? "";
881
- if (resolvedSkills.length > 0) {
882
- const injection = buildSkillInjection(resolvedSkills);
883
- systemPrompt = systemPrompt ? `${systemPrompt}\n\n${injection}` : injection;
884
- }
885
- const memoryInjection = buildAgentMemoryInjection(agentConfig, runnerCwd);
886
- if (memoryInjection) {
887
- systemPrompt = systemPrompt ? `${systemPrompt}\n\n${memoryInjection}` : memoryInjection;
888
- }
889
-
890
- const inheritedNestedRoute = resolveInheritedNestedRouteFromEnv();
891
- const nestedAddress = inheritedNestedRoute ? resolveNestedParentAddressFromEnv() : undefined;
892
- const asyncDir = inheritedNestedRoute
893
- ? path.join(TEMP_ROOT_DIR, "nested-subagent-runs", inheritedNestedRoute.rootRunId, id)
894
- : path.join(ASYNC_DIR, id);
895
- try {
896
- fs.mkdirSync(asyncDir, { recursive: true });
897
- } catch (error) {
898
- const message = error instanceof Error ? error.message : String(error);
899
- return {
900
- content: [{ type: "text", text: `Failed to create async run directory '${asyncDir}': ${message}` }],
901
- isError: true,
902
- details: { mode: "single" as const, results: [] },
903
- };
904
- }
905
-
906
- const effectiveOutput = normalizeSingleOutputOverride(params.output, agentConfig.output);
907
- const outputPath = resolveSingleOutputPath(effectiveOutput, ctx.cwd, runnerCwd, params.outputBaseDir ?? (artifactsDir ? path.join(artifactsDir, "outputs", id) : undefined));
908
- systemPrompt = injectOutputPathSystemPrompt(systemPrompt, outputPath);
909
- const outputMode = params.outputMode ?? "inline";
910
- const validationError = validateFileOnlyOutputMode(outputMode, outputPath, `Async single run (${agent})`);
911
- if (validationError) return formatAsyncStartError("single", validationError);
912
- const taskWithOutputInstruction = injectSingleOutputInstruction(task, outputPath);
913
- const primaryModel = resolveSubagentModelOverride(
914
- params.modelOverride ?? agentConfig.model,
915
- ctx.currentModel,
916
- availableModels,
917
- ctx.currentModelProvider,
918
- );
919
- const effectiveThinking = params.thinkingOverride ?? agentConfig.thinking;
920
- const model = applyThinkingSuffix(primaryModel, effectiveThinking, params.thinkingOverride !== undefined);
921
- const toolBudgetInput = params.toolBudget ?? agentConfig.toolBudget ?? params.configToolBudget;
922
- const resolvedToolBudget = validateToolBudgetConfig(toolBudgetInput, params.toolBudget ? "toolBudget" : agentConfig.toolBudget ? "agent.toolBudget" : "config.toolBudget");
923
- if (resolvedToolBudget.error) return formatAsyncStartError("single", resolvedToolBudget.error);
924
- const deadlineAt = params.timeoutMs !== undefined ? Date.now() + params.timeoutMs : undefined;
925
- const initialTurnBudget = params.turnBudget ? initialTurnBudgetState(params.turnBudget) : undefined;
926
- let spawnResult: { pid?: number; error?: string } = {};
927
- try {
928
- spawnResult = spawnRunner(
929
- {
930
- id,
931
- steps: [
932
- {
933
- parentSessionId: ctx.parentSessionId ?? ctx.currentSessionId,
934
- agent,
935
- task: taskWithOutputInstruction,
936
- cwd: runnerCwd,
937
- model,
938
- thinking: resolveEffectiveThinking(model, effectiveThinking),
939
- modelCandidates: buildModelCandidates(primaryModel, agentConfig.fallbackModels, availableModels, ctx.currentModelProvider, { scope: ctx.modelScope }).map((candidate) =>
940
- applyThinkingSuffix(candidate, effectiveThinking, params.thinkingOverride !== undefined),
941
- ),
942
- tools: agentConfig.tools,
943
- extensions: agentConfig.extensions,
944
- subagentOnlyExtensions: agentConfig.subagentOnlyExtensions,
945
- mcpDirectTools: agentConfig.mcpDirectTools,
946
- completionGuard: agentConfig.completionGuard,
947
- systemPrompt,
948
- systemPromptMode: agentConfig.systemPromptMode,
949
- inheritProjectContext: agentConfig.inheritProjectContext,
950
- inheritSkills: agentConfig.inheritSkills,
951
- skills: resolvedSkills.map((r) => r.name),
952
- outputPath,
953
- outputMode,
954
- sessionFile,
955
- maxSubagentDepth: resolveChildMaxSubagentDepth(maxSubagentDepth, agentConfig.maxSubagentDepth),
956
- effectiveAcceptance: resolveEffectiveAcceptance({
957
- explicit: params.acceptance,
958
- agentName: agent,
959
- task,
960
- mode: "single",
961
- async: true,
962
- }),
963
- ...(resolvedToolBudget.budget ? { toolBudget: resolvedToolBudget.budget } : {}),
964
- },
965
- ],
966
- resultPath: inheritedNestedRoute ? nestedResultsPath(inheritedNestedRoute.rootRunId, id) : path.join(RESULTS_DIR, `${id}.json`),
967
- cwd: runnerCwd,
968
- placeholder: "{previous}",
969
- maxOutput,
970
- artifactsDir: artifactConfig.enabled ? artifactsDir : undefined,
971
- artifactConfig,
972
- share: shareEnabled,
973
- sessionDir: sessionRoot ? path.join(sessionRoot, `async-${id}`) : undefined,
974
- asyncDir,
975
- sessionId: ctx.currentSessionId,
976
- piPackageRoot,
977
- piArgv1: process.argv[1],
978
- worktreeSetupHook,
979
- worktreeSetupHookTimeoutMs,
980
- worktreeBaseDir,
981
- controlConfig,
982
- timeoutMs: params.timeoutMs,
983
- deadlineAt,
984
- turnBudget: params.turnBudget,
985
- toolBudget: params.toolBudget,
986
- controlIntercomTarget,
987
- childIntercomTargets: childIntercomTarget ? [childIntercomTarget(agent, 0)] : undefined,
988
- resultMode: "single",
989
- nestedRoute: nestedRoute ?? inheritedNestedRoute,
990
- nestedSelf: inheritedNestedRoute && nestedAddress ? {
991
- parentRunId: nestedAddress.parentRunId,
992
- parentStepIndex: nestedAddress.parentStepIndex,
993
- depth: nestedAddress.depth,
994
- path: nestedAddress.path,
995
- } : undefined,
996
- },
997
- id,
998
- runnerCwd,
999
- );
1000
- } catch (error) {
1001
- const message = error instanceof Error ? error.message : String(error);
1002
- return formatAsyncStartError("single", `Failed to start async run '${id}': ${message}`);
1003
- }
1004
-
1005
- if (spawnResult.error) {
1006
- return formatAsyncStartError("single", `Failed to start async run '${id}': ${spawnResult.error}`);
1007
- }
1008
-
1009
- if (spawnResult.pid) {
1010
- if (inheritedNestedRoute && nestedAddress) {
1011
- const now = Date.now();
1012
- try {
1013
- writeNestedEvent(inheritedNestedRoute, {
1014
- type: "subagent.nested.started",
1015
- ts: now,
1016
- parentRunId: nestedAddress.parentRunId,
1017
- parentStepIndex: nestedAddress.parentStepIndex,
1018
- child: {
1019
- id,
1020
- parentRunId: nestedAddress.parentRunId,
1021
- parentStepIndex: nestedAddress.parentStepIndex,
1022
- depth: nestedAddress.depth,
1023
- path: nestedAddress.path,
1024
- asyncDir,
1025
- pid: spawnResult.pid,
1026
- ownerIntercomTarget: process.env.DM_SUBAGENT_INTERCOM_SESSION_NAME,
1027
- leafIntercomTarget: childIntercomTarget?.(agent, 0),
1028
- intercomTarget: childIntercomTarget?.(agent, 0),
1029
- ownerState: "live",
1030
- mode: "single",
1031
- state: "running",
1032
- agent,
1033
- agents: [agent],
1034
- chainStepCount: 1,
1035
- ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
1036
- ...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
1037
- startedAt: now,
1038
- lastUpdate: now,
1039
- },
1040
- });
1041
- } catch (error) {
1042
- console.error("Failed to emit nested async start event:", error);
1043
- }
1044
- }
1045
- ctx.pi.events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
1046
- lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
1047
- id,
1048
- pid: spawnResult.pid,
1049
- sessionId: ctx.currentSessionId,
1050
- mode: "single",
1051
- agent,
1052
- task: task?.slice(0, 50),
1053
- cwd: runnerCwd,
1054
- asyncDir,
1055
- ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}),
1056
- ...(initialTurnBudget ? { turnBudget: initialTurnBudget } : {}),
1057
- nestedRoute,
1058
- });
1059
- }
1060
-
1061
- return {
1062
- content: [{ type: "text", text: formatAsyncStartedMessage(`Async: ${agent} [${id}]`) }],
1063
- details: { mode: "single", runId: id, results: [], asyncId: id, asyncDir, ...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs, deadlineAt } : {}), ...(params.turnBudget ? { turnBudget: params.turnBudget } : {}), ...(params.toolBudget ? { toolBudget: params.toolBudget } : {}) },
1064
- };
1065
- }