@wahack/pi-coding-agent 15.11.0

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 (1152) hide show
  1. package/CHANGELOG.md +10031 -0
  2. package/README.md +36 -0
  3. package/examples/README.md +21 -0
  4. package/examples/custom-tools/README.md +104 -0
  5. package/examples/custom-tools/hello/index.ts +20 -0
  6. package/examples/extensions/README.md +142 -0
  7. package/examples/extensions/api-demo.ts +79 -0
  8. package/examples/extensions/chalk-logger.ts +25 -0
  9. package/examples/extensions/hello.ts +31 -0
  10. package/examples/extensions/pirate.ts +43 -0
  11. package/examples/extensions/plan-mode.ts +549 -0
  12. package/examples/extensions/reload-runtime.ts +38 -0
  13. package/examples/extensions/thinking-note.ts +13 -0
  14. package/examples/extensions/tools.ts +145 -0
  15. package/examples/extensions/with-deps/index.ts +36 -0
  16. package/examples/extensions/with-deps/package-lock.json +31 -0
  17. package/examples/extensions/with-deps/package.json +17 -0
  18. package/examples/hooks/README.md +56 -0
  19. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  20. package/examples/hooks/confirm-destructive.ts +58 -0
  21. package/examples/hooks/custom-compaction.ts +115 -0
  22. package/examples/hooks/dirty-repo-guard.ts +51 -0
  23. package/examples/hooks/file-trigger.ts +40 -0
  24. package/examples/hooks/git-checkpoint.ts +52 -0
  25. package/examples/hooks/handoff.ts +149 -0
  26. package/examples/hooks/permission-gate.ts +33 -0
  27. package/examples/hooks/protected-paths.ts +29 -0
  28. package/examples/hooks/qna.ts +118 -0
  29. package/examples/hooks/status-line.ts +39 -0
  30. package/examples/sdk/01-minimal.ts +21 -0
  31. package/examples/sdk/02-custom-model.ts +49 -0
  32. package/examples/sdk/03-custom-prompt.ts +46 -0
  33. package/examples/sdk/04-skills.ts +43 -0
  34. package/examples/sdk/06-extensions.ts +82 -0
  35. package/examples/sdk/06-hooks.ts +61 -0
  36. package/examples/sdk/07-context-files.ts +35 -0
  37. package/examples/sdk/08-prompt-templates.ts +41 -0
  38. package/examples/sdk/08-slash-commands.ts +46 -0
  39. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  40. package/examples/sdk/11-sessions.ts +47 -0
  41. package/examples/sdk/12-redis-sessions.ts +54 -0
  42. package/examples/sdk/13-sql-sessions.ts +61 -0
  43. package/examples/sdk/README.md +172 -0
  44. package/package.json +554 -0
  45. package/scripts/build-binary.ts +100 -0
  46. package/scripts/bundle-dist.ts +90 -0
  47. package/scripts/format-prompts.ts +68 -0
  48. package/scripts/generate-docs-index.ts +40 -0
  49. package/scripts/generate-template.ts +33 -0
  50. package/scripts/omp +42 -0
  51. package/scripts/omp.ts +19 -0
  52. package/src/async/index.ts +1 -0
  53. package/src/async/job-manager.ts +625 -0
  54. package/src/auto-thinking/classifier.ts +185 -0
  55. package/src/autoresearch/command-resume.md +14 -0
  56. package/src/autoresearch/dashboard.ts +436 -0
  57. package/src/autoresearch/git.ts +319 -0
  58. package/src/autoresearch/helpers.ts +218 -0
  59. package/src/autoresearch/index.ts +536 -0
  60. package/src/autoresearch/prompt-setup.md +43 -0
  61. package/src/autoresearch/prompt.md +103 -0
  62. package/src/autoresearch/resume-message.md +10 -0
  63. package/src/autoresearch/state.ts +273 -0
  64. package/src/autoresearch/storage.ts +699 -0
  65. package/src/autoresearch/tools/init-experiment.ts +272 -0
  66. package/src/autoresearch/tools/log-experiment.ts +524 -0
  67. package/src/autoresearch/tools/run-experiment.ts +407 -0
  68. package/src/autoresearch/tools/update-notes.ts +109 -0
  69. package/src/autoresearch/types.ts +168 -0
  70. package/src/bun-imports.d.ts +28 -0
  71. package/src/capability/context-file.ts +44 -0
  72. package/src/capability/extension-module.ts +34 -0
  73. package/src/capability/extension.ts +47 -0
  74. package/src/capability/fs.ts +117 -0
  75. package/src/capability/hook.ts +40 -0
  76. package/src/capability/index.ts +436 -0
  77. package/src/capability/instruction.ts +37 -0
  78. package/src/capability/mcp.ts +74 -0
  79. package/src/capability/prompt.ts +35 -0
  80. package/src/capability/rule-buckets.ts +66 -0
  81. package/src/capability/rule.ts +261 -0
  82. package/src/capability/settings.ts +34 -0
  83. package/src/capability/skill.ts +63 -0
  84. package/src/capability/slash-command.ts +40 -0
  85. package/src/capability/ssh.ts +41 -0
  86. package/src/capability/system-prompt.ts +34 -0
  87. package/src/capability/tool.ts +38 -0
  88. package/src/capability/types.ts +168 -0
  89. package/src/cli/agents-cli.ts +138 -0
  90. package/src/cli/args.ts +340 -0
  91. package/src/cli/auth-broker-cli.ts +895 -0
  92. package/src/cli/auth-gateway-cli.ts +611 -0
  93. package/src/cli/classify-install-target.ts +76 -0
  94. package/src/cli/claude-trace-cli.ts +795 -0
  95. package/src/cli/commands/init-xdg.ts +27 -0
  96. package/src/cli/completion-gen.ts +550 -0
  97. package/src/cli/config-cli.ts +418 -0
  98. package/src/cli/dry-balance-cli.ts +856 -0
  99. package/src/cli/extension-flags.ts +48 -0
  100. package/src/cli/file-processor.ts +133 -0
  101. package/src/cli/gallery-cli.ts +230 -0
  102. package/src/cli/gallery-fixtures/agentic.ts +407 -0
  103. package/src/cli/gallery-fixtures/codeintel.ts +187 -0
  104. package/src/cli/gallery-fixtures/edit.ts +194 -0
  105. package/src/cli/gallery-fixtures/fs.ts +220 -0
  106. package/src/cli/gallery-fixtures/index.ts +40 -0
  107. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  108. package/src/cli/gallery-fixtures/memory.ts +81 -0
  109. package/src/cli/gallery-fixtures/misc.ts +250 -0
  110. package/src/cli/gallery-fixtures/search.ts +213 -0
  111. package/src/cli/gallery-fixtures/shell.ts +167 -0
  112. package/src/cli/gallery-fixtures/types.ts +57 -0
  113. package/src/cli/gallery-fixtures/web.ts +158 -0
  114. package/src/cli/gallery-screenshot.ts +279 -0
  115. package/src/cli/grep-cli.ts +160 -0
  116. package/src/cli/grievances-cli.ts +256 -0
  117. package/src/cli/initial-message.ts +58 -0
  118. package/src/cli/list-models.ts +194 -0
  119. package/src/cli/plugin-cli.ts +996 -0
  120. package/src/cli/read-cli.ts +57 -0
  121. package/src/cli/session-picker.ts +79 -0
  122. package/src/cli/setup-cli.ts +231 -0
  123. package/src/cli/shell-cli.ts +176 -0
  124. package/src/cli/ssh-cli.ts +179 -0
  125. package/src/cli/startup-cwd.ts +68 -0
  126. package/src/cli/stats-cli.ts +238 -0
  127. package/src/cli/tiny-models-cli.ts +127 -0
  128. package/src/cli/update-cli.ts +611 -0
  129. package/src/cli/usage-cli.ts +603 -0
  130. package/src/cli/web-search-cli.ts +132 -0
  131. package/src/cli/worktree-cli.ts +291 -0
  132. package/src/cli-commands.ts +79 -0
  133. package/src/cli.ts +200 -0
  134. package/src/commands/acp.ts +24 -0
  135. package/src/commands/agents.ts +57 -0
  136. package/src/commands/auth-broker.ts +99 -0
  137. package/src/commands/auth-gateway.ts +69 -0
  138. package/src/commands/commit.ts +46 -0
  139. package/src/commands/complete.ts +66 -0
  140. package/src/commands/completions.ts +60 -0
  141. package/src/commands/config.ts +51 -0
  142. package/src/commands/dry-balance.ts +43 -0
  143. package/src/commands/gallery.ts +52 -0
  144. package/src/commands/grep.ts +48 -0
  145. package/src/commands/grievances.ts +51 -0
  146. package/src/commands/install.ts +107 -0
  147. package/src/commands/launch.ts +169 -0
  148. package/src/commands/plugin.ts +78 -0
  149. package/src/commands/read.ts +38 -0
  150. package/src/commands/setup.ts +67 -0
  151. package/src/commands/shell.ts +29 -0
  152. package/src/commands/ssh.ts +60 -0
  153. package/src/commands/stats.ts +29 -0
  154. package/src/commands/tiny-models.ts +36 -0
  155. package/src/commands/update.ts +21 -0
  156. package/src/commands/usage.ts +35 -0
  157. package/src/commands/web-search.ts +42 -0
  158. package/src/commands/worktree.ts +56 -0
  159. package/src/commit/agentic/agent.ts +317 -0
  160. package/src/commit/agentic/fallback.ts +96 -0
  161. package/src/commit/agentic/index.ts +355 -0
  162. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  163. package/src/commit/agentic/prompts/session-user.md +25 -0
  164. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  165. package/src/commit/agentic/prompts/system.md +38 -0
  166. package/src/commit/agentic/state.ts +60 -0
  167. package/src/commit/agentic/tools/analyze-file.ts +146 -0
  168. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  169. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  170. package/src/commit/agentic/tools/git-overview.ts +81 -0
  171. package/src/commit/agentic/tools/index.ts +54 -0
  172. package/src/commit/agentic/tools/propose-changelog.ts +144 -0
  173. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  174. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  175. package/src/commit/agentic/tools/schemas.ts +23 -0
  176. package/src/commit/agentic/tools/split-commit.ts +245 -0
  177. package/src/commit/agentic/topo-sort.ts +44 -0
  178. package/src/commit/agentic/trivial.ts +51 -0
  179. package/src/commit/agentic/validation.ts +183 -0
  180. package/src/commit/analysis/conventional.ts +64 -0
  181. package/src/commit/analysis/index.ts +4 -0
  182. package/src/commit/analysis/scope.ts +242 -0
  183. package/src/commit/analysis/summary.ts +105 -0
  184. package/src/commit/analysis/validation.ts +66 -0
  185. package/src/commit/changelog/detect.ts +40 -0
  186. package/src/commit/changelog/generate.ts +97 -0
  187. package/src/commit/changelog/index.ts +234 -0
  188. package/src/commit/changelog/parse.ts +44 -0
  189. package/src/commit/cli.ts +85 -0
  190. package/src/commit/git/diff.ts +148 -0
  191. package/src/commit/index.ts +5 -0
  192. package/src/commit/map-reduce/index.ts +69 -0
  193. package/src/commit/map-reduce/map-phase.ts +193 -0
  194. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  195. package/src/commit/map-reduce/utils.ts +9 -0
  196. package/src/commit/message.ts +11 -0
  197. package/src/commit/model-selection.ts +92 -0
  198. package/src/commit/pipeline.ts +243 -0
  199. package/src/commit/prompts/analysis-system.md +148 -0
  200. package/src/commit/prompts/analysis-user.md +38 -0
  201. package/src/commit/prompts/changelog-system.md +50 -0
  202. package/src/commit/prompts/changelog-user.md +18 -0
  203. package/src/commit/prompts/file-observer-system.md +24 -0
  204. package/src/commit/prompts/file-observer-user.md +8 -0
  205. package/src/commit/prompts/reduce-system.md +50 -0
  206. package/src/commit/prompts/reduce-user.md +17 -0
  207. package/src/commit/prompts/summary-retry.md +3 -0
  208. package/src/commit/prompts/summary-system.md +38 -0
  209. package/src/commit/prompts/summary-user.md +13 -0
  210. package/src/commit/prompts/types-description.md +2 -0
  211. package/src/commit/shared-llm.ts +77 -0
  212. package/src/commit/types.ts +118 -0
  213. package/src/commit/utils/exclusions.ts +42 -0
  214. package/src/commit/utils.ts +58 -0
  215. package/src/config/api-key-resolver.ts +60 -0
  216. package/src/config/append-only-context-mode.ts +31 -0
  217. package/src/config/config-file.ts +317 -0
  218. package/src/config/file-lock.ts +164 -0
  219. package/src/config/keybindings.ts +628 -0
  220. package/src/config/mcp-schema.json +230 -0
  221. package/src/config/model-discovery.ts +554 -0
  222. package/src/config/model-registry.ts +2090 -0
  223. package/src/config/model-resolver.ts +1502 -0
  224. package/src/config/model-roles.ts +74 -0
  225. package/src/config/models-config-schema.ts +226 -0
  226. package/src/config/models-config.ts +129 -0
  227. package/src/config/prompt-templates.ts +185 -0
  228. package/src/config/resolve-config-value.ts +94 -0
  229. package/src/config/settings-schema.ts +3530 -0
  230. package/src/config/settings.ts +1178 -0
  231. package/src/config.ts +242 -0
  232. package/src/cursor.ts +340 -0
  233. package/src/dap/client.ts +760 -0
  234. package/src/dap/config.ts +189 -0
  235. package/src/dap/defaults.json +212 -0
  236. package/src/dap/index.ts +4 -0
  237. package/src/dap/session.ts +1441 -0
  238. package/src/dap/types.ts +610 -0
  239. package/src/debug/index.ts +515 -0
  240. package/src/debug/log-formatting.ts +58 -0
  241. package/src/debug/log-viewer.ts +908 -0
  242. package/src/debug/profiler.ts +162 -0
  243. package/src/debug/protocol-probe.ts +267 -0
  244. package/src/debug/raw-sse-buffer.ts +273 -0
  245. package/src/debug/raw-sse.ts +292 -0
  246. package/src/debug/report-bundle.ts +374 -0
  247. package/src/debug/system-info.ts +111 -0
  248. package/src/debug/terminal-info.ts +124 -0
  249. package/src/discovery/agents-md.ts +67 -0
  250. package/src/discovery/agents.ts +230 -0
  251. package/src/discovery/at-imports.ts +273 -0
  252. package/src/discovery/builtin-defaults.ts +39 -0
  253. package/src/discovery/builtin-rules/index.ts +54 -0
  254. package/src/discovery/builtin-rules/rs-box-leak.md +48 -0
  255. package/src/discovery/builtin-rules/rs-future-prelude.md +23 -0
  256. package/src/discovery/builtin-rules/rs-lazylock.md +51 -0
  257. package/src/discovery/builtin-rules/rs-match-ergonomics.md +67 -0
  258. package/src/discovery/builtin-rules/rs-parking-lot.md +44 -0
  259. package/src/discovery/builtin-rules/rs-result-type.md +19 -0
  260. package/src/discovery/builtin-rules/ts-bare-catch.md +38 -0
  261. package/src/discovery/builtin-rules/ts-import-type.md +42 -0
  262. package/src/discovery/builtin-rules/ts-no-any.md +56 -0
  263. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
  264. package/src/discovery/builtin-rules/ts-no-dynamic-import.md +39 -0
  265. package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
  266. package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
  267. package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
  268. package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +65 -0
  269. package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
  270. package/src/discovery/builtin-rules/ts-set-map.md +28 -0
  271. package/src/discovery/builtin.ts +906 -0
  272. package/src/discovery/claude-plugins.ts +386 -0
  273. package/src/discovery/claude.ts +584 -0
  274. package/src/discovery/cline.ts +83 -0
  275. package/src/discovery/codex.ts +522 -0
  276. package/src/discovery/cursor.ts +220 -0
  277. package/src/discovery/gemini.ts +383 -0
  278. package/src/discovery/github.ts +154 -0
  279. package/src/discovery/helpers.ts +1016 -0
  280. package/src/discovery/index.ts +81 -0
  281. package/src/discovery/mcp-json.ts +171 -0
  282. package/src/discovery/omp-extension-roots.ts +190 -0
  283. package/src/discovery/omp-plugins.ts +383 -0
  284. package/src/discovery/opencode.ts +398 -0
  285. package/src/discovery/plugin-dir-roots.ts +28 -0
  286. package/src/discovery/ssh.ts +153 -0
  287. package/src/discovery/substitute-plugin-root.ts +29 -0
  288. package/src/discovery/vscode.ts +105 -0
  289. package/src/discovery/windsurf.ts +147 -0
  290. package/src/edit/apply-patch/index.ts +87 -0
  291. package/src/edit/apply-patch/parser.ts +174 -0
  292. package/src/edit/diff.ts +999 -0
  293. package/src/edit/file-snapshot-store.ts +91 -0
  294. package/src/edit/hashline/block-resolver.ts +33 -0
  295. package/src/edit/hashline/diff.ts +290 -0
  296. package/src/edit/hashline/execute.ts +242 -0
  297. package/src/edit/hashline/filesystem.ts +130 -0
  298. package/src/edit/hashline/index.ts +5 -0
  299. package/src/edit/hashline/noop-loop-guard.ts +99 -0
  300. package/src/edit/hashline/params.ts +18 -0
  301. package/src/edit/index.ts +571 -0
  302. package/src/edit/modes/apply-patch.lark +19 -0
  303. package/src/edit/modes/apply-patch.ts +53 -0
  304. package/src/edit/modes/patch.ts +1891 -0
  305. package/src/edit/modes/replace.ts +1137 -0
  306. package/src/edit/normalize.ts +345 -0
  307. package/src/edit/notebook.ts +242 -0
  308. package/src/edit/read-file.ts +25 -0
  309. package/src/edit/renderer.ts +769 -0
  310. package/src/edit/streaming.ts +517 -0
  311. package/src/eval/__tests__/agent-bridge.test.ts +708 -0
  312. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  313. package/src/eval/__tests__/budget-bridge.test.ts +69 -0
  314. package/src/eval/__tests__/completion-bridge.test.ts +412 -0
  315. package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
  316. package/src/eval/__tests__/idle-timeout.test.ts +80 -0
  317. package/src/eval/__tests__/js-context-manager.test.ts +241 -0
  318. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  319. package/src/eval/agent-bridge.ts +319 -0
  320. package/src/eval/backend.ts +71 -0
  321. package/src/eval/bridge-timeout.ts +44 -0
  322. package/src/eval/budget-bridge.ts +48 -0
  323. package/src/eval/completion-bridge.ts +207 -0
  324. package/src/eval/concurrency-bridge.ts +34 -0
  325. package/src/eval/idle-timeout.ts +91 -0
  326. package/src/eval/index.ts +4 -0
  327. package/src/eval/js/context-manager.ts +502 -0
  328. package/src/eval/js/executor.ts +173 -0
  329. package/src/eval/js/index.ts +51 -0
  330. package/src/eval/js/shared/helpers.ts +283 -0
  331. package/src/eval/js/shared/indirect-eval.ts +30 -0
  332. package/src/eval/js/shared/local-module-loader.ts +342 -0
  333. package/src/eval/js/shared/prelude.ts +2 -0
  334. package/src/eval/js/shared/prelude.txt +246 -0
  335. package/src/eval/js/shared/rewrite-imports.ts +532 -0
  336. package/src/eval/js/shared/runtime.ts +352 -0
  337. package/src/eval/js/shared/types.ts +18 -0
  338. package/src/eval/js/tool-bridge.ts +162 -0
  339. package/src/eval/js/worker-core.ts +132 -0
  340. package/src/eval/js/worker-entry.ts +30 -0
  341. package/src/eval/js/worker-protocol.ts +47 -0
  342. package/src/eval/py/__tests__/prelude.test.ts +19 -0
  343. package/src/eval/py/display.ts +71 -0
  344. package/src/eval/py/executor.ts +742 -0
  345. package/src/eval/py/index.ts +68 -0
  346. package/src/eval/py/kernel.ts +748 -0
  347. package/src/eval/py/prelude.py +658 -0
  348. package/src/eval/py/prelude.ts +3 -0
  349. package/src/eval/py/runner.py +1133 -0
  350. package/src/eval/py/runtime.ts +276 -0
  351. package/src/eval/py/spawn-options.ts +126 -0
  352. package/src/eval/py/tool-bridge.ts +182 -0
  353. package/src/eval/session-id.ts +8 -0
  354. package/src/eval/types.ts +48 -0
  355. package/src/exa/index.ts +2 -0
  356. package/src/exa/mcp-client.ts +370 -0
  357. package/src/exa/types.ts +69 -0
  358. package/src/exec/bash-executor.ts +419 -0
  359. package/src/exec/exec.ts +53 -0
  360. package/src/exec/non-interactive-env.ts +48 -0
  361. package/src/export/custom-share.ts +65 -0
  362. package/src/export/html/index.ts +164 -0
  363. package/src/export/html/template.css +1051 -0
  364. package/src/export/html/template.generated.ts +2 -0
  365. package/src/export/html/template.html +46 -0
  366. package/src/export/html/template.js +2271 -0
  367. package/src/export/html/template.macro.ts +25 -0
  368. package/src/export/html/vendor/highlight.min.js +1213 -0
  369. package/src/export/html/vendor/marked.min.js +6 -0
  370. package/src/export/ttsr.ts +583 -0
  371. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
  372. package/src/extensibility/custom-commands/bundled/review/index.ts +489 -0
  373. package/src/extensibility/custom-commands/index.ts +2 -0
  374. package/src/extensibility/custom-commands/loader.ts +238 -0
  375. package/src/extensibility/custom-commands/types.ts +113 -0
  376. package/src/extensibility/custom-tools/index.ts +7 -0
  377. package/src/extensibility/custom-tools/loader.ts +269 -0
  378. package/src/extensibility/custom-tools/types.ts +270 -0
  379. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  380. package/src/extensibility/extensions/compact-handler.ts +40 -0
  381. package/src/extensibility/extensions/get-commands-handler.ts +78 -0
  382. package/src/extensibility/extensions/index.ts +16 -0
  383. package/src/extensibility/extensions/loader.ts +572 -0
  384. package/src/extensibility/extensions/runner.ts +922 -0
  385. package/src/extensibility/extensions/types.ts +1322 -0
  386. package/src/extensibility/extensions/wrapper.ts +223 -0
  387. package/src/extensibility/hooks/index.ts +5 -0
  388. package/src/extensibility/hooks/loader.ts +257 -0
  389. package/src/extensibility/hooks/runner.ts +425 -0
  390. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  391. package/src/extensibility/hooks/types.ts +606 -0
  392. package/src/extensibility/legacy-pi-ai-shim.ts +24 -0
  393. package/src/extensibility/legacy-pi-coding-agent-shim.ts +15 -0
  394. package/src/extensibility/plugins/doctor.ts +65 -0
  395. package/src/extensibility/plugins/git-url.ts +367 -0
  396. package/src/extensibility/plugins/index.ts +9 -0
  397. package/src/extensibility/plugins/installer.ts +192 -0
  398. package/src/extensibility/plugins/legacy-pi-compat.ts +682 -0
  399. package/src/extensibility/plugins/loader.ts +313 -0
  400. package/src/extensibility/plugins/manager.ts +827 -0
  401. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  402. package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
  403. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  404. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  405. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  406. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  407. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  408. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  409. package/src/extensibility/plugins/parser.ts +105 -0
  410. package/src/extensibility/plugins/types.ts +194 -0
  411. package/src/extensibility/shared-events.ts +343 -0
  412. package/src/extensibility/skills.ts +312 -0
  413. package/src/extensibility/slash-commands.ts +227 -0
  414. package/src/extensibility/tool-proxy.ts +25 -0
  415. package/src/extensibility/typebox.ts +418 -0
  416. package/src/extensibility/utils.ts +44 -0
  417. package/src/goals/index.ts +3 -0
  418. package/src/goals/runtime.ts +528 -0
  419. package/src/goals/state.ts +37 -0
  420. package/src/goals/tools/goal-tool.ts +251 -0
  421. package/src/hindsight/backend.ts +354 -0
  422. package/src/hindsight/bank.ts +156 -0
  423. package/src/hindsight/client.ts +598 -0
  424. package/src/hindsight/config.ts +175 -0
  425. package/src/hindsight/content.ts +210 -0
  426. package/src/hindsight/index.ts +8 -0
  427. package/src/hindsight/mental-models.ts +429 -0
  428. package/src/hindsight/seeds.json +32 -0
  429. package/src/hindsight/state.ts +488 -0
  430. package/src/hindsight/transcript.ts +71 -0
  431. package/src/index.ts +59 -0
  432. package/src/internal-urls/agent-protocol.ts +146 -0
  433. package/src/internal-urls/artifact-protocol.ts +107 -0
  434. package/src/internal-urls/docs-index.generated.ts +106 -0
  435. package/src/internal-urls/history-protocol.ts +113 -0
  436. package/src/internal-urls/index.ts +25 -0
  437. package/src/internal-urls/issue-pr-protocol.ts +584 -0
  438. package/src/internal-urls/json-query.ts +126 -0
  439. package/src/internal-urls/local-protocol.ts +287 -0
  440. package/src/internal-urls/mcp-protocol.ts +151 -0
  441. package/src/internal-urls/memory-protocol.ts +169 -0
  442. package/src/internal-urls/omp-protocol.ts +93 -0
  443. package/src/internal-urls/parse.ts +72 -0
  444. package/src/internal-urls/registry-helpers.ts +25 -0
  445. package/src/internal-urls/router.ts +105 -0
  446. package/src/internal-urls/rule-protocol.ts +45 -0
  447. package/src/internal-urls/skill-protocol.ts +96 -0
  448. package/src/internal-urls/types.ts +152 -0
  449. package/src/internal-urls/vault-protocol.ts +936 -0
  450. package/src/irc/bus.ts +292 -0
  451. package/src/lib/xai-http.ts +124 -0
  452. package/src/lsp/client.ts +1193 -0
  453. package/src/lsp/clients/biome-client.ts +264 -0
  454. package/src/lsp/clients/index.ts +50 -0
  455. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  456. package/src/lsp/clients/swiftlint-client.ts +120 -0
  457. package/src/lsp/config.ts +502 -0
  458. package/src/lsp/defaults.json +493 -0
  459. package/src/lsp/diagnostics-ledger.ts +51 -0
  460. package/src/lsp/edits.ts +267 -0
  461. package/src/lsp/index.ts +2477 -0
  462. package/src/lsp/lspmux.ts +233 -0
  463. package/src/lsp/render.ts +694 -0
  464. package/src/lsp/startup-events.ts +13 -0
  465. package/src/lsp/types.ts +455 -0
  466. package/src/lsp/utils.ts +718 -0
  467. package/src/main.ts +1325 -0
  468. package/src/mcp/client.ts +484 -0
  469. package/src/mcp/config-writer.ts +225 -0
  470. package/src/mcp/config.ts +365 -0
  471. package/src/mcp/index.ts +29 -0
  472. package/src/mcp/json-rpc.ts +122 -0
  473. package/src/mcp/loader.ts +124 -0
  474. package/src/mcp/manager.ts +1275 -0
  475. package/src/mcp/oauth-discovery.ts +442 -0
  476. package/src/mcp/oauth-flow.ts +442 -0
  477. package/src/mcp/render.ts +132 -0
  478. package/src/mcp/smithery-auth.ts +104 -0
  479. package/src/mcp/smithery-connect.ts +145 -0
  480. package/src/mcp/smithery-registry.ts +477 -0
  481. package/src/mcp/timeout.ts +59 -0
  482. package/src/mcp/tool-bridge.ts +426 -0
  483. package/src/mcp/tool-cache.ts +117 -0
  484. package/src/mcp/transports/http.ts +519 -0
  485. package/src/mcp/transports/index.ts +6 -0
  486. package/src/mcp/transports/stdio.ts +528 -0
  487. package/src/mcp/types.ts +423 -0
  488. package/src/memories/index.ts +1150 -0
  489. package/src/memories/storage.ts +577 -0
  490. package/src/memory-backend/index.ts +18 -0
  491. package/src/memory-backend/local-backend.ts +39 -0
  492. package/src/memory-backend/off-backend.ts +25 -0
  493. package/src/memory-backend/resolve.ts +25 -0
  494. package/src/memory-backend/runtime.ts +66 -0
  495. package/src/memory-backend/types.ts +166 -0
  496. package/src/mnemopi/backend.ts +547 -0
  497. package/src/mnemopi/config.ts +160 -0
  498. package/src/mnemopi/index.ts +3 -0
  499. package/src/mnemopi/state.ts +584 -0
  500. package/src/modes/acp/acp-agent.ts +2407 -0
  501. package/src/modes/acp/acp-client-bridge.ts +154 -0
  502. package/src/modes/acp/acp-event-mapper.ts +929 -0
  503. package/src/modes/acp/acp-mode.ts +23 -0
  504. package/src/modes/acp/index.ts +2 -0
  505. package/src/modes/acp/terminal-auth.ts +37 -0
  506. package/src/modes/components/agent-dashboard.ts +1206 -0
  507. package/src/modes/components/agent-hub.ts +1071 -0
  508. package/src/modes/components/assistant-message.ts +307 -0
  509. package/src/modes/components/bash-execution.ts +220 -0
  510. package/src/modes/components/bordered-loader.ts +41 -0
  511. package/src/modes/components/branch-summary-message.ts +45 -0
  512. package/src/modes/components/btw-panel.ts +104 -0
  513. package/src/modes/components/chat-block.ts +111 -0
  514. package/src/modes/components/compaction-summary-message.ts +87 -0
  515. package/src/modes/components/copy-selector.ts +206 -0
  516. package/src/modes/components/countdown-timer.ts +75 -0
  517. package/src/modes/components/custom-editor.ts +398 -0
  518. package/src/modes/components/custom-message.ts +63 -0
  519. package/src/modes/components/diff.ts +277 -0
  520. package/src/modes/components/dynamic-border.ts +34 -0
  521. package/src/modes/components/error-banner.ts +33 -0
  522. package/src/modes/components/eval-execution.ts +158 -0
  523. package/src/modes/components/execution-shared.ts +101 -0
  524. package/src/modes/components/extensions/extension-dashboard.ts +399 -0
  525. package/src/modes/components/extensions/extension-list.ts +502 -0
  526. package/src/modes/components/extensions/index.ts +9 -0
  527. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  528. package/src/modes/components/extensions/state-manager.ts +627 -0
  529. package/src/modes/components/extensions/types.ts +186 -0
  530. package/src/modes/components/footer.ts +274 -0
  531. package/src/modes/components/history-search.ts +280 -0
  532. package/src/modes/components/hook-editor.ts +167 -0
  533. package/src/modes/components/hook-input.ts +87 -0
  534. package/src/modes/components/hook-message.ts +66 -0
  535. package/src/modes/components/hook-selector.ts +660 -0
  536. package/src/modes/components/index.ts +38 -0
  537. package/src/modes/components/keybinding-hints.ts +65 -0
  538. package/src/modes/components/late-diagnostics-message.ts +60 -0
  539. package/src/modes/components/login-dialog.ts +164 -0
  540. package/src/modes/components/mcp-add-wizard.ts +1340 -0
  541. package/src/modes/components/message-frame.ts +88 -0
  542. package/src/modes/components/model-selector.ts +1271 -0
  543. package/src/modes/components/oauth-selector.ts +368 -0
  544. package/src/modes/components/omfg-panel.ts +141 -0
  545. package/src/modes/components/overlay-box.ts +108 -0
  546. package/src/modes/components/plan-review-overlay.ts +820 -0
  547. package/src/modes/components/plan-toc.ts +138 -0
  548. package/src/modes/components/plugin-selector.ts +95 -0
  549. package/src/modes/components/plugin-settings.ts +722 -0
  550. package/src/modes/components/queue-mode-selector.ts +56 -0
  551. package/src/modes/components/read-tool-group.ts +670 -0
  552. package/src/modes/components/segment-track.ts +52 -0
  553. package/src/modes/components/session-selector.ts +625 -0
  554. package/src/modes/components/settings-defs.ts +189 -0
  555. package/src/modes/components/settings-selector.ts +651 -0
  556. package/src/modes/components/show-images-selector.ts +45 -0
  557. package/src/modes/components/skill-message.ts +89 -0
  558. package/src/modes/components/status-line/component.ts +869 -0
  559. package/src/modes/components/status-line/context-thresholds.ts +79 -0
  560. package/src/modes/components/status-line/git-utils.ts +42 -0
  561. package/src/modes/components/status-line/index.ts +5 -0
  562. package/src/modes/components/status-line/presets.ts +106 -0
  563. package/src/modes/components/status-line/segments.ts +584 -0
  564. package/src/modes/components/status-line/separators.ts +55 -0
  565. package/src/modes/components/status-line/token-rate.ts +66 -0
  566. package/src/modes/components/status-line/types.ts +108 -0
  567. package/src/modes/components/theme-selector.ts +63 -0
  568. package/src/modes/components/thinking-selector.ts +52 -0
  569. package/src/modes/components/tiny-title-download-progress.ts +90 -0
  570. package/src/modes/components/tips.txt +19 -0
  571. package/src/modes/components/todo-reminder.ts +38 -0
  572. package/src/modes/components/tool-execution.ts +1024 -0
  573. package/src/modes/components/transcript-container.ts +608 -0
  574. package/src/modes/components/tree-selector.ts +978 -0
  575. package/src/modes/components/ttsr-notification.ts +122 -0
  576. package/src/modes/components/user-message-selector.ts +227 -0
  577. package/src/modes/components/user-message.ts +66 -0
  578. package/src/modes/components/visual-truncate.ts +63 -0
  579. package/src/modes/components/welcome.ts +493 -0
  580. package/src/modes/controllers/btw-controller.ts +105 -0
  581. package/src/modes/controllers/command-controller-shared.ts +109 -0
  582. package/src/modes/controllers/command-controller.ts +1566 -0
  583. package/src/modes/controllers/event-controller.ts +1054 -0
  584. package/src/modes/controllers/extension-ui-controller.ts +886 -0
  585. package/src/modes/controllers/input-controller.ts +1073 -0
  586. package/src/modes/controllers/mcp-command-controller.ts +2017 -0
  587. package/src/modes/controllers/omfg-controller.ts +283 -0
  588. package/src/modes/controllers/omfg-rule.ts +647 -0
  589. package/src/modes/controllers/selector-controller.ts +1108 -0
  590. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  591. package/src/modes/controllers/streaming-reveal.ts +279 -0
  592. package/src/modes/controllers/tan-command-controller.ts +173 -0
  593. package/src/modes/controllers/todo-command-controller.ts +485 -0
  594. package/src/modes/data/emojis.json +1 -0
  595. package/src/modes/emoji-autocomplete.ts +285 -0
  596. package/src/modes/gradient-highlight.ts +87 -0
  597. package/src/modes/image-references.ts +117 -0
  598. package/src/modes/index.ts +17 -0
  599. package/src/modes/interactive-mode.ts +3370 -0
  600. package/src/modes/internal-url-autocomplete.ts +143 -0
  601. package/src/modes/loop-limit.ts +140 -0
  602. package/src/modes/magic-keywords.ts +20 -0
  603. package/src/modes/markdown-prose.ts +247 -0
  604. package/src/modes/oauth-manual-input.ts +69 -0
  605. package/src/modes/orchestrate.ts +42 -0
  606. package/src/modes/print-mode.ts +126 -0
  607. package/src/modes/prompt-action-autocomplete.ts +260 -0
  608. package/src/modes/rpc/host-tools.ts +186 -0
  609. package/src/modes/rpc/host-uris.ts +235 -0
  610. package/src/modes/rpc/rpc-client.ts +963 -0
  611. package/src/modes/rpc/rpc-mode.ts +947 -0
  612. package/src/modes/rpc/rpc-subagents.ts +265 -0
  613. package/src/modes/rpc/rpc-types.ts +458 -0
  614. package/src/modes/runtime-init.ts +116 -0
  615. package/src/modes/session-observer-registry.ts +146 -0
  616. package/src/modes/setup-version.ts +11 -0
  617. package/src/modes/setup-wizard/index.ts +99 -0
  618. package/src/modes/setup-wizard/lazy.ts +16 -0
  619. package/src/modes/setup-wizard/scenes/glyph.ts +96 -0
  620. package/src/modes/setup-wizard/scenes/outro.ts +35 -0
  621. package/src/modes/setup-wizard/scenes/providers.ts +69 -0
  622. package/src/modes/setup-wizard/scenes/sign-in.ts +205 -0
  623. package/src/modes/setup-wizard/scenes/splash.ts +201 -0
  624. package/src/modes/setup-wizard/scenes/theme.ts +299 -0
  625. package/src/modes/setup-wizard/scenes/types.ts +48 -0
  626. package/src/modes/setup-wizard/scenes/web-search.ts +129 -0
  627. package/src/modes/setup-wizard/wizard-overlay.ts +275 -0
  628. package/src/modes/shared.ts +47 -0
  629. package/src/modes/theme/dark.json +95 -0
  630. package/src/modes/theme/defaults/alabaster.json +93 -0
  631. package/src/modes/theme/defaults/amethyst.json +96 -0
  632. package/src/modes/theme/defaults/anthracite.json +93 -0
  633. package/src/modes/theme/defaults/basalt.json +91 -0
  634. package/src/modes/theme/defaults/birch.json +95 -0
  635. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  636. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  637. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  638. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  639. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  640. package/src/modes/theme/defaults/dark-copper.json +95 -0
  641. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  642. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  643. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  644. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  645. package/src/modes/theme/defaults/dark-ember.json +95 -0
  646. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  647. package/src/modes/theme/defaults/dark-forest.json +96 -0
  648. package/src/modes/theme/defaults/dark-github.json +105 -0
  649. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  650. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  651. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  652. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  653. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  654. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  655. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  656. package/src/modes/theme/defaults/dark-nord.json +97 -0
  657. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  658. package/src/modes/theme/defaults/dark-one.json +100 -0
  659. package/src/modes/theme/defaults/dark-poimandres.json +142 -0
  660. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  661. package/src/modes/theme/defaults/dark-reef.json +91 -0
  662. package/src/modes/theme/defaults/dark-retro.json +92 -0
  663. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  664. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  665. package/src/modes/theme/defaults/dark-slate.json +95 -0
  666. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  667. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  668. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  669. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  670. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  671. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  672. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  673. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  674. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  675. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  676. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  677. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  678. package/src/modes/theme/defaults/graphite.json +92 -0
  679. package/src/modes/theme/defaults/index.ts +199 -0
  680. package/src/modes/theme/defaults/light-arctic.json +107 -0
  681. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  682. package/src/modes/theme/defaults/light-canyon.json +91 -0
  683. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  684. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  685. package/src/modes/theme/defaults/light-coral.json +95 -0
  686. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  687. package/src/modes/theme/defaults/light-dawn.json +90 -0
  688. package/src/modes/theme/defaults/light-dunes.json +91 -0
  689. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  690. package/src/modes/theme/defaults/light-forest.json +100 -0
  691. package/src/modes/theme/defaults/light-frost.json +95 -0
  692. package/src/modes/theme/defaults/light-github.json +115 -0
  693. package/src/modes/theme/defaults/light-glacier.json +91 -0
  694. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  695. package/src/modes/theme/defaults/light-haze.json +90 -0
  696. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  697. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  698. package/src/modes/theme/defaults/light-lavender.json +95 -0
  699. package/src/modes/theme/defaults/light-meadow.json +91 -0
  700. package/src/modes/theme/defaults/light-mint.json +95 -0
  701. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  702. package/src/modes/theme/defaults/light-ocean.json +99 -0
  703. package/src/modes/theme/defaults/light-one.json +99 -0
  704. package/src/modes/theme/defaults/light-opal.json +91 -0
  705. package/src/modes/theme/defaults/light-orchard.json +91 -0
  706. package/src/modes/theme/defaults/light-paper.json +95 -0
  707. package/src/modes/theme/defaults/light-poimandres.json +142 -0
  708. package/src/modes/theme/defaults/light-prism.json +90 -0
  709. package/src/modes/theme/defaults/light-retro.json +98 -0
  710. package/src/modes/theme/defaults/light-sand.json +95 -0
  711. package/src/modes/theme/defaults/light-savanna.json +91 -0
  712. package/src/modes/theme/defaults/light-solarized.json +102 -0
  713. package/src/modes/theme/defaults/light-soleil.json +90 -0
  714. package/src/modes/theme/defaults/light-sunset.json +99 -0
  715. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  716. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  717. package/src/modes/theme/defaults/light-wetland.json +91 -0
  718. package/src/modes/theme/defaults/light-zenith.json +89 -0
  719. package/src/modes/theme/defaults/limestone.json +94 -0
  720. package/src/modes/theme/defaults/mahogany.json +97 -0
  721. package/src/modes/theme/defaults/marble.json +93 -0
  722. package/src/modes/theme/defaults/obsidian.json +91 -0
  723. package/src/modes/theme/defaults/onyx.json +91 -0
  724. package/src/modes/theme/defaults/pearl.json +93 -0
  725. package/src/modes/theme/defaults/porcelain.json +91 -0
  726. package/src/modes/theme/defaults/quartz.json +96 -0
  727. package/src/modes/theme/defaults/sandstone.json +95 -0
  728. package/src/modes/theme/defaults/titanium.json +90 -0
  729. package/src/modes/theme/light.json +93 -0
  730. package/src/modes/theme/mermaid-cache.ts +29 -0
  731. package/src/modes/theme/shimmer.ts +235 -0
  732. package/src/modes/theme/theme-schema.json +459 -0
  733. package/src/modes/theme/theme.ts +2676 -0
  734. package/src/modes/turn-budget.ts +31 -0
  735. package/src/modes/types.ts +359 -0
  736. package/src/modes/ultrathink.ts +41 -0
  737. package/src/modes/utils/context-usage.ts +339 -0
  738. package/src/modes/utils/copy-targets.ts +360 -0
  739. package/src/modes/utils/hotkeys-markdown.ts +61 -0
  740. package/src/modes/utils/keybinding-matchers.ts +51 -0
  741. package/src/modes/utils/tools-markdown.ts +27 -0
  742. package/src/modes/utils/ui-helpers.ts +801 -0
  743. package/src/modes/workflow.ts +42 -0
  744. package/src/plan-mode/approved-plan.ts +186 -0
  745. package/src/plan-mode/plan-handoff.ts +37 -0
  746. package/src/plan-mode/plan-protection.ts +31 -0
  747. package/src/plan-mode/state.ts +6 -0
  748. package/src/priority.json +41 -0
  749. package/src/prompts/agents/designer.md +66 -0
  750. package/src/prompts/agents/explore.md +58 -0
  751. package/src/prompts/agents/frontmatter.md +11 -0
  752. package/src/prompts/agents/init.md +33 -0
  753. package/src/prompts/agents/librarian.md +119 -0
  754. package/src/prompts/agents/oracle.md +55 -0
  755. package/src/prompts/agents/plan.md +48 -0
  756. package/src/prompts/agents/reviewer.md +140 -0
  757. package/src/prompts/agents/task.md +16 -0
  758. package/src/prompts/ci-green-request.md +36 -0
  759. package/src/prompts/dry-balance-bench.md +8 -0
  760. package/src/prompts/goals/goal-budget-limit.md +16 -0
  761. package/src/prompts/goals/goal-continuation.md +28 -0
  762. package/src/prompts/goals/goal-mode-active.md +23 -0
  763. package/src/prompts/memories/consolidation.md +30 -0
  764. package/src/prompts/memories/read-path.md +11 -0
  765. package/src/prompts/memories/stage_one_input.md +6 -0
  766. package/src/prompts/memories/stage_one_system.md +21 -0
  767. package/src/prompts/review-custom-request.md +22 -0
  768. package/src/prompts/review-headless-request.md +16 -0
  769. package/src/prompts/review-request.md +69 -0
  770. package/src/prompts/steering/user-interjection.md +10 -0
  771. package/src/prompts/system/agent-creation-architect.md +50 -0
  772. package/src/prompts/system/agent-creation-user.md +6 -0
  773. package/src/prompts/system/auto-continue.md +1 -0
  774. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  775. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  776. package/src/prompts/system/background-tan-dispatch.md +8 -0
  777. package/src/prompts/system/btw-user.md +8 -0
  778. package/src/prompts/system/commit-message-system.md +14 -0
  779. package/src/prompts/system/custom-system-prompt.md +64 -0
  780. package/src/prompts/system/eager-todo.md +13 -0
  781. package/src/prompts/system/empty-stop-retry.md +6 -0
  782. package/src/prompts/system/irc-incoming.md +7 -0
  783. package/src/prompts/system/manual-continue.md +7 -0
  784. package/src/prompts/system/memory-consolidation-system.md +8 -0
  785. package/src/prompts/system/memory-extraction-system.md +26 -0
  786. package/src/prompts/system/omfg-user.md +50 -0
  787. package/src/prompts/system/orchestrate-notice.md +40 -0
  788. package/src/prompts/system/plan-mode-active.md +109 -0
  789. package/src/prompts/system/plan-mode-approved.md +25 -0
  790. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  791. package/src/prompts/system/plan-mode-reference.md +11 -0
  792. package/src/prompts/system/plan-mode-subagent.md +33 -0
  793. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  794. package/src/prompts/system/project-prompt.md +52 -0
  795. package/src/prompts/system/subagent-system-prompt.md +64 -0
  796. package/src/prompts/system/subagent-user-prompt.md +3 -0
  797. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  798. package/src/prompts/system/system-prompt.md +258 -0
  799. package/src/prompts/system/tiny-title-system.md +8 -0
  800. package/src/prompts/system/title-system.md +16 -0
  801. package/src/prompts/system/ttsr-interrupt.md +7 -0
  802. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  803. package/src/prompts/system/ultrathink-notice.md +3 -0
  804. package/src/prompts/system/web-search.md +25 -0
  805. package/src/prompts/system/workflow-notice.md +70 -0
  806. package/src/prompts/tools/apply-patch.md +65 -0
  807. package/src/prompts/tools/ask.md +30 -0
  808. package/src/prompts/tools/ast-edit.md +39 -0
  809. package/src/prompts/tools/ast-grep.md +42 -0
  810. package/src/prompts/tools/async-result.md +8 -0
  811. package/src/prompts/tools/bash.md +46 -0
  812. package/src/prompts/tools/browser.md +73 -0
  813. package/src/prompts/tools/checkpoint.md +16 -0
  814. package/src/prompts/tools/debug.md +34 -0
  815. package/src/prompts/tools/eval.md +92 -0
  816. package/src/prompts/tools/find.md +36 -0
  817. package/src/prompts/tools/github.md +21 -0
  818. package/src/prompts/tools/goal.md +18 -0
  819. package/src/prompts/tools/image-gen.md +7 -0
  820. package/src/prompts/tools/inspect-image-system.md +20 -0
  821. package/src/prompts/tools/inspect-image.md +32 -0
  822. package/src/prompts/tools/irc.md +59 -0
  823. package/src/prompts/tools/job.md +19 -0
  824. package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
  825. package/src/prompts/tools/lsp.md +42 -0
  826. package/src/prompts/tools/memory-edit.md +8 -0
  827. package/src/prompts/tools/patch.md +70 -0
  828. package/src/prompts/tools/read.md +84 -0
  829. package/src/prompts/tools/recall.md +5 -0
  830. package/src/prompts/tools/reflect.md +5 -0
  831. package/src/prompts/tools/render-mermaid.md +9 -0
  832. package/src/prompts/tools/replace.md +30 -0
  833. package/src/prompts/tools/resolve.md +9 -0
  834. package/src/prompts/tools/retain.md +6 -0
  835. package/src/prompts/tools/rewind.md +13 -0
  836. package/src/prompts/tools/search-tool-bm25.md +32 -0
  837. package/src/prompts/tools/search.md +24 -0
  838. package/src/prompts/tools/ssh.md +31 -0
  839. package/src/prompts/tools/task-summary.md +17 -0
  840. package/src/prompts/tools/task.md +88 -0
  841. package/src/prompts/tools/todo.md +62 -0
  842. package/src/prompts/tools/web-search.md +10 -0
  843. package/src/prompts/tools/write.md +14 -0
  844. package/src/registry/agent-lifecycle.ts +218 -0
  845. package/src/registry/agent-registry.ts +151 -0
  846. package/src/sdk.ts +2558 -0
  847. package/src/secrets/index.ts +123 -0
  848. package/src/secrets/obfuscator.ts +298 -0
  849. package/src/secrets/regex.ts +21 -0
  850. package/src/session/agent-session.ts +10121 -0
  851. package/src/session/agent-storage.ts +455 -0
  852. package/src/session/artifacts.ts +135 -0
  853. package/src/session/auth-broker-config.ts +131 -0
  854. package/src/session/auth-storage.ts +29 -0
  855. package/src/session/blob-store.ts +255 -0
  856. package/src/session/client-bridge.ts +85 -0
  857. package/src/session/history-storage.ts +348 -0
  858. package/src/session/indexed-session-storage.ts +430 -0
  859. package/src/session/messages.ts +541 -0
  860. package/src/session/redis-session-storage.ts +170 -0
  861. package/src/session/session-dump-format.ts +209 -0
  862. package/src/session/session-history-format.ts +246 -0
  863. package/src/session/session-manager.ts +3676 -0
  864. package/src/session/session-storage.ts +529 -0
  865. package/src/session/shake-types.ts +43 -0
  866. package/src/session/sql-session-storage.ts +314 -0
  867. package/src/session/streaming-output.ts +1330 -0
  868. package/src/session/tool-choice-queue.ts +213 -0
  869. package/src/session/yield-queue.ts +173 -0
  870. package/src/slash-commands/acp-builtins.ts +70 -0
  871. package/src/slash-commands/builtin-registry.ts +1798 -0
  872. package/src/slash-commands/helpers/context-report.ts +39 -0
  873. package/src/slash-commands/helpers/format.ts +46 -0
  874. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  875. package/src/slash-commands/helpers/mcp.ts +532 -0
  876. package/src/slash-commands/helpers/parse.ts +85 -0
  877. package/src/slash-commands/helpers/ssh.ts +195 -0
  878. package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
  879. package/src/slash-commands/helpers/todo.ts +279 -0
  880. package/src/slash-commands/helpers/usage-report.ts +95 -0
  881. package/src/slash-commands/marketplace-install-parser.ts +99 -0
  882. package/src/slash-commands/types.ts +135 -0
  883. package/src/ssh/config-writer.ts +183 -0
  884. package/src/ssh/connection-manager.ts +509 -0
  885. package/src/ssh/ssh-executor.ts +189 -0
  886. package/src/ssh/sshfs-mount.ts +140 -0
  887. package/src/ssh/utils.ts +8 -0
  888. package/src/stt/downloader.ts +71 -0
  889. package/src/stt/index.ts +3 -0
  890. package/src/stt/recorder.ts +351 -0
  891. package/src/stt/setup.ts +52 -0
  892. package/src/stt/stt-controller.ts +160 -0
  893. package/src/stt/transcribe.py +70 -0
  894. package/src/stt/transcriber.ts +91 -0
  895. package/src/stubs/natives/index.ts +814 -0
  896. package/src/stubs/natives/package.json +7 -0
  897. package/src/stubs/tui/index.ts +282 -0
  898. package/src/stubs/tui/package.json +7 -0
  899. package/src/system-prompt.ts +611 -0
  900. package/src/task/agents.ts +167 -0
  901. package/src/task/commands.ts +132 -0
  902. package/src/task/discovery.ts +122 -0
  903. package/src/task/executor.ts +2133 -0
  904. package/src/task/index.ts +1419 -0
  905. package/src/task/name-generator.ts +1577 -0
  906. package/src/task/omp-command.ts +26 -0
  907. package/src/task/output-manager.ts +88 -0
  908. package/src/task/parallel.ts +116 -0
  909. package/src/task/render.ts +1381 -0
  910. package/src/task/repair-args.ts +129 -0
  911. package/src/task/subprocess-tool-registry.ts +88 -0
  912. package/src/task/types.ts +336 -0
  913. package/src/task/worktree.ts +514 -0
  914. package/src/telemetry-export.ts +144 -0
  915. package/src/thinking.ts +167 -0
  916. package/src/tiny/compiled-runtime.ts +179 -0
  917. package/src/tiny/device.ts +111 -0
  918. package/src/tiny/dtype.ts +101 -0
  919. package/src/tiny/models.ts +242 -0
  920. package/src/tiny/text.ts +165 -0
  921. package/src/tiny/title-client.ts +543 -0
  922. package/src/tiny/title-protocol.ts +56 -0
  923. package/src/tiny/worker.ts +568 -0
  924. package/src/tool-discovery/mode.ts +24 -0
  925. package/src/tool-discovery/tool-index.ts +256 -0
  926. package/src/tools/approval.ts +189 -0
  927. package/src/tools/archive-reader.ts +721 -0
  928. package/src/tools/ask.ts +928 -0
  929. package/src/tools/ast-edit.ts +642 -0
  930. package/src/tools/ast-grep.ts +452 -0
  931. package/src/tools/auto-generated-guard.ts +322 -0
  932. package/src/tools/bash-command-fixup.ts +37 -0
  933. package/src/tools/bash-interactive.ts +408 -0
  934. package/src/tools/bash-interceptor.ts +67 -0
  935. package/src/tools/bash-pty-selection.ts +14 -0
  936. package/src/tools/bash-skill-urls.ts +248 -0
  937. package/src/tools/bash.ts +1386 -0
  938. package/src/tools/browser/attach.ts +175 -0
  939. package/src/tools/browser/launch.ts +660 -0
  940. package/src/tools/browser/readable.ts +112 -0
  941. package/src/tools/browser/registry.ts +197 -0
  942. package/src/tools/browser/render.ts +216 -0
  943. package/src/tools/browser/tab-protocol.ts +105 -0
  944. package/src/tools/browser/tab-supervisor.ts +628 -0
  945. package/src/tools/browser/tab-worker-entry.ts +21 -0
  946. package/src/tools/browser/tab-worker.ts +1226 -0
  947. package/src/tools/browser.ts +343 -0
  948. package/src/tools/checkpoint.ts +136 -0
  949. package/src/tools/conflict-detect.ts +718 -0
  950. package/src/tools/context.ts +39 -0
  951. package/src/tools/debug.ts +1067 -0
  952. package/src/tools/eval-backends.ts +27 -0
  953. package/src/tools/eval-render.ts +752 -0
  954. package/src/tools/eval.ts +577 -0
  955. package/src/tools/fetch.ts +1926 -0
  956. package/src/tools/file-recorder.ts +35 -0
  957. package/src/tools/find.ts +609 -0
  958. package/src/tools/fs-cache-invalidation.ts +28 -0
  959. package/src/tools/gh-cache-invalidation.ts +255 -0
  960. package/src/tools/gh-format.ts +12 -0
  961. package/src/tools/gh-renderer.ts +481 -0
  962. package/src/tools/gh.ts +3720 -0
  963. package/src/tools/github-cache.ts +637 -0
  964. package/src/tools/grouped-file-output.ts +210 -0
  965. package/src/tools/image-gen.ts +1517 -0
  966. package/src/tools/index.ts +599 -0
  967. package/src/tools/inspect-image-renderer.ts +132 -0
  968. package/src/tools/inspect-image.ts +174 -0
  969. package/src/tools/irc.ts +723 -0
  970. package/src/tools/job.ts +557 -0
  971. package/src/tools/json-tree.ts +243 -0
  972. package/src/tools/jtd-to-json-schema.ts +219 -0
  973. package/src/tools/jtd-to-typescript.ts +136 -0
  974. package/src/tools/jtd-utils.ts +102 -0
  975. package/src/tools/list-limit.ts +40 -0
  976. package/src/tools/match-line-format.ts +20 -0
  977. package/src/tools/memory-edit.ts +59 -0
  978. package/src/tools/memory-recall.ts +100 -0
  979. package/src/tools/memory-reflect.ts +88 -0
  980. package/src/tools/memory-render.ts +202 -0
  981. package/src/tools/memory-retain.ts +91 -0
  982. package/src/tools/output-meta.ts +754 -0
  983. package/src/tools/output-schema-validator.ts +132 -0
  984. package/src/tools/path-utils.ts +1054 -0
  985. package/src/tools/plan-mode-guard.ts +108 -0
  986. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  987. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  988. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  989. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  990. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  991. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  992. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  993. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  994. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  995. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  996. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  997. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  998. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  999. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1000. package/src/tools/read.ts +2929 -0
  1001. package/src/tools/render-mermaid.ts +69 -0
  1002. package/src/tools/render-utils.ts +838 -0
  1003. package/src/tools/renderers.ts +77 -0
  1004. package/src/tools/report-tool-issue.ts +534 -0
  1005. package/src/tools/resolve.ts +276 -0
  1006. package/src/tools/review.ts +253 -0
  1007. package/src/tools/search-tool-bm25.ts +351 -0
  1008. package/src/tools/search.ts +1580 -0
  1009. package/src/tools/sqlite-reader.ts +828 -0
  1010. package/src/tools/ssh.ts +349 -0
  1011. package/src/tools/todo.ts +982 -0
  1012. package/src/tools/tool-errors.ts +62 -0
  1013. package/src/tools/tool-result.ts +94 -0
  1014. package/src/tools/tool-timeouts.ts +30 -0
  1015. package/src/tools/tts.ts +133 -0
  1016. package/src/tools/write.ts +1217 -0
  1017. package/src/tools/yield.ts +269 -0
  1018. package/src/tui/code-cell.ts +216 -0
  1019. package/src/tui/file-list.ts +55 -0
  1020. package/src/tui/hyperlink.ts +175 -0
  1021. package/src/tui/index.ts +12 -0
  1022. package/src/tui/output-block.ts +240 -0
  1023. package/src/tui/status-line.ts +54 -0
  1024. package/src/tui/tree-list.ts +84 -0
  1025. package/src/tui/types.ts +15 -0
  1026. package/src/tui/utils.ts +103 -0
  1027. package/src/utils/block-context.ts +312 -0
  1028. package/src/utils/changelog.ts +132 -0
  1029. package/src/utils/clipboard.ts +193 -0
  1030. package/src/utils/command-args.ts +76 -0
  1031. package/src/utils/commit-message-generator.ts +151 -0
  1032. package/src/utils/edit-mode.ts +41 -0
  1033. package/src/utils/enhanced-paste.ts +230 -0
  1034. package/src/utils/event-bus.ts +33 -0
  1035. package/src/utils/external-editor.ts +65 -0
  1036. package/src/utils/file-display-mode.ts +45 -0
  1037. package/src/utils/file-mentions.ts +281 -0
  1038. package/src/utils/git.ts +1833 -0
  1039. package/src/utils/image-loading.ts +132 -0
  1040. package/src/utils/image-resize.ts +309 -0
  1041. package/src/utils/jj.ts +248 -0
  1042. package/src/utils/lang-from-path.ts +239 -0
  1043. package/src/utils/markit.ts +89 -0
  1044. package/src/utils/open.ts +55 -0
  1045. package/src/utils/session-color.ts +68 -0
  1046. package/src/utils/shell-snapshot.ts +187 -0
  1047. package/src/utils/sixel.ts +69 -0
  1048. package/src/utils/title-generator.ts +373 -0
  1049. package/src/utils/tool-choice.ts +33 -0
  1050. package/src/utils/tools-manager.ts +363 -0
  1051. package/src/web/kagi.ts +305 -0
  1052. package/src/web/parallel.ts +353 -0
  1053. package/src/web/scrapers/artifacthub.ts +207 -0
  1054. package/src/web/scrapers/arxiv.ts +83 -0
  1055. package/src/web/scrapers/aur.ts +162 -0
  1056. package/src/web/scrapers/biorxiv.ts +133 -0
  1057. package/src/web/scrapers/bluesky.ts +262 -0
  1058. package/src/web/scrapers/brew.ts +172 -0
  1059. package/src/web/scrapers/cheatsh.ts +68 -0
  1060. package/src/web/scrapers/chocolatey.ts +196 -0
  1061. package/src/web/scrapers/choosealicense.ts +95 -0
  1062. package/src/web/scrapers/cisa-kev.ts +87 -0
  1063. package/src/web/scrapers/clojars.ts +154 -0
  1064. package/src/web/scrapers/coingecko.ts +177 -0
  1065. package/src/web/scrapers/crates-io.ts +97 -0
  1066. package/src/web/scrapers/crossref.ts +136 -0
  1067. package/src/web/scrapers/devto.ts +147 -0
  1068. package/src/web/scrapers/discogs.ts +306 -0
  1069. package/src/web/scrapers/discourse.ts +197 -0
  1070. package/src/web/scrapers/dockerhub.ts +138 -0
  1071. package/src/web/scrapers/docs-rs.ts +653 -0
  1072. package/src/web/scrapers/fdroid.ts +134 -0
  1073. package/src/web/scrapers/firefox-addons.ts +191 -0
  1074. package/src/web/scrapers/flathub.ts +223 -0
  1075. package/src/web/scrapers/github-gist.ts +58 -0
  1076. package/src/web/scrapers/github.ts +704 -0
  1077. package/src/web/scrapers/gitlab.ts +401 -0
  1078. package/src/web/scrapers/go-pkg.ts +266 -0
  1079. package/src/web/scrapers/hackage.ts +140 -0
  1080. package/src/web/scrapers/hackernews.ts +189 -0
  1081. package/src/web/scrapers/hex.ts +105 -0
  1082. package/src/web/scrapers/huggingface.ts +321 -0
  1083. package/src/web/scrapers/iacr.ts +89 -0
  1084. package/src/web/scrapers/index.ts +252 -0
  1085. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1086. package/src/web/scrapers/lemmy.ts +203 -0
  1087. package/src/web/scrapers/lobsters.ts +175 -0
  1088. package/src/web/scrapers/mastodon.ts +292 -0
  1089. package/src/web/scrapers/maven.ts +138 -0
  1090. package/src/web/scrapers/mdn.ts +173 -0
  1091. package/src/web/scrapers/metacpan.ts +222 -0
  1092. package/src/web/scrapers/musicbrainz.ts +250 -0
  1093. package/src/web/scrapers/npm.ts +98 -0
  1094. package/src/web/scrapers/nuget.ts +183 -0
  1095. package/src/web/scrapers/nvd.ts +222 -0
  1096. package/src/web/scrapers/ollama.ts +239 -0
  1097. package/src/web/scrapers/open-vsx.ts +106 -0
  1098. package/src/web/scrapers/opencorporates.ts +292 -0
  1099. package/src/web/scrapers/openlibrary.ts +336 -0
  1100. package/src/web/scrapers/orcid.ts +286 -0
  1101. package/src/web/scrapers/osv.ts +176 -0
  1102. package/src/web/scrapers/packagist.ts +160 -0
  1103. package/src/web/scrapers/pub-dev.ts +143 -0
  1104. package/src/web/scrapers/pubmed.ts +211 -0
  1105. package/src/web/scrapers/pypi.ts +112 -0
  1106. package/src/web/scrapers/rawg.ts +110 -0
  1107. package/src/web/scrapers/readthedocs.ts +120 -0
  1108. package/src/web/scrapers/reddit.ts +95 -0
  1109. package/src/web/scrapers/repology.ts +251 -0
  1110. package/src/web/scrapers/rfc.ts +201 -0
  1111. package/src/web/scrapers/rubygems.ts +103 -0
  1112. package/src/web/scrapers/searchcode.ts +189 -0
  1113. package/src/web/scrapers/sec-edgar.ts +261 -0
  1114. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1115. package/src/web/scrapers/snapcraft.ts +187 -0
  1116. package/src/web/scrapers/sourcegraph.ts +336 -0
  1117. package/src/web/scrapers/spdx.ts +108 -0
  1118. package/src/web/scrapers/spotify.ts +198 -0
  1119. package/src/web/scrapers/stackoverflow.ts +120 -0
  1120. package/src/web/scrapers/terraform.ts +277 -0
  1121. package/src/web/scrapers/tldr.ts +47 -0
  1122. package/src/web/scrapers/twitter.ts +94 -0
  1123. package/src/web/scrapers/types.ts +397 -0
  1124. package/src/web/scrapers/utils.ts +109 -0
  1125. package/src/web/scrapers/vimeo.ts +133 -0
  1126. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  1127. package/src/web/scrapers/w3c.ts +156 -0
  1128. package/src/web/scrapers/wikidata.ts +344 -0
  1129. package/src/web/scrapers/wikipedia.ts +84 -0
  1130. package/src/web/scrapers/youtube.ts +325 -0
  1131. package/src/web/search/index.ts +292 -0
  1132. package/src/web/search/provider.ts +157 -0
  1133. package/src/web/search/providers/anthropic.ts +318 -0
  1134. package/src/web/search/providers/base.ts +89 -0
  1135. package/src/web/search/providers/brave.ts +152 -0
  1136. package/src/web/search/providers/codex.ts +591 -0
  1137. package/src/web/search/providers/exa.ts +400 -0
  1138. package/src/web/search/providers/gemini.ts +460 -0
  1139. package/src/web/search/providers/jina.ts +111 -0
  1140. package/src/web/search/providers/kagi.ts +86 -0
  1141. package/src/web/search/providers/kimi.ts +196 -0
  1142. package/src/web/search/providers/parallel.ts +225 -0
  1143. package/src/web/search/providers/perplexity.ts +730 -0
  1144. package/src/web/search/providers/searxng.ts +313 -0
  1145. package/src/web/search/providers/synthetic.ts +114 -0
  1146. package/src/web/search/providers/tavily.ts +176 -0
  1147. package/src/web/search/providers/utils.ts +128 -0
  1148. package/src/web/search/providers/zai.ts +333 -0
  1149. package/src/web/search/render.ts +262 -0
  1150. package/src/web/search/types.ts +482 -0
  1151. package/src/web/search/utils.ts +17 -0
  1152. package/src/workspace-tree.ts +286 -0
