mixdog 1.1.2 → 1.2.1

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 (424) hide show
  1. package/README.md +8 -5
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +10 -0
  7. package/src/defaults/skills/pptx/SKILL.md +6 -6
  8. package/src/defaults/skills/pptx/references/review.md +6 -4
  9. package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
  10. package/src/defaults/skills/setup/references/actions.md +18 -5
  11. package/src/defaults/skills/visualize/SKILL.md +160 -0
  12. package/src/defaults/skills/visualize/references/craft.md +88 -0
  13. package/src/headless-command.mjs +56 -3
  14. package/src/headless-exec.mjs +17 -1
  15. package/src/help.mjs +2 -0
  16. package/src/rules/shared/60-verification.md +3 -1
  17. package/src/rules/shared/70-delivery.md +4 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
  22. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  24. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  25. package/src/runtime/agent/orchestrator/config.mjs +19 -5
  26. package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
  27. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
  28. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
  29. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +133 -15
  30. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +55 -8
  31. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +86 -8
  32. package/src/runtime/agent/orchestrator/mcp/client.mjs +474 -164
  33. package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
  34. package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
  35. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  36. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
  37. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  38. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  40. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +32 -12
  41. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
  43. package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
  44. package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
  45. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
  46. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  47. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
  50. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +21 -6
  51. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  52. package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
  53. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  54. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  55. package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
  56. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  57. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  58. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  59. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  60. package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
  61. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +82 -0
  62. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +556 -0
  63. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  64. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  65. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  66. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +15 -0
  67. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
  68. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
  72. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +15 -4
  73. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
  77. package/src/runtime/agent/orchestrator/providers/registry.mjs +47 -7
  78. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  79. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  80. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -11
  81. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
  83. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +278 -84
  85. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
  87. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
  88. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  89. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  90. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  91. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  92. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
  93. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
  94. package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
  95. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
  96. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  97. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +24 -13
  98. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  99. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  100. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  101. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
  102. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
  103. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
  104. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
  105. package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
  106. package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
  107. package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
  108. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
  109. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  112. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  113. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  114. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +5 -3
  115. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -4
  116. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +21 -10
  117. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
  118. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
  120. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -3
  121. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +22 -12
  122. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
  123. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +9 -3
  124. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  125. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  126. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  127. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
  128. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  131. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  133. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
  136. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  137. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  138. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +33 -22
  139. package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
  140. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  141. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
  142. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  143. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  144. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
  145. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +36 -0
  146. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +23 -12
  147. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
  148. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +202 -374
  149. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  150. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
  151. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
  152. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +48 -9
  153. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +161 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
  155. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
  156. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  157. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  158. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  159. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
  160. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
  161. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  162. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +203 -33
  163. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  164. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
  165. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  166. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  167. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -68
  168. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  169. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +20 -3
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  173. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  174. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  175. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  176. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
  177. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
  179. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  180. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  181. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
  182. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  184. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
  185. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
  186. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
  187. package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
  188. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
  189. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
  190. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  191. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  192. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
  193. package/src/runtime/attachments/store.d.mts +3 -0
  194. package/src/runtime/attachments/store.mjs +38 -0
  195. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
  196. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
  197. package/src/runtime/channels/lib/worker-main.mjs +17 -14
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
  199. package/src/runtime/effort-judge/judge-client.mjs +56 -18
  200. package/src/runtime/memory/lib/memory.mjs +1 -1
  201. package/src/runtime/memory/lib/session-ingest.mjs +2 -2
  202. package/src/runtime/shared/atomic-file.mjs +33 -6
  203. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  204. package/src/runtime/shared/code-graph-state.mjs +12 -0
  205. package/src/runtime/shared/defaults-separation.mjs +2 -0
  206. package/src/runtime/shared/extension-scopes.mjs +5 -3
  207. package/src/runtime/shared/file-lock.mjs +37 -11
  208. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  209. package/src/runtime/shared/git-runner.mjs +4 -3
  210. package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
  211. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  212. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  213. package/src/runtime/shared/llm/model-catalog.mjs +240 -130
  214. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  215. package/src/runtime/shared/llm/provider-catalog-registry.mjs +162 -0
  216. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  217. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  218. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  219. package/src/runtime/shared/plugin-manifest.mjs +18 -9
  220. package/src/runtime/shared/pristine-execution-contract.json +9 -2
  221. package/src/runtime/shared/pristine-execution.mjs +28 -4
  222. package/src/runtime/shared/provider-accounts.mjs +125 -21
  223. package/src/runtime/shared/provider-api-key.mjs +33 -1
  224. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  225. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  226. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  227. package/src/runtime/shared/shell-display.mjs +9 -3
  228. package/src/runtime/shared/singleton-owner.mjs +36 -6
  229. package/src/runtime/shared/skill-mentions.d.mts +10 -0
  230. package/src/runtime/shared/skill-mentions.mjs +133 -0
  231. package/src/runtime/shared/skill-script-runtime.mjs +264 -0
  232. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  233. package/src/runtime/shared/tool-primitives.mjs +35 -2
  234. package/src/runtime/shared/tool-surface.mjs +7 -0
  235. package/src/runtime/shared/tool-work-units.mjs +14 -0
  236. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  237. package/src/runtime/shared/turn-changes.mjs +791 -0
  238. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  239. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  240. package/src/runtime/shared/turn-worktree-snapshot.mjs +185 -15
  241. package/src/runtime/shared/worker-requests.mjs +15 -2
  242. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  243. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  244. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  245. package/src/runtime/shared/worktrees/git.mjs +247 -0
  246. package/src/runtime/shared/worktrees/include.mjs +480 -0
  247. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  248. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  249. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  250. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  251. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  252. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  253. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  254. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  255. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  256. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  257. package/src/runtime/visualize-bridge/client.mjs +181 -0
  258. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  259. package/src/session-runtime/automation-agents.mjs +8 -2
  260. package/src/session-runtime/boot/apis.mjs +90 -0
  261. package/src/session-runtime/boot/config.mjs +7 -2
  262. package/src/session-runtime/boot/facade.mjs +21 -0
  263. package/src/session-runtime/boot/infrastructure.mjs +30 -18
  264. package/src/session-runtime/boot/session.mjs +1 -0
  265. package/src/session-runtime/boot/tools.mjs +4 -0
  266. package/src/session-runtime/config-lifecycle.mjs +10 -1
  267. package/src/session-runtime/conversation-import/discovery.mjs +698 -0
  268. package/src/session-runtime/conversation-import/service.mjs +369 -0
  269. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +21 -6
  270. package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
  271. package/src/session-runtime/global-extensions.mjs +2 -2
  272. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  273. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  274. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  275. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  276. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  277. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  278. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  279. package/src/session-runtime/mcp-glue/connect.mjs +68 -16
  280. package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
  281. package/src/session-runtime/mcp-glue/server-catalog.mjs +122 -33
  282. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  283. package/src/session-runtime/mcp-glue.mjs +22 -2
  284. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  285. package/src/session-runtime/model-route/set-route.mjs +15 -2
  286. package/src/session-runtime/new-session-config.mjs +3 -2
  287. package/src/session-runtime/notification-bus.mjs +18 -3
  288. package/src/session-runtime/provider-auth/accounts.mjs +33 -15
  289. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  290. package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
  291. package/src/session-runtime/provider-readiness.mjs +16 -10
  292. package/src/session-runtime/resource-extension-sync.mjs +45 -7
  293. package/src/session-runtime/resource-mcp-api.mjs +121 -84
  294. package/src/session-runtime/resource-plugins-api.mjs +29 -41
  295. package/src/session-runtime/resource-scope-decorate.mjs +6 -8
  296. package/src/session-runtime/resource-skills-api.mjs +23 -2
  297. package/src/session-runtime/route-resolution.mjs +10 -1
  298. package/src/session-runtime/route-state.mjs +16 -2
  299. package/src/session-runtime/runtime-core.mjs +5 -0
  300. package/src/session-runtime/runtime-facade.mjs +8 -0
  301. package/src/session-runtime/runtime-review-api.mjs +9 -0
  302. package/src/session-runtime/schedule-session-run.mjs +1 -1
  303. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  304. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  305. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  306. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  307. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  308. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  309. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  310. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  311. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  312. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  313. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  314. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  315. package/src/session-runtime/services/agent-tool.mjs +1 -0
  316. package/src/session-runtime/services/channel-session-router.mjs +4 -1
  317. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  318. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  319. package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
  320. package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
  321. package/src/session-runtime/services/provider-admin.mjs +64 -18
  322. package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
  323. package/src/session-runtime/session-create/session-options.mjs +10 -1
  324. package/src/session-runtime/session-turn-api.mjs +1 -0
  325. package/src/session-runtime/settings-api.mjs +4 -2
  326. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  327. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  328. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  329. package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
  330. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -1
  331. package/src/session-runtime/setup-tool/tool-defs.mjs +38 -4
  332. package/src/session-runtime/skills-api.mjs +7 -3
  333. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  334. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +14 -3
  335. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  336. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  337. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  338. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  339. package/src/session-runtime/turn/turn-run.mjs +6 -7
  340. package/src/session-runtime/webhook-session-run.mjs +16 -4
  341. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  342. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  343. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  344. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  345. package/src/session-runtime/workspace/transitions.mjs +651 -0
  346. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  347. package/src/skill-script-entry.mjs +36 -0
  348. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  349. package/src/standalone/channel-transport.mjs +13 -1
  350. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  351. package/src/standalone/daemon-owner.mjs +372 -0
  352. package/src/standalone/daemon-stored-session-views.mjs +15 -4
  353. package/src/standalone/daemon.mjs +179 -8
  354. package/src/standalone/desktop-service-registry.mjs +20 -0
  355. package/src/standalone/local-session-runtime.mjs +11 -0
  356. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  357. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  358. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  359. package/src/standalone/session-client.mjs +104 -13
  360. package/src/standalone/session-protocol.mjs +21 -0
  361. package/src/standalone/session-proxy.mjs +3 -0
  362. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  363. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  364. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  365. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  366. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  367. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  368. package/src/standalone/session-service/session-calls/session-action.mjs +17 -4
  369. package/src/standalone/session-transport/call-route.mjs +13 -0
  370. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  371. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  372. package/src/standalone/session-transport/client-registry.mjs +20 -3
  373. package/src/standalone/session-transport/routes.mjs +79 -2
  374. package/src/standalone/session-transport/stack.mjs +2 -0
  375. package/src/standalone/session-transport.mjs +24 -1
  376. package/src/tui/App.jsx +9 -1
  377. package/src/tui/app/app-view/floating-panel.jsx +9 -1
  378. package/src/tui/app/app-view.jsx +6 -0
  379. package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
  380. package/src/tui/app/message-selector.mjs +2 -1
  381. package/src/tui/app/model-options.mjs +37 -5
  382. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  383. package/src/tui/app/model-picker.mjs +4 -2
  384. package/src/tui/app/skill-mention-palette.mjs +88 -0
  385. package/src/tui/app/slash-palette.mjs +23 -7
  386. package/src/tui/app/transcript-row-estimate.mjs +11 -3
  387. package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
  388. package/src/tui/app/use-prompt-state.mjs +5 -0
  389. package/src/tui/components/Message.jsx +22 -1
  390. package/src/tui/components/PromptInput.jsx +21 -3
  391. package/src/tui/components/SlashCommandPalette.jsx +12 -3
  392. package/src/tui/components/TranscriptItem.jsx +9 -1
  393. package/src/tui/components/prompt-input/key-handler.mjs +21 -8
  394. package/src/tui/components/user-message-skills.mjs +38 -0
  395. package/src/tui/dist/index.mjs +839 -207
  396. package/src/tui/index.jsx +10 -2
  397. package/src/tui/session/compaction-view.mjs +147 -0
  398. package/src/tui/session/context-state.mjs +6 -0
  399. package/src/tui/session/initial-state.mjs +3 -0
  400. package/src/tui/session/queue-helpers.mjs +7 -2
  401. package/src/tui/session/quota-resume.mjs +2 -1
  402. package/src/tui/session/session-api/commands.mjs +10 -2
  403. package/src/tui/session/session-api/controls.mjs +4 -0
  404. package/src/tui/session/session-api/extensions.mjs +4 -2
  405. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  406. package/src/tui/session/session-api/integrations.mjs +17 -0
  407. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  408. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  409. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  410. package/src/tui/session/session-api/routes.mjs +10 -1
  411. package/src/tui/session/session-api/settings.mjs +9 -0
  412. package/src/tui/session/session-api/worktree.mjs +60 -0
  413. package/src/tui/session/session-api.mjs +2 -0
  414. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  415. package/src/tui/session/session-flow/drain.mjs +27 -3
  416. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  417. package/src/tui/session/session-flow.mjs +2 -0
  418. package/src/tui/session/transcript-intake.mjs +14 -5
  419. package/src/tui/session/tui-steering-persist.mjs +25 -9
  420. package/src/tui/session/turn-stream.mjs +32 -4
  421. package/src/tui/session/turn-tool-cards.mjs +10 -2
  422. package/src/tui/session/turn.mjs +56 -10
  423. package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
  424. package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
