@duckmind/dm-darwin-x64 0.43.4 → 0.48.5

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 (254) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +242 -50
  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 +51 -51
  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/research.mjs +59 -59
  132. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +10 -10
  133. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
  134. package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
  135. package/extensions/greedysearch-dm/src/types.js +0 -0
  136. package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
  137. package/package.json +1 -1
  138. package/extensions/dm-9router-ext/src/index.ts +0 -541
  139. package/extensions/dm-ask-user/index.ts +0 -857
  140. package/extensions/dm-context/src/context.ts +0 -158
  141. package/extensions/dm-context/src/index.ts +0 -439
  142. package/extensions/dm-context/src/utils.ts +0 -6
  143. package/extensions/dm-fff/src/index.ts +0 -1023
  144. package/extensions/dm-fff/src/query.ts +0 -87
  145. package/extensions/dm-goal/src/goal.ts +0 -1073
  146. package/extensions/dm-grill-me/index.ts +0 -1085
  147. package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
  148. package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
  149. package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
  150. package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
  151. package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
  152. package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
  153. package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
  154. package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
  155. package/extensions/dm-subagents/src/agents/identity.ts +0 -30
  156. package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
  157. package/extensions/dm-subagents/src/agents/skills.ts +0 -729
  158. package/extensions/dm-subagents/src/extension/config.ts +0 -39
  159. package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
  160. package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
  161. package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
  162. package/extensions/dm-subagents/src/extension/index.ts +0 -656
  163. package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
  164. package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
  165. package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
  166. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
  167. package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
  168. package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
  169. package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
  170. package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
  171. package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
  172. package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
  173. package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
  174. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
  175. package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
  176. package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
  177. package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
  178. package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
  179. package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
  180. package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
  181. package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
  182. package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
  183. package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
  184. package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
  185. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
  186. package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
  187. package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
  188. package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
  189. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
  190. package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
  191. package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
  192. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
  193. package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
  194. package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
  195. package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
  196. package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
  197. package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
  198. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
  199. package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
  200. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
  201. package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
  202. package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
  203. package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
  204. package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
  205. package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
  206. package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
  207. package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
  208. package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
  209. package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
  210. package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
  211. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
  212. package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
  213. package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
  214. package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
  215. package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
  216. package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
  217. package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
  218. package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
  219. package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
  220. package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
  221. package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
  222. package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
  223. package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
  224. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  225. package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
  226. package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
  227. package/extensions/dm-subagents/src/shared/settings.ts +0 -450
  228. package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
  229. package/extensions/dm-subagents/src/shared/types.ts +0 -1257
  230. package/extensions/dm-subagents/src/shared/utils.ts +0 -554
  231. package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
  232. package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
  233. package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
  234. package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
  235. package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
  236. package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
  237. package/extensions/dm-subagents/src/tui/render.ts +0 -1748
  238. package/extensions/dm-tasks/src/auto-clear.ts +0 -91
  239. package/extensions/dm-tasks/src/index.ts +0 -1145
  240. package/extensions/dm-tasks/src/process-tracker.ts +0 -140
  241. package/extensions/dm-tasks/src/task-store.ts +0 -305
  242. package/extensions/dm-tasks/src/tasks-config.ts +0 -23
  243. package/extensions/dm-tasks/src/types.ts +0 -40
  244. package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
  245. package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
  246. package/extensions/dm-usage/index.ts +0 -1718
  247. package/extensions/greedysearch-dm/index.ts +0 -177
  248. package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
  249. package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
  250. package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
  251. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
  252. package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
  253. package/extensions/greedysearch-dm/src/types.ts +0 -110
  254. package/extensions/greedysearch-dm/src/utils/helpers.ts +0 -40
