@duckmind/dm-windows-x64 0.61.4 → 0.61.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +211 -67
  3. package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
  4. package/extensions/dm-subagents/agents/claude-code.md +15 -0
  5. package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
  6. package/extensions/dm-subagents/agents/codex-exec.md +15 -0
  7. package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
  8. package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
  9. package/extensions/dm-subagents/agents/delegate.md +3 -2
  10. package/extensions/dm-subagents/agents/oracle.md +10 -5
  11. package/extensions/dm-subagents/agents/researcher.md +2 -2
  12. package/extensions/dm-subagents/agents/reviewer.md +17 -7
  13. package/extensions/dm-subagents/agents/scout.md +5 -5
  14. package/extensions/dm-subagents/agents/worker.md +6 -2
  15. package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
  16. package/extensions/dm-subagents/index.js +4 -0
  17. package/extensions/dm-subagents/inspector-runner.mjs +10 -0
  18. package/extensions/dm-subagents/install.mjs +3 -2
  19. package/extensions/dm-subagents/package.json +2 -2
  20. package/extensions/dm-subagents/prompts/council.md +60 -0
  21. package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
  22. package/extensions/dm-subagents/prompts/review-loop.md +13 -7
  23. package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
  24. package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
  25. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
  26. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
  27. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
  28. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
  29. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
  30. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
  31. package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
  32. package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
  33. package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
  34. package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
  35. package/extensions/dm-subagents/src/agents/agents.js +1447 -299
  36. package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
  37. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
  38. package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
  39. package/extensions/dm-subagents/src/agents/identity.js +1 -1
  40. package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
  41. package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
  42. package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
  43. package/extensions/dm-subagents/src/agents/skills.js +52 -35
  44. package/extensions/dm-subagents/src/api/agents.js +6 -0
  45. package/extensions/dm-subagents/src/api/background-work.js +151 -0
  46. package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
  47. package/extensions/dm-subagents/src/api/control-channel.js +3 -0
  48. package/extensions/dm-subagents/src/api/delegation.js +5 -0
  49. package/extensions/dm-subagents/src/api/dm-args.js +3 -0
  50. package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
  51. package/extensions/dm-subagents/src/api/external-runs.js +233 -0
  52. package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
  53. package/extensions/dm-subagents/src/api/preflight.js +322 -0
  54. package/extensions/dm-subagents/src/api/project-panes.js +11 -0
  55. package/extensions/dm-subagents/src/api/shared-types.js +4 -0
  56. package/extensions/dm-subagents/src/extension/config.js +175 -0
  57. package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
  58. package/extensions/dm-subagents/src/extension/doctor.js +71 -17
  59. package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
  60. package/extensions/dm-subagents/src/extension/index.js +711 -265
  61. package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
  62. package/extensions/dm-subagents/src/extension/rpc.js +427 -22
  63. package/extensions/dm-subagents/src/extension/schemas.js +158 -65
  64. package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
  65. package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
  66. package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
  67. package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
  68. package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
  69. package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
  70. package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
  71. package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
  72. package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
  73. package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
  74. package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
  75. package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
  76. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
  77. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
  78. package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
  79. package/extensions/dm-subagents/src/missions/actions.js +394 -0
  80. package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
  81. package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
  82. package/extensions/dm-subagents/src/missions/store.js +548 -0
  83. package/extensions/dm-subagents/src/missions/types.js +9 -0
  84. package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
  85. package/extensions/dm-subagents/src/policy/authority.js +37 -0
  86. package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
  87. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
  88. package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
  89. package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
  90. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
  91. package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
  92. package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
  93. package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
  94. package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
  95. package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
  96. package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
  97. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
  98. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
  99. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
  100. package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
  101. package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
  102. package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
  103. package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
  104. package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
  105. package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
  106. package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
  107. package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
  108. package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
  109. package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
  110. package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
  111. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
  112. package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
  113. package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
  114. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
  115. package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
  116. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
  117. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
  118. package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
  119. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
  120. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
  121. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
  122. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
  123. package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
  124. package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
  125. package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
  126. package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
  127. package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
  128. package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
  129. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
  130. package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
  131. package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
  132. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
  133. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
  134. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
  135. package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
  136. package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
  137. package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
  138. package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
  139. package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
  140. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
  141. package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
  142. package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
  143. package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
  144. package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
  145. package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
  146. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
  147. package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
  148. package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
  149. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
  150. package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
  151. package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
  152. package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
  153. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
  154. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
  155. package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
  156. package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
  157. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
  158. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
  159. package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
  160. package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
  161. package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
  162. package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
  163. package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
  164. package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
  165. package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
  166. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
  167. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
  168. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
  169. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
  170. package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
  171. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
  172. package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
  173. package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
  174. package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
  175. package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
  176. package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
  177. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
  178. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
  179. package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
  180. package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
  181. package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
  182. package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
  183. package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
  184. package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
  185. package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
  186. package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
  187. package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
  188. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
  189. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
  190. package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
  191. package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
  192. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
  193. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
  194. package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
  195. package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
  196. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
  197. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
  198. package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
  199. package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
  200. package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
  201. package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
  202. package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
  203. package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
  204. package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
  205. package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
  206. package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
  207. package/extensions/dm-subagents/src/shared/display-text.js +142 -0
  208. package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
  209. package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
  210. package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
  211. package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
  212. package/extensions/dm-subagents/src/shared/formatters.js +21 -7
  213. package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
  214. package/extensions/dm-subagents/src/shared/model-info.js +10 -5
  215. package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
  216. package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
  217. package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
  218. package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
  219. package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
  220. package/extensions/dm-subagents/src/shared/settings.js +39 -47
  221. package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
  222. package/extensions/dm-subagents/src/shared/status-format.js +9 -2
  223. package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
  224. package/extensions/dm-subagents/src/shared/types.js +47 -7
  225. package/extensions/dm-subagents/src/shared/utf8.js +12 -0
  226. package/extensions/dm-subagents/src/shared/utils.js +151 -131
  227. package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
  228. package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
  229. package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
  230. package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
  231. package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
  232. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
  233. package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
  234. package/extensions/dm-subagents/src/slash/selector.js +101 -0
  235. package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
  236. package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
  237. package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
  238. package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
  239. package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
  240. package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
  241. package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
  242. package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
  243. package/extensions/dm-subagents/src/tui/render.js +1511 -261
  244. package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
  245. package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
  246. package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
  247. package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
  248. package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
  249. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
  250. package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
  251. package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
  252. package/extensions/dm-subagents/src/watchdog/render.js +54 -0
  253. package/extensions/dm-subagents/src/watchdog/review.js +251 -0
  254. package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
  255. package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
  256. package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
  257. package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
  258. package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
  259. package/extensions/dm-subagents/src/watchdog/types.js +29 -0
  260. package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
  261. package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
  262. package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
  263. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
  264. package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
  265. package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
  266. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
  267. package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
  268. package/package.json +4 -3
  269. package/extensions/dm-fff/package.json +0 -21
  270. package/extensions/dm-fff/src/index.js +0 -691
  271. package/extensions/dm-fff/src/query.js +0 -60
  272. package/extensions/dm-subagents/agents/context-builder.md +0 -46
  273. package/extensions/dm-subagents/agents/planner.md +0 -55
  274. package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
  275. package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
  276. package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
  277. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
  278. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
  279. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
@@ -1,27 +1,23 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
+ import { parse as parseYaml } from "yaml";
3
4
  import * as os from "node:os";
4
5
  import * as path from "node:path";
5
6
  import { fileURLToPath } from "node:url";
7
+ import { CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL, isCodeOwnedExternalCliAdapterId, parseExternalCliCapabilityNarrowing, validateCodeOwnedProfileRunner } from "../runs/shared/external-cli-contract.js";
6
8
  import { getAgentDir, getProjectConfigDir } from "../shared/utils.js";
7
9
  import { KNOWN_FIELDS } from "./agent-serializer.js";
8
10
  import { parseChain, parseJsonChain } from "./chain-serializer.js";
9
11
  import { mergeAgentsForScope } from "./agent-selection.js";
10
- import { parseFrontmatter } from "./frontmatter.js";
12
+ import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.js";
11
13
  import { buildRuntimeName, parsePackageName } from "./identity.js";
12
14
  import { parseModelScopeConfig } from "../runs/shared/model-scope.js";