@@ -0,0 +1,1275 @@
1
+ /**
2
+ * MCP Server Manager.
3
+ *
4
+ * Discovers, connects to, and manages MCP servers.
5
+ * Handles tool loading and lifecycle.
6
+ */
7
+ import * as path from "node:path";
8
+ import * as url from "node:url";
9
+ import { isDefinitiveOAuthFailure, type TSchema } from "@oh-my-pi/pi-ai";
10
+ import { logger } from "@oh-my-pi/pi-utils";
11
+ import type { SourceMeta } from "../capability/types";
12
+ import { resolveConfigValue } from "../config/resolve-config-value";
13
+ import type { CustomTool } from "../extensibility/custom-tools/types";
14
+ import type { AuthStorage } from "../session/auth-storage";
15
+ import {
16
+ connectToServer,
17
+ disconnectServer,
18
+ getPrompt,
19
+ listPrompts,
20
+ listResources,
21
+ listResourceTemplates,
22
+ listTools,
23
+ readResource,
24
+ serverSupportsPrompts,
25
+ serverSupportsResources,
26
+ subscribeToResources,
27
+ unsubscribeFromResources,
28
+ } from "./client";
29
+ import { loadAllMCPConfigs, validateServerConfig } from "./config";
30
+ import { refreshMCPOAuthToken } from "./oauth-flow";
31
+ import type { MCPToolDetails } from "./tool-bridge";
32
+ import { DeferredMCPTool, MCPTool } from "./tool-bridge";
33
+ import type { MCPToolCache } from "./tool-cache";
34
+ import { HttpTransport } from "./transports/http";
35
+ import type {
36
+ MCPGetPromptResult,
37
+ MCPPrompt,
38
+ MCPRequestOptions,
39
+ MCPResource,
40
+ MCPResourceReadResult,
41
+ MCPResourceTemplate,
42
+ MCPServerConfig,
43
+ MCPServerConnection,
44
+ MCPToolDefinition,
45
+ } from "./types";
46
+ import { MCPNotificationMethods } from "./types";
47
+
48
+ type ToolLoadResult = {
49
+ connection: MCPServerConnection;
50
+ serverTools: MCPToolDefinition[];
51
+ };
52
+
53
+ type TrackedPromise<T> = {
54
+ promise: Promise<T>;
55
+ status: "pending" | "fulfilled" | "rejected";
56
+ value?: T;
57
+ reason?: unknown;
58
+ };
59
+
60
+ const STARTUP_TIMEOUT_MS = 250;
61
+
62
+ /**
63
+ * Per-server reconnect-storm circuit breaker.
64
+ *
65
+ * `transport.onClose` (wired in {@link MCPManager.connectServers} and
66
+ * {@link MCPManager.#connectAndWireServer}) fires `reconnectServer` on every
67
+ * clean process exit, so a stdio MCP server that completes the
68
+ * `initialize` + `tools/list` handshake and then exits will pull the agent
69
+ * into a fork loop with no rate limit. That pathology shipped in issue #1592
70
+ * (a `php`-shebang MCP fork-bombing macOS, parented directly to the agent's
71
+ * `bun` PID via shebang exec).
72
+ *
73
+ * We keep the sliding window short — older crashes age out so a single
74
+ * transient failure stays cheap — but cap the burst tightly enough that the
75
+ * agent never spawns more than `RECONNECT_BURST_LIMIT * #doReconnect retries`
76
+ * (≤ 25) processes per stuck server per window. Manual `/mcp reconnect`
77
+ * resets the window so users can recover after fixing the underlying
78
+ * misconfiguration.
79
+ */
80
+ const RECONNECT_BURST_WINDOW_MS = 30_000;
81
+ const RECONNECT_BURST_LIMIT = 5;
82
+
83
+ function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
84
+ const tracked: TrackedPromise<T> = { promise, status: "pending" };
85
+ promise.then(
86
+ value => {
87
+ tracked.status = "fulfilled";
88
+ tracked.value = value;
89
+ },
90
+ reason => {
91
+ tracked.status = "rejected";
92
+ tracked.reason = reason;
93
+ },
94
+ );
95
+ return tracked;
96
+ }
97
+
98
+ function delay(ms: number): Promise<void> {
99
+ return Bun.sleep(ms);
100
+ }
101
+
102
+ /**
103
+ * Stable, total ordering on MCP tools by name.
104
+ *
105
+ * Anthropic prompt caching keys on byte-identical tool definitions: any reorder
106
+ * of the tools array invalidates the tools cache breakpoint and forces a full
107
+ * prefix rebuild on the next request. MCP servers connect/reconnect at arbitrary
108
+ * times, so the natural "insertion order" of `#tools` is non-deterministic.
109
+ * Sorting after every mutation makes the array bytes independent of connection
110
+ * sequence.
111
+ */
112
+ export function sortMCPToolsByName<T extends { name: string }>(tools: T[]): T[] {
113
+ tools.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
114
+ return tools;
115
+ }
116
+
117
+ export function resolveSubscriptionPostAction(
118
+ notificationsEnabled: boolean,
119
+ currentEpoch: number,
120
+ subscriptionEpoch: number,
121
+ ): "rollback" | "ignore" | "apply" {
122
+ if (!notificationsEnabled) return "rollback";
123
+ if (currentEpoch !== subscriptionEpoch) return "ignore";
124
+ return "apply";
125
+ }
126
+ /** Result of loading MCP tools */
127
+ export interface MCPLoadResult {
128
+ /** Loaded tools as CustomTool instances */
129
+ tools: CustomTool<TSchema, MCPToolDetails>[];
130
+ /** Connection errors by server name */
131
+ errors: Map<string, string>;
132
+ /** Connected server names */
133
+ connectedServers: string[];
134
+ /** Extracted Exa API keys from filtered MCP servers */
135
+ exaApiKeys: string[];
136
+ }
137
+
138
+ /** Options for discovering and connecting to MCP servers */
139
+ export interface MCPDiscoverOptions {
140
+ /** Whether to load project-level config (default: true) */
141
+ enableProjectConfig?: boolean;
142
+ /** Whether to filter out Exa MCP servers (default: true) */
143
+ filterExa?: boolean;
144
+ /** Whether to filter out browser MCP servers when builtin browser tool is enabled (default: false) */
145
+ filterBrowser?: boolean;
146
+ /** Called when starting to connect to servers */
147
+ onConnecting?: (serverNames: string[]) => void;
148
+ }
149
+
150
+ /**
151
+ * MCP Server Manager.
152
+ *
153
+ * Manages connections to MCP servers and provides tools to the agent.
154
+ */
155
+ export class MCPManager {
156
+ static #instance: MCPManager | undefined;
157
+
158
+ /** Process-global instance shared by internal URL protocol handlers and tools. */
159
+ static instance(): MCPManager | undefined {
160
+ return MCPManager.#instance;
161
+ }
162
+
163
+ /** Install or clear the process-global instance. */
164
+ static setInstance(value: MCPManager | undefined): void {
165
+ MCPManager.#instance = value;
166
+ }
167
+
168
+ /** Reset the process-global instance. Test-only. */
169
+ static resetForTests(): void {
170
+ MCPManager.#instance = undefined;
171
+ }
172
+
173
+ #connections = new Map<string, MCPServerConnection>();
174
+ #tools: CustomTool<TSchema, MCPToolDetails>[] = [];
175
+ #pendingConnections = new Map<string, Promise<MCPServerConnection>>();
176
+ #pendingToolLoads = new Map<string, Promise<ToolLoadResult>>();
177
+ #sources = new Map<string, SourceMeta>();
178
+ #authStorage: AuthStorage | null = null;
179
+ #onNotification?: (serverName: string, method: string, params: unknown) => void;
180
+ #onToolsChanged?: (tools: CustomTool<TSchema, MCPToolDetails>[]) => void;
181
+ #onResourcesChanged?: (serverName: string, uri: string) => void;
182
+ #onPromptsChanged?: (serverName: string) => void;
183
+ #notificationsEnabled = false;
184
+ #notificationsEpoch = 0;
185
+ #subscribedResources = new Map<string, Set<string>>();
186
+ #pendingResourceRefresh = new Map<string, { connection: MCPServerConnection; promise: Promise<void> }>();
187
+ #pendingReconnections = new Map<string, Promise<MCPServerConnection | null>>();
188
+ /** Preserved configs for reconnection after connection loss. */
189
+ #serverConfigs = new Map<string, MCPServerConfig>();
190
+ /**
191
+ * Timestamps of recent `reconnectServer` invocations per server, used by the
192
+ * crash-storm circuit breaker (see {@link RECONNECT_BURST_LIMIT}).
193
+ */
194
+ #reconnectHistory = new Map<string, number[]>();
195
+ /** Monotonic epoch incremented on disconnectAll to invalidate stale reconnections. */
196
+ #epoch = 0;
197
+
198
+ constructor(
199
+ private cwd: string,
200
+ private toolCache: MCPToolCache | null = null,
201
+ ) {}
202
+
203
+ /**
204
+ * Set a callback to receive all server notifications.
205
+ */
206
+ setOnNotification(handler: (serverName: string, method: string, params: unknown) => void): void {
207
+ this.#onNotification = handler;
208
+ }
209
+
210
+ /**
211
+ * Set a callback to fire when any server's tools change.
212
+ */
213
+ setOnToolsChanged(handler: (tools: CustomTool<TSchema, MCPToolDetails>[]) => void): void {
214
+ this.#onToolsChanged = handler;
215
+ }
216
+
217
+ /**
218
+ * Set a callback to fire when any server's resources change.
219
+ */
220
+ setOnResourcesChanged(handler: (serverName: string, uri: string) => void): void {
221
+ this.#onResourcesChanged = handler;
222
+ }
223
+
224
+ /**
225
+ * Set a callback to fire when any server's prompts change.
226
+ */
227
+ setOnPromptsChanged(handler: (serverName: string) => void): void {
228
+ this.#onPromptsChanged = handler;
229
+ // Fire immediately for servers that already have prompts loaded
230
+ for (const [name, connection] of this.#connections) {
231
+ if (connection.prompts?.length) {
232
+ handler(name);
233
+ }
234
+ }
235
+ }
236
+
237
+ #subscribeAndTrack(name: string, connection: MCPServerConnection, uris: string[], notificationEpoch: number): void {
238
+ void subscribeToResources(connection, uris)
239
+ .then(() => {
240
+ const action = resolveSubscriptionPostAction(
241
+ this.#notificationsEnabled,
242
+ this.#notificationsEpoch,
243
+ notificationEpoch,
244
+ );
245
+ if (action === "rollback") {
246
+ void unsubscribeFromResources(connection, uris).catch(error => {
247
+ logger.debug("Failed to rollback stale MCP resource subscription", {
248
+ path: `mcp:${name}`,
249
+ error,
250
+ });
251
+ });
252
+ return;
253
+ }
254
+ if (action === "ignore") {
255
+ return;
256
+ }
257
+ this.#subscribedResources.set(name, new Set(uris));
258
+ })
259
+ .catch(error => {
260
+ logger.debug("Failed to subscribe to MCP resources", { path: `mcp:${name}`, error });
261
+ });
262
+ }
263
+
264
+ setNotificationsEnabled(enabled: boolean): void {
265
+ const wasEnabled = this.#notificationsEnabled;
266
+ this.#notificationsEnabled = enabled;
267
+ if (enabled === wasEnabled) return;
268
+
269
+ this.#notificationsEpoch += 1;
270
+ const notificationEpoch = this.#notificationsEpoch;
271
+
272
+ if (enabled) {
273
+ // Subscribe to all connected servers that support it
274
+ for (const [name, connection] of this.#connections) {
275
+ if (connection.capabilities.resources?.subscribe && connection.resources) {
276
+ const uris = connection.resources.map(r => r.uri);
277
+ this.#subscribeAndTrack(name, connection, uris, notificationEpoch);
278
+ }
279
+ }
280
+ return;
281
+ }
282
+
283
+ // Unsubscribe from all servers
284
+ for (const [name, connection] of this.#connections) {
285
+ const uris = this.#subscribedResources.get(name);
286
+ if (uris && uris.size > 0) {
287
+ void unsubscribeFromResources(connection, Array.from(uris)).catch(error => {
288
+ logger.debug("Failed to unsubscribe MCP resources", { path: `mcp:${name}`, error });
289
+ });
290
+ }
291
+ }
292
+ this.#subscribedResources.clear();
293
+ }
294
+
295
+ /**
296
+ * Set the auth storage for resolving OAuth credentials.
297
+ */
298
+ setAuthStorage(authStorage: AuthStorage): void {
299
+ this.#authStorage = authStorage;
300
+ }
301
+
302
+ /**
303
+ * Discover and connect to all MCP servers from .mcp.json files.
304
+ * Returns tools and any connection errors.
305
+ */
306
+ async discoverAndConnect(options?: MCPDiscoverOptions): Promise<MCPLoadResult> {
307
+ const { configs, exaApiKeys, sources } = await loadAllMCPConfigs(this.cwd, {
308
+ enableProjectConfig: options?.enableProjectConfig,
309
+ filterExa: options?.filterExa,
310
+ filterBrowser: options?.filterBrowser,
311
+ });
312
+ const result = await this.connectServers(configs, sources, options?.onConnecting);
313
+ result.exaApiKeys = exaApiKeys;
314
+ return result;
315
+ }
316
+
317
+ /**
318
+ * Connect to specific MCP servers.
319
+ * Connections are made in parallel for faster startup.
320
+ */
321
+ async connectServers(
322
+ configs: Record<string, MCPServerConfig>,
323
+ sources: Record<string, SourceMeta>,
324
+ onConnecting?: (serverNames: string[]) => void,
325
+ ): Promise<MCPLoadResult> {
326
+ type ConnectionTask = {
327
+ name: string;
328
+ config: MCPServerConfig;
329
+ tracked: TrackedPromise<ToolLoadResult>;
330
+ toolsPromise: Promise<ToolLoadResult>;
331
+ };
332
+
333
+ const errors = new Map<string, string>();
334
+ const connectedServers = new Set<string>();
335
+ const allTools: CustomTool<TSchema, MCPToolDetails>[] = [];
336
+ const reportedErrors = new Set<string>();
337
+ let allowBackgroundLogging = false;
338
+
339
+ // Prepare connection tasks
340
+ const connectionTasks: ConnectionTask[] = [];
341
+
342
+ for (const [name, config] of Object.entries(configs)) {
343
+ if (sources[name]) {
344
+ this.#sources.set(name, sources[name]);
345
+ const existing = this.#connections.get(name);
346
+ if (existing) {
347
+ existing._source = sources[name];
348
+ }
349
+ }
350
+
351
+ // Skip if already connected
352
+ if (this.#connections.has(name)) {
353
+ connectedServers.add(name);
354
+ continue;
355
+ }
356
+
357
+ if (
358
+ this.#pendingConnections.has(name) ||
359
+ this.#pendingToolLoads.has(name) ||
360
+ this.#pendingReconnections.has(name)
361
+ ) {
362
+ continue;
363
+ }
364
+
365
+ // Validate config
366
+ const validationErrors = validateServerConfig(name, config);
367
+ if (validationErrors.length > 0) {
368
+ errors.set(name, validationErrors.join("; "));
369
+ reportedErrors.add(name);
370
+ continue;
371
+ }
372
+
373
+ // Save config early so reconnection works even if the initial connect times out
374
+ // and falls back to cached/deferred tools.
375
+ this.#serverConfigs.set(name, config);
376
+
377
+ // Resolve auth config before connecting, but do so per-server in parallel.
378
+ const connectionPromise = (async () => {
379
+ const resolvedConfig = await this.#resolveAuthConfig(config);
380
+ return connectToServer(name, resolvedConfig, {
381
+ onNotification: (method, params) => {
382
+ this.#handleServerNotification(name, method, params);
383
+ },
384
+ onRequest: (method, params) => {
385
+ return this.#handleServerRequest(method, params);
386
+ },
387
+ });
388
+ })().then(
389
+ connection => {
390
+ // Store original config (without resolved tokens) to keep
391
+ // cache keys stable and avoid leaking rotating credentials.
392
+ connection.config = config;
393
+ this.#serverConfigs.set(name, config);
394
+ if (sources[name]) {
395
+ connection._source = sources[name];
396
+ }
397
+ if (this.#pendingConnections.get(name) === connectionPromise) {
398
+ this.#pendingConnections.delete(name);
399
+ this.#connections.set(name, connection);
400
+ }
401
+
402
+ // Wire auth refresh for HTTP transports so 401s trigger token refresh.
403
+ if (connection.transport instanceof HttpTransport && config.auth?.type === "oauth") {
404
+ connection.transport.onAuthError = async () => {
405
+ const refreshed = await this.#resolveAuthConfig(config, true);
406
+ if (refreshed.type === "http" || refreshed.type === "sse") {
407
+ return refreshed.headers ?? null;
408
+ }
409
+ return null;
410
+ };
411
+ }
412
+
413
+ // Re-establish connection if the transport closes (server restart,
414
+ // network interruption).
415
+ connection.transport.onClose = () => {
416
+ logger.debug("MCP transport lost, triggering reconnect", { path: `mcp:${name}` });
417
+ void this.reconnectServer(name);
418
+ };
419
+
420
+ return connection;
421
+ },
422
+ error => {
423
+ if (this.#pendingConnections.get(name) === connectionPromise) {
424
+ this.#pendingConnections.delete(name);
425
+ }
426
+ throw error;
427
+ },
428
+ );
429
+ this.#pendingConnections.set(name, connectionPromise);
430
+
431
+ const toolsPromise = connectionPromise.then(async connection => {
432
+ const serverTools = await listTools(connection);
433
+ return { connection, serverTools };
434
+ });
435
+ this.#pendingToolLoads.set(name, toolsPromise);
436
+
437
+ const tracked = trackPromise(toolsPromise);
438
+ connectionTasks.push({ name, config, tracked, toolsPromise });
439
+
440
+ void toolsPromise
441
+ .then(async ({ connection, serverTools }) => {
442
+ if (this.#pendingToolLoads.get(name) !== toolsPromise) return;
443
+ this.#pendingToolLoads.delete(name);
444
+ const reconnect = () => this.reconnectServer(name);
445
+ const customTools = MCPTool.fromTools(connection, serverTools, reconnect);
446
+ this.#replaceServerTools(name, customTools);
447
+ this.#onToolsChanged?.(this.#tools);
448
+ void this.toolCache?.set(name, config, serverTools);
449
+
450
+ await this.#loadServerResourcesAndPrompts(name, connection);
451
+ })
452
+ .catch(error => {
453
+ if (this.#pendingToolLoads.get(name) !== toolsPromise) return;
454
+ this.#pendingToolLoads.delete(name);
455
+ if (!allowBackgroundLogging || reportedErrors.has(name)) return;
456
+ const message = error instanceof Error ? error.message : String(error);
457
+ logger.error("MCP tool load failed", { path: `mcp:${name}`, error: message });
458
+ });
459
+ }
460
+
461
+ // Notify about servers we're connecting to
462
+ if (connectionTasks.length > 0 && onConnecting) {
463
+ onConnecting(connectionTasks.map(task => task.name));
464
+ }
465
+
466
+ if (connectionTasks.length > 0) {
467
+ await Promise.race([
468
+ Promise.allSettled(connectionTasks.map(task => task.tracked.promise)),
469
+ delay(STARTUP_TIMEOUT_MS),
470
+ ]);
471
+
472
+ const cachedTools = new Map<string, MCPToolDefinition[]>();
473
+ const pendingTasks = connectionTasks.filter(task => task.tracked.status === "pending");
474
+
475
+ if (pendingTasks.length > 0 && this.toolCache) {
476
+ await Promise.all(
477
+ pendingTasks.map(async task => {
478
+ const cached = await this.toolCache?.get(task.name, task.config);
479
+ if (cached) {
480
+ cachedTools.set(task.name, cached);
481
+ }
482
+ }),
483
+ );
484
+ }
485
+
486
+ // Pending tasks without cached tools used to be awaited synchronously here,
487
+ // which gated the entire UI on the slowest server's per-request timeout
488
+ // (issue #2100: a single unresponsive MCP server blocked startup for the
489
+ // full 30 s `OMP_MCP_TIMEOUT_MS`). Leave them in flight — the background
490
+ // `void toolsPromise.then(...)` chain above registers their tools and
491
+ // fires `#onToolsChanged` once the connect finishes, or logs the failure
492
+ // after `allowBackgroundLogging` flips below.
493
+
494
+ for (const task of connectionTasks) {
495
+ const { name } = task;
496
+ if (task.tracked.status === "fulfilled") {
497
+ const value = task.tracked.value;
498
+ if (!value) continue;
499
+ const { connection, serverTools } = value;
500
+ connectedServers.add(name);
501
+ const reconnect = () => this.reconnectServer(name);
502
+ allTools.push(...MCPTool.fromTools(connection, serverTools, reconnect));
503
+ } else if (task.tracked.status === "rejected") {
504
+ const message =
505
+ task.tracked.reason instanceof Error ? task.tracked.reason.message : String(task.tracked.reason);
506
+ errors.set(name, message);
507
+ reportedErrors.add(name);
508
+ } else {
509
+ const cached = cachedTools.get(name);
510
+ if (cached) {
511
+ const source = this.#sources.get(name);
512
+ const reconnect = () => this.reconnectServer(name);
513
+ allTools.push(
514
+ ...DeferredMCPTool.fromTools(name, cached, () => this.waitForConnection(name), source, reconnect),
515
+ );
516
+ }
517
+ }
518
+ }
519
+ }
520
+
521
+ // Stable sort by name so the order is independent of connection completion.
522
+ // See `sortMCPToolsByName` for the cache-stability rationale.
523
+ sortMCPToolsByName(allTools);
524
+
525
+ // Update cached tools
526
+ this.#tools = allTools;
527
+ allowBackgroundLogging = true;
528
+
529
+ return {
530
+ tools: allTools,
531
+ errors,
532
+ connectedServers: Array.from(connectedServers),
533
+ exaApiKeys: [], // Will be populated by discoverAndConnect
534
+ };
535
+ }
536
+
537
+ #replaceServerTools(name: string, tools: CustomTool<TSchema, MCPToolDetails>[]): void {
538
+ this.#tools = this.#tools.filter(t => !t.name.startsWith(`mcp__${name}_`));
539
+ this.#tools.push(...tools);
540
+ // Stable sort by name so reconnect order does not perturb the array.
541
+ // See `sortMCPToolsByName` for the cache-stability rationale.
542
+ sortMCPToolsByName(this.#tools);
543
+ }
544
+
545
+ #triggerNotificationRefresh(serverName: string, kind: "tools" | "resources" | "prompts"): void {
546
+ const refresh = (() => {
547
+ switch (kind) {
548
+ case "tools":
549
+ return this.refreshServerTools(serverName);
550
+ case "resources":
551
+ return this.refreshServerResources(serverName);
552
+ case "prompts":
553
+ return this.refreshServerPrompts(serverName);
554
+ }
555
+ })();
556
+ void refresh.catch(error => {
557
+ logger.debug("Failed MCP notification refresh", { path: `mcp:${serverName}`, kind, error });
558
+ });
559
+ }
560
+ #handleServerNotification(serverName: string, method: string, params: unknown): void {
561
+ logger.debug("MCP notification received", { path: `mcp:${serverName}`, method });
562
+
563
+ switch (method) {
564
+ case MCPNotificationMethods.TOOLS_LIST_CHANGED:
565
+ this.#triggerNotificationRefresh(serverName, "tools");
566
+ break;
567
+ case MCPNotificationMethods.RESOURCES_LIST_CHANGED:
568
+ this.#triggerNotificationRefresh(serverName, "resources");
569
+ break;
570
+ case MCPNotificationMethods.RESOURCES_UPDATED: {
571
+ const uri = (params as { uri?: string })?.uri;
572
+ const subscribed = this.#subscribedResources.get(serverName);
573
+ if (uri && subscribed?.has(uri)) {
574
+ this.#onResourcesChanged?.(serverName, uri);
575
+ }
576
+ break;
577
+ }
578
+ case MCPNotificationMethods.PROMPTS_LIST_CHANGED:
579
+ this.#triggerNotificationRefresh(serverName, "prompts");
580
+ break;
581
+ default:
582
+ break;
583
+ }
584
+
585
+ this.#onNotification?.(serverName, method, params);
586
+ }
587
+
588
+ /** Handle server-to-client JSON-RPC requests (e.g. ping, roots/list). */
589
+ async #handleServerRequest(method: string, _params: unknown): Promise<unknown> {
590
+ switch (method) {
591
+ case "ping":
592
+ return {};
593
+ case "roots/list":
594
+ return this.#getRoots();
595
+ default:
596
+ throw Object.assign(new Error(`Unsupported server request: ${method}`), { code: -32601 });
597
+ }
598
+ }
599
+
600
+ #getRoots(): { roots: Array<{ uri: string; name: string }> } {
601
+ return {
602
+ roots: [
603
+ {
604
+ uri: url.pathToFileURL(this.cwd).href,
605
+ name: path.basename(this.cwd),
606
+ },
607
+ ],
608
+ };
609
+ }
610
+
611
+ /**
612
+ * Get all loaded tools.
613
+ */
614
+ getTools(): CustomTool<TSchema, MCPToolDetails>[] {
615
+ return this.#tools;
616
+ }
617
+
618
+ /**
619
+ * Get a specific connection.
620
+ */
621
+ getConnection(name: string): MCPServerConnection | undefined {
622
+ return this.#connections.get(name);
623
+ }
624
+
625
+ /**
626
+ * Get current connection status for a server.
627
+ */
628
+ getConnectionStatus(name: string): "connected" | "connecting" | "disconnected" {
629
+ if (this.#connections.has(name)) return "connected";
630
+ if (
631
+ this.#pendingConnections.has(name) ||
632
+ this.#pendingToolLoads.has(name) ||
633
+ this.#pendingReconnections.has(name)
634
+ )
635
+ return "connecting";
636
+ return "disconnected";
637
+ }
638
+
639
+ /**
640
+ * Get the source metadata for a server.
641
+ */
642
+ getSource(name: string): SourceMeta | undefined {
643
+ return this.#sources.get(name) ?? this.#connections.get(name)?._source;
644
+ }
645
+
646
+ /**
647
+ * Wait for a connection to complete (or fail).
648
+ */
649
+ async waitForConnection(name: string): Promise<MCPServerConnection> {
650
+ const connection = this.#connections.get(name);
651
+ if (connection) return connection;
652
+ const pending = this.#pendingConnections.get(name);
653
+ if (pending) return pending;
654
+ // If a reconnection is in flight, wait for it to complete
655
+ const reconnecting = this.#pendingReconnections.get(name);
656
+ if (reconnecting) {
657
+ const result = await reconnecting;
658
+ if (result) return result;
659
+ }
660
+ throw new Error(`MCP server not connected: ${name}`);
661
+ }
662
+
663
+ /**
664
+ * Resolve auth and shell-command substitutions in config before connecting.
665
+ */
666
+ async prepareConfig(config: MCPServerConfig): Promise<MCPServerConfig> {
667
+ return this.#resolveAuthConfig(config);
668
+ }
669
+
670
+ /**
671
+ * Get all connected server names.
672
+ */
673
+ getConnectedServers(): string[] {
674
+ return Array.from(this.#connections.keys());
675
+ }
676
+
677
+ /**
678
+ * Get all known server names (connected, connecting, or discovered).
679
+ */
680
+ getAllServerNames(): string[] {
681
+ return Array.from(
682
+ new Set([...this.#sources.keys(), ...this.#connections.keys(), ...this.#pendingConnections.keys()]),
683
+ );
684
+ }
685
+
686
+ /**
687
+ * Disconnect from a specific server.
688
+ */
689
+ async disconnectServer(name: string): Promise<void> {
690
+ this.#pendingConnections.delete(name);
691
+ this.#pendingToolLoads.delete(name);
692
+ this.#pendingReconnections.delete(name);
693
+ this.#sources.delete(name);
694
+ this.#serverConfigs.delete(name);
695
+ this.#pendingResourceRefresh.delete(name);
696
+ this.#reconnectHistory.delete(name);
697
+
698
+ const connection = this.#connections.get(name);
699
+
700
+ const subscribedUris = this.#subscribedResources.get(name);
701
+ if (subscribedUris && subscribedUris.size > 0 && connection) {
702
+ void unsubscribeFromResources(connection, Array.from(subscribedUris)).catch(() => {});
703
+ }
704
+ this.#subscribedResources.delete(name);
705
+
706
+ if (connection) {
707
+ // Detach onClose to prevent spurious reconnect from close()
708
+ connection.transport.onClose = undefined;
709
+ await disconnectServer(connection);
710
+ this.#connections.delete(name);
711
+ }
712
+
713
+ // Remove tools from this server and notify consumers
714
+ const hadTools = this.#tools.some(t => t.name.startsWith(`mcp__${name}_`));
715
+ this.#tools = this.#tools.filter(t => !t.name.startsWith(`mcp__${name}_`));
716
+ if (hadTools) this.#onToolsChanged?.(this.#tools);
717
+
718
+ // Notify prompt consumers so stale commands are cleared
719
+ if (connection?.prompts?.length) this.#onPromptsChanged?.(name);
720
+ }
721
+
722
+ /**
723
+ * Disconnect from all servers.
724
+ */
725
+ async disconnectAll(): Promise<void> {
726
+ // Invalidate any in-flight reconnection attempts that outlive this call.
727
+ // They captured the old epoch; after increment they'll detect staleness.
728
+ this.#epoch++;
729
+ // Detach onClose before closing to prevent spurious reconnect attempts
730
+ for (const conn of this.#connections.values()) {
731
+ conn.transport.onClose = undefined;
732
+ }
733
+ const promises = Array.from(this.#connections.values()).map(conn => disconnectServer(conn));
734
+ await Promise.allSettled(promises);
735
+
736
+ this.#pendingConnections.clear();
737
+ this.#pendingToolLoads.clear();
738
+ this.#pendingReconnections.clear();
739
+ this.#pendingResourceRefresh.clear();
740
+ this.#sources.clear();
741
+ this.#serverConfigs.clear();
742
+ this.#connections.clear();
743
+ this.#tools = [];
744
+ this.#subscribedResources.clear();
745
+ this.#reconnectHistory.clear();
746
+ }
747
+
748
+ /**
749
+ * Reconnect to a server after a connection failure.
750
+ *
751
+ * Tears down the stale connection, re-resolves auth, establishes a new
752
+ * connection, reloads tools, and notifies consumers. Concurrent calls for
753
+ * the same server share one reconnection attempt. Returns the new
754
+ * connection, or `null` if reconnection failed or the per-server crash
755
+ * burst limit (see {@link RECONNECT_BURST_LIMIT}) is exceeded.
756
+ *
757
+ * @param options.manual - When `true`, resets the crash-burst window so a
758
+ * user-driven retry (e.g. `/mcp reconnect`) is never blocked by an
759
+ * earlier storm. Defaults to `false`; the transport `onClose` callback
760
+ * and the per-tool-call retry path in `tool-bridge` MUST NOT set it.
761
+ */
762
+ async reconnectServer(name: string, options?: { manual?: boolean }): Promise<MCPServerConnection | null> {
763
+ if (options?.manual) {
764
+ this.#reconnectHistory.delete(name);
765
+ }
766
+
767
+ const pending = this.#pendingReconnections.get(name);
768
+ if (pending) return pending;
769
+
770
+ if (this.#tripReconnectBreaker(name)) {
771
+ return null;
772
+ }
773
+
774
+ const attempt = this.#doReconnect(name);
775
+ this.#pendingReconnections.set(name, attempt);
776
+ return attempt.finally(() => this.#pendingReconnections.delete(name));
777
+ }
778
+
779
+ /**
780
+ * Record a reconnect attempt against the per-server crash window and report
781
+ * whether the circuit breaker is now open. Sliding window: entries older
782
+ * than {@link RECONNECT_BURST_WINDOW_MS} are pruned before the new
783
+ * timestamp is appended, so a single transient failure ages out cheaply
784
+ * but repeated rapid crashes accumulate until the limit is hit.
785
+ */
786
+ #tripReconnectBreaker(name: string): boolean {
787
+ const now = Date.now();
788
+ const previous = this.#reconnectHistory.get(name) ?? [];
789
+ const recent = previous.filter(ts => now - ts < RECONNECT_BURST_WINDOW_MS);
790
+ recent.push(now);
791
+ this.#reconnectHistory.set(name, recent);
792
+
793
+ if (recent.length > RECONNECT_BURST_LIMIT) {
794
+ logger.error("MCP server crashed too many times; suspending automatic reconnects", {
795
+ path: `mcp:${name}`,
796
+ crashes: recent.length,
797
+ windowMs: RECONNECT_BURST_WINDOW_MS,
798
+ });
799
+ // Tear down the stale connection so `getConnectionStatus()` no
800
+ // longer reports it as "connected" and `waitForConnection()` does
801
+ // not hand a closed transport to callers. Tools stay registered
802
+ // in `#tools` — the user can recover with `/mcp reconnect <name>`
803
+ // once they've fixed the underlying misconfiguration. Mirrors the
804
+ // teardown in `#doReconnect`: detach `onClose` first so the
805
+ // transport's own `close()` cannot re-arm this path.
806
+ const stale = this.#connections.get(name);
807
+ if (stale) {
808
+ stale.transport.onClose = undefined;
809
+ void stale.transport.close().catch(() => {});
810
+ this.#connections.delete(name);
811
+ }
812
+ this.#pendingConnections.delete(name);
813
+ this.#pendingToolLoads.delete(name);
814
+ return true;
815
+ }
816
+ return false;
817
+ }
818
+
819
+ async #doReconnect(name: string): Promise<MCPServerConnection | null> {
820
+ const oldConnection = this.#connections.get(name);
821
+ const config = oldConnection?.config ?? this.#serverConfigs.get(name);
822
+ const source = this.#sources.get(name) ?? oldConnection?._source;
823
+ if (!config) return null;
824
+
825
+ logger.debug("MCP reconnecting", { path: `mcp:${name}` });
826
+
827
+ // Close the old transport without removing tools or notifying consumers.
828
+ // Tools stay available (stale) while we establish the new connection.
829
+ // Fire-and-forget: don't await the close — HttpTransport.close() sends a
830
+ // DELETE with config.timeout (30s default), and blocking here delays the
831
+ // reconnect loop by that amount on every server restart.
832
+ const reconnectEpoch = this.#epoch;
833
+ if (oldConnection) {
834
+ // Detach onClose to prevent re-entrant reconnect from the close itself
835
+ oldConnection.transport.onClose = undefined;
836
+ void oldConnection.transport.close().catch(() => {});
837
+ this.#connections.delete(name);
838
+ }
839
+ this.#pendingConnections.delete(name);
840
+ this.#pendingToolLoads.delete(name);
841
+
842
+ // Retry with backoff — the server may still be starting up.
843
+ const delays = [500, 1000, 2000, 4000];
844
+ for (let attempt = 0; attempt <= delays.length; attempt++) {
845
+ if (this.#epoch !== reconnectEpoch) {
846
+ logger.debug("MCP reconnect aborted before attempt after configuration changed", {
847
+ path: `mcp:${name}`,
848
+ storedEpoch: reconnectEpoch,
849
+ currentEpoch: this.#epoch,
850
+ });
851
+ return null;
852
+ }
853
+ try {
854
+ const connection = await this.#connectAndWireServer(name, config, source, reconnectEpoch);
855
+ logger.debug("MCP reconnected", { path: `mcp:${name}`, tools: connection.tools?.length ?? 0 });
856
+ return connection;
857
+ } catch (error) {
858
+ if (this.#epoch !== reconnectEpoch) {
859
+ logger.debug("MCP reconnect aborted after configuration changed", {
860
+ path: `mcp:${name}`,
861
+ storedEpoch: reconnectEpoch,
862
+ currentEpoch: this.#epoch,
863
+ });
864
+ return null;
865
+ }
866
+
867
+ const msg = error instanceof Error ? error.message : String(error);
868
+ if (attempt < delays.length) {
869
+ logger.debug("MCP reconnect attempt failed, retrying", {
870
+ path: `mcp:${name}`,
871
+ attempt: attempt + 1,
872
+ error: msg,
873
+ });
874
+ await Bun.sleep(delays[attempt]);
875
+ } else {
876
+ logger.error("MCP reconnect failed after retries", { path: `mcp:${name}`, error: msg });
877
+ // Don't remove stale tools — keep them in the registry so they
878
+ // remain selected. Calls will fail with MCP errors, which
879
+ // triggers the tool-level reconnect, or the user can run
880
+ // /mcp reconnect <name> manually.
881
+ }
882
+ }
883
+ }
884
+ return null;
885
+ }
886
+
887
+ /** Establish a new connection to a server, wire handlers, load tools. */
888
+ async #connectAndWireServer(
889
+ name: string,
890
+ config: MCPServerConfig,
891
+ source: SourceMeta | undefined,
892
+ reconnectEpoch: number,
893
+ ): Promise<MCPServerConnection> {
894
+ const resolvedConfig = await this.#resolveAuthConfig(config);
895
+ const connection = await connectToServer(name, resolvedConfig, {
896
+ onNotification: (method, params) => {
897
+ this.#handleServerNotification(name, method, params);
898
+ },
899
+ onRequest: (method, params) => {
900
+ return this.#handleServerRequest(method, params);
901
+ },
902
+ });
903
+
904
+ connection.config = config;
905
+ if (source) connection._source = source;
906
+
907
+ // Bail out if the server was disconnected or the manager was reset
908
+ // while we were connecting (e.g. /mcp reload called disconnectAll).
909
+ if (!this.#serverConfigs.has(name) || this.#epoch !== reconnectEpoch) {
910
+ await connection.transport.close().catch(() => {});
911
+ throw new Error(`Server "${name}" was disconnected during reconnection`);
912
+ }
913
+
914
+ this.#connections.set(name, connection);
915
+
916
+ // Wire auth refresh for HTTP transports, and reconnect for any transport.
917
+ if (connection.transport instanceof HttpTransport && config.auth?.type === "oauth") {
918
+ connection.transport.onAuthError = async () => {
919
+ const refreshed = await this.#resolveAuthConfig(config, true);
920
+ if (refreshed.type === "http" || refreshed.type === "sse") {
921
+ return refreshed.headers ?? null;
922
+ }
923
+ return null;
924
+ };
925
+ }
926
+ connection.transport.onClose = () => {
927
+ logger.debug("MCP transport lost, triggering reconnect", { path: `mcp:${name}` });
928
+ void this.reconnectServer(name);
929
+ };
930
+ try {
931
+ const serverTools = await listTools(connection);
932
+ const reconnect = () => this.reconnectServer(name);
933
+ const customTools = MCPTool.fromTools(connection, serverTools, reconnect);
934
+ void this.toolCache?.set(name, config, serverTools);
935
+ this.#replaceServerTools(name, customTools);
936
+ this.#onToolsChanged?.(this.#tools);
937
+ void this.#loadServerResourcesAndPrompts(name, connection);
938
+ return connection;
939
+ } catch (error) {
940
+ // Clean up the connection to avoid zombie transports
941
+ connection.transport.onClose = undefined;
942
+ await connection.transport.close().catch(() => {});
943
+ this.#connections.delete(name);
944
+ throw error;
945
+ }
946
+ }
947
+
948
+ /**
949
+ * Best-effort loading of resources, resource subscriptions, and prompts.
950
+ * Shared between initial connection and reconnection.
951
+ */
952
+ async #loadServerResourcesAndPrompts(name: string, connection: MCPServerConnection): Promise<void> {
953
+ if (serverSupportsResources(connection.capabilities)) {
954
+ try {
955
+ const [resources] = await Promise.all([listResources(connection), listResourceTemplates(connection)]);
956
+
957
+ if (this.#notificationsEnabled && connection.capabilities.resources?.subscribe) {
958
+ const uris = resources.map(r => r.uri);
959
+ const notificationEpoch = this.#notificationsEpoch;
960
+ this.#subscribeAndTrack(name, connection, uris, notificationEpoch);
961
+ }
962
+ } catch (error) {
963
+ logger.debug("Failed to load MCP resources", { path: `mcp:${name}`, error });
964
+ }
965
+ }
966
+
967
+ if (serverSupportsPrompts(connection.capabilities)) {
968
+ try {
969
+ await listPrompts(connection);
970
+ this.#onPromptsChanged?.(name);
971
+ } catch (error) {
972
+ logger.debug("Failed to load MCP prompts", { path: `mcp:${name}`, error });
973
+ }
974
+ }
975
+ }
976
+
977
+ /**
978
+ * Refresh tools from a specific server.
979
+ */
980
+ async refreshServerTools(name: string): Promise<void> {
981
+ const connection = this.#connections.get(name);
982
+ if (!connection) return;
983
+
984
+ // Clear cached tools
985
+ connection.tools = undefined;
986
+
987
+ // Reload tools
988
+ const serverTools = await listTools(connection);
989
+ const reconnect = () => this.reconnectServer(name);
990
+ const customTools = MCPTool.fromTools(connection, serverTools, reconnect);
991
+ void this.toolCache?.set(name, connection.config, serverTools);
992
+
993
+ // Replace tools from this server
994
+ this.#replaceServerTools(name, customTools);
995
+ this.#onToolsChanged?.(this.#tools);
996
+ }
997
+
998
+ /**
999
+ * Refresh tools from all servers.
1000
+ */
1001
+ async refreshAllTools(): Promise<void> {
1002
+ const promises = Array.from(this.#connections.keys()).map(name => this.refreshServerTools(name));
1003
+ await Promise.allSettled(promises);
1004
+ }
1005
+
1006
+ /**
1007
+ * Refresh resources from a specific server.
1008
+ */
1009
+ async refreshServerResources(name: string): Promise<void> {
1010
+ const connection = this.#connections.get(name);
1011
+ if (!connection || !serverSupportsResources(connection.capabilities)) return;
1012
+
1013
+ const existing = this.#pendingResourceRefresh.get(name);
1014
+ if (existing && existing.connection === connection) return existing.promise;
1015
+
1016
+ const doRefresh = async (): Promise<void> => {
1017
+ // Clear cached resources
1018
+ connection.resources = undefined;
1019
+ connection.resourceTemplates = undefined;
1020
+
1021
+ // Reload
1022
+ const [resources] = await Promise.all([listResources(connection), listResourceTemplates(connection)]);
1023
+ if (this.#notificationsEnabled && connection.capabilities.resources?.subscribe) {
1024
+ const newUris = new Set(resources.map(r => r.uri));
1025
+ const oldUris = this.#subscribedResources.get(name);
1026
+ const notificationEpoch = this.#notificationsEpoch;
1027
+
1028
+ // Unsubscribe URIs that were removed
1029
+ if (oldUris) {
1030
+ const removed = [...oldUris].filter(uri => !newUris.has(uri));
1031
+ if (removed.length > 0) {
1032
+ try {
1033
+ await unsubscribeFromResources(connection, removed);
1034
+ } catch (error) {
1035
+ logger.debug("Failed to unsubscribe stale MCP resources", { path: `mcp:${name}`, error });
1036
+ }
1037
+ }
1038
+ }
1039
+
1040
+ // Subscribe to the current set and update tracking atomically
1041
+ try {
1042
+ const allUris = [...newUris];
1043
+ await subscribeToResources(connection, allUris);
1044
+ const action = resolveSubscriptionPostAction(
1045
+ this.#notificationsEnabled,
1046
+ this.#notificationsEpoch,
1047
+ notificationEpoch,
1048
+ );
1049
+ if (action === "rollback") {
1050
+ await unsubscribeFromResources(connection, allUris).catch(error => {
1051
+ logger.debug("Failed to rollback stale MCP resource subscription", { path: `mcp:${name}`, error });
1052
+ });
1053
+ return;
1054
+ }
1055
+ if (action === "ignore") {
1056
+ return;
1057
+ }
1058
+ this.#subscribedResources.set(name, newUris);
1059
+ } catch (error) {
1060
+ logger.debug("Failed to re-subscribe to MCP resources", { path: `mcp:${name}`, error });
1061
+ }
1062
+ }
1063
+ };
1064
+
1065
+ const promise = doRefresh().finally(() => {
1066
+ const pending = this.#pendingResourceRefresh.get(name);
1067
+ if (pending?.promise === promise) {
1068
+ this.#pendingResourceRefresh.delete(name);
1069
+ }
1070
+ });
1071
+ this.#pendingResourceRefresh.set(name, { connection, promise });
1072
+ return promise;
1073
+ }
1074
+
1075
+ /**
1076
+ * Refresh prompts from a specific server.
1077
+ */
1078
+ async refreshServerPrompts(name: string): Promise<void> {
1079
+ const connection = this.#connections.get(name);
1080
+ if (!connection || !serverSupportsPrompts(connection.capabilities)) return;
1081
+
1082
+ connection.prompts = undefined;
1083
+ await listPrompts(connection);
1084
+
1085
+ this.#onPromptsChanged?.(name);
1086
+ }
1087
+
1088
+ /**
1089
+ * Get resources and templates for a specific server.
1090
+ */
1091
+ getServerResources(name: string): { resources: MCPResource[]; templates: MCPResourceTemplate[] } | undefined {
1092
+ const connection = this.#connections.get(name);
1093
+ if (!connection) return undefined;
1094
+ return {
1095
+ resources: connection.resources ?? [],
1096
+ templates: connection.resourceTemplates ?? [],
1097
+ };
1098
+ }
1099
+
1100
+ /**
1101
+ * Read a specific resource from a server.
1102
+ */
1103
+ async readServerResource(
1104
+ name: string,
1105
+ uri: string,
1106
+ options?: MCPRequestOptions,
1107
+ ): Promise<MCPResourceReadResult | undefined> {
1108
+ const connection = this.#connections.get(name);
1109
+ if (!connection) return undefined;
1110
+ return readResource(connection, uri, options);
1111
+ }
1112
+
1113
+ /**
1114
+ * Get prompts for a specific server.
1115
+ */
1116
+ getServerPrompts(name: string): MCPPrompt[] | undefined {
1117
+ const connection = this.#connections.get(name);
1118
+ if (!connection) return undefined;
1119
+ return connection.prompts ?? [];
1120
+ }
1121
+
1122
+ /**
1123
+ * Get a specific prompt from a server.
1124
+ */
1125
+ async executePrompt(
1126
+ name: string,
1127
+ promptName: string,
1128
+ args?: Record<string, string>,
1129
+ options?: MCPRequestOptions,
1130
+ ): Promise<MCPGetPromptResult | undefined> {
1131
+ const connection = this.#connections.get(name);
1132
+ if (!connection) return undefined;
1133
+ return getPrompt(connection, promptName, args, options);
1134
+ }
1135
+
1136
+ /**
1137
+ * Get all server instructions (for system prompt injection).
1138
+ */
1139
+ getServerInstructions(): Map<string, string> {
1140
+ const instructions = new Map<string, string>();
1141
+ for (const [name, connection] of this.#connections) {
1142
+ if (connection.instructions) {
1143
+ instructions.set(name, connection.instructions);
1144
+ }
1145
+ }
1146
+ return instructions;
1147
+ }
1148
+
1149
+ /**
1150
+ * Get notification state for display.
1151
+ */
1152
+ getNotificationState(): { enabled: boolean; subscriptions: Map<string, ReadonlySet<string>> } {
1153
+ return {
1154
+ enabled: this.#notificationsEnabled,
1155
+ subscriptions: this.#subscribedResources as Map<string, ReadonlySet<string>>,
1156
+ };
1157
+ }
1158
+
1159
+ /**
1160
+ * Resolve OAuth credentials and shell commands in config.
1161
+ */
1162
+ async #resolveAuthConfig(config: MCPServerConfig, forceRefresh = false): Promise<MCPServerConfig> {
1163
+ let resolved: MCPServerConfig = { ...config };
1164
+
1165
+ const auth = config.auth;
1166
+ if (auth?.type === "oauth" && auth.credentialId && this.#authStorage) {
1167
+ const credentialId = auth.credentialId;
1168
+ try {
1169
+ let credential = this.#authStorage.get(credentialId);
1170
+ if (credential?.type === "oauth") {
1171
+ // Proactive refresh: 5-minute buffer before expiry
1172
+ // Force refresh: on 401/403 auth errors (revoked tokens, clock skew, missing expires)
1173
+ const REFRESH_BUFFER_MS = 5 * 60_000;
1174
+ const shouldRefresh =
1175
+ forceRefresh || (credential.expires && Date.now() >= credential.expires - REFRESH_BUFFER_MS);
1176
+ if (shouldRefresh && credential.refresh && auth.tokenUrl) {
1177
+ try {
1178
+ const refreshed = await refreshMCPOAuthToken(
1179
+ auth.tokenUrl,
1180
+ credential.refresh,
1181
+ auth.clientId,
1182
+ auth.clientSecret,
1183
+ );
1184
+ const refreshedCredential = { type: "oauth" as const, ...refreshed };
1185
+ await this.#authStorage.set(credentialId, refreshedCredential);
1186
+ credential = refreshedCredential;
1187
+ } catch (refreshError) {
1188
+ const errorMsg = refreshError instanceof Error ? refreshError.message : String(refreshError);
1189
+ if (isDefinitiveOAuthFailure(errorMsg)) {
1190
+ // `invalid_grant` / `invalid_token` / 401 from the token endpoint means
1191
+ // the server has retired this credential — keeping the stale access
1192
+ // token would just re-fail with 401 on every MCP request and leave a
1193
+ // poisoned row in agent.db that survives restarts. Drop it now so the
1194
+ // next connect attempt surfaces a clean "needs reauth" failure and
1195
+ // the user can recover with `/mcp reauth <server>` (or `/mcp unauth`
1196
+ // to forget the server entirely).
1197
+ logger.warn("MCP OAuth refresh failed definitively; cleared credential", {
1198
+ credentialId,
1199
+ error: errorMsg,
1200
+ });
1201
+ await this.#authStorage.remove(credentialId);
1202
+ credential = undefined;
1203
+ } else {
1204
+ logger.warn("MCP OAuth refresh failed, using existing token", {
1205
+ credentialId,
1206
+ error: refreshError,
1207
+ });
1208
+ }
1209
+ }
1210
+ }
1211
+
1212
+ if (credential?.type === "oauth") {
1213
+ if (resolved.type === "http" || resolved.type === "sse") {
1214
+ resolved = {
1215
+ ...resolved,
1216
+ headers: {
1217
+ ...resolved.headers,
1218
+ Authorization: `Bearer ${credential.access}`,
1219
+ },
1220
+ };
1221
+ } else {
1222
+ resolved = {
1223
+ ...resolved,
1224
+ env: {
1225
+ ...resolved.env,
1226
+ OAUTH_ACCESS_TOKEN: credential.access,
1227
+ },
1228
+ };
1229
+ }
1230
+ }
1231
+ }
1232
+ } catch (error) {
1233
+ logger.warn("Failed to resolve OAuth credential", { credentialId, error });
1234
+ }
1235
+ }
1236
+
1237
+ if (resolved.type !== "http" && resolved.type !== "sse") {
1238
+ if (resolved.env) {
1239
+ const nextEnv: Record<string, string> = {};
1240
+ for (const [key, value] of Object.entries(resolved.env)) {
1241
+ const resolvedValue = await resolveConfigValue(value);
1242
+ if (resolvedValue) nextEnv[key] = resolvedValue;
1243
+ }
1244
+ resolved = { ...resolved, env: nextEnv };
1245
+ }
1246
+ } else {
1247
+ if (resolved.headers) {
1248
+ const nextHeaders: Record<string, string> = {};
1249
+ for (const [key, value] of Object.entries(resolved.headers)) {
1250
+ const resolvedValue = await resolveConfigValue(value);
1251
+ if (resolvedValue) nextHeaders[key] = resolvedValue;
1252
+ }
1253
+ resolved = { ...resolved, headers: nextHeaders };
1254
+ }
1255
+ }
1256
+
1257
+ return resolved;
1258
+ }
1259
+ }
1260
+
1261
+ /**
1262
+ * Create an MCP manager and discover servers.
1263
+ * Convenience function for quick setup.
1264
+ */
1265
+ export async function createMCPManager(
1266
+ cwd: string,
1267
+ options?: MCPDiscoverOptions,
1268
+ ): Promise<{
1269
+ manager: MCPManager;
1270
+ result: MCPLoadResult;
1271
+ }> {
1272
+ const manager = new MCPManager(cwd);
1273
+ const result = await manager.discoverAndConnect(options);
1274
+ return { manager, result };
1275
+ }