@@ -1,116 +0,0 @@
1
- import { isDynamicParallelStep, isParallelStep, type ChainStep, type SequentialStep } from "../../shared/settings.ts";
2
- import type { ChainOutputMap, ChainOutputMapEntry, SingleResult } from "../../shared/types.ts";
3
- import { getSingleResultOutput } from "../../shared/utils.ts";
4
- import { DynamicFanoutError, hasDynamicFanoutFields, type DynamicFanoutConfig, validateDynamicStepShape } from "./dynamic-fanout.ts";
5
-
6
- const OUTPUT_REF_PATTERN = /\{outputs\.([^}]*)\}/g;
7
- const SAFE_OUTPUT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
8
-
9
- export class ChainOutputValidationError extends Error {}
10
-
11
- export interface ChainOutputValidationContext {
12
- priorOutputNames?: Iterable<string>;
13
- startStepIndex?: number;
14
- }
15
-
16
- function outputNamesForStep(step: ChainStep): string[] {
17
- if (isParallelStep(step)) return step.parallel.map((task) => task.as).filter((name): name is string => Boolean(name));
18
- if (isDynamicParallelStep(step)) return [step.collect.as];
19
- const name = (step as SequentialStep).as;
20
- return name ? [name] : [];
21
- }
22
-
23
- function taskTemplatesForStep(step: ChainStep): string[] {
24
- if (isParallelStep(step)) return step.parallel.map((task) => task.task ?? "{previous}");
25
- if (isDynamicParallelStep(step)) return [step.parallel.task ?? "{previous}", step.parallel.label ?? ""].filter(Boolean);
26
- return [(step as SequentialStep).task ?? "{previous}"];
27
- }
28
-
29
- export function validateChainOutputBindings(steps: ChainStep[], dynamicFanoutConfig: DynamicFanoutConfig = {}): void {
30
- validateChainOutputBindingsWithContext(steps, dynamicFanoutConfig);
31
- }
32
-
33
- export function validateChainOutputBindingsWithContext(
34
- steps: ChainStep[],
35
- dynamicFanoutConfig: DynamicFanoutConfig = {},
36
- context: ChainOutputValidationContext = {},
37
- ): void {
38
- const priorOutputNames = [...(context.priorOutputNames ?? [])];
39
- const available = new Set<string>(priorOutputNames);
40
- const seen = new Set<string>(priorOutputNames);
41
- for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
42
- const displayStepIndex = (context.startStepIndex ?? 0) + stepIndex + 1;
43
- const step = steps[stepIndex]!;
44
- if (hasDynamicFanoutFields(step)) {
45
- if (!isDynamicParallelStep(step)) {
46
- throw new ChainOutputValidationError(`Dynamic chain step ${displayStepIndex} requires expand, a single parallel template object, and collect; dynamic expand/collect cannot be mixed with static parallel arrays.`);
47
- }
48
- try {
49
- validateDynamicStepShape(step, displayStepIndex - 1, dynamicFanoutConfig);
50
- } catch (error) {
51
- if (error instanceof DynamicFanoutError) throw new ChainOutputValidationError(error.message);
52
- throw error;
53
- }
54
- if (!available.has(step.expand.from.output)) {
55
- throw new ChainOutputValidationError(`Dynamic chain step ${displayStepIndex} references unknown output '${step.expand.from.output}'. Named outputs are only available after producing step/group completes.`);
56
- }
57
- }
58
- for (const name of outputNamesForStep(step)) {
59
- if (!SAFE_OUTPUT_NAME_PATTERN.test(name)) {
60
- throw new ChainOutputValidationError(`Invalid chain output name '${name}' at step ${displayStepIndex}. Use /^[A-Za-z_][A-Za-z0-9_]*$/.`);
61
- }
62
- if (seen.has(name)) {
63
- throw new ChainOutputValidationError(`Duplicate chain output name '${name}'. Each as name must be unique.`);
64
- }
65
- seen.add(name);
66
- }
67
- for (const template of taskTemplatesForStep(step)) {
68
- for (const match of template.matchAll(OUTPUT_REF_PATTERN)) {
69
- const rawReference = match[0];
70
- const name = match[1]!;
71
- if (!SAFE_OUTPUT_NAME_PATTERN.test(name)) {
72
- throw new ChainOutputValidationError(`Invalid chain output reference '${rawReference}' at step ${displayStepIndex}. Use {outputs.name} with /^[A-Za-z_][A-Za-z0-9_]*$/ names.`);
73
- }
74
- if (!available.has(name)) {
75
- throw new ChainOutputValidationError(`Unknown chain output reference '${rawReference}' at step ${displayStepIndex}. Named outputs are only available after producing step/group completes.`);
76
- }
77
- }
78
- }
79
- for (const name of outputNamesForStep(step)) {
80
- available.add(name);
81
- }
82
- }
83
- }
84
-
85
- export function resolveOutputReferences(template: string, outputs: ChainOutputMap): string {
86
- return template.replace(OUTPUT_REF_PATTERN, (rawReference, name: string) => {
87
- if (!SAFE_OUTPUT_NAME_PATTERN.test(name)) {
88
- throw new ChainOutputValidationError(`Invalid chain output reference '${rawReference}'. Use {outputs.name} with /^[A-Za-z_][A-Za-z0-9_]*$/ names.`);
89
- }
90
- const entry = outputs[name];
91
- if (!entry) throw new ChainOutputValidationError(`Unknown chain output reference '${rawReference}'.`);
92
- return entry.text;
93
- });
94
- }
95
-
96
- function compactStructuredText(value: unknown): string {
97
- return JSON.stringify(value);
98
- }
99
-
100
- export function outputEntryFromResult(result: SingleResult, stepIndex: number): ChainOutputMapEntry {
101
- return {
102
- text: result.structuredOutput !== undefined ? compactStructuredText(result.structuredOutput) : getSingleResultOutput(result),
103
- ...(result.structuredOutput !== undefined ? { structured: result.structuredOutput } : {}),
104
- agent: result.agent,
105
- stepIndex,
106
- };
107
- }
108
-
109
- export function outputEntryFromAsyncResult(result: { agent: string; output: string; structuredOutput?: unknown }, stepIndex: number): ChainOutputMapEntry {
110
- return {
111
- text: result.structuredOutput !== undefined ? compactStructuredText(result.structuredOutput) : result.output,
112
- ...(result.structuredOutput !== undefined ? { structured: result.structuredOutput } : {}),
113
- agent: result.agent,
114
- stepIndex,
115
- };
116
- }
@@ -1,147 +0,0 @@
1
- import type { Message } from "@duckmind/dm-ai";
2
- import { isMutatingBashCommand } from "./long-running-guard.ts";
3
-
4
- const REVIEW_ONLY_PATTERNS = [
5
- /\breview only\b/i,
6
- /\bsuggest fixes only\b/i,
7
- /\bonly return findings\b/i,
8
- /\breturn findings only\b/i,
9
- ];
10
-
11
- const REVIEWER_REQUIRED_EDIT_PATTERNS = [
12
- /\bmust\s+(?:edit|modify|change|fix|patch|apply)\b/i,
13
- /\brequired\s+to\s+(?:edit|modify|change|fix|patch|apply)\b/i,
14
- /\bregardless\s+of\s+findings\b/i,
15
- /\balways\s+(?:edit|modify|change|fix|patch|apply)\b/i,
16
- /\bapply\s+(?:the\s+)?fix(?:es)?\s+directly\b/i,
17
- /\bmake\s+(?:the\s+)?code\s+changes\b/i,
18
- ];
19
-
20
- const EXPLICIT_NO_EDIT_PATTERNS = [
21
- /\bdo not edit\b/i,
22
- /\bdon't edit\b/i,
23
- /\bdo not modify\b/i,
24
- /\bdo not change files\b/i,
25
- ];
26
-
27
- const SCOPED_NO_EDIT_CONSTRAINT_PATTERNS = [
28
- /\bdo not edit files?\s+outside\b/i,
29
- /\bdo not edit\s+outside\b/i,
30
- /\bdo not edit\s+unrelated files?\b/i,
31
- /\bdo not change\s+unrelated files?\b/i,
32
- /\bdo not modify\s+unrelated files?\b/i,
33
- ];
34
-
35
- const RESEARCH_AGENT_PATTERNS = [
36
- /\binvestigate\b/i,
37
- /\bscout\b/i,
38
- /\bresearch(?:er)?\b/i,
39
- ];
40
-
41
- const WORKER_IMPLEMENTATION_PATTERNS = [
42
- /\b(?:implement|fix|edit|modify|patch|refactor|delete)\b/i,
43
- /\b(?:update|add|remove|replace|create)\b(?!\s+(?:(?:a|an|the)\s+)?(?:report|summary|findings?)(?:\b|$))/i,
44
- /\bapply\s+(?:the\s+)?(?:changes?|fix(?:es)?|patch)\b/i,
45
- /\bmake\s+(?:the\s+)?changes\b/i,
46
- /\bdo those fixes\b/i,
47
- ];
48
-
49
- const GENERAL_IMPLEMENTATION_PATTERNS = [
50
- /\b(?:implement|fix|edit|modify|patch|refactor)\b/i,
51
- /\bapply\s+(?:the\s+)?(?:changes?|fix(?:es)?|patch)\b/i,
52
- /\bmake\s+(?:the\s+)?changes\b/i,
53
- /\bdo those fixes\b/i,
54
- /\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,
55
- ];
56
-
57
- const READ_ONLY_BUILTIN_TOOLS = new Set([
58
- "read",
59
- "grep",
60
- "find",
61
- "ls",
62
- "web_search",
63
- "fetch_content",
64
- "get_search_content",
65
- "intercom",
66
- "contact_supervisor",
67
- ]);
68
-
69
- interface CompletionMutationGuardInput {
70
- agent: string;
71
- task: string;
72
- messages: Message[];
73
- tools?: string[];
74
- mcpDirectTools?: string[];
75
- }
76
-
77
- interface CompletionMutationGuardResult {
78
- expectedMutation: boolean;
79
- attemptedMutation: boolean;
80
- triggered: boolean;
81
- }
82
-
83
- function stripFrameworkInstructions(task: string): string {
84
- return task
85
- .split("\n")
86
- .filter((line) => !/^\s*\[(?:Write to|Read from):/i.test(line))
87
- .filter((line) => !/^\s*(?:Create and maintain progress at:|Update progress at:|\*\*Output:\*\*|Write your findings to(?: exactly this path)?:|This path is authoritative for this run\.|Ignore any other output filename or output path mentioned elsewhere)/i.test(line))
88
- .join("\n");
89
- }
90
-
91
- function stripScopedNoEditConstraints(task: string): string {
92
- let stripped = task;
93
- for (const pattern of SCOPED_NO_EDIT_CONSTRAINT_PATTERNS) {
94
- stripped = stripped.replace(pattern, " ");
95
- }
96
- return stripped;
97
- }
98
-
99
- function declaresOnlyReadOnlyTools(tools: string[] | undefined, mcpDirectTools: string[] | undefined): boolean {
100
- return tools !== undefined
101
- && tools.length > 0
102
- && (mcpDirectTools?.length ?? 0) === 0
103
- && tools.every((tool) => READ_ONLY_BUILTIN_TOOLS.has(tool));
104
- }
105
-
106
- export function expectsImplementationMutation(agent: string, task: string): boolean {
107
- const taskText = stripFrameworkInstructions(task);
108
- const taskTextWithoutScopedConstraints = stripScopedNoEditConstraints(taskText);
109
- if (REVIEW_ONLY_PATTERNS.some((pattern) => pattern.test(taskTextWithoutScopedConstraints))) return false;
110
- if (EXPLICIT_NO_EDIT_PATTERNS.some((pattern) => pattern.test(taskTextWithoutScopedConstraints))) return false;
111
-
112
- if (RESEARCH_AGENT_PATTERNS.some((pattern) => pattern.test(agent))) return false;
113
- if (/\breviewer\b/i.test(agent)) return REVIEWER_REQUIRED_EDIT_PATTERNS.some((pattern) => pattern.test(taskText));
114
-
115
- const workerIntent = agent === "worker" && WORKER_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));
116
- if (workerIntent) return true;
117
-
118
- return GENERAL_IMPLEMENTATION_PATTERNS.some((pattern) => pattern.test(taskText));
119
- }
120
-
121
- export function hasMutationToolCall(messages: Message[]): boolean {
122
- for (const message of messages) {
123
- if (message.role !== "assistant") continue;
124
- for (const part of message.content) {
125
- if (part.type !== "toolCall") continue;
126
- if (part.name === "edit" || part.name === "write") return true;
127
- if (part.name !== "bash") continue;
128
- const args = typeof part.arguments === "object" && part.arguments !== null && !Array.isArray(part.arguments)
129
- ? part.arguments as Record<string, unknown>
130
- : {};
131
- if (typeof args.command === "string" && isMutatingBashCommand(args.command)) return true;
132
- }
133
- }
134
- return false;
135
- }
136
-
137
- export function evaluateCompletionMutationGuard(input: CompletionMutationGuardInput): CompletionMutationGuardResult {
138
- const expectedMutation = declaresOnlyReadOnlyTools(input.tools, input.mcpDirectTools)
139
- ? false
140
- : expectsImplementationMutation(input.agent, input.task);
141
- const attemptedMutation = hasMutationToolCall(input.messages);
142
- return {
143
- expectedMutation,
144
- attemptedMutation,
145
- triggered: expectedMutation && !attemptedMutation,
146
- };
147
- }
@@ -1,271 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { encodeNestedPathEnv, parseNestedPathEnv, type NestedPathEntry } from "./nested-path.ts";
6
- import { resolveMcpDirectToolNames } from "./mcp-direct-tool-allowlist.ts";
7
- import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV } from "./structured-output.ts";
8
- import { TEMP_ROOT_DIR, type JsonSchemaObject, type ResolvedToolBudget } from "../../shared/types.ts";
9
- import { TOOL_BUDGET_ENV, encodeToolBudgetEnv } from "./tool-budget.ts";
10
-
11
- const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
12
- const TASK_ARG_LIMIT = 8000;
13
- const PROMPT_RUNTIME_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "subagent-prompt-runtime.ts");
14
- const FANOUT_CHILD_EXTENSION_PATH = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "extension", "fanout-child.ts");
15
- export const SUBAGENT_CHILD_ENV = "DM_SUBAGENT_CHILD";
16
- export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = "DM_SUBAGENT_ORCHESTRATOR_TARGET";
17
- export const SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV = "DM_SUBAGENT_ORCHESTRATOR_SESSION_ID";
18
- export const SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV = "DM_SUBAGENT_SUPERVISOR_CHANNEL_DIR";
19
- export const SUBAGENT_RUN_ID_ENV = "DM_SUBAGENT_RUN_ID";
20
- export const SUBAGENT_CHILD_AGENT_ENV = "DM_SUBAGENT_CHILD_AGENT";
21
- export const SUBAGENT_CHILD_INDEX_ENV = "DM_SUBAGENT_CHILD_INDEX";
22
- export const SUBAGENT_FANOUT_CHILD_ENV = "DM_SUBAGENT_FANOUT_CHILD";
23
- export const SUBAGENT_PARENT_EVENT_SINK_ENV = "DM_SUBAGENT_PARENT_EVENT_SINK";
24
- export const SUBAGENT_PARENT_CONTROL_INBOX_ENV = "DM_SUBAGENT_PARENT_CONTROL_INBOX";
25
- export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = "DM_SUBAGENT_PARENT_ROOT_RUN_ID";
26
- export const SUBAGENT_PARENT_RUN_ID_ENV = "DM_SUBAGENT_PARENT_RUN_ID";
27
- export const SUBAGENT_PARENT_CHILD_INDEX_ENV = "DM_SUBAGENT_PARENT_CHILD_INDEX";
28
- export const SUBAGENT_PARENT_DEPTH_ENV = "DM_SUBAGENT_PARENT_DEPTH";
29
- export const SUBAGENT_PARENT_PATH_ENV = "DM_SUBAGENT_PARENT_PATH";
30
- export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = "DM_SUBAGENT_PARENT_CAPABILITY_TOKEN";
31
- export const SUBAGENT_PARENT_SESSION_ENV = "DM_SUBAGENT_PARENT_SESSION";
32
- export const SUBAGENT_STEER_INBOX_ENV = "DM_SUBAGENT_STEER_INBOX";
33
-
34
- interface BuildPiArgsInput {
35
- parentSessionId?: string;
36
- baseArgs: string[];
37
- task: string;
38
- sessionEnabled: boolean;
39
- sessionDir?: string;
40
- sessionFile?: string;
41
- model?: string;
42
- thinking?: string;
43
- systemPromptMode?: "append" | "replace";
44
- inheritProjectContext: boolean;
45
- inheritSkills: boolean;
46
- requireReadTool?: boolean;
47
- tools?: string[];
48
- extensions?: string[];
49
- subagentOnlyExtensions?: string[];
50
- systemPrompt?: string | null;
51
- mcpDirectTools?: string[];
52
- cwd?: string;
53
- promptFileStem?: string;
54
- intercomSessionName?: string;
55
- orchestratorIntercomTarget?: string;
56
- runId?: string;
57
- childAgentName?: string;
58
- childIndex?: number;
59
- parentEventSink?: string;
60
- parentControlInbox?: string;
61
- parentRootRunId?: string;
62
- parentRunId?: string;
63
- parentChildIndex?: number;
64
- parentDepth?: number;
65
- parentPath?: NestedPathEntry[];
66
- parentCapabilityToken?: string;
67
- steerInboxDir?: string;
68
- structuredOutput?: {
69
- schema: JsonSchemaObject;
70
- schemaPath: string;
71
- outputPath: string;
72
- };
73
- toolBudget?: ResolvedToolBudget;
74
- }
75
-
76
- interface BuildPiArgsResult {
77
- args: string[];
78
- env: Record<string, string | undefined>;
79
- tempDir?: string;
80
- }
81
-
82
- function sanitizeSupervisorChannelSegment(value: string): string {
83
- return value.trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
84
- }
85
-
86
- function supervisorChannelDir(runId: string, agent: string, childIndex: number): string {
87
- return path.join(TEMP_ROOT_DIR, "supervisor-channels", `${sanitizeSupervisorChannelSegment(runId)}-${sanitizeSupervisorChannelSegment(agent)}-${childIndex}`);
88
- }
89
-
90
- export function applyThinkingSuffix(model: string | undefined, thinking: string | undefined, replaceExisting = false): string | undefined {
91
- if (!model || !thinking) return model;
92
- const colonIdx = model.lastIndexOf(":");
93
- if (colonIdx !== -1 && THINKING_LEVELS.includes(model.substring(colonIdx + 1))) {
94
- return replaceExisting ? `${model.slice(0, colonIdx)}:${thinking}` : model;
95
- }
96
- return `${model}:${thinking}`;
97
- }
98
-
99
- export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
100
- const args = [...input.baseArgs];
101
-
102
- if (input.sessionFile) {
103
- fs.mkdirSync(path.dirname(input.sessionFile), { recursive: true });
104
- args.push("--session", input.sessionFile);
105
- } else {
106
- if (!input.sessionEnabled) {
107
- args.push("--no-session");
108
- }
109
- if (input.sessionDir) {
110
- fs.mkdirSync(input.sessionDir, { recursive: true });
111
- args.push("--session-dir", input.sessionDir);
112
- }
113
- }
114
-
115
- const modelArg = applyThinkingSuffix(input.model, input.thinking);
116
- if (modelArg) {
117
- args.push("--model", modelArg);
118
- }
119
-
120
- const declaredBuiltinToolsBase = input.tools?.filter((tool) => !(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) ?? [];
121
- const declaredBuiltinTools = input.requireReadTool && input.tools?.length && !declaredBuiltinToolsBase.includes("read")
122
- ? ["read", ...declaredBuiltinToolsBase]
123
- : declaredBuiltinToolsBase;
124
- const fanoutAuthorized = declaredBuiltinTools.includes("subagent");
125
- const toolExtensionPaths: string[] = [];
126
- if (input.tools?.length) {
127
- const builtinTools = [...declaredBuiltinTools];
128
- for (const tool of input.tools) {
129
- if (!declaredBuiltinTools.includes(tool) && (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) {
130
- toolExtensionPaths.push(tool);
131
- }
132
- }
133
- if (builtinTools.length > 0) {
134
- if (input.mcpDirectTools?.length) {
135
- builtinTools.push(...resolveMcpDirectToolNames(input.mcpDirectTools, input.cwd));
136
- }
137
- args.push("--tools", builtinTools.join(","));
138
- }
139
- }
140
-
141
- const runtimeExtensions = fanoutAuthorized
142
- ? [PROMPT_RUNTIME_EXTENSION_PATH, FANOUT_CHILD_EXTENSION_PATH]
143
- : [PROMPT_RUNTIME_EXTENSION_PATH];
144
- if (input.extensions !== undefined) {
145
- args.push("--no-extensions");
146
- for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...input.extensions, ...(input.subagentOnlyExtensions ?? [])])]) {
147
- args.push("--extension", extPath);
148
- }
149
- } else {
150
- for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...(input.subagentOnlyExtensions ?? [])])]) {
151
- args.push("--extension", extPath);
152
- }
153
- }
154
-
155
- if (!input.inheritSkills) {
156
- args.push("--no-skills");
157
- }
158
-
159
- let tempDir: string | undefined;
160
- if (input.systemPrompt !== undefined && input.systemPrompt !== null) {
161
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "dm-subagent-"));
162
- const stem = (input.promptFileStem ?? "prompt").replace(/[^\w.-]/g, "_");
163
- const promptPath = path.join(tempDir, `${stem}.md`);
164
- fs.writeFileSync(promptPath, input.systemPrompt, { mode: 0o600 });
165
- args.push(input.systemPromptMode === "replace" ? "--system-prompt" : "--append-system-prompt", promptPath);
166
- }
167
-
168
- if (input.task.length > TASK_ARG_LIMIT) {
169
- if (!tempDir) {
170
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "dm-subagent-"));
171
- }
172
- const taskFilePath = path.join(tempDir, "task.md");
173
- fs.writeFileSync(taskFilePath, `Task: ${input.task}`, { mode: 0o600 });
174
- args.push(`@${taskFilePath}`);
175
- } else {
176
- args.push(`Task: ${input.task}`);
177
- }
178
-
179
- const env: Record<string, string | undefined> = {};
180
- env[SUBAGENT_CHILD_ENV] = "1";
181
- env[SUBAGENT_FANOUT_CHILD_ENV] = fanoutAuthorized ? "1" : "0";
182
- const inheritedNestedRoute = Boolean(process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] && process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] && process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV]);
183
- const parentRunId = input.parentRunId ?? input.runId ?? (inheritedNestedRoute ? process.env[SUBAGENT_RUN_ID_ENV] : undefined) ?? process.env[SUBAGENT_PARENT_RUN_ID_ENV] ?? "";
184
- const parentChildIndex = input.parentChildIndex !== undefined
185
- ? String(input.parentChildIndex)
186
- : input.childIndex !== undefined
187
- ? String(input.childIndex)
188
- : process.env[SUBAGENT_PARENT_CHILD_INDEX_ENV] ?? "";
189
- const inheritedDepth = Number(process.env[SUBAGENT_PARENT_DEPTH_ENV]);
190
- const parentDepth = input.parentDepth ?? (inheritedNestedRoute && Number.isFinite(inheritedDepth) ? inheritedDepth + 1 : 1);
191
- const parentPath = input.parentPath ?? [
192
- ...parseNestedPathEnv(process.env[SUBAGENT_PARENT_PATH_ENV]),
193
- ...(parentRunId ? [{
194
- runId: parentRunId,
195
- ...(parentChildIndex && /^\d+$/.test(parentChildIndex) ? { stepIndex: Number(parentChildIndex) } : {}),
196
- ...(input.childAgentName ? { agent: input.childAgentName } : {}),
197
- }] : []),
198
- ];
199
- env[SUBAGENT_PARENT_EVENT_SINK_ENV] = fanoutAuthorized
200
- ? input.parentEventSink ?? process.env[SUBAGENT_PARENT_EVENT_SINK_ENV] ?? ""
201
- : "";
202
- env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = fanoutAuthorized
203
- ? input.parentControlInbox ?? process.env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] ?? ""
204
- : "";
205
- env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = fanoutAuthorized
206
- ? input.parentRootRunId ?? process.env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] ?? input.runId ?? ""
207
- : "";
208
- env[SUBAGENT_PARENT_RUN_ID_ENV] = fanoutAuthorized ? parentRunId : "";
209
- env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = fanoutAuthorized ? parentChildIndex : "";
210
- env[SUBAGENT_PARENT_DEPTH_ENV] = fanoutAuthorized ? String(parentDepth) : "";
211
- env[SUBAGENT_PARENT_PATH_ENV] = fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
212
- env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
213
- ? input.parentCapabilityToken ?? process.env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] ?? ""
214
- : "";
215
- env.DM_SUBAGENT_INHERIT_PROJECT_CONTEXT = input.inheritProjectContext ? "1" : "0";
216
- env.DM_SUBAGENT_INHERIT_SKILLS = input.inheritSkills ? "1" : "0";
217
- if (input.intercomSessionName) {
218
- env.DM_SUBAGENT_INTERCOM_SESSION_NAME = input.intercomSessionName;
219
- }
220
- if (input.orchestratorIntercomTarget) {
221
- env[SUBAGENT_ORCHESTRATOR_TARGET_ENV] = input.orchestratorIntercomTarget;
222
- }
223
- if (input.parentSessionId) {
224
- env[SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV] = input.parentSessionId;
225
- }
226
- if (input.orchestratorIntercomTarget && input.parentSessionId && input.runId && input.childAgentName) {
227
- const childIndex = input.childIndex ?? 0;
228
- const channelDir = supervisorChannelDir(input.runId, input.childAgentName, childIndex);
229
- fs.mkdirSync(path.join(channelDir, "requests"), { recursive: true });
230
- fs.mkdirSync(path.join(channelDir, "replies"), { recursive: true });
231
- env[SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV] = channelDir;
232
- }
233
- if (input.runId) {
234
- env[SUBAGENT_RUN_ID_ENV] = input.runId;
235
- }
236
- if (input.childAgentName) {
237
- env[SUBAGENT_CHILD_AGENT_ENV] = input.childAgentName;
238
- }
239
- if (input.childIndex !== undefined) {
240
- env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
241
- }
242
- if (input.mcpDirectTools?.length) {
243
- env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
244
- } else {
245
- env.MCP_DIRECT_TOOLS = "__none__";
246
- }
247
- if (input.structuredOutput) {
248
- env[STRUCTURED_OUTPUT_CAPTURE_ENV] = input.structuredOutput.outputPath;
249
- env[STRUCTURED_OUTPUT_SCHEMA_ENV] = input.structuredOutput.schemaPath;
250
- }
251
- if (input.steerInboxDir) {
252
- env[SUBAGENT_STEER_INBOX_ENV] = input.steerInboxDir;
253
- }
254
- const encodedToolBudget = encodeToolBudgetEnv(input.toolBudget);
255
- if (encodedToolBudget) env[TOOL_BUDGET_ENV] = encodedToolBudget;
256
-
257
- env[SUBAGENT_PARENT_SESSION_ENV] = input.parentSessionId ?? process.env[SUBAGENT_PARENT_SESSION_ENV] ?? "";
258
-
259
- return { args, env, tempDir };
260
- }
261
-
262
- export const parseParentPathEnv = parseNestedPathEnv;
263
-
264
- export function cleanupTempDir(tempDir: string | null | undefined): void {
265
- if (!tempDir) return;
266
- try {
267
- fs.rmSync(tempDir, { recursive: true, force: true });
268
- } catch {
269
- // Temp cleanup is best effort.
270
- }
271
- }
@@ -1,147 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
-
5
- export const PI_CODING_AGENT_PACKAGE = "@duckmind/dm-coding-agent";
6
- export const DM_SUBAGENT_PI_BINARY_ENV = "DM_SUBAGENT_PI_BINARY";
7
-
8
- export function findPiPackageRootFromEntry(
9
- entryPoint: string,
10
- ): string | undefined {
11
- let dir = path.dirname(entryPoint);
12
- while (dir !== path.dirname(dir)) {
13
- const packageJsonPath = path.join(dir, "package.json");
14
- if (fs.existsSync(packageJsonPath)) {
15
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
16
- name?: unknown;
17
- };
18
- if (pkg.name === PI_CODING_AGENT_PACKAGE) return dir;
19
- }
20
- dir = path.dirname(dir);
21
- }
22
- return undefined;
23
- }
24
-
25
- export function resolveInstalledPiPackageRoot(): string | undefined {
26
- return findPiPackageRootFromEntry(
27
- fileURLToPath(import.meta.resolve(PI_CODING_AGENT_PACKAGE)),
28
- );
29
- }
30
-
31
- export function resolvePiPackageRoot(): string | undefined {
32
- try {
33
- const entry = process.argv[1];
34
- return entry
35
- ? findPiPackageRootFromEntry(fs.realpathSync(entry))
36
- : undefined;
37
- } catch {
38
- // process.argv[1] probing is best-effort; callers can fall back to PATH/package resolution.
39
- return undefined;
40
- }
41
- }
42
-
43
- export interface PiSpawnDeps {
44
- platform?: NodeJS.Platform;
45
- execPath?: string;
46
- argv1?: string;
47
- existsSync?: (filePath: string) => boolean;
48
- readFileSync?: (filePath: string, encoding: "utf-8") => string;
49
- resolvePackageJson?: () => string;
50
- resolvePackageEntry?: () => string;
51
- piPackageRoot?: string;
52
- env?: NodeJS.ProcessEnv;
53
- }
54
-
55
- interface PiSpawnCommand {
56
- command: string;
57
- args: string[];
58
- }
59
-
60
- function isRunnableNodeScript(
61
- filePath: string,
62
- existsSync: (filePath: string) => boolean,
63
- ): boolean {
64
- if (!existsSync(filePath)) return false;
65
- return /\.(?:mjs|cjs|js)$/i.test(filePath);
66
- }
67
-
68
- function normalizePath(filePath: string): string {
69
- return path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
70
- }
71
-
72
- export function resolveWindowsPiCliScript(
73
- deps: PiSpawnDeps = {},
74
- ): string | undefined {
75
- const existsSync = deps.existsSync ?? fs.existsSync;
76
- const readFileSync =
77
- deps.readFileSync ??
78
- ((filePath, encoding) => fs.readFileSync(filePath, encoding));
79
- const argv1 = deps.argv1 ?? process.argv[1];
80
-
81
- if (argv1) {
82
- const argvPath = normalizePath(argv1);
83
- if (isRunnableNodeScript(argvPath, existsSync)) {
84
- return argvPath;
85
- }
86
- }
87
-
88
- try {
89
- const resolvePackageJson =
90
- deps.resolvePackageJson ??
91
- (() => {
92
- const root = deps.piPackageRoot ?? resolvePiPackageRoot();
93
- if (root) return path.join(root, "package.json");
94
- const packageRoot = deps.resolvePackageEntry
95
- ? findPiPackageRootFromEntry(deps.resolvePackageEntry())
96
- : resolveInstalledPiPackageRoot();
97
- if (!packageRoot)
98
- throw new Error(
99
- `Could not resolve ${PI_CODING_AGENT_PACKAGE} package root`,
100
- );
101
- return path.join(packageRoot, "package.json");
102
- });
103
- const packageJsonPath = resolvePackageJson();
104
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
105
- bin?: string | Record<string, string>;
106
- };
107
- const binField = packageJson.bin;
108
- const binPath =
109
- typeof binField === "string"
110
- ? binField
111
- : (binField?.pi ?? Object.values(binField ?? {})[0]);
112
- if (!binPath) return undefined;
113
- const candidate = path.resolve(path.dirname(packageJsonPath), binPath);
114
- if (isRunnableNodeScript(candidate, existsSync)) {
115
- return candidate;
116
- }
117
- } catch {
118
- // Windows CLI resolution is optional; falling back to `dm` lets PATH handle execution.
119
- return undefined;
120
- }
121
-
122
- return undefined;
123
- }
124
-
125
- export function getPiSpawnCommand(
126
- args: string[],
127
- deps: PiSpawnDeps = {},
128
- ): PiSpawnCommand {
129
- const env = deps.env ?? process.env;
130
- const piBinary = env[DM_SUBAGENT_PI_BINARY_ENV]?.trim();
131
- if (piBinary) {
132
- return { command: piBinary, args };
133
- }
134
-
135
- const platform = deps.platform ?? process.platform;
136
- if (platform === "win32") {
137
- const piCliPath = resolveWindowsPiCliScript(deps);
138
- if (piCliPath) {
139
- return {
140
- command: deps.execPath ?? process.execPath,
141
- args: [piCliPath, ...args],
142
- };
143
- }
144
- }
145
-
146
- return { command: "dm", args };
147
- }