15
+ export { BUILTIN_AGENT_NAMES } from "./builtin-names.js";
13
16
  export { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from "./identity.js";
14
17
  import { parseMemoryFrontmatter } from "./agent-memory.js";
15
- export const BUILTIN_AGENT_NAMES = [
16
- "context-builder",
17
- "delegate",
18
- "oracle",
19
- "planner",
20
- "researcher",
21
- "reviewer",
22
- "scout",
23
- "worker"
24
- ];
18
+ import { validateAcceptanceInput } from "../runs/shared/acceptance.js";
19
+ import { validatePermissionRules } from "../runs/shared/permissions.js";
20
+ import { parseThinkingLevel } from "../shared/thinking-ceiling.js";
25
21
  export function defaultSystemPromptMode(name) {
26
22
  return name === "delegate" ? "append" : "replace";
27
23
  }
@@ -31,8 +27,54 @@ export function defaultInheritProjectContext(name) {
31
27
  export function defaultInheritSkills() {
32
28
  return false;
33
29
  }
34
- const EMPTY_SUBAGENT_SETTINGS = { overrides: {} };
30
+ const EMPTY_SUBAGENT_SETTINGS = { overrides: {}, providerOverrides: {} };
35
31
  const agentFrontmatterFields = new WeakMap;
32
+ const AGENT_SOURCE_PRIORITY = {
33
+ builtin: 0,
34
+ package: 1,
35
+ user: 2,
36
+ project: 3,
37
+ runtime: 4
38
+ };
39
+ function agentDefinitionPriority(definition) {
40
+ return AGENT_SOURCE_PRIORITY[definition.source] * 1e6 + (definition.discoveryPriority ?? 0);
41
+ }
42
+ export function findBlockingAgentDiagnostic(name, agent, diagnostics) {
43
+ const normalizedName = name.trim();
44
+ const agents = Array.isArray(agent) ? agent : agent ? [agent] : [];
45
+ let match;
46
+ for (const diagnostic of diagnostics ?? []) {
47
+ if ((diagnostic.runtimeName === normalizedName || diagnostic.name === normalizedName && (!diagnostic.packageSpecified || diagnostic.runtimeName === undefined || agents.some((agent) => agent.name === diagnostic.runtimeName && agent.localName === diagnostic.name))) && (!match || agentDefinitionPriority(diagnostic) > agentDefinitionPriority(match))) {
48
+ match = diagnostic;
49
+ }
50
+ }
51
+ const highestPriority = Math.max(...agents.map(agentDefinitionPriority), -1 / 0);
52
+ return !agents.length || match && agentDefinitionPriority(match) > highestPriority ? match : undefined;
53
+ }
54
+ export function unknownAgentDiagnosticContext(discovered) {
55
+ return {
56
+ cwd: discovered.cwd,
57
+ scope: discovered.scope,
58
+ directories: discovered.directories,
59
+ agents: discovered.agents
60
+ };
61
+ }
62
+ export function formatUnknownAgentError(name, context, prefix = "Unknown agent") {
63
+ const directories = context.directories.map((directory) => {
64
+ const state = directory.state === "candidates" ? `${directory.candidateCount ?? 0} candidate${directory.candidateCount === 1 ? "" : "s"}` : directory.state === "empty" ? "present but empty" : directory.state === "not-directory" ? "not a directory" : directory.state;
65
+ return `- ${directory.source}: ${directory.path} (${state})`;
66
+ });
67
+ const agents = [...context.agents].sort((left, right) => left.name.localeCompare(right.name) || left.source.localeCompare(right.source)).map((agent) => `- ${agent.name} (${agent.source})`);
68
+ return [
69
+ `${prefix}: ${name}`,
70
+ `Effective cwd: ${path.resolve(context.cwd)}`,
71
+ "Consulted agent-definition directories:",
72
+ ...directories.length ? directories : ["- (none)"],
73
+ "Discovered agents:",
74
+ ...agents.length ? agents : ["- (none)"]
75
+ ].join(`
76
+ `);
77
+ }
36
78
  function getUserChainDir() {
37
79
  return path.join(getAgentDir(), "chains");
38
80
  }
@@ -44,16 +86,6 @@ function readJsonFileBestEffort(filePath) {
44
86
  return null;
45
87
  }
46
88
  }
47
- function readOptionalJsonFile(filePath) {
48
- try {
49
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
50
- } catch (error) {
51
- const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
52
- if (code === "ENOENT")
53
- return null;
54
- throw error;
55
- }
56
- }
57
89
  function isSafePackagePath(value) {
58
90
  return value.length > 0 && !path.isAbsolute(value) && value.split(/[\\/]/).every((part) => part.length > 0 && part !== "." && part !== "..");
59
91
  }
@@ -124,13 +156,29 @@ function resolveSettingsPackageRoot(source, baseDir) {
124
156
  if (normalized === "." || normalized === ".." || normalized.startsWith("./") || normalized.startsWith("../")) {
125
157
  return path.resolve(baseDir, normalized);
126
158
  }
159
+ if (/^https?:\/\//i.test(trimmed)) {
160
+ const parsed = parseGitPackagePath(`git:${trimmed}`);
161
+ return parsed ? path.join(baseDir, "git", parsed.host, parsed.repoPath) : undefined;
162
+ }
127
163
  return;
128
164
  }
129
165
  function getGlobalNpmRoot() {
166
+ const offline = process.env.PI_OFFLINE?.toLowerCase();
167
+ if (offline === "1" || offline === "true" || offline === "yes")
168
+ return null;
130
169
  if (cachedGlobalNpmRoot !== null)
131
170
  return cachedGlobalNpmRoot;
171
+ const windowsGlobalRoot = process.platform === "win32" && process.env.APPDATA ? path.join(process.env.APPDATA, "npm", "node_modules") : undefined;
172
+ if (windowsGlobalRoot) {
173
+ try {
174
+ if (fs.statSync(windowsGlobalRoot).isDirectory()) {
175
+ cachedGlobalNpmRoot = fs.realpathSync(windowsGlobalRoot);
176
+ return cachedGlobalNpmRoot;
177
+ }
178
+ } catch {}
179
+ }
132
180
  try {
133
- cachedGlobalNpmRoot = fs.realpathSync(execSync("npm root -g", { encoding: "utf-8", timeout: 5000 }).trim());
181
+ cachedGlobalNpmRoot = fs.realpathSync(execSync("npm root -g", { encoding: "utf-8", timeout: 5000, windowsHide: true }).trim());
134
182
  return cachedGlobalNpmRoot;
135
183
  } catch {
136
184
  cachedGlobalNpmRoot = "";
@@ -142,19 +190,30 @@ function stringArray(value) {
142
190
  return [];
143
191
  return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
144
192
  }
145
- function extractSubagentPathsFromPackageRoot(packageRoot) {
193
+ function packageMetadata(pkg, packageRoot) {
194
+ const name = typeof pkg.name === "string" && pkg.name.trim() ? pkg.name.trim() : undefined;
195
+ const version = typeof pkg.version === "string" && pkg.version.trim() ? pkg.version.trim() : undefined;
196
+ return {
197
+ packageRoot,
198
+ ...name ? { packageName: name } : {},
199
+ ...version ? { packageVersion: version } : {}
200
+ };
201
+ }
202
+ function extractSubagentPathsFromPackageRoot(packageRoot, scope) {
146
203
  const packageJsonPath = path.join(packageRoot, "package.json");
147
204
  const pkg = readJsonFileBestEffort(packageJsonPath);
148
205
  if (!pkg || typeof pkg !== "object" || Array.isArray(pkg))
149
- return { agents: [], chains: [] };
206
+ return { agents: [], chains: [], watchPaths: [packageJsonPath], settingsErrors: {} };
207
+ const pkgRecord = pkg;
208
+ const metadata = packageMetadata(pkgRecord, packageRoot);
150
209
  const roots = [];
151
- const piSubagents = pkg["dm-subagents"];
210
+ const piSubagents = pkgRecord["dm-subagents"];
152
211
  if (piSubagents && typeof piSubagents === "object" && !Array.isArray(piSubagents)) {
153
212
  roots.push(piSubagents);
154
213
  }
155
- const pi = pkg.pi;
156
- if (pi && typeof pi === "object" && !Array.isArray(pi)) {
157
- const subagents = pi.subagents;
214
+ const dm = pkgRecord.dm;
215
+ if (dm && typeof dm === "object" && !Array.isArray(dm)) {
216
+ const subagents = dm.subagents;
158
217
  if (subagents && typeof subagents === "object" && !Array.isArray(subagents)) {
159
218
  roots.push(subagents);
160
219
  }
@@ -163,14 +222,15 @@ function extractSubagentPathsFromPackageRoot(packageRoot) {
163
222
  const chains = [];
164
223
  for (const root of roots) {
165
224
  for (const entry of stringArray(root.agents))
166
- agents.push(path.resolve(packageRoot, entry));
225
+ agents.push({ dir: path.resolve(packageRoot, entry), scope, ...metadata });
167
226
  for (const entry of stringArray(root.chains))
168
- chains.push(path.resolve(packageRoot, entry));
227
+ chains.push({ dir: path.resolve(packageRoot, entry), scope, packageRoot });
169
228
  }
170
- return { agents, chains };
229
+ return { agents, chains, watchPaths: [packageJsonPath], settingsErrors: {} };
171
230
  }
172
- function collectPackageRootsFromNodeModules(nodeModulesDir) {
231
+ function collectPackageRootsFromNodeModules(nodeModulesDir, watchPaths) {
173
232
  const roots = [];
233
+ watchPaths?.push(nodeModulesDir);
174
234
  if (!fs.existsSync(nodeModulesDir))
175
235
  return roots;
176
236
  let entries;
@@ -186,6 +246,7 @@ function collectPackageRootsFromNodeModules(nodeModulesDir) {
186
246
  continue;
187
247
  if (entry.name.startsWith("@")) {
188
248
  const scopeDir = path.join(nodeModulesDir, entry.name);
249
+ watchPaths?.push(scopeDir);
189
250
  let scopeEntries;
190
251
  try {
191
252
  scopeEntries = fs.readdirSync(scopeDir, { withFileTypes: true });
@@ -206,9 +267,7 @@ function collectPackageRootsFromNodeModules(nodeModulesDir) {
206
267
  return roots;
207
268
  }
208
269
  function collectSettingsPackageRoots(settingsFile, baseDir) {
209
- const settings = readOptionalJsonFile(settingsFile);
210
- if (!settings || typeof settings !== "object" || Array.isArray(settings))
211
- return [];
270
+ const settings = readSettingsFileStrict(settingsFile);
212
271
  const packages = settings.packages;
213
272
  if (!Array.isArray(packages))
214
273
  return [];
@@ -225,47 +284,112 @@ function collectSettingsPackageRoots(settingsFile, baseDir) {
225
284
  }
226
285
  function collectPackageSubagentPaths(cwd, options = { includeUser: true, includeProject: true }) {
227
286
  const agentDir = getAgentDir();
228
- const projectRoot = findNearestProjectRoot(cwd) ?? cwd;
287
+ const projectRoot = findConfiguredProjectRoot(cwd) ?? cwd;
229
288
  const packageRoots = [
230
- projectRoot
289
+ { root: projectRoot, scope: "root" }
231
290
  ];
291
+ const watchPaths = [path.join(projectRoot, "package.json")];
292
+ const settingsErrors = {};
293
+ const collectScopedSettingsRoots = (scope, settingsFile, baseDir) => {
294
+ try {
295
+ return collectSettingsPackageRoots(settingsFile, baseDir);
296
+ } catch (error) {
297
+ settingsErrors[scope] = error instanceof Error ? error : new Error(`Failed to read settings file '${settingsFile}': ${String(error)}`, { cause: error });
298
+ return [];
299
+ }
300
+ };
232
301
  if (options.includeProject) {
233
302
  const projectConfigDir = getProjectConfigDir(projectRoot);
234
- packageRoots.push(...collectPackageRootsFromNodeModules(path.join(projectConfigDir, "npm", "node_modules")), ...collectSettingsPackageRoots(path.join(projectConfigDir, "settings.json"), projectConfigDir));
303
+ const nodeModulesDir = path.join(projectConfigDir, "npm", "node_modules");
304
+ packageRoots.push(...collectPackageRootsFromNodeModules(nodeModulesDir, watchPaths).map((root) => ({ root, scope: "project" })));
305
+ packageRoots.push(...collectScopedSettingsRoots("project", path.join(projectConfigDir, "settings.json"), projectConfigDir).map((root) => ({ root, scope: "project" })));
235
306
  }
236
307
  if (options.includeUser) {
237
- packageRoots.push(...collectPackageRootsFromNodeModules(path.join(agentDir, "npm", "node_modules")), ...collectSettingsPackageRoots(path.join(agentDir, "settings.json"), agentDir));
308
+ const nodeModulesDir = path.join(agentDir, "npm", "node_modules");
309
+ packageRoots.push(...collectPackageRootsFromNodeModules(nodeModulesDir, watchPaths).map((root) => ({ root, scope: "user" })));
310
+ packageRoots.push(...collectScopedSettingsRoots("user", path.join(agentDir, "settings.json"), agentDir).map((root) => ({ root, scope: "user" })));
238
311
  }
239
312
  if (options.includeUser) {
240
313
  const globalRoot = getGlobalNpmRoot();
241
- if (globalRoot)
242
- packageRoots.push(...collectPackageRootsFromNodeModules(globalRoot));
314
+ if (globalRoot) {
315
+ packageRoots.push(...collectPackageRootsFromNodeModules(globalRoot, watchPaths).map((root) => ({ root, scope: "user" })));
316
+ }
243
317
  }
244
- const seenRoots = new Set;
245
- const seenAgents = new Set;
246
- const seenChains = new Set;
318
+ const seenRoots = new Map;
319
+ const seenAgents = new Map;
320
+ const seenChains = new Map;
247
321
  const agents = [];
248
322
  const chains = [];
249
- for (const packageRoot of packageRoots) {
323
+ for (const { root: packageRoot, scope } of packageRoots) {
250
324
  const resolvedRoot = path.resolve(packageRoot);
251
- if (seenRoots.has(resolvedRoot))
325
+ const scopes = seenRoots.get(resolvedRoot);
326
+ if (scopes !== undefined) {
327
+ scopes.add(scope);
252
328
  continue;
253
- seenRoots.add(resolvedRoot);
254
- const paths = extractSubagentPathsFromPackageRoot(resolvedRoot);
255
- for (const agentDir of paths.agents) {
256
- if (seenAgents.has(agentDir))
329
+ }
330
+ const packageScopes = new Set([scope]);
331
+ seenRoots.set(resolvedRoot, packageScopes);
332
+ const paths = extractSubagentPathsFromPackageRoot(resolvedRoot, packageScopes);
333
+ watchPaths.push(...paths.watchPaths);
334
+ for (const agentPath of paths.agents) {
335
+ const agentKey = `${agentPath.dir}\x00${agentPath.packageRoot}`;
336
+ const existing = seenAgents.get(agentKey);
337
+ if (existing) {
338
+ for (const packageScope of agentPath.scope)
339
+ existing.scope.add(packageScope);
257
340
  continue;
258
- seenAgents.add(agentDir);
259
- agents.push(agentDir);
341
+ }
342
+ seenAgents.set(agentKey, agentPath);
343
+ agents.push(agentPath);
260
344
  }
261
345
  for (const chainDir of paths.chains) {
262
- if (seenChains.has(chainDir))
346
+ const chainKey = `${chainDir.dir}\x00${chainDir.packageRoot}`;
347
+ const existing = seenChains.get(chainKey);
348
+ if (existing) {
349
+ for (const packageScope of chainDir.scope)
350
+ existing.scope.add(packageScope);
263
351
  continue;
264
- seenChains.add(chainDir);
352
+ }
353
+ seenChains.set(chainKey, chainDir);
265
354
  chains.push(chainDir);
266
355
  }
267
356
  }
268
- return { agents, chains };
357
+ return { agents, chains, watchPaths, settingsErrors };
358
+ }
359
+ function normalizeAgentAliases(rawAliases, agentName) {
360
+ const aliases = [...new Set((rawAliases ?? []).map((alias) => alias.trim()).filter(Boolean))].filter((alias) => alias !== agentName);
361
+ return aliases.length > 0 ? aliases : undefined;
362
+ }
363
+ function effectiveAgentMatch(matches) {
364
+ const distinctNames = [...new Set(matches.map((agent) => agent.name))];
365
+ if (distinctNames.length === 1) {
366
+ const sourceRank = new Map([["builtin", 0], ["package", 1], ["user", 2], ["project", 3], ["runtime", 4]]);
367
+ const agent = [...matches].sort((a, b) => (sourceRank.get(b.source) ?? 0) - (sourceRank.get(a.source) ?? 0))[0];
368
+ return agent ? { agent } : {};
369
+ }
370
+ return {};
371
+ }
372
+ export function resolveAgentName(name, agents) {
373
+ const raw = name.trim();
374
+ const exact = agents.filter((agent) => agent.name === raw || agent.localName === raw);
375
+ if (exact.length === 1)
376
+ return exact[0] ? { agent: exact[0] } : {};
377
+ if (exact.length > 1) {
378
+ const effective = effectiveAgentMatch(exact);
379
+ if (effective.agent)
380
+ return effective;
381
+ return { error: `Ambiguous agent name '${name}': ${exact.map((agent) => agent.name).join(", ")}` };
382
+ }
383
+ const aliases = agents.filter((agent) => agent.aliases?.includes(raw));
384
+ if (aliases.length === 1)
385
+ return aliases[0] ? { agent: aliases[0] } : {};
386
+ if (aliases.length > 1) {
387
+ const effective = effectiveAgentMatch(aliases);
388
+ if (effective.agent)
389
+ return effective;
390
+ return { error: `Ambiguous agent alias '${name}': ${aliases.map((agent) => agent.name).join(", ")}` };
391
+ }
392
+ return {};
269
393
  }
270
394
  function splitToolList(rawTools) {
271
395
  const mcpDirectTools = [];
@@ -278,7 +402,7 @@ function splitToolList(rawTools) {
278
402
  }
279
403
  }
280
404
  return {
281
- ...tools.length > 0 ? { tools } : {},
405
+ ...rawTools !== undefined ? { tools } : {},
282
406
  ...mcpDirectTools.length > 0 ? { mcpDirectTools } : {}
283
407
  };
284
408
  }
@@ -304,58 +428,137 @@ function arraysEqual(a, b) {
304
428
  }
305
429
  function cloneOverrideBase(agent) {
306
430
  return {
307
- model: agent.model,
308
- fallbackModels: agent.fallbackModels ? [...agent.fallbackModels] : undefined,
309
- thinking: agent.thinking,
431
+ description: agent.description,
432
+ ...agent.output !== undefined ? { output: agent.output } : {},
433
+ ...agent.outputMode !== undefined ? { outputMode: agent.outputMode } : {},
434
+ ...agent.defaultReads !== undefined ? { defaultReads: [...agent.defaultReads] } : {},
435
+ ...agent.model !== undefined ? { model: agent.model } : {},
436
+ ...agent.modelProvider !== undefined ? { modelProvider: agent.modelProvider } : {},
437
+ ...agent.fallbackModels ? { fallbackModels: [...agent.fallbackModels] } : {},
438
+ ...agent.fast !== undefined ? { fast: agent.fast } : {},
439
+ ...agent.thinking !== undefined ? { thinking: agent.thinking } : {},
310
440
  systemPromptMode: agent.systemPromptMode,
311
441
  inheritProjectContext: agent.inheritProjectContext,
442
+ inheritGlobalContext: agent.inheritGlobalContext,
312
443
  inheritSkills: agent.inheritSkills,
313
- defaultContext: agent.defaultContext,
314
- disabled: agent.disabled,
444
+ ...agent.defaultContext !== undefined ? { defaultContext: agent.defaultContext } : {},
445
+ ...agent.acceptanceRole !== undefined ? { acceptanceRole: agent.acceptanceRole } : {},
446
+ ...agent.disabled !== undefined ? { disabled: agent.disabled } : {},
315
447
  systemPrompt: agent.systemPrompt,
316
- skills: agent.skills ? [...agent.skills] : undefined,
317
- tools: agent.tools ? [...agent.tools] : undefined,
318
- mcpDirectTools: agent.mcpDirectTools ? [...agent.mcpDirectTools] : undefined,
319
- subagentOnlyExtensions: agent.subagentOnlyExtensions ? [...agent.subagentOnlyExtensions] : undefined,
320
- completionGuard: agent.completionGuard,
321
- toolBudget: agent.toolBudget
448
+ ...agent.skills ? { skills: [...agent.skills] } : {},
449
+ ...agent.skillPath ? { skillPath: [...agent.skillPath] } : {},
450
+ ...agent.tools ? { tools: [...agent.tools] } : {},
451
+ ...agent.allowNestedSubagents !== undefined ? { allowNestedSubagents: agent.allowNestedSubagents } : {},
452
+ ...agent.mcpDirectTools ? { mcpDirectTools: [...agent.mcpDirectTools] } : {},
453
+ ...!agent.extensionsFromDefault && agent.extensions ? { extensions: [...agent.extensions] } : {},
454
+ ...agent.subagentOnlyExtensions ? { subagentOnlyExtensions: [...agent.subagentOnlyExtensions] } : {},
455
+ ...agent.mutationTools ? { mutationTools: [...agent.mutationTools] } : {},
456
+ ...agent.completionGuard !== undefined ? { completionGuard: agent.completionGuard } : {},
457
+ ...agent.toolBudget !== undefined ? { toolBudget: agent.toolBudget } : {}
322
458
  };
323
459
  }
324
460
  function cloneOverrideValue(override) {
325
461
  return {
462
+ ...override.description !== undefined ? { description: override.description } : {},
463
+ ...override.output !== undefined ? { output: override.output } : {},
464
+ ...override.outputMode !== undefined ? { outputMode: override.outputMode } : {},
465
+ ...override.defaultReads !== undefined ? { defaultReads: override.defaultReads === false ? false : [...override.defaultReads] } : {},
326
466
  ...override.model !== undefined ? { model: override.model } : {},
467
+ ...override.defaultProvider !== undefined ? { defaultProvider: override.defaultProvider } : {},
327
468
  ...override.fallbackModels !== undefined ? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] } : {},
469
+ ...override.fast !== undefined ? { fast: override.fast } : {},
328
470
  ...override.thinking !== undefined ? { thinking: override.thinking } : {},
329
471
  ...override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {},
330
472
  ...override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {},
473
+ ...override.inheritGlobalContext !== undefined ? { inheritGlobalContext: override.inheritGlobalContext } : {},
331
474
  ...override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {},
332
475
  ...override.defaultContext !== undefined ? { defaultContext: override.defaultContext } : {},
476
+ ...override.acceptanceRole !== undefined ? { acceptanceRole: override.acceptanceRole } : {},
333
477
  ...override.disabled !== undefined ? { disabled: override.disabled } : {},
334
478
  ...override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {},
335
479
  ...override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {},
336
- ...override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {},
480
+ ...override.tools !== undefined ? { tools: Array.isArray(override.tools) ? [...override.tools] : override.tools } : {},
481
+ ...override.allowNestedSubagents !== undefined ? { allowNestedSubagents: override.allowNestedSubagents } : {},
482
+ ...override.extensions !== undefined ? { extensions: override.extensions === false ? false : [...override.extensions] } : {},
337
483
  ...override.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: override.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions] } : {},
484
+ ...override.mutationTools !== undefined ? { mutationTools: override.mutationTools === false ? false : [...override.mutationTools] } : {},
338
485
  ...override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {},
339
486
  ...override.toolBudget !== undefined ? { toolBudget: override.toolBudget === false ? false : { ...override.toolBudget, ...Array.isArray(override.toolBudget.block) ? { block: [...override.toolBudget.block] } : {} } } : {}
340
487
  };
341
488
  }
342
- export function findNearestProjectRoot(cwd) {
489
+ function isProjectRootCandidate(dir) {
490
+ return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
491
+ }
492
+ function findProjectRootCandidates(cwd) {
493
+ const roots = [];
494
+ let currentDir = cwd;
495
+ while (true) {
496
+ if (isProjectRootCandidate(currentDir))
497
+ roots.push(currentDir);
498
+ const parentDir = path.dirname(currentDir);
499
+ if (parentDir === currentDir)
500
+ return roots;
501
+ currentDir = parentDir;
502
+ }
503
+ }
504
+ function findNearestGitRoot(cwd) {
343
505
  let currentDir = cwd;
344
506
  while (true) {
345
- if (isDirectory(getProjectConfigDir(currentDir)) || isDirectory(path.join(currentDir, ".agents"))) {
507
+ if (fs.existsSync(path.join(currentDir, ".git")))
346
508
  return currentDir;
347
- }
348
509
  const parentDir = path.dirname(currentDir);
349
510
  if (parentDir === currentDir)
350
511
  return null;
351
512
  currentDir = parentDir;
352
513
  }
353
514
  }
515
+ function readProjectRootResolution(projectRoot) {
516
+ const settingsPath = path.join(getProjectConfigDir(projectRoot), "settings.json");
517
+ if (!fs.existsSync(settingsPath))
518
+ return;
519
+ const settings = readSettingsFileStrict(settingsPath);
520
+ const subagents = settings.subagents;
521
+ if (!subagents || typeof subagents !== "object" || Array.isArray(subagents))
522
+ return;
523
+ const value = subagents.projectRootResolution;
524
+ if (value === undefined)
525
+ return;
526
+ if (value === "nearest" || value === "git-root")
527
+ return value;
528
+ throw new Error(`Subagent settings in '${settingsPath}' have invalid 'projectRootResolution'; expected 'nearest' or 'git-root'.`);
529
+ }
530
+ export function findNearestProjectRoot(cwd) {
531
+ return findProjectRootCandidates(cwd)[0] ?? null;
532
+ }
533
+ export function findConfiguredProjectRoot(cwd) {
534
+ const candidates = findProjectRootCandidates(cwd);
535
+ const nearestRoot = candidates[0];
536
+ if (!nearestRoot)
537
+ return null;
538
+ let policyRoot;
539
+ let policyRootIndex = -1;
540
+ for (const [index, candidate] of candidates.entries()) {
541
+ const mode = readProjectRootResolution(candidate);
542
+ if (mode === "nearest")
543
+ return nearestRoot;
544
+ if (mode === "git-root") {
545
+ policyRoot = candidate;
546
+ policyRootIndex = index;
547
+ break;
548
+ }
549
+ }
550
+ if (!policyRoot)
551
+ return nearestRoot;
552
+ const gitRoot = findNearestGitRoot(cwd);
553
+ const gitProjectRoot = gitRoot ? candidates.slice(policyRootIndex).find((candidate) => path.resolve(candidate) === path.resolve(gitRoot)) : undefined;
554
+ const configuredGitRoot = fs.existsSync(path.join(policyRoot, ".git")) ? policyRoot : undefined;
555
+ return gitProjectRoot ?? configuredGitRoot ?? nearestRoot;
556
+ }
354
557
  function getUserAgentSettingsPath() {
355
558
  return path.join(getAgentDir(), "settings.json");
356
559
  }
357
560
  function getProjectAgentSettingsPath(cwd) {
358
- const projectRoot = findNearestProjectRoot(cwd);
561
+ const projectRoot = findConfiguredProjectRoot(cwd);
359
562
  return projectRoot ? path.join(getProjectConfigDir(projectRoot), "settings.json") : null;
360
563
  }
361
564
  function readSettingsFileStrict(filePath) {
@@ -404,18 +607,52 @@ function parseOverrideStringArrayOrFalse(value, meta) {
404
607
  }
405
608
  return items;
406
609
  }
610
+ function parseToolsOverride(value, meta) {
611
+ if (typeof value === "string" && value.trim() === "inherit")
612
+ return "inherit";
613
+ if (value === undefined || value === false || Array.isArray(value)) {
614
+ return parseOverrideStringArrayOrFalse(value, { ...meta, field: "tools" });
615
+ }
616
+ throw new Error(`Builtin override '${meta.name}' in '${meta.filePath}' has invalid 'tools'; expected an array of strings, "inherit", or false.`);
617
+ }
407
618
  function parseBuiltinOverrideEntry(name, value, filePath) {
408
619
  if (!value || typeof value !== "object" || Array.isArray(value)) {
409
620
  throw new Error(`Builtin override '${name}' in '${filePath}' must be an object.`);
410
621
  }
411
622
  const input = value;
412
623
  const override = {};
624
+ if ("description" in input) {
625
+ if (typeof input.description === "string" && input.description.trim()) {
626
+ override.description = input.description.trim();
627
+ } else {
628
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'description'; expected a non-empty string.`);
629
+ }
630
+ }
631
+ if ("output" in input) {
632
+ if (typeof input.output === "string" && input.output.trim() || input.output === false)
633
+ override.output = input.output;
634
+ else
635
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'output'; expected a non-empty string or false.`);
636
+ }
637
+ if ("outputMode" in input) {
638
+ if (input.outputMode === "inline" || input.outputMode === "file-only") {
639
+ override.outputMode = input.outputMode;
640
+ } else {
641
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'outputMode'; expected 'inline' or 'file-only'.`);
642
+ }
643
+ }
413
644
  if ("model" in input) {
414
645
  if (typeof input.model === "string" || input.model === false)
415
646
  override.model = input.model;
416
647
  else
417
648
  throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'model'; expected a string or false.`);
418
649
  }
650
+ if ("fast" in input) {
651
+ if (typeof input.fast === "boolean")
652
+ override.fast = input.fast;
653
+ else
654
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'fast'; expected a boolean.`);
655
+ }
419
656
  if ("thinking" in input) {
420
657
  if (typeof input.thinking === "string" || input.thinking === false)
421
658
  override.thinking = input.thinking;
@@ -436,6 +673,13 @@ function parseBuiltinOverrideEntry(name, value, filePath) {
436
673
  throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritProjectContext'; expected a boolean.`);
437
674
  }
438
675
  }
676
+ if ("inheritGlobalContext" in input) {
677
+ if (typeof input.inheritGlobalContext === "boolean") {
678
+ override.inheritGlobalContext = input.inheritGlobalContext;
679
+ } else {
680
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'inheritGlobalContext'; expected a boolean.`);
681
+ }
682
+ }
439
683
  if ("inheritSkills" in input) {
440
684
  if (typeof input.inheritSkills === "boolean") {
441
685
  override.inheritSkills = input.inheritSkills;
@@ -450,6 +694,13 @@ function parseBuiltinOverrideEntry(name, value, filePath) {
450
694
  throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'defaultContext'; expected 'fresh', 'fork', or false.`);
451
695
  }
452
696
  }
697
+ if ("acceptanceRole" in input) {
698
+ if (input.acceptanceRole === "read-only" || input.acceptanceRole === "writer" || input.acceptanceRole === false) {
699
+ override.acceptanceRole = input.acceptanceRole;
700
+ } else {
701
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'acceptanceRole'; expected 'read-only', 'writer', or false.`);
702
+ }
703
+ }
453
704
  if ("disabled" in input) {
454
705
  if (typeof input.disabled === "boolean") {
455
706
  override.disabled = input.disabled;
@@ -479,18 +730,41 @@ function parseBuiltinOverrideEntry(name, value, filePath) {
479
730
  else
480
731
  throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);
481
732
  }
733
+ const defaultReads = parseOverrideStringArrayOrFalse(input.defaultReads, { filePath, name, field: "defaultReads" });
734
+ if (defaultReads !== undefined)
735
+ override.defaultReads = defaultReads;
482
736
  const fallbackModels = parseOverrideStringArrayOrFalse(input.fallbackModels, { filePath, name, field: "fallbackModels" });
483
737
  if (fallbackModels !== undefined)
484
738
  override.fallbackModels = fallbackModels;
739
+ if ("defaultProvider" in input) {
740
+ if (input.defaultProvider === false)
741
+ override.defaultProvider = false;
742
+ else if (typeof input.defaultProvider === "string" && input.defaultProvider.trim())
743
+ override.defaultProvider = input.defaultProvider.trim();
744
+ else
745
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'defaultProvider'; expected a non-empty string or false.`);
746
+ }
485
747
  const skills = parseOverrideStringArrayOrFalse(input.skills, { filePath, name, field: "skills" });
486
748
  if (skills !== undefined)
487
749
  override.skills = skills;
488
- const tools = parseOverrideStringArrayOrFalse(input.tools, { filePath, name, field: "tools" });
750
+ const tools = parseToolsOverride(input.tools, { filePath, name });
489
751
  if (tools !== undefined)
490
752
  override.tools = tools;
753
+ if ("allowNestedSubagents" in input) {
754
+ if (typeof input.allowNestedSubagents === "boolean")
755
+ override.allowNestedSubagents = input.allowNestedSubagents;
756
+ else
757
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'allowNestedSubagents'; expected a boolean.`);
758
+ }
759
+ const extensions = parseOverrideStringArrayOrFalse(input.extensions, { filePath, name, field: "extensions" });
760
+ if (extensions !== undefined)
761
+ override.extensions = extensions;
491
762
  const subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, { filePath, name, field: "subagentOnlyExtensions" });
492
763
  if (subagentOnlyExtensions !== undefined)
493
764
  override.subagentOnlyExtensions = subagentOnlyExtensions;
765
+ const mutationTools = parseOverrideStringArrayOrFalse(input.mutationTools, { filePath, name, field: "mutationTools" });
766
+ if (mutationTools !== undefined)
767
+ override.mutationTools = mutationTools;
494
768
  return Object.keys(override).length > 0 ? override : undefined;
495
769
  }
496
770
  function readSubagentSettings(filePath) {
@@ -525,86 +799,300 @@ function readSubagentSettings(filePath) {
525
799
  throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`);
526
800
  }
527
801
  }
802
+ let defaultProvider;
803
+ if ("defaultProvider" in subagentsObject) {
804
+ if (typeof subagentsObject.defaultProvider === "string" && subagentsObject.defaultProvider.trim()) {
805
+ defaultProvider = subagentsObject.defaultProvider.trim();
806
+ } else {
807
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultProvider'; expected a non-empty string.`);
808
+ }
809
+ }
810
+ let defaultThinking;
811
+ if ("defaultThinking" in subagentsObject) {
812
+ if (typeof subagentsObject.defaultThinking === "string" && subagentsObject.defaultThinking.trim()) {
813
+ defaultThinking = subagentsObject.defaultThinking.trim();
814
+ } else {
815
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultThinking'; expected a non-empty string.`);
816
+ }
817
+ }
818
+ let maxThinking;
819
+ if ("maxThinking" in subagentsObject) {
820
+ try {
821
+ maxThinking = parseThinkingLevel(subagentsObject.maxThinking, `'${filePath}' subagents.maxThinking`);
822
+ } catch (error) {
823
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'maxThinking'; expected one of off, minimal, low, medium, high, xhigh, or max.`, { cause: error instanceof Error ? error : undefined });
824
+ }
825
+ }
826
+ let defaultExtensions;
827
+ if ("defaultExtensions" in subagentsObject) {
828
+ if (!Array.isArray(subagentsObject.defaultExtensions) || subagentsObject.defaultExtensions.some((item) => typeof item !== "string" || !item.trim())) {
829
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultExtensions'; expected an array of non-empty strings.`);
830
+ }
831
+ defaultExtensions = subagentsObject.defaultExtensions.map((item) => item.trim());
832
+ }
528
833
  const modelScope = parseModelScopeConfig(subagentsObject.modelScope, { filePath });
529
834
  const parsed = {};
835
+ const providerOverrides = {};
530
836
  const agentOverrides = subagentsObject.agentOverrides;
531
- if (!agentOverrides || typeof agentOverrides !== "object" || Array.isArray(agentOverrides)) {
532
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
837
+ const agentOverridesByProvider = subagentsObject.agentOverridesByProvider;
838
+ const parsedSettings = {
839
+ overrides: parsed,
840
+ providerOverrides,
841
+ ...defaultModel !== undefined ? { defaultModel } : {},
842
+ ...defaultProvider !== undefined ? { defaultProvider } : {},
843
+ ...defaultThinking !== undefined ? { defaultThinking } : {},
844
+ ...maxThinking !== undefined ? { maxThinking } : {},
845
+ ...defaultExtensions !== undefined ? { defaultExtensions } : {},
846
+ ...disableBuiltins !== undefined ? { disableBuiltins } : {},
847
+ ...disableThinking !== undefined ? { disableThinking } : {},
848
+ ...modelScope !== undefined ? { modelScope } : {}
849
+ };
850
+ if (agentOverrides && typeof agentOverrides === "object" && !Array.isArray(agentOverrides)) {
851
+ for (const [name, value] of Object.entries(agentOverrides)) {
852
+ const override = parseBuiltinOverrideEntry(name, value, filePath);
853
+ if (override)
854
+ parsed[name] = override;
855
+ }
533
856
  }
534
- for (const [name, value] of Object.entries(agentOverrides)) {
535
- const override = parseBuiltinOverrideEntry(name, value, filePath);
536
- if (override)
537
- parsed[name] = override;
857
+ if (agentOverridesByProvider !== undefined) {
858
+ if (!agentOverridesByProvider || typeof agentOverridesByProvider !== "object" || Array.isArray(agentOverridesByProvider)) {
859
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'agentOverridesByProvider'; expected an object keyed by provider.`);
860
+ }
861
+ for (const [provider, value] of Object.entries(agentOverridesByProvider)) {
862
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
863
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'agentOverridesByProvider.${provider}'; expected an object keyed by agent.`);
864
+ }
865
+ const entries = {};
866
+ for (const [agentName, agentValue] of Object.entries(value)) {
867
+ const override = parseBuiltinOverrideEntry(`agentOverridesByProvider.${provider}.${agentName}`, agentValue, filePath);
868
+ if (override)
869
+ entries[agentName] = override;
870
+ }
871
+ providerOverrides[provider] = entries;
872
+ }
538
873
  }
539
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
874
+ return parsedSettings;
875
+ }
876
+ function selectProviderOverrides(settings, provider) {
877
+ if (!provider)
878
+ return settings;
879
+ const selected = settings.providerOverrides[provider];
880
+ if (!selected)
881
+ return settings;
882
+ const overrides = { ...settings.overrides };
883
+ for (const [name, override] of Object.entries(selected)) {
884
+ overrides[name] = { ...overrides[name], ...override };
885
+ }
886
+ return { ...settings, overrides };
540
887
  }
541
- function resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath) {
888
+ function resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath) {
889
+ if (projectSettingsPath && projectSettings.defaultProvider !== undefined)
890
+ return projectSettings.defaultProvider;
891
+ return userSettings.defaultProvider;
892
+ }
893
+ function resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider) {
542
894
  if (projectSettingsPath && projectSettings.defaultModel !== undefined) {
543
- return { type: "subagents.defaultModel", scope: "project", path: projectSettingsPath, model: projectSettings.defaultModel };
895
+ return { type: "subagents.defaultModel", scope: "project", path: projectSettingsPath, model: projectSettings.defaultModel, ...defaultProvider ? { defaultProvider } : {} };
544
896
  }
545
- return userSettings.defaultModel !== undefined ? { type: "subagents.defaultModel", scope: "user", path: userSettingsPath, model: userSettings.defaultModel } : undefined;
897
+ return userSettings.defaultModel !== undefined ? { type: "subagents.defaultModel", scope: "user", path: userSettingsPath, model: userSettings.defaultModel, ...defaultProvider ? { defaultProvider } : {} } : undefined;
898
+ }
899
+ function applySubagentDefaultModel(agents, defaultModel, defaultProvider) {
900
+ if (!defaultModel && !defaultProvider)
901
+ return agents;
902
+ return agents.map((agent) => {
903
+ if (agent.model !== undefined && (agent.modelProvider !== undefined || !defaultProvider))
904
+ return agent;
905
+ const next = {
906
+ ...agent,
907
+ ...agent.model === undefined && defaultModel ? { model: defaultModel.model, modelSource: defaultModel } : {},
908
+ ...defaultProvider ? { modelProvider: defaultProvider } : {}
909
+ };
910
+ const frontmatterFields = agentFrontmatterFields.get(agent);
911
+ if (frontmatterFields)
912
+ agentFrontmatterFields.set(next, frontmatterFields);
913
+ return next;
914
+ });
915
+ }
916
+ function resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath) {
917
+ if (projectSettingsPath && projectSettings.defaultThinking !== undefined)
918
+ return projectSettings.defaultThinking;
919
+ return userSettings.defaultThinking;
546
920
  }
547
- function applySubagentDefaultModel(agents, defaultModel) {
548
- if (!defaultModel)
921
+ function applySubagentDefaultThinking(agents, defaultThinking) {
922
+ if (defaultThinking === undefined)
549
923
  return agents;
550
924
  return agents.map((agent) => {
551
- if (agent.model !== undefined)
925
+ if (agent.thinking !== undefined)
552
926
  return agent;
553
- const next = { ...agent, model: defaultModel.model, modelSource: defaultModel };
927
+ const next = { ...agent, thinking: defaultThinking };
554
928
  const frontmatterFields = agentFrontmatterFields.get(agent);
555
929
  if (frontmatterFields)
556
930
  agentFrontmatterFields.set(next, frontmatterFields);
557
931
  return next;
558
932
  });
559
933
  }
934
+ function resolveSubagentMaxThinking(userSettings, projectSettings, projectSettingsPath) {
935
+ if (projectSettingsPath && projectSettings.maxThinking !== undefined)
936
+ return projectSettings.maxThinking;
937
+ return userSettings.maxThinking;
938
+ }
939
+ function applySubagentMaxThinking(agents, maxThinking) {
940
+ if (maxThinking === undefined)
941
+ return agents;
942
+ return agents.map((agent) => agent.maxThinking === maxThinking ? agent : { ...agent, maxThinking });
943
+ }
944
+ function resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath) {
945
+ if (projectSettingsPath && projectSettings.defaultExtensions !== undefined)
946
+ return projectSettings.defaultExtensions;
947
+ return userSettings.defaultExtensions;
948
+ }
949
+ function applySubagentDefaultExtensions(agents, defaultExtensions) {
950
+ if (defaultExtensions === undefined)
951
+ return agents;
952
+ return agents.map((agent) => {
953
+ if (agent.extensions !== undefined)
954
+ return agent;
955
+ const next = { ...agent, extensions: [...defaultExtensions], extensionsFromDefault: true };
956
+ const frontmatterFields = agentFrontmatterFields.get(agent);
957
+ if (frontmatterFields)
958
+ agentFrontmatterFields.set(next, frontmatterFields);
959
+ return next;
960
+ });
961
+ }
962
+ function applySubagentDefaults(agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions) {
963
+ return applySubagentDefaultExtensions(applySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel, defaultProvider), defaultThinking), defaultExtensions);
964
+ }
965
+ function applyToolsOverride(target, toolsOverride) {
966
+ if (toolsOverride === "inherit") {
967
+ delete target.tools;
968
+ delete target.mcpDirectTools;
969
+ return;
970
+ }
971
+ const { tools, mcpDirectTools } = splitToolList(toolsOverride === false ? [] : toolsOverride);
972
+ if (tools === undefined)
973
+ delete target.tools;
974
+ else
975
+ target.tools = tools;
976
+ if (mcpDirectTools === undefined)
977
+ delete target.mcpDirectTools;
978
+ else
979
+ target.mcpDirectTools = mcpDirectTools;
980
+ }
560
981
  function applyBuiltinOverride(agent, override, meta) {
561
982
  const next = {
562
983
  ...agent,
563
984
  override: { ...meta, base: cloneOverrideBase(agent) }
564
985
  };
565
- if (override.model !== undefined)
566
- next.model = override.model === false ? undefined : override.model;
986
+ if (override.description !== undefined)
987
+ next.description = override.description;
988
+ if (override.output !== undefined) {
989
+ if (override.output === false)
990
+ delete next.output;
991
+ else
992
+ next.output = override.output;
993
+ }
994
+ if (override.outputMode !== undefined)
995
+ next.outputMode = override.outputMode;
996
+ if (override.defaultReads !== undefined) {
997
+ if (override.defaultReads === false)
998
+ delete next.defaultReads;
999
+ else
1000
+ next.defaultReads = [...override.defaultReads];
1001
+ }
1002
+ if (override.model !== undefined) {
1003
+ if (override.model === false)
1004
+ delete next.model;
1005
+ else
1006
+ next.model = override.model;
1007
+ delete next.modelSource;
1008
+ }
1009
+ if (override.defaultProvider !== undefined) {
1010
+ if (override.defaultProvider === false)
1011
+ delete next.modelProvider;
1012
+ else
1013
+ next.modelProvider = override.defaultProvider;
1014
+ }
567
1015
  if (override.fallbackModels !== undefined) {
568
- next.fallbackModels = override.fallbackModels === false ? undefined : [...override.fallbackModels];
1016
+ if (override.fallbackModels === false)
1017
+ delete next.fallbackModels;
1018
+ else
1019
+ next.fallbackModels = [...override.fallbackModels];
1020
+ }
1021
+ if (override.fast !== undefined)
1022
+ next.fast = override.fast;
1023
+ if (override.thinking !== undefined) {
1024
+ if (override.thinking === false)
1025
+ delete next.thinking;
1026
+ else
1027
+ next.thinking = override.thinking;
569
1028
  }
570
- if (override.thinking !== undefined)
571
- next.thinking = override.thinking === false ? undefined : override.thinking;
572
1029
  if (override.systemPromptMode !== undefined)
573
1030
  next.systemPromptMode = override.systemPromptMode;
574
1031
  if (override.inheritProjectContext !== undefined)
575
1032
  next.inheritProjectContext = override.inheritProjectContext;
1033
+ if (override.inheritGlobalContext !== undefined)
1034
+ next.inheritGlobalContext = override.inheritGlobalContext;
576
1035
  if (override.inheritSkills !== undefined)
577
1036
  next.inheritSkills = override.inheritSkills;
578
- if (override.defaultContext !== undefined)
579
- next.defaultContext = override.defaultContext === false ? undefined : override.defaultContext;
1037
+ if (override.defaultContext !== undefined) {
1038
+ if (override.defaultContext === false)
1039
+ delete next.defaultContext;
1040
+ else
1041
+ next.defaultContext = override.defaultContext;
1042
+ }
1043
+ if (override.acceptanceRole !== undefined) {
1044
+ if (override.acceptanceRole === false)
1045
+ delete next.acceptanceRole;
1046
+ else
1047
+ next.acceptanceRole = override.acceptanceRole;
1048
+ }
580
1049
  if (override.disabled !== undefined)
581
1050
  next.disabled = override.disabled;
582
1051
  if (override.systemPrompt !== undefined)
583
1052
  next.systemPrompt = override.systemPrompt;
584
- if (override.skills !== undefined)
585
- next.skills = override.skills === false ? undefined : [...override.skills];
586
- if (override.tools !== undefined) {
587
- const { tools, mcpDirectTools } = splitToolList(override.tools === false ? [] : override.tools);
588
- next.tools = tools;
589
- next.mcpDirectTools = mcpDirectTools;
1053
+ if (override.skills !== undefined) {
1054
+ if (override.skills === false)
1055
+ delete next.skills;
1056
+ else
1057
+ next.skills = [...override.skills];
1058
+ }
1059
+ if (override.tools !== undefined)
1060
+ applyToolsOverride(next, override.tools);
1061
+ if (override.allowNestedSubagents !== undefined)
1062
+ next.allowNestedSubagents = override.allowNestedSubagents;
1063
+ if (override.extensions !== undefined) {
1064
+ if (override.extensions === false)
1065
+ delete next.extensions;
1066
+ else
1067
+ next.extensions = [...override.extensions];
590
1068
  }
591
1069
  if (override.subagentOnlyExtensions !== undefined) {
592
- next.subagentOnlyExtensions = override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions];
1070
+ if (override.subagentOnlyExtensions === false)
1071
+ delete next.subagentOnlyExtensions;
1072
+ else
1073
+ next.subagentOnlyExtensions = [...override.subagentOnlyExtensions];
1074
+ }
1075
+ if (override.mutationTools !== undefined) {
1076
+ if (override.mutationTools === false)
1077
+ delete next.mutationTools;
1078
+ else
1079
+ next.mutationTools = [...override.mutationTools];
593
1080
  }
594
1081
  if (override.completionGuard !== undefined)
595
1082
  next.completionGuard = override.completionGuard;
596
- if (override.toolBudget !== undefined)
597
- next.toolBudget = override.toolBudget === false ? undefined : override.toolBudget;
1083
+ if (override.toolBudget !== undefined) {
1084
+ if (override.toolBudget === false)
1085
+ delete next.toolBudget;
1086
+ else
1087
+ next.toolBudget = override.toolBudget;
1088
+ }
598
1089
  return next;
599
1090
  }