@@ -0,0 +1,499 @@
1
+ // MCP servers derived live from enabled plugins. Nothing here is written into
2
+ // `config.mcpServers`: every resolve reads the registered plugins' declarations
3
+ // and folds in the user's per-server intent (`config.pluginMcp`). Also owns the
4
+ // one-time adoption of server copies an older enable action wrote into
5
+ // `config.mcpServers`, as a pure plan the caller may persist.
6
+ import { createHash } from 'node:crypto';
7
+ import { mkdirSync } from 'node:fs';
8
+ import { isAbsolute, join, resolve } from 'node:path';
9
+ import { isDeepStrictEqual } from 'node:util';
10
+ import {
11
+ PLUGIN_MCP_OVERRIDE_MAP_FIELDS,
12
+ PLUGIN_MCP_OVERRIDE_VALUE_FIELDS,
13
+ declaredMcpTransport,
14
+ loadPluginMcpDeclarations,
15
+ normalizePluginMcpIntents,
16
+ } from '../../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
17
+ import {
18
+ pluginServerEnv,
19
+ resolvePluginPlaceholders,
20
+ } from '../../runtime/agent/orchestrator/mcp/plugin-placeholders.mjs';
21
+ import { clean } from '../../runtime/shared/clean.mjs';
22
+ import { isPlainObject } from '../../runtime/shared/object.mjs';
23
+
24
+ // Tool names are `mcp__<server>__<tool>` and providers cap a tool name at 64
25
+ // characters of [A-Za-z0-9_-]; a short hyphenated server name leaves the tool
26
+ // its room and can never contain the `__` delimiter.
27
+ export const PLUGIN_MCP_NAME_MAX = 32;
28
+ const LEGACY_ENV_KEYS = new Set(['MIXDOG_PLUGIN_ROOT', 'MIXDOG_PLUGIN_DATA']);
29
+ const CASE_INSENSITIVE_PATHS = process.platform === 'win32';
30
+
31
+ function slug(value) {
32
+ return String(value || '')
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9]+/g, '-')
35
+ .replace(/^-+|-+$/g, '');
36
+ }
37
+
38
+ function shortHash(text, length) {
39
+ return createHash('sha1').update(text).digest('hex').slice(0, length);
40
+ }
41
+
42
+ function withSuffix(name, suffix) {
43
+ return `${name.slice(0, PLUGIN_MCP_NAME_MAX - suffix.length - 1).replace(/-+$/, '')}-${suffix}`;
44
+ }
45
+
46
+ /** Name of one plugin server: the registry id (without its source hash) and
47
+ * the declared key, the key dropped when it repeats the plugin. Never depends
48
+ * on how many servers the plugin declares. */
49
+ export function pluginMcpServerBaseName(pluginId, key) {
50
+ const stem = slug(String(pluginId || '').replace(/-[0-9a-f]{8}$/i, '')) || 'plugin';
51
+ const leaf = slug(key) || 'mcp';
52
+ const name = leaf === stem ? `plugin-${stem}` : `plugin-${stem}-${leaf}`;
53
+ return name.length <= PLUGIN_MCP_NAME_MAX ? name : withSuffix(name, shortHash(`${pluginId}\0${key}`, 8));
54
+ }
55
+
56
+ function disambiguatedName(base, pluginId, key, taken) {
57
+ const suffix = shortHash(`${pluginId}\0${key}`, 6);
58
+ let name = withSuffix(base, suffix);
59
+ for (let n = 2; taken.has(name); n += 1) name = withSuffix(base, `${suffix}${n}`);
60
+ return name;
61
+ }
62
+
63
+ // The name an earlier enable action gave a plugin's server copy.
64
+ function legacyServerName(plugin) {
65
+ const base = clean(plugin.name || plugin.title || 'plugin')
66
+ .toLowerCase()
67
+ .replace(/[^a-z0-9_.-]+/g, '-')
68
+ .replace(/^-+|-+$/g, '');
69
+ return base ? `plugin-${base}` : 'plugin-mcp';
70
+ }
71
+
72
+ function comparablePath(path) {
73
+ const text = clean(path);
74
+ if (!text) return '';
75
+ const unified = resolve(text)
76
+ .replace(/[\\/]+/g, '/')
77
+ .replace(/\/$/, '');
78
+ return CASE_INSENSITIVE_PATHS ? unified.toLowerCase() : unified;
79
+ }
80
+
81
+ // How an earlier enable action rewrote a declaration before copying it.
82
+ function legacyCopyForm(value, root) {
83
+ if (typeof value === 'string') {
84
+ return value.replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, root).replace(/\$\{CODEX_PLUGIN_ROOT\}/g, root);
85
+ }
86
+ if (Array.isArray(value)) return value.map((v) => legacyCopyForm(v, root));
87
+ if (isPlainObject(value))
88
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, legacyCopyForm(v, root)]));
89
+ return value;
90
+ }
91
+
92
+ function sameTransport(copy, declared, root) {
93
+ const form = legacyCopyForm(declared, root);
94
+ return ['command', 'args', 'url'].every((field) => isDeepStrictEqual(copy[field], form[field]));
95
+ }
96
+
97
+ const comparableTransport = (config) => {
98
+ const type = declaredMcpTransport(config);
99
+ return type === 'streamable-http' ? 'http' : type;
100
+ };
101
+
102
+ /** What the user changed in a copy relative to the declaration it was made
103
+ * from: `{ overrides }` when every change is something a plugin server
104
+ * override applies, else `{ reason }` (the copy is then left as configured,
105
+ * so nothing is ever dropped). Values the earlier enable action generated
106
+ * itself (plugin env markers, the forced cwd, enable flags) are not changes. */
107
+ function copyOverrides(copy, declared, root) {
108
+ const form = legacyCopyForm(declared, root);
109
+ const out = {};
110
+ const kept = [];
111
+ for (const field of new Set([...Object.keys(copy), ...Object.keys(form)])) {
112
+ if (field === 'enabled' || field === '_mixdogPluginDisabled') continue;
113
+ if (field === 'type' || field === 'transport') {
114
+ if (comparableTransport(copy) !== comparableTransport(form)) kept.push(field);
115
+ continue;
116
+ }
117
+ if (field === 'cwd') {
118
+ const declaredCwd = typeof form.cwd === 'string' && form.cwd ? form.cwd : '';
119
+ let generated = root;
120
+ if (declaredCwd) generated = isAbsolute(declaredCwd) ? declaredCwd : join(root, declaredCwd);
121
+ if (copy.cwd !== undefined && comparablePath(copy.cwd) !== comparablePath(generated)) kept.push(field);
122
+ continue;
123
+ }
124
+ if (PLUGIN_MCP_OVERRIDE_MAP_FIELDS.includes(field)) {
125
+ const copyMap = isPlainObject(copy[field]) ? copy[field] : {};
126
+ const declaredMap = isPlainObject(form[field]) ? form[field] : {};
127
+ if (copy[field] !== undefined && !isPlainObject(copy[field])) kept.push(field);
128
+ // A removed declared entry cannot be expressed as an added override.
129
+ else if (Object.keys(declaredMap).some((name) => !Object.hasOwn(copyMap, name))) kept.push(field);
130
+ const added = {};
131
+ for (const [name, value] of Object.entries(copyMap)) {
132
+ if (field === 'env' && LEGACY_ENV_KEYS.has(name)) continue;
133
+ if (!isDeepStrictEqual(value, declaredMap[name])) added[name] = value;
134
+ }
135
+ if (Object.keys(added).length) out[field] = added;
136
+ continue;
137
+ }
138
+ if (isDeepStrictEqual(copy[field], form[field])) continue;
139
+ if (PLUGIN_MCP_OVERRIDE_VALUE_FIELDS.includes(field) && Object.hasOwn(copy, field)) out[field] = copy[field];
140
+ else kept.push(field);
141
+ }
142
+ if (!kept.length) return { overrides: out };
143
+ const fields = [...new Set(kept)].map((field) => `"${field}"`).join(', ');
144
+ return { reason: `its ${fields} differ from the plugin declaration in a way a plugin server override cannot keep` };
145
+ }
146
+
147
+ // Declared key a copy stands for, or a reason it cannot be told apart.
148
+ function copyKey(name, copy, plugin, declared) {
149
+ const base = legacyServerName(plugin);
150
+ const keys = declared.servers.map((server) => server.key);
151
+ if (!keys.length) return { reason: 'the plugin declares no MCP servers' };
152
+ if (name === base) {
153
+ if (keys.length === 1) return { key: keys[0] };
154
+ const matches = declared.servers.filter((server) => sameTransport(copy, server.config, plugin.root));
155
+ return matches.length === 1 ? { key: matches[0].key } : { reason: 'it matches none or several declared servers' };
156
+ }
157
+ if (name.startsWith(`${base}--`)) {
158
+ const key = name.slice(base.length + 2);
159
+ return keys.includes(key) ? { key } : { reason: `the plugin no longer declares "${key}"` };
160
+ }
161
+ return { reason: `its name does not follow the plugin's naming (${base})` };
162
+ }
163
+
164
+ /**
165
+ * Adoption of server copies made by the earlier enable action. A copy is
166
+ * adopted only when its `env.MIXDOG_PLUGIN_ROOT` is a registered plugin's root
167
+ * AND its name follows that plugin's earlier naming; it then leaves
168
+ * `mcpServers` and its name, disabled state and user-added connection values
169
+ * become that server's intent. Everything else stays untouched with a warning.
170
+ * Pure and idempotent: an already-adopted config yields an empty plan.
171
+ */
172
+ function planCopyAdoption(userServers, intents, declared) {
173
+ // A present declaration wins over a missing one sharing its root, in any order.
174
+ const byRoot = new Map();
175
+ for (const d of declared) {
176
+ const root = comparablePath(d.plugin.root);
177
+ if (!d.missing || !byRoot.has(root)) byRoot.set(root, d);
178
+ }
179
+ const next = structuredClone(intents);
180
+ const removed = [];
181
+ const warnings = [];
182
+ // Copies of a registered plugin that cannot be adopted: left as configured
183
+ // (their own transport is honored) but still bound to the plugin's lifecycle.
184
+ const owned = new Map();
185
+ for (const [name, copy] of Object.entries(userServers)) {
186
+ const marker = isPlainObject(copy) && isPlainObject(copy.env) ? clean(copy.env.MIXDOG_PLUGIN_ROOT) : '';
187
+ if (!marker) continue;
188
+ const owner = byRoot.get(comparablePath(marker));
189
+ const leave = (reason) =>
190
+ warnings.push({ name, message: `"${name}" looks like a plugin MCP copy but was left as configured: ${reason}` });
191
+ if (!owner) {
192
+ leave(`no registered plugin has root ${marker}`);
193
+ continue;
194
+ }
195
+ // A registered plugin whose directory is gone still owns its copies, so
196
+ // its disablement and project scopes keep applying; nothing is adopted.
197
+ if (owner.missing) {
198
+ owned.set(name, { d: owner, key: name });
199
+ leave(`plugin root ${marker} is missing`);
200
+ continue;
201
+ }
202
+ const { key, reason } = copyKey(name, copy, owner.plugin, owner);
203
+ owned.set(name, { d: owner, key: key || name });
204
+ if (!key) {
205
+ leave(reason);
206
+ continue;
207
+ }
208
+ const id = owner.plugin.id;
209
+ const stored = next[id]?.[key];
210
+ if (stored?.alias && stored.alias !== name) {
211
+ leave(`plugin server "${key}" already keeps the name "${stored.alias}"`);
212
+ continue;
213
+ }
214
+ const declaration = owner.servers.find((server) => server.key === key).config;
215
+ const changes = copyOverrides(copy, declaration, owner.plugin.root);
216
+ if (!changes.overrides) {
217
+ leave(changes.reason);
218
+ continue;
219
+ }
220
+ const disabled = copy.enabled === false || (copy._mixdogPluginDisabled === true && owner.plugin.enabled !== false);
221
+ const declaredOn = declaration.enabled !== false;
222
+ next[id] = {
223
+ ...(next[id] || {}),
224
+ [key]: {
225
+ alias: name,
226
+ ...(disabled === declaredOn ? { enabled: !disabled } : {}),
227
+ ...changes.overrides,
228
+ ...(stored || {}),
229
+ },
230
+ };
231
+ removed.push(name);
232
+ owned.delete(name);
233
+ }
234
+ return { removed, intents: next, warnings, owned };
235
+ }
236
+
237
+ function declarationsOf(plugins) {
238
+ return plugins.map((plugin) => {
239
+ const root = clean(plugin.root);
240
+ if (!root || plugin.exists === false) {
241
+ return {
242
+ plugin,
243
+ missing: true,
244
+ format: 'none',
245
+ servers: [],
246
+ errors: [{ message: `plugin root not found: ${root}` }],
247
+ };
248
+ }
249
+ try {
250
+ return { plugin, ...loadPluginMcpDeclarations(root) };
251
+ } catch (error) {
252
+ return {
253
+ plugin,
254
+ format: 'none',
255
+ servers: [],
256
+ errors: [{ source: root, message: `cannot read MCP declarations${error?.code ? ` (${error.code})` : ''}` }],
257
+ };
258
+ }
259
+ });
260
+ }
261
+
262
+ /** Names for every declared server: configured servers keep theirs, then kept
263
+ * aliases, then generated names in registry order; a later claimant of a taken
264
+ * name gets a deterministic suffix and a warning. */
265
+ function assignNames(userNames, declared, intents) {
266
+ const claimedBy = new Map(userNames.map((name) => [name, null]));
267
+ const names = new Map();
268
+ const warnings = new Map();
269
+ // Slots running under a generated collision name that is not yet kept.
270
+ const unpinned = new Set();
271
+ const slots = declared.flatMap((d) => d.servers.map((server) => ({ d, server, id: d.plugin.id })));
272
+ const claim = (slot, name) => {
273
+ claimedBy.set(name, slot.id);
274
+ names.set(slot, name);
275
+ };
276
+ const conflict = (wanted) => {
277
+ const holder = claimedBy.get(wanted);
278
+ return holder === null ? 'a configured MCP server' : `plugin "${holder}"`;
279
+ };
280
+ for (const slot of slots) {
281
+ const alias = intents[slot.id]?.[slot.server.key]?.alias;
282
+ if (!alias) continue;
283
+ if (claimedBy.has(alias)) warnings.set(slot, [`kept name "${alias}" is taken by ${conflict(alias)}`]);
284
+ else claim(slot, alias);
285
+ }
286
+ for (const slot of slots) {
287
+ if (names.has(slot)) continue;
288
+ const base = pluginMcpServerBaseName(slot.id, slot.server.key);
289
+ if (!claimedBy.has(base)) {
290
+ claim(slot, base);
291
+ continue;
292
+ }
293
+ const name = disambiguatedName(base, slot.id, slot.server.key, claimedBy);
294
+ warnings.set(slot, [
295
+ ...(warnings.get(slot) || []),
296
+ `name "${base}" is taken by ${conflict(base)}; using "${name}"`,
297
+ ]);
298
+ claim(slot, name);
299
+ if (!intents[slot.id]?.[slot.server.key]?.alias) unpinned.add(slot);
300
+ }
301
+ // A kept name standing in for a generated one that someone else holds still
302
+ // reports the conflict.
303
+ for (const slot of slots) {
304
+ const name = names.get(slot);
305
+ const base = pluginMcpServerBaseName(slot.id, slot.server.key);
306
+ if (warnings.has(slot) || name === base || !claimedBy.has(base) || claimedBy.get(base) === slot.id) continue;
307
+ if (name === intents[slot.id]?.[slot.server.key]?.alias) {
308
+ warnings.set(slot, [`name "${base}" is taken by ${conflict(base)}; keeping "${name}"`]);
309
+ }
310
+ }
311
+ return { slots, names, warnings, unpinned };
312
+ }
313
+
314
+ function withIntentOverrides(config, intent) {
315
+ const out = { ...config };
316
+ for (const field of PLUGIN_MCP_OVERRIDE_MAP_FIELDS) {
317
+ if (intent?.[field]) out[field] = { ...(isPlainObject(out[field]) ? out[field] : {}), ...intent[field] };
318
+ }
319
+ for (const field of PLUGIN_MCP_OVERRIDE_VALUE_FIELDS) {
320
+ if (intent && Object.hasOwn(intent, field)) out[field] = intent[field];
321
+ }
322
+ return out;
323
+ }
324
+
325
+ /** Launchable config of one plugin server for a runtime whose session cwd is `cwd`. */
326
+ function resolveServerConfig({ plugin, format, server, intent, cwd, dataDir, platform }) {
327
+ const root = clean(plugin.root);
328
+ const data = dataDir ? join(dataDir, 'plugins', 'data', plugin.id) : '';
329
+ const { enabled: _declaredEnabled, ...declared } = server.config;
330
+ const cfg = resolvePluginPlaceholders(withIntentOverrides(declared, intent), { root, data, platform });
331
+ const stdio = declaredMcpTransport(cfg) === 'stdio';
332
+ let cwdDependent = false;
333
+ if (stdio) {
334
+ const declaredCwd = typeof cfg.cwd === 'string' ? cfg.cwd.trim() : '';
335
+ if (declaredCwd) {
336
+ cfg.cwd = isAbsolute(declaredCwd) || declaredCwd.startsWith('${') ? declaredCwd : resolve(root, declaredCwd);
337
+ } else if (format === 'mixdog') {
338
+ cfg.cwd = root;
339
+ } else {
340
+ cwdDependent = true;
341
+ if (cwd) cfg.cwd = cwd;
342
+ else delete cfg.cwd;
343
+ }
344
+ cfg.env = { ...pluginServerEnv({ root, data }), ...(isPlainObject(cfg.env) ? cfg.env : {}) };
345
+ }
346
+ return {
347
+ ...cfg,
348
+ // Unset variables without a default fail a plugin server instead of
349
+ // launching it with empty values; MCP roots follow the session cwd.
350
+ _mixdogStrictEnv: true,
351
+ _mixdogRootsFollowScope: true,
352
+ _mixdogPlugin: { id: plugin.id, key: server.key, format, root, source: server.source, data, cwdDependent },
353
+ };
354
+ }
355
+
356
+ /**
357
+ * The effective MCP server set: the user's configured servers plus the servers
358
+ * every registered plugin declares (disabled ones included, `enabled: false`).
359
+ * `plugins` is the registry list in registration order.
360
+ */
361
+ export function resolveMcpServerCatalog({ config, plugins = [], cwd = '', dataDir = '', platform = process.platform }) {
362
+ const configured = isPlainObject(config?.mcpServers) ? config.mcpServers : {};
363
+ const declared = declarationsOf(plugins.filter((plugin) => clean(plugin?.id)));
364
+ const adoption = planCopyAdoption(configured, normalizePluginMcpIntents(config?.pluginMcp), declared);
365
+ const removed = new Set(adoption.removed);
366
+ const servers = {};
367
+ const sources = {};
368
+ const entries = {};
369
+ const warnings = [...adoption.warnings];
370
+ for (const [name, cfg] of Object.entries(configured)) {
371
+ if (removed.has(name)) continue;
372
+ const ownedBy = adoption.owned.get(name);
373
+ const entryWarnings = adoption.warnings.filter((w) => w.name === name).map((w) => w.message);
374
+ sources[name] = 'config';
375
+ if (!ownedBy) {
376
+ servers[name] = { ...cfg, ...(cfg?._mixdogPluginDisabled === true ? { enabled: false } : {}) };
377
+ entries[name] = { owner: null, warnings: entryWarnings };
378
+ continue;
379
+ }
380
+ const { plugin, format } = ownedBy.d;
381
+ const pluginEnabled = plugin.enabled !== false;
382
+ const serverEnabled = !(cfg.enabled === false || (cfg._mixdogPluginDisabled === true && pluginEnabled));
383
+ const marker = {
384
+ id: plugin.id,
385
+ key: ownedBy.key,
386
+ format,
387
+ root: clean(plugin.root),
388
+ source: 'config',
389
+ data: '',
390
+ cwdDependent: false,
391
+ };
392
+ servers[name] = { ...cfg, enabled: pluginEnabled && serverEnabled, _mixdogPlugin: marker };
393
+ entries[name] = {
394
+ owner: { kind: 'plugin', ...marker, name: clean(plugin.name) || plugin.id },
395
+ pluginEnabled,
396
+ serverEnabled,
397
+ declaredEnabled: true,
398
+ warnings: entryWarnings,
399
+ };
400
+ }
401
+ const {
402
+ slots,
403
+ names,
404
+ warnings: nameWarnings,
405
+ unpinned,
406
+ } = assignNames(Object.keys(servers), declared, adoption.intents);
407
+ const pluginRows = {};
408
+ for (const d of declared) {
409
+ pluginRows[d.plugin.id] = {
410
+ id: d.plugin.id,
411
+ name: clean(d.plugin.name) || d.plugin.id,
412
+ enabled: d.plugin.enabled !== false,
413
+ format: d.format,
414
+ errors: d.errors,
415
+ servers: [],
416
+ ...(d.missing ? { missing: true } : {}),
417
+ };
418
+ }
419
+ for (const slot of slots) {
420
+ const { d, server, id } = slot;
421
+ const name = names.get(slot);
422
+ const intent = adoption.intents[id]?.[server.key];
423
+ const pluginEnabled = d.plugin.enabled !== false;
424
+ // A declaration may ship a server off by default; the user's intent wins.
425
+ const declaredEnabled = server.config.enabled !== false;
426
+ const serverEnabled = typeof intent?.enabled === 'boolean' ? intent.enabled : declaredEnabled;
427
+ const cfg = resolveServerConfig({ plugin: d.plugin, format: d.format, server, intent, cwd, dataDir, platform });
428
+ cfg.enabled = pluginEnabled && serverEnabled;
429
+ servers[name] = cfg;
430
+ sources[name] = 'plugin';
431
+ entries[name] = {
432
+ owner: { kind: 'plugin', ...cfg._mixdogPlugin, name: pluginRows[id].name },
433
+ pluginEnabled,
434
+ serverEnabled,
435
+ declaredEnabled,
436
+ ...(unpinned.has(slot) ? { unpinned: true } : {}),
437
+ warnings: nameWarnings.get(slot) || [],
438
+ };
439
+ for (const message of entries[name].warnings) warnings.push({ name, plugin: id, message });
440
+ pluginRows[id].servers.push(name);
441
+ }
442
+ return {
443
+ servers,
444
+ sources,
445
+ entries,
446
+ plugins: pluginRows,
447
+ warnings,
448
+ adoption: adoption.removed.length ? { removed: adoption.removed, intents: adoption.intents } : null,
449
+ };
450
+ }
451
+
452
+ /** `config` with adopted copies removed from `mcpServers` and their intent recorded. */
453
+ export function withAdoptedCopies(config, adoption) {
454
+ if (!adoption) return config;
455
+ const mcpServers = { ...(config.mcpServers || {}) };
456
+ for (const name of adoption.removed) delete mcpServers[name];
457
+ return { ...config, mcpServers, pluginMcp: adoption.intents };
458
+ }
459
+
460
+ /** `config` (already carrying `catalog`'s adoption) with every plugin server
461
+ * that runs under a generated collision name keeping that name, so it does
462
+ * not flip back (changing its tool names and name-keyed scopes) once the
463
+ * conflicting server goes away. Returns `config` itself when nothing changes. */
464
+ export function withPinnedCollisionNames(config, catalog) {
465
+ let next = config;
466
+ for (const [name, entry] of Object.entries(catalog?.entries || {})) {
467
+ if (!entry?.unpinned || !entry.owner) continue;
468
+ next = withPluginServerIntent(next, entry.owner.id, entry.owner.key, (intent) => ({ ...intent, alias: name }));
469
+ }
470
+ return next;
471
+ }
472
+
473
+ /** `config` with one plugin server's intent replaced by `update(intent)`. */
474
+ export function withPluginServerIntent(config, pluginId, key, update) {
475
+ const intents = normalizePluginMcpIntents(config.pluginMcp);
476
+ const servers = { ...(intents[pluginId] || {}) };
477
+ const next = normalizePluginMcpIntents({ [pluginId]: { [key]: update({ ...(servers[key] || {}) }) } })[pluginId]?.[
478
+ key
479
+ ];
480
+ if (next) servers[key] = next;
481
+ else delete servers[key];
482
+ if (Object.keys(servers).length) intents[pluginId] = servers;
483
+ else delete intents[pluginId];
484
+ return { ...config, pluginMcp: intents };
485
+ }
486
+
487
+ /** `config` without any intent recorded for `pluginId`. */
488
+ export function withoutPluginIntents(config, pluginId) {
489
+ const intents = normalizePluginMcpIntents(config.pluginMcp);
490
+ if (!intents[pluginId]) return config;
491
+ delete intents[pluginId];
492
+ return { ...config, pluginMcp: intents };
493
+ }
494
+
495
+ /** Create a plugin server's data directory; runs just before it connects. */
496
+ export function ensurePluginServerData(cfg) {
497
+ const data = cfg?._mixdogPlugin?.data;
498
+ if (data) mkdirSync(data, { recursive: true });
499
+ }