@duckmind/dm-windows-x64 0.60.6 → 0.60.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +70 -123
  3. package/extensions/dm-9router-ext/src/index.js +410 -5
  4. package/extensions/dm-caveman/extensions/caveman.js +283 -12
  5. package/extensions/dm-cliproxy/index.js +182 -2
  6. package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
  7. package/extensions/dm-cliproxy/src/apply.js +228 -1
  8. package/extensions/dm-cliproxy/src/cache.js +42 -1
  9. package/extensions/dm-cliproxy/src/commands.js +50 -2
  10. package/extensions/dm-cliproxy/src/compat.js +81 -1
  11. package/extensions/dm-cliproxy/src/config.js +192 -2
  12. package/extensions/dm-cliproxy/src/conflicts.js +46 -1
  13. package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
  14. package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
  15. package/extensions/dm-cliproxy/src/log.js +23 -1
  16. package/extensions/dm-cliproxy/src/status-quota.js +77 -1
  17. package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
  18. package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
  19. package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
  20. package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
  21. package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
  22. package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
  23. package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
  24. package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
  25. package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
  26. package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
  27. package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
  28. package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
  29. package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
  30. package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
  31. package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
  32. package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
  33. package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
  34. package/extensions/dm-context/src/context.js +144 -1
  35. package/extensions/dm-context/src/index.js +339 -7
  36. package/extensions/dm-context/src/utils.js +9 -1
  37. package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
  38. package/extensions/dm-cua/index.js +75 -6
  39. package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
  40. package/extensions/dm-cua/src/browser-install.mjs +331 -2
  41. package/extensions/dm-fff/src/index.js +688 -12
  42. package/extensions/dm-fff/src/query.js +60 -1
  43. package/extensions/dm-goal/src/goal.js +894 -23
  44. package/extensions/dm-image2/index.js +103 -9
  45. package/extensions/dm-image2/src/image-lib.mjs +1275 -8
  46. package/extensions/dm-subagents/install.mjs +62 -8
  47. package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
  48. package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
  49. package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
  50. package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
  51. package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
  52. package/extensions/dm-subagents/src/agents/agents.js +1139 -11
  53. package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
  54. package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
  55. package/extensions/dm-subagents/src/agents/identity.js +29 -1
  56. package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
  57. package/extensions/dm-subagents/src/agents/skills.js +614 -6
  58. package/extensions/dm-subagents/src/extension/config.js +35 -2
  59. package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
  60. package/extensions/dm-subagents/src/extension/doctor.js +172 -15
  61. package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
  62. package/extensions/dm-subagents/src/extension/index.js +521 -359
  63. package/extensions/dm-subagents/src/extension/rpc.js +266 -7
  64. package/extensions/dm-subagents/src/extension/schemas.js +275 -1
  65. package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
  66. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
  67. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
  68. package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
  69. package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
  70. package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
  71. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
  72. package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
  73. package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
  74. package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
  75. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
  76. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
  77. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
  78. package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
  79. package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
  80. package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
  81. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
  82. package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
  83. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
  84. package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
  85. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
  86. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
  87. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
  88. package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
  89. package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
  90. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
  91. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
  92. package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
  93. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
  94. package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
  95. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
  96. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
  97. package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
  98. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
  99. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
  100. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
  101. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
  102. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
  103. package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
  104. package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
  105. package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
  106. package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
  107. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
  108. package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
  109. package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
  110. package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
  111. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
  112. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
  113. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
  114. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
  115. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
  116. package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
  117. package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
  118. package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
  119. package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
  120. package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
  121. package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
  122. package/extensions/dm-subagents/src/shared/formatters.js +98 -7
  123. package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
  124. package/extensions/dm-subagents/src/shared/model-info.js +62 -1
  125. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
  126. package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
  127. package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
  128. package/extensions/dm-subagents/src/shared/settings.js +198 -11
  129. package/extensions/dm-subagents/src/shared/status-format.js +53 -1
  130. package/extensions/dm-subagents/src/shared/types.js +184 -6
  131. package/extensions/dm-subagents/src/shared/utils.js +462 -2
  132. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
  133. package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
  134. package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
  135. package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
  136. package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
  137. package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
  138. package/extensions/dm-subagents/src/tui/render.js +1542 -4
  139. package/extensions/dm-usage/index.js +1294 -9
  140. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
  141. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
  142. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
  143. package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
  144. package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
  145. package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
  146. package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
  147. package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
  148. package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
  149. package/extensions/greedysearch-dm/bin/search.mjs +620 -540
  150. package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
  151. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
  152. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
  153. package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
  154. package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
  155. package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
  156. package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
  157. package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
  158. package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
  159. package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
  160. package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
  161. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
  162. package/extensions/greedysearch-dm/index.js +123 -23
  163. package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
  164. package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
  165. package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
  166. package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
  167. package/extensions/greedysearch-dm/src/github.mjs +222 -7
  168. package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
  169. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
  170. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
  171. package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
  172. package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
  173. package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
  174. package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
  175. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
  176. package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
  177. package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
  178. package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
  179. package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
  180. package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
  181. package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
  182. package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
  183. package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
  184. package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
  185. package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
  186. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
  187. package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
  188. package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
  189. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
  190. package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
  191. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
  192. package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
  193. package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
  194. package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
  195. package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
  196. package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
  197. package/package.json +1 -1