600
1091
  function clearBuiltinThinking(agent, meta) {
601
1092
  if (agent.thinking === undefined)
602
1093
  return agent;
603
- return {
604
- ...agent,
605
- thinking: undefined,
606
- override: agent.override ?? { ...meta, base: cloneOverrideBase(agent) }
607
- };
1094
+ const { thinking: _thinking, ...next } = agent;
1095
+ return { ...next, override: agent.override ?? { ...meta, base: cloneOverrideBase(agent) } };
608
1096
  }
609
1097
  function applyBuiltinOverrides(builtinAgents, userSettings, projectSettings, userSettingsPath, projectSettingsPath) {
610
1098
  const projectBulkDisabled = projectSettings.disableBuiltins === true && projectSettingsPath !== null;
@@ -635,7 +1123,7 @@ function applyBuiltinOverrides(builtinAgents, userSettings, projectSettings, use
635
1123
  return applyGlobalThinking(agent, false);
636
1124
  });
637
1125
  }
638
- function customAgentHasFrontmatterField(agent, ...fields) {
1126
+ export function agentHasFrontmatterField(agent, ...fields) {
639
1127
  const frontmatterFields = agentFrontmatterFields.get(agent);
640
1128
  return frontmatterFields ? fields.some((field) => frontmatterFields.has(field)) : false;
641
1129
  }
@@ -647,17 +1135,46 @@ function applyCustomAgentOverride(agent, override, meta) {
647
1135
  return next;
648
1136
  };
649
1137
  const fill = (field, frontmatterFields, value) => {
650
- if (customAgentHasFrontmatterField(agent, ...frontmatterFields))
1138
+ if (agentHasFrontmatterField(agent, ...frontmatterFields))
651
1139
  return;
652
- mutable()[field] = value;
1140
+ const target = mutable();
1141
+ if (value === undefined)
1142
+ delete target[field];
1143
+ else
1144
+ target[field] = value;
653
1145
  anyFilled = true;
654
1146
  };
655
- if (override.model !== undefined) {
656
- fill("model", ["model"], override.model === false ? undefined : override.model);
1147
+ if (override.description !== undefined) {
1148
+ mutable().description = override.description;
1149
+ anyFilled = true;
1150
+ }
1151
+ if (override.output !== undefined) {
1152
+ fill("output", ["output"], override.output === false ? undefined : override.output);
1153
+ }
1154
+ if (override.outputMode !== undefined) {
1155
+ fill("outputMode", ["outputMode"], override.outputMode);
1156
+ }
1157
+ if (override.defaultReads !== undefined) {
1158
+ fill("defaultReads", ["defaultReads"], override.defaultReads === false ? undefined : [...override.defaultReads]);
1159
+ }
1160
+ if (override.model !== undefined && !agentHasFrontmatterField(agent, "model")) {
1161
+ const target = mutable();
1162
+ if (override.model === false)
1163
+ delete target.model;
1164
+ else
1165
+ target.model = override.model;
1166
+ delete target.modelSource;
1167
+ anyFilled = true;
1168
+ }
1169
+ if (override.defaultProvider !== undefined) {
1170
+ fill("modelProvider", ["modelProvider", "defaultProvider"], override.defaultProvider === false ? undefined : override.defaultProvider);
657
1171
  }
658
1172
  if (override.fallbackModels !== undefined) {
659
1173
  fill("fallbackModels", ["fallbackModels"], override.fallbackModels === false ? undefined : [...override.fallbackModels]);
660
1174
  }
1175
+ if (override.fast !== undefined) {
1176
+ fill("fast", ["fast"], override.fast);
1177
+ }
661
1178
  if (override.thinking !== undefined) {
662
1179
  fill("thinking", ["thinking"], override.thinking === false ? undefined : override.thinking);
663
1180
  }
@@ -667,29 +1184,41 @@ function applyCustomAgentOverride(agent, override, meta) {
667
1184
  if (override.inheritProjectContext !== undefined) {
668
1185
  fill("inheritProjectContext", ["inheritProjectContext"], override.inheritProjectContext);
669
1186
  }
1187
+ if (override.inheritGlobalContext !== undefined) {
1188
+ fill("inheritGlobalContext", ["inheritGlobalContext"], override.inheritGlobalContext);
1189
+ }
670
1190
  if (override.inheritSkills !== undefined) {
671
1191
  fill("inheritSkills", ["inheritSkills"], override.inheritSkills);
672
1192
  }
673
1193
  if (override.defaultContext !== undefined) {
674
1194
  fill("defaultContext", ["defaultContext"], override.defaultContext === false ? undefined : override.defaultContext);
675
1195
  }
676
- if (override.disabled !== undefined && agent.disabled === undefined) {
1196
+ if (override.acceptanceRole !== undefined) {
1197
+ fill("acceptanceRole", ["acceptanceRole"], override.acceptanceRole === false ? undefined : override.acceptanceRole);
1198
+ }
1199
+ if (override.disabled !== undefined) {
677
1200
  mutable().disabled = override.disabled;
678
1201
  anyFilled = true;
679
1202
  }
680
1203
  if (override.skills !== undefined) {
681
1204
  fill("skills", ["skill", "skills"], override.skills === false ? undefined : [...override.skills]);
682
1205
  }
683
- if (override.tools !== undefined && !customAgentHasFrontmatterField(agent, "tools")) {
684
- const { tools, mcpDirectTools } = splitToolList(override.tools === false ? [] : override.tools);
685
- const target = mutable();
686
- target.tools = tools;
687
- target.mcpDirectTools = mcpDirectTools;
1206
+ if (override.tools !== undefined && !agentHasFrontmatterField(agent, "tools")) {
1207
+ applyToolsOverride(mutable(), override.tools);
688
1208
  anyFilled = true;
689
1209
  }
1210
+ if (override.allowNestedSubagents !== undefined) {
1211
+ fill("allowNestedSubagents", ["allowNestedSubagents"], override.allowNestedSubagents);
1212
+ }
1213
+ if (override.extensions !== undefined) {
1214
+ fill("extensions", ["extensions"], override.extensions === false ? undefined : [...override.extensions]);
1215
+ }
690
1216
  if (override.subagentOnlyExtensions !== undefined) {
691
1217
  fill("subagentOnlyExtensions", ["subagentOnlyExtensions"], override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions]);
692
1218
  }
1219
+ if (override.mutationTools !== undefined) {
1220
+ fill("mutationTools", ["mutationTools"], override.mutationTools === false ? undefined : [...override.mutationTools]);
1221
+ }
693
1222
  if (override.completionGuard !== undefined) {
694
1223
  fill("completionGuard", ["completionGuard"], override.completionGuard);
695
1224
  }
@@ -698,38 +1227,58 @@ function applyCustomAgentOverride(agent, override, meta) {
698
1227
  }
699
1228
  if (!anyFilled || !next)
700
1229
  return agent;
701
- next.override = { ...meta, base: cloneOverrideBase(agent) };
1230
+ next.override = { ...meta, base: agent.override?.base ?? cloneOverrideBase(agent) };
1231
+ const frontmatterFields = agentFrontmatterFields.get(agent);
1232
+ if (frontmatterFields)
1233
+ agentFrontmatterFields.set(next, frontmatterFields);
702
1234
  return next;
703
1235
  }
704
1236
  function applyCustomAgentOverrides(agents, userSettings, projectSettings, userSettingsPath, projectSettingsPath) {
705
1237
  return agents.map((agent) => {
1238
+ const userOverride = userSettings.overrides[agent.name];
1239
+ const withUserOverride = userOverride ? applyCustomAgentOverride(agent, userOverride, { scope: "user", path: userSettingsPath }) : agent;
706
1240
  const projectOverride = projectSettings.overrides[agent.name];
707
1241
  if (projectOverride && projectSettingsPath) {
708
- return applyCustomAgentOverride(agent, projectOverride, { scope: "project", path: projectSettingsPath });
1242
+ return applyCustomAgentOverride(withUserOverride, projectOverride, { scope: "project", path: projectSettingsPath });
709
1243
  }
710
- const userOverride = userSettings.overrides[agent.name];
711
- if (userOverride) {
712
- return applyCustomAgentOverride(agent, userOverride, { scope: "user", path: userSettingsPath });
713
- }
714
- return agent;
1244
+ return withUserOverride;
715
1245
  });
716
1246
  }
717
1247
  export function buildBuiltinOverrideConfig(base, draft) {
718
1248
  const override = {};
1249
+ if (draft.description !== undefined) {
1250
+ const description = draft.description.trim();
1251
+ if (description && description !== base.description)
1252
+ override.description = description;
1253
+ }
1254
+ if (draft.output !== base.output)
1255
+ override.output = draft.output ?? false;
1256
+ if (draft.outputMode !== undefined && draft.outputMode !== base.outputMode)
1257
+ override.outputMode = draft.outputMode;
1258
+ if (!arraysEqual(draft.defaultReads, base.defaultReads))
1259
+ override.defaultReads = draft.defaultReads ? [...draft.defaultReads] : false;
719
1260
  if (draft.model !== base.model)
720
1261
  override.model = draft.model ?? false;
1262
+ if (draft.modelProvider !== base.modelProvider)
1263
+ override.defaultProvider = draft.modelProvider ?? false;
721
1264
  if (!arraysEqual(draft.fallbackModels, base.fallbackModels))
722
1265
  override.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;
1266
+ if (draft.fast !== base.fast)
1267
+ override.fast = draft.fast === true;
723
1268
  if (draft.thinking !== base.thinking)
724
1269
  override.thinking = draft.thinking ?? false;
725
1270
  if (draft.systemPromptMode !== base.systemPromptMode)
726
1271
  override.systemPromptMode = draft.systemPromptMode;
727
1272
  if (draft.inheritProjectContext !== base.inheritProjectContext)
728
1273
  override.inheritProjectContext = draft.inheritProjectContext;
1274
+ if (draft.inheritGlobalContext !== base.inheritGlobalContext)
1275
+ override.inheritGlobalContext = draft.inheritGlobalContext;
729
1276
  if (draft.inheritSkills !== base.inheritSkills)
730
1277
  override.inheritSkills = draft.inheritSkills;
731
1278
  if (draft.defaultContext !== base.defaultContext)
732
1279
  override.defaultContext = draft.defaultContext ?? false;
1280
+ if (draft.acceptanceRole !== base.acceptanceRole)
1281
+ override.acceptanceRole = draft.acceptanceRole ?? false;
733
1282
  if (draft.disabled !== base.disabled)
734
1283
  override.disabled = draft.disabled ?? false;
735
1284
  if (draft.systemPrompt !== base.systemPrompt)
@@ -740,9 +1289,15 @@ export function buildBuiltinOverrideConfig(base, draft) {
740
1289
  const draftTools = joinToolList(draft);
741
1290
  if (!arraysEqual(draftTools, baseTools))
742
1291
  override.tools = draftTools ? [...draftTools] : false;
1292
+ if (draft.allowNestedSubagents !== base.allowNestedSubagents)
1293
+ override.allowNestedSubagents = draft.allowNestedSubagents === true;
1294
+ if (!arraysEqual(draft.extensions, base.extensions))
1295
+ override.extensions = draft.extensions ? [...draft.extensions] : false;
743
1296
  if (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {
744
1297
  override.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;
745
1298
  }
1299
+ if (!arraysEqual(draft.mutationTools, base.mutationTools))
1300
+ override.mutationTools = draft.mutationTools ? [...draft.mutationTools] : false;
746
1301
  if (draft.completionGuard !== false !== (base.completionGuard !== false)) {
747
1302
  override.completionGuard = draft.completionGuard !== false;
748
1303
  }
@@ -851,10 +1406,31 @@ export function removeBuiltinAgentOverrideFields(cwd, name, scope, fields) {
851
1406
  writeSettingsFile(filePath, settings);
852
1407
  return { path: filePath, removed: true };
853
1408
  }
854
- function listFilesRecursive(dir, predicate) {
1409
+ const DISCOVERY_PRUNED_DIR_NAMES = new Set([".git", "node_modules", ".dm", "sync-backups"]);
1410
+ function isDiscoveryNestedProjectRoot(dir) {
1411
+ return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
1412
+ }
1413
+ function shouldPruneDiscoveryDir(rootDir, dir, dirName) {
1414
+ if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName))
1415
+ return true;
1416
+ if (fs.existsSync(path.join(dir, ".git")))
1417
+ return true;
1418
+ return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);
1419
+ }
1420
+ function listFilesRecursive(dir, predicate, rootDir = dir, visitedDirectories = new Set, inspectedDirectories = new Set) {
855
1421
  const files = [];
856
1422
  if (!fs.existsSync(dir))
857
1423
  return files;
1424
+ inspectedDirectories.add(path.resolve(dir));
1425
+ let realDir;
1426
+ try {
1427
+ realDir = fs.realpathSync(dir);
1428
+ } catch {
1429
+ return files;
1430
+ }
1431
+ if (visitedDirectories.has(realDir))
1432
+ return files;
1433
+ visitedDirectories.add(realDir);
858
1434
  let entries;
859
1435
  try {
860
1436
  entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
@@ -863,8 +1439,18 @@ function listFilesRecursive(dir, predicate) {
863
1439
  }
864
1440
  for (const entry of entries) {
865
1441
  const filePath = path.join(dir, entry.name);
866
- if (entry.isDirectory()) {
867
- files.push(...listFilesRecursive(filePath, predicate));
1442
+ let isDirectory = entry.isDirectory();
1443
+ if (entry.isSymbolicLink()) {
1444
+ try {
1445
+ isDirectory = fs.statSync(filePath).isDirectory();
1446
+ } catch {
1447
+ isDirectory = false;
1448
+ }
1449
+ }
1450
+ if (isDirectory) {
1451
+ if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {
1452
+ files.push(...listFilesRecursive(filePath, predicate, rootDir, visitedDirectories, inspectedDirectories));
1453
+ }
868
1454
  continue;
869
1455
  }
870
1456
  if (!entry.isFile() && !entry.isSymbolicLink())
@@ -875,6 +1461,75 @@ function listFilesRecursive(dir, predicate) {
875
1461
  }
876
1462
  return files;
877
1463
  }
1464
+ const agentDefinitionInspectionDirectories = new WeakMap;
1465
+ function rememberAgentDefinitionInspection(inspection, directories) {
1466
+ agentDefinitionInspectionDirectories.set(inspection, [...new Set([...directories].map((directory) => path.resolve(directory)))]);
1467
+ return inspection;
1468
+ }
1469
+ function inspectedAgentDefinitionDirectories(inspection, root) {
1470
+ return agentDefinitionInspectionDirectories.get(inspection) ?? [path.resolve(root)];
1471
+ }
1472
+ const DEFAULT_AGENT_DEFINITION_INSPECTION_FS = {
1473
+ existsSync: fs.existsSync,
1474
+ realpathSync: fs.realpathSync,
1475
+ statSync: fs.statSync,
1476
+ readdirSync: (dir) => fs.readdirSync(dir, { withFileTypes: true })
1477
+ };
1478
+ export function inspectAgentDefinitionDirectory(dir, operations = DEFAULT_AGENT_DEFINITION_INSPECTION_FS) {
1479
+ const root = path.resolve(dir);
1480
+ try {
1481
+ if (!operations.existsSync(root))
1482
+ return rememberAgentDefinitionInspection({ files: [], state: "absent" }, [root]);
1483
+ if (!operations.statSync(root).isDirectory())
1484
+ return rememberAgentDefinitionInspection({ files: [], state: "not-directory" }, [root]);
1485
+ } catch {
1486
+ return rememberAgentDefinitionInspection({ files: [], state: "unreadable" }, [root]);
1487
+ }
1488
+ const files = [];
1489
+ let unreadable = false;
1490
+ const visitedDirectories = new Set;
1491
+ const inspectedDirectories = new Set;
1492
+ const visit = (current) => {
1493
+ inspectedDirectories.add(path.resolve(current));
1494
+ let realDir;
1495
+ try {
1496
+ realDir = operations.realpathSync?.(current) ?? path.resolve(current);
1497
+ } catch {
1498
+ unreadable = true;
1499
+ return;
1500
+ }
1501
+ if (visitedDirectories.has(realDir))
1502
+ return;
1503
+ visitedDirectories.add(realDir);
1504
+ let entries;
1505
+ try {
1506
+ entries = operations.readdirSync(current).sort((a, b) => a.name.localeCompare(b.name));
1507
+ } catch {
1508
+ unreadable = true;
1509
+ return;
1510
+ }
1511
+ for (const entry of entries) {
1512
+ const filePath = path.join(current, entry.name);
1513
+ let isDirectory = entry.isDirectory();
1514
+ if (entry.isSymbolicLink()) {
1515
+ try {
1516
+ isDirectory = operations.statSync(filePath).isDirectory();
1517
+ } catch {
1518
+ isDirectory = false;
1519
+ }
1520
+ }
1521
+ if (isDirectory) {
1522
+ if (!shouldPruneDiscoveryDir(root, filePath, entry.name))
1523
+ visit(filePath);
1524
+ continue;
1525
+ }
1526
+ if ((entry.isFile() || entry.isSymbolicLink()) && entry.name.endsWith(".md") && !entry.name.endsWith(".chain.md") && !isLegacyAgentSkillPath(root, filePath))
1527
+ files.push(filePath);
1528
+ }
1529
+ };
1530
+ visit(root);
1531
+ return rememberAgentDefinitionInspection({ files, state: unreadable ? "unreadable" : files.length ? "candidates" : "empty" }, inspectedDirectories);
1532
+ }
878
1533
  function isLegacyAgentSkillPath(rootDir, filePath) {
879
1534
  const relative = path.relative(rootDir, filePath);
880
1535
  const parts = relative.split(path.sep).map((part) => part.toLowerCase());
@@ -883,110 +1538,327 @@ function isLegacyAgentSkillPath(rootDir, filePath) {
883
1538
  }
884
1539
  return parts.some((part, index) => part === ".agents" && parts[index + 1] === "skills");
885
1540
  }
886
- function loadAgentsFromDir(dir, source) {
887
- const agents = [];
888
- for (const filePath of listFilesRecursive(dir, (fileName) => fileName.endsWith(".md") && !fileName.endsWith(".chain.md"))) {
1541
+ function isJsonSerializable(value) {
1542
+ if (value === null || typeof value === "string" || typeof value === "boolean")
1543
+ return true;
1544
+ if (typeof value === "number")
1545
+ return Number.isFinite(value);
1546
+ if (Array.isArray(value))
1547
+ return value.every(isJsonSerializable);
1548
+ if (value && typeof value === "object")
1549
+ return Object.values(value).every(isJsonSerializable);
1550
+ return false;
1551
+ }
1552
+ function parseAgentRunnerFrontmatter(raw, agentName) {
1553
+ if (raw === undefined || !raw.trim())
1554
+ return;
1555
+ let parsed;
1556
+ try {
1557
+ parsed = parseYaml(raw);
1558
+ } catch (error) {
1559
+ throw new Error(`Agent '${agentName}' has invalid runner frontmatter: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
1560
+ }
1561
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1562
+ throw new Error(`Agent '${agentName}' has invalid runner frontmatter; expected an object.`);
1563
+ }
1564
+ const runner = parsed;
1565
+ if (runner.type === "dm") {
1566
+ if (Object.keys(runner).some((key) => key !== "type"))
1567
+ throw new Error(`Agent '${agentName}' has invalid DM runner frontmatter; only 'type' is supported.`);
1568
+ return { type: "dm" };
1569
+ }
1570
+ if (runner.type === "external-job") {
1571
+ if (typeof runner.provider !== "string" || !runner.provider.trim() || runner.provider.trim() !== runner.provider) {
1572
+ throw new Error(`Agent '${agentName}' external-job runner requires a non-empty trimmed provider string.`);
1573
+ }
1574
+ if (runner.options !== undefined && (!runner.options || typeof runner.options !== "object" || Array.isArray(runner.options) || !isJsonSerializable(runner.options))) {
1575
+ throw new Error(`Agent '${agentName}' external-job runner options must be a JSON-serializable object.`);
1576
+ }
1577
+ const supported = new Set(["type", "provider", "options"]);
1578
+ const unknown = Object.keys(runner).filter((key) => !supported.has(key));
1579
+ if (unknown.length > 0)
1580
+ throw new Error(`Agent '${agentName}' external-job runner has unsupported fields: ${unknown.join(", ")}.`);
1581
+ return {
1582
+ type: "external-job",
1583
+ provider: runner.provider,
1584
+ ...runner.options ? { options: runner.options } : {}
1585
+ };
1586
+ }
1587
+ if (runner.type !== "external-cli") {
1588
+ throw new Error(`Agent '${agentName}' has invalid runner.type; expected 'dm', 'external-cli', or 'external-job'.`);
1589
+ }
1590
+ if (typeof runner.command !== "string" || !runner.command.trim()) {
1591
+ throw new Error(`Agent '${agentName}' external-cli runner requires a non-empty command string.`);
1592
+ }
1593
+ if (runner.args !== undefined && (!Array.isArray(runner.args) || runner.args.some((arg) => typeof arg !== "string"))) {
1594
+ throw new Error(`Agent '${agentName}' external-cli runner args must be an array of strings.`);
1595
+ }
1596
+ if (runner.adapter !== undefined && !isCodeOwnedExternalCliAdapterId(runner.adapter))
1597
+ throw new Error(`Agent '${agentName}' external-cli runner adapter must be ${CODE_OWNED_EXTERNAL_CLI_ADAPTER_LABEL}.`);
1598
+ if (runner.adapter !== undefined && Array.isArray(runner.args) && runner.args.length > 0)
1599
+ throw new Error(`Agent '${agentName}' ${runner.adapter} adapter owns its argv; runner args are not supported.`);
1600
+ if (runner.promptDelivery !== undefined && runner.promptDelivery !== "stdin") {
1601
+ throw new Error(`Agent '${agentName}' external-cli runner promptDelivery must be 'stdin'.`);
1602
+ }
1603
+ const capabilities = parseExternalCliCapabilityNarrowing(runner.capabilities, `Agent '${agentName}' external-cli runner capabilities`);
1604
+ const supported = new Set(["type", "adapter", "command", "args", "promptDelivery", "capabilities"]);
1605
+ const unknown = Object.keys(runner).filter((key) => !supported.has(key));
1606
+ if (unknown.length > 0)
1607
+ throw new Error(`Agent '${agentName}' external-cli runner has unsupported fields: ${unknown.join(", ")}.`);
1608
+ const runnerArgs = Array.isArray(runner.args) ? runner.args.filter((arg) => typeof arg === "string") : undefined;
1609
+ return {
1610
+ type: "external-cli",
1611
+ ...isCodeOwnedExternalCliAdapterId(runner.adapter) ? { adapter: runner.adapter } : {},
1612
+ command: runner.command.trim(),
1613
+ ...runnerArgs?.length ? { args: runnerArgs } : {},
1614
+ ...runner.promptDelivery ? { promptDelivery: "stdin" } : {},
1615
+ ...capabilities ? { capabilities } : {}
1616
+ };
1617
+ }
1618
+ function validateExternalRunnerProfile(frontmatter, agentName, runner) {
1619
+ if (runner?.type !== "external-cli" && runner?.type !== "external-job")
1620
+ return;
1621
+ const unsupported = ["tools", "allowNestedSubagents", "model", "fallbackModels", "thinking", "extensions", "subagentOnlyExtensions", "mutationTools", "maxSubagentDepth", "completionGuard", "skills", "skill", "skillPath", "toolBudget", "permission", "permissions"].filter((field) => frontmatter[field] !== undefined);
1622
+ if (unsupported.length > 0) {
1623
+ throw new Error(`Agent '${agentName}' uses runner.type='${runner.type}' and declares unsupported DM-only fields: ${unsupported.join(", ")}.`);
1624
+ }
1625
+ }
1626
+ function parseAgentAcceptanceFrontmatter(raw, agentName) {
1627
+ if (raw === undefined || !raw.trim())
1628
+ return;
1629
+ let parsed;
1630
+ try {
1631
+ parsed = parseYaml(raw);
1632
+ } catch (error) {
1633
+ throw new Error(`Agent '${agentName}' has invalid acceptance frontmatter: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
1634
+ }
1635
+ const errors = validateAcceptanceInput(parsed, `Agent '${agentName}' acceptance frontmatter`);
1636
+ if (errors.length > 0)
1637
+ throw new Error(errors.join(" "));
1638
+ return parsed;
1639
+ }
1640
+ function readAgentDefinitionFiles(dir, inspection = inspectAgentDefinitionDirectory(dir)) {
1641
+ const files = [];
1642
+ for (const filePath of inspection.files) {
889
1643
  if (isLegacyAgentSkillPath(dir, filePath)) {
890
1644
  continue;
891
1645
  }
892
- let content;
893
1646
  try {
894
- content = fs.readFileSync(filePath, "utf-8");
1647
+ files.push({ filePath, content: fs.readFileSync(filePath, "utf-8") });
895
1648
  } catch {
896
1649
  continue;
897
1650
  }
898
- const { frontmatter, body } = parseFrontmatter(content);
899
- if (!frontmatter.name || !frontmatter.description) {
900
- continue;
1651
+ }
1652
+ return files;
1653
+ }
1654
+ function resolveAgentRelativeExtensionPaths(paths, agentFilePath) {
1655
+ if (paths === undefined)
1656
+ return;
1657
+ const baseDir = path.dirname(agentFilePath);
1658
+ return paths.map((entry) => {
1659
+ const trimmed = entry.trim();
1660
+ if (trimmed === "." || trimmed === ".." || trimmed.startsWith("./") || trimmed.startsWith("../")) {
1661
+ return path.resolve(baseDir, trimmed);
901
1662
  }
902
- const localName = frontmatter.name;
903
- const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);
904
- if (parsedPackage.error)
905
- continue;
906
- const packageName = parsedPackage.packageName;
907
- const runtimeName = buildRuntimeName(localName, packageName);
908
- const rawTools = frontmatter.tools?.split(",").map((t) => t.trim()).filter(Boolean);
909
- const mcpDirectTools = [];
910
- const tools = [];
911
- if (rawTools) {
912
- for (const tool of rawTools) {
913
- if (tool.startsWith("mcp:")) {
914
- mcpDirectTools.push(tool.slice(4));
915
- } else {
916
- tools.push(tool);
1663
+ return entry;
1664
+ });
1665
+ }
1666
+ function loadAgentsFromDefinitionFiles(files, source, discoveryPriority, packageSource) {
1667
+ const agents = [];
1668
+ const diagnostics = [];
1669
+ for (const { filePath, content } of files) {
1670
+ let name;
1671
+ let runtimeName;
1672
+ let packageSpecified = false;
1673
+ try {
1674
+ const { frontmatter, body } = parseFrontmatter(content);
1675
+ if (!frontmatter.name || !frontmatter.description) {
1676
+ continue;
1677
+ }
1678
+ const localName = frontmatter.name;
1679
+ name = localName;
1680
+ const parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);
1681
+ packageSpecified = parsedPackage.packageName !== undefined || parsedPackage.error !== undefined;
1682
+ if (parsedPackage.error)
1683
+ throw new Error(parsedPackage.error);
1684
+ const packageName = parsedPackage.packageName;
1685
+ runtimeName = buildRuntimeName(localName, packageName);
1686
+ const runner = parseAgentRunnerFrontmatter(frontmatter.runner, localName);
1687
+ validateExternalRunnerProfile(frontmatter, localName, runner);
1688
+ const rawTools = parseFrontmatterList(frontmatter.tools);
1689
+ const parsedTools = splitToolList(rawTools);
1690
+ const tools = parsedTools.tools ?? [];
1691
+ const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
1692
+ const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
1693
+ const aliases = normalizeAgentAliases(parseFrontmatterList(frontmatter.aliases ?? frontmatter.alias), runtimeName);
1694
+ const profileError = validateCodeOwnedProfileRunner({ name: runtimeName, localName, aliases, runner });
1695
+ if (profileError)
1696
+ throw new Error(profileError);
1697
+ const skillStr = frontmatter.skill || frontmatter.skills;
1698
+ const skills = parseFrontmatterList(skillStr);
1699
+ const skillPath = parseFrontmatterList(frontmatter.skillPath);
1700
+ const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);
1701
+ const systemPromptMode = frontmatter.systemPromptMode === "replace" ? "replace" : frontmatter.systemPromptMode === "append" ? "append" : defaultSystemPromptMode(localName);
1702
+ const inheritProjectContext = frontmatter.inheritProjectContext === "true" ? true : frontmatter.inheritProjectContext === "false" ? false : defaultInheritProjectContext(localName);
1703
+ const inheritGlobalContext = frontmatter.inheritGlobalContext === "true";
1704
+ const inheritSkills = frontmatter.inheritSkills === "true" ? true : frontmatter.inheritSkills === "false" ? false : defaultInheritSkills();
1705
+ const defaultContext = frontmatter.defaultContext === "fork" ? "fork" : frontmatter.defaultContext === "fresh" ? "fresh" : undefined;
1706
+ let defaultAsync;
1707
+ if (frontmatter.async !== undefined) {
1708
+ if (frontmatter.async === "true")
1709
+ defaultAsync = true;
1710
+ else if (frontmatter.async === "false")
1711
+ defaultAsync = false;
1712
+ else
1713
+ throw new Error(`Agent '${localName}' has invalid async frontmatter; expected true or false.`);
1714
+ }
1715
+ let defaultTimeoutMs;
1716
+ if (frontmatter.timeoutMs !== undefined) {
1717
+ const parsed = Number(frontmatter.timeoutMs);
1718
+ if (!Number.isInteger(parsed) || parsed <= 0) {
1719
+ throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);
917
1720
  }
1721
+ defaultTimeoutMs = parsed;
918
1722
  }
919
- }
920
- const defaultReads = frontmatter.defaultReads?.split(",").map((f) => f.trim()).filter(Boolean);
921
- const skillStr = frontmatter.skill || frontmatter.skills;
922
- const skills = skillStr?.split(",").map((s) => s.trim()).filter(Boolean);
923
- const fallbackModels = frontmatter.fallbackModels?.split(",").map((model) => model.trim()).filter(Boolean);
924
- const systemPromptMode = frontmatter.systemPromptMode === "replace" ? "replace" : frontmatter.systemPromptMode === "append" ? "append" : defaultSystemPromptMode(localName);
925
- const inheritProjectContext = frontmatter.inheritProjectContext === "true" ? true : frontmatter.inheritProjectContext === "false" ? false : defaultInheritProjectContext(localName);
926
- const inheritSkills = frontmatter.inheritSkills === "true" ? true : frontmatter.inheritSkills === "false" ? false : defaultInheritSkills();
927
- const defaultContext = frontmatter.defaultContext === "fork" ? "fork" : frontmatter.defaultContext === "fresh" ? "fresh" : undefined;
928
- let extensions;
929
- if (frontmatter.extensions !== undefined) {
930
- extensions = frontmatter.extensions.split(",").map((e) => e.trim()).filter(Boolean);
931
- }
932
- let subagentOnlyExtensions;
933
- if (frontmatter.subagentOnlyExtensions !== undefined) {
934
- subagentOnlyExtensions = frontmatter.subagentOnlyExtensions.split(",").map((e) => e.trim()).filter(Boolean);
935
- }
936
- const extraFields = {};
937
- for (const [key, value] of Object.entries(frontmatter)) {
938
- if (!KNOWN_FIELDS.has(key))
939
- extraFields[key] = value;
940
- }
941
- const parsedMaxSubagentDepth = Number(frontmatter.maxSubagentDepth);
942
- let toolBudget;
943
- if (frontmatter.toolBudget !== undefined && frontmatter.toolBudget.trim()) {
944
- const parsed = JSON.parse(frontmatter.toolBudget);
945
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
946
- throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);
1723
+ let defaultToolTimeoutMs;
1724
+ if (frontmatter.toolTimeoutMs !== undefined) {
1725
+ const parsed = Number(frontmatter.toolTimeoutMs);
1726
+ if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 2147483647) {
1727
+ throw new Error(`Agent '${localName}' has invalid toolTimeoutMs frontmatter; expected a positive integer no larger than 2147483647.`);
1728
+ }
1729
+ defaultToolTimeoutMs = parsed;
1730
+ }
1731
+ const defaultAcceptance = parseAgentAcceptanceFrontmatter(frontmatter.acceptance, localName);
1732
+ let outputMode;
1733
+ if (frontmatter.outputMode !== undefined) {
1734
+ if (frontmatter.outputMode === "inline" || frontmatter.outputMode === "file-only")
1735
+ outputMode = frontmatter.outputMode;
1736
+ else
1737
+ throw new Error(`Agent '${localName}' has invalid outputMode frontmatter; expected 'inline' or 'file-only'.`);
947
1738
  }
948
- toolBudget = parsed;
1739
+ let acceptanceRole;
1740
+ if (frontmatter.acceptanceRole !== undefined && frontmatter.acceptanceRole.trim()) {
1741
+ if (frontmatter.acceptanceRole === "read-only" || frontmatter.acceptanceRole === "writer")
1742
+ acceptanceRole = frontmatter.acceptanceRole;
1743
+ else
1744
+ throw new Error(`Agent '${localName}' has invalid acceptanceRole frontmatter; expected 'read-only' or 'writer'.`);
1745
+ }
1746
+ const extensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.extensions), filePath);
1747
+ const subagentOnlyExtensions = resolveAgentRelativeExtensionPaths(parseFrontmatterList(frontmatter.subagentOnlyExtensions), filePath);
1748
+ const mutationTools = parseFrontmatterList(frontmatter.mutationTools);
1749
+ let fast;
1750
+ if (frontmatter.fast !== undefined) {
1751
+ if (frontmatter.fast === "true")
1752
+ fast = true;
1753
+ else if (frontmatter.fast === "false")
1754
+ fast = false;
1755
+ else
1756
+ throw new Error(`Agent '${localName}' has invalid fast frontmatter; expected true or false.`);
1757
+ }
1758
+ let allowNestedSubagents;
1759
+ if (frontmatter.allowNestedSubagents !== undefined) {
1760
+ if (frontmatter.allowNestedSubagents === "true")
1761
+ allowNestedSubagents = true;
1762
+ else if (frontmatter.allowNestedSubagents === "false")
1763
+ allowNestedSubagents = false;
1764
+ else
1765
+ throw new Error(`Agent '${localName}' has invalid allowNestedSubagents frontmatter; expected true or false.`);
1766
+ }
1767
+ const extraFields = {};
1768
+ for (const [key, value] of Object.entries(frontmatter)) {
1769
+ if (!KNOWN_FIELDS.has(key))
1770
+ extraFields[key] = value;
1771
+ }
1772
+ const parsedMaxSubagentDepth = Number(frontmatter.maxSubagentDepth);
1773
+ if (frontmatter.permission !== undefined && frontmatter.permissions !== undefined) {
1774
+ throw new Error(`Agent '${localName}' cannot declare both permission and permissions frontmatter.`);
1775
+ }
1776
+ const permissionSource = frontmatter.permissions ?? frontmatter.permission;
1777
+ const permissions = permissionSource?.trim() ? validatePermissionRules(parseYaml(permissionSource), `Agent '${localName}' permissions`) : undefined;
1778
+ let toolBudget;
1779
+ if (frontmatter.toolBudget !== undefined && frontmatter.toolBudget.trim()) {
1780
+ const parsed = JSON.parse(frontmatter.toolBudget);
1781
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1782
+ throw new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);
1783
+ }
1784
+ toolBudget = parsed;
1785
+ }
1786
+ const completionGuard = frontmatter.completionGuard === "false" ? false : frontmatter.completionGuard === "true" ? true : undefined;
1787
+ const maxSubagentDepth = Number.isInteger(parsedMaxSubagentDepth) && parsedMaxSubagentDepth >= 0 ? parsedMaxSubagentDepth : undefined;
1788
+ const memory = parseMemoryFrontmatter(frontmatter.memory);
1789
+ const agent = {
1790
+ name: runtimeName,
1791
+ ...runner !== undefined ? { runner } : {},
1792
+ localName,
1793
+ ...packageName !== undefined ? { packageName } : {},
1794
+ ...packageSource?.packageName ? { packageSourceName: packageSource.packageName } : {},
1795
+ ...packageSource?.packageVersion ? { packageSourceVersion: packageSource.packageVersion } : {},
1796
+ ...packageSource?.packageRoot ? { packageSourceRoot: packageSource.packageRoot } : {},
1797
+ description: frontmatter.description,
1798
+ ...aliases !== undefined ? { aliases } : {},
1799
+ ...rawTools !== undefined ? { tools } : {},
1800
+ ...allowNestedSubagents !== undefined ? { allowNestedSubagents } : {},
1801
+ ...mcpDirectTools.length > 0 ? { mcpDirectTools } : {},
1802
+ ...frontmatter.model !== undefined ? { model: frontmatter.model } : {},
1803
+ ...fallbackModels?.length ? { fallbackModels } : {},
1804
+ ...fast !== undefined ? { fast } : {},
1805
+ ...frontmatter.thinking !== undefined ? { thinking: frontmatter.thinking === "false" ? false : frontmatter.thinking } : {},
1806
+ systemPromptMode,
1807
+ inheritProjectContext,
1808
+ inheritGlobalContext,
1809
+ inheritSkills,
1810
+ ...defaultContext !== undefined ? { defaultContext } : {},
1811
+ ...defaultAsync !== undefined ? { defaultAsync } : {},
1812
+ ...defaultTimeoutMs !== undefined ? { defaultTimeoutMs } : {},
1813
+ ...defaultToolTimeoutMs !== undefined ? { defaultToolTimeoutMs } : {},
1814
+ ...defaultAcceptance !== undefined ? { defaultAcceptance } : {},
1815
+ ...acceptanceRole !== undefined ? { acceptanceRole } : {},
1816
+ systemPrompt: body,
1817
+ source,
1818
+ filePath,
1819
+ ...discoveryPriority !== undefined ? { discoveryPriority } : {},
1820
+ ...skills?.length ? { skills } : {},
1821
+ ...skillPath?.length ? { skillPath } : {},
1822
+ ...extensions !== undefined ? { extensions } : {},
1823
+ ...subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions } : {},
1824
+ ...mutationTools?.length ? { mutationTools } : {},
1825
+ ...frontmatter.output !== undefined ? { output: frontmatter.output } : {},
1826
+ ...outputMode !== undefined ? { outputMode } : {},
1827
+ ...defaultReads?.length ? { defaultReads } : {},
1828
+ defaultProgress: frontmatter.defaultProgress === "true",
1829
+ interactive: frontmatter.interactive === "true",
1830
+ ...maxSubagentDepth !== undefined ? { maxSubagentDepth } : {},
1831
+ ...completionGuard !== undefined ? { completionGuard } : {},
1832
+ ...toolBudget !== undefined ? { toolBudget } : {},
1833
+ ...permissions !== undefined ? { permissions } : {},
1834
+ ...memory !== undefined ? { memory } : {},
1835
+ ...Object.keys(extraFields).length > 0 ? { extraFields } : {}
1836
+ };
1837
+ agentFrontmatterFields.set(agent, new Set(Object.keys(frontmatter)));
1838
+ agents.push(agent);
1839
+ } catch (error) {
1840
+ diagnostics.push({ source, filePath, ...name ? { name } : {}, ...runtimeName && runtimeName !== name ? { runtimeName } : {}, ...packageSpecified ? { packageSpecified: true } : {}, ...discoveryPriority !== undefined ? { discoveryPriority } : {}, error: error instanceof Error ? error.message : String(error) });
949
1841
  }
950
- const completionGuard = frontmatter.completionGuard === "false" ? false : frontmatter.completionGuard === "true" ? true : undefined;
951
- const agent = {
952
- name: runtimeName,
953
- localName,
954
- packageName,
955
- description: frontmatter.description,
956
- tools: tools.length > 0 ? tools : undefined,
957
- mcpDirectTools: mcpDirectTools.length > 0 ? mcpDirectTools : undefined,
958
- model: frontmatter.model,
959
- fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,
960
- thinking: frontmatter.thinking,
961
- systemPromptMode,
962
- inheritProjectContext,
963
- inheritSkills,
964
- defaultContext,
965
- systemPrompt: body,
966
- source,
967
- filePath,
968
- skills: skills && skills.length > 0 ? skills : undefined,
969
- extensions,
970
- subagentOnlyExtensions,
971
- output: frontmatter.output,
972
- defaultReads: defaultReads && defaultReads.length > 0 ? defaultReads : undefined,
973
- defaultProgress: frontmatter.defaultProgress === "true",
974
- interactive: frontmatter.interactive === "true",
975
- maxSubagentDepth: Number.isInteger(parsedMaxSubagentDepth) && parsedMaxSubagentDepth >= 0 ? parsedMaxSubagentDepth : undefined,
976
- completionGuard,
977
- toolBudget,
978
- memory: parseMemoryFrontmatter(frontmatter.memory),
979
- extraFields: Object.keys(extraFields).length > 0 ? extraFields : undefined
980
- };
981
- agentFrontmatterFields.set(agent, new Set(Object.keys(frontmatter)));
982
- agents.push(agent);
983
1842
  }
984
- return agents;
1843
+ return { agents, diagnostics };
1844
+ }
1845
+ function loadAgentsFromDir(dir, source, discoveryPriority, packageSource, inspection = inspectAgentDefinitionDirectory(dir)) {
1846
+ return loadAgentsFromDefinitionFiles(readAgentDefinitionFiles(dir, inspection), source, discoveryPriority, packageSource);
1847
+ }
1848
+ function reportAgentDefinitionDirectory(source, dir, inspection) {
1849
+ return {
1850
+ source,
1851
+ path: path.resolve(dir),
1852
+ state: inspection.state,
1853
+ ...inspection.state === "candidates" ? { candidateCount: inspection.files.length } : {}
1854
+ };
985
1855
  }
986
1856
  function loadChainsFromDir(dir, source) {
987
1857
  const chains = new Map;
988
1858
  const diagnostics = [];
989
- for (const filePath of listFilesRecursive(dir, (fileName) => fileName.endsWith(".chain.md") || fileName.endsWith(".chain.json"))) {
1859
+ const directories = new Set;
1860
+ const files = listFilesRecursive(dir, (fileName) => fileName.endsWith(".chain.md") || fileName.endsWith(".chain.json"), dir, new Set, directories);
1861
+ for (const filePath of files) {
990
1862
  let content;
991
1863
  try {
992
1864
  content = fs.readFileSync(filePath, "utf-8");
@@ -1004,7 +1876,7 @@ function loadChainsFromDir(dir, source) {
1004
1876
  continue;
1005
1877
  }
1006
1878
  }
1007
- return { chains: Array.from(chains.values()), diagnostics };
1879
+ return { chains: Array.from(chains.values()), diagnostics, files, directories: [...directories] };
1008
1880
  }
1009
1881
  function isDirectory(p) {
1010
1882
  try {
@@ -1014,23 +1886,21 @@ function isDirectory(p) {
1014
1886
  }
1015
1887
  }
1016
1888
  function resolveNearestProjectAgentDirs(cwd) {
1017
- const projectRoot = findNearestProjectRoot(cwd);
1889
+ const projectRoot = findConfiguredProjectRoot(cwd);
1018
1890
  if (!projectRoot)
1019
- return { readDirs: [], preferredDir: null };
1891
+ return { readDirs: [], candidateDirs: [], preferredDir: null };
1020
1892
  const legacyDir = path.join(projectRoot, ".agents");
1021
1893
  const preferredDir = path.join(getProjectConfigDir(projectRoot), "agents");
1894
+ const candidateDirs = [legacyDir, preferredDir];
1022
1895
  const readDirs = [];
1023
1896
  if (isDirectory(legacyDir))
1024
1897
  readDirs.push(legacyDir);
1025
1898
  if (isDirectory(preferredDir))
1026
1899
  readDirs.push(preferredDir);
1027
- return {
1028
- readDirs,
1029
- preferredDir
1030
- };
1900
+ return { readDirs, candidateDirs, preferredDir };
1031
1901
  }
1032
1902
  function resolveNearestProjectChainDirs(cwd) {
1033
- const projectRoot = findNearestProjectRoot(cwd);
1903
+ const projectRoot = findConfiguredProjectRoot(cwd);
1034
1904
  if (!projectRoot)
1035
1905
  return { readDirs: [], preferredDir: null };
1036
1906
  const preferredDir = path.join(getProjectConfigDir(projectRoot), "chains");
@@ -1040,6 +1910,8 @@ function resolveNearestProjectChainDirs(cwd) {
1040
1910
  };
1041
1911
  }
1042
1912
  const BUILTIN_AGENTS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "agents");
1913
+ const BUILTIN_AGENT_DEFINITION_INSPECTION = inspectAgentDefinitionDirectory(BUILTIN_AGENTS_DIR);
1914
+ const BUILTIN_AGENT_DEFINITION_FILES = readAgentDefinitionFiles(BUILTIN_AGENTS_DIR, BUILTIN_AGENT_DEFINITION_INSPECTION);
1043
1915
  export const EXTRA_AGENT_DIRS_ENV = "DM_SUBAGENT_EXTRA_AGENT_DIRS";
1044
1916
  function extraUserAgentDirs() {
1045
1917
  const raw = process.env[EXTRA_AGENT_DIRS_ENV];
@@ -1047,93 +1919,369 @@ function extraUserAgentDirs() {
1047
1919
  return [];
1048
1920
  return raw.split(path.delimiter).map((dir) => dir.trim()).filter((dir) => dir.length > 0);
1049
1921
  }
1050
- export function discoverAgents(cwd, scope) {
1051
- const userDirOld = path.join(getAgentDir(), "agents");
1052
- const userDirNew = path.join(os.homedir(), ".agents");
1053
- const { readDirs: projectAgentDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(cwd);
1054
- const userSettingsPath = getUserAgentSettingsPath();
1055
- const projectSettingsPath = getProjectAgentSettingsPath(cwd);
1056
- const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
1057
- const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
1058
- const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1059
- const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
1060
- const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
1061
- includeUser: scope !== "project",
1062
- includeProject: scope !== "user"
1063
- });
1064
- const builtinAgents = applyBuiltinOverrides(applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1065
- const userAgentsExtra = scope === "project" ? [] : extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, "user"));
1066
- const userAgentsOld = scope === "project" ? [] : loadAgentsFromDir(userDirOld, "user");
1067
- const userAgentsNew = scope === "project" ? [] : loadAgentsFromDir(userDirNew, "user");
1068
- const userAgents = applyCustomAgentOverrides(applySubagentDefaultModel([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1069
- const projectAgents = applyCustomAgentOverrides(applySubagentDefaultModel(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1070
- const packageAgents = applyCustomAgentOverrides(applySubagentDefaultModel(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1071
- const agents = mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents).filter((agent) => agent.disabled !== true);
1072
- return { agents, projectAgentsDir, modelScope };
1073
- }
1074
- export function discoverAgentsAll(cwd) {
1922
+ const agentDiscoveryCache = new Map;
1923
+ function isPathWithin(root, candidate) {
1924
+ const relative = path.relative(path.resolve(root), path.resolve(candidate));
1925
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
1926
+ }
1927
+ function addDirectoryWatchPaths(paths, root, files, directories = []) {
1928
+ const resolvedRoot = path.resolve(root);
1929
+ paths.add(resolvedRoot);
1930
+ for (const directory of directories) {
1931
+ if (isPathWithin(resolvedRoot, directory))
1932
+ paths.add(path.resolve(directory));
1933
+ }
1934
+ for (const file of files) {
1935
+ paths.add(path.resolve(file));
1936
+ let current = path.resolve(path.dirname(file));
1937
+ while (isPathWithin(resolvedRoot, current)) {
1938
+ paths.add(current);
1939
+ if (current === resolvedRoot)
1940
+ break;
1941
+ current = path.dirname(current);
1942
+ }
1943
+ }
1944
+ }
1945
+ function watchPathSignature(filePath) {
1946
+ try {
1947
+ const stat = fs.statSync(filePath);
1948
+ if (stat.isDirectory()) {
1949
+ const entries = fs.readdirSync(filePath, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name)).map((entry) => `${entry.name}:${entry.isDirectory() ? "d" : entry.isSymbolicLink() ? "l" : "f"}`).join("|");
1950
+ return `directory:${entries}`;
1951
+ }
1952
+ return `file:${stat.size}:${stat.mtimeMs}`;
1953
+ } catch {
1954
+ return "missing";
1955
+ }
1956
+ }
1957
+ function discoveryFingerprint(paths) {
1958
+ return [...new Set(paths)].sort((left, right) => left.localeCompare(right)).map((filePath) => `${filePath}:${watchPathSignature(filePath)}`).join(`
1959
+ `);
1960
+ }
1961
+ function discoveryCacheKey(cwd, preferredModelProvider) {
1962
+ return JSON.stringify([
1963
+ path.resolve(cwd),
1964
+ preferredModelProvider ?? null,
1965
+ getProjectConfigDir(path.resolve(cwd)),
1966
+ getAgentDir(),
1967
+ os.homedir(),
1968
+ process.env.HOME ?? "",
1969
+ process.env.USERPROFILE ?? "",
1970
+ process.env[EXTRA_AGENT_DIRS_ENV] ?? "",
1971
+ process.env.PI_OFFLINE ?? "",
1972
+ process.env.APPDATA ?? ""
1973
+ ]);
1974
+ }
1975
+ function projectDiscoveryWatchPaths(cwd) {
1976
+ const paths = [];
1977
+ let current = path.resolve(cwd);
1978
+ while (true) {
1979
+ paths.push(getProjectConfigDir(current), path.join(current, ".agents"), path.join(current, ".git"));
1980
+ const parent = path.dirname(current);
1981
+ if (parent === current)
1982
+ break;
1983
+ current = parent;
1984
+ }
1985
+ return paths;
1986
+ }
1987
+ function packageEntryIncluded(scope, packageScopes) {
1988
+ if (scope === "both" || packageScopes.has("root"))
1989
+ return true;
1990
+ return packageScopes.has(scope);
1991
+ }
1992
+ function buildAgentDiscoverySources(cwd, preferredModelProvider) {
1993
+ const effectiveCwd = path.resolve(cwd);
1075
1994
  const userDirOld = path.join(getAgentDir(), "agents");
1076
1995
  const userDirNew = path.join(os.homedir(), ".agents");
1077
1996
  const userChainDir = getUserChainDir();
1078
- const { readDirs: projectDirs, preferredDir: projectDir } = resolveNearestProjectAgentDirs(cwd);
1079
- const { readDirs: projectChainDirs, preferredDir: projectChainDir } = resolveNearestProjectChainDirs(cwd);
1997
+ const { readDirs: projectAgentDirs, candidateDirs: projectCandidateDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(effectiveCwd);
1998
+ const { readDirs: projectChainDirs, preferredDir: projectChainDir } = resolveNearestProjectChainDirs(effectiveCwd);
1080
1999
  const userSettingsPath = getUserAgentSettingsPath();
1081
- const projectSettingsPath = getProjectAgentSettingsPath(cwd);
1082
- const userSettings = readSubagentSettings(userSettingsPath);
1083
- const projectSettings = readSubagentSettings(projectSettingsPath);
1084
- const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1085
- const packageSubagentPaths = collectPackageSubagentPaths(cwd);
1086
- const builtin = applyBuiltinOverrides(applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1087
- const user = applyCustomAgentOverrides(applySubagentDefaultModel([
1088
- ...extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, "user")),
1089
- ...loadAgentsFromDir(userDirOld, "user"),
1090
- ...loadAgentsFromDir(userDirNew, "user")
1091
- ], defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1092
- const packageMap = new Map;
1093
- for (const dir of packageSubagentPaths.agents) {
1094
- for (const agent of loadAgentsFromDir(dir, "package")) {
1095
- if (!packageMap.has(agent.name))
1096
- packageMap.set(agent.name, agent);
2000
+ const projectSettingsPath = getProjectAgentSettingsPath(effectiveCwd);
2001
+ const packageSubagentPaths = collectPackageSubagentPaths(effectiveCwd);
2002
+ const builtinLoaded = loadAgentsFromDefinitionFiles(BUILTIN_AGENT_DEFINITION_FILES, "builtin");
2003
+ const userLoaded = [...extraUserAgentDirs(), userDirOld, userDirNew].map((dir, discoveryPriority) => {
2004
+ const inspection = inspectAgentDefinitionDirectory(dir);
2005
+ return { dir, inspection, loaded: loadAgentsFromDir(dir, "user", discoveryPriority, undefined, inspection) };
2006
+ });
2007
+ const projectInspections = new Map(projectCandidateDirs.map((dir) => [dir, inspectAgentDefinitionDirectory(dir)]));
2008
+ const projectLoaded = projectAgentDirs.map((dir) => {
2009
+ const inspection = projectInspections.get(dir);
2010
+ return { dir, inspection, loaded: loadAgentsFromDir(dir, "project", dir === projectAgentsDir ? 1 : 0, undefined, inspection) };
2011
+ });
2012
+ const packageLoaded = packageSubagentPaths.agents.map((entry, index) => {
2013
+ const inspection = inspectAgentDefinitionDirectory(entry.dir);
2014
+ return { dir: entry.dir, inspection, packageEntry: entry, loaded: loadAgentsFromDir(entry.dir, "package", packageSubagentPaths.agents.length - index, entry, inspection) };
2015
+ });
2016
+ const watchPaths = new Set([
2017
+ userSettingsPath,
2018
+ ...projectSettingsPath ? [projectSettingsPath] : [],
2019
+ ...projectDiscoveryWatchPaths(effectiveCwd),
2020
+ ...findProjectRootCandidates(effectiveCwd).map((root) => path.join(getProjectConfigDir(root), "settings.json")),
2021
+ ...packageSubagentPaths.watchPaths
2022
+ ]);
2023
+ for (const directory of userLoaded)
2024
+ addDirectoryWatchPaths(watchPaths, directory.dir, directory.inspection.files, inspectedAgentDefinitionDirectories(directory.inspection, directory.dir));
2025
+ for (const dir of projectCandidateDirs) {
2026
+ const inspection = projectInspections.get(dir);
2027
+ addDirectoryWatchPaths(watchPaths, dir, inspection?.files ?? [], inspection ? inspectedAgentDefinitionDirectories(inspection, dir) : []);
2028
+ }
2029
+ for (const directory of packageLoaded)
2030
+ addDirectoryWatchPaths(watchPaths, directory.dir, directory.inspection.files, inspectedAgentDefinitionDirectories(directory.inspection, directory.dir));
2031
+ const userDir = process.env.DM_CODING_AGENT_DIR ? userDirOld : fs.existsSync(userDirNew) ? userDirNew : userDirOld;
2032
+ return {
2033
+ cwd: effectiveCwd,
2034
+ ...preferredModelProvider !== undefined ? { preferredModelProvider } : {},
2035
+ userDir,
2036
+ userDirOld,
2037
+ userDirNew,
2038
+ userChainDir,
2039
+ projectAgentDirs,
2040
+ projectCandidateDirs,
2041
+ projectAgentsDir,
2042
+ projectChainDirs,
2043
+ projectChainDir,
2044
+ userSettingsPath,
2045
+ projectSettingsPath,
2046
+ packageSubagentPaths,
2047
+ builtinLoaded,
2048
+ userLoaded,
2049
+ projectLoaded,
2050
+ projectInspections,
2051
+ packageLoaded,
2052
+ watchPaths: [...watchPaths]
2053
+ };
2054
+ }
2055
+ function ensureDiscoveryChains(sources) {
2056
+ if (sources.userChains)
2057
+ return;
2058
+ sources.packageChainLoaded = sources.packageSubagentPaths.chains.map((entry) => ({ entry, loaded: loadChainsFromDir(entry.dir, "package") }));
2059
+ sources.userChains = loadChainsFromDir(sources.userChainDir, "user");
2060
+ sources.projectChainLoaded = sources.projectChainDirs.map((dir) => ({ dir, loaded: loadChainsFromDir(dir, "project") }));
2061
+ const watchPaths = new Set(sources.watchPaths);
2062
+ addDirectoryWatchPaths(watchPaths, sources.userChainDir, sources.userChains.files, sources.userChains.directories);
2063
+ for (const chain of sources.projectChainLoaded)
2064
+ addDirectoryWatchPaths(watchPaths, chain.dir, chain.loaded.files, chain.loaded.directories);
2065
+ for (const chain of sources.packageChainLoaded)
2066
+ addDirectoryWatchPaths(watchPaths, chain.entry.dir, chain.loaded.files, chain.loaded.directories);
2067
+ sources.watchPaths = [...watchPaths];
2068
+ }
2069
+ function getAgentDiscoverySources(cwd, preferredModelProvider, includeChains = false) {
2070
+ const key = discoveryCacheKey(cwd, preferredModelProvider);
2071
+ const cached = agentDiscoveryCache.get(key);
2072
+ if (cached && cached.fingerprint === discoveryFingerprint(cached.sources.watchPaths)) {
2073
+ if (includeChains) {
2074
+ ensureDiscoveryChains(cached.sources);
2075
+ cached.fingerprint = discoveryFingerprint(cached.sources.watchPaths);
1097
2076
  }
2077
+ return cached.sources;
2078
+ }
2079
+ const sources = buildAgentDiscoverySources(cwd, preferredModelProvider);
2080
+ const entry = { sources, fingerprint: discoveryFingerprint(sources.watchPaths) };
2081
+ agentDiscoveryCache.set(key, entry);
2082
+ if (includeChains) {
2083
+ ensureDiscoveryChains(sources);
2084
+ entry.fingerprint = discoveryFingerprint(sources.watchPaths);
2085
+ }
2086
+ return sources;
2087
+ }
2088
+ export function clearAgentDiscoveryCache() {
2089
+ agentDiscoveryCache.clear();
2090
+ }
2091
+ function ensureSettingsForScope(sources, scope, preferredModelProvider) {
2092
+ if (scope !== "project" && sources.userSettings === undefined) {
2093
+ if (sources.packageSubagentPaths.settingsErrors.user)
2094
+ throw sources.packageSubagentPaths.settingsErrors.user;
2095
+ sources.userSettings = selectProviderOverrides(readSubagentSettings(sources.userSettingsPath), preferredModelProvider);
2096
+ }
2097
+ if (scope !== "user" && sources.projectSettings === undefined) {
2098
+ if (sources.packageSubagentPaths.settingsErrors.project)
2099
+ throw sources.packageSubagentPaths.settingsErrors.project;
2100
+ sources.projectSettings = selectProviderOverrides(readSubagentSettings(sources.projectSettingsPath), preferredModelProvider);
1098
2101
  }
1099
- const packageAgents = applyCustomAgentOverrides(applySubagentDefaultModel(Array.from(packageMap.values()), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
2102
+ }
2103
+ function settingsForScope(sources, scope) {
2104
+ ensureSettingsForScope(sources, scope, sources.preferredModelProvider);
2105
+ return {
2106
+ user: scope === "project" ? EMPTY_SUBAGENT_SETTINGS : sources.userSettings ?? EMPTY_SUBAGENT_SETTINGS,
2107
+ project: scope === "user" ? EMPTY_SUBAGENT_SETTINGS : sources.projectSettings ?? EMPTY_SUBAGENT_SETTINGS
2108
+ };
2109
+ }
2110
+ function configuredAgentsForScope(sources, scope, settingsScope = scope) {
2111
+ const { user: userSettings, project: projectSettings } = settingsForScope(sources, settingsScope);
2112
+ const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, sources.projectSettingsPath);
2113
+ const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, sources.userSettingsPath, sources.projectSettingsPath, defaultProvider);
2114
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, sources.projectSettingsPath);
2115
+ const maxThinking = resolveSubagentMaxThinking(userSettings, projectSettings, sources.projectSettingsPath);
2116
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, sources.projectSettingsPath);
2117
+ const applyDefaults = (agents) => applySubagentDefaults(agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions);
2118
+ const builtin = applyBuiltinOverrides(applyDefaults(sources.builtinLoaded.agents), userSettings, projectSettings, sources.userSettingsPath, sources.projectSettingsPath);
2119
+ const user = applyCustomAgentOverrides(applyDefaults(scope === "project" ? [] : sources.userLoaded.flatMap((loaded) => loaded.loaded.agents)), userSettings, projectSettings, sources.userSettingsPath, sources.projectSettingsPath);
1100
2120
  const projectMap = new Map;
1101
- for (const dir of projectDirs) {
1102
- for (const agent of loadAgentsFromDir(dir, "project")) {
1103
- projectMap.set(agent.name, agent);
1104
- }
2121
+ if (scope !== "user")
2122
+ for (const loaded of sources.projectLoaded)
2123
+ for (const agent of loaded.loaded.agents)
2124
+ projectMap.set(agent.name, agent);
2125
+ const project = applyCustomAgentOverrides(applyDefaults(Array.from(projectMap.values())), userSettings, projectSettings, sources.userSettingsPath, sources.projectSettingsPath);
2126
+ const packageMap = new Map;
2127
+ for (const loaded of sources.packageLoaded) {
2128
+ if (!loaded.packageEntry || !packageEntryIncluded(scope, loaded.packageEntry.scope))
2129
+ continue;
2130
+ for (const agent of loaded.loaded.agents)
2131
+ if (!packageMap.has(agent.name))
2132
+ packageMap.set(agent.name, agent);
1105
2133
  }
1106
- const project = applyCustomAgentOverrides(applySubagentDefaultModel(Array.from(projectMap.values()), defaultModel), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1107
- const chainMap = new Map;
1108
- const packageChainDiagnostics = [];
2134
+ const packageAgents = applyCustomAgentOverrides(applyDefaults(Array.from(packageMap.values())), userSettings, projectSettings, sources.userSettingsPath, sources.projectSettingsPath);
2135
+ return {
2136
+ builtin,
2137
+ package: packageAgents,
2138
+ user,
2139
+ project,
2140
+ userSettings,
2141
+ projectSettings,
2142
+ maxThinking,
2143
+ modelScope: projectSettings.modelScope ?? userSettings.modelScope
2144
+ };
2145
+ }
2146
+ function discoveryDirectories(sources, scope) {
2147
+ const directories = [reportAgentDefinitionDirectory("builtin", BUILTIN_AGENTS_DIR, BUILTIN_AGENT_DEFINITION_INSPECTION)];
2148
+ if (scope !== "project")
2149
+ for (const directory of sources.userLoaded)
2150
+ directories.push(reportAgentDefinitionDirectory("user", directory.dir, directory.inspection));
2151
+ if (scope !== "user")
2152
+ for (const dir of sources.projectCandidateDirs)
2153
+ directories.push(reportAgentDefinitionDirectory("project", dir, sources.projectInspections.get(dir)));
2154
+ for (const directory of sources.packageLoaded) {
2155
+ if (directory.packageEntry && packageEntryIncluded(scope, directory.packageEntry.scope))
2156
+ directories.push(reportAgentDefinitionDirectory("package", directory.dir, directory.inspection));
2157
+ }
2158
+ return directories;
2159
+ }
2160
+ function discoveryDiagnostics(sources, scope) {
2161
+ return [
2162
+ ...sources.builtinLoaded.diagnostics,
2163
+ ...scope === "project" ? [] : sources.userLoaded.flatMap((loaded) => loaded.loaded.diagnostics),
2164
+ ...scope === "user" ? [] : sources.projectLoaded.flatMap((loaded) => loaded.loaded.diagnostics),
2165
+ ...sources.packageLoaded.filter((loaded) => loaded.packageEntry && packageEntryIncluded(scope, loaded.packageEntry.scope)).flatMap((loaded) => loaded.loaded.diagnostics)
2166
+ ];
2167
+ }
2168
+ function buildEffectiveDiscovery(sources, scope) {
2169
+ const configured = configuredAgentsForScope(sources, scope);
2170
+ const agents = applySubagentMaxThinking(mergeAgentsForScope(scope, configured.user, configured.project, configured.builtin, configured.package).filter((agent) => agent.disabled !== true), configured.maxThinking);
2171
+ return {
2172
+ agents,
2173
+ agentDiagnostics: discoveryDiagnostics(sources, scope),
2174
+ projectAgentsDir: sources.projectAgentsDir,
2175
+ cwd: sources.cwd,
2176
+ scope,
2177
+ directories: discoveryDirectories(sources, scope),
2178
+ ...configured.modelScope !== undefined ? { modelScope: configured.modelScope } : {},
2179
+ ...configured.maxThinking !== undefined ? { maxThinking: configured.maxThinking } : {}
2180
+ };
2181
+ }
2182
+ function buildAllDiscovery(sources, includeChains, settingsScope) {
2183
+ if (includeChains)
2184
+ ensureDiscoveryChains(sources);
2185
+ const configured = configuredAgentsForScope(sources, "both", settingsScope);
1109
2186
  const packageChainMap = new Map;
1110
- for (const dir of packageSubagentPaths.chains) {
1111
- const loaded = loadChainsFromDir(dir, "package");
1112
- packageChainDiagnostics.push(...loaded.diagnostics);
1113
- for (const chain of loaded.chains) {
1114
- if (!packageChainMap.has(chain.name))
1115
- packageChainMap.set(chain.name, chain);
1116
- }
2187
+ const packageChainDiagnostics = [];
2188
+ for (const chain of sources.packageChainLoaded ?? []) {
2189
+ packageChainDiagnostics.push(...chain.loaded.diagnostics);
2190
+ for (const definition of chain.loaded.chains)
2191
+ if (!packageChainMap.has(definition.name))
2192
+ packageChainMap.set(definition.name, definition);
1117
2193
  }
2194
+ const projectChainMap = new Map;
1118
2195
  const projectChainDiagnostics = [];
1119
- for (const dir of projectChainDirs) {
1120
- const loaded = loadChainsFromDir(dir, "project");
1121
- projectChainDiagnostics.push(...loaded.diagnostics);
1122
- for (const chain of loaded.chains) {
1123
- chainMap.set(chain.name, chain);
1124
- }
2196
+ for (const chain of sources.projectChainLoaded ?? []) {
2197
+ projectChainDiagnostics.push(...chain.loaded.diagnostics);
2198
+ for (const definition of chain.loaded.chains)
2199
+ projectChainMap.set(definition.name, definition);
1125
2200
  }
1126
- const userChains = loadChainsFromDir(userChainDir, "user");
1127
2201
  const chains = [
1128
2202
  ...Array.from(packageChainMap.values()),
1129
- ...userChains.chains,
1130
- ...Array.from(chainMap.values())
2203
+ ...sources.userChains?.chains ?? [],
2204
+ ...Array.from(projectChainMap.values())
1131
2205
  ];
1132
- const chainDiagnostics = [
1133
- ...packageChainDiagnostics,
1134
- ...userChains.diagnostics,
1135
- ...projectChainDiagnostics
1136
- ];
1137
- const userDir = process.env.DM_CODING_AGENT_DIR ? userDirOld : fs.existsSync(userDirNew) ? userDirNew : userDirOld;
1138
- return { builtin, package: packageAgents, user, project, chains, chainDiagnostics, userDir, projectDir, userChainDir, projectChainDir, userSettingsPath, projectSettingsPath };
2206
+ return {
2207
+ builtin: applySubagentMaxThinking(configured.builtin, configured.maxThinking),
2208
+ package: applySubagentMaxThinking(configured.package, configured.maxThinking),
2209
+ user: applySubagentMaxThinking(configured.user, configured.maxThinking),
2210
+ project: applySubagentMaxThinking(configured.project, configured.maxThinking),
2211
+ agentDiagnostics: [
2212
+ ...sources.builtinLoaded.diagnostics,
2213
+ ...sources.userLoaded.flatMap((loaded) => loaded.loaded.diagnostics),
2214
+ ...sources.packageLoaded.flatMap((loaded) => loaded.loaded.diagnostics),
2215
+ ...sources.projectLoaded.flatMap((loaded) => loaded.loaded.diagnostics)
2216
+ ],
2217
+ chains,
2218
+ chainDiagnostics: [...packageChainDiagnostics, ...sources.userChains?.diagnostics ?? [], ...projectChainDiagnostics],
2219
+ userDir: sources.userDir,
2220
+ projectDir: sources.projectAgentsDir,
2221
+ userChainDir: sources.userChainDir,
2222
+ projectChainDir: sources.projectChainDir,
2223
+ userSettingsPath: sources.userSettingsPath,
2224
+ projectSettingsPath: sources.projectSettingsPath,
2225
+ ...configured.maxThinking !== undefined ? { maxThinking: configured.maxThinking } : {}
2226
+ };
2227
+ }
2228
+ export function discoverAgentSnapshot(cwd, scope, preferredModelProvider, options = {}) {
2229
+ const includeChains = options.includeChains !== false;
2230
+ const sources = getAgentDiscoverySources(cwd, preferredModelProvider, includeChains);
2231
+ return { effective: buildEffectiveDiscovery(sources, scope), all: buildAllDiscovery(sources, includeChains, scope) };
2232
+ }
2233
+ function discoverAgentsUncached(cwd, scope, preferredModelProvider) {
2234
+ const effectiveCwd = path.resolve(cwd);
2235
+ const userDirOld = path.join(getAgentDir(), "agents");
2236
+ const userDirNew = path.join(os.homedir(), ".agents");
2237
+ const { readDirs: projectAgentDirs, candidateDirs: projectCandidateDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(effectiveCwd);
2238
+ const userSettingsPath = getUserAgentSettingsPath();
2239
+ const projectSettingsPath = getProjectAgentSettingsPath(effectiveCwd);
2240
+ const userSettings = selectProviderOverrides(scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath), preferredModelProvider);
2241
+ const projectSettings = selectProviderOverrides(scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath), preferredModelProvider);
2242
+ const defaultProvider = resolveSubagentDefaultProvider(userSettings, projectSettings, projectSettingsPath);
2243
+ const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath, defaultProvider);
2244
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
2245
+ const maxThinking = resolveSubagentMaxThinking(userSettings, projectSettings, projectSettingsPath);
2246
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
2247
+ const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
2248
+ const packageSubagentPaths = collectPackageSubagentPaths(effectiveCwd, { includeUser: scope !== "project", includeProject: scope !== "user" });
2249
+ const directories = [reportAgentDefinitionDirectory("builtin", BUILTIN_AGENTS_DIR, BUILTIN_AGENT_DEFINITION_INSPECTION)];
2250
+ const builtinLoaded = loadAgentsFromDefinitionFiles(BUILTIN_AGENT_DEFINITION_FILES, "builtin");
2251
+ const builtinAgents = applyBuiltinOverrides(applySubagentDefaults(builtinLoaded.agents, defaultModel, defaultProvider, defaultThinking, defaultExtensions), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
2252
+ const userLoaded = scope === "project" ? [] : [...extraUserAgentDirs(), userDirOld, userDirNew].map((dir, discoveryPriority) => {
2253
+ const inspection = inspectAgentDefinitionDirectory(dir);
2254
+ directories.push(reportAgentDefinitionDirectory("user", dir, inspection));
2255
+ return loadAgentsFromDir(dir, "user", discoveryPriority, undefined, inspection);
2256
+ });
2257
+ const userAgents = applyCustomAgentOverrides(applySubagentDefaults(userLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
2258
+ const projectInspections = scope === "user" ? new Map : new Map(projectCandidateDirs.map((dir) => [dir, inspectAgentDefinitionDirectory(dir)]));
2259
+ if (scope !== "user")
2260
+ for (const dir of projectCandidateDirs)
2261
+ directories.push(reportAgentDefinitionDirectory("project", dir, projectInspections.get(dir)));
2262
+ const projectLoaded = scope === "user" ? [] : projectAgentDirs.map((dir) => loadAgentsFromDir(dir, "project", dir === projectAgentsDir ? 1 : 0, undefined, projectInspections.get(dir)));
2263
+ const projectAgents = applyCustomAgentOverrides(applySubagentDefaults(projectLoaded.flatMap((loaded) => loaded.agents), defaultModel, defaultProvider, defaultThinking, defaultExtensions), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
2264
+ const packageLoaded = packageSubagentPaths.agents.map((entry, index) => {
2265
+ const inspection = inspectAgentDefinitionDirectory(entry.dir);
2266
+ directories.push(reportAgentDefinitionDirectory("package", entry.dir, inspection));
2267
+ return loadAgentsFromDir(entry.dir, "package", packageSubagentPaths.agents.length - index, entry, inspection);
2268
+ });
2269
+ const packageMap = new Map;
2270
+ for (const loaded of packageLoaded)
2271
+ for (const agent of loaded.agents)
2272
+ if (!packageMap.has(agent.name))
2273
+ packageMap.set(agent.name, agent);
2274
+ const packageAgents = applyCustomAgentOverrides(applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultProvider, defaultThinking, defaultExtensions), userSettings, projectSettings, userSettingsPath, projectSettingsPath);
2275
+ const agents = applySubagentMaxThinking(mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents).filter((agent) => agent.disabled !== true), maxThinking);
2276
+ const agentDiagnostics = [...builtinLoaded.diagnostics, ...userLoaded.flatMap((loaded) => loaded.diagnostics), ...projectLoaded.flatMap((loaded) => loaded.diagnostics), ...packageLoaded.flatMap((loaded) => loaded.diagnostics)];
2277
+ return { agents, agentDiagnostics, projectAgentsDir, cwd: effectiveCwd, scope, directories, ...modelScope !== undefined ? { modelScope } : {}, ...maxThinking !== undefined ? { maxThinking } : {} };
2278
+ }
2279
+ export function discoverAgents(cwd, scope, preferredModelProvider) {
2280
+ if (scope !== "both")
2281
+ return discoverAgentsUncached(cwd, scope, preferredModelProvider);
2282
+ const sources = getAgentDiscoverySources(cwd, preferredModelProvider);
2283
+ return buildEffectiveDiscovery(sources, scope);
2284
+ }
2285
+ export function discoverAgentsAll(cwd, preferredModelProvider) {
2286
+ return discoverAgentSnapshot(cwd, "both", preferredModelProvider).all;
1139
2287
  }