@duckmind/dm-darwin-x64 0.43.2 → 0.43.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +242 -49
  3. package/extensions/dm-9router-ext/package.json +2 -19
  4. package/extensions/dm-9router-ext/src/index.js +5 -0
  5. package/extensions/dm-ask-user/index.js +10 -0
  6. package/extensions/dm-ask-user/package.json +1 -21
  7. package/extensions/dm-cli-anything/package.json +0 -6
  8. package/extensions/dm-context/package.json +2 -12
  9. package/extensions/dm-context/src/context.js +1 -0
  10. package/extensions/dm-context/src/index.js +7 -0
  11. package/extensions/dm-context/src/utils.js +1 -0
  12. package/extensions/dm-cua/package.json +0 -7
  13. package/extensions/dm-fff/package.json +1 -28
  14. package/extensions/dm-fff/src/index.js +15 -0
  15. package/extensions/dm-fff/src/query.js +1 -0
  16. package/extensions/dm-goal/package.json +2 -31
  17. package/extensions/dm-goal/src/goal.js +43 -0
  18. package/extensions/dm-grill-me/index.js +174 -0
  19. package/extensions/dm-grill-me/package.json +1 -26
  20. package/extensions/dm-image2/package.json +0 -7
  21. package/extensions/dm-subagents/package.json +1 -32
  22. package/extensions/dm-subagents/src/agents/agent-management.js +37 -0
  23. package/extensions/dm-subagents/src/agents/agent-memory.js +6 -0
  24. package/extensions/dm-subagents/src/agents/agent-scope.js +1 -0
  25. package/extensions/dm-subagents/src/agents/agent-selection.js +1 -0
  26. package/extensions/dm-subagents/src/agents/agent-serializer.js +7 -0
  27. package/extensions/dm-subagents/src/agents/agents.js +11 -0
  28. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -0
  29. package/extensions/dm-subagents/src/agents/frontmatter.js +6 -0
  30. package/extensions/dm-subagents/src/agents/identity.js +1 -0
  31. package/extensions/dm-subagents/src/agents/proactive-skills.js +1 -0
  32. package/extensions/dm-subagents/src/agents/skills.js +6 -0
  33. package/extensions/dm-subagents/src/extension/config.js +2 -0
  34. package/extensions/dm-subagents/src/extension/control-notices.js +4 -0
  35. package/extensions/dm-subagents/src/extension/doctor.js +16 -0
  36. package/extensions/dm-subagents/src/extension/fanout-child.js +231 -0
  37. package/extensions/dm-subagents/src/extension/index.js +367 -0
  38. package/extensions/dm-subagents/src/extension/rpc.js +8 -0
  39. package/extensions/dm-subagents/src/extension/schemas.js +1 -0
  40. package/extensions/dm-subagents/src/extension/{tool-description.ts → tool-description.js} +6 -126
  41. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +13 -0
  42. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -0
  43. package/extensions/dm-subagents/src/intercom/result-intercom.js +3 -0
  44. package/extensions/dm-subagents/src/profiles/profiles.js +3 -0
  45. package/extensions/dm-subagents/src/runs/background/async-execution.js +46 -0
  46. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +14 -0
  47. package/extensions/dm-subagents/src/runs/background/async-resume.js +8 -0
  48. package/extensions/dm-subagents/src/runs/background/async-status.js +12 -0
  49. package/extensions/dm-subagents/src/runs/background/chain-append.js +2 -0
  50. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +1 -0
  51. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +1 -0
  52. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +1 -0
  53. package/extensions/dm-subagents/src/runs/background/control-channel.js +1 -0
  54. package/extensions/dm-subagents/src/runs/background/fleet-view.js +17 -0
  55. package/extensions/dm-subagents/src/runs/background/notify.js +3 -0
  56. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +1 -0
  57. package/extensions/dm-subagents/src/runs/background/result-watcher.js +8 -0
  58. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +4 -0
  59. package/extensions/dm-subagents/src/runs/background/run-status.js +23 -0
  60. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +4 -0
  61. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +11 -0
  62. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +78 -0
  63. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -0
  64. package/extensions/dm-subagents/src/runs/background/wait.js +11 -0
  65. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +12 -0
  66. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +102 -0
  67. package/extensions/dm-subagents/src/runs/foreground/execution.js +51 -0
  68. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +228 -0
  69. package/extensions/dm-subagents/src/runs/shared/acceptance.js +3 -0
  70. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +1 -0
  71. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +3 -0
  72. package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -0
  73. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +1 -0
  74. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +1 -0
  75. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +1 -0
  76. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +1 -0
  77. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +1 -0
  78. package/extensions/dm-subagents/src/runs/shared/model-scope.js +1 -0
  79. package/extensions/dm-subagents/src/runs/shared/nested-events.js +8 -0
  80. package/extensions/dm-subagents/src/runs/shared/nested-path.js +1 -0
  81. package/extensions/dm-subagents/src/runs/shared/nested-render.js +1 -0
  82. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +5 -0
  83. package/extensions/dm-subagents/src/runs/shared/run-history.js +5 -0
  84. package/extensions/dm-subagents/src/runs/shared/single-output.js +14 -0
  85. package/extensions/dm-subagents/src/runs/shared/structured-output.js +1 -0
  86. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +5 -0
  87. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +22 -0
  88. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +1 -0
  89. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +7 -0
  90. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +1 -0
  91. package/extensions/dm-subagents/src/runs/shared/worktree.js +3 -0
  92. package/extensions/dm-subagents/src/shared/artifacts.js +2 -0
  93. package/extensions/dm-subagents/src/shared/atomic-json.js +1 -0
  94. package/extensions/dm-subagents/src/shared/child-transcript.js +5 -0
  95. package/extensions/dm-subagents/src/shared/file-coalescer.js +1 -0
  96. package/extensions/dm-subagents/src/shared/fork-context.js +6 -0
  97. package/extensions/dm-subagents/src/shared/formatters.js +9 -0
  98. package/extensions/dm-subagents/src/shared/jsonl-writer.js +2 -0
  99. package/extensions/dm-subagents/src/shared/model-info.js +1 -0
  100. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +1 -0
  101. package/extensions/dm-subagents/src/shared/session-identity.js +1 -0
  102. package/extensions/dm-subagents/src/shared/session-tokens.js +2 -0
  103. package/extensions/dm-subagents/src/shared/settings.js +23 -0
  104. package/extensions/dm-subagents/src/shared/status-format.js +1 -0
  105. package/extensions/dm-subagents/src/shared/types.js +8 -0
  106. package/extensions/dm-subagents/src/shared/utils.js +2 -0
  107. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +1 -0
  108. package/extensions/dm-subagents/src/slash/prompt-workflows.js +7 -0
  109. package/extensions/dm-subagents/src/slash/slash-bridge.js +1 -0
  110. package/extensions/dm-subagents/src/slash/slash-commands.js +38 -0
  111. package/extensions/dm-subagents/src/slash/slash-live-state.js +6 -0
  112. package/extensions/dm-subagents/src/tui/render-helpers.js +1 -0
  113. package/extensions/dm-subagents/src/tui/render.js +4 -0
  114. package/extensions/dm-tasks/package.json +1 -30
  115. package/extensions/dm-tasks/src/auto-clear.js +1 -0
  116. package/extensions/dm-tasks/src/index.js +212 -0
  117. package/extensions/dm-tasks/src/process-tracker.js +1 -0
  118. package/extensions/dm-tasks/src/task-store.js +1 -0
  119. package/extensions/dm-tasks/src/tasks-config.js +1 -0
  120. package/extensions/dm-tasks/src/types.js +0 -0
  121. package/extensions/dm-tasks/src/ui/settings-menu.js +1 -0
  122. package/extensions/dm-tasks/src/ui/task-widget.js +1 -0
  123. package/extensions/dm-usage/index.js +9 -0
  124. package/extensions/dm-usage/package.json +1 -18
  125. package/extensions/greedysearch-dm/bin/search.mjs +135 -135
  126. package/extensions/greedysearch-dm/index.js +20 -0
  127. package/extensions/greedysearch-dm/package.json +1 -22
  128. package/extensions/greedysearch-dm/src/formatters/results.js +8 -0
  129. package/extensions/greedysearch-dm/src/formatters/sources.js +1 -0
  130. package/extensions/greedysearch-dm/src/formatters/synthesis.js +1 -0
  131. package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
  132. package/extensions/greedysearch-dm/src/search/paths.mjs +1 -0
  133. package/extensions/greedysearch-dm/src/search/research.mjs +100 -100
  134. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +10 -10
  135. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +20 -0
  136. package/extensions/greedysearch-dm/src/tools/shared.js +9 -0
  137. package/extensions/greedysearch-dm/src/types.js +0 -0
  138. package/extensions/greedysearch-dm/src/utils/helpers.js +1 -0
  139. package/package.json +1 -1
  140. package/extensions/dm-9router-ext/src/index.ts +0 -541
  141. package/extensions/dm-ask-user/index.ts +0 -857
  142. package/extensions/dm-context/src/context.ts +0 -158
  143. package/extensions/dm-context/src/index.ts +0 -439
  144. package/extensions/dm-context/src/utils.ts +0 -6
  145. package/extensions/dm-fff/src/index.ts +0 -1023
  146. package/extensions/dm-fff/src/query.ts +0 -87
  147. package/extensions/dm-goal/src/goal.ts +0 -1073
  148. package/extensions/dm-grill-me/index.ts +0 -1085
  149. package/extensions/dm-subagents/src/agents/agent-management.ts +0 -1052
  150. package/extensions/dm-subagents/src/agents/agent-memory.ts +0 -254
  151. package/extensions/dm-subagents/src/agents/agent-scope.ts +0 -6
  152. package/extensions/dm-subagents/src/agents/agent-selection.ts +0 -25
  153. package/extensions/dm-subagents/src/agents/agent-serializer.ts +0 -121
  154. package/extensions/dm-subagents/src/agents/agents.ts +0 -1553
  155. package/extensions/dm-subagents/src/agents/chain-serializer.ts +0 -277
  156. package/extensions/dm-subagents/src/agents/frontmatter.ts +0 -93
  157. package/extensions/dm-subagents/src/agents/identity.ts +0 -30
  158. package/extensions/dm-subagents/src/agents/proactive-skills.ts +0 -191
  159. package/extensions/dm-subagents/src/agents/skills.ts +0 -729
  160. package/extensions/dm-subagents/src/extension/config.ts +0 -39
  161. package/extensions/dm-subagents/src/extension/control-notices.ts +0 -92
  162. package/extensions/dm-subagents/src/extension/doctor.ts +0 -214
  163. package/extensions/dm-subagents/src/extension/fanout-child.ts +0 -172
  164. package/extensions/dm-subagents/src/extension/index.ts +0 -656
  165. package/extensions/dm-subagents/src/extension/rpc.ts +0 -369
  166. package/extensions/dm-subagents/src/extension/schemas.ts +0 -309
  167. package/extensions/dm-subagents/src/intercom/intercom-bridge.ts +0 -180
  168. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.ts +0 -519
  169. package/extensions/dm-subagents/src/intercom/result-intercom.ts +0 -377
  170. package/extensions/dm-subagents/src/profiles/profiles.ts +0 -637
  171. package/extensions/dm-subagents/src/runs/background/async-execution.ts +0 -1065
  172. package/extensions/dm-subagents/src/runs/background/async-job-tracker.ts +0 -441
  173. package/extensions/dm-subagents/src/runs/background/async-resume.ts +0 -391
  174. package/extensions/dm-subagents/src/runs/background/async-status.ts +0 -395
  175. package/extensions/dm-subagents/src/runs/background/chain-append.ts +0 -282
  176. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.ts +0 -191
  177. package/extensions/dm-subagents/src/runs/background/completion-batcher.ts +0 -166
  178. package/extensions/dm-subagents/src/runs/background/completion-dedupe.ts +0 -63
  179. package/extensions/dm-subagents/src/runs/background/control-channel.ts +0 -332
  180. package/extensions/dm-subagents/src/runs/background/fleet-view.ts +0 -515
  181. package/extensions/dm-subagents/src/runs/background/notify.ts +0 -225
  182. package/extensions/dm-subagents/src/runs/background/parallel-groups.ts +0 -45
  183. package/extensions/dm-subagents/src/runs/background/result-watcher.ts +0 -315
  184. package/extensions/dm-subagents/src/runs/background/run-id-resolver.ts +0 -84
  185. package/extensions/dm-subagents/src/runs/background/run-status.ts +0 -434
  186. package/extensions/dm-subagents/src/runs/background/scheduled-runs.ts +0 -514
  187. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.ts +0 -368
  188. package/extensions/dm-subagents/src/runs/background/subagent-runner.ts +0 -3171
  189. package/extensions/dm-subagents/src/runs/background/top-level-async.ts +0 -13
  190. package/extensions/dm-subagents/src/runs/background/wait.ts +0 -353
  191. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.ts +0 -1333
  192. package/extensions/dm-subagents/src/runs/foreground/chain-execution.ts +0 -1313
  193. package/extensions/dm-subagents/src/runs/foreground/execution.ts +0 -1239
  194. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.ts +0 -3613
  195. package/extensions/dm-subagents/src/runs/shared/acceptance.ts +0 -879
  196. package/extensions/dm-subagents/src/runs/shared/chain-outputs.ts +0 -116
  197. package/extensions/dm-subagents/src/runs/shared/completion-guard.ts +0 -147
  198. package/extensions/dm-subagents/src/runs/shared/dm-args.ts +0 -271
  199. package/extensions/dm-subagents/src/runs/shared/dm-spawn.ts +0 -147
  200. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.ts +0 -295
  201. package/extensions/dm-subagents/src/runs/shared/long-running-guard.ts +0 -175
  202. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +0 -365
  203. package/extensions/dm-subagents/src/runs/shared/model-fallback.ts +0 -292
  204. package/extensions/dm-subagents/src/runs/shared/model-scope.ts +0 -128
  205. package/extensions/dm-subagents/src/runs/shared/nested-events.ts +0 -908
  206. package/extensions/dm-subagents/src/runs/shared/nested-path.ts +0 -52
  207. package/extensions/dm-subagents/src/runs/shared/nested-render.ts +0 -115
  208. package/extensions/dm-subagents/src/runs/shared/parallel-utils.ts +0 -198
  209. package/extensions/dm-subagents/src/runs/shared/run-history.ts +0 -60
  210. package/extensions/dm-subagents/src/runs/shared/single-output.ts +0 -180
  211. package/extensions/dm-subagents/src/runs/shared/structured-output.ts +0 -77
  212. package/extensions/dm-subagents/src/runs/shared/subagent-control.ts +0 -223
  213. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.ts +0 -342
  214. package/extensions/dm-subagents/src/runs/shared/tool-budget.ts +0 -74
  215. package/extensions/dm-subagents/src/runs/shared/turn-budget.ts +0 -52
  216. package/extensions/dm-subagents/src/runs/shared/workflow-graph.ts +0 -206
  217. package/extensions/dm-subagents/src/runs/shared/worktree.ts +0 -600
  218. package/extensions/dm-subagents/src/shared/artifacts.ts +0 -113
  219. package/extensions/dm-subagents/src/shared/atomic-json.ts +0 -86
  220. package/extensions/dm-subagents/src/shared/child-transcript.ts +0 -212
  221. package/extensions/dm-subagents/src/shared/file-coalescer.ts +0 -40
  222. package/extensions/dm-subagents/src/shared/fork-context.ts +0 -194
  223. package/extensions/dm-subagents/src/shared/formatters.ts +0 -133
  224. package/extensions/dm-subagents/src/shared/jsonl-writer.ts +0 -81
  225. package/extensions/dm-subagents/src/shared/model-info.ts +0 -78
  226. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  227. package/extensions/dm-subagents/src/shared/session-identity.ts +0 -10
  228. package/extensions/dm-subagents/src/shared/session-tokens.ts +0 -44
  229. package/extensions/dm-subagents/src/shared/settings.ts +0 -450
  230. package/extensions/dm-subagents/src/shared/status-format.ts +0 -49
  231. package/extensions/dm-subagents/src/shared/types.ts +0 -1257
  232. package/extensions/dm-subagents/src/shared/utils.ts +0 -554
  233. package/extensions/dm-subagents/src/slash/prompt-template-bridge.ts +0 -420
  234. package/extensions/dm-subagents/src/slash/prompt-workflows.ts +0 -330
  235. package/extensions/dm-subagents/src/slash/slash-bridge.ts +0 -176
  236. package/extensions/dm-subagents/src/slash/slash-commands.ts +0 -1296
  237. package/extensions/dm-subagents/src/slash/slash-live-state.ts +0 -292
  238. package/extensions/dm-subagents/src/tui/render-helpers.ts +0 -80
  239. package/extensions/dm-subagents/src/tui/render.ts +0 -1748
  240. package/extensions/dm-tasks/src/auto-clear.ts +0 -91
  241. package/extensions/dm-tasks/src/index.ts +0 -1145
  242. package/extensions/dm-tasks/src/process-tracker.ts +0 -140
  243. package/extensions/dm-tasks/src/task-store.ts +0 -305
  244. package/extensions/dm-tasks/src/tasks-config.ts +0 -23
  245. package/extensions/dm-tasks/src/types.ts +0 -40
  246. package/extensions/dm-tasks/src/ui/settings-menu.ts +0 -100
  247. package/extensions/dm-tasks/src/ui/task-widget.ts +0 -265
  248. package/extensions/dm-usage/index.ts +0 -1718
  249. package/extensions/greedysearch-dm/index.ts +0 -177
  250. package/extensions/greedysearch-dm/src/formatters/results.ts +0 -163
  251. package/extensions/greedysearch-dm/src/formatters/sources.ts +0 -116
  252. package/extensions/greedysearch-dm/src/formatters/synthesis.ts +0 -87
  253. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.ts +0 -370
  254. package/extensions/greedysearch-dm/src/tools/shared.ts +0 -187
  255. package/extensions/greedysearch-dm/src/types.ts +0 -110
  256. package/extensions/greedysearch-dm/src/utils/helpers.ts +0 -40
@@ -1,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
- }