@@ -1 +1,305 @@
1
- import{createHash as d}from"node:crypto";import*as V from"node:fs";import*as q from"node:os";import*as Z from"node:path";import*as X from"node:fs";import*as L from"node:os";import*as B from"node:path";import*as K from"node:os";import*as G from"node:path";function N(j){return j.trim().replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}function m(j){let $=j?.env??process.env,A=j&&Object.hasOwn(j,"getuid")?j.getuid:process.getuid?.bind(process);if(typeof A==="function")return`uid-${A()}`;for(let Y of["USERNAME","USER","LOGNAME"]){let E=$[Y];if(E)return`user-${N(E)}`}let J=j&&Object.hasOwn(j,"userInfo")?j.userInfo:K.userInfo;try{let Y=J?.().username;if(Y)return`user-${N(Y)}`}catch{}let W=$.USERPROFILE??$.HOME;if(W)return`home-${N(W)}`;let Q=j&&Object.hasOwn(j,"homedir")?j.homedir:K.homedir;try{let Y=Q?.();if(Y)return`home-${N(Y)}`}catch{}return"shared"}var I=G.join(K.tmpdir(),`dm-subagents-${m()}`),Gj=G.join(I,"async-subagent-results"),Vj=G.join(I,"async-subagent-runs"),h=G.join(I,"chain-runs"),Mj=G.join(I,"artifacts");var u=".dm",k="@duckmind/dm-coding-agent",g="DM_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT";function w(j){return typeof j==="string"&&j.trim()?j:void 0}function b(j){if(!j)return;try{let $=JSON.parse(X.readFileSync(B.join(j,"package.json"),"utf-8"));if($.name!==k)return;return w($.piConfig?.configDir)}catch{return}}function o(j=process.argv[1],$=process.env[g]){let A=b($);if(A)return A;if(!j)return;try{let J=B.dirname(X.realpathSync(j));while(J!==B.dirname(J)){let W=b(J);if(W)return W;J=B.dirname(J)}}catch{}return}function p(j,$,A){return(j&&typeof j==="object"?w(j.CONFIG_DIR_NAME):void 0)??o($,A)??u}function x(){return p()}function S(j){return B.join(j,x())}function C(){let j=process.env.DM_CODING_AGENT_DIR;if(j==="~")return L.homedir();if(j?.startsWith("~/"))return B.join(L.homedir(),j.slice(2));return j||B.join(L.homedir(),x(),"agent")}var r=1,i=604800000,D=new Set(["read","bash","edit","write","grep","find","ls","mcp"]),v=Z.join(q.homedir(),".config","mcp","mcp.json"),P={cursor:[Z.join(q.homedir(),".cursor","mcp.json")],"claude-code":[Z.join(q.homedir(),".claude","mcp.json"),Z.join(q.homedir(),".claude.json"),Z.join(q.homedir(),".claude","claude_desktop_config.json")],"claude-desktop":[Z.join(q.homedir(),"Library","Application Support","Claude","claude_desktop_config.json")],codex:[Z.join(q.homedir(),".codex","config.json")],windsurf:[Z.join(q.homedir(),".windsurf","mcp.json")],vscode:[".vscode/mcp.json"]};function kj(j,$=process.cwd()){if(!j?.length)return[];try{let A=t($),J=l();if(!J)return[];return Wj(A,J,Xj(A.settings?.toolPrefix),j)}catch{return[]}}function l(){let j=Z.join(C(),"mcp-cache.json"),$;try{$=JSON.parse(V.readFileSync(j,"utf-8"))}catch{return null}if(!$||typeof $!=="object")return null;let A=$;if(A.version!==r||!A.servers||typeof A.servers!=="object"||Array.isArray(A.servers))return null;return A}function t(j){let $={mcpServers:{}};for(let A of s(j)){let J=a(A);if(!J)continue;$=jj($,$j(J,j))}return $}function s(j){let $=Z.join(C(),"mcp.json"),A=Z.resolve(j,".mcp.json"),J=Z.resolve(S(j),"mcp.json"),W=[];if(v!==$)W.push(v);if(W.push($),A!==$)W.push(A);if(J!==$&&J!==A)W.push(J);return W}function a(j){let $;try{$=JSON.parse(V.readFileSync(j,"utf-8"))}catch{return null}return e($)}function e(j){if(!j||typeof j!=="object"||Array.isArray(j))return{mcpServers:{}};let $=j,A=$.mcpServers??$["mcp-servers"]??{};return{mcpServers:A&&typeof A==="object"&&!Array.isArray(A)?A:{},imports:Array.isArray($.imports)?$.imports.filter((J)=>_j(J)):void 0,settings:$.settings&&typeof $.settings==="object"&&!Array.isArray($.settings)?$.settings:void 0}}function jj(j,$){let A=[...j.imports??[],...$.imports??[]];return{mcpServers:{...j.mcpServers,...$.mcpServers},imports:A.length?[...new Set(A)]:void 0,settings:$.settings?{...j.settings,...$.settings}:j.settings}}function $j(j,$){if(!j.imports?.length)return j;let A={};for(let J of j.imports){let W=Aj(J,$);if(!W)continue;let Q;try{Q=JSON.parse(V.readFileSync(W,"utf-8"))}catch{continue}for(let[Y,E]of Object.entries(Jj(Q,J)))if(!A[Y])A[Y]=E}return{imports:j.imports,settings:j.settings,mcpServers:{...A,...j.mcpServers}}}function Aj(j,$){for(let A of P[j]){let J=A.startsWith(".")?Z.resolve($,A):A;if(V.existsSync(J))return J}return null}function Jj(j,$){if(!j||typeof j!=="object"||Array.isArray(j))return{};let A=j,J=$==="cursor"||$==="windsurf"||$==="vscode"?A.mcpServers??A["mcp-servers"]:A.mcpServers;return J&&typeof J==="object"&&!Array.isArray(J)?J:{}}function Wj(j,$,A,J){let W=[],Q=new Set,{servers:Y,tools:E}=Zj(J);for(let[U,z]of Object.entries(j.mcpServers)){let M=$.servers[U];if(!Qj(M,z))continue;let H=Y.has(U)?!0:E.get(U);if(!H)continue;for(let _ of Array.isArray(M.tools)?M.tools:[]){if(typeof _?.name!=="string"||!_.name)continue;if(H!==!0&&!H.has(_.name))continue;if(c(_.name,U,A,z.excludeTools))continue;let T=R(_.name,U,A);if(D.has(T)||Q.has(T))continue;Q.add(T),W.push(T)}if(z.exposeResources===!1)continue;for(let _ of Array.isArray(M.resources)?M.resources:[]){if(typeof _?.name!=="string"||!_.name||typeof _.uri!=="string"||!_.uri)continue;let T=`get_${qj(_.name)}`;if(H!==!0&&!H.has(T))continue;if(c(T,U,A,z.excludeTools))continue;let F=R(T,U,A);if(D.has(F)||Q.has(F))continue;Q.add(F),W.push(F)}}return W}function Zj(j){let $=new Set,A=new Map;for(let J of j)if(J=J.replace(/\/+$/,""),J.includes("/")){let[W,Q]=J.split("/",2);if(W&&Q){if(!A.has(W))A.set(W,new Set);A.get(W).add(Q)}else if(W)$.add(W)}else if(J)$.add(J);return{servers:$,tools:A}}function Qj(j,$){if(!j||j.configHash!==Yj($))return!1;if(!j.cachedAt||typeof j.cachedAt!=="number")return!1;return Date.now()-j.cachedAt<=i}function Yj(j){let $={command:j.command,args:j.args,env:n(j.env),cwd:Tj(j.cwd),url:j.url,headers:n(j.headers),auth:j.auth,bearerToken:Uj(j),bearerTokenEnv:j.bearerTokenEnv,exposeResources:j.exposeResources,excludeTools:j.excludeTools};return d("sha256").update(y($)).digest("hex")}function Xj(j){return j==="none"||j==="short"||j==="server"?j:"server"}function _j(j){return typeof j==="string"&&Object.hasOwn(P,j)}function Bj(j,$){if($==="none")return"";if($==="short")return j.replace(/-?mcp$/i,"").replace(/-/g,"_")||"mcp";return j.replace(/-/g,"_")}function R(j,$,A){let J=Bj($,A);return J?`${J}_${j}`:j}function c(j,$,A,J){if(!Array.isArray(J)||J.length===0)return!1;let W=new Set([O(j),O(R(j,$,A)),O(R(j,$,"server")),O(R(j,$,"short"))]);return J.some((Q)=>typeof Q==="string"&&W.has(O(Q)))}function O(j){return j.replace(/-/g,"_")}function qj(j){let $=j.replace(/[^a-zA-Z0-9]/g,"_").replace(/_+/g,"_").replace(/^_+/,"").replace(/_+$/,"").toLowerCase();if(!$||/^\d/.test($))$=`resource${$?`_${$}`:""}`;return $}function n(j){if(!j||typeof j!=="object"||Array.isArray(j))return;let $={};for(let[A,J]of Object.entries(j))if(typeof J==="string")$[A]=f(J);return $}function f(j){return j.replace(/\$\{(\w+)\}/g,($,A)=>process.env[A]??"").replace(/\$env:(\w+)/g,($,A)=>process.env[A]??"")}function Tj(j){if(typeof j!=="string")return;let $=f(j);if($==="~")return q.homedir();if($.startsWith("~/")||$.startsWith("~\\"))return Z.join(q.homedir(),$.slice(2));return $}function Uj(j){if(typeof j.bearerToken==="string")return f(j.bearerToken);return typeof j.bearerTokenEnv==="string"?process.env[j.bearerTokenEnv]:void 0}function y(j){if(j===null||j===void 0||typeof j!=="object"){let A=JSON.stringify(j);return A===void 0?"undefined":A}if(Array.isArray(j))return`[${j.map((A)=>y(A)).join(",")}]`;let $=j;return`{${Object.keys($).sort().map((A)=>`${JSON.stringify(A)}:${y($[A])}`).join(",")}}`}export{kj as resolveMcpDirectToolNames,Yj as computeMcpServerHash};
1
+ import { createHash } from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { getAgentDir, getProjectConfigDir } from "../../shared/utils.js";
6
+ const CACHE_VERSION = 1;
7
+ const CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
8
+ const BUILTIN_TOOL_NAMES = new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
9
+ const GENERIC_GLOBAL_CONFIG_PATH = path.join(os.homedir(), ".config", "mcp", "mcp.json");
10
+ const IMPORT_PATHS = {
11
+ cursor: [path.join(os.homedir(), ".cursor", "mcp.json")],
12
+ "claude-code": [
13
+ path.join(os.homedir(), ".claude", "mcp.json"),
14
+ path.join(os.homedir(), ".claude.json"),
15
+ path.join(os.homedir(), ".claude", "claude_desktop_config.json")
16
+ ],
17
+ "claude-desktop": [path.join(os.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json")],
18
+ codex: [path.join(os.homedir(), ".codex", "config.json")],
19
+ windsurf: [path.join(os.homedir(), ".windsurf", "mcp.json")],
20
+ vscode: [".vscode/mcp.json"]
21
+ };
22
+ export function resolveMcpDirectToolNames(mcpDirectTools, cwd = process.cwd()) {
23
+ if (!mcpDirectTools?.length)
24
+ return [];
25
+ try {
26
+ const config = loadMcpConfig(cwd);
27
+ const cache = loadMetadataCache();
28
+ if (!cache)
29
+ return [];
30
+ return resolveDirectToolNames(config, cache, getToolPrefix(config.settings?.toolPrefix), mcpDirectTools);
31
+ } catch {
32
+ return [];
33
+ }
34
+ }
35
+ function loadMetadataCache() {
36
+ const cachePath = path.join(getAgentDir(), "mcp-cache.json");
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(fs.readFileSync(cachePath, "utf-8"));
40
+ } catch {
41
+ return null;
42
+ }
43
+ if (!parsed || typeof parsed !== "object")
44
+ return null;
45
+ const raw = parsed;
46
+ if (raw.version !== CACHE_VERSION || !raw.servers || typeof raw.servers !== "object" || Array.isArray(raw.servers)) {
47
+ return null;
48
+ }
49
+ return raw;
50
+ }
51
+ function loadMcpConfig(cwd) {
52
+ let config = { mcpServers: {} };
53
+ for (const sourcePath of getConfigPaths(cwd)) {
54
+ const loaded = readConfig(sourcePath);
55
+ if (!loaded)
56
+ continue;
57
+ config = mergeConfigs(config, expandImports(loaded, cwd));
58
+ }
59
+ return config;
60
+ }
61
+ function getConfigPaths(cwd) {
62
+ const piGlobalPath = path.join(getAgentDir(), "mcp.json");
63
+ const projectPath = path.resolve(cwd, ".mcp.json");
64
+ const projectPiPath = path.resolve(getProjectConfigDir(cwd), "mcp.json");
65
+ const sources = [];
66
+ if (GENERIC_GLOBAL_CONFIG_PATH !== piGlobalPath)
67
+ sources.push(GENERIC_GLOBAL_CONFIG_PATH);
68
+ sources.push(piGlobalPath);
69
+ if (projectPath !== piGlobalPath)
70
+ sources.push(projectPath);
71
+ if (projectPiPath !== piGlobalPath && projectPiPath !== projectPath)
72
+ sources.push(projectPiPath);
73
+ return sources;
74
+ }
75
+ function readConfig(configPath) {
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(fs.readFileSync(configPath, "utf-8"));
79
+ } catch {
80
+ return null;
81
+ }
82
+ return validateConfig(parsed);
83
+ }
84
+ function validateConfig(raw) {
85
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
86
+ return { mcpServers: {} };
87
+ const obj = raw;
88
+ const servers = obj.mcpServers ?? obj["mcp-servers"] ?? {};
89
+ return {
90
+ mcpServers: servers && typeof servers === "object" && !Array.isArray(servers) ? servers : {},
91
+ imports: Array.isArray(obj.imports) ? obj.imports.filter((value) => isImportKind(value)) : undefined,
92
+ settings: obj.settings && typeof obj.settings === "object" && !Array.isArray(obj.settings) ? obj.settings : undefined
93
+ };
94
+ }
95
+ function mergeConfigs(base, next) {
96
+ const imports = [...base.imports ?? [], ...next.imports ?? []];
97
+ return {
98
+ mcpServers: { ...base.mcpServers, ...next.mcpServers },
99
+ imports: imports.length ? [...new Set(imports)] : undefined,
100
+ settings: next.settings ? { ...base.settings, ...next.settings } : base.settings
101
+ };
102
+ }
103
+ function expandImports(config, cwd) {
104
+ if (!config.imports?.length)
105
+ return config;
106
+ const importedServers = {};
107
+ for (const importKind of config.imports) {
108
+ const importPath = resolveImportPath(importKind, cwd);
109
+ if (!importPath)
110
+ continue;
111
+ let imported;
112
+ try {
113
+ imported = JSON.parse(fs.readFileSync(importPath, "utf-8"));
114
+ } catch {
115
+ continue;
116
+ }
117
+ for (const [name, definition] of Object.entries(extractServers(imported, importKind))) {
118
+ if (!importedServers[name])
119
+ importedServers[name] = definition;
120
+ }
121
+ }
122
+ return {
123
+ imports: config.imports,
124
+ settings: config.settings,
125
+ mcpServers: { ...importedServers, ...config.mcpServers }
126
+ };
127
+ }
128
+ function resolveImportPath(importKind, cwd) {
129
+ for (const candidate of IMPORT_PATHS[importKind]) {
130
+ const fullPath = candidate.startsWith(".") ? path.resolve(cwd, candidate) : candidate;
131
+ if (fs.existsSync(fullPath))
132
+ return fullPath;
133
+ }
134
+ return null;
135
+ }
136
+ function extractServers(config, kind) {
137
+ if (!config || typeof config !== "object" || Array.isArray(config))
138
+ return {};
139
+ const obj = config;
140
+ const servers = kind === "cursor" || kind === "windsurf" || kind === "vscode" ? obj.mcpServers ?? obj["mcp-servers"] : obj.mcpServers;
141
+ return servers && typeof servers === "object" && !Array.isArray(servers) ? servers : {};
142
+ }
143
+ function resolveDirectToolNames(config, cache, prefix, envOverride) {
144
+ const names = [];
145
+ const seenNames = new Set;
146
+ const { servers: selectedServers, tools: selectedTools } = parseSelections(envOverride);
147
+ for (const [serverName, definition] of Object.entries(config.mcpServers)) {
148
+ const serverCache = cache.servers[serverName];
149
+ if (!isServerCacheValid(serverCache, definition))
150
+ continue;
151
+ const toolFilter = selectedServers.has(serverName) ? true : selectedTools.get(serverName);
152
+ if (!toolFilter)
153
+ continue;
154
+ for (const tool of Array.isArray(serverCache.tools) ? serverCache.tools : []) {
155
+ if (typeof tool?.name !== "string" || !tool.name)
156
+ continue;
157
+ if (toolFilter !== true && !toolFilter.has(tool.name))
158
+ continue;
159
+ if (isToolExcluded(tool.name, serverName, prefix, definition.excludeTools))
160
+ continue;
161
+ const prefixedName = formatToolName(tool.name, serverName, prefix);
162
+ if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName))
163
+ continue;
164
+ seenNames.add(prefixedName);
165
+ names.push(prefixedName);
166
+ }
167
+ if (definition.exposeResources === false)
168
+ continue;
169
+ for (const resource of Array.isArray(serverCache.resources) ? serverCache.resources : []) {
170
+ if (typeof resource?.name !== "string" || !resource.name || typeof resource.uri !== "string" || !resource.uri)
171
+ continue;
172
+ const baseName = `get_${resourceNameToToolName(resource.name)}`;
173
+ if (toolFilter !== true && !toolFilter.has(baseName))
174
+ continue;
175
+ if (isToolExcluded(baseName, serverName, prefix, definition.excludeTools))
176
+ continue;
177
+ const prefixedName = formatToolName(baseName, serverName, prefix);
178
+ if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName))
179
+ continue;
180
+ seenNames.add(prefixedName);
181
+ names.push(prefixedName);
182
+ }
183
+ }
184
+ return names;
185
+ }
186
+ function parseSelections(selections) {
187
+ const servers = new Set;
188
+ const tools = new Map;
189
+ for (let item of selections) {
190
+ item = item.replace(/\/+$/, "");
191
+ if (item.includes("/")) {
192
+ const [server, tool] = item.split("/", 2);
193
+ if (server && tool) {
194
+ if (!tools.has(server))
195
+ tools.set(server, new Set);
196
+ tools.get(server).add(tool);
197
+ } else if (server) {
198
+ servers.add(server);
199
+ }
200
+ } else if (item) {
201
+ servers.add(item);
202
+ }
203
+ }
204
+ return { servers, tools };
205
+ }
206
+ function isServerCacheValid(entry, definition) {
207
+ if (!entry || entry.configHash !== computeMcpServerHash(definition))
208
+ return false;
209
+ if (!entry.cachedAt || typeof entry.cachedAt !== "number")
210
+ return false;
211
+ return Date.now() - entry.cachedAt <= CACHE_MAX_AGE_MS;
212
+ }
213
+ export function computeMcpServerHash(definition) {
214
+ const identity = {
215
+ command: definition.command,
216
+ args: definition.args,
217
+ env: interpolateEnvRecord(definition.env),
218
+ cwd: resolveConfigPath(definition.cwd),
219
+ url: definition.url,
220
+ headers: interpolateEnvRecord(definition.headers),
221
+ auth: definition.auth,
222
+ bearerToken: resolveBearerToken(definition),
223
+ bearerTokenEnv: definition.bearerTokenEnv,
224
+ exposeResources: definition.exposeResources,
225
+ excludeTools: definition.excludeTools
226
+ };
227
+ return createHash("sha256").update(stableStringify(identity)).digest("hex");
228
+ }
229
+ function getToolPrefix(value) {
230
+ return value === "none" || value === "short" || value === "server" ? value : "server";
231
+ }
232
+ function isImportKind(value) {
233
+ return typeof value === "string" && Object.hasOwn(IMPORT_PATHS, value);
234
+ }
235
+ function getServerPrefix(serverName, mode) {
236
+ if (mode === "none")
237
+ return "";
238
+ if (mode === "short") {
239
+ const short = serverName.replace(/-?mcp$/i, "").replace(/-/g, "_");
240
+ return short || "mcp";
241
+ }
242
+ return serverName.replace(/-/g, "_");
243
+ }
244
+ function formatToolName(toolName, serverName, prefix) {
245
+ const serverPrefix = getServerPrefix(serverName, prefix);
246
+ return serverPrefix ? `${serverPrefix}_${toolName}` : toolName;
247
+ }
248
+ function isToolExcluded(toolName, serverName, prefix, excludeTools) {
249
+ if (!Array.isArray(excludeTools) || excludeTools.length === 0)
250
+ return false;
251
+ const candidates = new Set([
252
+ normalizeToolName(toolName),
253
+ normalizeToolName(formatToolName(toolName, serverName, prefix)),
254
+ normalizeToolName(formatToolName(toolName, serverName, "server")),
255
+ normalizeToolName(formatToolName(toolName, serverName, "short"))
256
+ ]);
257
+ return excludeTools.some((excluded) => typeof excluded === "string" && candidates.has(normalizeToolName(excluded)));
258
+ }
259
+ function normalizeToolName(value) {
260
+ return value.replace(/-/g, "_");
261
+ }
262
+ function resourceNameToToolName(name) {
263
+ let result = name.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_+/, "").replace(/_+$/, "").toLowerCase();
264
+ if (!result || /^\d/.test(result))
265
+ result = `resource${result ? `_${result}` : ""}`;
266
+ return result;
267
+ }
268
+ function interpolateEnvRecord(values) {
269
+ if (!values || typeof values !== "object" || Array.isArray(values))
270
+ return;
271
+ const resolved = {};
272
+ for (const [key, value] of Object.entries(values)) {
273
+ if (typeof value === "string")
274
+ resolved[key] = interpolateEnvVars(value);
275
+ }
276
+ return resolved;
277
+ }
278
+ function interpolateEnvVars(value) {
279
+ return value.replace(/\$\{(\w+)\}/g, (_, name) => process.env[name] ?? "").replace(/\$env:(\w+)/g, (_, name) => process.env[name] ?? "");
280
+ }
281
+ function resolveConfigPath(value) {
282
+ if (typeof value !== "string")
283
+ return;
284
+ const resolved = interpolateEnvVars(value);
285
+ if (resolved === "~")
286
+ return os.homedir();
287
+ if (resolved.startsWith("~/") || resolved.startsWith("~\\"))
288
+ return path.join(os.homedir(), resolved.slice(2));
289
+ return resolved;
290
+ }
291
+ function resolveBearerToken(definition) {
292
+ if (typeof definition.bearerToken === "string")
293
+ return interpolateEnvVars(definition.bearerToken);
294
+ return typeof definition.bearerTokenEnv === "string" ? process.env[definition.bearerTokenEnv] : undefined;
295
+ }
296
+ function stableStringify(value) {
297
+ if (value === null || value === undefined || typeof value !== "object") {
298
+ const serialized = JSON.stringify(value);
299
+ return serialized === undefined ? "undefined" : serialized;
300
+ }
301
+ if (Array.isArray(value))
302
+ return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
303
+ const obj = value;
304
+ return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(obj[key])}`).join(",")}}`;
305
+ }
@@ -1 +1,194 @@
1
- var N=["off","minimal","low","medium","high","xhigh"];function G(j){let J=j.lastIndexOf(":");if(J===-1)return{baseModel:j,thinkingSuffix:""};let Q=N.find((X)=>X===j.substring(J+1));if(!Q)return{baseModel:j,thinkingSuffix:""};return{baseModel:j.substring(0,J),thinkingSuffix:`:${Q}`}}function H(j){return G(j).baseModel}function q(j){let J=j.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${J}$`,"i")}function E(j,J){return q(J).test(H(j))}function A(j,J,Q){if(!j||!J?.enforce)return;let X=J.allow;if(!X||X.length===0)return;if(X.some((F)=>E(j,F)))return;let Z=H(j);return{model:Z,severity:Q==="explicit"?"error":"warn",allowedPatterns:X,message:`Model '${Z}' is outside the configured subagent model scope. Allowed patterns: ${X.join(", ")}.`}}function T(j){let J=j.lastIndexOf(":");if(J===-1)return{baseModel:j,thinkingSuffix:""};return{baseModel:j.substring(0,J),thinkingSuffix:j.substring(J)}}var k="inherit";function W(j){return j.toLowerCase().replace(/[._]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function z(j,J,Q){let X=Number(j),Z=Number(J),$=Number(Q);return X>=1900&&X<=2099&&Z>=1&&Z<=12&&$>=1&&$<=31}function V(j){let J=/^(.*)-(\d{4})-(\d{2})-(\d{2})$/.exec(j);if(J&&z(J[2],J[3],J[4]))return J[1];let Q=/^(.*)-(\d{4})(\d{2})(\d{2})$/.exec(j);if(Q&&z(Q[2],Q[3],Q[4]))return Q[1];return j}function K(j,J,Q){if(j.includes("/")){let X=J.find((Z)=>Z.fullId===j);if(X)return X.fullId}else{let X=J.filter((Z)=>Z.id===j);if(Q){let Z=X.find(($)=>$.provider===Q);if(Z)return Z.fullId}if(X.length===1)return X[0].fullId}return S(j,J,Q)}function S(j,J,Q){let X,Z=j,$=j.indexOf("/");if($!==-1)X=W(j.slice(0,$)),Z=j.slice($+1);else{let O=[":","."];for(let U of O){let D=j.indexOf(U);if(D<=0)continue;let B=W(j.slice(0,D));if(!J.some((L)=>W(L.provider)===B))continue;X=B,Z=j.slice(D+1);break}}let F=W(Z),C=V(F),Y=J.filter((O)=>{let U=W(O.id);if(U!==F&&V(U)!==C)return!1;if(X!==void 0&&W(O.provider)!==X)return!1;return!0});if(Y.length===0)return;if(Q){let O=W(Q),U=Y.find((D)=>W(D.provider)===O);if(U)return U.fullId}if(Y.length===1)return Y[0].fullId;return}function _(j,J,Q){if(!j)return;if(!J||J.length===0)return j;let X=K(j,J,Q);if(X)return X;let{baseModel:Z,thinkingSuffix:$}=T(j);if(!$)return j;let F=K(Z,J,Q);if(F)return`${F}${$}`;return j}function R(j){console.warn(`[dm-subagents] ${j.message}`)}function h(j,J,Q,X,Z){let $=typeof j==="string"?j.trim():"",F=$&&$!==k?$:void 0,C;if(F===void 0)C=J?`${J.provider}/${J.id}`:void 0;else C=_(F,Q,X);if(C&&Z?.scope?.enforce){let Y=F===void 0?"inherited":Z.source??"inherited",O=A(C,Z.scope,Y);if(O){if(O.severity==="error")throw Error(O.message);(Z.onWarn??R)(O)}}return C}function y(j,J,Q,X,Z){let $=new Set,F=[],C=[j,...J??[]];for(let Y=0;Y<C.length;Y++){let O=C[Y];if(!O)continue;let U=_(O.trim(),Q,X);if(!U||$.has(U))continue;if(Y>0&&Z?.scope?.enforce){let D=A(U,Z.scope,"inherited");if(D)(Z.onWarn??R)(D)}$.add(U),F.push(U)}return F}var w=[/rate\s*limit/i,/too many requests/i,/\b429\b/,/quota/i,/billing/i,/credit/i,/auth(?:entication)?/i,/unauthori[sz]ed/i,/forbidden/i,/api key/i,/token expired/i,/invalid key/i,/provider.*unavailable/i,/model.*unavailable/i,/model.*disabled/i,/model.*not found/i,/unknown model/i,/overloaded/i,/service unavailable/i,/temporar(?:ily)? unavailable/i,/connection refused/i,/fetch failed/i,/network error/i,/socket hang up/i,/upstream/i,/timed? out/i,/timeout/i,/\b502\b/,/\b503\b/,/\b504\b/,/cold.?start/i,/empty response/i,/no output/i,/model.*(?:load|fail|error)/i];function u(j){if(!j)return!1;return w.some((J)=>J.test(j))}function b(j,J){let Q=j.error?.trim()||`exit ${j.exitCode??1}`;return J?`[fallback] ${j.model} failed: ${Q}. Retrying with ${J}.`:`[fallback] ${j.model} failed: ${Q}.`}export{T as splitThinkingSuffix,h as resolveSubagentModelOverride,_ as resolveModelCandidate,W as normalizeModelSegment,u as isRetryableModelFailure,S as fuzzyResolveModel,b as formatModelAttemptNote,y as buildModelCandidates,k as INHERIT_MODEL};
1
+ import { checkModelScope } from "./model-scope.js";
2
+ export function splitThinkingSuffix(model) {
3
+ const colonIdx = model.lastIndexOf(":");
4
+ if (colonIdx === -1)
5
+ return { baseModel: model, thinkingSuffix: "" };
6
+ return {
7
+ baseModel: model.substring(0, colonIdx),
8
+ thinkingSuffix: model.substring(colonIdx)
9
+ };
10
+ }
11
+ export const INHERIT_MODEL = "inherit";
12
+ export function normalizeModelSegment(segment) {
13
+ return segment.toLowerCase().replace(/[._]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
14
+ }
15
+ function isPlausibleDateStamp(year, month, day) {
16
+ const yyyy = Number(year);
17
+ const mm = Number(month);
18
+ const dd = Number(day);
19
+ return yyyy >= 1900 && yyyy <= 2099 && mm >= 1 && mm <= 12 && dd >= 1 && dd <= 31;
20
+ }
21
+ function stripTrailingDateStamp(segment) {
22
+ const dashed = /^(.*)-(\d{4})-(\d{2})-(\d{2})$/.exec(segment);
23
+ if (dashed && isPlausibleDateStamp(dashed[2], dashed[3], dashed[4]))
24
+ return dashed[1];
25
+ const compact = /^(.*)-(\d{4})(\d{2})(\d{2})$/.exec(segment);
26
+ if (compact && isPlausibleDateStamp(compact[2], compact[3], compact[4]))
27
+ return compact[1];
28
+ return segment;
29
+ }
30
+ function resolveBaseModelCandidate(baseModel, availableModels, preferredProvider) {
31
+ if (baseModel.includes("/")) {
32
+ const exact = availableModels.find((entry) => entry.fullId === baseModel);
33
+ if (exact)
34
+ return exact.fullId;
35
+ } else {
36
+ const exactMatches = availableModels.filter((entry) => entry.id === baseModel);
37
+ if (preferredProvider) {
38
+ const preferredMatch = exactMatches.find((entry) => entry.provider === preferredProvider);
39
+ if (preferredMatch)
40
+ return preferredMatch.fullId;
41
+ }
42
+ if (exactMatches.length === 1)
43
+ return exactMatches[0].fullId;
44
+ }
45
+ return fuzzyResolveModel(baseModel, availableModels, preferredProvider);
46
+ }
47
+ export function fuzzyResolveModel(baseModel, availableModels, preferredProvider) {
48
+ let queryProvider;
49
+ let queryIdRaw = baseModel;
50
+ const slashIdx = baseModel.indexOf("/");
51
+ if (slashIdx !== -1) {
52
+ queryProvider = normalizeModelSegment(baseModel.slice(0, slashIdx));
53
+ queryIdRaw = baseModel.slice(slashIdx + 1);
54
+ } else {
55
+ const providerSeparators = [":", "."];
56
+ for (const separator of providerSeparators) {
57
+ const separatorIdx = baseModel.indexOf(separator);
58
+ if (separatorIdx <= 0)
59
+ continue;
60
+ const providerPart = normalizeModelSegment(baseModel.slice(0, separatorIdx));
61
+ if (!availableModels.some((entry) => normalizeModelSegment(entry.provider) === providerPart))
62
+ continue;
63
+ queryProvider = providerPart;
64
+ queryIdRaw = baseModel.slice(separatorIdx + 1);
65
+ break;
66
+ }
67
+ }
68
+ const queryId = normalizeModelSegment(queryIdRaw);
69
+ const queryIdNoDate = stripTrailingDateStamp(queryId);
70
+ const candidates = availableModels.filter((entry) => {
71
+ const entryId = normalizeModelSegment(entry.id);
72
+ if (entryId !== queryId && stripTrailingDateStamp(entryId) !== queryIdNoDate)
73
+ return false;
74
+ if (queryProvider !== undefined && normalizeModelSegment(entry.provider) !== queryProvider)
75
+ return false;
76
+ return true;
77
+ });
78
+ if (candidates.length === 0)
79
+ return;
80
+ if (preferredProvider) {
81
+ const preferredProviderNorm = normalizeModelSegment(preferredProvider);
82
+ const preferred = candidates.find((entry) => normalizeModelSegment(entry.provider) === preferredProviderNorm);
83
+ if (preferred)
84
+ return preferred.fullId;
85
+ }
86
+ if (candidates.length === 1)
87
+ return candidates[0].fullId;
88
+ return;
89
+ }
90
+ export function resolveModelCandidate(model, availableModels, preferredProvider) {
91
+ if (!model)
92
+ return;
93
+ if (!availableModels || availableModels.length === 0)
94
+ return model;
95
+ const resolvedWhole = resolveBaseModelCandidate(model, availableModels, preferredProvider);
96
+ if (resolvedWhole)
97
+ return resolvedWhole;
98
+ const { baseModel, thinkingSuffix } = splitThinkingSuffix(model);
99
+ if (!thinkingSuffix)
100
+ return model;
101
+ const resolvedBase = resolveBaseModelCandidate(baseModel, availableModels, preferredProvider);
102
+ if (resolvedBase)
103
+ return `${resolvedBase}${thinkingSuffix}`;
104
+ return model;
105
+ }
106
+ function defaultScopeWarn(violation) {
107
+ console.warn(`[dm-subagents] ${violation.message}`);
108
+ }
109
+ export function resolveSubagentModelOverride(requestedModel, parentModel, availableModels, preferredProvider, options) {
110
+ const trimmed = typeof requestedModel === "string" ? requestedModel.trim() : "";
111
+ const explicit = trimmed && trimmed !== INHERIT_MODEL ? trimmed : undefined;
112
+ let resolved;
113
+ if (explicit === undefined) {
114
+ resolved = parentModel ? `${parentModel.provider}/${parentModel.id}` : undefined;
115
+ } else {
116
+ resolved = resolveModelCandidate(explicit, availableModels, preferredProvider);
117
+ }
118
+ if (resolved && options?.scope?.enforce) {
119
+ const source = explicit === undefined ? "inherited" : options.source ?? "inherited";
120
+ const violation = checkModelScope(resolved, options.scope, source);
121
+ if (violation) {
122
+ if (violation.severity === "error")
123
+ throw new Error(violation.message);
124
+ (options.onWarn ?? defaultScopeWarn)(violation);
125
+ }
126
+ }
127
+ return resolved;
128
+ }
129
+ export function buildModelCandidates(primaryModel, fallbackModels, availableModels, preferredProvider, options) {
130
+ const seen = new Set;
131
+ const candidates = [];
132
+ const rawCandidates = [primaryModel, ...fallbackModels ?? []];
133
+ for (let index = 0;index < rawCandidates.length; index++) {
134
+ const raw = rawCandidates[index];
135
+ if (!raw)
136
+ continue;
137
+ const normalized = resolveModelCandidate(raw.trim(), availableModels, preferredProvider);
138
+ if (!normalized || seen.has(normalized))
139
+ continue;
140
+ if (index > 0 && options?.scope?.enforce) {
141
+ const violation = checkModelScope(normalized, options.scope, "inherited");
142
+ if (violation)
143
+ (options.onWarn ?? defaultScopeWarn)(violation);
144
+ }
145
+ seen.add(normalized);
146
+ candidates.push(normalized);
147
+ }
148
+ return candidates;
149
+ }
150
+ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
151
+ /rate\s*limit/i,
152
+ /too many requests/i,
153
+ /\b429\b/,
154
+ /quota/i,
155
+ /billing/i,
156
+ /credit/i,
157
+ /auth(?:entication)?/i,
158
+ /unauthori[sz]ed/i,
159
+ /forbidden/i,
160
+ /api key/i,
161
+ /token expired/i,
162
+ /invalid key/i,
163
+ /provider.*unavailable/i,
164
+ /model.*unavailable/i,
165
+ /model.*disabled/i,
166
+ /model.*not found/i,
167
+ /unknown model/i,
168
+ /overloaded/i,
169
+ /service unavailable/i,
170
+ /temporar(?:ily)? unavailable/i,
171
+ /connection refused/i,
172
+ /fetch failed/i,
173
+ /network error/i,
174
+ /socket hang up/i,
175
+ /upstream/i,
176
+ /timed? out/i,
177
+ /timeout/i,
178
+ /\b502\b/,
179
+ /\b503\b/,
180
+ /\b504\b/,
181
+ /cold.?start/i,
182
+ /empty response/i,
183
+ /no output/i,
184
+ /model.*(?:load|fail|error)/i
185
+ ];
186
+ export function isRetryableModelFailure(error) {
187
+ if (!error)
188
+ return false;
189
+ return RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(error));
190
+ }
191
+ export function formatModelAttemptNote(attempt, nextModel) {
192
+ const failure = attempt.error?.trim() || `exit ${attempt.exitCode ?? 1}`;
193
+ return nextModel ? `[fallback] ${attempt.model} failed: ${failure}. Retrying with ${nextModel}.` : `[fallback] ${attempt.model} failed: ${failure}.`;
194
+ }
@@ -1 +1,65 @@
1
- var Q=["off","minimal","low","medium","high","xhigh"];function J(j){let q=j.lastIndexOf(":");if(q===-1)return{baseModel:j,thinkingSuffix:""};let B=Q.find((A)=>A===j.substring(q+1));if(!B)return{baseModel:j,thinkingSuffix:""};return{baseModel:j.substring(0,q),thinkingSuffix:`:${B}`}}function O(j){return J(j).baseModel}function U(j){let q=j.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${q}$`,"i")}function W(j,q){return U(q).test(O(j))}function Z(j,q,B){if(!j||!q?.enforce)return;let A=q.allow;if(!A||A.length===0)return;if(A.some((D)=>W(j,D)))return;let C=O(j);return{model:C,severity:B==="explicit"?"error":"warn",allowedPatterns:A,message:`Model '${C}' is outside the configured subagent model scope. Allowed patterns: ${A.join(", ")}.`}}function $(j,q){if(j===void 0)return;if(!j||typeof j!=="object"||Array.isArray(j))throw Error(`Subagent settings in '${q.filePath}' have invalid 'modelScope'; expected an object.`);let B=j,A={};if("enforce"in B){if(typeof B.enforce!=="boolean")throw Error(`Subagent settings in '${q.filePath}' have invalid 'modelScope.enforce'; expected a boolean.`);A.enforce=B.enforce}if("allow"in B){if(!Array.isArray(B.allow))throw Error(`Subagent settings in '${q.filePath}' have invalid 'modelScope.allow'; expected an array of strings.`);let C=[];for(let F of B.allow){if(typeof F!=="string")throw Error(`Subagent settings in '${q.filePath}' have invalid 'modelScope.allow'; expected an array of strings.`);let D=F.trim();if(D)C.push(D)}if(C.length===0)throw Error(`Subagent settings in '${q.filePath}' have invalid 'modelScope.allow'; expected a non-empty array of patterns.`);A.allow=C}if(A.enforce===!0&&(!A.allow||A.allow.length===0))throw Error(`Subagent settings in '${q.filePath}' set modelScope.enforce without a non-empty 'allow' list; supply allowed model patterns or disable enforcement.`);return Object.keys(A).length>0?A:void 0}export{$ as parseModelScopeConfig,W as matchesScopePattern,Z as checkModelScope};
1
+ import { splitKnownThinkingSuffix } from "../../shared/model-info.js";
2
+ function stripThinkingSuffix(model) {
3
+ return splitKnownThinkingSuffix(model).baseModel;
4
+ }
5
+ function globToRegExp(pattern) {
6
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
7
+ return new RegExp(`^${escaped}$`, "i");
8
+ }
9
+ export function matchesScopePattern(model, pattern) {
10
+ return globToRegExp(pattern).test(stripThinkingSuffix(model));
11
+ }
12
+ export function checkModelScope(model, scope, source) {
13
+ if (!model || !scope?.enforce)
14
+ return;
15
+ const allow = scope.allow;
16
+ if (!allow || allow.length === 0)
17
+ return;
18
+ if (allow.some((pattern) => matchesScopePattern(model, pattern)))
19
+ return;
20
+ const baseModel = stripThinkingSuffix(model);
21
+ const severity = source === "explicit" ? "error" : "warn";
22
+ return {
23
+ model: baseModel,
24
+ severity,
25
+ allowedPatterns: allow,
26
+ message: `Model '${baseModel}' is outside the configured subagent model scope. ` + `Allowed patterns: ${allow.join(", ")}.`
27
+ };
28
+ }
29
+ export function parseModelScopeConfig(value, meta) {
30
+ if (value === undefined)
31
+ return;
32
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
33
+ throw new Error(`Subagent settings in '${meta.filePath}' have invalid 'modelScope'; expected an object.`);
34
+ }
35
+ const input = value;
36
+ const config = {};
37
+ if ("enforce" in input) {
38
+ if (typeof input.enforce !== "boolean") {
39
+ throw new Error(`Subagent settings in '${meta.filePath}' have invalid 'modelScope.enforce'; expected a boolean.`);
40
+ }
41
+ config.enforce = input.enforce;
42
+ }
43
+ if ("allow" in input) {
44
+ if (!Array.isArray(input.allow)) {
45
+ throw new Error(`Subagent settings in '${meta.filePath}' have invalid 'modelScope.allow'; expected an array of strings.`);
46
+ }
47
+ const allow = [];
48
+ for (const entry of input.allow) {
49
+ if (typeof entry !== "string") {
50
+ throw new Error(`Subagent settings in '${meta.filePath}' have invalid 'modelScope.allow'; expected an array of strings.`);
51
+ }
52
+ const trimmed = entry.trim();
53
+ if (trimmed)
54
+ allow.push(trimmed);
55
+ }
56
+ if (allow.length === 0) {
57
+ throw new Error(`Subagent settings in '${meta.filePath}' have invalid 'modelScope.allow'; expected a non-empty array of patterns.`);
58
+ }
59
+ config.allow = allow;
60
+ }
61
+ if (config.enforce === true && (!config.allow || config.allow.length === 0)) {
62
+ throw new Error(`Subagent settings in '${meta.filePath}' set modelScope.enforce without a non-empty 'allow' list; supply allowed model patterns or disable enforcement.`);
63
+ }
64
+ return Object.keys(config).length > 0 ? config : undefined;
65
+ }