@duckmind/dm-darwin-x64 0.43.4 → 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 (251) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +241 -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/index.js +20 -0
  126. package/extensions/greedysearch-dm/package.json +1 -22
  127. package/extensions/greedysearch-dm/src/formatters/results.js +8 -0
  128. package/extensions/greedysearch-dm/src/formatters/sources.js +1 -0
  129. package/extensions/greedysearch-dm/src/formatters/synthesis.js +1 -0
  130. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
  131. package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
  132. package/extensions/greedysearch-dm/src/types.js +0 -0
  133. package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
  134. package/package.json +1 -1
  135. package/extensions/dm-9router-ext/src/index.ts +0 -541
  136. package/extensions/dm-ask-user/index.ts +0 -857
  137. package/extensions/dm-context/src/context.ts +0 -158
  138. package/extensions/dm-context/src/index.ts +0 -439
  139. package/extensions/dm-context/src/utils.ts +0 -6
  140. package/extensions/dm-fff/src/index.ts +0 -1023
  141. package/extensions/dm-fff/src/query.ts +0 -87
  142. package/extensions/dm-goal/src/goal.ts +0 -1073
  143. package/extensions/dm-grill-me/index.ts +0 -1085
  144. package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
  145. package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
  146. package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
  147. package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
  148. package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
  149. package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
  150. package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
  151. package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
  152. package/extensions/dm-subagents/src/agents/identity.ts +0 -30
  153. package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
  154. package/extensions/dm-subagents/src/agents/skills.ts +0 -729
  155. package/extensions/dm-subagents/src/extension/config.ts +0 -39
  156. package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
  157. package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
  158. package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
  159. package/extensions/dm-subagents/src/extension/index.ts +0 -656
  160. package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
  161. package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
  162. package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
  163. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
  164. package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
  165. package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
  166. package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
  167. package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
  168. package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
  169. package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
  170. package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
  171. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
  172. package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
  173. package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
  174. package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
  175. package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
  176. package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
  177. package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
  178. package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
  179. package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
  180. package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
  181. package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
  182. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
  183. package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
  184. package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
  185. package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
  186. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
  187. package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
  188. package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
  189. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
  190. package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
  191. package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
  192. package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
  193. package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
  194. package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
  195. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
  196. package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
  197. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
  198. package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
  199. package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
  200. package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
  201. package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
  202. package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
  203. package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
  204. package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
  205. package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
  206. package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
  207. package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
  208. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
  209. package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
  210. package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
  211. package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
  212. package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
  213. package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
  214. package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
  215. package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
  216. package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
  217. package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
  218. package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
  219. package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
  220. package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
  221. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  222. package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
  223. package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
  224. package/extensions/dm-subagents/src/shared/settings.ts +0 -450
  225. package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
  226. package/extensions/dm-subagents/src/shared/types.ts +0 -1257
  227. package/extensions/dm-subagents/src/shared/utils.ts +0 -554
  228. package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
  229. package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
  230. package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
  231. package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
  232. package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
  233. package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
  234. package/extensions/dm-subagents/src/tui/render.ts +0 -1748
  235. package/extensions/dm-tasks/src/auto-clear.ts +0 -91
  236. package/extensions/dm-tasks/src/index.ts +0 -1145
  237. package/extensions/dm-tasks/src/process-tracker.ts +0 -140
  238. package/extensions/dm-tasks/src/task-store.ts +0 -305
  239. package/extensions/dm-tasks/src/tasks-config.ts +0 -23
  240. package/extensions/dm-tasks/src/types.ts +0 -40
  241. package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
  242. package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
  243. package/extensions/dm-usage/index.ts +0 -1718
  244. package/extensions/greedysearch-dm/index.ts +0 -177
  245. package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
  246. package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
  247. package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
  248. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
  249. package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
  250. package/extensions/greedysearch-dm/src/types.ts +0 -110
  251. 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
- }